1/** 2 * TinyMCE version 7.7.1 (2025-03-05
vendor: 10,145 bytes, lines 2-390
2) 3 */ 4 5(function () { 6 'use strict'; 7 8 var typeOf$1 = function (x) { 9 if (x === null) { 10 return 'null'; 11 } 12 if (x === undefined) { 13 return 'undefined'; 14 } 15 var t = typeof x; 16 if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) { 17 return 'array'; 18 } 19 if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) { 20 return 'string'; 21 } 22 return t; 23 }; 24 var isEquatableType = function (x) { 25 return [ 26 'undefined', 27 'boolean', 28 'number', 29 'string', 30 'function', 31 'xml', 32 'null' 33 ].indexOf(x) !== -1; 34 }; 35 36 var sort$1 = function (xs, compareFn) { 37 var clone = Array.prototype.slice.call(xs); 38 return clone.sort(compareFn); 39 }; 40 41 var contramap = function (eqa, f) { 42 return eq$2(function (x, y) { 43 return eqa.eq(f(x), f(y)); 44 }); 45 }; 46 var eq$2 = function (f) { 47 return { eq: f }; 48 }; 49 var tripleEq = eq$2(function (x, y) { 50 return x === y; 51 }); 52 var eqString = tripleEq; 53 var eqArray = function (eqa) { 54 return eq$2(function (x, y) { 55 if (x.length !== y.length) { 56 return false; 57 } 58 var len = x.length; 59 for (var i = 0; i < len; i++) { 60 if (!eqa.eq(x[i], y[i])) { 61 return false; 62 } 63 } 64 return true; 65 }); 66 }; 67 var eqSortedArray = function (eqa, compareFn) { 68 return contramap(eqArray(eqa), function (xs) { 69 return sort$1(xs, compareFn); 70 }); 71 }; 72 var eqRecord = function (eqa) { 73 return eq$2(function (x, y) { 74 var kx = Object.keys(x); 75 var ky = Object.keys(y); 76 if (!eqSortedArray(eqString).eq(kx, ky)) { 77 return false; 78 } 79 var len = kx.length; 80 for (var i = 0; i < len; i++) { 81 var q = kx[i]; 82 if (!eqa.eq(x[q], y[q])) { 83 return false; 84 } 85 } 86 return true; 87 }); 88 }; 89 var eqAny = eq$2(function (x, y) { 90 if (x === y) { 91 return true; 92 } 93 var tx = typeOf$1(x); 94 var ty = typeOf$1(y); 95 if (tx !== ty) { 96 return false; 97 } 98 if (isEquatableType(tx)) { 99 return x === y; 100 } else if (tx === 'array') { 101 return eqArray(eqAny).eq(x, y); 102 } else if (tx === 'object') { 103 return eqRecord(eqAny).eq(x, y); 104 } 105 return false; 106 }); 107 108 const getPrototypeOf$2 = Object.getPrototypeOf; 109 const hasProto = (v, constructor, predicate) => { 110 var _a; 111 if (predicate(v, constructor.prototype)) { 112 return true; 113 } else { 114 return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name; 115 } 116 }; 117 const typeOf = x => { 118 const t = typeof x; 119 if (x === null) { 120 return 'null'; 121 } else if (t === 'object' && Array.isArray(x)) { 122 return 'array'; 123 } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) { 124 return 'string'; 125 } else { 126 return t; 127 } 128 }; 129 const isType$1 = type => value => typeOf(value) === type; 130 const isSimpleType = type => value => typeof value === type; 131 const eq$1 = t => a => t === a; 132 const is$4 = (value, constructor) => isObject(value) && hasProto(value, constructor, (o, proto) => getPrototypeOf$2(o) === proto); 133 const isString = isType$1('string'); 134 const isObject = isType$1('object'); 135 const isPlainObject = value => is$4(value, Object); 136 const isArray$1 = isType$1('array'); 137 const isNull = eq$1(null); 138 const isBoolean = isSimpleType('boolean'); 139 const isUndefined = eq$1(undefined); 140 const isNullable = a => a === null || a === undefined; 141 const isNonNullable = a => !isNullable(a); 142 const isFunction = isSimpleType('function'); 143 const isNumber = isSimpleType('number'); 144 const isArrayOf = (value, pred) => { 145 if (isArray$1(value)) { 146 for (let i = 0, len = value.length; i < len; ++i) { 147 if (!pred(value[i])) { 148 return false; 149 } 150 } 151 return true; 152 } 153 return false; 154 }; 155 156 const noop = () => { 157 }; 158 const compose = (fa, fb) => { 159 return (...args) => { 160 return fa(fb.apply(null, args)); 161 }; 162 }; 163 const compose1 = (fbc, fab) => a => fbc(fab(a)); 164 const constant = value => { 165 return () => { 166 return value; 167 }; 168 }; 169 const identity = x => { 170 return x; 171 }; 172 const tripleEquals = (a, b) => { 173 return a === b; 174 }; 175 function curry(fn, ...initialArgs) { 176 return (...restArgs) => { 177 const all = initialArgs.concat(restArgs); 178 return fn.apply(null, all); 179 }; 180 } 181 const not = f => t => !f(t); 182 const die = msg => { 183 return () => { 184 throw new Error(msg); 185 }; 186 }; 187 const apply$1 = f => { 188 return f(); 189 }; 190 const call = f => { 191 f(); 192 }; 193 const never = constant(false); 194 const always = constant(true); 195 196 class Optional { 197 constructor(tag, value) { 198 this.tag = tag; 199 this.value = value; 200 } 201 static some(value) { 202 return new Optional(true, value); 203 } 204 static none() { 205 return Optional.singletonNone; 206 } 207 fold(onNone, onSome) { 208 if (this.tag) { 209 return onSome(this.value); 210 } else { 211 return onNone(); 212 } 213 } 214 isSome() { 215 return this.tag; 216 } 217 isNone() { 218 return !this.tag; 219 } 220 map(mapper) { 221 if (this.tag) { 222 return Optional.some(mapper(this.value)); 223 } else { 224 return Optional.none(); 225 } 226 } 227 bind(binder) { 228 if (this.tag) { 229 return binder(this.value); 230 } else { 231 return Optional.none(); 232 } 233 } 234 exists(predicate) { 235 return this.tag && predicate(this.value); 236 } 237 forall(predicate) { 238 return !this.tag || predicate(this.value); 239 } 240 filter(predicate) { 241 if (!this.tag || predicate(this.value)) { 242 return this; 243 } else { 244 return Optional.none(); 245 } 246 } 247 getOr(replacement) { 248 return this.tag ? this.value : replacement; 249 } 250 or(replacement) { 251 return this.tag ? this : replacement; 252 } 253 getOrThunk(thunk) { 254 return this.tag ? this.value : thunk(); 255 } 256 orThunk(thunk) { 257 return this.tag ? this : thunk(); 258 } 259 getOrDie(message) { 260 if (!this.tag) { 261 throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None'); 262 } else { 263 return this.value; 264 } 265 } 266 static from(value) { 267 return isNonNullable(value) ? Optional.some(value) : Optional.none(); 268 } 269 getOrNull() { 270 return this.tag ? this.value : null; 271 } 272 getOrUndefined() { 273 return this.value; 274 } 275 each(worker) { 276 if (this.tag) { 277 worker(this.value); 278 } 279 } 280 toArray() { 281 return this.tag ? [this.value] : []; 282 } 283 toString() { 284 return this.tag ? `some(${ this.value })` : 'none()'; 285 } 286 } 287 Optional.singletonNone = new Optional(false); 288 289 const nativeSlice = Array.prototype.slice; 290 const nativeIndexOf = Array.prototype.indexOf; 291 const nativePush = Array.prototype.push; 292 const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t); 293 const indexOf$1 = (xs, x) => { 294 const r = rawIndexOf(xs, x); 295 return r === -1 ? Optional.none() : Optional.some(r); 296 }; 297 const contains$2 = (xs, x) => rawIndexOf(xs, x) > -1; 298 const exists = (xs, pred) => { 299 for (let i = 0, len = xs.length; i < len; i++) { 300 const x = xs[i]; 301 if (pred(x, i)) { 302 return true; 303 } 304 } 305 return false; 306 }; 307 const map$3 = (xs, f) => { 308 const len = xs.length; 309 const r = new Array(len); 310 for (let i = 0; i < len; i++) { 311 const x = xs[i]; 312 r[i] = f(x, i); 313 } 314 return r; 315 }; 316 const each$e = (xs, f) => { 317 for (let i = 0, len = xs.length; i < len; i++) { 318 const x = xs[i]; 319 f(x, i); 320 } 321 }; 322 const eachr = (xs, f) => { 323 for (let i = xs.length - 1; i >= 0; i--) { 324 const x = xs[i]; 325 f(x, i); 326 } 327 }; 328 const partition$2 = (xs, pred) => { 329 const pass = []; 330 const fail = []; 331 for (let i = 0, len = xs.length; i < len; i++) { 332 const x = xs[i]; 333 const arr = pred(x, i) ? pass : fail; 334 arr.push(x); 335 } 336 return { 337 pass, 338 fail 339 }; 340 }; 341 const filter$5 = (xs, pred) => { 342 const r = []; 343 for (let i = 0, len = xs.length; i < len; i++) { 344 const x = xs[i]; 345 if (pred(x, i)) { 346 r.push(x); 347 } 348 } 349 return r; 350 }; 351 const foldr = (xs, f, acc) => { 352 eachr(xs, (x, i) => { 353 acc = f(acc, x, i); 354 }); 355 return acc; 356 }; 357 const foldl = (xs, f, acc) => { 358 each$e(xs, (x, i) => { 359 acc = f(acc, x, i); 360 }); 361 return acc; 362 }; 363 const findUntil$1 = (xs, pred, until) => { 364 for (let i = 0, len = xs.length; i < len; i++) { 365 const x = xs[i]; 366 if (pred(x, i)) { 367 return Optional.some(x); 368 } else if (until(x, i)) { 369 break; 370 } 371 } 372 return Optional.none(); 373 }; 374 const find$2 = (xs, pred) => { 375 return findUntil$1(xs, pred, never); 376 }; 377 const findIndex$2 = (xs, pred) => { 378 for (let i = 0, len = xs.length; i < len; i++) { 379 const x = xs[i]; 380 if (pred(x, i)) { 381 return Optional.some(i); 382 } 383 } 384 return Optional.none(); 385 }; 386 const flatten = xs => { 387 const r = []; 388 for (let i = 0, len = xs.length; i < len; ++i) { 389 if (!isArray$1(xs[i])) { 390 throw new Error('Arr.flatten item ' + i + ' was not an array, input
vendor: 16,351 bytes, lines 390-958
390: ' + xs); 391 } 392 nativePush.apply(r, xs[i]); 393 } 394 return r; 395 }; 396 const bind$3 = (xs, f) => flatten(map$3(xs, f)); 397 const forall = (xs, pred) => { 398 for (let i = 0, len = xs.length; i < len; ++i) { 399 const x = xs[i]; 400 if (pred(x, i) !== true) { 401 return false; 402 } 403 } 404 return true; 405 }; 406 const reverse = xs => { 407 const r = nativeSlice.call(xs, 0); 408 r.reverse(); 409 return r; 410 }; 411 const difference = (a1, a2) => filter$5(a1, x => !contains$2(a2, x)); 412 const mapToObject = (xs, f) => { 413 const r = {}; 414 for (let i = 0, len = xs.length; i < len; i++) { 415 const x = xs[i]; 416 r[String(x)] = f(x, i); 417 } 418 return r; 419 }; 420 const sort = (xs, comparator) => { 421 const copy = nativeSlice.call(xs, 0); 422 copy.sort(comparator); 423 return copy; 424 }; 425 const get$b = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none(); 426 const head = xs => get$b(xs, 0); 427 const last$2 = xs => get$b(xs, xs.length - 1); 428 const from = isFunction(Array.from) ? Array.from : x => nativeSlice.call(x); 429 const findMap = (arr, f) => { 430 for (let i = 0; i < arr.length; i++) { 431 const r = f(arr[i], i); 432 if (r.isSome()) { 433 return r; 434 } 435 } 436 return Optional.none(); 437 }; 438 const unique$1 = (xs, comparator) => { 439 const r = []; 440 const isDuplicated = isFunction(comparator) ? x => exists(r, i => comparator(i, x)) : x => contains$2(r, x); 441 for (let i = 0, len = xs.length; i < len; i++) { 442 const x = xs[i]; 443 if (!isDuplicated(x)) { 444 r.push(x); 445 } 446 } 447 return r; 448 }; 449 450 const keys = Object.keys; 451 const hasOwnProperty$1 = Object.hasOwnProperty; 452 const each$d = (obj, f) => { 453 const props = keys(obj); 454 for (let k = 0, len = props.length; k < len; k++) { 455 const i = props[k]; 456 const x = obj[i]; 457 f(x, i); 458 } 459 }; 460 const map$2 = (obj, f) => { 461 return tupleMap(obj, (x, i) => ({ 462 k: i, 463 v: f(x, i) 464 })); 465 }; 466 const tupleMap = (obj, f) => { 467 const r = {}; 468 each$d(obj, (x, i) => { 469 const tuple = f(x, i); 470 r[tuple.k] = tuple.v; 471 }); 472 return r; 473 }; 474 const objAcc = r => (x, i) => { 475 r[i] = x; 476 }; 477 const internalFilter = (obj, pred, onTrue, onFalse) => { 478 each$d(obj, (x, i) => { 479 (pred(x, i) ? onTrue : onFalse)(x, i); 480 }); 481 }; 482 const bifilter = (obj, pred) => { 483 const t = {}; 484 const f = {}; 485 internalFilter(obj, pred, objAcc(t), objAcc(f)); 486 return { 487 t, 488 f 489 }; 490 }; 491 const filter$4 = (obj, pred) => { 492 const t = {}; 493 internalFilter(obj, pred, objAcc(t), noop); 494 return t; 495 }; 496 const mapToArray = (obj, f) => { 497 const r = []; 498 each$d(obj, (value, name) => { 499 r.push(f(value, name)); 500 }); 501 return r; 502 }; 503 const values = obj => { 504 return mapToArray(obj, identity); 505 }; 506 const get$a = (obj, key) => { 507 return has$2(obj, key) ? Optional.from(obj[key]) : Optional.none(); 508 }; 509 const has$2 = (obj, key) => hasOwnProperty$1.call(obj, key); 510 const hasNonNullableKey = (obj, key) => has$2(obj, key) && obj[key] !== undefined && obj[key] !== null; 511 const equal$1 = (a1, a2, eq = eqAny) => eqRecord(eq).eq(a1, a2); 512 513 const stringArray = a => { 514 const all = {}; 515 each$e(a, key => { 516 all[key] = {}; 517 }); 518 return keys(all); 519 }; 520 521 const isArrayLike = o => o.length !== undefined; 522 const isArray = Array.isArray; 523 const toArray$1 = obj => { 524 if (!isArray(obj)) { 525 const array = []; 526 for (let i = 0, l = obj.length; i < l; i++) { 527 array[i] = obj[i]; 528 } 529 return array; 530 } else { 531 return obj; 532 } 533 }; 534 const each$c = (o, cb, s) => { 535 if (!o) { 536 return false; 537 } 538 s = s || o; 539 if (isArrayLike(o)) { 540 for (let n = 0, l = o.length; n < l; n++) { 541 if (cb.call(s, o[n], n, o) === false) { 542 return false; 543 } 544 } 545 } else { 546 for (const n in o) { 547 if (has$2(o, n)) { 548 if (cb.call(s, o[n], n, o) === false) { 549 return false; 550 } 551 } 552 } 553 } 554 return true; 555 }; 556 const map$1 = (array, callback) => { 557 const out = []; 558 each$c(array, (item, index) => { 559 out.push(callback(item, index, array)); 560 }); 561 return out; 562 }; 563 const filter$3 = (a, f) => { 564 const o = []; 565 each$c(a, (v, index) => { 566 if (!f || f(v, index, a)) { 567 o.push(v); 568 } 569 }); 570 return o; 571 }; 572 const indexOf = (a, v) => { 573 if (a) { 574 for (let i = 0, l = a.length; i < l; i++) { 575 if (a[i] === v) { 576 return i; 577 } 578 } 579 } 580 return -1; 581 }; 582 const reduce = (collection, iteratee, accumulator, thisArg) => { 583 let acc = isUndefined(accumulator) ? collection[0] : accumulator; 584 for (let i = 0; i < collection.length; i++) { 585 acc = iteratee.call(thisArg, acc, collection[i], i); 586 } 587 return acc; 588 }; 589 const findIndex$1 = (array, predicate, thisArg) => { 590 for (let i = 0, l = array.length; i < l; i++) { 591 if (predicate.call(thisArg, array[i], i, array)) { 592 return i; 593 } 594 } 595 return -1; 596 }; 597 const last$1 = collection => collection[collection.length - 1]; 598 599 const cached = f => { 600 let called = false; 601 let r; 602 return (...args) => { 603 if (!called) { 604 called = true; 605 r = f.apply(null, args); 606 } 607 return r; 608 }; 609 }; 610 611 const DeviceType = (os, browser, userAgent, mediaMatch) => { 612 const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true; 613 const isiPhone = os.isiOS() && !isiPad; 614 const isMobile = os.isiOS() || os.isAndroid(); 615 const isTouch = isMobile || mediaMatch('(pointer:coarse)'); 616 const isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)'); 617 const isPhone = isiPhone || isMobile && !isTablet; 618 const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false; 619 const isDesktop = !isPhone && !isTablet && !iOSwebview; 620 return { 621 isiPad: constant(isiPad), 622 isiPhone: constant(isiPhone), 623 isTablet: constant(isTablet), 624 isPhone: constant(isPhone), 625 isTouch: constant(isTouch), 626 isAndroid: os.isAndroid, 627 isiOS: os.isiOS, 628 isWebView: constant(iOSwebview), 629 isDesktop: constant(isDesktop) 630 }; 631 }; 632 633 const firstMatch = (regexes, s) => { 634 for (let i = 0; i < regexes.length; i++) { 635 const x = regexes[i]; 636 if (x.test(s)) { 637 return x; 638 } 639 } 640 return undefined; 641 }; 642 const find$1 = (regexes, agent) => { 643 const r = firstMatch(regexes, agent); 644 if (!r) { 645 return { 646 major: 0, 647 minor: 0 648 }; 649 } 650 const group = i => { 651 return Number(agent.replace(r, '$' + i)); 652 }; 653 return nu$3(group(1), group(2)); 654 }; 655 const detect$4 = (versionRegexes, agent) => { 656 const cleanedAgent = String(agent).toLowerCase(); 657 if (versionRegexes.length === 0) { 658 return unknown$2(); 659 } 660 return find$1(versionRegexes, cleanedAgent); 661 }; 662 const unknown$2 = () => { 663 return nu$3(0, 0); 664 }; 665 const nu$3 = (major, minor) => { 666 return { 667 major, 668 minor 669 }; 670 }; 671 const Version = { 672 nu: nu$3, 673 detect: detect$4, 674 unknown: unknown$2 675 }; 676 677 const detectBrowser$1 = (browsers, userAgentData) => { 678 return findMap(userAgentData.brands, uaBrand => { 679 const lcBrand = uaBrand.brand.toLowerCase(); 680 return find$2(browsers, browser => { 681 var _a; 682 return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase()); 683 }).map(info => ({ 684 current: info.name, 685 version: Version.nu(parseInt(uaBrand.version, 10), 0) 686 })); 687 }); 688 }; 689 690 const detect$3 = (candidates, userAgent) => { 691 const agent = String(userAgent).toLowerCase(); 692 return find$2(candidates, candidate => { 693 return candidate.search(agent); 694 }); 695 }; 696 const detectBrowser = (browsers, userAgent) => { 697 return detect$3(browsers, userAgent).map(browser => { 698 const version = Version.detect(browser.versionRegexes, userAgent); 699 return { 700 current: browser.name, 701 version 702 }; 703 }); 704 }; 705 const detectOs = (oses, userAgent) => { 706 return detect$3(oses, userAgent).map(os => { 707 const version = Version.detect(os.versionRegexes, userAgent); 708 return { 709 current: os.name, 710 version 711 }; 712 }); 713 }; 714 715 const removeFromStart = (str, numChars) => { 716 return str.substring(numChars); 717 }; 718 719 const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr; 720 const removeLeading = (str, prefix) => { 721 return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str; 722 }; 723 const contains$1 = (str, substr, start = 0, end) => { 724 const idx = str.indexOf(substr, start); 725 if (idx !== -1) { 726 return isUndefined(end) ? true : idx + substr.length <= end; 727 } else { 728 return false; 729 } 730 }; 731 const startsWith = (str, prefix) => { 732 return checkRange(str, prefix, 0); 733 }; 734 const endsWith = (str, suffix) => { 735 return checkRange(str, suffix, str.length - suffix.length); 736 }; 737 const blank = r => s => s.replace(r, ''); 738 const trim$4 = blank(/^\s+|\s+$/g); 739 const lTrim = blank(/^\s+/g); 740 const rTrim = blank(/\s+$/g); 741 const isNotEmpty = s => s.length > 0; 742 const isEmpty$3 = s => !isNotEmpty(s); 743 const repeat = (s, count) => count <= 0 ? '' : new Array(count + 1).join(s); 744 const toInt = (value, radix = 10) => { 745 const num = parseInt(value, radix); 746 return isNaN(num) ? Optional.none() : Optional.some(num); 747 }; 748 749 const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/; 750 const checkContains = target => { 751 return uastring => { 752 return contains$1(uastring, target); 753 }; 754 }; 755 const browsers = [ 756 { 757 name: 'Edge', 758 versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/], 759 search: uastring => { 760 return contains$1(uastring, 'edge/') && contains$1(uastring, 'chrome') && contains$1(uastring, 'safari') && contains$1(uastring, 'applewebkit'); 761 } 762 }, 763 { 764 name: 'Chromium', 765 brand: 'Chromium', 766 versionRegexes: [ 767 /.*?chrome\/([0-9]+)\.([0-9]+).*/, 768 normalVersionRegex 769 ], 770 search: uastring => { 771 return contains$1(uastring, 'chrome') && !contains$1(uastring, 'chromeframe'); 772 } 773 }, 774 { 775 name: 'IE', 776 versionRegexes: [ 777 /.*?msie\ ?([0-9]+)\.([0-9]+).*/, 778 /.*?rv:([0-9]+)\.([0-9]+).*/ 779 ], 780 search: uastring => { 781 return contains$1(uastring, 'msie') || contains$1(uastring, 'trident'); 782 } 783 }, 784 { 785 name: 'Opera', 786 versionRegexes: [ 787 normalVersionRegex, 788 /.*?opera\/([0-9]+)\.([0-9]+).*/ 789 ], 790 search: checkContains('opera') 791 }, 792 { 793 name: 'Firefox', 794 versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/], 795 search: checkContains('firefox') 796 }, 797 { 798 name: 'Safari', 799 versionRegexes: [ 800 normalVersionRegex, 801 /.*?cpu os ([0-9]+)_([0-9]+).*/ 802 ], 803 search: uastring => { 804 return (contains$1(uastring, 'safari') || contains$1(uastring, 'mobile/')) && contains$1(uastring, 'applewebkit'); 805 } 806 } 807 ]; 808 const oses = [ 809 { 810 name: 'Windows', 811 search: checkContains('win'), 812 versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/] 813 }, 814 { 815 name: 'iOS', 816 search: uastring => { 817 return contains$1(uastring, 'iphone') || contains$1(uastring, 'ipad'); 818 }, 819 versionRegexes: [ 820 /.*?version\/\ ?([0-9]+)\.([0-9]+).*/, 821 /.*cpu os ([0-9]+)_([0-9]+).*/, 822 /.*cpu iphone os ([0-9]+)_([0-9]+).*/ 823 ] 824 }, 825 { 826 name: 'Android', 827 search: checkContains('android'), 828 versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/] 829 }, 830 { 831 name: 'macOS', 832 search: checkContains('mac os x'), 833 versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/] 834 }, 835 { 836 name: 'Linux', 837 search: checkContains('linux'), 838 versionRegexes: [] 839 }, 840 { 841 name: 'Solaris', 842 search: checkContains('sunos'), 843 versionRegexes: [] 844 }, 845 { 846 name: 'FreeBSD', 847 search: checkContains('freebsd'), 848 versionRegexes: [] 849 }, 850 { 851 name: 'ChromeOS', 852 search: checkContains('cros'), 853 versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/] 854 } 855 ]; 856 const PlatformInfo = { 857 browsers: constant(browsers), 858 oses: constant(oses) 859 }; 860 861 const edge = 'Edge'; 862 const chromium = 'Chromium'; 863 const ie = 'IE'; 864 const opera = 'Opera'; 865 const firefox = 'Firefox'; 866 const safari = 'Safari'; 867 const unknown$1 = () => { 868 return nu$2({ 869 current: undefined, 870 version: Version.unknown() 871 }); 872 }; 873 const nu$2 = info => { 874 const current = info.current; 875 const version = info.version; 876 const isBrowser = name => () => current === name; 877 return { 878 current, 879 version, 880 isEdge: isBrowser(edge), 881 isChromium: isBrowser(chromium), 882 isIE: isBrowser(ie), 883 isOpera: isBrowser(opera), 884 isFirefox: isBrowser(firefox), 885 isSafari: isBrowser(safari) 886 }; 887 }; 888 const Browser = { 889 unknown: unknown$1, 890 nu: nu$2, 891 edge: constant(edge), 892 chromium: constant(chromium), 893 ie: constant(ie), 894 opera: constant(opera), 895 firefox: constant(firefox), 896 safari: constant(safari) 897 }; 898 899 const windows = 'Windows'; 900 const ios = 'iOS'; 901 const android = 'Android'; 902 const linux = 'Linux'; 903 const macos = 'macOS'; 904 const solaris = 'Solaris'; 905 const freebsd = 'FreeBSD'; 906 const chromeos = 'ChromeOS'; 907 const unknown = () => { 908 return nu$1({ 909 current: undefined, 910 version: Version.unknown() 911 }); 912 }; 913 const nu$1 = info => { 914 const current = info.current; 915 const version = info.version; 916 const isOS = name => () => current === name; 917 return { 918 current, 919 version, 920 isWindows: isOS(windows), 921 isiOS: isOS(ios), 922 isAndroid: isOS(android), 923 isMacOS: isOS(macos), 924 isLinux: isOS(linux), 925 isSolaris: isOS(solaris), 926 isFreeBSD: isOS(freebsd), 927 isChromeOS: isOS(chromeos) 928 }; 929 }; 930 const OperatingSystem = { 931 unknown, 932 nu: nu$1, 933 windows: constant(windows), 934 ios: constant(ios), 935 android: constant(android), 936 linux: constant(linux), 937 macos: constant(macos), 938 solaris: constant(solaris), 939 freebsd: constant(freebsd), 940 chromeos: constant(chromeos) 941 }; 942 943 const detect$2 = (userAgent, userAgentDataOpt, mediaMatch) => { 944 const browsers = PlatformInfo.browsers(); 945 const oses = PlatformInfo.oses(); 946 const browser = userAgentDataOpt.bind(userAgentData => detectBrowser$1(browsers, userAgentData)).orThunk(() => detectBrowser(browsers, userAgent)).fold(Browser.unknown, Browser.nu); 947 const os = detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu); 948 const deviceType = DeviceType(os, browser, userAgent, mediaMatch); 949 return { 950 browser, 951 os, 952 deviceType 953 }; 954 }; 955 const PlatformDetection = { detect: detect$2 }; 956 957 const mediaMatch = query => window.matchMedia(query).matches; 958 let platform$4 = cached(() => PlatformDetection.detect(
vendor: 2,931 bytes, lines 958-1051
958window.navigator.userAgent, Optional.from(window.navigator.userAgentData), mediaMatch)); 959 const detect$1 = () => platform$4(); 960 961 const userAgent = window.navigator.userAgent; 962 const platform$3 = detect$1(); 963 const browser$3 = platform$3.browser; 964 const os$1 = platform$3.os; 965 const deviceType = platform$3.deviceType; 966 const windowsPhone = userAgent.indexOf('Windows Phone') !== -1; 967 const Env = { 968 transparentSrc: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 969 documentMode: browser$3.isIE() ? document.documentMode || 7 : 10, 970 cacheSuffix: null, 971 container: null, 972 canHaveCSP: !browser$3.isIE(), 973 windowsPhone, 974 browser: { 975 current: browser$3.current, 976 version: browser$3.version, 977 isChromium: browser$3.isChromium, 978 isEdge: browser$3.isEdge, 979 isFirefox: browser$3.isFirefox, 980 isIE: browser$3.isIE, 981 isOpera: browser$3.isOpera, 982 isSafari: browser$3.isSafari 983 }, 984 os: { 985 current: os$1.current, 986 version: os$1.version, 987 isAndroid: os$1.isAndroid, 988 isChromeOS: os$1.isChromeOS, 989 isFreeBSD: os$1.isFreeBSD, 990 isiOS: os$1.isiOS, 991 isLinux: os$1.isLinux, 992 isMacOS: os$1.isMacOS, 993 isSolaris: os$1.isSolaris, 994 isWindows: os$1.isWindows 995 }, 996 deviceType: { 997 isDesktop: deviceType.isDesktop, 998 isiPad: deviceType.isiPad, 999 isiPhone: deviceType.isiPhone, 1000 isPhone: deviceType.isPhone, 1001 isTablet: deviceType.isTablet, 1002 isTouch: deviceType.isTouch, 1003 isWebView: deviceType.isWebView 1004 } 1005 }; 1006 1007 const whiteSpaceRegExp$1 = /^\s*|\s*$/g; 1008 const trim$3 = str => { 1009 return isNullable(str) ? '' : ('' + str).replace(whiteSpaceRegExp$1, ''); 1010 }; 1011 const is$3 = (obj, type) => { 1012 if (!type) { 1013 return obj !== undefined; 1014 } 1015 if (type === 'array' && isArray(obj)) { 1016 return true; 1017 } 1018 return typeof obj === type; 1019 }; 1020 const makeMap$4 = (items, delim, map = {}) => { 1021 const resolvedItems = isString(items) ? items.split(delim || ',') : items || []; 1022 let i = resolvedItems.length; 1023 while (i--) { 1024 map[resolvedItems[i]] = {}; 1025 } 1026 return map; 1027 }; 1028 const hasOwnProperty = has$2; 1029 const extend$3 = (obj, ...exts) => { 1030 for (let i = 0; i < exts.length; i++) { 1031 const ext = exts[i]; 1032 for (const name in ext) { 1033 if (has$2(ext, name)) { 1034 const value = ext[name]; 1035 if (value !== undefined) { 1036 obj[name] = value; 1037 } 1038 } 1039 } 1040 } 1041 return obj; 1042 }; 1043 const walk$4 = function (o, f, n, s) { 1044 s = s || this; 1045 if (o) { 1046 if (n) { 1047 o = o[n]; 1048 } 1049 each$c(o, (o, i) => { 1050 if (f.call(s, o, i, n) === false) { 1051 return false;
vendor: 16,632 bytes, lines 1052-1513
1052 } else { 1053 walk$4(o, f, n, s); 1054 return true; 1055 } 1056 }); 1057 } 1058 }; 1059 const resolve$3 = (n, o = window) => { 1060 const path = n.split('.'); 1061 for (let i = 0, l = path.length; i < l; i++) { 1062 o = o[path[i]]; 1063 if (!o) { 1064 break; 1065 } 1066 } 1067 return o; 1068 }; 1069 const explode$3 = (s, d) => { 1070 if (isArray$1(s)) { 1071 return s; 1072 } else if (s === '') { 1073 return []; 1074 } else { 1075 return map$1(s.split(d || ','), trim$3); 1076 } 1077 }; 1078 const _addCacheSuffix = url => { 1079 const cacheSuffix = Env.cacheSuffix; 1080 if (cacheSuffix) { 1081 url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix; 1082 } 1083 return url; 1084 }; 1085 const Tools = { 1086 trim: trim$3, 1087 isArray: isArray, 1088 is: is$3, 1089 toArray: toArray$1, 1090 makeMap: makeMap$4, 1091 each: each$c, 1092 map: map$1, 1093 grep: filter$3, 1094 inArray: indexOf, 1095 hasOwn: hasOwnProperty, 1096 extend: extend$3, 1097 walk: walk$4, 1098 resolve: resolve$3, 1099 explode: explode$3, 1100 _addCacheSuffix 1101 }; 1102 1103 const is$2 = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs)); 1104 const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone()); 1105 const cat = arr => { 1106 const r = []; 1107 const push = x => { 1108 r.push(x); 1109 }; 1110 for (let i = 0; i < arr.length; i++) { 1111 arr[i].each(push); 1112 } 1113 return r; 1114 }; 1115 const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none(); 1116 const lift3 = (oa, ob, oc, f) => oa.isSome() && ob.isSome() && oc.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Optional.none(); 1117 const someIf = (b, a) => b ? Optional.some(a) : Optional.none(); 1118 1119 const Global = typeof window !== 'undefined' ? window : Function('return this;')(); 1120 1121 const path = (parts, scope) => { 1122 let o = scope !== undefined && scope !== null ? scope : Global; 1123 for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) { 1124 o = o[parts[i]]; 1125 } 1126 return o; 1127 }; 1128 const resolve$2 = (p, scope) => { 1129 const parts = p.split('.'); 1130 return path(parts, scope); 1131 }; 1132 1133 const unsafe = (name, scope) => { 1134 return resolve$2(name, scope); 1135 }; 1136 const getOrDie = (name, scope) => { 1137 const actual = unsafe(name, scope); 1138 if (actual === undefined || actual === null) { 1139 throw new Error(name + ' not available on this browser'); 1140 } 1141 return actual; 1142 }; 1143 1144 const getPrototypeOf$1 = Object.getPrototypeOf; 1145 const sandHTMLElement = scope => { 1146 return getOrDie('HTMLElement', scope); 1147 }; 1148 const isPrototypeOf = x => { 1149 const scope = resolve$2('ownerDocument.defaultView', x); 1150 return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf$1(x).constructor.name)); 1151 }; 1152 1153 const COMMENT = 8; 1154 const DOCUMENT = 9; 1155 const DOCUMENT_FRAGMENT = 11; 1156 const ELEMENT = 1; 1157 const TEXT = 3; 1158 1159 const name = element => { 1160 const r = element.dom.nodeName; 1161 return r.toLowerCase(); 1162 }; 1163 const type$1 = element => element.dom.nodeType; 1164 const isType = t => element => type$1(element) === t; 1165 const isComment$1 = element => type$1(element) === COMMENT || name(element) === '#comment'; 1166 const isHTMLElement$1 = element => isElement$7(element) && isPrototypeOf(element.dom); 1167 const isElement$7 = isType(ELEMENT); 1168 const isText$c = isType(TEXT); 1169 const isDocument$2 = isType(DOCUMENT); 1170 const isDocumentFragment$1 = isType(DOCUMENT_FRAGMENT); 1171 const isTag = tag => e => isElement$7(e) && name(e) === tag; 1172 1173 const rawSet = (dom, key, value) => { 1174 if (isString(value) || isBoolean(value) || isNumber(value)) { 1175 dom.setAttribute(key, value + ''); 1176 } else { 1177 console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom); 1178 throw new Error('Attribute value was not simple'); 1179 } 1180 }; 1181 const set$4 = (element, key, value) => { 1182 rawSet(element.dom, key, value); 1183 }; 1184 const setAll$1 = (element, attrs) => { 1185 const dom = element.dom; 1186 each$d(attrs, (v, k) => { 1187 rawSet(dom, k, v); 1188 }); 1189 }; 1190 const get$9 = (element, key) => { 1191 const v = element.dom.getAttribute(key); 1192 return v === null ? undefined : v; 1193 }; 1194 const getOpt = (element, key) => Optional.from(get$9(element, key)); 1195 const has$1 = (element, key) => { 1196 const dom = element.dom; 1197 return dom && dom.hasAttribute ? dom.hasAttribute(key) : false; 1198 }; 1199 const remove$9 = (element, key) => { 1200 element.dom.removeAttribute(key); 1201 }; 1202 const hasNone = element => { 1203 const attrs = element.dom.attributes; 1204 return attrs === undefined || attrs === null || attrs.length === 0; 1205 }; 1206 const clone$4 = element => foldl(element.dom.attributes, (acc, attr) => { 1207 acc[attr.name] = attr.value; 1208 return acc; 1209 }, {}); 1210 1211 const read$4 = (element, attr) => { 1212 const value = get$9(element, attr); 1213 return value === undefined || value === '' ? [] : value.split(' '); 1214 }; 1215 const add$4 = (element, attr, id) => { 1216 const old = read$4(element, attr); 1217 const nu = old.concat([id]); 1218 set$4(element, attr, nu.join(' ')); 1219 return true; 1220 }; 1221 const remove$8 = (element, attr, id) => { 1222 const nu = filter$5(read$4(element, attr), v => v !== id); 1223 if (nu.length > 0) { 1224 set$4(element, attr, nu.join(' ')); 1225 } else { 1226 remove$9(element, attr); 1227 } 1228 return false; 1229 }; 1230 1231 const supports = element => element.dom.classList !== undefined; 1232 const get$8 = element => read$4(element, 'class'); 1233 const add$3 = (element, clazz) => add$4(element, 'class', clazz); 1234 const remove$7 = (element, clazz) => remove$8(element, 'class', clazz); 1235 const toggle$2 = (element, clazz) => { 1236 if (contains$2(get$8(element), clazz)) { 1237 return remove$7(element, clazz); 1238 } else { 1239 return add$3(element, clazz); 1240 } 1241 }; 1242 1243 const add$2 = (element, clazz) => { 1244 if (supports(element)) { 1245 element.dom.classList.add(clazz); 1246 } else { 1247 add$3(element, clazz); 1248 } 1249 }; 1250 const cleanClass = element => { 1251 const classList = supports(element) ? element.dom.classList : get$8(element); 1252 if (classList.length === 0) { 1253 remove$9(element, 'class'); 1254 } 1255 }; 1256 const remove$6 = (element, clazz) => { 1257 if (supports(element)) { 1258 const classList = element.dom.classList; 1259 classList.remove(clazz); 1260 } else { 1261 remove$7(element, clazz); 1262 } 1263 cleanClass(element); 1264 }; 1265 const toggle$1 = (element, clazz) => { 1266 const result = supports(element) ? element.dom.classList.toggle(clazz) : toggle$2(element, clazz); 1267 cleanClass(element); 1268 return result; 1269 }; 1270 const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz); 1271 1272 const fromHtml$1 = (html, scope) => { 1273 const doc = scope || document; 1274 const div = doc.createElement('div'); 1275 div.innerHTML = html; 1276 if (!div.hasChildNodes() || div.childNodes.length > 1) { 1277 const message = 'HTML does not have a single root node'; 1278 console.error(message, html); 1279 throw new Error(message); 1280 } 1281 return fromDom$2(div.childNodes[0]); 1282 }; 1283 const fromTag = (tag, scope) => { 1284 const doc = scope || document; 1285 const node = doc.createElement(tag); 1286 return fromDom$2(node); 1287 }; 1288 const fromText = (text, scope) => { 1289 const doc = scope || document; 1290 const node = doc.createTextNode(text); 1291 return fromDom$2(node); 1292 }; 1293 const fromDom$2 = node => { 1294 if (node === null || node === undefined) { 1295 throw new Error('Node cannot be null or undefined'); 1296 } 1297 return { dom: node }; 1298 }; 1299 const fromPoint$2 = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$2); 1300 const SugarElement = { 1301 fromHtml: fromHtml$1, 1302 fromTag, 1303 fromText, 1304 fromDom: fromDom$2, 1305 fromPoint: fromPoint$2 1306 }; 1307 1308 const toArray = (target, f) => { 1309 const r = []; 1310 const recurse = e => { 1311 r.push(e); 1312 return f(e); 1313 }; 1314 let cur = f(target); 1315 do { 1316 cur = cur.bind(recurse); 1317 } while (cur.isSome()); 1318 return r; 1319 }; 1320 1321 const is$1 = (element, selector) => { 1322 const dom = element.dom; 1323 if (dom.nodeType !== ELEMENT) { 1324 return false; 1325 } else { 1326 const elem = dom; 1327 if (elem.matches !== undefined) { 1328 return elem.matches(selector); 1329 } else if (elem.msMatchesSelector !== undefined) { 1330 return elem.msMatchesSelector(selector); 1331 } else if (elem.webkitMatchesSelector !== undefined) { 1332 return elem.webkitMatchesSelector(selector); 1333 } else if (elem.mozMatchesSelector !== undefined) { 1334 return elem.mozMatchesSelector(selector); 1335 } else { 1336 throw new Error('Browser lacks native selectors'); 1337 } 1338 } 1339 }; 1340 const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0; 1341 const all = (selector, scope) => { 1342 const base = scope === undefined ? document : scope.dom; 1343 return bypassSelector(base) ? [] : map$3(base.querySelectorAll(selector), SugarElement.fromDom); 1344 }; 1345 const one = (selector, scope) => { 1346 const base = scope === undefined ? document : scope.dom; 1347 return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom); 1348 }; 1349 1350 const eq = (e1, e2) => e1.dom === e2.dom; 1351 const contains = (e1, e2) => { 1352 const d1 = e1.dom; 1353 const d2 = e2.dom; 1354 return d1 === d2 ? false : d1.contains(d2); 1355 }; 1356 1357 const owner$1 = element => SugarElement.fromDom(element.dom.ownerDocument); 1358 const documentOrOwner = dos => isDocument$2(dos) ? dos : owner$1(dos); 1359 const documentElement = element => SugarElement.fromDom(documentOrOwner(element).dom.documentElement); 1360 const defaultView = element => SugarElement.fromDom(documentOrOwner(element).dom.defaultView); 1361 const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom); 1362 const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom); 1363 const parents$1 = (element, isRoot) => { 1364 const stop = isFunction(isRoot) ? isRoot : never; 1365 let dom = element.dom; 1366 const ret = []; 1367 while (dom.parentNode !== null && dom.parentNode !== undefined) { 1368 const rawParent = dom.parentNode; 1369 const p = SugarElement.fromDom(rawParent); 1370 ret.push(p); 1371 if (stop(p) === true) { 1372 break; 1373 } else { 1374 dom = rawParent; 1375 } 1376 } 1377 return ret; 1378 }; 1379 const siblings = element => { 1380 const filterSelf = elements => filter$5(elements, x => !eq(element, x)); 1381 return parent(element).map(children$1).map(filterSelf).getOr([]); 1382 }; 1383 const prevSibling = element => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom); 1384 const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom); 1385 const prevSiblings = element => reverse(toArray(element, prevSibling)); 1386 const nextSiblings = element => toArray(element, nextSibling); 1387 const children$1 = element => map$3(element.dom.childNodes, SugarElement.fromDom); 1388 const child$1 = (element, index) => { 1389 const cs = element.dom.childNodes; 1390 return Optional.from(cs[index]).map(SugarElement.fromDom); 1391 }; 1392 const firstChild = element => child$1(element, 0); 1393 const lastChild = element => child$1(element, element.dom.childNodes.length - 1); 1394 const childNodesCount = element => element.dom.childNodes.length; 1395 1396 const getHead = doc => { 1397 const b = doc.dom.head; 1398 if (b === null || b === undefined) { 1399 throw new Error('Head is not available yet'); 1400 } 1401 return SugarElement.fromDom(b); 1402 }; 1403 1404 const isShadowRoot = dos => isDocumentFragment$1(dos) && isNonNullable(dos.dom.host); 1405 const getRootNode = e => SugarElement.fromDom(e.dom.getRootNode()); 1406 const getStyleContainer = dos => isShadowRoot(dos) ? dos : getHead(documentOrOwner(dos)); 1407 const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body); 1408 const getShadowRoot = e => { 1409 const r = getRootNode(e); 1410 return isShadowRoot(r) ? Optional.some(r) : Optional.none(); 1411 }; 1412 const getShadowHost = e => SugarElement.fromDom(e.dom.host); 1413 const getOriginalEventTarget = event => { 1414 if (isNonNullable(event.target)) { 1415 const el = SugarElement.fromDom(event.target); 1416 if (isElement$7(el) && isOpenShadowHost(el)) { 1417 if (event.composed && event.composedPath) { 1418 const composedPath = event.composedPath(); 1419 if (composedPath) { 1420 return head(composedPath); 1421 } 1422 } 1423 } 1424 } 1425 return Optional.from(event.target); 1426 }; 1427 const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot); 1428 1429 const inBody = element => { 1430 const dom = isText$c(element) ? element.dom.parentNode : element.dom; 1431 if (dom === undefined || dom === null || dom.ownerDocument === null) { 1432 return false; 1433 } 1434 const doc = dom.ownerDocument; 1435 return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost)); 1436 }; 1437 1438 var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => { 1439 if (is(scope, a)) { 1440 return Optional.some(scope); 1441 } else if (isFunction(isRoot) && isRoot(scope)) { 1442 return Optional.none(); 1443 } else { 1444 return ancestor(scope, a, isRoot); 1445 } 1446 }; 1447 1448 const ancestor$4 = (scope, predicate, isRoot) => { 1449 let element = scope.dom; 1450 const stop = isFunction(isRoot) ? isRoot : never; 1451 while (element.parentNode) { 1452 element = element.parentNode; 1453 const el = SugarElement.fromDom(element); 1454 if (predicate(el)) { 1455 return Optional.some(el); 1456 } else if (stop(el)) { 1457 break; 1458 } 1459 } 1460 return Optional.none(); 1461 }; 1462 const closest$4 = (scope, predicate, isRoot) => { 1463 const is = (s, test) => test(s); 1464 return ClosestOrAncestor(is, ancestor$4, scope, predicate, isRoot); 1465 }; 1466 const sibling$1 = (scope, predicate) => { 1467 const element = scope.dom; 1468 if (!element.parentNode) { 1469 return Optional.none(); 1470 } 1471 return child(SugarElement.fromDom(element.parentNode), x => !eq(scope, x) && predicate(x)); 1472 }; 1473 const child = (scope, predicate) => { 1474 const pred = node => predicate(SugarElement.fromDom(node)); 1475 const result = find$2(scope.dom.childNodes, pred); 1476 return result.map(SugarElement.fromDom); 1477 }; 1478 const descendant$2 = (scope, predicate) => { 1479 const descend = node => { 1480 for (let i = 0; i < node.childNodes.length; i++) { 1481 const child = SugarElement.fromDom(node.childNodes[i]); 1482 if (predicate(child)) { 1483 return Optional.some(child); 1484 } 1485 const res = descend(node.childNodes[i]); 1486 if (res.isSome()) { 1487 return res; 1488 } 1489 } 1490 return Optional.none(); 1491 }; 1492 return descend(scope.dom); 1493 }; 1494 1495 const ancestor$3 = (scope, selector, isRoot) => ancestor$4(scope, e => is$1(e, selector), isRoot); 1496 const descendant$1 = (scope, selector) => one(selector, scope); 1497 const closest$3 = (scope, selector, isRoot) => { 1498 const is = (element, selector) => is$1(element, selector); 1499 return ClosestOrAncestor(is, ancestor$3, scope, selector, isRoot); 1500 }; 1501 1502 const closest$2 = target => closest$3(target, '[contenteditable]'); 1503 const isEditable$2 = (element, assumeEditable = false) => { 1504 if (inBody(element)) { 1505 return element.dom.isContentEditable; 1506 } else { 1507 return closest$2(element).fold(constant(assumeEditable), editable => getRaw$1(editable) === 'true'); 1508 } 1509 }; 1510 const getRaw$1 = element => element.dom.contentEditable; 1511 const set$3 = (element, editable) => { 1512 element.dom.contentEditable = editable ? 'true' : 'false'; 1513 }
vendor: 16,462 bytes, lines 1513-2002
1513; 1514 1515 const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue); 1516 1517 const internalSet = (dom, property, value) => { 1518 if (!isString(value)) { 1519 console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom); 1520 throw new Error('CSS value must be a string: ' + value); 1521 } 1522 if (isSupported(dom)) { 1523 dom.style.setProperty(property, value); 1524 } 1525 }; 1526 const internalRemove = (dom, property) => { 1527 if (isSupported(dom)) { 1528 dom.style.removeProperty(property); 1529 } 1530 }; 1531 const set$2 = (element, property, value) => { 1532 const dom = element.dom; 1533 internalSet(dom, property, value); 1534 }; 1535 const setAll = (element, css) => { 1536 const dom = element.dom; 1537 each$d(css, (v, k) => { 1538 internalSet(dom, k, v); 1539 }); 1540 }; 1541 const get$7 = (element, property) => { 1542 const dom = element.dom; 1543 const styles = window.getComputedStyle(dom); 1544 const r = styles.getPropertyValue(property); 1545 return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r; 1546 }; 1547 const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : ''; 1548 const getRaw = (element, property) => { 1549 const dom = element.dom; 1550 const raw = getUnsafeProperty(dom, property); 1551 return Optional.from(raw).filter(r => r.length > 0); 1552 }; 1553 const getAllRaw = element => { 1554 const css = {}; 1555 const dom = element.dom; 1556 if (isSupported(dom)) { 1557 for (let i = 0; i < dom.style.length; i++) { 1558 const ruleName = dom.style.item(i); 1559 css[ruleName] = dom.style[ruleName]; 1560 } 1561 } 1562 return css; 1563 }; 1564 const remove$5 = (element, property) => { 1565 const dom = element.dom; 1566 internalRemove(dom, property); 1567 if (is$2(getOpt(element, 'style').map(trim$4), '')) { 1568 remove$9(element, 'style'); 1569 } 1570 }; 1571 const reflow = e => e.dom.offsetWidth; 1572 1573 const before$3 = (marker, element) => { 1574 const parent$1 = parent(marker); 1575 parent$1.each(v => { 1576 v.dom.insertBefore(element.dom, marker.dom); 1577 }); 1578 }; 1579 const after$4 = (marker, element) => { 1580 const sibling = nextSibling(marker); 1581 sibling.fold(() => { 1582 const parent$1 = parent(marker); 1583 parent$1.each(v => { 1584 append$1(v, element); 1585 }); 1586 }, v => { 1587 before$3(v, element); 1588 }); 1589 }; 1590 const prepend = (parent, element) => { 1591 const firstChild$1 = firstChild(parent); 1592 firstChild$1.fold(() => { 1593 append$1(parent, element); 1594 }, v => { 1595 parent.dom.insertBefore(element.dom, v.dom); 1596 }); 1597 }; 1598 const append$1 = (parent, element) => { 1599 parent.dom.appendChild(element.dom); 1600 }; 1601 const wrap$2 = (element, wrapper) => { 1602 before$3(element, wrapper); 1603 append$1(wrapper, element); 1604 }; 1605 1606 const after$3 = (marker, elements) => { 1607 each$e(elements, (x, i) => { 1608 const e = i === 0 ? marker : elements[i - 1]; 1609 after$4(e, x); 1610 }); 1611 }; 1612 const append = (parent, elements) => { 1613 each$e(elements, x => { 1614 append$1(parent, x); 1615 }); 1616 }; 1617 1618 const empty = element => { 1619 element.dom.textContent = ''; 1620 each$e(children$1(element), rogue => { 1621 remove$4(rogue); 1622 }); 1623 }; 1624 const remove$4 = element => { 1625 const dom = element.dom; 1626 if (dom.parentNode !== null) { 1627 dom.parentNode.removeChild(dom); 1628 } 1629 }; 1630 const unwrap = wrapper => { 1631 const children = children$1(wrapper); 1632 if (children.length > 0) { 1633 after$3(wrapper, children); 1634 } 1635 remove$4(wrapper); 1636 }; 1637 1638 const fromHtml = (html, scope) => { 1639 const doc = scope || document; 1640 const div = doc.createElement('div'); 1641 div.innerHTML = html; 1642 return children$1(SugarElement.fromDom(div)); 1643 }; 1644 const fromDom$1 = nodes => map$3(nodes, SugarElement.fromDom); 1645 1646 const get$6 = element => element.dom.innerHTML; 1647 const set$1 = (element, content) => { 1648 const owner = owner$1(element); 1649 const docDom = owner.dom; 1650 const fragment = SugarElement.fromDom(docDom.createDocumentFragment()); 1651 const contentElements = fromHtml(content, docDom); 1652 append(fragment, contentElements); 1653 empty(element); 1654 append$1(element, fragment); 1655 }; 1656 const getOuter = element => { 1657 const container = SugarElement.fromTag('div'); 1658 const clone = SugarElement.fromDom(element.dom.cloneNode(true)); 1659 append$1(container, clone); 1660 return get$6(container); 1661 }; 1662 1663 const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({ 1664 target, 1665 x, 1666 y, 1667 stop, 1668 prevent, 1669 kill, 1670 raw 1671 }); 1672 const fromRawEvent = rawEvent => { 1673 const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target)); 1674 const stop = () => rawEvent.stopPropagation(); 1675 const prevent = () => rawEvent.preventDefault(); 1676 const kill = compose(prevent, stop); 1677 return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent); 1678 }; 1679 const handle$1 = (filter, handler) => rawEvent => { 1680 if (filter(rawEvent)) { 1681 handler(fromRawEvent(rawEvent)); 1682 } 1683 }; 1684 const binder = (element, event, filter, handler, useCapture) => { 1685 const wrapped = handle$1(filter, handler); 1686 element.dom.addEventListener(event, wrapped, useCapture); 1687 return { unbind: curry(unbind, element, event, wrapped, useCapture) }; 1688 }; 1689 const bind$2 = (element, event, filter, handler) => binder(element, event, filter, handler, false); 1690 const unbind = (element, event, handler, useCapture) => { 1691 element.dom.removeEventListener(event, handler, useCapture); 1692 }; 1693 1694 const r = (left, top) => { 1695 const translate = (x, y) => r(left + x, top + y); 1696 return { 1697 left, 1698 top, 1699 translate 1700 }; 1701 }; 1702 const SugarPosition = r; 1703 1704 const boxPosition = dom => { 1705 const box = dom.getBoundingClientRect(); 1706 return SugarPosition(box.left, box.top); 1707 }; 1708 const firstDefinedOrZero = (a, b) => { 1709 if (a !== undefined) { 1710 return a; 1711 } else { 1712 return b !== undefined ? b : 0; 1713 } 1714 }; 1715 const absolute = element => { 1716 const doc = element.dom.ownerDocument; 1717 const body = doc.body; 1718 const win = doc.defaultView; 1719 const html = doc.documentElement; 1720 if (body === element.dom) { 1721 return SugarPosition(body.offsetLeft, body.offsetTop); 1722 } 1723 const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html.scrollTop); 1724 const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html.scrollLeft); 1725 const clientTop = firstDefinedOrZero(html.clientTop, body.clientTop); 1726 const clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft); 1727 return viewport(element).translate(scrollLeft - clientLeft, scrollTop - clientTop); 1728 }; 1729 const viewport = element => { 1730 const dom = element.dom; 1731 const doc = dom.ownerDocument; 1732 const body = doc.body; 1733 if (body === dom) { 1734 return SugarPosition(body.offsetLeft, body.offsetTop); 1735 } 1736 if (!inBody(element)) { 1737 return SugarPosition(0, 0); 1738 } 1739 return boxPosition(dom); 1740 }; 1741 1742 const get$5 = _DOC => { 1743 const doc = _DOC !== undefined ? _DOC.dom : document; 1744 const x = doc.body.scrollLeft || doc.documentElement.scrollLeft; 1745 const y = doc.body.scrollTop || doc.documentElement.scrollTop; 1746 return SugarPosition(x, y); 1747 }; 1748 const to = (x, y, _DOC) => { 1749 const doc = _DOC !== undefined ? _DOC.dom : document; 1750 const win = doc.defaultView; 1751 if (win) { 1752 win.scrollTo(x, y); 1753 } 1754 }; 1755 const intoView = (element, alignToTop) => { 1756 const isSafari = detect$1().browser.isSafari(); 1757 if (isSafari && isFunction(element.dom.scrollIntoViewIfNeeded)) { 1758 element.dom.scrollIntoViewIfNeeded(false); 1759 } else { 1760 element.dom.scrollIntoView(alignToTop); 1761 } 1762 }; 1763 1764 const get$4 = _win => { 1765 const win = _win === undefined ? window : _win; 1766 if (detect$1().browser.isFirefox()) { 1767 return Optional.none(); 1768 } else { 1769 return Optional.from(win.visualViewport); 1770 } 1771 }; 1772 const bounds = (x, y, width, height) => ({ 1773 x, 1774 y, 1775 width, 1776 height, 1777 right: x + width, 1778 bottom: y + height 1779 }); 1780 const getBounds = _win => { 1781 const win = _win === undefined ? window : _win; 1782 const doc = win.document; 1783 const scroll = get$5(SugarElement.fromDom(doc)); 1784 return get$4(win).fold(() => { 1785 const html = win.document.documentElement; 1786 const width = html.clientWidth; 1787 const height = html.clientHeight; 1788 return bounds(scroll.left, scroll.top, width, height); 1789 }, visualViewport => bounds(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height)); 1790 }; 1791 1792 const children = (scope, predicate) => filter$5(children$1(scope), predicate); 1793 const descendants$1 = (scope, predicate) => { 1794 let result = []; 1795 each$e(children$1(scope), x => { 1796 if (predicate(x)) { 1797 result = result.concat([x]); 1798 } 1799 result = result.concat(descendants$1(x, predicate)); 1800 }); 1801 return result; 1802 }; 1803 1804 const descendants = (scope, selector) => all(selector, scope); 1805 1806 const ancestor$2 = (scope, predicate, isRoot) => ancestor$4(scope, predicate, isRoot).isSome(); 1807 const sibling = (scope, predicate) => sibling$1(scope, predicate).isSome(); 1808 const descendant = (scope, predicate) => descendant$2(scope, predicate).isSome(); 1809 1810 class DomTreeWalker { 1811 constructor(startNode, rootNode) { 1812 this.node = startNode; 1813 this.rootNode = rootNode; 1814 this.current = this.current.bind(this); 1815 this.next = this.next.bind(this); 1816 this.prev = this.prev.bind(this); 1817 this.prev2 = this.prev2.bind(this); 1818 } 1819 current() { 1820 return this.node; 1821 } 1822 next(shallow) { 1823 this.node = this.findSibling(this.node, 'firstChild', 'nextSibling', shallow); 1824 return this.node; 1825 } 1826 prev(shallow) { 1827 this.node = this.findSibling(this.node, 'lastChild', 'previousSibling', shallow); 1828 return this.node; 1829 } 1830 prev2(shallow) { 1831 this.node = this.findPreviousNode(this.node, shallow); 1832 return this.node; 1833 } 1834 findSibling(node, startName, siblingName, shallow) { 1835 if (node) { 1836 if (!shallow && node[startName]) { 1837 return node[startName]; 1838 } 1839 if (node !== this.rootNode) { 1840 let sibling = node[siblingName]; 1841 if (sibling) { 1842 return sibling; 1843 } 1844 for (let parent = node.parentNode; parent && parent !== this.rootNode; parent = parent.parentNode) { 1845 sibling = parent[siblingName]; 1846 if (sibling) { 1847 return sibling; 1848 } 1849 } 1850 } 1851 } 1852 return undefined; 1853 } 1854 findPreviousNode(node, shallow) { 1855 if (node) { 1856 const sibling = node.previousSibling; 1857 if (this.rootNode && sibling === this.rootNode) { 1858 return; 1859 } 1860 if (sibling) { 1861 if (!shallow) { 1862 for (let child = sibling.lastChild; child; child = child.lastChild) { 1863 if (!child.lastChild) { 1864 return child; 1865 } 1866 } 1867 } 1868 return sibling; 1869 } 1870 const parent = node.parentNode; 1871 if (parent && parent !== this.rootNode) { 1872 return parent; 1873 } 1874 } 1875 return undefined; 1876 } 1877 } 1878 1879 const zeroWidth = '\uFEFF'; 1880 const nbsp = '\xA0'; 1881 const isZwsp$2 = char => char === zeroWidth; 1882 const removeZwsp = s => s.replace(/\uFEFF/g, ''); 1883 1884 const whiteSpaceRegExp = /^[ \t\r\n]*$/; 1885 const isWhitespaceText = text => whiteSpaceRegExp.test(text); 1886 const isZwsp$1 = text => { 1887 for (const c of text) { 1888 if (!isZwsp$2(c)) { 1889 return false; 1890 } 1891 } 1892 return true; 1893 }; 1894 const isCollapsibleWhitespace$1 = c => ' \f\t\x0B'.indexOf(c) !== -1; 1895 const isNewLineChar = c => c === '\n' || c === '\r'; 1896 const isNewline = (text, idx) => idx < text.length && idx >= 0 ? isNewLineChar(text[idx]) : false; 1897 const normalize$4 = (text, tabSpaces = 4, isStartOfContent = true, isEndOfContent = true) => { 1898 const tabSpace = repeat(' ', tabSpaces); 1899 const normalizedText = text.replace(/\t/g, tabSpace); 1900 const result = foldl(normalizedText, (acc, c) => { 1901 if (isCollapsibleWhitespace$1(c) || c === nbsp) { 1902 if (acc.pcIsSpace || acc.str === '' && isStartOfContent || acc.str.length === normalizedText.length - 1 && isEndOfContent || isNewline(normalizedText, acc.str.length + 1)) { 1903 return { 1904 pcIsSpace: false, 1905 str: acc.str + nbsp 1906 }; 1907 } else { 1908 return { 1909 pcIsSpace: true, 1910 str: acc.str + ' ' 1911 }; 1912 } 1913 } else { 1914 return { 1915 pcIsSpace: isNewLineChar(c), 1916 str: acc.str + c 1917 }; 1918 } 1919 }, { 1920 pcIsSpace: false, 1921 str: '' 1922 }); 1923 return result.str; 1924 }; 1925 1926 const isNodeType = type => { 1927 return node => { 1928 return !!node && node.nodeType === type; 1929 }; 1930 }; 1931 const isRestrictedNode = node => !!node && !Object.getPrototypeOf(node); 1932 const isElement$6 = isNodeType(1); 1933 const isHTMLElement = node => isElement$6(node) && isHTMLElement$1(SugarElement.fromDom(node)); 1934 const isSVGElement = node => isElement$6(node) && node.namespaceURI === 'http://www.w3.org/2000/svg'; 1935 const matchNodeName = name => { 1936 const lowerCasedName = name.toLowerCase(); 1937 return node => isNonNullable(node) && node.nodeName.toLowerCase() === lowerCasedName; 1938 }; 1939 const matchNodeNames = names => { 1940 const lowerCasedNames = names.map(s => s.toLowerCase()); 1941 return node => { 1942 if (node && node.nodeName) { 1943 const nodeName = node.nodeName.toLowerCase(); 1944 return contains$2(lowerCasedNames, nodeName); 1945 } 1946 return false; 1947 }; 1948 }; 1949 const matchStyleValues = (name, values) => { 1950 const items = values.toLowerCase().split(' '); 1951 return node => { 1952 if (isElement$6(node)) { 1953 const win = node.ownerDocument.defaultView; 1954 if (win) { 1955 for (let i = 0; i < items.length; i++) { 1956 const computed = win.getComputedStyle(node, null); 1957 const cssValue = computed ? computed.getPropertyValue(name) : null; 1958 if (cssValue === items[i]) { 1959 return true; 1960 } 1961 } 1962 } 1963 } 1964 return false; 1965 }; 1966 }; 1967 const hasAttribute = attrName => { 1968 return node => { 1969 return isElement$6(node) && node.hasAttribute(attrName); 1970 }; 1971 }; 1972 const isBogus$1 = node => isElement$6(node) && node.hasAttribute('data-mce-bogus'); 1973 const isBogusAll = node => isElement$6(node) && node.getAttribute('data-mce-bogus') === 'all'; 1974 const isTable$2 = node => isElement$6(node) && node.tagName === 'TABLE'; 1975 const hasContentEditableState = value => { 1976 return node => { 1977 if (isHTMLElement(node)) { 1978 if (node.contentEditable === value) { 1979 return true; 1980 } 1981 if (node.getAttribute('data-mce-contenteditable') === value) { 1982 return true; 1983 } 1984 } 1985 return false; 1986 }; 1987 }; 1988 const isTextareaOrInput = matchNodeNames([ 1989 'textarea', 1990 'input' 1991 ]); 1992 const isText$b = isNodeType(3); 1993 const isCData = isNodeType(4); 1994 const isPi = isNodeType(7); 1995 const isComment = isNodeType(8); 1996 const isDocument$1 = isNodeType(9); 1997 const isDocumentFragment = isNodeType(11); 1998 const isBr$6 = matchNodeName('br'); 1999 const isImg = matchNodeName('img'); 2000 const isContentEditableTrue$3 = hasContentEditableState('true'); 2001 const isContentEditableFalse$b = hasContentEditableState('false'); 2002 const is
vendor: 17,129 bytes, lines 2002-2453
2002EditingHost = node => isHTMLElement(node) && node.isContentEditable && isNonNullable(node.parentElement) && !node.parentElement.isContentEditable; 2003 const isTableCell$3 = matchNodeNames([ 2004 'td', 2005 'th' 2006 ]); 2007 const isTableCellOrCaption = matchNodeNames([ 2008 'td', 2009 'th', 2010 'caption' 2011 ]); 2012 const isMedia$2 = matchNodeNames([ 2013 'video', 2014 'audio', 2015 'object', 2016 'embed' 2017 ]); 2018 const isListItem$2 = matchNodeName('li'); 2019 const isDetails = matchNodeName('details'); 2020 const isSummary$1 = matchNodeName('summary'); 2021 2022 const defaultOptionValues = { 2023 skipBogus: true, 2024 includeZwsp: false, 2025 checkRootAsContent: false 2026 }; 2027 const hasWhitespacePreserveParent = (node, rootNode, schema) => { 2028 const rootElement = SugarElement.fromDom(rootNode); 2029 const startNode = SugarElement.fromDom(node); 2030 const whitespaceElements = schema.getWhitespaceElements(); 2031 const predicate = node => has$2(whitespaceElements, name(node)); 2032 return ancestor$2(startNode, predicate, curry(eq, rootElement)); 2033 }; 2034 const isNamedAnchor = node => { 2035 return isElement$6(node) && node.nodeName === 'A' && !node.hasAttribute('href') && (node.hasAttribute('name') || node.hasAttribute('id')); 2036 }; 2037 const isNonEmptyElement$1 = (node, schema) => { 2038 return isElement$6(node) && has$2(schema.getNonEmptyElements(), node.nodeName); 2039 }; 2040 const isBookmark = hasAttribute('data-mce-bookmark'); 2041 const hasNonEditableParent = node => parentElement(SugarElement.fromDom(node)).exists(parent => !isEditable$2(parent)); 2042 const isWhitespace$1 = (node, rootNode, schema) => isWhitespaceText(node.data) && !hasWhitespacePreserveParent(node, rootNode, schema); 2043 const isText$a = (node, rootNode, schema, options) => isText$b(node) && !isWhitespace$1(node, rootNode, schema) && (!options.includeZwsp || !isZwsp$1(node.data)); 2044 const isContentNode = (schema, node, rootNode, options) => { 2045 return isFunction(options.isContent) && options.isContent(node) || isNonEmptyElement$1(node, schema) || isBookmark(node) || isNamedAnchor(node) || isText$a(node, rootNode, schema, options) || isContentEditableFalse$b(node) || isContentEditableTrue$3(node) && hasNonEditableParent(node); 2046 }; 2047 const isEmptyNode = (schema, targetNode, opts) => { 2048 const options = { 2049 ...defaultOptionValues, 2050 ...opts 2051 }; 2052 if (options.checkRootAsContent) { 2053 if (isContentNode(schema, targetNode, targetNode, options)) { 2054 return false; 2055 } 2056 } 2057 let node = targetNode.firstChild; 2058 let brCount = 0; 2059 if (!node) { 2060 return true; 2061 } 2062 const walker = new DomTreeWalker(node, targetNode); 2063 do { 2064 if (options.skipBogus && isElement$6(node)) { 2065 const bogusValue = node.getAttribute('data-mce-bogus'); 2066 if (bogusValue) { 2067 node = walker.next(bogusValue === 'all'); 2068 continue; 2069 } 2070 } 2071 if (isComment(node)) { 2072 node = walker.next(true); 2073 continue; 2074 } 2075 if (isBr$6(node)) { 2076 brCount++; 2077 node = walker.next(); 2078 continue; 2079 } 2080 if (isContentNode(schema, node, targetNode, options)) { 2081 return false; 2082 } 2083 node = walker.next(); 2084 } while (node); 2085 return brCount <= 1; 2086 }; 2087 const isEmpty$2 = (schema, elm, options) => { 2088 return isEmptyNode(schema, elm.dom, { 2089 checkRootAsContent: true, 2090 ...options 2091 }); 2092 }; 2093 const isContent$1 = (schema, node, options) => { 2094 return isContentNode(schema, node, node, { 2095 includeZwsp: defaultOptionValues.includeZwsp, 2096 ...options 2097 }); 2098 }; 2099 2100 const Cell = initial => { 2101 let value = initial; 2102 const get = () => { 2103 return value; 2104 }; 2105 const set = v => { 2106 value = v; 2107 }; 2108 return { 2109 get, 2110 set 2111 }; 2112 }; 2113 2114 const singleton = doRevoke => { 2115 const subject = Cell(Optional.none()); 2116 const revoke = () => subject.get().each(doRevoke); 2117 const clear = () => { 2118 revoke(); 2119 subject.set(Optional.none()); 2120 }; 2121 const isSet = () => subject.get().isSome(); 2122 const get = () => subject.get(); 2123 const set = s => { 2124 revoke(); 2125 subject.set(Optional.some(s)); 2126 }; 2127 return { 2128 clear, 2129 isSet, 2130 get, 2131 set 2132 }; 2133 }; 2134 const repeatable = delay => { 2135 const intervalId = Cell(Optional.none()); 2136 const revoke = () => intervalId.get().each(id => clearInterval(id)); 2137 const clear = () => { 2138 revoke(); 2139 intervalId.set(Optional.none()); 2140 }; 2141 const isSet = () => intervalId.get().isSome(); 2142 const get = () => intervalId.get(); 2143 const set = functionToRepeat => { 2144 revoke(); 2145 intervalId.set(Optional.some(setInterval(functionToRepeat, delay))); 2146 }; 2147 return { 2148 clear, 2149 isSet, 2150 get, 2151 set 2152 }; 2153 }; 2154 const value$2 = () => { 2155 const subject = singleton(noop); 2156 const on = f => subject.get().each(f); 2157 return { 2158 ...subject, 2159 on 2160 }; 2161 }; 2162 2163 const nodeNameToNamespaceType = name => { 2164 const lowerCaseName = name.toLowerCase(); 2165 if (lowerCaseName === 'svg') { 2166 return 'svg'; 2167 } else if (lowerCaseName === 'math') { 2168 return 'math'; 2169 } else { 2170 return 'html'; 2171 } 2172 }; 2173 const isNonHtmlElementRootName = name => nodeNameToNamespaceType(name) !== 'html'; 2174 const isNonHtmlElementRoot = node => isNonHtmlElementRootName(node.nodeName); 2175 const toScopeType = node => nodeNameToNamespaceType(node.nodeName); 2176 const namespaceElements = [ 2177 'svg', 2178 'math' 2179 ]; 2180 const createNamespaceTracker = () => { 2181 const currentScope = value$2(); 2182 const current = () => currentScope.get().map(toScopeType).getOr('html'); 2183 const track = node => { 2184 if (isNonHtmlElementRoot(node)) { 2185 currentScope.set(node); 2186 } else if (currentScope.get().exists(scopeNode => !scopeNode.contains(node))) { 2187 currentScope.clear(); 2188 } 2189 return current(); 2190 }; 2191 const reset = () => { 2192 currentScope.clear(); 2193 }; 2194 return { 2195 track, 2196 current, 2197 reset 2198 }; 2199 }; 2200 2201 const transparentBlockAttr = 'data-mce-block'; 2202 const elementNames = map => filter$5(keys(map), key => !/[A-Z]/.test(key)); 2203 const makeSelectorFromSchemaMap = map => map$3(elementNames(map), name => { 2204 const escapedName = CSS.escape(name); 2205 return `${ escapedName }:` + map$3(namespaceElements, ns => `not(${ ns } ${ escapedName })`).join(':'); 2206 }).join(','); 2207 const updateTransparent = (blocksSelector, transparent) => { 2208 if (isNonNullable(transparent.querySelector(blocksSelector))) { 2209 transparent.setAttribute(transparentBlockAttr, 'true'); 2210 if (transparent.getAttribute('data-mce-selected') === 'inline-boundary') { 2211 transparent.removeAttribute('data-mce-selected'); 2212 } 2213 return true; 2214 } else { 2215 transparent.removeAttribute(transparentBlockAttr); 2216 return false; 2217 } 2218 }; 2219 const updateBlockStateOnChildren = (schema, scope) => { 2220 const transparentSelector = makeSelectorFromSchemaMap(schema.getTransparentElements()); 2221 const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements()); 2222 return filter$5(scope.querySelectorAll(transparentSelector), transparent => updateTransparent(blocksSelector, transparent)); 2223 }; 2224 const trimEdge = (schema, el, leftSide) => { 2225 var _a; 2226 const childPropertyName = leftSide ? 'lastChild' : 'firstChild'; 2227 for (let child = el[childPropertyName]; child; child = child[childPropertyName]) { 2228 if (isEmptyNode(schema, child, { checkRootAsContent: true })) { 2229 (_a = child.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(child); 2230 return; 2231 } 2232 } 2233 }; 2234 const split$2 = (schema, parentElm, splitElm) => { 2235 const range = document.createRange(); 2236 const parentNode = parentElm.parentNode; 2237 if (parentNode) { 2238 range.setStartBefore(parentElm); 2239 range.setEndBefore(splitElm); 2240 const beforeFragment = range.extractContents(); 2241 trimEdge(schema, beforeFragment, true); 2242 range.setStartAfter(splitElm); 2243 range.setEndAfter(parentElm); 2244 const afterFragment = range.extractContents(); 2245 trimEdge(schema, afterFragment, false); 2246 if (!isEmptyNode(schema, beforeFragment, { checkRootAsContent: true })) { 2247 parentNode.insertBefore(beforeFragment, parentElm); 2248 } 2249 if (!isEmptyNode(schema, splitElm, { checkRootAsContent: true })) { 2250 parentNode.insertBefore(splitElm, parentElm); 2251 } 2252 if (!isEmptyNode(schema, afterFragment, { checkRootAsContent: true })) { 2253 parentNode.insertBefore(afterFragment, parentElm); 2254 } 2255 parentNode.removeChild(parentElm); 2256 } 2257 }; 2258 const splitInvalidChildren = (schema, scope, transparentBlocks) => { 2259 const blocksElements = schema.getBlockElements(); 2260 const rootNode = SugarElement.fromDom(scope); 2261 const isBlock = el => name(el) in blocksElements; 2262 const isRoot = el => eq(el, rootNode); 2263 each$e(fromDom$1(transparentBlocks), transparentBlock => { 2264 ancestor$4(transparentBlock, isBlock, isRoot).each(parentBlock => { 2265 const invalidChildren = children(transparentBlock, el => isBlock(el) && !schema.isValidChild(name(parentBlock), name(el))); 2266 if (invalidChildren.length > 0) { 2267 const stateScope = parentElement(parentBlock); 2268 each$e(invalidChildren, child => { 2269 ancestor$4(child, isBlock, isRoot).each(parentBlock => { 2270 split$2(schema, parentBlock.dom, child.dom); 2271 }); 2272 }); 2273 stateScope.each(scope => updateBlockStateOnChildren(schema, scope.dom)); 2274 } 2275 }); 2276 }); 2277 }; 2278 const unwrapInvalidChildren = (schema, scope, transparentBlocks) => { 2279 each$e([ 2280 ...transparentBlocks, 2281 ...isTransparentBlock(schema, scope) ? [scope] : [] 2282 ], block => each$e(descendants(SugarElement.fromDom(block), block.nodeName.toLowerCase()), elm => { 2283 if (isTransparentInline(schema, elm.dom)) { 2284 unwrap(elm); 2285 } 2286 })); 2287 }; 2288 const updateChildren = (schema, scope) => { 2289 const transparentBlocks = updateBlockStateOnChildren(schema, scope); 2290 splitInvalidChildren(schema, scope, transparentBlocks); 2291 unwrapInvalidChildren(schema, scope, transparentBlocks); 2292 }; 2293 const updateElement = (schema, target) => { 2294 if (isTransparentElement(schema, target)) { 2295 const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements()); 2296 updateTransparent(blocksSelector, target); 2297 } 2298 }; 2299 const updateCaret = (schema, root, caretParent) => { 2300 const isRoot = el => eq(el, SugarElement.fromDom(root)); 2301 const parents = parents$1(SugarElement.fromDom(caretParent), isRoot); 2302 get$b(parents, parents.length - 2).filter(isElement$7).fold(() => updateChildren(schema, root), scope => updateChildren(schema, scope.dom)); 2303 }; 2304 const hasBlockAttr = el => el.hasAttribute(transparentBlockAttr); 2305 const isTransparentElementName = (schema, name) => has$2(schema.getTransparentElements(), name); 2306 const isTransparentElement = (schema, node) => isElement$6(node) && isTransparentElementName(schema, node.nodeName); 2307 const isTransparentBlock = (schema, node) => isTransparentElement(schema, node) && hasBlockAttr(node); 2308 const isTransparentInline = (schema, node) => isTransparentElement(schema, node) && !hasBlockAttr(node); 2309 const isTransparentAstBlock = (schema, node) => node.type === 1 && isTransparentElementName(schema, node.name) && isString(node.attr(transparentBlockAttr)); 2310 2311 const browser$2 = detect$1().browser; 2312 const firstElement = nodes => find$2(nodes, isElement$7); 2313 const getTableCaptionDeltaY = elm => { 2314 if (browser$2.isFirefox() && name(elm) === 'table') { 2315 return firstElement(children$1(elm)).filter(elm => { 2316 return name(elm) === 'caption'; 2317 }).bind(caption => { 2318 return firstElement(nextSiblings(caption)).map(body => { 2319 const bodyTop = body.dom.offsetTop; 2320 const captionTop = caption.dom.offsetTop; 2321 const captionHeight = caption.dom.offsetHeight; 2322 return bodyTop <= captionTop ? -captionHeight : 0; 2323 }); 2324 }).getOr(0); 2325 } else { 2326 return 0; 2327 } 2328 }; 2329 const hasChild = (elm, child) => elm.children && contains$2(elm.children, child); 2330 const getPos = (body, elm, rootElm) => { 2331 let x = 0, y = 0; 2332 const doc = body.ownerDocument; 2333 rootElm = rootElm ? rootElm : body; 2334 if (elm) { 2335 if (rootElm === body && elm.getBoundingClientRect && get$7(SugarElement.fromDom(body), 'position') === 'static') { 2336 const pos = elm.getBoundingClientRect(); 2337 x = pos.left + (doc.documentElement.scrollLeft || body.scrollLeft) - doc.documentElement.clientLeft; 2338 y = pos.top + (doc.documentElement.scrollTop || body.scrollTop) - doc.documentElement.clientTop; 2339 return { 2340 x, 2341 y 2342 }; 2343 } 2344 let offsetParent = elm; 2345 while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) { 2346 const castOffsetParent = offsetParent; 2347 x += castOffsetParent.offsetLeft || 0; 2348 y += castOffsetParent.offsetTop || 0; 2349 offsetParent = castOffsetParent.offsetParent; 2350 } 2351 offsetParent = elm.parentNode; 2352 while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) { 2353 x -= offsetParent.scrollLeft || 0; 2354 y -= offsetParent.scrollTop || 0; 2355 offsetParent = offsetParent.parentNode; 2356 } 2357 y += getTableCaptionDeltaY(SugarElement.fromDom(elm)); 2358 } 2359 return { 2360 x, 2361 y 2362 }; 2363 }; 2364 2365 const StyleSheetLoader = (documentOrShadowRoot, settings = {}) => { 2366 let idCount = 0; 2367 const loadedStates = {}; 2368 const edos = SugarElement.fromDom(documentOrShadowRoot); 2369 const doc = documentOrOwner(edos); 2370 const _setReferrerPolicy = referrerPolicy => { 2371 settings.referrerPolicy = referrerPolicy; 2372 }; 2373 const _setContentCssCors = contentCssCors => { 2374 settings.contentCssCors = contentCssCors; 2375 }; 2376 const addStyle = element => { 2377 append$1(getStyleContainer(edos), element); 2378 }; 2379 const removeStyle = id => { 2380 const styleContainer = getStyleContainer(edos); 2381 descendant$1(styleContainer, '#' + id).each(remove$4); 2382 }; 2383 const getOrCreateState = url => get$a(loadedStates, url).getOrThunk(() => ({ 2384 id: 'mce-u' + idCount++, 2385 passed: [], 2386 failed: [], 2387 count: 0 2388 })); 2389 const load = url => new Promise((success, failure) => { 2390 let link; 2391 const urlWithSuffix = Tools._addCacheSuffix(url); 2392 const state = getOrCreateState(urlWithSuffix); 2393 loadedStates[urlWithSuffix] = state; 2394 state.count++; 2395 const resolve = (callbacks, status) => { 2396 each$e(callbacks, call); 2397 state.status = status; 2398 state.passed = []; 2399 state.failed = []; 2400 if (link) { 2401 link.onload = null; 2402 link.onerror = null; 2403 link = null; 2404 } 2405 }; 2406 const passed = () => resolve(state.passed, 2); 2407 const failed = () => resolve(state.failed, 3); 2408 if (success) { 2409 state.passed.push(success); 2410 } 2411 if (failure) { 2412 state.failed.push(failure); 2413 } 2414 if (state.status === 1) { 2415 return; 2416 } 2417 if (state.status === 2) { 2418 passed(); 2419 return; 2420 } 2421 if (state.status === 3) { 2422 failed(); 2423 return; 2424 } 2425 state.status = 1; 2426 const linkElem = SugarElement.fromTag('link', doc.dom); 2427 setAll$1(linkElem, { 2428 rel: 'stylesheet', 2429 type: 'text/css', 2430 id: state.id 2431 }); 2432 if (settings.contentCssCors) { 2433 set$4(linkElem, 'crossOrigin', 'anonymous'); 2434 } 2435 if (settings.referrerPolicy) { 2436 set$4(linkElem, 'referrerpolicy', settings.referrerPolicy); 2437 } 2438 link = linkElem.dom; 2439 link.onload = passed; 2440 link.onerror = failed; 2441 addStyle(linkElem); 2442 set$4(linkElem, 'href', urlWithSuffix); 2443 }); 2444 const loadRawCss = (key, css) => { 2445 const state = getOrCreateState(key); 2446 loadedStates[key] = state; 2447 state.count++; 2448 const styleElem = SugarElement.fromTag('style', doc.dom); 2449 setAll$1(styleElem, { 2450 'rel': 'stylesheet', 2451 'type': 'text/css', 2452 'id': state.id, 2453 'data-mce-key': key
vendor: 12,560 bytes, lines 2453-2759
2453 2454 }); 2455 styleElem.dom.innerHTML = css; 2456 addStyle(styleElem); 2457 }; 2458 const loadAll = urls => { 2459 const loadedUrls = Promise.allSettled(map$3(urls, url => load(url).then(constant(url)))); 2460 return loadedUrls.then(results => { 2461 const parts = partition$2(results, r => r.status === 'fulfilled'); 2462 if (parts.fail.length > 0) { 2463 return Promise.reject(map$3(parts.fail, result => result.reason)); 2464 } else { 2465 return map$3(parts.pass, result => result.value); 2466 } 2467 }); 2468 }; 2469 const unload = url => { 2470 const urlWithSuffix = Tools._addCacheSuffix(url); 2471 get$a(loadedStates, urlWithSuffix).each(state => { 2472 const count = --state.count; 2473 if (count === 0) { 2474 delete loadedStates[urlWithSuffix]; 2475 removeStyle(state.id); 2476 } 2477 }); 2478 }; 2479 const unloadRawCss = key => { 2480 get$a(loadedStates, key).each(state => { 2481 const count = --state.count; 2482 if (count === 0) { 2483 delete loadedStates[key]; 2484 removeStyle(state.id); 2485 } 2486 }); 2487 }; 2488 const unloadAll = urls => { 2489 each$e(urls, url => { 2490 unload(url); 2491 }); 2492 }; 2493 return { 2494 load, 2495 loadRawCss, 2496 loadAll, 2497 unload, 2498 unloadRawCss, 2499 unloadAll, 2500 _setReferrerPolicy, 2501 _setContentCssCors 2502 }; 2503 }; 2504 2505 const create$c = () => { 2506 const map = new WeakMap(); 2507 const forElement = (referenceElement, settings) => { 2508 const root = getRootNode(referenceElement); 2509 const rootDom = root.dom; 2510 return Optional.from(map.get(rootDom)).getOrThunk(() => { 2511 const sl = StyleSheetLoader(rootDom, settings); 2512 map.set(rootDom, sl); 2513 return sl; 2514 }); 2515 }; 2516 return { forElement }; 2517 }; 2518 const instance = create$c(); 2519 2520 const isSpan = node => node.nodeName.toLowerCase() === 'span'; 2521 const isInlineContent = (node, schema) => isNonNullable(node) && (isContent$1(schema, node) || schema.isInline(node.nodeName.toLowerCase())); 2522 const surroundedByInlineContent = (node, root, schema) => { 2523 const prev = new DomTreeWalker(node, root).prev(false); 2524 const next = new DomTreeWalker(node, root).next(false); 2525 const prevIsInline = isUndefined(prev) || isInlineContent(prev, schema); 2526 const nextIsInline = isUndefined(next) || isInlineContent(next, schema); 2527 return prevIsInline && nextIsInline; 2528 }; 2529 const isBookmarkNode$2 = node => isSpan(node) && node.getAttribute('data-mce-type') === 'bookmark'; 2530 const isKeepTextNode = (node, root, schema) => isText$b(node) && node.data.length > 0 && surroundedByInlineContent(node, root, schema); 2531 const isKeepElement = node => isElement$6(node) ? node.childNodes.length > 0 : false; 2532 const isDocument = node => isDocumentFragment(node) || isDocument$1(node); 2533 const trimNode = (dom, node, schema, root) => { 2534 var _a; 2535 const rootNode = root || node; 2536 if (isElement$6(node) && isBookmarkNode$2(node)) { 2537 return node; 2538 } 2539 const children = node.childNodes; 2540 for (let i = children.length - 1; i >= 0; i--) { 2541 trimNode(dom, children[i], schema, rootNode); 2542 } 2543 if (isElement$6(node)) { 2544 const currentChildren = node.childNodes; 2545 if (currentChildren.length === 1 && isBookmarkNode$2(currentChildren[0])) { 2546 (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(currentChildren[0], node); 2547 } 2548 } 2549 if (!isDocument(node) && !isContent$1(schema, node) && !isKeepElement(node) && !isKeepTextNode(node, rootNode, schema)) { 2550 dom.remove(node); 2551 } 2552 return node; 2553 }; 2554 2555 const makeMap$3 = Tools.makeMap; 2556 const attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g; 2557 const textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g; 2558 const rawCharsRegExp = /[<>&\"\']/g; 2559 const entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi; 2560 const asciiMap = { 2561 128: '\u20AC', 2562 130: '\u201A', 2563 131: '\u0192', 2564 132: '\u201E', 2565 133: '\u2026', 2566 134: '\u2020', 2567 135: '\u2021', 2568 136: '\u02c6', 2569 137: '\u2030', 2570 138: '\u0160', 2571 139: '\u2039', 2572 140: '\u0152', 2573 142: '\u017d', 2574 145: '\u2018', 2575 146: '\u2019', 2576 147: '\u201C', 2577 148: '\u201D', 2578 149: '\u2022', 2579 150: '\u2013', 2580 151: '\u2014', 2581 152: '\u02DC', 2582 153: '\u2122', 2583 154: '\u0161', 2584 155: '\u203A', 2585 156: '\u0153', 2586 158: '\u017e', 2587 159: '\u0178' 2588 }; 2589 const baseEntities = { 2590 '"': '"', 2591 '\'': ''', 2592 '<': '<', 2593 '>': '>', 2594 '&': '&', 2595 '`': '`' 2596 }; 2597 const reverseEntities = { 2598 '<': '<', 2599 '>': '>', 2600 '&': '&', 2601 '"': '"', 2602 ''': `'` 2603 }; 2604 const nativeDecode = text => { 2605 const elm = SugarElement.fromTag('div').dom; 2606 elm.innerHTML = text; 2607 return elm.textContent || elm.innerText || text; 2608 }; 2609 const buildEntitiesLookup = (items, radix) => { 2610 const lookup = {}; 2611 if (items) { 2612 const itemList = items.split(','); 2613 radix = radix || 10; 2614 for (let i = 0; i < itemList.length; i += 2) { 2615 const chr = String.fromCharCode(parseInt(itemList[i], radix)); 2616 if (!baseEntities[chr]) { 2617 const entity = '&' + itemList[i + 1] + ';'; 2618 lookup[chr] = entity; 2619 lookup[entity] = chr; 2620 } 2621 } 2622 return lookup; 2623 } else { 2624 return undefined; 2625 } 2626 }; 2627 const namedEntities = buildEntitiesLookup('50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' + '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' + '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' + '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' + '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' + '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' + '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' + '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' + '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' + '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' + 'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' + 'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' + 't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' + 'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' + 'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' + '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' + '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' + '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' + '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' + '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' + 'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' + 'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' + 'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' + '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' + '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', 32); 2628 const encodeRaw = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => { 2629 return baseEntities[chr] || chr; 2630 }); 2631 const encodeAllRaw = text => ('' + text).replace(rawCharsRegExp, chr => { 2632 return baseEntities[chr] || chr; 2633 }); 2634 const encodeNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => { 2635 if (chr.length > 1) { 2636 return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';'; 2637 } 2638 return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';'; 2639 }); 2640 const encodeNamed = (text, attr, entities) => { 2641 const resolveEntities = entities || namedEntities; 2642 return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => { 2643 return baseEntities[chr] || resolveEntities[chr] || chr; 2644 }); 2645 }; 2646 const getEncodeFunc = (name, entities) => { 2647 const entitiesMap = buildEntitiesLookup(entities) || namedEntities; 2648 const encodeNamedAndNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => { 2649 if (baseEntities[chr] !== undefined) { 2650 return baseEntities[chr]; 2651 } 2652 if (entitiesMap[chr] !== undefined) { 2653 return entitiesMap[chr]; 2654 } 2655 if (chr.length > 1) { 2656 return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';'; 2657 } 2658 return '&#' + chr.charCodeAt(0) + ';'; 2659 }); 2660 const encodeCustomNamed = (text, attr) => { 2661 return encodeNamed(text, attr, entitiesMap); 2662 }; 2663 const nameMap = makeMap$3(name.replace(/\+/g, ',')); 2664 if (nameMap.named && nameMap.numeric) { 2665 return encodeNamedAndNumeric; 2666 } 2667 if (nameMap.named) { 2668 if (entities) { 2669 return encodeCustomNamed; 2670 } 2671 return encodeNamed; 2672 } 2673 if (nameMap.numeric) { 2674 return encodeNumeric; 2675 } 2676 return encodeRaw; 2677 }; 2678 const decode = text => text.replace(entityRegExp, (all, numeric) => { 2679 if (numeric) { 2680 if (numeric.charAt(0).toLowerCase() === 'x') { 2681 numeric = parseInt(numeric.substr(1), 16); 2682 } else { 2683 numeric = parseInt(numeric, 10); 2684 } 2685 if (numeric > 65535) { 2686 numeric -= 65536; 2687 return String.fromCharCode(55296 + (numeric >> 10), 56320 + (numeric & 1023)); 2688 } 2689 return asciiMap[numeric] || String.fromCharCode(numeric); 2690 } 2691 return reverseEntities[all] || namedEntities[all] || nativeDecode(all); 2692 }); 2693 const Entities = { 2694 encodeRaw, 2695 encodeAllRaw, 2696 encodeNumeric, 2697 encodeNamed, 2698 getEncodeFunc, 2699 decode 2700 }; 2701 2702 const split$1 = (items, delim) => { 2703 items = Tools.trim(items); 2704 return items ? items.split(delim || ' ') : []; 2705 }; 2706 const patternToRegExp = str => new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$'); 2707 const isRegExp$1 = obj => isObject(obj) && obj.source && Object.prototype.toString.call(obj) === '[object RegExp]'; 2708 const deepCloneElementRule = obj => { 2709 const helper = value => { 2710 if (isArray$1(value)) { 2711 return map$3(value, helper); 2712 } else if (isRegExp$1(value)) { 2713 return new RegExp(value.source, value.flags); 2714 } else if (isObject(value)) { 2715 return map$2(value, helper); 2716 } else { 2717 return value; 2718 } 2719 }; 2720 return helper(obj); 2721 }; 2722 2723 const parseCustomElementsRules = value => { 2724 const customElementRegExp = /^(~)?(.+)$/; 2725 return bind$3(split$1(value, ','), rule => { 2726 const matches = customElementRegExp.exec(rule); 2727 if (matches) { 2728 const inline = matches[1] === '~'; 2729 const cloneName = inline ? 'span' : 'div'; 2730 const name = matches[2]; 2731 return [{ 2732 cloneName, 2733 name 2734 }]; 2735 } else { 2736 return []; 2737 } 2738 }); 2739 }; 2740 2741 const getGlobalAttributeSet = type => { 2742 return Object.freeze([ 2743 'id', 2744 'accesskey', 2745 'class', 2746 'dir', 2747 'lang', 2748 'style', 2749 'tabindex', 2750 'title', 2751 'role', 2752 ...type !== 'html4' ? [ 2753 'contenteditable', 2754 'contextmenu', 2755 'draggable', 2756 'dropzone', 2757 'hidden', 2758 'spellcheck', 2759 'translate'
vendor: 2,018 bytes, lines 2759-2814
2759, 2760 'itemprop', 2761 'itemscope', 2762 'itemtype' 2763 ] : [], 2764 ...type !== 'html5-strict' ? ['xml:lang'] : [] 2765 ]); 2766 }; 2767 2768 const getElementSetsAsStrings = type => { 2769 let blockContent; 2770 let phrasingContent; 2771 blockContent = 'address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul'; 2772 phrasingContent = 'a abbr b bdo br button cite code del dfn em embed i iframe img input ins kbd ' + 'label map noscript object q s samp script select small span strong sub sup ' + 'textarea u var #text #comment'; 2773 if (type !== 'html4') { 2774 const transparentContent = 'a ins del canvas map'; 2775 blockContent += ' article aside details dialog figure main header footer hgroup section nav ' + transparentContent; 2776 phrasingContent += ' audio canvas command data datalist mark meter output picture ' + 'progress time wbr video ruby bdi keygen svg'; 2777 } 2778 if (type !== 'html5-strict') { 2779 const html4PhrasingContent = 'acronym applet basefont big font strike tt'; 2780 phrasingContent = [ 2781 phrasingContent, 2782 html4PhrasingContent 2783 ].join(' '); 2784 const html4BlockContent = 'center dir isindex noframes'; 2785 blockContent = [ 2786 blockContent, 2787 html4BlockContent 2788 ].join(' '); 2789 } 2790 const flowContent = [ 2791 blockContent, 2792 phrasingContent 2793 ].join(' '); 2794 return { 2795 blockContent, 2796 phrasingContent, 2797 flowContent 2798 }; 2799 }; 2800 const getElementSets = type => { 2801 const {blockContent, phrasingContent, flowContent} = getElementSetsAsStrings(type); 2802 const toArr = value => { 2803 return Object.freeze(value.split(' ')); 2804 }; 2805 return Object.freeze({ 2806 blockContent: toArr(blockContent), 2807 phrasingContent: toArr(phrasingContent), 2808 flowContent: toArr(flowContent) 2809 }); 2810 }; 2811 2812 const cachedSets = { 2813 'html4': cached(() => getElementSets('html4')), 2814 'html5'
vendor: 9,727 bytes, lines 2814-3021
2814: cached(() => getElementSets('html5')), 2815 'html5-strict': cached(() => getElementSets('html5-strict')) 2816 }; 2817 const getElementsPreset = (type, name) => { 2818 const {blockContent, phrasingContent, flowContent} = cachedSets[type](); 2819 if (name === 'blocks') { 2820 return Optional.some(blockContent); 2821 } else if (name === 'phrasing') { 2822 return Optional.some(phrasingContent); 2823 } else if (name === 'flow') { 2824 return Optional.some(flowContent); 2825 } else { 2826 return Optional.none(); 2827 } 2828 }; 2829 2830 const makeSchema = type => { 2831 const globalAttributes = getGlobalAttributeSet(type); 2832 const {phrasingContent, flowContent} = getElementSetsAsStrings(type); 2833 const schema = {}; 2834 const addElement = (name, attributes, children) => { 2835 schema[name] = { 2836 attributes: mapToObject(attributes, constant({})), 2837 attributesOrder: attributes, 2838 children: mapToObject(children, constant({})) 2839 }; 2840 }; 2841 const add = (name, attributes = '', children = '') => { 2842 const childNames = split$1(children); 2843 const names = split$1(name); 2844 let ni = names.length; 2845 const allAttributes = [ 2846 ...globalAttributes, 2847 ...split$1(attributes) 2848 ]; 2849 while (ni--) { 2850 addElement(names[ni], allAttributes.slice(), childNames); 2851 } 2852 }; 2853 const addAttrs = (name, attributes) => { 2854 const names = split$1(name); 2855 const attrs = split$1(attributes); 2856 let ni = names.length; 2857 while (ni--) { 2858 const schemaItem = schema[names[ni]]; 2859 for (let i = 0, l = attrs.length; i < l; i++) { 2860 schemaItem.attributes[attrs[i]] = {}; 2861 schemaItem.attributesOrder.push(attrs[i]); 2862 } 2863 } 2864 }; 2865 if (type !== 'html5-strict') { 2866 const html4PhrasingContent = 'acronym applet basefont big font strike tt'; 2867 each$e(split$1(html4PhrasingContent), name => { 2868 add(name, '', phrasingContent); 2869 }); 2870 const html4BlockContent = 'center dir isindex noframes'; 2871 each$e(split$1(html4BlockContent), name => { 2872 add(name, '', flowContent); 2873 }); 2874 } 2875 add('html', 'manifest', 'head body'); 2876 add('head', '', 'base command link meta noscript script style title'); 2877 add('title hr noscript br'); 2878 add('base', 'href target'); 2879 add('link', 'href rel media hreflang type sizes hreflang'); 2880 add('meta', 'name http-equiv content charset'); 2881 add('style', 'media type scoped'); 2882 add('script', 'src async defer type charset'); 2883 add('body', 'onafterprint onbeforeprint onbeforeunload onblur onerror onfocus ' + 'onhashchange onload onmessage onoffline ononline onpagehide onpageshow ' + 'onpopstate onresize onscroll onstorage onunload', flowContent); 2884 add('dd div', '', flowContent); 2885 add('address dt caption', '', type === 'html4' ? phrasingContent : flowContent); 2886 add('h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn', '', phrasingContent); 2887 add('blockquote', 'cite', flowContent); 2888 add('ol', 'reversed start type', 'li'); 2889 add('ul', '', 'li'); 2890 add('li', 'value', flowContent); 2891 add('dl', '', 'dt dd'); 2892 add('a', 'href target rel media hreflang type', type === 'html4' ? phrasingContent : flowContent); 2893 add('q', 'cite', phrasingContent); 2894 add('ins del', 'cite datetime', flowContent); 2895 add('img', 'src sizes srcset alt usemap ismap width height'); 2896 add('iframe', 'src name width height', flowContent); 2897 add('embed', 'src type width height'); 2898 add('object', 'data type typemustmatch name usemap form width height', [ 2899 flowContent, 2900 'param' 2901 ].join(' ')); 2902 add('param', 'name value'); 2903 add('map', 'name', [ 2904 flowContent, 2905 'area' 2906 ].join(' ')); 2907 add('area', 'alt coords shape href target rel media hreflang type'); 2908 add('table', 'border', 'caption colgroup thead tfoot tbody tr' + (type === 'html4' ? ' col' : '')); 2909 add('colgroup', 'span', 'col'); 2910 add('col', 'span'); 2911 add('tbody thead tfoot', '', 'tr'); 2912 add('tr', '', 'td th'); 2913 add('td', 'colspan rowspan headers', flowContent); 2914 add('th', 'colspan rowspan headers scope abbr', flowContent); 2915 add('form', 'accept-charset action autocomplete enctype method name novalidate target', flowContent); 2916 add('fieldset', 'disabled form name', [ 2917 flowContent, 2918 'legend' 2919 ].join(' ')); 2920 add('label', 'form for', phrasingContent); 2921 add('input', 'accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate ' + 'formtarget height list max maxlength min multiple name pattern readonly required size src step type value width'); 2922 add('button', 'disabled form formaction formenctype formmethod formnovalidate formtarget name type value', type === 'html4' ? flowContent : phrasingContent); 2923 add('select', 'disabled form multiple name required size', 'option optgroup'); 2924 add('optgroup', 'disabled label', 'option'); 2925 add('option', 'disabled label selected value'); 2926 add('textarea', 'cols dirname disabled form maxlength name readonly required rows wrap'); 2927 add('menu', 'type label', [ 2928 flowContent, 2929 'li' 2930 ].join(' ')); 2931 add('noscript', '', flowContent); 2932 if (type !== 'html4') { 2933 add('wbr'); 2934 add('ruby', '', [ 2935 phrasingContent, 2936 'rt rp' 2937 ].join(' ')); 2938 add('figcaption', '', flowContent); 2939 add('mark rt rp bdi', '', phrasingContent); 2940 add('summary', '', [ 2941 phrasingContent, 2942 'h1 h2 h3 h4 h5 h6' 2943 ].join(' ')); 2944 add('canvas', 'width height', flowContent); 2945 add('data', 'value', phrasingContent); 2946 add('video', 'src crossorigin poster preload autoplay mediagroup loop ' + 'muted controls width height buffered', [ 2947 flowContent, 2948 'track source' 2949 ].join(' ')); 2950 add('audio', 'src crossorigin preload autoplay mediagroup loop muted controls ' + 'buffered volume', [ 2951 flowContent, 2952 'track source' 2953 ].join(' ')); 2954 add('picture', '', 'img source'); 2955 add('source', 'src srcset type media sizes'); 2956 add('track', 'kind src srclang label default'); 2957 add('datalist', '', [ 2958 phrasingContent, 2959 'option' 2960 ].join(' ')); 2961 add('article section nav aside main header footer', '', flowContent); 2962 add('hgroup', '', 'h1 h2 h3 h4 h5 h6'); 2963 add('figure', '', [ 2964 flowContent, 2965 'figcaption' 2966 ].join(' ')); 2967 add('time', 'datetime', phrasingContent); 2968 add('dialog', 'open', flowContent); 2969 add('command', 'type label icon disabled checked radiogroup command'); 2970 add('output', 'for form name', phrasingContent); 2971 add('progress', 'value max', phrasingContent); 2972 add('meter', 'value min max low high optimum', phrasingContent); 2973 add('details', 'open', [ 2974 flowContent, 2975 'summary' 2976 ].join(' ')); 2977 add('keygen', 'autofocus challenge disabled form keytype name'); 2978 addElement('svg', 'id tabindex lang xml:space class style x y width height viewBox preserveAspectRatio zoomAndPan transform'.split(' '), []); 2979 } 2980 if (type !== 'html5-strict') { 2981 addAttrs('script', 'language xml:space'); 2982 addAttrs('style', 'xml:space'); 2983 addAttrs('object', 'declare classid code codebase codetype archive standby align border hspace vspace'); 2984 addAttrs('embed', 'align name hspace vspace'); 2985 addAttrs('param', 'valuetype type'); 2986 addAttrs('a', 'charset name rev shape coords'); 2987 addAttrs('br', 'clear'); 2988 addAttrs('applet', 'codebase archive code object alt name width height align hspace vspace'); 2989 addAttrs('img', 'name longdesc align border hspace vspace'); 2990 addAttrs('iframe', 'longdesc frameborder marginwidth marginheight scrolling align'); 2991 addAttrs('font basefont', 'size color face'); 2992 addAttrs('input', 'usemap align'); 2993 addAttrs('select'); 2994 addAttrs('textarea'); 2995 addAttrs('h1 h2 h3 h4 h5 h6 div p legend caption', 'align'); 2996 addAttrs('ul', 'type compact'); 2997 addAttrs('li', 'type'); 2998 addAttrs('ol dl menu dir', 'compact'); 2999 addAttrs('pre', 'width xml:space'); 3000 addAttrs('hr', 'align noshade size width'); 3001 addAttrs('isindex', 'prompt'); 3002 addAttrs('table', 'summary width frame rules cellspacing cellpadding align bgcolor'); 3003 addAttrs('col', 'width align char charoff valign'); 3004 addAttrs('colgroup', 'width align char charoff valign'); 3005 addAttrs('thead', 'align char charoff valign'); 3006 addAttrs('tr', 'align char charoff valign bgcolor'); 3007 addAttrs('th', 'axis align char charoff valign nowrap bgcolor width height'); 3008 addAttrs('form', 'accept'); 3009 addAttrs('td', 'abbr axis scope align char charoff valign nowrap bgcolor width height'); 3010 addAttrs('tfoot', 'align char charoff valign'); 3011 addAttrs('tbody', 'align char charoff valign'); 3012 addAttrs('area', 'nohref'); 3013 addAttrs('body', 'background bgcolor text link vlink alink'); 3014 } 3015 if (type !== 'html4') { 3016 addAttrs('input button select textarea', 'autofocus'); 3017 addAttrs('input textarea', 'placeholder'); 3018 addAttrs('a', 'download'); 3019 addAttrs('link script img', 'crossorigin'); 3020 addAttrs('img', 'loading'); 3021 addAttrs('iframe', 'sandbox seamless allow allowfullscreen loading
3021 referrerpolicy
vendor: 21,997 bytes, lines 3021-3569
3021'); 3022 } 3023 if (type !== 'html4') { 3024 each$e([ 3025 schema.video, 3026 schema.audio 3027 ], item => { 3028 delete item.children.audio; 3029 delete item.children.video; 3030 }); 3031 } 3032 each$e(split$1('a form meter progress dfn'), name => { 3033 if (schema[name]) { 3034 delete schema[name].children[name]; 3035 } 3036 }); 3037 delete schema.caption.children.table; 3038 delete schema.script; 3039 return schema; 3040 }; 3041 3042 const prefixToOperation = prefix => prefix === '-' ? 'remove' : 'add'; 3043 const parseValidChild = name => { 3044 const validChildRegExp = /^(@?)([A-Za-z0-9_\-.\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]+)$/; 3045 return Optional.from(validChildRegExp.exec(name)).map(matches => ({ 3046 preset: matches[1] === '@', 3047 name: matches[2] 3048 })); 3049 }; 3050 const parseValidChildrenRules = value => { 3051 const childRuleRegExp = /^([+\-]?)([A-Za-z0-9_\-.\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]+)\[([^\]]+)]$/; 3052 return bind$3(split$1(value, ','), rule => { 3053 const matches = childRuleRegExp.exec(rule); 3054 if (matches) { 3055 const prefix = matches[1]; 3056 const operation = prefix ? prefixToOperation(prefix) : 'replace'; 3057 const name = matches[2]; 3058 const validChildren = bind$3(split$1(matches[3], '|'), validChild => parseValidChild(validChild).toArray()); 3059 return [{ 3060 operation, 3061 name, 3062 validChildren 3063 }]; 3064 } else { 3065 return []; 3066 } 3067 }); 3068 }; 3069 3070 const parseValidElementsAttrDataIntoElement = (attrData, targetElement) => { 3071 const attrRuleRegExp = /^([!\-])?(\w+[\\:]:\w+|[^=~<]+)?(?:([=~<])(.*))?$/; 3072 const hasPatternsRegExp = /[*?+]/; 3073 const {attributes, attributesOrder} = targetElement; 3074 return each$e(split$1(attrData, '|'), rule => { 3075 const matches = attrRuleRegExp.exec(rule); 3076 if (matches) { 3077 const attr = {}; 3078 const attrType = matches[1]; 3079 const attrName = matches[2].replace(/[\\:]:/g, ':'); 3080 const attrPrefix = matches[3]; 3081 const value = matches[4]; 3082 if (attrType === '!') { 3083 targetElement.attributesRequired = targetElement.attributesRequired || []; 3084 targetElement.attributesRequired.push(attrName); 3085 attr.required = true; 3086 } 3087 if (attrType === '-') { 3088 delete attributes[attrName]; 3089 attributesOrder.splice(Tools.inArray(attributesOrder, attrName), 1); 3090 return; 3091 } 3092 if (attrPrefix) { 3093 if (attrPrefix === '=') { 3094 targetElement.attributesDefault = targetElement.attributesDefault || []; 3095 targetElement.attributesDefault.push({ 3096 name: attrName, 3097 value 3098 }); 3099 attr.defaultValue = value; 3100 } else if (attrPrefix === '~') { 3101 targetElement.attributesForced = targetElement.attributesForced || []; 3102 targetElement.attributesForced.push({ 3103 name: attrName, 3104 value 3105 }); 3106 attr.forcedValue = value; 3107 } else if (attrPrefix === '<') { 3108 attr.validValues = Tools.makeMap(value, '?'); 3109 } 3110 } 3111 if (hasPatternsRegExp.test(attrName)) { 3112 const attrPattern = attr; 3113 targetElement.attributePatterns = targetElement.attributePatterns || []; 3114 attrPattern.pattern = patternToRegExp(attrName); 3115 targetElement.attributePatterns.push(attrPattern); 3116 } else { 3117 if (!attributes[attrName]) { 3118 attributesOrder.push(attrName); 3119 } 3120 attributes[attrName] = attr; 3121 } 3122 } 3123 }); 3124 }; 3125 const cloneAttributesInto = (from, to) => { 3126 each$d(from.attributes, (value, key) => { 3127 to.attributes[key] = value; 3128 }); 3129 to.attributesOrder.push(...from.attributesOrder); 3130 }; 3131 const parseValidElementsRules = (globalElement, validElements) => { 3132 const elementRuleRegExp = /^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)])?$/; 3133 return bind$3(split$1(validElements, ','), rule => { 3134 const matches = elementRuleRegExp.exec(rule); 3135 if (matches) { 3136 const prefix = matches[1]; 3137 const elementName = matches[2]; 3138 const outputName = matches[3]; 3139 const attrsPrefix = matches[4]; 3140 const attrData = matches[5]; 3141 const element = { 3142 attributes: {}, 3143 attributesOrder: [] 3144 }; 3145 globalElement.each(el => cloneAttributesInto(el, element)); 3146 if (prefix === '#') { 3147 element.paddEmpty = true; 3148 } else if (prefix === '-') { 3149 element.removeEmpty = true; 3150 } 3151 if (attrsPrefix === '!') { 3152 element.removeEmptyAttrs = true; 3153 } 3154 if (attrData) { 3155 parseValidElementsAttrDataIntoElement(attrData, element); 3156 } 3157 if (outputName) { 3158 element.outputName = elementName; 3159 } 3160 if (elementName === '@') { 3161 if (globalElement.isNone()) { 3162 globalElement = Optional.some(element); 3163 } else { 3164 return []; 3165 } 3166 } 3167 return [outputName ? { 3168 name: elementName, 3169 element, 3170 aliasName: outputName 3171 } : { 3172 name: elementName, 3173 element 3174 }]; 3175 } else { 3176 return []; 3177 } 3178 }); 3179 }; 3180 3181 const mapCache = {}; 3182 const makeMap$2 = Tools.makeMap, each$b = Tools.each, extend$2 = Tools.extend, explode$2 = Tools.explode; 3183 const createMap = (defaultValue, extendWith = {}) => { 3184 const value = makeMap$2(defaultValue, ' ', makeMap$2(defaultValue.toUpperCase(), ' ')); 3185 return extend$2(value, extendWith); 3186 }; 3187 const getTextRootBlockElements = schema => createMap('td th li dt dd figcaption caption details summary', schema.getTextBlockElements()); 3188 const compileElementMap = (value, mode) => { 3189 if (value) { 3190 const styles = {}; 3191 if (isString(value)) { 3192 value = { '*': value }; 3193 } 3194 each$b(value, (value, key) => { 3195 styles[key] = styles[key.toUpperCase()] = mode === 'map' ? makeMap$2(value, /[, ]/) : explode$2(value, /[, ]/); 3196 }); 3197 return styles; 3198 } else { 3199 return undefined; 3200 } 3201 }; 3202 const Schema = (settings = {}) => { 3203 var _a; 3204 const elements = {}; 3205 const children = {}; 3206 let patternElements = []; 3207 const customElementsMap = {}; 3208 const specialElements = {}; 3209 const createLookupTable = (option, defaultValue, extendWith) => { 3210 const value = settings[option]; 3211 if (!value) { 3212 let newValue = mapCache[option]; 3213 if (!newValue) { 3214 newValue = createMap(defaultValue, extendWith); 3215 mapCache[option] = newValue; 3216 } 3217 return newValue; 3218 } else { 3219 return makeMap$2(value, /[, ]/, makeMap$2(value.toUpperCase(), /[, ]/)); 3220 } 3221 }; 3222 const schemaType = (_a = settings.schema) !== null && _a !== void 0 ? _a : 'html5'; 3223 const schemaItems = makeSchema(schemaType); 3224 if (settings.verify_html === false) { 3225 settings.valid_elements = '*[*]'; 3226 } 3227 const validStyles = compileElementMap(settings.valid_styles); 3228 const invalidStyles = compileElementMap(settings.invalid_styles, 'map'); 3229 const validClasses = compileElementMap(settings.valid_classes, 'map'); 3230 const whitespaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea video audio iframe object code'); 3231 const selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr'); 3232 const voidElementsMap = createLookupTable('void_elements', 'area base basefont br col frame hr img input isindex link ' + 'meta param embed source wbr track'); 3233 const boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' + 'noshade nowrap readonly selected autoplay loop controls allowfullscreen'); 3234 const nonEmptyOrMoveCaretBeforeOnEnter = 'td th iframe video audio object script code'; 3235 const nonEmptyElementsMap = createLookupTable('non_empty_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' pre svg textarea summary', voidElementsMap); 3236 const moveCaretBeforeOnEnterElementsMap = createLookupTable('move_caret_before_on_enter_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' table', voidElementsMap); 3237 const headings = 'h1 h2 h3 h4 h5 h6'; 3238 const textBlockElementsMap = createLookupTable('text_block_elements', headings + ' p div address pre form ' + 'blockquote center dir fieldset header footer article section hgroup aside main nav figure'); 3239 const blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' + 'th tr td li ol ul caption dl dt dd noscript menu isindex option ' + 'datalist select optgroup figcaption details summary html body multicol listing', textBlockElementsMap); 3240 const textInlineElementsMap = createLookupTable('text_inline_elements', 'span strong b em i font s strike u var cite ' + 'dfn code mark q sup sub samp'); 3241 const transparentElementsMap = createLookupTable('transparent_elements', 'a ins del canvas map'); 3242 const wrapBlockElementsMap = createLookupTable('wrap_block_elements', 'pre ' + headings); 3243 each$b('script noscript iframe noframes noembed title style textarea xmp plaintext'.split(' '), name => { 3244 specialElements[name] = new RegExp('</' + name + '[^>]*>', 'gi'); 3245 }); 3246 const addValidElements = validElements => { 3247 const globalElement = Optional.from(elements['@']); 3248 const hasPatternsRegExp = /[*?+]/; 3249 each$e(parseValidElementsRules(globalElement, validElements !== null && validElements !== void 0 ? validElements : ''), ({name, element, aliasName}) => { 3250 if (aliasName) { 3251 elements[aliasName] = element; 3252 } 3253 if (hasPatternsRegExp.test(name)) { 3254 const patternElement = element; 3255 patternElement.pattern = patternToRegExp(name); 3256 patternElements.push(patternElement); 3257 } else { 3258 elements[name] = element; 3259 } 3260 }); 3261 }; 3262 const setValidElements = validElements => { 3263 patternElements = []; 3264 each$e(keys(elements), name => { 3265 delete elements[name]; 3266 }); 3267 addValidElements(validElements); 3268 }; 3269 const addCustomElement = (name, spec) => { 3270 var _a, _b; 3271 delete mapCache.text_block_elements; 3272 delete mapCache.block_elements; 3273 const inline = spec.extends ? !isBlock(spec.extends) : false; 3274 const cloneName = spec.extends; 3275 children[name] = cloneName ? children[cloneName] : {}; 3276 customElementsMap[name] = cloneName !== null && cloneName !== void 0 ? cloneName : name; 3277 nonEmptyElementsMap[name.toUpperCase()] = {}; 3278 nonEmptyElementsMap[name] = {}; 3279 if (!inline) { 3280 blockElementsMap[name.toUpperCase()] = {}; 3281 blockElementsMap[name] = {}; 3282 } 3283 if (cloneName && !elements[name] && elements[cloneName]) { 3284 const customRule = deepCloneElementRule(elements[cloneName]); 3285 delete customRule.removeEmptyAttrs; 3286 delete customRule.removeEmpty; 3287 elements[name] = customRule; 3288 } else { 3289 elements[name] = { 3290 attributesOrder: [], 3291 attributes: {} 3292 }; 3293 } 3294 if (isArray$1(spec.attributes)) { 3295 const processAttrName = name => { 3296 customRule.attributesOrder.push(name); 3297 customRule.attributes[name] = {}; 3298 }; 3299 const customRule = (_a = elements[name]) !== null && _a !== void 0 ? _a : {}; 3300 delete customRule.attributesDefault; 3301 delete customRule.attributesForced; 3302 delete customRule.attributePatterns; 3303 delete customRule.attributesRequired; 3304 customRule.attributesOrder = []; 3305 customRule.attributes = {}; 3306 each$e(spec.attributes, attrName => { 3307 const globalAttrs = getGlobalAttributeSet(schemaType); 3308 parseValidChild(attrName).each(({preset, name}) => { 3309 if (preset) { 3310 if (name === 'global') { 3311 each$e(globalAttrs, processAttrName); 3312 } 3313 } else { 3314 processAttrName(name); 3315 } 3316 }); 3317 }); 3318 elements[name] = customRule; 3319 } 3320 if (isBoolean(spec.padEmpty)) { 3321 const customRule = (_b = elements[name]) !== null && _b !== void 0 ? _b : {}; 3322 customRule.paddEmpty = spec.padEmpty; 3323 elements[name] = customRule; 3324 } 3325 if (isArray$1(spec.children)) { 3326 const customElementChildren = {}; 3327 const processNodeName = name => { 3328 customElementChildren[name] = {}; 3329 }; 3330 const processPreset = name => { 3331 getElementsPreset(schemaType, name).each(names => { 3332 each$e(names, processNodeName); 3333 }); 3334 }; 3335 each$e(spec.children, child => { 3336 parseValidChild(child).each(({preset, name}) => { 3337 if (preset) { 3338 processPreset(name); 3339 } else { 3340 processNodeName(name); 3341 } 3342 }); 3343 }); 3344 children[name] = customElementChildren; 3345 } 3346 if (cloneName) { 3347 each$d(children, (element, elmName) => { 3348 if (element[cloneName]) { 3349 children[elmName] = element = extend$2({}, children[elmName]); 3350 element[name] = element[cloneName]; 3351 } 3352 }); 3353 } 3354 }; 3355 const addCustomElementsFromString = customElements => { 3356 each$e(parseCustomElementsRules(customElements !== null && customElements !== void 0 ? customElements : ''), ({name, cloneName}) => { 3357 addCustomElement(name, { extends: cloneName }); 3358 }); 3359 }; 3360 const addCustomElements = customElements => { 3361 if (isObject(customElements)) { 3362 each$d(customElements, (spec, name) => addCustomElement(name, spec)); 3363 } else if (isString(customElements)) { 3364 addCustomElementsFromString(customElements); 3365 } 3366 }; 3367 const addValidChildren = validChildren => { 3368 each$e(parseValidChildrenRules(validChildren !== null && validChildren !== void 0 ? validChildren : ''), ({operation, name, validChildren}) => { 3369 const parent = operation === 'replace' ? { '#comment': {} } : children[name]; 3370 const processNodeName = name => { 3371 if (operation === 'remove') { 3372 delete parent[name]; 3373 } else { 3374 parent[name] = {}; 3375 } 3376 }; 3377 const processPreset = name => { 3378 getElementsPreset(schemaType, name).each(names => { 3379 each$e(names, processNodeName); 3380 }); 3381 }; 3382 each$e(validChildren, ({preset, name}) => { 3383 if (preset) { 3384 processPreset(name); 3385 } else { 3386 processNodeName(name); 3387 } 3388 }); 3389 children[name] = parent; 3390 }); 3391 }; 3392 const getElementRule = name => { 3393 const element = elements[name]; 3394 if (element) { 3395 return element; 3396 } 3397 let i = patternElements.length; 3398 while (i--) { 3399 const patternElement = patternElements[i]; 3400 if (patternElement.pattern.test(name)) { 3401 return patternElement; 3402 } 3403 } 3404 return undefined; 3405 }; 3406 const setup = () => { 3407 if (!settings.valid_elements) { 3408 each$b(schemaItems, (element, name) => { 3409 elements[name] = { 3410 attributes: element.attributes, 3411 attributesOrder: element.attributesOrder 3412 }; 3413 children[name] = element.children; 3414 }); 3415 each$b(split$1('strong/b em/i'), item => { 3416 const items = split$1(item, '/'); 3417 elements[items[1]].outputName = items[0]; 3418 }); 3419 each$b(textInlineElementsMap, (_val, name) => { 3420 if (elements[name]) { 3421 if (settings.padd_empty_block_inline_children) { 3422 elements[name].paddInEmptyBlock = true; 3423 } 3424 elements[name].removeEmpty = true; 3425 } 3426 }); 3427 each$b(split$1('ol ul blockquote a table tbody'), name => { 3428 if (elements[name]) { 3429 elements[name].removeEmpty = true; 3430 } 3431 }); 3432 each$b(split$1('p h1 h2 h3 h4 h5 h6 th td pre div address caption li summary'), name => { 3433 if (elements[name]) { 3434 elements[name].paddEmpty = true; 3435 } 3436 }); 3437 each$b(split$1('span'), name => { 3438 elements[name].removeEmptyAttrs = true; 3439 }); 3440 } else { 3441 setValidElements(settings.valid_elements); 3442 each$b(schemaItems, (element, name) => { 3443 children[name] = element.children; 3444 }); 3445 } 3446 delete elements.svg; 3447 addCustomElements(settings.custom_elements); 3448 addValidChildren(settings.valid_children); 3449 addValidElements(settings.extended_valid_elements); 3450 addValidChildren('+ol[ul|ol],+ul[ul|ol]'); 3451 each$b({ 3452 dd: 'dl', 3453 dt: 'dl', 3454 li: 'ul ol', 3455 td: 'tr', 3456 th: 'tr', 3457 tr: 'tbody thead tfoot', 3458 tbody: 'table', 3459 thead: 'table', 3460 tfoot: 'table', 3461 legend: 'fieldset', 3462 area: 'map', 3463 param: 'video audio object' 3464 }, (parents, item) => { 3465 if (elements[item]) { 3466 elements[item].parentsRequired = split$1(parents); 3467 } 3468 }); 3469 if (settings.invalid_elements) { 3470 each$b(explode$2(settings.invalid_elements), item => { 3471 if (elements[item]) { 3472 delete elements[item]; 3473 } 3474 }); 3475 } 3476 if (!getElementRule('span')) { 3477 addValidElements('span[!data-mce-type|*]'); 3478 } 3479 }; 3480 const getValidStyles = constant(validStyles); 3481 const getInvalidStyles = constant(invalidStyles); 3482 const getValidClasses = constant(validClasses); 3483 const getBoolAttrs = constant(boolAttrMap); 3484 const getBlockElements = constant(blockElementsMap); 3485 const getTextBlockElements = constant(textBlockElementsMap); 3486 const getTextInlineElements = constant(textInlineElementsMap); 3487 const getVoidElements = constant(Object.seal(voidElementsMap)); 3488 const getSelfClosingElements = constant(selfClosingElementsMap); 3489 const getNonEmptyElements = constant(nonEmptyElementsMap); 3490 const getMoveCaretBeforeOnEnterElements = constant(moveCaretBeforeOnEnterElementsMap); 3491 const getWhitespaceElements = constant(whitespaceElementsMap); 3492 const getTransparentElements = constant(transparentElementsMap); 3493 const getWrapBlockElements = constant(wrapBlockElementsMap); 3494 const getSpecialElements = constant(Object.seal(specialElements)); 3495 const isValidChild = (name, child) => { 3496 const parent = children[name.toLowerCase()]; 3497 return !!(parent && parent[child.toLowerCase()]); 3498 }; 3499 const isValid = (name, attr) => { 3500 const rule = getElementRule(name); 3501 if (rule) { 3502 if (attr) { 3503 if (rule.attributes[attr]) { 3504 return true; 3505 } 3506 const attrPatterns = rule.attributePatterns; 3507 if (attrPatterns) { 3508 let i = attrPatterns.length; 3509 while (i--) { 3510 if (attrPatterns[i].pattern.test(attr)) { 3511 return true; 3512 } 3513 } 3514 } 3515 } else { 3516 return true; 3517 } 3518 } 3519 return false; 3520 }; 3521 const isBlock = name => has$2(getBlockElements(), name); 3522 const isInline = name => !startsWith(name, '#') && isValid(name) && !isBlock(name); 3523 const isWrapper = name => has$2(getWrapBlockElements(), name) || isInline(name); 3524 const getCustomElements = constant(customElementsMap); 3525 setup(); 3526 return { 3527 type: schemaType, 3528 children, 3529 elements, 3530 getValidStyles, 3531 getValidClasses, 3532 getBlockElements, 3533 getInvalidStyles, 3534 getVoidElements, 3535 getTextBlockElements, 3536 getTextInlineElements, 3537 getBoolAttrs, 3538 getElementRule, 3539 getSelfClosingElements, 3540 getNonEmptyElements, 3541 getMoveCaretBeforeOnEnterElements, 3542 getWhitespaceElements, 3543 getTransparentElements, 3544 getSpecialElements, 3545 isValidChild, 3546 isValid, 3547 isBlock, 3548 isInline, 3549 isWrapper, 3550 getCustomElements, 3551 addValidElements, 3552 setValidElements, 3553 addCustomElements, 3554 addValidChildren 3555 }; 3556 }; 3557 3558 const hexColour = value => ({ value: normalizeHex(value) }); 3559 const normalizeHex = hex => removeLeading(hex, '#').toUpperCase(); 3560 const toHex = component => { 3561 const hex = component.toString(16); 3562 return (hex.length === 1 ? '0' + hex : hex).toUpperCase(); 3563 }; 3564 const fromRgba = rgbaColour => { 3565 const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue); 3566 return hexColour(value); 3567 }; 3568 3569 const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*
vendor: 7,525 bytes, lines 3569-3766
3569[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*\)\s*$/i; 3570 const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*((?:\d?\.\d+|\d+)%?)\s*\)\s*$/i; 3571 const rgbaColour = (red, green, blue, alpha) => ({ 3572 red, 3573 green, 3574 blue, 3575 alpha 3576 }); 3577 const fromStringValues = (red, green, blue, alpha) => { 3578 const r = parseInt(red, 10); 3579 const g = parseInt(green, 10); 3580 const b = parseInt(blue, 10); 3581 const a = parseFloat(alpha); 3582 return rgbaColour(r, g, b, a); 3583 }; 3584 const getColorFormat = colorString => { 3585 if (rgbRegex.test(colorString)) { 3586 return 'rgb'; 3587 } else if (rgbaRegex.test(colorString)) { 3588 return 'rgba'; 3589 } 3590 return 'other'; 3591 }; 3592 const fromString = rgbaString => { 3593 const rgbMatch = rgbRegex.exec(rgbaString); 3594 if (rgbMatch !== null) { 3595 return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1')); 3596 } 3597 const rgbaMatch = rgbaRegex.exec(rgbaString); 3598 if (rgbaMatch !== null) { 3599 return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4])); 3600 } 3601 return Optional.none(); 3602 }; 3603 const toString = rgba => `rgba(${ rgba.red },${ rgba.green },${ rgba.blue },${ rgba.alpha })`; 3604 3605 const rgbaToHexString = color => fromString(color).map(fromRgba).map(h => '#' + h.value).getOr(color); 3606 3607 const Styles = (settings = {}, schema) => { 3608 const urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi; 3609 const styleRegExp = /\s*([^:]+):\s*([^;]+);?/g; 3610 const trimRightRegExp = /\s+$/; 3611 const encodingLookup = {}; 3612 let validStyles; 3613 let invalidStyles; 3614 const invisibleChar = zeroWidth; 3615 if (schema) { 3616 validStyles = schema.getValidStyles(); 3617 invalidStyles = schema.getInvalidStyles(); 3618 } 3619 const encodingItems = (`\\" \\' \\; \\: ; : ` + invisibleChar).split(' '); 3620 for (let i = 0; i < encodingItems.length; i++) { 3621 encodingLookup[encodingItems[i]] = invisibleChar + i; 3622 encodingLookup[invisibleChar + i] = encodingItems[i]; 3623 } 3624 const self = { 3625 parse: css => { 3626 const styles = {}; 3627 let isEncoded = false; 3628 const urlConverter = settings.url_converter; 3629 const urlConverterScope = settings.url_converter_scope || self; 3630 const compress = (prefix, suffix, noJoin) => { 3631 const top = styles[prefix + '-top' + suffix]; 3632 if (!top) { 3633 return; 3634 } 3635 const right = styles[prefix + '-right' + suffix]; 3636 if (!right) { 3637 return; 3638 } 3639 const bottom = styles[prefix + '-bottom' + suffix]; 3640 if (!bottom) { 3641 return; 3642 } 3643 const left = styles[prefix + '-left' + suffix]; 3644 if (!left) { 3645 return; 3646 } 3647 const box = [ 3648 top, 3649 right, 3650 bottom, 3651 left 3652 ]; 3653 let i = box.length - 1; 3654 while (i--) { 3655 if (box[i] !== box[i + 1]) { 3656 break; 3657 } 3658 } 3659 if (i > -1 && noJoin) { 3660 return; 3661 } 3662 styles[prefix + suffix] = i === -1 ? box[0] : box.join(' '); 3663 delete styles[prefix + '-top' + suffix]; 3664 delete styles[prefix + '-right' + suffix]; 3665 delete styles[prefix + '-bottom' + suffix]; 3666 delete styles[prefix + '-left' + suffix]; 3667 }; 3668 const canCompress = key => { 3669 const value = styles[key]; 3670 if (!value) { 3671 return; 3672 } 3673 const values = value.indexOf(',') > -1 ? [value] : value.split(' '); 3674 let i = values.length; 3675 while (i--) { 3676 if (values[i] !== values[0]) { 3677 return false; 3678 } 3679 } 3680 styles[key] = values[0]; 3681 return true; 3682 }; 3683 const compress2 = (target, a, b, c) => { 3684 if (!canCompress(a)) { 3685 return; 3686 } 3687 if (!canCompress(b)) { 3688 return; 3689 } 3690 if (!canCompress(c)) { 3691 return; 3692 } 3693 styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c]; 3694 delete styles[a]; 3695 delete styles[b]; 3696 delete styles[c]; 3697 }; 3698 const encode = str => { 3699 isEncoded = true; 3700 return encodingLookup[str]; 3701 }; 3702 const decode = (str, keepSlashes) => { 3703 if (isEncoded) { 3704 str = str.replace(/\uFEFF[0-9]/g, str => { 3705 return encodingLookup[str]; 3706 }); 3707 } 3708 if (!keepSlashes) { 3709 str = str.replace(/\\([\'\";:])/g, '$1'); 3710 } 3711 return str; 3712 }; 3713 const decodeSingleHexSequence = escSeq => { 3714 return String.fromCharCode(parseInt(escSeq.slice(1), 16)); 3715 }; 3716 const decodeHexSequences = value => { 3717 return value.replace(/\\[0-9a-f]+/gi, decodeSingleHexSequence); 3718 }; 3719 const processUrl = (match, url, url2, url3, str, str2) => { 3720 str = str || str2; 3721 if (str) { 3722 str = decode(str); 3723 return `'` + str.replace(/\'/g, `\\'`) + `'`; 3724 } 3725 url = decode(url || url2 || url3 || ''); 3726 if (!settings.allow_script_urls) { 3727 const scriptUrl = url.replace(/[\s\r\n]+/g, ''); 3728 if (/(java|vb)script:/i.test(scriptUrl)) { 3729 return ''; 3730 } 3731 if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) { 3732 return ''; 3733 } 3734 } 3735 if (urlConverter) { 3736 url = urlConverter.call(urlConverterScope, url, 'style'); 3737 } 3738 return `url('` + url.replace(/\'/g, `\\'`) + `')`; 3739 }; 3740 if (css) { 3741 css = css.replace(/[\u0000-\u001F]/g, ''); 3742 css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, str => { 3743 return str.replace(/[;:]/g, encode); 3744 }); 3745 let matches; 3746 while (matches = styleRegExp.exec(css)) { 3747 styleRegExp.lastIndex = matches.index + matches[0].length; 3748 let name = matches[1].replace(trimRightRegExp, '').toLowerCase(); 3749 let value = matches[2].replace(trimRightRegExp, ''); 3750 if (name && value) { 3751 name = decodeHexSequences(name); 3752 value = decodeHexSequences(value); 3753 if (name.indexOf(invisibleChar) !== -1 || name.indexOf('"') !== -1) { 3754 continue; 3755 } 3756 if (!settings.allow_script_urls && (name === 'behavior' || /expression\s*\(|\/\*|\*\//.test(value))) { 3757 continue; 3758 } 3759 if (name === 'font-weight' && value === '700') { 3760 value = 'bold'; 3761 } else if (name === 'color' || name === 'background-color') { 3762 value = value.toLowerCase(); 3763 } 3764 if (getColorFormat(value) === 'rgb') { 3765 fromString(value).each(rgba => { 3766 value = rgbaToHexString(toString(rgba)).toLowerCase();
vendor: 11,552 bytes, lines 3766-4071
3766 3767 }); 3768 } 3769 value = value.replace(urlOrStrRegExp, processUrl); 3770 styles[name] = isEncoded ? decode(value, true) : value; 3771 } 3772 } 3773 compress('border', '', true); 3774 compress('border', '-width'); 3775 compress('border', '-color'); 3776 compress('border', '-style'); 3777 compress('padding', ''); 3778 compress('margin', ''); 3779 compress2('border', 'border-width', 'border-style', 'border-color'); 3780 if (styles.border === 'medium none') { 3781 delete styles.border; 3782 } 3783 if (styles['border-image'] === 'none') { 3784 delete styles['border-image']; 3785 } 3786 } 3787 return styles; 3788 }, 3789 serialize: (styles, elementName) => { 3790 let css = ''; 3791 const serializeStyles = (elemName, validStyleList) => { 3792 const styleList = validStyleList[elemName]; 3793 if (styleList) { 3794 for (let i = 0, l = styleList.length; i < l; i++) { 3795 const name = styleList[i]; 3796 const value = styles[name]; 3797 if (value) { 3798 css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';'; 3799 } 3800 } 3801 } 3802 }; 3803 const isValid = (name, elemName) => { 3804 if (!invalidStyles || !elemName) { 3805 return true; 3806 } 3807 let styleMap = invalidStyles['*']; 3808 if (styleMap && styleMap[name]) { 3809 return false; 3810 } 3811 styleMap = invalidStyles[elemName]; 3812 return !(styleMap && styleMap[name]); 3813 }; 3814 if (elementName && validStyles) { 3815 serializeStyles('*', validStyles); 3816 serializeStyles(elementName, validStyles); 3817 } else { 3818 each$d(styles, (value, name) => { 3819 if (value && isValid(name, elementName)) { 3820 css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';'; 3821 } 3822 }); 3823 } 3824 return css; 3825 } 3826 }; 3827 return self; 3828 }; 3829 3830 const deprecated = { 3831 keyLocation: true, 3832 layerX: true, 3833 layerY: true, 3834 returnValue: true, 3835 webkitMovementX: true, 3836 webkitMovementY: true, 3837 keyIdentifier: true, 3838 mozPressure: true 3839 }; 3840 const isNativeEvent = event => event instanceof Event || isFunction(event.initEvent); 3841 const hasIsDefaultPrevented = event => event.isDefaultPrevented === always || event.isDefaultPrevented === never; 3842 const needsNormalizing = event => isNullable(event.preventDefault) || isNativeEvent(event); 3843 const clone$3 = (originalEvent, data) => { 3844 const event = data !== null && data !== void 0 ? data : {}; 3845 for (const name in originalEvent) { 3846 if (!has$2(deprecated, name)) { 3847 event[name] = originalEvent[name]; 3848 } 3849 } 3850 if (isNonNullable(originalEvent.composedPath)) { 3851 event.composedPath = () => originalEvent.composedPath(); 3852 } 3853 if (isNonNullable(originalEvent.getModifierState)) { 3854 event.getModifierState = keyArg => originalEvent.getModifierState(keyArg); 3855 } 3856 if (isNonNullable(originalEvent.getTargetRanges)) { 3857 event.getTargetRanges = () => originalEvent.getTargetRanges(); 3858 } 3859 return event; 3860 }; 3861 const normalize$3 = (type, originalEvent, fallbackTarget, data) => { 3862 var _a; 3863 const event = clone$3(originalEvent, data); 3864 event.type = type; 3865 if (isNullable(event.target)) { 3866 event.target = (_a = event.srcElement) !== null && _a !== void 0 ? _a : fallbackTarget; 3867 } 3868 if (needsNormalizing(originalEvent)) { 3869 event.preventDefault = () => { 3870 event.defaultPrevented = true; 3871 event.isDefaultPrevented = always; 3872 if (isFunction(originalEvent.preventDefault)) { 3873 originalEvent.preventDefault(); 3874 } 3875 }; 3876 event.stopPropagation = () => { 3877 event.cancelBubble = true; 3878 event.isPropagationStopped = always; 3879 if (isFunction(originalEvent.stopPropagation)) { 3880 originalEvent.stopPropagation(); 3881 } 3882 }; 3883 event.stopImmediatePropagation = () => { 3884 event.isImmediatePropagationStopped = always; 3885 event.stopPropagation(); 3886 }; 3887 if (!hasIsDefaultPrevented(event)) { 3888 event.isDefaultPrevented = event.defaultPrevented === true ? always : never; 3889 event.isPropagationStopped = event.cancelBubble === true ? always : never; 3890 event.isImmediatePropagationStopped = never; 3891 } 3892 } 3893 return event; 3894 }; 3895 3896 const eventExpandoPrefix = 'mce-data-'; 3897 const mouseEventRe = /^(?:mouse|contextmenu)|click/; 3898 const addEvent = (target, name, callback, capture) => { 3899 target.addEventListener(name, callback, capture || false); 3900 }; 3901 const removeEvent = (target, name, callback, capture) => { 3902 target.removeEventListener(name, callback, capture || false); 3903 }; 3904 const isMouseEvent = event => isNonNullable(event) && mouseEventRe.test(event.type); 3905 const fix = (originalEvent, data) => { 3906 const event = normalize$3(originalEvent.type, originalEvent, document, data); 3907 if (isMouseEvent(originalEvent) && isUndefined(originalEvent.pageX) && !isUndefined(originalEvent.clientX)) { 3908 const eventDoc = event.target.ownerDocument || document; 3909 const doc = eventDoc.documentElement; 3910 const body = eventDoc.body; 3911 const mouseEvent = event; 3912 mouseEvent.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); 3913 mouseEvent.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); 3914 } 3915 return event; 3916 }; 3917 const bindOnReady = (win, callback, eventUtils) => { 3918 const doc = win.document, event = { type: 'ready' }; 3919 if (eventUtils.domLoaded) { 3920 callback(event); 3921 return; 3922 } 3923 const isDocReady = () => { 3924 return doc.readyState === 'complete' || doc.readyState === 'interactive' && doc.body; 3925 }; 3926 const readyHandler = () => { 3927 removeEvent(win, 'DOMContentLoaded', readyHandler); 3928 removeEvent(win, 'load', readyHandler); 3929 if (!eventUtils.domLoaded) { 3930 eventUtils.domLoaded = true; 3931 callback(event); 3932 } 3933 win = null; 3934 }; 3935 if (isDocReady()) { 3936 readyHandler(); 3937 } else { 3938 addEvent(win, 'DOMContentLoaded', readyHandler); 3939 } 3940 if (!eventUtils.domLoaded) { 3941 addEvent(win, 'load', readyHandler); 3942 } 3943 }; 3944 class EventUtils { 3945 constructor() { 3946 this.domLoaded = false; 3947 this.events = {}; 3948 this.count = 1; 3949 this.expando = eventExpandoPrefix + (+new Date()).toString(32); 3950 this.hasFocusIn = 'onfocusin' in document.documentElement; 3951 this.count = 1; 3952 } 3953 bind(target, names, callback, scope) { 3954 const self = this; 3955 let callbackList; 3956 const win = window; 3957 const defaultNativeHandler = evt => { 3958 self.executeHandlers(fix(evt || win.event), id); 3959 }; 3960 if (!target || isText$b(target) || isComment(target)) { 3961 return callback; 3962 } 3963 let id; 3964 if (!target[self.expando]) { 3965 id = self.count++; 3966 target[self.expando] = id; 3967 self.events[id] = {}; 3968 } else { 3969 id = target[self.expando]; 3970 } 3971 scope = scope || target; 3972 const namesList = names.split(' '); 3973 let i = namesList.length; 3974 while (i--) { 3975 let name = namesList[i]; 3976 let nativeHandler = defaultNativeHandler; 3977 let capture = false; 3978 let fakeName = false; 3979 if (name === 'DOMContentLoaded') { 3980 name = 'ready'; 3981 } 3982 if (self.domLoaded && name === 'ready' && target.readyState === 'complete') { 3983 callback.call(scope, fix({ type: name })); 3984 continue; 3985 } 3986 if (!self.hasFocusIn && (name === 'focusin' || name === 'focusout')) { 3987 capture = true; 3988 fakeName = name === 'focusin' ? 'focus' : 'blur'; 3989 nativeHandler = evt => { 3990 const event = fix(evt || win.event); 3991 event.type = event.type === 'focus' ? 'focusin' : 'focusout'; 3992 self.executeHandlers(event, id); 3993 }; 3994 } 3995 callbackList = self.events[id][name]; 3996 if (!callbackList) { 3997 self.events[id][name] = callbackList = [{ 3998 func: callback, 3999 scope 4000 }]; 4001 callbackList.fakeName = fakeName; 4002 callbackList.capture = capture; 4003 callbackList.nativeHandler = nativeHandler; 4004 if (name === 'ready') { 4005 bindOnReady(target, nativeHandler, self); 4006 } else { 4007 addEvent(target, fakeName || name, nativeHandler, capture); 4008 } 4009 } else { 4010 if (name === 'ready' && self.domLoaded) { 4011 callback(fix({ type: name })); 4012 } else { 4013 callbackList.push({ 4014 func: callback, 4015 scope 4016 }); 4017 } 4018 } 4019 } 4020 target = callbackList = null; 4021 return callback; 4022 } 4023 unbind(target, names, callback) { 4024 if (!target || isText$b(target) || isComment(target)) { 4025 return this; 4026 } 4027 const id = target[this.expando]; 4028 if (id) { 4029 let eventMap = this.events[id]; 4030 if (names) { 4031 const namesList = names.split(' '); 4032 let i = namesList.length; 4033 while (i--) { 4034 const name = namesList[i]; 4035 const callbackList = eventMap[name]; 4036 if (callbackList) { 4037 if (callback) { 4038 let ci = callbackList.length; 4039 while (ci--) { 4040 if (callbackList[ci].func === callback) { 4041 const nativeHandler = callbackList.nativeHandler; 4042 const fakeName = callbackList.fakeName, capture = callbackList.capture; 4043 const newCallbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1)); 4044 newCallbackList.nativeHandler = nativeHandler; 4045 newCallbackList.fakeName = fakeName; 4046 newCallbackList.capture = capture; 4047 eventMap[name] = newCallbackList; 4048 } 4049 } 4050 } 4051 if (!callback || callbackList.length === 0) { 4052 delete eventMap[name]; 4053 removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture); 4054 } 4055 } 4056 } 4057 } else { 4058 each$d(eventMap, (callbackList, name) => { 4059 removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture); 4060 }); 4061 eventMap = {}; 4062 } 4063 for (const name in eventMap) { 4064 if (has$2(eventMap, name)) { 4065 return this; 4066 } 4067 } 4068 delete this.events[id]; 4069 try { 4070 delete target[this.expando]; 4071 } catch (_
vendor: 6,220 bytes, lines 4071-4252
4071a) { 4072 target[this.expando] = null; 4073 } 4074 } 4075 return this; 4076 } 4077 fire(target, name, args) { 4078 return this.dispatch(target, name, args); 4079 } 4080 dispatch(target, name, args) { 4081 if (!target || isText$b(target) || isComment(target)) { 4082 return this; 4083 } 4084 const event = fix({ 4085 type: name, 4086 target 4087 }, args); 4088 do { 4089 const id = target[this.expando]; 4090 if (id) { 4091 this.executeHandlers(event, id); 4092 } 4093 target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow; 4094 } while (target && !event.isPropagationStopped()); 4095 return this; 4096 } 4097 clean(target) { 4098 if (!target || isText$b(target) || isComment(target)) { 4099 return this; 4100 } 4101 if (target[this.expando]) { 4102 this.unbind(target); 4103 } 4104 if (!target.getElementsByTagName) { 4105 target = target.document; 4106 } 4107 if (target && target.getElementsByTagName) { 4108 this.unbind(target); 4109 const children = target.getElementsByTagName('*'); 4110 let i = children.length; 4111 while (i--) { 4112 target = children[i]; 4113 if (target[this.expando]) { 4114 this.unbind(target); 4115 } 4116 } 4117 } 4118 return this; 4119 } 4120 destroy() { 4121 this.events = {}; 4122 } 4123 cancel(e) { 4124 if (e) { 4125 e.preventDefault(); 4126 e.stopImmediatePropagation(); 4127 } 4128 return false; 4129 } 4130 executeHandlers(evt, id) { 4131 const container = this.events[id]; 4132 const callbackList = container && container[evt.type]; 4133 if (callbackList) { 4134 for (let i = 0, l = callbackList.length; i < l; i++) { 4135 const callback = callbackList[i]; 4136 if (callback && callback.func.call(callback.scope, evt) === false) { 4137 evt.preventDefault(); 4138 } 4139 if (evt.isImmediatePropagationStopped()) { 4140 return; 4141 } 4142 } 4143 } 4144 } 4145 } 4146 EventUtils.Event = new EventUtils(); 4147 4148 const each$a = Tools.each; 4149 const grep = Tools.grep; 4150 const internalStyleName = 'data-mce-style'; 4151 const numericalCssMap = Tools.makeMap('fill-opacity font-weight line-height opacity orphans widows z-index zoom', ' '); 4152 const legacySetAttribute = (elm, name, value) => { 4153 if (isNullable(value) || value === '') { 4154 remove$9(elm, name); 4155 } else { 4156 set$4(elm, name, value); 4157 } 4158 }; 4159 const camelCaseToHyphens = name => name.replace(/[A-Z]/g, v => '-' + v.toLowerCase()); 4160 const findNodeIndex = (node, normalized) => { 4161 let idx = 0; 4162 if (node) { 4163 for (let lastNodeType = node.nodeType, tempNode = node.previousSibling; tempNode; tempNode = tempNode.previousSibling) { 4164 const nodeType = tempNode.nodeType; 4165 if (normalized && isText$b(tempNode)) { 4166 if (nodeType === lastNodeType || !tempNode.data.length) { 4167 continue; 4168 } 4169 } 4170 idx++; 4171 lastNodeType = nodeType; 4172 } 4173 } 4174 return idx; 4175 }; 4176 const updateInternalStyleAttr = (styles, elm) => { 4177 const rawValue = get$9(elm, 'style'); 4178 const value = styles.serialize(styles.parse(rawValue), name(elm)); 4179 legacySetAttribute(elm, internalStyleName, value); 4180 }; 4181 const convertStyleToString = (cssValue, cssName) => { 4182 if (isNumber(cssValue)) { 4183 return has$2(numericalCssMap, cssName) ? cssValue + '' : cssValue + 'px'; 4184 } else { 4185 return cssValue; 4186 } 4187 }; 4188 const applyStyle$1 = ($elm, cssName, cssValue) => { 4189 const normalizedName = camelCaseToHyphens(cssName); 4190 if (isNullable(cssValue) || cssValue === '') { 4191 remove$5($elm, normalizedName); 4192 } else { 4193 set$2($elm, normalizedName, convertStyleToString(cssValue, normalizedName)); 4194 } 4195 }; 4196 const setupAttrHooks = (styles, settings, getContext) => { 4197 const keepValues = settings.keep_values; 4198 const keepUrlHook = { 4199 set: (elm, value, name) => { 4200 const sugarElm = SugarElement.fromDom(elm); 4201 if (isFunction(settings.url_converter) && isNonNullable(value)) { 4202 value = settings.url_converter.call(settings.url_converter_scope || getContext(), String(value), name, elm); 4203 } 4204 const internalName = 'data-mce-' + name; 4205 legacySetAttribute(sugarElm, internalName, value); 4206 legacySetAttribute(sugarElm, name, value); 4207 }, 4208 get: (elm, name) => { 4209 const sugarElm = SugarElement.fromDom(elm); 4210 return get$9(sugarElm, 'data-mce-' + name) || get$9(sugarElm, name); 4211 } 4212 }; 4213 const attrHooks = { 4214 style: { 4215 set: (elm, value) => { 4216 const sugarElm = SugarElement.fromDom(elm); 4217 if (keepValues) { 4218 legacySetAttribute(sugarElm, internalStyleName, value); 4219 } 4220 remove$9(sugarElm, 'style'); 4221 if (isString(value)) { 4222 setAll(sugarElm, styles.parse(value)); 4223 } 4224 }, 4225 get: elm => { 4226 const sugarElm = SugarElement.fromDom(elm); 4227 const value = get$9(sugarElm, internalStyleName) || get$9(sugarElm, 'style'); 4228 return styles.serialize(styles.parse(value), name(sugarElm)); 4229 } 4230 } 4231 }; 4232 if (keepValues) { 4233 attrHooks.href = attrHooks.src = keepUrlHook; 4234 } 4235 return attrHooks; 4236 }; 4237 const DOMUtils = (doc, settings = {}) => { 4238 const addedStyles = {}; 4239 const win = window; 4240 const files = {}; 4241 let counter = 0; 4242 const stdMode = true; 4243 const boxModel = true; 4244 const styleSheetLoader = instance.forElement(SugarElement.fromDom(doc), { 4245 contentCssCors: settings.contentCssCors, 4246 referrerPolicy: settings.referrerPolicy 4247 }); 4248 const boundEvents = []; 4249 const schema = settings.schema ? settings.schema : Schema({}); 4250 const styles = Styles({ 4251 url_converter: settings.url_converter, 4252 url_converter_scope: settings.url_converter_scope
vendor: 26,072 bytes, lines 4252-5055
4252 4253 }, settings.schema); 4254 const events = settings.ownEvents ? new EventUtils() : EventUtils.Event; 4255 const blockElementsMap = schema.getBlockElements(); 4256 const isBlock = node => { 4257 if (isString(node)) { 4258 return has$2(blockElementsMap, node); 4259 } else { 4260 return isElement$6(node) && (has$2(blockElementsMap, node.nodeName) || isTransparentBlock(schema, node)); 4261 } 4262 }; 4263 const get = elm => elm && doc && isString(elm) ? doc.getElementById(elm) : elm; 4264 const _get = elm => { 4265 const value = get(elm); 4266 return isNonNullable(value) ? SugarElement.fromDom(value) : null; 4267 }; 4268 const getAttrib = (elm, name, defaultVal = '') => { 4269 let value; 4270 const $elm = _get(elm); 4271 if (isNonNullable($elm) && isElement$7($elm)) { 4272 const hook = attrHooks[name]; 4273 if (hook && hook.get) { 4274 value = hook.get($elm.dom, name); 4275 } else { 4276 value = get$9($elm, name); 4277 } 4278 } 4279 return isNonNullable(value) ? value : defaultVal; 4280 }; 4281 const getAttribs = elm => { 4282 const node = get(elm); 4283 return isNullable(node) ? [] : node.attributes; 4284 }; 4285 const setAttrib = (elm, name, value) => { 4286 run(elm, e => { 4287 if (isElement$6(e)) { 4288 const $elm = SugarElement.fromDom(e); 4289 const val = value === '' ? null : value; 4290 const originalValue = get$9($elm, name); 4291 const hook = attrHooks[name]; 4292 if (hook && hook.set) { 4293 hook.set($elm.dom, val, name); 4294 } else { 4295 legacySetAttribute($elm, name, val); 4296 } 4297 if (originalValue !== val && settings.onSetAttrib) { 4298 settings.onSetAttrib({ 4299 attrElm: $elm.dom, 4300 attrName: name, 4301 attrValue: val 4302 }); 4303 } 4304 } 4305 }); 4306 }; 4307 const clone = (node, deep) => { 4308 return node.cloneNode(deep); 4309 }; 4310 const getRoot = () => settings.root_element || doc.body; 4311 const getViewPort = argWin => { 4312 const vp = getBounds(argWin); 4313 return { 4314 x: vp.x, 4315 y: vp.y, 4316 w: vp.width, 4317 h: vp.height 4318 }; 4319 }; 4320 const getPos$1 = (elm, rootElm) => getPos(doc.body, get(elm), rootElm); 4321 const setStyle = (elm, name, value) => { 4322 run(elm, e => { 4323 const $elm = SugarElement.fromDom(e); 4324 applyStyle$1($elm, name, value); 4325 if (settings.update_styles) { 4326 updateInternalStyleAttr(styles, $elm); 4327 } 4328 }); 4329 }; 4330 const setStyles = (elm, stylesArg) => { 4331 run(elm, e => { 4332 const $elm = SugarElement.fromDom(e); 4333 each$d(stylesArg, (v, n) => { 4334 applyStyle$1($elm, n, v); 4335 }); 4336 if (settings.update_styles) { 4337 updateInternalStyleAttr(styles, $elm); 4338 } 4339 }); 4340 }; 4341 const getStyle = (elm, name, computed) => { 4342 const $elm = get(elm); 4343 if (isNullable($elm) || !isHTMLElement($elm) && !isSVGElement($elm)) { 4344 return undefined; 4345 } 4346 if (computed) { 4347 return get$7(SugarElement.fromDom($elm), camelCaseToHyphens(name)); 4348 } else { 4349 name = name.replace(/-(\D)/g, (a, b) => b.toUpperCase()); 4350 if (name === 'float') { 4351 name = 'cssFloat'; 4352 } 4353 return $elm.style ? $elm.style[name] : undefined; 4354 } 4355 }; 4356 const getSize = elm => { 4357 const $elm = get(elm); 4358 if (!$elm) { 4359 return { 4360 w: 0, 4361 h: 0 4362 }; 4363 } 4364 let w = getStyle($elm, 'width'); 4365 let h = getStyle($elm, 'height'); 4366 if (!w || w.indexOf('px') === -1) { 4367 w = '0'; 4368 } 4369 if (!h || h.indexOf('px') === -1) { 4370 h = '0'; 4371 } 4372 return { 4373 w: parseInt(w, 10) || $elm.offsetWidth || $elm.clientWidth, 4374 h: parseInt(h, 10) || $elm.offsetHeight || $elm.clientHeight 4375 }; 4376 }; 4377 const getRect = elm => { 4378 const $elm = get(elm); 4379 const pos = getPos$1($elm); 4380 const size = getSize($elm); 4381 return { 4382 x: pos.x, 4383 y: pos.y, 4384 w: size.w, 4385 h: size.h 4386 }; 4387 }; 4388 const is = (elm, selector) => { 4389 if (!elm) { 4390 return false; 4391 } 4392 const elms = isArray$1(elm) ? elm : [elm]; 4393 return exists(elms, e => { 4394 return is$1(SugarElement.fromDom(e), selector); 4395 }); 4396 }; 4397 const getParents = (elm, selector, root, collect) => { 4398 const result = []; 4399 let node = get(elm); 4400 collect = collect === undefined; 4401 const resolvedRoot = root || (getRoot().nodeName !== 'BODY' ? getRoot().parentNode : null); 4402 if (isString(selector)) { 4403 if (selector === '*') { 4404 selector = isElement$6; 4405 } else { 4406 const selectorVal = selector; 4407 selector = node => is(node, selectorVal); 4408 } 4409 } 4410 while (node) { 4411 if (node === resolvedRoot || isNullable(node.nodeType) || isDocument$1(node) || isDocumentFragment(node)) { 4412 break; 4413 } 4414 if (!selector || selector(node)) { 4415 if (collect) { 4416 result.push(node); 4417 } else { 4418 return [node]; 4419 } 4420 } 4421 node = node.parentNode; 4422 } 4423 return collect ? result : null; 4424 }; 4425 const getParent = (node, selector, root) => { 4426 const parents = getParents(node, selector, root, false); 4427 return parents && parents.length > 0 ? parents[0] : null; 4428 }; 4429 const _findSib = (node, selector, name) => { 4430 let func = selector; 4431 if (node) { 4432 if (isString(selector)) { 4433 func = node => { 4434 return is(node, selector); 4435 }; 4436 } 4437 for (let tempNode = node[name]; tempNode; tempNode = tempNode[name]) { 4438 if (isFunction(func) && func(tempNode)) { 4439 return tempNode; 4440 } 4441 } 4442 } 4443 return null; 4444 }; 4445 const getNext = (node, selector) => _findSib(node, selector, 'nextSibling'); 4446 const getPrev = (node, selector) => _findSib(node, selector, 'previousSibling'); 4447 const isParentNode = node => isFunction(node.querySelectorAll); 4448 const select = (selector, scope) => { 4449 var _a, _b; 4450 const elm = (_b = (_a = get(scope)) !== null && _a !== void 0 ? _a : settings.root_element) !== null && _b !== void 0 ? _b : doc; 4451 return isParentNode(elm) ? from(elm.querySelectorAll(selector)) : []; 4452 }; 4453 const run = function (elm, func, scope) { 4454 const context = scope !== null && scope !== void 0 ? scope : this; 4455 if (isArray$1(elm)) { 4456 const result = []; 4457 each$a(elm, (e, i) => { 4458 const node = get(e); 4459 if (node) { 4460 result.push(func.call(context, node, i)); 4461 } 4462 }); 4463 return result; 4464 } else { 4465 const node = get(elm); 4466 return !node ? false : func.call(context, node); 4467 } 4468 }; 4469 const setAttribs = (elm, attrs) => { 4470 run(elm, $elm => { 4471 each$d(attrs, (value, name) => { 4472 setAttrib($elm, name, value); 4473 }); 4474 }); 4475 }; 4476 const setHTML = (elm, html) => { 4477 run(elm, e => { 4478 const $elm = SugarElement.fromDom(e); 4479 set$1($elm, html); 4480 }); 4481 }; 4482 const add = (parentElm, name, attrs, html, create) => run(parentElm, parentElm => { 4483 const newElm = isString(name) ? doc.createElement(name) : name; 4484 if (isNonNullable(attrs)) { 4485 setAttribs(newElm, attrs); 4486 } 4487 if (html) { 4488 if (!isString(html) && html.nodeType) { 4489 newElm.appendChild(html); 4490 } else if (isString(html)) { 4491 setHTML(newElm, html); 4492 } 4493 } 4494 return !create ? parentElm.appendChild(newElm) : newElm; 4495 }); 4496 const create = (name, attrs, html) => add(doc.createElement(name), name, attrs, html, true); 4497 const decode = Entities.decode; 4498 const encode = Entities.encodeAllRaw; 4499 const createHTML = (name, attrs, html = '') => { 4500 let outHtml = '<' + name; 4501 for (const key in attrs) { 4502 if (hasNonNullableKey(attrs, key)) { 4503 outHtml += ' ' + key + '="' + encode(attrs[key]) + '"'; 4504 } 4505 } 4506 if (isEmpty$3(html) && has$2(schema.getVoidElements(), name)) { 4507 return outHtml + ' />'; 4508 } else { 4509 return outHtml + '>' + html + '</' + name + '>'; 4510 } 4511 }; 4512 const createFragment = html => { 4513 const container = doc.createElement('div'); 4514 const frag = doc.createDocumentFragment(); 4515 frag.appendChild(container); 4516 if (html) { 4517 container.innerHTML = html; 4518 } 4519 let node; 4520 while (node = container.firstChild) { 4521 frag.appendChild(node); 4522 } 4523 frag.removeChild(container); 4524 return frag; 4525 }; 4526 const remove = (node, keepChildren) => { 4527 return run(node, n => { 4528 const $node = SugarElement.fromDom(n); 4529 if (keepChildren) { 4530 each$e(children$1($node), child => { 4531 if (isText$c(child) && child.dom.length === 0) { 4532 remove$4(child); 4533 } else { 4534 before$3($node, child); 4535 } 4536 }); 4537 } 4538 remove$4($node); 4539 return $node.dom; 4540 }); 4541 }; 4542 const removeAllAttribs = e => run(e, e => { 4543 const attrs = e.attributes; 4544 for (let i = attrs.length - 1; i >= 0; i--) { 4545 e.removeAttributeNode(attrs.item(i)); 4546 } 4547 }); 4548 const parseStyle = cssText => styles.parse(cssText); 4549 const serializeStyle = (stylesArg, name) => styles.serialize(stylesArg, name); 4550 const addStyle = cssText => { 4551 if (self !== DOMUtils.DOM && doc === document) { 4552 if (addedStyles[cssText]) { 4553 return; 4554 } 4555 addedStyles[cssText] = true; 4556 } 4557 let styleElm = doc.getElementById('mceDefaultStyles'); 4558 if (!styleElm) { 4559 styleElm = doc.createElement('style'); 4560 styleElm.id = 'mceDefaultStyles'; 4561 styleElm.type = 'text/css'; 4562 const head = doc.head; 4563 if (head.firstChild) { 4564 head.insertBefore(styleElm, head.firstChild); 4565 } else { 4566 head.appendChild(styleElm); 4567 } 4568 } 4569 if (styleElm.styleSheet) { 4570 styleElm.styleSheet.cssText += cssText; 4571 } else { 4572 styleElm.appendChild(doc.createTextNode(cssText)); 4573 } 4574 }; 4575 const loadCSS = urls => { 4576 if (!urls) { 4577 urls = ''; 4578 } 4579 each$e(urls.split(','), url => { 4580 files[url] = true; 4581 styleSheetLoader.load(url).catch(noop); 4582 }); 4583 }; 4584 const toggleClass = (elm, cls, state) => { 4585 run(elm, e => { 4586 if (isElement$6(e)) { 4587 const $elm = SugarElement.fromDom(e); 4588 const classes = cls.split(' '); 4589 each$e(classes, c => { 4590 if (isNonNullable(state)) { 4591 const fn = state ? add$2 : remove$6; 4592 fn($elm, c); 4593 } else { 4594 toggle$1($elm, c); 4595 } 4596 }); 4597 } 4598 }); 4599 }; 4600 const addClass = (elm, cls) => { 4601 toggleClass(elm, cls, true); 4602 }; 4603 const removeClass = (elm, cls) => { 4604 toggleClass(elm, cls, false); 4605 }; 4606 const hasClass = (elm, cls) => { 4607 const $elm = _get(elm); 4608 const classes = cls.split(' '); 4609 return isNonNullable($elm) && forall(classes, c => has($elm, c)); 4610 }; 4611 const show = elm => { 4612 run(elm, e => remove$5(SugarElement.fromDom(e), 'display')); 4613 }; 4614 const hide = elm => { 4615 run(elm, e => set$2(SugarElement.fromDom(e), 'display', 'none')); 4616 }; 4617 const isHidden = elm => { 4618 const $elm = _get(elm); 4619 return isNonNullable($elm) && is$2(getRaw($elm, 'display'), 'none'); 4620 }; 4621 const uniqueId = prefix => (!prefix ? 'mce_' : prefix) + counter++; 4622 const getOuterHTML = elm => { 4623 const $elm = _get(elm); 4624 if (isNonNullable($elm)) { 4625 return isElement$6($elm.dom) ? $elm.dom.outerHTML : getOuter($elm); 4626 } else { 4627 return ''; 4628 } 4629 }; 4630 const setOuterHTML = (elm, html) => { 4631 run(elm, $elm => { 4632 if (isElement$6($elm)) { 4633 $elm.outerHTML = html; 4634 } 4635 }); 4636 }; 4637 const insertAfter = (node, reference) => { 4638 const referenceNode = get(reference); 4639 return run(node, node => { 4640 const parent = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.parentNode; 4641 const nextSibling = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.nextSibling; 4642 if (parent) { 4643 if (nextSibling) { 4644 parent.insertBefore(node, nextSibling); 4645 } else { 4646 parent.appendChild(node); 4647 } 4648 } 4649 return node; 4650 }); 4651 }; 4652 const replace = (newElm, oldElm, keepChildren) => run(oldElm, elm => { 4653 var _a; 4654 const replacee = isArray$1(oldElm) ? newElm.cloneNode(true) : newElm; 4655 if (keepChildren) { 4656 each$a(grep(elm.childNodes), node => { 4657 replacee.appendChild(node); 4658 }); 4659 } 4660 (_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(replacee, elm); 4661 return elm; 4662 }); 4663 const rename = (elm, name) => { 4664 if (elm.nodeName !== name.toUpperCase()) { 4665 const newElm = create(name); 4666 each$a(getAttribs(elm), attrNode => { 4667 setAttrib(newElm, attrNode.nodeName, getAttrib(elm, attrNode.nodeName)); 4668 }); 4669 replace(newElm, elm, true); 4670 return newElm; 4671 } else { 4672 return elm; 4673 } 4674 }; 4675 const findCommonAncestor = (a, b) => { 4676 let ps = a; 4677 while (ps) { 4678 let pe = b; 4679 while (pe && ps !== pe) { 4680 pe = pe.parentNode; 4681 } 4682 if (ps === pe) { 4683 break; 4684 } 4685 ps = ps.parentNode; 4686 } 4687 if (!ps && a.ownerDocument) { 4688 return a.ownerDocument.documentElement; 4689 } else { 4690 return ps; 4691 } 4692 }; 4693 const isEmpty = (node, elements, options) => { 4694 if (isPlainObject(elements)) { 4695 const isContent = node => { 4696 const name = node.nodeName.toLowerCase(); 4697 return Boolean(elements[name]); 4698 }; 4699 return isEmptyNode(schema, node, { 4700 ...options, 4701 isContent 4702 }); 4703 } else { 4704 return isEmptyNode(schema, node, options); 4705 } 4706 }; 4707 const createRng = () => doc.createRange(); 4708 const split = (parentElm, splitElm, replacementElm) => { 4709 let range = createRng(); 4710 let beforeFragment; 4711 let afterFragment; 4712 if (parentElm && splitElm && parentElm.parentNode && splitElm.parentNode) { 4713 const parentNode = parentElm.parentNode; 4714 range.setStart(parentNode, findNodeIndex(parentElm)); 4715 range.setEnd(splitElm.parentNode, findNodeIndex(splitElm)); 4716 beforeFragment = range.extractContents(); 4717 range = createRng(); 4718 range.setStart(splitElm.parentNode, findNodeIndex(splitElm) + 1); 4719 range.setEnd(parentNode, findNodeIndex(parentElm) + 1); 4720 afterFragment = range.extractContents(); 4721 parentNode.insertBefore(trimNode(self, beforeFragment, schema), parentElm); 4722 if (replacementElm) { 4723 parentNode.insertBefore(replacementElm, parentElm); 4724 } else { 4725 parentNode.insertBefore(splitElm, parentElm); 4726 } 4727 parentNode.insertBefore(trimNode(self, afterFragment, schema), parentElm); 4728 remove(parentElm); 4729 return replacementElm || splitElm; 4730 } else { 4731 return undefined; 4732 } 4733 }; 4734 const bind = (target, name, func, scope) => { 4735 if (isArray$1(target)) { 4736 let i = target.length; 4737 const rv = []; 4738 while (i--) { 4739 rv[i] = bind(target[i], name, func, scope); 4740 } 4741 return rv; 4742 } else { 4743 if (settings.collect && (target === doc || target === win)) { 4744 boundEvents.push([ 4745 target, 4746 name, 4747 func, 4748 scope 4749 ]); 4750 } 4751 return events.bind(target, name, func, scope || self); 4752 } 4753 }; 4754 const unbind = (target, name, func) => { 4755 if (isArray$1(target)) { 4756 let i = target.length; 4757 const rv = []; 4758 while (i--) { 4759 rv[i] = unbind(target[i], name, func); 4760 } 4761 return rv; 4762 } else { 4763 if (boundEvents.length > 0 && (target === doc || target === win)) { 4764 let i = boundEvents.length; 4765 while (i--) { 4766 const [boundTarget, boundName, boundFunc] = boundEvents[i]; 4767 if (target === boundTarget && (!name || name === boundName) && (!func || func === boundFunc)) { 4768 events.unbind(boundTarget, boundName, boundFunc); 4769 } 4770 } 4771 } 4772 return events.unbind(target, name, func); 4773 } 4774 }; 4775 const dispatch = (target, name, evt) => events.dispatch(target, name, evt); 4776 const fire = (target, name, evt) => events.dispatch(target, name, evt); 4777 const getContentEditable = node => { 4778 if (node && isHTMLElement(node)) { 4779 const contentEditable = node.getAttribute('data-mce-contenteditable'); 4780 if (contentEditable && contentEditable !== 'inherit') { 4781 return contentEditable; 4782 } 4783 return node.contentEditable !== 'inherit' ? node.contentEditable : null; 4784 } else { 4785 return null; 4786 } 4787 }; 4788 const getContentEditableParent = node => { 4789 const root = getRoot(); 4790 let state = null; 4791 for (let tempNode = node; tempNode && tempNode !== root; tempNode = tempNode.parentNode) { 4792 state = getContentEditable(tempNode); 4793 if (state !== null) { 4794 break; 4795 } 4796 } 4797 return state; 4798 }; 4799 const isEditable = node => { 4800 if (isNonNullable(node)) { 4801 const scope = isElement$6(node) ? node : node.parentElement; 4802 return isNonNullable(scope) && isHTMLElement(scope) && isEditable$2(SugarElement.fromDom(scope)); 4803 } else { 4804 return false; 4805 } 4806 }; 4807 const destroy = () => { 4808 if (boundEvents.length > 0) { 4809 let i = boundEvents.length; 4810 while (i--) { 4811 const [boundTarget, boundName, boundFunc] = boundEvents[i]; 4812 events.unbind(boundTarget, boundName, boundFunc); 4813 } 4814 } 4815 each$d(files, (_, url) => { 4816 styleSheetLoader.unload(url); 4817 delete files[url]; 4818 }); 4819 }; 4820 const isChildOf = (node, parent) => { 4821 return node === parent || parent.contains(node); 4822 }; 4823 const dumpRng = r => 'startContainer: ' + r.startContainer.nodeName + ', startOffset: ' + r.startOffset + ', endContainer: ' + r.endContainer.nodeName + ', endOffset: ' + r.endOffset; 4824 const self = { 4825 doc, 4826 settings, 4827 win, 4828 files, 4829 stdMode, 4830 boxModel, 4831 styleSheetLoader, 4832 boundEvents, 4833 styles, 4834 schema, 4835 events, 4836 isBlock: isBlock, 4837 root: null, 4838 clone, 4839 getRoot, 4840 getViewPort, 4841 getRect, 4842 getSize, 4843 getParent, 4844 getParents: getParents, 4845 get, 4846 getNext, 4847 getPrev, 4848 select, 4849 is, 4850 add, 4851 create, 4852 createHTML, 4853 createFragment, 4854 remove, 4855 setStyle, 4856 getStyle: getStyle, 4857 setStyles, 4858 removeAllAttribs, 4859 setAttrib, 4860 setAttribs, 4861 getAttrib, 4862 getPos: getPos$1, 4863 parseStyle, 4864 serializeStyle, 4865 addStyle, 4866 loadCSS, 4867 addClass, 4868 removeClass, 4869 hasClass, 4870 toggleClass, 4871 show, 4872 hide, 4873 isHidden, 4874 uniqueId, 4875 setHTML, 4876 getOuterHTML, 4877 setOuterHTML, 4878 decode, 4879 encode, 4880 insertAfter, 4881 replace, 4882 rename, 4883 findCommonAncestor, 4884 run, 4885 getAttribs, 4886 isEmpty, 4887 createRng, 4888 nodeIndex: findNodeIndex, 4889 split, 4890 bind: bind, 4891 unbind: unbind, 4892 fire, 4893 dispatch, 4894 getContentEditable, 4895 getContentEditableParent, 4896 isEditable, 4897 destroy, 4898 isChildOf, 4899 dumpRng 4900 }; 4901 const attrHooks = setupAttrHooks(styles, settings, constant(self)); 4902 return self; 4903 }; 4904 DOMUtils.DOM = DOMUtils(document); 4905 DOMUtils.nodeIndex = findNodeIndex; 4906 4907 const DOM$b = DOMUtils.DOM; 4908 const QUEUED = 0; 4909 const LOADING = 1; 4910 const LOADED = 2; 4911 const FAILED = 3; 4912 class ScriptLoader { 4913 constructor(settings = {}) { 4914 this.states = {}; 4915 this.queue = []; 4916 this.scriptLoadedCallbacks = {}; 4917 this.queueLoadedCallbacks = []; 4918 this.loading = false; 4919 this.settings = settings; 4920 } 4921 _setReferrerPolicy(referrerPolicy) { 4922 this.settings.referrerPolicy = referrerPolicy; 4923 } 4924 loadScript(url) { 4925 return new Promise((resolve, reject) => { 4926 const dom = DOM$b; 4927 let elm; 4928 const cleanup = () => { 4929 dom.remove(id); 4930 if (elm) { 4931 elm.onerror = elm.onload = elm = null; 4932 } 4933 }; 4934 const done = () => { 4935 cleanup(); 4936 resolve(); 4937 }; 4938 const error = () => { 4939 cleanup(); 4940 reject('Failed to load script: ' + url); 4941 }; 4942 const id = dom.uniqueId(); 4943 elm = document.createElement('script'); 4944 elm.id = id; 4945 elm.type = 'text/javascript'; 4946 elm.src = Tools._addCacheSuffix(url); 4947 if (this.settings.referrerPolicy) { 4948 dom.setAttrib(elm, 'referrerpolicy', this.settings.referrerPolicy); 4949 } 4950 elm.onload = done; 4951 elm.onerror = error; 4952 (document.getElementsByTagName('head')[0] || document.body).appendChild(elm); 4953 }); 4954 } 4955 isDone(url) { 4956 return this.states[url] === LOADED; 4957 } 4958 markDone(url) { 4959 this.states[url] = LOADED; 4960 } 4961 add(url) { 4962 const self = this; 4963 self.queue.push(url); 4964 const state = self.states[url]; 4965 if (state === undefined) { 4966 self.states[url] = QUEUED; 4967 } 4968 return new Promise((resolve, reject) => { 4969 if (!self.scriptLoadedCallbacks[url]) { 4970 self.scriptLoadedCallbacks[url] = []; 4971 } 4972 self.scriptLoadedCallbacks[url].push({ 4973 resolve, 4974 reject 4975 }); 4976 }); 4977 } 4978 load(url) { 4979 return this.add(url); 4980 } 4981 remove(url) { 4982 delete this.states[url]; 4983 delete this.scriptLoadedCallbacks[url]; 4984 } 4985 loadQueue() { 4986 const queue = this.queue; 4987 this.queue = []; 4988 return this.loadScripts(queue); 4989 } 4990 loadScripts(scripts) { 4991 const self = this; 4992 const execCallbacks = (name, url) => { 4993 get$a(self.scriptLoadedCallbacks, url).each(callbacks => { 4994 each$e(callbacks, callback => callback[name](url)); 4995 }); 4996 delete self.scriptLoadedCallbacks[url]; 4997 }; 4998 const processResults = results => { 4999 const failures = filter$5(results, result => result.status === 'rejected'); 5000 if (failures.length > 0) { 5001 return Promise.reject(bind$3(failures, ({reason}) => isArray$1(reason) ? reason : [reason])); 5002 } else { 5003 return Promise.resolve(); 5004 } 5005 }; 5006 const load = urls => Promise.allSettled(map$3(urls, url => { 5007 if (self.states[url] === LOADED) { 5008 execCallbacks('resolve', url); 5009 return Promise.resolve(); 5010 } else if (self.states[url] === FAILED) { 5011 execCallbacks('reject', url); 5012 return Promise.reject(url); 5013 } else { 5014 self.states[url] = LOADING; 5015 return self.loadScript(url).then(() => { 5016 self.states[url] = LOADED; 5017 execCallbacks('resolve', url); 5018 const queue = self.queue; 5019 if (queue.length > 0) { 5020 self.queue = []; 5021 return load(queue).then(processResults); 5022 } else { 5023 return Promise.resolve(); 5024 } 5025 }, () => { 5026 self.states[url] = FAILED; 5027 execCallbacks('reject', url); 5028 return Promise.reject(url); 5029 }); 5030 } 5031 })); 5032 const processQueue = urls => { 5033 self.loading = true; 5034 return load(urls).then(results => { 5035 self.loading = false; 5036 const nextQueuedItem = self.queueLoadedCallbacks.shift(); 5037 Optional.from(nextQueuedItem).each(call); 5038 return processResults(results); 5039 }); 5040 }; 5041 const uniqueScripts = stringArray(scripts); 5042 if (self.loading) { 5043 return new Promise((resolve, reject) => { 5044 self.queueLoadedCallbacks.push(() => { 5045 processQueue(uniqueScripts).then(resolve, reject); 5046 }); 5047 }); 5048 } else { 5049 return processQueue(uniqueScripts); 5050 } 5051 } 5052 } 5053 ScriptLoader.ScriptLoader = new ScriptLoader(); 5054 5055 const
vendor: 1,774 bytes, lines 5055-5100
5055isDuplicated = (items, item) => { 5056 const firstIndex = items.indexOf(item); 5057 return firstIndex !== -1 && items.indexOf(item, firstIndex + 1) > firstIndex; 5058 }; 5059 const isRaw = str => isObject(str) && has$2(str, 'raw'); 5060 const isTokenised = str => isArray$1(str) && str.length > 1; 5061 const data = {}; 5062 const currentCode = Cell('en'); 5063 const getLanguageData = () => get$a(data, currentCode.get()); 5064 const getData$1 = () => map$2(data, value => ({ ...value })); 5065 const setCode = newCode => { 5066 if (newCode) { 5067 currentCode.set(newCode); 5068 } 5069 }; 5070 const getCode = () => currentCode.get(); 5071 const add$1 = (code, items) => { 5072 let langData = data[code]; 5073 if (!langData) { 5074 data[code] = langData = {}; 5075 } 5076 const lcNames = map$3(keys(items), name => name.toLowerCase()); 5077 each$d(items, (translation, name) => { 5078 const lcName = name.toLowerCase(); 5079 if (lcName !== name && isDuplicated(lcNames, lcName)) { 5080 if (!has$2(items, lcName)) { 5081 langData[lcName] = translation; 5082 } 5083 langData[name] = translation; 5084 } else { 5085 langData[lcName] = translation; 5086 } 5087 }); 5088 }; 5089 const translate = text => { 5090 const langData = getLanguageData().getOr({}); 5091 const toString = obj => { 5092 if (isFunction(obj)) { 5093 return Object.prototype.toString.call(obj); 5094 } 5095 return !isEmpty(obj) ? '' + obj : ''; 5096 }; 5097 const isEmpty = text => text === '' || text === null || text === undefined; 5098 const getLangData = text => { 5099 const textStr = toString(text); 5100 return has$2(langData, textStr) ? toString(langData[textStr]) : get$a(langData, textStr.toLowerCase()).map(toString).getOr(textS
vendor: 4,338 bytes, lines 5100-5240
5100tr); 5101 }; 5102 const removeContext = str => str.replace(/{context:\w+}$/, ''); 5103 if (isEmpty(text)) { 5104 return ''; 5105 } 5106 if (isRaw(text)) { 5107 return toString(text.raw); 5108 } 5109 if (isTokenised(text)) { 5110 const values = text.slice(1); 5111 const substitued = getLangData(text[0]).replace(/\{([0-9]+)\}/g, ($1, $2) => has$2(values, $2) ? toString(values[$2]) : $1); 5112 return removeContext(substitued); 5113 } 5114 return removeContext(getLangData(text)); 5115 }; 5116 const isRtl$1 = () => getLanguageData().bind(items => get$a(items, '_dir')).exists(dir => dir === 'rtl'); 5117 const hasCode = code => has$2(data, code); 5118 const I18n = { 5119 getData: getData$1, 5120 setCode, 5121 getCode, 5122 add: add$1, 5123 translate, 5124 isRtl: isRtl$1, 5125 hasCode 5126 }; 5127 5128 const AddOnManager = () => { 5129 const items = []; 5130 const urls = {}; 5131 const lookup = {}; 5132 const _listeners = []; 5133 const runListeners = (name, state) => { 5134 const matchedListeners = filter$5(_listeners, listener => listener.name === name && listener.state === state); 5135 each$e(matchedListeners, listener => listener.resolve()); 5136 }; 5137 const isLoaded = name => has$2(urls, name); 5138 const isAdded = name => has$2(lookup, name); 5139 const get = name => { 5140 if (lookup[name]) { 5141 return lookup[name].instance; 5142 } 5143 return undefined; 5144 }; 5145 const loadLanguagePack = (name, languages) => { 5146 const language = I18n.getCode(); 5147 const wrappedLanguages = ',' + (languages || '') + ','; 5148 if (!language || languages && wrappedLanguages.indexOf(',' + language + ',') === -1) { 5149 return; 5150 } 5151 ScriptLoader.ScriptLoader.add(urls[name] + '/langs/' + language + '.js'); 5152 }; 5153 const requireLangPack = (name, languages) => { 5154 if (AddOnManager.languageLoad !== false) { 5155 if (isLoaded(name)) { 5156 loadLanguagePack(name, languages); 5157 } else { 5158 waitFor(name, 'loaded').then(() => loadLanguagePack(name, languages)); 5159 } 5160 } 5161 }; 5162 const add = (id, addOn) => { 5163 items.push(addOn); 5164 lookup[id] = { instance: addOn }; 5165 runListeners(id, 'added'); 5166 return addOn; 5167 }; 5168 const remove = name => { 5169 delete urls[name]; 5170 delete lookup[name]; 5171 }; 5172 const createUrl = (baseUrl, dep) => { 5173 if (isString(dep)) { 5174 return isString(baseUrl) ? { 5175 prefix: '', 5176 resource: dep, 5177 suffix: '' 5178 } : { 5179 prefix: baseUrl.prefix, 5180 resource: dep, 5181 suffix: baseUrl.suffix 5182 }; 5183 } else { 5184 return dep; 5185 } 5186 }; 5187 const load = (name, addOnUrl) => { 5188 if (urls[name]) { 5189 return Promise.resolve(); 5190 } 5191 let urlString = isString(addOnUrl) ? addOnUrl : addOnUrl.prefix + addOnUrl.resource + addOnUrl.suffix; 5192 if (urlString.indexOf('/') !== 0 && urlString.indexOf('://') === -1) { 5193 urlString = AddOnManager.baseURL + '/' + urlString; 5194 } 5195 urls[name] = urlString.substring(0, urlString.lastIndexOf('/')); 5196 const done = () => { 5197 runListeners(name, 'loaded'); 5198 return Promise.resolve(); 5199 }; 5200 if (lookup[name]) { 5201 return done(); 5202 } else { 5203 return ScriptLoader.ScriptLoader.add(urlString).then(done); 5204 } 5205 }; 5206 const waitFor = (name, state = 'added') => { 5207 if (state === 'added' && isAdded(name)) { 5208 return Promise.resolve(); 5209 } else if (state === 'loaded' && isLoaded(name)) { 5210 return Promise.resolve(); 5211 } else { 5212 return new Promise(resolve => { 5213 _listeners.push({ 5214 name, 5215 state, 5216 resolve 5217 }); 5218 }); 5219 } 5220 }; 5221 return { 5222 items, 5223 urls, 5224 lookup, 5225 get, 5226 requireLangPack, 5227 add, 5228 remove, 5229 createUrl, 5230 load, 5231 waitFor 5232 }; 5233 }; 5234 AddOnManager.languageLoad = true; 5235 AddOnManager.baseURL = ''; 5236 AddOnManager.PluginManager = AddOnManager(); 5237 AddOnManager.ThemeManager = AddOnManager(); 5238 AddOnManager.ModelManager = AddOnManager(); 5239 5240 const
vendor: 13,819 bytes, lines 5240-5663
5240first$1 = (fn, rate) => { 5241 let timer = null; 5242 const cancel = () => { 5243 if (!isNull(timer)) { 5244 clearTimeout(timer); 5245 timer = null; 5246 } 5247 }; 5248 const throttle = (...args) => { 5249 if (isNull(timer)) { 5250 timer = setTimeout(() => { 5251 timer = null; 5252 fn.apply(null, args); 5253 }, rate); 5254 } 5255 }; 5256 return { 5257 cancel, 5258 throttle 5259 }; 5260 }; 5261 const last = (fn, rate) => { 5262 let timer = null; 5263 const cancel = () => { 5264 if (!isNull(timer)) { 5265 clearTimeout(timer); 5266 timer = null; 5267 } 5268 }; 5269 const throttle = (...args) => { 5270 cancel(); 5271 timer = setTimeout(() => { 5272 timer = null; 5273 fn.apply(null, args); 5274 }, rate); 5275 }; 5276 return { 5277 cancel, 5278 throttle 5279 }; 5280 }; 5281 5282 const ancestor$1 = (scope, selector, isRoot) => ancestor$3(scope, selector, isRoot).isSome(); 5283 5284 const annotation = constant('mce-annotation'); 5285 const dataAnnotation = constant('data-mce-annotation'); 5286 const dataAnnotationId = constant('data-mce-annotation-uid'); 5287 const dataAnnotationActive = constant('data-mce-annotation-active'); 5288 const dataAnnotationClasses = constant('data-mce-annotation-classes'); 5289 const dataAnnotationAttributes = constant('data-mce-annotation-attrs'); 5290 5291 const isRoot$1 = root => node => eq(node, root); 5292 const identify = (editor, annotationName) => { 5293 const rng = editor.selection.getRng(); 5294 const start = SugarElement.fromDom(rng.startContainer); 5295 const root = SugarElement.fromDom(editor.getBody()); 5296 const selector = annotationName.fold(() => '.' + annotation(), an => `[${ dataAnnotation() }="${ an }"]`); 5297 const newStart = child$1(start, rng.startOffset).getOr(start); 5298 const closest = closest$3(newStart, selector, isRoot$1(root)); 5299 return closest.bind(c => getOpt(c, `${ dataAnnotationId() }`).bind(uid => getOpt(c, `${ dataAnnotation() }`).map(name => { 5300 const elements = findMarkers(editor, uid); 5301 return { 5302 uid, 5303 name, 5304 elements 5305 }; 5306 }))); 5307 }; 5308 const isAnnotation = elem => isElement$7(elem) && has(elem, annotation()); 5309 const isBogusElement = (elem, root) => has$1(elem, 'data-mce-bogus') || ancestor$1(elem, '[data-mce-bogus="all"]', isRoot$1(root)); 5310 const findMarkers = (editor, uid) => { 5311 const body = SugarElement.fromDom(editor.getBody()); 5312 const descendants$1 = descendants(body, `[${ dataAnnotationId() }="${ uid }"]`); 5313 return filter$5(descendants$1, descendant => !isBogusElement(descendant, body)); 5314 }; 5315 const findAll = (editor, name) => { 5316 const body = SugarElement.fromDom(editor.getBody()); 5317 const markers = descendants(body, `[${ dataAnnotation() }="${ name }"]`); 5318 const directory = {}; 5319 each$e(markers, m => { 5320 if (!isBogusElement(m, body)) { 5321 const uid = get$9(m, dataAnnotationId()); 5322 const nodesAlready = get$a(directory, uid).getOr([]); 5323 directory[uid] = nodesAlready.concat([m]); 5324 } 5325 }); 5326 return directory; 5327 }; 5328 5329 const setup$y = (editor, registry) => { 5330 const changeCallbacks = Cell({}); 5331 const initData = () => ({ 5332 listeners: [], 5333 previous: value$2() 5334 }); 5335 const withCallbacks = (name, f) => { 5336 updateCallbacks(name, data => { 5337 f(data); 5338 return data; 5339 }); 5340 }; 5341 const updateCallbacks = (name, f) => { 5342 const callbackMap = changeCallbacks.get(); 5343 const data = get$a(callbackMap, name).getOrThunk(initData); 5344 const outputData = f(data); 5345 callbackMap[name] = outputData; 5346 changeCallbacks.set(callbackMap); 5347 }; 5348 const fireCallbacks = (name, uid, elements) => { 5349 withCallbacks(name, data => { 5350 each$e(data.listeners, f => f(true, name, { 5351 uid, 5352 nodes: map$3(elements, elem => elem.dom) 5353 })); 5354 }); 5355 }; 5356 const fireNoAnnotation = name => { 5357 withCallbacks(name, data => { 5358 each$e(data.listeners, f => f(false, name)); 5359 }); 5360 }; 5361 const toggleActiveAttr = (uid, state) => { 5362 each$e(findMarkers(editor, uid), elem => { 5363 if (state) { 5364 set$4(elem, dataAnnotationActive(), 'true'); 5365 } else { 5366 remove$9(elem, dataAnnotationActive()); 5367 } 5368 }); 5369 }; 5370 const onNodeChange = last(() => { 5371 const annotations = sort(registry.getNames()); 5372 each$e(annotations, name => { 5373 updateCallbacks(name, data => { 5374 const prev = data.previous.get(); 5375 identify(editor, Optional.some(name)).fold(() => { 5376 prev.each(uid => { 5377 fireNoAnnotation(name); 5378 data.previous.clear(); 5379 toggleActiveAttr(uid, false); 5380 }); 5381 }, ({uid, name, elements}) => { 5382 if (!is$2(prev, uid)) { 5383 prev.each(uid => toggleActiveAttr(uid, false)); 5384 fireCallbacks(name, uid, elements); 5385 data.previous.set(uid); 5386 toggleActiveAttr(uid, true); 5387 } 5388 }); 5389 return { 5390 previous: data.previous, 5391 listeners: data.listeners 5392 }; 5393 }); 5394 }); 5395 }, 30); 5396 editor.on('remove', () => { 5397 onNodeChange.cancel(); 5398 }); 5399 editor.on('NodeChange', () => { 5400 onNodeChange.throttle(); 5401 }); 5402 const addListener = (name, f) => { 5403 updateCallbacks(name, data => ({ 5404 previous: data.previous, 5405 listeners: data.listeners.concat([f]) 5406 })); 5407 }; 5408 return { addListener }; 5409 }; 5410 5411 const setup$x = (editor, registry) => { 5412 const dataAnnotation$1 = dataAnnotation(); 5413 const identifyParserNode = node => Optional.from(node.attr(dataAnnotation$1)).bind(registry.lookup); 5414 const removeDirectAnnotation = node => { 5415 var _a, _b; 5416 node.attr(dataAnnotationId(), null); 5417 node.attr(dataAnnotation(), null); 5418 node.attr(dataAnnotationActive(), null); 5419 const customAttrNames = Optional.from(node.attr(dataAnnotationAttributes())).map(names => names.split(',')).getOr([]); 5420 const customClasses = Optional.from(node.attr(dataAnnotationClasses())).map(names => names.split(',')).getOr([]); 5421 each$e(customAttrNames, name => node.attr(name, null)); 5422 const classList = (_b = (_a = node.attr('class')) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : []; 5423 const newClassList = difference(classList, [annotation()].concat(customClasses)); 5424 node.attr('class', newClassList.length > 0 ? newClassList.join(' ') : null); 5425 node.attr(dataAnnotationClasses(), null); 5426 node.attr(dataAnnotationAttributes(), null); 5427 }; 5428 editor.serializer.addTempAttr(dataAnnotationActive()); 5429 editor.serializer.addAttributeFilter(dataAnnotation$1, nodes => { 5430 for (const node of nodes) { 5431 identifyParserNode(node).each(settings => { 5432 if (settings.persistent === false) { 5433 if (node.name === 'span') { 5434 node.unwrap(); 5435 } else { 5436 removeDirectAnnotation(node); 5437 } 5438 } 5439 }); 5440 } 5441 }); 5442 }; 5443 5444 const create$b = () => { 5445 const annotations = {}; 5446 const register = (name, settings) => { 5447 annotations[name] = { 5448 name, 5449 settings 5450 }; 5451 }; 5452 const lookup = name => get$a(annotations, name).map(a => a.settings); 5453 const getNames = () => keys(annotations); 5454 return { 5455 register, 5456 lookup, 5457 getNames 5458 }; 5459 }; 5460 5461 const clamp$2 = (value, min, max) => Math.min(Math.max(value, min), max); 5462 const random = () => window.crypto.getRandomValues(new Uint32Array(1))[0] / 4294967295; 5463 5464 let unique = 0; 5465 const generate$1 = prefix => { 5466 const date = new Date(); 5467 const time = date.getTime(); 5468 const random$1 = Math.floor(random() * 1000000000); 5469 unique++; 5470 return prefix + '_' + random$1 + unique + String(time); 5471 }; 5472 5473 const add = (element, classes) => { 5474 each$e(classes, x => { 5475 add$2(element, x); 5476 }); 5477 }; 5478 const remove$3 = (element, classes) => { 5479 each$e(classes, x => { 5480 remove$6(element, x); 5481 }); 5482 }; 5483 5484 const clone$2 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep)); 5485 const shallow$1 = original => clone$2(original, false); 5486 const deep$1 = original => clone$2(original, true); 5487 const shallowAs = (original, tag) => { 5488 const nu = SugarElement.fromTag(tag); 5489 const attributes = clone$4(original); 5490 setAll$1(nu, attributes); 5491 return nu; 5492 }; 5493 const mutate = (original, tag) => { 5494 const nu = shallowAs(original, tag); 5495 after$4(original, nu); 5496 const children = children$1(original); 5497 append(nu, children); 5498 remove$4(original); 5499 return nu; 5500 }; 5501 5502 const TextWalker = (startNode, rootNode, isBoundary = never) => { 5503 const walker = new DomTreeWalker(startNode, rootNode); 5504 const walk = direction => { 5505 let next; 5506 do { 5507 next = walker[direction](); 5508 } while (next && !isText$b(next) && !isBoundary(next)); 5509 return Optional.from(next).filter(isText$b); 5510 }; 5511 return { 5512 current: () => Optional.from(walker.current()).filter(isText$b), 5513 next: () => walk('next'), 5514 prev: () => walk('prev'), 5515 prev2: () => walk('prev2') 5516 }; 5517 }; 5518 5519 const TextSeeker = (dom, isBoundary) => { 5520 const isBlockBoundary = isBoundary ? isBoundary : node => dom.isBlock(node) || isBr$6(node) || isContentEditableFalse$b(node); 5521 const walk = (node, offset, walker, process) => { 5522 if (isText$b(node)) { 5523 const newOffset = process(node, offset, node.data); 5524 if (newOffset !== -1) { 5525 return Optional.some({ 5526 container: node, 5527 offset: newOffset 5528 }); 5529 } 5530 } 5531 return walker().bind(next => walk(next.container, next.offset, walker, process)); 5532 }; 5533 const backwards = (node, offset, process, root) => { 5534 const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary); 5535 return walk(node, offset, () => walker.prev().map(prev => ({ 5536 container: prev, 5537 offset: prev.length 5538 })), process).getOrNull(); 5539 }; 5540 const forwards = (node, offset, process, root) => { 5541 const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary); 5542 return walk(node, offset, () => walker.next().map(next => ({ 5543 container: next, 5544 offset: 0 5545 })), process).getOrNull(); 5546 }; 5547 return { 5548 backwards, 5549 forwards 5550 }; 5551 }; 5552 5553 const NodeValue = (is, name) => { 5554 const get = element => { 5555 if (!is(element)) { 5556 throw new Error('Can only get ' + name + ' value of a ' + name + ' node'); 5557 } 5558 return getOption(element).getOr(''); 5559 }; 5560 const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none(); 5561 const set = (element, value) => { 5562 if (!is(element)) { 5563 throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node'); 5564 } 5565 element.dom.nodeValue = value; 5566 }; 5567 return { 5568 get, 5569 getOption, 5570 set 5571 }; 5572 }; 5573 5574 const api$1 = NodeValue(isText$c, 'text'); 5575 const get$3 = element => api$1.get(element); 5576 const getOption = element => api$1.getOption(element); 5577 const set = (element, value) => api$1.set(element, value); 5578 5579 const tableCells = [ 5580 'td', 5581 'th' 5582 ]; 5583 const tableSections = [ 5584 'thead', 5585 'tbody', 5586 'tfoot' 5587 ]; 5588 const textBlocks = [ 5589 'h1', 5590 'h2', 5591 'h3', 5592 'h4', 5593 'h5', 5594 'h6', 5595 'p', 5596 'div', 5597 'address', 5598 'pre', 5599 'form', 5600 'blockquote', 5601 'center', 5602 'dir', 5603 'fieldset', 5604 'header', 5605 'footer', 5606 'article', 5607 'section', 5608 'hgroup', 5609 'aside', 5610 'nav', 5611 'figure' 5612 ]; 5613 const listItems$1 = [ 5614 'li', 5615 'dd', 5616 'dt' 5617 ]; 5618 const lists = [ 5619 'ul', 5620 'ol', 5621 'dl' 5622 ]; 5623 const wsElements = [ 5624 'pre', 5625 'script', 5626 'textarea', 5627 'style' 5628 ]; 5629 const lazyLookup = items => { 5630 let lookup; 5631 return node => { 5632 lookup = lookup ? lookup : mapToObject(items, always); 5633 return has$2(lookup, name(node)); 5634 }; 5635 }; 5636 const isTable$1 = node => name(node) === 'table'; 5637 const isBr$5 = node => isElement$7(node) && name(node) === 'br'; 5638 const isTextBlock$2 = lazyLookup(textBlocks); 5639 const isList = lazyLookup(lists); 5640 const isListItem$1 = lazyLookup(listItems$1); 5641 const isTableSection = lazyLookup(tableSections); 5642 const isTableCell$2 = lazyLookup(tableCells); 5643 const isWsPreserveElement = lazyLookup(wsElements); 5644 5645 const getLastChildren$1 = elm => { 5646 const children = []; 5647 let rawNode = elm.dom; 5648 while (rawNode) { 5649 children.push(SugarElement.fromDom(rawNode)); 5650 rawNode = rawNode.lastChild; 5651 } 5652 return children; 5653 }; 5654 const removeTrailingBr = elm => { 5655 const allBrs = descendants(elm, 'br'); 5656 const brs = filter$5(getLastChildren$1(elm).slice(-1), isBr$5); 5657 if (allBrs.length === brs.length) { 5658 each$e(brs, remove$4); 5659 } 5660 }; 5661 const createPaddingBr = () => { 5662 const br = SugarElement.fromTag('br'); 5663 set$4
vendor: 33,024 bytes, lines 5663-6498
5663(br, 'data-mce-bogus', '1'); 5664 return br; 5665 }; 5666 const fillWithPaddingBr = elm => { 5667 empty(elm); 5668 append$1(elm, createPaddingBr()); 5669 }; 5670 const trimBlockTrailingBr = (elm, schema) => { 5671 lastChild(elm).each(lastChild => { 5672 prevSibling(lastChild).each(lastChildPrevSibling => { 5673 if (schema.isBlock(name(elm)) && isBr$5(lastChild) && schema.isBlock(name(lastChildPrevSibling))) { 5674 remove$4(lastChild); 5675 } 5676 }); 5677 }); 5678 }; 5679 5680 const ZWSP$1 = zeroWidth; 5681 const isZwsp = isZwsp$2; 5682 const trim$2 = removeZwsp; 5683 const insert$5 = editor => editor.insertContent(ZWSP$1, { preserve_zwsp: true }); 5684 5685 const isElement$5 = isElement$6; 5686 const isText$9 = isText$b; 5687 const isCaretContainerBlock$1 = node => { 5688 if (isText$9(node)) { 5689 node = node.parentNode; 5690 } 5691 return isElement$5(node) && node.hasAttribute('data-mce-caret'); 5692 }; 5693 const isCaretContainerInline = node => isText$9(node) && isZwsp(node.data); 5694 const isCaretContainer$2 = node => isCaretContainerBlock$1(node) || isCaretContainerInline(node); 5695 const hasContent = node => node.firstChild !== node.lastChild || !isBr$6(node.firstChild); 5696 const insertInline$1 = (node, before) => { 5697 var _a; 5698 const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document; 5699 const textNode = doc.createTextNode(ZWSP$1); 5700 const parentNode = node.parentNode; 5701 if (!before) { 5702 const sibling = node.nextSibling; 5703 if (isText$9(sibling)) { 5704 if (isCaretContainer$2(sibling)) { 5705 return sibling; 5706 } 5707 if (startsWithCaretContainer$1(sibling)) { 5708 sibling.splitText(1); 5709 return sibling; 5710 } 5711 } 5712 if (node.nextSibling) { 5713 parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node.nextSibling); 5714 } else { 5715 parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(textNode); 5716 } 5717 } else { 5718 const sibling = node.previousSibling; 5719 if (isText$9(sibling)) { 5720 if (isCaretContainer$2(sibling)) { 5721 return sibling; 5722 } 5723 if (endsWithCaretContainer$1(sibling)) { 5724 return sibling.splitText(sibling.data.length - 1); 5725 } 5726 } 5727 parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node); 5728 } 5729 return textNode; 5730 }; 5731 const isBeforeInline = pos => { 5732 const container = pos.container(); 5733 if (!isText$b(container)) { 5734 return false; 5735 } 5736 return container.data.charAt(pos.offset()) === ZWSP$1 || pos.isAtStart() && isCaretContainerInline(container.previousSibling); 5737 }; 5738 const isAfterInline = pos => { 5739 const container = pos.container(); 5740 if (!isText$b(container)) { 5741 return false; 5742 } 5743 return container.data.charAt(pos.offset() - 1) === ZWSP$1 || pos.isAtEnd() && isCaretContainerInline(container.nextSibling); 5744 }; 5745 const insertBlock = (blockName, node, before) => { 5746 var _a; 5747 const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document; 5748 const blockNode = doc.createElement(blockName); 5749 blockNode.setAttribute('data-mce-caret', before ? 'before' : 'after'); 5750 blockNode.setAttribute('data-mce-bogus', 'all'); 5751 blockNode.appendChild(createPaddingBr().dom); 5752 const parentNode = node.parentNode; 5753 if (!before) { 5754 if (node.nextSibling) { 5755 parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node.nextSibling); 5756 } else { 5757 parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(blockNode); 5758 } 5759 } else { 5760 parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node); 5761 } 5762 return blockNode; 5763 }; 5764 const startsWithCaretContainer$1 = node => isText$9(node) && node.data[0] === ZWSP$1; 5765 const endsWithCaretContainer$1 = node => isText$9(node) && node.data[node.data.length - 1] === ZWSP$1; 5766 const trimBogusBr = elm => { 5767 var _a; 5768 const brs = elm.getElementsByTagName('br'); 5769 const lastBr = brs[brs.length - 1]; 5770 if (isBogus$1(lastBr)) { 5771 (_a = lastBr.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(lastBr); 5772 } 5773 }; 5774 const showCaretContainerBlock = caretContainer => { 5775 if (caretContainer && caretContainer.hasAttribute('data-mce-caret')) { 5776 trimBogusBr(caretContainer); 5777 caretContainer.removeAttribute('data-mce-caret'); 5778 caretContainer.removeAttribute('data-mce-bogus'); 5779 caretContainer.removeAttribute('style'); 5780 caretContainer.removeAttribute('data-mce-style'); 5781 caretContainer.removeAttribute('_moz_abspos'); 5782 return caretContainer; 5783 } 5784 return null; 5785 }; 5786 const isRangeInCaretContainerBlock = range => isCaretContainerBlock$1(range.startContainer); 5787 5788 const round$2 = Math.round; 5789 const clone$1 = rect => { 5790 if (!rect) { 5791 return { 5792 left: 0, 5793 top: 0, 5794 bottom: 0, 5795 right: 0, 5796 width: 0, 5797 height: 0 5798 }; 5799 } 5800 return { 5801 left: round$2(rect.left), 5802 top: round$2(rect.top), 5803 bottom: round$2(rect.bottom), 5804 right: round$2(rect.right), 5805 width: round$2(rect.width), 5806 height: round$2(rect.height) 5807 }; 5808 }; 5809 const collapse = (rect, toStart) => { 5810 rect = clone$1(rect); 5811 if (toStart) { 5812 rect.right = rect.left; 5813 } else { 5814 rect.left = rect.left + rect.width; 5815 rect.right = rect.left; 5816 } 5817 rect.width = 0; 5818 return rect; 5819 }; 5820 const isEqual = (rect1, rect2) => rect1.left === rect2.left && rect1.top === rect2.top && rect1.bottom === rect2.bottom && rect1.right === rect2.right; 5821 const isValidOverflow = (overflowY, rect1, rect2) => overflowY >= 0 && overflowY <= Math.min(rect1.height, rect2.height) / 2; 5822 const isAbove$1 = (rect1, rect2) => { 5823 const halfHeight = Math.min(rect2.height / 2, rect1.height / 2); 5824 if (rect1.bottom - halfHeight < rect2.top) { 5825 return true; 5826 } 5827 if (rect1.top > rect2.bottom) { 5828 return false; 5829 } 5830 return isValidOverflow(rect2.top - rect1.bottom, rect1, rect2); 5831 }; 5832 const isBelow$1 = (rect1, rect2) => { 5833 if (rect1.top > rect2.bottom) { 5834 return true; 5835 } 5836 if (rect1.bottom < rect2.top) { 5837 return false; 5838 } 5839 return isValidOverflow(rect2.bottom - rect1.top, rect1, rect2); 5840 }; 5841 const containsXY = (rect, clientX, clientY) => clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom; 5842 const boundingClientRectFromRects = rects => { 5843 return foldl(rects, (acc, rect) => { 5844 return acc.fold(() => Optional.some(rect), prevRect => { 5845 const left = Math.min(rect.left, prevRect.left); 5846 const top = Math.min(rect.top, prevRect.top); 5847 const right = Math.max(rect.right, prevRect.right); 5848 const bottom = Math.max(rect.bottom, prevRect.bottom); 5849 return Optional.some({ 5850 top, 5851 right, 5852 bottom, 5853 left, 5854 width: right - left, 5855 height: bottom - top 5856 }); 5857 }); 5858 }, Optional.none()); 5859 }; 5860 const distanceToRectEdgeFromXY = (rect, x, y) => { 5861 const cx = Math.max(Math.min(x, rect.left + rect.width), rect.left); 5862 const cy = Math.max(Math.min(y, rect.top + rect.height), rect.top); 5863 return Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)); 5864 }; 5865 const overlapY = (r1, r2) => Math.max(0, Math.min(r1.bottom, r2.bottom) - Math.max(r1.top, r2.top)); 5866 5867 const getSelectedNode = range => { 5868 const startContainer = range.startContainer, startOffset = range.startOffset; 5869 if (startContainer === range.endContainer && startContainer.hasChildNodes() && range.endOffset === startOffset + 1) { 5870 return startContainer.childNodes[startOffset]; 5871 } 5872 return null; 5873 }; 5874 const getNode$1 = (container, offset) => { 5875 if (isElement$6(container) && container.hasChildNodes()) { 5876 const childNodes = container.childNodes; 5877 const safeOffset = clamp$2(offset, 0, childNodes.length - 1); 5878 return childNodes[safeOffset]; 5879 } else { 5880 return container; 5881 } 5882 }; 5883 const getNodeUnsafe = (container, offset) => { 5884 if (offset < 0 && isElement$6(container) && container.hasChildNodes()) { 5885 return undefined; 5886 } else { 5887 return getNode$1(container, offset); 5888 } 5889 }; 5890 5891 const extendingChars = new RegExp('[\u0300-\u036f\u0483-\u0487\u0488-\u0489\u0591-\u05bd\u05bf\u05c1-\u05c2\u05c4-\u05c5\u05c7\u0610-\u061a' + '\u064b-\u065f\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7-\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0' + '\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e3-\u0902\u093a\u093c' + '\u0941-\u0948\u094d\u0951-\u0957\u0962-\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2-\u09e3' + '\u0a01-\u0a02\u0a3c\u0a41-\u0a42\u0a47-\u0a48\u0a4b-\u0a4d\u0a51\u0a70-\u0a71\u0a75\u0a81-\u0a82\u0abc' + '\u0ac1-\u0ac5\u0ac7-\u0ac8\u0acd\u0ae2-\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57' + '\u0b62-\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c00\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55-\u0c56' + '\u0c62-\u0c63\u0c81\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc-\u0ccd\u0cd5-\u0cd6\u0ce2-\u0ce3\u0d01\u0d3e\u0d41-\u0d44' + '\u0d4d\u0d57\u0d62-\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9' + '\u0ebb-\u0ebc\u0ec8-\u0ecd\u0f18-\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86-\u0f87\u0f8d-\u0f97' + '\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039-\u103a\u103d-\u103e\u1058-\u1059\u105e-\u1060\u1071-\u1074' + '\u1082\u1085-\u1086\u108d\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752-\u1753\u1772-\u1773\u17b4-\u17b5' + '\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927-\u1928\u1932\u1939-\u193b\u1a17-\u1a18' + '\u1a1b\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1ab0-\u1abd\u1ABE\u1b00-\u1b03\u1b34' + '\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80-\u1b81\u1ba2-\u1ba5\u1ba8-\u1ba9\u1bab-\u1bad\u1be6\u1be8-\u1be9' + '\u1bed\u1bef-\u1bf1\u1c2c-\u1c33\u1c36-\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1cf4\u1cf8-\u1cf9' + '\u1dc0-\u1df5\u1dfc-\u1dff\u200c-\u200d\u20d0-\u20dc\u20DD-\u20E0\u20e1\u20E2-\u20E4\u20e5-\u20f0\u2cef-\u2cf1' + '\u2d7f\u2de0-\u2dff\u302a-\u302d\u302e-\u302f\u3099-\u309a\ua66f\uA670-\uA672\ua674-\ua67d\ua69e-\ua69f\ua6f0-\ua6f1' + '\ua802\ua806\ua80b\ua825-\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc' + '\ua9e5\uaa29-\uaa2e\uaa31-\uaa32\uaa35-\uaa36\uaa43\uaa4c\uaa7c\uaab0\uaab2-\uaab4\uaab7-\uaab8\uaabe-\uaabf\uaac1' + '\uaaec-\uaaed\uaaf6\uabe5\uabe8\uabed\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\uff9e-\uff9f]'); 5892 const isExtendingChar = ch => isString(ch) && ch.charCodeAt(0) >= 768 && extendingChars.test(ch); 5893 5894 const or = (...args) => { 5895 return x => { 5896 for (let i = 0; i < args.length; i++) { 5897 if (args[i](x)) { 5898 return true; 5899 } 5900 } 5901 return false; 5902 }; 5903 }; 5904 const and = (...args) => { 5905 return x => { 5906 for (let i = 0; i < args.length; i++) { 5907 if (!args[i](x)) { 5908 return false; 5909 } 5910 } 5911 return true; 5912 }; 5913 }; 5914 5915 const isContentEditableTrue$2 = isContentEditableTrue$3; 5916 const isContentEditableFalse$a = isContentEditableFalse$b; 5917 const isBr$4 = isBr$6; 5918 const isText$8 = isText$b; 5919 const isInvalidTextElement = matchNodeNames([ 5920 'script', 5921 'style', 5922 'textarea' 5923 ]); 5924 const isAtomicInline = matchNodeNames([ 5925 'img', 5926 'input', 5927 'textarea', 5928 'hr', 5929 'iframe', 5930 'video', 5931 'audio', 5932 'object', 5933 'embed' 5934 ]); 5935 const isTable = matchNodeNames(['table']); 5936 const isCaretContainer$1 = isCaretContainer$2; 5937 const isCaretCandidate$3 = node => { 5938 if (isCaretContainer$1(node)) { 5939 return false; 5940 } 5941 if (isText$8(node)) { 5942 return !isInvalidTextElement(node.parentNode); 5943 } 5944 return isAtomicInline(node) || isBr$4(node) || isTable(node) || isNonUiContentEditableFalse(node); 5945 }; 5946 const isUnselectable = node => isElement$6(node) && node.getAttribute('unselectable') === 'true'; 5947 const isNonUiContentEditableFalse = node => !isUnselectable(node) && isContentEditableFalse$a(node); 5948 const isInEditable = (node, root) => { 5949 for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) { 5950 if (isNonUiContentEditableFalse(tempNode)) { 5951 return false; 5952 } 5953 if (isContentEditableTrue$2(tempNode)) { 5954 return true; 5955 } 5956 } 5957 return true; 5958 }; 5959 const isAtomicContentEditableFalse = node => { 5960 if (!isNonUiContentEditableFalse(node)) { 5961 return false; 5962 } 5963 return !foldl(from(node.getElementsByTagName('*')), (result, elm) => { 5964 return result || isContentEditableTrue$2(elm); 5965 }, false); 5966 }; 5967 const isAtomic$1 = node => isAtomicInline(node) || isAtomicContentEditableFalse(node); 5968 const isEditableCaretCandidate$1 = (node, root) => isCaretCandidate$3(node) && isInEditable(node, root); 5969 5970 const isElement$4 = isElement$6; 5971 const isCaretCandidate$2 = isCaretCandidate$3; 5972 const isBlock$2 = matchStyleValues('display', 'block table'); 5973 const isFloated = matchStyleValues('float', 'left right'); 5974 const isValidElementCaretCandidate = and(isElement$4, isCaretCandidate$2, not(isFloated)); 5975 const isNotPre = not(matchStyleValues('white-space', 'pre pre-line pre-wrap')); 5976 const isText$7 = isText$b; 5977 const isBr$3 = isBr$6; 5978 const nodeIndex$1 = DOMUtils.nodeIndex; 5979 const resolveIndex$1 = getNodeUnsafe; 5980 const createRange$1 = doc => doc ? doc.createRange() : DOMUtils.DOM.createRng(); 5981 const isWhiteSpace$1 = chr => isString(chr) && /[\r\n\t ]/.test(chr); 5982 const isRange = rng => !!rng.setStart && !!rng.setEnd; 5983 const isHiddenWhiteSpaceRange = range => { 5984 const container = range.startContainer; 5985 const offset = range.startOffset; 5986 if (isWhiteSpace$1(range.toString()) && isNotPre(container.parentNode) && isText$b(container)) { 5987 const text = container.data; 5988 if (isWhiteSpace$1(text[offset - 1]) || isWhiteSpace$1(text[offset + 1])) { 5989 return true; 5990 } 5991 } 5992 return false; 5993 }; 5994 const getBrClientRect = brNode => { 5995 const doc = brNode.ownerDocument; 5996 const rng = createRange$1(doc); 5997 const nbsp$1 = doc.createTextNode(nbsp); 5998 const parentNode = brNode.parentNode; 5999 parentNode.insertBefore(nbsp$1, brNode); 6000 rng.setStart(nbsp$1, 0); 6001 rng.setEnd(nbsp$1, 1); 6002 const clientRect = clone$1(rng.getBoundingClientRect()); 6003 parentNode.removeChild(nbsp$1); 6004 return clientRect; 6005 }; 6006 const getBoundingClientRectWebKitText = rng => { 6007 const sc = rng.startContainer; 6008 const ec = rng.endContainer; 6009 const so = rng.startOffset; 6010 const eo = rng.endOffset; 6011 if (sc === ec && isText$b(ec) && so === 0 && eo === 1) { 6012 const newRng = rng.cloneRange(); 6013 newRng.setEndAfter(ec); 6014 return getBoundingClientRect$1(newRng); 6015 } else { 6016 return null; 6017 } 6018 }; 6019 const isZeroRect = r => r.left === 0 && r.right === 0 && r.top === 0 && r.bottom === 0; 6020 const getBoundingClientRect$1 = item => { 6021 var _a; 6022 let clientRect; 6023 const clientRects = item.getClientRects(); 6024 if (clientRects.length > 0) { 6025 clientRect = clone$1(clientRects[0]); 6026 } else { 6027 clientRect = clone$1(item.getBoundingClientRect()); 6028 } 6029 if (!isRange(item) && isBr$3(item) && isZeroRect(clientRect)) { 6030 return getBrClientRect(item); 6031 } 6032 if (isZeroRect(clientRect) && isRange(item)) { 6033 return (_a = getBoundingClientRectWebKitText(item)) !== null && _a !== void 0 ? _a : clientRect; 6034 } 6035 return clientRect; 6036 }; 6037 const collapseAndInflateWidth = (clientRect, toStart) => { 6038 const newClientRect = collapse(clientRect, toStart); 6039 newClientRect.width = 1; 6040 newClientRect.right = newClientRect.left + 1; 6041 return newClientRect; 6042 }; 6043 const getCaretPositionClientRects = caretPosition => { 6044 const clientRects = []; 6045 const addUniqueAndValidRect = clientRect => { 6046 if (clientRect.height === 0) { 6047 return; 6048 } 6049 if (clientRects.length > 0) { 6050 if (isEqual(clientRect, clientRects[clientRects.length - 1])) { 6051 return; 6052 } 6053 } 6054 clientRects.push(clientRect); 6055 }; 6056 const addCharacterOffset = (container, offset) => { 6057 const range = createRange$1(container.ownerDocument); 6058 if (offset < container.data.length) { 6059 if (isExtendingChar(container.data[offset])) { 6060 return; 6061 } 6062 if (isExtendingChar(container.data[offset - 1])) { 6063 range.setStart(container, offset); 6064 range.setEnd(container, offset + 1); 6065 if (!isHiddenWhiteSpaceRange(range)) { 6066 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false)); 6067 return; 6068 } 6069 } 6070 } 6071 if (offset > 0) { 6072 range.setStart(container, offset - 1); 6073 range.setEnd(container, offset); 6074 if (!isHiddenWhiteSpaceRange(range)) { 6075 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false)); 6076 } 6077 } 6078 if (offset < container.data.length) { 6079 range.setStart(container, offset); 6080 range.setEnd(container, offset + 1); 6081 if (!isHiddenWhiteSpaceRange(range)) { 6082 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), true)); 6083 } 6084 } 6085 }; 6086 const container = caretPosition.container(); 6087 const offset = caretPosition.offset(); 6088 if (isText$7(container)) { 6089 addCharacterOffset(container, offset); 6090 return clientRects; 6091 } 6092 if (isElement$4(container)) { 6093 if (caretPosition.isAtEnd()) { 6094 const node = resolveIndex$1(container, offset); 6095 if (isText$7(node)) { 6096 addCharacterOffset(node, node.data.length); 6097 } 6098 if (isValidElementCaretCandidate(node) && !isBr$3(node)) { 6099 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false)); 6100 } 6101 } else { 6102 const node = resolveIndex$1(container, offset); 6103 if (isText$7(node)) { 6104 addCharacterOffset(node, 0); 6105 } 6106 if (isValidElementCaretCandidate(node) && caretPosition.isAtEnd()) { 6107 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false)); 6108 return clientRects; 6109 } 6110 const beforeNode = resolveIndex$1(caretPosition.container(), caretPosition.offset() - 1); 6111 if (isValidElementCaretCandidate(beforeNode) && !isBr$3(beforeNode)) { 6112 if (isBlock$2(beforeNode) || isBlock$2(node) || !isValidElementCaretCandidate(node)) { 6113 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(beforeNode), false)); 6114 } 6115 } 6116 if (isValidElementCaretCandidate(node)) { 6117 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), true)); 6118 } 6119 } 6120 } 6121 return clientRects; 6122 }; 6123 const CaretPosition = (container, offset, clientRects) => { 6124 const isAtStart = () => { 6125 if (isText$7(container)) { 6126 return offset === 0; 6127 } 6128 return offset === 0; 6129 }; 6130 const isAtEnd = () => { 6131 if (isText$7(container)) { 6132 return offset >= container.data.length; 6133 } 6134 return offset >= container.childNodes.length; 6135 }; 6136 const toRange = () => { 6137 const range = createRange$1(container.ownerDocument); 6138 range.setStart(container, offset); 6139 range.setEnd(container, offset); 6140 return range; 6141 }; 6142 const getClientRects = () => { 6143 if (!clientRects) { 6144 clientRects = getCaretPositionClientRects(CaretPosition(container, offset)); 6145 } 6146 return clientRects; 6147 }; 6148 const isVisible = () => getClientRects().length > 0; 6149 const isEqual = caretPosition => caretPosition && container === caretPosition.container() && offset === caretPosition.offset(); 6150 const getNode = before => resolveIndex$1(container, before ? offset - 1 : offset); 6151 return { 6152 container: constant(container), 6153 offset: constant(offset), 6154 toRange, 6155 getClientRects, 6156 isVisible, 6157 isAtStart, 6158 isAtEnd, 6159 isEqual, 6160 getNode 6161 }; 6162 }; 6163 CaretPosition.fromRangeStart = range => CaretPosition(range.startContainer, range.startOffset); 6164 CaretPosition.fromRangeEnd = range => CaretPosition(range.endContainer, range.endOffset); 6165 CaretPosition.after = node => CaretPosition(node.parentNode, nodeIndex$1(node) + 1); 6166 CaretPosition.before = node => CaretPosition(node.parentNode, nodeIndex$1(node)); 6167 CaretPosition.isAbove = (pos1, pos2) => lift2(head(pos2.getClientRects()), last$2(pos1.getClientRects()), isAbove$1).getOr(false); 6168 CaretPosition.isBelow = (pos1, pos2) => lift2(last$2(pos2.getClientRects()), head(pos1.getClientRects()), isBelow$1).getOr(false); 6169 CaretPosition.isAtStart = pos => pos ? pos.isAtStart() : false; 6170 CaretPosition.isAtEnd = pos => pos ? pos.isAtEnd() : false; 6171 CaretPosition.isTextPosition = pos => pos ? isText$b(pos.container()) : false; 6172 CaretPosition.isElementPosition = pos => !CaretPosition.isTextPosition(pos); 6173 6174 const trimEmptyTextNode$1 = (dom, node) => { 6175 if (isText$b(node) && node.data.length === 0) { 6176 dom.remove(node); 6177 } 6178 }; 6179 const insertNode = (dom, rng, node) => { 6180 rng.insertNode(node); 6181 trimEmptyTextNode$1(dom, node.previousSibling); 6182 trimEmptyTextNode$1(dom, node.nextSibling); 6183 }; 6184 const insertFragment = (dom, rng, frag) => { 6185 const firstChild = Optional.from(frag.firstChild); 6186 const lastChild = Optional.from(frag.lastChild); 6187 rng.insertNode(frag); 6188 firstChild.each(child => trimEmptyTextNode$1(dom, child.previousSibling)); 6189 lastChild.each(child => trimEmptyTextNode$1(dom, child.nextSibling)); 6190 }; 6191 const rangeInsertNode = (dom, rng, node) => { 6192 if (isDocumentFragment(node)) { 6193 insertFragment(dom, rng, node); 6194 } else { 6195 insertNode(dom, rng, node); 6196 } 6197 }; 6198 6199 const isText$6 = isText$b; 6200 const isBogus = isBogus$1; 6201 const nodeIndex = DOMUtils.nodeIndex; 6202 const normalizedParent = node => { 6203 const parentNode = node.parentNode; 6204 if (isBogus(parentNode)) { 6205 return normalizedParent(parentNode); 6206 } 6207 return parentNode; 6208 }; 6209 const getChildNodes = node => { 6210 if (!node) { 6211 return []; 6212 } 6213 return reduce(node.childNodes, (result, node) => { 6214 if (isBogus(node) && node.nodeName !== 'BR') { 6215 result = result.concat(getChildNodes(node)); 6216 } else { 6217 result.push(node); 6218 } 6219 return result; 6220 }, []); 6221 }; 6222 const normalizedTextOffset = (node, offset) => { 6223 let tempNode = node; 6224 while (tempNode = tempNode.previousSibling) { 6225 if (!isText$6(tempNode)) { 6226 break; 6227 } 6228 offset += tempNode.data.length; 6229 } 6230 return offset; 6231 }; 6232 const equal = a => b => a === b; 6233 const normalizedNodeIndex = node => { 6234 let nodes, index; 6235 nodes = getChildNodes(normalizedParent(node)); 6236 index = findIndex$1(nodes, equal(node), node); 6237 nodes = nodes.slice(0, index + 1); 6238 const numTextFragments = reduce(nodes, (result, node, i) => { 6239 if (isText$6(node) && isText$6(nodes[i - 1])) { 6240 result++; 6241 } 6242 return result; 6243 }, 0); 6244 nodes = filter$3(nodes, matchNodeNames([node.nodeName])); 6245 index = findIndex$1(nodes, equal(node), node); 6246 return index - numTextFragments; 6247 }; 6248 const createPathItem = node => { 6249 const name = isText$6(node) ? 'text()' : node.nodeName.toLowerCase(); 6250 return name + '[' + normalizedNodeIndex(node) + ']'; 6251 }; 6252 const parentsUntil$1 = (root, node, predicate) => { 6253 const parents = []; 6254 for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) { 6255 if (predicate && predicate(tempNode)) { 6256 break; 6257 } 6258 parents.push(tempNode); 6259 } 6260 return parents; 6261 }; 6262 const create$a = (root, caretPosition) => { 6263 let path = []; 6264 let container = caretPosition.container(); 6265 let offset = caretPosition.offset(); 6266 let outputOffset; 6267 if (isText$6(container)) { 6268 outputOffset = normalizedTextOffset(container, offset); 6269 } else { 6270 const childNodes = container.childNodes; 6271 if (offset >= childNodes.length) { 6272 outputOffset = 'after'; 6273 offset = childNodes.length - 1; 6274 } else { 6275 outputOffset = 'before'; 6276 } 6277 container = childNodes[offset]; 6278 } 6279 path.push(createPathItem(container)); 6280 let parents = parentsUntil$1(root, container); 6281 parents = filter$3(parents, not(isBogus$1)); 6282 path = path.concat(map$1(parents, node => { 6283 return createPathItem(node); 6284 })); 6285 return path.reverse().join('/') + ',' + outputOffset; 6286 }; 6287 const resolvePathItem = (node, name, index) => { 6288 let nodes = getChildNodes(node); 6289 nodes = filter$3(nodes, (node, index) => { 6290 return !isText$6(node) || !isText$6(nodes[index - 1]); 6291 }); 6292 nodes = filter$3(nodes, matchNodeNames([name])); 6293 return nodes[index]; 6294 }; 6295 const findTextPosition = (container, offset) => { 6296 let node = container; 6297 let targetOffset = 0; 6298 while (isText$6(node)) { 6299 const dataLen = node.data.length; 6300 if (offset >= targetOffset && offset <= targetOffset + dataLen) { 6301 container = node; 6302 offset = offset - targetOffset; 6303 break; 6304 } 6305 if (!isText$6(node.nextSibling)) { 6306 container = node; 6307 offset = dataLen; 6308 break; 6309 } 6310 targetOffset += dataLen; 6311 node = node.nextSibling; 6312 } 6313 if (isText$6(container) && offset > container.data.length) { 6314 offset = container.data.length; 6315 } 6316 return CaretPosition(container, offset); 6317 }; 6318 const resolve$1 = (root, path) => { 6319 if (!path) { 6320 return null; 6321 } 6322 const parts = path.split(','); 6323 const paths = parts[0].split('/'); 6324 const offset = parts.length > 1 ? parts[1] : 'before'; 6325 const container = reduce(paths, (result, value) => { 6326 const match = /([\w\-\(\)]+)\[([0-9]+)\]/.exec(value); 6327 if (!match) { 6328 return null; 6329 } 6330 if (match[1] === 'text()') { 6331 match[1] = '#text'; 6332 } 6333 return resolvePathItem(result, match[1], parseInt(match[2], 10)); 6334 }, root); 6335 if (!container) { 6336 return null; 6337 } 6338 if (!isText$6(container) && container.parentNode) { 6339 let nodeOffset; 6340 if (offset === 'after') { 6341 nodeOffset = nodeIndex(container) + 1; 6342 } else { 6343 nodeOffset = nodeIndex(container); 6344 } 6345 return CaretPosition(container.parentNode, nodeOffset); 6346 } 6347 return findTextPosition(container, parseInt(offset, 10)); 6348 }; 6349 6350 const isContentEditableFalse$9 = isContentEditableFalse$b; 6351 const getNormalizedTextOffset$1 = (trim, container, offset) => { 6352 let trimmedOffset = trim(container.data.slice(0, offset)).length; 6353 for (let node = container.previousSibling; node && isText$b(node); node = node.previousSibling) { 6354 trimmedOffset += trim(node.data).length; 6355 } 6356 return trimmedOffset; 6357 }; 6358 const getPoint = (dom, trim, normalized, rng, start) => { 6359 const container = start ? rng.startContainer : rng.endContainer; 6360 let offset = start ? rng.startOffset : rng.endOffset; 6361 const point = []; 6362 const root = dom.getRoot(); 6363 if (isText$b(container)) { 6364 point.push(normalized ? getNormalizedTextOffset$1(trim, container, offset) : offset); 6365 } else { 6366 let after = 0; 6367 const childNodes = container.childNodes; 6368 if (offset >= childNodes.length && childNodes.length) { 6369 after = 1; 6370 offset = Math.max(0, childNodes.length - 1); 6371 } 6372 point.push(dom.nodeIndex(childNodes[offset], normalized) + after); 6373 } 6374 for (let node = container; node && node !== root; node = node.parentNode) { 6375 point.push(dom.nodeIndex(node, normalized)); 6376 } 6377 return point; 6378 }; 6379 const getLocation = (trim, selection, normalized, rng) => { 6380 const dom = selection.dom; 6381 const start = getPoint(dom, trim, normalized, rng, true); 6382 const forward = selection.isForward(); 6383 const fakeCaret = isRangeInCaretContainerBlock(rng) ? { isFakeCaret: true } : {}; 6384 if (!selection.isCollapsed()) { 6385 const end = getPoint(dom, trim, normalized, rng, false); 6386 return { 6387 start, 6388 end, 6389 forward, 6390 ...fakeCaret 6391 }; 6392 } else { 6393 return { 6394 start, 6395 forward, 6396 ...fakeCaret 6397 }; 6398 } 6399 }; 6400 const findIndex = (dom, name, element) => { 6401 let count = 0; 6402 Tools.each(dom.select(name), node => { 6403 if (node.getAttribute('data-mce-bogus') === 'all') { 6404 return; 6405 } else if (node === element) { 6406 return false; 6407 } else { 6408 count++; 6409 return; 6410 } 6411 }); 6412 return count; 6413 }; 6414 const moveEndPoint$1 = (rng, start) => { 6415 let container = start ? rng.startContainer : rng.endContainer; 6416 let offset = start ? rng.startOffset : rng.endOffset; 6417 if (isElement$6(container) && container.nodeName === 'TR') { 6418 const childNodes = container.childNodes; 6419 container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)]; 6420 if (container) { 6421 offset = start ? 0 : container.childNodes.length; 6422 if (start) { 6423 rng.setStart(container, offset); 6424 } else { 6425 rng.setEnd(container, offset); 6426 } 6427 } 6428 } 6429 }; 6430 const normalizeTableCellSelection = rng => { 6431 moveEndPoint$1(rng, true); 6432 moveEndPoint$1(rng, false); 6433 return rng; 6434 }; 6435 const findSibling = (node, offset) => { 6436 if (isElement$6(node)) { 6437 node = getNode$1(node, offset); 6438 if (isContentEditableFalse$9(node)) { 6439 return node; 6440 } 6441 } 6442 if (isCaretContainer$2(node)) { 6443 if (isText$b(node) && isCaretContainerBlock$1(node)) { 6444 node = node.parentNode; 6445 } 6446 let sibling = node.previousSibling; 6447 if (isContentEditableFalse$9(sibling)) { 6448 return sibling; 6449 } 6450 sibling = node.nextSibling; 6451 if (isContentEditableFalse$9(sibling)) { 6452 return sibling; 6453 } 6454 } 6455 return undefined; 6456 }; 6457 const findAdjacentContentEditableFalseElm = rng => { 6458 return findSibling(rng.startContainer, rng.startOffset) || findSibling(rng.endContainer, rng.endOffset); 6459 }; 6460 const getOffsetBookmark = (trim, normalized, selection) => { 6461 const element = selection.getNode(); 6462 const rng = selection.getRng(); 6463 if (element.nodeName === 'IMG' || isContentEditableFalse$9(element)) { 6464 const name = element.nodeName; 6465 return { 6466 name, 6467 index: findIndex(selection.dom, name, element) 6468 }; 6469 } 6470 const sibling = findAdjacentContentEditableFalseElm(rng); 6471 if (sibling) { 6472 const name = sibling.tagName; 6473 return { 6474 name, 6475 index: findIndex(selection.dom, name, sibling) 6476 }; 6477 } 6478 return getLocation(trim, selection, normalized, rng); 6479 }; 6480 const getCaretBookmark = selection => { 6481 const rng = selection.getRng(); 6482 return { 6483 start: create$a(selection.dom.getRoot(), CaretPosition.fromRangeStart(rng)), 6484 end: create$a(selection.dom.getRoot(), CaretPosition.fromRangeEnd(rng)), 6485 forward: selection.isForward() 6486 }; 6487 }; 6488 const getRangeBookmark = selection => { 6489 return { 6490 rng: selection.getRng(), 6491 forward: selection.isForward() 6492 }; 6493 }; 6494 const createBookmarkSpan = (dom, id, filled) => { 6495 const args = { 6496 'data-mce-type': 'bookmark', 6497 id, 6498
vendor: 20,636 bytes, lines 6498-7142
6498'style': 'overflow:hidden;line-height:0px' 6499 }; 6500 return filled ? dom.create('span', args, '') : dom.create('span', args); 6501 }; 6502 const getPersistentBookmark = (selection, filled) => { 6503 const dom = selection.dom; 6504 let rng = selection.getRng(); 6505 const id = dom.uniqueId(); 6506 const collapsed = selection.isCollapsed(); 6507 const element = selection.getNode(); 6508 const name = element.nodeName; 6509 const forward = selection.isForward(); 6510 if (name === 'IMG') { 6511 return { 6512 name, 6513 index: findIndex(dom, name, element) 6514 }; 6515 } 6516 const rng2 = normalizeTableCellSelection(rng.cloneRange()); 6517 if (!collapsed) { 6518 rng2.collapse(false); 6519 const endBookmarkNode = createBookmarkSpan(dom, id + '_end', filled); 6520 rangeInsertNode(dom, rng2, endBookmarkNode); 6521 } 6522 rng = normalizeTableCellSelection(rng); 6523 rng.collapse(true); 6524 const startBookmarkNode = createBookmarkSpan(dom, id + '_start', filled); 6525 rangeInsertNode(dom, rng, startBookmarkNode); 6526 selection.moveToBookmark({ 6527 id, 6528 keep: true, 6529 forward 6530 }); 6531 return { 6532 id, 6533 forward 6534 }; 6535 }; 6536 const getBookmark$3 = (selection, type, normalized = false) => { 6537 if (type === 2) { 6538 return getOffsetBookmark(trim$2, normalized, selection); 6539 } else if (type === 3) { 6540 return getCaretBookmark(selection); 6541 } else if (type) { 6542 return getRangeBookmark(selection); 6543 } else { 6544 return getPersistentBookmark(selection, false); 6545 } 6546 }; 6547 const getUndoBookmark = curry(getOffsetBookmark, identity, true); 6548 6549 const value$1 = value => { 6550 const applyHelper = fn => fn(value); 6551 const constHelper = constant(value); 6552 const outputHelper = () => output; 6553 const output = { 6554 tag: true, 6555 inner: value, 6556 fold: (_onError, onValue) => onValue(value), 6557 isValue: always, 6558 isError: never, 6559 map: mapper => Result.value(mapper(value)), 6560 mapError: outputHelper, 6561 bind: applyHelper, 6562 exists: applyHelper, 6563 forall: applyHelper, 6564 getOr: constHelper, 6565 or: outputHelper, 6566 getOrThunk: constHelper, 6567 orThunk: outputHelper, 6568 getOrDie: constHelper, 6569 each: fn => { 6570 fn(value); 6571 }, 6572 toOptional: () => Optional.some(value) 6573 }; 6574 return output; 6575 }; 6576 const error = error => { 6577 const outputHelper = () => output; 6578 const output = { 6579 tag: false, 6580 inner: error, 6581 fold: (onError, _onValue) => onError(error), 6582 isValue: never, 6583 isError: always, 6584 map: outputHelper, 6585 mapError: mapper => Result.error(mapper(error)), 6586 bind: outputHelper, 6587 exists: never, 6588 forall: always, 6589 getOr: identity, 6590 or: identity, 6591 getOrThunk: apply$1, 6592 orThunk: apply$1, 6593 getOrDie: die(String(error)), 6594 each: noop, 6595 toOptional: Optional.none 6596 }; 6597 return output; 6598 }; 6599 const fromOption = (optional, err) => optional.fold(() => error(err), value$1); 6600 const Result = { 6601 value: value$1, 6602 error, 6603 fromOption 6604 }; 6605 6606 const generate = cases => { 6607 if (!isArray$1(cases)) { 6608 throw new Error('cases must be an array'); 6609 } 6610 if (cases.length === 0) { 6611 throw new Error('there must be at least one case'); 6612 } 6613 const constructors = []; 6614 const adt = {}; 6615 each$e(cases, (acase, count) => { 6616 const keys$1 = keys(acase); 6617 if (keys$1.length !== 1) { 6618 throw new Error('one and only one name per case'); 6619 } 6620 const key = keys$1[0]; 6621 const value = acase[key]; 6622 if (adt[key] !== undefined) { 6623 throw new Error('duplicate key detected:' + key); 6624 } else if (key === 'cata') { 6625 throw new Error('cannot have a case named cata (sorry)'); 6626 } else if (!isArray$1(value)) { 6627 throw new Error('case arguments must be an array'); 6628 } 6629 constructors.push(key); 6630 adt[key] = (...args) => { 6631 const argLength = args.length; 6632 if (argLength !== value.length) { 6633 throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength); 6634 } 6635 const match = branches => { 6636 const branchKeys = keys(branches); 6637 if (constructors.length !== branchKeys.length) { 6638 throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(',')); 6639 } 6640 const allReqd = forall(constructors, reqKey => { 6641 return contains$2(branchKeys, reqKey); 6642 }); 6643 if (!allReqd) { 6644 throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', ')); 6645 } 6646 return branches[key].apply(null, args); 6647 }; 6648 return { 6649 fold: (...foldArgs) => { 6650 if (foldArgs.length !== cases.length) { 6651 throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length); 6652 } 6653 const target = foldArgs[count]; 6654 return target.apply(null, args); 6655 }, 6656 match, 6657 log: label => { 6658 console.log(label, { 6659 constructors, 6660 constructor: key, 6661 params: args 6662 }); 6663 } 6664 }; 6665 }; 6666 }); 6667 return adt; 6668 }; 6669 const Adt = { generate }; 6670 6671 Adt.generate([ 6672 { 6673 bothErrors: [ 6674 'error1', 6675 'error2' 6676 ] 6677 }, 6678 { 6679 firstError: [ 6680 'error1', 6681 'value2' 6682 ] 6683 }, 6684 { 6685 secondError: [ 6686 'value1', 6687 'error2' 6688 ] 6689 }, 6690 { 6691 bothValues: [ 6692 'value1', 6693 'value2' 6694 ] 6695 } 6696 ]); 6697 const partition$1 = results => { 6698 const errors = []; 6699 const values = []; 6700 each$e(results, result => { 6701 result.fold(err => { 6702 errors.push(err); 6703 }, value => { 6704 values.push(value); 6705 }); 6706 }); 6707 return { 6708 errors, 6709 values 6710 }; 6711 }; 6712 6713 const isInlinePattern = pattern => pattern.type === 'inline-command' || pattern.type === 'inline-format'; 6714 const isBlockPattern = pattern => pattern.type === 'block-command' || pattern.type === 'block-format'; 6715 const hasBlockTrigger = (pattern, trigger) => (pattern.type === 'block-command' || pattern.type === 'block-format') && pattern.trigger === trigger; 6716 const normalizePattern = pattern => { 6717 var _a; 6718 const err = message => Result.error({ 6719 message, 6720 pattern 6721 }); 6722 const formatOrCmd = (name, onFormat, onCommand) => { 6723 if (pattern.format !== undefined) { 6724 let formats; 6725 if (isArray$1(pattern.format)) { 6726 if (!forall(pattern.format, isString)) { 6727 return err(name + ' pattern has non-string items in the `format` array'); 6728 } 6729 formats = pattern.format; 6730 } else if (isString(pattern.format)) { 6731 formats = [pattern.format]; 6732 } else { 6733 return err(name + ' pattern has non-string `format` parameter'); 6734 } 6735 return Result.value(onFormat(formats)); 6736 } else if (pattern.cmd !== undefined) { 6737 if (!isString(pattern.cmd)) { 6738 return err(name + ' pattern has non-string `cmd` parameter'); 6739 } 6740 return Result.value(onCommand(pattern.cmd, pattern.value)); 6741 } else { 6742 return err(name + ' pattern is missing both `format` and `cmd` parameters'); 6743 } 6744 }; 6745 if (!isObject(pattern)) { 6746 return err('Raw pattern is not an object'); 6747 } 6748 if (!isString(pattern.start)) { 6749 return err('Raw pattern is missing `start` parameter'); 6750 } 6751 if (pattern.end !== undefined) { 6752 if (!isString(pattern.end)) { 6753 return err('Inline pattern has non-string `end` parameter'); 6754 } 6755 if (pattern.start.length === 0 && pattern.end.length === 0) { 6756 return err('Inline pattern has empty `start` and `end` parameters'); 6757 } 6758 let start = pattern.start; 6759 let end = pattern.end; 6760 if (end.length === 0) { 6761 end = start; 6762 start = ''; 6763 } 6764 return formatOrCmd('Inline', format => ({ 6765 type: 'inline-format', 6766 start, 6767 end, 6768 format 6769 }), (cmd, value) => ({ 6770 type: 'inline-command', 6771 start, 6772 end, 6773 cmd, 6774 value 6775 })); 6776 } else if (pattern.replacement !== undefined) { 6777 if (!isString(pattern.replacement)) { 6778 return err('Replacement pattern has non-string `replacement` parameter'); 6779 } 6780 if (pattern.start.length === 0) { 6781 return err('Replacement pattern has empty `start` parameter'); 6782 } 6783 return Result.value({ 6784 type: 'inline-command', 6785 start: '', 6786 end: pattern.start, 6787 cmd: 'mceInsertContent', 6788 value: pattern.replacement 6789 }); 6790 } else { 6791 const trigger = (_a = pattern.trigger) !== null && _a !== void 0 ? _a : 'space'; 6792 if (pattern.start.length === 0) { 6793 return err('Block pattern has empty `start` parameter'); 6794 } 6795 return formatOrCmd('Block', formats => ({ 6796 type: 'block-format', 6797 start: pattern.start, 6798 format: formats[0], 6799 trigger 6800 }), (command, commandValue) => ({ 6801 type: 'block-command', 6802 start: pattern.start, 6803 cmd: command, 6804 value: commandValue, 6805 trigger 6806 })); 6807 } 6808 }; 6809 const getBlockPatterns = patterns => filter$5(patterns, isBlockPattern); 6810 const getInlinePatterns = patterns => filter$5(patterns, isInlinePattern); 6811 const createPatternSet = (patterns, dynamicPatternsLookup) => ({ 6812 inlinePatterns: getInlinePatterns(patterns), 6813 blockPatterns: getBlockPatterns(patterns), 6814 dynamicPatternsLookup 6815 }); 6816 const filterByTrigger = (patterns, trigger) => { 6817 return { 6818 ...patterns, 6819 blockPatterns: filter$5(patterns.blockPatterns, pattern => hasBlockTrigger(pattern, trigger)) 6820 }; 6821 }; 6822 const fromRawPatterns = patterns => { 6823 const normalized = partition$1(map$3(patterns, normalizePattern)); 6824 each$e(normalized.errors, err => console.error(err.message, err.pattern)); 6825 return normalized.values; 6826 }; 6827 const fromRawPatternsLookup = lookupFn => { 6828 return ctx => { 6829 const rawPatterns = lookupFn(ctx); 6830 return fromRawPatterns(rawPatterns); 6831 }; 6832 }; 6833 6834 const firePreProcess = (editor, args) => editor.dispatch('PreProcess', args); 6835 const firePostProcess = (editor, args) => editor.dispatch('PostProcess', args); 6836 const fireRemove = editor => { 6837 editor.dispatch('remove'); 6838 }; 6839 const fireDetach = editor => { 6840 editor.dispatch('detach'); 6841 }; 6842 const fireSwitchMode = (editor, mode) => { 6843 editor.dispatch('SwitchMode', { mode }); 6844 }; 6845 const fireObjectResizeStart = (editor, target, width, height, origin) => { 6846 editor.dispatch('ObjectResizeStart', { 6847 target, 6848 width, 6849 height, 6850 origin 6851 }); 6852 }; 6853 const fireObjectResized = (editor, target, width, height, origin) => { 6854 editor.dispatch('ObjectResized', { 6855 target, 6856 width, 6857 height, 6858 origin 6859 }); 6860 }; 6861 const firePreInit = editor => { 6862 editor.dispatch('PreInit'); 6863 }; 6864 const firePostRender = editor => { 6865 editor.dispatch('PostRender'); 6866 }; 6867 const fireInit = editor => { 6868 editor.dispatch('Init'); 6869 }; 6870 const firePlaceholderToggle = (editor, state) => { 6871 editor.dispatch('PlaceholderToggle', { state }); 6872 }; 6873 const fireError = (editor, errorType, error) => { 6874 editor.dispatch(errorType, error); 6875 }; 6876 const fireFormatApply = (editor, format, node, vars) => { 6877 editor.dispatch('FormatApply', { 6878 format, 6879 node, 6880 vars 6881 }); 6882 }; 6883 const fireFormatRemove = (editor, format, node, vars) => { 6884 editor.dispatch('FormatRemove', { 6885 format, 6886 node, 6887 vars 6888 }); 6889 }; 6890 const fireBeforeSetContent = (editor, args) => editor.dispatch('BeforeSetContent', args); 6891 const fireSetContent = (editor, args) => editor.dispatch('SetContent', args); 6892 const fireBeforeGetContent = (editor, args) => editor.dispatch('BeforeGetContent', args); 6893 const fireGetContent = (editor, args) => editor.dispatch('GetContent', args); 6894 const fireAutocompleterStart = (editor, args) => { 6895 editor.dispatch('AutocompleterStart', args); 6896 }; 6897 const fireAutocompleterUpdate = (editor, args) => { 6898 editor.dispatch('AutocompleterUpdate', args); 6899 }; 6900 const fireAutocompleterUpdateActiveRange = (editor, args) => { 6901 editor.dispatch('AutocompleterUpdateActiveRange', args); 6902 }; 6903 const fireAutocompleterEnd = editor => { 6904 editor.dispatch('AutocompleterEnd'); 6905 }; 6906 const firePastePreProcess = (editor, html, internal) => editor.dispatch('PastePreProcess', { 6907 content: html, 6908 internal 6909 }); 6910 const firePastePostProcess = (editor, node, internal) => editor.dispatch('PastePostProcess', { 6911 node, 6912 internal 6913 }); 6914 const firePastePlainTextToggle = (editor, state) => editor.dispatch('PastePlainTextToggle', { state }); 6915 const fireEditableRootStateChange = (editor, state) => editor.dispatch('EditableRootStateChange', { state }); 6916 const fireDisabledStateChange = (editor, state) => editor.dispatch('DisabledStateChange', { state }); 6917 6918 const deviceDetection$1 = detect$1().deviceType; 6919 const isTouch = deviceDetection$1.isTouch(); 6920 const DOM$a = DOMUtils.DOM; 6921 const getHash = value => { 6922 const items = value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(','); 6923 return foldl(items, (output, item) => { 6924 const arr = item.split('='); 6925 const key = arr[0]; 6926 const val = arr.length > 1 ? arr[1] : key; 6927 output[trim$4(key)] = trim$4(val); 6928 return output; 6929 }, {}); 6930 }; 6931 const isRegExp = x => is$4(x, RegExp); 6932 const option = name => editor => editor.options.get(name); 6933 const stringOrObjectProcessor = value => isString(value) || isObject(value); 6934 const bodyOptionProcessor = (editor, defaultValue = '') => value => { 6935 const valid = isString(value); 6936 if (valid) { 6937 if (value.indexOf('=') !== -1) { 6938 const bodyObj = getHash(value); 6939 return { 6940 value: get$a(bodyObj, editor.id).getOr(defaultValue), 6941 valid 6942 }; 6943 } else { 6944 return { 6945 value, 6946 valid 6947 }; 6948 } 6949 } else { 6950 return { 6951 valid: false, 6952 message: 'Must be a string.' 6953 }; 6954 } 6955 }; 6956 const register$7 = editor => { 6957 const registerOption = editor.options.register; 6958 registerOption('id', { 6959 processor: 'string', 6960 default: editor.id 6961 }); 6962 registerOption('selector', { processor: 'string' }); 6963 registerOption('target', { processor: 'object' }); 6964 registerOption('suffix', { processor: 'string' }); 6965 registerOption('cache_suffix', { processor: 'string' }); 6966 registerOption('base_url', { processor: 'string' }); 6967 registerOption('referrer_policy', { 6968 processor: 'string', 6969 default: '' 6970 }); 6971 registerOption('language_load', { 6972 processor: 'boolean', 6973 default: true 6974 }); 6975 registerOption('inline', { 6976 processor: 'boolean', 6977 default: false 6978 }); 6979 registerOption('iframe_attrs', { 6980 processor: 'object', 6981 default: {} 6982 }); 6983 registerOption('doctype', { 6984 processor: 'string', 6985 default: '<!DOCTYPE html>' 6986 }); 6987 registerOption('document_base_url', { 6988 processor: 'string', 6989 default: editor.documentBaseUrl 6990 }); 6991 registerOption('body_id', { 6992 processor: bodyOptionProcessor(editor, 'tinymce'), 6993 default: 'tinymce' 6994 }); 6995 registerOption('body_class', { 6996 processor: bodyOptionProcessor(editor), 6997 default: '' 6998 }); 6999 registerOption('content_security_policy', { 7000 processor: 'string', 7001 default: '' 7002 }); 7003 registerOption('br_in_pre', { 7004 processor: 'boolean', 7005 default: true 7006 }); 7007 registerOption('forced_root_block', { 7008 processor: value => { 7009 const valid = isString(value) && isNotEmpty(value); 7010 if (valid) { 7011 return { 7012 value, 7013 valid 7014 }; 7015 } else { 7016 return { 7017 valid: false, 7018 message: 'Must be a non-empty string.' 7019 }; 7020 } 7021 }, 7022 default: 'p' 7023 }); 7024 registerOption('forced_root_block_attrs', { 7025 processor: 'object', 7026 default: {} 7027 }); 7028 registerOption('newline_behavior', { 7029 processor: value => { 7030 const valid = contains$2([ 7031 'block', 7032 'linebreak', 7033 'invert', 7034 'default' 7035 ], value); 7036 return valid ? { 7037 value, 7038 valid 7039 } : { 7040 valid: false, 7041 message: 'Must be one of: block, linebreak, invert or default.' 7042 }; 7043 }, 7044 default: 'default' 7045 }); 7046 registerOption('br_newline_selector', { 7047 processor: 'string', 7048 default: '.mce-toc h2,figcaption,caption' 7049 }); 7050 registerOption('no_newline_selector', { 7051 processor: 'string', 7052 default: '' 7053 }); 7054 registerOption('keep_styles', { 7055 processor: 'boolean', 7056 default: true 7057 }); 7058 registerOption('end_container_on_empty_block', { 7059 processor: value => { 7060 if (isBoolean(value)) { 7061 return { 7062 valid: true, 7063 value 7064 }; 7065 } else if (isString(value)) { 7066 return { 7067 valid: true, 7068 value 7069 }; 7070 } else { 7071 return { 7072 valid: false, 7073 message: 'Must be boolean or a string' 7074 }; 7075 } 7076 }, 7077 default: 'blockquote' 7078 }); 7079 registerOption('font_size_style_values', { 7080 processor: 'string', 7081 default: 'xx-small,x-small,small,medium,large,x-large,xx-large' 7082 }); 7083 registerOption('font_size_legacy_values', { 7084 processor: 'string', 7085 default: 'xx-small,small,medium,large,x-large,xx-large,300%' 7086 }); 7087 registerOption('font_size_classes', { 7088 processor: 'string', 7089 default: '' 7090 }); 7091 registerOption('automatic_uploads', { 7092 processor: 'boolean', 7093 default: true 7094 }); 7095 registerOption('images_reuse_filename', { 7096 processor: 'boolean', 7097 default: false 7098 }); 7099 registerOption('images_replace_blob_uris', { 7100 processor: 'boolean', 7101 default: true 7102 }); 7103 registerOption('icons', { 7104 processor: 'string', 7105 default: '' 7106 }); 7107 registerOption('icons_url', { 7108 processor: 'string', 7109 default: '' 7110 }); 7111 registerOption('images_upload_url', { 7112 processor: 'string', 7113 default: '' 7114 }); 7115 registerOption('images_upload_base_path', { 7116 processor: 'string', 7117 default: '' 7118 }); 7119 registerOption('images_upload_credentials', { 7120 processor: 'boolean', 7121 default: false 7122 }); 7123 registerOption('images_upload_handler', { processor: 'function' }); 7124 registerOption('language', { 7125 processor: 'string', 7126 default: 'en' 7127 }); 7128 registerOption('language_url', { 7129 processor: 'string', 7130 default: '' 7131 }); 7132 registerOption('entity_encoding', { 7133 processor: 'string', 7134 default: 'named' 7135 }); 7136 registerOption('indent', { 7137 processor: 'boolean', 7138 default: true 7139 }); 7140 registerOption('indent_before', { 7141 processor: 'string', 7142 default: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' + 'tfoot,tbody,tr,section,details,summary,article,hgroup,aside,f
vendor: 7,091 bytes, lines 7142-7368
7142igure,figcaption,option,optgroup,datalist' 7143 }); 7144 registerOption('indent_after', { 7145 processor: 'string', 7146 default: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' + 'tfoot,tbody,tr,section,details,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist' 7147 }); 7148 registerOption('indent_use_margin', { 7149 processor: 'boolean', 7150 default: false 7151 }); 7152 registerOption('indentation', { 7153 processor: 'string', 7154 default: '40px' 7155 }); 7156 registerOption('content_css', { 7157 processor: value => { 7158 const valid = value === false || isString(value) || isArrayOf(value, isString); 7159 if (valid) { 7160 if (isString(value)) { 7161 return { 7162 value: map$3(value.split(','), trim$4), 7163 valid 7164 }; 7165 } else if (isArray$1(value)) { 7166 return { 7167 value, 7168 valid 7169 }; 7170 } else if (value === false) { 7171 return { 7172 value: [], 7173 valid 7174 }; 7175 } else { 7176 return { 7177 value, 7178 valid 7179 }; 7180 } 7181 } else { 7182 return { 7183 valid: false, 7184 message: 'Must be false, a string or an array of strings.' 7185 }; 7186 } 7187 }, 7188 default: isInline$1(editor) ? [] : ['default'] 7189 }); 7190 registerOption('content_style', { processor: 'string' }); 7191 registerOption('content_css_cors', { 7192 processor: 'boolean', 7193 default: false 7194 }); 7195 registerOption('font_css', { 7196 processor: value => { 7197 const valid = isString(value) || isArrayOf(value, isString); 7198 if (valid) { 7199 const newValue = isArray$1(value) ? value : map$3(value.split(','), trim$4); 7200 return { 7201 value: newValue, 7202 valid 7203 }; 7204 } else { 7205 return { 7206 valid: false, 7207 message: 'Must be a string or an array of strings.' 7208 }; 7209 } 7210 }, 7211 default: [] 7212 }); 7213 registerOption('inline_boundaries', { 7214 processor: 'boolean', 7215 default: true 7216 }); 7217 registerOption('inline_boundaries_selector', { 7218 processor: 'string', 7219 default: 'a[href],code,span.mce-annotation' 7220 }); 7221 registerOption('object_resizing', { 7222 processor: value => { 7223 const valid = isBoolean(value) || isString(value); 7224 if (valid) { 7225 if (value === false || deviceDetection$1.isiPhone() || deviceDetection$1.isiPad()) { 7226 return { 7227 value: '', 7228 valid 7229 }; 7230 } else { 7231 return { 7232 value: value === true ? 'table,img,figure.image,div,video,iframe' : value, 7233 valid 7234 }; 7235 } 7236 } else { 7237 return { 7238 valid: false, 7239 message: 'Must be boolean or a string' 7240 }; 7241 } 7242 }, 7243 default: !isTouch 7244 }); 7245 registerOption('resize_img_proportional', { 7246 processor: 'boolean', 7247 default: true 7248 }); 7249 registerOption('event_root', { processor: 'string' }); 7250 registerOption('service_message', { processor: 'string' }); 7251 registerOption('theme', { 7252 processor: value => value === false || isString(value) || isFunction(value), 7253 default: 'silver' 7254 }); 7255 registerOption('theme_url', { processor: 'string' }); 7256 registerOption('formats', { processor: 'object' }); 7257 registerOption('format_empty_lines', { 7258 processor: 'boolean', 7259 default: false 7260 }); 7261 registerOption('format_noneditable_selector', { 7262 processor: 'string', 7263 default: '' 7264 }); 7265 registerOption('preview_styles', { 7266 processor: value => { 7267 const valid = value === false || isString(value); 7268 if (valid) { 7269 return { 7270 value: value === false ? '' : value, 7271 valid 7272 }; 7273 } else { 7274 return { 7275 valid: false, 7276 message: 'Must be false or a string' 7277 }; 7278 } 7279 }, 7280 default: 'font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow' 7281 }); 7282 registerOption('custom_ui_selector', { 7283 processor: 'string', 7284 default: '' 7285 }); 7286 registerOption('hidden_input', { 7287 processor: 'boolean', 7288 default: true 7289 }); 7290 registerOption('submit_patch', { 7291 processor: 'boolean', 7292 default: true 7293 }); 7294 registerOption('encoding', { processor: 'string' }); 7295 registerOption('add_form_submit_trigger', { 7296 processor: 'boolean', 7297 default: true 7298 }); 7299 registerOption('add_unload_trigger', { 7300 processor: 'boolean', 7301 default: true 7302 }); 7303 registerOption('custom_undo_redo_levels', { 7304 processor: 'number', 7305 default: 0 7306 }); 7307 registerOption('disable_nodechange', { 7308 processor: 'boolean', 7309 default: false 7310 }); 7311 registerOption('disabled', { 7312 processor: value => { 7313 if (isBoolean(value)) { 7314 if (editor.initialized && isDisabled$1(editor) !== value) { 7315 Promise.resolve().then(() => { 7316 fireDisabledStateChange(editor, value); 7317 }); 7318 } 7319 return { 7320 valid: true, 7321 value 7322 }; 7323 } 7324 return { 7325 valid: false, 7326 message: 'The value must be a boolean.' 7327 }; 7328 }, 7329 default: false 7330 }); 7331 registerOption('readonly', { 7332 processor: 'boolean', 7333 default: false 7334 }); 7335 registerOption('editable_root', { 7336 processor: 'boolean', 7337 default: true 7338 }); 7339 registerOption('plugins', { 7340 processor: 'string[]', 7341 default: [] 7342 }); 7343 registerOption('external_plugins', { processor: 'object' }); 7344 registerOption('forced_plugins', { processor: 'string[]' }); 7345 registerOption('model', { 7346 processor: 'string', 7347 default: editor.hasPlugin('rtc') ? 'plugin' : 'dom' 7348 }); 7349 registerOption('model_url', { processor: 'string' }); 7350 registerOption('block_unsupported_drop', { 7351 processor: 'boolean', 7352 default: true 7353 }); 7354 registerOption('visual', { 7355 processor: 'boolean', 7356 default: true 7357 }); 7358 registerOption('visual_table_class', { 7359 processor: 'string', 7360 default: 'mce-item-table' 7361 }); 7362 registerOption('visual_anchor_class', { 7363 processor: 'string', 7364 default: 'mce-item-anchor' 7365 }); 7366 registerOption('iframe_aria_text', { 7367 processor: 'string', 7368 default: 'Rich Text Area'.concat(editor.hasPlugin('help') ? '. Press ALT
vendor: 15,423 bytes, lines 7368-7825
7368-0 for help.' : '') 7369 }); 7370 registerOption('setup', { processor: 'function' }); 7371 registerOption('init_instance_callback', { processor: 'function' }); 7372 registerOption('url_converter', { 7373 processor: 'function', 7374 default: editor.convertURL 7375 }); 7376 registerOption('url_converter_scope', { 7377 processor: 'object', 7378 default: editor 7379 }); 7380 registerOption('urlconverter_callback', { processor: 'function' }); 7381 registerOption('allow_conditional_comments', { 7382 processor: 'boolean', 7383 default: false 7384 }); 7385 registerOption('allow_html_data_urls', { 7386 processor: 'boolean', 7387 default: false 7388 }); 7389 registerOption('allow_svg_data_urls', { processor: 'boolean' }); 7390 registerOption('allow_html_in_named_anchor', { 7391 processor: 'boolean', 7392 default: false 7393 }); 7394 registerOption('allow_script_urls', { 7395 processor: 'boolean', 7396 default: false 7397 }); 7398 registerOption('allow_unsafe_link_target', { 7399 processor: 'boolean', 7400 default: false 7401 }); 7402 registerOption('allow_mathml_annotation_encodings', { 7403 processor: value => { 7404 const valid = isArrayOf(value, isString); 7405 return valid ? { 7406 value, 7407 valid 7408 } : { 7409 valid: false, 7410 message: 'Must be an array of strings.' 7411 }; 7412 }, 7413 default: [] 7414 }); 7415 registerOption('convert_fonts_to_spans', { 7416 processor: 'boolean', 7417 default: true, 7418 deprecated: true 7419 }); 7420 registerOption('fix_list_elements', { 7421 processor: 'boolean', 7422 default: false 7423 }); 7424 registerOption('preserve_cdata', { 7425 processor: 'boolean', 7426 default: false 7427 }); 7428 registerOption('remove_trailing_brs', { 7429 processor: 'boolean', 7430 default: true 7431 }); 7432 registerOption('pad_empty_with_br', { 7433 processor: 'boolean', 7434 default: false 7435 }); 7436 registerOption('inline_styles', { 7437 processor: 'boolean', 7438 default: true, 7439 deprecated: true 7440 }); 7441 registerOption('element_format', { 7442 processor: 'string', 7443 default: 'html' 7444 }); 7445 registerOption('entities', { processor: 'string' }); 7446 registerOption('schema', { 7447 processor: 'string', 7448 default: 'html5' 7449 }); 7450 registerOption('convert_urls', { 7451 processor: 'boolean', 7452 default: true 7453 }); 7454 registerOption('relative_urls', { 7455 processor: 'boolean', 7456 default: true 7457 }); 7458 registerOption('remove_script_host', { 7459 processor: 'boolean', 7460 default: true 7461 }); 7462 registerOption('custom_elements', { processor: stringOrObjectProcessor }); 7463 registerOption('extended_valid_elements', { processor: 'string' }); 7464 registerOption('invalid_elements', { processor: 'string' }); 7465 registerOption('invalid_styles', { processor: stringOrObjectProcessor }); 7466 registerOption('valid_children', { processor: 'string' }); 7467 registerOption('valid_classes', { processor: stringOrObjectProcessor }); 7468 registerOption('valid_elements', { processor: 'string' }); 7469 registerOption('valid_styles', { processor: stringOrObjectProcessor }); 7470 registerOption('verify_html', { 7471 processor: 'boolean', 7472 default: true 7473 }); 7474 registerOption('auto_focus', { processor: value => isString(value) || value === true }); 7475 registerOption('browser_spellcheck', { 7476 processor: 'boolean', 7477 default: false 7478 }); 7479 registerOption('protect', { processor: 'array' }); 7480 registerOption('images_file_types', { 7481 processor: 'string', 7482 default: 'jpeg,jpg,jpe,jfi,jif,jfif,png,gif,bmp,webp' 7483 }); 7484 registerOption('deprecation_warnings', { 7485 processor: 'boolean', 7486 default: true 7487 }); 7488 registerOption('a11y_advanced_options', { 7489 processor: 'boolean', 7490 default: false 7491 }); 7492 registerOption('api_key', { processor: 'string' }); 7493 registerOption('license_key', { processor: 'string' }); 7494 registerOption('paste_block_drop', { 7495 processor: 'boolean', 7496 default: false 7497 }); 7498 registerOption('paste_data_images', { 7499 processor: 'boolean', 7500 default: true 7501 }); 7502 registerOption('paste_preprocess', { processor: 'function' }); 7503 registerOption('paste_postprocess', { processor: 'function' }); 7504 registerOption('paste_webkit_styles', { 7505 processor: 'string', 7506 default: 'none' 7507 }); 7508 registerOption('paste_remove_styles_if_webkit', { 7509 processor: 'boolean', 7510 default: true 7511 }); 7512 registerOption('paste_merge_formats', { 7513 processor: 'boolean', 7514 default: true 7515 }); 7516 registerOption('smart_paste', { 7517 processor: 'boolean', 7518 default: true 7519 }); 7520 registerOption('paste_as_text', { 7521 processor: 'boolean', 7522 default: false 7523 }); 7524 registerOption('paste_tab_spaces', { 7525 processor: 'number', 7526 default: 4 7527 }); 7528 registerOption('text_patterns', { 7529 processor: value => { 7530 if (isArrayOf(value, isObject) || value === false) { 7531 const patterns = value === false ? [] : value; 7532 return { 7533 value: fromRawPatterns(patterns), 7534 valid: true 7535 }; 7536 } else { 7537 return { 7538 valid: false, 7539 message: 'Must be an array of objects or false.' 7540 }; 7541 } 7542 }, 7543 default: [ 7544 { 7545 start: '*', 7546 end: '*', 7547 format: 'italic' 7548 }, 7549 { 7550 start: '**', 7551 end: '**', 7552 format: 'bold' 7553 }, 7554 { 7555 start: '#', 7556 format: 'h1', 7557 trigger: 'space' 7558 }, 7559 { 7560 start: '##', 7561 format: 'h2', 7562 trigger: 'space' 7563 }, 7564 { 7565 start: '###', 7566 format: 'h3', 7567 trigger: 'space' 7568 }, 7569 { 7570 start: '####', 7571 format: 'h4', 7572 trigger: 'space' 7573 }, 7574 { 7575 start: '#####', 7576 format: 'h5', 7577 trigger: 'space' 7578 }, 7579 { 7580 start: '######', 7581 format: 'h6', 7582 trigger: 'space' 7583 }, 7584 { 7585 start: '1.', 7586 cmd: 'InsertOrderedList', 7587 trigger: 'space' 7588 }, 7589 { 7590 start: '*', 7591 cmd: 'InsertUnorderedList', 7592 trigger: 'space' 7593 }, 7594 { 7595 start: '-', 7596 cmd: 'InsertUnorderedList', 7597 trigger: 'space' 7598 }, 7599 { 7600 start: '>', 7601 cmd: 'mceBlockQuote', 7602 trigger: 'space' 7603 }, 7604 { 7605 start: '---', 7606 cmd: 'InsertHorizontalRule', 7607 trigger: 'space' 7608 } 7609 ] 7610 }); 7611 registerOption('text_patterns_lookup', { 7612 processor: value => { 7613 if (isFunction(value)) { 7614 return { 7615 value: fromRawPatternsLookup(value), 7616 valid: true 7617 }; 7618 } else { 7619 return { 7620 valid: false, 7621 message: 'Must be a single function' 7622 }; 7623 } 7624 }, 7625 default: _ctx => [] 7626 }); 7627 registerOption('noneditable_class', { 7628 processor: 'string', 7629 default: 'mceNonEditable' 7630 }); 7631 registerOption('editable_class', { 7632 processor: 'string', 7633 default: 'mceEditable' 7634 }); 7635 registerOption('noneditable_regexp', { 7636 processor: value => { 7637 if (isArrayOf(value, isRegExp)) { 7638 return { 7639 value, 7640 valid: true 7641 }; 7642 } else if (isRegExp(value)) { 7643 return { 7644 value: [value], 7645 valid: true 7646 }; 7647 } else { 7648 return { 7649 valid: false, 7650 message: 'Must be a RegExp or an array of RegExp.' 7651 }; 7652 } 7653 }, 7654 default: [] 7655 }); 7656 registerOption('table_tab_navigation', { 7657 processor: 'boolean', 7658 default: true 7659 }); 7660 registerOption('highlight_on_focus', { 7661 processor: 'boolean', 7662 default: true 7663 }); 7664 registerOption('xss_sanitization', { 7665 processor: 'boolean', 7666 default: true 7667 }); 7668 registerOption('details_initial_state', { 7669 processor: value => { 7670 const valid = contains$2([ 7671 'inherited', 7672 'collapsed', 7673 'expanded' 7674 ], value); 7675 return valid ? { 7676 value, 7677 valid 7678 } : { 7679 valid: false, 7680 message: 'Must be one of: inherited, collapsed, or expanded.' 7681 }; 7682 }, 7683 default: 'inherited' 7684 }); 7685 registerOption('details_serialized_state', { 7686 processor: value => { 7687 const valid = contains$2([ 7688 'inherited', 7689 'collapsed', 7690 'expanded' 7691 ], value); 7692 return valid ? { 7693 value, 7694 valid 7695 } : { 7696 valid: false, 7697 message: 'Must be one of: inherited, collapsed, or expanded.' 7698 }; 7699 }, 7700 default: 'inherited' 7701 }); 7702 registerOption('init_content_sync', { 7703 processor: 'boolean', 7704 default: false 7705 }); 7706 registerOption('newdocument_content', { 7707 processor: 'string', 7708 default: '' 7709 }); 7710 registerOption('sandbox_iframes', { 7711 processor: 'boolean', 7712 default: true 7713 }); 7714 registerOption('sandbox_iframes_exclusions', { 7715 processor: 'string[]', 7716 default: [ 7717 'youtube.com', 7718 'youtu.be', 7719 'vimeo.com', 7720 'player.vimeo.com', 7721 'dailymotion.com', 7722 'embed.music.apple.com', 7723 'open.spotify.com', 7724 'giphy.com', 7725 'dai.ly', 7726 'codepen.io' 7727 ] 7728 }); 7729 registerOption('convert_unsafe_embeds', { 7730 processor: 'boolean', 7731 default: true 7732 }); 7733 editor.on('ScriptsLoaded', () => { 7734 registerOption('directionality', { 7735 processor: 'string', 7736 default: I18n.isRtl() ? 'rtl' : undefined 7737 }); 7738 registerOption('placeholder', { 7739 processor: 'string', 7740 default: DOM$a.getAttrib(editor.getElement(), 'placeholder') 7741 }); 7742 }); 7743 }; 7744 const getIframeAttrs = option('iframe_attrs'); 7745 const getDocType = option('doctype'); 7746 const getDocumentBaseUrl = option('document_base_url'); 7747 const getBodyId = option('body_id'); 7748 const getBodyClass = option('body_class'); 7749 const getContentSecurityPolicy = option('content_security_policy'); 7750 const shouldPutBrInPre$1 = option('br_in_pre'); 7751 const getForcedRootBlock = option('forced_root_block'); 7752 const getForcedRootBlockAttrs = option('forced_root_block_attrs'); 7753 const getNewlineBehavior = option('newline_behavior'); 7754 const getBrNewLineSelector = option('br_newline_selector'); 7755 const getNoNewLineSelector = option('no_newline_selector'); 7756 const shouldKeepStyles = option('keep_styles'); 7757 const shouldEndContainerOnEmptyBlock = option('end_container_on_empty_block'); 7758 const isAutomaticUploadsEnabled = option('automatic_uploads'); 7759 const shouldReuseFileName = option('images_reuse_filename'); 7760 const shouldReplaceBlobUris = option('images_replace_blob_uris'); 7761 const getIconPackName = option('icons'); 7762 const getIconsUrl = option('icons_url'); 7763 const getImageUploadUrl = option('images_upload_url'); 7764 const getImageUploadBasePath = option('images_upload_base_path'); 7765 const getImagesUploadCredentials = option('images_upload_credentials'); 7766 const getImagesUploadHandler = option('images_upload_handler'); 7767 const shouldUseContentCssCors = option('content_css_cors'); 7768 const getReferrerPolicy = option('referrer_policy'); 7769 const getLanguageCode = option('language'); 7770 const getLanguageUrl = option('language_url'); 7771 const shouldIndentUseMargin = option('indent_use_margin'); 7772 const getIndentation = option('indentation'); 7773 const getContentCss = option('content_css'); 7774 const getContentStyle = option('content_style'); 7775 const getFontCss = option('font_css'); 7776 const getDirectionality = option('directionality'); 7777 const getInlineBoundarySelector = option('inline_boundaries_selector'); 7778 const getObjectResizing = option('object_resizing'); 7779 const getResizeImgProportional = option('resize_img_proportional'); 7780 const getPlaceholder = option('placeholder'); 7781 const getEventRoot = option('event_root'); 7782 const getServiceMessage = option('service_message'); 7783 const getTheme = option('theme'); 7784 const getThemeUrl = option('theme_url'); 7785 const getModel = option('model'); 7786 const getModelUrl = option('model_url'); 7787 const isInlineBoundariesEnabled = option('inline_boundaries'); 7788 const getFormats = option('formats'); 7789 const getPreviewStyles = option('preview_styles'); 7790 const canFormatEmptyLines = option('format_empty_lines'); 7791 const getFormatNoneditableSelector = option('format_noneditable_selector'); 7792 const getCustomUiSelector = option('custom_ui_selector'); 7793 const isInline$1 = option('inline'); 7794 const hasHiddenInput = option('hidden_input'); 7795 const shouldPatchSubmit = option('submit_patch'); 7796 const shouldAddFormSubmitTrigger = option('add_form_submit_trigger'); 7797 const shouldAddUnloadTrigger = option('add_unload_trigger'); 7798 const getCustomUndoRedoLevels = option('custom_undo_redo_levels'); 7799 const shouldDisableNodeChange = option('disable_nodechange'); 7800 const isReadOnly$1 = option('readonly'); 7801 const hasEditableRoot$1 = option('editable_root'); 7802 const hasContentCssCors = option('content_css_cors'); 7803 const getPlugins = option('plugins'); 7804 const getExternalPlugins$1 = option('external_plugins'); 7805 const shouldBlockUnsupportedDrop = option('block_unsupported_drop'); 7806 const isVisualAidsEnabled = option('visual'); 7807 const getVisualAidsTableClass = option('visual_table_class'); 7808 const getVisualAidsAnchorClass = option('visual_anchor_class'); 7809 const getIframeAriaText = option('iframe_aria_text'); 7810 const getSetupCallback = option('setup'); 7811 const getInitInstanceCallback = option('init_instance_callback'); 7812 const getUrlConverterCallback = option('urlconverter_callback'); 7813 const getAutoFocus = option('auto_focus'); 7814 const shouldBrowserSpellcheck = option('browser_spellcheck'); 7815 const getProtect = option('protect'); 7816 const shouldPasteBlockDrop = option('paste_block_drop'); 7817 const shouldPasteDataImages = option('paste_data_images'); 7818 const getPastePreProcess = option('paste_preprocess'); 7819 const getPastePostProcess = option('paste_postprocess'); 7820 const getNewDocumentContent = option('newdocument_content'); 7821 const getPasteWebkitStyles = option('paste_webkit_styles'); 7822 const shouldPasteRemoveWebKitStyles = option('paste_remove_styles_if_webkit'); 7823 const shouldPasteMergeFormats = option('paste_merge_formats'); 7824 const isSmartPasteEnabled = option('smart_paste'); 7825 const isPasteAsTextEnabled = option('paste_as_text');
vendor: 12,420 bytes, lines 7826-8124
7826 const getPasteTabSpaces = option('paste_tab_spaces'); 7827 const shouldAllowHtmlDataUrls = option('allow_html_data_urls'); 7828 const getTextPatterns = option('text_patterns'); 7829 const getTextPatternsLookup = option('text_patterns_lookup'); 7830 const getNonEditableClass = option('noneditable_class'); 7831 const getEditableClass = option('editable_class'); 7832 const getNonEditableRegExps = option('noneditable_regexp'); 7833 const shouldPreserveCData = option('preserve_cdata'); 7834 const shouldHighlightOnFocus = option('highlight_on_focus'); 7835 const shouldSanitizeXss = option('xss_sanitization'); 7836 const shouldUseDocumentWrite = option('init_content_sync'); 7837 const hasTextPatternsLookup = editor => editor.options.isSet('text_patterns_lookup'); 7838 const getFontStyleValues = editor => Tools.explode(editor.options.get('font_size_style_values')); 7839 const getFontSizeClasses = editor => Tools.explode(editor.options.get('font_size_classes')); 7840 const isEncodingXml = editor => editor.options.get('encoding') === 'xml'; 7841 const getAllowedImageFileTypes = editor => Tools.explode(editor.options.get('images_file_types')); 7842 const hasTableTabNavigation = option('table_tab_navigation'); 7843 const getDetailsInitialState = option('details_initial_state'); 7844 const getDetailsSerializedState = option('details_serialized_state'); 7845 const shouldSandboxIframes = option('sandbox_iframes'); 7846 const getSandboxIframesExclusions = editor => editor.options.get('sandbox_iframes_exclusions'); 7847 const shouldConvertUnsafeEmbeds = option('convert_unsafe_embeds'); 7848 const getLicenseKey = option('license_key'); 7849 const getApiKey = option('api_key'); 7850 const isDisabled$1 = option('disabled'); 7851 7852 const isElement$3 = isElement$6; 7853 const isText$5 = isText$b; 7854 const removeNode$1 = node => { 7855 const parentNode = node.parentNode; 7856 if (parentNode) { 7857 parentNode.removeChild(node); 7858 } 7859 }; 7860 const trimCount = text => { 7861 const trimmedText = trim$2(text); 7862 return { 7863 count: text.length - trimmedText.length, 7864 text: trimmedText 7865 }; 7866 }; 7867 const deleteZwspChars = caretContainer => { 7868 let idx; 7869 while ((idx = caretContainer.data.lastIndexOf(ZWSP$1)) !== -1) { 7870 caretContainer.deleteData(idx, 1); 7871 } 7872 }; 7873 const removeUnchanged = (caretContainer, pos) => { 7874 remove$2(caretContainer); 7875 return pos; 7876 }; 7877 const removeTextAndReposition = (caretContainer, pos) => { 7878 const before = trimCount(caretContainer.data.substr(0, pos.offset())); 7879 const after = trimCount(caretContainer.data.substr(pos.offset())); 7880 const text = before.text + after.text; 7881 if (text.length > 0) { 7882 deleteZwspChars(caretContainer); 7883 return CaretPosition(caretContainer, pos.offset() - before.count); 7884 } else { 7885 return pos; 7886 } 7887 }; 7888 const removeElementAndReposition = (caretContainer, pos) => { 7889 const parentNode = pos.container(); 7890 const newPosition = indexOf$1(from(parentNode.childNodes), caretContainer).map(index => { 7891 return index < pos.offset() ? CaretPosition(parentNode, pos.offset() - 1) : pos; 7892 }).getOr(pos); 7893 remove$2(caretContainer); 7894 return newPosition; 7895 }; 7896 const removeTextCaretContainer = (caretContainer, pos) => isText$5(caretContainer) && pos.container() === caretContainer ? removeTextAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos); 7897 const removeElementCaretContainer = (caretContainer, pos) => pos.container() === caretContainer.parentNode ? removeElementAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos); 7898 const removeAndReposition = (container, pos) => CaretPosition.isTextPosition(pos) ? removeTextCaretContainer(container, pos) : removeElementCaretContainer(container, pos); 7899 const remove$2 = caretContainerNode => { 7900 if (isElement$3(caretContainerNode) && isCaretContainer$2(caretContainerNode)) { 7901 if (hasContent(caretContainerNode)) { 7902 caretContainerNode.removeAttribute('data-mce-caret'); 7903 } else { 7904 removeNode$1(caretContainerNode); 7905 } 7906 } 7907 if (isText$5(caretContainerNode)) { 7908 deleteZwspChars(caretContainerNode); 7909 if (caretContainerNode.data.length === 0) { 7910 removeNode$1(caretContainerNode); 7911 } 7912 } 7913 }; 7914 7915 const isContentEditableFalse$8 = isContentEditableFalse$b; 7916 const isMedia$1 = isMedia$2; 7917 const isTableCell$1 = isTableCell$3; 7918 const inlineFakeCaretSelector = '*[contentEditable=false],video,audio,embed,object'; 7919 const getAbsoluteClientRect = (root, element, before) => { 7920 const clientRect = collapse(element.getBoundingClientRect(), before); 7921 let scrollX; 7922 let scrollY; 7923 if (root.tagName === 'BODY') { 7924 const docElm = root.ownerDocument.documentElement; 7925 scrollX = root.scrollLeft || docElm.scrollLeft; 7926 scrollY = root.scrollTop || docElm.scrollTop; 7927 } else { 7928 const rootRect = root.getBoundingClientRect(); 7929 scrollX = root.scrollLeft - rootRect.left; 7930 scrollY = root.scrollTop - rootRect.top; 7931 } 7932 clientRect.left += scrollX; 7933 clientRect.right += scrollX; 7934 clientRect.top += scrollY; 7935 clientRect.bottom += scrollY; 7936 clientRect.width = 1; 7937 let margin = element.offsetWidth - element.clientWidth; 7938 if (margin > 0) { 7939 if (before) { 7940 margin *= -1; 7941 } 7942 clientRect.left += margin; 7943 clientRect.right += margin; 7944 } 7945 return clientRect; 7946 }; 7947 const trimInlineCaretContainers = root => { 7948 var _a, _b; 7949 const fakeCaretTargetNodes = descendants(SugarElement.fromDom(root), inlineFakeCaretSelector); 7950 for (let i = 0; i < fakeCaretTargetNodes.length; i++) { 7951 const node = fakeCaretTargetNodes[i].dom; 7952 let sibling = node.previousSibling; 7953 if (endsWithCaretContainer$1(sibling)) { 7954 const data = sibling.data; 7955 if (data.length === 1) { 7956 (_a = sibling.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(sibling); 7957 } else { 7958 sibling.deleteData(data.length - 1, 1); 7959 } 7960 } 7961 sibling = node.nextSibling; 7962 if (startsWithCaretContainer$1(sibling)) { 7963 const data = sibling.data; 7964 if (data.length === 1) { 7965 (_b = sibling.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(sibling); 7966 } else { 7967 sibling.deleteData(0, 1); 7968 } 7969 } 7970 } 7971 }; 7972 const FakeCaret = (editor, root, isBlock, hasFocus) => { 7973 const lastVisualCaret = value$2(); 7974 let cursorInterval; 7975 let caretContainerNode; 7976 const caretBlock = getForcedRootBlock(editor); 7977 const dom = editor.dom; 7978 const show = (before, element) => { 7979 let rng; 7980 hide(); 7981 if (isTableCell$1(element)) { 7982 return null; 7983 } 7984 if (isBlock(element)) { 7985 const caretContainer = insertBlock(caretBlock, element, before); 7986 const clientRect = getAbsoluteClientRect(root, element, before); 7987 dom.setStyle(caretContainer, 'top', clientRect.top); 7988 dom.setStyle(caretContainer, 'caret-color', 'transparent'); 7989 caretContainerNode = caretContainer; 7990 const caret = dom.create('div', { 7991 'class': 'mce-visual-caret', 7992 'data-mce-bogus': 'all' 7993 }); 7994 dom.setStyles(caret, { ...clientRect }); 7995 dom.add(root, caret); 7996 lastVisualCaret.set({ 7997 caret, 7998 element, 7999 before 8000 }); 8001 if (before) { 8002 dom.addClass(caret, 'mce-visual-caret-before'); 8003 } 8004 startBlink(); 8005 rng = element.ownerDocument.createRange(); 8006 rng.setStart(caretContainer, 0); 8007 rng.setEnd(caretContainer, 0); 8008 } else { 8009 caretContainerNode = insertInline$1(element, before); 8010 rng = element.ownerDocument.createRange(); 8011 if (isInlineFakeCaretTarget(caretContainerNode.nextSibling)) { 8012 rng.setStart(caretContainerNode, 0); 8013 rng.setEnd(caretContainerNode, 0); 8014 } else { 8015 rng.setStart(caretContainerNode, 1); 8016 rng.setEnd(caretContainerNode, 1); 8017 } 8018 return rng; 8019 } 8020 return rng; 8021 }; 8022 const hide = () => { 8023 trimInlineCaretContainers(root); 8024 if (caretContainerNode) { 8025 remove$2(caretContainerNode); 8026 caretContainerNode = null; 8027 } 8028 lastVisualCaret.on(caretState => { 8029 dom.remove(caretState.caret); 8030 lastVisualCaret.clear(); 8031 }); 8032 if (cursorInterval) { 8033 clearInterval(cursorInterval); 8034 cursorInterval = undefined; 8035 } 8036 }; 8037 const startBlink = () => { 8038 cursorInterval = setInterval(() => { 8039 lastVisualCaret.on(caretState => { 8040 if (hasFocus()) { 8041 dom.toggleClass(caretState.caret, 'mce-visual-caret-hidden'); 8042 } else { 8043 dom.addClass(caretState.caret, 'mce-visual-caret-hidden'); 8044 } 8045 }); 8046 }, 500); 8047 }; 8048 const reposition = () => { 8049 lastVisualCaret.on(caretState => { 8050 const clientRect = getAbsoluteClientRect(root, caretState.element, caretState.before); 8051 dom.setStyles(caretState.caret, { ...clientRect }); 8052 }); 8053 }; 8054 const destroy = () => clearInterval(cursorInterval); 8055 const getCss = () => '.mce-visual-caret {' + 'position: absolute;' + 'background-color: black;' + 'background-color: currentcolor;' + '}' + '.mce-visual-caret-hidden {' + 'display: none;' + '}' + '*[data-mce-caret] {' + 'position: absolute;' + 'left: -1000px;' + 'right: auto;' + 'top: 0;' + 'margin: 0;' + 'padding: 0;' + '}'; 8056 return { 8057 show, 8058 hide, 8059 getCss, 8060 reposition, 8061 destroy 8062 }; 8063 }; 8064 const isFakeCaretTableBrowser = () => Env.browser.isFirefox(); 8065 const isInlineFakeCaretTarget = node => isContentEditableFalse$8(node) || isMedia$1(node); 8066 const isFakeCaretTarget = node => { 8067 const isTarget = isInlineFakeCaretTarget(node) || isTable$2(node) && isFakeCaretTableBrowser(); 8068 return isTarget && parentElement(SugarElement.fromDom(node)).exists(isEditable$2); 8069 }; 8070 8071 const isContentEditableTrue$1 = isContentEditableTrue$3; 8072 const isContentEditableFalse$7 = isContentEditableFalse$b; 8073 const isMedia = isMedia$2; 8074 const isBlockLike = matchStyleValues('display', 'block table table-cell table-row table-caption list-item'); 8075 const isCaretContainer = isCaretContainer$2; 8076 const isCaretContainerBlock = isCaretContainerBlock$1; 8077 const isElement$2 = isElement$6; 8078 const isText$4 = isText$b; 8079 const isCaretCandidate$1 = isCaretCandidate$3; 8080 const isForwards = direction => direction === 1; 8081 const isBackwards = direction => direction === -1; 8082 const skipCaretContainers = (walk, shallow) => { 8083 let node; 8084 while (node = walk(shallow)) { 8085 if (!isCaretContainerBlock(node)) { 8086 return node; 8087 } 8088 } 8089 return null; 8090 }; 8091 const findNode = (node, direction, predicateFn, rootNode, shallow) => { 8092 const walker = new DomTreeWalker(node, rootNode); 8093 const isCefOrCaretContainer = isContentEditableFalse$7(node) || isCaretContainerBlock(node); 8094 let tempNode; 8095 if (isBackwards(direction)) { 8096 if (isCefOrCaretContainer) { 8097 tempNode = skipCaretContainers(walker.prev.bind(walker), true); 8098 if (predicateFn(tempNode)) { 8099 return tempNode; 8100 } 8101 } 8102 while (tempNode = skipCaretContainers(walker.prev.bind(walker), shallow)) { 8103 if (predicateFn(tempNode)) { 8104 return tempNode; 8105 } 8106 } 8107 } 8108 if (isForwards(direction)) { 8109 if (isCefOrCaretContainer) { 8110 tempNode = skipCaretContainers(walker.next.bind(walker), true); 8111 if (predicateFn(tempNode)) { 8112 return tempNode; 8113 } 8114 } 8115 while (tempNode = skipCaretContainers(walker.next.bind(walker), shallow)) { 8116 if (predicateFn(tempNode)) { 8117 return tempNode; 8118 } 8119 } 8120 } 8121 return null; 8122 }; 8123 const getEditingHost = (node, rootNode) => { 8124 const isCETrue = node => isContentEditableTrue$1(node.dom);
vendor: 5,993 bytes, lines 8125-8298
8125 const isRoot = node => node.dom === rootNode; 8126 return ancestor$4(SugarElement.fromDom(node), isCETrue, isRoot).map(elm => elm.dom).getOr(rootNode); 8127 }; 8128 const getParentBlock$3 = (node, rootNode) => { 8129 while (node && node !== rootNode) { 8130 if (isBlockLike(node)) { 8131 return node; 8132 } 8133 node = node.parentNode; 8134 } 8135 return null; 8136 }; 8137 const isInSameBlock = (caretPosition1, caretPosition2, rootNode) => getParentBlock$3(caretPosition1.container(), rootNode) === getParentBlock$3(caretPosition2.container(), rootNode); 8138 const getChildNodeAtRelativeOffset = (relativeOffset, caretPosition) => { 8139 if (!caretPosition) { 8140 return Optional.none(); 8141 } 8142 const container = caretPosition.container(); 8143 const offset = caretPosition.offset(); 8144 if (!isElement$2(container)) { 8145 return Optional.none(); 8146 } 8147 return Optional.from(container.childNodes[offset + relativeOffset]); 8148 }; 8149 const beforeAfter = (before, node) => { 8150 var _a; 8151 const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document; 8152 const range = doc.createRange(); 8153 if (before) { 8154 range.setStartBefore(node); 8155 range.setEndBefore(node); 8156 } else { 8157 range.setStartAfter(node); 8158 range.setEndAfter(node); 8159 } 8160 return range; 8161 }; 8162 const isNodesInSameBlock = (root, node1, node2) => getParentBlock$3(node1, root) === getParentBlock$3(node2, root); 8163 const lean = (left, root, node) => { 8164 const siblingName = left ? 'previousSibling' : 'nextSibling'; 8165 let tempNode = node; 8166 while (tempNode && tempNode !== root) { 8167 let sibling = tempNode[siblingName]; 8168 if (sibling && isCaretContainer(sibling)) { 8169 sibling = sibling[siblingName]; 8170 } 8171 if (isContentEditableFalse$7(sibling) || isMedia(sibling)) { 8172 if (isNodesInSameBlock(root, sibling, tempNode)) { 8173 return sibling; 8174 } 8175 break; 8176 } 8177 if (isCaretCandidate$1(sibling)) { 8178 break; 8179 } 8180 tempNode = tempNode.parentNode; 8181 } 8182 return null; 8183 }; 8184 const before$2 = curry(beforeAfter, true); 8185 const after$2 = curry(beforeAfter, false); 8186 const normalizeRange = (direction, root, range) => { 8187 let node; 8188 const leanLeft = curry(lean, true, root); 8189 const leanRight = curry(lean, false, root); 8190 const container = range.startContainer; 8191 const offset = range.startOffset; 8192 if (isCaretContainerBlock$1(container)) { 8193 const block = isText$4(container) ? container.parentNode : container; 8194 const location = block.getAttribute('data-mce-caret'); 8195 if (location === 'before') { 8196 node = block.nextSibling; 8197 if (isFakeCaretTarget(node)) { 8198 return before$2(node); 8199 } 8200 } 8201 if (location === 'after') { 8202 node = block.previousSibling; 8203 if (isFakeCaretTarget(node)) { 8204 return after$2(node); 8205 } 8206 } 8207 } 8208 if (!range.collapsed) { 8209 return range; 8210 } 8211 if (isText$b(container)) { 8212 if (isCaretContainer(container)) { 8213 if (direction === 1) { 8214 node = leanRight(container); 8215 if (node) { 8216 return before$2(node); 8217 } 8218 node = leanLeft(container); 8219 if (node) { 8220 return after$2(node); 8221 } 8222 } 8223 if (direction === -1) { 8224 node = leanLeft(container); 8225 if (node) { 8226 return after$2(node); 8227 } 8228 node = leanRight(container); 8229 if (node) { 8230 return before$2(node); 8231 } 8232 } 8233 return range; 8234 } 8235 if (endsWithCaretContainer$1(container) && offset >= container.data.length - 1) { 8236 if (direction === 1) { 8237 node = leanRight(container); 8238 if (node) { 8239 return before$2(node); 8240 } 8241 } 8242 return range; 8243 } 8244 if (startsWithCaretContainer$1(container) && offset <= 1) { 8245 if (direction === -1) { 8246 node = leanLeft(container); 8247 if (node) { 8248 return after$2(node); 8249 } 8250 } 8251 return range; 8252 } 8253 if (offset === container.data.length) { 8254 node = leanRight(container); 8255 if (node) { 8256 return before$2(node); 8257 } 8258 return range; 8259 } 8260 if (offset === 0) { 8261 node = leanLeft(container); 8262 if (node) { 8263 return after$2(node); 8264 } 8265 return range; 8266 } 8267 } 8268 return range; 8269 }; 8270 const getRelativeCefElm = (forward, caretPosition) => getChildNodeAtRelativeOffset(forward ? 0 : -1, caretPosition).filter(isContentEditableFalse$7); 8271 const getNormalizedRangeEndPoint = (direction, root, range) => { 8272 const normalizedRange = normalizeRange(direction, root, range); 8273 return direction === -1 ? CaretPosition.fromRangeStart(normalizedRange) : CaretPosition.fromRangeEnd(normalizedRange); 8274 }; 8275 const getElementFromPosition = pos => Optional.from(pos.getNode()).map(SugarElement.fromDom); 8276 const getElementFromPrevPosition = pos => Optional.from(pos.getNode(true)).map(SugarElement.fromDom); 8277 const getVisualCaretPosition = (walkFn, caretPosition) => { 8278 let pos = caretPosition; 8279 while (pos = walkFn(pos)) { 8280 if (pos.isVisible()) { 8281 return pos; 8282 } 8283 } 8284 return pos; 8285 }; 8286 const isMoveInsideSameBlock = (from, to) => { 8287 const inSameBlock = isInSameBlock(from, to); 8288 if (!inSameBlock && isBr$6(from.getNode())) { 8289 return true; 8290 } 8291 return inSameBlock; 8292 }; 8293 8294 const isContentEditableFalse$6 = isContentEditableFalse$b; 8295 const isText$3 = isText$b; 8296 const isElement$1 = isElement$6; 8297 const isBr$2 = isBr$6; 8298 const isCaretCandidate = isCaretCandidate$3;
vendor: 4,458 bytes, lines 8299-8420
8299 const isAtomic = isAtomic$1; 8300 const isEditableCaretCandidate = isEditableCaretCandidate$1; 8301 const getParents$3 = (node, root) => { 8302 const parents = []; 8303 let tempNode = node; 8304 while (tempNode && tempNode !== root) { 8305 parents.push(tempNode); 8306 tempNode = tempNode.parentNode; 8307 } 8308 return parents; 8309 }; 8310 const nodeAtIndex = (container, offset) => { 8311 if (container.hasChildNodes() && offset < container.childNodes.length) { 8312 return container.childNodes[offset]; 8313 } 8314 return null; 8315 }; 8316 const getCaretCandidatePosition = (direction, node) => { 8317 if (isForwards(direction)) { 8318 if (isCaretCandidate(node.previousSibling) && !isText$3(node.previousSibling)) { 8319 return CaretPosition.before(node); 8320 } 8321 if (isText$3(node)) { 8322 return CaretPosition(node, 0); 8323 } 8324 } 8325 if (isBackwards(direction)) { 8326 if (isCaretCandidate(node.nextSibling) && !isText$3(node.nextSibling)) { 8327 return CaretPosition.after(node); 8328 } 8329 if (isText$3(node)) { 8330 return CaretPosition(node, node.data.length); 8331 } 8332 } 8333 if (isBackwards(direction)) { 8334 if (isBr$2(node)) { 8335 return CaretPosition.before(node); 8336 } 8337 return CaretPosition.after(node); 8338 } 8339 return CaretPosition.before(node); 8340 }; 8341 const moveForwardFromBr = (root, nextNode) => { 8342 const nextSibling = nextNode.nextSibling; 8343 if (nextSibling && isCaretCandidate(nextSibling)) { 8344 if (isText$3(nextSibling)) { 8345 return CaretPosition(nextSibling, 0); 8346 } else { 8347 return CaretPosition.before(nextSibling); 8348 } 8349 } else { 8350 return findCaretPosition$1(1, CaretPosition.after(nextNode), root); 8351 } 8352 }; 8353 const findCaretPosition$1 = (direction, startPos, root) => { 8354 let node; 8355 let nextNode; 8356 let innerNode; 8357 let caretPosition; 8358 if (!isElement$1(root) || !startPos) { 8359 return null; 8360 } 8361 if (startPos.isEqual(CaretPosition.after(root)) && root.lastChild) { 8362 caretPosition = CaretPosition.after(root.lastChild); 8363 if (isBackwards(direction) && isCaretCandidate(root.lastChild) && isElement$1(root.lastChild)) { 8364 return isBr$2(root.lastChild) ? CaretPosition.before(root.lastChild) : caretPosition; 8365 } 8366 } else { 8367 caretPosition = startPos; 8368 } 8369 const container = caretPosition.container(); 8370 let offset = caretPosition.offset(); 8371 if (isText$3(container)) { 8372 if (isBackwards(direction) && offset > 0) { 8373 return CaretPosition(container, --offset); 8374 } 8375 if (isForwards(direction) && offset < container.length) { 8376 return CaretPosition(container, ++offset); 8377 } 8378 node = container; 8379 } else { 8380 if (isBackwards(direction) && offset > 0) { 8381 nextNode = nodeAtIndex(container, offset - 1); 8382 if (isCaretCandidate(nextNode)) { 8383 if (!isAtomic(nextNode)) { 8384 innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode); 8385 if (innerNode) { 8386 if (isText$3(innerNode)) { 8387 return CaretPosition(innerNode, innerNode.data.length); 8388 } 8389 return CaretPosition.after(innerNode); 8390 } 8391 } 8392 if (isText$3(nextNode)) { 8393 return CaretPosition(nextNode, nextNode.data.length); 8394 } 8395 return CaretPosition.before(nextNode); 8396 } 8397 } 8398 if (isForwards(direction) && offset < container.childNodes.length) { 8399 nextNode = nodeAtIndex(container, offset); 8400 if (isCaretCandidate(nextNode)) { 8401 if (isBr$2(nextNode)) { 8402 return moveForwardFromBr(root, nextNode); 8403 } 8404 if (!isAtomic(nextNode)) { 8405 innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode); 8406 if (innerNode) { 8407 if (isText$3(innerNode)) { 8408 return CaretPosition(innerNode, 0); 8409 } 8410 return CaretPosition.before(innerNode); 8411 } 8412 } 8413 if (isText$3(nextNode)) { 8414 return CaretPosition(nextNode, 0); 8415 } 8416 return CaretPosition.after(nextNode); 8417 } 8418 } 8419 node = nextNode ? nextNode : caretPosition.getNode(); 8420 }
vendor: 1,211 bytes, lines 8421-8447
8421 if (node && (isForwards(direction) && caretPosition.isAtEnd() || isBackwards(direction) && caretPosition.isAtStart())) { 8422 node = findNode(node, direction, always, root, true); 8423 if (isEditableCaretCandidate(node, root)) { 8424 return getCaretCandidatePosition(direction, node); 8425 } 8426 } 8427 nextNode = node ? findNode(node, direction, isEditableCaretCandidate, root) : node; 8428 const rootContentEditableFalseElm = last$1(filter$5(getParents$3(container, root), isContentEditableFalse$6)); 8429 if (rootContentEditableFalseElm && (!nextNode || !rootContentEditableFalseElm.contains(nextNode))) { 8430 if (isForwards(direction)) { 8431 caretPosition = CaretPosition.after(rootContentEditableFalseElm); 8432 } else { 8433 caretPosition = CaretPosition.before(rootContentEditableFalseElm); 8434 } 8435 return caretPosition; 8436 } 8437 if (nextNode) { 8438 return getCaretCandidatePosition(direction, nextNode); 8439 } 8440 return null; 8441 }; 8442 const CaretWalker = root => ({ 8443 next: caretPosition => { 8444 return findCaretPosition$1(1, caretPosition, root); 8445 }, 8446 prev: caretPosition => { 8447 return findCaretPosition$1(-1
vendor: 10,714 bytes, lines 8447-8727
8447, caretPosition, root); 8448 } 8449 }); 8450 8451 const walkToPositionIn = (forward, root, start) => { 8452 const position = forward ? CaretPosition.before(start) : CaretPosition.after(start); 8453 return fromPosition(forward, root, position); 8454 }; 8455 const afterElement = node => isBr$6(node) ? CaretPosition.before(node) : CaretPosition.after(node); 8456 const isBeforeOrStart = position => { 8457 if (CaretPosition.isTextPosition(position)) { 8458 return position.offset() === 0; 8459 } else { 8460 return isCaretCandidate$3(position.getNode()); 8461 } 8462 }; 8463 const isAfterOrEnd = position => { 8464 if (CaretPosition.isTextPosition(position)) { 8465 const container = position.container(); 8466 return position.offset() === container.data.length; 8467 } else { 8468 return isCaretCandidate$3(position.getNode(true)); 8469 } 8470 }; 8471 const isBeforeAfterSameElement = (from, to) => !CaretPosition.isTextPosition(from) && !CaretPosition.isTextPosition(to) && from.getNode() === to.getNode(true); 8472 const isAtBr = position => !CaretPosition.isTextPosition(position) && isBr$6(position.getNode()); 8473 const shouldSkipPosition = (forward, from, to) => { 8474 if (forward) { 8475 return !isBeforeAfterSameElement(from, to) && !isAtBr(from) && isAfterOrEnd(from) && isBeforeOrStart(to); 8476 } else { 8477 return !isBeforeAfterSameElement(to, from) && isBeforeOrStart(from) && isAfterOrEnd(to); 8478 } 8479 }; 8480 const fromPosition = (forward, root, pos) => { 8481 const walker = CaretWalker(root); 8482 return Optional.from(forward ? walker.next(pos) : walker.prev(pos)); 8483 }; 8484 const navigate = (forward, root, from) => fromPosition(forward, root, from).bind(to => { 8485 if (isInSameBlock(from, to, root) && shouldSkipPosition(forward, from, to)) { 8486 return fromPosition(forward, root, to); 8487 } else { 8488 return Optional.some(to); 8489 } 8490 }); 8491 const navigateIgnore = (forward, root, from, ignoreFilter) => navigate(forward, root, from).bind(pos => ignoreFilter(pos) ? navigateIgnore(forward, root, pos, ignoreFilter) : Optional.some(pos)); 8492 const positionIn = (forward, element) => { 8493 const startNode = forward ? element.firstChild : element.lastChild; 8494 if (isText$b(startNode)) { 8495 return Optional.some(CaretPosition(startNode, forward ? 0 : startNode.data.length)); 8496 } else if (startNode) { 8497 if (isCaretCandidate$3(startNode)) { 8498 return Optional.some(forward ? CaretPosition.before(startNode) : afterElement(startNode)); 8499 } else { 8500 return walkToPositionIn(forward, element, startNode); 8501 } 8502 } else { 8503 return Optional.none(); 8504 } 8505 }; 8506 const nextPosition = curry(fromPosition, true); 8507 const prevPosition = curry(fromPosition, false); 8508 const firstPositionIn = curry(positionIn, true); 8509 const lastPositionIn = curry(positionIn, false); 8510 8511 const CARET_ID = '_mce_caret'; 8512 const isCaretNode = node => isElement$6(node) && node.id === CARET_ID; 8513 const getParentCaretContainer = (body, node) => { 8514 let currentNode = node; 8515 while (currentNode && currentNode !== body) { 8516 if (isCaretNode(currentNode)) { 8517 return currentNode; 8518 } 8519 currentNode = currentNode.parentNode; 8520 } 8521 return null; 8522 }; 8523 8524 const isStringPathBookmark = bookmark => isString(bookmark.start); 8525 const isRangeBookmark = bookmark => has$2(bookmark, 'rng'); 8526 const isIdBookmark = bookmark => has$2(bookmark, 'id'); 8527 const isIndexBookmark = bookmark => has$2(bookmark, 'name'); 8528 const isPathBookmark = bookmark => Tools.isArray(bookmark.start); 8529 8530 const isForwardBookmark = bookmark => !isIndexBookmark(bookmark) && isBoolean(bookmark.forward) ? bookmark.forward : true; 8531 const addBogus = (dom, node) => { 8532 if (isElement$6(node) && dom.isBlock(node) && !node.innerHTML) { 8533 node.innerHTML = '<br data-mce-bogus="1" />'; 8534 } 8535 return node; 8536 }; 8537 const resolveCaretPositionBookmark = (dom, bookmark) => { 8538 const startPos = Optional.from(resolve$1(dom.getRoot(), bookmark.start)); 8539 const endPos = Optional.from(resolve$1(dom.getRoot(), bookmark.end)); 8540 return lift2(startPos, endPos, (start, end) => { 8541 const range = dom.createRng(); 8542 range.setStart(start.container(), start.offset()); 8543 range.setEnd(end.container(), end.offset()); 8544 return { 8545 range, 8546 forward: isForwardBookmark(bookmark) 8547 }; 8548 }); 8549 }; 8550 const insertZwsp = (node, rng) => { 8551 var _a; 8552 const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document; 8553 const textNode = doc.createTextNode(ZWSP$1); 8554 node.appendChild(textNode); 8555 rng.setStart(textNode, 0); 8556 rng.setEnd(textNode, 0); 8557 }; 8558 const isEmpty$1 = node => !node.hasChildNodes(); 8559 const tryFindRangePosition = (node, rng) => lastPositionIn(node).fold(never, pos => { 8560 rng.setStart(pos.container(), pos.offset()); 8561 rng.setEnd(pos.container(), pos.offset()); 8562 return true; 8563 }); 8564 const padEmptyCaretContainer = (root, node, rng) => { 8565 if (isEmpty$1(node) && getParentCaretContainer(root, node)) { 8566 insertZwsp(node, rng); 8567 return true; 8568 } else { 8569 return false; 8570 } 8571 }; 8572 const setEndPoint = (dom, start, bookmark, rng) => { 8573 const point = bookmark[start ? 'start' : 'end']; 8574 const root = dom.getRoot(); 8575 if (point) { 8576 let node = root; 8577 let offset = point[0]; 8578 for (let i = point.length - 1; node && i >= 1; i--) { 8579 const children = node.childNodes; 8580 if (padEmptyCaretContainer(root, node, rng)) { 8581 return true; 8582 } 8583 if (point[i] > children.length - 1) { 8584 if (padEmptyCaretContainer(root, node, rng)) { 8585 return true; 8586 } 8587 return tryFindRangePosition(node, rng); 8588 } 8589 node = children[point[i]]; 8590 } 8591 if (isText$b(node)) { 8592 offset = Math.min(point[0], node.data.length); 8593 } 8594 if (isElement$6(node)) { 8595 offset = Math.min(point[0], node.childNodes.length); 8596 } 8597 if (start) { 8598 rng.setStart(node, offset); 8599 } else { 8600 rng.setEnd(node, offset); 8601 } 8602 } 8603 return true; 8604 }; 8605 const isValidTextNode = node => isText$b(node) && node.data.length > 0; 8606 const restoreEndPoint = (dom, suffix, bookmark) => { 8607 const marker = dom.get(bookmark.id + '_' + suffix); 8608 const markerParent = marker === null || marker === void 0 ? void 0 : marker.parentNode; 8609 const keep = bookmark.keep; 8610 if (marker && markerParent) { 8611 let container; 8612 let offset; 8613 if (suffix === 'start') { 8614 if (!keep) { 8615 container = markerParent; 8616 offset = dom.nodeIndex(marker); 8617 } else { 8618 if (marker.hasChildNodes()) { 8619 container = marker.firstChild; 8620 offset = 1; 8621 } else if (isValidTextNode(marker.nextSibling)) { 8622 container = marker.nextSibling; 8623 offset = 0; 8624 } else if (isValidTextNode(marker.previousSibling)) { 8625 container = marker.previousSibling; 8626 offset = marker.previousSibling.data.length; 8627 } else { 8628 container = markerParent; 8629 offset = dom.nodeIndex(marker) + 1; 8630 } 8631 } 8632 } else { 8633 if (!keep) { 8634 container = markerParent; 8635 offset = dom.nodeIndex(marker); 8636 } else { 8637 if (marker.hasChildNodes()) { 8638 container = marker.firstChild; 8639 offset = 1; 8640 } else if (isValidTextNode(marker.previousSibling)) { 8641 container = marker.previousSibling; 8642 offset = marker.previousSibling.data.length; 8643 } else { 8644 container = markerParent; 8645 offset = dom.nodeIndex(marker); 8646 } 8647 } 8648 } 8649 if (!keep) { 8650 const prev = marker.previousSibling; 8651 const next = marker.nextSibling; 8652 Tools.each(Tools.grep(marker.childNodes), node => { 8653 if (isText$b(node)) { 8654 node.data = node.data.replace(/\uFEFF/g, ''); 8655 } 8656 }); 8657 let otherMarker; 8658 while (otherMarker = dom.get(bookmark.id + '_' + suffix)) { 8659 dom.remove(otherMarker, true); 8660 } 8661 if (isText$b(next) && isText$b(prev) && !Env.browser.isOpera()) { 8662 const idx = prev.data.length; 8663 prev.appendData(next.data); 8664 dom.remove(next); 8665 container = prev; 8666 offset = idx; 8667 } 8668 } 8669 return Optional.some(CaretPosition(container, offset)); 8670 } else { 8671 return Optional.none(); 8672 } 8673 }; 8674 const resolvePaths = (dom, bookmark) => { 8675 const range = dom.createRng(); 8676 if (setEndPoint(dom, true, bookmark, range) && setEndPoint(dom, false, bookmark, range)) { 8677 return Optional.some({ 8678 range, 8679 forward: isForwardBookmark(bookmark) 8680 }); 8681 } else { 8682 return Optional.none(); 8683 } 8684 }; 8685 const resolveId = (dom, bookmark) => { 8686 const startPos = restoreEndPoint(dom, 'start', bookmark); 8687 const endPos = restoreEndPoint(dom, 'end', bookmark); 8688 return lift2(startPos, endPos.or(startPos), (spos, epos) => { 8689 const range = dom.createRng(); 8690 range.setStart(addBogus(dom, spos.container()), spos.offset()); 8691 range.setEnd(addBogus(dom, epos.container()), epos.offset()); 8692 return { 8693 range, 8694 forward: isForwardBookmark(bookmark) 8695 }; 8696 }); 8697 }; 8698 const resolveIndex = (dom, bookmark) => Optional.from(dom.select(bookmark.name)[bookmark.index]).map(elm => { 8699 const range = dom.createRng(); 8700 range.selectNode(elm); 8701 return { 8702 range, 8703 forward: true 8704 }; 8705 }); 8706 const resolve = (selection, bookmark) => { 8707 const dom = selection.dom; 8708 if (bookmark) { 8709 if (isPathBookmark(bookmark)) { 8710 return resolvePaths(dom, bookmark); 8711 } else if (isStringPathBookmark(bookmark)) { 8712 return resolveCaretPositionBookmark(dom, bookmark); 8713 } else if (isIdBookmark(bookmark)) { 8714 return resolveId(dom, bookmark); 8715 } else if (isIndexBookmark(bookmark)) { 8716 return resolveIndex(dom, bookmark); 8717 } else if (isRangeBookmark(bookmark)) { 8718 return Optional.some({ 8719 range: bookmark.rng, 8720 forward: isForwardBookmark(bookmark) 8721 }); 8722 } 8723 } 8724 return Optional.none(); 8725 }; 8726 8727 const getBookmark$
87272 = (selection, type, normalized) => { 8728 return getBookmark$3
vendor: 15,457 bytes, lines 8728-9120
8728(selection, type, normalized); 8729 }; 8730 const moveToBookmark = (selection, bookmark) => { 8731 resolve(selection, bookmark).each(({range, forward}) => { 8732 selection.setRng(range, forward); 8733 }); 8734 }; 8735 const isBookmarkNode$1 = node => { 8736 return isElement$6(node) && node.tagName === 'SPAN' && node.getAttribute('data-mce-type') === 'bookmark'; 8737 }; 8738 8739 const is = expected => actual => expected === actual; 8740 const isNbsp = is(nbsp); 8741 const isWhiteSpace = chr => chr !== '' && ' \f\n\r\t\x0B'.indexOf(chr) !== -1; 8742 const isContent = chr => !isWhiteSpace(chr) && !isNbsp(chr) && !isZwsp$2(chr); 8743 8744 const getRanges$1 = selection => { 8745 const ranges = []; 8746 if (selection) { 8747 for (let i = 0; i < selection.rangeCount; i++) { 8748 ranges.push(selection.getRangeAt(i)); 8749 } 8750 } 8751 return ranges; 8752 }; 8753 const getSelectedNodes = ranges => { 8754 return bind$3(ranges, range => { 8755 const node = getSelectedNode(range); 8756 return node ? [SugarElement.fromDom(node)] : []; 8757 }); 8758 }; 8759 const hasMultipleRanges = selection => { 8760 return getRanges$1(selection).length > 1; 8761 }; 8762 8763 const getCellsFromRanges = ranges => filter$5(getSelectedNodes(ranges), isTableCell$2); 8764 const getCellsFromElement = elm => descendants(elm, 'td[data-mce-selected],th[data-mce-selected]'); 8765 const getCellsFromElementOrRanges = (ranges, element) => { 8766 const selectedCells = getCellsFromElement(element); 8767 return selectedCells.length > 0 ? selectedCells : getCellsFromRanges(ranges); 8768 }; 8769 const getCellsFromEditor = editor => getCellsFromElementOrRanges(getRanges$1(editor.selection.getSel()), SugarElement.fromDom(editor.getBody())); 8770 const getClosestTable = (cell, isRoot) => ancestor$3(cell, 'table', isRoot); 8771 8772 const getStartNode = rng => { 8773 const sc = rng.startContainer, so = rng.startOffset; 8774 if (isText$b(sc)) { 8775 return so === 0 ? Optional.some(SugarElement.fromDom(sc)) : Optional.none(); 8776 } else { 8777 return Optional.from(sc.childNodes[so]).map(SugarElement.fromDom); 8778 } 8779 }; 8780 const getEndNode = rng => { 8781 const ec = rng.endContainer, eo = rng.endOffset; 8782 if (isText$b(ec)) { 8783 return eo === ec.data.length ? Optional.some(SugarElement.fromDom(ec)) : Optional.none(); 8784 } else { 8785 return Optional.from(ec.childNodes[eo - 1]).map(SugarElement.fromDom); 8786 } 8787 }; 8788 const getFirstChildren = node => { 8789 return firstChild(node).fold(constant([node]), child => { 8790 return [node].concat(getFirstChildren(child)); 8791 }); 8792 }; 8793 const getLastChildren = node => { 8794 return lastChild(node).fold(constant([node]), child => { 8795 if (name(child) === 'br') { 8796 return prevSibling(child).map(sibling => { 8797 return [node].concat(getLastChildren(sibling)); 8798 }).getOr([]); 8799 } else { 8800 return [node].concat(getLastChildren(child)); 8801 } 8802 }); 8803 }; 8804 const hasAllContentsSelected = (elm, rng) => { 8805 return lift2(getStartNode(rng), getEndNode(rng), (startNode, endNode) => { 8806 const start = find$2(getFirstChildren(elm), curry(eq, startNode)); 8807 const end = find$2(getLastChildren(elm), curry(eq, endNode)); 8808 return start.isSome() && end.isSome(); 8809 }).getOr(false); 8810 }; 8811 const moveEndPoint = (dom, rng, node, start) => { 8812 const root = node; 8813 const walker = new DomTreeWalker(node, root); 8814 const moveCaretBeforeOnEnterElementsMap = filter$4(dom.schema.getMoveCaretBeforeOnEnterElements(), (_, name) => !contains$2([ 8815 'td', 8816 'th', 8817 'table' 8818 ], name.toLowerCase())); 8819 let currentNode = node; 8820 do { 8821 if (isText$b(currentNode) && Tools.trim(currentNode.data).length !== 0) { 8822 if (start) { 8823 rng.setStart(currentNode, 0); 8824 } else { 8825 rng.setEnd(currentNode, currentNode.data.length); 8826 } 8827 return; 8828 } 8829 if (moveCaretBeforeOnEnterElementsMap[currentNode.nodeName]) { 8830 if (start) { 8831 rng.setStartBefore(currentNode); 8832 } else { 8833 if (currentNode.nodeName === 'BR') { 8834 rng.setEndBefore(currentNode); 8835 } else { 8836 rng.setEndAfter(currentNode); 8837 } 8838 } 8839 return; 8840 } 8841 } while (currentNode = start ? walker.next() : walker.prev()); 8842 if (root.nodeName === 'BODY') { 8843 if (start) { 8844 rng.setStart(root, 0); 8845 } else { 8846 rng.setEnd(root, root.childNodes.length); 8847 } 8848 } 8849 }; 8850 const hasAnyRanges = editor => { 8851 const sel = editor.selection.getSel(); 8852 return isNonNullable(sel) && sel.rangeCount > 0; 8853 }; 8854 const runOnRanges = (editor, executor) => { 8855 const fakeSelectionNodes = getCellsFromEditor(editor); 8856 if (fakeSelectionNodes.length > 0) { 8857 each$e(fakeSelectionNodes, elem => { 8858 const node = elem.dom; 8859 const fakeNodeRng = editor.dom.createRng(); 8860 fakeNodeRng.setStartBefore(node); 8861 fakeNodeRng.setEndAfter(node); 8862 executor(fakeNodeRng, true); 8863 }); 8864 } else { 8865 executor(editor.selection.getRng(), false); 8866 } 8867 }; 8868 const preserve = (selection, fillBookmark, executor) => { 8869 const bookmark = getPersistentBookmark(selection, fillBookmark); 8870 executor(bookmark); 8871 selection.moveToBookmark(bookmark); 8872 }; 8873 8874 const isNode = node => isNumber(node === null || node === void 0 ? void 0 : node.nodeType); 8875 const isElementNode$1 = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node); 8876 const isElementDirectlySelected = (dom, node) => { 8877 if (isElementNode$1(node) && !/^(TD|TH)$/.test(node.nodeName)) { 8878 const selectedAttr = dom.getAttrib(node, 'data-mce-selected'); 8879 const value = parseInt(selectedAttr, 10); 8880 return !isNaN(value) && value > 0; 8881 } else { 8882 return false; 8883 } 8884 }; 8885 const preserveSelection = (editor, action, shouldMoveStart) => { 8886 const {selection, dom} = editor; 8887 const selectedNodeBeforeAction = selection.getNode(); 8888 const isSelectedBeforeNodeNoneditable = isContentEditableFalse$b(selectedNodeBeforeAction); 8889 preserve(selection, true, () => { 8890 action(); 8891 }); 8892 const isBeforeNodeStillNoneditable = isSelectedBeforeNodeNoneditable && isContentEditableFalse$b(selectedNodeBeforeAction); 8893 if (isBeforeNodeStillNoneditable && dom.isChildOf(selectedNodeBeforeAction, editor.getBody())) { 8894 editor.selection.select(selectedNodeBeforeAction); 8895 } else if (shouldMoveStart(selection.getStart())) { 8896 moveStartToNearestText(dom, selection); 8897 } 8898 }; 8899 const moveStartToNearestText = (dom, selection) => { 8900 var _a, _b; 8901 const rng = selection.getRng(); 8902 const {startContainer, startOffset} = rng; 8903 const selectedNode = selection.getNode(); 8904 if (isElementDirectlySelected(dom, selectedNode)) { 8905 return; 8906 } 8907 if (isElement$6(startContainer)) { 8908 const nodes = startContainer.childNodes; 8909 const root = dom.getRoot(); 8910 let walker; 8911 if (startOffset < nodes.length) { 8912 const startNode = nodes[startOffset]; 8913 walker = new DomTreeWalker(startNode, (_a = dom.getParent(startNode, dom.isBlock)) !== null && _a !== void 0 ? _a : root); 8914 } else { 8915 const startNode = nodes[nodes.length - 1]; 8916 walker = new DomTreeWalker(startNode, (_b = dom.getParent(startNode, dom.isBlock)) !== null && _b !== void 0 ? _b : root); 8917 walker.next(true); 8918 } 8919 for (let node = walker.current(); node; node = walker.next()) { 8920 if (dom.getContentEditable(node) === 'false') { 8921 return; 8922 } else if (isText$b(node) && !isWhiteSpaceNode$1(node)) { 8923 rng.setStart(node, 0); 8924 selection.setRng(rng); 8925 return; 8926 } 8927 } 8928 } 8929 }; 8930 const getNonWhiteSpaceSibling = (node, next, inc) => { 8931 if (node) { 8932 const nextName = next ? 'nextSibling' : 'previousSibling'; 8933 for (node = inc ? node : node[nextName]; node; node = node[nextName]) { 8934 if (isElement$6(node) || !isWhiteSpaceNode$1(node)) { 8935 return node; 8936 } 8937 } 8938 } 8939 return undefined; 8940 }; 8941 const isTextBlock$1 = (schema, node) => !!schema.getTextBlockElements()[node.nodeName.toLowerCase()] || isTransparentBlock(schema, node); 8942 const isValid = (ed, parent, child) => { 8943 return ed.schema.isValidChild(parent, child); 8944 }; 8945 const isWhiteSpaceNode$1 = (node, allowSpaces = false) => { 8946 if (isNonNullable(node) && isText$b(node)) { 8947 const data = allowSpaces ? node.data.replace(/ /g, '\xA0') : node.data; 8948 return isWhitespaceText(data); 8949 } else { 8950 return false; 8951 } 8952 }; 8953 const isEmptyTextNode$1 = node => { 8954 return isNonNullable(node) && isText$b(node) && node.length === 0; 8955 }; 8956 const isWrapNoneditableTarget = (editor, node) => { 8957 const baseDataSelector = '[data-mce-cef-wrappable]'; 8958 const formatNoneditableSelector = getFormatNoneditableSelector(editor); 8959 const selector = isEmpty$3(formatNoneditableSelector) ? baseDataSelector : `${ baseDataSelector },${ formatNoneditableSelector }`; 8960 return is$1(SugarElement.fromDom(node), selector); 8961 }; 8962 const isWrappableNoneditable = (editor, node) => { 8963 const dom = editor.dom; 8964 return isElementNode$1(node) && dom.getContentEditable(node) === 'false' && isWrapNoneditableTarget(editor, node) && dom.select('[contenteditable="true"]', node).length === 0; 8965 }; 8966 const replaceVars = (value, vars) => { 8967 if (isFunction(value)) { 8968 return value(vars); 8969 } else if (isNonNullable(vars)) { 8970 value = value.replace(/%(\w+)/g, (str, name) => { 8971 return vars[name] || str; 8972 }); 8973 } 8974 return value; 8975 }; 8976 const isEq$5 = (str1, str2) => { 8977 str1 = str1 || ''; 8978 str2 = str2 || ''; 8979 str1 = '' + (str1.nodeName || str1); 8980 str2 = '' + (str2.nodeName || str2); 8981 return str1.toLowerCase() === str2.toLowerCase(); 8982 }; 8983 const normalizeStyleValue = (value, name) => { 8984 if (isNullable(value)) { 8985 return null; 8986 } else { 8987 let strValue = String(value); 8988 if (name === 'color' || name === 'backgroundColor') { 8989 strValue = rgbaToHexString(strValue); 8990 } 8991 if (name === 'fontWeight' && value === 700) { 8992 strValue = 'bold'; 8993 } 8994 if (name === 'fontFamily') { 8995 strValue = strValue.replace(/[\'\"]/g, '').replace(/,\s+/g, ','); 8996 } 8997 return strValue; 8998 } 8999 }; 9000 const getStyle = (dom, node, name) => { 9001 const style = dom.getStyle(node, name); 9002 return normalizeStyleValue(style, name); 9003 }; 9004 const getTextDecoration = (dom, node) => { 9005 let decoration; 9006 dom.getParent(node, n => { 9007 if (isElement$6(n)) { 9008 decoration = dom.getStyle(n, 'text-decoration'); 9009 return !!decoration && decoration !== 'none'; 9010 } else { 9011 return false; 9012 } 9013 }); 9014 return decoration; 9015 }; 9016 const getParents$2 = (dom, node, selector) => { 9017 return dom.getParents(node, selector, dom.getRoot()); 9018 }; 9019 const isFormatPredicate = (editor, formatName, predicate) => { 9020 const formats = editor.formatter.get(formatName); 9021 return isNonNullable(formats) && exists(formats, predicate); 9022 }; 9023 const isVariableFormatName = (editor, formatName) => { 9024 const hasVariableValues = format => { 9025 const isVariableValue = val => isFunction(val) || val.length > 1 && val.charAt(0) === '%'; 9026 return exists([ 9027 'styles', 9028 'attributes' 9029 ], key => get$a(format, key).exists(field => { 9030 const fieldValues = isArray$1(field) ? field : values(field); 9031 return exists(fieldValues, isVariableValue); 9032 })); 9033 }; 9034 return isFormatPredicate(editor, formatName, hasVariableValues); 9035 }; 9036 const areSimilarFormats = (editor, formatName, otherFormatName) => { 9037 const validKeys = [ 9038 'inline', 9039 'block', 9040 'selector', 9041 'attributes', 9042 'styles', 9043 'classes' 9044 ]; 9045 const filterObj = format => filter$4(format, (_, key) => exists(validKeys, validKey => validKey === key)); 9046 return isFormatPredicate(editor, formatName, fmt1 => { 9047 const filteredFmt1 = filterObj(fmt1); 9048 return isFormatPredicate(editor, otherFormatName, fmt2 => { 9049 const filteredFmt2 = filterObj(fmt2); 9050 return equal$1(filteredFmt1, filteredFmt2); 9051 }); 9052 }); 9053 }; 9054 const isBlockFormat = format => hasNonNullableKey(format, 'block'); 9055 const isWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper === true; 9056 const isNonWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper !== true; 9057 const isSelectorFormat = format => hasNonNullableKey(format, 'selector'); 9058 const isInlineFormat = format => hasNonNullableKey(format, 'inline'); 9059 const isMixedFormat = format => isSelectorFormat(format) && isInlineFormat(format) && is$2(get$a(format, 'mixed'), true); 9060 const shouldExpandToSelector = format => isSelectorFormat(format) && format.expand !== false && !isInlineFormat(format); 9061 const getEmptyCaretContainers = node => { 9062 const nodes = []; 9063 let tempNode = node; 9064 while (tempNode) { 9065 if (isText$b(tempNode) && tempNode.data !== ZWSP$1 || tempNode.childNodes.length > 1) { 9066 return []; 9067 } 9068 if (isElement$6(tempNode)) { 9069 nodes.push(tempNode); 9070 } 9071 tempNode = tempNode.firstChild; 9072 } 9073 return nodes; 9074 }; 9075 const isCaretContainerEmpty = node => { 9076 return getEmptyCaretContainers(node).length > 0; 9077 }; 9078 const isEmptyCaretFormatElement = element => { 9079 return isCaretNode(element.dom) && isCaretContainerEmpty(element.dom); 9080 }; 9081 9082 const isBookmarkNode = isBookmarkNode$1; 9083 const getParents$1 = getParents$2; 9084 const isWhiteSpaceNode = isWhiteSpaceNode$1; 9085 const isTextBlock = isTextBlock$1; 9086 const isBogusBr = node => { 9087 return isBr$6(node) && node.getAttribute('data-mce-bogus') && !node.nextSibling; 9088 }; 9089 const findParentContentEditable = (dom, node) => { 9090 let parent = node; 9091 while (parent) { 9092 if (isElement$6(parent) && dom.getContentEditable(parent)) { 9093 return dom.getContentEditable(parent) === 'false' ? parent : node; 9094 } 9095 parent = parent.parentNode; 9096 } 9097 return node; 9098 }; 9099 const walkText = (start, node, offset, predicate) => { 9100 const str = node.data; 9101 if (start) { 9102 for (let i = offset; i > 0; i--) { 9103 if (predicate(str.charAt(i - 1))) { 9104 return i; 9105 } 9106 } 9107 } else { 9108 for (let i = offset; i < str.length; i++) { 9109 if (predicate(str.charAt(i))) { 9110 return i; 9111 } 9112 } 9113 } 9114 return -1; 9115 }; 9116 const findSpace = (start, node, offset) => walkText(start, node, offset, c => isNbsp(c) || isWhiteSpace(c)); 9117 const findContent = (start, node, offset) => walkText(start, node, offset, isContent); 9118 const findWordEndPoint = (dom, body, container, offset, start, includeTrailingSpaces) => { 9119 let lastTextNode; 9120 const
vendor: 10,118 bytes, lines 9120-9350
9120closestRoot = dom.getParent(container, node => isEditingHost(node) || dom.isBlock(node)); 9121 const rootNode = isNonNullable(closestRoot) ? closestRoot : body; 9122 const walk = (container, offset, pred) => { 9123 const textSeeker = TextSeeker(dom); 9124 const walker = start ? textSeeker.backwards : textSeeker.forwards; 9125 return Optional.from(walker(container, offset, (text, textOffset) => { 9126 if (isBookmarkNode(text.parentNode)) { 9127 return -1; 9128 } else { 9129 lastTextNode = text; 9130 return pred(start, text, textOffset); 9131 } 9132 }, rootNode)); 9133 }; 9134 const spaceResult = walk(container, offset, findSpace); 9135 return spaceResult.bind(result => includeTrailingSpaces ? walk(result.container, result.offset + (start ? -1 : 0), findContent) : Optional.some(result)).orThunk(() => lastTextNode ? Optional.some({ 9136 container: lastTextNode, 9137 offset: start ? 0 : lastTextNode.length 9138 }) : Optional.none()); 9139 }; 9140 const findSelectorEndPoint = (dom, formatList, rng, container, siblingName) => { 9141 const sibling = container[siblingName]; 9142 if (isText$b(container) && isEmpty$3(container.data) && sibling) { 9143 container = sibling; 9144 } 9145 const parents = getParents$1(dom, container); 9146 for (let i = 0; i < parents.length; i++) { 9147 for (let y = 0; y < formatList.length; y++) { 9148 const curFormat = formatList[y]; 9149 if (isNonNullable(curFormat.collapsed) && curFormat.collapsed !== rng.collapsed) { 9150 continue; 9151 } 9152 if (isSelectorFormat(curFormat) && dom.is(parents[i], curFormat.selector)) { 9153 return parents[i]; 9154 } 9155 } 9156 } 9157 return container; 9158 }; 9159 const findBlockEndPoint = (dom, formatList, container, siblingName) => { 9160 var _a; 9161 let node = container; 9162 const root = dom.getRoot(); 9163 const format = formatList[0]; 9164 if (isBlockFormat(format)) { 9165 node = format.wrapper ? null : dom.getParent(container, format.block, root); 9166 } 9167 if (!node) { 9168 const scopeRoot = (_a = dom.getParent(container, 'LI,TD,TH,SUMMARY')) !== null && _a !== void 0 ? _a : root; 9169 node = dom.getParent(isText$b(container) ? container.parentNode : container, node => node !== root && isTextBlock(dom.schema, node), scopeRoot); 9170 } 9171 if (node && isBlockFormat(format) && format.wrapper) { 9172 node = getParents$1(dom, node, 'ul,ol').reverse()[0] || node; 9173 } 9174 if (!node) { 9175 node = container; 9176 while (node && node[siblingName] && !dom.isBlock(node[siblingName])) { 9177 node = node[siblingName]; 9178 if (isEq$5(node, 'br')) { 9179 break; 9180 } 9181 } 9182 } 9183 return node || container; 9184 }; 9185 const isAtBlockBoundary$1 = (dom, root, container, siblingName) => { 9186 const parent = container.parentNode; 9187 if (isNonNullable(container[siblingName])) { 9188 return false; 9189 } else if (parent === root || isNullable(parent) || dom.isBlock(parent)) { 9190 return true; 9191 } else { 9192 return isAtBlockBoundary$1(dom, root, parent, siblingName); 9193 } 9194 }; 9195 const findParentContainer = (dom, formatList, container, offset, start, expandToBlock) => { 9196 let parent = container; 9197 const siblingName = start ? 'previousSibling' : 'nextSibling'; 9198 const root = dom.getRoot(); 9199 if (isText$b(container) && !isWhiteSpaceNode(container)) { 9200 if (start ? offset > 0 : offset < container.data.length) { 9201 return container; 9202 } 9203 } 9204 while (parent) { 9205 if (isEditingHost(parent)) { 9206 return container; 9207 } 9208 if (!formatList[0].block_expand && dom.isBlock(parent)) { 9209 return expandToBlock ? parent : container; 9210 } 9211 for (let sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) { 9212 const allowSpaces = isText$b(sibling) && !isAtBlockBoundary$1(dom, root, sibling, siblingName); 9213 if (!isBookmarkNode(sibling) && !isBogusBr(sibling) && !isWhiteSpaceNode(sibling, allowSpaces)) { 9214 return parent; 9215 } 9216 } 9217 if (parent === root || parent.parentNode === root) { 9218 container = parent; 9219 break; 9220 } 9221 parent = parent.parentNode; 9222 } 9223 return container; 9224 }; 9225 const isSelfOrParentBookmark = container => isBookmarkNode(container.parentNode) || isBookmarkNode(container); 9226 const expandRng = (dom, rng, formatList, expandOptions = {}) => { 9227 const {includeTrailingSpace = false, expandToBlock = true} = expandOptions; 9228 const editableHost = dom.getParent(rng.commonAncestorContainer, node => isEditingHost(node)); 9229 const root = isNonNullable(editableHost) ? editableHost : dom.getRoot(); 9230 let {startContainer, startOffset, endContainer, endOffset} = rng; 9231 const format = formatList[0]; 9232 if (isElement$6(startContainer) && startContainer.hasChildNodes()) { 9233 startContainer = getNode$1(startContainer, startOffset); 9234 if (isText$b(startContainer)) { 9235 startOffset = 0; 9236 } 9237 } 9238 if (isElement$6(endContainer) && endContainer.hasChildNodes()) { 9239 endContainer = getNode$1(endContainer, rng.collapsed ? endOffset : endOffset - 1); 9240 if (isText$b(endContainer)) { 9241 endOffset = endContainer.data.length; 9242 } 9243 } 9244 startContainer = findParentContentEditable(dom, startContainer); 9245 endContainer = findParentContentEditable(dom, endContainer); 9246 if (isSelfOrParentBookmark(startContainer)) { 9247 startContainer = isBookmarkNode(startContainer) ? startContainer : startContainer.parentNode; 9248 if (rng.collapsed) { 9249 startContainer = startContainer.previousSibling || startContainer; 9250 } else { 9251 startContainer = startContainer.nextSibling || startContainer; 9252 } 9253 if (isText$b(startContainer)) { 9254 startOffset = rng.collapsed ? startContainer.length : 0; 9255 } 9256 } 9257 if (isSelfOrParentBookmark(endContainer)) { 9258 endContainer = isBookmarkNode(endContainer) ? endContainer : endContainer.parentNode; 9259 if (rng.collapsed) { 9260 endContainer = endContainer.nextSibling || endContainer; 9261 } else { 9262 endContainer = endContainer.previousSibling || endContainer; 9263 } 9264 if (isText$b(endContainer)) { 9265 endOffset = rng.collapsed ? 0 : endContainer.length; 9266 } 9267 } 9268 if (rng.collapsed) { 9269 const startPoint = findWordEndPoint(dom, root, startContainer, startOffset, true, includeTrailingSpace); 9270 startPoint.each(({container, offset}) => { 9271 startContainer = container; 9272 startOffset = offset; 9273 }); 9274 const endPoint = findWordEndPoint(dom, root, endContainer, endOffset, false, includeTrailingSpace); 9275 endPoint.each(({container, offset}) => { 9276 endContainer = container; 9277 endOffset = offset; 9278 }); 9279 } 9280 if (isInlineFormat(format) || format.block_expand) { 9281 if (!isInlineFormat(format) || (!isText$b(startContainer) || startOffset === 0)) { 9282 startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true, expandToBlock); 9283 } 9284 if (!isInlineFormat(format) || (!isText$b(endContainer) || endOffset === endContainer.data.length)) { 9285 endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false, expandToBlock); 9286 } 9287 } 9288 if (shouldExpandToSelector(format)) { 9289 startContainer = findSelectorEndPoint(dom, formatList, rng, startContainer, 'previousSibling'); 9290 endContainer = findSelectorEndPoint(dom, formatList, rng, endContainer, 'nextSibling'); 9291 } 9292 if (isBlockFormat(format) || isSelectorFormat(format)) { 9293 startContainer = findBlockEndPoint(dom, formatList, startContainer, 'previousSibling'); 9294 endContainer = findBlockEndPoint(dom, formatList, endContainer, 'nextSibling'); 9295 if (isBlockFormat(format)) { 9296 if (!dom.isBlock(startContainer)) { 9297 startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true, expandToBlock); 9298 if (isText$b(startContainer)) { 9299 startOffset = 0; 9300 } 9301 } 9302 if (!dom.isBlock(endContainer)) { 9303 endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false, expandToBlock); 9304 if (isText$b(endContainer)) { 9305 endOffset = endContainer.data.length; 9306 } 9307 } 9308 } 9309 } 9310 if (isElement$6(startContainer) && startContainer.parentNode) { 9311 startOffset = dom.nodeIndex(startContainer); 9312 startContainer = startContainer.parentNode; 9313 } 9314 if (isElement$6(endContainer) && endContainer.parentNode) { 9315 endOffset = dom.nodeIndex(endContainer) + 1; 9316 endContainer = endContainer.parentNode; 9317 } 9318 return { 9319 startContainer, 9320 startOffset, 9321 endContainer, 9322 endOffset 9323 }; 9324 }; 9325 9326 const walk$3 = (dom, rng, callback) => { 9327 var _a; 9328 const startOffset = rng.startOffset; 9329 const startContainer = getNode$1(rng.startContainer, startOffset); 9330 const endOffset = rng.endOffset; 9331 const endContainer = getNode$1(rng.endContainer, endOffset - 1); 9332 const exclude = nodes => { 9333 const firstNode = nodes[0]; 9334 if (isText$b(firstNode) && firstNode === startContainer && startOffset >= firstNode.data.length) { 9335 nodes.splice(0, 1); 9336 } 9337 const lastNode = nodes[nodes.length - 1]; 9338 if (endOffset === 0 && nodes.length > 0 && lastNode === endContainer && isText$b(lastNode)) { 9339 nodes.splice(nodes.length - 1, 1); 9340 } 9341 return nodes; 9342 }; 9343 const collectSiblings = (node, name, endNode) => { 9344 const siblings = []; 9345 for (; node && node !== endNode; node = node[name]) { 9346 siblings.push(node); 9347 } 9348 return siblings; 9349 }; 9350 const findEndPoint = (node, root) => dom.getParent(node, node =>
vendor: 29,940 bytes, lines 9350-10171
9350 node.parentNode === root, root); 9351 const walkBoundary = (startNode, endNode, next) => { 9352 const siblingName = next ? 'nextSibling' : 'previousSibling'; 9353 for (let node = startNode, parent = node.parentNode; node && node !== endNode; node = parent) { 9354 parent = node.parentNode; 9355 const siblings = collectSiblings(node === startNode ? node : node[siblingName], siblingName); 9356 if (siblings.length) { 9357 if (!next) { 9358 siblings.reverse(); 9359 } 9360 callback(exclude(siblings)); 9361 } 9362 } 9363 }; 9364 if (startContainer === endContainer) { 9365 return callback(exclude([startContainer])); 9366 } 9367 const ancestor = (_a = dom.findCommonAncestor(startContainer, endContainer)) !== null && _a !== void 0 ? _a : dom.getRoot(); 9368 if (dom.isChildOf(startContainer, endContainer)) { 9369 return walkBoundary(startContainer, ancestor, true); 9370 } 9371 if (dom.isChildOf(endContainer, startContainer)) { 9372 return walkBoundary(endContainer, ancestor); 9373 } 9374 const startPoint = findEndPoint(startContainer, ancestor) || startContainer; 9375 const endPoint = findEndPoint(endContainer, ancestor) || endContainer; 9376 walkBoundary(startContainer, startPoint, true); 9377 const siblings = collectSiblings(startPoint === startContainer ? startPoint : startPoint.nextSibling, 'nextSibling', endPoint === endContainer ? endPoint.nextSibling : endPoint); 9378 if (siblings.length) { 9379 callback(exclude(siblings)); 9380 } 9381 walkBoundary(endContainer, endPoint); 9382 }; 9383 9384 const validBlocks = [ 9385 'pre[class*=language-][contenteditable="false"]', 9386 'figure.image', 9387 'div[data-ephox-embed-iri]', 9388 'div.tiny-pageembed', 9389 'div.mce-toc', 9390 'div[data-mce-toc]' 9391 ]; 9392 const isZeroWidth = elem => isText$c(elem) && get$3(elem) === ZWSP$1; 9393 const context = (editor, elem, wrapName, nodeName) => parent(elem).fold(() => 'skipping', parent => { 9394 if (nodeName === 'br' || isZeroWidth(elem)) { 9395 return 'valid'; 9396 } else if (isAnnotation(elem)) { 9397 return 'existing'; 9398 } else if (isCaretNode(elem.dom)) { 9399 return 'caret'; 9400 } else if (exists(validBlocks, selector => is$1(elem, selector))) { 9401 return 'valid-block'; 9402 } else if (!isValid(editor, wrapName, nodeName) || !isValid(editor, name(parent), wrapName)) { 9403 return 'invalid-child'; 9404 } else { 9405 return 'valid'; 9406 } 9407 }); 9408 9409 const applyWordGrab = (editor, rng) => { 9410 const r = expandRng(editor.dom, rng, [{ inline: 'span' }]); 9411 rng.setStart(r.startContainer, r.startOffset); 9412 rng.setEnd(r.endContainer, r.endOffset); 9413 editor.selection.setRng(rng); 9414 }; 9415 const applyAnnotation = (elem, masterUId, data, annotationName, decorate, directAnnotation) => { 9416 const {uid = masterUId, ...otherData} = data; 9417 add$2(elem, annotation()); 9418 set$4(elem, `${ dataAnnotationId() }`, uid); 9419 set$4(elem, `${ dataAnnotation() }`, annotationName); 9420 const {attributes = {}, classes = []} = decorate(uid, otherData); 9421 setAll$1(elem, attributes); 9422 add(elem, classes); 9423 if (directAnnotation) { 9424 if (classes.length > 0) { 9425 set$4(elem, `${ dataAnnotationClasses() }`, classes.join(',')); 9426 } 9427 const attributeNames = keys(attributes); 9428 if (attributeNames.length > 0) { 9429 set$4(elem, `${ dataAnnotationAttributes() }`, attributeNames.join(',')); 9430 } 9431 } 9432 }; 9433 const removeDirectAnnotation = elem => { 9434 remove$6(elem, annotation()); 9435 remove$9(elem, `${ dataAnnotationId() }`); 9436 remove$9(elem, `${ dataAnnotation() }`); 9437 remove$9(elem, `${ dataAnnotationActive() }`); 9438 const customAttrNames = getOpt(elem, `${ dataAnnotationAttributes() }`).map(names => names.split(',')).getOr([]); 9439 const customClasses = getOpt(elem, `${ dataAnnotationClasses() }`).map(names => names.split(',')).getOr([]); 9440 each$e(customAttrNames, name => remove$9(elem, name)); 9441 remove$3(elem, customClasses); 9442 remove$9(elem, `${ dataAnnotationClasses() }`); 9443 remove$9(elem, `${ dataAnnotationAttributes() }`); 9444 }; 9445 const makeAnnotation = (eDoc, uid, data, annotationName, decorate) => { 9446 const master = SugarElement.fromTag('span', eDoc); 9447 applyAnnotation(master, uid, data, annotationName, decorate, false); 9448 return master; 9449 }; 9450 const annotate = (editor, rng, uid, annotationName, decorate, data) => { 9451 const newWrappers = []; 9452 const master = makeAnnotation(editor.getDoc(), uid, data, annotationName, decorate); 9453 const wrapper = value$2(); 9454 const finishWrapper = () => { 9455 wrapper.clear(); 9456 }; 9457 const getOrOpenWrapper = () => wrapper.get().getOrThunk(() => { 9458 const nu = shallow$1(master); 9459 newWrappers.push(nu); 9460 wrapper.set(nu); 9461 return nu; 9462 }); 9463 const processElements = elems => { 9464 each$e(elems, processElement); 9465 }; 9466 const processElement = elem => { 9467 const ctx = context(editor, elem, 'span', name(elem)); 9468 switch (ctx) { 9469 case 'invalid-child': { 9470 finishWrapper(); 9471 const children = children$1(elem); 9472 processElements(children); 9473 finishWrapper(); 9474 break; 9475 } 9476 case 'valid-block': { 9477 finishWrapper(); 9478 applyAnnotation(elem, uid, data, annotationName, decorate, true); 9479 break; 9480 } 9481 case 'valid': { 9482 const w = getOrOpenWrapper(); 9483 wrap$2(elem, w); 9484 break; 9485 } 9486 } 9487 }; 9488 const processNodes = nodes => { 9489 const elems = map$3(nodes, SugarElement.fromDom); 9490 processElements(elems); 9491 }; 9492 walk$3(editor.dom, rng, nodes => { 9493 finishWrapper(); 9494 processNodes(nodes); 9495 }); 9496 return newWrappers; 9497 }; 9498 const annotateWithBookmark = (editor, name, settings, data) => { 9499 editor.undoManager.transact(() => { 9500 const selection = editor.selection; 9501 const initialRng = selection.getRng(); 9502 const hasFakeSelection = getCellsFromEditor(editor).length > 0; 9503 const masterUid = generate$1('mce-annotation'); 9504 if (initialRng.collapsed && !hasFakeSelection) { 9505 applyWordGrab(editor, initialRng); 9506 } 9507 if (selection.getRng().collapsed && !hasFakeSelection) { 9508 const wrapper = makeAnnotation(editor.getDoc(), masterUid, data, name, settings.decorate); 9509 set$1(wrapper, nbsp); 9510 selection.getRng().insertNode(wrapper.dom); 9511 selection.select(wrapper.dom); 9512 } else { 9513 preserve(selection, false, () => { 9514 runOnRanges(editor, selectionRng => { 9515 annotate(editor, selectionRng, masterUid, name, settings.decorate, data); 9516 }); 9517 }); 9518 } 9519 }); 9520 }; 9521 9522 const Annotator = editor => { 9523 const registry = create$b(); 9524 setup$x(editor, registry); 9525 const changes = setup$y(editor, registry); 9526 const isSpan = isTag('span'); 9527 const removeAnnotations = elements => { 9528 each$e(elements, element => { 9529 if (isSpan(element)) { 9530 unwrap(element); 9531 } else { 9532 removeDirectAnnotation(element); 9533 } 9534 }); 9535 }; 9536 return { 9537 register: (name, settings) => { 9538 registry.register(name, settings); 9539 }, 9540 annotate: (name, data) => { 9541 registry.lookup(name).each(settings => { 9542 annotateWithBookmark(editor, name, settings, data); 9543 }); 9544 }, 9545 annotationChanged: (name, callback) => { 9546 changes.addListener(name, callback); 9547 }, 9548 remove: name => { 9549 identify(editor, Optional.some(name)).each(({elements}) => { 9550 const bookmark = editor.selection.getBookmark(); 9551 removeAnnotations(elements); 9552 editor.selection.moveToBookmark(bookmark); 9553 }); 9554 }, 9555 removeAll: name => { 9556 const bookmark = editor.selection.getBookmark(); 9557 each$d(findAll(editor, name), (elements, _) => { 9558 removeAnnotations(elements); 9559 }); 9560 editor.selection.moveToBookmark(bookmark); 9561 }, 9562 getAll: name => { 9563 const directory = findAll(editor, name); 9564 return map$2(directory, elems => map$3(elems, elem => elem.dom)); 9565 } 9566 }; 9567 }; 9568 9569 const BookmarkManager = selection => { 9570 return { 9571 getBookmark: curry(getBookmark$2, selection), 9572 moveToBookmark: curry(moveToBookmark, selection) 9573 }; 9574 }; 9575 BookmarkManager.isBookmarkNode = isBookmarkNode$1; 9576 9577 const isXYWithinRange = (clientX, clientY, range) => { 9578 if (range.collapsed) { 9579 return false; 9580 } else { 9581 return exists(range.getClientRects(), rect => containsXY(rect, clientX, clientY)); 9582 } 9583 }; 9584 9585 const getDocument = () => SugarElement.fromDom(document); 9586 9587 const focus$1 = (element, preventScroll = false) => element.dom.focus({ preventScroll }); 9588 const hasFocus$1 = element => { 9589 const root = getRootNode(element).dom; 9590 return element.dom === root.activeElement; 9591 }; 9592 const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom); 9593 const search = element => active$1(getRootNode(element)).filter(e => element.dom.contains(e.dom)); 9594 9595 const create$9 = (start, soffset, finish, foffset) => ({ 9596 start, 9597 soffset, 9598 finish, 9599 foffset 9600 }); 9601 const SimRange = { create: create$9 }; 9602 9603 const adt$3 = Adt.generate([ 9604 { before: ['element'] }, 9605 { 9606 on: [ 9607 'element', 9608 'offset' 9609 ] 9610 }, 9611 { after: ['element'] } 9612 ]); 9613 const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter); 9614 const getStart$2 = situ => situ.fold(identity, identity, identity); 9615 const before$1 = adt$3.before; 9616 const on = adt$3.on; 9617 const after$1 = adt$3.after; 9618 const Situ = { 9619 before: before$1, 9620 on, 9621 after: after$1, 9622 cata, 9623 getStart: getStart$2 9624 }; 9625 9626 const adt$2 = Adt.generate([ 9627 { domRange: ['rng'] }, 9628 { 9629 relative: [ 9630 'startSitu', 9631 'finishSitu' 9632 ] 9633 }, 9634 { 9635 exact: [ 9636 'start', 9637 'soffset', 9638 'finish', 9639 'foffset' 9640 ] 9641 } 9642 ]); 9643 const exactFromRange = simRange => adt$2.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset); 9644 const getStart$1 = selection => selection.match({ 9645 domRange: rng => SugarElement.fromDom(rng.startContainer), 9646 relative: (startSitu, _finishSitu) => Situ.getStart(startSitu), 9647 exact: (start, _soffset, _finish, _foffset) => start 9648 }); 9649 const domRange = adt$2.domRange; 9650 const relative = adt$2.relative; 9651 const exact = adt$2.exact; 9652 const getWin = selection => { 9653 const start = getStart$1(selection); 9654 return defaultView(start); 9655 }; 9656 const range = SimRange.create; 9657 const SimSelection = { 9658 domRange, 9659 relative, 9660 exact, 9661 exactFromRange, 9662 getWin, 9663 range 9664 }; 9665 9666 const clamp$1 = (offset, element) => { 9667 const max = isText$c(element) ? get$3(element).length : children$1(element).length + 1; 9668 if (offset > max) { 9669 return max; 9670 } else if (offset < 0) { 9671 return 0; 9672 } 9673 return offset; 9674 }; 9675 const normalizeRng = rng => SimSelection.range(rng.start, clamp$1(rng.soffset, rng.start), rng.finish, clamp$1(rng.foffset, rng.finish)); 9676 const isOrContains = (root, elm) => !isRestrictedNode(elm.dom) && (contains(root, elm) || eq(root, elm)); 9677 const isRngInRoot = root => rng => isOrContains(root, rng.start) && isOrContains(root, rng.finish); 9678 const shouldStore = editor => editor.inline || Env.browser.isFirefox(); 9679 const nativeRangeToSelectionRange = r => SimSelection.range(SugarElement.fromDom(r.startContainer), r.startOffset, SugarElement.fromDom(r.endContainer), r.endOffset); 9680 const readRange = win => { 9681 const selection = win.getSelection(); 9682 const rng = !selection || selection.rangeCount === 0 ? Optional.none() : Optional.from(selection.getRangeAt(0)); 9683 return rng.map(nativeRangeToSelectionRange); 9684 }; 9685 const getBookmark$1 = root => { 9686 const win = defaultView(root); 9687 return readRange(win.dom).filter(isRngInRoot(root)); 9688 }; 9689 const validate = (root, bookmark) => Optional.from(bookmark).filter(isRngInRoot(root)).map(normalizeRng); 9690 const bookmarkToNativeRng = bookmark => { 9691 const rng = document.createRange(); 9692 try { 9693 rng.setStart(bookmark.start.dom, bookmark.soffset); 9694 rng.setEnd(bookmark.finish.dom, bookmark.foffset); 9695 return Optional.some(rng); 9696 } catch (_a) { 9697 return Optional.none(); 9698 } 9699 }; 9700 const store = editor => { 9701 const newBookmark = shouldStore(editor) ? getBookmark$1(SugarElement.fromDom(editor.getBody())) : Optional.none(); 9702 editor.bookmark = newBookmark.isSome() ? newBookmark : editor.bookmark; 9703 }; 9704 const getRng = editor => { 9705 const bookmark = editor.bookmark ? editor.bookmark : Optional.none(); 9706 return bookmark.bind(x => validate(SugarElement.fromDom(editor.getBody()), x)).bind(bookmarkToNativeRng); 9707 }; 9708 const restore = editor => { 9709 getRng(editor).each(rng => editor.selection.setRng(rng)); 9710 }; 9711 9712 const isEditorUIElement$1 = elm => { 9713 const className = elm.className.toString(); 9714 return className.indexOf('tox-') !== -1 || className.indexOf('mce-') !== -1; 9715 }; 9716 const FocusManager = { isEditorUIElement: isEditorUIElement$1 }; 9717 9718 const wrappedSetTimeout = (callback, time) => { 9719 if (!isNumber(time)) { 9720 time = 0; 9721 } 9722 return setTimeout(callback, time); 9723 }; 9724 const wrappedSetInterval = (callback, time) => { 9725 if (!isNumber(time)) { 9726 time = 0; 9727 } 9728 return setInterval(callback, time); 9729 }; 9730 const Delay = { 9731 setEditorTimeout: (editor, callback, time) => { 9732 return wrappedSetTimeout(() => { 9733 if (!editor.removed) { 9734 callback(); 9735 } 9736 }, time); 9737 }, 9738 setEditorInterval: (editor, callback, time) => { 9739 const timer = wrappedSetInterval(() => { 9740 if (!editor.removed) { 9741 callback(); 9742 } else { 9743 clearInterval(timer); 9744 } 9745 }, time); 9746 return timer; 9747 } 9748 }; 9749 9750 const isManualNodeChange = e => { 9751 return e.type === 'nodechange' && e.selectionChange; 9752 }; 9753 const registerPageMouseUp = (editor, throttledStore) => { 9754 const mouseUpPage = () => { 9755 throttledStore.throttle(); 9756 }; 9757 DOMUtils.DOM.bind(document, 'mouseup', mouseUpPage); 9758 editor.on('remove', () => { 9759 DOMUtils.DOM.unbind(document, 'mouseup', mouseUpPage); 9760 }); 9761 }; 9762 const registerMouseUp = (editor, throttledStore) => { 9763 editor.on('mouseup touchend', _e => { 9764 throttledStore.throttle(); 9765 }); 9766 }; 9767 const registerEditorEvents = (editor, throttledStore) => { 9768 registerMouseUp(editor, throttledStore); 9769 editor.on('keyup NodeChange AfterSetSelectionRange', e => { 9770 if (!isManualNodeChange(e)) { 9771 store(editor); 9772 } 9773 }); 9774 }; 9775 const register$6 = editor => { 9776 const throttledStore = first$1(() => { 9777 store(editor); 9778 }, 0); 9779 editor.on('init', () => { 9780 if (editor.inline) { 9781 registerPageMouseUp(editor, throttledStore); 9782 } 9783 registerEditorEvents(editor, throttledStore); 9784 }); 9785 editor.on('remove', () => { 9786 throttledStore.cancel(); 9787 }); 9788 }; 9789 9790 let documentFocusInHandler; 9791 const DOM$9 = DOMUtils.DOM; 9792 const isEditorUIElement = elm => { 9793 return isElement$6(elm) && FocusManager.isEditorUIElement(elm); 9794 }; 9795 const isEditorContentAreaElement = elm => { 9796 const classList = elm.classList; 9797 if (classList !== undefined) { 9798 return classList.contains('tox-edit-area') || classList.contains('tox-edit-area__iframe') || classList.contains('mce-content-body'); 9799 } else { 9800 return false; 9801 } 9802 }; 9803 const isUIElement = (editor, elm) => { 9804 const customSelector = getCustomUiSelector(editor); 9805 const parent = DOM$9.getParent(elm, elm => { 9806 return isEditorUIElement(elm) || (customSelector ? editor.dom.is(elm, customSelector) : false); 9807 }); 9808 return parent !== null; 9809 }; 9810 const getActiveElement = editor => { 9811 try { 9812 const root = getRootNode(SugarElement.fromDom(editor.getElement())); 9813 return active$1(root).fold(() => document.body, x => x.dom); 9814 } catch (_a) { 9815 return document.body; 9816 } 9817 }; 9818 const registerEvents$1 = (editorManager, e) => { 9819 const editor = e.editor; 9820 register$6(editor); 9821 const toggleContentAreaOnFocus = (editor, fn) => { 9822 if (shouldHighlightOnFocus(editor) && editor.inline !== true) { 9823 const contentArea = SugarElement.fromDom(editor.getContainer()); 9824 fn(contentArea, 'tox-edit-focus'); 9825 } 9826 }; 9827 editor.on('focusin', () => { 9828 const focusedEditor = editorManager.focusedEditor; 9829 if (isEditorContentAreaElement(getActiveElement(editor))) { 9830 toggleContentAreaOnFocus(editor, add$2); 9831 } 9832 if (focusedEditor !== editor) { 9833 if (focusedEditor) { 9834 focusedEditor.dispatch('blur', { focusedEditor: editor }); 9835 } 9836 editorManager.setActive(editor); 9837 editorManager.focusedEditor = editor; 9838 editor.dispatch('focus', { blurredEditor: focusedEditor }); 9839 editor.focus(true); 9840 } 9841 }); 9842 editor.on('focusout', () => { 9843 Delay.setEditorTimeout(editor, () => { 9844 const focusedEditor = editorManager.focusedEditor; 9845 if (!isEditorContentAreaElement(getActiveElement(editor)) || focusedEditor !== editor) { 9846 toggleContentAreaOnFocus(editor, remove$6); 9847 } 9848 if (!isUIElement(editor, getActiveElement(editor)) && focusedEditor === editor) { 9849 editor.dispatch('blur', { focusedEditor: null }); 9850 editorManager.focusedEditor = null; 9851 } 9852 }); 9853 }); 9854 if (!documentFocusInHandler) { 9855 documentFocusInHandler = e => { 9856 const activeEditor = editorManager.activeEditor; 9857 if (activeEditor) { 9858 getOriginalEventTarget(e).each(target => { 9859 const elem = target; 9860 if (elem.ownerDocument === document) { 9861 if (elem !== document.body && !isUIElement(activeEditor, elem) && editorManager.focusedEditor === activeEditor) { 9862 activeEditor.dispatch('blur', { focusedEditor: null }); 9863 editorManager.focusedEditor = null; 9864 } 9865 } 9866 }); 9867 } 9868 }; 9869 DOM$9.bind(document, 'focusin', documentFocusInHandler); 9870 } 9871 }; 9872 const unregisterDocumentEvents = (editorManager, e) => { 9873 if (editorManager.focusedEditor === e.editor) { 9874 editorManager.focusedEditor = null; 9875 } 9876 if (!editorManager.activeEditor && documentFocusInHandler) { 9877 DOM$9.unbind(document, 'focusin', documentFocusInHandler); 9878 documentFocusInHandler = null; 9879 } 9880 }; 9881 const setup$w = editorManager => { 9882 editorManager.on('AddEditor', curry(registerEvents$1, editorManager)); 9883 editorManager.on('RemoveEditor', curry(unregisterDocumentEvents, editorManager)); 9884 }; 9885 9886 const getContentEditableHost = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'true'); 9887 const hasContentEditableFalseParent$1 = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'false') !== null; 9888 const getCollapsedNode = rng => rng.collapsed ? Optional.from(getNode$1(rng.startContainer, rng.startOffset)).map(SugarElement.fromDom) : Optional.none(); 9889 const getFocusInElement = (root, rng) => getCollapsedNode(rng).bind(node => { 9890 if (isTableSection(node)) { 9891 return Optional.some(node); 9892 } else if (!contains(root, node)) { 9893 return Optional.some(root); 9894 } else { 9895 return Optional.none(); 9896 } 9897 }); 9898 const normalizeSelection = (editor, rng) => { 9899 getFocusInElement(SugarElement.fromDom(editor.getBody()), rng).bind(elm => { 9900 return firstPositionIn(elm.dom); 9901 }).fold(() => { 9902 editor.selection.normalize(); 9903 }, caretPos => editor.selection.setRng(caretPos.toRange())); 9904 }; 9905 const focusBody = body => { 9906 if (body.setActive) { 9907 try { 9908 body.setActive(); 9909 } catch (_a) { 9910 body.focus(); 9911 } 9912 } else { 9913 body.focus(); 9914 } 9915 }; 9916 const hasElementFocus = elm => hasFocus$1(elm) || search(elm).isSome(); 9917 const hasIframeFocus = editor => isNonNullable(editor.iframeElement) && hasFocus$1(SugarElement.fromDom(editor.iframeElement)); 9918 const hasInlineFocus = editor => { 9919 const rawBody = editor.getBody(); 9920 return rawBody && hasElementFocus(SugarElement.fromDom(rawBody)); 9921 }; 9922 const hasUiFocus = editor => { 9923 const dos = getRootNode(SugarElement.fromDom(editor.getElement())); 9924 return active$1(dos).filter(elem => !isEditorContentAreaElement(elem.dom) && isUIElement(editor, elem.dom)).isSome(); 9925 }; 9926 const hasFocus = editor => editor.inline ? hasInlineFocus(editor) : hasIframeFocus(editor); 9927 const hasEditorOrUiFocus = editor => hasFocus(editor) || hasUiFocus(editor); 9928 const focusEditor = editor => { 9929 const selection = editor.selection; 9930 const body = editor.getBody(); 9931 let rng = selection.getRng(); 9932 editor.quirks.refreshContentEditable(); 9933 const restoreBookmark = editor => { 9934 getRng(editor).each(bookmarkRng => { 9935 editor.selection.setRng(bookmarkRng); 9936 rng = bookmarkRng; 9937 }); 9938 }; 9939 if (!hasFocus(editor) && editor.hasEditableRoot()) { 9940 restoreBookmark(editor); 9941 } 9942 const contentEditableHost = getContentEditableHost(editor, selection.getNode()); 9943 if (contentEditableHost && editor.dom.isChildOf(contentEditableHost, body)) { 9944 if (!hasContentEditableFalseParent$1(editor, contentEditableHost)) { 9945 focusBody(body); 9946 } 9947 focusBody(contentEditableHost); 9948 if (!editor.hasEditableRoot()) { 9949 restoreBookmark(editor); 9950 } 9951 normalizeSelection(editor, rng); 9952 activateEditor(editor); 9953 return; 9954 } 9955 if (!editor.inline) { 9956 if (!Env.browser.isOpera()) { 9957 focusBody(body); 9958 } 9959 editor.getWin().focus(); 9960 } 9961 if (Env.browser.isFirefox() || editor.inline) { 9962 focusBody(body); 9963 normalizeSelection(editor, rng); 9964 } 9965 activateEditor(editor); 9966 }; 9967 const activateEditor = editor => editor.editorManager.setActive(editor); 9968 const focus = (editor, skipFocus) => { 9969 if (editor.removed) { 9970 return; 9971 } 9972 if (skipFocus) { 9973 activateEditor(editor); 9974 } else { 9975 focusEditor(editor); 9976 } 9977 }; 9978 9979 const VK = { 9980 BACKSPACE: 8, 9981 DELETE: 46, 9982 DOWN: 40, 9983 ENTER: 13, 9984 ESC: 27, 9985 LEFT: 37, 9986 RIGHT: 39, 9987 SPACEBAR: 32, 9988 TAB: 9, 9989 UP: 38, 9990 PAGE_UP: 33, 9991 PAGE_DOWN: 34, 9992 END: 35, 9993 HOME: 36, 9994 modifierPressed: e => { 9995 return e.shiftKey || e.ctrlKey || e.altKey || VK.metaKeyPressed(e); 9996 }, 9997 metaKeyPressed: e => { 9998 return Env.os.isMacOS() || Env.os.isiOS() ? e.metaKey : e.ctrlKey && !e.altKey; 9999 } 10000 }; 10001 10002 const elementSelectionAttr = 'data-mce-selected'; 10003 const controlElmSelector = 'table,img,figure.image,hr,video,span.mce-preview-object,details'; 10004 const abs = Math.abs; 10005 const round$1 = Math.round; 10006 const resizeHandles = { 10007 nw: [ 10008 0, 10009 0, 10010 -1, 10011 -1 10012 ], 10013 ne: [ 10014 1, 10015 0, 10016 1, 10017 -1 10018 ], 10019 se: [ 10020 1, 10021 1, 10022 1, 10023 1 10024 ], 10025 sw: [ 10026 0, 10027 1, 10028 -1, 10029 1 10030 ] 10031 }; 10032 const isTouchEvent = evt => evt.type === 'longpress' || evt.type.indexOf('touch') === 0; 10033 const ControlSelection = (selection, editor) => { 10034 const dom = editor.dom; 10035 const editableDoc = editor.getDoc(); 10036 const rootDocument = document; 10037 const rootElement = editor.getBody(); 10038 let selectedElm, selectedElmGhost, resizeHelper, selectedHandle, resizeBackdrop; 10039 let startX, startY, startW, startH, ratio, resizeStarted; 10040 let width; 10041 let height; 10042 let startScrollWidth; 10043 let startScrollHeight; 10044 const isImage = elm => isNonNullable(elm) && (isImg(elm) || dom.is(elm, 'figure.image')); 10045 const isMedia = elm => isMedia$2(elm) || dom.hasClass(elm, 'mce-preview-object'); 10046 const isEventOnImageOutsideRange = (evt, range) => { 10047 if (isTouchEvent(evt)) { 10048 const touch = evt.touches[0]; 10049 return isImage(evt.target) && !isXYWithinRange(touch.clientX, touch.clientY, range); 10050 } else { 10051 return isImage(evt.target) && !isXYWithinRange(evt.clientX, evt.clientY, range); 10052 } 10053 }; 10054 const contextMenuSelectImage = evt => { 10055 const target = evt.target; 10056 if (isEventOnImageOutsideRange(evt, editor.selection.getRng()) && !evt.isDefaultPrevented()) { 10057 editor.selection.select(target); 10058 } 10059 }; 10060 const getResizeTargets = elm => { 10061 if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) { 10062 return [ 10063 elm, 10064 elm.firstElementChild 10065 ]; 10066 } else if (dom.is(elm, 'figure.image')) { 10067 return [elm.querySelector('img')]; 10068 } else { 10069 return [elm]; 10070 } 10071 }; 10072 const isResizable = elm => { 10073 const selector = getObjectResizing(editor); 10074 if (!selector || editor.mode.isReadOnly()) { 10075 return false; 10076 } 10077 if (elm.getAttribute('data-mce-resize') === 'false') { 10078 return false; 10079 } 10080 if (elm === editor.getBody()) { 10081 return false; 10082 } 10083 if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) { 10084 return is$1(SugarElement.fromDom(elm.firstElementChild), selector); 10085 } else { 10086 return is$1(SugarElement.fromDom(elm), selector); 10087 } 10088 }; 10089 const createGhostElement = (dom, elm) => { 10090 if (isMedia(elm)) { 10091 return dom.create('img', { src: Env.transparentSrc }); 10092 } else if (isTable$2(elm)) { 10093 const isNorth = startsWith(selectedHandle.name, 'n'); 10094 const rowSelect = isNorth ? head : last$2; 10095 const tableElm = elm.cloneNode(true); 10096 rowSelect(dom.select('tr', tableElm)).each(tr => { 10097 const cells = dom.select('td,th', tr); 10098 dom.setStyle(tr, 'height', null); 10099 each$e(cells, cell => dom.setStyle(cell, 'height', null)); 10100 }); 10101 return tableElm; 10102 } else { 10103 return elm.cloneNode(true); 10104 } 10105 }; 10106 const setSizeProp = (element, name, value) => { 10107 if (isNonNullable(value)) { 10108 const targets = getResizeTargets(element); 10109 each$e(targets, target => { 10110 if (target.style[name] || !editor.schema.isValid(target.nodeName.toLowerCase(), name)) { 10111 dom.setStyle(target, name, value); 10112 } else { 10113 dom.setAttrib(target, name, '' + value); 10114 } 10115 }); 10116 } 10117 }; 10118 const setGhostElmSize = (ghostElm, width, height) => { 10119 setSizeProp(ghostElm, 'width', width); 10120 setSizeProp(ghostElm, 'height', height); 10121 }; 10122 const resizeGhostElement = e => { 10123 let deltaX, deltaY, proportional; 10124 let resizeHelperX, resizeHelperY; 10125 deltaX = e.screenX - startX; 10126 deltaY = e.screenY - startY; 10127 width = deltaX * selectedHandle[2] + startW; 10128 height = deltaY * selectedHandle[3] + startH; 10129 width = width < 5 ? 5 : width; 10130 height = height < 5 ? 5 : height; 10131 if ((isImage(selectedElm) || isMedia(selectedElm)) && getResizeImgProportional(editor) !== false) { 10132 proportional = !VK.modifierPressed(e); 10133 } else { 10134 proportional = VK.modifierPressed(e); 10135 } 10136 if (proportional) { 10137 if (abs(deltaX) > abs(deltaY)) { 10138 height = round$1(width * ratio); 10139 width = round$1(height / ratio); 10140 } else { 10141 width = round$1(height / ratio); 10142 height = round$1(width * ratio); 10143 } 10144 } 10145 setGhostElmSize(selectedElmGhost, width, height); 10146 resizeHelperX = selectedHandle.startPos.x + deltaX; 10147 resizeHelperY = selectedHandle.startPos.y + deltaY; 10148 resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0; 10149 resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0; 10150 dom.setStyles(resizeHelper, { 10151 left: resizeHelperX, 10152 top: resizeHelperY, 10153 display: 'block' 10154 }); 10155 resizeHelper.innerHTML = width + ' × ' + height; 10156 deltaX = rootElement.scrollWidth - startScrollWidth; 10157 deltaY = rootElement.scrollHeight - startScrollHeight; 10158 if (deltaX + deltaY !== 0) { 10159 dom.setStyles(resizeHelper, { 10160 left: resizeHelperX - deltaX, 10161 top: resizeHelperY - deltaY 10162 }); 10163 } 10164 if (!resizeStarted) { 10165 fireObjectResizeStart(editor, selectedElm, startW, startH, 'corner-' + selectedHandle.name); 10166 resizeStarted = true; 10167 } 10168 }; 10169 const endGhostResize = () => { 10170 const wasResizeStarted = resizeStarted; 10171 resizeStarted = false;
vendor: 4,776 bytes, lines 10172-10279
10172 if (wasResizeStarted) { 10173 setSizeProp(selectedElm, 'width', width); 10174 setSizeProp(selectedElm, 'height', height); 10175 } 10176 dom.unbind(editableDoc, 'mousemove', resizeGhostElement); 10177 dom.unbind(editableDoc, 'mouseup', endGhostResize); 10178 if (rootDocument !== editableDoc) { 10179 dom.unbind(rootDocument, 'mousemove', resizeGhostElement); 10180 dom.unbind(rootDocument, 'mouseup', endGhostResize); 10181 } 10182 dom.remove(selectedElmGhost); 10183 dom.remove(resizeHelper); 10184 dom.remove(resizeBackdrop); 10185 showResizeRect(selectedElm); 10186 if (wasResizeStarted) { 10187 fireObjectResized(editor, selectedElm, width, height, 'corner-' + selectedHandle.name); 10188 dom.setAttrib(selectedElm, 'style', dom.getAttrib(selectedElm, 'style')); 10189 } 10190 editor.nodeChanged(); 10191 }; 10192 const showResizeRect = targetElm => { 10193 unbindResizeHandleEvents(); 10194 const position = dom.getPos(targetElm, rootElement); 10195 const selectedElmX = position.x; 10196 const selectedElmY = position.y; 10197 const rect = targetElm.getBoundingClientRect(); 10198 const targetWidth = rect.width || rect.right - rect.left; 10199 const targetHeight = rect.height || rect.bottom - rect.top; 10200 if (selectedElm !== targetElm) { 10201 hideResizeRect(); 10202 selectedElm = targetElm; 10203 width = height = 0; 10204 } 10205 const e = editor.dispatch('ObjectSelected', { target: targetElm }); 10206 if (isResizable(targetElm) && !e.isDefaultPrevented()) { 10207 each$d(resizeHandles, (handle, name) => { 10208 const startDrag = e => { 10209 const target = getResizeTargets(selectedElm)[0]; 10210 startX = e.screenX; 10211 startY = e.screenY; 10212 startW = target.clientWidth; 10213 startH = target.clientHeight; 10214 ratio = startH / startW; 10215 selectedHandle = handle; 10216 selectedHandle.name = name; 10217 selectedHandle.startPos = { 10218 x: targetWidth * handle[0] + selectedElmX, 10219 y: targetHeight * handle[1] + selectedElmY 10220 }; 10221 startScrollWidth = rootElement.scrollWidth; 10222 startScrollHeight = rootElement.scrollHeight; 10223 resizeBackdrop = dom.add(rootElement, 'div', { 10224 'class': 'mce-resize-backdrop', 10225 'data-mce-bogus': 'all' 10226 }); 10227 dom.setStyles(resizeBackdrop, { 10228 position: 'fixed', 10229 left: '0', 10230 top: '0', 10231 width: '100%', 10232 height: '100%' 10233 }); 10234 selectedElmGhost = createGhostElement(dom, selectedElm); 10235 dom.addClass(selectedElmGhost, 'mce-clonedresizable'); 10236 dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all'); 10237 selectedElmGhost.contentEditable = 'false'; 10238 dom.setStyles(selectedElmGhost, { 10239 left: selectedElmX, 10240 top: selectedElmY, 10241 margin: 0 10242 }); 10243 setGhostElmSize(selectedElmGhost, targetWidth, targetHeight); 10244 selectedElmGhost.removeAttribute(elementSelectionAttr); 10245 rootElement.appendChild(selectedElmGhost); 10246 dom.bind(editableDoc, 'mousemove', resizeGhostElement); 10247 dom.bind(editableDoc, 'mouseup', endGhostResize); 10248 if (rootDocument !== editableDoc) { 10249 dom.bind(rootDocument, 'mousemove', resizeGhostElement); 10250 dom.bind(rootDocument, 'mouseup', endGhostResize); 10251 } 10252 resizeHelper = dom.add(rootElement, 'div', { 10253 'class': 'mce-resize-helper', 10254 'data-mce-bogus': 'all' 10255 }, startW + ' × ' + startH); 10256 }; 10257 let handleElm = dom.get('mceResizeHandle' + name); 10258 if (handleElm) { 10259 dom.remove(handleElm); 10260 } 10261 handleElm = dom.add(rootElement, 'div', { 10262 'id': 'mceResizeHandle' + name, 10263 'data-mce-bogus': 'all', 10264 'class': 'mce-resizehandle', 10265 'unselectable': true, 10266 'style': 'cursor:' + name + '-resize; margin:0; padding:0' 10267 }); 10268 dom.bind(handleElm, 'mousedown', e => { 10269 e.stopImmediatePropagation(); 10270 e.preventDefault(); 10271 startDrag(e); 10272 }); 10273 handle.elm = handleElm; 10274 dom.setStyles(handleElm, { 10275 left: targetWidth * handle[0] + selectedElmX - handleElm.offsetWidth / 2, 10276 top: targetHeight * handle[1] + selectedElmY - handleElm.offsetHeight / 2 10277 }); 10278 }); 10279 } else {
vendor: 21,699 bytes, lines 10280-10857
10280 hideResizeRect(false); 10281 } 10282 }; 10283 const throttledShowResizeRect = first$1(showResizeRect, 0); 10284 const hideResizeRect = (removeSelected = true) => { 10285 throttledShowResizeRect.cancel(); 10286 unbindResizeHandleEvents(); 10287 if (selectedElm && removeSelected) { 10288 selectedElm.removeAttribute(elementSelectionAttr); 10289 } 10290 each$d(resizeHandles, (value, name) => { 10291 const handleElm = dom.get('mceResizeHandle' + name); 10292 if (handleElm) { 10293 dom.unbind(handleElm); 10294 dom.remove(handleElm); 10295 } 10296 }); 10297 }; 10298 const isChildOrEqual = (node, parent) => dom.isChildOf(node, parent); 10299 const updateResizeRect = e => { 10300 if (resizeStarted || editor.removed || editor.composing) { 10301 return; 10302 } 10303 const targetElm = e.type === 'mousedown' ? e.target : selection.getNode(); 10304 const controlElm = closest$3(SugarElement.fromDom(targetElm), controlElmSelector).map(e => e.dom).filter(e => dom.isEditable(e.parentElement) || e.nodeName === 'IMG' && dom.isEditable(e)).getOrUndefined(); 10305 const selectedValue = isNonNullable(controlElm) ? dom.getAttrib(controlElm, elementSelectionAttr, '1') : '1'; 10306 each$e(dom.select(`img[${ elementSelectionAttr }],hr[${ elementSelectionAttr }]`), img => { 10307 img.removeAttribute(elementSelectionAttr); 10308 }); 10309 if (isNonNullable(controlElm) && isChildOrEqual(controlElm, rootElement) && hasEditorOrUiFocus(editor)) { 10310 disableGeckoResize(); 10311 const startElm = selection.getStart(true); 10312 if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) { 10313 dom.setAttrib(controlElm, elementSelectionAttr, selectedValue); 10314 throttledShowResizeRect.throttle(controlElm); 10315 return; 10316 } 10317 } 10318 hideResizeRect(); 10319 }; 10320 const unbindResizeHandleEvents = () => { 10321 each$d(resizeHandles, handle => { 10322 if (handle.elm) { 10323 dom.unbind(handle.elm); 10324 delete handle.elm; 10325 } 10326 }); 10327 }; 10328 const disableGeckoResize = () => { 10329 try { 10330 editor.getDoc().execCommand('enableObjectResizing', false, 'false'); 10331 } catch (_a) { 10332 } 10333 }; 10334 editor.on('init', () => { 10335 disableGeckoResize(); 10336 editor.on('NodeChange ResizeEditor ResizeWindow ResizeContent drop', updateResizeRect); 10337 editor.on('keyup compositionend', e => { 10338 if (selectedElm && selectedElm.nodeName === 'TABLE') { 10339 updateResizeRect(e); 10340 } 10341 }); 10342 editor.on('hide blur', hideResizeRect); 10343 editor.on('contextmenu longpress', contextMenuSelectImage, true); 10344 }); 10345 editor.on('remove', unbindResizeHandleEvents); 10346 const destroy = () => { 10347 throttledShowResizeRect.cancel(); 10348 selectedElm = selectedElmGhost = resizeBackdrop = null; 10349 }; 10350 return { 10351 isResizable, 10352 showResizeRect, 10353 hideResizeRect, 10354 updateResizeRect, 10355 destroy 10356 }; 10357 }; 10358 10359 const setStart = (rng, situ) => { 10360 situ.fold(e => { 10361 rng.setStartBefore(e.dom); 10362 }, (e, o) => { 10363 rng.setStart(e.dom, o); 10364 }, e => { 10365 rng.setStartAfter(e.dom); 10366 }); 10367 }; 10368 const setFinish = (rng, situ) => { 10369 situ.fold(e => { 10370 rng.setEndBefore(e.dom); 10371 }, (e, o) => { 10372 rng.setEnd(e.dom, o); 10373 }, e => { 10374 rng.setEndAfter(e.dom); 10375 }); 10376 }; 10377 const relativeToNative = (win, startSitu, finishSitu) => { 10378 const range = win.document.createRange(); 10379 setStart(range, startSitu); 10380 setFinish(range, finishSitu); 10381 return range; 10382 }; 10383 const exactToNative = (win, start, soffset, finish, foffset) => { 10384 const rng = win.document.createRange(); 10385 rng.setStart(start.dom, soffset); 10386 rng.setEnd(finish.dom, foffset); 10387 return rng; 10388 }; 10389 10390 const adt$1 = Adt.generate([ 10391 { 10392 ltr: [ 10393 'start', 10394 'soffset', 10395 'finish', 10396 'foffset' 10397 ] 10398 }, 10399 { 10400 rtl: [ 10401 'start', 10402 'soffset', 10403 'finish', 10404 'foffset' 10405 ] 10406 } 10407 ]); 10408 const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset); 10409 const getRanges = (win, selection) => selection.match({ 10410 domRange: rng => { 10411 return { 10412 ltr: constant(rng), 10413 rtl: Optional.none 10414 }; 10415 }, 10416 relative: (startSitu, finishSitu) => { 10417 return { 10418 ltr: cached(() => relativeToNative(win, startSitu, finishSitu)), 10419 rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu))) 10420 }; 10421 }, 10422 exact: (start, soffset, finish, foffset) => { 10423 return { 10424 ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)), 10425 rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset))) 10426 }; 10427 } 10428 }); 10429 const doDiagnose = (win, ranges) => { 10430 const rng = ranges.ltr(); 10431 if (rng.collapsed) { 10432 const reversed = ranges.rtl().filter(rev => rev.collapsed === false); 10433 return reversed.map(rev => adt$1.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$1.ltr, rng)); 10434 } else { 10435 return fromRange(win, adt$1.ltr, rng); 10436 } 10437 }; 10438 const diagnose = (win, selection) => { 10439 const ranges = getRanges(win, selection); 10440 return doDiagnose(win, ranges); 10441 }; 10442 adt$1.ltr; 10443 adt$1.rtl; 10444 10445 const caretPositionFromPoint = (doc, x, y) => { 10446 var _a; 10447 return Optional.from((_a = doc.caretPositionFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y)).bind(pos => { 10448 if (pos.offsetNode === null) { 10449 return Optional.none(); 10450 } 10451 const r = doc.createRange(); 10452 r.setStart(pos.offsetNode, pos.offset); 10453 r.collapse(); 10454 return Optional.some(r); 10455 }); 10456 }; 10457 const caretRangeFromPoint = (doc, x, y) => { 10458 var _a; 10459 return Optional.from((_a = doc.caretRangeFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y)); 10460 }; 10461 const availableSearch = (doc, x, y) => { 10462 if (doc.caretPositionFromPoint) { 10463 return caretPositionFromPoint(doc, x, y); 10464 } else if (doc.caretRangeFromPoint) { 10465 return caretRangeFromPoint(doc, x, y); 10466 } else { 10467 return Optional.none(); 10468 } 10469 }; 10470 const fromPoint$1 = (win, x, y) => { 10471 const doc = win.document; 10472 return availableSearch(doc, x, y).map(rng => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset)); 10473 }; 10474 10475 const beforeSpecial = (element, offset) => { 10476 const name$1 = name(element); 10477 if ('input' === name$1) { 10478 return Situ.after(element); 10479 } else if (!contains$2([ 10480 'br', 10481 'img' 10482 ], name$1)) { 10483 return Situ.on(element, offset); 10484 } else { 10485 return offset === 0 ? Situ.before(element) : Situ.after(element); 10486 } 10487 }; 10488 const preprocessRelative = (startSitu, finishSitu) => { 10489 const start = startSitu.fold(Situ.before, beforeSpecial, Situ.after); 10490 const finish = finishSitu.fold(Situ.before, beforeSpecial, Situ.after); 10491 return SimSelection.relative(start, finish); 10492 }; 10493 const preprocessExact = (start, soffset, finish, foffset) => { 10494 const startSitu = beforeSpecial(start, soffset); 10495 const finishSitu = beforeSpecial(finish, foffset); 10496 return SimSelection.relative(startSitu, finishSitu); 10497 }; 10498 const preprocess = selection => selection.match({ 10499 domRange: rng => { 10500 const start = SugarElement.fromDom(rng.startContainer); 10501 const finish = SugarElement.fromDom(rng.endContainer); 10502 return preprocessExact(start, rng.startOffset, finish, rng.endOffset); 10503 }, 10504 relative: preprocessRelative, 10505 exact: preprocessExact 10506 }); 10507 10508 const fromElements = (elements, scope) => { 10509 const doc = scope || document; 10510 const fragment = doc.createDocumentFragment(); 10511 each$e(elements, element => { 10512 fragment.appendChild(element.dom); 10513 }); 10514 return SugarElement.fromDom(fragment); 10515 }; 10516 10517 const toNative = selection => { 10518 const win = SimSelection.getWin(selection).dom; 10519 const getDomRange = (start, soffset, finish, foffset) => exactToNative(win, start, soffset, finish, foffset); 10520 const filtered = preprocess(selection); 10521 return diagnose(win, filtered).match({ 10522 ltr: getDomRange, 10523 rtl: getDomRange 10524 }); 10525 }; 10526 const getAtPoint = (win, x, y) => fromPoint$1(win, x, y); 10527 10528 const fromPoint = (clientX, clientY, doc) => { 10529 const win = defaultView(SugarElement.fromDom(doc)); 10530 return getAtPoint(win.dom, clientX, clientY).map(simRange => { 10531 const rng = doc.createRange(); 10532 rng.setStart(simRange.start.dom, simRange.soffset); 10533 rng.setEnd(simRange.finish.dom, simRange.foffset); 10534 return rng; 10535 }).getOrUndefined(); 10536 }; 10537 10538 const isEq$4 = (rng1, rng2) => { 10539 return isNonNullable(rng1) && isNonNullable(rng2) && (rng1.startContainer === rng2.startContainer && rng1.startOffset === rng2.startOffset) && (rng1.endContainer === rng2.endContainer && rng1.endOffset === rng2.endOffset); 10540 }; 10541 10542 const findParent = (node, rootNode, predicate) => { 10543 let currentNode = node; 10544 while (currentNode && currentNode !== rootNode) { 10545 if (predicate(currentNode)) { 10546 return currentNode; 10547 } 10548 currentNode = currentNode.parentNode; 10549 } 10550 return null; 10551 }; 10552 const hasParent$1 = (node, rootNode, predicate) => findParent(node, rootNode, predicate) !== null; 10553 const hasParentWithName = (node, rootNode, name) => hasParent$1(node, rootNode, node => node.nodeName === name); 10554 const isCeFalseCaretContainer = (node, rootNode) => isCaretContainer$2(node) && !hasParent$1(node, rootNode, isCaretNode); 10555 const hasBrBeforeAfter = (dom, node, left) => { 10556 const parentNode = node.parentNode; 10557 if (parentNode) { 10558 const walker = new DomTreeWalker(node, dom.getParent(parentNode, dom.isBlock) || dom.getRoot()); 10559 let currentNode; 10560 while (currentNode = walker[left ? 'prev' : 'next']()) { 10561 if (isBr$6(currentNode)) { 10562 return true; 10563 } 10564 } 10565 } 10566 return false; 10567 }; 10568 const isPrevNode = (node, name) => { 10569 var _a; 10570 return ((_a = node.previousSibling) === null || _a === void 0 ? void 0 : _a.nodeName) === name; 10571 }; 10572 const hasContentEditableFalseParent = (root, node) => { 10573 let currentNode = node; 10574 while (currentNode && currentNode !== root) { 10575 if (isContentEditableFalse$b(currentNode)) { 10576 return true; 10577 } 10578 currentNode = currentNode.parentNode; 10579 } 10580 return false; 10581 }; 10582 const findTextNodeRelative = (dom, isAfterNode, collapsed, left, startNode) => { 10583 const body = dom.getRoot(); 10584 const nonEmptyElementsMap = dom.schema.getNonEmptyElements(); 10585 const parentNode = startNode.parentNode; 10586 let lastInlineElement; 10587 let node; 10588 if (!parentNode) { 10589 return Optional.none(); 10590 } 10591 const parentBlockContainer = dom.getParent(parentNode, dom.isBlock) || body; 10592 if (left && isBr$6(startNode) && isAfterNode && dom.isEmpty(parentBlockContainer)) { 10593 return Optional.some(CaretPosition(parentNode, dom.nodeIndex(startNode))); 10594 } 10595 const walker = new DomTreeWalker(startNode, parentBlockContainer); 10596 while (node = walker[left ? 'prev' : 'next']()) { 10597 if (dom.getContentEditableParent(node) === 'false' || isCeFalseCaretContainer(node, body)) { 10598 return Optional.none(); 10599 } 10600 if (isText$b(node) && node.data.length > 0) { 10601 if (!hasParentWithName(node, body, 'A')) { 10602 return Optional.some(CaretPosition(node, left ? node.data.length : 0)); 10603 } 10604 return Optional.none(); 10605 } 10606 if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) { 10607 return Optional.none(); 10608 } 10609 lastInlineElement = node; 10610 } 10611 if (isComment(lastInlineElement)) { 10612 return Optional.none(); 10613 } 10614 if (collapsed && lastInlineElement) { 10615 return Optional.some(CaretPosition(lastInlineElement, 0)); 10616 } 10617 return Optional.none(); 10618 }; 10619 const normalizeEndPoint = (dom, collapsed, start, rng) => { 10620 const body = dom.getRoot(); 10621 let node; 10622 let normalized = false; 10623 let container = start ? rng.startContainer : rng.endContainer; 10624 let offset = start ? rng.startOffset : rng.endOffset; 10625 const isAfterNode = isElement$6(container) && offset === container.childNodes.length; 10626 const nonEmptyElementsMap = dom.schema.getNonEmptyElements(); 10627 let directionLeft = start; 10628 if (isCaretContainer$2(container)) { 10629 return Optional.none(); 10630 } 10631 if (isElement$6(container) && offset > container.childNodes.length - 1) { 10632 directionLeft = false; 10633 } 10634 if (isDocument$1(container)) { 10635 container = body; 10636 offset = 0; 10637 } 10638 if (container === body) { 10639 if (directionLeft) { 10640 node = container.childNodes[offset > 0 ? offset - 1 : 0]; 10641 if (node) { 10642 if (isCaretContainer$2(node)) { 10643 return Optional.none(); 10644 } 10645 if (nonEmptyElementsMap[node.nodeName] || isTable$2(node)) { 10646 return Optional.none(); 10647 } 10648 } 10649 } 10650 if (container.hasChildNodes()) { 10651 offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1); 10652 container = container.childNodes[offset]; 10653 offset = isText$b(container) && isAfterNode ? container.data.length : 0; 10654 if (!collapsed && container === body.lastChild && isTable$2(container)) { 10655 return Optional.none(); 10656 } 10657 if (hasContentEditableFalseParent(body, container) || isCaretContainer$2(container)) { 10658 return Optional.none(); 10659 } 10660 if (isDetails(container)) { 10661 return Optional.none(); 10662 } 10663 if (container.hasChildNodes() && !isTable$2(container)) { 10664 node = container; 10665 const walker = new DomTreeWalker(container, body); 10666 do { 10667 if (isContentEditableFalse$b(node) || isCaretContainer$2(node)) { 10668 normalized = false; 10669 break; 10670 } 10671 if (isText$b(node) && node.data.length > 0) { 10672 offset = directionLeft ? 0 : node.data.length; 10673 container = node; 10674 normalized = true; 10675 break; 10676 } 10677 if (nonEmptyElementsMap[node.nodeName.toLowerCase()] && !isTableCellOrCaption(node)) { 10678 offset = dom.nodeIndex(node); 10679 container = node.parentNode; 10680 if (!directionLeft) { 10681 offset++; 10682 } 10683 normalized = true; 10684 break; 10685 } 10686 } while (node = directionLeft ? walker.next() : walker.prev()); 10687 } 10688 } 10689 } 10690 if (collapsed) { 10691 if (isText$b(container) && offset === 0) { 10692 findTextNodeRelative(dom, isAfterNode, collapsed, true, container).each(pos => { 10693 container = pos.container(); 10694 offset = pos.offset(); 10695 normalized = true; 10696 }); 10697 } 10698 if (isElement$6(container)) { 10699 node = container.childNodes[offset]; 10700 if (!node) { 10701 node = container.childNodes[offset - 1]; 10702 } 10703 if (node && isBr$6(node) && !isPrevNode(node, 'A') && !hasBrBeforeAfter(dom, node, false) && !hasBrBeforeAfter(dom, node, true)) { 10704 findTextNodeRelative(dom, isAfterNode, collapsed, true, node).each(pos => { 10705 container = pos.container(); 10706 offset = pos.offset(); 10707 normalized = true; 10708 }); 10709 } 10710 } 10711 } 10712 if (directionLeft && !collapsed && isText$b(container) && offset === container.data.length) { 10713 findTextNodeRelative(dom, isAfterNode, collapsed, false, container).each(pos => { 10714 container = pos.container(); 10715 offset = pos.offset(); 10716 normalized = true; 10717 }); 10718 } 10719 return normalized && container ? Optional.some(CaretPosition(container, offset)) : Optional.none(); 10720 }; 10721 const normalize$2 = (dom, rng) => { 10722 const collapsed = rng.collapsed, normRng = rng.cloneRange(); 10723 const startPos = CaretPosition.fromRangeStart(rng); 10724 normalizeEndPoint(dom, collapsed, true, normRng).each(pos => { 10725 if (!collapsed || !CaretPosition.isAbove(startPos, pos)) { 10726 normRng.setStart(pos.container(), pos.offset()); 10727 } 10728 }); 10729 if (!collapsed) { 10730 normalizeEndPoint(dom, collapsed, false, normRng).each(pos => { 10731 normRng.setEnd(pos.container(), pos.offset()); 10732 }); 10733 } 10734 if (collapsed) { 10735 normRng.collapse(true); 10736 } 10737 return isEq$4(rng, normRng) ? Optional.none() : Optional.some(normRng); 10738 }; 10739 10740 const splitText = (node, offset) => { 10741 return node.splitText(offset); 10742 }; 10743 const split = rng => { 10744 let startContainer = rng.startContainer, startOffset = rng.startOffset, endContainer = rng.endContainer, endOffset = rng.endOffset; 10745 if (startContainer === endContainer && isText$b(startContainer)) { 10746 if (startOffset > 0 && startOffset < startContainer.data.length) { 10747 endContainer = splitText(startContainer, startOffset); 10748 startContainer = endContainer.previousSibling; 10749 if (endOffset > startOffset) { 10750 endOffset = endOffset - startOffset; 10751 const newContainer = splitText(endContainer, endOffset).previousSibling; 10752 startContainer = endContainer = newContainer; 10753 endOffset = newContainer.data.length; 10754 startOffset = 0; 10755 } else { 10756 endOffset = 0; 10757 } 10758 } 10759 } else { 10760 if (isText$b(startContainer) && startOffset > 0 && startOffset < startContainer.data.length) { 10761 startContainer = splitText(startContainer, startOffset); 10762 startOffset = 0; 10763 } 10764 if (isText$b(endContainer) && endOffset > 0 && endOffset < endContainer.data.length) { 10765 const newContainer = splitText(endContainer, endOffset).previousSibling; 10766 endContainer = newContainer; 10767 endOffset = newContainer.data.length; 10768 } 10769 } 10770 return { 10771 startContainer, 10772 startOffset, 10773 endContainer, 10774 endOffset 10775 }; 10776 }; 10777 10778 const RangeUtils = dom => { 10779 const walk = (rng, callback) => { 10780 return walk$3(dom, rng, callback); 10781 }; 10782 const split$1 = split; 10783 const normalize = rng => { 10784 return normalize$2(dom, rng).fold(never, normalizedRng => { 10785 rng.setStart(normalizedRng.startContainer, normalizedRng.startOffset); 10786 rng.setEnd(normalizedRng.endContainer, normalizedRng.endOffset); 10787 return true; 10788 }); 10789 }; 10790 const expand = (rng, options = { type: 'word' }) => { 10791 if (options.type === 'word') { 10792 const rangeLike = expandRng(dom, rng, [{ inline: 'span' }], { 10793 includeTrailingSpace: false, 10794 expandToBlock: false 10795 }); 10796 const newRange = dom.createRng(); 10797 newRange.setStart(rangeLike.startContainer, rangeLike.startOffset); 10798 newRange.setEnd(rangeLike.endContainer, rangeLike.endOffset); 10799 return newRange; 10800 } 10801 return rng; 10802 }; 10803 return { 10804 walk, 10805 split: split$1, 10806 expand, 10807 normalize 10808 }; 10809 }; 10810 RangeUtils.compareRanges = isEq$4; 10811 RangeUtils.getCaretRangeFromPoint = fromPoint; 10812 RangeUtils.getSelectedNode = getSelectedNode; 10813 RangeUtils.getNode = getNode$1; 10814 10815 const Dimension = (name, getOffset) => { 10816 const set = (element, h) => { 10817 if (!isNumber(h) && !h.match(/^[0-9]+$/)) { 10818 throw new Error(name + '.set accepts only positive integer values. Value was ' + h); 10819 } 10820 const dom = element.dom; 10821 if (isSupported(dom)) { 10822 dom.style[name] = h + 'px'; 10823 } 10824 }; 10825 const get = element => { 10826 const r = getOffset(element); 10827 if (r <= 0 || r === null) { 10828 const css = get$7(element, name); 10829 return parseFloat(css) || 0; 10830 } 10831 return r; 10832 }; 10833 const getOuter = get; 10834 const aggregate = (element, properties) => foldl(properties, (acc, property) => { 10835 const val = get$7(element, property); 10836 const value = val === undefined ? 0 : parseInt(val, 10); 10837 return isNaN(value) ? acc : acc + value; 10838 }, 0); 10839 const max = (element, value, properties) => { 10840 const cumulativeInclusions = aggregate(element, properties); 10841 const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0; 10842 return absoluteMax; 10843 }; 10844 return { 10845 set, 10846 get, 10847 getOuter, 10848 aggregate, 10849 max 10850 }; 10851 }; 10852 10853 const api = Dimension('height', element => { 10854 const dom = element.dom; 10855 return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight; 10856 }); 10857 const get$2 = element => api.get(ele
vendor: 24,320 bytes, lines 10857-11550
10857ment); 10858 10859 const walkUp = (navigation, doc) => { 10860 const frame = navigation.view(doc); 10861 return frame.fold(constant([]), f => { 10862 const parent = navigation.owner(f); 10863 const rest = walkUp(navigation, parent); 10864 return [f].concat(rest); 10865 }); 10866 }; 10867 const pathTo = (element, navigation) => { 10868 const d = navigation.owner(element); 10869 return walkUp(navigation, d); 10870 }; 10871 10872 const view = doc => { 10873 var _a; 10874 const element = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement); 10875 return element.map(SugarElement.fromDom); 10876 }; 10877 const owner = element => documentOrOwner(element); 10878 10879 var Navigation = /*#__PURE__*/Object.freeze({ 10880 __proto__: null, 10881 view: view, 10882 owner: owner 10883 }); 10884 10885 const find = element => { 10886 const doc = getDocument(); 10887 const scroll = get$5(doc); 10888 const frames = pathTo(element, Navigation); 10889 const offset = viewport(element); 10890 const r = foldr(frames, (b, a) => { 10891 const loc = viewport(a); 10892 return { 10893 left: b.left + loc.left, 10894 top: b.top + loc.top 10895 }; 10896 }, { 10897 left: 0, 10898 top: 0 10899 }); 10900 return SugarPosition(r.left + offset.left + scroll.left, r.top + offset.top + scroll.top); 10901 }; 10902 10903 const excludeFromDescend = element => name(element) === 'textarea'; 10904 const fireScrollIntoViewEvent = (editor, data) => { 10905 const scrollEvent = editor.dispatch('ScrollIntoView', data); 10906 return scrollEvent.isDefaultPrevented(); 10907 }; 10908 const fireAfterScrollIntoViewEvent = (editor, data) => { 10909 editor.dispatch('AfterScrollIntoView', data); 10910 }; 10911 const descend = (element, offset) => { 10912 const children = children$1(element); 10913 if (children.length === 0 || excludeFromDescend(element)) { 10914 return { 10915 element, 10916 offset 10917 }; 10918 } else if (offset < children.length && !excludeFromDescend(children[offset])) { 10919 return { 10920 element: children[offset], 10921 offset: 0 10922 }; 10923 } else { 10924 const last = children[children.length - 1]; 10925 if (excludeFromDescend(last)) { 10926 return { 10927 element, 10928 offset 10929 }; 10930 } else { 10931 if (name(last) === 'img') { 10932 return { 10933 element: last, 10934 offset: 1 10935 }; 10936 } else if (isText$c(last)) { 10937 return { 10938 element: last, 10939 offset: get$3(last).length 10940 }; 10941 } else { 10942 return { 10943 element: last, 10944 offset: children$1(last).length 10945 }; 10946 } 10947 } 10948 } 10949 }; 10950 const markerInfo = (element, cleanupFun) => { 10951 const pos = absolute(element); 10952 const height = get$2(element); 10953 return { 10954 element, 10955 bottom: pos.top + height, 10956 height, 10957 pos, 10958 cleanup: cleanupFun 10959 }; 10960 }; 10961 const createMarker$1 = (element, offset) => { 10962 const startPoint = descend(element, offset); 10963 const span = SugarElement.fromHtml('<span data-mce-bogus="all" style="display: inline-block;">' + ZWSP$1 + '</span>'); 10964 before$3(startPoint.element, span); 10965 return markerInfo(span, () => remove$4(span)); 10966 }; 10967 const elementMarker = element => markerInfo(SugarElement.fromDom(element), noop); 10968 const withMarker = (editor, f, rng, alignToTop) => { 10969 preserveWith(editor, (_s, _e) => applyWithMarker(editor, f, rng, alignToTop), rng); 10970 }; 10971 const withScrollEvents = (editor, doc, f, marker, alignToTop) => { 10972 const data = { 10973 elm: marker.element.dom, 10974 alignToTop 10975 }; 10976 if (fireScrollIntoViewEvent(editor, data)) { 10977 return; 10978 } 10979 const scrollTop = get$5(doc).top; 10980 f(editor, doc, scrollTop, marker, alignToTop); 10981 fireAfterScrollIntoViewEvent(editor, data); 10982 }; 10983 const applyWithMarker = (editor, f, rng, alignToTop) => { 10984 const body = SugarElement.fromDom(editor.getBody()); 10985 const doc = SugarElement.fromDom(editor.getDoc()); 10986 reflow(body); 10987 const marker = createMarker$1(SugarElement.fromDom(rng.startContainer), rng.startOffset); 10988 withScrollEvents(editor, doc, f, marker, alignToTop); 10989 marker.cleanup(); 10990 }; 10991 const withElement = (editor, element, f, alignToTop) => { 10992 const doc = SugarElement.fromDom(editor.getDoc()); 10993 withScrollEvents(editor, doc, f, elementMarker(element), alignToTop); 10994 }; 10995 const preserveWith = (editor, f, rng) => { 10996 const startElement = rng.startContainer; 10997 const startOffset = rng.startOffset; 10998 const endElement = rng.endContainer; 10999 const endOffset = rng.endOffset; 11000 f(SugarElement.fromDom(startElement), SugarElement.fromDom(endElement)); 11001 const newRng = editor.dom.createRng(); 11002 newRng.setStart(startElement, startOffset); 11003 newRng.setEnd(endElement, endOffset); 11004 editor.selection.setRng(rng); 11005 }; 11006 const scrollToMarker = (editor, marker, viewHeight, alignToTop, doc) => { 11007 const pos = marker.pos; 11008 if (alignToTop) { 11009 to(pos.left, pos.top, doc); 11010 } else { 11011 const y = pos.top - viewHeight + marker.height; 11012 to(-editor.getBody().getBoundingClientRect().left, y, doc); 11013 } 11014 }; 11015 const intoWindowIfNeeded = (editor, doc, scrollTop, viewHeight, marker, alignToTop) => { 11016 const viewportBottom = viewHeight + scrollTop; 11017 const markerTop = marker.pos.top; 11018 const markerBottom = marker.bottom; 11019 const largerThanViewport = markerBottom - markerTop >= viewHeight; 11020 if (markerTop < scrollTop) { 11021 scrollToMarker(editor, marker, viewHeight, alignToTop !== false, doc); 11022 } else if (markerTop > viewportBottom) { 11023 const align = largerThanViewport ? alignToTop !== false : alignToTop === true; 11024 scrollToMarker(editor, marker, viewHeight, align, doc); 11025 } else if (markerBottom > viewportBottom && !largerThanViewport) { 11026 scrollToMarker(editor, marker, viewHeight, alignToTop === true, doc); 11027 } 11028 }; 11029 const intoWindow = (editor, doc, scrollTop, marker, alignToTop) => { 11030 const viewHeight = defaultView(doc).dom.innerHeight; 11031 intoWindowIfNeeded(editor, doc, scrollTop, viewHeight, marker, alignToTop); 11032 }; 11033 const intoFrame = (editor, doc, scrollTop, marker, alignToTop) => { 11034 const frameViewHeight = defaultView(doc).dom.innerHeight; 11035 intoWindowIfNeeded(editor, doc, scrollTop, frameViewHeight, marker, alignToTop); 11036 const op = find(marker.element); 11037 const viewportBounds = getBounds(window); 11038 if (op.top < viewportBounds.y) { 11039 intoView(marker.element, alignToTop !== false); 11040 } else if (op.top > viewportBounds.bottom) { 11041 intoView(marker.element, alignToTop === true); 11042 } 11043 }; 11044 const rangeIntoWindow = (editor, rng, alignToTop) => withMarker(editor, intoWindow, rng, alignToTop); 11045 const elementIntoWindow = (editor, element, alignToTop) => withElement(editor, element, intoWindow, alignToTop); 11046 const rangeIntoFrame = (editor, rng, alignToTop) => withMarker(editor, intoFrame, rng, alignToTop); 11047 const elementIntoFrame = (editor, element, alignToTop) => withElement(editor, element, intoFrame, alignToTop); 11048 const scrollElementIntoView = (editor, element, alignToTop) => { 11049 const scroller = editor.inline ? elementIntoWindow : elementIntoFrame; 11050 scroller(editor, element, alignToTop); 11051 }; 11052 const scrollRangeIntoView = (editor, rng, alignToTop) => { 11053 const scroller = editor.inline ? rangeIntoWindow : rangeIntoFrame; 11054 scroller(editor, rng, alignToTop); 11055 }; 11056 11057 const isEditableRange = (dom, rng) => { 11058 if (rng.collapsed) { 11059 return dom.isEditable(rng.startContainer); 11060 } else { 11061 return dom.isEditable(rng.startContainer) && dom.isEditable(rng.endContainer); 11062 } 11063 }; 11064 11065 const getEndpointElement = (root, rng, start, real, resolve) => { 11066 const container = start ? rng.startContainer : rng.endContainer; 11067 const offset = start ? rng.startOffset : rng.endOffset; 11068 return Optional.from(container).map(SugarElement.fromDom).map(elm => !real || !rng.collapsed ? child$1(elm, resolve(elm, offset)).getOr(elm) : elm).bind(elm => isElement$7(elm) ? Optional.some(elm) : parent(elm).filter(isElement$7)).map(elm => elm.dom).getOr(root); 11069 }; 11070 const getStart = (root, rng, real = false) => getEndpointElement(root, rng, true, real, (elm, offset) => Math.min(childNodesCount(elm), offset)); 11071 const getEnd = (root, rng, real = false) => getEndpointElement(root, rng, false, real, (elm, offset) => offset > 0 ? offset - 1 : offset); 11072 const skipEmptyTextNodes = (node, forwards) => { 11073 const orig = node; 11074 while (node && isText$b(node) && node.length === 0) { 11075 node = forwards ? node.nextSibling : node.previousSibling; 11076 } 11077 return node || orig; 11078 }; 11079 const getNode = (root, rng) => { 11080 if (!rng) { 11081 return root; 11082 } 11083 let startContainer = rng.startContainer; 11084 let endContainer = rng.endContainer; 11085 const startOffset = rng.startOffset; 11086 const endOffset = rng.endOffset; 11087 let node = rng.commonAncestorContainer; 11088 if (!rng.collapsed) { 11089 if (startContainer === endContainer) { 11090 if (endOffset - startOffset < 2) { 11091 if (startContainer.hasChildNodes()) { 11092 node = startContainer.childNodes[startOffset]; 11093 } 11094 } 11095 } 11096 if (isText$b(startContainer) && isText$b(endContainer)) { 11097 if (startContainer.length === startOffset) { 11098 startContainer = skipEmptyTextNodes(startContainer.nextSibling, true); 11099 } else { 11100 startContainer = startContainer.parentNode; 11101 } 11102 if (endOffset === 0) { 11103 endContainer = skipEmptyTextNodes(endContainer.previousSibling, false); 11104 } else { 11105 endContainer = endContainer.parentNode; 11106 } 11107 if (startContainer && startContainer === endContainer) { 11108 node = startContainer; 11109 } 11110 } 11111 } 11112 const elm = isText$b(node) ? node.parentNode : node; 11113 return isHTMLElement(elm) ? elm : root; 11114 }; 11115 const getSelectedBlocks = (dom, rng, startElm, endElm) => { 11116 const selectedBlocks = []; 11117 const root = dom.getRoot(); 11118 const start = dom.getParent(startElm || getStart(root, rng, rng.collapsed), dom.isBlock); 11119 const end = dom.getParent(endElm || getEnd(root, rng, rng.collapsed), dom.isBlock); 11120 if (start && start !== root) { 11121 selectedBlocks.push(start); 11122 } 11123 if (start && end && start !== end) { 11124 let node; 11125 const walker = new DomTreeWalker(start, root); 11126 while ((node = walker.next()) && node !== end) { 11127 if (dom.isBlock(node)) { 11128 selectedBlocks.push(node); 11129 } 11130 } 11131 } 11132 if (end && start !== end && end !== root) { 11133 selectedBlocks.push(end); 11134 } 11135 return selectedBlocks; 11136 }; 11137 const select = (dom, node, content) => Optional.from(node).bind(node => Optional.from(node.parentNode).map(parent => { 11138 const idx = dom.nodeIndex(node); 11139 const rng = dom.createRng(); 11140 rng.setStart(parent, idx); 11141 rng.setEnd(parent, idx + 1); 11142 if (content) { 11143 moveEndPoint(dom, rng, node, true); 11144 moveEndPoint(dom, rng, node, false); 11145 } 11146 return rng; 11147 })); 11148 11149 const processRanges = (editor, ranges) => map$3(ranges, range => { 11150 const evt = editor.dispatch('GetSelectionRange', { range }); 11151 return evt.range !== range ? evt.range : range; 11152 }); 11153 11154 const typeLookup = { 11155 '#text': 3, 11156 '#comment': 8, 11157 '#cdata': 4, 11158 '#pi': 7, 11159 '#doctype': 10, 11160 '#document-fragment': 11 11161 }; 11162 const walk$2 = (node, root, prev) => { 11163 const startName = prev ? 'lastChild' : 'firstChild'; 11164 const siblingName = prev ? 'prev' : 'next'; 11165 if (node[startName]) { 11166 return node[startName]; 11167 } 11168 if (node !== root) { 11169 let sibling = node[siblingName]; 11170 if (sibling) { 11171 return sibling; 11172 } 11173 for (let parent = node.parent; parent && parent !== root; parent = parent.parent) { 11174 sibling = parent[siblingName]; 11175 if (sibling) { 11176 return sibling; 11177 } 11178 } 11179 } 11180 return undefined; 11181 }; 11182 const isEmptyTextNode = node => { 11183 var _a; 11184 const text = (_a = node.value) !== null && _a !== void 0 ? _a : ''; 11185 if (!isWhitespaceText(text)) { 11186 return false; 11187 } 11188 const parentNode = node.parent; 11189 if (parentNode && (parentNode.name !== 'span' || parentNode.attr('style')) && /^[ ]+$/.test(text)) { 11190 return false; 11191 } 11192 return true; 11193 }; 11194 const isNonEmptyElement = node => { 11195 const isNamedAnchor = node.name === 'a' && !node.attr('href') && node.attr('id'); 11196 return node.attr('name') || node.attr('id') && !node.firstChild || node.attr('data-mce-bookmark') || isNamedAnchor; 11197 }; 11198 class AstNode { 11199 static create(name, attrs) { 11200 const node = new AstNode(name, typeLookup[name] || 1); 11201 if (attrs) { 11202 each$d(attrs, (value, attrName) => { 11203 node.attr(attrName, value); 11204 }); 11205 } 11206 return node; 11207 } 11208 constructor(name, type) { 11209 this.name = name; 11210 this.type = type; 11211 if (type === 1) { 11212 this.attributes = []; 11213 this.attributes.map = {}; 11214 } 11215 } 11216 replace(node) { 11217 const self = this; 11218 if (node.parent) { 11219 node.remove(); 11220 } 11221 self.insert(node, self); 11222 self.remove(); 11223 return self; 11224 } 11225 attr(name, value) { 11226 const self = this; 11227 if (!isString(name)) { 11228 if (isNonNullable(name)) { 11229 each$d(name, (value, key) => { 11230 self.attr(key, value); 11231 }); 11232 } 11233 return self; 11234 } 11235 const attrs = self.attributes; 11236 if (attrs) { 11237 if (value !== undefined) { 11238 if (value === null) { 11239 if (name in attrs.map) { 11240 delete attrs.map[name]; 11241 let i = attrs.length; 11242 while (i--) { 11243 if (attrs[i].name === name) { 11244 attrs.splice(i, 1); 11245 return self; 11246 } 11247 } 11248 } 11249 return self; 11250 } 11251 if (name in attrs.map) { 11252 let i = attrs.length; 11253 while (i--) { 11254 if (attrs[i].name === name) { 11255 attrs[i].value = value; 11256 break; 11257 } 11258 } 11259 } else { 11260 attrs.push({ 11261 name, 11262 value 11263 }); 11264 } 11265 attrs.map[name] = value; 11266 return self; 11267 } 11268 return attrs.map[name]; 11269 } 11270 return undefined; 11271 } 11272 clone() { 11273 const self = this; 11274 const clone = new AstNode(self.name, self.type); 11275 const selfAttrs = self.attributes; 11276 if (selfAttrs) { 11277 const cloneAttrs = []; 11278 cloneAttrs.map = {}; 11279 for (let i = 0, l = selfAttrs.length; i < l; i++) { 11280 const selfAttr = selfAttrs[i]; 11281 if (selfAttr.name !== 'id') { 11282 cloneAttrs[cloneAttrs.length] = { 11283 name: selfAttr.name, 11284 value: selfAttr.value 11285 }; 11286 cloneAttrs.map[selfAttr.name] = selfAttr.value; 11287 } 11288 } 11289 clone.attributes = cloneAttrs; 11290 } 11291 clone.value = self.value; 11292 return clone; 11293 } 11294 wrap(wrapper) { 11295 const self = this; 11296 if (self.parent) { 11297 self.parent.insert(wrapper, self); 11298 wrapper.append(self); 11299 } 11300 return self; 11301 } 11302 unwrap() { 11303 const self = this; 11304 for (let node = self.firstChild; node;) { 11305 const next = node.next; 11306 self.insert(node, self, true); 11307 node = next; 11308 } 11309 self.remove(); 11310 } 11311 remove() { 11312 const self = this, parent = self.parent, next = self.next, prev = self.prev; 11313 if (parent) { 11314 if (parent.firstChild === self) { 11315 parent.firstChild = next; 11316 if (next) { 11317 next.prev = null; 11318 } 11319 } else if (prev) { 11320 prev.next = next; 11321 } 11322 if (parent.lastChild === self) { 11323 parent.lastChild = prev; 11324 if (prev) { 11325 prev.next = null; 11326 } 11327 } else if (next) { 11328 next.prev = prev; 11329 } 11330 self.parent = self.next = self.prev = null; 11331 } 11332 return self; 11333 } 11334 append(node) { 11335 const self = this; 11336 if (node.parent) { 11337 node.remove(); 11338 } 11339 const last = self.lastChild; 11340 if (last) { 11341 last.next = node; 11342 node.prev = last; 11343 self.lastChild = node; 11344 } else { 11345 self.lastChild = self.firstChild = node; 11346 } 11347 node.parent = self; 11348 return node; 11349 } 11350 insert(node, refNode, before) { 11351 if (node.parent) { 11352 node.remove(); 11353 } 11354 const parent = refNode.parent || this; 11355 if (before) { 11356 if (refNode === parent.firstChild) { 11357 parent.firstChild = node; 11358 } else if (refNode.prev) { 11359 refNode.prev.next = node; 11360 } 11361 node.prev = refNode.prev; 11362 node.next = refNode; 11363 refNode.prev = node; 11364 } else { 11365 if (refNode === parent.lastChild) { 11366 parent.lastChild = node; 11367 } else if (refNode.next) { 11368 refNode.next.prev = node; 11369 } 11370 node.next = refNode.next; 11371 node.prev = refNode; 11372 refNode.next = node; 11373 } 11374 node.parent = parent; 11375 return node; 11376 } 11377 getAll(name) { 11378 const self = this; 11379 const collection = []; 11380 for (let node = self.firstChild; node; node = walk$2(node, self)) { 11381 if (node.name === name) { 11382 collection.push(node); 11383 } 11384 } 11385 return collection; 11386 } 11387 children() { 11388 const self = this; 11389 const collection = []; 11390 for (let node = self.firstChild; node; node = node.next) { 11391 collection.push(node); 11392 } 11393 return collection; 11394 } 11395 empty() { 11396 const self = this; 11397 if (self.firstChild) { 11398 const nodes = []; 11399 for (let node = self.firstChild; node; node = walk$2(node, self)) { 11400 nodes.push(node); 11401 } 11402 let i = nodes.length; 11403 while (i--) { 11404 const node = nodes[i]; 11405 node.parent = node.firstChild = node.lastChild = node.next = node.prev = null; 11406 } 11407 } 11408 self.firstChild = self.lastChild = null; 11409 return self; 11410 } 11411 isEmpty(elements, whitespace = {}, predicate) { 11412 var _a; 11413 const self = this; 11414 let node = self.firstChild; 11415 if (isNonEmptyElement(self)) { 11416 return false; 11417 } 11418 if (node) { 11419 do { 11420 if (node.type === 1) { 11421 if (node.attr('data-mce-bogus')) { 11422 continue; 11423 } 11424 if (elements[node.name]) { 11425 return false; 11426 } 11427 if (isNonEmptyElement(node)) { 11428 return false; 11429 } 11430 } 11431 if (node.type === 8) { 11432 return false; 11433 } 11434 if (node.type === 3 && !isEmptyTextNode(node)) { 11435 return false; 11436 } 11437 if (node.type === 3 && node.parent && whitespace[node.parent.name] && isWhitespaceText((_a = node.value) !== null && _a !== void 0 ? _a : '')) { 11438 return false; 11439 } 11440 if (predicate && predicate(node)) { 11441 return false; 11442 } 11443 } while (node = walk$2(node, self)); 11444 } 11445 return true; 11446 } 11447 walk(prev) { 11448 return walk$2(this, null, prev); 11449 } 11450 } 11451 11452 const unescapedTextParents = Tools.makeMap('NOSCRIPT STYLE SCRIPT XMP IFRAME NOEMBED NOFRAMES PLAINTEXT', ' '); 11453 const containsZwsp = node => isString(node.nodeValue) && node.nodeValue.includes(ZWSP$1); 11454 const getTemporaryNodeSelector = tempAttrs => `${ tempAttrs.length === 0 ? '' : `${ map$3(tempAttrs, attr => `[${ attr }]`).join(',') },` }[data-mce-bogus="all"]`; 11455 const getTemporaryNodes = (tempAttrs, body) => body.querySelectorAll(getTemporaryNodeSelector(tempAttrs)); 11456 const createZwspCommentWalker = body => document.createTreeWalker(body, NodeFilter.SHOW_COMMENT, node => containsZwsp(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP); 11457 const createUnescapedZwspTextWalker = body => document.createTreeWalker(body, NodeFilter.SHOW_TEXT, node => { 11458 if (containsZwsp(node)) { 11459 const parent = node.parentNode; 11460 return parent && has$2(unescapedTextParents, parent.nodeName) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; 11461 } else { 11462 return NodeFilter.FILTER_SKIP; 11463 } 11464 }); 11465 const hasZwspComment = body => createZwspCommentWalker(body).nextNode() !== null; 11466 const hasUnescapedZwspText = body => createUnescapedZwspTextWalker(body).nextNode() !== null; 11467 const hasTemporaryNode = (tempAttrs, body) => body.querySelector(getTemporaryNodeSelector(tempAttrs)) !== null; 11468 const trimTemporaryNodes = (tempAttrs, body) => { 11469 each$e(getTemporaryNodes(tempAttrs, body), elm => { 11470 const element = SugarElement.fromDom(elm); 11471 if (get$9(element, 'data-mce-bogus') === 'all') { 11472 remove$4(element); 11473 } else { 11474 each$e(tempAttrs, attr => { 11475 if (has$1(element, attr)) { 11476 remove$9(element, attr); 11477 } 11478 }); 11479 } 11480 }); 11481 }; 11482 const emptyAllNodeValuesInWalker = walker => { 11483 let curr = walker.nextNode(); 11484 while (curr !== null) { 11485 curr.nodeValue = null; 11486 curr = walker.nextNode(); 11487 } 11488 }; 11489 const emptyZwspComments = compose(emptyAllNodeValuesInWalker, createZwspCommentWalker); 11490 const emptyUnescapedZwspTexts = compose(emptyAllNodeValuesInWalker, createUnescapedZwspTextWalker); 11491 const trim$1 = (body, tempAttrs) => { 11492 const conditionalTrims = [ 11493 { 11494 condition: curry(hasTemporaryNode, tempAttrs), 11495 action: curry(trimTemporaryNodes, tempAttrs) 11496 }, 11497 { 11498 condition: hasZwspComment, 11499 action: emptyZwspComments 11500 }, 11501 { 11502 condition: hasUnescapedZwspText, 11503 action: emptyUnescapedZwspTexts 11504 } 11505 ]; 11506 let trimmed = body; 11507 let cloned = false; 11508 each$e(conditionalTrims, ({condition, action}) => { 11509 if (condition(trimmed)) { 11510 if (!cloned) { 11511 trimmed = body.cloneNode(true); 11512 cloned = true; 11513 } 11514 action(trimmed); 11515 } 11516 }); 11517 return trimmed; 11518 }; 11519 11520 const cleanupBogusElements = parent => { 11521 const bogusElements = descendants(parent, '[data-mce-bogus]'); 11522 each$e(bogusElements, elem => { 11523 const bogusValue = get$9(elem, 'data-mce-bogus'); 11524 if (bogusValue === 'all') { 11525 remove$4(elem); 11526 } else if (isBr$5(elem)) { 11527 before$3(elem, SugarElement.fromText(zeroWidth)); 11528 remove$4(elem); 11529 } else { 11530 unwrap(elem); 11531 } 11532 }); 11533 }; 11534 const cleanupInputNames = parent => { 11535 const inputs = descendants(parent, 'input'); 11536 each$e(inputs, input => { 11537 remove$9(input, 'name'); 11538 }); 11539 }; 11540 11541 const trimEmptyContents = (editor, html) => { 11542 const blockName = getForcedRootBlock(editor); 11543 const emptyRegExp = new RegExp(`^(<${ blockName }[^>]*>( | |\\s|\u00a0|<br \\/>|)<\\/${ blockName }>[\r\n]*|<br \\/>[\r\n]*)$`); 11544 return html.replace(emptyRegExp, ''); 11545 }; 11546 const getPlainTextContent = (editor, body) => { 11547 const doc = editor.getDoc(); 11548 const dos = getRootNode(SugarElement.fromDom(editor.getBody())); 11549 const offscreenDiv = SugarElement.fromTag('div', doc); 11550 set$
vendor: 10,042 bytes, lines 11550-11840
115504(offscreenDiv, 'data-mce-bogus', 'all'); 11551 setAll(offscreenDiv, { 11552 position: 'fixed', 11553 left: '-9999999px', 11554 top: '0' 11555 }); 11556 set$1(offscreenDiv, body.innerHTML); 11557 cleanupBogusElements(offscreenDiv); 11558 cleanupInputNames(offscreenDiv); 11559 const root = getContentContainer(dos); 11560 append$1(root, offscreenDiv); 11561 const content = trim$2(offscreenDiv.dom.innerText); 11562 remove$4(offscreenDiv); 11563 return content; 11564 }; 11565 const getContentFromBody = (editor, args, body) => { 11566 let content; 11567 if (args.format === 'raw') { 11568 content = Tools.trim(trim$2(trim$1(body, editor.serializer.getTempAttrs()).innerHTML)); 11569 } else if (args.format === 'text') { 11570 content = getPlainTextContent(editor, body); 11571 } else if (args.format === 'tree') { 11572 content = editor.serializer.serialize(body, args); 11573 } else { 11574 content = trimEmptyContents(editor, editor.serializer.serialize(body, args)); 11575 } 11576 const shouldTrim = args.format !== 'text' && !isWsPreserveElement(SugarElement.fromDom(body)); 11577 return shouldTrim && isString(content) ? Tools.trim(content) : content; 11578 }; 11579 const getContentInternal = (editor, args) => Optional.from(editor.getBody()).fold(constant(args.format === 'tree' ? new AstNode('body', 11) : ''), body => getContentFromBody(editor, args, body)); 11580 11581 const makeMap$1 = Tools.makeMap; 11582 const Writer = settings => { 11583 const html = []; 11584 settings = settings || {}; 11585 const indent = settings.indent; 11586 const indentBefore = makeMap$1(settings.indent_before || ''); 11587 const indentAfter = makeMap$1(settings.indent_after || ''); 11588 const encode = Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities); 11589 const htmlOutput = settings.element_format !== 'xhtml'; 11590 return { 11591 start: (name, attrs, empty) => { 11592 if (indent && indentBefore[name] && html.length > 0) { 11593 const value = html[html.length - 1]; 11594 if (value.length > 0 && value !== '\n') { 11595 html.push('\n'); 11596 } 11597 } 11598 html.push('<', name); 11599 if (attrs) { 11600 for (let i = 0, l = attrs.length; i < l; i++) { 11601 const attr = attrs[i]; 11602 html.push(' ', attr.name, '="', encode(attr.value, true), '"'); 11603 } 11604 } 11605 if (!empty || htmlOutput) { 11606 html[html.length] = '>'; 11607 } else { 11608 html[html.length] = ' />'; 11609 } 11610 if (empty && indent && indentAfter[name] && html.length > 0) { 11611 const value = html[html.length - 1]; 11612 if (value.length > 0 && value !== '\n') { 11613 html.push('\n'); 11614 } 11615 } 11616 }, 11617 end: name => { 11618 let value; 11619 html.push('</', name, '>'); 11620 if (indent && indentAfter[name] && html.length > 0) { 11621 value = html[html.length - 1]; 11622 if (value.length > 0 && value !== '\n') { 11623 html.push('\n'); 11624 } 11625 } 11626 }, 11627 text: (text, raw) => { 11628 if (text.length > 0) { 11629 html[html.length] = raw ? text : encode(text); 11630 } 11631 }, 11632 cdata: text => { 11633 html.push('<![CDATA[', text, ']]>'); 11634 }, 11635 comment: text => { 11636 html.push('<!--', text, '-->'); 11637 }, 11638 pi: (name, text) => { 11639 if (text) { 11640 html.push('<?', name, ' ', encode(text), '?>'); 11641 } else { 11642 html.push('<?', name, '?>'); 11643 } 11644 if (indent) { 11645 html.push('\n'); 11646 } 11647 }, 11648 doctype: text => { 11649 html.push('<!DOCTYPE', text, '>', indent ? '\n' : ''); 11650 }, 11651 reset: () => { 11652 html.length = 0; 11653 }, 11654 getContent: () => { 11655 return html.join('').replace(/\n$/, ''); 11656 } 11657 }; 11658 }; 11659 11660 const HtmlSerializer = (settings = {}, schema = Schema()) => { 11661 const writer = Writer(settings); 11662 settings.validate = 'validate' in settings ? settings.validate : true; 11663 const serialize = node => { 11664 const validate = settings.validate; 11665 const handlers = { 11666 3: node => { 11667 var _a; 11668 writer.text((_a = node.value) !== null && _a !== void 0 ? _a : '', node.raw); 11669 }, 11670 8: node => { 11671 var _a; 11672 writer.comment((_a = node.value) !== null && _a !== void 0 ? _a : ''); 11673 }, 11674 7: node => { 11675 writer.pi(node.name, node.value); 11676 }, 11677 10: node => { 11678 var _a; 11679 writer.doctype((_a = node.value) !== null && _a !== void 0 ? _a : ''); 11680 }, 11681 4: node => { 11682 var _a; 11683 writer.cdata((_a = node.value) !== null && _a !== void 0 ? _a : ''); 11684 }, 11685 11: node => { 11686 let tempNode = node; 11687 if (tempNode = tempNode.firstChild) { 11688 do { 11689 walk(tempNode); 11690 } while (tempNode = tempNode.next); 11691 } 11692 } 11693 }; 11694 writer.reset(); 11695 const walk = node => { 11696 var _a; 11697 const handler = handlers[node.type]; 11698 if (!handler) { 11699 const name = node.name; 11700 const isEmpty = name in schema.getVoidElements(); 11701 let attrs = node.attributes; 11702 if (validate && attrs && attrs.length > 1) { 11703 const sortedAttrs = []; 11704 sortedAttrs.map = {}; 11705 const elementRule = schema.getElementRule(node.name); 11706 if (elementRule) { 11707 for (let i = 0, l = elementRule.attributesOrder.length; i < l; i++) { 11708 const attrName = elementRule.attributesOrder[i]; 11709 if (attrName in attrs.map) { 11710 const attrValue = attrs.map[attrName]; 11711 sortedAttrs.map[attrName] = attrValue; 11712 sortedAttrs.push({ 11713 name: attrName, 11714 value: attrValue 11715 }); 11716 } 11717 } 11718 for (let i = 0, l = attrs.length; i < l; i++) { 11719 const attrName = attrs[i].name; 11720 if (!(attrName in sortedAttrs.map)) { 11721 const attrValue = attrs.map[attrName]; 11722 sortedAttrs.map[attrName] = attrValue; 11723 sortedAttrs.push({ 11724 name: attrName, 11725 value: attrValue 11726 }); 11727 } 11728 } 11729 attrs = sortedAttrs; 11730 } 11731 } 11732 writer.start(name, attrs, isEmpty); 11733 if (isNonHtmlElementRootName(name)) { 11734 if (isString(node.value)) { 11735 writer.text(node.value, true); 11736 } 11737 writer.end(name); 11738 } else { 11739 if (!isEmpty) { 11740 let child = node.firstChild; 11741 if (child) { 11742 if ((name === 'pre' || name === 'textarea') && child.type === 3 && ((_a = child.value) === null || _a === void 0 ? void 0 : _a[0]) === '\n') { 11743 writer.text('\n', true); 11744 } 11745 do { 11746 walk(child); 11747 } while (child = child.next); 11748 } 11749 writer.end(name); 11750 } 11751 } 11752 } else { 11753 handler(node); 11754 } 11755 }; 11756 if (node.type === 1 && !settings.inner) { 11757 walk(node); 11758 } else if (node.type === 3) { 11759 handlers[3](node); 11760 } else { 11761 handlers[11](node); 11762 } 11763 return writer.getContent(); 11764 }; 11765 return { serialize }; 11766 }; 11767 11768 const nonInheritableStyles = new Set(); 11769 (() => { 11770 const nonInheritableStylesArr = [ 11771 'margin', 11772 'margin-left', 11773 'margin-right', 11774 'margin-top', 11775 'margin-bottom', 11776 'padding', 11777 'padding-left', 11778 'padding-right', 11779 'padding-top', 11780 'padding-bottom', 11781 'border', 11782 'border-width', 11783 'border-style', 11784 'border-color', 11785 'background', 11786 'background-attachment', 11787 'background-clip', 11788 'background-image', 11789 'background-origin', 11790 'background-position', 11791 'background-repeat', 11792 'background-size', 11793 'float', 11794 'position', 11795 'left', 11796 'right', 11797 'top', 11798 'bottom', 11799 'z-index', 11800 'display', 11801 'transform', 11802 'width', 11803 'max-width', 11804 'min-width', 11805 'height', 11806 'max-height', 11807 'min-height', 11808 'overflow', 11809 'overflow-x', 11810 'overflow-y', 11811 'text-overflow', 11812 'vertical-align', 11813 'transition', 11814 'transition-delay', 11815 'transition-duration', 11816 'transition-property', 11817 'transition-timing-function' 11818 ]; 11819 each$e(nonInheritableStylesArr, style => { 11820 nonInheritableStyles.add(style); 11821 }); 11822 })(); 11823 const conditionalNonInheritableStyles = new Set(); 11824 (() => { 11825 const conditionalNonInheritableStylesArr = ['background-color']; 11826 each$e(conditionalNonInheritableStylesArr, style => { 11827 conditionalNonInheritableStyles.add(style); 11828 }); 11829 })(); 11830 const shorthandStyleProps = [ 11831 'font', 11832 'text-decoration', 11833 'text-emphasis' 11834 ]; 11835 const getStyles$1 = (dom, node) => dom.parseStyle(dom.getAttrib(node, 'style')); 11836 const getStyleProps = (dom, node) => keys(getStyles$1(dom, node)); 11837 const isNonInheritableStyle = style => nonInheritableStyles.has(style); 11838 const isConditionalNonInheritableStyle = style => conditionalNonInheritableStyles.has(style); 11839 const hasNonInheritableStyles = (dom, node) => exists(getStyleProps(dom, node), style => isNonInheritableStyle(style)); 11840 const hasConditionalNonInheritableStyles = (dom, node) => hasNonInheritableStyles(dom, node) && exists(getStyleProps(dom, node), style => isConditional
vendor: 10,717 bytes, lines 11840-12042
11840NonInheritableStyle(style)); 11841 const getLonghandStyleProps = styles => filter$5(styles, style => exists(shorthandStyleProps, prop => startsWith(style, prop))); 11842 const hasStyleConflict = (dom, node, parentNode) => { 11843 const nodeStyleProps = getStyleProps(dom, node); 11844 const parentNodeStyleProps = getStyleProps(dom, parentNode); 11845 const valueMismatch = prop => { 11846 var _a, _b; 11847 const nodeValue = (_a = dom.getStyle(node, prop)) !== null && _a !== void 0 ? _a : ''; 11848 const parentValue = (_b = dom.getStyle(parentNode, prop)) !== null && _b !== void 0 ? _b : ''; 11849 return isNotEmpty(nodeValue) && isNotEmpty(parentValue) && nodeValue !== parentValue; 11850 }; 11851 return exists(nodeStyleProps, nodeStyleProp => { 11852 const propExists = props => exists(props, prop => prop === nodeStyleProp); 11853 if (!propExists(parentNodeStyleProps) && propExists(shorthandStyleProps)) { 11854 const longhandProps = getLonghandStyleProps(parentNodeStyleProps); 11855 return exists(longhandProps, valueMismatch); 11856 } else { 11857 return valueMismatch(nodeStyleProp); 11858 } 11859 }); 11860 }; 11861 11862 const isChar = (forward, predicate, pos) => Optional.from(pos.container()).filter(isText$b).exists(text => { 11863 const delta = forward ? 0 : -1; 11864 return predicate(text.data.charAt(pos.offset() + delta)); 11865 }); 11866 const isBeforeSpace = curry(isChar, true, isWhiteSpace); 11867 const isAfterSpace = curry(isChar, false, isWhiteSpace); 11868 const isEmptyText = pos => { 11869 const container = pos.container(); 11870 return isText$b(container) && (container.data.length === 0 || isZwsp(container.data) && BookmarkManager.isBookmarkNode(container.parentNode)); 11871 }; 11872 const matchesElementPosition = (before, predicate) => pos => getChildNodeAtRelativeOffset(before ? 0 : -1, pos).filter(predicate).isSome(); 11873 const isImageBlock = node => isImg(node) && get$7(SugarElement.fromDom(node), 'display') === 'block'; 11874 const isCefNode = node => isContentEditableFalse$b(node) && !isBogusAll(node); 11875 const isBeforeImageBlock = matchesElementPosition(true, isImageBlock); 11876 const isAfterImageBlock = matchesElementPosition(false, isImageBlock); 11877 const isBeforeMedia = matchesElementPosition(true, isMedia$2); 11878 const isAfterMedia = matchesElementPosition(false, isMedia$2); 11879 const isBeforeTable = matchesElementPosition(true, isTable$2); 11880 const isAfterTable = matchesElementPosition(false, isTable$2); 11881 const isBeforeContentEditableFalse = matchesElementPosition(true, isCefNode); 11882 const isAfterContentEditableFalse = matchesElementPosition(false, isCefNode); 11883 11884 const dropLast = xs => xs.slice(0, -1); 11885 const parentsUntil = (start, root, predicate) => { 11886 if (contains(root, start)) { 11887 return dropLast(parents$1(start, elm => { 11888 return predicate(elm) || eq(elm, root); 11889 })); 11890 } else { 11891 return []; 11892 } 11893 }; 11894 const parents = (start, root) => parentsUntil(start, root, never); 11895 const parentsAndSelf = (start, root) => [start].concat(parents(start, root)); 11896 11897 const navigateIgnoreEmptyTextNodes = (forward, root, from) => navigateIgnore(forward, root, from, isEmptyText); 11898 const isBlock$1 = schema => el => schema.isBlock(name(el)); 11899 const getClosestBlock$1 = (root, pos, schema) => find$2(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$1(schema)); 11900 const isAtBeforeAfterBlockBoundary = (forward, root, pos, schema) => navigateIgnoreEmptyTextNodes(forward, root.dom, pos).forall(newPos => getClosestBlock$1(root, pos, schema).fold(() => !isInSameBlock(newPos, pos, root.dom), fromBlock => !isInSameBlock(newPos, pos, root.dom) && contains(fromBlock, SugarElement.fromDom(newPos.container())))); 11901 const isAtBlockBoundary = (forward, root, pos, schema) => getClosestBlock$1(root, pos, schema).fold(() => navigateIgnoreEmptyTextNodes(forward, root.dom, pos).forall(newPos => !isInSameBlock(newPos, pos, root.dom)), parent => navigateIgnoreEmptyTextNodes(forward, parent.dom, pos).isNone()); 11902 const isAtStartOfBlock = curry(isAtBlockBoundary, false); 11903 const isAtEndOfBlock = curry(isAtBlockBoundary, true); 11904 const isBeforeBlock = curry(isAtBeforeAfterBlockBoundary, false); 11905 const isAfterBlock = curry(isAtBeforeAfterBlockBoundary, true); 11906 11907 const isBr$1 = pos => getElementFromPosition(pos).exists(isBr$5); 11908 const findBr = (forward, root, pos, schema) => { 11909 const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), el => schema.isBlock(name(el))); 11910 const scope = head(parentBlocks).getOr(root); 11911 return fromPosition(forward, scope.dom, pos).filter(isBr$1); 11912 }; 11913 const isBeforeBr$1 = (root, pos, schema) => getElementFromPosition(pos).exists(isBr$5) || findBr(true, root, pos, schema).isSome(); 11914 const isAfterBr = (root, pos, schema) => getElementFromPrevPosition(pos).exists(isBr$5) || findBr(false, root, pos, schema).isSome(); 11915 const findPreviousBr = curry(findBr, false); 11916 const findNextBr = curry(findBr, true); 11917 11918 const isInMiddleOfText = pos => CaretPosition.isTextPosition(pos) && !pos.isAtStart() && !pos.isAtEnd(); 11919 const getClosestBlock = (root, pos, schema) => { 11920 const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), el => schema.isBlock(name(el))); 11921 return head(parentBlocks).getOr(root); 11922 }; 11923 const hasSpaceBefore = (root, pos, schema) => { 11924 if (isInMiddleOfText(pos)) { 11925 return isAfterSpace(pos); 11926 } else { 11927 return isAfterSpace(pos) || prevPosition(getClosestBlock(root, pos, schema).dom, pos).exists(isAfterSpace); 11928 } 11929 }; 11930 const hasSpaceAfter = (root, pos, schema) => { 11931 if (isInMiddleOfText(pos)) { 11932 return isBeforeSpace(pos); 11933 } else { 11934 return isBeforeSpace(pos) || nextPosition(getClosestBlock(root, pos, schema).dom, pos).exists(isBeforeSpace); 11935 } 11936 }; 11937 const isPreValue = value => contains$2([ 11938 'pre', 11939 'pre-wrap' 11940 ], value); 11941 const isInPre = pos => getElementFromPosition(pos).bind(elm => closest$4(elm, isElement$7)).exists(elm => isPreValue(get$7(elm, 'white-space'))); 11942 const isAtBeginningOfBody = (root, pos) => prevPosition(root.dom, pos).isNone(); 11943 const isAtEndOfBody = (root, pos) => nextPosition(root.dom, pos).isNone(); 11944 const isAtLineBoundary = (root, pos, schema) => isAtBeginningOfBody(root, pos) || isAtEndOfBody(root, pos) || isAtStartOfBlock(root, pos, schema) || isAtEndOfBlock(root, pos, schema) || isAfterBr(root, pos, schema) || isBeforeBr$1(root, pos, schema); 11945 const isCefBlock = node => isNonNullable(node) && isContentEditableFalse$b(node) && isBlockLike(node); 11946 const isSiblingCefBlock = (root, direction) => container => { 11947 return isCefBlock(new DomTreeWalker(container, root)[direction]()); 11948 }; 11949 const isBeforeCefBlock = (root, pos) => { 11950 const nextPos = nextPosition(root.dom, pos).getOr(pos); 11951 const isNextCefBlock = isSiblingCefBlock(root.dom, 'next'); 11952 return pos.isAtEnd() && (isNextCefBlock(pos.container()) || isNextCefBlock(nextPos.container())); 11953 }; 11954 const isAfterCefBlock = (root, pos) => { 11955 const prevPos = prevPosition(root.dom, pos).getOr(pos); 11956 const isPrevCefBlock = isSiblingCefBlock(root.dom, 'prev'); 11957 return pos.isAtStart() && (isPrevCefBlock(pos.container()) || isPrevCefBlock(prevPos.container())); 11958 }; 11959 const needsToHaveNbsp = (root, pos, schema) => { 11960 if (isInPre(pos)) { 11961 return false; 11962 } else { 11963 return isAtLineBoundary(root, pos, schema) || hasSpaceBefore(root, pos, schema) || hasSpaceAfter(root, pos, schema); 11964 } 11965 }; 11966 const needsToBeNbspLeft = (root, pos, schema) => { 11967 if (isInPre(pos)) { 11968 return false; 11969 } else { 11970 return isAtStartOfBlock(root, pos, schema) || isBeforeBlock(root, pos, schema) || isAfterBr(root, pos, schema) || hasSpaceBefore(root, pos, schema) || isAfterCefBlock(root, pos); 11971 } 11972 }; 11973 const leanRight = pos => { 11974 const container = pos.container(); 11975 const offset = pos.offset(); 11976 if (isText$b(container) && offset < container.data.length) { 11977 return CaretPosition(container, offset + 1); 11978 } else { 11979 return pos; 11980 } 11981 }; 11982 const needsToBeNbspRight = (root, pos, schema) => { 11983 if (isInPre(pos)) { 11984 return false; 11985 } else { 11986 return isAtEndOfBlock(root, pos, schema) || isAfterBlock(root, pos, schema) || isBeforeBr$1(root, pos, schema) || hasSpaceAfter(root, pos, schema) || isBeforeCefBlock(root, pos); 11987 } 11988 }; 11989 const needsToBeNbsp = (root, pos, schema) => needsToBeNbspLeft(root, pos, schema) || needsToBeNbspRight(root, leanRight(pos), schema); 11990 const isNbspAt = (text, offset) => isNbsp(text.charAt(offset)); 11991 const isWhiteSpaceAt = (text, offset) => isWhiteSpace(text.charAt(offset)); 11992 const hasNbsp = pos => { 11993 const container = pos.container(); 11994 return isText$b(container) && contains$1(container.data, nbsp); 11995 }; 11996 const normalizeNbspMiddle = text => { 11997 const chars = text.split(''); 11998 return map$3(chars, (chr, i) => { 11999 if (isNbsp(chr) && i > 0 && i < chars.length - 1 && isContent(chars[i - 1]) && isContent(chars[i + 1])) { 12000 return ' '; 12001 } else { 12002 return chr; 12003 } 12004 }).join(''); 12005 }; 12006 const normalizeNbspAtStart = (root, node, makeNbsp, schema) => { 12007 const text = node.data; 12008 const firstPos = CaretPosition(node, 0); 12009 if (!makeNbsp && isNbspAt(text, 0) && !needsToBeNbsp(root, firstPos, schema)) { 12010 node.data = ' ' + text.slice(1); 12011 return true; 12012 } else if (makeNbsp && isWhiteSpaceAt(text, 0) && needsToBeNbspLeft(root, firstPos, schema)) { 12013 node.data = nbsp + text.slice(1); 12014 return true; 12015 } else { 12016 return false; 12017 } 12018 }; 12019 const normalizeNbspInMiddleOfTextNode = node => { 12020 const text = node.data; 12021 const newText = normalizeNbspMiddle(text); 12022 if (newText !== text) { 12023 node.data = newText; 12024 return true; 12025 } else { 12026 return false; 12027 } 12028 }; 12029 const normalizeNbspAtEnd = (root, node, makeNbsp, schema) => { 12030 const text = node.data; 12031 const lastPos = CaretPosition(node, text.length - 1); 12032 if (!makeNbsp && isNbspAt(text, text.length - 1) && !needsToBeNbsp(root, lastPos, schema)) { 12033 node.data = text.slice(0, -1) + ' '; 12034 return true; 12035 } else if (makeNbsp && isWhiteSpaceAt(text, text.length - 1) && needsToBeNbspRight(root, lastPos, schema)) { 12036 node.data = text.slice(0, -1) + nbsp; 12037 return true; 12038 } else { 12039 return false; 12040 } 12041 }; 12042 const normalizeNbsps
vendor: 854 bytes, lines 12042-12060
12042$1 = (root, pos, schema) => { 12043 const container = pos.container(); 12044 if (!isText$b(container)) { 12045 return Optional.none(); 12046 } 12047 if (hasNbsp(pos)) { 12048 const normalized = normalizeNbspAtStart(root, container, false, schema) || normalizeNbspInMiddleOfTextNode(container) || normalizeNbspAtEnd(root, container, false, schema); 12049 return someIf(normalized, pos); 12050 } else if (needsToBeNbsp(root, pos, schema)) { 12051 const normalized = normalizeNbspAtStart(root, container, true, schema) || normalizeNbspAtEnd(root, container, true, schema); 12052 return someIf(normalized, pos); 12053 } else { 12054 return Optional.none(); 12055 } 12056 }; 12057 const normalizeNbspsInEditor = editor => { 12058 const root = SugarElement.fromDom(editor.getBody()); 12059 if (editor.selection.isCollapsed()) { 12060 normalizeNbsps$1
vendor: 21,816 bytes, lines 12060-12495
12060(root, CaretPosition.fromRangeStart(editor.selection.getRng()), editor.schema).each(pos => { 12061 editor.selection.setRng(pos.toRange()); 12062 }); 12063 } 12064 }; 12065 12066 const normalize$1 = (node, offset, count, schema) => { 12067 if (count === 0) { 12068 return; 12069 } 12070 const elm = SugarElement.fromDom(node); 12071 const root = ancestor$4(elm, el => schema.isBlock(name(el))).getOr(elm); 12072 const whitespace = node.data.slice(offset, offset + count); 12073 const isEndOfContent = offset + count >= node.data.length && needsToBeNbspRight(root, CaretPosition(node, node.data.length), schema); 12074 const isStartOfContent = offset === 0 && needsToBeNbspLeft(root, CaretPosition(node, 0), schema); 12075 node.replaceData(offset, count, normalize$4(whitespace, 4, isStartOfContent, isEndOfContent)); 12076 }; 12077 const normalizeWhitespaceAfter = (node, offset, schema) => { 12078 const content = node.data.slice(offset); 12079 const whitespaceCount = content.length - lTrim(content).length; 12080 normalize$1(node, offset, whitespaceCount, schema); 12081 }; 12082 const normalizeWhitespaceBefore = (node, offset, schema) => { 12083 const content = node.data.slice(0, offset); 12084 const whitespaceCount = content.length - rTrim(content).length; 12085 normalize$1(node, offset - whitespaceCount, whitespaceCount, schema); 12086 }; 12087 const mergeTextNodes = (prevNode, nextNode, schema, normalizeWhitespace, mergeToPrev = true) => { 12088 const whitespaceOffset = rTrim(prevNode.data).length; 12089 const newNode = mergeToPrev ? prevNode : nextNode; 12090 const removeNode = mergeToPrev ? nextNode : prevNode; 12091 if (mergeToPrev) { 12092 newNode.appendData(removeNode.data); 12093 } else { 12094 newNode.insertData(0, removeNode.data); 12095 } 12096 remove$4(SugarElement.fromDom(removeNode)); 12097 if (normalizeWhitespace) { 12098 normalizeWhitespaceAfter(newNode, whitespaceOffset, schema); 12099 } 12100 return newNode; 12101 }; 12102 12103 const needsReposition = (pos, elm) => { 12104 const container = pos.container(); 12105 const offset = pos.offset(); 12106 return !CaretPosition.isTextPosition(pos) && container === elm.parentNode && offset > CaretPosition.before(elm).offset(); 12107 }; 12108 const reposition = (elm, pos) => needsReposition(pos, elm) ? CaretPosition(pos.container(), pos.offset() - 1) : pos; 12109 const beforeOrStartOf = node => isText$b(node) ? CaretPosition(node, 0) : CaretPosition.before(node); 12110 const afterOrEndOf = node => isText$b(node) ? CaretPosition(node, node.data.length) : CaretPosition.after(node); 12111 const getPreviousSiblingCaretPosition = elm => { 12112 if (isCaretCandidate$3(elm.previousSibling)) { 12113 return Optional.some(afterOrEndOf(elm.previousSibling)); 12114 } else { 12115 return elm.previousSibling ? lastPositionIn(elm.previousSibling) : Optional.none(); 12116 } 12117 }; 12118 const getNextSiblingCaretPosition = elm => { 12119 if (isCaretCandidate$3(elm.nextSibling)) { 12120 return Optional.some(beforeOrStartOf(elm.nextSibling)); 12121 } else { 12122 return elm.nextSibling ? firstPositionIn(elm.nextSibling) : Optional.none(); 12123 } 12124 }; 12125 const findCaretPositionBackwardsFromElm = (rootElement, elm) => { 12126 return Optional.from(elm.previousSibling ? elm.previousSibling : elm.parentNode).bind(node => prevPosition(rootElement, CaretPosition.before(node))).orThunk(() => nextPosition(rootElement, CaretPosition.after(elm))); 12127 }; 12128 const findCaretPositionForwardsFromElm = (rootElement, elm) => nextPosition(rootElement, CaretPosition.after(elm)).orThunk(() => prevPosition(rootElement, CaretPosition.before(elm))); 12129 const findCaretPositionBackwards = (rootElement, elm) => getPreviousSiblingCaretPosition(elm).orThunk(() => getNextSiblingCaretPosition(elm)).orThunk(() => findCaretPositionBackwardsFromElm(rootElement, elm)); 12130 const findCaretPositionForward = (rootElement, elm) => getNextSiblingCaretPosition(elm).orThunk(() => getPreviousSiblingCaretPosition(elm)).orThunk(() => findCaretPositionForwardsFromElm(rootElement, elm)); 12131 const findCaretPosition = (forward, rootElement, elm) => forward ? findCaretPositionForward(rootElement, elm) : findCaretPositionBackwards(rootElement, elm); 12132 const findCaretPosOutsideElmAfterDelete = (forward, rootElement, elm) => findCaretPosition(forward, rootElement, elm).map(curry(reposition, elm)); 12133 const setSelection$1 = (editor, forward, pos) => { 12134 pos.fold(() => { 12135 editor.focus(); 12136 }, pos => { 12137 editor.selection.setRng(pos.toRange(), forward); 12138 }); 12139 }; 12140 const eqRawNode = rawNode => elm => elm.dom === rawNode; 12141 const isBlock = (editor, elm) => elm && has$2(editor.schema.getBlockElements(), name(elm)); 12142 const paddEmptyBlock = (schema, elm, preserveEmptyCaret) => { 12143 if (isEmpty$2(schema, elm)) { 12144 const br = SugarElement.fromHtml('<br data-mce-bogus="1">'); 12145 if (preserveEmptyCaret) { 12146 each$e(children$1(elm), node => { 12147 if (!isEmptyCaretFormatElement(node)) { 12148 remove$4(node); 12149 } 12150 }); 12151 } else { 12152 empty(elm); 12153 } 12154 append$1(elm, br); 12155 return Optional.some(CaretPosition.before(br.dom)); 12156 } else { 12157 return Optional.none(); 12158 } 12159 }; 12160 const deleteNormalized = (elm, afterDeletePosOpt, schema, normalizeWhitespace) => { 12161 const prevTextOpt = prevSibling(elm).filter(isText$c); 12162 const nextTextOpt = nextSibling(elm).filter(isText$c); 12163 remove$4(elm); 12164 return lift3(prevTextOpt, nextTextOpt, afterDeletePosOpt, (prev, next, pos) => { 12165 const prevNode = prev.dom, nextNode = next.dom; 12166 const offset = prevNode.data.length; 12167 mergeTextNodes(prevNode, nextNode, schema, normalizeWhitespace); 12168 return pos.container() === nextNode ? CaretPosition(prevNode, offset) : pos; 12169 }).orThunk(() => { 12170 if (normalizeWhitespace) { 12171 prevTextOpt.each(elm => normalizeWhitespaceBefore(elm.dom, elm.dom.length, schema)); 12172 nextTextOpt.each(elm => normalizeWhitespaceAfter(elm.dom, 0, schema)); 12173 } 12174 return afterDeletePosOpt; 12175 }); 12176 }; 12177 const isInlineElement = (editor, element) => has$2(editor.schema.getTextInlineElements(), name(element)); 12178 const deleteElement$2 = (editor, forward, elm, moveCaret = true, preserveEmptyCaret = false) => { 12179 const afterDeletePos = findCaretPosOutsideElmAfterDelete(forward, editor.getBody(), elm.dom); 12180 const parentBlock = ancestor$4(elm, curry(isBlock, editor), eqRawNode(editor.getBody())); 12181 const normalizedAfterDeletePos = deleteNormalized(elm, afterDeletePos, editor.schema, isInlineElement(editor, elm)); 12182 if (editor.dom.isEmpty(editor.getBody())) { 12183 editor.setContent(''); 12184 editor.selection.setCursorLocation(); 12185 } else { 12186 parentBlock.bind(elm => paddEmptyBlock(editor.schema, elm, preserveEmptyCaret)).fold(() => { 12187 if (moveCaret) { 12188 setSelection$1(editor, forward, normalizedAfterDeletePos); 12189 } 12190 }, paddPos => { 12191 if (moveCaret) { 12192 setSelection$1(editor, forward, Optional.some(paddPos)); 12193 } 12194 }); 12195 } 12196 }; 12197 12198 const strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/; 12199 const hasStrongRtl = text => strongRtl.test(text); 12200 12201 const isInlineTarget = (editor, elm) => is$1(SugarElement.fromDom(elm), getInlineBoundarySelector(editor)) && !isTransparentBlock(editor.schema, elm) && editor.dom.isEditable(elm); 12202 const isRtl = element => { 12203 var _a; 12204 return DOMUtils.DOM.getStyle(element, 'direction', true) === 'rtl' || hasStrongRtl((_a = element.textContent) !== null && _a !== void 0 ? _a : ''); 12205 }; 12206 const findInlineParents = (isInlineTarget, rootNode, pos) => filter$5(DOMUtils.DOM.getParents(pos.container(), '*', rootNode), isInlineTarget); 12207 const findRootInline = (isInlineTarget, rootNode, pos) => { 12208 const parents = findInlineParents(isInlineTarget, rootNode, pos); 12209 return Optional.from(parents[parents.length - 1]); 12210 }; 12211 const hasSameParentBlock = (rootNode, node1, node2) => { 12212 const block1 = getParentBlock$3(node1, rootNode); 12213 const block2 = getParentBlock$3(node2, rootNode); 12214 return isNonNullable(block1) && block1 === block2; 12215 }; 12216 const isAtZwsp = pos => isBeforeInline(pos) || isAfterInline(pos); 12217 const normalizePosition = (forward, pos) => { 12218 const container = pos.container(), offset = pos.offset(); 12219 if (forward) { 12220 if (isCaretContainerInline(container)) { 12221 if (isText$b(container.nextSibling)) { 12222 return CaretPosition(container.nextSibling, 0); 12223 } else { 12224 return CaretPosition.after(container); 12225 } 12226 } else { 12227 return isBeforeInline(pos) ? CaretPosition(container, offset + 1) : pos; 12228 } 12229 } else { 12230 if (isCaretContainerInline(container)) { 12231 if (isText$b(container.previousSibling)) { 12232 return CaretPosition(container.previousSibling, container.previousSibling.data.length); 12233 } else { 12234 return CaretPosition.before(container); 12235 } 12236 } else { 12237 return isAfterInline(pos) ? CaretPosition(container, offset - 1) : pos; 12238 } 12239 } 12240 }; 12241 const normalizeForwards = curry(normalizePosition, true); 12242 const normalizeBackwards = curry(normalizePosition, false); 12243 12244 const execCommandIgnoreInputEvents = (editor, command) => { 12245 const inputBlocker = e => e.stopImmediatePropagation(); 12246 editor.on('beforeinput input', inputBlocker, true); 12247 editor.getDoc().execCommand(command); 12248 editor.off('beforeinput input', inputBlocker); 12249 }; 12250 const execEditorDeleteCommand = editor => { 12251 editor.execCommand('delete'); 12252 }; 12253 const execNativeDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'Delete'); 12254 const execNativeForwardDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'ForwardDelete'); 12255 const isBeforeRoot = rootNode => elm => is$2(parent(elm), rootNode, eq); 12256 const isTextBlockOrListItem = element => isTextBlock$2(element) || isListItem$1(element); 12257 const getParentBlock$2 = (rootNode, elm) => { 12258 if (contains(rootNode, elm)) { 12259 return closest$4(elm, isTextBlockOrListItem, isBeforeRoot(rootNode)); 12260 } else { 12261 return Optional.none(); 12262 } 12263 }; 12264 const paddEmptyBody = (editor, moveSelection = true) => { 12265 if (editor.dom.isEmpty(editor.getBody())) { 12266 editor.setContent('', { no_selection: !moveSelection }); 12267 } 12268 }; 12269 const willDeleteLastPositionInElement = (forward, fromPos, elm) => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => { 12270 const normalizedFirstPos = normalizePosition(true, firstPos); 12271 const normalizedLastPos = normalizePosition(false, lastPos); 12272 const normalizedFromPos = normalizePosition(false, fromPos); 12273 if (forward) { 12274 return nextPosition(elm, normalizedFromPos).exists(nextPos => nextPos.isEqual(normalizedLastPos) && fromPos.isEqual(normalizedFirstPos)); 12275 } else { 12276 return prevPosition(elm, normalizedFromPos).exists(prevPos => prevPos.isEqual(normalizedFirstPos) && fromPos.isEqual(normalizedLastPos)); 12277 } 12278 }).getOr(true); 12279 const freefallRtl = root => { 12280 const child = isComment$1(root) ? prevSibling(root) : lastChild(root); 12281 return child.bind(freefallRtl).orThunk(() => Optional.some(root)); 12282 }; 12283 const deleteRangeContents = (editor, rng, root, moveSelection = true) => { 12284 var _a; 12285 rng.deleteContents(); 12286 const lastNode = freefallRtl(root).getOr(root); 12287 const lastBlock = SugarElement.fromDom((_a = editor.dom.getParent(lastNode.dom, editor.dom.isBlock)) !== null && _a !== void 0 ? _a : root.dom); 12288 if (lastBlock.dom === editor.getBody()) { 12289 paddEmptyBody(editor, moveSelection); 12290 } else if (isEmpty$2(editor.schema, lastBlock, { checkRootAsContent: false })) { 12291 fillWithPaddingBr(lastBlock); 12292 if (moveSelection) { 12293 editor.selection.setCursorLocation(lastBlock.dom, 0); 12294 } 12295 } 12296 if (!eq(root, lastBlock)) { 12297 const additionalCleanupNodes = is$2(parent(lastBlock), root) ? [] : siblings(lastBlock); 12298 each$e(additionalCleanupNodes.concat(children$1(root)), node => { 12299 if (!eq(node, lastBlock) && !contains(node, lastBlock) && isEmpty$2(editor.schema, node)) { 12300 remove$4(node); 12301 } 12302 }); 12303 } 12304 }; 12305 12306 const isRootFromElement = root => cur => eq(root, cur); 12307 const getTableCells = table => descendants(table, 'td,th'); 12308 const getTable$1 = (node, isRoot) => getClosestTable(SugarElement.fromDom(node), isRoot); 12309 const selectionInTableWithNestedTable = details => { 12310 return lift2(details.startTable, details.endTable, (startTable, endTable) => { 12311 const isStartTableParentOfEndTable = descendant(startTable, t => eq(t, endTable)); 12312 const isEndTableParentOfStartTable = descendant(endTable, t => eq(t, startTable)); 12313 return !isStartTableParentOfEndTable && !isEndTableParentOfStartTable ? details : { 12314 ...details, 12315 startTable: isStartTableParentOfEndTable ? Optional.none() : details.startTable, 12316 endTable: isEndTableParentOfStartTable ? Optional.none() : details.endTable, 12317 isSameTable: false, 12318 isMultiTable: false 12319 }; 12320 }).getOr(details); 12321 }; 12322 const adjustQuirksInDetails = details => { 12323 return selectionInTableWithNestedTable(details); 12324 }; 12325 const getTableDetailsFromRange = (rng, isRoot) => { 12326 const startTable = getTable$1(rng.startContainer, isRoot); 12327 const endTable = getTable$1(rng.endContainer, isRoot); 12328 const isStartInTable = startTable.isSome(); 12329 const isEndInTable = endTable.isSome(); 12330 const isSameTable = lift2(startTable, endTable, eq).getOr(false); 12331 const isMultiTable = !isSameTable && isStartInTable && isEndInTable; 12332 return adjustQuirksInDetails({ 12333 startTable, 12334 endTable, 12335 isStartInTable, 12336 isEndInTable, 12337 isSameTable, 12338 isMultiTable 12339 }); 12340 }; 12341 12342 const tableCellRng = (start, end) => ({ 12343 start, 12344 end 12345 }); 12346 const tableSelection = (rng, table, cells) => ({ 12347 rng, 12348 table, 12349 cells 12350 }); 12351 const deleteAction = Adt.generate([ 12352 { 12353 singleCellTable: [ 12354 'rng', 12355 'cell' 12356 ] 12357 }, 12358 { fullTable: ['table'] }, 12359 { 12360 partialTable: [ 12361 'cells', 12362 'outsideDetails' 12363 ] 12364 }, 12365 { 12366 multiTable: [ 12367 'startTableCells', 12368 'endTableCells', 12369 'betweenRng' 12370 ] 12371 } 12372 ]); 12373 const getClosestCell$1 = (container, isRoot) => closest$3(SugarElement.fromDom(container), 'td,th', isRoot); 12374 const isExpandedCellRng = cellRng => !eq(cellRng.start, cellRng.end); 12375 const getTableFromCellRng = (cellRng, isRoot) => getClosestTable(cellRng.start, isRoot).bind(startParentTable => getClosestTable(cellRng.end, isRoot).bind(endParentTable => someIf(eq(startParentTable, endParentTable), startParentTable))); 12376 const isSingleCellTable = (cellRng, isRoot) => !isExpandedCellRng(cellRng) && getTableFromCellRng(cellRng, isRoot).exists(table => { 12377 const rows = table.dom.rows; 12378 return rows.length === 1 && rows[0].cells.length === 1; 12379 }); 12380 const getCellRng = (rng, isRoot) => { 12381 const startCell = getClosestCell$1(rng.startContainer, isRoot); 12382 const endCell = getClosestCell$1(rng.endContainer, isRoot); 12383 return lift2(startCell, endCell, tableCellRng); 12384 }; 12385 const getCellRangeFromStartTable = isRoot => startCell => getClosestTable(startCell, isRoot).bind(table => last$2(getTableCells(table)).map(endCell => tableCellRng(startCell, endCell))); 12386 const getCellRangeFromEndTable = isRoot => endCell => getClosestTable(endCell, isRoot).bind(table => head(getTableCells(table)).map(startCell => tableCellRng(startCell, endCell))); 12387 const getTableSelectionFromCellRng = isRoot => cellRng => getTableFromCellRng(cellRng, isRoot).map(table => tableSelection(cellRng, table, getTableCells(table))); 12388 const getTableSelections = (cellRng, selectionDetails, rng, isRoot) => { 12389 if (rng.collapsed || !cellRng.forall(isExpandedCellRng)) { 12390 return Optional.none(); 12391 } else if (selectionDetails.isSameTable) { 12392 const sameTableSelection = cellRng.bind(getTableSelectionFromCellRng(isRoot)); 12393 return Optional.some({ 12394 start: sameTableSelection, 12395 end: sameTableSelection 12396 }); 12397 } else { 12398 const startCell = getClosestCell$1(rng.startContainer, isRoot); 12399 const endCell = getClosestCell$1(rng.endContainer, isRoot); 12400 const startTableSelection = startCell.bind(getCellRangeFromStartTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot)); 12401 const endTableSelection = endCell.bind(getCellRangeFromEndTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot)); 12402 return Optional.some({ 12403 start: startTableSelection, 12404 end: endTableSelection 12405 }); 12406 } 12407 }; 12408 const getCellIndex = (cells, cell) => findIndex$2(cells, x => eq(x, cell)); 12409 const getSelectedCells = tableSelection => lift2(getCellIndex(tableSelection.cells, tableSelection.rng.start), getCellIndex(tableSelection.cells, tableSelection.rng.end), (startIndex, endIndex) => tableSelection.cells.slice(startIndex, endIndex + 1)); 12410 const isSingleCellTableContentSelected = (optCellRng, rng, isRoot) => optCellRng.exists(cellRng => isSingleCellTable(cellRng, isRoot) && hasAllContentsSelected(cellRng.start, rng)); 12411 const unselectCells = (rng, selectionDetails) => { 12412 const {startTable, endTable} = selectionDetails; 12413 const otherContentRng = rng.cloneRange(); 12414 startTable.each(table => otherContentRng.setStartAfter(table.dom)); 12415 endTable.each(table => otherContentRng.setEndBefore(table.dom)); 12416 return otherContentRng; 12417 }; 12418 const handleSingleTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => start.or(end)).bind(tableSelection => { 12419 const {isSameTable} = selectionDetails; 12420 const selectedCells = getSelectedCells(tableSelection).getOr([]); 12421 if (isSameTable && tableSelection.cells.length === selectedCells.length) { 12422 return Optional.some(deleteAction.fullTable(tableSelection.table)); 12423 } else if (selectedCells.length > 0) { 12424 if (isSameTable) { 12425 return Optional.some(deleteAction.partialTable(selectedCells, Optional.none())); 12426 } else { 12427 const otherContentRng = unselectCells(rng, selectionDetails); 12428 return Optional.some(deleteAction.partialTable(selectedCells, Optional.some({ 12429 ...selectionDetails, 12430 rng: otherContentRng 12431 }))); 12432 } 12433 } else { 12434 return Optional.none(); 12435 } 12436 }); 12437 const handleMultiTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => { 12438 const startTableSelectedCells = start.bind(getSelectedCells).getOr([]); 12439 const endTableSelectedCells = end.bind(getSelectedCells).getOr([]); 12440 if (startTableSelectedCells.length > 0 && endTableSelectedCells.length > 0) { 12441 const otherContentRng = unselectCells(rng, selectionDetails); 12442 return Optional.some(deleteAction.multiTable(startTableSelectedCells, endTableSelectedCells, otherContentRng)); 12443 } else { 12444 return Optional.none(); 12445 } 12446 }); 12447 const getActionFromRange = (root, rng) => { 12448 const isRoot = isRootFromElement(root); 12449 const optCellRng = getCellRng(rng, isRoot); 12450 const selectionDetails = getTableDetailsFromRange(rng, isRoot); 12451 if (isSingleCellTableContentSelected(optCellRng, rng, isRoot)) { 12452 return optCellRng.map(cellRng => deleteAction.singleCellTable(rng, cellRng.start)); 12453 } else if (selectionDetails.isMultiTable) { 12454 return handleMultiTable(optCellRng, selectionDetails, rng, isRoot); 12455 } else { 12456 return handleSingleTable(optCellRng, selectionDetails, rng, isRoot); 12457 } 12458 }; 12459 12460 const cleanCells = cells => each$e(cells, cell => { 12461 remove$9(cell, 'contenteditable'); 12462 fillWithPaddingBr(cell); 12463 }); 12464 const getOutsideBlock = (editor, container) => Optional.from(editor.dom.getParent(container, editor.dom.isBlock)).map(SugarElement.fromDom); 12465 const handleEmptyBlock = (editor, startInTable, emptyBlock) => { 12466 emptyBlock.each(block => { 12467 if (startInTable) { 12468 remove$4(block); 12469 } else { 12470 fillWithPaddingBr(block); 12471 editor.selection.setCursorLocation(block.dom, 0); 12472 } 12473 }); 12474 }; 12475 const deleteContentInsideCell = (editor, cell, rng, isFirstCellInSelection) => { 12476 const insideTableRng = rng.cloneRange(); 12477 if (isFirstCellInSelection) { 12478 insideTableRng.setStart(rng.startContainer, rng.startOffset); 12479 insideTableRng.setEndAfter(cell.dom.lastChild); 12480 } else { 12481 insideTableRng.setStartBefore(cell.dom.firstChild); 12482 insideTableRng.setEnd(rng.endContainer, rng.endOffset); 12483 } 12484 deleteCellContents(editor, insideTableRng, cell, false).each(action => action()); 12485 }; 12486 const collapseAndRestoreCellSelection = editor => { 12487 const selectedCells = getCellsFromEditor(editor); 12488 const selectedNode = SugarElement.fromDom(editor.selection.getNode()); 12489 if (isTableCell$3(selectedNode.dom) && isEmpty$2(editor.schema, selectedNode)) { 12490 editor.selection.setCursorLocation(selectedNode.dom, 0); 12491 } else { 12492 editor.selection.collapse(true); 12493 } 12494 if (selectedCells.length > 1 && exists(selectedCells, cell => eq(cell, selectedNode))) { 12495 set$
vendor: 5,907 bytes, lines 12495-12567
124954(selectedNode, 'data-mce-selected', '1'); 12496 } 12497 }; 12498 const emptySingleTableCells = (editor, cells, outsideDetails) => Optional.some(() => { 12499 const editorRng = editor.selection.getRng(); 12500 const cellsToClean = outsideDetails.bind(({rng, isStartInTable}) => { 12501 const outsideBlock = getOutsideBlock(editor, isStartInTable ? rng.endContainer : rng.startContainer); 12502 rng.deleteContents(); 12503 handleEmptyBlock(editor, isStartInTable, outsideBlock.filter(curry(isEmpty$2, editor.schema))); 12504 const endPointCell = isStartInTable ? cells[0] : cells[cells.length - 1]; 12505 deleteContentInsideCell(editor, endPointCell, editorRng, isStartInTable); 12506 if (!isEmpty$2(editor.schema, endPointCell)) { 12507 return Optional.some(isStartInTable ? cells.slice(1) : cells.slice(0, -1)); 12508 } else { 12509 return Optional.none(); 12510 } 12511 }).getOr(cells); 12512 cleanCells(cellsToClean); 12513 collapseAndRestoreCellSelection(editor); 12514 }); 12515 const emptyMultiTableCells = (editor, startTableCells, endTableCells, betweenRng) => Optional.some(() => { 12516 const rng = editor.selection.getRng(); 12517 const startCell = startTableCells[0]; 12518 const endCell = endTableCells[endTableCells.length - 1]; 12519 deleteContentInsideCell(editor, startCell, rng, true); 12520 deleteContentInsideCell(editor, endCell, rng, false); 12521 const startTableCellsToClean = isEmpty$2(editor.schema, startCell) ? startTableCells : startTableCells.slice(1); 12522 const endTableCellsToClean = isEmpty$2(editor.schema, endCell) ? endTableCells : endTableCells.slice(0, -1); 12523 cleanCells(startTableCellsToClean.concat(endTableCellsToClean)); 12524 betweenRng.deleteContents(); 12525 collapseAndRestoreCellSelection(editor); 12526 }); 12527 const deleteCellContents = (editor, rng, cell, moveSelection = true) => Optional.some(() => { 12528 deleteRangeContents(editor, rng, cell, moveSelection); 12529 }); 12530 const deleteTableElement = (editor, table) => Optional.some(() => deleteElement$2(editor, false, table)); 12531 const deleteCellRange = (editor, rootElm, rng) => getActionFromRange(rootElm, rng).bind(action => action.fold(curry(deleteCellContents, editor), curry(deleteTableElement, editor), curry(emptySingleTableCells, editor), curry(emptyMultiTableCells, editor))); 12532 const deleteCaptionRange = (editor, caption) => emptyElement(editor, caption); 12533 const deleteTableRange = (editor, rootElm, rng, startElm) => getParentCaption(rootElm, startElm).fold(() => deleteCellRange(editor, rootElm, rng), caption => deleteCaptionRange(editor, caption)); 12534 const deleteRange$3 = (editor, startElm, selectedCells) => { 12535 const rootNode = SugarElement.fromDom(editor.getBody()); 12536 const rng = editor.selection.getRng(); 12537 return selectedCells.length !== 0 ? emptySingleTableCells(editor, selectedCells, Optional.none()) : deleteTableRange(editor, rootNode, rng, startElm); 12538 }; 12539 const getParentCell = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTableCell$2); 12540 const getParentCaption = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTag('caption')); 12541 const deleteBetweenCells = (editor, rootElm, forward, fromCell, from) => navigate(forward, editor.getBody(), from).bind(to => getParentCell(rootElm, SugarElement.fromDom(to.getNode())).bind(toCell => eq(toCell, fromCell) ? Optional.none() : Optional.some(noop))); 12542 const emptyElement = (editor, elm) => Optional.some(() => { 12543 fillWithPaddingBr(elm); 12544 editor.selection.setCursorLocation(elm.dom, 0); 12545 }); 12546 const isDeleteOfLastCharPos = (fromCaption, forward, from, to) => firstPositionIn(fromCaption.dom).bind(first => lastPositionIn(fromCaption.dom).map(last => forward ? from.isEqual(first) && to.isEqual(last) : from.isEqual(last) && to.isEqual(first))).getOr(true); 12547 const emptyCaretCaption = (editor, elm) => emptyElement(editor, elm); 12548 const validateCaretCaption = (rootElm, fromCaption, to) => getParentCaption(rootElm, SugarElement.fromDom(to.getNode())).fold(() => Optional.some(noop), toCaption => someIf(!eq(toCaption, fromCaption), noop)); 12549 const deleteCaretInsideCaption = (editor, rootElm, forward, fromCaption, from) => navigate(forward, editor.getBody(), from).fold(() => Optional.some(noop), to => isDeleteOfLastCharPos(fromCaption, forward, from, to) ? emptyCaretCaption(editor, fromCaption) : validateCaretCaption(rootElm, fromCaption, to)); 12550 const deleteCaretCells = (editor, forward, rootElm, startElm) => { 12551 const from = CaretPosition.fromRangeStart(editor.selection.getRng()); 12552 return getParentCell(rootElm, startElm).bind(fromCell => isEmpty$2(editor.schema, fromCell, { checkRootAsContent: false }) ? emptyElement(editor, fromCell) : deleteBetweenCells(editor, rootElm, forward, fromCell, from)); 12553 }; 12554 const deleteCaretCaption = (editor, forward, rootElm, fromCaption) => { 12555 const from = CaretPosition.fromRangeStart(editor.selection.getRng()); 12556 return isEmpty$2(editor.schema, fromCaption) ? emptyElement(editor, fromCaption) : deleteCaretInsideCaption(editor, rootElm, forward, fromCaption, from); 12557 }; 12558 const isNearTable = (forward, pos) => forward ? isBeforeTable(pos) : isAfterTable(pos); 12559 const isBeforeOrAfterTable = (editor, forward) => { 12560 const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng()); 12561 return isNearTable(forward, fromPos) || fromPosition(forward, editor.getBody(), fromPos).exists(pos => isNearTable(forward, pos)); 12562 }; 12563 const deleteCaret$3 = (editor, forward, startElm) => { 12564 const rootElm = SugarElement.fromDom(editor.getBody()); 12565 return getParentCaption(rootElm, startElm).fold(() => deleteCaretCells(editor, forward, rootElm, startElm).orThunk(() => someIf(isBeforeOrAfterTable(editor, forward), noop)), fromCaption => deleteCaretCaption(editor, forward, rootElm, fromCaption)); 12566 }; 12567 const backspaceDelete$b
vendor: 20,531 bytes, lines 12567-13098
12567 = (editor, forward) => { 12568 const startElm = SugarElement.fromDom(editor.selection.getStart(true)); 12569 const cells = getCellsFromEditor(editor); 12570 return editor.selection.isCollapsed() && cells.length === 0 ? deleteCaret$3(editor, forward, startElm) : deleteRange$3(editor, startElm, cells); 12571 }; 12572 12573 const getContentEditableRoot$1 = (root, node) => { 12574 let tempNode = node; 12575 while (tempNode && tempNode !== root) { 12576 if (isContentEditableTrue$3(tempNode) || isContentEditableFalse$b(tempNode)) { 12577 return tempNode; 12578 } 12579 tempNode = tempNode.parentNode; 12580 } 12581 return null; 12582 }; 12583 12584 const internalAttributesPrefixes = [ 12585 'data-ephox-', 12586 'data-mce-', 12587 'data-alloy-', 12588 'data-snooker-', 12589 '_' 12590 ]; 12591 const each$9 = Tools.each; 12592 const ElementUtils = editor => { 12593 const dom = editor.dom; 12594 const internalAttributes = new Set(editor.serializer.getTempAttrs()); 12595 const compare = (node1, node2) => { 12596 if (node1.nodeName !== node2.nodeName || node1.nodeType !== node2.nodeType) { 12597 return false; 12598 } 12599 const getAttribs = node => { 12600 const attribs = {}; 12601 each$9(dom.getAttribs(node), attr => { 12602 const name = attr.nodeName.toLowerCase(); 12603 if (name !== 'style' && !isAttributeInternal(name)) { 12604 attribs[name] = dom.getAttrib(node, name); 12605 } 12606 }); 12607 return attribs; 12608 }; 12609 const compareObjects = (obj1, obj2) => { 12610 for (const name in obj1) { 12611 if (has$2(obj1, name)) { 12612 const value = obj2[name]; 12613 if (isUndefined(value)) { 12614 return false; 12615 } 12616 if (obj1[name] !== value) { 12617 return false; 12618 } 12619 delete obj2[name]; 12620 } 12621 } 12622 for (const name in obj2) { 12623 if (has$2(obj2, name)) { 12624 return false; 12625 } 12626 } 12627 return true; 12628 }; 12629 if (isElement$6(node1) && isElement$6(node2)) { 12630 if (!compareObjects(getAttribs(node1), getAttribs(node2))) { 12631 return false; 12632 } 12633 if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style')))) { 12634 return false; 12635 } 12636 } 12637 return !isBookmarkNode$1(node1) && !isBookmarkNode$1(node2); 12638 }; 12639 const isAttributeInternal = attributeName => exists(internalAttributesPrefixes, value => startsWith(attributeName, value)) || internalAttributes.has(attributeName); 12640 return { 12641 compare, 12642 isAttributeInternal 12643 }; 12644 }; 12645 12646 const isHeading = node => [ 12647 'h1', 12648 'h2', 12649 'h3', 12650 'h4', 12651 'h5', 12652 'h6' 12653 ].includes(node.name); 12654 const isSummary = node => node.name === 'summary'; 12655 12656 const traverse = (root, fn) => { 12657 let node = root; 12658 while (node = node.walk()) { 12659 fn(node); 12660 } 12661 }; 12662 const matchNode$1 = (nodeFilters, attributeFilters, node, matches) => { 12663 const name = node.name; 12664 for (let ni = 0, nl = nodeFilters.length; ni < nl; ni++) { 12665 const filter = nodeFilters[ni]; 12666 if (filter.name === name) { 12667 const match = matches.nodes[name]; 12668 if (match) { 12669 match.nodes.push(node); 12670 } else { 12671 matches.nodes[name] = { 12672 filter, 12673 nodes: [node] 12674 }; 12675 } 12676 } 12677 } 12678 if (node.attributes) { 12679 for (let ai = 0, al = attributeFilters.length; ai < al; ai++) { 12680 const filter = attributeFilters[ai]; 12681 const attrName = filter.name; 12682 if (attrName in node.attributes.map) { 12683 const match = matches.attributes[attrName]; 12684 if (match) { 12685 match.nodes.push(node); 12686 } else { 12687 matches.attributes[attrName] = { 12688 filter, 12689 nodes: [node] 12690 }; 12691 } 12692 } 12693 } 12694 } 12695 }; 12696 const findMatchingNodes = (nodeFilters, attributeFilters, node) => { 12697 const matches = { 12698 nodes: {}, 12699 attributes: {} 12700 }; 12701 if (node.firstChild) { 12702 traverse(node, childNode => { 12703 matchNode$1(nodeFilters, attributeFilters, childNode, matches); 12704 }); 12705 } 12706 return matches; 12707 }; 12708 const runFilters = (matches, args) => { 12709 const run = (matchRecord, filteringAttributes) => { 12710 each$d(matchRecord, match => { 12711 const nodes = from(match.nodes); 12712 each$e(match.filter.callbacks, callback => { 12713 for (let i = nodes.length - 1; i >= 0; i--) { 12714 const node = nodes[i]; 12715 const valueMatches = filteringAttributes ? node.attr(match.filter.name) !== undefined : node.name === match.filter.name; 12716 if (!valueMatches || isNullable(node.parent)) { 12717 nodes.splice(i, 1); 12718 } 12719 } 12720 if (nodes.length > 0) { 12721 callback(nodes, match.filter.name, args); 12722 } 12723 }); 12724 }); 12725 }; 12726 run(matches.nodes, false); 12727 run(matches.attributes, true); 12728 }; 12729 const filter$2 = (nodeFilters, attributeFilters, node, args = {}) => { 12730 const matches = findMatchingNodes(nodeFilters, attributeFilters, node); 12731 runFilters(matches, args); 12732 }; 12733 12734 const paddEmptyNode = (settings, args, isBlock, node) => { 12735 const brPreferred = settings.pad_empty_with_br || args.insert; 12736 if (brPreferred && isBlock(node)) { 12737 const astNode = new AstNode('br', 1); 12738 if (args.insert) { 12739 astNode.attr('data-mce-bogus', '1'); 12740 } 12741 node.empty().append(astNode); 12742 } else { 12743 node.empty().append(new AstNode('#text', 3)).value = nbsp; 12744 } 12745 }; 12746 const isPaddedWithNbsp = node => { 12747 var _a; 12748 return hasOnlyChild(node, '#text') && ((_a = node === null || node === void 0 ? void 0 : node.firstChild) === null || _a === void 0 ? void 0 : _a.value) === nbsp; 12749 }; 12750 const hasOnlyChild = (node, name) => { 12751 const firstChild = node === null || node === void 0 ? void 0 : node.firstChild; 12752 return isNonNullable(firstChild) && firstChild === node.lastChild && firstChild.name === name; 12753 }; 12754 const isPadded = (schema, node) => { 12755 const rule = schema.getElementRule(node.name); 12756 return (rule === null || rule === void 0 ? void 0 : rule.paddEmpty) === true; 12757 }; 12758 const isEmpty = (schema, nonEmptyElements, whitespaceElements, node) => node.isEmpty(nonEmptyElements, whitespaceElements, node => isPadded(schema, node)); 12759 const isLineBreakNode = (node, isBlock) => isNonNullable(node) && (isBlock(node) || node.name === 'br'); 12760 const findClosestEditingHost = scope => { 12761 let editableNode; 12762 for (let node = scope; node; node = node.parent) { 12763 const contentEditable = node.attr('contenteditable'); 12764 if (contentEditable === 'false') { 12765 break; 12766 } else if (contentEditable === 'true') { 12767 editableNode = node; 12768 } 12769 } 12770 return Optional.from(editableNode); 12771 }; 12772 12773 const removeOrUnwrapInvalidNode = (node, schema, originalNodeParent = node.parent) => { 12774 if (schema.getSpecialElements()[node.name]) { 12775 node.empty().remove(); 12776 } else { 12777 const children = node.children(); 12778 for (const childNode of children) { 12779 if (originalNodeParent && !schema.isValidChild(originalNodeParent.name, childNode.name)) { 12780 removeOrUnwrapInvalidNode(childNode, schema, originalNodeParent); 12781 } 12782 } 12783 node.unwrap(); 12784 } 12785 }; 12786 const cleanInvalidNodes = (nodes, schema, rootNode, onCreate = noop) => { 12787 const textBlockElements = schema.getTextBlockElements(); 12788 const nonEmptyElements = schema.getNonEmptyElements(); 12789 const whitespaceElements = schema.getWhitespaceElements(); 12790 const nonSplittableElements = Tools.makeMap('tr,td,th,tbody,thead,tfoot,table,summary'); 12791 const fixed = new Set(); 12792 const isSplittableElement = node => node !== rootNode && !nonSplittableElements[node.name]; 12793 for (let ni = 0; ni < nodes.length; ni++) { 12794 const node = nodes[ni]; 12795 let parent; 12796 let newParent; 12797 let tempNode; 12798 if (!node.parent || fixed.has(node)) { 12799 continue; 12800 } 12801 if (textBlockElements[node.name] && node.parent.name === 'li') { 12802 let sibling = node.next; 12803 while (sibling) { 12804 if (textBlockElements[sibling.name]) { 12805 sibling.name = 'li'; 12806 fixed.add(sibling); 12807 node.parent.insert(sibling, node.parent); 12808 } else { 12809 break; 12810 } 12811 sibling = sibling.next; 12812 } 12813 node.unwrap(); 12814 continue; 12815 } 12816 const parents = [node]; 12817 for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && isSplittableElement(parent); parent = parent.parent) { 12818 parents.push(parent); 12819 } 12820 if (parent && parents.length > 1) { 12821 if (!isInvalid(schema, node, parent)) { 12822 parents.reverse(); 12823 newParent = parents[0].clone(); 12824 onCreate(newParent); 12825 let currentNode = newParent; 12826 for (let i = 0; i < parents.length - 1; i++) { 12827 if (schema.isValidChild(currentNode.name, parents[i].name) && i > 0) { 12828 tempNode = parents[i].clone(); 12829 onCreate(tempNode); 12830 currentNode.append(tempNode); 12831 } else { 12832 tempNode = currentNode; 12833 } 12834 for (let childNode = parents[i].firstChild; childNode && childNode !== parents[i + 1];) { 12835 const nextNode = childNode.next; 12836 tempNode.append(childNode); 12837 childNode = nextNode; 12838 } 12839 currentNode = tempNode; 12840 } 12841 if (!isEmpty(schema, nonEmptyElements, whitespaceElements, newParent)) { 12842 parent.insert(newParent, parents[0], true); 12843 parent.insert(node, newParent); 12844 } else { 12845 parent.insert(node, parents[0], true); 12846 } 12847 parent = parents[0]; 12848 if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent) || hasOnlyChild(parent, 'br')) { 12849 parent.empty().remove(); 12850 } 12851 } else { 12852 removeOrUnwrapInvalidNode(node, schema); 12853 } 12854 } else if (node.parent) { 12855 if (node.name === 'li') { 12856 let sibling = node.prev; 12857 if (sibling && (sibling.name === 'ul' || sibling.name === 'ol')) { 12858 sibling.append(node); 12859 continue; 12860 } 12861 sibling = node.next; 12862 if (sibling && (sibling.name === 'ul' || sibling.name === 'ol') && sibling.firstChild) { 12863 sibling.insert(node, sibling.firstChild, true); 12864 continue; 12865 } 12866 const wrapper = new AstNode('ul', 1); 12867 onCreate(wrapper); 12868 node.wrap(wrapper); 12869 continue; 12870 } 12871 if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) { 12872 const wrapper = new AstNode('div', 1); 12873 onCreate(wrapper); 12874 node.wrap(wrapper); 12875 } else { 12876 removeOrUnwrapInvalidNode(node, schema); 12877 } 12878 } 12879 } 12880 }; 12881 const hasClosest = (node, parentName) => { 12882 let tempNode = node; 12883 while (tempNode) { 12884 if (tempNode.name === parentName) { 12885 return true; 12886 } 12887 tempNode = tempNode.parent; 12888 } 12889 return false; 12890 }; 12891 const isInvalid = (schema, node, parent = node.parent) => { 12892 if (!parent) { 12893 return false; 12894 } 12895 if (schema.children[node.name] && !schema.isValidChild(parent.name, node.name)) { 12896 return true; 12897 } 12898 if (node.name === 'a' && hasClosest(parent, 'a')) { 12899 return true; 12900 } 12901 if (isSummary(parent) && isHeading(node)) { 12902 return !((parent === null || parent === void 0 ? void 0 : parent.firstChild) === node && (parent === null || parent === void 0 ? void 0 : parent.lastChild) === node); 12903 } 12904 return false; 12905 }; 12906 12907 const createRange = (sc, so, ec, eo) => { 12908 const rng = document.createRange(); 12909 rng.setStart(sc, so); 12910 rng.setEnd(ec, eo); 12911 return rng; 12912 }; 12913 const normalizeBlockSelectionRange = rng => { 12914 const startPos = CaretPosition.fromRangeStart(rng); 12915 const endPos = CaretPosition.fromRangeEnd(rng); 12916 const rootNode = rng.commonAncestorContainer; 12917 return fromPosition(false, rootNode, endPos).map(newEndPos => { 12918 if (!isInSameBlock(startPos, endPos, rootNode) && isInSameBlock(startPos, newEndPos, rootNode)) { 12919 return createRange(startPos.container(), startPos.offset(), newEndPos.container(), newEndPos.offset()); 12920 } else { 12921 return rng; 12922 } 12923 }).getOr(rng); 12924 }; 12925 const normalize = rng => rng.collapsed ? rng : normalizeBlockSelectionRange(rng); 12926 12927 const hasOnlyOneChild$1 = node => { 12928 return isNonNullable(node.firstChild) && node.firstChild === node.lastChild; 12929 }; 12930 const isPaddingNode = node => { 12931 return node.name === 'br' || node.value === nbsp; 12932 }; 12933 const isPaddedEmptyBlock = (schema, node) => { 12934 const blockElements = schema.getBlockElements(); 12935 return blockElements[node.name] && hasOnlyOneChild$1(node) && isPaddingNode(node.firstChild); 12936 }; 12937 const isEmptyFragmentElement = (schema, node) => { 12938 const nonEmptyElements = schema.getNonEmptyElements(); 12939 return isNonNullable(node) && (node.isEmpty(nonEmptyElements) || isPaddedEmptyBlock(schema, node)); 12940 }; 12941 const isListFragment = (schema, fragment) => { 12942 let firstChild = fragment.firstChild; 12943 let lastChild = fragment.lastChild; 12944 if (firstChild && firstChild.name === 'meta') { 12945 firstChild = firstChild.next; 12946 } 12947 if (lastChild && lastChild.attr('id') === 'mce_marker') { 12948 lastChild = lastChild.prev; 12949 } 12950 if (isEmptyFragmentElement(schema, lastChild)) { 12951 lastChild = lastChild === null || lastChild === void 0 ? void 0 : lastChild.prev; 12952 } 12953 if (!firstChild || firstChild !== lastChild) { 12954 return false; 12955 } 12956 return firstChild.name === 'ul' || firstChild.name === 'ol'; 12957 }; 12958 const cleanupDomFragment = domFragment => { 12959 var _a, _b; 12960 const firstChild = domFragment.firstChild; 12961 const lastChild = domFragment.lastChild; 12962 if (firstChild && firstChild.nodeName === 'META') { 12963 (_a = firstChild.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(firstChild); 12964 } 12965 if (lastChild && lastChild.id === 'mce_marker') { 12966 (_b = lastChild.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(lastChild); 12967 } 12968 return domFragment; 12969 }; 12970 const toDomFragment = (dom, serializer, fragment) => { 12971 const html = serializer.serialize(fragment); 12972 const domFragment = dom.createFragment(html); 12973 return cleanupDomFragment(domFragment); 12974 }; 12975 const listItems = elm => { 12976 var _a; 12977 return filter$5((_a = elm === null || elm === void 0 ? void 0 : elm.childNodes) !== null && _a !== void 0 ? _a : [], child => { 12978 return child.nodeName === 'LI'; 12979 }); 12980 }; 12981 const isPadding = node => { 12982 return node.data === nbsp || isBr$6(node); 12983 }; 12984 const isListItemPadded = node => { 12985 return isNonNullable(node === null || node === void 0 ? void 0 : node.firstChild) && node.firstChild === node.lastChild && isPadding(node.firstChild); 12986 }; 12987 const isEmptyOrPadded = elm => { 12988 return !elm.firstChild || isListItemPadded(elm); 12989 }; 12990 const trimListItems = elms => { 12991 return elms.length > 0 && isEmptyOrPadded(elms[elms.length - 1]) ? elms.slice(0, -1) : elms; 12992 }; 12993 const getParentLi = (dom, node) => { 12994 const parentBlock = dom.getParent(node, dom.isBlock); 12995 return parentBlock && parentBlock.nodeName === 'LI' ? parentBlock : null; 12996 }; 12997 const isParentBlockLi = (dom, node) => { 12998 return !!getParentLi(dom, node); 12999 }; 13000 const getSplit = (parentNode, rng) => { 13001 const beforeRng = rng.cloneRange(); 13002 const afterRng = rng.cloneRange(); 13003 beforeRng.setStartBefore(parentNode); 13004 afterRng.setEndAfter(parentNode); 13005 return [ 13006 beforeRng.cloneContents(), 13007 afterRng.cloneContents() 13008 ]; 13009 }; 13010 const findFirstIn = (node, rootNode) => { 13011 const caretPos = CaretPosition.before(node); 13012 const caretWalker = CaretWalker(rootNode); 13013 const newCaretPos = caretWalker.next(caretPos); 13014 return newCaretPos ? newCaretPos.toRange() : null; 13015 }; 13016 const findLastOf = (node, rootNode) => { 13017 const caretPos = CaretPosition.after(node); 13018 const caretWalker = CaretWalker(rootNode); 13019 const newCaretPos = caretWalker.prev(caretPos); 13020 return newCaretPos ? newCaretPos.toRange() : null; 13021 }; 13022 const insertMiddle = (target, elms, rootNode, rng) => { 13023 const parts = getSplit(target, rng); 13024 const parentElm = target.parentNode; 13025 if (parentElm) { 13026 parentElm.insertBefore(parts[0], target); 13027 Tools.each(elms, li => { 13028 parentElm.insertBefore(li, target); 13029 }); 13030 parentElm.insertBefore(parts[1], target); 13031 parentElm.removeChild(target); 13032 } 13033 return findLastOf(elms[elms.length - 1], rootNode); 13034 }; 13035 const insertBefore$2 = (target, elms, rootNode) => { 13036 const parentElm = target.parentNode; 13037 if (parentElm) { 13038 Tools.each(elms, elm => { 13039 parentElm.insertBefore(elm, target); 13040 }); 13041 } 13042 return findFirstIn(target, rootNode); 13043 }; 13044 const insertAfter$2 = (target, elms, rootNode, dom) => { 13045 dom.insertAfter(elms.reverse(), target); 13046 return findLastOf(elms[0], rootNode); 13047 }; 13048 const insertAtCaret$1 = (serializer, dom, rng, fragment) => { 13049 const domFragment = toDomFragment(dom, serializer, fragment); 13050 const liTarget = getParentLi(dom, rng.startContainer); 13051 const liElms = trimListItems(listItems(domFragment.firstChild)); 13052 const BEGINNING = 1, END = 2; 13053 const rootNode = dom.getRoot(); 13054 const isAt = location => { 13055 const caretPos = CaretPosition.fromRangeStart(rng); 13056 const caretWalker = CaretWalker(dom.getRoot()); 13057 const newPos = location === BEGINNING ? caretWalker.prev(caretPos) : caretWalker.next(caretPos); 13058 const newPosNode = newPos === null || newPos === void 0 ? void 0 : newPos.getNode(); 13059 return newPosNode ? getParentLi(dom, newPosNode) !== liTarget : true; 13060 }; 13061 if (!liTarget) { 13062 return null; 13063 } else if (isAt(BEGINNING)) { 13064 return insertBefore$2(liTarget, liElms, rootNode); 13065 } else if (isAt(END)) { 13066 return insertAfter$2(liTarget, liElms, rootNode, dom); 13067 } else { 13068 return insertMiddle(liTarget, liElms, rootNode, rng); 13069 } 13070 }; 13071 13072 const mergeableWrappedElements = ['pre']; 13073 const shouldPasteContentOnly = (dom, fragment, parentNode, root) => { 13074 var _a; 13075 const firstNode = fragment.firstChild; 13076 const lastNode = fragment.lastChild; 13077 const last = lastNode.attr('data-mce-type') === 'bookmark' ? lastNode.prev : lastNode; 13078 const isPastingSingleElement = firstNode === last; 13079 const isWrappedElement = contains$2(mergeableWrappedElements, firstNode.name); 13080 if (isPastingSingleElement && isWrappedElement) { 13081 const isContentEditable = firstNode.attr('contenteditable') !== 'false'; 13082 const isPastingInTheSameBlockTag = ((_a = dom.getParent(parentNode, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName.toLowerCase()) === firstNode.name; 13083 const isPastingInContentEditable = Optional.from(getContentEditableRoot$1(root, parentNode)).forall(isContentEditableTrue$3); 13084 return isContentEditable && isPastingInTheSameBlockTag && isPastingInContentEditable; 13085 } else { 13086 return false; 13087 } 13088 }; 13089 const isTableCell = isTableCell$3; 13090 const isTableCellContentSelected = (dom, rng, cell) => { 13091 if (isNonNullable(cell)) { 13092 const endCell = dom.getParent(rng.endContainer, isTableCell); 13093 return cell === endCell && hasAllContentsSelected(SugarElement.fromDom(cell), rng); 13094 } else { 13095 return false; 13096 } 13097 }; 13098 const
vendor: 14,129 bytes, lines 13098-13420
13098isEditableEmptyBlock = (dom, node) => { 13099 if (dom.isBlock(node) && dom.isEditable(node)) { 13100 const childNodes = node.childNodes; 13101 return childNodes.length === 1 && isBr$6(childNodes[0]) || childNodes.length === 0; 13102 } else { 13103 return false; 13104 } 13105 }; 13106 const validInsertion = (editor, value, parentNode) => { 13107 var _a; 13108 if (parentNode.getAttribute('data-mce-bogus') === 'all') { 13109 (_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(editor.dom.createFragment(value), parentNode); 13110 } else { 13111 if (isEditableEmptyBlock(editor.dom, parentNode)) { 13112 editor.dom.setHTML(parentNode, value); 13113 } else { 13114 editor.selection.setContent(value, { no_events: true }); 13115 } 13116 } 13117 }; 13118 const trimBrsFromTableCell = (dom, elm, schema) => { 13119 Optional.from(dom.getParent(elm, 'td,th')).map(SugarElement.fromDom).each(el => trimBlockTrailingBr(el, schema)); 13120 }; 13121 const reduceInlineTextElements = (editor, merge) => { 13122 const textInlineElements = editor.schema.getTextInlineElements(); 13123 const dom = editor.dom; 13124 if (merge) { 13125 const root = editor.getBody(); 13126 const elementUtils = ElementUtils(editor); 13127 const fragmentSelector = '*[data-mce-fragment]'; 13128 const fragments = dom.select(fragmentSelector); 13129 Tools.each(fragments, node => { 13130 const isInline = currentNode => isNonNullable(textInlineElements[currentNode.nodeName.toLowerCase()]); 13131 const hasOneChild = currentNode => currentNode.childNodes.length === 1; 13132 const hasNoNonInheritableStyles = currentNode => !(hasNonInheritableStyles(dom, currentNode) || hasConditionalNonInheritableStyles(dom, currentNode)); 13133 if (hasNoNonInheritableStyles(node) && isInline(node) && hasOneChild(node)) { 13134 const styles = getStyleProps(dom, node); 13135 const isOverridden = (oldStyles, newStyles) => forall(oldStyles, style => contains$2(newStyles, style)); 13136 const overriddenByAllChildren = childNode => hasOneChild(node) && dom.is(childNode, fragmentSelector) && isInline(childNode) && (childNode.nodeName === node.nodeName && isOverridden(styles, getStyleProps(dom, childNode)) || overriddenByAllChildren(childNode.children[0])); 13137 const identicalToParent = parentNode => isNonNullable(parentNode) && parentNode !== root && (elementUtils.compare(node, parentNode) || identicalToParent(parentNode.parentElement)); 13138 const conflictWithInsertedParent = parentNode => isNonNullable(parentNode) && parentNode !== root && dom.is(parentNode, fragmentSelector) && (hasStyleConflict(dom, node, parentNode) || conflictWithInsertedParent(parentNode.parentElement)); 13139 if (overriddenByAllChildren(node.children[0]) || identicalToParent(node.parentElement) && !conflictWithInsertedParent(node.parentElement)) { 13140 dom.remove(node, true); 13141 } 13142 } 13143 }); 13144 } 13145 }; 13146 const markFragmentElements = fragment => { 13147 let node = fragment; 13148 while (node = node.walk()) { 13149 if (node.type === 1) { 13150 node.attr('data-mce-fragment', '1'); 13151 } 13152 } 13153 }; 13154 const unmarkFragmentElements = elm => { 13155 Tools.each(elm.getElementsByTagName('*'), elm => { 13156 elm.removeAttribute('data-mce-fragment'); 13157 }); 13158 }; 13159 const isPartOfFragment = node => { 13160 return !!node.getAttribute('data-mce-fragment'); 13161 }; 13162 const canHaveChildren = (editor, node) => { 13163 return isNonNullable(node) && !editor.schema.getVoidElements()[node.nodeName]; 13164 }; 13165 const moveSelectionToMarker = (editor, marker) => { 13166 var _a, _b, _c; 13167 let nextRng; 13168 const dom = editor.dom; 13169 const selection = editor.selection; 13170 if (!marker) { 13171 return; 13172 } 13173 selection.scrollIntoView(marker); 13174 const parentEditableElm = getContentEditableRoot$1(editor.getBody(), marker); 13175 if (parentEditableElm && dom.getContentEditable(parentEditableElm) === 'false') { 13176 dom.remove(marker); 13177 selection.select(parentEditableElm); 13178 return; 13179 } 13180 let rng = dom.createRng(); 13181 const node = marker.previousSibling; 13182 if (isText$b(node)) { 13183 rng.setStart(node, (_b = (_a = node.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0); 13184 const node2 = marker.nextSibling; 13185 if (isText$b(node2)) { 13186 node.appendData(node2.data); 13187 (_c = node2.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(node2); 13188 } 13189 } else { 13190 rng.setStartBefore(marker); 13191 rng.setEndBefore(marker); 13192 } 13193 const findNextCaretRng = rng => { 13194 let caretPos = CaretPosition.fromRangeStart(rng); 13195 const caretWalker = CaretWalker(editor.getBody()); 13196 caretPos = caretWalker.next(caretPos); 13197 return caretPos === null || caretPos === void 0 ? void 0 : caretPos.toRange(); 13198 }; 13199 const parentBlock = dom.getParent(marker, dom.isBlock); 13200 dom.remove(marker); 13201 if (parentBlock && dom.isEmpty(parentBlock)) { 13202 const isCell = isTableCell(parentBlock); 13203 empty(SugarElement.fromDom(parentBlock)); 13204 rng.setStart(parentBlock, 0); 13205 rng.setEnd(parentBlock, 0); 13206 if (!isCell && !isPartOfFragment(parentBlock) && (nextRng = findNextCaretRng(rng))) { 13207 rng = nextRng; 13208 dom.remove(parentBlock); 13209 } else { 13210 dom.add(parentBlock, dom.create('br', isCell ? {} : { 'data-mce-bogus': '1' })); 13211 } 13212 } 13213 selection.setRng(rng); 13214 }; 13215 const deleteSelectedContent = editor => { 13216 const dom = editor.dom; 13217 const rng = normalize(editor.selection.getRng()); 13218 editor.selection.setRng(rng); 13219 const startCell = dom.getParent(rng.startContainer, isTableCell); 13220 if (isTableCellContentSelected(dom, rng, startCell)) { 13221 deleteCellContents(editor, rng, SugarElement.fromDom(startCell)); 13222 } else if (rng.startContainer === rng.endContainer && rng.endOffset - rng.startOffset === 1 && isText$b(rng.startContainer.childNodes[rng.startOffset])) { 13223 rng.deleteContents(); 13224 } else { 13225 editor.getDoc().execCommand('Delete', false); 13226 } 13227 }; 13228 const findMarkerNode = scope => { 13229 for (let markerNode = scope; markerNode; markerNode = markerNode.walk()) { 13230 if (markerNode.attr('id') === 'mce_marker') { 13231 return Optional.some(markerNode); 13232 } 13233 } 13234 return Optional.none(); 13235 }; 13236 const notHeadingsInSummary = (dom, node, fragment) => { 13237 var _a; 13238 return exists(fragment.children(), isHeading) && ((_a = dom.getParent(node, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName) === 'SUMMARY'; 13239 }; 13240 const insertHtmlAtCaret = (editor, value, details) => { 13241 var _a, _b; 13242 const selection = editor.selection; 13243 const dom = editor.dom; 13244 const parser = editor.parser; 13245 const merge = details.merge; 13246 const serializer = HtmlSerializer({ validate: true }, editor.schema); 13247 const bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark"></span>'; 13248 if (!details.preserve_zwsp) { 13249 value = trim$2(value); 13250 } 13251 if (value.indexOf('{$caret}') === -1) { 13252 value += '{$caret}'; 13253 } 13254 value = value.replace(/\{\$caret\}/, bookmarkHtml); 13255 let rng = selection.getRng(); 13256 const caretElement = rng.startContainer; 13257 const body = editor.getBody(); 13258 if (caretElement === body && selection.isCollapsed()) { 13259 if (dom.isBlock(body.firstChild) && canHaveChildren(editor, body.firstChild) && dom.isEmpty(body.firstChild)) { 13260 rng = dom.createRng(); 13261 rng.setStart(body.firstChild, 0); 13262 rng.setEnd(body.firstChild, 0); 13263 selection.setRng(rng); 13264 } 13265 } 13266 if (!selection.isCollapsed()) { 13267 deleteSelectedContent(editor); 13268 } 13269 const parentNode = selection.getNode(); 13270 const parserArgs = { 13271 context: parentNode.nodeName.toLowerCase(), 13272 data: details.data, 13273 insert: true 13274 }; 13275 const fragment = parser.parse(value, parserArgs); 13276 if (details.paste === true && isListFragment(editor.schema, fragment) && isParentBlockLi(dom, parentNode)) { 13277 rng = insertAtCaret$1(serializer, dom, selection.getRng(), fragment); 13278 if (rng) { 13279 selection.setRng(rng); 13280 } 13281 return value; 13282 } 13283 if (details.paste === true && shouldPasteContentOnly(dom, fragment, parentNode, editor.getBody())) { 13284 (_a = fragment.firstChild) === null || _a === void 0 ? void 0 : _a.unwrap(); 13285 } 13286 markFragmentElements(fragment); 13287 let node = fragment.lastChild; 13288 if (node && node.attr('id') === 'mce_marker') { 13289 const marker = node; 13290 for (node = node.prev; node; node = node.walk(true)) { 13291 if (node.name === 'table') { 13292 break; 13293 } 13294 if (node.type === 3 || !dom.isBlock(node.name)) { 13295 if (node.parent && editor.schema.isValidChild(node.parent.name, 'span')) { 13296 node.parent.insert(marker, node, node.name === 'br'); 13297 } 13298 break; 13299 } 13300 } 13301 } 13302 editor._selectionOverrides.showBlockCaretContainer(parentNode); 13303 if (!parserArgs.invalid && !notHeadingsInSummary(dom, parentNode, fragment)) { 13304 value = serializer.serialize(fragment); 13305 validInsertion(editor, value, parentNode); 13306 } else { 13307 editor.selection.setContent(bookmarkHtml); 13308 let parentNode = selection.getNode(); 13309 let tempNode; 13310 const rootNode = editor.getBody(); 13311 if (isDocument$1(parentNode)) { 13312 parentNode = tempNode = rootNode; 13313 } else { 13314 tempNode = parentNode; 13315 } 13316 while (tempNode && tempNode !== rootNode) { 13317 parentNode = tempNode; 13318 tempNode = tempNode.parentNode; 13319 } 13320 value = parentNode === rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode); 13321 const root = parser.parse(value); 13322 const markerNode = findMarkerNode(root); 13323 const editingHost = markerNode.bind(findClosestEditingHost).getOr(root); 13324 markerNode.each(marker => marker.replace(fragment)); 13325 const toExtract = fragment.children(); 13326 const parent = (_b = fragment.parent) !== null && _b !== void 0 ? _b : root; 13327 fragment.unwrap(); 13328 const invalidChildren = filter$5(toExtract, node => isInvalid(editor.schema, node, parent)); 13329 cleanInvalidNodes(invalidChildren, editor.schema, editingHost); 13330 filter$2(parser.getNodeFilters(), parser.getAttributeFilters(), root); 13331 value = serializer.serialize(root); 13332 if (parentNode === rootNode) { 13333 dom.setHTML(rootNode, value); 13334 } else { 13335 dom.setOuterHTML(parentNode, value); 13336 } 13337 } 13338 reduceInlineTextElements(editor, merge); 13339 moveSelectionToMarker(editor, dom.get('mce_marker')); 13340 unmarkFragmentElements(editor.getBody()); 13341 trimBrsFromTableCell(dom, selection.getStart(), editor.schema); 13342 updateCaret(editor.schema, editor.getBody(), selection.getStart()); 13343 return value; 13344 }; 13345 13346 const isTreeNode = content => content instanceof AstNode; 13347 13348 const moveSelection = editor => { 13349 if (hasFocus(editor)) { 13350 firstPositionIn(editor.getBody()).each(pos => { 13351 const node = pos.getNode(); 13352 const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos; 13353 editor.selection.setRng(caretPos.toRange()); 13354 }); 13355 } 13356 }; 13357 const setEditorHtml = (editor, html, noSelection) => { 13358 editor.dom.setHTML(editor.getBody(), html); 13359 if (noSelection !== true) { 13360 moveSelection(editor); 13361 } 13362 }; 13363 const setContentString = (editor, body, content, args) => { 13364 content = trim$2(content); 13365 if (content.length === 0 || /^\s+$/.test(content)) { 13366 const padd = '<br data-mce-bogus="1">'; 13367 if (body.nodeName === 'TABLE') { 13368 content = '<tr><td>' + padd + '</td></tr>'; 13369 } else if (/^(UL|OL)$/.test(body.nodeName)) { 13370 content = '<li>' + padd + '</li>'; 13371 } 13372 const forcedRootBlockName = getForcedRootBlock(editor); 13373 if (editor.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) { 13374 content = padd; 13375 content = editor.dom.createHTML(forcedRootBlockName, getForcedRootBlockAttrs(editor), content); 13376 } else if (!content) { 13377 content = padd; 13378 } 13379 setEditorHtml(editor, content, args.no_selection); 13380 return { 13381 content, 13382 html: content 13383 }; 13384 } else { 13385 if (args.format !== 'raw') { 13386 content = HtmlSerializer({ validate: false }, editor.schema).serialize(editor.parser.parse(content, { 13387 isRootContent: true, 13388 insert: true 13389 })); 13390 } 13391 const trimmedHtml = isWsPreserveElement(SugarElement.fromDom(body)) ? content : Tools.trim(content); 13392 setEditorHtml(editor, trimmedHtml, args.no_selection); 13393 return { 13394 content: trimmedHtml, 13395 html: trimmedHtml 13396 }; 13397 } 13398 }; 13399 const setContentTree = (editor, body, content, args) => { 13400 filter$2(editor.parser.getNodeFilters(), editor.parser.getAttributeFilters(), content); 13401 const html = HtmlSerializer({ validate: false }, editor.schema).serialize(content); 13402 const trimmedHtml = trim$2(isWsPreserveElement(SugarElement.fromDom(body)) ? html : Tools.trim(html)); 13403 setEditorHtml(editor, trimmedHtml, args.no_selection); 13404 return { 13405 content, 13406 html: trimmedHtml 13407 }; 13408 }; 13409 const setContentInternal = (editor, content, args) => { 13410 return Optional.from(editor.getBody()).map(body => { 13411 if (isTreeNode(content)) { 13412 return setContentTree(editor, body, content, args); 13413 } else { 13414 return setContentString(editor, body, content, args); 13415 } 13416 }).getOr({ 13417 content, 13418 html: isTreeNode(args.content) ? '' : args.content 13419 }); 13420 }
vendor: 6,822 bytes, lines 13420-13606
13420; 13421 13422 const ensureIsRoot = isRoot => isFunction(isRoot) ? isRoot : never; 13423 const ancestor = (scope, transform, isRoot) => { 13424 let element = scope.dom; 13425 const stop = ensureIsRoot(isRoot); 13426 while (element.parentNode) { 13427 element = element.parentNode; 13428 const el = SugarElement.fromDom(element); 13429 const transformed = transform(el); 13430 if (transformed.isSome()) { 13431 return transformed; 13432 } else if (stop(el)) { 13433 break; 13434 } 13435 } 13436 return Optional.none(); 13437 }; 13438 const closest$1 = (scope, transform, isRoot) => { 13439 const current = transform(scope); 13440 const stop = ensureIsRoot(isRoot); 13441 return current.orThunk(() => stop(scope) ? Optional.none() : ancestor(scope, transform, stop)); 13442 }; 13443 13444 const isEq$3 = isEq$5; 13445 const matchesUnInheritedFormatSelector = (ed, node, name) => { 13446 const formatList = ed.formatter.get(name); 13447 if (formatList) { 13448 for (let i = 0; i < formatList.length; i++) { 13449 const format = formatList[i]; 13450 if (isSelectorFormat(format) && format.inherit === false && ed.dom.is(node, format.selector)) { 13451 return true; 13452 } 13453 } 13454 } 13455 return false; 13456 }; 13457 const matchParents = (editor, node, name, vars, similar) => { 13458 const root = editor.dom.getRoot(); 13459 if (node === root) { 13460 return false; 13461 } 13462 const matchedNode = editor.dom.getParent(node, elm => { 13463 if (matchesUnInheritedFormatSelector(editor, elm, name)) { 13464 return true; 13465 } 13466 return elm.parentNode === root || !!matchNode(editor, elm, name, vars, true); 13467 }); 13468 return !!matchNode(editor, matchedNode, name, vars, similar); 13469 }; 13470 const matchName = (dom, node, format) => { 13471 if (isInlineFormat(format) && isEq$3(node, format.inline)) { 13472 return true; 13473 } 13474 if (isBlockFormat(format) && isEq$3(node, format.block)) { 13475 return true; 13476 } 13477 if (isSelectorFormat(format)) { 13478 return isElement$6(node) && dom.is(node, format.selector); 13479 } 13480 return false; 13481 }; 13482 const matchItems = (dom, node, format, itemName, similar, vars) => { 13483 const items = format[itemName]; 13484 const matchAttributes = itemName === 'attributes'; 13485 if (isFunction(format.onmatch)) { 13486 return format.onmatch(node, format, itemName); 13487 } 13488 if (items) { 13489 if (!isArrayLike(items)) { 13490 for (const key in items) { 13491 if (has$2(items, key)) { 13492 const value = matchAttributes ? dom.getAttrib(node, key) : getStyle(dom, node, key); 13493 const expectedValue = replaceVars(items[key], vars); 13494 const isEmptyValue = isNullable(value) || isEmpty$3(value); 13495 if (isEmptyValue && isNullable(expectedValue)) { 13496 continue; 13497 } 13498 if (similar && isEmptyValue && !format.exact) { 13499 return false; 13500 } 13501 if ((!similar || format.exact) && !isEq$3(value, normalizeStyleValue(expectedValue, key))) { 13502 return false; 13503 } 13504 } 13505 } 13506 } else { 13507 for (let i = 0; i < items.length; i++) { 13508 if (matchAttributes ? dom.getAttrib(node, items[i]) : getStyle(dom, node, items[i])) { 13509 return true; 13510 } 13511 } 13512 } 13513 } 13514 return true; 13515 }; 13516 const matchNode = (ed, node, name, vars, similar) => { 13517 const formatList = ed.formatter.get(name); 13518 const dom = ed.dom; 13519 if (formatList && isElement$6(node)) { 13520 for (let i = 0; i < formatList.length; i++) { 13521 const format = formatList[i]; 13522 if (matchName(ed.dom, node, format) && matchItems(dom, node, format, 'attributes', similar, vars) && matchItems(dom, node, format, 'styles', similar, vars)) { 13523 const classes = format.classes; 13524 if (classes) { 13525 for (let x = 0; x < classes.length; x++) { 13526 if (!ed.dom.hasClass(node, replaceVars(classes[x], vars))) { 13527 return; 13528 } 13529 } 13530 } 13531 return format; 13532 } 13533 } 13534 } 13535 return undefined; 13536 }; 13537 const match$2 = (editor, name, vars, node, similar) => { 13538 if (node) { 13539 return matchParents(editor, node, name, vars, similar); 13540 } 13541 node = editor.selection.getNode(); 13542 if (matchParents(editor, node, name, vars, similar)) { 13543 return true; 13544 } 13545 const startNode = editor.selection.getStart(); 13546 if (startNode !== node) { 13547 if (matchParents(editor, startNode, name, vars, similar)) { 13548 return true; 13549 } 13550 } 13551 return false; 13552 }; 13553 const matchAll = (editor, names, vars) => { 13554 const matchedFormatNames = []; 13555 const checkedMap = {}; 13556 const startElement = editor.selection.getStart(); 13557 editor.dom.getParent(startElement, node => { 13558 for (let i = 0; i < names.length; i++) { 13559 const name = names[i]; 13560 if (!checkedMap[name] && matchNode(editor, node, name, vars)) { 13561 checkedMap[name] = true; 13562 matchedFormatNames.push(name); 13563 } 13564 } 13565 }, editor.dom.getRoot()); 13566 return matchedFormatNames; 13567 }; 13568 const closest = (editor, names) => { 13569 const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody())); 13570 const match = (elm, name) => matchNode(editor, elm.dom, name) ? Optional.some(name) : Optional.none(); 13571 return Optional.from(editor.selection.getStart(true)).bind(rawElm => closest$1(SugarElement.fromDom(rawElm), elm => findMap(names, name => match(elm, name)), isRoot)).getOrNull(); 13572 }; 13573 const canApply = (editor, name) => { 13574 const formatList = editor.formatter.get(name); 13575 const dom = editor.dom; 13576 if (formatList && editor.selection.isEditable()) { 13577 const startNode = editor.selection.getStart(); 13578 const parents = getParents$2(dom, startNode); 13579 for (let x = formatList.length - 1; x >= 0; x--) { 13580 const format = formatList[x]; 13581 if (!isSelectorFormat(format)) { 13582 return true; 13583 } 13584 for (let i = parents.length - 1; i >= 0; i--) { 13585 if (dom.is(parents[i], format.selector)) { 13586 return true; 13587 } 13588 } 13589 } 13590 } 13591 return false; 13592 }; 13593 const matchAllOnNode = (editor, node, formatNames) => foldl(formatNames, (acc, name) => { 13594 const matchSimilar = isVariableFormatName(editor, name); 13595 if (editor.formatter.matchNode(node, name, {}, matchSimilar)) { 13596 return acc.concat([name]); 13597 } else { 13598 return acc; 13599 } 13600 }, []); 13601 13602 const ZWSP = ZWSP$1; 13603 const importNode = (ownerDocument, node) => { 13604 return ownerDocument.importNode(node, true); 13605 }; 13606 const
vendor: 6,827 bytes, lines 13606-13770
13606findFirstTextNode = node => { 13607 if (node) { 13608 const walker = new DomTreeWalker(node, node); 13609 for (let tempNode = walker.current(); tempNode; tempNode = walker.next()) { 13610 if (isText$b(tempNode)) { 13611 return tempNode; 13612 } 13613 } 13614 } 13615 return null; 13616 }; 13617 const createCaretContainer = fill => { 13618 const caretContainer = SugarElement.fromTag('span'); 13619 setAll$1(caretContainer, { 13620 'id': CARET_ID, 13621 'data-mce-bogus': '1', 13622 'data-mce-type': 'format-caret' 13623 }); 13624 if (fill) { 13625 append$1(caretContainer, SugarElement.fromText(ZWSP)); 13626 } 13627 return caretContainer; 13628 }; 13629 const trimZwspFromCaretContainer = caretContainerNode => { 13630 const textNode = findFirstTextNode(caretContainerNode); 13631 if (textNode && textNode.data.charAt(0) === ZWSP) { 13632 textNode.deleteData(0, 1); 13633 } 13634 return textNode; 13635 }; 13636 const removeCaretContainerNode = (editor, node, moveCaret) => { 13637 const dom = editor.dom, selection = editor.selection; 13638 if (isCaretContainerEmpty(node)) { 13639 deleteElement$2(editor, false, SugarElement.fromDom(node), moveCaret, true); 13640 } else { 13641 const rng = selection.getRng(); 13642 const block = dom.getParent(node, dom.isBlock); 13643 const startContainer = rng.startContainer; 13644 const startOffset = rng.startOffset; 13645 const endContainer = rng.endContainer; 13646 const endOffset = rng.endOffset; 13647 const textNode = trimZwspFromCaretContainer(node); 13648 dom.remove(node, true); 13649 if (startContainer === textNode && startOffset > 0) { 13650 rng.setStart(textNode, startOffset - 1); 13651 } 13652 if (endContainer === textNode && endOffset > 0) { 13653 rng.setEnd(textNode, endOffset - 1); 13654 } 13655 if (block && dom.isEmpty(block)) { 13656 fillWithPaddingBr(SugarElement.fromDom(block)); 13657 } 13658 selection.setRng(rng); 13659 } 13660 }; 13661 const removeCaretContainer = (editor, node, moveCaret) => { 13662 const dom = editor.dom, selection = editor.selection; 13663 if (!node) { 13664 node = getParentCaretContainer(editor.getBody(), selection.getStart()); 13665 if (!node) { 13666 while (node = dom.get(CARET_ID)) { 13667 removeCaretContainerNode(editor, node, moveCaret); 13668 } 13669 } 13670 } else { 13671 removeCaretContainerNode(editor, node, moveCaret); 13672 } 13673 }; 13674 const insertCaretContainerNode = (editor, caretContainer, formatNode) => { 13675 var _a, _b; 13676 const dom = editor.dom; 13677 const block = dom.getParent(formatNode, curry(isTextBlock$1, editor.schema)); 13678 if (block && dom.isEmpty(block)) { 13679 (_a = formatNode.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(caretContainer, formatNode); 13680 } else { 13681 removeTrailingBr(SugarElement.fromDom(formatNode)); 13682 if (dom.isEmpty(formatNode)) { 13683 (_b = formatNode.parentNode) === null || _b === void 0 ? void 0 : _b.replaceChild(caretContainer, formatNode); 13684 } else { 13685 dom.insertAfter(caretContainer, formatNode); 13686 } 13687 } 13688 }; 13689 const appendNode = (parentNode, node) => { 13690 parentNode.appendChild(node); 13691 return node; 13692 }; 13693 const insertFormatNodesIntoCaretContainer = (formatNodes, caretContainer) => { 13694 var _a; 13695 const innerMostFormatNode = foldr(formatNodes, (parentNode, formatNode) => { 13696 return appendNode(parentNode, formatNode.cloneNode(false)); 13697 }, caretContainer); 13698 const doc = (_a = innerMostFormatNode.ownerDocument) !== null && _a !== void 0 ? _a : document; 13699 return appendNode(innerMostFormatNode, doc.createTextNode(ZWSP)); 13700 }; 13701 const cleanFormatNode = (editor, caretContainer, formatNode, name, vars, similar) => { 13702 const formatter = editor.formatter; 13703 const dom = editor.dom; 13704 const validFormats = filter$5(keys(formatter.get()), formatName => formatName !== name && !contains$1(formatName, 'removeformat')); 13705 const matchedFormats = matchAllOnNode(editor, formatNode, validFormats); 13706 const uniqueFormats = filter$5(matchedFormats, fmtName => !areSimilarFormats(editor, fmtName, name)); 13707 if (uniqueFormats.length > 0) { 13708 const clonedFormatNode = formatNode.cloneNode(false); 13709 dom.add(caretContainer, clonedFormatNode); 13710 formatter.remove(name, vars, clonedFormatNode, similar); 13711 dom.remove(clonedFormatNode); 13712 return Optional.some(clonedFormatNode); 13713 } else { 13714 return Optional.none(); 13715 } 13716 }; 13717 const normalizeNbsps = node => set(node, get$3(node).replace(new RegExp(`${ nbsp }$`), ' ')); 13718 const normalizeNbspsBetween = (editor, caretContainer) => { 13719 const handler = () => { 13720 if (caretContainer !== null && !editor.dom.isEmpty(caretContainer)) { 13721 prevSibling(SugarElement.fromDom(caretContainer)).each(node => { 13722 if (isText$c(node)) { 13723 normalizeNbsps(node); 13724 } else { 13725 descendant$2(node, e => isText$c(e)).each(textNode => { 13726 if (isText$c(textNode)) { 13727 normalizeNbsps(textNode); 13728 } 13729 }); 13730 } 13731 }); 13732 } 13733 }; 13734 editor.once('input', e => { 13735 if (e.data && !isWhiteSpace(e.data)) { 13736 if (!e.isComposing) { 13737 handler(); 13738 } else { 13739 editor.once('compositionend', () => { 13740 handler(); 13741 }); 13742 } 13743 } 13744 }); 13745 }; 13746 const applyCaretFormat = (editor, name, vars) => { 13747 let caretContainer; 13748 const selection = editor.selection; 13749 const formatList = editor.formatter.get(name); 13750 if (!formatList) { 13751 return; 13752 } 13753 const selectionRng = selection.getRng(); 13754 let offset = selectionRng.startOffset; 13755 const container = selectionRng.startContainer; 13756 const text = container.nodeValue; 13757 caretContainer = getParentCaretContainer(editor.getBody(), selection.getStart()); 13758 const wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/; 13759 if (text && offset > 0 && offset < text.length && wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) { 13760 const bookmark = selection.getBookmark(); 13761 selectionRng.collapse(true); 13762 let rng = expandRng(editor.dom, selectionRng, formatList); 13763 rng = split(rng); 13764 editor.formatter.apply(name, vars, rng); 13765 selection.moveToBookmark(bookmark); 13766 } else { 13767 let textNode = caretContainer ? findFirstTextNode(caretContainer) : null; 13768 if (!caretContainer || (textNode === null || textNode === void 0 ? void 0 : textNode.data) !== ZWSP) { 13769 caretContainer = importNode(editor.getDoc(), createCaretContainer(true).dom); 13770 textNode = caretContainer.firstChild;
vendor: 2,650 bytes, lines 13771-13837
13771 selectionRng.insertNode(caretContainer); 13772 offset = 1; 13773 normalizeNbspsBetween(editor, caretContainer); 13774 editor.formatter.apply(name, vars, caretContainer); 13775 } else { 13776 editor.formatter.apply(name, vars, caretContainer); 13777 } 13778 selection.setCursorLocation(textNode, offset); 13779 } 13780 }; 13781 const removeCaretFormat = (editor, name, vars, similar) => { 13782 const dom = editor.dom; 13783 const selection = editor.selection; 13784 let hasContentAfter = false; 13785 const formatList = editor.formatter.get(name); 13786 if (!formatList) { 13787 return; 13788 } 13789 const rng = selection.getRng(); 13790 const container = rng.startContainer; 13791 const offset = rng.startOffset; 13792 let node = container; 13793 if (isText$b(container)) { 13794 if (offset !== container.data.length) { 13795 hasContentAfter = true; 13796 } 13797 node = node.parentNode; 13798 } 13799 const parents = []; 13800 let formatNode; 13801 while (node) { 13802 if (matchNode(editor, node, name, vars, similar)) { 13803 formatNode = node; 13804 break; 13805 } 13806 if (node.nextSibling) { 13807 hasContentAfter = true; 13808 } 13809 parents.push(node); 13810 node = node.parentNode; 13811 } 13812 if (!formatNode) { 13813 return; 13814 } 13815 if (hasContentAfter) { 13816 const bookmark = selection.getBookmark(); 13817 rng.collapse(true); 13818 let expandedRng = expandRng(dom, rng, formatList, { includeTrailingSpace: true }); 13819 expandedRng = split(expandedRng); 13820 editor.formatter.remove(name, vars, expandedRng, similar); 13821 selection.moveToBookmark(bookmark); 13822 } else { 13823 const caretContainer = getParentCaretContainer(editor.getBody(), formatNode); 13824 const parentsAfter = isNonNullable(caretContainer) ? dom.getParents(formatNode.parentNode, always, caretContainer) : []; 13825 const newCaretContainer = createCaretContainer(false).dom; 13826 insertCaretContainerNode(editor, newCaretContainer, caretContainer !== null && caretContainer !== void 0 ? caretContainer : formatNode); 13827 const cleanedFormatNode = cleanFormatNode(editor, newCaretContainer, formatNode, name, vars, similar); 13828 const caretTextNode = insertFormatNodesIntoCaretContainer([ 13829 ...parents, 13830 ...cleanedFormatNode.toArray(), 13831 ...parentsAfter 13832 ], newCaretContainer); 13833 if (caretContainer) { 13834 removeCaretContainerNode(editor, caretContainer, isNonNullable(caretContainer)); 13835 } 13836 selection.setCursorLocation(caretTextNode, 1); 13837 normalizeNbspsBetween(editor, newCaretContainer
vendor: 22,019 bytes, lines 13837-14380
13837); 13838 if (dom.isEmpty(formatNode)) { 13839 dom.remove(formatNode); 13840 } 13841 } 13842 }; 13843 const disableCaretContainer = (editor, keyCode, moveCaret) => { 13844 const selection = editor.selection, body = editor.getBody(); 13845 removeCaretContainer(editor, null, moveCaret); 13846 if ((keyCode === 8 || keyCode === 46) && selection.isCollapsed() && selection.getStart().innerHTML === ZWSP) { 13847 removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()), true); 13848 } 13849 if (keyCode === 37 || keyCode === 39) { 13850 removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()), true); 13851 } 13852 }; 13853 const endsWithNbsp = element => isText$b(element) && endsWith(element.data, nbsp); 13854 const setup$v = editor => { 13855 editor.on('mouseup keydown', e => { 13856 disableCaretContainer(editor, e.keyCode, endsWithNbsp(editor.selection.getRng().endContainer)); 13857 }); 13858 }; 13859 const createCaretFormat = formatNodes => { 13860 const caretContainer = createCaretContainer(false); 13861 const innerMost = insertFormatNodesIntoCaretContainer(formatNodes, caretContainer.dom); 13862 return { 13863 caretContainer, 13864 caretPosition: CaretPosition(innerMost, 0) 13865 }; 13866 }; 13867 const replaceWithCaretFormat = (targetNode, formatNodes) => { 13868 const {caretContainer, caretPosition} = createCaretFormat(formatNodes); 13869 before$3(SugarElement.fromDom(targetNode), caretContainer); 13870 remove$4(SugarElement.fromDom(targetNode)); 13871 return caretPosition; 13872 }; 13873 const createCaretFormatAtStart$1 = (rng, formatNodes) => { 13874 const {caretContainer, caretPosition} = createCaretFormat(formatNodes); 13875 rng.insertNode(caretContainer.dom); 13876 return caretPosition; 13877 }; 13878 const isFormatElement = (editor, element) => { 13879 if (isCaretNode(element.dom)) { 13880 return false; 13881 } 13882 const inlineElements = editor.schema.getTextInlineElements(); 13883 return has$2(inlineElements, name(element)) && !isCaretNode(element.dom) && !isBogus$1(element.dom); 13884 }; 13885 13886 const postProcessHooks = {}; 13887 const isPre = matchNodeNames(['pre']); 13888 const addPostProcessHook = (name, hook) => { 13889 const hooks = postProcessHooks[name]; 13890 if (!hooks) { 13891 postProcessHooks[name] = []; 13892 } 13893 postProcessHooks[name].push(hook); 13894 }; 13895 const postProcess$1 = (name, editor) => { 13896 if (has$2(postProcessHooks, name)) { 13897 each$e(postProcessHooks[name], hook => { 13898 hook(editor); 13899 }); 13900 } 13901 }; 13902 addPostProcessHook('pre', editor => { 13903 const rng = editor.selection.getRng(); 13904 const hasPreSibling = blocks => pre => { 13905 const prev = pre.previousSibling; 13906 return isPre(prev) && contains$2(blocks, prev); 13907 }; 13908 const joinPre = (pre1, pre2) => { 13909 const sPre2 = SugarElement.fromDom(pre2); 13910 const doc = documentOrOwner(sPre2).dom; 13911 remove$4(sPre2); 13912 append(SugarElement.fromDom(pre1), [ 13913 SugarElement.fromTag('br', doc), 13914 SugarElement.fromTag('br', doc), 13915 ...children$1(sPre2) 13916 ]); 13917 }; 13918 if (!rng.collapsed) { 13919 const blocks = editor.selection.getSelectedBlocks(); 13920 const preBlocks = filter$5(filter$5(blocks, isPre), hasPreSibling(blocks)); 13921 each$e(preBlocks, pre => { 13922 joinPre(pre.previousSibling, pre); 13923 }); 13924 } 13925 }); 13926 13927 const listItemStyles = [ 13928 'fontWeight', 13929 'fontStyle', 13930 'color', 13931 'fontSize', 13932 'fontFamily' 13933 ]; 13934 const hasListStyles = fmt => isObject(fmt.styles) && exists(keys(fmt.styles), name => contains$2(listItemStyles, name)); 13935 const findExpandedListItemFormat = formats => find$2(formats, fmt => isInlineFormat(fmt) && fmt.inline === 'span' && hasListStyles(fmt)); 13936 const getExpandedListItemFormat = (formatter, format) => { 13937 const formatList = formatter.get(format); 13938 return isArray$1(formatList) ? findExpandedListItemFormat(formatList) : Optional.none(); 13939 }; 13940 const isRngStartAtStartOfElement = (rng, elm) => prevPosition(elm, CaretPosition.fromRangeStart(rng)).isNone(); 13941 const isRngEndAtEndOfElement = (rng, elm) => { 13942 return nextPosition(elm, CaretPosition.fromRangeEnd(rng)).exists(pos => !isBr$6(pos.getNode()) || nextPosition(elm, pos).isSome()) === false; 13943 }; 13944 const isEditableListItem = dom => elm => isListItem$2(elm) && dom.isEditable(elm); 13945 const getFullySelectedBlocks = selection => { 13946 const blocks = selection.getSelectedBlocks(); 13947 const rng = selection.getRng(); 13948 if (selection.isCollapsed()) { 13949 return []; 13950 } 13951 if (blocks.length === 1) { 13952 return isRngStartAtStartOfElement(rng, blocks[0]) && isRngEndAtEndOfElement(rng, blocks[0]) ? blocks : []; 13953 } else { 13954 const first = head(blocks).filter(elm => isRngStartAtStartOfElement(rng, elm)).toArray(); 13955 const last = last$2(blocks).filter(elm => isRngEndAtEndOfElement(rng, elm)).toArray(); 13956 const middle = blocks.slice(1, -1); 13957 return first.concat(middle).concat(last); 13958 } 13959 }; 13960 const getFullySelectedListItems = selection => filter$5(getFullySelectedBlocks(selection), isEditableListItem(selection.dom)); 13961 const getPartiallySelectedListItems = selection => filter$5(selection.getSelectedBlocks(), isEditableListItem(selection.dom)); 13962 13963 const each$8 = Tools.each; 13964 const isElementNode = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node); 13965 const findElementSibling = (node, siblingName) => { 13966 for (let sibling = node; sibling; sibling = sibling[siblingName]) { 13967 if (isText$b(sibling) && isNotEmpty(sibling.data)) { 13968 return node; 13969 } 13970 if (isElement$6(sibling) && !isBookmarkNode$1(sibling)) { 13971 return sibling; 13972 } 13973 } 13974 return node; 13975 }; 13976 const mergeSiblingsNodes = (editor, prev, next) => { 13977 const elementUtils = ElementUtils(editor); 13978 const isPrevEditable = isHTMLElement(prev) && editor.dom.isEditable(prev); 13979 const isNextEditable = isHTMLElement(next) && editor.dom.isEditable(next); 13980 if (isPrevEditable && isNextEditable) { 13981 const prevSibling = findElementSibling(prev, 'previousSibling'); 13982 const nextSibling = findElementSibling(next, 'nextSibling'); 13983 if (elementUtils.compare(prevSibling, nextSibling)) { 13984 for (let sibling = prevSibling.nextSibling; sibling && sibling !== nextSibling;) { 13985 const tmpSibling = sibling; 13986 sibling = sibling.nextSibling; 13987 prevSibling.appendChild(tmpSibling); 13988 } 13989 editor.dom.remove(nextSibling); 13990 Tools.each(Tools.grep(nextSibling.childNodes), node => { 13991 prevSibling.appendChild(node); 13992 }); 13993 return prevSibling; 13994 } 13995 } 13996 return next; 13997 }; 13998 const mergeSiblings = (editor, format, vars, node) => { 13999 var _a; 14000 if (node && format.merge_siblings !== false) { 14001 const newNode = (_a = mergeSiblingsNodes(editor, getNonWhiteSpaceSibling(node), node)) !== null && _a !== void 0 ? _a : node; 14002 mergeSiblingsNodes(editor, newNode, getNonWhiteSpaceSibling(newNode, true)); 14003 } 14004 }; 14005 const clearChildStyles = (dom, format, node) => { 14006 if (format.clear_child_styles) { 14007 const selector = format.links ? '*:not(a)' : '*'; 14008 each$8(dom.select(selector, node), childNode => { 14009 if (isElementNode(childNode) && dom.isEditable(childNode)) { 14010 each$8(format.styles, (_value, name) => { 14011 dom.setStyle(childNode, name, ''); 14012 }); 14013 } 14014 }); 14015 } 14016 }; 14017 const processChildElements = (node, filter, process) => { 14018 each$8(node.childNodes, node => { 14019 if (isElementNode(node)) { 14020 if (filter(node)) { 14021 process(node); 14022 } 14023 if (node.hasChildNodes()) { 14024 processChildElements(node, filter, process); 14025 } 14026 } 14027 }); 14028 }; 14029 const unwrapEmptySpan = (dom, node) => { 14030 if (node.nodeName === 'SPAN' && dom.getAttribs(node).length === 0) { 14031 dom.remove(node, true); 14032 } 14033 }; 14034 const hasStyle = (dom, name) => node => !!(node && getStyle(dom, node, name)); 14035 const applyStyle = (dom, name, value) => node => { 14036 dom.setStyle(node, name, value); 14037 if (node.getAttribute('style') === '') { 14038 node.removeAttribute('style'); 14039 } 14040 unwrapEmptySpan(dom, node); 14041 }; 14042 14043 const removeResult = Adt.generate([ 14044 { keep: [] }, 14045 { rename: ['name'] }, 14046 { removed: [] } 14047 ]); 14048 const MCE_ATTR_RE = /^(src|href|style)$/; 14049 const each$7 = Tools.each; 14050 const isEq$2 = isEq$5; 14051 const isTableCellOrRow = node => /^(TR|TH|TD)$/.test(node.nodeName); 14052 const isChildOfInlineParent = (dom, node, parent) => dom.isChildOf(node, parent) && node !== parent && !dom.isBlock(parent); 14053 const getContainer = (ed, rng, start) => { 14054 let container = rng[start ? 'startContainer' : 'endContainer']; 14055 let offset = rng[start ? 'startOffset' : 'endOffset']; 14056 if (isElement$6(container)) { 14057 const lastIdx = container.childNodes.length - 1; 14058 if (!start && offset) { 14059 offset--; 14060 } 14061 container = container.childNodes[offset > lastIdx ? lastIdx : offset]; 14062 } 14063 if (isText$b(container) && start && offset >= container.data.length) { 14064 container = new DomTreeWalker(container, ed.getBody()).next() || container; 14065 } 14066 if (isText$b(container) && !start && offset === 0) { 14067 container = new DomTreeWalker(container, ed.getBody()).prev() || container; 14068 } 14069 return container; 14070 }; 14071 const normalizeTableSelection = (node, start) => { 14072 const prop = start ? 'firstChild' : 'lastChild'; 14073 const childNode = node[prop]; 14074 if (isTableCellOrRow(node) && childNode) { 14075 if (node.nodeName === 'TR') { 14076 return childNode[prop] || childNode; 14077 } else { 14078 return childNode; 14079 } 14080 } 14081 return node; 14082 }; 14083 const wrap$1 = (dom, node, name, attrs) => { 14084 var _a; 14085 const wrapper = dom.create(name, attrs); 14086 (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(wrapper, node); 14087 wrapper.appendChild(node); 14088 return wrapper; 14089 }; 14090 const wrapWithSiblings = (dom, node, next, name, attrs) => { 14091 const start = SugarElement.fromDom(node); 14092 const wrapper = SugarElement.fromDom(dom.create(name, attrs)); 14093 const siblings = next ? nextSiblings(start) : prevSiblings(start); 14094 append(wrapper, siblings); 14095 if (next) { 14096 before$3(start, wrapper); 14097 prepend(wrapper, start); 14098 } else { 14099 after$4(start, wrapper); 14100 append$1(wrapper, start); 14101 } 14102 return wrapper.dom; 14103 }; 14104 const isColorFormatAndAnchor = (node, format) => format.links && node.nodeName === 'A'; 14105 const removeNode = (ed, node, format) => { 14106 const parentNode = node.parentNode; 14107 let rootBlockElm; 14108 const dom = ed.dom; 14109 const forcedRootBlock = getForcedRootBlock(ed); 14110 if (isBlockFormat(format)) { 14111 if (parentNode === dom.getRoot()) { 14112 if (!format.list_block || !isEq$2(node, format.list_block)) { 14113 each$e(from(node.childNodes), node => { 14114 if (isValid(ed, forcedRootBlock, node.nodeName.toLowerCase())) { 14115 if (!rootBlockElm) { 14116 rootBlockElm = wrap$1(dom, node, forcedRootBlock); 14117 dom.setAttribs(rootBlockElm, getForcedRootBlockAttrs(ed)); 14118 } else { 14119 rootBlockElm.appendChild(node); 14120 } 14121 } else { 14122 rootBlockElm = null; 14123 } 14124 }); 14125 } 14126 } 14127 } 14128 if (isMixedFormat(format) && !isEq$2(format.inline, node)) { 14129 return; 14130 } 14131 dom.remove(node, true); 14132 }; 14133 const processFormatAttrOrStyle = (name, value, vars) => { 14134 if (isNumber(name)) { 14135 return { 14136 name: value, 14137 value: null 14138 }; 14139 } else { 14140 return { 14141 name, 14142 value: replaceVars(value, vars) 14143 }; 14144 } 14145 }; 14146 const removeEmptyStyleAttributeIfNeeded = (dom, elm) => { 14147 if (dom.getAttrib(elm, 'style') === '') { 14148 elm.removeAttribute('style'); 14149 elm.removeAttribute('data-mce-style'); 14150 } 14151 }; 14152 const removeStyles = (dom, elm, format, vars, compareNode) => { 14153 let stylesModified = false; 14154 each$7(format.styles, (value, name) => { 14155 const { 14156 name: styleName, 14157 value: styleValue 14158 } = processFormatAttrOrStyle(name, value, vars); 14159 const normalizedStyleValue = normalizeStyleValue(styleValue, styleName); 14160 if (format.remove_similar || isNull(styleValue) || !isElement$6(compareNode) || isEq$2(getStyle(dom, compareNode, styleName), normalizedStyleValue)) { 14161 dom.setStyle(elm, styleName, ''); 14162 } 14163 stylesModified = true; 14164 }); 14165 if (stylesModified) { 14166 removeEmptyStyleAttributeIfNeeded(dom, elm); 14167 } 14168 }; 14169 const removeListStyleFormats = (editor, name, vars) => { 14170 if (name === 'removeformat') { 14171 each$e(getPartiallySelectedListItems(editor.selection), li => { 14172 each$e(listItemStyles, name => editor.dom.setStyle(li, name, '')); 14173 removeEmptyStyleAttributeIfNeeded(editor.dom, li); 14174 }); 14175 } else { 14176 getExpandedListItemFormat(editor.formatter, name).each(liFmt => { 14177 each$e(getPartiallySelectedListItems(editor.selection), li => removeStyles(editor.dom, li, liFmt, vars, null)); 14178 }); 14179 } 14180 }; 14181 const removeNodeFormatInternal = (ed, format, vars, node, compareNode) => { 14182 const dom = ed.dom; 14183 const elementUtils = ElementUtils(ed); 14184 const schema = ed.schema; 14185 if (isInlineFormat(format) && isTransparentElementName(schema, format.inline) && isTransparentBlock(schema, node) && node.parentElement === ed.getBody()) { 14186 removeNode(ed, node, format); 14187 return removeResult.removed(); 14188 } 14189 if (!format.ceFalseOverride && node && dom.getContentEditableParent(node) === 'false') { 14190 return removeResult.keep(); 14191 } 14192 if (node && !matchName(dom, node, format) && !isColorFormatAndAnchor(node, format)) { 14193 return removeResult.keep(); 14194 } 14195 const elm = node; 14196 const preserveAttributes = format.preserve_attributes; 14197 if (isInlineFormat(format) && format.remove === 'all' && isArray$1(preserveAttributes)) { 14198 const attrsToPreserve = filter$5(dom.getAttribs(elm), attr => contains$2(preserveAttributes, attr.name.toLowerCase())); 14199 dom.removeAllAttribs(elm); 14200 each$e(attrsToPreserve, attr => dom.setAttrib(elm, attr.name, attr.value)); 14201 if (attrsToPreserve.length > 0) { 14202 return removeResult.rename('span'); 14203 } 14204 } 14205 if (format.remove !== 'all') { 14206 removeStyles(dom, elm, format, vars, compareNode); 14207 each$7(format.attributes, (value, name) => { 14208 const { 14209 name: attrName, 14210 value: attrValue 14211 } = processFormatAttrOrStyle(name, value, vars); 14212 if (format.remove_similar || isNull(attrValue) || !isElement$6(compareNode) || isEq$2(dom.getAttrib(compareNode, attrName), attrValue)) { 14213 if (attrName === 'class') { 14214 const currentValue = dom.getAttrib(elm, attrName); 14215 if (currentValue) { 14216 let valueOut = ''; 14217 each$e(currentValue.split(/\s+/), cls => { 14218 if (/mce\-\w+/.test(cls)) { 14219 valueOut += (valueOut ? ' ' : '') + cls; 14220 } 14221 }); 14222 if (valueOut) { 14223 dom.setAttrib(elm, attrName, valueOut); 14224 return; 14225 } 14226 } 14227 } 14228 if (MCE_ATTR_RE.test(attrName)) { 14229 elm.removeAttribute('data-mce-' + attrName); 14230 } 14231 if (attrName === 'style' && matchNodeNames(['li'])(elm) && dom.getStyle(elm, 'list-style-type') === 'none') { 14232 elm.removeAttribute(attrName); 14233 dom.setStyle(elm, 'list-style-type', 'none'); 14234 return; 14235 } 14236 if (attrName === 'class') { 14237 elm.removeAttribute('className'); 14238 } 14239 elm.removeAttribute(attrName); 14240 } 14241 }); 14242 each$7(format.classes, value => { 14243 value = replaceVars(value, vars); 14244 if (!isElement$6(compareNode) || dom.hasClass(compareNode, value)) { 14245 dom.removeClass(elm, value); 14246 } 14247 }); 14248 const attrs = dom.getAttribs(elm); 14249 for (let i = 0; i < attrs.length; i++) { 14250 const attrName = attrs[i].nodeName; 14251 if (!elementUtils.isAttributeInternal(attrName)) { 14252 return removeResult.keep(); 14253 } 14254 } 14255 } 14256 if (format.remove !== 'none') { 14257 removeNode(ed, elm, format); 14258 return removeResult.removed(); 14259 } 14260 return removeResult.keep(); 14261 }; 14262 const findFormatRoot = (editor, container, name, vars, similar) => { 14263 let formatRoot; 14264 if (container.parentNode) { 14265 each$e(getParents$2(editor.dom, container.parentNode).reverse(), parent => { 14266 if (!formatRoot && isElement$6(parent) && parent.id !== '_start' && parent.id !== '_end') { 14267 const format = matchNode(editor, parent, name, vars, similar); 14268 if (format && format.split !== false) { 14269 formatRoot = parent; 14270 } 14271 } 14272 }); 14273 } 14274 return formatRoot; 14275 }; 14276 const removeNodeFormatFromClone = (editor, format, vars, clone) => removeNodeFormatInternal(editor, format, vars, clone, clone).fold(constant(clone), newName => { 14277 const fragment = editor.dom.createFragment(); 14278 fragment.appendChild(clone); 14279 return editor.dom.rename(clone, newName); 14280 }, constant(null)); 14281 const wrapAndSplit = (editor, formatList, formatRoot, container, target, split, format, vars) => { 14282 var _a, _b; 14283 let lastClone; 14284 let firstClone; 14285 const dom = editor.dom; 14286 if (formatRoot) { 14287 const formatRootParent = formatRoot.parentNode; 14288 for (let parent = container.parentNode; parent && parent !== formatRootParent; parent = parent.parentNode) { 14289 let clone = dom.clone(parent, false); 14290 for (let i = 0; i < formatList.length; i++) { 14291 clone = removeNodeFormatFromClone(editor, formatList[i], vars, clone); 14292 if (clone === null) { 14293 break; 14294 } 14295 } 14296 if (clone) { 14297 if (lastClone) { 14298 clone.appendChild(lastClone); 14299 } 14300 if (!firstClone) { 14301 firstClone = clone; 14302 } 14303 lastClone = clone; 14304 } 14305 } 14306 if (split && (!format.mixed || !dom.isBlock(formatRoot))) { 14307 container = (_a = dom.split(formatRoot, container)) !== null && _a !== void 0 ? _a : container; 14308 } 14309 if (lastClone && firstClone) { 14310 (_b = target.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(lastClone, target); 14311 firstClone.appendChild(target); 14312 if (isInlineFormat(format)) { 14313 mergeSiblings(editor, format, vars, lastClone); 14314 } 14315 } 14316 } 14317 return container; 14318 }; 14319 const removeFormatInternal = (ed, name, vars, node, similar) => { 14320 const formatList = ed.formatter.get(name); 14321 const format = formatList[0]; 14322 const dom = ed.dom; 14323 const selection = ed.selection; 14324 const splitToFormatRoot = container => { 14325 const formatRoot = findFormatRoot(ed, container, name, vars, similar); 14326 return wrapAndSplit(ed, formatList, formatRoot, container, container, true, format, vars); 14327 }; 14328 const isRemoveBookmarkNode = node => isBookmarkNode$1(node) && isElement$6(node) && (node.id === '_start' || node.id === '_end'); 14329 const removeFormatOnNode = node => exists(formatList, fmt => removeNodeFormat(ed, fmt, vars, node, node)); 14330 const process = node => { 14331 const children = from(node.childNodes); 14332 const removed = removeFormatOnNode(node); 14333 const currentNodeMatches = removed || exists(formatList, f => matchName(dom, node, f)); 14334 const parentNode = node.parentNode; 14335 if (!currentNodeMatches && isNonNullable(parentNode) && shouldExpandToSelector(format)) { 14336 removeFormatOnNode(parentNode); 14337 } 14338 if (format.deep) { 14339 if (children.length) { 14340 for (let i = 0; i < children.length; i++) { 14341 process(children[i]); 14342 } 14343 } 14344 } 14345 const textDecorations = [ 14346 'underline', 14347 'line-through', 14348 'overline' 14349 ]; 14350 each$e(textDecorations, decoration => { 14351 if (isElement$6(node) && ed.dom.getStyle(node, 'text-decoration') === decoration && node.parentNode && getTextDecoration(dom, node.parentNode) === decoration) { 14352 removeNodeFormat(ed, { 14353 deep: false, 14354 exact: true, 14355 inline: 'span', 14356 styles: { textDecoration: decoration } 14357 }, undefined, node); 14358 } 14359 }); 14360 }; 14361 const unwrap = start => { 14362 const node = dom.get(start ? '_start' : '_end'); 14363 if (node) { 14364 let out = node[start ? 'firstChild' : 'lastChild']; 14365 if (isRemoveBookmarkNode(out)) { 14366 out = out[start ? 'firstChild' : 'lastChild']; 14367 } 14368 if (isText$b(out) && out.data.length === 0) { 14369 out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling; 14370 } 14371 dom.remove(node, true); 14372 return out; 14373 } else { 14374 return null; 14375 } 14376 }; 14377 const removeRngStyle = rng => { 14378 let startContainer; 14379 let endContainer; 14380 let expandedRng = expandRng(dom, rng, formatList,
vendor: 4,723 bytes, lines 14380-14489
14380{ includeTrailingSpace: rng.collapsed }); 14381 if (format.split) { 14382 expandedRng = split(expandedRng); 14383 startContainer = getContainer(ed, expandedRng, true); 14384 endContainer = getContainer(ed, expandedRng); 14385 if (startContainer !== endContainer) { 14386 startContainer = normalizeTableSelection(startContainer, true); 14387 endContainer = normalizeTableSelection(endContainer, false); 14388 if (isChildOfInlineParent(dom, startContainer, endContainer)) { 14389 const marker = Optional.from(startContainer.firstChild).getOr(startContainer); 14390 splitToFormatRoot(wrapWithSiblings(dom, marker, true, 'span', { 14391 'id': '_start', 14392 'data-mce-type': 'bookmark' 14393 })); 14394 unwrap(true); 14395 return; 14396 } 14397 if (isChildOfInlineParent(dom, endContainer, startContainer)) { 14398 const marker = Optional.from(endContainer.lastChild).getOr(endContainer); 14399 splitToFormatRoot(wrapWithSiblings(dom, marker, false, 'span', { 14400 'id': '_end', 14401 'data-mce-type': 'bookmark' 14402 })); 14403 unwrap(false); 14404 return; 14405 } 14406 startContainer = wrap$1(dom, startContainer, 'span', { 14407 'id': '_start', 14408 'data-mce-type': 'bookmark' 14409 }); 14410 endContainer = wrap$1(dom, endContainer, 'span', { 14411 'id': '_end', 14412 'data-mce-type': 'bookmark' 14413 }); 14414 const newRng = dom.createRng(); 14415 newRng.setStartAfter(startContainer); 14416 newRng.setEndBefore(endContainer); 14417 walk$3(dom, newRng, nodes => { 14418 each$e(nodes, n => { 14419 if (!isBookmarkNode$1(n) && !isBookmarkNode$1(n.parentNode)) { 14420 splitToFormatRoot(n); 14421 } 14422 }); 14423 }); 14424 splitToFormatRoot(startContainer); 14425 splitToFormatRoot(endContainer); 14426 startContainer = unwrap(true); 14427 endContainer = unwrap(); 14428 } else { 14429 startContainer = endContainer = splitToFormatRoot(startContainer); 14430 } 14431 expandedRng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer; 14432 expandedRng.startOffset = dom.nodeIndex(startContainer); 14433 expandedRng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer; 14434 expandedRng.endOffset = dom.nodeIndex(endContainer) + 1; 14435 } 14436 walk$3(dom, expandedRng, nodes => { 14437 each$e(nodes, process); 14438 }); 14439 }; 14440 if (node) { 14441 if (isNode(node)) { 14442 const rng = dom.createRng(); 14443 rng.setStartBefore(node); 14444 rng.setEndAfter(node); 14445 removeRngStyle(rng); 14446 } else { 14447 removeRngStyle(node); 14448 } 14449 fireFormatRemove(ed, name, node, vars); 14450 return; 14451 } 14452 if (!selection.isCollapsed() || !isInlineFormat(format) || getCellsFromEditor(ed).length) { 14453 preserveSelection(ed, () => runOnRanges(ed, removeRngStyle), startNode => isInlineFormat(format) && match$2(ed, name, vars, startNode)); 14454 ed.nodeChanged(); 14455 } else { 14456 removeCaretFormat(ed, name, vars, similar); 14457 } 14458 removeListStyleFormats(ed, name, vars); 14459 fireFormatRemove(ed, name, node, vars); 14460 }; 14461 const removeFormat$1 = (ed, name, vars, node, similar) => { 14462 if (node || ed.selection.isEditable()) { 14463 removeFormatInternal(ed, name, vars, node, similar); 14464 } 14465 }; 14466 const removeNodeFormat = (editor, format, vars, node, compareNode) => { 14467 return removeNodeFormatInternal(editor, format, vars, node, compareNode).fold(never, newName => { 14468 editor.dom.rename(node, newName); 14469 return true; 14470 }, always); 14471 }; 14472 14473 const each$6 = Tools.each; 14474 const mergeTextDecorationsAndColor = (dom, format, vars, node) => { 14475 const processTextDecorationsAndColor = n => { 14476 if (isHTMLElement(n) && isElement$6(n.parentNode) && dom.isEditable(n)) { 14477 const parentTextDecoration = getTextDecoration(dom, n.parentNode); 14478 if (dom.getStyle(n, 'color') && parentTextDecoration) { 14479 dom.setStyle(n, 'text-decoration', parentTextDecoration); 14480 } else if (dom.getStyle(n, 'text-decoration') === parentTextDecoration) { 14481 dom.setStyle(n, 'text-decoration', null); 14482 } 14483 } 14484 }; 14485 if (format.styles && (format.styles.color || format.styles.textDecoration)) { 14486 Tools.walk(node, processTextDecorationsAndColor, 'childNodes'); 14487 processTextDecorationsAndColor(node); 14488 } 14489 };
vendor: 10,546 bytes, lines 14490-14737
14490 const mergeBackgroundColorAndFontSize = (dom, format, vars, node) => { 14491 if (format.styles && format.styles.backgroundColor) { 14492 const hasFontSize = hasStyle(dom, 'fontSize'); 14493 processChildElements(node, elm => hasFontSize(elm) && dom.isEditable(elm), applyStyle(dom, 'backgroundColor', replaceVars(format.styles.backgroundColor, vars))); 14494 } 14495 }; 14496 const mergeSubSup = (dom, format, vars, node) => { 14497 if (isInlineFormat(format) && (format.inline === 'sub' || format.inline === 'sup')) { 14498 const hasFontSize = hasStyle(dom, 'fontSize'); 14499 processChildElements(node, elm => hasFontSize(elm) && dom.isEditable(elm), applyStyle(dom, 'fontSize', '')); 14500 const inverseTagDescendants = filter$5(dom.select(format.inline === 'sup' ? 'sub' : 'sup', node), dom.isEditable); 14501 dom.remove(inverseTagDescendants, true); 14502 } 14503 }; 14504 const mergeWithChildren = (editor, formatList, vars, node) => { 14505 each$6(formatList, format => { 14506 if (isInlineFormat(format)) { 14507 each$6(editor.dom.select(format.inline, node), child => { 14508 if (isElementNode(child)) { 14509 removeNodeFormat(editor, format, vars, child, format.exact ? child : null); 14510 } 14511 }); 14512 } 14513 clearChildStyles(editor.dom, format, node); 14514 }); 14515 }; 14516 const mergeWithParents = (editor, format, name, vars, node) => { 14517 const parentNode = node.parentNode; 14518 if (matchNode(editor, parentNode, name, vars)) { 14519 if (removeNodeFormat(editor, format, vars, node)) { 14520 return; 14521 } 14522 } 14523 if (format.merge_with_parents && parentNode) { 14524 editor.dom.getParent(parentNode, parent => { 14525 if (matchNode(editor, parent, name, vars)) { 14526 removeNodeFormat(editor, format, vars, node); 14527 return true; 14528 } else { 14529 return false; 14530 } 14531 }); 14532 } 14533 }; 14534 14535 const each$5 = Tools.each; 14536 const canFormatBR = (editor, format, node, parentName) => { 14537 if (canFormatEmptyLines(editor) && isInlineFormat(format) && node.parentNode) { 14538 const validBRParentElements = getTextRootBlockElements(editor.schema); 14539 const hasCaretNodeSibling = sibling(SugarElement.fromDom(node), sibling => isCaretNode(sibling.dom)); 14540 return hasNonNullableKey(validBRParentElements, parentName) && isEmptyNode(editor.schema, node.parentNode, { 14541 skipBogus: false, 14542 includeZwsp: true 14543 }) && !hasCaretNodeSibling; 14544 } else { 14545 return false; 14546 } 14547 }; 14548 const applyStyles = (dom, elm, format, vars) => { 14549 each$5(format.styles, (value, name) => { 14550 dom.setStyle(elm, name, replaceVars(value, vars)); 14551 }); 14552 if (format.styles) { 14553 const styleVal = dom.getAttrib(elm, 'style'); 14554 if (styleVal) { 14555 dom.setAttrib(elm, 'data-mce-style', styleVal); 14556 } 14557 } 14558 }; 14559 const applyFormatAction = (ed, name, vars, node) => { 14560 const formatList = ed.formatter.get(name); 14561 const format = formatList[0]; 14562 const isCollapsed = !node && ed.selection.isCollapsed(); 14563 const dom = ed.dom; 14564 const selection = ed.selection; 14565 const setElementFormat = (elm, fmt = format) => { 14566 if (isFunction(fmt.onformat)) { 14567 fmt.onformat(elm, fmt, vars, node); 14568 } 14569 applyStyles(dom, elm, fmt, vars); 14570 each$5(fmt.attributes, (value, name) => { 14571 dom.setAttrib(elm, name, replaceVars(value, vars)); 14572 }); 14573 each$5(fmt.classes, value => { 14574 const newValue = replaceVars(value, vars); 14575 if (!dom.hasClass(elm, newValue)) { 14576 dom.addClass(elm, newValue); 14577 } 14578 }); 14579 }; 14580 const applyNodeStyle = (formatList, node) => { 14581 let found = false; 14582 each$5(formatList, format => { 14583 if (!isSelectorFormat(format)) { 14584 return false; 14585 } 14586 if (dom.getContentEditable(node) === 'false' && !format.ceFalseOverride) { 14587 return true; 14588 } 14589 if (isNonNullable(format.collapsed) && format.collapsed !== isCollapsed) { 14590 return true; 14591 } 14592 if (dom.is(node, format.selector) && !isCaretNode(node)) { 14593 setElementFormat(node, format); 14594 found = true; 14595 return false; 14596 } 14597 return true; 14598 }); 14599 return found; 14600 }; 14601 const createWrapElement = wrapName => { 14602 if (isString(wrapName)) { 14603 const wrapElm = dom.create(wrapName); 14604 setElementFormat(wrapElm); 14605 return wrapElm; 14606 } else { 14607 return null; 14608 } 14609 }; 14610 const applyRngStyle = (dom, rng, nodeSpecific) => { 14611 const newWrappers = []; 14612 let contentEditable = true; 14613 const wrapName = format.inline || format.block; 14614 const wrapElm = createWrapElement(wrapName); 14615 const isMatchingWrappingBlock = node => isWrappingBlockFormat(format) && matchNode(ed, node, name, vars); 14616 const canRenameBlock = (node, parentName, isEditableDescendant) => { 14617 const isValidBlockFormatForNode = isNonWrappingBlockFormat(format) && isTextBlock$1(ed.schema, node) && isValid(ed, parentName, wrapName); 14618 return isEditableDescendant && isValidBlockFormatForNode; 14619 }; 14620 const canWrapNode = (node, parentName, isEditableDescendant, isWrappableNoneditableElm) => { 14621 const nodeName = node.nodeName.toLowerCase(); 14622 const isValidWrapNode = isValid(ed, wrapName, nodeName) && isValid(ed, parentName, wrapName); 14623 const isZwsp$1 = !nodeSpecific && isText$b(node) && isZwsp(node.data); 14624 const isCaret = isCaretNode(node); 14625 const isCorrectFormatForNode = !isInlineFormat(format) || !dom.isBlock(node); 14626 return (isEditableDescendant || isWrappableNoneditableElm) && isValidWrapNode && !isZwsp$1 && !isCaret && isCorrectFormatForNode; 14627 }; 14628 walk$3(dom, rng, nodes => { 14629 let currentWrapElm; 14630 const process = node => { 14631 let hasContentEditableState = false; 14632 let lastContentEditable = contentEditable; 14633 let isWrappableNoneditableElm = false; 14634 const parentNode = node.parentNode; 14635 const parentName = parentNode.nodeName.toLowerCase(); 14636 const contentEditableValue = dom.getContentEditable(node); 14637 if (isNonNullable(contentEditableValue)) { 14638 lastContentEditable = contentEditable; 14639 contentEditable = contentEditableValue === 'true'; 14640 hasContentEditableState = true; 14641 isWrappableNoneditableElm = isWrappableNoneditable(ed, node); 14642 } 14643 const isEditableDescendant = contentEditable && !hasContentEditableState; 14644 if (isBr$6(node) && !canFormatBR(ed, format, node, parentName)) { 14645 currentWrapElm = null; 14646 if (isBlockFormat(format)) { 14647 dom.remove(node); 14648 } 14649 return; 14650 } 14651 if (isMatchingWrappingBlock(node)) { 14652 currentWrapElm = null; 14653 return; 14654 } 14655 if (canRenameBlock(node, parentName, isEditableDescendant)) { 14656 const elm = dom.rename(node, wrapName); 14657 setElementFormat(elm); 14658 newWrappers.push(elm); 14659 currentWrapElm = null; 14660 return; 14661 } 14662 if (isSelectorFormat(format)) { 14663 let found = applyNodeStyle(formatList, node); 14664 if (!found && isNonNullable(parentNode) && shouldExpandToSelector(format)) { 14665 found = applyNodeStyle(formatList, parentNode); 14666 } 14667 if (!isInlineFormat(format) || found) { 14668 currentWrapElm = null; 14669 return; 14670 } 14671 } 14672 if (isNonNullable(wrapElm) && canWrapNode(node, parentName, isEditableDescendant, isWrappableNoneditableElm)) { 14673 if (!currentWrapElm) { 14674 currentWrapElm = dom.clone(wrapElm, false); 14675 parentNode.insertBefore(currentWrapElm, node); 14676 newWrappers.push(currentWrapElm); 14677 } 14678 if (isWrappableNoneditableElm && hasContentEditableState) { 14679 contentEditable = lastContentEditable; 14680 } 14681 currentWrapElm.appendChild(node); 14682 } else { 14683 currentWrapElm = null; 14684 each$e(from(node.childNodes), process); 14685 if (hasContentEditableState) { 14686 contentEditable = lastContentEditable; 14687 } 14688 currentWrapElm = null; 14689 } 14690 }; 14691 each$e(nodes, process); 14692 }); 14693 if (format.links === true) { 14694 each$e(newWrappers, node => { 14695 const process = node => { 14696 if (node.nodeName === 'A') { 14697 setElementFormat(node, format); 14698 } 14699 each$e(from(node.childNodes), process); 14700 }; 14701 process(node); 14702 }); 14703 } 14704 each$e(newWrappers, node => { 14705 const getChildCount = node => { 14706 let count = 0; 14707 each$e(node.childNodes, node => { 14708 if (!isEmptyTextNode$1(node) && !isBookmarkNode$1(node)) { 14709 count++; 14710 } 14711 }); 14712 return count; 14713 }; 14714 const mergeStyles = node => { 14715 const childElement = find$2(node.childNodes, isElementNode$1).filter(child => dom.getContentEditable(child) !== 'false' && matchName(dom, child, format)); 14716 return childElement.map(child => { 14717 const clone = dom.clone(child, false); 14718 setElementFormat(clone); 14719 dom.replace(clone, node, true); 14720 dom.remove(child, true); 14721 return clone; 14722 }).getOr(node); 14723 }; 14724 const childCount = getChildCount(node); 14725 if ((newWrappers.length > 1 || !dom.isBlock(node)) && childCount === 0) { 14726 dom.remove(node, true); 14727 return; 14728 } 14729 if (isInlineFormat(format) || isBlockFormat(format) && format.wrapper) { 14730 if (!format.exact && childCount === 1) { 14731 node = mergeStyles(node); 14732 } 14733 mergeWithChildren(ed, formatList, vars, node); 14734 mergeWithParents(ed, format, name, vars, node); 14735 mergeBackgroundColorAndFontSize(dom, format, vars, node); 14736 mergeTextDecorationsAndColor(dom, format, vars, node); 14737 mergeSubSup(dom
vendor: 10,930 bytes, lines 14737-15036
14737, format, vars, node); 14738 mergeSiblings(ed, format, vars, node); 14739 } 14740 }); 14741 }; 14742 const targetNode = isNode(node) ? node : selection.getNode(); 14743 if (dom.getContentEditable(targetNode) === 'false' && !isWrappableNoneditable(ed, targetNode)) { 14744 node = targetNode; 14745 applyNodeStyle(formatList, node); 14746 fireFormatApply(ed, name, node, vars); 14747 return; 14748 } 14749 if (format) { 14750 if (node) { 14751 if (isNode(node)) { 14752 if (!applyNodeStyle(formatList, node)) { 14753 const rng = dom.createRng(); 14754 rng.setStartBefore(node); 14755 rng.setEndAfter(node); 14756 applyRngStyle(dom, expandRng(dom, rng, formatList), true); 14757 } 14758 } else { 14759 applyRngStyle(dom, node, true); 14760 } 14761 } else { 14762 if (!isCollapsed || !isInlineFormat(format) || getCellsFromEditor(ed).length) { 14763 selection.setRng(normalize(selection.getRng())); 14764 preserveSelection(ed, () => { 14765 runOnRanges(ed, (selectionRng, fake) => { 14766 const expandedRng = fake ? selectionRng : expandRng(dom, selectionRng, formatList); 14767 applyRngStyle(dom, expandedRng, false); 14768 }); 14769 }, always); 14770 ed.nodeChanged(); 14771 } else { 14772 applyCaretFormat(ed, name, vars); 14773 } 14774 getExpandedListItemFormat(ed.formatter, name).each(liFmt => { 14775 each$e(getFullySelectedListItems(ed.selection), li => applyStyles(dom, li, liFmt, vars)); 14776 }); 14777 } 14778 postProcess$1(name, ed); 14779 } 14780 fireFormatApply(ed, name, node, vars); 14781 }; 14782 const applyFormat$1 = (editor, name, vars, node) => { 14783 if (node || editor.selection.isEditable()) { 14784 applyFormatAction(editor, name, vars, node); 14785 } 14786 }; 14787 14788 const hasVars = value => has$2(value, 'vars'); 14789 const setup$u = (registeredFormatListeners, editor) => { 14790 registeredFormatListeners.set({}); 14791 editor.on('NodeChange', e => { 14792 updateAndFireChangeCallbacks(editor, e.element, registeredFormatListeners.get()); 14793 }); 14794 editor.on('FormatApply FormatRemove', e => { 14795 const element = Optional.from(e.node).map(nodeOrRange => isNode(nodeOrRange) ? nodeOrRange : nodeOrRange.startContainer).bind(node => isElement$6(node) ? Optional.some(node) : Optional.from(node.parentElement)).getOrThunk(() => fallbackElement(editor)); 14796 updateAndFireChangeCallbacks(editor, element, registeredFormatListeners.get()); 14797 }); 14798 }; 14799 const fallbackElement = editor => editor.selection.getStart(); 14800 const matchingNode = (editor, parents, format, similar, vars) => { 14801 const isMatchingNode = node => { 14802 const matchingFormat = editor.formatter.matchNode(node, format, vars !== null && vars !== void 0 ? vars : {}, similar); 14803 return !isUndefined(matchingFormat); 14804 }; 14805 const isUnableToMatch = node => { 14806 if (matchesUnInheritedFormatSelector(editor, node, format)) { 14807 return true; 14808 } else { 14809 if (!similar) { 14810 return isNonNullable(editor.formatter.matchNode(node, format, vars, true)); 14811 } else { 14812 return false; 14813 } 14814 } 14815 }; 14816 return findUntil$1(parents, isMatchingNode, isUnableToMatch); 14817 }; 14818 const getParents = (editor, elm) => { 14819 const element = elm !== null && elm !== void 0 ? elm : fallbackElement(editor); 14820 return filter$5(getParents$2(editor.dom, element), node => isElement$6(node) && !isBogus$1(node)); 14821 }; 14822 const updateAndFireChangeCallbacks = (editor, elm, registeredCallbacks) => { 14823 const parents = getParents(editor, elm); 14824 each$d(registeredCallbacks, (data, format) => { 14825 const runIfChanged = spec => { 14826 const match = matchingNode(editor, parents, format, spec.similar, hasVars(spec) ? spec.vars : undefined); 14827 const isSet = match.isSome(); 14828 if (spec.state.get() !== isSet) { 14829 spec.state.set(isSet); 14830 const node = match.getOr(elm); 14831 if (hasVars(spec)) { 14832 spec.callback(isSet, { 14833 node, 14834 format, 14835 parents 14836 }); 14837 } else { 14838 each$e(spec.callbacks, callback => callback(isSet, { 14839 node, 14840 format, 14841 parents 14842 })); 14843 } 14844 } 14845 }; 14846 each$e([ 14847 data.withSimilar, 14848 data.withoutSimilar 14849 ], runIfChanged); 14850 each$e(data.withVars, runIfChanged); 14851 }); 14852 }; 14853 const addListeners = (editor, registeredFormatListeners, formats, callback, similar, vars) => { 14854 const formatChangeItems = registeredFormatListeners.get(); 14855 each$e(formats.split(','), format => { 14856 const group = get$a(formatChangeItems, format).getOrThunk(() => { 14857 const base = { 14858 withSimilar: { 14859 state: Cell(false), 14860 similar: true, 14861 callbacks: [] 14862 }, 14863 withoutSimilar: { 14864 state: Cell(false), 14865 similar: false, 14866 callbacks: [] 14867 }, 14868 withVars: [] 14869 }; 14870 formatChangeItems[format] = base; 14871 return base; 14872 }); 14873 const getCurrent = () => { 14874 const parents = getParents(editor); 14875 return matchingNode(editor, parents, format, similar, vars).isSome(); 14876 }; 14877 if (isUndefined(vars)) { 14878 const toAppendTo = similar ? group.withSimilar : group.withoutSimilar; 14879 toAppendTo.callbacks.push(callback); 14880 if (toAppendTo.callbacks.length === 1) { 14881 toAppendTo.state.set(getCurrent()); 14882 } 14883 } else { 14884 group.withVars.push({ 14885 state: Cell(getCurrent()), 14886 similar, 14887 vars, 14888 callback 14889 }); 14890 } 14891 }); 14892 registeredFormatListeners.set(formatChangeItems); 14893 }; 14894 const removeListeners = (registeredFormatListeners, formats, callback) => { 14895 const formatChangeItems = registeredFormatListeners.get(); 14896 each$e(formats.split(','), format => get$a(formatChangeItems, format).each(group => { 14897 formatChangeItems[format] = { 14898 withSimilar: { 14899 ...group.withSimilar, 14900 callbacks: filter$5(group.withSimilar.callbacks, cb => cb !== callback) 14901 }, 14902 withoutSimilar: { 14903 ...group.withoutSimilar, 14904 callbacks: filter$5(group.withoutSimilar.callbacks, cb => cb !== callback) 14905 }, 14906 withVars: filter$5(group.withVars, item => item.callback !== callback) 14907 }; 14908 })); 14909 registeredFormatListeners.set(formatChangeItems); 14910 }; 14911 const formatChangedInternal = (editor, registeredFormatListeners, formats, callback, similar, vars) => { 14912 addListeners(editor, registeredFormatListeners, formats, callback, similar, vars); 14913 return { unbind: () => removeListeners(registeredFormatListeners, formats, callback) }; 14914 }; 14915 14916 const toggle = (editor, name, vars, node) => { 14917 const fmt = editor.formatter.get(name); 14918 if (fmt) { 14919 if (match$2(editor, name, vars, node) && (!('toggle' in fmt[0]) || fmt[0].toggle)) { 14920 removeFormat$1(editor, name, vars, node); 14921 } else { 14922 applyFormat$1(editor, name, vars, node); 14923 } 14924 } 14925 }; 14926 14927 const explode$1 = Tools.explode; 14928 const create$8 = () => { 14929 const filters = {}; 14930 const addFilter = (name, callback) => { 14931 each$e(explode$1(name), name => { 14932 if (!has$2(filters, name)) { 14933 filters[name] = { 14934 name, 14935 callbacks: [] 14936 }; 14937 } 14938 filters[name].callbacks.push(callback); 14939 }); 14940 }; 14941 const getFilters = () => values(filters); 14942 const removeFilter = (name, callback) => { 14943 each$e(explode$1(name), name => { 14944 if (has$2(filters, name)) { 14945 if (isNonNullable(callback)) { 14946 const filter = filters[name]; 14947 const newCallbacks = filter$5(filter.callbacks, c => c !== callback); 14948 if (newCallbacks.length > 0) { 14949 filter.callbacks = newCallbacks; 14950 } else { 14951 delete filters[name]; 14952 } 14953 } else { 14954 delete filters[name]; 14955 } 14956 } 14957 }); 14958 }; 14959 return { 14960 addFilter, 14961 getFilters, 14962 removeFilter 14963 }; 14964 }; 14965 14966 const removeAttrs = (node, names) => { 14967 each$e(names, name => { 14968 node.attr(name, null); 14969 }); 14970 }; 14971 const addFontToSpansFilter = (domParser, styles, fontSizes) => { 14972 domParser.addNodeFilter('font', nodes => { 14973 each$e(nodes, node => { 14974 const props = styles.parse(node.attr('style')); 14975 const color = node.attr('color'); 14976 const face = node.attr('face'); 14977 const size = node.attr('size'); 14978 if (color) { 14979 props.color = color; 14980 } 14981 if (face) { 14982 props['font-family'] = face; 14983 } 14984 if (size) { 14985 toInt(size).each(num => { 14986 props['font-size'] = fontSizes[num - 1]; 14987 }); 14988 } 14989 node.name = 'span'; 14990 node.attr('style', styles.serialize(props)); 14991 removeAttrs(node, [ 14992 'color', 14993 'face', 14994 'size' 14995 ]); 14996 }); 14997 }); 14998 }; 14999 const addStrikeFilter = (domParser, schema, styles) => { 15000 domParser.addNodeFilter('strike', nodes => { 15001 const convertToSTag = schema.type !== 'html4'; 15002 each$e(nodes, node => { 15003 if (convertToSTag) { 15004 node.name = 's'; 15005 } else { 15006 const props = styles.parse(node.attr('style')); 15007 props['text-decoration'] = 'line-through'; 15008 node.name = 'span'; 15009 node.attr('style', styles.serialize(props)); 15010 } 15011 }); 15012 }); 15013 }; 15014 const addFilters = (domParser, settings, schema) => { 15015 var _a; 15016 const styles = Styles(); 15017 if (settings.convert_fonts_to_spans) { 15018 addFontToSpansFilter(domParser, styles, Tools.explode((_a = settings.font_size_legacy_values) !== null && _a !== void 0 ? _a : '')); 15019 } 15020 addStrikeFilter(domParser, schema, styles); 15021 }; 15022 const register$5 = (domParser, settings, schema) => { 15023 if (settings.inline_styles) { 15024 addFilters(domParser, settings, schema); 15025 } 15026 }; 15027 15028 const blobUriToBlob = url => fetch(url).then(res => res.ok ? res.blob() : Promise.reject()).catch(() => Promise.reject({ 15029 message: `Cannot convert ${ url } to Blob. Resource might not exist or is inaccessible.`, 15030 uriType: 'blob' 15031 })); 15032 const extractBase64Data = data => { 15033 const matches = /([a-z0-9+\/=\s]+)/i.exec(data); 15034 return matches ? matches[1] : ''; 15035 }; 15036 const
vendor: 885 bytes, lines 15036-15065
15036decodeData = data => { 15037 try { 15038 return decodeURIComponent(data); 15039 } catch (_a) { 15040 return data; 15041 } 15042 }; 15043 const parseDataUri = uri => { 15044 const [type, ...rest] = uri.split(','); 15045 const data = rest.join(','); 15046 const matches = /data:([^/]+\/[^;]+)(;.+)?/.exec(type); 15047 if (matches) { 15048 const base64Encoded = matches[2] === ';base64'; 15049 const decodedData = decodeData(data); 15050 const extractedData = base64Encoded ? extractBase64Data(decodedData) : decodedData; 15051 return Optional.some({ 15052 type: matches[1], 15053 data: extractedData, 15054 base64Encoded 15055 }); 15056 } else { 15057 return Optional.none(); 15058 } 15059 }; 15060 const buildBlob = (type, data, base64Encoded = true) => { 15061 let str = data; 15062 if (base64Encoded) { 15063 try { 15064 str = atob(data); 15065 } catch (_a
vendor: 9,846 bytes, lines 15065-15317
15065) { 15066 return Optional.none(); 15067 } 15068 } 15069 const arr = new Uint8Array(str.length); 15070 for (let i = 0; i < arr.length; i++) { 15071 arr[i] = str.charCodeAt(i); 15072 } 15073 return Optional.some(new Blob([arr], { type })); 15074 }; 15075 const dataUriToBlob = uri => { 15076 return new Promise((resolve, reject) => { 15077 parseDataUri(uri).bind(({type, data, base64Encoded}) => buildBlob(type, data, base64Encoded)).fold(() => reject('Invalid data URI'), resolve); 15078 }); 15079 }; 15080 const uriToBlob = url => { 15081 if (startsWith(url, 'blob:')) { 15082 return blobUriToBlob(url); 15083 } else if (startsWith(url, 'data:')) { 15084 return dataUriToBlob(url); 15085 } else { 15086 return Promise.reject('Unknown URI format'); 15087 } 15088 }; 15089 const blobToDataUri = blob => { 15090 return new Promise((resolve, reject) => { 15091 const reader = new FileReader(); 15092 reader.onloadend = () => { 15093 resolve(reader.result); 15094 }; 15095 reader.onerror = () => { 15096 var _a; 15097 reject((_a = reader.error) === null || _a === void 0 ? void 0 : _a.message); 15098 }; 15099 reader.readAsDataURL(blob); 15100 }); 15101 }; 15102 15103 let count$1 = 0; 15104 const uniqueId$1 = prefix => { 15105 return (prefix || 'blobid') + count$1++; 15106 }; 15107 const processDataUri = (dataUri, base64Only, generateBlobInfo) => { 15108 return parseDataUri(dataUri).bind(({data, type, base64Encoded}) => { 15109 if (base64Only && !base64Encoded) { 15110 return Optional.none(); 15111 } else { 15112 const base64 = base64Encoded ? data : btoa(data); 15113 return generateBlobInfo(base64, type); 15114 } 15115 }); 15116 }; 15117 const createBlobInfo$1 = (blobCache, blob, base64) => { 15118 const blobInfo = blobCache.create(uniqueId$1(), blob, base64); 15119 blobCache.add(blobInfo); 15120 return blobInfo; 15121 }; 15122 const dataUriToBlobInfo = (blobCache, dataUri, base64Only = false) => { 15123 return processDataUri(dataUri, base64Only, (base64, type) => Optional.from(blobCache.getByData(base64, type)).orThunk(() => buildBlob(type, base64).map(blob => createBlobInfo$1(blobCache, blob, base64)))); 15124 }; 15125 const imageToBlobInfo = (blobCache, imageSrc) => { 15126 const invalidDataUri = () => Promise.reject('Invalid data URI'); 15127 if (startsWith(imageSrc, 'blob:')) { 15128 const blobInfo = blobCache.getByUri(imageSrc); 15129 if (isNonNullable(blobInfo)) { 15130 return Promise.resolve(blobInfo); 15131 } else { 15132 return uriToBlob(imageSrc).then(blob => { 15133 return blobToDataUri(blob).then(dataUri => { 15134 return processDataUri(dataUri, false, base64 => { 15135 return Optional.some(createBlobInfo$1(blobCache, blob, base64)); 15136 }).getOrThunk(invalidDataUri); 15137 }); 15138 }); 15139 } 15140 } else if (startsWith(imageSrc, 'data:')) { 15141 return dataUriToBlobInfo(blobCache, imageSrc).fold(invalidDataUri, blobInfo => Promise.resolve(blobInfo)); 15142 } else { 15143 return Promise.reject('Unknown image data format'); 15144 } 15145 }; 15146 15147 const hostCaptureRegex = /^(?:(?:(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)([A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*))(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+)?)?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+)?)?)$/; 15148 const extractHost = url => Optional.from(url.match(hostCaptureRegex)).bind(ms => get$b(ms, 1)).map(h => startsWith(h, 'www.') ? h.substring(4) : h); 15149 15150 const sandboxIframe = (iframeNode, exclusions) => { 15151 if (Optional.from(iframeNode.attr('src')).bind(extractHost).forall(host => !contains$2(exclusions, host))) { 15152 iframeNode.attr('sandbox', ''); 15153 } 15154 }; 15155 const isMimeType = (mime, type) => startsWith(mime, `${ type }/`); 15156 const getEmbedType = type => { 15157 if (isUndefined(type)) { 15158 return 'iframe'; 15159 } else if (isMimeType(type, 'image')) { 15160 return 'img'; 15161 } else if (isMimeType(type, 'video')) { 15162 return 'video'; 15163 } else if (isMimeType(type, 'audio')) { 15164 return 'audio'; 15165 } else { 15166 return 'iframe'; 15167 } 15168 }; 15169 const createSafeEmbed = ({type, src, width, height} = {}, sandboxIframes, sandboxIframesExclusions) => { 15170 const name = getEmbedType(type); 15171 const embed = new AstNode(name, 1); 15172 embed.attr(name === 'audio' ? { src } : { 15173 src, 15174 width, 15175 height 15176 }); 15177 if (name === 'audio' || name === 'video') { 15178 embed.attr('controls', ''); 15179 } 15180 if (name === 'iframe' && sandboxIframes) { 15181 sandboxIframe(embed, sandboxIframesExclusions); 15182 } 15183 return embed; 15184 }; 15185 15186 const isBogusImage = img => isNonNullable(img.attr('data-mce-bogus')); 15187 const isInternalImageSource = img => img.attr('src') === Env.transparentSrc || isNonNullable(img.attr('data-mce-placeholder')); 15188 const registerBase64ImageFilter = (parser, settings) => { 15189 const {blob_cache: blobCache} = settings; 15190 if (blobCache) { 15191 const processImage = img => { 15192 const inputSrc = img.attr('src'); 15193 if (isInternalImageSource(img) || isBogusImage(img) || isNullable(inputSrc)) { 15194 return; 15195 } 15196 dataUriToBlobInfo(blobCache, inputSrc, true).each(blobInfo => { 15197 img.attr('src', blobInfo.blobUri()); 15198 }); 15199 }; 15200 parser.addAttributeFilter('src', nodes => each$e(nodes, processImage)); 15201 } 15202 }; 15203 const register$4 = (parser, settings) => { 15204 var _a, _b; 15205 const schema = parser.schema; 15206 parser.addAttributeFilter('href', nodes => { 15207 let i = nodes.length; 15208 const appendRel = rel => { 15209 const parts = rel.split(' ').filter(p => p.length > 0); 15210 return parts.concat(['noopener']).sort().join(' '); 15211 }; 15212 const addNoOpener = rel => { 15213 const newRel = rel ? Tools.trim(rel) : ''; 15214 if (!/\b(noopener)\b/g.test(newRel)) { 15215 return appendRel(newRel); 15216 } else { 15217 return newRel; 15218 } 15219 }; 15220 if (!settings.allow_unsafe_link_target) { 15221 while (i--) { 15222 const node = nodes[i]; 15223 if (node.name === 'a' && node.attr('target') === '_blank') { 15224 node.attr('rel', addNoOpener(node.attr('rel'))); 15225 } 15226 } 15227 } 15228 }); 15229 if (!settings.allow_html_in_named_anchor) { 15230 parser.addAttributeFilter('id,name', nodes => { 15231 let i = nodes.length, sibling, prevSibling, parent, node; 15232 while (i--) { 15233 node = nodes[i]; 15234 if (node.name === 'a' && node.firstChild && !node.attr('href')) { 15235 parent = node.parent; 15236 sibling = node.lastChild; 15237 while (sibling && parent) { 15238 prevSibling = sibling.prev; 15239 parent.insert(sibling, node); 15240 sibling = prevSibling; 15241 } 15242 } 15243 } 15244 }); 15245 } 15246 if (settings.fix_list_elements) { 15247 parser.addNodeFilter('ul,ol', nodes => { 15248 let i = nodes.length, node, parentNode; 15249 while (i--) { 15250 node = nodes[i]; 15251 parentNode = node.parent; 15252 if (parentNode && (parentNode.name === 'ul' || parentNode.name === 'ol')) { 15253 if (node.prev && node.prev.name === 'li') { 15254 node.prev.append(node); 15255 } else { 15256 const li = new AstNode('li', 1); 15257 li.attr('style', 'list-style-type: none'); 15258 node.wrap(li); 15259 } 15260 } 15261 } 15262 }); 15263 } 15264 const validClasses = schema.getValidClasses(); 15265 if (settings.validate && validClasses) { 15266 parser.addAttributeFilter('class', nodes => { 15267 var _a; 15268 let i = nodes.length; 15269 while (i--) { 15270 const node = nodes[i]; 15271 const clazz = (_a = node.attr('class')) !== null && _a !== void 0 ? _a : ''; 15272 const classList = Tools.explode(clazz, ' '); 15273 let classValue = ''; 15274 for (let ci = 0; ci < classList.length; ci++) { 15275 const className = classList[ci]; 15276 let valid = false; 15277 let validClassesMap = validClasses['*']; 15278 if (validClassesMap && validClassesMap[className]) { 15279 valid = true; 15280 } 15281 validClassesMap = validClasses[node.name]; 15282 if (!valid && validClassesMap && validClassesMap[className]) { 15283 valid = true; 15284 } 15285 if (valid) { 15286 if (classValue) { 15287 classValue += ' '; 15288 } 15289 classValue += className; 15290 } 15291 } 15292 if (!classValue.length) { 15293 classValue = null; 15294 } 15295 node.attr('class', classValue); 15296 } 15297 }); 15298 } 15299 registerBase64ImageFilter(parser, settings); 15300 const shouldSandboxIframes = (_a = settings.sandbox_iframes) !== null && _a !== void 0 ? _a : false; 15301 const sandboxIframesExclusions = unique$1((_b = settings.sandbox_iframes_exclusions) !== null && _b !== void 0 ? _b : []); 15302 if (settings.convert_unsafe_embeds) { 15303 parser.addNodeFilter('object,embed', nodes => each$e(nodes, node => { 15304 node.replace(createSafeEmbed({ 15305 type: node.attr('type'), 15306 src: node.name === 'object' ? node.attr('data') : node.attr('src'), 15307 width: node.attr('width'), 15308 height: node.attr('height') 15309 }, shouldSandboxIframes, sandboxIframesExclusions)); 15310 })); 15311 } 15312 if (shouldSandboxIframes) { 15313 parser.addNodeFilter('iframe', nodes => each$e(nodes, node => sandboxIframe(node, sandboxIframesExclusions))); 15314 } 15315 }; 15316 15317 /*! @license DOMPurify 3.
153172.4 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.4/LICENSE */ 15318 15319 const { 15320 entries, 15321 setPrototypeOf, 15322 isFrozen, 15323 getPrototypeOf, 15324 getOwnPropertyDescriptor 15325 } = Object; 15326 let { 15327 freeze, 15328 seal, 15329 create: create$7 15330 } = Object; // eslint-disable-line import/no-mutable-exports 15331 let { 15332 apply, 15333 construct 15334 } = typeof Reflect !== 'undefined' && Reflect; 15335 if (!freeze) { 15336 freeze = function freeze(x) { 15337 return x; 15338 }; 15339 } 15340 if (!seal) { 15341 seal = function seal(x) { 15342 return x; 15343 }; 15344 } 15345 if (!apply) { 15346 apply = function apply(fun, thisValue, args) { 15347 return fun.apply(thisValue, args); 15348 }; 15349 } 15350 if (!construct) { 15351 construct = function construct(Func, args) { 15352 return new Func(...args); 15353 }; 15354 } 15355 const arrayForEach = unapply(Array.prototype.forEach); 15356 const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf); 15357 const arrayPop = unapply(Array.prototype.pop); 15358 const arrayPush = unapply(Array.prototype.push); 15359 const arraySplice = unapply(Array.prototype.splice); 15360 const stringToLowerCase = unapply(String.prototype.toLowerCase); 15361 const stringToString = unapply(String.prototype.toString); 15362 const stringMatch = unapply(String.prototype.match); 15363 const stringReplace = unapply(String.prototype.replace); 15364 const stringIndexOf = unapply(String.prototype.indexOf); 15365 const stringTrim = unapply(String.prototype.trim); 15366 const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty); 15367 const regExpTest = unapply(RegExp.prototype.test); 15368 const typeErrorCreate = unconstruct(TypeError); 15369 /** 15370 * Creates a new function that calls the given function with a specified thisArg and arguments. 15371 * 15372 * @param func - The function to be wrapped and called. 15373 * @returns A new function that calls the given function with a specified thisArg and arguments. 15374 */ 15375 function unapply(func) { 15376 return function (thisArg) { 15377 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 15378 args[_key - 1] = arguments[_key]; 15379 } 15380 return apply(func, thisArg, args); 15381 }; 15382 } 15383 /** 15384 * Creates a new function that constructs an instance of the given constructor function with the provided arguments. 15385 * 15386 * @param func - The constructor function to be wrapped and called. 15387 * @returns A new function that constructs an instance of the given constructor function with the provided arguments. 15388 */ 15389 function unconstruct(func) { 15390 return function () { 15391 for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 15392 args[_key2] = arguments[_key2]; 15393 } 15394 return construct(func, args); 15395 }; 15396 } 15397 /** 15398 * Add properties to a lookup table 15399 * 15400 * @param set - The set to which elements will be added. 15401 * @param array - The array containing elements to be added to the set. 15402 * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set. 15403 * @returns The modified set with added elements. 15404 */ 15405 function addToSet(set, array) {
vendor: 6,003 bytes, lines 15406-15504
15406 let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase; 15407 if (setPrototypeOf) { 15408 // Make 'in' and truthy checks like Boolean(set.constructor) 15409 // independent of any properties defined on Object.prototype. 15410 // Prevent prototype setters from intercepting set as a this value. 15411 setPrototypeOf(set, null); 15412 } 15413 let l = array.length; 15414 while (l--) { 15415 let element = array[l]; 15416 if (typeof element === 'string') { 15417 const lcElement = transformCaseFunc(element); 15418 if (lcElement !== element) { 15419 // Config presets (e.g. tags.js, attrs.js) are immutable. 15420 if (!isFrozen(array)) { 15421 array[l] = lcElement; 15422 } 15423 element = lcElement; 15424 } 15425 } 15426 set[element] = true; 15427 } 15428 return set; 15429 } 15430 /** 15431 * Clean up an array to harden against CSPP 15432 * 15433 * @param array - The array to be cleaned. 15434 * @returns The cleaned version of the array 15435 */ 15436 function cleanArray(array) { 15437 for (let index = 0; index < array.length; index++) { 15438 const isPropertyExist = objectHasOwnProperty(array, index); 15439 if (!isPropertyExist) { 15440 array[index] = null; 15441 } 15442 } 15443 return array; 15444 } 15445 /** 15446 * Shallow clone an object 15447 * 15448 * @param object - The object to be cloned. 15449 * @returns A new object that copies the original. 15450 */ 15451 function clone(object) { 15452 const newObject = create$7(null); 15453 for (const [property, value] of entries(object)) { 15454 const isPropertyExist = objectHasOwnProperty(object, property); 15455 if (isPropertyExist) { 15456 if (Array.isArray(value)) { 15457 newObject[property] = cleanArray(value); 15458 } else if (value && typeof value === 'object' && value.constructor === Object) { 15459 newObject[property] = clone(value); 15460 } else { 15461 newObject[property] = value; 15462 } 15463 } 15464 } 15465 return newObject; 15466 } 15467 /** 15468 * This method automatically checks if the prop is function or getter and behaves accordingly. 15469 * 15470 * @param object - The object to look up the getter function in its prototype chain. 15471 * @param prop - The property name for which to find the getter function. 15472 * @returns The getter function found in the prototype chain or a fallback function. 15473 */ 15474 function lookupGetter(object, prop) { 15475 while (object !== null) { 15476 const desc = getOwnPropertyDescriptor(object, prop); 15477 if (desc) { 15478 if (desc.get) { 15479 return unapply(desc.get); 15480 } 15481 if (typeof desc.value === 'function') { 15482 return unapply(desc.value); 15483 } 15484 } 15485 object = getPrototypeOf(object); 15486 } 15487 function fallbackValue() { 15488 return null; 15489 } 15490 return fallbackValue; 15491 } 15492 15493 const 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', 'section', 'select', 'shadow', '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']); 15494 const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']); 15495 const 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']); 15496 // List of SVG elements that are disallowed by default. 15497 // We still need to know them so that we can do namespace 15498 // checks properly in case one wants to add them to 15499 // allow-list. 15500 const 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']); 15501 const 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']); 15502 // Similarly to SVG, we want to know all MathML elements, 15503 // even those that we disallow by default. 15504 const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'n
15504one']); 15505 const text = freeze(['#text']); 15506 15507 const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', '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', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']); 15508 const 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', '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', '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-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']); 15509 const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', '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']); 15510 const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']); 15511 15512 // eslint-disable-next-line unicorn/better-regex 15513 const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode 15514 const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm); 15515 const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex 15516 const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape 15517 const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
vendor: 4,106 bytes, lines 15518-15620
15518 const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape 15519 ); 15520 const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i); 15521 const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex 15522 ); 15523 const DOCTYPE_NAME = seal(/^html$/i); 15524 const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i); 15525 15526 var EXPRESSIONS = /*#__PURE__*/Object.freeze({ 15527 __proto__: null, 15528 ARIA_ATTR: ARIA_ATTR, 15529 ATTR_WHITESPACE: ATTR_WHITESPACE, 15530 CUSTOM_ELEMENT: CUSTOM_ELEMENT, 15531 DATA_ATTR: DATA_ATTR, 15532 DOCTYPE_NAME: DOCTYPE_NAME, 15533 ERB_EXPR: ERB_EXPR, 15534 IS_ALLOWED_URI: IS_ALLOWED_URI, 15535 IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA, 15536 MUSTACHE_EXPR: MUSTACHE_EXPR, 15537 TMPLIT_EXPR: TMPLIT_EXPR 15538 }); 15539 15540 /* eslint-disable @typescript-eslint/indent */ 15541 // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType 15542 const NODE_TYPE = { 15543 element: 1, 15544 attribute: 2, 15545 text: 3, 15546 cdataSection: 4, 15547 entityReference: 5, 15548 // Deprecated 15549 entityNode: 6, 15550 // Deprecated 15551 progressingInstruction: 7, 15552 comment: 8, 15553 document: 9, 15554 documentType: 10, 15555 documentFragment: 11, 15556 notation: 12 // Deprecated 15557 }; 15558 const getGlobal = function getGlobal() { 15559 return typeof window === 'undefined' ? null : window; 15560 }; 15561 /** 15562 * Creates a no-op policy for internal use only. 15563 * Don't export this function outside this module! 15564 * @param trustedTypes The policy factory. 15565 * @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix). 15566 * @return The policy created (or null, if Trusted Types 15567 * are not supported or creating the policy failed). 15568 */ 15569 const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) { 15570 if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') { 15571 return null; 15572 } 15573 // Allow the callers to control the unique policy name 15574 // by adding a data-tt-policy-suffix to the script element with the DOMPurify. 15575 // Policy creation with duplicate names throws in Trusted Types. 15576 let suffix = null; 15577 const ATTR_NAME = 'data-tt-policy-suffix'; 15578 if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) { 15579 suffix = purifyHostElement.getAttribute(ATTR_NAME); 15580 } 15581 const policyName = 'dompurify' + (suffix ? '#' + suffix : ''); 15582 try { 15583 return trustedTypes.createPolicy(policyName, { 15584 createHTML(html) { 15585 return html; 15586 }, 15587 createScriptURL(scriptUrl) { 15588 return scriptUrl; 15589 } 15590 }); 15591 } catch (_) { 15592 // Policy creation failed (most likely another DOMPurify script has 15593 // already run). Skip creating the policy, as this will only cause errors 15594 // if TT are enforced. 15595 console.warn('TrustedTypes policy ' + policyName + ' could not be created.'); 15596 return null; 15597 } 15598 }; 15599 const _createHooksMap = function _createHooksMap() { 15600 return { 15601 afterSanitizeAttributes: [], 15602 afterSanitizeElements: [], 15603 afterSanitizeShadowDOM: [], 15604 beforeSanitizeAttributes: [], 15605 beforeSanitizeElements: [], 15606 beforeSanitizeShadowDOM: [], 15607 uponSanitizeAttribute: [], 15608 uponSanitizeElement: [], 15609 uponSanitizeShadowNode: [] 15610 }; 15611 }; 15612 function createDOMPurify() { 15613 let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal(); 15614 const DOMPurify = root => createDOMPurify(root); 15615 DOMPurify.version = '3.2.4'; 15616 DOMPurify.removed = []; 15617 if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) { 15618 // Not running in a browser, provide a factory function 15619 // so that you can pass your own Window 15620 DOMPurify.isSupported = false;
vendor: 4,492 bytes, lines 15621-15731
15621 return DOMPurify; 15622 } 15623 let { 15624 document 15625 } = window; 15626 const originalDocument = document; 15627 const currentScript = originalDocument.currentScript; 15628 const { 15629 DocumentFragment, 15630 HTMLTemplateElement, 15631 Node, 15632 Element, 15633 NodeFilter, 15634 NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap, 15635 HTMLFormElement, 15636 DOMParser, 15637 trustedTypes 15638 } = window; 15639 const ElementPrototype = Element.prototype; 15640 const cloneNode = lookupGetter(ElementPrototype, 'cloneNode'); 15641 const remove = lookupGetter(ElementPrototype, 'remove'); 15642 const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling'); 15643 const getChildNodes = lookupGetter(ElementPrototype, 'childNodes'); 15644 const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); 15645 // As per issue #47, the web-components registry is inherited by a 15646 // new document created via createHTMLDocument. As per the spec 15647 // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries) 15648 // a new empty registry is used when creating a template contents owner 15649 // document, so we use that as our parent document to ensure nothing 15650 // is inherited. 15651 if (typeof HTMLTemplateElement === 'function') { 15652 const template = document.createElement('template'); 15653 if (template.content && template.content.ownerDocument) { 15654 document = template.content.ownerDocument; 15655 } 15656 } 15657 let trustedTypesPolicy; 15658 let emptyHTML = ''; 15659 const { 15660 implementation, 15661 createNodeIterator, 15662 createDocumentFragment, 15663 getElementsByTagName 15664 } = document; 15665 const { 15666 importNode 15667 } = originalDocument; 15668 let hooks = _createHooksMap(); 15669 /** 15670 * Expose whether this browser supports running the full DOMPurify. 15671 */ 15672 DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined; 15673 const { 15674 MUSTACHE_EXPR, 15675 ERB_EXPR, 15676 TMPLIT_EXPR, 15677 DATA_ATTR, 15678 ARIA_ATTR, 15679 IS_SCRIPT_OR_DATA, 15680 ATTR_WHITESPACE, 15681 CUSTOM_ELEMENT 15682 } = EXPRESSIONS; 15683 let { 15684 IS_ALLOWED_URI: IS_ALLOWED_URI$1 15685 } = EXPRESSIONS; 15686 /** 15687 * We consider the elements and attributes below to be safe. Ideally 15688 * don't add any new ones but feel free to remove unwanted ones. 15689 */ 15690 /* allowed element names */ 15691 let ALLOWED_TAGS = null; 15692 const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]); 15693 /* Allowed attribute names */ 15694 let ALLOWED_ATTR = null; 15695 const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]); 15696 /* 15697 * Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements. 15698 * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements) 15699 * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list) 15700 * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`. 15701 */ 15702 let CUSTOM_ELEMENT_HANDLING = Object.seal(create$7(null, { 15703 tagNameCheck: { 15704 writable: true, 15705 configurable: false, 15706 enumerable: true, 15707 value: null 15708 }, 15709 attributeNameCheck: { 15710 writable: true, 15711 configurable: false, 15712 enumerable: true, 15713 value: null 15714 }, 15715 allowCustomizedBuiltInElements: { 15716 writable: true, 15717 configurable: false, 15718 enumerable: true, 15719 value: false 15720 } 15721 })); 15722 /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */ 15723 let FORBID_TAGS = null; 15724 /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */ 15725 let FORBID_ATTR = null; 15726 /* Decide if ARIA attributes are okay */ 15727 let ALLOW_ARIA_ATTR = true; 15728 /* Decide if custom data attributes are okay */ 15729 let ALLOW_DATA_ATTR = true; 15730 /* Decide if unknown protocols are okay */ 15731 let ALLOW_UNKNOWN_PROTOCOLS = false;
15732 /* Decide if self-closing tags in attributes are allowed. 15733 * Usually removed due to a mXSS issue in jQuery 3.0 */ 15734 let ALLOW_SELF_CLOSE_IN_ATTR = true; 15735 /* Output should be safe for common template engines. 15736 * This means, DOMPurify removes data attributes, mustaches and ERB 15737 */ 15738 let SAFE_FOR_TEMPLATES = false; 15739 /* Output should be safe even for XML used within HTML and alike. 15740 * This means, DOMPurify removes comments when containing risky content. 15741 */ 15742 let SAFE_FOR_XML = true; 15743 /* Decide if document with <html>... should be returned */ 15744 let WHOLE_DOCUMENT = false; 15745 /* Track whether config is already set on this instance of DOMPurify. */ 15746 let SET_CONFIG = false; 15747 /* Decide if all elements (e.g. style, script) must be children of 15748 * document.body. By default, browsers might move them to document.head */ 15749 let FORCE_BODY = false; 15750 /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html 15751 * string (or a TrustedHTML object if Trusted Types are supported). 15752 * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead 15753 */ 15754 let RETURN_DOM = false; 15755 /* Decide if a DOM `DocumentFragment` should be returned, instead of a html 15756 * string (or a TrustedHTML object if Trusted Types are supported) */ 15757 let RETURN_DOM_FRAGMENT = false; 15758 /* Try to return a Trusted Type object instead of a string, return a string in 15759 * case Trusted Types are not supported */ 15760 let RETURN_TRUSTED_TYPE = false; 15761 /* Output should be free from DOM clobbering attacks? 15762 * This sanitizes markups named with colliding, clobberable built-in DOM APIs. 15763 */ 15764 let SANITIZE_DOM = true; 15765 /* Achieve full DOM Clobbering protection by isolating the namespace of named 15766 * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules. 15767 * 15768 * HTML/DOM spec rules that enable DOM Clobbering: 15769 * - Named Access on Window (§7.3.3) 15770 * - DOM Tree Accessors (§3.1.5) 15771 * - Form Element Parent-Child Relations (§4.10.3) 15772 * - Iframe srcdoc / Nested WindowProxies (§4.8.5) 15773 * - HTMLCollection (§4.2.10.2) 15774 * 15775 * Namespace isolation is implemented by prefixing `id` and `name` attributes 15776 * with a constant string, i.e., `user-content-` 15777 */ 15778 let SANITIZE_NAMED_PROPS = false; 15779 const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-'; 15780 /* Keep element content when removing element? */ 15781 let KEEP_CONTENT = true; 15782 /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead 15783 * of importing it into a new Document and returning a sanitized copy */ 15784 let IN_PLACE = false; 15785 /* Allow usage of profiles like html, svg and mathMl */ 15786 let USE_PROFILES = {}; 15787 /* Tags to ignore content of when KEEP_CONTENT is true */ 15788 let FORBID_CONTENTS = null; 15789 const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'n
vendor: 3,516 bytes, lines 15789-15849
15789oscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']); 15790 /* Tags that are safe for data: URIs */ 15791 let DATA_URI_TAGS = null; 15792 const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']); 15793 /* Attributes safe for values like "javascript:" */ 15794 let URI_SAFE_ATTRIBUTES = null; 15795 const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']); 15796 const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML'; 15797 const SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; 15798 const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; 15799 /* Document namespace */ 15800 let NAMESPACE = HTML_NAMESPACE; 15801 let IS_EMPTY_INPUT = false; 15802 /* Allowed XHTML+XML namespaces */ 15803 let ALLOWED_NAMESPACES = null; 15804 const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString); 15805 let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']); 15806 let HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']); 15807 // Certain elements are allowed in both SVG and HTML 15808 // namespace. We need to specify them explicitly 15809 // so that they don't get erroneously deleted from 15810 // HTML namespace. 15811 const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']); 15812 /* Parsing of strict XHTML documents */ 15813 let PARSER_MEDIA_TYPE = null; 15814 const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html']; 15815 const DEFAULT_PARSER_MEDIA_TYPE = 'text/html'; 15816 let transformCaseFunc = null; 15817 /* Keep a reference to config to pass to hooks */ 15818 let CONFIG = null; 15819 /* Ideally, do not touch anything below this line */ 15820 /* ______________________________________________ */ 15821 const formElement = document.createElement('form'); 15822 const isRegexOrFunction = function isRegexOrFunction(testValue) { 15823 return testValue instanceof RegExp || testValue instanceof Function; 15824 }; 15825 /** 15826 * _parseConfig 15827 * 15828 * @param cfg optional config literal 15829 */ 15830 // eslint-disable-next-line complexity 15831 const _parseConfig = function _parseConfig() { 15832 let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 15833 if (CONFIG && CONFIG === cfg) { 15834 return; 15835 } 15836 /* Shield configuration object from tampering */ 15837 if (!cfg || typeof cfg !== 'object') { 15838 cfg = {}; 15839 } 15840 /* Shield configuration object from prototype pollution */ 15841 cfg = clone(cfg); 15842 PARSER_MEDIA_TYPE = 15843 // eslint-disable-next-line unicorn/prefer-includes 15844 SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE; 15845 // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is. 15846 transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase; 15847 /* Set configuration parameters */ 15848 ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS; 15849 ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
vendor: 4,219 bytes, lines 15850-15915
15850 ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES; 15851 URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES; 15852 DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS; 15853 FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS; 15854 FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {}; 15855 FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {}; 15856 USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false; 15857 ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true 15858 ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true 15859 ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false 15860 ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true 15861 SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false 15862 SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true 15863 WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false 15864 RETURN_DOM = cfg.RETURN_DOM || false; // Default false 15865 RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false 15866 RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false 15867 FORCE_BODY = cfg.FORCE_BODY || false; // Default false 15868 SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true 15869 SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false 15870 KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true 15871 IN_PLACE = cfg.IN_PLACE || false; // Default false 15872 IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI; 15873 NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE; 15874 MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS; 15875 HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS; 15876 CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {}; 15877 if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) { 15878 CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck; 15879 } 15880 if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) { 15881 CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck; 15882 } 15883 if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') { 15884 CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements; 15885 } 15886 if (SAFE_FOR_TEMPLATES) { 15887 ALLOW_DATA_ATTR = false; 15888 } 15889 if (RETURN_DOM_FRAGMENT) { 15890 RETURN_DOM = true; 15891 } 15892 /* Parse profile info */ 15893 if (USE_PROFILES) { 15894 ALLOWED_TAGS = addToSet({}, text); 15895 ALLOWED_ATTR = []; 15896 if (USE_PROFILES.html === true) { 15897 addToSet(ALLOWED_TAGS, html$1); 15898 addToSet(ALLOWED_ATTR, html); 15899 } 15900 if (USE_PROFILES.svg === true) { 15901 addToSet(ALLOWED_TAGS, svg$1); 15902 addToSet(ALLOWED_ATTR, svg); 15903 addToSet(ALLOWED_ATTR, xml); 15904 } 15905 if (USE_PROFILES.svgFilters === true) { 15906 addToSet(ALLOWED_TAGS, svgFilters); 15907 addToSet(ALLOWED_ATTR, svg); 15908 addToSet(ALLOWED_ATTR, xml); 15909 } 15910 if (USE_PROFILES.mathMl === true) { 15911 addToSet(ALLOWED_TAGS, mathMl$1); 15912 addToSet(ALLOWED_ATTR, mathMl); 15913 addToSet(ALLOWED_ATTR, xml); 15914 } 15915 }
vendor: 5,920 bytes, lines 15916-16043
15916 /* Merge configuration parameters */ 15917 if (cfg.ADD_TAGS) { 15918 if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) { 15919 ALLOWED_TAGS = clone(ALLOWED_TAGS); 15920 } 15921 addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc); 15922 } 15923 if (cfg.ADD_ATTR) { 15924 if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) { 15925 ALLOWED_ATTR = clone(ALLOWED_ATTR); 15926 } 15927 addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc); 15928 } 15929 if (cfg.ADD_URI_SAFE_ATTR) { 15930 addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc); 15931 } 15932 if (cfg.FORBID_CONTENTS) { 15933 if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) { 15934 FORBID_CONTENTS = clone(FORBID_CONTENTS); 15935 } 15936 addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc); 15937 } 15938 /* Add #text in case KEEP_CONTENT is set to true */ 15939 if (KEEP_CONTENT) { 15940 ALLOWED_TAGS['#text'] = true; 15941 } 15942 /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */ 15943 if (WHOLE_DOCUMENT) { 15944 addToSet(ALLOWED_TAGS, ['html', 'head', 'body']); 15945 } 15946 /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */ 15947 if (ALLOWED_TAGS.table) { 15948 addToSet(ALLOWED_TAGS, ['tbody']); 15949 delete FORBID_TAGS.tbody; 15950 } 15951 if (cfg.TRUSTED_TYPES_POLICY) { 15952 if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') { 15953 throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.'); 15954 } 15955 if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') { 15956 throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.'); 15957 } 15958 // Overwrite existing TrustedTypes policy. 15959 trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY; 15960 // Sign local variables required by `sanitize`. 15961 emptyHTML = trustedTypesPolicy.createHTML(''); 15962 } else { 15963 // Uninitialized policy, attempt to initialize the internal dompurify policy. 15964 if (trustedTypesPolicy === undefined) { 15965 trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript); 15966 } 15967 // If creating the internal policy succeeded sign internal variables. 15968 if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') { 15969 emptyHTML = trustedTypesPolicy.createHTML(''); 15970 } 15971 } 15972 // Prevent further manipulation of configuration. 15973 // Not available in IE8, Safari 5, etc. 15974 if (freeze) { 15975 freeze(cfg); 15976 } 15977 CONFIG = cfg; 15978 }; 15979 /* Keep track of all possible SVG and MathML tags 15980 * so that we can perform the namespace checks 15981 * correctly. */ 15982 const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]); 15983 const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]); 15984 /** 15985 * @param element a DOM element whose namespace is being checked 15986 * @returns Return false if the element has a 15987 * namespace that a spec-compliant parser would never 15988 * return. Return true otherwise. 15989 */ 15990 const _checkValidNamespace = function _checkValidNamespace(element) { 15991 let parent = getParentNode(element); 15992 // In JSDOM, if we're inside shadow DOM, then parentNode 15993 // can be null. We just simulate parent in this case. 15994 if (!parent || !parent.tagName) { 15995 parent = { 15996 namespaceURI: NAMESPACE, 15997 tagName: 'template' 15998 }; 15999 } 16000 const tagName = stringToLowerCase(element.tagName); 16001 const parentTagName = stringToLowerCase(parent.tagName); 16002 if (!ALLOWED_NAMESPACES[element.namespaceURI]) { 16003 return false; 16004 } 16005 if (element.namespaceURI === SVG_NAMESPACE) { 16006 // The only way to switch from HTML namespace to SVG 16007 // is via <svg>. If it happens via any other tag, then 16008 // it should be killed. 16009 if (parent.namespaceURI === HTML_NAMESPACE) { 16010 return tagName === 'svg'; 16011 } 16012 // The only way to switch from MathML to SVG is via` 16013 // svg if parent is either <annotation-xml> or MathML 16014 // text integration points. 16015 if (parent.namespaceURI === MATHML_NAMESPACE) { 16016 return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]); 16017 } 16018 // We only allow elements that are defined in SVG 16019 // spec. All others are disallowed in SVG namespace. 16020 return Boolean(ALL_SVG_TAGS[tagName]); 16021 } 16022 if (element.namespaceURI === MATHML_NAMESPACE) { 16023 // The only way to switch from HTML namespace to MathML 16024 // is via <math>. If it happens via any other tag, then 16025 // it should be killed. 16026 if (parent.namespaceURI === HTML_NAMESPACE) { 16027 return tagName === 'math'; 16028 } 16029 // The only way to switch from SVG to MathML is via 16030 // <math> and HTML integration points 16031 if (parent.namespaceURI === SVG_NAMESPACE) { 16032 return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName]; 16033 } 16034 // We only allow elements that are defined in MathML 16035 // spec. All others are disallowed in MathML namespace. 16036 return Boolean(ALL_MATHML_TAGS[tagName]); 16037 } 16038 if (element.namespaceURI === HTML_NAMESPACE) { 16039 // The only way to switch from SVG to HTML is via 16040 // HTML integration points, and from MathML to HTML 16041 // is via MathML text integration points 16042 if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) { 16043 return false;
16044 } 16045 if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) { 16046 return false; 16047 } 16048 // We disallow tags that are specific for MathML 16049 // or SVG and should never appear in HTML namespace 16050 return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]); 16051 } 16052 // For XHTML and XML documents that support custom namespaces 16053 if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) { 16054 return true; 16055 } 16056 // The code should never reach this place (this means 16057 // that the element somehow got namespace that is not 16058 // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES). 16059 // Return false just in case. 16060 return false; 16061 }; 16062 /** 16063 * _forceRemove 16064 * 16065 * @param node a DOM node 16066 */ 16067 const _forceRemove = function _forceRemove(node) { 16068 arrayPush(DOMPurify.removed, { 16069 element: node 16070 }); 16071 try {
vendor: 12,163 bytes, lines 16072-16316
16072 // eslint-disable-next-line unicorn/prefer-dom-node-remove 16073 getParentNode(node).removeChild(node); 16074 } catch (_) { 16075 remove(node); 16076 } 16077 }; 16078 /** 16079 * _removeAttribute 16080 * 16081 * @param name an Attribute name 16082 * @param element a DOM node 16083 */ 16084 const _removeAttribute = function _removeAttribute(name, element) { 16085 try { 16086 arrayPush(DOMPurify.removed, { 16087 attribute: element.getAttributeNode(name), 16088 from: element 16089 }); 16090 } catch (_) { 16091 arrayPush(DOMPurify.removed, { 16092 attribute: null, 16093 from: element 16094 }); 16095 } 16096 element.removeAttribute(name); 16097 // We void attribute values for unremovable "is" attributes 16098 if (name === 'is') { 16099 if (RETURN_DOM || RETURN_DOM_FRAGMENT) { 16100 try { 16101 _forceRemove(element); 16102 } catch (_) {} 16103 } else { 16104 try { 16105 element.setAttribute(name, ''); 16106 } catch (_) {} 16107 } 16108 } 16109 }; 16110 /** 16111 * _initDocument 16112 * 16113 * @param dirty - a string of dirty markup 16114 * @return a DOM, filled with the dirty markup 16115 */ 16116 const _initDocument = function _initDocument(dirty) { 16117 /* Create a HTML document */ 16118 let doc = null; 16119 let leadingWhitespace = null; 16120 if (FORCE_BODY) { 16121 dirty = '<remove></remove>' + dirty; 16122 } else { 16123 /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */ 16124 const matches = stringMatch(dirty, /^[\r\n\t ]+/); 16125 leadingWhitespace = matches && matches[0]; 16126 } 16127 if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) { 16128 // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict) 16129 dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>'; 16130 } 16131 const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty; 16132 /* 16133 * Use the DOMParser API by default, fallback later if needs be 16134 * DOMParser not work for svg when has multiple root element. 16135 */ 16136 if (NAMESPACE === HTML_NAMESPACE) { 16137 try { 16138 doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE); 16139 } catch (_) {} 16140 } 16141 /* Use createHTMLDocument in case DOMParser is not available */ 16142 if (!doc || !doc.documentElement) { 16143 doc = implementation.createDocument(NAMESPACE, 'template', null); 16144 try { 16145 doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload; 16146 } catch (_) { 16147 // Syntax error if dirtyPayload is invalid xml 16148 } 16149 } 16150 const body = doc.body || doc.documentElement; 16151 if (dirty && leadingWhitespace) { 16152 body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null); 16153 } 16154 /* Work on whole document or just its body */ 16155 if (NAMESPACE === HTML_NAMESPACE) { 16156 return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0]; 16157 } 16158 return WHOLE_DOCUMENT ? doc.documentElement : body; 16159 }; 16160 /** 16161 * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document. 16162 * 16163 * @param root The root element or node to start traversing on. 16164 * @return The created NodeIterator 16165 */ 16166 const _createNodeIterator = function _createNodeIterator(root) { 16167 return createNodeIterator.call(root.ownerDocument || root, root, 16168 // eslint-disable-next-line no-bitwise 16169 NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null); 16170 }; 16171 /** 16172 * _isClobbered 16173 * 16174 * @param element element to check for clobbering attacks 16175 * @return true if clobbered, false if safe 16176 */ 16177 const _isClobbered = function _isClobbered(element) { 16178 return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function'); 16179 }; 16180 /** 16181 * Checks whether the given object is a DOM node. 16182 * 16183 * @param value object to check whether it's a DOM node 16184 * @return true is object is a DOM node 16185 */ 16186 const _isNode = function _isNode(value) { 16187 return typeof Node === 'function' && value instanceof Node; 16188 }; 16189 function _executeHooks(hooks, currentNode, data) { 16190 arrayForEach(hooks, hook => { 16191 hook.call(DOMPurify, currentNode, data, CONFIG); 16192 }); 16193 } 16194 /** 16195 * _sanitizeElements 16196 * 16197 * @protect nodeName 16198 * @protect textContent 16199 * @protect removeChild 16200 * @param currentNode to check for permission to exist 16201 * @return true if node was killed, false if left alive 16202 */ 16203 const _sanitizeElements = function _sanitizeElements(currentNode) { 16204 let content = null; 16205 /* Execute a hook if present */ 16206 _executeHooks(hooks.beforeSanitizeElements, currentNode, null); 16207 /* Check if element is clobbered or can clobber */ 16208 if (_isClobbered(currentNode)) { 16209 _forceRemove(currentNode); 16210 return true; 16211 } 16212 /* Now let's check the element's type and name */ 16213 const tagName = transformCaseFunc(currentNode.nodeName); 16214 /* Execute a hook if present */ 16215 _executeHooks(hooks.uponSanitizeElement, currentNode, { 16216 tagName, 16217 allowedTags: ALLOWED_TAGS 16218 }); 16219 /* Detect mXSS attempts abusing namespace confusion */ 16220 if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) { 16221 _forceRemove(currentNode); 16222 return true; 16223 } 16224 /* Remove any occurrence of processing instructions */ 16225 if (currentNode.nodeType === NODE_TYPE.progressingInstruction) { 16226 _forceRemove(currentNode); 16227 return true; 16228 } 16229 /* Remove any kind of possibly harmful comments */ 16230 if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) { 16231 _forceRemove(currentNode); 16232 return true; 16233 } 16234 /* Remove element if anything forbids its presence */ 16235 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { 16236 /* Check if we have a custom element to handle */ 16237 if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) { 16238 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) { 16239 return false; 16240 } 16241 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) { 16242 return false; 16243 } 16244 } 16245 /* Keep content except for bad-listed elements */ 16246 if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) { 16247 const parentNode = getParentNode(currentNode) || currentNode.parentNode; 16248 const childNodes = getChildNodes(currentNode) || currentNode.childNodes; 16249 if (childNodes && parentNode) { 16250 const childCount = childNodes.length; 16251 for (let i = childCount - 1; i >= 0; --i) { 16252 const childClone = cloneNode(childNodes[i], true); 16253 childClone.__removalCount = (currentNode.__removalCount || 0) + 1; 16254 parentNode.insertBefore(childClone, getNextSibling(currentNode)); 16255 } 16256 } 16257 } 16258 _forceRemove(currentNode); 16259 return true; 16260 } 16261 /* Check whether element has a valid namespace */ 16262 if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) { 16263 _forceRemove(currentNode); 16264 return true; 16265 } 16266 /* Make sure that older browsers don't get fallback-tag mXSS */ 16267 if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) { 16268 _forceRemove(currentNode); 16269 return true; 16270 } 16271 /* Sanitize element content to be template-safe */ 16272 if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) { 16273 /* Get the element's text content */ 16274 content = currentNode.textContent; 16275 arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => { 16276 content = stringReplace(content, expr, ' '); 16277 }); 16278 if (currentNode.textContent !== content) { 16279 arrayPush(DOMPurify.removed, { 16280 element: currentNode.cloneNode() 16281 }); 16282 currentNode.textContent = content; 16283 } 16284 } 16285 /* Execute a hook if present */ 16286 _executeHooks(hooks.afterSanitizeElements, currentNode, null); 16287 return false; 16288 }; 16289 /** 16290 * _isValidAttribute 16291 * 16292 * @param lcTag Lowercase tag name of containing element. 16293 * @param lcName Lowercase attribute name. 16294 * @param value Attribute value. 16295 * @return Returns true if `value` is valid, otherwise false. 16296 */ 16297 // eslint-disable-next-line complexity 16298 const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) { 16299 /* Make sure attribute cannot clobber */ 16300 if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) { 16301 return false; 16302 } 16303 /* Allow valid data-* attributes: At least one character after "-" 16304 (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes) 16305 XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804) 16306 We don't need to check the value; it's always URI safe. */ 16307 if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) { 16308 if ( 16309 // First condition does a very basic check if a) it's basically a valid custom element tagname AND 16310 // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck 16311 // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck 16312 _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)) || 16313 // Alternative, second condition checks if it's an `is`-attribute, AND 16314 // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck 16315 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 { 16316 return false;
vendor: 11,439 bytes, lines 16317-16585
16317 } 16318 /* Check value is safe. First, is attr inert? If so, is safe */ 16319 } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; 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, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) { 16320 return false; 16321 } else ; 16322 return true; 16323 }; 16324 /** 16325 * _isBasicCustomElement 16326 * checks if at least one dash is included in tagName, and it's not the first char 16327 * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name 16328 * 16329 * @param tagName name of the tag of the node to sanitize 16330 * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false. 16331 */ 16332 const _isBasicCustomElement = function _isBasicCustomElement(tagName) { 16333 return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT); 16334 }; 16335 /** 16336 * _sanitizeAttributes 16337 * 16338 * @protect attributes 16339 * @protect nodeName 16340 * @protect removeAttribute 16341 * @protect setAttribute 16342 * 16343 * @param currentNode to sanitize 16344 */ 16345 const _sanitizeAttributes = function _sanitizeAttributes(currentNode) { 16346 /* Execute a hook if present */ 16347 _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null); 16348 const { 16349 attributes 16350 } = currentNode; 16351 /* Check if we have attributes; if not we might have a text node */ 16352 if (!attributes || _isClobbered(currentNode)) { 16353 return; 16354 } 16355 const hookEvent = { 16356 attrName: '', 16357 attrValue: '', 16358 keepAttr: true, 16359 allowedAttributes: ALLOWED_ATTR, 16360 forceKeepAttr: undefined 16361 }; 16362 let l = attributes.length; 16363 /* Go backwards over all attributes; safely remove bad ones */ 16364 while (l--) { 16365 const attr = attributes[l]; 16366 const { 16367 name, 16368 namespaceURI, 16369 value: attrValue 16370 } = attr; 16371 const lcName = transformCaseFunc(name); 16372 let value = name === 'value' ? attrValue : stringTrim(attrValue); 16373 const initValue = value; 16374 /* Execute a hook if present */ 16375 hookEvent.attrName = lcName; 16376 hookEvent.attrValue = value; 16377 hookEvent.keepAttr = true; 16378 hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set 16379 _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent); 16380 value = hookEvent.attrValue; 16381 /* Full DOM Clobbering protection via namespace isolation, 16382 * Prefix id and name attributes with `user-content-` 16383 */ 16384 if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) { 16385 // Remove the attribute with this value 16386 _removeAttribute(name, currentNode); 16387 // Prefix the value and later re-create the attribute with the sanitized value 16388 value = SANITIZE_NAMED_PROPS_PREFIX + value; 16389 } 16390 /* Work around a security issue with comments inside attributes */ 16391 if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) { 16392 _removeAttribute(name, currentNode); 16393 continue; 16394 } 16395 /* Did the hooks approve of the attribute? */ 16396 if (hookEvent.forceKeepAttr) { 16397 continue; 16398 } 16399 /* Remove attribute */ 16400 /* Did the hooks approve of the attribute? */ 16401 if (!hookEvent.keepAttr) { 16402 _removeAttribute(name, currentNode); 16403 continue; 16404 } 16405 /* Work around a security issue in jQuery 3.0 */ 16406 if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) { 16407 _removeAttribute(name, currentNode); 16408 continue; 16409 } 16410 /* Sanitize attribute content to be template-safe */ 16411 if (SAFE_FOR_TEMPLATES) { 16412 arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => { 16413 value = stringReplace(value, expr, ' '); 16414 }); 16415 } 16416 /* Is `value` valid for this attribute? */ 16417 const lcTag = transformCaseFunc(currentNode.nodeName); 16418 if (!_isValidAttribute(lcTag, lcName, value)) { 16419 _removeAttribute(name, currentNode); 16420 continue; 16421 } 16422 /* Handle attributes that require Trusted Types */ 16423 if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') { 16424 if (namespaceURI) ; else { 16425 switch (trustedTypes.getAttributeType(lcTag, lcName)) { 16426 case 'TrustedHTML': 16427 { 16428 value = trustedTypesPolicy.createHTML(value); 16429 break; 16430 } 16431 case 'TrustedScriptURL': 16432 { 16433 value = trustedTypesPolicy.createScriptURL(value); 16434 break; 16435 } 16436 } 16437 } 16438 } 16439 /* Handle invalid data-* attribute set by try-catching it */ 16440 if (value !== initValue) { 16441 try { 16442 if (namespaceURI) { 16443 currentNode.setAttributeNS(namespaceURI, name, value); 16444 } else { 16445 /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */ 16446 currentNode.setAttribute(name, value); 16447 } 16448 if (_isClobbered(currentNode)) { 16449 _forceRemove(currentNode); 16450 } else { 16451 arrayPop(DOMPurify.removed); 16452 } 16453 } catch (_) {} 16454 } 16455 } 16456 /* Execute a hook if present */ 16457 _executeHooks(hooks.afterSanitizeAttributes, currentNode, null); 16458 }; 16459 /** 16460 * _sanitizeShadowDOM 16461 * 16462 * @param fragment to iterate over recursively 16463 */ 16464 const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) { 16465 let shadowNode = null; 16466 const shadowIterator = _createNodeIterator(fragment); 16467 /* Execute a hook if present */ 16468 _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null); 16469 while (shadowNode = shadowIterator.nextNode()) { 16470 /* Execute a hook if present */ 16471 _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null); 16472 /* Sanitize tags and elements */ 16473 _sanitizeElements(shadowNode); 16474 /* Check attributes next */ 16475 _sanitizeAttributes(shadowNode); 16476 /* Deep shadow DOM detected */ 16477 if (shadowNode.content instanceof DocumentFragment) { 16478 _sanitizeShadowDOM(shadowNode.content); 16479 } 16480 } 16481 /* Execute a hook if present */ 16482 _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null); 16483 }; 16484 // eslint-disable-next-line complexity 16485 DOMPurify.sanitize = function (dirty) { 16486 let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 16487 let body = null; 16488 let importedNode = null; 16489 let currentNode = null; 16490 let returnNode = null; 16491 /* Make sure we have a string to sanitize. 16492 DO NOT return early, as this will return the wrong type if 16493 the user has requested a DOM object rather than a string */ 16494 IS_EMPTY_INPUT = !dirty; 16495 if (IS_EMPTY_INPUT) { 16496 dirty = '<!-->'; 16497 } 16498 /* Stringify, in case dirty is an object */ 16499 if (typeof dirty !== 'string' && !_isNode(dirty)) { 16500 if (typeof dirty.toString === 'function') { 16501 dirty = dirty.toString(); 16502 if (typeof dirty !== 'string') { 16503 throw typeErrorCreate('dirty is not a string, aborting'); 16504 } 16505 } else { 16506 throw typeErrorCreate('toString is not a function'); 16507 } 16508 } 16509 /* Return dirty HTML if DOMPurify cannot run */ 16510 if (!DOMPurify.isSupported) { 16511 return dirty; 16512 } 16513 /* Assign config vars */ 16514 if (!SET_CONFIG) { 16515 _parseConfig(cfg); 16516 } 16517 /* Clean up removed elements */ 16518 DOMPurify.removed = []; 16519 /* Check if dirty is correctly typed for IN_PLACE */ 16520 if (typeof dirty === 'string') { 16521 IN_PLACE = false; 16522 } 16523 if (IN_PLACE) { 16524 /* Do some early pre-sanitization to avoid unsafe root nodes */ 16525 if (dirty.nodeName) { 16526 const tagName = transformCaseFunc(dirty.nodeName); 16527 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { 16528 throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place'); 16529 } 16530 } 16531 } else if (dirty instanceof Node) { 16532 /* If dirty is a DOM element, append to an empty document to avoid 16533 elements being stripped by the parser */ 16534 body = _initDocument('<!---->'); 16535 importedNode = body.ownerDocument.importNode(dirty, true); 16536 if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') { 16537 /* Node is already a body, use as is */ 16538 body = importedNode; 16539 } else if (importedNode.nodeName === 'HTML') { 16540 body = importedNode; 16541 } else { 16542 // eslint-disable-next-line unicorn/prefer-dom-node-append 16543 body.appendChild(importedNode); 16544 } 16545 } else { 16546 /* Exit directly if we have nothing to do */ 16547 if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && 16548 // eslint-disable-next-line unicorn/prefer-includes 16549 dirty.indexOf('<') === -1) { 16550 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty; 16551 } 16552 /* Initialize the document to work on */ 16553 body = _initDocument(dirty); 16554 /* Check we have a DOM node from the data */ 16555 if (!body) { 16556 return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : ''; 16557 } 16558 } 16559 /* Remove first element node (ours) if FORCE_BODY is set */ 16560 if (body && FORCE_BODY) { 16561 _forceRemove(body.firstChild); 16562 } 16563 /* Get node iterator */ 16564 const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body); 16565 /* Now start iterating over the created document */ 16566 while (currentNode = nodeIterator.nextNode()) { 16567 /* Sanitize tags and elements */ 16568 _sanitizeElements(currentNode); 16569 /* Check attributes next */ 16570 _sanitizeAttributes(currentNode); 16571 /* Shadow DOM detected, sanitize it */ 16572 if (currentNode.content instanceof DocumentFragment) { 16573 _sanitizeShadowDOM(currentNode.content); 16574 } 16575 } 16576 /* If we sanitized `dirty` in-place, return it. */ 16577 if (IN_PLACE) { 16578 return dirty; 16579 } 16580 /* Return sanitized string or DOM */ 16581 if (RETURN_DOM) { 16582 if (RETURN_DOM_FRAGMENT) { 16583 returnNode = createDocumentFragment.call(body.ownerDocument); 16584 while (body.firstChild) { 16585 // eslint-disable-next-line unicorn/prefer-dom-node
16585-append 16586 returnNode.appendChild(body.firstChild); 16587 } 16588 } else { 16589 returnNode = body; 16590 } 16591 if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) { 16592 /* 16593 AdoptNode() is not used because internal state is not reset 16594 (e.g. the past names map of a HTMLFormElement), this is safe 16595 in theory but we would rather not risk another attack vector. 16596 The state that is cloned by importNode() is explicitly defined 16597 by the specs. 16598 */ 16599 returnNode = importNode.call(originalDocument, returnNode, true); 16600 } 16601 return returnNode; 16602 } 16603 let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML; 16604 /* Serialize doctype if allowed */ 16605 if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) { 16606 serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML; 16607 } 16608 /* Sanitize final string template-safe */ 16609 if (SAFE_FOR_TEMPLATES) { 16610 arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => { 16611 serializedHTML = stringReplace(serializedHTML, expr, ' '); 16612 }); 16613 } 16614 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML; 16615 }; 16616 DOMPurify.setConfig = function () { 16617 let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 16618 _parseConfig(cfg); 16619 SET_CONFIG = true; 16620 }; 16621 DOMPurify.clearConfig = function () { 16622 CONFIG = null; 16623 SET_CONFIG = false; 16624 }; 16625 DOMPurify.isValidAttribute = function (tag, attr, value) { 16626 /* Initialize shared config vars if necessary. */ 16627 if (!CONFIG) { 16628 _parseConfig({}); 16629 } 16630 const lcTag = transformCaseFunc(tag); 16631 const lcName = transformCaseFunc(attr); 16632 return _isValidAttribute(lcTag, lcName, value); 16633 }; 16634 DOMPurify.addHook = function (entryPoint, hookFunction) { 16635 if (typeof hookFunction !== 'function') { 16636 return; 16637 } 16638 arrayPush(hooks[entryPoint], hookFunction); 16639 }; 16640 DOMPurify.removeHook = function (entryPoint, hookFunction) { 16641 if (hookFunction !== undefined) { 16642 const index = arrayLastIndexOf(hooks[entryPoint], hookFunction); 16643 return index === -1 ? undefined : arraySplice(hooks[entryPoint], index, 1)[0]; 16644 } 16645 return arrayPop(hooks[entryPoint]); 16646 }; 16647 DOMPurify.removeHooks = function (entryPoint) { 16648 hooks[entryPoint] = []; 16649 }; 16650 DOMPurify.removeAllHooks = function () { 16651 hooks = _createHooksMap(); 16652 }; 16653 return DOMPurify; 16654 } 16655 var purify = createDOMPurify(); 16656 16657 const each$4 = Tools.each, trim = Tools.trim; 16658 const queryParts = [ 16659 'source', 16660 'protocol', 16661 'authority', 16662 'userInfo', 16663 'user', 16664 'password', 16665 'host', 16666 'port', 16667 'relative', 16668 'path', 16669 'directory', 16670 'file', 16671 'query', 16672 'anchor' 16673 ]; 16674 const DEFAULT_PORTS = { 16675 ftp: 21, 16676 http: 80, 16677 https: 443, 16678 mailto: 25 16679 }; 16680 const safeSvgDataUrlElements = [ 16681 'img', 16682 'video' 16683 ]; 16684 const blockSvgDataUris = (allowSvgDataUrls, tagName) => { 16685 if (isNonNullable(allowSvgDataUrls)) { 16686 return !allowSvgDataUrls; 16687 } else { 16688 return isNonNullable(tagName) ? !contains$2(safeSvgDataUrlElements, tagName) : true; 16689 } 16690 }; 16691 const decodeUri = encodedUri => { 16692 try { 16693 return decodeURIComponent(encodedUri); 16694 } catch (_a) { 16695 return unescape(encodedUri); 16696 } 16697 }; 16698 const isInvalidUri = (settings, uri, tagName) => { 16699 const decodedUri = decodeUri(uri).replace(/\s/g, ''); 16700 if (settings.allow_script_urls) { 16701 return false; 16702 } else if (/((java|vb)script|mhtml):/i.test(decodedUri)) { 16703 return true; 16704 } else if (settings.allow_html_data_urls) { 16705 return false;
vendor: 5,413 bytes, lines 16706-16850
16706 } else if (/^data:image\//i.test(decodedUri)) { 16707 return blockSvgDataUris(settings.allow_svg_data_urls, tagName) && /^data:image\/svg\+xml/i.test(decodedUri); 16708 } else { 16709 return /^data:/i.test(decodedUri); 16710 } 16711 }; 16712 class URI { 16713 static parseDataUri(uri) { 16714 let type; 16715 const uriComponents = decodeURIComponent(uri).split(','); 16716 const matches = /data:([^;]+)/.exec(uriComponents[0]); 16717 if (matches) { 16718 type = matches[1]; 16719 } 16720 return { 16721 type, 16722 data: uriComponents[1] 16723 }; 16724 } 16725 static isDomSafe(uri, context, options = {}) { 16726 if (options.allow_script_urls) { 16727 return true; 16728 } else { 16729 const decodedUri = Entities.decode(uri).replace(/[\s\u0000-\u001F]+/g, ''); 16730 return !isInvalidUri(options, decodedUri, context); 16731 } 16732 } 16733 static getDocumentBaseUrl(loc) { 16734 var _a; 16735 let baseUrl; 16736 if (loc.protocol.indexOf('http') !== 0 && loc.protocol !== 'file:') { 16737 baseUrl = (_a = loc.href) !== null && _a !== void 0 ? _a : ''; 16738 } else { 16739 baseUrl = loc.protocol + '//' + loc.host + loc.pathname; 16740 } 16741 if (/^[^:]+:\/\/\/?[^\/]+\//.test(baseUrl)) { 16742 baseUrl = baseUrl.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, ''); 16743 if (!/[\/\\]$/.test(baseUrl)) { 16744 baseUrl += '/'; 16745 } 16746 } 16747 return baseUrl; 16748 } 16749 constructor(url, settings = {}) { 16750 this.path = ''; 16751 this.directory = ''; 16752 url = trim(url); 16753 this.settings = settings; 16754 const baseUri = settings.base_uri; 16755 const self = this; 16756 if (/^([\w\-]+):([^\/]{2})/i.test(url) || /^\s*#/.test(url)) { 16757 self.source = url; 16758 return; 16759 } 16760 const isProtocolRelative = url.indexOf('//') === 0; 16761 if (url.indexOf('/') === 0 && !isProtocolRelative) { 16762 url = (baseUri ? baseUri.protocol || 'http' : 'http') + '://mce_host' + url; 16763 } 16764 if (!/^[\w\-]*:?\/\//.test(url)) { 16765 const baseUrl = baseUri ? baseUri.path : new URI(document.location.href).directory; 16766 if ((baseUri === null || baseUri === void 0 ? void 0 : baseUri.protocol) === '') { 16767 url = '//mce_host' + self.toAbsPath(baseUrl, url); 16768 } else { 16769 const match = /([^#?]*)([#?]?.*)/.exec(url); 16770 if (match) { 16771 url = (baseUri && baseUri.protocol || 'http') + '://mce_host' + self.toAbsPath(baseUrl, match[1]) + match[2]; 16772 } 16773 } 16774 } 16775 url = url.replace(/@@/g, '(mce_at)'); 16776 const urlMatch = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?(\[[a-zA-Z0-9:.%]+\]|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url); 16777 if (urlMatch) { 16778 each$4(queryParts, (v, i) => { 16779 let part = urlMatch[i]; 16780 if (part) { 16781 part = part.replace(/\(mce_at\)/g, '@@'); 16782 } 16783 self[v] = part; 16784 }); 16785 } 16786 if (baseUri) { 16787 if (!self.protocol) { 16788 self.protocol = baseUri.protocol; 16789 } 16790 if (!self.userInfo) { 16791 self.userInfo = baseUri.userInfo; 16792 } 16793 if (!self.port && self.host === 'mce_host') { 16794 self.port = baseUri.port; 16795 } 16796 if (!self.host || self.host === 'mce_host') { 16797 self.host = baseUri.host; 16798 } 16799 self.source = ''; 16800 } 16801 if (isProtocolRelative) { 16802 self.protocol = ''; 16803 } 16804 } 16805 setPath(path) { 16806 const pathMatch = /^(.*?)\/?(\w+)?$/.exec(path); 16807 if (pathMatch) { 16808 this.path = pathMatch[0]; 16809 this.directory = pathMatch[1]; 16810 this.file = pathMatch[2]; 16811 } 16812 this.source = ''; 16813 this.getURI(); 16814 } 16815 toRelative(uri) { 16816 if (uri === './') { 16817 return uri; 16818 } 16819 const relativeUri = new URI(uri, { base_uri: this }); 16820 if (relativeUri.host !== 'mce_host' && this.host !== relativeUri.host && relativeUri.host || this.port !== relativeUri.port || this.protocol !== relativeUri.protocol && relativeUri.protocol !== '') { 16821 return relativeUri.getURI(); 16822 } 16823 const tu = this.getURI(), uu = relativeUri.getURI(); 16824 if (tu === uu || tu.charAt(tu.length - 1) === '/' && tu.substr(0, tu.length - 1) === uu) { 16825 return tu; 16826 } 16827 let output = this.toRelPath(this.path, relativeUri.path); 16828 if (relativeUri.query) { 16829 output += '?' + relativeUri.query; 16830 } 16831 if (relativeUri.anchor) { 16832 output += '#' + relativeUri.anchor; 16833 } 16834 return output; 16835 } 16836 toAbsolute(uri, noHost) { 16837 const absoluteUri = new URI(uri, { base_uri: this }); 16838 return absoluteUri.getURI(noHost && this.isSameOrigin(absoluteUri)); 16839 } 16840 isSameOrigin(uri) { 16841 if (this.host == uri.host && this.protocol == uri.protocol) { 16842 if (this.port == uri.port) { 16843 return true; 16844 } 16845 const defaultPort = this.protocol ? DEFAULT_PORTS[this.protocol] : null; 16846 if (defaultPort && (this.port || defaultPort) == (uri.port || defaultPort)) { 16847 return true; 16848 } 16849 } 16850 return false;
vendor: 5,705 bytes, lines 16851-17023
16851 } 16852 toRelPath(base, path) { 16853 let breakPoint = 0, out = '', i, l; 16854 const normalizedBase = base.substring(0, base.lastIndexOf('/')).split('/'); 16855 const items = path.split('/'); 16856 if (normalizedBase.length >= items.length) { 16857 for (i = 0, l = normalizedBase.length; i < l; i++) { 16858 if (i >= items.length || normalizedBase[i] !== items[i]) { 16859 breakPoint = i + 1; 16860 break; 16861 } 16862 } 16863 } 16864 if (normalizedBase.length < items.length) { 16865 for (i = 0, l = items.length; i < l; i++) { 16866 if (i >= normalizedBase.length || normalizedBase[i] !== items[i]) { 16867 breakPoint = i + 1; 16868 break; 16869 } 16870 } 16871 } 16872 if (breakPoint === 1) { 16873 return path; 16874 } 16875 for (i = 0, l = normalizedBase.length - (breakPoint - 1); i < l; i++) { 16876 out += '../'; 16877 } 16878 for (i = breakPoint - 1, l = items.length; i < l; i++) { 16879 if (i !== breakPoint - 1) { 16880 out += '/' + items[i]; 16881 } else { 16882 out += items[i]; 16883 } 16884 } 16885 return out; 16886 } 16887 toAbsPath(base, path) { 16888 let nb = 0; 16889 const tr = /\/$/.test(path) ? '/' : ''; 16890 const normalizedBase = base.split('/'); 16891 const normalizedPath = path.split('/'); 16892 const baseParts = []; 16893 each$4(normalizedBase, k => { 16894 if (k) { 16895 baseParts.push(k); 16896 } 16897 }); 16898 const pathParts = []; 16899 for (let i = normalizedPath.length - 1; i >= 0; i--) { 16900 if (normalizedPath[i].length === 0 || normalizedPath[i] === '.') { 16901 continue; 16902 } 16903 if (normalizedPath[i] === '..') { 16904 nb++; 16905 continue; 16906 } 16907 if (nb > 0) { 16908 nb--; 16909 continue; 16910 } 16911 pathParts.push(normalizedPath[i]); 16912 } 16913 const i = baseParts.length - nb; 16914 let outPath; 16915 if (i <= 0) { 16916 outPath = reverse(pathParts).join('/'); 16917 } else { 16918 outPath = baseParts.slice(0, i).join('/') + '/' + reverse(pathParts).join('/'); 16919 } 16920 if (outPath.indexOf('/') !== 0) { 16921 outPath = '/' + outPath; 16922 } 16923 if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) { 16924 outPath += tr; 16925 } 16926 return outPath; 16927 } 16928 getURI(noProtoHost = false) { 16929 let s; 16930 if (!this.source || noProtoHost) { 16931 s = ''; 16932 if (!noProtoHost) { 16933 if (this.protocol) { 16934 s += this.protocol + '://'; 16935 } else { 16936 s += '//'; 16937 } 16938 if (this.userInfo) { 16939 s += this.userInfo + '@'; 16940 } 16941 if (this.host) { 16942 s += this.host; 16943 } 16944 if (this.port) { 16945 s += ':' + this.port; 16946 } 16947 } 16948 if (this.path) { 16949 s += this.path; 16950 } 16951 if (this.query) { 16952 s += '?' + this.query; 16953 } 16954 if (this.anchor) { 16955 s += '#' + this.anchor; 16956 } 16957 this.source = s; 16958 } 16959 return this.source; 16960 } 16961 } 16962 16963 const filteredUrlAttrs = Tools.makeMap('src,href,data,background,action,formaction,poster,xlink:href'); 16964 const internalElementAttr = 'data-mce-type'; 16965 let uid = 0; 16966 const processNode = (node, settings, schema, scope, evt) => { 16967 var _a, _b, _c, _d; 16968 const validate = settings.validate; 16969 const specialElements = schema.getSpecialElements(); 16970 if (node.nodeType === COMMENT && !settings.allow_conditional_comments && /^\[if/i.test((_a = node.nodeValue) !== null && _a !== void 0 ? _a : '')) { 16971 node.nodeValue = ' ' + node.nodeValue; 16972 } 16973 const lcTagName = (_b = evt === null || evt === void 0 ? void 0 : evt.tagName) !== null && _b !== void 0 ? _b : node.nodeName.toLowerCase(); 16974 if (scope !== 'html' && schema.isValid(scope)) { 16975 if (isNonNullable(evt)) { 16976 evt.allowedTags[lcTagName] = true; 16977 } 16978 return; 16979 } 16980 if (node.nodeType !== ELEMENT || lcTagName === 'body') { 16981 return; 16982 } 16983 const element = SugarElement.fromDom(node); 16984 const isInternalElement = has$1(element, internalElementAttr); 16985 const bogus = get$9(element, 'data-mce-bogus'); 16986 if (!isInternalElement && isString(bogus)) { 16987 if (bogus === 'all') { 16988 remove$4(element); 16989 } else { 16990 unwrap(element); 16991 } 16992 return; 16993 } 16994 const rule = schema.getElementRule(lcTagName); 16995 if (validate && !rule) { 16996 if (has$2(specialElements, lcTagName)) { 16997 remove$4(element); 16998 } else { 16999 unwrap(element); 17000 } 17001 return; 17002 } else { 17003 if (isNonNullable(evt)) { 17004 evt.allowedTags[lcTagName] = true; 17005 } 17006 } 17007 if (validate && rule && !isInternalElement) { 17008 each$e((_c = rule.attributesForced) !== null && _c !== void 0 ? _c : [], attr => { 17009 set$4(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value); 17010 }); 17011 each$e((_d = rule.attributesDefault) !== null && _d !== void 0 ? _d : [], attr => { 17012 if (!has$1(element, attr.name)) { 17013 set$4(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value); 17014 } 17015 }); 17016 if (rule.attributesRequired && !exists(rule.attributesRequired, attr => has$1(element, attr))) { 17017 unwrap(element); 17018 return; 17019 } 17020 if (rule.removeEmptyAttrs && hasNone(element)) { 17021 unwrap(element); 17022 return; 17023 }
17024 if (rule.outputName && rule.outputName !== lcTagName) { 17025 mutate(element, rule.outputName); 17026 } 17027 } 17028 }; 17029 const processAttr = (ele, settings, schema, scope, evt) => { 17030 const tagName = ele.tagName.toLowerCase(); 17031 const {attrName, attrValue} = evt; 17032 evt.keepAttr = shouldKeepAttribute(settings, schema, scope, tagName, attrName, attrValue); 17033 if (evt.keepAttr) { 17034 evt.allowedAttributes[attrName] = true; 17035 if (isBooleanAttribute(attrName, schema)) { 17036 evt.attrValue = attrName; 17037 } 17038 if (settings.allow_svg_data_urls && startsWith(attrValue, 'data:image/svg+xml')) { 17039 evt.forceKeepAttr = true; 17040 } 17041 } else if (isRequiredAttributeOfInternalElement(ele, attrName)) { 17042 evt.forceKeepAttr = true; 17043 } 17044 }; 17045 const shouldKeepAttribute = (settings, schema, scope, tagName, attrName, attrValue) => { 17046 if (scope !== 'html' && !isNonHtmlElementRootName(tagName)) { 17047 return true; 17048 } 17049 return !(attrName in filteredUrlAttrs && isInvalidUri(settings, attrValue, tagName)) && (!settings.validate || schema.isValid(tagName, attrName) || startsWith(attrName, 'data-') || startsWith(attrName, 'aria-')); 17050 }; 17051 const isRequiredAttributeOfInternalElement = (ele, attrName) => ele.hasAttribute(internalElementAttr) && (attrName === 'id' || attrName === 'class' || attrName === 'style'); 17052 const isBooleanAttribute = (attrName, schema) => attrName in schema.getBoolAttrs(); 17053 const filterAttributes = (ele, settings, schema, scope) => { 17054 const {attributes} = ele; 17055 for (let i = attributes.length - 1; i >= 0; i--) { 17056 const attr = attributes[i]; 17057 const attrName = attr.name; 17058 const attrValue = attr.value; 17059 if (!shouldKeepAttribute(settings, schema, scope, ele.tagName.toLowerCase(), attrName, attrValue) && !isRequiredAttributeOfInternalElement(ele, attrName)) { 17060 ele.removeAttribute(attrName); 17061 } else if (isBooleanAttribute(attrName, schema)) { 17062 ele.setAttribute(attrName, attrName); 17063 } 17064 } 17065 }; 17066 const setupPurify = (settings, schema, namespaceTracker) => { 17067 const purify$1 = purify(); 17068 purify$1.addHook('uponSanitizeElement', (ele, evt) => { 17069 processNode(ele, settings, schema, namespaceTracker.track(ele), evt); 17070 }); 17071 purify$1.addHook('uponSanitizeAttribute', (ele, evt) => { 17072 processAttr(ele, settings, schema, namespaceTracker.current(), evt); 17073 }); 17074 return purify$1; 17075 }; 17076 const getPurifyConfig = (settings, mimeType) => { 17077 const basePurifyConfig = { 17078 IN_PLACE: true, 17079 ALLOW_UNKNOWN_PROTOCOLS: true, 17080 ALLOWED_TAGS: [ 17081 '#comment', 17082 '#cdata-section', 17083 'body' 17084 ], 17085 ALLOWED_ATTR: [], 17086 SAFE_FOR_XML: false 17087 }; 17088 const config = { ...basePurifyConfig }; 17089 config.PARSER_MEDIA_TYPE = mimeType; 17090 if (settings.allow_script_urls) { 17091 config.ALLOWED_URI_REGEXP = /.*/; 17092 } else if (settings.allow_html_data_urls) { 17093 config.ALLOWED_URI_REGEXP = /^(?!(\w+script|mhtml):)/i; 17094 } 17095 return config; 17096 }; 17097 const sanitizeSvgElement = ele => { 17098 const xlinkAttrs = [ 17099 'type', 17100 'href', 17101 'role', 17102 'arcrole', 17103 'title', 17104 'show', 17105 'actuate', 17106 'label', 17107 'from', 17108 'to' 17109 ].map(name => `xlink:${ name }`); 17110 const config = { 17111 IN_PLACE: true, 17112 USE_PROFILES: { 17113 html: true, 17114 svg: true, 17115 svgFilters: true 17116 }, 17117 ALLOWED_ATTR: xlinkAttrs 17118 }; 17119 purify().sanitize(ele, config); 17120 }; 17121 const sanitizeMathmlElement = (node, settings) => { 17122 const config = { 17123 IN_PLACE: true, 17124 USE_PROFILES: { mathMl: true } 17125 }; 17126 const purify$1 = purify(); 17127 const allowedEncodings = settings.allow_mathml_annotation_encodings; 17128 const hasAllowedEncodings = isArray$1(allowedEncodings) && allowedEncodings.length > 0; 17129 const hasValidEncoding = el => { 17130 const encoding = el.getAttribute('encoding'); 17131 return hasAllowedEncodings && isString(encoding) && contains$2(allowedEncodings, encoding); 17132 }; 17133 purify$1.addHook('uponSanitizeElement', (node, evt) => { 17134 var _a; 17135 const lcTagName = (_a = evt.tagName) !== null && _a !== void 0 ? _a : node.nodeName.toLowerCase(); 17136 if (hasAllowedEncodings && lcTagName === 'semantics') { 17137 evt.allowedTags[lcTagName] = true; 17138 } 17139 if (lcTagName === 'annotation') { 17140 const elm = node;
vendor: 9,375 bytes, lines 17141-17372
17141 const keepElement = hasValidEncoding(elm); 17142 evt.allowedTags[lcTagName] = keepElement; 17143 if (!keepElement) { 17144 elm.remove(); 17145 } 17146 } 17147 }); 17148 purify$1.sanitize(node, config); 17149 }; 17150 const mkSanitizeNamespaceElement = settings => ele => { 17151 const namespaceType = toScopeType(ele); 17152 if (namespaceType === 'svg') { 17153 sanitizeSvgElement(ele); 17154 } else if (namespaceType === 'math') { 17155 sanitizeMathmlElement(ele, settings); 17156 } else { 17157 throw new Error('Not a namespace element'); 17158 } 17159 }; 17160 const getSanitizer = (settings, schema) => { 17161 const namespaceTracker = createNamespaceTracker(); 17162 if (settings.sanitize) { 17163 const purify = setupPurify(settings, schema, namespaceTracker); 17164 const sanitizeHtmlElement = (body, mimeType) => { 17165 purify.sanitize(body, getPurifyConfig(settings, mimeType)); 17166 purify.removed = []; 17167 namespaceTracker.reset(); 17168 }; 17169 return { 17170 sanitizeHtmlElement, 17171 sanitizeNamespaceElement: mkSanitizeNamespaceElement(settings) 17172 }; 17173 } else { 17174 const sanitizeHtmlElement = (body, _mimeType) => { 17175 const nodeIterator = document.createNodeIterator(body, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT); 17176 let node; 17177 while (node = nodeIterator.nextNode()) { 17178 const currentScope = namespaceTracker.track(node); 17179 processNode(node, settings, schema, currentScope); 17180 if (isElement$6(node)) { 17181 filterAttributes(node, settings, schema, currentScope); 17182 } 17183 } 17184 namespaceTracker.reset(); 17185 }; 17186 const sanitizeNamespaceElement = noop; 17187 return { 17188 sanitizeHtmlElement, 17189 sanitizeNamespaceElement 17190 }; 17191 } 17192 }; 17193 17194 const makeMap = Tools.makeMap, extend$1 = Tools.extend; 17195 const transferChildren = (parent, nativeParent, specialElements, nsSanitizer) => { 17196 const parentName = parent.name; 17197 const isSpecial = parentName in specialElements && parentName !== 'title' && parentName !== 'textarea' && parentName !== 'noscript'; 17198 const childNodes = nativeParent.childNodes; 17199 for (let ni = 0, nl = childNodes.length; ni < nl; ni++) { 17200 const nativeChild = childNodes[ni]; 17201 const child = new AstNode(nativeChild.nodeName.toLowerCase(), nativeChild.nodeType); 17202 if (isElement$6(nativeChild)) { 17203 const attributes = nativeChild.attributes; 17204 for (let ai = 0, al = attributes.length; ai < al; ai++) { 17205 const attr = attributes[ai]; 17206 child.attr(attr.name, attr.value); 17207 } 17208 if (isNonHtmlElementRootName(child.name)) { 17209 nsSanitizer(nativeChild); 17210 child.value = nativeChild.innerHTML; 17211 } 17212 } else if (isText$b(nativeChild)) { 17213 child.value = nativeChild.data; 17214 if (isSpecial) { 17215 child.raw = true; 17216 } 17217 } else if (isComment(nativeChild) || isCData(nativeChild) || isPi(nativeChild)) { 17218 child.value = nativeChild.data; 17219 } 17220 if (!isNonHtmlElementRootName(child.name)) { 17221 transferChildren(child, nativeChild, specialElements, nsSanitizer); 17222 } 17223 parent.append(child); 17224 } 17225 }; 17226 const walkTree = (root, preprocessors, postprocessors) => { 17227 const traverseOrder = []; 17228 for (let node = root, lastNode = node; node; lastNode = node, node = node.walk()) { 17229 const tempNode = node; 17230 each$e(preprocessors, preprocess => preprocess(tempNode)); 17231 if (isNullable(tempNode.parent) && tempNode !== root) { 17232 node = lastNode; 17233 } else { 17234 traverseOrder.push(tempNode); 17235 } 17236 } 17237 for (let i = traverseOrder.length - 1; i >= 0; i--) { 17238 const node = traverseOrder[i]; 17239 each$e(postprocessors, postprocess => postprocess(node)); 17240 } 17241 }; 17242 const whitespaceCleaner = (root, schema, settings, args) => { 17243 const validate = settings.validate; 17244 const nonEmptyElements = schema.getNonEmptyElements(); 17245 const whitespaceElements = schema.getWhitespaceElements(); 17246 const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements()); 17247 const textRootBlockElements = getTextRootBlockElements(schema); 17248 const allWhiteSpaceRegExp = /[ \t\r\n]+/g; 17249 const startWhiteSpaceRegExp = /^[ \t\r\n]+/; 17250 const endWhiteSpaceRegExp = /[ \t\r\n]+$/; 17251 const hasWhitespaceParent = node => { 17252 let tempNode = node.parent; 17253 while (isNonNullable(tempNode)) { 17254 if (tempNode.name in whitespaceElements) { 17255 return true; 17256 } else { 17257 tempNode = tempNode.parent; 17258 } 17259 } 17260 return false; 17261 }; 17262 const isTextRootBlockEmpty = node => { 17263 let tempNode = node; 17264 while (isNonNullable(tempNode)) { 17265 if (tempNode.name in textRootBlockElements) { 17266 return isEmpty(schema, nonEmptyElements, whitespaceElements, tempNode); 17267 } else { 17268 tempNode = tempNode.parent; 17269 } 17270 } 17271 return false; 17272 }; 17273 const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node) || isNonHtmlElementRootName(node.name) && node.parent === root; 17274 const isAtEdgeOfBlock = (node, start) => { 17275 const neighbour = start ? node.prev : node.next; 17276 if (isNonNullable(neighbour) || isNullable(node.parent)) { 17277 return false; 17278 } 17279 return isBlock(node.parent) && (node.parent !== root || args.isRootContent === true); 17280 }; 17281 const preprocess = node => { 17282 var _a; 17283 if (node.type === 3) { 17284 if (!hasWhitespaceParent(node)) { 17285 let text = (_a = node.value) !== null && _a !== void 0 ? _a : ''; 17286 text = text.replace(allWhiteSpaceRegExp, ' '); 17287 if (isLineBreakNode(node.prev, isBlock) || isAtEdgeOfBlock(node, true)) { 17288 text = text.replace(startWhiteSpaceRegExp, ''); 17289 } 17290 if (text.length === 0) { 17291 node.remove(); 17292 } else if (text === ' ' && node.prev && node.prev.type === COMMENT && node.next && node.next.type === COMMENT) { 17293 node.remove(); 17294 } else { 17295 node.value = text; 17296 } 17297 } 17298 } 17299 }; 17300 const postprocess = node => { 17301 var _a; 17302 if (node.type === 1) { 17303 const elementRule = schema.getElementRule(node.name); 17304 if (validate && elementRule) { 17305 const isNodeEmpty = isEmpty(schema, nonEmptyElements, whitespaceElements, node); 17306 if (elementRule.paddInEmptyBlock && isNodeEmpty && isTextRootBlockEmpty(node)) { 17307 paddEmptyNode(settings, args, isBlock, node); 17308 } else if (elementRule.removeEmpty && isNodeEmpty) { 17309 if (isBlock(node)) { 17310 node.remove(); 17311 } else { 17312 node.unwrap(); 17313 } 17314 } else if (elementRule.paddEmpty && (isNodeEmpty || isPaddedWithNbsp(node))) { 17315 paddEmptyNode(settings, args, isBlock, node); 17316 } 17317 } 17318 } else if (node.type === 3) { 17319 if (!hasWhitespaceParent(node)) { 17320 let text = (_a = node.value) !== null && _a !== void 0 ? _a : ''; 17321 if (node.next && isBlock(node.next) || isAtEdgeOfBlock(node, false)) { 17322 text = text.replace(endWhiteSpaceRegExp, ''); 17323 } 17324 if (text.length === 0) { 17325 node.remove(); 17326 } else { 17327 node.value = text; 17328 } 17329 } 17330 } 17331 }; 17332 return [ 17333 preprocess, 17334 postprocess 17335 ]; 17336 }; 17337 const getRootBlockName = (settings, args) => { 17338 var _a; 17339 const name = (_a = args.forced_root_block) !== null && _a !== void 0 ? _a : settings.forced_root_block; 17340 if (name === false) { 17341 return ''; 17342 } else if (name === true) { 17343 return 'p'; 17344 } else { 17345 return name; 17346 } 17347 }; 17348 const DomParser = (settings = {}, schema = Schema()) => { 17349 const nodeFilterRegistry = create$8(); 17350 const attributeFilterRegistry = create$8(); 17351 const defaultedSettings = { 17352 validate: true, 17353 root_name: 'body', 17354 sanitize: true, 17355 ...settings 17356 }; 17357 const parser = new DOMParser(); 17358 const sanitizer = getSanitizer(defaultedSettings, schema); 17359 const parseAndSanitizeWithContext = (html, rootName, format = 'html') => { 17360 const mimeType = format === 'xhtml' ? 'application/xhtml+xml' : 'text/html'; 17361 const isSpecialRoot = has$2(schema.getSpecialElements(), rootName.toLowerCase()); 17362 const content = isSpecialRoot ? `<${ rootName }>${ html }</${ rootName }>` : html; 17363 const makeWrap = () => { 17364 if (format === 'xhtml') { 17365 return `<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>${ content }</body></html>`; 17366 } else if (/^[\s]*<head/i.test(html) || /^[\s]*<html/i.test(html) || /^[\s]*<!DOCTYPE/i.test(html)) { 17367 return `<html>${ content }</html>`; 17368 } else { 17369 return `<body>${ content }</body>`; 17370 } 17371 }; 17372 const body = parser.parseFromString(makeWrap()
vendor: 15,328 bytes, lines 17372-17755
17372, mimeType).body; 17373 sanitizer.sanitizeHtmlElement(body, mimeType); 17374 return isSpecialRoot ? body.firstChild : body; 17375 }; 17376 const addNodeFilter = nodeFilterRegistry.addFilter; 17377 const getNodeFilters = nodeFilterRegistry.getFilters; 17378 const removeNodeFilter = nodeFilterRegistry.removeFilter; 17379 const addAttributeFilter = attributeFilterRegistry.addFilter; 17380 const getAttributeFilters = attributeFilterRegistry.getFilters; 17381 const removeAttributeFilter = attributeFilterRegistry.removeFilter; 17382 const findInvalidChildren = (node, invalidChildren) => { 17383 if (isInvalid(schema, node)) { 17384 invalidChildren.push(node); 17385 } 17386 }; 17387 const isWrappableNode = (blockElements, node) => { 17388 const isInternalElement = isString(node.attr(internalElementAttr)); 17389 const isInlineElement = node.type === 1 && (!has$2(blockElements, node.name) && !isTransparentAstBlock(schema, node)) && !isNonHtmlElementRootName(node.name); 17390 return node.type === 3 || isInlineElement && !isInternalElement; 17391 }; 17392 const addRootBlocks = (rootNode, rootBlockName) => { 17393 const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements()); 17394 const startWhiteSpaceRegExp = /^[ \t\r\n]+/; 17395 const endWhiteSpaceRegExp = /[ \t\r\n]+$/; 17396 let node = rootNode.firstChild, rootBlockNode = null; 17397 const trim = rootBlock => { 17398 var _a, _b; 17399 if (rootBlock) { 17400 node = rootBlock.firstChild; 17401 if (node && node.type === 3) { 17402 node.value = (_a = node.value) === null || _a === void 0 ? void 0 : _a.replace(startWhiteSpaceRegExp, ''); 17403 } 17404 node = rootBlock.lastChild; 17405 if (node && node.type === 3) { 17406 node.value = (_b = node.value) === null || _b === void 0 ? void 0 : _b.replace(endWhiteSpaceRegExp, ''); 17407 } 17408 } 17409 }; 17410 if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) { 17411 return; 17412 } 17413 while (node) { 17414 const next = node.next; 17415 if (isWrappableNode(blockElements, node)) { 17416 if (!rootBlockNode) { 17417 rootBlockNode = new AstNode(rootBlockName, 1); 17418 rootBlockNode.attr(defaultedSettings.forced_root_block_attrs); 17419 rootNode.insert(rootBlockNode, node); 17420 rootBlockNode.append(node); 17421 } else { 17422 rootBlockNode.append(node); 17423 } 17424 } else { 17425 trim(rootBlockNode); 17426 rootBlockNode = null; 17427 } 17428 node = next; 17429 } 17430 trim(rootBlockNode); 17431 }; 17432 const parse = (html, args = {}) => { 17433 var _a; 17434 const validate = defaultedSettings.validate; 17435 const rootName = (_a = args.context) !== null && _a !== void 0 ? _a : defaultedSettings.root_name; 17436 const element = parseAndSanitizeWithContext(html, rootName, args.format); 17437 updateChildren(schema, element); 17438 const rootNode = new AstNode(rootName, 11); 17439 transferChildren(rootNode, element, schema.getSpecialElements(), sanitizer.sanitizeNamespaceElement); 17440 element.innerHTML = ''; 17441 const [whitespacePre, whitespacePost] = whitespaceCleaner(rootNode, schema, defaultedSettings, args); 17442 const invalidChildren = []; 17443 const invalidFinder = validate ? node => findInvalidChildren(node, invalidChildren) : noop; 17444 const matches = { 17445 nodes: {}, 17446 attributes: {} 17447 }; 17448 const matchFinder = node => matchNode$1(getNodeFilters(), getAttributeFilters(), node, matches); 17449 walkTree(rootNode, [ 17450 whitespacePre, 17451 matchFinder 17452 ], [ 17453 whitespacePost, 17454 invalidFinder 17455 ]); 17456 invalidChildren.reverse(); 17457 if (validate && invalidChildren.length > 0) { 17458 if (args.context) { 17459 const { 17460 pass: topLevelChildren, 17461 fail: otherChildren 17462 } = partition$2(invalidChildren, child => child.parent === rootNode); 17463 cleanInvalidNodes(otherChildren, schema, rootNode, matchFinder); 17464 args.invalid = topLevelChildren.length > 0; 17465 } else { 17466 cleanInvalidNodes(invalidChildren, schema, rootNode, matchFinder); 17467 } 17468 } 17469 const rootBlockName = getRootBlockName(defaultedSettings, args); 17470 if (rootBlockName && (rootNode.name === 'body' || args.isRootContent)) { 17471 addRootBlocks(rootNode, rootBlockName); 17472 } 17473 if (!args.invalid) { 17474 runFilters(matches, args); 17475 } 17476 return rootNode; 17477 }; 17478 const exports = { 17479 schema, 17480 addAttributeFilter, 17481 getAttributeFilters, 17482 removeAttributeFilter, 17483 addNodeFilter, 17484 getNodeFilters, 17485 removeNodeFilter, 17486 parse 17487 }; 17488 register$4(exports, defaultedSettings); 17489 register$5(exports, defaultedSettings, schema); 17490 return exports; 17491 }; 17492 17493 const serializeContent = content => isTreeNode(content) ? HtmlSerializer({ validate: false }).serialize(content) : content; 17494 const withSerializedContent = (content, fireEvent, parserSettings) => { 17495 const serializedContent = serializeContent(content); 17496 const eventArgs = fireEvent(serializedContent); 17497 if (eventArgs.isDefaultPrevented()) { 17498 return eventArgs; 17499 } else if (isTreeNode(content)) { 17500 if (eventArgs.content !== serializedContent) { 17501 const rootNode = DomParser({ 17502 validate: false, 17503 forced_root_block: false, 17504 ...parserSettings 17505 }).parse(eventArgs.content, { context: content.name }); 17506 return { 17507 ...eventArgs, 17508 content: rootNode 17509 }; 17510 } else { 17511 return { 17512 ...eventArgs, 17513 content 17514 }; 17515 } 17516 } else { 17517 return eventArgs; 17518 } 17519 }; 17520 const makeParserSettings = editor => ({ 17521 sanitize: shouldSanitizeXss(editor), 17522 sandbox_iframes: shouldSandboxIframes(editor), 17523 sandbox_iframes_exclusions: getSandboxIframesExclusions(editor) 17524 }); 17525 const preProcessGetContent = (editor, args) => { 17526 if (args.no_events) { 17527 return Result.value(args); 17528 } else { 17529 const eventArgs = fireBeforeGetContent(editor, args); 17530 if (eventArgs.isDefaultPrevented()) { 17531 return Result.error(fireGetContent(editor, { 17532 content: '', 17533 ...eventArgs 17534 }).content); 17535 } else { 17536 return Result.value(eventArgs); 17537 } 17538 } 17539 }; 17540 const postProcessGetContent = (editor, content, args) => { 17541 if (args.no_events) { 17542 return content; 17543 } else { 17544 const processedEventArgs = withSerializedContent(content, content => fireGetContent(editor, { 17545 ...args, 17546 content 17547 }), makeParserSettings(editor)); 17548 return processedEventArgs.content; 17549 } 17550 }; 17551 const preProcessSetContent = (editor, args) => { 17552 if (args.no_events) { 17553 return Result.value(args); 17554 } else { 17555 const processedEventArgs = withSerializedContent(args.content, content => fireBeforeSetContent(editor, { 17556 ...args, 17557 content 17558 }), makeParserSettings(editor)); 17559 if (processedEventArgs.isDefaultPrevented()) { 17560 fireSetContent(editor, processedEventArgs); 17561 return Result.error(undefined); 17562 } else { 17563 return Result.value(processedEventArgs); 17564 } 17565 } 17566 }; 17567 const postProcessSetContent = (editor, content, args) => { 17568 if (!args.no_events) { 17569 fireSetContent(editor, { 17570 ...args, 17571 content 17572 }); 17573 } 17574 }; 17575 17576 const tableModel = (element, width, rows) => ({ 17577 element, 17578 width, 17579 rows 17580 }); 17581 const tableRow = (element, cells) => ({ 17582 element, 17583 cells 17584 }); 17585 const cellPosition = (x, y) => ({ 17586 x, 17587 y 17588 }); 17589 const getSpan = (td, key) => { 17590 return getOpt(td, key).bind(toInt).getOr(1); 17591 }; 17592 const fillout = (table, x, y, tr, td) => { 17593 const rowspan = getSpan(td, 'rowspan'); 17594 const colspan = getSpan(td, 'colspan'); 17595 const rows = table.rows; 17596 for (let y2 = y; y2 < y + rowspan; y2++) { 17597 if (!rows[y2]) { 17598 rows[y2] = tableRow(deep$1(tr), []); 17599 } 17600 for (let x2 = x; x2 < x + colspan; x2++) { 17601 const cells = rows[y2].cells; 17602 cells[x2] = y2 === y && x2 === x ? td : shallow$1(td); 17603 } 17604 } 17605 }; 17606 const cellExists = (table, x, y) => { 17607 const rows = table.rows; 17608 const cells = rows[y] ? rows[y].cells : []; 17609 return !!cells[x]; 17610 }; 17611 const skipCellsX = (table, x, y) => { 17612 while (cellExists(table, x, y)) { 17613 x++; 17614 } 17615 return x; 17616 }; 17617 const getWidth = rows => { 17618 return foldl(rows, (acc, row) => { 17619 return row.cells.length > acc ? row.cells.length : acc; 17620 }, 0); 17621 }; 17622 const findElementPos = (table, element) => { 17623 const rows = table.rows; 17624 for (let y = 0; y < rows.length; y++) { 17625 const cells = rows[y].cells; 17626 for (let x = 0; x < cells.length; x++) { 17627 if (eq(cells[x], element)) { 17628 return Optional.some(cellPosition(x, y)); 17629 } 17630 } 17631 } 17632 return Optional.none(); 17633 }; 17634 const extractRows = (table, sx, sy, ex, ey) => { 17635 const newRows = []; 17636 const rows = table.rows; 17637 for (let y = sy; y <= ey; y++) { 17638 const cells = rows[y].cells; 17639 const slice = sx < ex ? cells.slice(sx, ex + 1) : cells.slice(ex, sx + 1); 17640 newRows.push(tableRow(rows[y].element, slice)); 17641 } 17642 return newRows; 17643 }; 17644 const subTable = (table, startPos, endPos) => { 17645 const sx = startPos.x, sy = startPos.y; 17646 const ex = endPos.x, ey = endPos.y; 17647 const newRows = sy < ey ? extractRows(table, sx, sy, ex, ey) : extractRows(table, sx, ey, ex, sy); 17648 return tableModel(table.element, getWidth(newRows), newRows); 17649 }; 17650 const createDomTable = (table, rows) => { 17651 const tableElement = shallow$1(table.element); 17652 const tableBody = SugarElement.fromTag('tbody'); 17653 append(tableBody, rows); 17654 append$1(tableElement, tableBody); 17655 return tableElement; 17656 }; 17657 const modelRowsToDomRows = table => { 17658 return map$3(table.rows, row => { 17659 const cells = map$3(row.cells, cell => { 17660 const td = deep$1(cell); 17661 remove$9(td, 'colspan'); 17662 remove$9(td, 'rowspan'); 17663 return td; 17664 }); 17665 const tr = shallow$1(row.element); 17666 append(tr, cells); 17667 return tr; 17668 }); 17669 }; 17670 const fromDom = tableElm => { 17671 const table = tableModel(shallow$1(tableElm), 0, []); 17672 each$e(descendants(tableElm, 'tr'), (tr, y) => { 17673 each$e(descendants(tr, 'td,th'), (td, x) => { 17674 fillout(table, skipCellsX(table, x, y), y, tr, td); 17675 }); 17676 }); 17677 return tableModel(table.element, getWidth(table.rows), table.rows); 17678 }; 17679 const toDom = table => { 17680 return createDomTable(table, modelRowsToDomRows(table)); 17681 }; 17682 const subsection = (table, startElement, endElement) => { 17683 return findElementPos(table, startElement).bind(startPos => { 17684 return findElementPos(table, endElement).map(endPos => { 17685 return subTable(table, startPos, endPos); 17686 }); 17687 }); 17688 }; 17689 17690 const findParentListContainer = parents => find$2(parents, elm => name(elm) === 'ul' || name(elm) === 'ol'); 17691 const getFullySelectedListWrappers = (parents, rng) => find$2(parents, elm => name(elm) === 'li' && hasAllContentsSelected(elm, rng)).fold(constant([]), _li => findParentListContainer(parents).map(listCont => { 17692 const listElm = SugarElement.fromTag(name(listCont)); 17693 const listStyles = filter$4(getAllRaw(listCont), (_style, name) => startsWith(name, 'list-style')); 17694 setAll(listElm, listStyles); 17695 return [ 17696 SugarElement.fromTag('li'), 17697 listElm 17698 ]; 17699 }).getOr([])); 17700 const wrap = (innerElm, elms) => { 17701 const wrapped = foldl(elms, (acc, elm) => { 17702 append$1(elm, acc); 17703 return elm; 17704 }, innerElm); 17705 return elms.length > 0 ? fromElements([wrapped]) : wrapped; 17706 }; 17707 const directListWrappers = commonAnchorContainer => { 17708 if (isListItem$1(commonAnchorContainer)) { 17709 return parent(commonAnchorContainer).filter(isList).fold(constant([]), listElm => [ 17710 commonAnchorContainer, 17711 listElm 17712 ]); 17713 } else { 17714 return isList(commonAnchorContainer) ? [commonAnchorContainer] : []; 17715 } 17716 }; 17717 const getWrapElements = (rootNode, rng, schema) => { 17718 const commonAnchorContainer = SugarElement.fromDom(rng.commonAncestorContainer); 17719 const parents = parentsAndSelf(commonAnchorContainer, rootNode); 17720 const wrapElements = filter$5(parents, el => schema.isWrapper(name(el))); 17721 const listWrappers = getFullySelectedListWrappers(parents, rng); 17722 const allWrappers = wrapElements.concat(listWrappers.length ? listWrappers : directListWrappers(commonAnchorContainer)); 17723 return map$3(allWrappers, shallow$1); 17724 }; 17725 const emptyFragment = () => fromElements([]); 17726 const getFragmentFromRange = (rootNode, rng, schema) => wrap(SugarElement.fromDom(rng.cloneContents()), getWrapElements(rootNode, rng, schema)); 17727 const getParentTable = (rootElm, cell) => ancestor$3(cell, 'table', curry(eq, rootElm)); 17728 const getTableFragment = (rootNode, selectedTableCells) => getParentTable(rootNode, selectedTableCells[0]).bind(tableElm => { 17729 const firstCell = selectedTableCells[0]; 17730 const lastCell = selectedTableCells[selectedTableCells.length - 1]; 17731 const fullTableModel = fromDom(tableElm); 17732 return subsection(fullTableModel, firstCell, lastCell).map(sectionedTableModel => fromElements([toDom(sectionedTableModel)])); 17733 }).getOrThunk(emptyFragment); 17734 const getSelectionFragment = (rootNode, ranges, schema) => ranges.length > 0 && ranges[0].collapsed ? emptyFragment() : getFragmentFromRange(rootNode, ranges[0], schema); 17735 const read$3 = (rootNode, ranges, schema) => { 17736 const selectedCells = getCellsFromElementOrRanges(ranges, rootNode); 17737 return selectedCells.length > 0 ? getTableFragment(rootNode, selectedCells) : getSelectionFragment(rootNode, ranges, schema); 17738 }; 17739 17740 const isCollapsibleWhitespace = (text, index) => index >= 0 && index < text.length && isWhiteSpace(text.charAt(index)); 17741 const getInnerText = bin => { 17742 return trim$2(bin.innerText); 17743 }; 17744 const getContextNodeName = parentBlockOpt => parentBlockOpt.map(block => block.nodeName).getOr('div').toLowerCase(); 17745 const getTextContent = editor => Optional.from(editor.selection.getRng()).map(rng => { 17746 var _a; 17747 const parentBlockOpt = Optional.from(editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock)); 17748 const body = editor.getBody(); 17749 const contextNodeName = getContextNodeName(parentBlockOpt); 17750 const rangeContentClone = SugarElement.fromDom(rng.cloneContents()); 17751 cleanupBogusElements(rangeContentClone); 17752 cleanupInputNames(rangeContentClone); 17753 const bin = editor.dom.add(body, contextNodeName, { 17754 'data-mce-bogus': 'all', 17755
17755'style'
vendor: 10,233 bytes, lines 17755-18042
17755: 'overflow: hidden; opacity: 0;' 17756 }, rangeContentClone.dom); 17757 const text = getInnerText(bin); 17758 const nonRenderedText = trim$2((_a = bin.textContent) !== null && _a !== void 0 ? _a : ''); 17759 editor.dom.remove(bin); 17760 if (isCollapsibleWhitespace(nonRenderedText, 0) || isCollapsibleWhitespace(nonRenderedText, nonRenderedText.length - 1)) { 17761 const parentBlock = parentBlockOpt.getOr(body); 17762 const parentBlockText = getInnerText(parentBlock); 17763 const textIndex = parentBlockText.indexOf(text); 17764 if (textIndex === -1) { 17765 return text; 17766 } else { 17767 const hasProceedingSpace = isCollapsibleWhitespace(parentBlockText, textIndex - 1); 17768 const hasTrailingSpace = isCollapsibleWhitespace(parentBlockText, textIndex + text.length); 17769 return (hasProceedingSpace ? ' ' : '') + text + (hasTrailingSpace ? ' ' : ''); 17770 } 17771 } else { 17772 return text; 17773 } 17774 }).getOr(''); 17775 const getSerializedContent = (editor, args) => { 17776 const rng = editor.selection.getRng(), tmpElm = editor.dom.create('body'); 17777 const sel = editor.selection.getSel(); 17778 const ranges = processRanges(editor, getRanges$1(sel)); 17779 const fragment = args.contextual ? read$3(SugarElement.fromDom(editor.getBody()), ranges, editor.schema).dom : rng.cloneContents(); 17780 if (fragment) { 17781 tmpElm.appendChild(fragment); 17782 } 17783 return editor.selection.serializer.serialize(tmpElm, args); 17784 }; 17785 const extractSelectedContent = (editor, args) => { 17786 if (args.format === 'text') { 17787 return getTextContent(editor); 17788 } else { 17789 const content = getSerializedContent(editor, args); 17790 if (args.format === 'tree') { 17791 return content; 17792 } else { 17793 return editor.selection.isCollapsed() ? '' : content; 17794 } 17795 } 17796 }; 17797 const setupArgs$3 = (args, format) => ({ 17798 ...args, 17799 format, 17800 get: true, 17801 selection: true, 17802 getInner: true 17803 }); 17804 const getSelectedContentInternal = (editor, format, args = {}) => { 17805 const defaultedArgs = setupArgs$3(args, format); 17806 return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => { 17807 const content = extractSelectedContent(editor, updatedArgs); 17808 return postProcessGetContent(editor, content, updatedArgs); 17809 }); 17810 }; 17811 17812 const KEEP = 0, INSERT = 1, DELETE = 2; 17813 const diff = (left, right) => { 17814 const size = left.length + right.length + 2; 17815 const vDown = new Array(size); 17816 const vUp = new Array(size); 17817 const snake = (start, end, diag) => { 17818 return { 17819 start, 17820 end, 17821 diag 17822 }; 17823 }; 17824 const buildScript = (start1, end1, start2, end2, script) => { 17825 const middle = getMiddleSnake(start1, end1, start2, end2); 17826 if (middle === null || middle.start === end1 && middle.diag === end1 - end2 || middle.end === start1 && middle.diag === start1 - start2) { 17827 let i = start1; 17828 let j = start2; 17829 while (i < end1 || j < end2) { 17830 if (i < end1 && j < end2 && left[i] === right[j]) { 17831 script.push([ 17832 KEEP, 17833 left[i] 17834 ]); 17835 ++i; 17836 ++j; 17837 } else { 17838 if (end1 - start1 > end2 - start2) { 17839 script.push([ 17840 DELETE, 17841 left[i] 17842 ]); 17843 ++i; 17844 } else { 17845 script.push([ 17846 INSERT, 17847 right[j] 17848 ]); 17849 ++j; 17850 } 17851 } 17852 } 17853 } else { 17854 buildScript(start1, middle.start, start2, middle.start - middle.diag, script); 17855 for (let i2 = middle.start; i2 < middle.end; ++i2) { 17856 script.push([ 17857 KEEP, 17858 left[i2] 17859 ]); 17860 } 17861 buildScript(middle.end, end1, middle.end - middle.diag, end2, script); 17862 } 17863 }; 17864 const buildSnake = (start, diag, end1, end2) => { 17865 let end = start; 17866 while (end - diag < end2 && end < end1 && left[end] === right[end - diag]) { 17867 ++end; 17868 } 17869 return snake(start, end, diag); 17870 }; 17871 const getMiddleSnake = (start1, end1, start2, end2) => { 17872 const m = end1 - start1; 17873 const n = end2 - start2; 17874 if (m === 0 || n === 0) { 17875 return null; 17876 } 17877 const delta = m - n; 17878 const sum = n + m; 17879 const offset = (sum % 2 === 0 ? sum : sum + 1) / 2; 17880 vDown[1 + offset] = start1; 17881 vUp[1 + offset] = end1 + 1; 17882 let d, k, i, x, y; 17883 for (d = 0; d <= offset; ++d) { 17884 for (k = -d; k <= d; k += 2) { 17885 i = k + offset; 17886 if (k === -d || k !== d && vDown[i - 1] < vDown[i + 1]) { 17887 vDown[i] = vDown[i + 1]; 17888 } else { 17889 vDown[i] = vDown[i - 1] + 1; 17890 } 17891 x = vDown[i]; 17892 y = x - start1 + start2 - k; 17893 while (x < end1 && y < end2 && left[x] === right[y]) { 17894 vDown[i] = ++x; 17895 ++y; 17896 } 17897 if (delta % 2 !== 0 && delta - d <= k && k <= delta + d) { 17898 if (vUp[i - delta] <= vDown[i]) { 17899 return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2); 17900 } 17901 } 17902 } 17903 for (k = delta - d; k <= delta + d; k += 2) { 17904 i = k + offset - delta; 17905 if (k === delta - d || k !== delta + d && vUp[i + 1] <= vUp[i - 1]) { 17906 vUp[i] = vUp[i + 1] - 1; 17907 } else { 17908 vUp[i] = vUp[i - 1]; 17909 } 17910 x = vUp[i] - 1; 17911 y = x - start1 + start2 - k; 17912 while (x >= start1 && y >= start2 && left[x] === right[y]) { 17913 vUp[i] = x--; 17914 y--; 17915 } 17916 if (delta % 2 === 0 && -d <= k && k <= d) { 17917 if (vUp[i] <= vDown[i + delta]) { 17918 return buildSnake(vUp[i], k + start1 - start2, end1, end2); 17919 } 17920 } 17921 } 17922 } 17923 return null; 17924 }; 17925 const script = []; 17926 buildScript(0, left.length, 0, right.length, script); 17927 return script; 17928 }; 17929 17930 const getOuterHtml = elm => { 17931 if (isElement$6(elm)) { 17932 return elm.outerHTML; 17933 } else if (isText$b(elm)) { 17934 return Entities.encodeRaw(elm.data, false); 17935 } else if (isComment(elm)) { 17936 return '<!--' + elm.data + '-->'; 17937 } 17938 return ''; 17939 }; 17940 const createFragment = html => { 17941 let node; 17942 const container = document.createElement('div'); 17943 const frag = document.createDocumentFragment(); 17944 if (html) { 17945 container.innerHTML = html; 17946 } 17947 while (node = container.firstChild) { 17948 frag.appendChild(node); 17949 } 17950 return frag; 17951 }; 17952 const insertAt = (elm, html, index) => { 17953 const fragment = createFragment(html); 17954 if (elm.hasChildNodes() && index < elm.childNodes.length) { 17955 const target = elm.childNodes[index]; 17956 elm.insertBefore(fragment, target); 17957 } else { 17958 elm.appendChild(fragment); 17959 } 17960 }; 17961 const removeAt = (elm, index) => { 17962 if (elm.hasChildNodes() && index < elm.childNodes.length) { 17963 const target = elm.childNodes[index]; 17964 elm.removeChild(target); 17965 } 17966 }; 17967 const applyDiff = (diff, elm) => { 17968 let index = 0; 17969 each$e(diff, action => { 17970 if (action[0] === KEEP) { 17971 index++; 17972 } else if (action[0] === INSERT) { 17973 insertAt(elm, action[1], index); 17974 index++; 17975 } else if (action[0] === DELETE) { 17976 removeAt(elm, index); 17977 } 17978 }); 17979 }; 17980 const read$2 = (elm, trimZwsp) => filter$5(map$3(from(elm.childNodes), trimZwsp ? compose(trim$2, getOuterHtml) : getOuterHtml), item => { 17981 return item.length > 0; 17982 }); 17983 const write = (fragments, elm) => { 17984 const currentFragments = map$3(from(elm.childNodes), getOuterHtml); 17985 applyDiff(diff(currentFragments, fragments), elm); 17986 return elm; 17987 }; 17988 17989 const lazyTempDocument = cached(() => document.implementation.createHTMLDocument('undo')); 17990 const hasIframes = body => body.querySelector('iframe') !== null; 17991 const createFragmentedLevel = fragments => { 17992 return { 17993 type: 'fragmented', 17994 fragments, 17995 content: '', 17996 bookmark: null, 17997 beforeBookmark: null 17998 }; 17999 }; 18000 const createCompleteLevel = content => { 18001 return { 18002 type: 'complete', 18003 fragments: null, 18004 content, 18005 bookmark: null, 18006 beforeBookmark: null 18007 }; 18008 }; 18009 const createFromEditor = editor => { 18010 const tempAttrs = editor.serializer.getTempAttrs(); 18011 const body = trim$1(editor.getBody(), tempAttrs); 18012 return hasIframes(body) ? createFragmentedLevel(read$2(body, true)) : createCompleteLevel(trim$2(body.innerHTML)); 18013 }; 18014 const applyToEditor = (editor, level, before) => { 18015 const bookmark = before ? level.beforeBookmark : level.bookmark; 18016 if (level.type === 'fragmented') { 18017 write(level.fragments, editor.getBody()); 18018 } else { 18019 editor.setContent(level.content, { 18020 format: 'raw', 18021 no_selection: isNonNullable(bookmark) && isPathBookmark(bookmark) ? !bookmark.isFakeCaret : true 18022 }); 18023 } 18024 if (bookmark) { 18025 editor.selection.moveToBookmark(bookmark); 18026 editor.selection.scrollIntoView(); 18027 } 18028 }; 18029 const getLevelContent = level => { 18030 return level.type === 'fragmented' ? level.fragments.join('') : level.content; 18031 }; 18032 const getCleanLevelContent = level => { 18033 const elm = SugarElement.fromTag('body', lazyTempDocument()); 18034 set$1(elm, getLevelContent(level)); 18035 each$e(descendants(elm, '*[data-mce-bogus]'), unwrap); 18036 return get$6(elm); 18037 }; 18038 const hasEqualContent = (level1, level2) => getLevelContent(level1) === getLevelContent(level2); 18039 const hasEqualCleanedContent = (level1, level2) => getCleanLevelContent(level1) === getCleanLevelContent(level2); 18040 const isEq$1 = (level1, level2) => { 18041 if (!level1 || !level2) { 18042 return false;
vendor: 4,404 bytes, lines 18043-18175
18043 } else if (hasEqualContent(level1, level2)) { 18044 return true; 18045 } else { 18046 return hasEqualCleanedContent(level1, level2); 18047 } 18048 }; 18049 18050 const isUnlocked = locks => locks.get() === 0; 18051 18052 const setTyping = (undoManager, typing, locks) => { 18053 if (isUnlocked(locks)) { 18054 undoManager.typing = typing; 18055 } 18056 }; 18057 const endTyping = (undoManager, locks) => { 18058 if (undoManager.typing) { 18059 setTyping(undoManager, false, locks); 18060 undoManager.add(); 18061 } 18062 }; 18063 const endTypingLevelIgnoreLocks = undoManager => { 18064 if (undoManager.typing) { 18065 undoManager.typing = false; 18066 undoManager.add(); 18067 } 18068 }; 18069 18070 const beforeChange$1 = (editor, locks, beforeBookmark) => { 18071 if (isUnlocked(locks)) { 18072 beforeBookmark.set(getUndoBookmark(editor.selection)); 18073 } 18074 }; 18075 const addUndoLevel$1 = (editor, undoManager, index, locks, beforeBookmark, level, event) => { 18076 const currentLevel = createFromEditor(editor); 18077 const newLevel = Tools.extend(level || {}, currentLevel); 18078 if (!isUnlocked(locks) || editor.removed) { 18079 return null; 18080 } 18081 const lastLevel = undoManager.data[index.get()]; 18082 if (editor.dispatch('BeforeAddUndo', { 18083 level: newLevel, 18084 lastLevel, 18085 originalEvent: event 18086 }).isDefaultPrevented()) { 18087 return null; 18088 } 18089 if (lastLevel && isEq$1(lastLevel, newLevel)) { 18090 return null; 18091 } 18092 if (undoManager.data[index.get()]) { 18093 beforeBookmark.get().each(bm => { 18094 undoManager.data[index.get()].beforeBookmark = bm; 18095 }); 18096 } 18097 const customUndoRedoLevels = getCustomUndoRedoLevels(editor); 18098 if (customUndoRedoLevels) { 18099 if (undoManager.data.length > customUndoRedoLevels) { 18100 for (let i = 0; i < undoManager.data.length - 1; i++) { 18101 undoManager.data[i] = undoManager.data[i + 1]; 18102 } 18103 undoManager.data.length--; 18104 index.set(undoManager.data.length); 18105 } 18106 } 18107 newLevel.bookmark = getUndoBookmark(editor.selection); 18108 if (index.get() < undoManager.data.length - 1) { 18109 undoManager.data.length = index.get() + 1; 18110 } 18111 undoManager.data.push(newLevel); 18112 index.set(undoManager.data.length - 1); 18113 const args = { 18114 level: newLevel, 18115 lastLevel, 18116 originalEvent: event 18117 }; 18118 if (index.get() > 0) { 18119 editor.setDirty(true); 18120 editor.dispatch('AddUndo', args); 18121 editor.dispatch('change', args); 18122 } else { 18123 editor.dispatch('AddUndo', args); 18124 } 18125 return newLevel; 18126 }; 18127 const clear$1 = (editor, undoManager, index) => { 18128 undoManager.data = []; 18129 index.set(0); 18130 undoManager.typing = false; 18131 editor.dispatch('ClearUndos'); 18132 }; 18133 const extra$1 = (editor, undoManager, index, callback1, callback2) => { 18134 if (undoManager.transact(callback1)) { 18135 const bookmark = undoManager.data[index.get()].bookmark; 18136 const lastLevel = undoManager.data[index.get() - 1]; 18137 applyToEditor(editor, lastLevel, true); 18138 if (undoManager.transact(callback2)) { 18139 undoManager.data[index.get() - 1].beforeBookmark = bookmark; 18140 } 18141 } 18142 }; 18143 const redo$1 = (editor, index, data) => { 18144 let level; 18145 if (index.get() < data.length - 1) { 18146 index.set(index.get() + 1); 18147 level = data[index.get()]; 18148 applyToEditor(editor, level, false); 18149 editor.setDirty(true); 18150 editor.dispatch('Redo', { level }); 18151 } 18152 return level; 18153 }; 18154 const undo$1 = (editor, undoManager, locks, index) => { 18155 let level; 18156 if (undoManager.typing) { 18157 undoManager.add(); 18158 undoManager.typing = false; 18159 setTyping(undoManager, false, locks); 18160 } 18161 if (index.get() > 0) { 18162 index.set(index.get() - 1); 18163 level = undoManager.data[index.get()]; 18164 applyToEditor(editor, level, true); 18165 editor.setDirty(true); 18166 editor.dispatch('Undo', { level }); 18167 } 18168 return level; 18169 }; 18170 const reset$1 = undoManager => { 18171 undoManager.clear(); 18172 undoManager.add(); 18173 }; 18174 const hasUndo$1 = (editor, undoManager, index) => index.get() > 0 || undoManager.typing && undoManager.data[0] && !isEq$1(createFromEditor(editor), undoManager.data[0]); 18175 const hasRedo$1 = (undoManager, index) =>
vendor: 20,423 bytes, lines 18175-18638
18175 index.get() < undoManager.data.length - 1 && !undoManager.typing; 18176 const transact$1 = (undoManager, locks, callback) => { 18177 endTyping(undoManager, locks); 18178 undoManager.beforeChange(); 18179 undoManager.ignore(callback); 18180 return undoManager.add(); 18181 }; 18182 const ignore$1 = (locks, callback) => { 18183 try { 18184 locks.set(locks.get() + 1); 18185 callback(); 18186 } finally { 18187 locks.set(locks.get() - 1); 18188 } 18189 }; 18190 18191 const addVisualInternal = (editor, elm) => { 18192 const dom = editor.dom; 18193 const scope = isNonNullable(elm) ? elm : editor.getBody(); 18194 each$e(dom.select('table,a', scope), matchedElm => { 18195 switch (matchedElm.nodeName) { 18196 case 'TABLE': 18197 const cls = getVisualAidsTableClass(editor); 18198 const value = dom.getAttrib(matchedElm, 'border'); 18199 if ((!value || value === '0') && editor.hasVisual) { 18200 dom.addClass(matchedElm, cls); 18201 } else { 18202 dom.removeClass(matchedElm, cls); 18203 } 18204 break; 18205 case 'A': 18206 if (!dom.getAttrib(matchedElm, 'href')) { 18207 const value = dom.getAttrib(matchedElm, 'name') || matchedElm.id; 18208 const cls = getVisualAidsAnchorClass(editor); 18209 if (value && editor.hasVisual) { 18210 dom.addClass(matchedElm, cls); 18211 } else { 18212 dom.removeClass(matchedElm, cls); 18213 } 18214 } 18215 break; 18216 } 18217 }); 18218 editor.dispatch('VisualAid', { 18219 element: elm, 18220 hasVisual: editor.hasVisual 18221 }); 18222 }; 18223 18224 const makePlainAdaptor = editor => ({ 18225 init: { bindEvents: noop }, 18226 undoManager: { 18227 beforeChange: (locks, beforeBookmark) => beforeChange$1(editor, locks, beforeBookmark), 18228 add: (undoManager, index, locks, beforeBookmark, level, event) => addUndoLevel$1(editor, undoManager, index, locks, beforeBookmark, level, event), 18229 undo: (undoManager, locks, index) => undo$1(editor, undoManager, locks, index), 18230 redo: (index, data) => redo$1(editor, index, data), 18231 clear: (undoManager, index) => clear$1(editor, undoManager, index), 18232 reset: undoManager => reset$1(undoManager), 18233 hasUndo: (undoManager, index) => hasUndo$1(editor, undoManager, index), 18234 hasRedo: (undoManager, index) => hasRedo$1(undoManager, index), 18235 transact: (undoManager, locks, callback) => transact$1(undoManager, locks, callback), 18236 ignore: (locks, callback) => ignore$1(locks, callback), 18237 extra: (undoManager, index, callback1, callback2) => extra$1(editor, undoManager, index, callback1, callback2) 18238 }, 18239 formatter: { 18240 match: (name, vars, node, similar) => match$2(editor, name, vars, node, similar), 18241 matchAll: (names, vars) => matchAll(editor, names, vars), 18242 matchNode: (node, name, vars, similar) => matchNode(editor, node, name, vars, similar), 18243 canApply: name => canApply(editor, name), 18244 closest: names => closest(editor, names), 18245 apply: (name, vars, node) => applyFormat$1(editor, name, vars, node), 18246 remove: (name, vars, node, similar) => removeFormat$1(editor, name, vars, node, similar), 18247 toggle: (name, vars, node) => toggle(editor, name, vars, node), 18248 formatChanged: (registeredFormatListeners, formats, callback, similar, vars) => formatChangedInternal(editor, registeredFormatListeners, formats, callback, similar, vars) 18249 }, 18250 editor: { 18251 getContent: args => getContentInternal(editor, args), 18252 setContent: (content, args) => setContentInternal(editor, content, args), 18253 insertContent: (value, details) => insertHtmlAtCaret(editor, value, details), 18254 addVisual: elm => addVisualInternal(editor, elm) 18255 }, 18256 selection: { getContent: (format, args) => getSelectedContentInternal(editor, format, args) }, 18257 autocompleter: { 18258 addDecoration: noop, 18259 removeDecoration: noop 18260 }, 18261 raw: { getModel: () => Optional.none() } 18262 }); 18263 const makeRtcAdaptor = rtcEditor => { 18264 const defaultVars = vars => isObject(vars) ? vars : {}; 18265 const {init, undoManager, formatter, editor, selection, autocompleter, raw} = rtcEditor; 18266 return { 18267 init: { bindEvents: init.bindEvents }, 18268 undoManager: { 18269 beforeChange: undoManager.beforeChange, 18270 add: undoManager.add, 18271 undo: undoManager.undo, 18272 redo: undoManager.redo, 18273 clear: undoManager.clear, 18274 reset: undoManager.reset, 18275 hasUndo: undoManager.hasUndo, 18276 hasRedo: undoManager.hasRedo, 18277 transact: (_undoManager, _locks, fn) => undoManager.transact(fn), 18278 ignore: (_locks, callback) => undoManager.ignore(callback), 18279 extra: (_undoManager, _index, callback1, callback2) => undoManager.extra(callback1, callback2) 18280 }, 18281 formatter: { 18282 match: (name, vars, _node, similar) => formatter.match(name, defaultVars(vars), similar), 18283 matchAll: formatter.matchAll, 18284 matchNode: formatter.matchNode, 18285 canApply: name => formatter.canApply(name), 18286 closest: names => formatter.closest(names), 18287 apply: (name, vars, _node) => formatter.apply(name, defaultVars(vars)), 18288 remove: (name, vars, _node, _similar) => formatter.remove(name, defaultVars(vars)), 18289 toggle: (name, vars, _node) => formatter.toggle(name, defaultVars(vars)), 18290 formatChanged: (_rfl, formats, callback, similar, vars) => formatter.formatChanged(formats, callback, similar, vars) 18291 }, 18292 editor: { 18293 getContent: args => editor.getContent(args), 18294 setContent: (content, args) => { 18295 return { 18296 content: editor.setContent(content, args), 18297 html: '' 18298 }; 18299 }, 18300 insertContent: (content, _details) => { 18301 editor.insertContent(content); 18302 return ''; 18303 }, 18304 addVisual: editor.addVisual 18305 }, 18306 selection: { getContent: (_format, args) => selection.getContent(args) }, 18307 autocompleter: { 18308 addDecoration: autocompleter.addDecoration, 18309 removeDecoration: autocompleter.removeDecoration 18310 }, 18311 raw: { getModel: () => Optional.some(raw.getRawModel()) } 18312 }; 18313 }; 18314 const makeNoopAdaptor = () => { 18315 const nul = constant(null); 18316 const empty = constant(''); 18317 return { 18318 init: { bindEvents: noop }, 18319 undoManager: { 18320 beforeChange: noop, 18321 add: nul, 18322 undo: nul, 18323 redo: nul, 18324 clear: noop, 18325 reset: noop, 18326 hasUndo: never, 18327 hasRedo: never, 18328 transact: nul, 18329 ignore: noop, 18330 extra: noop 18331 }, 18332 formatter: { 18333 match: never, 18334 matchAll: constant([]), 18335 matchNode: constant(undefined), 18336 canApply: never, 18337 closest: empty, 18338 apply: noop, 18339 remove: noop, 18340 toggle: noop, 18341 formatChanged: constant({ unbind: noop }) 18342 }, 18343 editor: { 18344 getContent: empty, 18345 setContent: constant({ 18346 content: '', 18347 html: '' 18348 }), 18349 insertContent: constant(''), 18350 addVisual: noop 18351 }, 18352 selection: { getContent: empty }, 18353 autocompleter: { 18354 addDecoration: noop, 18355 removeDecoration: noop 18356 }, 18357 raw: { getModel: constant(Optional.none()) } 18358 }; 18359 }; 18360 const isRtc = editor => has$2(editor.plugins, 'rtc'); 18361 const getRtcSetup = editor => get$a(editor.plugins, 'rtc').bind(rtcPlugin => Optional.from(rtcPlugin.setup)); 18362 const setup$t = editor => { 18363 const editorCast = editor; 18364 return getRtcSetup(editor).fold(() => { 18365 editorCast.rtcInstance = makePlainAdaptor(editor); 18366 return Optional.none(); 18367 }, setup => { 18368 editorCast.rtcInstance = makeNoopAdaptor(); 18369 return Optional.some(() => setup().then(rtcEditor => { 18370 editorCast.rtcInstance = makeRtcAdaptor(rtcEditor); 18371 return rtcEditor.rtc.isRemote; 18372 })); 18373 }); 18374 }; 18375 const getRtcInstanceWithFallback = editor => editor.rtcInstance ? editor.rtcInstance : makePlainAdaptor(editor); 18376 const getRtcInstanceWithError = editor => { 18377 const rtcInstance = editor.rtcInstance; 18378 if (!rtcInstance) { 18379 throw new Error('Failed to get RTC instance not yet initialized.'); 18380 } else { 18381 return rtcInstance; 18382 } 18383 }; 18384 const beforeChange = (editor, locks, beforeBookmark) => { 18385 getRtcInstanceWithError(editor).undoManager.beforeChange(locks, beforeBookmark); 18386 }; 18387 const addUndoLevel = (editor, undoManager, index, locks, beforeBookmark, level, event) => getRtcInstanceWithError(editor).undoManager.add(undoManager, index, locks, beforeBookmark, level, event); 18388 const undo = (editor, undoManager, locks, index) => getRtcInstanceWithError(editor).undoManager.undo(undoManager, locks, index); 18389 const redo = (editor, index, data) => getRtcInstanceWithError(editor).undoManager.redo(index, data); 18390 const clear = (editor, undoManager, index) => { 18391 getRtcInstanceWithError(editor).undoManager.clear(undoManager, index); 18392 }; 18393 const reset = (editor, undoManager) => { 18394 getRtcInstanceWithError(editor).undoManager.reset(undoManager); 18395 }; 18396 const hasUndo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasUndo(undoManager, index); 18397 const hasRedo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasRedo(undoManager, index); 18398 const transact = (editor, undoManager, locks, callback) => getRtcInstanceWithError(editor).undoManager.transact(undoManager, locks, callback); 18399 const ignore = (editor, locks, callback) => { 18400 getRtcInstanceWithError(editor).undoManager.ignore(locks, callback); 18401 }; 18402 const extra = (editor, undoManager, index, callback1, callback2) => { 18403 getRtcInstanceWithError(editor).undoManager.extra(undoManager, index, callback1, callback2); 18404 }; 18405 const matchFormat = (editor, name, vars, node, similar) => getRtcInstanceWithError(editor).formatter.match(name, vars, node, similar); 18406 const matchAllFormats = (editor, names, vars) => getRtcInstanceWithError(editor).formatter.matchAll(names, vars); 18407 const matchNodeFormat = (editor, node, name, vars, similar) => getRtcInstanceWithError(editor).formatter.matchNode(node, name, vars, similar); 18408 const canApplyFormat = (editor, name) => getRtcInstanceWithError(editor).formatter.canApply(name); 18409 const closestFormat = (editor, names) => getRtcInstanceWithError(editor).formatter.closest(names); 18410 const applyFormat = (editor, name, vars, node) => { 18411 getRtcInstanceWithError(editor).formatter.apply(name, vars, node); 18412 }; 18413 const removeFormat = (editor, name, vars, node, similar) => { 18414 getRtcInstanceWithError(editor).formatter.remove(name, vars, node, similar); 18415 }; 18416 const toggleFormat = (editor, name, vars, node) => { 18417 getRtcInstanceWithError(editor).formatter.toggle(name, vars, node); 18418 }; 18419 const formatChanged = (editor, registeredFormatListeners, formats, callback, similar, vars) => getRtcInstanceWithError(editor).formatter.formatChanged(registeredFormatListeners, formats, callback, similar, vars); 18420 const getContent$2 = (editor, args) => getRtcInstanceWithFallback(editor).editor.getContent(args); 18421 const setContent$2 = (editor, content, args) => getRtcInstanceWithFallback(editor).editor.setContent(content, args); 18422 const insertContent$1 = (editor, value, details) => getRtcInstanceWithFallback(editor).editor.insertContent(value, details); 18423 const getSelectedContent = (editor, format, args) => getRtcInstanceWithError(editor).selection.getContent(format, args); 18424 const addVisual$1 = (editor, elm) => getRtcInstanceWithError(editor).editor.addVisual(elm); 18425 const bindEvents = editor => getRtcInstanceWithError(editor).init.bindEvents(); 18426 18427 const getContent$1 = (editor, args = {}) => { 18428 const format = args.format ? args.format : 'html'; 18429 return getSelectedContent(editor, format, args); 18430 }; 18431 18432 const removeEmpty = text => { 18433 if (text.dom.length === 0) { 18434 remove$4(text); 18435 return Optional.none(); 18436 } else { 18437 return Optional.some(text); 18438 } 18439 }; 18440 const walkPastBookmark = (node, start) => node.filter(elm => BookmarkManager.isBookmarkNode(elm.dom)).bind(start ? nextSibling : prevSibling); 18441 const merge$1 = (outer, inner, rng, start, schema) => { 18442 const outerElm = outer.dom; 18443 const innerElm = inner.dom; 18444 const oldLength = start ? outerElm.length : innerElm.length; 18445 if (start) { 18446 mergeTextNodes(outerElm, innerElm, schema, false, !start); 18447 rng.setStart(innerElm, oldLength); 18448 } else { 18449 mergeTextNodes(innerElm, outerElm, schema, false, !start); 18450 rng.setEnd(innerElm, oldLength); 18451 } 18452 }; 18453 const normalizeTextIfRequired = (inner, start, schema) => { 18454 parent(inner).each(root => { 18455 const text = inner.dom; 18456 if (start && needsToBeNbspLeft(root, CaretPosition(text, 0), schema)) { 18457 normalizeWhitespaceAfter(text, 0, schema); 18458 } else if (!start && needsToBeNbspRight(root, CaretPosition(text, text.length), schema)) { 18459 normalizeWhitespaceBefore(text, text.length, schema); 18460 } 18461 }); 18462 }; 18463 const mergeAndNormalizeText = (outerNode, innerNode, rng, start, schema) => { 18464 outerNode.bind(outer => { 18465 const normalizer = start ? normalizeWhitespaceBefore : normalizeWhitespaceAfter; 18466 normalizer(outer.dom, start ? outer.dom.length : 0, schema); 18467 return innerNode.filter(isText$c).map(inner => merge$1(outer, inner, rng, start, schema)); 18468 }).orThunk(() => { 18469 const innerTextNode = walkPastBookmark(innerNode, start).or(innerNode).filter(isText$c); 18470 return innerTextNode.map(inner => normalizeTextIfRequired(inner, start, schema)); 18471 }); 18472 }; 18473 const rngSetContent = (rng, fragment, schema) => { 18474 const firstChild = Optional.from(fragment.firstChild).map(SugarElement.fromDom); 18475 const lastChild = Optional.from(fragment.lastChild).map(SugarElement.fromDom); 18476 rng.deleteContents(); 18477 rng.insertNode(fragment); 18478 const prevText = firstChild.bind(prevSibling).filter(isText$c).bind(removeEmpty); 18479 const nextText = lastChild.bind(nextSibling).filter(isText$c).bind(removeEmpty); 18480 mergeAndNormalizeText(prevText, firstChild, rng, true, schema); 18481 mergeAndNormalizeText(nextText, lastChild, rng, false, schema); 18482 rng.collapse(false); 18483 }; 18484 const setupArgs$2 = (args, content) => ({ 18485 format: 'html', 18486 ...args, 18487 set: true, 18488 selection: true, 18489 content 18490 }); 18491 const cleanContent = (editor, args) => { 18492 if (args.format !== 'raw') { 18493 const rng = editor.selection.getRng(); 18494 const contextBlock = editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock); 18495 const contextArgs = contextBlock ? { context: contextBlock.nodeName.toLowerCase() } : {}; 18496 const node = editor.parser.parse(args.content, { 18497 forced_root_block: false, 18498 ...contextArgs, 18499 ...args 18500 }); 18501 return HtmlSerializer({ validate: false }, editor.schema).serialize(node); 18502 } else { 18503 return args.content; 18504 } 18505 }; 18506 const setContent$1 = (editor, content, args = {}) => { 18507 const defaultedArgs = setupArgs$2(args, content); 18508 preProcessSetContent(editor, defaultedArgs).each(updatedArgs => { 18509 const cleanedContent = cleanContent(editor, updatedArgs); 18510 const rng = editor.selection.getRng(); 18511 rngSetContent(rng, rng.createContextualFragment(cleanedContent), editor.schema); 18512 editor.selection.setRng(rng); 18513 scrollRangeIntoView(editor, rng); 18514 postProcessSetContent(editor, cleanedContent, updatedArgs); 18515 }); 18516 }; 18517 18518 const deleteFromCallbackMap = (callbackMap, selector, callback) => { 18519 if (has$2(callbackMap, selector)) { 18520 const newCallbacks = filter$5(callbackMap[selector], cb => cb !== callback); 18521 if (newCallbacks.length === 0) { 18522 delete callbackMap[selector]; 18523 } else { 18524 callbackMap[selector] = newCallbacks; 18525 } 18526 } 18527 }; 18528 var SelectorChanged = (dom, editor) => { 18529 let selectorChangedData; 18530 let currentSelectors; 18531 const findMatchingNode = (selector, nodes) => find$2(nodes, node => dom.is(node, selector)); 18532 const getParents = elem => dom.getParents(elem, undefined, dom.getRoot()); 18533 const setup = () => { 18534 selectorChangedData = {}; 18535 currentSelectors = {}; 18536 editor.on('NodeChange', e => { 18537 const node = e.element; 18538 const parents = getParents(node); 18539 const matchedSelectors = {}; 18540 each$d(selectorChangedData, (callbacks, selector) => { 18541 findMatchingNode(selector, parents).each(node => { 18542 if (!currentSelectors[selector]) { 18543 each$e(callbacks, callback => { 18544 callback(true, { 18545 node, 18546 selector, 18547 parents 18548 }); 18549 }); 18550 currentSelectors[selector] = callbacks; 18551 } 18552 matchedSelectors[selector] = callbacks; 18553 }); 18554 }); 18555 each$d(currentSelectors, (callbacks, selector) => { 18556 if (!matchedSelectors[selector]) { 18557 delete currentSelectors[selector]; 18558 each$e(callbacks, callback => { 18559 callback(false, { 18560 node, 18561 selector, 18562 parents 18563 }); 18564 }); 18565 } 18566 }); 18567 }); 18568 }; 18569 return { 18570 selectorChangedWithUnbind: (selector, callback) => { 18571 if (!selectorChangedData) { 18572 setup(); 18573 } 18574 if (!selectorChangedData[selector]) { 18575 selectorChangedData[selector] = []; 18576 } 18577 selectorChangedData[selector].push(callback); 18578 findMatchingNode(selector, getParents(editor.selection.getStart())).each(() => { 18579 currentSelectors[selector] = selectorChangedData[selector]; 18580 }); 18581 return { 18582 unbind: () => { 18583 deleteFromCallbackMap(selectorChangedData, selector, callback); 18584 deleteFromCallbackMap(currentSelectors, selector, callback); 18585 } 18586 }; 18587 } 18588 }; 18589 }; 18590 18591 const isAttachedToDom = node => { 18592 return !!(node && node.ownerDocument) && contains(SugarElement.fromDom(node.ownerDocument), SugarElement.fromDom(node)); 18593 }; 18594 const isValidRange = rng => { 18595 if (!rng) { 18596 return false; 18597 } else { 18598 return isAttachedToDom(rng.startContainer) && isAttachedToDom(rng.endContainer); 18599 } 18600 }; 18601 const EditorSelection = (dom, win, serializer, editor) => { 18602 let selectedRange; 18603 let explicitRange; 18604 const {selectorChangedWithUnbind} = SelectorChanged(dom, editor); 18605 const setCursorLocation = (node, offset) => { 18606 const rng = dom.createRng(); 18607 if (isNonNullable(node) && isNonNullable(offset)) { 18608 rng.setStart(node, offset); 18609 rng.setEnd(node, offset); 18610 setRng(rng); 18611 collapse(false); 18612 } else { 18613 moveEndPoint(dom, rng, editor.getBody(), true); 18614 setRng(rng); 18615 } 18616 }; 18617 const getContent = args => getContent$1(editor, args); 18618 const setContent = (content, args) => setContent$1(editor, content, args); 18619 const getStart$1 = real => getStart(editor.getBody(), getRng$1(), real); 18620 const getEnd$1 = real => getEnd(editor.getBody(), getRng$1(), real); 18621 const getBookmark = (type, normalized) => bookmarkManager.getBookmark(type, normalized); 18622 const moveToBookmark = bookmark => bookmarkManager.moveToBookmark(bookmark); 18623 const select$1 = (node, content) => { 18624 select(dom, node, content).each(setRng); 18625 return node; 18626 }; 18627 const isCollapsed = () => { 18628 const rng = getRng$1(), sel = getSel(); 18629 if (!rng || rng.item) { 18630 return false; 18631 } 18632 if (rng.compareEndPoints) { 18633 return rng.compareEndPoints('StartToEnd', rng) === 0; 18634 } 18635 return !sel || rng.collapsed; 18636 }; 18637 const isEditable = () => { 18638
vendor: 5,378 bytes, lines 18638-18782
18638if (editor.mode.isReadOnly()) { 18639 return false; 18640 } 18641 const rng = getRng$1(); 18642 const fakeSelectedElements = editor.getBody().querySelectorAll('[data-mce-selected="1"]'); 18643 if (fakeSelectedElements.length > 0) { 18644 return forall(fakeSelectedElements, el => dom.isEditable(el.parentElement)); 18645 } else { 18646 return isEditableRange(dom, rng); 18647 } 18648 }; 18649 const collapse = toStart => { 18650 const rng = getRng$1(); 18651 rng.collapse(!!toStart); 18652 setRng(rng); 18653 }; 18654 const getSel = () => win.getSelection ? win.getSelection() : win.document.selection; 18655 const getRng$1 = () => { 18656 let rng; 18657 const tryCompareBoundaryPoints = (how, sourceRange, destinationRange) => { 18658 try { 18659 return sourceRange.compareBoundaryPoints(how, destinationRange); 18660 } catch (_a) { 18661 return -1; 18662 } 18663 }; 18664 const doc = win.document; 18665 if (isNonNullable(editor.bookmark) && !hasFocus(editor)) { 18666 const bookmark = getRng(editor); 18667 if (bookmark.isSome()) { 18668 return bookmark.map(r => processRanges(editor, [r])[0]).getOr(doc.createRange()); 18669 } 18670 } 18671 try { 18672 const selection = getSel(); 18673 if (selection && !isRestrictedNode(selection.anchorNode)) { 18674 if (selection.rangeCount > 0) { 18675 rng = selection.getRangeAt(0); 18676 } else { 18677 rng = doc.createRange(); 18678 } 18679 rng = processRanges(editor, [rng])[0]; 18680 } 18681 } catch (_a) { 18682 } 18683 if (!rng) { 18684 rng = doc.createRange(); 18685 } 18686 if (isDocument$1(rng.startContainer) && rng.collapsed) { 18687 const elm = dom.getRoot(); 18688 rng.setStart(elm, 0); 18689 rng.setEnd(elm, 0); 18690 } 18691 if (selectedRange && explicitRange) { 18692 if (tryCompareBoundaryPoints(rng.START_TO_START, rng, selectedRange) === 0 && tryCompareBoundaryPoints(rng.END_TO_END, rng, selectedRange) === 0) { 18693 rng = explicitRange; 18694 } else { 18695 selectedRange = null; 18696 explicitRange = null; 18697 } 18698 } 18699 return rng; 18700 }; 18701 const setRng = (rng, forward) => { 18702 if (!isValidRange(rng)) { 18703 return; 18704 } 18705 const sel = getSel(); 18706 const evt = editor.dispatch('SetSelectionRange', { 18707 range: rng, 18708 forward 18709 }); 18710 rng = evt.range; 18711 if (sel) { 18712 explicitRange = rng; 18713 try { 18714 sel.removeAllRanges(); 18715 sel.addRange(rng); 18716 } catch (_a) { 18717 } 18718 if (forward === false && sel.extend) { 18719 sel.collapse(rng.endContainer, rng.endOffset); 18720 sel.extend(rng.startContainer, rng.startOffset); 18721 } 18722 selectedRange = sel.rangeCount > 0 ? sel.getRangeAt(0) : null; 18723 } 18724 if (!rng.collapsed && rng.startContainer === rng.endContainer && (sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent)) { 18725 if (rng.endOffset - rng.startOffset < 2) { 18726 if (rng.startContainer.hasChildNodes()) { 18727 const node = rng.startContainer.childNodes[rng.startOffset]; 18728 if (node && node.nodeName === 'IMG') { 18729 sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset); 18730 if (sel.anchorNode !== rng.startContainer || sel.focusNode !== rng.endContainer) { 18731 sel.setBaseAndExtent(node, 0, node, 1); 18732 } 18733 } 18734 } 18735 } 18736 } 18737 editor.dispatch('AfterSetSelectionRange', { 18738 range: rng, 18739 forward 18740 }); 18741 }; 18742 const setNode = elm => { 18743 setContent(dom.getOuterHTML(elm)); 18744 return elm; 18745 }; 18746 const getNode$1 = () => getNode(editor.getBody(), getRng$1()); 18747 const getSelectedBlocks$1 = (startElm, endElm) => getSelectedBlocks(dom, getRng$1(), startElm, endElm); 18748 const isForward = () => { 18749 const sel = getSel(); 18750 const anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode; 18751 const focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode; 18752 if (!sel || !anchorNode || !focusNode || isRestrictedNode(anchorNode) || isRestrictedNode(focusNode)) { 18753 return true; 18754 } 18755 const anchorRange = dom.createRng(); 18756 const focusRange = dom.createRng(); 18757 try { 18758 anchorRange.setStart(anchorNode, sel.anchorOffset); 18759 anchorRange.collapse(true); 18760 focusRange.setStart(focusNode, sel.focusOffset); 18761 focusRange.collapse(true); 18762 } catch (_a) { 18763 return true; 18764 } 18765 return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0; 18766 }; 18767 const normalize = () => { 18768 const rng = getRng$1(); 18769 const sel = getSel(); 18770 if (!hasMultipleRanges(sel) && hasAnyRanges(editor)) { 18771 const normRng = normalize$2(dom, rng); 18772 normRng.each(normRng => { 18773 setRng(normRng, isForward()); 18774 }); 18775 return normRng.getOr(rng); 18776 } 18777 return rng; 18778 }; 18779 const selectorChanged = (selector, callback) => { 18780 selectorChangedWithUnbind(selector, callback); 18781 return exports; 18782 };
vendor: 12,091 bytes, lines 18783-19114
18783 const getScrollContainer = () => { 18784 let scrollContainer; 18785 let node = dom.getRoot(); 18786 while (node && node.nodeName !== 'BODY') { 18787 if (node.scrollHeight > node.clientHeight) { 18788 scrollContainer = node; 18789 break; 18790 } 18791 node = node.parentNode; 18792 } 18793 return scrollContainer; 18794 }; 18795 const scrollIntoView = (elm, alignToTop) => { 18796 if (isNonNullable(elm)) { 18797 scrollElementIntoView(editor, elm, alignToTop); 18798 } else { 18799 scrollRangeIntoView(editor, getRng$1(), alignToTop); 18800 } 18801 }; 18802 const placeCaretAt = (clientX, clientY) => setRng(fromPoint(clientX, clientY, editor.getDoc())); 18803 const getBoundingClientRect = () => { 18804 const rng = getRng$1(); 18805 return rng.collapsed ? CaretPosition.fromRangeStart(rng).getClientRects()[0] : rng.getBoundingClientRect(); 18806 }; 18807 const destroy = () => { 18808 win = selectedRange = explicitRange = null; 18809 controlSelection.destroy(); 18810 }; 18811 const expand = (options = { type: 'word' }) => setRng(RangeUtils(dom).expand(getRng$1(), options)); 18812 const exports = { 18813 dom, 18814 win, 18815 serializer, 18816 editor, 18817 expand, 18818 collapse, 18819 setCursorLocation, 18820 getContent, 18821 setContent, 18822 getBookmark, 18823 moveToBookmark, 18824 select: select$1, 18825 isCollapsed, 18826 isEditable, 18827 isForward, 18828 setNode, 18829 getNode: getNode$1, 18830 getSel, 18831 setRng, 18832 getRng: getRng$1, 18833 getStart: getStart$1, 18834 getEnd: getEnd$1, 18835 getSelectedBlocks: getSelectedBlocks$1, 18836 normalize, 18837 selectorChanged, 18838 selectorChangedWithUnbind, 18839 getScrollContainer, 18840 scrollIntoView, 18841 placeCaretAt, 18842 getBoundingClientRect, 18843 destroy 18844 }; 18845 const bookmarkManager = BookmarkManager(exports); 18846 const controlSelection = ControlSelection(exports, editor); 18847 exports.bookmarkManager = bookmarkManager; 18848 exports.controlSelection = controlSelection; 18849 return exports; 18850 }; 18851 18852 const addNodeFilter = (settings, htmlParser, schema) => { 18853 htmlParser.addNodeFilter('br', (nodes, _, args) => { 18854 const blockElements = Tools.extend({}, schema.getBlockElements()); 18855 const nonEmptyElements = schema.getNonEmptyElements(); 18856 const whitespaceElements = schema.getWhitespaceElements(); 18857 blockElements.body = 1; 18858 const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node); 18859 for (let i = 0, l = nodes.length; i < l; i++) { 18860 let node = nodes[i]; 18861 let parent = node.parent; 18862 if (parent && isBlock(parent) && node === parent.lastChild) { 18863 let prev = node.prev; 18864 while (prev) { 18865 const prevName = prev.name; 18866 if (prevName !== 'span' || prev.attr('data-mce-type') !== 'bookmark') { 18867 if (prevName === 'br') { 18868 node = null; 18869 } 18870 break; 18871 } 18872 prev = prev.prev; 18873 } 18874 if (node) { 18875 node.remove(); 18876 if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent)) { 18877 const elementRule = schema.getElementRule(parent.name); 18878 if (elementRule) { 18879 if (elementRule.removeEmpty) { 18880 parent.remove(); 18881 } else if (elementRule.paddEmpty) { 18882 paddEmptyNode(settings, args, isBlock, parent); 18883 } 18884 } 18885 } 18886 } 18887 } else { 18888 let lastParent = node; 18889 while (parent && parent.firstChild === lastParent && parent.lastChild === lastParent) { 18890 lastParent = parent; 18891 if (blockElements[parent.name]) { 18892 break; 18893 } 18894 parent = parent.parent; 18895 } 18896 if (lastParent === parent) { 18897 const textNode = new AstNode('#text', 3); 18898 textNode.value = nbsp; 18899 node.replace(textNode); 18900 } 18901 } 18902 } 18903 }); 18904 }; 18905 18906 const register$3 = (htmlParser, settings, dom) => { 18907 htmlParser.addAttributeFilter('data-mce-tabindex', (nodes, name) => { 18908 let i = nodes.length; 18909 while (i--) { 18910 const node = nodes[i]; 18911 node.attr('tabindex', node.attr('data-mce-tabindex')); 18912 node.attr(name, null); 18913 } 18914 }); 18915 htmlParser.addAttributeFilter('src,href,style', (nodes, name) => { 18916 const internalName = 'data-mce-' + name; 18917 const urlConverter = settings.url_converter; 18918 const urlConverterScope = settings.url_converter_scope; 18919 let i = nodes.length; 18920 while (i--) { 18921 const node = nodes[i]; 18922 let value = node.attr(internalName); 18923 if (value !== undefined) { 18924 node.attr(name, value.length > 0 ? value : null); 18925 node.attr(internalName, null); 18926 } else { 18927 value = node.attr(name); 18928 if (name === 'style') { 18929 value = dom.serializeStyle(dom.parseStyle(value), node.name); 18930 } else if (urlConverter) { 18931 value = urlConverter.call(urlConverterScope, value, name, node.name); 18932 } 18933 node.attr(name, value.length > 0 ? value : null); 18934 } 18935 } 18936 }); 18937 htmlParser.addAttributeFilter('class', nodes => { 18938 let i = nodes.length; 18939 while (i--) { 18940 const node = nodes[i]; 18941 let value = node.attr('class'); 18942 if (value) { 18943 value = value.replace(/(?:^|\s)mce-item-\w+(?!\S)/g, ''); 18944 node.attr('class', value.length > 0 ? value : null); 18945 } 18946 } 18947 }); 18948 htmlParser.addAttributeFilter('data-mce-type', (nodes, name, args) => { 18949 let i = nodes.length; 18950 while (i--) { 18951 const node = nodes[i]; 18952 if (node.attr('data-mce-type') === 'bookmark' && !args.cleanup) { 18953 const hasChildren = Optional.from(node.firstChild).exists(firstChild => { 18954 var _a; 18955 return !isZwsp((_a = firstChild.value) !== null && _a !== void 0 ? _a : ''); 18956 }); 18957 if (hasChildren) { 18958 node.unwrap(); 18959 } else { 18960 node.remove(); 18961 } 18962 } 18963 } 18964 }); 18965 htmlParser.addNodeFilter('script,style', (nodes, name) => { 18966 var _a; 18967 const trim = value => { 18968 return value.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n').replace(/^[\r\n]*|[\r\n]*$/g, '').replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi, '').replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g, ''); 18969 }; 18970 let i = nodes.length; 18971 while (i--) { 18972 const node = nodes[i]; 18973 const firstChild = node.firstChild; 18974 const value = (_a = firstChild === null || firstChild === void 0 ? void 0 : firstChild.value) !== null && _a !== void 0 ? _a : ''; 18975 if (name === 'script') { 18976 const type = node.attr('type'); 18977 if (type) { 18978 node.attr('type', type === 'mce-no/type' ? null : type.replace(/^mce\-/, '')); 18979 } 18980 if (settings.element_format === 'xhtml' && firstChild && value.length > 0) { 18981 firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>'; 18982 } 18983 } else { 18984 if (settings.element_format === 'xhtml' && firstChild && value.length > 0) { 18985 firstChild.value = '<!--\n' + trim(value) + '\n-->'; 18986 } 18987 } 18988 } 18989 }); 18990 htmlParser.addNodeFilter('#comment', nodes => { 18991 let i = nodes.length; 18992 while (i--) { 18993 const node = nodes[i]; 18994 const value = node.value; 18995 if (settings.preserve_cdata && (value === null || value === void 0 ? void 0 : value.indexOf('[CDATA[')) === 0) { 18996 node.name = '#cdata'; 18997 node.type = 4; 18998 node.value = dom.decode(value.replace(/^\[CDATA\[|\]\]$/g, '')); 18999 } else if ((value === null || value === void 0 ? void 0 : value.indexOf('mce:protected ')) === 0) { 19000 node.name = '#text'; 19001 node.type = 3; 19002 node.raw = true; 19003 node.value = unescape(value).substr(14); 19004 } 19005 } 19006 }); 19007 htmlParser.addNodeFilter('xml:namespace,input', (nodes, name) => { 19008 let i = nodes.length; 19009 while (i--) { 19010 const node = nodes[i]; 19011 if (node.type === 7) { 19012 node.remove(); 19013 } else if (node.type === 1) { 19014 if (name === 'input' && !node.attr('type')) { 19015 node.attr('type', 'text'); 19016 } 19017 } 19018 } 19019 }); 19020 htmlParser.addAttributeFilter('data-mce-type', nodes => { 19021 each$e(nodes, node => { 19022 if (node.attr('data-mce-type') === 'format-caret') { 19023 if (node.isEmpty(htmlParser.schema.getNonEmptyElements())) { 19024 node.remove(); 19025 } else { 19026 node.unwrap(); 19027 } 19028 } 19029 }); 19030 }); 19031 htmlParser.addAttributeFilter('data-mce-src,data-mce-href,data-mce-style,' + 'data-mce-selected,data-mce-expando,data-mce-block,' + 'data-mce-type,data-mce-resize,data-mce-placeholder', (nodes, name) => { 19032 let i = nodes.length; 19033 while (i--) { 19034 nodes[i].attr(name, null); 19035 } 19036 }); 19037 if (settings.remove_trailing_brs) { 19038 addNodeFilter(settings, htmlParser, htmlParser.schema); 19039 } 19040 }; 19041 const trimTrailingBr = rootNode => { 19042 const isBr = node => { 19043 return (node === null || node === void 0 ? void 0 : node.name) === 'br'; 19044 }; 19045 const brNode1 = rootNode.lastChild; 19046 if (isBr(brNode1)) { 19047 const brNode2 = brNode1.prev; 19048 if (isBr(brNode2)) { 19049 brNode1.remove(); 19050 brNode2.remove(); 19051 } 19052 } 19053 }; 19054 19055 const preProcess$1 = (editor, node, args) => { 19056 let oldDoc; 19057 const dom = editor.dom; 19058 let clonedNode = node.cloneNode(true); 19059 const impl = document.implementation; 19060 if (impl.createHTMLDocument) { 19061 const doc = impl.createHTMLDocument(''); 19062 Tools.each(clonedNode.nodeName === 'BODY' ? clonedNode.childNodes : [clonedNode], node => { 19063 doc.body.appendChild(doc.importNode(node, true)); 19064 }); 19065 if (clonedNode.nodeName !== 'BODY') { 19066 clonedNode = doc.body.firstChild; 19067 } else { 19068 clonedNode = doc.body; 19069 } 19070 oldDoc = dom.doc; 19071 dom.doc = doc; 19072 } 19073 firePreProcess(editor, { 19074 ...args, 19075 node: clonedNode 19076 }); 19077 if (oldDoc) { 19078 dom.doc = oldDoc; 19079 } 19080 return clonedNode; 19081 }; 19082 const shouldFireEvent = (editor, args) => { 19083 return isNonNullable(editor) && editor.hasEventListeners('PreProcess') && !args.no_events; 19084 }; 19085 const process$1 = (editor, node, args) => { 19086 return shouldFireEvent(editor, args) ? preProcess$1(editor, node, args) : node; 19087 }; 19088 19089 const addTempAttr = (htmlParser, tempAttrs, name) => { 19090 if (Tools.inArray(tempAttrs, name) === -1) { 19091 htmlParser.addAttributeFilter(name, (nodes, name) => { 19092 let i = nodes.length; 19093 while (i--) { 19094 nodes[i].attr(name, null); 19095 } 19096 }); 19097 tempAttrs.push(name); 19098 } 19099 }; 19100 const postProcess = (editor, args, content) => { 19101 if (!args.no_events && editor) { 19102 const outArgs = firePostProcess(editor, { 19103 ...args, 19104 content 19105 }); 19106 return outArgs.content; 19107 } else { 19108 return content; 19109 } 19110 }; 19111 const getHtmlFromNode = (dom, node, args) => { 19112 const html = trim$2(args.getInner ? node.innerHTML : dom.getOuterHTML(node)); 19113 return args.selection || isWsPreserveElement(SugarElement.fromDom(node)) ? html : Tools.trim(html); 19114 };
vendor: 13,863 bytes, lines 19115-19418
19115 const parseHtml = (htmlParser, html, args) => { 19116 const parserArgs = args.selection ? { 19117 forced_root_block: false, 19118 ...args 19119 } : args; 19120 const rootNode = htmlParser.parse(html, parserArgs); 19121 trimTrailingBr(rootNode); 19122 return rootNode; 19123 }; 19124 const serializeNode = (settings, schema, node) => { 19125 const htmlSerializer = HtmlSerializer(settings, schema); 19126 return htmlSerializer.serialize(node); 19127 }; 19128 const toHtml = (editor, settings, schema, rootNode, args) => { 19129 const content = serializeNode(settings, schema, rootNode); 19130 return postProcess(editor, args, content); 19131 }; 19132 const DomSerializerImpl = (settings, editor) => { 19133 const tempAttrs = ['data-mce-selected']; 19134 const defaultedSettings = { 19135 entity_encoding: 'named', 19136 remove_trailing_brs: true, 19137 pad_empty_with_br: false, 19138 ...settings 19139 }; 19140 const dom = editor && editor.dom ? editor.dom : DOMUtils.DOM; 19141 const schema = editor && editor.schema ? editor.schema : Schema(defaultedSettings); 19142 const htmlParser = DomParser(defaultedSettings, schema); 19143 register$3(htmlParser, defaultedSettings, dom); 19144 const serialize = (node, parserArgs = {}) => { 19145 const args = { 19146 format: 'html', 19147 ...parserArgs 19148 }; 19149 const targetNode = process$1(editor, node, args); 19150 const html = getHtmlFromNode(dom, targetNode, args); 19151 const rootNode = parseHtml(htmlParser, html, args); 19152 return args.format === 'tree' ? rootNode : toHtml(editor, defaultedSettings, schema, rootNode, args); 19153 }; 19154 return { 19155 schema, 19156 addNodeFilter: htmlParser.addNodeFilter, 19157 addAttributeFilter: htmlParser.addAttributeFilter, 19158 serialize: serialize, 19159 addRules: schema.addValidElements, 19160 setRules: schema.setValidElements, 19161 addTempAttr: curry(addTempAttr, htmlParser, tempAttrs), 19162 getTempAttrs: constant(tempAttrs), 19163 getNodeFilters: htmlParser.getNodeFilters, 19164 getAttributeFilters: htmlParser.getAttributeFilters, 19165 removeNodeFilter: htmlParser.removeNodeFilter, 19166 removeAttributeFilter: htmlParser.removeAttributeFilter 19167 }; 19168 }; 19169 19170 const DomSerializer = (settings, editor) => { 19171 const domSerializer = DomSerializerImpl(settings, editor); 19172 return { 19173 schema: domSerializer.schema, 19174 addNodeFilter: domSerializer.addNodeFilter, 19175 addAttributeFilter: domSerializer.addAttributeFilter, 19176 serialize: domSerializer.serialize, 19177 addRules: domSerializer.addRules, 19178 setRules: domSerializer.setRules, 19179 addTempAttr: domSerializer.addTempAttr, 19180 getTempAttrs: domSerializer.getTempAttrs, 19181 getNodeFilters: domSerializer.getNodeFilters, 19182 getAttributeFilters: domSerializer.getAttributeFilters, 19183 removeNodeFilter: domSerializer.removeNodeFilter, 19184 removeAttributeFilter: domSerializer.removeAttributeFilter 19185 }; 19186 }; 19187 19188 const defaultFormat$1 = 'html'; 19189 const setupArgs$1 = (args, format) => ({ 19190 ...args, 19191 format, 19192 get: true, 19193 getInner: true 19194 }); 19195 const getContent = (editor, args = {}) => { 19196 const format = args.format ? args.format : defaultFormat$1; 19197 const defaultedArgs = setupArgs$1(args, format); 19198 return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => { 19199 const content = getContent$2(editor, updatedArgs); 19200 return postProcessGetContent(editor, content, updatedArgs); 19201 }); 19202 }; 19203 19204 const defaultFormat = 'html'; 19205 const setupArgs = (args, content) => ({ 19206 format: defaultFormat, 19207 ...args, 19208 set: true, 19209 content 19210 }); 19211 const setContent = (editor, content, args = {}) => { 19212 const defaultedArgs = setupArgs(args, content); 19213 return preProcessSetContent(editor, defaultedArgs).map(updatedArgs => { 19214 const result = setContent$2(editor, updatedArgs.content, updatedArgs); 19215 postProcessSetContent(editor, result.html, updatedArgs); 19216 return result.content; 19217 }).getOr(content); 19218 }; 19219 19220 const removedOptions = ('autoresize_on_init,content_editable_state,padd_empty_with_br,block_elements,' + 'boolean_attributes,editor_deselector,editor_selector,elements,file_browser_callback_types,filepicker_validator_handler,' + 'force_hex_style_colors,force_p_newlines,gecko_spellcheck,images_dataimg_filter,media_scripts,mode,move_caret_before_on_enter_elements,' + 'non_empty_elements,self_closing_elements,short_ended_elements,special,spellchecker_select_languages,spellchecker_whitelist,' + 'tab_focus,tabfocus_elements,table_responsive_width,text_block_elements,text_inline_elements,toolbar_drawer,types,validate,whitespace_elements,' + 'paste_enable_default_filters,paste_filter_drop,paste_word_valid_elements,paste_retain_style_properties,paste_convert_word_fake_lists,' + 'template_cdate_classes,template_mdate_classes,template_selected_content_classes,template_preview_replace_values,template_replace_values,templates,template_cdate_format,template_mdate_format').split(','); 19221 const deprecatedOptions = []; 19222 const removedPlugins = 'bbcode,colorpicker,contextmenu,fullpage,legacyoutput,spellchecker,template,textcolor,rtc'.split(','); 19223 const deprecatedPlugins = []; 19224 const getMatchingOptions = (options, searchingFor) => { 19225 const settingNames = filter$5(searchingFor, setting => has$2(options, setting)); 19226 return sort(settingNames); 19227 }; 19228 const getRemovedOptions = options => { 19229 const settingNames = getMatchingOptions(options, removedOptions); 19230 const forcedRootBlock = options.forced_root_block; 19231 if (forcedRootBlock === false || forcedRootBlock === '') { 19232 settingNames.push('forced_root_block (false only)'); 19233 } 19234 return sort(settingNames); 19235 }; 19236 const getDeprecatedOptions = options => getMatchingOptions(options, deprecatedOptions); 19237 const getMatchingPlugins = (options, searchingFor) => { 19238 const plugins = Tools.makeMap(options.plugins, ' '); 19239 const hasPlugin = plugin => has$2(plugins, plugin); 19240 const pluginNames = filter$5(searchingFor, hasPlugin); 19241 return sort(pluginNames); 19242 }; 19243 const getRemovedPlugins = options => getMatchingPlugins(options, removedPlugins); 19244 const getDeprecatedPlugins = options => getMatchingPlugins(options, deprecatedPlugins.map(entry => entry.name)); 19245 const logRemovedWarnings = (rawOptions, normalizedOptions) => { 19246 const removedOptions = getRemovedOptions(rawOptions); 19247 const removedPlugins = getRemovedPlugins(normalizedOptions); 19248 const hasRemovedPlugins = removedPlugins.length > 0; 19249 const hasRemovedOptions = removedOptions.length > 0; 19250 const isLegacyMobileTheme = normalizedOptions.theme === 'mobile'; 19251 if (hasRemovedPlugins || hasRemovedOptions || isLegacyMobileTheme) { 19252 const listJoiner = '\n- '; 19253 const themesMessage = isLegacyMobileTheme ? `\n\nThemes:${ listJoiner }mobile` : ''; 19254 const pluginsMessage = hasRemovedPlugins ? `\n\nPlugins:${ listJoiner }${ removedPlugins.join(listJoiner) }` : ''; 19255 const optionsMessage = hasRemovedOptions ? `\n\nOptions:${ listJoiner }${ removedOptions.join(listJoiner) }` : ''; 19256 console.warn('The following deprecated features are currently enabled and have been removed in TinyMCE 7.0. These features will no longer work and should be removed from the TinyMCE configuration. ' + 'See https://www.tiny.cloud/docs/tinymce/7/migration-from-6x/ for more information.' + themesMessage + pluginsMessage + optionsMessage); 19257 } 19258 }; 19259 const getPluginDescription = name => find$2(deprecatedPlugins, entry => entry.name === name).fold(() => name, entry => { 19260 if (entry.replacedWith) { 19261 return `${ name }, replaced by ${ entry.replacedWith }`; 19262 } else { 19263 return name; 19264 } 19265 }); 19266 const logDeprecatedWarnings = (rawOptions, normalizedOptions) => { 19267 const deprecatedOptions = getDeprecatedOptions(rawOptions); 19268 const deprecatedPlugins = getDeprecatedPlugins(normalizedOptions); 19269 const hasDeprecatedPlugins = deprecatedPlugins.length > 0; 19270 const hasDeprecatedOptions = deprecatedOptions.length > 0; 19271 if (hasDeprecatedPlugins || hasDeprecatedOptions) { 19272 const listJoiner = '\n- '; 19273 const pluginsMessage = hasDeprecatedPlugins ? `\n\nPlugins:${ listJoiner }${ deprecatedPlugins.map(getPluginDescription).join(listJoiner) }` : ''; 19274 const optionsMessage = hasDeprecatedOptions ? `\n\nOptions:${ listJoiner }${ deprecatedOptions.join(listJoiner) }` : ''; 19275 console.warn('The following deprecated features are currently enabled but will be removed soon.' + pluginsMessage + optionsMessage); 19276 } 19277 }; 19278 const logWarnings = (rawOptions, normalizedOptions) => { 19279 logRemovedWarnings(rawOptions, normalizedOptions); 19280 logDeprecatedWarnings(rawOptions, normalizedOptions); 19281 }; 19282 19283 const DOM$8 = DOMUtils.DOM; 19284 const restoreOriginalStyles = editor => { 19285 DOM$8.setStyle(editor.id, 'display', editor.orgDisplay); 19286 }; 19287 const safeDestroy = x => Optional.from(x).each(x => x.destroy()); 19288 const clearDomReferences = editor => { 19289 const ed = editor; 19290 ed.contentAreaContainer = ed.formElement = ed.container = ed.editorContainer = null; 19291 ed.bodyElement = ed.contentDocument = ed.contentWindow = null; 19292 ed.iframeElement = ed.targetElm = null; 19293 const selection = editor.selection; 19294 if (selection) { 19295 const dom = selection.dom; 19296 ed.selection = selection.win = selection.dom = dom.doc = null; 19297 } 19298 }; 19299 const restoreForm = editor => { 19300 const form = editor.formElement; 19301 if (form) { 19302 if (form._mceOldSubmit) { 19303 form.submit = form._mceOldSubmit; 19304 delete form._mceOldSubmit; 19305 } 19306 DOM$8.unbind(form, 'submit reset', editor.formEventDelegate); 19307 } 19308 }; 19309 const remove$1 = editor => { 19310 if (!editor.removed) { 19311 const {_selectionOverrides, editorUpload} = editor; 19312 const body = editor.getBody(); 19313 const element = editor.getElement(); 19314 if (body) { 19315 editor.save({ is_removing: true }); 19316 } 19317 editor.removed = true; 19318 editor.unbindAllNativeEvents(); 19319 if (editor.hasHiddenInput && isNonNullable(element === null || element === void 0 ? void 0 : element.nextSibling)) { 19320 DOM$8.remove(element.nextSibling); 19321 } 19322 fireRemove(editor); 19323 editor.editorManager.remove(editor); 19324 if (!editor.inline && body) { 19325 restoreOriginalStyles(editor); 19326 } 19327 fireDetach(editor); 19328 DOM$8.remove(editor.getContainer()); 19329 safeDestroy(_selectionOverrides); 19330 safeDestroy(editorUpload); 19331 editor.destroy(); 19332 } 19333 }; 19334 const destroy = (editor, automatic) => { 19335 const {selection, dom} = editor; 19336 if (editor.destroyed) { 19337 return; 19338 } 19339 if (!automatic && !editor.removed) { 19340 editor.remove(); 19341 return; 19342 } 19343 if (!automatic) { 19344 editor.editorManager.off('beforeunload', editor._beforeUnload); 19345 if (editor.theme && editor.theme.destroy) { 19346 editor.theme.destroy(); 19347 } 19348 safeDestroy(selection); 19349 safeDestroy(dom); 19350 } 19351 restoreForm(editor); 19352 clearDomReferences(editor); 19353 editor.destroyed = true; 19354 }; 19355 19356 const CreateIconManager = () => { 19357 const lookup = {}; 19358 const add = (id, iconPack) => { 19359 lookup[id] = iconPack; 19360 }; 19361 const get = id => { 19362 if (lookup[id]) { 19363 return lookup[id]; 19364 } else { 19365 return { icons: {} }; 19366 } 19367 }; 19368 const has = id => has$2(lookup, id); 19369 return { 19370 add, 19371 get, 19372 has 19373 }; 19374 }; 19375 const IconManager = CreateIconManager(); 19376 19377 const ModelManager = AddOnManager.ModelManager; 19378 19379 const getProp = (propName, elm) => { 19380 const rawElm = elm.dom; 19381 return rawElm[propName]; 19382 }; 19383 const getComputedSizeProp = (propName, elm) => parseInt(get$7(elm, propName), 10); 19384 const getClientWidth = curry(getProp, 'clientWidth'); 19385 const getClientHeight = curry(getProp, 'clientHeight'); 19386 const getMarginTop = curry(getComputedSizeProp, 'margin-top'); 19387 const getMarginLeft = curry(getComputedSizeProp, 'margin-left'); 19388 const getBoundingClientRect = elm => elm.dom.getBoundingClientRect(); 19389 const isInsideElementContentArea = (bodyElm, clientX, clientY) => { 19390 const clientWidth = getClientWidth(bodyElm); 19391 const clientHeight = getClientHeight(bodyElm); 19392 return clientX >= 0 && clientY >= 0 && clientX <= clientWidth && clientY <= clientHeight; 19393 }; 19394 const transpose = (inline, elm, clientX, clientY) => { 19395 const clientRect = getBoundingClientRect(elm); 19396 const deltaX = inline ? clientRect.left + elm.dom.clientLeft + getMarginLeft(elm) : 0; 19397 const deltaY = inline ? clientRect.top + elm.dom.clientTop + getMarginTop(elm) : 0; 19398 const x = clientX - deltaX; 19399 const y = clientY - deltaY; 19400 return { 19401 x, 19402 y 19403 }; 19404 }; 19405 const isXYInContentArea = (editor, clientX, clientY) => { 19406 const bodyElm = SugarElement.fromDom(editor.getBody()); 19407 const targetElm = editor.inline ? bodyElm : documentElement(bodyElm); 19408 const transposedPoint = transpose(editor.inline, targetElm, clientX, clientY); 19409 return isInsideElementContentArea(targetElm, transposedPoint.x, transposedPoint.y); 19410 }; 19411 const fromDomSafe = node => Optional.from(node).map(SugarElement.fromDom); 19412 const isEditorAttachedToDom = editor => { 19413 const rawContainer = editor.inline ? editor.getBody() : editor.getContentAreaContainer(); 19414 return fromDomSafe(rawContainer).map(inBody).getOr(false); 19415 }; 19416 19417 var NotificationManagerImpl = () => { 19418 const unimplemented = () => {
vendor: 5,830 bytes, lines 19419-19586
19419 throw new Error('Theme did not provide a NotificationManager implementation.'); 19420 }; 19421 return { 19422 open: unimplemented, 19423 close: unimplemented, 19424 getArgs: unimplemented 19425 }; 19426 }; 19427 19428 const NotificationManager = editor => { 19429 const notifications = []; 19430 const getImplementation = () => { 19431 const theme = editor.theme; 19432 return theme && theme.getNotificationManagerImpl ? theme.getNotificationManagerImpl() : NotificationManagerImpl(); 19433 }; 19434 const getTopNotification = () => { 19435 return Optional.from(notifications[0]); 19436 }; 19437 const isEqual = (a, b) => { 19438 return a.type === b.type && a.text === b.text && !a.progressBar && !a.timeout && !b.progressBar && !b.timeout; 19439 }; 19440 const reposition = () => { 19441 getTopNotification().each(notification => { 19442 notification.reposition(); 19443 }); 19444 }; 19445 const addNotification = notification => { 19446 notifications.push(notification); 19447 }; 19448 const closeNotification = notification => { 19449 findIndex$2(notifications, otherNotification => { 19450 return otherNotification === notification; 19451 }).each(index => { 19452 notifications.splice(index, 1); 19453 }); 19454 }; 19455 const open = (spec, fireEvent = true) => { 19456 if (editor.removed || !isEditorAttachedToDom(editor)) { 19457 return {}; 19458 } 19459 if (fireEvent) { 19460 editor.dispatch('BeforeOpenNotification', { notification: spec }); 19461 } 19462 return find$2(notifications, notification => { 19463 return isEqual(getImplementation().getArgs(notification), spec); 19464 }).getOrThunk(() => { 19465 editor.editorManager.setActive(editor); 19466 const notification = getImplementation().open(spec, () => { 19467 closeNotification(notification); 19468 }, () => hasEditorOrUiFocus(editor)); 19469 addNotification(notification); 19470 reposition(); 19471 editor.dispatch('OpenNotification', { notification: { ...notification } }); 19472 return notification; 19473 }); 19474 }; 19475 const close = () => { 19476 getTopNotification().each(notification => { 19477 getImplementation().close(notification); 19478 closeNotification(notification); 19479 reposition(); 19480 }); 19481 }; 19482 const getNotifications = constant(notifications); 19483 const registerEvents = editor => { 19484 editor.on('SkinLoaded', () => { 19485 const serviceMessage = getServiceMessage(editor); 19486 if (serviceMessage) { 19487 open({ 19488 text: serviceMessage, 19489 type: 'warning', 19490 timeout: 0 19491 }, false); 19492 } 19493 reposition(); 19494 }); 19495 editor.on('show ResizeEditor ResizeWindow NodeChange ToggleView FullscreenStateChanged', () => { 19496 requestAnimationFrame(reposition); 19497 }); 19498 editor.on('remove', () => { 19499 each$e(notifications.slice(), notification => { 19500 getImplementation().close(notification); 19501 }); 19502 }); 19503 editor.on('keydown', e => { 19504 var _a; 19505 const isF12 = ((_a = e.key) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'f12' || e.keyCode === 123; 19506 if (e.altKey && isF12) { 19507 e.preventDefault(); 19508 getTopNotification().map(notificationApi => SugarElement.fromDom(notificationApi.getEl())).each(elm => focus$1(elm)); 19509 } 19510 }); 19511 }; 19512 registerEvents(editor); 19513 return { 19514 open, 19515 close, 19516 getNotifications 19517 }; 19518 }; 19519 19520 const PluginManager = AddOnManager.PluginManager; 19521 19522 const ThemeManager = AddOnManager.ThemeManager; 19523 19524 var WindowManagerImpl = () => { 19525 const unimplemented = () => { 19526 throw new Error('Theme did not provide a WindowManager implementation.'); 19527 }; 19528 return { 19529 open: unimplemented, 19530 openUrl: unimplemented, 19531 alert: unimplemented, 19532 confirm: unimplemented, 19533 close: unimplemented 19534 }; 19535 }; 19536 19537 const WindowManager = editor => { 19538 let dialogs = []; 19539 const getImplementation = () => { 19540 const theme = editor.theme; 19541 return theme && theme.getWindowManagerImpl ? theme.getWindowManagerImpl() : WindowManagerImpl(); 19542 }; 19543 const funcBind = (scope, f) => { 19544 return (...args) => { 19545 return f ? f.apply(scope, args) : undefined; 19546 }; 19547 }; 19548 const fireOpenEvent = dialog => { 19549 editor.dispatch('OpenWindow', { dialog }); 19550 }; 19551 const fireCloseEvent = dialog => { 19552 editor.dispatch('CloseWindow', { dialog }); 19553 }; 19554 const addDialog = dialog => { 19555 dialogs.push(dialog); 19556 fireOpenEvent(dialog); 19557 }; 19558 const closeDialog = dialog => { 19559 fireCloseEvent(dialog); 19560 dialogs = filter$5(dialogs, otherDialog => { 19561 return otherDialog !== dialog; 19562 }); 19563 if (dialogs.length === 0) { 19564 editor.focus(); 19565 } 19566 }; 19567 const getTopDialog = () => { 19568 return Optional.from(dialogs[dialogs.length - 1]); 19569 }; 19570 const storeSelectionAndOpenDialog = openDialog => { 19571 editor.editorManager.setActive(editor); 19572 store(editor); 19573 editor.ui.show(); 19574 const dialog = openDialog(); 19575 addDialog(dialog); 19576 return dialog; 19577 }; 19578 const open = (args, params) => { 19579 return storeSelectionAndOpenDialog(() => getImplementation().open(args, params, closeDialog)); 19580 }; 19581 const openUrl = args => { 19582 return storeSelectionAndOpenDialog(() => getImplementation().openUrl(args, closeDialog)); 19583 }; 19584 const alert = (message, callback, scope) => { 19585 const windowManagerImpl = getImplementation(); 19586 windowManagerImpl.alert(message, funcBind(scope ? scope : windowManagerImpl,
vendor: 12,329 bytes, lines 19586-19948
19586callback)); 19587 }; 19588 const confirm = (message, callback, scope) => { 19589 const windowManagerImpl = getImplementation(); 19590 windowManagerImpl.confirm(message, funcBind(scope ? scope : windowManagerImpl, callback)); 19591 }; 19592 const close = () => { 19593 getTopDialog().each(dialog => { 19594 getImplementation().close(dialog); 19595 closeDialog(dialog); 19596 }); 19597 }; 19598 editor.on('remove', () => { 19599 each$e(dialogs, dialog => { 19600 getImplementation().close(dialog); 19601 }); 19602 }); 19603 return { 19604 open, 19605 openUrl, 19606 alert, 19607 confirm, 19608 close 19609 }; 19610 }; 19611 19612 const displayNotification = (editor, message) => { 19613 editor.notificationManager.open({ 19614 type: 'error', 19615 text: message 19616 }); 19617 }; 19618 const displayError = (editor, message) => { 19619 if (editor._skinLoaded) { 19620 displayNotification(editor, message); 19621 } else { 19622 editor.on('SkinLoaded', () => { 19623 displayNotification(editor, message); 19624 }); 19625 } 19626 }; 19627 const uploadError = (editor, message) => { 19628 displayError(editor, I18n.translate([ 19629 'Failed to upload image: {0}', 19630 message 19631 ])); 19632 }; 19633 const logError = (editor, errorType, msg) => { 19634 fireError(editor, errorType, { message: msg }); 19635 console.error(msg); 19636 }; 19637 const createLoadError = (type, url, name) => name ? `Failed to load ${ type }: ${ name } from url ${ url }` : `Failed to load ${ type } url: ${ url }`; 19638 const pluginLoadError = (editor, url, name) => { 19639 logError(editor, 'PluginLoadError', createLoadError('plugin', url, name)); 19640 }; 19641 const iconsLoadError = (editor, url, name) => { 19642 logError(editor, 'IconsLoadError', createLoadError('icons', url, name)); 19643 }; 19644 const languageLoadError = (editor, url, name) => { 19645 logError(editor, 'LanguageLoadError', createLoadError('language', url, name)); 19646 }; 19647 const themeLoadError = (editor, url, name) => { 19648 logError(editor, 'ThemeLoadError', createLoadError('theme', url, name)); 19649 }; 19650 const modelLoadError = (editor, url, name) => { 19651 logError(editor, 'ModelLoadError', createLoadError('model', url, name)); 19652 }; 19653 const pluginInitError = (editor, name, err) => { 19654 const message = I18n.translate([ 19655 'Failed to initialize plugin: {0}', 19656 name 19657 ]); 19658 fireError(editor, 'PluginLoadError', { message }); 19659 initError(message, err); 19660 displayError(editor, message); 19661 }; 19662 const initError = (message, ...x) => { 19663 const console = window.console; 19664 if (console) { 19665 if (console.error) { 19666 console.error(message, ...x); 19667 } else { 19668 console.log(message, ...x); 19669 } 19670 } 19671 }; 19672 19673 const removeFakeSelection = editor => { 19674 Optional.from(editor.selection.getNode()).each(elm => { 19675 elm.removeAttribute('data-mce-selected'); 19676 }); 19677 }; 19678 const setEditorCommandState = (editor, cmd, state) => { 19679 try { 19680 editor.getDoc().execCommand(cmd, false, String(state)); 19681 } catch (_a) { 19682 } 19683 }; 19684 const setCommonEditorCommands = (editor, state) => { 19685 setEditorCommandState(editor, 'StyleWithCSS', state); 19686 setEditorCommandState(editor, 'enableInlineTableEditing', state); 19687 setEditorCommandState(editor, 'enableObjectResizing', state); 19688 }; 19689 const restoreFakeSelection = editor => { 19690 editor.selection.setRng(editor.selection.getRng()); 19691 }; 19692 const toggleClass = (elm, cls, state) => { 19693 if (has(elm, cls) && !state) { 19694 remove$6(elm, cls); 19695 } else if (state) { 19696 add$2(elm, cls); 19697 } 19698 }; 19699 const disableEditor = editor => { 19700 const body = SugarElement.fromDom(editor.getBody()); 19701 toggleClass(body, 'mce-content-readonly', true); 19702 editor.selection.controlSelection.hideResizeRect(); 19703 editor._selectionOverrides.hideFakeCaret(); 19704 removeFakeSelection(editor); 19705 }; 19706 const enableEditor = editor => { 19707 const body = SugarElement.fromDom(editor.getBody()); 19708 toggleClass(body, 'mce-content-readonly', false); 19709 if (editor.hasEditableRoot()) { 19710 set$3(body, true); 19711 } 19712 setCommonEditorCommands(editor, false); 19713 if (hasEditorOrUiFocus(editor)) { 19714 editor.focus(); 19715 } 19716 restoreFakeSelection(editor); 19717 editor.nodeChanged(); 19718 }; 19719 19720 const isDisabled = editor => isDisabled$1(editor); 19721 const internalContentEditableAttr = 'data-mce-contenteditable'; 19722 const switchOffContentEditableTrue = elm => { 19723 each$e(descendants(elm, '*[contenteditable="true"]'), elm => { 19724 set$4(elm, internalContentEditableAttr, 'true'); 19725 set$3(elm, false); 19726 }); 19727 }; 19728 const switchOnContentEditableTrue = elm => { 19729 each$e(descendants(elm, `*[${ internalContentEditableAttr }="true"]`), elm => { 19730 remove$9(elm, internalContentEditableAttr); 19731 set$3(elm, true); 19732 }); 19733 }; 19734 const toggleDisabled = (editor, state) => { 19735 const body = SugarElement.fromDom(editor.getBody()); 19736 if (state) { 19737 disableEditor(editor); 19738 set$3(body, false); 19739 switchOffContentEditableTrue(body); 19740 } else { 19741 switchOnContentEditableTrue(body); 19742 enableEditor(editor); 19743 } 19744 }; 19745 const registerDisabledContentFilters = editor => { 19746 if (editor.serializer) { 19747 registerFilters(editor); 19748 } else { 19749 editor.on('PreInit', () => { 19750 registerFilters(editor); 19751 }); 19752 } 19753 }; 19754 const registerFilters = editor => { 19755 editor.parser.addAttributeFilter('contenteditable', nodes => { 19756 if (isDisabled(editor)) { 19757 each$e(nodes, node => { 19758 node.attr(internalContentEditableAttr, node.attr('contenteditable')); 19759 node.attr('contenteditable', 'false'); 19760 }); 19761 } 19762 }); 19763 editor.serializer.addAttributeFilter(internalContentEditableAttr, nodes => { 19764 if (isDisabled(editor)) { 19765 each$e(nodes, node => { 19766 node.attr('contenteditable', node.attr(internalContentEditableAttr)); 19767 }); 19768 } 19769 }); 19770 editor.serializer.addTempAttr(internalContentEditableAttr); 19771 }; 19772 const isClickEvent = e => e.type === 'click'; 19773 const allowedEvents = ['copy']; 19774 const isAllowedEventInDisabledMode = e => contains$2(allowedEvents, e.type); 19775 const getAnchorHrefOpt = (editor, elm) => { 19776 const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody())); 19777 return closest$3(elm, 'a', isRoot).bind(a => getOpt(a, 'href')); 19778 }; 19779 const processDisabledEvents = (editor, e) => { 19780 if (isClickEvent(e) && !VK.metaKeyPressed(e)) { 19781 const elm = SugarElement.fromDom(e.target); 19782 getAnchorHrefOpt(editor, elm).each(href => { 19783 e.preventDefault(); 19784 if (/^#/.test(href)) { 19785 const targetEl = editor.dom.select(`${ href },[name="${ removeLeading(href, '#') }"]`); 19786 if (targetEl.length) { 19787 editor.selection.scrollIntoView(targetEl[0], true); 19788 } 19789 } else { 19790 window.open(href, '_blank', 'rel=noopener noreferrer,menubar=yes,toolbar=yes,location=yes,status=yes,resizable=yes,scrollbars=yes'); 19791 } 19792 }); 19793 } else if (isAllowedEventInDisabledMode(e)) { 19794 editor.dispatch(e.type, e); 19795 } 19796 }; 19797 const registerDisabledModeEventHandlers = editor => { 19798 editor.on('ShowCaret ObjectSelected', e => { 19799 if (isDisabled(editor)) { 19800 e.preventDefault(); 19801 } 19802 }); 19803 editor.on('DisabledStateChange', e => { 19804 if (!e.isDefaultPrevented()) { 19805 toggleDisabled(editor, e.state); 19806 } 19807 }); 19808 }; 19809 const registerEventsAndFilters$1 = editor => { 19810 registerDisabledContentFilters(editor); 19811 registerDisabledModeEventHandlers(editor); 19812 }; 19813 19814 const isContentCssSkinName = url => /^[a-z0-9\-]+$/i.test(url); 19815 const toContentSkinResourceName = url => 'content/' + url + '/content.css'; 19816 const isBundledCssSkinName = url => tinymce.Resource.has(toContentSkinResourceName(url)); 19817 const getContentCssUrls = editor => { 19818 return transformToUrls(editor, getContentCss(editor)); 19819 }; 19820 const getFontCssUrls = editor => { 19821 return transformToUrls(editor, getFontCss(editor)); 19822 }; 19823 const transformToUrls = (editor, cssLinks) => { 19824 const skinUrl = editor.editorManager.baseURL + '/skins/content'; 19825 const suffix = editor.editorManager.suffix; 19826 const contentCssFile = `content${ suffix }.css`; 19827 return map$3(cssLinks, url => { 19828 if (isBundledCssSkinName(url)) { 19829 return url; 19830 } else if (isContentCssSkinName(url) && !editor.inline) { 19831 return `${ skinUrl }/${ url }/${ contentCssFile }`; 19832 } else { 19833 return editor.documentBaseURI.toAbsolute(url); 19834 } 19835 }); 19836 }; 19837 const appendContentCssFromSettings = editor => { 19838 editor.contentCSS = editor.contentCSS.concat(getContentCssUrls(editor), getFontCssUrls(editor)); 19839 }; 19840 19841 const getAllImages = elm => { 19842 return elm ? from(elm.getElementsByTagName('img')) : []; 19843 }; 19844 const ImageScanner = (uploadStatus, blobCache) => { 19845 const cachedPromises = {}; 19846 const findAll = (elm, predicate = always) => { 19847 const images = filter$5(getAllImages(elm), img => { 19848 const src = img.src; 19849 if (img.hasAttribute('data-mce-bogus')) { 19850 return false; 19851 } 19852 if (img.hasAttribute('data-mce-placeholder')) { 19853 return false; 19854 } 19855 if (!src || src === Env.transparentSrc) { 19856 return false; 19857 } 19858 if (startsWith(src, 'blob:')) { 19859 return !uploadStatus.isUploaded(src) && predicate(img); 19860 } 19861 if (startsWith(src, 'data:')) { 19862 return predicate(img); 19863 } 19864 return false; 19865 }); 19866 const promises = map$3(images, img => { 19867 const imageSrc = img.src; 19868 if (has$2(cachedPromises, imageSrc)) { 19869 return cachedPromises[imageSrc].then(imageInfo => { 19870 if (isString(imageInfo)) { 19871 return imageInfo; 19872 } else { 19873 return { 19874 image: img, 19875 blobInfo: imageInfo.blobInfo 19876 }; 19877 } 19878 }); 19879 } else { 19880 const newPromise = imageToBlobInfo(blobCache, imageSrc).then(blobInfo => { 19881 delete cachedPromises[imageSrc]; 19882 return { 19883 image: img, 19884 blobInfo 19885 }; 19886 }).catch(error => { 19887 delete cachedPromises[imageSrc]; 19888 return error; 19889 }); 19890 cachedPromises[imageSrc] = newPromise; 19891 return newPromise; 19892 } 19893 }); 19894 return Promise.all(promises); 19895 }; 19896 return { findAll }; 19897 }; 19898 19899 const UploadStatus = () => { 19900 const PENDING = 1, UPLOADED = 2; 19901 let blobUriStatuses = {}; 19902 const createStatus = (status, resultUri) => { 19903 return { 19904 status, 19905 resultUri 19906 }; 19907 }; 19908 const hasBlobUri = blobUri => { 19909 return blobUri in blobUriStatuses; 19910 }; 19911 const getResultUri = blobUri => { 19912 const result = blobUriStatuses[blobUri]; 19913 return result ? result.resultUri : null; 19914 }; 19915 const isPending = blobUri => { 19916 return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === PENDING : false; 19917 }; 19918 const isUploaded = blobUri => { 19919 return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === UPLOADED : false; 19920 }; 19921 const markPending = blobUri => { 19922 blobUriStatuses[blobUri] = createStatus(PENDING, null); 19923 }; 19924 const markUploaded = (blobUri, resultUri) => { 19925 blobUriStatuses[blobUri] = createStatus(UPLOADED, resultUri); 19926 }; 19927 const removeFailed = blobUri => { 19928 delete blobUriStatuses[blobUri]; 19929 }; 19930 const destroy = () => { 19931 blobUriStatuses = {}; 19932 }; 19933 return { 19934 hasBlobUri, 19935 getResultUri, 19936 isPending, 19937 isUploaded, 19938 markPending, 19939 markUploaded, 19940 removeFailed, 19941 destroy 19942 }; 19943 }; 19944 19945 let count = 0; 19946 const seed = () => { 19947 const rnd = () => { 19948 return Math.round(
vendor: 11,181 bytes, lines 19948-20238
19948random() * 4294967295).toString(36); 19949 }; 19950 const now = new Date().getTime(); 19951 return 's' + now.toString(36) + rnd() + rnd() + rnd(); 19952 }; 19953 const uuid = prefix => { 19954 return prefix + count++ + seed(); 19955 }; 19956 19957 const BlobCache = () => { 19958 let cache = []; 19959 const mimeToExt = mime => { 19960 const mimes = { 19961 'image/jpeg': 'jpg', 19962 'image/jpg': 'jpg', 19963 'image/gif': 'gif', 19964 'image/png': 'png', 19965 'image/apng': 'apng', 19966 'image/avif': 'avif', 19967 'image/svg+xml': 'svg', 19968 'image/webp': 'webp', 19969 'image/bmp': 'bmp', 19970 'image/tiff': 'tiff' 19971 }; 19972 return mimes[mime.toLowerCase()] || 'dat'; 19973 }; 19974 const create = (o, blob, base64, name, filename) => { 19975 if (isString(o)) { 19976 const id = o; 19977 return toBlobInfo({ 19978 id, 19979 name, 19980 filename, 19981 blob: blob, 19982 base64: base64 19983 }); 19984 } else if (isObject(o)) { 19985 return toBlobInfo(o); 19986 } else { 19987 throw new Error('Unknown input type'); 19988 } 19989 }; 19990 const toBlobInfo = o => { 19991 if (!o.blob || !o.base64) { 19992 throw new Error('blob and base64 representations of the image are required for BlobInfo to be created'); 19993 } 19994 const id = o.id || uuid('blobid'); 19995 const name = o.name || id; 19996 const blob = o.blob; 19997 return { 19998 id: constant(id), 19999 name: constant(name), 20000 filename: constant(o.filename || name + '.' + mimeToExt(blob.type)), 20001 blob: constant(blob), 20002 base64: constant(o.base64), 20003 blobUri: constant(o.blobUri || URL.createObjectURL(blob)), 20004 uri: constant(o.uri) 20005 }; 20006 }; 20007 const add = blobInfo => { 20008 if (!get(blobInfo.id())) { 20009 cache.push(blobInfo); 20010 } 20011 }; 20012 const findFirst = predicate => find$2(cache, predicate).getOrUndefined(); 20013 const get = id => findFirst(cachedBlobInfo => cachedBlobInfo.id() === id); 20014 const getByUri = blobUri => findFirst(blobInfo => blobInfo.blobUri() === blobUri); 20015 const getByData = (base64, type) => findFirst(blobInfo => blobInfo.base64() === base64 && blobInfo.blob().type === type); 20016 const removeByUri = blobUri => { 20017 cache = filter$5(cache, blobInfo => { 20018 if (blobInfo.blobUri() === blobUri) { 20019 URL.revokeObjectURL(blobInfo.blobUri()); 20020 return false; 20021 } 20022 return true; 20023 }); 20024 }; 20025 const destroy = () => { 20026 each$e(cache, cachedBlobInfo => { 20027 URL.revokeObjectURL(cachedBlobInfo.blobUri()); 20028 }); 20029 cache = []; 20030 }; 20031 return { 20032 create, 20033 add, 20034 get, 20035 getByUri, 20036 getByData, 20037 findFirst, 20038 removeByUri, 20039 destroy 20040 }; 20041 }; 20042 20043 const Uploader = (uploadStatus, settings) => { 20044 const pendingPromises = {}; 20045 const pathJoin = (path1, path2) => { 20046 if (path1) { 20047 return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, ''); 20048 } 20049 return path2; 20050 }; 20051 const defaultHandler = (blobInfo, progress) => new Promise((success, failure) => { 20052 const xhr = new XMLHttpRequest(); 20053 xhr.open('POST', settings.url); 20054 xhr.withCredentials = settings.credentials; 20055 xhr.upload.onprogress = e => { 20056 progress(e.loaded / e.total * 100); 20057 }; 20058 xhr.onerror = () => { 20059 failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status); 20060 }; 20061 xhr.onload = () => { 20062 if (xhr.status < 200 || xhr.status >= 300) { 20063 failure('HTTP Error: ' + xhr.status); 20064 return; 20065 } 20066 const json = JSON.parse(xhr.responseText); 20067 if (!json || !isString(json.location)) { 20068 failure('Invalid JSON: ' + xhr.responseText); 20069 return; 20070 } 20071 success(pathJoin(settings.basePath, json.location)); 20072 }; 20073 const formData = new FormData(); 20074 formData.append('file', blobInfo.blob(), blobInfo.filename()); 20075 xhr.send(formData); 20076 }); 20077 const uploadHandler = isFunction(settings.handler) ? settings.handler : defaultHandler; 20078 const noUpload = () => new Promise(resolve => { 20079 resolve([]); 20080 }); 20081 const handlerSuccess = (blobInfo, url) => ({ 20082 url, 20083 blobInfo, 20084 status: true 20085 }); 20086 const handlerFailure = (blobInfo, error) => ({ 20087 url: '', 20088 blobInfo, 20089 status: false, 20090 error 20091 }); 20092 const resolvePending = (blobUri, result) => { 20093 Tools.each(pendingPromises[blobUri], resolve => { 20094 resolve(result); 20095 }); 20096 delete pendingPromises[blobUri]; 20097 }; 20098 const uploadBlobInfo = (blobInfo, handler, openNotification) => { 20099 uploadStatus.markPending(blobInfo.blobUri()); 20100 return new Promise(resolve => { 20101 let notification; 20102 let progress; 20103 try { 20104 const closeNotification = () => { 20105 if (notification) { 20106 notification.close(); 20107 progress = noop; 20108 } 20109 }; 20110 const success = url => { 20111 closeNotification(); 20112 uploadStatus.markUploaded(blobInfo.blobUri(), url); 20113 resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url)); 20114 resolve(handlerSuccess(blobInfo, url)); 20115 }; 20116 const failure = error => { 20117 closeNotification(); 20118 uploadStatus.removeFailed(blobInfo.blobUri()); 20119 resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, error)); 20120 resolve(handlerFailure(blobInfo, error)); 20121 }; 20122 progress = percent => { 20123 if (percent < 0 || percent > 100) { 20124 return; 20125 } 20126 Optional.from(notification).orThunk(() => Optional.from(openNotification).map(apply$1)).each(n => { 20127 notification = n; 20128 n.progressBar.value(percent); 20129 }); 20130 }; 20131 handler(blobInfo, progress).then(success, err => { 20132 failure(isString(err) ? { message: err } : err); 20133 }); 20134 } catch (ex) { 20135 resolve(handlerFailure(blobInfo, ex)); 20136 } 20137 }); 20138 }; 20139 const isDefaultHandler = handler => handler === defaultHandler; 20140 const pendingUploadBlobInfo = blobInfo => { 20141 const blobUri = blobInfo.blobUri(); 20142 return new Promise(resolve => { 20143 pendingPromises[blobUri] = pendingPromises[blobUri] || []; 20144 pendingPromises[blobUri].push(resolve); 20145 }); 20146 }; 20147 const uploadBlobs = (blobInfos, openNotification) => { 20148 blobInfos = Tools.grep(blobInfos, blobInfo => !uploadStatus.isUploaded(blobInfo.blobUri())); 20149 return Promise.all(Tools.map(blobInfos, blobInfo => uploadStatus.isPending(blobInfo.blobUri()) ? pendingUploadBlobInfo(blobInfo) : uploadBlobInfo(blobInfo, uploadHandler, openNotification))); 20150 }; 20151 const upload = (blobInfos, openNotification) => !settings.url && isDefaultHandler(uploadHandler) ? noUpload() : uploadBlobs(blobInfos, openNotification); 20152 return { upload }; 20153 }; 20154 20155 const openNotification = editor => () => editor.notificationManager.open({ 20156 text: editor.translate('Image uploading...'), 20157 type: 'info', 20158 timeout: -1, 20159 progressBar: true 20160 }); 20161 const createUploader = (editor, uploadStatus) => Uploader(uploadStatus, { 20162 url: getImageUploadUrl(editor), 20163 basePath: getImageUploadBasePath(editor), 20164 credentials: getImagesUploadCredentials(editor), 20165 handler: getImagesUploadHandler(editor) 20166 }); 20167 const ImageUploader = editor => { 20168 const uploadStatus = UploadStatus(); 20169 const uploader = createUploader(editor, uploadStatus); 20170 return { upload: (blobInfos, showNotification = true) => uploader.upload(blobInfos, showNotification ? openNotification(editor) : undefined) }; 20171 }; 20172 20173 const isEmptyForPadding = (editor, element) => editor.dom.isEmpty(element.dom) && isNonNullable(editor.schema.getTextBlockElements()[name(element)]); 20174 const addPaddingToEmpty = editor => element => { 20175 if (isEmptyForPadding(editor, element)) { 20176 append$1(element, SugarElement.fromHtml('<br data-mce-bogus="1" />')); 20177 } 20178 }; 20179 const EditorUpload = editor => { 20180 const blobCache = BlobCache(); 20181 let uploader, imageScanner; 20182 const uploadStatus = UploadStatus(); 20183 const urlFilters = []; 20184 const aliveGuard = callback => { 20185 return result => { 20186 if (editor.selection) { 20187 return callback(result); 20188 } 20189 return []; 20190 }; 20191 }; 20192 const cacheInvalidator = url => url + (url.indexOf('?') === -1 ? '?' : '&') + new Date().getTime(); 20193 const replaceString = (content, search, replace) => { 20194 let index = 0; 20195 do { 20196 index = content.indexOf(search, index); 20197 if (index !== -1) { 20198 content = content.substring(0, index) + replace + content.substr(index + search.length); 20199 index += replace.length - search.length + 1; 20200 } 20201 } while (index !== -1); 20202 return content; 20203 }; 20204 const replaceImageUrl = (content, targetUrl, replacementUrl) => { 20205 const replacementString = `src="${ replacementUrl }"${ replacementUrl === Env.transparentSrc ? ' data-mce-placeholder="1"' : '' }`; 20206 content = replaceString(content, `src="${ targetUrl }"`, replacementString); 20207 content = replaceString(content, 'data-mce-src="' + targetUrl + '"', 'data-mce-src="' + replacementUrl + '"'); 20208 return content; 20209 }; 20210 const replaceUrlInUndoStack = (targetUrl, replacementUrl) => { 20211 each$e(editor.undoManager.data, level => { 20212 if (level.type === 'fragmented') { 20213 level.fragments = map$3(level.fragments, fragment => replaceImageUrl(fragment, targetUrl, replacementUrl)); 20214 } else { 20215 level.content = replaceImageUrl(level.content, targetUrl, replacementUrl); 20216 } 20217 }); 20218 }; 20219 const replaceImageUriInView = (image, resultUri) => { 20220 const src = editor.convertURL(resultUri, 'src'); 20221 replaceUrlInUndoStack(image.src, resultUri); 20222 setAll$1(SugarElement.fromDom(image), { 20223 'src': shouldReuseFileName(editor) ? cacheInvalidator(resultUri) : resultUri, 20224 'data-mce-src': src 20225 }); 20226 }; 20227 const uploadImages = () => { 20228 if (!uploader) { 20229 uploader = createUploader(editor, uploadStatus); 20230 } 20231 return scanForImages().then(aliveGuard(imageInfos => { 20232 const blobInfos = map$3(imageInfos, imageInfo => imageInfo.blobInfo); 20233 return uploader.upload(blobInfos, openNotification(editor)).then(aliveGuard(result => { 20234 const imagesToRemove = []; 20235 let shouldDispatchChange = false; 20236 const filteredResult = map$3(result, (uploadInfo, index) => { 20237 const {blobInfo, image} = imageInfos[index]; 20238 let removed = false;
vendor: 5,955 bytes, lines 20239-20410
20239 if (uploadInfo.status && shouldReplaceBlobUris(editor)) { 20240 if (uploadInfo.url && !contains$1(image.src, uploadInfo.url)) { 20241 shouldDispatchChange = true; 20242 } 20243 blobCache.removeByUri(image.src); 20244 if (isRtc(editor)) ; else { 20245 replaceImageUriInView(image, uploadInfo.url); 20246 } 20247 } else if (uploadInfo.error) { 20248 if (uploadInfo.error.remove) { 20249 replaceUrlInUndoStack(image.src, Env.transparentSrc); 20250 imagesToRemove.push(image); 20251 removed = true; 20252 } 20253 uploadError(editor, uploadInfo.error.message); 20254 } 20255 return { 20256 element: image, 20257 status: uploadInfo.status, 20258 uploadUri: uploadInfo.url, 20259 blobInfo, 20260 removed 20261 }; 20262 }); 20263 if (imagesToRemove.length > 0 && !isRtc(editor)) { 20264 editor.undoManager.transact(() => { 20265 each$e(fromDom$1(imagesToRemove), sugarElement => { 20266 const parentOpt = parent(sugarElement); 20267 remove$4(sugarElement); 20268 parentOpt.each(addPaddingToEmpty(editor)); 20269 blobCache.removeByUri(sugarElement.dom.src); 20270 }); 20271 }); 20272 } else if (shouldDispatchChange) { 20273 editor.undoManager.dispatchChange(); 20274 } 20275 return filteredResult; 20276 })); 20277 })); 20278 }; 20279 const uploadImagesAuto = () => isAutomaticUploadsEnabled(editor) ? uploadImages() : Promise.resolve([]); 20280 const isValidDataUriImage = imgElm => forall(urlFilters, filter => filter(imgElm)); 20281 const addFilter = filter => { 20282 urlFilters.push(filter); 20283 }; 20284 const scanForImages = () => { 20285 if (!imageScanner) { 20286 imageScanner = ImageScanner(uploadStatus, blobCache); 20287 } 20288 return imageScanner.findAll(editor.getBody(), isValidDataUriImage).then(aliveGuard(result => { 20289 const filteredResult = filter$5(result, resultItem => { 20290 if (isString(resultItem)) { 20291 displayError(editor, resultItem); 20292 return false; 20293 } else if (resultItem.uriType === 'blob') { 20294 return false; 20295 } else { 20296 return true; 20297 } 20298 }); 20299 if (isRtc(editor)) ; else { 20300 each$e(filteredResult, resultItem => { 20301 replaceUrlInUndoStack(resultItem.image.src, resultItem.blobInfo.blobUri()); 20302 resultItem.image.src = resultItem.blobInfo.blobUri(); 20303 resultItem.image.removeAttribute('data-mce-src'); 20304 }); 20305 } 20306 return filteredResult; 20307 })); 20308 }; 20309 const destroy = () => { 20310 blobCache.destroy(); 20311 uploadStatus.destroy(); 20312 imageScanner = uploader = null; 20313 }; 20314 const replaceBlobUris = content => { 20315 return content.replace(/src="(blob:[^"]+)"/g, (match, blobUri) => { 20316 const resultUri = uploadStatus.getResultUri(blobUri); 20317 if (resultUri) { 20318 return 'src="' + resultUri + '"'; 20319 } 20320 let blobInfo = blobCache.getByUri(blobUri); 20321 if (!blobInfo) { 20322 blobInfo = foldl(editor.editorManager.get(), (result, editor) => { 20323 return result || editor.editorUpload && editor.editorUpload.blobCache.getByUri(blobUri); 20324 }, undefined); 20325 } 20326 if (blobInfo) { 20327 const blob = blobInfo.blob(); 20328 return 'src="data:' + blob.type + ';base64,' + blobInfo.base64() + '"'; 20329 } 20330 return match; 20331 }); 20332 }; 20333 editor.on('SetContent', () => { 20334 if (isAutomaticUploadsEnabled(editor)) { 20335 uploadImagesAuto(); 20336 } else { 20337 scanForImages(); 20338 } 20339 }); 20340 editor.on('RawSaveContent', e => { 20341 e.content = replaceBlobUris(e.content); 20342 }); 20343 editor.on('GetContent', e => { 20344 if (e.source_view || e.format === 'raw' || e.format === 'tree') { 20345 return; 20346 } 20347 e.content = replaceBlobUris(e.content); 20348 }); 20349 editor.on('PostRender', () => { 20350 editor.parser.addNodeFilter('img', images => { 20351 each$e(images, img => { 20352 const src = img.attr('src'); 20353 if (!src || blobCache.getByUri(src)) { 20354 return; 20355 } 20356 const resultUri = uploadStatus.getResultUri(src); 20357 if (resultUri) { 20358 img.attr('src', resultUri); 20359 } 20360 }); 20361 }); 20362 }); 20363 return { 20364 blobCache, 20365 addFilter, 20366 uploadImages, 20367 uploadImagesAuto, 20368 scanForImages, 20369 destroy 20370 }; 20371 }; 20372 20373 const get$1 = editor => { 20374 const dom = editor.dom; 20375 const schemaType = editor.schema.type; 20376 const formats = { 20377 valigntop: [{ 20378 selector: 'td,th', 20379 styles: { verticalAlign: 'top' } 20380 }], 20381 valignmiddle: [{ 20382 selector: 'td,th', 20383 styles: { verticalAlign: 'middle' } 20384 }], 20385 valignbottom: [{ 20386 selector: 'td,th', 20387 styles: { verticalAlign: 'bottom' } 20388 }], 20389 alignleft: [ 20390 { 20391 selector: 'figure.image', 20392 collapsed: false, 20393 classes: 'align-left', 20394 ceFalseOverride: true, 20395 preview: 'font-family font-size' 20396 }, 20397 { 20398 selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre', 20399 styles: { textAlign: 'left' }, 20400 inherit: false, 20401 preview: false 20402 }, 20403 { 20404 selector: 'img,audio,video', 20405 collapsed: false, 20406 styles: { float: 'left' }, 20407 preview: 'font-family font-size' 20408 }, 20409 { 20410 selector: '
vendor: 3,137 bytes, lines 20410-20520
20410.mce-placeholder', 20411 styles: { float: 'left' }, 20412 ceFalseOverride: true 20413 }, 20414 { 20415 selector: 'table', 20416 collapsed: false, 20417 styles: { 20418 marginLeft: '0px', 20419 marginRight: 'auto' 20420 }, 20421 onformat: table => { 20422 dom.setStyle(table, 'float', null); 20423 }, 20424 preview: 'font-family font-size' 20425 }, 20426 { 20427 selector: '.mce-preview-object,[data-ephox-embed-iri]', 20428 ceFalseOverride: true, 20429 styles: { float: 'left' } 20430 } 20431 ], 20432 aligncenter: [ 20433 { 20434 selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre', 20435 styles: { textAlign: 'center' }, 20436 inherit: false, 20437 preview: 'font-family font-size' 20438 }, 20439 { 20440 selector: 'figure.image', 20441 collapsed: false, 20442 classes: 'align-center', 20443 ceFalseOverride: true, 20444 preview: 'font-family font-size' 20445 }, 20446 { 20447 selector: 'img,audio,video', 20448 collapsed: false, 20449 styles: { 20450 display: 'block', 20451 marginLeft: 'auto', 20452 marginRight: 'auto' 20453 }, 20454 preview: false 20455 }, 20456 { 20457 selector: '.mce-placeholder', 20458 styles: { 20459 display: 'block', 20460 marginLeft: 'auto', 20461 marginRight: 'auto' 20462 }, 20463 ceFalseOverride: true 20464 }, 20465 { 20466 selector: 'table', 20467 collapsed: false, 20468 styles: { 20469 marginLeft: 'auto', 20470 marginRight: 'auto' 20471 }, 20472 preview: 'font-family font-size' 20473 }, 20474 { 20475 selector: '.mce-preview-object', 20476 ceFalseOverride: true, 20477 styles: { 20478 display: 'table', 20479 marginLeft: 'auto', 20480 marginRight: 'auto' 20481 }, 20482 preview: false 20483 }, 20484 { 20485 selector: '[data-ephox-embed-iri]', 20486 ceFalseOverride: true, 20487 styles: { 20488 marginLeft: 'auto', 20489 marginRight: 'auto' 20490 }, 20491 preview: false 20492 } 20493 ], 20494 alignright: [ 20495 { 20496 selector: 'figure.image', 20497 collapsed: false, 20498 classes: 'align-right', 20499 ceFalseOverride: true, 20500 preview: 'font-family font-size' 20501 }, 20502 { 20503 selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre', 20504 styles: { textAlign: 'right' }, 20505 inherit: false, 20506 preview: 'font-family font-size' 20507 }, 20508 { 20509 selector: 'img,audio,video', 20510 collapsed: false, 20511 styles: { float: 'right' }, 20512 preview: 'font-family font-size' 20513 }, 20514 { 20515 selector: '.mce-placeholder', 20516 styles: { float: 'right' }, 20517 ceFalseOverride: true 20518 }, 20519 { 20520 selector: 'table',
vendor: 5,600 bytes, lines 20521-20737
20521 collapsed: false, 20522 styles: { 20523 marginRight: '0px', 20524 marginLeft: 'auto' 20525 }, 20526 onformat: table => { 20527 dom.setStyle(table, 'float', null); 20528 }, 20529 preview: 'font-family font-size' 20530 }, 20531 { 20532 selector: '.mce-preview-object,[data-ephox-embed-iri]', 20533 ceFalseOverride: true, 20534 styles: { float: 'right' }, 20535 preview: false 20536 } 20537 ], 20538 alignjustify: [{ 20539 selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre', 20540 styles: { textAlign: 'justify' }, 20541 inherit: false, 20542 preview: 'font-family font-size' 20543 }], 20544 bold: [ 20545 { 20546 inline: 'strong', 20547 remove: 'all', 20548 preserve_attributes: [ 20549 'class', 20550 'style' 20551 ] 20552 }, 20553 { 20554 inline: 'span', 20555 styles: { fontWeight: 'bold' } 20556 }, 20557 { 20558 inline: 'b', 20559 remove: 'all', 20560 preserve_attributes: [ 20561 'class', 20562 'style' 20563 ] 20564 } 20565 ], 20566 italic: [ 20567 { 20568 inline: 'em', 20569 remove: 'all', 20570 preserve_attributes: [ 20571 'class', 20572 'style' 20573 ] 20574 }, 20575 { 20576 inline: 'span', 20577 styles: { fontStyle: 'italic' } 20578 }, 20579 { 20580 inline: 'i', 20581 remove: 'all', 20582 preserve_attributes: [ 20583 'class', 20584 'style' 20585 ] 20586 } 20587 ], 20588 underline: [ 20589 { 20590 inline: 'span', 20591 styles: { textDecoration: 'underline' }, 20592 exact: true 20593 }, 20594 { 20595 inline: 'u', 20596 remove: 'all', 20597 preserve_attributes: [ 20598 'class', 20599 'style' 20600 ] 20601 } 20602 ], 20603 strikethrough: (() => { 20604 const span = { 20605 inline: 'span', 20606 styles: { textDecoration: 'line-through' }, 20607 exact: true 20608 }; 20609 const strike = { 20610 inline: 'strike', 20611 remove: 'all', 20612 preserve_attributes: [ 20613 'class', 20614 'style' 20615 ] 20616 }; 20617 const s = { 20618 inline: 's', 20619 remove: 'all', 20620 preserve_attributes: [ 20621 'class', 20622 'style' 20623 ] 20624 }; 20625 return schemaType !== 'html4' ? [ 20626 s, 20627 span, 20628 strike 20629 ] : [ 20630 span, 20631 s, 20632 strike 20633 ]; 20634 })(), 20635 forecolor: { 20636 inline: 'span', 20637 styles: { color: '%value' }, 20638 links: true, 20639 remove_similar: true, 20640 clear_child_styles: true 20641 }, 20642 hilitecolor: { 20643 inline: 'span', 20644 styles: { backgroundColor: '%value' }, 20645 links: true, 20646 remove_similar: true, 20647 clear_child_styles: true 20648 }, 20649 fontname: { 20650 inline: 'span', 20651 toggle: false, 20652 styles: { fontFamily: '%value' }, 20653 clear_child_styles: true 20654 }, 20655 fontsize: { 20656 inline: 'span', 20657 toggle: false, 20658 styles: { fontSize: '%value' }, 20659 clear_child_styles: true 20660 }, 20661 lineheight: { 20662 selector: 'h1,h2,h3,h4,h5,h6,p,li,td,th,div', 20663 styles: { lineHeight: '%value' } 20664 }, 20665 fontsize_class: { 20666 inline: 'span', 20667 attributes: { class: '%value' } 20668 }, 20669 blockquote: { 20670 block: 'blockquote', 20671 wrapper: true, 20672 remove: 'all' 20673 }, 20674 subscript: { inline: 'sub' }, 20675 superscript: { inline: 'sup' }, 20676 code: { inline: 'code' }, 20677 samp: { inline: 'samp' }, 20678 link: { 20679 inline: 'a', 20680 selector: 'a', 20681 remove: 'all', 20682 split: true, 20683 deep: true, 20684 onmatch: (node, _fmt, _itemName) => { 20685 return isElement$6(node) && node.hasAttribute('href'); 20686 }, 20687 onformat: (elm, _fmt, vars) => { 20688 Tools.each(vars, (value, key) => { 20689 dom.setAttrib(elm, key, value); 20690 }); 20691 } 20692 }, 20693 lang: { 20694 inline: 'span', 20695 clear_child_styles: true, 20696 remove_similar: true, 20697 attributes: { 20698 'lang': '%value', 20699 'data-mce-lang': vars => { 20700 var _a; 20701 return (_a = vars === null || vars === void 0 ? void 0 : vars.customValue) !== null && _a !== void 0 ? _a : null; 20702 } 20703 } 20704 }, 20705 removeformat: [ 20706 { 20707 selector: 'b,strong,em,i,font,u,strike,s,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins,small', 20708 remove: 'all', 20709 split: true, 20710 expand: false, 20711 block_expand: true, 20712 deep: true 20713 }, 20714 { 20715 selector: 'span', 20716 attributes: [ 20717 'style', 20718 'class' 20719 ], 20720 remove: 'empty', 20721 split: true, 20722 expand: false, 20723 deep: true 20724 }, 20725 { 20726 selector: '*', 20727 attributes: [ 20728 'style', 20729 'class' 20730 ], 20731 split: false, 20732 expand: false, 20733 deep: true 20734 } 20735 ] 20736 }; 20737 Tools.each('p h1 h2 h3 h4 h5 h6 div address pre dt dd
vendor: 10,296 bytes, lines 20737-21057
20737'.split(/\s/), name => { 20738 formats[name] = { 20739 block: name, 20740 remove: 'all' 20741 }; 20742 }); 20743 return formats; 20744 }; 20745 20746 const genericBase = { 20747 remove_similar: true, 20748 inherit: false 20749 }; 20750 const cellBase = { 20751 selector: 'td,th', 20752 ...genericBase 20753 }; 20754 const cellFormats = { 20755 tablecellbackgroundcolor: { 20756 styles: { backgroundColor: '%value' }, 20757 ...cellBase 20758 }, 20759 tablecellverticalalign: { 20760 styles: { 'vertical-align': '%value' }, 20761 ...cellBase 20762 }, 20763 tablecellbordercolor: { 20764 styles: { borderColor: '%value' }, 20765 ...cellBase 20766 }, 20767 tablecellclass: { 20768 classes: ['%value'], 20769 ...cellBase 20770 }, 20771 tableclass: { 20772 selector: 'table', 20773 classes: ['%value'], 20774 ...genericBase 20775 }, 20776 tablecellborderstyle: { 20777 styles: { borderStyle: '%value' }, 20778 ...cellBase 20779 }, 20780 tablecellborderwidth: { 20781 styles: { borderWidth: '%value' }, 20782 ...cellBase 20783 } 20784 }; 20785 const get = constant(cellFormats); 20786 20787 const FormatRegistry = editor => { 20788 const formats = {}; 20789 const get$2 = name => isNonNullable(name) ? formats[name] : formats; 20790 const has = name => has$2(formats, name); 20791 const register = (name, format) => { 20792 if (name) { 20793 if (!isString(name)) { 20794 each$d(name, (format, name) => { 20795 register(name, format); 20796 }); 20797 } else { 20798 if (!isArray$1(format)) { 20799 format = [format]; 20800 } 20801 each$e(format, format => { 20802 if (isUndefined(format.deep)) { 20803 format.deep = !isSelectorFormat(format); 20804 } 20805 if (isUndefined(format.split)) { 20806 format.split = !isSelectorFormat(format) || isInlineFormat(format); 20807 } 20808 if (isUndefined(format.remove) && isSelectorFormat(format) && !isInlineFormat(format)) { 20809 format.remove = 'none'; 20810 } 20811 if (isSelectorFormat(format) && isInlineFormat(format)) { 20812 format.mixed = true; 20813 format.block_expand = true; 20814 } 20815 if (isString(format.classes)) { 20816 format.classes = format.classes.split(/\s+/); 20817 } 20818 }); 20819 formats[name] = format; 20820 } 20821 } 20822 }; 20823 const unregister = name => { 20824 if (name && formats[name]) { 20825 delete formats[name]; 20826 } 20827 return formats; 20828 }; 20829 register(get$1(editor)); 20830 register(get()); 20831 register(getFormats(editor)); 20832 return { 20833 get: get$2, 20834 has, 20835 register, 20836 unregister 20837 }; 20838 }; 20839 20840 const each$3 = Tools.each; 20841 const dom = DOMUtils.DOM; 20842 const isPreviewItem = item => isNonNullable(item) && isObject(item); 20843 const parsedSelectorToHtml = (ancestry, editor) => { 20844 const schema = editor && editor.schema || Schema({}); 20845 const decorate = (elm, item) => { 20846 if (item.classes.length > 0) { 20847 dom.addClass(elm, item.classes.join(' ')); 20848 } 20849 dom.setAttribs(elm, item.attrs); 20850 }; 20851 const createElement = sItem => { 20852 const item = isString(sItem) ? { 20853 name: sItem, 20854 classes: [], 20855 attrs: {} 20856 } : sItem; 20857 const elm = dom.create(item.name); 20858 decorate(elm, item); 20859 return elm; 20860 }; 20861 const getRequiredParent = (elm, candidate) => { 20862 const elmRule = schema.getElementRule(elm.nodeName.toLowerCase()); 20863 const parentsRequired = elmRule === null || elmRule === void 0 ? void 0 : elmRule.parentsRequired; 20864 if (parentsRequired && parentsRequired.length) { 20865 return candidate && contains$2(parentsRequired, candidate) ? candidate : parentsRequired[0]; 20866 } else { 20867 return false; 20868 } 20869 }; 20870 const wrapInHtml = (elm, ancestors, siblings) => { 20871 let parentCandidate; 20872 const ancestor = ancestors[0]; 20873 const ancestorName = isPreviewItem(ancestor) ? ancestor.name : undefined; 20874 const parentRequired = getRequiredParent(elm, ancestorName); 20875 if (parentRequired) { 20876 if (ancestorName === parentRequired) { 20877 parentCandidate = ancestor; 20878 ancestors = ancestors.slice(1); 20879 } else { 20880 parentCandidate = parentRequired; 20881 } 20882 } else if (ancestor) { 20883 parentCandidate = ancestor; 20884 ancestors = ancestors.slice(1); 20885 } else if (!siblings) { 20886 return elm; 20887 } 20888 const parent = parentCandidate ? createElement(parentCandidate) : dom.create('div'); 20889 parent.appendChild(elm); 20890 if (siblings) { 20891 Tools.each(siblings, sibling => { 20892 const siblingElm = createElement(sibling); 20893 parent.insertBefore(siblingElm, elm); 20894 }); 20895 } 20896 const parentSiblings = isPreviewItem(parentCandidate) ? parentCandidate.siblings : undefined; 20897 return wrapInHtml(parent, ancestors, parentSiblings); 20898 }; 20899 const fragment = dom.create('div'); 20900 if (ancestry.length > 0) { 20901 const item = ancestry[0]; 20902 const elm = createElement(item); 20903 const siblings = isPreviewItem(item) ? item.siblings : undefined; 20904 fragment.appendChild(wrapInHtml(elm, ancestry.slice(1), siblings)); 20905 } 20906 return fragment; 20907 }; 20908 const parseSelectorItem = item => { 20909 item = Tools.trim(item); 20910 let tagName = 'div'; 20911 const obj = { 20912 name: tagName, 20913 classes: [], 20914 attrs: {}, 20915 selector: item 20916 }; 20917 if (item !== '*') { 20918 tagName = item.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g, ($0, $1, $2, $3, $4) => { 20919 switch ($1) { 20920 case '#': 20921 obj.attrs.id = $2; 20922 break; 20923 case '.': 20924 obj.classes.push($2); 20925 break; 20926 case ':': 20927 if (Tools.inArray('checked disabled enabled read-only required'.split(' '), $2) !== -1) { 20928 obj.attrs[$2] = $2; 20929 } 20930 break; 20931 } 20932 if ($3 === '[') { 20933 const m = $4.match(/([\w\-]+)(?:\=\"([^\"]+))?/); 20934 if (m) { 20935 obj.attrs[m[1]] = m[2]; 20936 } 20937 } 20938 return ''; 20939 }); 20940 } 20941 obj.name = tagName || 'div'; 20942 return obj; 20943 }; 20944 const parseSelector = selector => { 20945 if (!isString(selector)) { 20946 return []; 20947 } 20948 selector = selector.split(/\s*,\s*/)[0]; 20949 selector = selector.replace(/\s*(~\+|~|\+|>)\s*/g, '$1'); 20950 return Tools.map(selector.split(/(?:>|\s+(?![^\[\]]+\]))/), item => { 20951 const siblings = Tools.map(item.split(/(?:~\+|~|\+)/), parseSelectorItem); 20952 const obj = siblings.pop(); 20953 if (siblings.length) { 20954 obj.siblings = siblings; 20955 } 20956 return obj; 20957 }).reverse(); 20958 }; 20959 const getCssText = (editor, format) => { 20960 let previewCss = ''; 20961 let previewStyles = getPreviewStyles(editor); 20962 if (previewStyles === '') { 20963 return ''; 20964 } 20965 const removeVars = val => { 20966 return isString(val) ? val.replace(/%(\w+)/g, '') : ''; 20967 }; 20968 const getComputedStyle = (name, elm) => { 20969 return dom.getStyle(elm !== null && elm !== void 0 ? elm : editor.getBody(), name, true); 20970 }; 20971 if (isString(format)) { 20972 const formats = editor.formatter.get(format); 20973 if (!formats) { 20974 return ''; 20975 } 20976 format = formats[0]; 20977 } 20978 if ('preview' in format) { 20979 const preview = format.preview; 20980 if (preview === false) { 20981 return ''; 20982 } else { 20983 previewStyles = preview || previewStyles; 20984 } 20985 } 20986 let name = format.block || format.inline || 'span'; 20987 let previewFrag; 20988 const items = parseSelector(format.selector); 20989 if (items.length > 0) { 20990 if (!items[0].name) { 20991 items[0].name = name; 20992 } 20993 name = format.selector; 20994 previewFrag = parsedSelectorToHtml(items, editor); 20995 } else { 20996 previewFrag = parsedSelectorToHtml([name], editor); 20997 } 20998 const previewElm = dom.select(name, previewFrag)[0] || previewFrag.firstChild; 20999 each$3(format.styles, (value, name) => { 21000 const newValue = removeVars(value); 21001 if (newValue) { 21002 dom.setStyle(previewElm, name, newValue); 21003 } 21004 }); 21005 each$3(format.attributes, (value, name) => { 21006 const newValue = removeVars(value); 21007 if (newValue) { 21008 dom.setAttrib(previewElm, name, newValue); 21009 } 21010 }); 21011 each$3(format.classes, value => { 21012 const newValue = removeVars(value); 21013 if (!dom.hasClass(previewElm, newValue)) { 21014 dom.addClass(previewElm, newValue); 21015 } 21016 }); 21017 editor.dispatch('PreviewFormats'); 21018 dom.setStyles(previewFrag, { 21019 position: 'absolute', 21020 left: -65535 21021 }); 21022 editor.getBody().appendChild(previewFrag); 21023 const rawParentFontSize = getComputedStyle('fontSize'); 21024 const parentFontSize = /px$/.test(rawParentFontSize) ? parseInt(rawParentFontSize, 10) : 0; 21025 each$3(previewStyles.split(' '), name => { 21026 let value = getComputedStyle(name, previewElm); 21027 if (name === 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) { 21028 value = getComputedStyle(name); 21029 if (rgbaToHexString(value).toLowerCase() === '#ffffff') { 21030 return; 21031 } 21032 } 21033 if (name === 'color') { 21034 if (rgbaToHexString(value).toLowerCase() === '#000000') { 21035 return; 21036 } 21037 } 21038 if (name === 'font-size') { 21039 if (/em|%$/.test(value)) { 21040 if (parentFontSize === 0) { 21041 return; 21042 } 21043 const numValue = parseFloat(value) / (/%$/.test(value) ? 100 : 1); 21044 value = numValue * parentFontSize + 'px'; 21045 } 21046 } 21047 if (name === 'border' && value) { 21048 previewCss += 'padding:0 2px;'; 21049 } 21050 previewCss += name + ':' + value + ';'; 21051 }); 21052 editor.dispatch('AfterPreviewFormats'); 21053 dom.remove(previewFrag); 21054 return previewCss; 21055 }; 21056 21057 const setup$
vendor: 868 bytes, lines 21057-21091
21057s = editor => { 21058 editor.addShortcut('meta+b', '', 'Bold'); 21059 editor.addShortcut('meta+i', '', 'Italic'); 21060 editor.addShortcut('meta+u', '', 'Underline'); 21061 for (let i = 1; i <= 6; i++) { 21062 editor.addShortcut('access+' + i, '', [ 21063 'FormatBlock', 21064 false, 21065 'h' + i 21066 ]); 21067 } 21068 editor.addShortcut('access+7', '', [ 21069 'FormatBlock', 21070 false, 21071 'p' 21072 ]); 21073 editor.addShortcut('access+8', '', [ 21074 'FormatBlock', 21075 false, 21076 'div' 21077 ]); 21078 editor.addShortcut('access+9', '', [ 21079 'FormatBlock', 21080 false, 21081 'address' 21082 ]); 21083 }; 21084 21085 const Formatter = editor => { 21086 const formats = FormatRegistry(editor); 21087 const formatChangeState = Cell({}); 21088 setup$s(editor); 21089 setup$v(editor); 21090 if (!isRtc(editor)) { 21091 setup$u
vendor: 7,773 bytes, lines 21091-21321
21091(formatChangeState, editor); 21092 } 21093 return { 21094 get: formats.get, 21095 has: formats.has, 21096 register: formats.register, 21097 unregister: formats.unregister, 21098 apply: (name, vars, node) => { 21099 applyFormat(editor, name, vars, node); 21100 }, 21101 remove: (name, vars, node, similar) => { 21102 removeFormat(editor, name, vars, node, similar); 21103 }, 21104 toggle: (name, vars, node) => { 21105 toggleFormat(editor, name, vars, node); 21106 }, 21107 match: (name, vars, node, similar) => matchFormat(editor, name, vars, node, similar), 21108 closest: names => closestFormat(editor, names), 21109 matchAll: (names, vars) => matchAllFormats(editor, names, vars), 21110 matchNode: (node, name, vars, similar) => matchNodeFormat(editor, node, name, vars, similar), 21111 canApply: name => canApplyFormat(editor, name), 21112 formatChanged: (formats, callback, similar, vars) => formatChanged(editor, formatChangeState, formats, callback, similar, vars), 21113 getCssText: curry(getCssText, editor) 21114 }; 21115 }; 21116 21117 const shouldIgnoreCommand = cmd => { 21118 switch (cmd.toLowerCase()) { 21119 case 'undo': 21120 case 'redo': 21121 case 'mcefocus': 21122 return true; 21123 default: 21124 return false; 21125 } 21126 }; 21127 const registerEvents = (editor, undoManager, locks) => { 21128 const isFirstTypedCharacter = Cell(false); 21129 const addNonTypingUndoLevel = e => { 21130 setTyping(undoManager, false, locks); 21131 undoManager.add({}, e); 21132 }; 21133 editor.on('init', () => { 21134 undoManager.add(); 21135 }); 21136 editor.on('BeforeExecCommand', e => { 21137 const cmd = e.command; 21138 if (!shouldIgnoreCommand(cmd)) { 21139 endTyping(undoManager, locks); 21140 undoManager.beforeChange(); 21141 } 21142 }); 21143 editor.on('ExecCommand', e => { 21144 const cmd = e.command; 21145 if (!shouldIgnoreCommand(cmd)) { 21146 addNonTypingUndoLevel(e); 21147 } 21148 }); 21149 editor.on('ObjectResizeStart cut', () => { 21150 undoManager.beforeChange(); 21151 }); 21152 editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel); 21153 editor.on('dragend', addNonTypingUndoLevel); 21154 editor.on('keyup', e => { 21155 const keyCode = e.keyCode; 21156 if (e.isDefaultPrevented()) { 21157 return; 21158 } 21159 const isMeta = Env.os.isMacOS() && e.key === 'Meta'; 21160 if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45 || e.ctrlKey || isMeta) { 21161 addNonTypingUndoLevel(); 21162 editor.nodeChanged(); 21163 } 21164 if (keyCode === 46 || keyCode === 8) { 21165 editor.nodeChanged(); 21166 } 21167 if (isFirstTypedCharacter.get() && undoManager.typing && !isEq$1(createFromEditor(editor), undoManager.data[0])) { 21168 if (!editor.isDirty()) { 21169 editor.setDirty(true); 21170 } 21171 editor.dispatch('TypingUndo'); 21172 isFirstTypedCharacter.set(false); 21173 editor.nodeChanged(); 21174 } 21175 }); 21176 editor.on('keydown', e => { 21177 const keyCode = e.keyCode; 21178 if (e.isDefaultPrevented()) { 21179 return; 21180 } 21181 if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45) { 21182 if (undoManager.typing) { 21183 addNonTypingUndoLevel(e); 21184 } 21185 return; 21186 } 21187 const modKey = e.ctrlKey && !e.altKey || e.metaKey; 21188 if ((keyCode < 16 || keyCode > 20) && keyCode !== 224 && keyCode !== 91 && !undoManager.typing && !modKey) { 21189 undoManager.beforeChange(); 21190 setTyping(undoManager, true, locks); 21191 undoManager.add({}, e); 21192 isFirstTypedCharacter.set(true); 21193 return; 21194 } 21195 const hasOnlyMetaOrCtrlModifier = Env.os.isMacOS() ? e.metaKey : e.ctrlKey && !e.altKey; 21196 if (hasOnlyMetaOrCtrlModifier) { 21197 undoManager.beforeChange(); 21198 } 21199 }); 21200 editor.on('mousedown', e => { 21201 if (undoManager.typing) { 21202 addNonTypingUndoLevel(e); 21203 } 21204 }); 21205 const isInsertReplacementText = event => event.inputType === 'insertReplacementText'; 21206 const isInsertTextDataNull = event => event.inputType === 'insertText' && event.data === null; 21207 const isInsertFromPasteOrDrop = event => event.inputType === 'insertFromPaste' || event.inputType === 'insertFromDrop'; 21208 editor.on('input', e => { 21209 if (e.inputType && (isInsertReplacementText(e) || isInsertTextDataNull(e) || isInsertFromPasteOrDrop(e))) { 21210 addNonTypingUndoLevel(e); 21211 } 21212 }); 21213 editor.on('AddUndo Undo Redo ClearUndos', e => { 21214 if (!e.isDefaultPrevented()) { 21215 editor.nodeChanged(); 21216 } 21217 }); 21218 }; 21219 const addKeyboardShortcuts = editor => { 21220 editor.addShortcut('meta+z', '', 'Undo'); 21221 editor.addShortcut('meta+y,meta+shift+z', '', 'Redo'); 21222 }; 21223 21224 const UndoManager = editor => { 21225 const beforeBookmark = value$2(); 21226 const locks = Cell(0); 21227 const index = Cell(0); 21228 const undoManager = { 21229 data: [], 21230 typing: false, 21231 beforeChange: () => { 21232 beforeChange(editor, locks, beforeBookmark); 21233 }, 21234 add: (level, event) => { 21235 return addUndoLevel(editor, undoManager, index, locks, beforeBookmark, level, event); 21236 }, 21237 dispatchChange: () => { 21238 editor.setDirty(true); 21239 const level = createFromEditor(editor); 21240 level.bookmark = getUndoBookmark(editor.selection); 21241 editor.dispatch('change', { 21242 level, 21243 lastLevel: get$b(undoManager.data, index.get()).getOrUndefined() 21244 }); 21245 }, 21246 undo: () => { 21247 return undo(editor, undoManager, locks, index); 21248 }, 21249 redo: () => { 21250 return redo(editor, index, undoManager.data); 21251 }, 21252 clear: () => { 21253 clear(editor, undoManager, index); 21254 }, 21255 reset: () => { 21256 reset(editor, undoManager); 21257 }, 21258 hasUndo: () => { 21259 return hasUndo(editor, undoManager, index); 21260 }, 21261 hasRedo: () => { 21262 return hasRedo(editor, undoManager, index); 21263 }, 21264 transact: callback => { 21265 return transact(editor, undoManager, locks, callback); 21266 }, 21267 ignore: callback => { 21268 ignore(editor, locks, callback); 21269 }, 21270 extra: (callback1, callback2) => { 21271 extra(editor, undoManager, index, callback1, callback2); 21272 } 21273 }; 21274 if (!isRtc(editor)) { 21275 registerEvents(editor, undoManager, locks); 21276 } 21277 addKeyboardShortcuts(editor); 21278 return undoManager; 21279 }; 21280 21281 const nonTypingKeycodes = [ 21282 9, 21283 27, 21284 VK.HOME, 21285 VK.END, 21286 19, 21287 20, 21288 44, 21289 144, 21290 145, 21291 33, 21292 34, 21293 45, 21294 16, 21295 17, 21296 18, 21297 91, 21298 92, 21299 93, 21300 VK.DOWN, 21301 VK.UP, 21302 VK.LEFT, 21303 VK.RIGHT 21304 ].concat(Env.browser.isFirefox() ? [224] : []); 21305 const placeholderAttr = 'data-mce-placeholder'; 21306 const isKeyboardEvent = e => e.type === 'keydown' || e.type === 'keyup'; 21307 const isDeleteEvent = e => { 21308 const keyCode = e.keyCode; 21309 return keyCode === VK.BACKSPACE || keyCode === VK.DELETE; 21310 }; 21311 const isNonTypingKeyboardEvent = e => { 21312 if (isKeyboardEvent(e)) { 21313 const keyCode = e.keyCode; 21314 return !isDeleteEvent(e) && (VK.metaKeyPressed(e) || e.altKey || keyCode >= 112 && keyCode <= 123 || contains$2(nonTypingKeycodes, keyCode)); 21315 } else { 21316 return false; 21317 } 21318 }; 21319 const isTypingKeyboardEvent = e => isKeyboardEvent(e) && !(isDeleteEvent(e) || e.type === 'keyup' && e.keyCode === 229); 21320 const isVisuallyEmpty = (dom, rootElm, forcedRootBlock) => { 21321 if (
vendor: 2,533 bytes, lines 21321-21380
21321dom.isEmpty(rootElm, undefined, { 21322 skipBogus: false, 21323 includeZwsp: true 21324 })) { 21325 const firstElement = rootElm.firstElementChild; 21326 if (!firstElement) { 21327 return true; 21328 } else if (dom.getStyle(rootElm.firstElementChild, 'padding-left') || dom.getStyle(rootElm.firstElementChild, 'padding-right')) { 21329 return false; 21330 } else { 21331 return forcedRootBlock === firstElement.nodeName.toLowerCase(); 21332 } 21333 } else { 21334 return false; 21335 } 21336 }; 21337 const setup$r = editor => { 21338 var _a; 21339 const dom = editor.dom; 21340 const rootBlock = getForcedRootBlock(editor); 21341 const placeholder = (_a = getPlaceholder(editor)) !== null && _a !== void 0 ? _a : ''; 21342 const updatePlaceholder = (e, initial) => { 21343 if (isNonTypingKeyboardEvent(e)) { 21344 return; 21345 } 21346 const body = editor.getBody(); 21347 const showPlaceholder = isTypingKeyboardEvent(e) ? false : isVisuallyEmpty(dom, body, rootBlock); 21348 const isPlaceholderShown = dom.getAttrib(body, placeholderAttr) !== ''; 21349 if (isPlaceholderShown !== showPlaceholder || initial) { 21350 dom.setAttrib(body, placeholderAttr, showPlaceholder ? placeholder : null); 21351 firePlaceholderToggle(editor, showPlaceholder); 21352 editor.on(showPlaceholder ? 'keydown' : 'keyup', updatePlaceholder); 21353 editor.off(showPlaceholder ? 'keyup' : 'keydown', updatePlaceholder); 21354 } 21355 }; 21356 if (isNotEmpty(placeholder)) { 21357 editor.on('init', e => { 21358 updatePlaceholder(e, true); 21359 editor.on('change SetContent ExecCommand', updatePlaceholder); 21360 editor.on('paste', e => Delay.setEditorTimeout(editor, () => updatePlaceholder(e))); 21361 }); 21362 } 21363 }; 21364 21365 const blockPosition = (block, position) => ({ 21366 block, 21367 position 21368 }); 21369 const blockBoundary = (from, to) => ({ 21370 from, 21371 to 21372 }); 21373 const getBlockPosition = (rootNode, pos) => { 21374 const rootElm = SugarElement.fromDom(rootNode); 21375 const containerElm = SugarElement.fromDom(pos.container()); 21376 return getParentBlock$2(rootElm, containerElm).map(block => blockPosition(block, pos)); 21377 }; 21378 const isNotAncestorial = blockBoundary => !(contains(blockBoundary.to.block, blockBoundary.from.block) || contains(blockBoundary.from.block, blockBoundary.to.block)); 21379 const isDifferentBlocks = blockBoundary => !eq(blockBoundary.from.block, blockBoundary.to.block); 21380 const getClosestHost = (root, scope) => {
vendor: 16,490 bytes, lines 21381-21682
21381 const isRoot = node => eq(node, root); 21382 const isHost = node => isTableCell$2(node) || isContentEditableTrue$3(node.dom); 21383 return closest$4(scope, isHost, isRoot).filter(isElement$7).getOr(root); 21384 }; 21385 const hasSameHost = (rootNode, blockBoundary) => { 21386 const root = SugarElement.fromDom(rootNode); 21387 return eq(getClosestHost(root, blockBoundary.from.block), getClosestHost(root, blockBoundary.to.block)); 21388 }; 21389 const isEditable$1 = blockBoundary => isContentEditableFalse$b(blockBoundary.from.block.dom) === false && isContentEditableFalse$b(blockBoundary.to.block.dom) === false; 21390 const hasValidBlocks = blockBoundary => { 21391 const isValidBlock = block => isTextBlock$2(block) || hasBlockAttr(block.dom) || isListItem$1(block); 21392 return isValidBlock(blockBoundary.from.block) && isValidBlock(blockBoundary.to.block); 21393 }; 21394 const skipLastBr = (schema, rootNode, forward, blockPosition) => { 21395 if (isBr$6(blockPosition.position.getNode()) && !isEmpty$2(schema, blockPosition.block)) { 21396 return positionIn(false, blockPosition.block.dom).bind(lastPositionInBlock => { 21397 if (lastPositionInBlock.isEqual(blockPosition.position)) { 21398 return fromPosition(forward, rootNode, lastPositionInBlock).bind(to => getBlockPosition(rootNode, to)); 21399 } else { 21400 return Optional.some(blockPosition); 21401 } 21402 }).getOr(blockPosition); 21403 } else { 21404 return blockPosition; 21405 } 21406 }; 21407 const readFromRange = (schema, rootNode, forward, rng) => { 21408 const fromBlockPos = getBlockPosition(rootNode, CaretPosition.fromRangeStart(rng)); 21409 const toBlockPos = fromBlockPos.bind(blockPos => fromPosition(forward, rootNode, blockPos.position).bind(to => getBlockPosition(rootNode, to).map(blockPos => skipLastBr(schema, rootNode, forward, blockPos)))); 21410 return lift2(fromBlockPos, toBlockPos, blockBoundary).filter(blockBoundary => isDifferentBlocks(blockBoundary) && hasSameHost(rootNode, blockBoundary) && isEditable$1(blockBoundary) && hasValidBlocks(blockBoundary) && isNotAncestorial(blockBoundary)); 21411 }; 21412 const read$1 = (schema, rootNode, forward, rng) => rng.collapsed ? readFromRange(schema, rootNode, forward, rng) : Optional.none(); 21413 21414 const getChildrenUntilBlockBoundary = (block, schema) => { 21415 const children = children$1(block); 21416 return findIndex$2(children, el => schema.isBlock(name(el))).fold(constant(children), index => children.slice(0, index)); 21417 }; 21418 const extractChildren = (block, schema) => { 21419 const children = getChildrenUntilBlockBoundary(block, schema); 21420 each$e(children, remove$4); 21421 return children; 21422 }; 21423 const removeEmptyRoot = (schema, rootNode, block) => { 21424 const parents = parentsAndSelf(block, rootNode); 21425 return find$2(parents.reverse(), element => isEmpty$2(schema, element)).each(remove$4); 21426 }; 21427 const isEmptyBefore = (schema, el) => filter$5(prevSiblings(el), el => !isEmpty$2(schema, el)).length === 0; 21428 const nestedBlockMerge = (rootNode, fromBlock, toBlock, schema, insertionPoint) => { 21429 if (isEmpty$2(schema, toBlock)) { 21430 fillWithPaddingBr(toBlock); 21431 return firstPositionIn(toBlock.dom); 21432 } 21433 if (isEmptyBefore(schema, insertionPoint) && isEmpty$2(schema, fromBlock)) { 21434 before$3(insertionPoint, SugarElement.fromTag('br')); 21435 } 21436 const position = prevPosition(toBlock.dom, CaretPosition.before(insertionPoint.dom)); 21437 each$e(extractChildren(fromBlock, schema), child => { 21438 before$3(insertionPoint, child); 21439 }); 21440 removeEmptyRoot(schema, rootNode, fromBlock); 21441 return position; 21442 }; 21443 const isInline = (schema, node) => schema.isInline(name(node)); 21444 const sidelongBlockMerge = (rootNode, fromBlock, toBlock, schema) => { 21445 if (isEmpty$2(schema, toBlock)) { 21446 if (isEmpty$2(schema, fromBlock)) { 21447 const getInlineToBlockDescendants = el => { 21448 const helper = (node, elements) => firstChild(node).fold(() => elements, child => isInline(schema, child) ? helper(child, elements.concat(shallow$1(child))) : elements); 21449 return helper(el, []); 21450 }; 21451 const newFromBlockDescendants = foldr(getInlineToBlockDescendants(toBlock), (element, descendant) => { 21452 wrap$2(element, descendant); 21453 return descendant; 21454 }, createPaddingBr()); 21455 empty(fromBlock); 21456 append$1(fromBlock, newFromBlockDescendants); 21457 } 21458 remove$4(toBlock); 21459 return firstPositionIn(fromBlock.dom); 21460 } 21461 const position = lastPositionIn(toBlock.dom); 21462 each$e(extractChildren(fromBlock, schema), child => { 21463 append$1(toBlock, child); 21464 }); 21465 removeEmptyRoot(schema, rootNode, fromBlock); 21466 return position; 21467 }; 21468 const findInsertionPoint = (toBlock, block) => { 21469 const parentsAndSelf$1 = parentsAndSelf(block, toBlock); 21470 return Optional.from(parentsAndSelf$1[parentsAndSelf$1.length - 1]); 21471 }; 21472 const getInsertionPoint = (fromBlock, toBlock) => contains(toBlock, fromBlock) ? findInsertionPoint(toBlock, fromBlock) : Optional.none(); 21473 const trimBr = (first, block) => { 21474 positionIn(first, block.dom).bind(position => Optional.from(position.getNode())).map(SugarElement.fromDom).filter(isBr$5).each(remove$4); 21475 }; 21476 const mergeBlockInto = (rootNode, fromBlock, toBlock, schema) => { 21477 trimBr(true, fromBlock); 21478 trimBr(false, toBlock); 21479 return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock, schema), curry(nestedBlockMerge, rootNode, fromBlock, toBlock, schema)); 21480 }; 21481 const mergeBlocks = (rootNode, forward, block1, block2, schema) => forward ? mergeBlockInto(rootNode, block2, block1, schema) : mergeBlockInto(rootNode, block1, block2, schema); 21482 21483 const backspaceDelete$a = (editor, forward) => { 21484 const rootNode = SugarElement.fromDom(editor.getBody()); 21485 const position = read$1(editor.schema, rootNode.dom, forward, editor.selection.getRng()).map(blockBoundary => () => { 21486 mergeBlocks(rootNode, forward, blockBoundary.from.block, blockBoundary.to.block, editor.schema).each(pos => { 21487 editor.selection.setRng(pos.toRange()); 21488 }); 21489 }); 21490 return position; 21491 }; 21492 21493 const deleteRangeMergeBlocks = (rootNode, selection, schema) => { 21494 const rng = selection.getRng(); 21495 return lift2(getParentBlock$2(rootNode, SugarElement.fromDom(rng.startContainer)), getParentBlock$2(rootNode, SugarElement.fromDom(rng.endContainer)), (block1, block2) => { 21496 if (!eq(block1, block2)) { 21497 return Optional.some(() => { 21498 rng.deleteContents(); 21499 mergeBlocks(rootNode, true, block1, block2, schema).each(pos => { 21500 selection.setRng(pos.toRange()); 21501 }); 21502 }); 21503 } else { 21504 return Optional.none(); 21505 } 21506 }).getOr(Optional.none()); 21507 }; 21508 const isRawNodeInTable = (root, rawNode) => { 21509 const node = SugarElement.fromDom(rawNode); 21510 const isRoot = curry(eq, root); 21511 return ancestor$4(node, isTableCell$2, isRoot).isSome(); 21512 }; 21513 const isSelectionInTable = (root, rng) => isRawNodeInTable(root, rng.startContainer) || isRawNodeInTable(root, rng.endContainer); 21514 const isEverythingSelected = (root, rng) => { 21515 const noPrevious = prevPosition(root.dom, CaretPosition.fromRangeStart(rng)).isNone(); 21516 const noNext = nextPosition(root.dom, CaretPosition.fromRangeEnd(rng)).isNone(); 21517 return !isSelectionInTable(root, rng) && noPrevious && noNext; 21518 }; 21519 const emptyEditor = editor => { 21520 return Optional.some(() => { 21521 editor.setContent(''); 21522 editor.selection.setCursorLocation(); 21523 }); 21524 }; 21525 const deleteRange$2 = editor => { 21526 const rootNode = SugarElement.fromDom(editor.getBody()); 21527 const rng = editor.selection.getRng(); 21528 return isEverythingSelected(rootNode, rng) ? emptyEditor(editor) : deleteRangeMergeBlocks(rootNode, editor.selection, editor.schema); 21529 }; 21530 const backspaceDelete$9 = (editor, _forward) => editor.selection.isCollapsed() ? Optional.none() : deleteRange$2(editor); 21531 21532 const showCaret = (direction, editor, node, before, scrollIntoView) => Optional.from(editor._selectionOverrides.showCaret(direction, node, before, scrollIntoView)); 21533 const getNodeRange = node => { 21534 const rng = node.ownerDocument.createRange(); 21535 rng.selectNode(node); 21536 return rng; 21537 }; 21538 const selectNode = (editor, node) => { 21539 const e = editor.dispatch('BeforeObjectSelected', { target: node }); 21540 if (e.isDefaultPrevented()) { 21541 return Optional.none(); 21542 } 21543 return Optional.some(getNodeRange(node)); 21544 }; 21545 const renderCaretAtRange = (editor, range, scrollIntoView) => { 21546 const normalizedRange = normalizeRange(1, editor.getBody(), range); 21547 const caretPosition = CaretPosition.fromRangeStart(normalizedRange); 21548 const caretPositionNode = caretPosition.getNode(); 21549 if (isInlineFakeCaretTarget(caretPositionNode)) { 21550 return showCaret(1, editor, caretPositionNode, !caretPosition.isAtEnd(), false); 21551 } 21552 const caretPositionBeforeNode = caretPosition.getNode(true); 21553 if (isInlineFakeCaretTarget(caretPositionBeforeNode)) { 21554 return showCaret(1, editor, caretPositionBeforeNode, false, false); 21555 } 21556 const ceRoot = getContentEditableRoot$1(editor.dom.getRoot(), caretPosition.getNode()); 21557 if (isInlineFakeCaretTarget(ceRoot)) { 21558 return showCaret(1, editor, ceRoot, false, scrollIntoView); 21559 } 21560 return Optional.none(); 21561 }; 21562 const renderRangeCaret = (editor, range, scrollIntoView) => range.collapsed ? renderCaretAtRange(editor, range, scrollIntoView).getOr(range) : range; 21563 21564 const isBeforeBoundary = pos => isBeforeContentEditableFalse(pos) || isBeforeMedia(pos); 21565 const isAfterBoundary = pos => isAfterContentEditableFalse(pos) || isAfterMedia(pos); 21566 const trimEmptyTextNode = (dom, node) => { 21567 if (isText$b(node) && node.data.length === 0) { 21568 dom.remove(node); 21569 } 21570 }; 21571 const deleteContentAndShowCaret = (editor, range, node, direction, forward, peekCaretPosition) => { 21572 showCaret(direction, editor, peekCaretPosition.getNode(!forward), forward, true).each(caretRange => { 21573 if (range.collapsed) { 21574 const deleteRange = range.cloneRange(); 21575 if (forward) { 21576 deleteRange.setEnd(caretRange.startContainer, caretRange.startOffset); 21577 } else { 21578 deleteRange.setStart(caretRange.endContainer, caretRange.endOffset); 21579 } 21580 deleteRange.deleteContents(); 21581 } else { 21582 range.deleteContents(); 21583 } 21584 editor.selection.setRng(caretRange); 21585 }); 21586 trimEmptyTextNode(editor.dom, node); 21587 }; 21588 const deleteBoundaryText = (editor, forward) => { 21589 const range = editor.selection.getRng(); 21590 if (!isText$b(range.commonAncestorContainer)) { 21591 return Optional.none(); 21592 } 21593 const direction = forward ? 1 : -1; 21594 const caretWalker = CaretWalker(editor.getBody()); 21595 const getNextPosFn = curry(getVisualCaretPosition, forward ? caretWalker.next : caretWalker.prev); 21596 const isBeforeFn = forward ? isBeforeBoundary : isAfterBoundary; 21597 const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range); 21598 const nextCaretPosition = getNextPosFn(caretPosition); 21599 const normalizedNextCaretPosition = nextCaretPosition ? normalizePosition(forward, nextCaretPosition) : nextCaretPosition; 21600 if (!normalizedNextCaretPosition || !isMoveInsideSameBlock(caretPosition, normalizedNextCaretPosition)) { 21601 return Optional.none(); 21602 } else if (isBeforeFn(normalizedNextCaretPosition)) { 21603 return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, normalizedNextCaretPosition)); 21604 } 21605 const peekCaretPosition = getNextPosFn(normalizedNextCaretPosition); 21606 if (peekCaretPosition && isBeforeFn(peekCaretPosition)) { 21607 if (isMoveInsideSameBlock(normalizedNextCaretPosition, peekCaretPosition)) { 21608 return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, peekCaretPosition)); 21609 } 21610 } 21611 return Optional.none(); 21612 }; 21613 const backspaceDelete$8 = (editor, forward) => deleteBoundaryText(editor, forward); 21614 21615 const getEdgeCefPosition = (editor, atStart) => { 21616 const root = editor.getBody(); 21617 return atStart ? firstPositionIn(root).filter(isBeforeContentEditableFalse) : lastPositionIn(root).filter(isAfterContentEditableFalse); 21618 }; 21619 const isCefAtEdgeSelected = editor => { 21620 const rng = editor.selection.getRng(); 21621 return !rng.collapsed && (getEdgeCefPosition(editor, true).exists(pos => pos.isEqual(CaretPosition.fromRangeStart(rng))) || getEdgeCefPosition(editor, false).exists(pos => pos.isEqual(CaretPosition.fromRangeEnd(rng)))); 21622 }; 21623 21624 const isCompoundElement = node => isNonNullable(node) && (isTableCell$2(SugarElement.fromDom(node)) || isListItem$1(SugarElement.fromDom(node))); 21625 const DeleteAction = Adt.generate([ 21626 { remove: ['element'] }, 21627 { moveToElement: ['element'] }, 21628 { moveToPosition: ['position'] } 21629 ]); 21630 const isAtContentEditableBlockCaret = (forward, from) => { 21631 const elm = from.getNode(!forward); 21632 const caretLocation = forward ? 'after' : 'before'; 21633 return isElement$6(elm) && elm.getAttribute('data-mce-caret') === caretLocation; 21634 }; 21635 const isDeleteFromCefDifferentBlocks = (root, forward, from, to, schema) => { 21636 const inSameBlock = elm => schema.isInline(elm.nodeName.toLowerCase()) && !isInSameBlock(from, to, root); 21637 return getRelativeCefElm(!forward, from).fold(() => getRelativeCefElm(forward, to).fold(never, inSameBlock), inSameBlock); 21638 }; 21639 const deleteEmptyBlockOrMoveToCef = (schema, root, forward, from, to) => { 21640 const toCefElm = to.getNode(!forward); 21641 return getParentBlock$2(SugarElement.fromDom(root), SugarElement.fromDom(from.getNode())).map(blockElm => isEmpty$2(schema, blockElm) ? DeleteAction.remove(blockElm.dom) : DeleteAction.moveToElement(toCefElm)).orThunk(() => Optional.some(DeleteAction.moveToElement(toCefElm))); 21642 }; 21643 const findCefPosition = (root, forward, from, schema) => fromPosition(forward, root, from).bind(to => { 21644 if (isCompoundElement(to.getNode())) { 21645 return Optional.none(); 21646 } else if (isDeleteFromCefDifferentBlocks(root, forward, from, to, schema)) { 21647 return Optional.none(); 21648 } else if (forward && isContentEditableFalse$b(to.getNode())) { 21649 return deleteEmptyBlockOrMoveToCef(schema, root, forward, from, to); 21650 } else if (!forward && isContentEditableFalse$b(to.getNode(true))) { 21651 return deleteEmptyBlockOrMoveToCef(schema, root, forward, from, to); 21652 } else if (forward && isAfterContentEditableFalse(from)) { 21653 return Optional.some(DeleteAction.moveToPosition(to)); 21654 } else if (!forward && isBeforeContentEditableFalse(from)) { 21655 return Optional.some(DeleteAction.moveToPosition(to)); 21656 } else { 21657 return Optional.none(); 21658 } 21659 }); 21660 const getContentEditableBlockAction = (forward, elm) => { 21661 if (isNullable(elm)) { 21662 return Optional.none(); 21663 } else if (forward && isContentEditableFalse$b(elm.nextSibling)) { 21664 return Optional.some(DeleteAction.moveToElement(elm.nextSibling)); 21665 } else if (!forward && isContentEditableFalse$b(elm.previousSibling)) { 21666 return Optional.some(DeleteAction.moveToElement(elm.previousSibling)); 21667 } else { 21668 return Optional.none(); 21669 } 21670 }; 21671 const skipMoveToActionFromInlineCefToContent = (root, from, deleteAction) => deleteAction.fold(elm => Optional.some(DeleteAction.remove(elm)), elm => Optional.some(DeleteAction.moveToElement(elm)), to => { 21672 if (isInSameBlock(from, to, root)) { 21673 return Optional.none(); 21674 } else { 21675 return Optional.some(DeleteAction.moveToPosition(to)); 21676 } 21677 }); 21678 const getContentEditableAction = (root, forward, from, schema) => { 21679 if (isAtContentEditableBlockCaret(forward, from)) { 21680 return getContentEditableBlockAction(forward, from.getNode(!forward)).orThunk(() => findCefPosition(root, forward, from, schema)); 21681 } else { 21682 return findCefPosition(root, forward, from, schema).bind(deleteAction =>
21682 skipMoveToActionFromInlineCefToContent(root, from, deleteAction)); 21683 } 21684 }; 21685 const read = (root, forward, rng, schema) => { 21686 const normalizedRange = normalizeRange(forward ? 1 : -1, root, rng); 21687 const from = CaretPosition.fromRangeStart(normalizedRange); 21688 const rootElement = SugarElement.fromDom(root); 21689 if (!forward && isAfterContentEditableFalse(from)) { 21690 return Optional.some(DeleteAction.remove(from.getNode(true))); 21691 } else if (forward && isBeforeContentEditableFalse(from)) { 21692 return Optional.some(DeleteAction.remove(from.getNode())); 21693 } else if (!forward && isBeforeContentEditableFalse(from) && isAfterBr(rootElement, from, schema)) { 21694 return findPreviousBr(rootElement, from, schema).map(br => DeleteAction.remove(br.getNode())); 21695 } else if (forward && isAfterContentEditableFalse(from) && isBeforeBr$1(rootElement, from, schema)) { 21696 return findNextBr(rootElement, from, schema).map(br => DeleteAction.remove(br.getNode())); 21697 } else { 21698 return getContentEditableAction(root, forward, from, schema); 21699 } 21700 }; 21701 21702 const deleteElement$1 = (editor, forward) => element => { 21703 editor._selectionOverrides.hideFakeCaret(); 21704 deleteElement$2(editor, forward, SugarElement.fromDom(element)); 21705 return true; 21706 }; 21707 const moveToElement = (editor, forward) => element => { 21708 const pos = forward ? CaretPosition.before(element) : CaretPosition.after(element); 21709 editor.selection.setRng(pos.toRange()); 21710 return true; 21711 }; 21712 const moveToPosition = editor => pos => { 21713 editor.selection.setRng(pos.toRange()); 21714 return true; 21715 }; 21716 const getAncestorCe = (editor, node) => Optional.from(getContentEditableRoot$1(editor.getBody(), node)); 21717 const backspaceDeleteCaret = (editor, forward) => { 21718 const selectedNode = editor.selection.getNode(); 21719 return getAncestorCe(editor, selectedNode).filter(isContentEditableFalse$b).fold(() => read(editor.getBody(), forward, editor.selection.getRng(), editor.schema).map(deleteAction => () => deleteAction.fold(deleteElement$1(editor, forward), moveToElement(editor, forward), moveToPosition(editor))), () => Optional.some(noop)); 21720 }; 21721 const deleteOffscreenSelection = rootElement => { 21722 each$e(descendants(rootElement, '.mce-offscreen-selection'), remove$4); 21723 }; 21724 const backspaceDeleteRange = (editor, forward) => { 21725 const selectedNode = editor.selection.getNode(); 21726 if (isContentEditableFalse$b(selectedNode) && !isTableCell$3(selectedNode)) { 21727 const hasCefAncestor = getAncestorCe(editor, selectedNode.parentNode).filter(isContentEditableFalse$b); 21728 return hasCefAncestor.fold(() => Optional.some(() => { 21729 deleteOffscreenSelection(SugarElement.fromDom(editor.getBody())); 21730 deleteElement$2(editor, forward, SugarElement.fromDom(editor.selection.getNode())); 21731 paddEmptyBody(editor); 21732 }), () => Optional.some(noop)); 21733 } 21734 if (isCefAtEdgeSelected(editor)) { 21735 return Optional.some(() => { 21736 deleteRangeContents(editor, editor.selection.getRng(), SugarElement.fromDom(editor.getBody())); 21737 }); 21738 } 21739 return Optional.none(); 21740 }; 21741 const paddEmptyElement = editor => { 21742 const dom = editor.dom, selection = editor.selection; 21743 const ceRoot = getContentEditableRoot$1(editor.getBody(), selection.getNode()); 21744 if (isContentEditableTrue$3(ceRoot) && dom.isBlock(ceRoot) && dom.isEmpty(ceRoot)) { 21745 const br = dom.create('br', { 'data-mce-bogus': '1' }); 21746 dom.setHTML(ceRoot, ''); 21747 ceRoot.appendChild(br); 21748 selection.setRng(CaretPosition.before(br).toRange()); 21749 } 21750 return true; 21751 }; 21752 const backspaceDelete$7 = (editor, forward) => { 21753 if (editor.selection.isCollapsed()) { 21754 return backspaceDeleteCaret(editor, forward); 21755 } else { 21756 return backspaceDeleteRange(editor, forward); 21757 } 21758 }; 21759 21760 const isTextEndpoint = endpoint => endpoint.hasOwnProperty('text'); 21761 const isElementEndpoint = endpoint => endpoint.hasOwnProperty('marker'); 21762 const getBookmark = (range, createMarker) => { 21763 const getEndpoint = (container, offset) => { 21764 if (isText$b(container)) { 21765 return { 21766 text: container, 21767 offset 21768 }; 21769 } else { 21770 const marker = createMarker(); 21771 const children = container.childNodes; 21772 if (offset < children.length) { 21773 container.insertBefore(marker, children[offset]); 21774 return { 21775 marker, 21776 before: true 21777 }; 21778 } else { 21779 container.appendChild(marker); 21780 return { 21781 marker, 21782 before: false 21783 }; 21784 } 21785 } 21786 }; 21787 const end = getEndpoint(range.endContainer, range.endOffset); 21788 const start = getEndpoint(range.startContainer, range.startOffset); 21789 return { 21790 start, 21791 end 21792 }; 21793 }; 21794 const resolveBookmark = bm => { 21795 var _a, _b; 21796 const {start, end} = bm; 21797 const rng = new window.Range(); 21798 if (isTextEndpoint(start)) { 21799 rng.setStart(start.text, start.offset); 21800 } else { 21801 if (isElementEndpoint(start)) { 21802 if (start.before) { 21803 rng.setStartBefore(start.marker); 21804 } else { 21805 rng.setStartAfter(start.marker); 21806 } 21807 (_a = start.marker.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(start.marker); 21808 } 21809 } 21810 if (isTextEndpoint(end)) { 21811 rng.setEnd(end.text, end.offset); 21812 } else { 21813 if (isElementEndpoint(end)) { 21814 if (end.before) { 21815 rng.setEndBefore(end.marker); 21816 } else { 21817 rng.setEndAfter(end.marker); 21818 } 21819 (_b = end.marker.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(end.marker); 21820 } 21821 } 21822 return rng; 21823 }; 21824 21825 const backspaceDelete$6 = (editor, forward) => { 21826 var _a; 21827 const dom = editor.dom; 21828 const startBlock = dom.getParent(editor.selection.getStart(), dom.isBlock); 21829 const endBlock = dom.getParent(editor.selection.getEnd(), dom.isBlock); 21830 const body = editor.getBody(); 21831 const startBlockName = (_a = startBlock === null || startBlock === void 0 ? void 0 : startBlock.nodeName) === null || _a === void 0 ? void 0 : _a.toLowerCase(); 21832 if (startBlockName === 'div' && startBlock && endBlock && startBlock === body.firstChild && endBlock === body.lastChild && !dom.isEmpty(body)) { 21833 const wrapper = startBlock.cloneNode(false); 21834 const deleteAction = () => { 21835 if (forward) { 21836 execNativeForwardDeleteCommand(editor); 21837 } else { 21838 execNativeDeleteCommand(editor); 21839 } 21840 if (body.firstChild !== startBlock) { 21841 const bookmark = getBookmark(editor.selection.getRng(), () => document.createElement('span'));
vendor: 20,843 bytes, lines 21842-22312
21842 Array.from(body.childNodes).forEach(node => wrapper.appendChild(node)); 21843 body.appendChild(wrapper); 21844 editor.selection.setRng(resolveBookmark(bookmark)); 21845 } 21846 }; 21847 return Optional.some(deleteAction); 21848 } 21849 return Optional.none(); 21850 }; 21851 21852 const deleteCaret$2 = (editor, forward) => { 21853 const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng()); 21854 return fromPosition(forward, editor.getBody(), fromPos).filter(pos => forward ? isBeforeImageBlock(pos) : isAfterImageBlock(pos)).bind(pos => getChildNodeAtRelativeOffset(forward ? 0 : -1, pos)).map(elm => () => editor.selection.select(elm)); 21855 }; 21856 const backspaceDelete$5 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$2(editor, forward) : Optional.none(); 21857 21858 const isText$2 = isText$b; 21859 const startsWithCaretContainer = node => isText$2(node) && node.data[0] === ZWSP$1; 21860 const endsWithCaretContainer = node => isText$2(node) && node.data[node.data.length - 1] === ZWSP$1; 21861 const createZwsp = node => { 21862 var _a; 21863 const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document; 21864 return doc.createTextNode(ZWSP$1); 21865 }; 21866 const insertBefore$1 = node => { 21867 var _a; 21868 if (isText$2(node.previousSibling)) { 21869 if (endsWithCaretContainer(node.previousSibling)) { 21870 return node.previousSibling; 21871 } else { 21872 node.previousSibling.appendData(ZWSP$1); 21873 return node.previousSibling; 21874 } 21875 } else if (isText$2(node)) { 21876 if (startsWithCaretContainer(node)) { 21877 return node; 21878 } else { 21879 node.insertData(0, ZWSP$1); 21880 return node; 21881 } 21882 } else { 21883 const newNode = createZwsp(node); 21884 (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node); 21885 return newNode; 21886 } 21887 }; 21888 const insertAfter$1 = node => { 21889 var _a, _b; 21890 if (isText$2(node.nextSibling)) { 21891 if (startsWithCaretContainer(node.nextSibling)) { 21892 return node.nextSibling; 21893 } else { 21894 node.nextSibling.insertData(0, ZWSP$1); 21895 return node.nextSibling; 21896 } 21897 } else if (isText$2(node)) { 21898 if (endsWithCaretContainer(node)) { 21899 return node; 21900 } else { 21901 node.appendData(ZWSP$1); 21902 return node; 21903 } 21904 } else { 21905 const newNode = createZwsp(node); 21906 if (node.nextSibling) { 21907 (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node.nextSibling); 21908 } else { 21909 (_b = node.parentNode) === null || _b === void 0 ? void 0 : _b.appendChild(newNode); 21910 } 21911 return newNode; 21912 } 21913 }; 21914 const insertInline = (before, node) => before ? insertBefore$1(node) : insertAfter$1(node); 21915 const insertInlineBefore = curry(insertInline, true); 21916 const insertInlineAfter = curry(insertInline, false); 21917 21918 const insertInlinePos = (pos, before) => { 21919 if (isText$b(pos.container())) { 21920 return insertInline(before, pos.container()); 21921 } else { 21922 return insertInline(before, pos.getNode()); 21923 } 21924 }; 21925 const isPosCaretContainer = (pos, caret) => { 21926 const caretNode = caret.get(); 21927 return caretNode && pos.container() === caretNode && isCaretContainerInline(caretNode); 21928 }; 21929 const renderCaret = (caret, location) => location.fold(element => { 21930 remove$2(caret.get()); 21931 const text = insertInlineBefore(element); 21932 caret.set(text); 21933 return Optional.some(CaretPosition(text, text.length - 1)); 21934 }, element => firstPositionIn(element).map(pos => { 21935 if (!isPosCaretContainer(pos, caret)) { 21936 remove$2(caret.get()); 21937 const text = insertInlinePos(pos, true); 21938 caret.set(text); 21939 return CaretPosition(text, 1); 21940 } else { 21941 const node = caret.get(); 21942 return CaretPosition(node, 1); 21943 } 21944 }), element => lastPositionIn(element).map(pos => { 21945 if (!isPosCaretContainer(pos, caret)) { 21946 remove$2(caret.get()); 21947 const text = insertInlinePos(pos, false); 21948 caret.set(text); 21949 return CaretPosition(text, text.length - 1); 21950 } else { 21951 const node = caret.get(); 21952 return CaretPosition(node, node.length - 1); 21953 } 21954 }), element => { 21955 remove$2(caret.get()); 21956 const text = insertInlineAfter(element); 21957 caret.set(text); 21958 return Optional.some(CaretPosition(text, 1)); 21959 }); 21960 21961 const evaluateUntil = (fns, args) => { 21962 for (let i = 0; i < fns.length; i++) { 21963 const result = fns[i].apply(null, args); 21964 if (result.isSome()) { 21965 return result; 21966 } 21967 } 21968 return Optional.none(); 21969 }; 21970 21971 const Location = Adt.generate([ 21972 { before: ['element'] }, 21973 { start: ['element'] }, 21974 { end: ['element'] }, 21975 { after: ['element'] } 21976 ]); 21977 const rescope$1 = (rootNode, node) => { 21978 const parentBlock = getParentBlock$3(node, rootNode); 21979 return parentBlock ? parentBlock : rootNode; 21980 }; 21981 const before = (isInlineTarget, rootNode, pos) => { 21982 const nPos = normalizeForwards(pos); 21983 const scope = rescope$1(rootNode, nPos.container()); 21984 return findRootInline(isInlineTarget, scope, nPos).fold(() => nextPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.before(inline)), Optional.none); 21985 }; 21986 const isNotInsideFormatCaretContainer = (rootNode, elm) => getParentCaretContainer(rootNode, elm) === null; 21987 const findInsideRootInline = (isInlineTarget, rootNode, pos) => findRootInline(isInlineTarget, rootNode, pos).filter(curry(isNotInsideFormatCaretContainer, rootNode)); 21988 const start$1 = (isInlineTarget, rootNode, pos) => { 21989 const nPos = normalizeBackwards(pos); 21990 return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => { 21991 const prevPos = prevPosition(inline, nPos); 21992 return prevPos.isNone() ? Optional.some(Location.start(inline)) : Optional.none(); 21993 }); 21994 }; 21995 const end = (isInlineTarget, rootNode, pos) => { 21996 const nPos = normalizeForwards(pos); 21997 return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => { 21998 const nextPos = nextPosition(inline, nPos); 21999 return nextPos.isNone() ? Optional.some(Location.end(inline)) : Optional.none(); 22000 }); 22001 }; 22002 const after = (isInlineTarget, rootNode, pos) => { 22003 const nPos = normalizeBackwards(pos); 22004 const scope = rescope$1(rootNode, nPos.container()); 22005 return findRootInline(isInlineTarget, scope, nPos).fold(() => prevPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.after(inline)), Optional.none); 22006 }; 22007 const isValidLocation = location => !isRtl(getElement(location)); 22008 const readLocation = (isInlineTarget, rootNode, pos) => { 22009 const location = evaluateUntil([ 22010 before, 22011 start$1, 22012 end, 22013 after 22014 ], [ 22015 isInlineTarget, 22016 rootNode, 22017 pos 22018 ]); 22019 return location.filter(isValidLocation); 22020 }; 22021 const getElement = location => location.fold(identity, identity, identity, identity); 22022 const getName = location => location.fold(constant('before'), constant('start'), constant('end'), constant('after')); 22023 const outside = location => location.fold(Location.before, Location.before, Location.after, Location.after); 22024 const inside = location => location.fold(Location.start, Location.start, Location.end, Location.end); 22025 const isEq = (location1, location2) => getName(location1) === getName(location2) && getElement(location1) === getElement(location2); 22026 const betweenInlines = (forward, isInlineTarget, rootNode, from, to, location) => lift2(findRootInline(isInlineTarget, rootNode, from), findRootInline(isInlineTarget, rootNode, to), (fromInline, toInline) => { 22027 if (fromInline !== toInline && hasSameParentBlock(rootNode, fromInline, toInline)) { 22028 return Location.after(forward ? fromInline : toInline); 22029 } else { 22030 return location; 22031 } 22032 }).getOr(location); 22033 const skipNoMovement = (fromLocation, toLocation) => fromLocation.fold(always, fromLocation => !isEq(fromLocation, toLocation)); 22034 const findLocationTraverse = (forward, isInlineTarget, rootNode, fromLocation, pos) => { 22035 const from = normalizePosition(forward, pos); 22036 const to = fromPosition(forward, rootNode, from).map(curry(normalizePosition, forward)); 22037 const location = to.fold(() => fromLocation.map(outside), to => readLocation(isInlineTarget, rootNode, to).map(curry(betweenInlines, forward, isInlineTarget, rootNode, from, to)).filter(curry(skipNoMovement, fromLocation))); 22038 return location.filter(isValidLocation); 22039 }; 22040 const findLocationSimple = (forward, location) => { 22041 if (forward) { 22042 return location.fold(compose(Optional.some, Location.start), Optional.none, compose(Optional.some, Location.after), Optional.none); 22043 } else { 22044 return location.fold(Optional.none, compose(Optional.some, Location.before), Optional.none, compose(Optional.some, Location.end)); 22045 } 22046 }; 22047 const findLocation$1 = (forward, isInlineTarget, rootNode, pos) => { 22048 const from = normalizePosition(forward, pos); 22049 const fromLocation = readLocation(isInlineTarget, rootNode, from); 22050 return readLocation(isInlineTarget, rootNode, from).bind(curry(findLocationSimple, forward)).orThunk(() => findLocationTraverse(forward, isInlineTarget, rootNode, fromLocation, pos)); 22051 }; 22052 22053 const hasSelectionModifyApi = editor => { 22054 return isFunction(editor.selection.getSel().modify); 22055 }; 22056 const moveRel = (forward, selection, pos) => { 22057 const delta = forward ? 1 : -1; 22058 selection.setRng(CaretPosition(pos.container(), pos.offset() + delta).toRange()); 22059 selection.getSel().modify('move', forward ? 'forward' : 'backward', 'word'); 22060 return true; 22061 }; 22062 const moveByWord = (forward, editor) => { 22063 const rng = editor.selection.getRng(); 22064 const pos = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng); 22065 if (!hasSelectionModifyApi(editor)) { 22066 return false; 22067 } else if (forward && isBeforeInline(pos)) { 22068 return moveRel(true, editor.selection, pos); 22069 } else if (!forward && isAfterInline(pos)) { 22070 return moveRel(false, editor.selection, pos); 22071 } else { 22072 return false; 22073 } 22074 }; 22075 22076 var BreakType; 22077 (function (BreakType) { 22078 BreakType[BreakType['Br'] = 0] = 'Br'; 22079 BreakType[BreakType['Block'] = 1] = 'Block'; 22080 BreakType[BreakType['Wrap'] = 2] = 'Wrap'; 22081 BreakType[BreakType['Eol'] = 3] = 'Eol'; 22082 }(BreakType || (BreakType = {}))); 22083 const flip = (direction, positions) => direction === -1 ? reverse(positions) : positions; 22084 const walk$1 = (direction, caretWalker, pos) => direction === 1 ? caretWalker.next(pos) : caretWalker.prev(pos); 22085 const getBreakType = (scope, direction, currentPos, nextPos) => { 22086 if (isBr$6(nextPos.getNode(direction === 1))) { 22087 return BreakType.Br; 22088 } else if (isInSameBlock(currentPos, nextPos) === false) { 22089 return BreakType.Block; 22090 } else { 22091 return BreakType.Wrap; 22092 } 22093 }; 22094 const getPositionsUntil = (predicate, direction, scope, start) => { 22095 const caretWalker = CaretWalker(scope); 22096 let currentPos = start; 22097 const positions = []; 22098 while (currentPos) { 22099 const nextPos = walk$1(direction, caretWalker, currentPos); 22100 if (!nextPos) { 22101 break; 22102 } 22103 if (isBr$6(nextPos.getNode(false))) { 22104 if (direction === 1) { 22105 return { 22106 positions: flip(direction, positions).concat([nextPos]), 22107 breakType: BreakType.Br, 22108 breakAt: Optional.some(nextPos) 22109 }; 22110 } else { 22111 return { 22112 positions: flip(direction, positions), 22113 breakType: BreakType.Br, 22114 breakAt: Optional.some(nextPos) 22115 }; 22116 } 22117 } 22118 if (!nextPos.isVisible()) { 22119 currentPos = nextPos; 22120 continue; 22121 } 22122 if (predicate(currentPos, nextPos)) { 22123 const breakType = getBreakType(scope, direction, currentPos, nextPos); 22124 return { 22125 positions: flip(direction, positions), 22126 breakType, 22127 breakAt: Optional.some(nextPos) 22128 }; 22129 } 22130 positions.push(nextPos); 22131 currentPos = nextPos; 22132 } 22133 return { 22134 positions: flip(direction, positions), 22135 breakType: BreakType.Eol, 22136 breakAt: Optional.none() 22137 }; 22138 }; 22139 const getAdjacentLinePositions = (direction, getPositionsUntilBreak, scope, start) => getPositionsUntilBreak(scope, start).breakAt.map(pos => { 22140 const positions = getPositionsUntilBreak(scope, pos).positions; 22141 return direction === -1 ? positions.concat(pos) : [pos].concat(positions); 22142 }).getOr([]); 22143 const findClosestHorizontalPositionFromPoint = (positions, x) => foldl(positions, (acc, newPos) => acc.fold(() => Optional.some(newPos), lastPos => lift2(head(lastPos.getClientRects()), head(newPos.getClientRects()), (lastRect, newRect) => { 22144 const lastDist = Math.abs(x - lastRect.left); 22145 const newDist = Math.abs(x - newRect.left); 22146 return newDist <= lastDist ? newPos : lastPos; 22147 }).or(acc)), Optional.none()); 22148 const findClosestHorizontalPosition = (positions, pos) => head(pos.getClientRects()).bind(targetRect => findClosestHorizontalPositionFromPoint(positions, targetRect.left)); 22149 const getPositionsUntilPreviousLine = curry(getPositionsUntil, CaretPosition.isAbove, -1); 22150 const getPositionsUntilNextLine = curry(getPositionsUntil, CaretPosition.isBelow, 1); 22151 const getPositionsAbove = curry(getAdjacentLinePositions, -1, getPositionsUntilPreviousLine); 22152 const getPositionsBelow = curry(getAdjacentLinePositions, 1, getPositionsUntilNextLine); 22153 const isAtFirstLine = (scope, pos) => getPositionsUntilPreviousLine(scope, pos).breakAt.isNone(); 22154 const isAtLastLine = (scope, pos) => getPositionsUntilNextLine(scope, pos).breakAt.isNone(); 22155 const getFirstLinePositions = scope => firstPositionIn(scope).map(pos => [pos].concat(getPositionsUntilNextLine(scope, pos).positions)).getOr([]); 22156 const getLastLinePositions = scope => lastPositionIn(scope).map(pos => getPositionsUntilPreviousLine(scope, pos).positions.concat(pos)).getOr([]); 22157 const getClosestPositionAbove = (scope, pos) => findClosestHorizontalPosition(getPositionsAbove(scope, pos), pos); 22158 const getClosestPositionBelow = (scope, pos) => findClosestHorizontalPosition(getPositionsBelow(scope, pos), pos); 22159 22160 const isContentEditableFalse$5 = isContentEditableFalse$b; 22161 const distanceToRectLeft$1 = (clientRect, clientX) => Math.abs(clientRect.left - clientX); 22162 const distanceToRectRight$1 = (clientRect, clientX) => Math.abs(clientRect.right - clientX); 22163 const isNodeClientRect = rect => hasNonNullableKey(rect, 'node'); 22164 const findClosestClientRect = (clientRects, clientX) => reduce(clientRects, (oldClientRect, clientRect) => { 22165 const oldDistance = Math.min(distanceToRectLeft$1(oldClientRect, clientX), distanceToRectRight$1(oldClientRect, clientX)); 22166 const newDistance = Math.min(distanceToRectLeft$1(clientRect, clientX), distanceToRectRight$1(clientRect, clientX)); 22167 if (newDistance === oldDistance && isNodeClientRect(clientRect) && isContentEditableFalse$5(clientRect.node)) { 22168 return clientRect; 22169 } 22170 if (newDistance < oldDistance) { 22171 return clientRect; 22172 } 22173 return oldClientRect; 22174 }); 22175 22176 const getNodeClientRects = node => { 22177 const toArrayWithNode = clientRects => { 22178 return map$3(clientRects, rect => { 22179 const clientRect = clone$1(rect); 22180 clientRect.node = node; 22181 return clientRect; 22182 }); 22183 }; 22184 if (isElement$6(node)) { 22185 return toArrayWithNode(node.getClientRects()); 22186 } else if (isText$b(node)) { 22187 const rng = node.ownerDocument.createRange(); 22188 rng.setStart(node, 0); 22189 rng.setEnd(node, node.data.length); 22190 return toArrayWithNode(rng.getClientRects()); 22191 } else { 22192 return []; 22193 } 22194 }; 22195 const getClientRects = nodes => bind$3(nodes, getNodeClientRects); 22196 22197 var VDirection; 22198 (function (VDirection) { 22199 VDirection[VDirection['Up'] = -1] = 'Up'; 22200 VDirection[VDirection['Down'] = 1] = 'Down'; 22201 }(VDirection || (VDirection = {}))); 22202 const findUntil = (direction, root, predicateFn, node) => { 22203 let currentNode = node; 22204 while (currentNode = findNode(currentNode, direction, isEditableCaretCandidate$1, root)) { 22205 if (predicateFn(currentNode)) { 22206 return; 22207 } 22208 } 22209 }; 22210 const walkUntil = (direction, isAboveFn, isBeflowFn, root, predicateFn, caretPosition) => { 22211 let line = 0; 22212 const result = []; 22213 const add = node => { 22214 let clientRects = getClientRects([node]); 22215 if (direction === VDirection.Up) { 22216 clientRects = clientRects.reverse(); 22217 } 22218 for (let i = 0; i < clientRects.length; i++) { 22219 const clientRect = clientRects[i]; 22220 if (isBeflowFn(clientRect, targetClientRect)) { 22221 continue; 22222 } 22223 if (result.length > 0 && isAboveFn(clientRect, last$1(result))) { 22224 line++; 22225 } 22226 clientRect.line = line; 22227 if (predicateFn(clientRect)) { 22228 return true; 22229 } 22230 result.push(clientRect); 22231 } 22232 return false; 22233 }; 22234 const targetClientRect = last$1(caretPosition.getClientRects()); 22235 if (!targetClientRect) { 22236 return result; 22237 } 22238 const node = caretPosition.getNode(); 22239 if (node) { 22240 add(node); 22241 findUntil(direction, root, add, node); 22242 } 22243 return result; 22244 }; 22245 const aboveLineNumber = (lineNumber, clientRect) => clientRect.line > lineNumber; 22246 const isLineNumber = (lineNumber, clientRect) => clientRect.line === lineNumber; 22247 const upUntil = curry(walkUntil, VDirection.Up, isAbove$1, isBelow$1); 22248 const downUntil = curry(walkUntil, VDirection.Down, isBelow$1, isAbove$1); 22249 const getLastClientRect = caretPosition => { 22250 return last$1(caretPosition.getClientRects()); 22251 }; 22252 const positionsUntil = (direction, root, predicateFn, node) => { 22253 const caretWalker = CaretWalker(root); 22254 let walkFn; 22255 let isBelowFn; 22256 let isAboveFn; 22257 let caretPosition; 22258 const result = []; 22259 let line = 0; 22260 if (direction === VDirection.Down) { 22261 walkFn = caretWalker.next; 22262 isBelowFn = isBelow$1; 22263 isAboveFn = isAbove$1; 22264 caretPosition = CaretPosition.after(node); 22265 } else { 22266 walkFn = caretWalker.prev; 22267 isBelowFn = isAbove$1; 22268 isAboveFn = isBelow$1; 22269 caretPosition = CaretPosition.before(node); 22270 } 22271 const targetClientRect = getLastClientRect(caretPosition); 22272 do { 22273 if (!caretPosition.isVisible()) { 22274 continue; 22275 } 22276 const rect = getLastClientRect(caretPosition); 22277 if (isAboveFn(rect, targetClientRect)) { 22278 continue; 22279 } 22280 if (result.length > 0 && isBelowFn(rect, last$1(result))) { 22281 line++; 22282 } 22283 const clientRect = clone$1(rect); 22284 clientRect.position = caretPosition; 22285 clientRect.line = line; 22286 if (predicateFn(clientRect)) { 22287 return result; 22288 } 22289 result.push(clientRect); 22290 } while (caretPosition = walkFn(caretPosition)); 22291 return result; 22292 }; 22293 const isAboveLine = lineNumber => clientRect => aboveLineNumber(lineNumber, clientRect); 22294 const isLine = lineNumber => clientRect => isLineNumber(lineNumber, clientRect); 22295 22296 const moveToRange = (editor, rng) => { 22297 editor.selection.setRng(rng); 22298 scrollRangeIntoView(editor, editor.selection.getRng()); 22299 }; 22300 const renderRangeCaretOpt = (editor, range, scrollIntoView) => Optional.some(renderRangeCaret(editor, range, scrollIntoView)); 22301 const moveHorizontally = (editor, direction, range, isBefore, isAfter, isElement) => { 22302 const forwards = direction === 1; 22303 const caretWalker = CaretWalker(editor.getBody()); 22304 const getNextPosFn = curry(getVisualCaretPosition, forwards ? caretWalker.next : caretWalker.prev); 22305 const isBeforeFn = forwards ? isBefore : isAfter; 22306 if (!range.collapsed) { 22307 const node = getSelectedNode(range); 22308 if (isElement(node)) { 22309 return showCaret(direction, editor, node, direction === -1, false); 22310 } else if (isCefAtEdgeSelected(editor)) { 22311 const newRange = range.cloneRange(); 22312 newRange.collapse(direction === -1
vendor: 18,279 bytes, lines 22312-22678
22312); 22313 return Optional.from(newRange); 22314 } 22315 } 22316 const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range); 22317 if (isBeforeFn(caretPosition)) { 22318 return selectNode(editor, caretPosition.getNode(!forwards)); 22319 } 22320 let nextCaretPosition = getNextPosFn(caretPosition); 22321 const rangeIsInContainerBlock = isRangeInCaretContainerBlock(range); 22322 if (!nextCaretPosition) { 22323 return rangeIsInContainerBlock ? Optional.some(range) : Optional.none(); 22324 } else { 22325 nextCaretPosition = normalizePosition(forwards, nextCaretPosition); 22326 } 22327 if (isBeforeFn(nextCaretPosition)) { 22328 return showCaret(direction, editor, nextCaretPosition.getNode(!forwards), forwards, false); 22329 } 22330 const peekCaretPosition = getNextPosFn(nextCaretPosition); 22331 if (peekCaretPosition && isBeforeFn(peekCaretPosition)) { 22332 if (isMoveInsideSameBlock(nextCaretPosition, peekCaretPosition)) { 22333 return showCaret(direction, editor, peekCaretPosition.getNode(!forwards), forwards, false); 22334 } 22335 } 22336 if (rangeIsInContainerBlock) { 22337 return renderRangeCaretOpt(editor, nextCaretPosition.toRange(), false); 22338 } 22339 return Optional.none(); 22340 }; 22341 const moveVertically = (editor, direction, range, isBefore, isAfter, isElement) => { 22342 const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range); 22343 const caretClientRect = last$1(caretPosition.getClientRects()); 22344 const forwards = direction === VDirection.Down; 22345 const root = editor.getBody(); 22346 if (!caretClientRect) { 22347 return Optional.none(); 22348 } 22349 if (isCefAtEdgeSelected(editor)) { 22350 const caretPosition = forwards ? CaretPosition.fromRangeEnd(range) : CaretPosition.fromRangeStart(range); 22351 const getClosestFn = !forwards ? getClosestPositionAbove : getClosestPositionBelow; 22352 return getClosestFn(root, caretPosition).orThunk(() => Optional.from(caretPosition)).map(pos => pos.toRange()); 22353 } 22354 const walkerFn = forwards ? downUntil : upUntil; 22355 const linePositions = walkerFn(root, isAboveLine(1), caretPosition); 22356 const nextLinePositions = filter$5(linePositions, isLine(1)); 22357 const clientX = caretClientRect.left; 22358 const nextLineRect = findClosestClientRect(nextLinePositions, clientX); 22359 if (nextLineRect && isElement(nextLineRect.node)) { 22360 const dist1 = Math.abs(clientX - nextLineRect.left); 22361 const dist2 = Math.abs(clientX - nextLineRect.right); 22362 return showCaret(direction, editor, nextLineRect.node, dist1 < dist2, false); 22363 } 22364 let currentNode; 22365 if (isBefore(caretPosition)) { 22366 currentNode = caretPosition.getNode(); 22367 } else if (isAfter(caretPosition)) { 22368 currentNode = caretPosition.getNode(true); 22369 } else { 22370 currentNode = getSelectedNode(range); 22371 } 22372 if (currentNode) { 22373 const caretPositions = positionsUntil(direction, root, isAboveLine(1), currentNode); 22374 let closestNextLineRect = findClosestClientRect(filter$5(caretPositions, isLine(1)), clientX); 22375 if (closestNextLineRect) { 22376 return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false); 22377 } 22378 closestNextLineRect = last$1(filter$5(caretPositions, isLine(0))); 22379 if (closestNextLineRect) { 22380 return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false); 22381 } 22382 } 22383 if (nextLinePositions.length === 0) { 22384 return getLineEndPoint(editor, forwards).filter(forwards ? isAfter : isBefore).map(pos => renderRangeCaret(editor, pos.toRange(), false)); 22385 } 22386 return Optional.none(); 22387 }; 22388 const getLineEndPoint = (editor, forward) => { 22389 const rng = editor.selection.getRng(); 22390 const from = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng); 22391 const host = getEditingHost(from.container(), editor.getBody()); 22392 if (forward) { 22393 const lineInfo = getPositionsUntilNextLine(host, from); 22394 return last$2(lineInfo.positions); 22395 } else { 22396 const lineInfo = getPositionsUntilPreviousLine(host, from); 22397 return head(lineInfo.positions); 22398 } 22399 }; 22400 const moveToLineEndPoint$3 = (editor, forward, isElementPosition) => getLineEndPoint(editor, forward).filter(isElementPosition).exists(pos => { 22401 editor.selection.setRng(pos.toRange()); 22402 return true; 22403 }); 22404 22405 const setCaretPosition = (editor, pos) => { 22406 const rng = editor.dom.createRng(); 22407 rng.setStart(pos.container(), pos.offset()); 22408 rng.setEnd(pos.container(), pos.offset()); 22409 editor.selection.setRng(rng); 22410 }; 22411 const setSelected = (state, elm) => { 22412 if (state) { 22413 elm.setAttribute('data-mce-selected', 'inline-boundary'); 22414 } else { 22415 elm.removeAttribute('data-mce-selected'); 22416 } 22417 }; 22418 const renderCaretLocation = (editor, caret, location) => renderCaret(caret, location).map(pos => { 22419 setCaretPosition(editor, pos); 22420 return location; 22421 }); 22422 const getPositionFromRange = (range, root, forward) => { 22423 const start = CaretPosition.fromRangeStart(range); 22424 if (range.collapsed) { 22425 return start; 22426 } else { 22427 const end = CaretPosition.fromRangeEnd(range); 22428 return forward ? prevPosition(root, end).getOr(end) : nextPosition(root, start).getOr(start); 22429 } 22430 }; 22431 const findLocation = (editor, caret, forward) => { 22432 const rootNode = editor.getBody(); 22433 const from = getPositionFromRange(editor.selection.getRng(), rootNode, forward); 22434 const isInlineTarget$1 = curry(isInlineTarget, editor); 22435 const location = findLocation$1(forward, isInlineTarget$1, rootNode, from); 22436 return location.bind(location => renderCaretLocation(editor, caret, location)); 22437 }; 22438 const toggleInlines = (isInlineTarget, dom, elms) => { 22439 const inlineBoundaries = map$3(descendants(SugarElement.fromDom(dom.getRoot()), '*[data-mce-selected="inline-boundary"]'), e => e.dom); 22440 const selectedInlines = filter$5(inlineBoundaries, isInlineTarget); 22441 const targetInlines = filter$5(elms, isInlineTarget); 22442 each$e(difference(selectedInlines, targetInlines), curry(setSelected, false)); 22443 each$e(difference(targetInlines, selectedInlines), curry(setSelected, true)); 22444 }; 22445 const safeRemoveCaretContainer = (editor, caret) => { 22446 const caretValue = caret.get(); 22447 if (editor.selection.isCollapsed() && !editor.composing && caretValue) { 22448 const pos = CaretPosition.fromRangeStart(editor.selection.getRng()); 22449 if (CaretPosition.isTextPosition(pos) && !isAtZwsp(pos)) { 22450 setCaretPosition(editor, removeAndReposition(caretValue, pos)); 22451 caret.set(null); 22452 } 22453 } 22454 }; 22455 const renderInsideInlineCaret = (isInlineTarget, editor, caret, elms) => { 22456 if (editor.selection.isCollapsed()) { 22457 const inlines = filter$5(elms, isInlineTarget); 22458 each$e(inlines, _inline => { 22459 const pos = CaretPosition.fromRangeStart(editor.selection.getRng()); 22460 readLocation(isInlineTarget, editor.getBody(), pos).bind(location => renderCaretLocation(editor, caret, location)); 22461 }); 22462 } 22463 }; 22464 const move$3 = (editor, caret, forward) => isInlineBoundariesEnabled(editor) ? findLocation(editor, caret, forward).isSome() : false; 22465 const moveWord = (forward, editor, _caret) => isInlineBoundariesEnabled(editor) ? moveByWord(forward, editor) : false; 22466 const setupSelectedState = editor => { 22467 const caret = Cell(null); 22468 const isInlineTarget$1 = curry(isInlineTarget, editor); 22469 editor.on('NodeChange', e => { 22470 if (isInlineBoundariesEnabled(editor)) { 22471 toggleInlines(isInlineTarget$1, editor.dom, e.parents); 22472 safeRemoveCaretContainer(editor, caret); 22473 renderInsideInlineCaret(isInlineTarget$1, editor, caret, e.parents); 22474 } 22475 }); 22476 return caret; 22477 }; 22478 const moveNextWord = curry(moveWord, true); 22479 const movePrevWord = curry(moveWord, false); 22480 const moveToLineEndPoint$2 = (editor, forward, caret) => { 22481 if (isInlineBoundariesEnabled(editor)) { 22482 const linePoint = getLineEndPoint(editor, forward).getOrThunk(() => { 22483 const rng = editor.selection.getRng(); 22484 return forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng); 22485 }); 22486 return readLocation(curry(isInlineTarget, editor), editor.getBody(), linePoint).exists(loc => { 22487 const outsideLoc = outside(loc); 22488 return renderCaret(caret, outsideLoc).exists(pos => { 22489 setCaretPosition(editor, pos); 22490 return true; 22491 }); 22492 }); 22493 } else { 22494 return false; 22495 } 22496 }; 22497 22498 const rangeFromPositions = (from, to) => { 22499 const range = document.createRange(); 22500 range.setStart(from.container(), from.offset()); 22501 range.setEnd(to.container(), to.offset()); 22502 return range; 22503 }; 22504 const hasOnlyTwoOrLessPositionsLeft = elm => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => { 22505 const normalizedFirstPos = normalizePosition(true, firstPos); 22506 const normalizedLastPos = normalizePosition(false, lastPos); 22507 return nextPosition(elm, normalizedFirstPos).forall(pos => pos.isEqual(normalizedLastPos)); 22508 }).getOr(true); 22509 const setCaretLocation = (editor, caret) => location => renderCaret(caret, location).map(pos => () => setCaretPosition(editor, pos)); 22510 const deleteFromTo = (editor, caret, from, to) => { 22511 const rootNode = editor.getBody(); 22512 const isInlineTarget$1 = curry(isInlineTarget, editor); 22513 editor.undoManager.ignore(() => { 22514 editor.selection.setRng(rangeFromPositions(from, to)); 22515 execNativeDeleteCommand(editor); 22516 readLocation(isInlineTarget$1, rootNode, CaretPosition.fromRangeStart(editor.selection.getRng())).map(inside).bind(setCaretLocation(editor, caret)).each(call); 22517 }); 22518 editor.nodeChanged(); 22519 }; 22520 const rescope = (rootNode, node) => { 22521 const parentBlock = getParentBlock$3(node, rootNode); 22522 return parentBlock ? parentBlock : rootNode; 22523 }; 22524 const backspaceDeleteCollapsed = (editor, caret, forward, from) => { 22525 const rootNode = rescope(editor.getBody(), from.container()); 22526 const isInlineTarget$1 = curry(isInlineTarget, editor); 22527 const fromLocation = readLocation(isInlineTarget$1, rootNode, from); 22528 const location = fromLocation.bind(location => { 22529 if (forward) { 22530 return location.fold(constant(Optional.some(inside(location))), Optional.none, constant(Optional.some(outside(location))), Optional.none); 22531 } else { 22532 return location.fold(Optional.none, constant(Optional.some(outside(location))), Optional.none, constant(Optional.some(inside(location)))); 22533 } 22534 }); 22535 return location.map(setCaretLocation(editor, caret)).getOrThunk(() => { 22536 const toPosition = navigate(forward, rootNode, from); 22537 const toLocation = toPosition.bind(pos => readLocation(isInlineTarget$1, rootNode, pos)); 22538 return lift2(fromLocation, toLocation, () => findRootInline(isInlineTarget$1, rootNode, from).bind(elm => { 22539 if (hasOnlyTwoOrLessPositionsLeft(elm)) { 22540 return Optional.some(() => { 22541 deleteElement$2(editor, forward, SugarElement.fromDom(elm)); 22542 }); 22543 } else { 22544 return Optional.none(); 22545 } 22546 })).getOrThunk(() => toLocation.bind(() => toPosition.map(to => { 22547 return () => { 22548 if (forward) { 22549 deleteFromTo(editor, caret, from, to); 22550 } else { 22551 deleteFromTo(editor, caret, to, from); 22552 } 22553 }; 22554 }))); 22555 }); 22556 }; 22557 const backspaceDelete$4 = (editor, caret, forward) => { 22558 if (editor.selection.isCollapsed() && isInlineBoundariesEnabled(editor)) { 22559 const from = CaretPosition.fromRangeStart(editor.selection.getRng()); 22560 return backspaceDeleteCollapsed(editor, caret, forward, from); 22561 } 22562 return Optional.none(); 22563 }; 22564 22565 const hasMultipleChildren = elm => childNodesCount(elm) > 1; 22566 const getParentsUntil = (editor, pred) => { 22567 const rootElm = SugarElement.fromDom(editor.getBody()); 22568 const startElm = SugarElement.fromDom(editor.selection.getStart()); 22569 const parents = parentsAndSelf(startElm, rootElm); 22570 return findIndex$2(parents, pred).fold(constant(parents), index => parents.slice(0, index)); 22571 }; 22572 const hasOnlyOneChild = elm => childNodesCount(elm) === 1; 22573 const getParentInlinesUntilMultichildInline = editor => getParentsUntil(editor, elm => editor.schema.isBlock(name(elm)) || hasMultipleChildren(elm)); 22574 const getParentInlines = editor => getParentsUntil(editor, el => editor.schema.isBlock(name(el))); 22575 const getFormatNodes = (editor, parentInlines) => { 22576 const isFormatElement$1 = curry(isFormatElement, editor); 22577 return bind$3(parentInlines, elm => isFormatElement$1(elm) ? [elm.dom] : []); 22578 }; 22579 const getFormatNodesAtStart = editor => { 22580 const parentInlines = getParentInlines(editor); 22581 return getFormatNodes(editor, parentInlines); 22582 }; 22583 const deleteLastPosition = (forward, editor, target, parentInlines) => { 22584 const formatNodes = getFormatNodes(editor, parentInlines); 22585 if (formatNodes.length === 0) { 22586 deleteElement$2(editor, forward, target); 22587 } else { 22588 const pos = replaceWithCaretFormat(target.dom, formatNodes); 22589 editor.selection.setRng(pos.toRange()); 22590 } 22591 }; 22592 const deleteCaret$1 = (editor, forward) => { 22593 const parentInlines = filter$5(getParentInlinesUntilMultichildInline(editor), hasOnlyOneChild); 22594 return last$2(parentInlines).bind(target => { 22595 const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng()); 22596 if (willDeleteLastPositionInElement(forward, fromPos, target.dom) && !isEmptyCaretFormatElement(target)) { 22597 return Optional.some(() => deleteLastPosition(forward, editor, target, parentInlines)); 22598 } else { 22599 return Optional.none(); 22600 } 22601 }); 22602 }; 22603 const isBrInEmptyElement = (editor, elm) => { 22604 const parentElm = elm.parentElement; 22605 return isBr$6(elm) && !isNull(parentElm) && editor.dom.isEmpty(parentElm); 22606 }; 22607 const isEmptyCaret = elm => isEmptyCaretFormatElement(SugarElement.fromDom(elm)); 22608 const createCaretFormatAtStart = (editor, formatNodes) => { 22609 const startElm = editor.selection.getStart(); 22610 const pos = isBrInEmptyElement(editor, startElm) || isEmptyCaret(startElm) ? replaceWithCaretFormat(startElm, formatNodes) : createCaretFormatAtStart$1(editor.selection.getRng(), formatNodes); 22611 editor.selection.setRng(pos.toRange()); 22612 }; 22613 const updateCaretFormat = (editor, updateFormats) => { 22614 const missingFormats = difference(updateFormats, getFormatNodesAtStart(editor)); 22615 if (missingFormats.length > 0) { 22616 createCaretFormatAtStart(editor, missingFormats); 22617 } 22618 }; 22619 const rangeStartsAtTextContainer = rng => isText$b(rng.startContainer); 22620 const rangeStartsAtStartOfTextContainer = rng => rng.startOffset === 0 && rangeStartsAtTextContainer(rng); 22621 const rangeStartParentIsFormatElement = (editor, rng) => { 22622 const startParent = rng.startContainer.parentElement; 22623 return !isNull(startParent) && isFormatElement(editor, SugarElement.fromDom(startParent)); 22624 }; 22625 const rangeStartAndEndHaveSameParent = rng => { 22626 const startParent = rng.startContainer.parentNode; 22627 const endParent = rng.endContainer.parentNode; 22628 return !isNull(startParent) && !isNull(endParent) && startParent.isEqualNode(endParent); 22629 }; 22630 const rangeEndsAtEndOfEndContainer = rng => { 22631 const endContainer = rng.endContainer; 22632 return rng.endOffset === (isText$b(endContainer) ? endContainer.length : endContainer.childNodes.length); 22633 }; 22634 const rangeEndsAtEndOfStartContainer = rng => rangeStartAndEndHaveSameParent(rng) && rangeEndsAtEndOfEndContainer(rng); 22635 const rangeEndsAfterEndOfStartContainer = rng => !rng.endContainer.isEqualNode(rng.commonAncestorContainer); 22636 const rangeEndsAtOrAfterEndOfStartContainer = rng => rangeEndsAtEndOfStartContainer(rng) || rangeEndsAfterEndOfStartContainer(rng); 22637 const requiresDeleteRangeOverride = editor => { 22638 const rng = editor.selection.getRng(); 22639 return rangeStartsAtStartOfTextContainer(rng) && rangeStartParentIsFormatElement(editor, rng) && rangeEndsAtOrAfterEndOfStartContainer(rng); 22640 }; 22641 const deleteRange$1 = editor => { 22642 if (requiresDeleteRangeOverride(editor)) { 22643 const formatNodes = getFormatNodesAtStart(editor); 22644 return Optional.some(() => { 22645 execNativeDeleteCommand(editor); 22646 updateCaretFormat(editor, formatNodes); 22647 }); 22648 } else { 22649 return Optional.none(); 22650 } 22651 }; 22652 const backspaceDelete$3 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$1(editor, forward) : deleteRange$1(editor); 22653 const hasAncestorInlineCaret = (elm, schema) => ancestor$2(elm, node => isCaretNode(node.dom), el => schema.isBlock(name(el))); 22654 const hasAncestorInlineCaretAtStart = editor => hasAncestorInlineCaret(SugarElement.fromDom(editor.selection.getStart()), editor.schema); 22655 const requiresRefreshCaretOverride = editor => { 22656 const rng = editor.selection.getRng(); 22657 return rng.collapsed && (rangeStartsAtTextContainer(rng) || editor.dom.isEmpty(rng.startContainer)) && !hasAncestorInlineCaretAtStart(editor); 22658 }; 22659 const refreshCaret = editor => { 22660 if (requiresRefreshCaretOverride(editor)) { 22661 createCaretFormatAtStart(editor, []); 22662 } 22663 return true; 22664 }; 22665 22666 const deleteElement = (editor, forward, element) => { 22667 if (isNonNullable(element)) { 22668 return Optional.some(() => { 22669 editor._selectionOverrides.hideFakeCaret(); 22670 deleteElement$2(editor, forward, SugarElement.fromDom(element)); 22671 }); 22672 } else { 22673 return Optional.none(); 22674 } 22675 }; 22676 const deleteCaret = (editor, forward) => { 22677 const isNearMedia = forward ? isBeforeMedia : isAfterMedia; 22678 const direction = forward ?
vendor: 7,769 bytes, lines 22678-22865
226781 : -1; 22679 const fromPos = getNormalizedRangeEndPoint(direction, editor.getBody(), editor.selection.getRng()); 22680 if (isNearMedia(fromPos)) { 22681 return deleteElement(editor, forward, fromPos.getNode(!forward)); 22682 } else { 22683 return Optional.from(normalizePosition(forward, fromPos)).filter(pos => isNearMedia(pos) && isMoveInsideSameBlock(fromPos, pos)).bind(pos => deleteElement(editor, forward, pos.getNode(!forward))); 22684 } 22685 }; 22686 const deleteRange = (editor, forward) => { 22687 const selectedNode = editor.selection.getNode(); 22688 return isMedia$2(selectedNode) ? deleteElement(editor, forward, selectedNode) : Optional.none(); 22689 }; 22690 const backspaceDelete$2 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret(editor, forward) : deleteRange(editor, forward); 22691 22692 const isEditable = target => closest$4(target, elm => isContentEditableTrue$3(elm.dom) || isContentEditableFalse$b(elm.dom)).exists(elm => isContentEditableTrue$3(elm.dom)); 22693 const parseIndentValue = value => toInt(value !== null && value !== void 0 ? value : '').getOr(0); 22694 const getIndentStyleName = (useMargin, element) => { 22695 const indentStyleName = useMargin || isTable$1(element) ? 'margin' : 'padding'; 22696 const suffix = get$7(element, 'direction') === 'rtl' ? '-right' : '-left'; 22697 return indentStyleName + suffix; 22698 }; 22699 const indentElement = (dom, command, useMargin, value, unit, element) => { 22700 const indentStyleName = getIndentStyleName(useMargin, SugarElement.fromDom(element)); 22701 const parsedValue = parseIndentValue(dom.getStyle(element, indentStyleName)); 22702 if (command === 'outdent') { 22703 const styleValue = Math.max(0, parsedValue - value); 22704 dom.setStyle(element, indentStyleName, styleValue ? styleValue + unit : ''); 22705 } else { 22706 const styleValue = parsedValue + value + unit; 22707 dom.setStyle(element, indentStyleName, styleValue); 22708 } 22709 }; 22710 const validateBlocks = (editor, blocks) => forall(blocks, block => { 22711 const indentStyleName = getIndentStyleName(shouldIndentUseMargin(editor), block); 22712 const intentValue = getRaw(block, indentStyleName).map(parseIndentValue).getOr(0); 22713 const contentEditable = editor.dom.getContentEditable(block.dom); 22714 return contentEditable !== 'false' && intentValue > 0; 22715 }); 22716 const canOutdent = editor => { 22717 const blocks = getBlocksToIndent(editor); 22718 return !editor.mode.isReadOnly() && (blocks.length > 1 || validateBlocks(editor, blocks)); 22719 }; 22720 const isListComponent = el => isList(el) || isListItem$1(el); 22721 const parentIsListComponent = el => parent(el).exists(isListComponent); 22722 const getBlocksToIndent = editor => filter$5(fromDom$1(editor.selection.getSelectedBlocks()), el => !isListComponent(el) && !parentIsListComponent(el) && isEditable(el)); 22723 const handle = (editor, command) => { 22724 var _a, _b; 22725 if (editor.mode.isReadOnly()) { 22726 return; 22727 } 22728 const {dom} = editor; 22729 const indentation = getIndentation(editor); 22730 const indentUnit = (_b = (_a = /[a-z%]+$/i.exec(indentation)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 'px'; 22731 const indentValue = parseIndentValue(indentation); 22732 const useMargin = shouldIndentUseMargin(editor); 22733 each$e(getBlocksToIndent(editor), block => { 22734 indentElement(dom, command, useMargin, indentValue, indentUnit, block.dom); 22735 }); 22736 }; 22737 const indent = editor => handle(editor, 'indent'); 22738 const outdent = editor => handle(editor, 'outdent'); 22739 22740 const backspaceDelete$1 = editor => { 22741 if (editor.selection.isCollapsed() && canOutdent(editor)) { 22742 const dom = editor.dom; 22743 const rng = editor.selection.getRng(); 22744 const pos = CaretPosition.fromRangeStart(rng); 22745 const block = dom.getParent(rng.startContainer, dom.isBlock); 22746 if (block !== null && isAtStartOfBlock(SugarElement.fromDom(block), pos, editor.schema)) { 22747 return Optional.some(() => outdent(editor)); 22748 } 22749 } 22750 return Optional.none(); 22751 }; 22752 22753 const findAction = (editor, caret, forward) => findMap([ 22754 backspaceDelete$1, 22755 backspaceDelete$7, 22756 backspaceDelete$8, 22757 (editor, forward) => backspaceDelete$4(editor, caret, forward), 22758 backspaceDelete$a, 22759 backspaceDelete$b, 22760 backspaceDelete$5, 22761 backspaceDelete$2, 22762 backspaceDelete$9, 22763 backspaceDelete$3, 22764 backspaceDelete$6 22765 ], item => item(editor, forward)).filter(_ => editor.selection.isEditable()); 22766 const deleteCommand = (editor, caret) => { 22767 const result = findAction(editor, caret, false); 22768 result.fold(() => { 22769 if (editor.selection.isEditable()) { 22770 execNativeDeleteCommand(editor); 22771 paddEmptyBody(editor); 22772 } 22773 }, call); 22774 }; 22775 const forwardDeleteCommand = (editor, caret) => { 22776 const result = findAction(editor, caret, true); 22777 result.fold(() => { 22778 if (editor.selection.isEditable()) { 22779 execNativeForwardDeleteCommand(editor); 22780 } 22781 }, call); 22782 }; 22783 const setup$q = (editor, caret) => { 22784 editor.addCommand('delete', () => { 22785 deleteCommand(editor, caret); 22786 }); 22787 editor.addCommand('forwardDelete', () => { 22788 forwardDeleteCommand(editor, caret); 22789 }); 22790 }; 22791 22792 const SIGNIFICANT_MOVE = 5; 22793 const LONGPRESS_DELAY = 400; 22794 const getTouch = event => { 22795 if (event.touches === undefined || event.touches.length !== 1) { 22796 return Optional.none(); 22797 } 22798 return Optional.some(event.touches[0]); 22799 }; 22800 const isFarEnough = (touch, data) => { 22801 const distX = Math.abs(touch.clientX - data.x); 22802 const distY = Math.abs(touch.clientY - data.y); 22803 return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE; 22804 }; 22805 const setup$p = editor => { 22806 const startData = value$2(); 22807 const longpressFired = Cell(false); 22808 const debounceLongpress = last(e => { 22809 editor.dispatch('longpress', { 22810 ...e, 22811 type: 'longpress' 22812 }); 22813 longpressFired.set(true); 22814 }, LONGPRESS_DELAY); 22815 editor.on('touchstart', e => { 22816 getTouch(e).each(touch => { 22817 debounceLongpress.cancel(); 22818 const data = { 22819 x: touch.clientX, 22820 y: touch.clientY, 22821 target: e.target 22822 }; 22823 debounceLongpress.throttle(e); 22824 longpressFired.set(false); 22825 startData.set(data); 22826 }); 22827 }, true); 22828 editor.on('touchmove', e => { 22829 debounceLongpress.cancel(); 22830 getTouch(e).each(touch => { 22831 startData.on(data => { 22832 if (isFarEnough(touch, data)) { 22833 startData.clear(); 22834 longpressFired.set(false); 22835 editor.dispatch('longpresscancel'); 22836 } 22837 }); 22838 }); 22839 }, true); 22840 editor.on('touchend touchcancel', e => { 22841 debounceLongpress.cancel(); 22842 if (e.type === 'touchcancel') { 22843 return; 22844 } 22845 startData.get().filter(data => data.target.isEqualNode(e.target)).each(() => { 22846 if (longpressFired.get()) { 22847 e.preventDefault(); 22848 } else { 22849 editor.dispatch('tap', { 22850 ...e, 22851 type: 'tap' 22852 }); 22853 } 22854 }); 22855 }, true); 22856 }; 22857 22858 const isBlockElement = (blockElements, node) => has$2(blockElements, node.nodeName); 22859 const isValidTarget = (schema, node) => { 22860 if (isText$b(node)) { 22861 return true; 22862 } else if (isElement$6(node)) { 22863 return !isBlockElement(schema.getBlockElements(), node) && !isBookmarkNode$1(node) && !isTransparentBlock(schema, node) && !isNonHtmlElementRoot(node); 22864 } else { 22865 return false;
vendor: 4,968 bytes, lines 22866-22995
22866 } 22867 }; 22868 const hasBlockParent = (blockElements, root, node) => { 22869 return exists(parents(SugarElement.fromDom(node), SugarElement.fromDom(root)), elm => { 22870 return isBlockElement(blockElements, elm.dom); 22871 }); 22872 }; 22873 const shouldRemoveTextNode = (blockElements, node) => { 22874 if (isText$b(node)) { 22875 if (node.data.length === 0) { 22876 return true; 22877 } else if (/^\s+$/.test(node.data)) { 22878 return !node.nextSibling || isBlockElement(blockElements, node.nextSibling) || isNonHtmlElementRoot(node.nextSibling); 22879 } 22880 } 22881 return false; 22882 }; 22883 const createRootBlock = editor => editor.dom.create(getForcedRootBlock(editor), getForcedRootBlockAttrs(editor)); 22884 const addRootBlocks = editor => { 22885 const dom = editor.dom, selection = editor.selection; 22886 const schema = editor.schema; 22887 const blockElements = schema.getBlockElements(); 22888 const startNode = selection.getStart(); 22889 const rootNode = editor.getBody(); 22890 let rootBlockNode; 22891 let tempNode; 22892 let bm = null; 22893 const forcedRootBlock = getForcedRootBlock(editor); 22894 if (!startNode || !isElement$6(startNode)) { 22895 return; 22896 } 22897 const rootNodeName = rootNode.nodeName.toLowerCase(); 22898 if (!schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase()) || hasBlockParent(blockElements, rootNode, startNode)) { 22899 return; 22900 } 22901 if (rootNode.firstChild === rootNode.lastChild && isBr$6(rootNode.firstChild)) { 22902 rootBlockNode = createRootBlock(editor); 22903 rootBlockNode.appendChild(createPaddingBr().dom); 22904 rootNode.replaceChild(rootBlockNode, rootNode.firstChild); 22905 editor.selection.setCursorLocation(rootBlockNode, 0); 22906 editor.nodeChanged(); 22907 return; 22908 } 22909 let node = rootNode.firstChild; 22910 while (node) { 22911 if (isElement$6(node)) { 22912 updateElement(schema, node); 22913 } 22914 if (isValidTarget(schema, node)) { 22915 if (shouldRemoveTextNode(blockElements, node)) { 22916 tempNode = node; 22917 node = node.nextSibling; 22918 dom.remove(tempNode); 22919 continue; 22920 } 22921 if (!rootBlockNode) { 22922 if (!bm && editor.hasFocus()) { 22923 bm = getBookmark(editor.selection.getRng(), () => document.createElement('span')); 22924 } 22925 if (!node.parentNode) { 22926 node = null; 22927 break; 22928 } 22929 rootBlockNode = createRootBlock(editor); 22930 rootNode.insertBefore(rootBlockNode, node); 22931 } 22932 tempNode = node; 22933 node = node.nextSibling; 22934 rootBlockNode.appendChild(tempNode); 22935 } else { 22936 rootBlockNode = null; 22937 node = node.nextSibling; 22938 } 22939 } 22940 if (bm) { 22941 editor.selection.setRng(resolveBookmark(bm)); 22942 editor.nodeChanged(); 22943 } 22944 }; 22945 const insertEmptyLine = (editor, root, insertBlock) => { 22946 const block = SugarElement.fromDom(createRootBlock(editor)); 22947 const br = createPaddingBr(); 22948 append$1(block, br); 22949 insertBlock(root, block); 22950 const rng = document.createRange(); 22951 rng.setStartBefore(br.dom); 22952 rng.setEndBefore(br.dom); 22953 return rng; 22954 }; 22955 const setup$o = editor => { 22956 editor.on('NodeChange', () => addRootBlocks(editor)); 22957 }; 22958 22959 const hasClass = checkClassName => node => (' ' + node.attr('class') + ' ').indexOf(checkClassName) !== -1; 22960 const replaceMatchWithSpan = (editor, content, cls) => { 22961 return function (match) { 22962 const args = arguments, index = args[args.length - 2]; 22963 const prevChar = index > 0 ? content.charAt(index - 1) : ''; 22964 if (prevChar === '"') { 22965 return match; 22966 } 22967 if (prevChar === '>') { 22968 const findStartTagIndex = content.lastIndexOf('<', index); 22969 if (findStartTagIndex !== -1) { 22970 const tagHtml = content.substring(findStartTagIndex, index); 22971 if (tagHtml.indexOf('contenteditable="false"') !== -1) { 22972 return match; 22973 } 22974 } 22975 } 22976 return '<span class="' + cls + '" data-mce-content="' + editor.dom.encode(args[0]) + '">' + editor.dom.encode(typeof args[1] === 'string' ? args[1] : args[0]) + '</span>'; 22977 }; 22978 }; 22979 const convertRegExpsToNonEditable = (editor, nonEditableRegExps, e) => { 22980 let i = nonEditableRegExps.length, content = e.content; 22981 if (e.format === 'raw') { 22982 return; 22983 } 22984 while (i--) { 22985 content = content.replace(nonEditableRegExps[i], replaceMatchWithSpan(editor, content, getNonEditableClass(editor))); 22986 } 22987 e.content = content; 22988 }; 22989 const isValidContent = (nonEditableRegExps, content) => { 22990 return forall(nonEditableRegExps, re => { 22991 const matches = content.match(re); 22992 return matches !== null && matches[0].length === content.length; 22993 }); 22994 }; 22995 const setup$n = editor => {
vendor: 10,089 bytes, lines 22996-23231
22996 const contentEditableAttrName = 'contenteditable'; 22997 const editClass = ' ' + Tools.trim(getEditableClass(editor)) + ' '; 22998 const nonEditClass = ' ' + Tools.trim(getNonEditableClass(editor)) + ' '; 22999 const hasEditClass = hasClass(editClass); 23000 const hasNonEditClass = hasClass(nonEditClass); 23001 const nonEditableRegExps = getNonEditableRegExps(editor); 23002 if (nonEditableRegExps.length > 0) { 23003 editor.on('BeforeSetContent', e => { 23004 convertRegExpsToNonEditable(editor, nonEditableRegExps, e); 23005 }); 23006 } 23007 editor.parser.addAttributeFilter('class', nodes => { 23008 let i = nodes.length; 23009 while (i--) { 23010 const node = nodes[i]; 23011 if (hasEditClass(node)) { 23012 node.attr(contentEditableAttrName, 'true'); 23013 } else if (hasNonEditClass(node)) { 23014 node.attr(contentEditableAttrName, 'false'); 23015 } 23016 } 23017 }); 23018 editor.serializer.addAttributeFilter(contentEditableAttrName, nodes => { 23019 let i = nodes.length; 23020 while (i--) { 23021 const node = nodes[i]; 23022 if (!hasEditClass(node) && !hasNonEditClass(node)) { 23023 continue; 23024 } 23025 const content = node.attr('data-mce-content'); 23026 if (nonEditableRegExps.length > 0 && content) { 23027 if (isValidContent(nonEditableRegExps, content)) { 23028 node.name = '#text'; 23029 node.type = 3; 23030 node.raw = true; 23031 node.value = content; 23032 } else { 23033 node.remove(); 23034 } 23035 } else { 23036 node.attr(contentEditableAttrName, null); 23037 } 23038 } 23039 }); 23040 }; 23041 23042 const findBlockCaretContainer = editor => descendant$1(SugarElement.fromDom(editor.getBody()), '*[data-mce-caret]').map(elm => elm.dom).getOrNull(); 23043 const showBlockCaretContainer = (editor, blockCaretContainer) => { 23044 if (blockCaretContainer.hasAttribute('data-mce-caret')) { 23045 showCaretContainerBlock(blockCaretContainer); 23046 editor.selection.setRng(editor.selection.getRng()); 23047 editor.selection.scrollIntoView(blockCaretContainer); 23048 } 23049 }; 23050 const handleBlockContainer = (editor, e) => { 23051 const blockCaretContainer = findBlockCaretContainer(editor); 23052 if (!blockCaretContainer) { 23053 return; 23054 } 23055 if (e.type === 'compositionstart') { 23056 e.preventDefault(); 23057 e.stopPropagation(); 23058 showBlockCaretContainer(editor, blockCaretContainer); 23059 return; 23060 } 23061 if (hasContent(blockCaretContainer)) { 23062 showBlockCaretContainer(editor, blockCaretContainer); 23063 editor.undoManager.add(); 23064 } 23065 }; 23066 const setup$m = editor => { 23067 editor.on('keyup compositionstart', curry(handleBlockContainer, editor)); 23068 }; 23069 23070 const isContentEditableFalse$4 = isContentEditableFalse$b; 23071 const moveToCeFalseHorizontally = (direction, editor, range) => moveHorizontally(editor, direction, range, isBeforeContentEditableFalse, isAfterContentEditableFalse, isContentEditableFalse$4); 23072 const moveToCeFalseVertically = (direction, editor, range) => { 23073 const isBefore = caretPosition => isBeforeContentEditableFalse(caretPosition) || isBeforeTable(caretPosition); 23074 const isAfter = caretPosition => isAfterContentEditableFalse(caretPosition) || isAfterTable(caretPosition); 23075 return moveVertically(editor, direction, range, isBefore, isAfter, isContentEditableFalse$4); 23076 }; 23077 const createTextBlock = editor => { 23078 const textBlock = editor.dom.create(getForcedRootBlock(editor)); 23079 textBlock.innerHTML = '<br data-mce-bogus="1">'; 23080 return textBlock; 23081 }; 23082 const exitPreBlock = (editor, direction, range) => { 23083 const caretWalker = CaretWalker(editor.getBody()); 23084 const getVisualCaretPosition$1 = curry(getVisualCaretPosition, direction === 1 ? caretWalker.next : caretWalker.prev); 23085 if (range.collapsed) { 23086 const pre = editor.dom.getParent(range.startContainer, 'PRE'); 23087 if (!pre) { 23088 return; 23089 } 23090 const caretPos = getVisualCaretPosition$1(CaretPosition.fromRangeStart(range)); 23091 if (!caretPos) { 23092 const newBlock = SugarElement.fromDom(createTextBlock(editor)); 23093 if (direction === 1) { 23094 after$4(SugarElement.fromDom(pre), newBlock); 23095 } else { 23096 before$3(SugarElement.fromDom(pre), newBlock); 23097 } 23098 editor.selection.select(newBlock.dom, true); 23099 editor.selection.collapse(); 23100 } 23101 } 23102 }; 23103 const getHorizontalRange = (editor, forward) => { 23104 const direction = forward ? 1 : -1; 23105 const range = editor.selection.getRng(); 23106 return moveToCeFalseHorizontally(direction, editor, range).orThunk(() => { 23107 exitPreBlock(editor, direction, range); 23108 return Optional.none(); 23109 }); 23110 }; 23111 const getVerticalRange = (editor, down) => { 23112 const direction = down ? 1 : -1; 23113 const range = editor.selection.getRng(); 23114 return moveToCeFalseVertically(direction, editor, range).orThunk(() => { 23115 exitPreBlock(editor, direction, range); 23116 return Optional.none(); 23117 }); 23118 }; 23119 const flipDirection = (selection, forward) => { 23120 const elm = forward ? selection.getEnd(true) : selection.getStart(true); 23121 return isRtl(elm) ? !forward : forward; 23122 }; 23123 const moveH$2 = (editor, forward) => getHorizontalRange(editor, flipDirection(editor.selection, forward)).exists(newRange => { 23124 moveToRange(editor, newRange); 23125 return true; 23126 }); 23127 const moveV$4 = (editor, down) => getVerticalRange(editor, down).exists(newRange => { 23128 moveToRange(editor, newRange); 23129 return true; 23130 }); 23131 const moveToLineEndPoint$1 = (editor, forward) => { 23132 const isCefPosition = forward ? isAfterContentEditableFalse : isBeforeContentEditableFalse; 23133 return moveToLineEndPoint$3(editor, forward, isCefPosition); 23134 }; 23135 const selectToEndPoint = (editor, forward) => getEdgeCefPosition(editor, !forward).map(pos => { 23136 const rng = pos.toRange(); 23137 const curRng = editor.selection.getRng(); 23138 if (forward) { 23139 rng.setStart(curRng.startContainer, curRng.startOffset); 23140 } else { 23141 rng.setEnd(curRng.endContainer, curRng.endOffset); 23142 } 23143 return rng; 23144 }).exists(rng => { 23145 moveToRange(editor, rng); 23146 return true; 23147 }); 23148 23149 const isTarget = node => contains$2(['figcaption'], name(node)); 23150 const getClosestTargetBlock = (pos, root, schema) => { 23151 const isRoot = curry(eq, root); 23152 return closest$4(SugarElement.fromDom(pos.container()), el => schema.isBlock(name(el)), isRoot).filter(isTarget); 23153 }; 23154 const isAtFirstOrLastLine = (root, forward, pos) => forward ? isAtLastLine(root.dom, pos) : isAtFirstLine(root.dom, pos); 23155 const moveCaretToNewEmptyLine = (editor, forward) => { 23156 const root = SugarElement.fromDom(editor.getBody()); 23157 const pos = CaretPosition.fromRangeStart(editor.selection.getRng()); 23158 return getClosestTargetBlock(pos, root, editor.schema).exists(() => { 23159 if (isAtFirstOrLastLine(root, forward, pos)) { 23160 const insertFn = forward ? append$1 : prepend; 23161 const rng = insertEmptyLine(editor, root, insertFn); 23162 editor.selection.setRng(rng); 23163 return true; 23164 } else { 23165 return false; 23166 } 23167 }); 23168 }; 23169 const moveV$3 = (editor, forward) => { 23170 if (editor.selection.isCollapsed()) { 23171 return moveCaretToNewEmptyLine(editor, forward); 23172 } else { 23173 return false; 23174 } 23175 }; 23176 23177 const moveUp = (editor, details, summary) => { 23178 const rng = editor.selection.getRng(); 23179 const pos = CaretPosition.fromRangeStart(rng); 23180 const root = editor.getBody(); 23181 if (root.firstChild === details && isAtFirstLine(summary, pos)) { 23182 editor.execCommand('InsertNewBlockBefore'); 23183 return true; 23184 } else { 23185 return false; 23186 } 23187 }; 23188 const moveDown = (editor, details) => { 23189 const rng = editor.selection.getRng(); 23190 const pos = CaretPosition.fromRangeStart(rng); 23191 const root = editor.getBody(); 23192 if (root.lastChild === details && isAtLastLine(details, pos)) { 23193 editor.execCommand('InsertNewBlockAfter'); 23194 return true; 23195 } else { 23196 return false; 23197 } 23198 }; 23199 const move$2 = (editor, forward) => { 23200 if (forward) { 23201 return Optional.from(editor.dom.getParent(editor.selection.getNode(), 'details')).map(details => moveDown(editor, details)).getOr(false); 23202 } else { 23203 return Optional.from(editor.dom.getParent(editor.selection.getNode(), 'summary')).bind(summary => Optional.from(editor.dom.getParent(summary, 'details')).map(details => moveUp(editor, details, summary))).getOr(false); 23204 } 23205 }; 23206 const moveV$2 = (editor, forward) => move$2(editor, forward); 23207 23208 const baseKeyPattern = { 23209 shiftKey: false, 23210 altKey: false, 23211 ctrlKey: false, 23212 metaKey: false, 23213 keyCode: 0 23214 }; 23215 const defaultPatterns = patterns => map$3(patterns, pattern => ({ 23216 ...baseKeyPattern, 23217 ...pattern 23218 })); 23219 const defaultDelayedPatterns = patterns => map$3(patterns, pattern => ({ 23220 ...baseKeyPattern, 23221 ...pattern 23222 })); 23223 const matchesEvent = (pattern, evt) => evt.keyCode === pattern.keyCode && evt.shiftKey === pattern.shiftKey && evt.altKey === pattern.altKey && evt.ctrlKey === pattern.ctrlKey && evt.metaKey === pattern.metaKey; 23224 const match$1 = (patterns, evt) => bind$3(defaultPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []); 23225 const matchDelayed = (patterns, evt) => bind$3(defaultDelayedPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []); 23226 const action = (f, ...x) => () => f.apply(null, x); 23227 const execute = (patterns, evt) => find$2(match$1(patterns, evt), pattern => pattern.action()); 23228 const executeWithDelayedAction = (patterns, evt) => findMap(matchDelayed(patterns, evt), pattern => pattern.action()); 23229 23230 const moveH$1 = (editor, forward) => { 23231 const direction = forward ? 1 : -1
vendor: 10,719 bytes, lines 23231-23467
23231; 23232 const range = editor.selection.getRng(); 23233 return moveHorizontally(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => { 23234 moveToRange(editor, newRange); 23235 return true; 23236 }); 23237 }; 23238 const moveV$1 = (editor, down) => { 23239 const direction = down ? 1 : -1; 23240 const range = editor.selection.getRng(); 23241 return moveVertically(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => { 23242 moveToRange(editor, newRange); 23243 return true; 23244 }); 23245 }; 23246 const moveToLineEndPoint = (editor, forward) => { 23247 const isNearMedia = forward ? isAfterMedia : isBeforeMedia; 23248 return moveToLineEndPoint$3(editor, forward, isNearMedia); 23249 }; 23250 23251 const adt = Adt.generate([ 23252 { none: ['current'] }, 23253 { first: ['current'] }, 23254 { 23255 middle: [ 23256 'current', 23257 'target' 23258 ] 23259 }, 23260 { last: ['current'] } 23261 ]); 23262 const none = current => adt.none(current); 23263 const CellLocation = { 23264 ...adt, 23265 none 23266 }; 23267 23268 const firstLayer = (scope, selector) => { 23269 return filterFirstLayer(scope, selector, always); 23270 }; 23271 const filterFirstLayer = (scope, selector, predicate) => { 23272 return bind$3(children$1(scope), x => { 23273 if (is$1(x, selector)) { 23274 return predicate(x) ? [x] : []; 23275 } else { 23276 return filterFirstLayer(x, selector, predicate); 23277 } 23278 }); 23279 }; 23280 23281 const lookup$1 = (tags, element, isRoot = never) => { 23282 if (isRoot(element)) { 23283 return Optional.none(); 23284 } 23285 if (contains$2(tags, name(element))) { 23286 return Optional.some(element); 23287 } 23288 const isRootOrUpperTable = elm => is$1(elm, 'table') || isRoot(elm); 23289 return ancestor$3(element, tags.join(','), isRootOrUpperTable); 23290 }; 23291 const cell = (element, isRoot) => lookup$1([ 23292 'td', 23293 'th' 23294 ], element, isRoot); 23295 const cells = ancestor => firstLayer(ancestor, 'th,td'); 23296 const table = (element, isRoot) => closest$3(element, 'table', isRoot); 23297 23298 const walk = (all, current, index, direction, isEligible = always) => { 23299 const forwards = direction === 1; 23300 if (!forwards && index <= 0) { 23301 return CellLocation.first(all[0]); 23302 } else if (forwards && index >= all.length - 1) { 23303 return CellLocation.last(all[all.length - 1]); 23304 } else { 23305 const newIndex = index + direction; 23306 const elem = all[newIndex]; 23307 return isEligible(elem) ? CellLocation.middle(current, elem) : walk(all, current, newIndex, direction, isEligible); 23308 } 23309 }; 23310 const detect = (current, isRoot) => { 23311 return table(current, isRoot).bind(table => { 23312 const all = cells(table); 23313 const index = findIndex$2(all, x => eq(current, x)); 23314 return index.map(index => ({ 23315 index, 23316 all 23317 })); 23318 }); 23319 }; 23320 const next = (current, isEligible, isRoot) => { 23321 const detection = detect(current, isRoot); 23322 return detection.fold(() => { 23323 return CellLocation.none(current); 23324 }, info => { 23325 return walk(info.all, current, info.index, 1, isEligible); 23326 }); 23327 }; 23328 const prev = (current, isEligible, isRoot) => { 23329 const detection = detect(current, isRoot); 23330 return detection.fold(() => { 23331 return CellLocation.none(); 23332 }, info => { 23333 return walk(info.all, current, info.index, -1, isEligible); 23334 }); 23335 }; 23336 23337 const isTextNodeWithCursorPosition = el => getOption(el).filter(text => text.trim().length !== 0 || text.indexOf(nbsp) > -1).isSome(); 23338 const isContentEditableFalse$3 = elem => isHTMLElement$1(elem) && get$9(elem, 'contenteditable') === 'false'; 23339 const elementsWithCursorPosition = [ 23340 'img', 23341 'br' 23342 ]; 23343 const isCursorPosition = elem => { 23344 const hasCursorPosition = isTextNodeWithCursorPosition(elem); 23345 return hasCursorPosition || contains$2(elementsWithCursorPosition, name(elem)) || isContentEditableFalse$3(elem); 23346 }; 23347 23348 const first = element => descendant$2(element, isCursorPosition); 23349 23350 const deflate = (rect, delta) => ({ 23351 left: rect.left - delta, 23352 top: rect.top - delta, 23353 right: rect.right + delta * 2, 23354 bottom: rect.bottom + delta * 2, 23355 width: rect.width + delta, 23356 height: rect.height + delta 23357 }); 23358 const getCorners = (getYAxisValue, tds) => bind$3(tds, td => { 23359 const rect = deflate(clone$1(td.getBoundingClientRect()), -1); 23360 return [ 23361 { 23362 x: rect.left, 23363 y: getYAxisValue(rect), 23364 cell: td 23365 }, 23366 { 23367 x: rect.right, 23368 y: getYAxisValue(rect), 23369 cell: td 23370 } 23371 ]; 23372 }); 23373 const findClosestCorner = (corners, x, y) => foldl(corners, (acc, newCorner) => acc.fold(() => Optional.some(newCorner), oldCorner => { 23374 const oldDist = Math.sqrt(Math.abs(oldCorner.x - x) + Math.abs(oldCorner.y - y)); 23375 const newDist = Math.sqrt(Math.abs(newCorner.x - x) + Math.abs(newCorner.y - y)); 23376 return Optional.some(newDist < oldDist ? newCorner : oldCorner); 23377 }), Optional.none()); 23378 const getClosestCell = (getYAxisValue, isTargetCorner, table, x, y) => { 23379 const cells = descendants(SugarElement.fromDom(table), 'td,th,caption').map(e => e.dom); 23380 const corners = filter$5(getCorners(getYAxisValue, cells), corner => isTargetCorner(corner, y)); 23381 return findClosestCorner(corners, x, y).map(corner => corner.cell); 23382 }; 23383 const getBottomValue = rect => rect.bottom; 23384 const getTopValue = rect => rect.top; 23385 const isAbove = (corner, y) => corner.y < y; 23386 const isBelow = (corner, y) => corner.y > y; 23387 const getClosestCellAbove = curry(getClosestCell, getBottomValue, isAbove); 23388 const getClosestCellBelow = curry(getClosestCell, getTopValue, isBelow); 23389 const findClosestPositionInAboveCell = (table, pos) => head(pos.getClientRects()).bind(rect => getClosestCellAbove(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getLastLinePositions(cell), pos)); 23390 const findClosestPositionInBelowCell = (table, pos) => last$2(pos.getClientRects()).bind(rect => getClosestCellBelow(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getFirstLinePositions(cell), pos)); 23391 23392 const hasNextBreak = (getPositionsUntil, scope, lineInfo) => lineInfo.breakAt.exists(breakPos => getPositionsUntil(scope, breakPos).breakAt.isSome()); 23393 const startsWithWrapBreak = lineInfo => lineInfo.breakType === BreakType.Wrap && lineInfo.positions.length === 0; 23394 const startsWithBrBreak = lineInfo => lineInfo.breakType === BreakType.Br && lineInfo.positions.length === 1; 23395 const isAtTableCellLine = (getPositionsUntil, scope, pos) => { 23396 const lineInfo = getPositionsUntil(scope, pos); 23397 if (startsWithWrapBreak(lineInfo) || !isBr$6(pos.getNode()) && startsWithBrBreak(lineInfo)) { 23398 return !hasNextBreak(getPositionsUntil, scope, lineInfo); 23399 } else { 23400 return lineInfo.breakAt.isNone(); 23401 } 23402 }; 23403 const isAtFirstTableCellLine = curry(isAtTableCellLine, getPositionsUntilPreviousLine); 23404 const isAtLastTableCellLine = curry(isAtTableCellLine, getPositionsUntilNextLine); 23405 const isCaretAtStartOrEndOfTable = (forward, rng, table) => { 23406 const caretPos = CaretPosition.fromRangeStart(rng); 23407 return positionIn(!forward, table).exists(pos => pos.isEqual(caretPos)); 23408 }; 23409 const navigateHorizontally = (editor, forward, table, _td) => { 23410 const rng = editor.selection.getRng(); 23411 const direction = forward ? 1 : -1; 23412 if (isFakeCaretTableBrowser() && isCaretAtStartOrEndOfTable(forward, rng, table)) { 23413 showCaret(direction, editor, table, !forward, false).each(newRng => { 23414 moveToRange(editor, newRng); 23415 }); 23416 return true; 23417 } 23418 return false; 23419 }; 23420 const getClosestAbovePosition = (root, table, start) => findClosestPositionInAboveCell(table, start).orThunk(() => head(start.getClientRects()).bind(rect => findClosestHorizontalPositionFromPoint(getPositionsAbove(root, CaretPosition.before(table)), rect.left))).getOr(CaretPosition.before(table)); 23421 const getClosestBelowPosition = (root, table, start) => findClosestPositionInBelowCell(table, start).orThunk(() => head(start.getClientRects()).bind(rect => findClosestHorizontalPositionFromPoint(getPositionsBelow(root, CaretPosition.after(table)), rect.left))).getOr(CaretPosition.after(table)); 23422 const getTable = (previous, pos) => { 23423 const node = pos.getNode(previous); 23424 return isTable$2(node) ? Optional.some(node) : Optional.none(); 23425 }; 23426 const renderBlock = (down, editor, table) => { 23427 editor.undoManager.transact(() => { 23428 const insertFn = down ? after$4 : before$3; 23429 const rng = insertEmptyLine(editor, SugarElement.fromDom(table), insertFn); 23430 moveToRange(editor, rng); 23431 }); 23432 }; 23433 const moveCaret = (editor, down, pos) => { 23434 const table = down ? getTable(true, pos) : getTable(false, pos); 23435 const last = down === false; 23436 table.fold(() => moveToRange(editor, pos.toRange()), table => positionIn(last, editor.getBody()).filter(lastPos => lastPos.isEqual(pos)).fold(() => moveToRange(editor, pos.toRange()), _ => renderBlock(down, editor, table))); 23437 }; 23438 const navigateVertically = (editor, down, table, td) => { 23439 const rng = editor.selection.getRng(); 23440 const pos = CaretPosition.fromRangeStart(rng); 23441 const root = editor.getBody(); 23442 if (!down && isAtFirstTableCellLine(td, pos)) { 23443 const newPos = getClosestAbovePosition(root, table, pos); 23444 moveCaret(editor, down, newPos); 23445 return true; 23446 } else if (down && isAtLastTableCellLine(td, pos)) { 23447 const newPos = getClosestBelowPosition(root, table, pos); 23448 moveCaret(editor, down, newPos); 23449 return true; 23450 } else { 23451 return false; 23452 } 23453 }; 23454 const move$1 = (editor, forward, mover) => Optional.from(editor.dom.getParent(editor.selection.getNode(), 'td,th')).bind(td => Optional.from(editor.dom.getParent(td, 'table')).map(table => mover(editor, forward, table, td))).getOr(false); 23455 const moveH = (editor, forward) => move$1(editor, forward, navigateHorizontally); 23456 const moveV = (editor, forward) => move$1(editor, forward, navigateVertically); 23457 const getCellFirstCursorPosition = cell => { 23458 const selection = SimSelection.exact(cell, 0, cell, 0); 23459 return toNative(selection); 23460 }; 23461 const tabGo = (editor, isRoot, cell) => { 23462 return cell.fold(Optional.none, Optional.none, (_current, next) => { 23463 return first(next).map(cell => { 23464 return getCellFirstCursorPosition(cell); 23465 }); 23466 }, current => { 23467
vendor: 8,704 bytes, lines 23467-23733
23467if (editor.mode.isReadOnly()) { 23468 return Optional.none(); 23469 } 23470 editor.execCommand('mceTableInsertRowAfter'); 23471 return tabForward(editor, isRoot, current); 23472 }); 23473 }; 23474 const tabForward = (editor, isRoot, cell) => tabGo(editor, isRoot, next(cell, isEditable$2)); 23475 const tabBackward = (editor, isRoot, cell) => tabGo(editor, isRoot, prev(cell, isEditable$2)); 23476 const handleTab = (editor, forward) => { 23477 const rootElements = [ 23478 'table', 23479 'li', 23480 'dl' 23481 ]; 23482 const body = SugarElement.fromDom(editor.getBody()); 23483 const isRoot = element => { 23484 const name$1 = name(element); 23485 return eq(element, body) || contains$2(rootElements, name$1); 23486 }; 23487 const rng = editor.selection.getRng(); 23488 const container = SugarElement.fromDom(!forward ? rng.startContainer : rng.endContainer); 23489 return cell(container, isRoot).map(cell => { 23490 table(cell, isRoot).each(table => { 23491 editor.model.table.clearSelectedCells(table.dom); 23492 }); 23493 editor.selection.collapse(!forward); 23494 const navigation = !forward ? tabBackward : tabForward; 23495 const rng = navigation(editor, isRoot, cell); 23496 rng.each(range => { 23497 editor.selection.setRng(range); 23498 }); 23499 return true; 23500 }).getOr(false); 23501 }; 23502 23503 const executeKeydownOverride$4 = (editor, caret, evt) => { 23504 const isMac = Env.os.isMacOS() || Env.os.isiOS(); 23505 execute([ 23506 { 23507 keyCode: VK.RIGHT, 23508 action: action(moveH$2, editor, true) 23509 }, 23510 { 23511 keyCode: VK.LEFT, 23512 action: action(moveH$2, editor, false) 23513 }, 23514 { 23515 keyCode: VK.UP, 23516 action: action(moveV$4, editor, false) 23517 }, 23518 { 23519 keyCode: VK.DOWN, 23520 action: action(moveV$4, editor, true) 23521 }, 23522 ...isMac ? [ 23523 { 23524 keyCode: VK.UP, 23525 action: action(selectToEndPoint, editor, false), 23526 metaKey: true, 23527 shiftKey: true 23528 }, 23529 { 23530 keyCode: VK.DOWN, 23531 action: action(selectToEndPoint, editor, true), 23532 metaKey: true, 23533 shiftKey: true 23534 } 23535 ] : [], 23536 { 23537 keyCode: VK.RIGHT, 23538 action: action(moveH, editor, true) 23539 }, 23540 { 23541 keyCode: VK.LEFT, 23542 action: action(moveH, editor, false) 23543 }, 23544 { 23545 keyCode: VK.UP, 23546 action: action(moveV, editor, false) 23547 }, 23548 { 23549 keyCode: VK.DOWN, 23550 action: action(moveV, editor, true) 23551 }, 23552 { 23553 keyCode: VK.UP, 23554 action: action(moveV, editor, false) 23555 }, 23556 { 23557 keyCode: VK.UP, 23558 action: action(moveV$2, editor, false) 23559 }, 23560 { 23561 keyCode: VK.DOWN, 23562 action: action(moveV$2, editor, true) 23563 }, 23564 { 23565 keyCode: VK.RIGHT, 23566 action: action(moveH$1, editor, true) 23567 }, 23568 { 23569 keyCode: VK.LEFT, 23570 action: action(moveH$1, editor, false) 23571 }, 23572 { 23573 keyCode: VK.UP, 23574 action: action(moveV$1, editor, false) 23575 }, 23576 { 23577 keyCode: VK.DOWN, 23578 action: action(moveV$1, editor, true) 23579 }, 23580 { 23581 keyCode: VK.RIGHT, 23582 action: action(move$3, editor, caret, true) 23583 }, 23584 { 23585 keyCode: VK.LEFT, 23586 action: action(move$3, editor, caret, false) 23587 }, 23588 { 23589 keyCode: VK.RIGHT, 23590 ctrlKey: !isMac, 23591 altKey: isMac, 23592 action: action(moveNextWord, editor, caret) 23593 }, 23594 { 23595 keyCode: VK.LEFT, 23596 ctrlKey: !isMac, 23597 altKey: isMac, 23598 action: action(movePrevWord, editor, caret) 23599 }, 23600 { 23601 keyCode: VK.UP, 23602 action: action(moveV$3, editor, false) 23603 }, 23604 { 23605 keyCode: VK.DOWN, 23606 action: action(moveV$3, editor, true) 23607 } 23608 ], evt).each(_ => { 23609 evt.preventDefault(); 23610 }); 23611 }; 23612 const setup$l = (editor, caret) => { 23613 editor.on('keydown', evt => { 23614 if (!evt.isDefaultPrevented()) { 23615 executeKeydownOverride$4(editor, caret, evt); 23616 } 23617 }); 23618 }; 23619 23620 const point = (container, offset) => ({ 23621 container, 23622 offset 23623 }); 23624 23625 const DOM$7 = DOMUtils.DOM; 23626 const alwaysNext = startNode => node => startNode === node ? -1 : 0; 23627 const isBoundary = dom => node => dom.isBlock(node) || contains$2([ 23628 'BR', 23629 'IMG', 23630 'HR', 23631 'INPUT' 23632 ], node.nodeName) || dom.getContentEditable(node) === 'false'; 23633 const textBefore = (node, offset, rootNode) => { 23634 if (isText$b(node) && offset >= 0) { 23635 return Optional.some(point(node, offset)); 23636 } else { 23637 const textSeeker = TextSeeker(DOM$7); 23638 return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, prev.container.data.length)); 23639 } 23640 }; 23641 const textAfter = (node, offset, rootNode) => { 23642 if (isText$b(node) && offset >= node.length) { 23643 return Optional.some(point(node, offset)); 23644 } else { 23645 const textSeeker = TextSeeker(DOM$7); 23646 return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, 0)); 23647 } 23648 }; 23649 const scanLeft = (node, offset, rootNode) => { 23650 if (!isText$b(node)) { 23651 return Optional.none(); 23652 } 23653 const text = node.data; 23654 if (offset >= 0 && offset <= text.length) { 23655 return Optional.some(point(node, offset)); 23656 } else { 23657 const textSeeker = TextSeeker(DOM$7); 23658 return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).bind(prev => { 23659 const prevText = prev.container.data; 23660 return scanLeft(prev.container, offset + prevText.length, rootNode); 23661 }); 23662 } 23663 }; 23664 const scanRight = (node, offset, rootNode) => { 23665 if (!isText$b(node)) { 23666 return Optional.none(); 23667 } 23668 const text = node.data; 23669 if (offset <= text.length) { 23670 return Optional.some(point(node, offset)); 23671 } else { 23672 const textSeeker = TextSeeker(DOM$7); 23673 return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).bind(next => scanRight(next.container, offset - text.length, rootNode)); 23674 } 23675 }; 23676 const repeatLeft = (dom, node, offset, process, rootNode) => { 23677 const search = TextSeeker(dom, isBoundary(dom)); 23678 return Optional.from(search.backwards(node, offset, process, rootNode)); 23679 }; 23680 23681 const isValidTextRange = rng => rng.collapsed && isText$b(rng.startContainer); 23682 const getText = rng => trim$2(rng.toString().replace(/\u00A0/g, ' ')); 23683 const isWhitespace = chr => chr !== '' && ' \xA0\uFEFF\f\n\r\t\x0B'.indexOf(chr) !== -1; 23684 23685 const stripTrigger = (text, trigger) => text.substring(trigger.length); 23686 const findTrigger = (text, index, trigger, includeWhitespace = false) => { 23687 let i; 23688 const firstChar = trigger.charAt(0); 23689 for (i = index - 1; i >= 0; i--) { 23690 const char = text.charAt(i); 23691 if (!includeWhitespace && isWhitespace(char)) { 23692 return Optional.none(); 23693 } 23694 if (firstChar === char && contains$1(text, trigger, i, index)) { 23695 break; 23696 } 23697 } 23698 return Optional.some(i); 23699 }; 23700 const getContext = (dom, initRange, trigger, includeWhitespace = false) => { 23701 if (!isValidTextRange(initRange)) { 23702 return Optional.none(); 23703 } 23704 const buffer = { 23705 text: '', 23706 offset: 0 23707 }; 23708 const findTriggerIndex = (element, offset, text) => { 23709 buffer.text = text + buffer.text; 23710 buffer.offset += offset; 23711 return findTrigger(buffer.text, buffer.offset, trigger, includeWhitespace).getOr(offset); 23712 }; 23713 const root = dom.getParent(initRange.startContainer, dom.isBlock) || dom.getRoot(); 23714 return repeatLeft(dom, initRange.startContainer, initRange.startOffset, findTriggerIndex, root).bind(spot => { 23715 const range = initRange.cloneRange(); 23716 range.setStart(spot.container, spot.offset); 23717 range.setEnd(initRange.endContainer, initRange.endOffset); 23718 if (range.collapsed) { 23719 return Optional.none(); 23720 } 23721 const text = getText(range); 23722 const triggerIndex = text.lastIndexOf(trigger); 23723 if (triggerIndex !== 0) { 23724 return Optional.none(); 23725 } else { 23726 return Optional.some({ 23727 text: stripTrigger(text, trigger), 23728 range, 23729 trigger 23730 }); 23731 } 23732 }); 23733 }
vendor: 12,204 bytes, lines 23733-24073
23733; 23734 23735 const isText$1 = node => node.nodeType === TEXT; 23736 const isElement = node => node.nodeType === ELEMENT; 23737 const toLast = node => { 23738 if (isText$1(node)) { 23739 return point(node, node.data.length); 23740 } else { 23741 const children = node.childNodes; 23742 return children.length > 0 ? toLast(children[children.length - 1]) : point(node, children.length); 23743 } 23744 }; 23745 const toLeaf = (node, offset) => { 23746 const children = node.childNodes; 23747 if (children.length > 0 && offset < children.length) { 23748 return toLeaf(children[offset], 0); 23749 } else if (children.length > 0 && isElement(node) && children.length === offset) { 23750 return toLast(children[children.length - 1]); 23751 } else { 23752 return point(node, offset); 23753 } 23754 }; 23755 23756 const isPreviousCharContent = (dom, leaf) => { 23757 var _a; 23758 const root = (_a = dom.getParent(leaf.container, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot(); 23759 return repeatLeft(dom, leaf.container, leaf.offset, (_element, offset) => offset === 0 ? -1 : offset, root).filter(spot => { 23760 const char = spot.container.data.charAt(spot.offset - 1); 23761 return !isWhitespace(char); 23762 }).isSome(); 23763 }; 23764 const isStartOfWord = dom => rng => { 23765 const leaf = toLeaf(rng.startContainer, rng.startOffset); 23766 return !isPreviousCharContent(dom, leaf); 23767 }; 23768 const getTriggerContext = (dom, initRange, database) => findMap(database.triggers, trigger => getContext(dom, initRange, trigger)); 23769 const lookup = (editor, getDatabase) => { 23770 const database = getDatabase(); 23771 const rng = editor.selection.getRng(); 23772 return getTriggerContext(editor.dom, rng, database).bind(context => lookupWithContext(editor, getDatabase, context)); 23773 }; 23774 const lookupWithContext = (editor, getDatabase, context, fetchOptions = {}) => { 23775 var _a; 23776 const database = getDatabase(); 23777 const rng = editor.selection.getRng(); 23778 const startText = (_a = rng.startContainer.nodeValue) !== null && _a !== void 0 ? _a : ''; 23779 const autocompleters = filter$5(database.lookupByTrigger(context.trigger), autocompleter => context.text.length >= autocompleter.minChars && autocompleter.matches.getOrThunk(() => isStartOfWord(editor.dom))(context.range, startText, context.text)); 23780 if (autocompleters.length === 0) { 23781 return Optional.none(); 23782 } 23783 const lookupData = Promise.all(map$3(autocompleters, ac => { 23784 const fetchResult = ac.fetch(context.text, ac.maxResults, fetchOptions); 23785 return fetchResult.then(results => ({ 23786 matchText: context.text, 23787 items: results, 23788 columns: ac.columns, 23789 onAction: ac.onAction, 23790 highlightOn: ac.highlightOn 23791 })); 23792 })); 23793 return Optional.some({ 23794 lookupData, 23795 context 23796 }); 23797 }; 23798 23799 var SimpleResultType; 23800 (function (SimpleResultType) { 23801 SimpleResultType[SimpleResultType['Error'] = 0] = 'Error'; 23802 SimpleResultType[SimpleResultType['Value'] = 1] = 'Value'; 23803 }(SimpleResultType || (SimpleResultType = {}))); 23804 const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue); 23805 const partition = results => { 23806 const values = []; 23807 const errors = []; 23808 each$e(results, obj => { 23809 fold$1(obj, err => errors.push(err), val => values.push(val)); 23810 }); 23811 return { 23812 values, 23813 errors 23814 }; 23815 }; 23816 const mapError = (res, f) => { 23817 if (res.stype === SimpleResultType.Error) { 23818 return { 23819 stype: SimpleResultType.Error, 23820 serror: f(res.serror) 23821 }; 23822 } else { 23823 return res; 23824 } 23825 }; 23826 const map = (res, f) => { 23827 if (res.stype === SimpleResultType.Value) { 23828 return { 23829 stype: SimpleResultType.Value, 23830 svalue: f(res.svalue) 23831 }; 23832 } else { 23833 return res; 23834 } 23835 }; 23836 const bind$1 = (res, f) => { 23837 if (res.stype === SimpleResultType.Value) { 23838 return f(res.svalue); 23839 } else { 23840 return res; 23841 } 23842 }; 23843 const bindError = (res, f) => { 23844 if (res.stype === SimpleResultType.Error) { 23845 return f(res.serror); 23846 } else { 23847 return res; 23848 } 23849 }; 23850 const svalue = v => ({ 23851 stype: SimpleResultType.Value, 23852 svalue: v 23853 }); 23854 const serror = e => ({ 23855 stype: SimpleResultType.Error, 23856 serror: e 23857 }); 23858 const toResult = res => fold$1(res, Result.error, Result.value); 23859 const fromResult = res => res.fold(serror, svalue); 23860 const SimpleResult = { 23861 fromResult, 23862 toResult, 23863 svalue, 23864 partition, 23865 serror, 23866 bind: bind$1, 23867 bindError, 23868 map, 23869 mapError, 23870 fold: fold$1 23871 }; 23872 23873 const formatObj = input => { 23874 return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2); 23875 }; 23876 const formatErrors = errors => { 23877 const es = errors.length > 10 ? errors.slice(0, 10).concat([{ 23878 path: [], 23879 getErrorInfo: constant('... (only showing first ten failures)') 23880 }]) : errors; 23881 return map$3(es, e => { 23882 return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo(); 23883 }); 23884 }; 23885 23886 const nu = (path, getErrorInfo) => { 23887 return SimpleResult.serror([{ 23888 path, 23889 getErrorInfo 23890 }]); 23891 }; 23892 const missingRequired = (path, key, obj) => nu(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj)); 23893 const missingKey = (path, key) => nu(path, () => 'Choice schema did not contain choice key: "' + key + '"'); 23894 const missingBranch = (path, branches, branch) => nu(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches)); 23895 const custom = (path, err) => nu(path, constant(err)); 23896 23897 const chooseFrom = (path, input, branches, ch) => { 23898 const fields = get$a(branches, ch); 23899 return fields.fold(() => missingBranch(path, branches, ch), vp => vp.extract(path.concat(['branch: ' + ch]), input)); 23900 }; 23901 const choose$1 = (key, branches) => { 23902 const extract = (path, input) => { 23903 const choice = get$a(input, key); 23904 return choice.fold(() => missingKey(path, key), chosen => chooseFrom(path, input, branches, chosen)); 23905 }; 23906 const toString = () => 'chooseOn(' + key + '). Possible values: ' + keys(branches); 23907 return { 23908 extract, 23909 toString 23910 }; 23911 }; 23912 23913 const shallow = (old, nu) => { 23914 return nu; 23915 }; 23916 const deep = (old, nu) => { 23917 const bothObjects = isPlainObject(old) && isPlainObject(nu); 23918 return bothObjects ? deepMerge(old, nu) : nu; 23919 }; 23920 const baseMerge = merger => { 23921 return (...objects) => { 23922 if (objects.length === 0) { 23923 throw new Error(`Can't merge zero objects`); 23924 } 23925 const ret = {}; 23926 for (let j = 0; j < objects.length; j++) { 23927 const curObject = objects[j]; 23928 for (const key in curObject) { 23929 if (has$2(curObject, key)) { 23930 ret[key] = merger(ret[key], curObject[key]); 23931 } 23932 } 23933 } 23934 return ret; 23935 }; 23936 }; 23937 const deepMerge = baseMerge(deep); 23938 const merge = baseMerge(shallow); 23939 23940 const required = () => ({ 23941 tag: 'required', 23942 process: {} 23943 }); 23944 const defaultedThunk = fallbackThunk => ({ 23945 tag: 'defaultedThunk', 23946 process: fallbackThunk 23947 }); 23948 const defaulted$1 = fallback => defaultedThunk(constant(fallback)); 23949 const asOption = () => ({ 23950 tag: 'option', 23951 process: {} 23952 }); 23953 23954 const mergeValues = (values, base) => values.length > 0 ? SimpleResult.svalue(deepMerge(base, merge.apply(undefined, values))) : SimpleResult.svalue(base); 23955 const mergeErrors = errors => compose(SimpleResult.serror, flatten)(errors); 23956 const consolidateObj = (objects, base) => { 23957 const partition = SimpleResult.partition(objects); 23958 return partition.errors.length > 0 ? mergeErrors(partition.errors) : mergeValues(partition.values, base); 23959 }; 23960 const consolidateArr = objects => { 23961 const partitions = SimpleResult.partition(objects); 23962 return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : SimpleResult.svalue(partitions.values); 23963 }; 23964 const ResultCombine = { 23965 consolidateObj, 23966 consolidateArr 23967 }; 23968 23969 const field$1 = (key, newKey, presence, prop) => ({ 23970 tag: 'field', 23971 key, 23972 newKey, 23973 presence, 23974 prop 23975 }); 23976 const customField$1 = (newKey, instantiator) => ({ 23977 tag: 'custom', 23978 newKey, 23979 instantiator 23980 }); 23981 const fold = (value, ifField, ifCustom) => { 23982 switch (value.tag) { 23983 case 'field': 23984 return ifField(value.key, value.newKey, value.presence, value.prop); 23985 case 'custom': 23986 return ifCustom(value.newKey, value.instantiator); 23987 } 23988 }; 23989 23990 const value = validator => { 23991 const extract = (path, val) => { 23992 return SimpleResult.bindError(validator(val), err => custom(path, err)); 23993 }; 23994 const toString = constant('val'); 23995 return { 23996 extract, 23997 toString 23998 }; 23999 }; 24000 const anyValue$1 = value(SimpleResult.svalue); 24001 24002 const requiredAccess = (path, obj, key, bundle) => get$a(obj, key).fold(() => missingRequired(path, key, obj), bundle); 24003 const fallbackAccess = (obj, key, fallback, bundle) => { 24004 const v = get$a(obj, key).getOrThunk(() => fallback(obj)); 24005 return bundle(v); 24006 }; 24007 const optionAccess = (obj, key, bundle) => bundle(get$a(obj, key)); 24008 const optionDefaultedAccess = (obj, key, fallback, bundle) => { 24009 const opt = get$a(obj, key).map(val => val === true ? fallback(obj) : val); 24010 return bundle(opt); 24011 }; 24012 const extractField = (field, path, obj, key, prop) => { 24013 const bundle = av => prop.extract(path.concat([key]), av); 24014 const bundleAsOption = optValue => optValue.fold(() => SimpleResult.svalue(Optional.none()), ov => { 24015 const result = prop.extract(path.concat([key]), ov); 24016 return SimpleResult.map(result, Optional.some); 24017 }); 24018 switch (field.tag) { 24019 case 'required': 24020 return requiredAccess(path, obj, key, bundle); 24021 case 'defaultedThunk': 24022 return fallbackAccess(obj, key, field.process, bundle); 24023 case 'option': 24024 return optionAccess(obj, key, bundleAsOption); 24025 case 'defaultedOptionThunk': 24026 return optionDefaultedAccess(obj, key, field.process, bundleAsOption); 24027 case 'mergeWithThunk': { 24028 return fallbackAccess(obj, key, constant({}), v => { 24029 const result = deepMerge(field.process(obj), v); 24030 return bundle(result); 24031 }); 24032 } 24033 } 24034 }; 24035 const extractFields = (path, obj, fields) => { 24036 const success = {}; 24037 const errors = []; 24038 for (const field of fields) { 24039 fold(field, (key, newKey, presence, prop) => { 24040 const result = extractField(presence, path, obj, key, prop); 24041 SimpleResult.fold(result, err => { 24042 errors.push(...err); 24043 }, res => { 24044 success[newKey] = res; 24045 }); 24046 }, (newKey, instantiator) => { 24047 success[newKey] = instantiator(obj); 24048 }); 24049 } 24050 return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success); 24051 }; 24052 const objOf = values => { 24053 const extract = (path, o) => extractFields(path, o, values); 24054 const toString = () => { 24055 const fieldStrings = map$3(values, value => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')')); 24056 return 'obj{\n' + fieldStrings.join('\n') + '}'; 24057 }; 24058 return { 24059 extract, 24060 toString 24061 }; 24062 }; 24063 const arrOf = prop => { 24064 const extract = (path, array) => { 24065 const results = map$3(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a)); 24066 return ResultCombine.consolidateArr(results); 24067 }; 24068 const toString = () => 'array(' + prop.toString() + ')'; 24069 return { 24070 extract, 24071 toString 24072 }; 24073 };
vendor: 1,298 bytes, lines 24074-24109
24074 const oneOf = (props, rawF) => { 24075 const f = rawF !== undefined ? rawF : identity; 24076 const extract = (path, val) => { 24077 const errors = []; 24078 for (const prop of props) { 24079 const res = prop.extract(path, val); 24080 if (res.stype === SimpleResultType.Value) { 24081 return { 24082 stype: SimpleResultType.Value, 24083 svalue: f(res.svalue) 24084 }; 24085 } 24086 errors.push(res); 24087 } 24088 return ResultCombine.consolidateArr(errors); 24089 }; 24090 const toString = () => 'oneOf(' + map$3(props, prop => prop.toString()).join(', ') + ')'; 24091 return { 24092 extract, 24093 toString 24094 }; 24095 }; 24096 const arrOfObj = compose(arrOf, objOf); 24097 24098 const valueOf = validator => value(v => validator(v).fold(SimpleResult.serror, SimpleResult.svalue)); 24099 const extractValue = (label, prop, obj) => { 24100 const res = prop.extract([label], obj); 24101 return SimpleResult.mapError(res, errs => ({ 24102 input: obj, 24103 errors: errs 24104 })); 24105 }; 24106 const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj)); 24107 const formatError = errInfo => { 24108 return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input); 24109 };
24110 const choose = (key, branches) => choose$1(key, map$2(branches, objOf)); 24111 24112 const anyValue = constant(anyValue$1); 24113 const typedValue = (validator, expectedType) => value(a => { 24114 const actualType = typeof a; 24115 return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${ expectedType } but got: ${ actualType }`); 24116 }); 24117 const number = typedValue(isNumber, 'number'); 24118 const string = typedValue(isString, 'string'); 24119 const boolean = typedValue(isBoolean, 'boolean'); 24120 const functionProcessor = typedValue(isFunction, 'function'); 24121 24122 const field = field$1; 24123 const customField = customField$1; 24124 const validateEnum = values => valueOf(value => contains$2(values, value) ? Result.value(value) : Result.error(`Unsupported value: "${ value }", choose one of "${ values.join(', ') }".`)); 24125 const requiredOf = (key, schema) => field(key, key, required(), schema); 24126 const requiredString = key => requiredOf(key, string); 24127 const requiredStringEnum = (key, values) => field(key, key, required(), validateEnum(values)); 24128 const requiredFunction = key => requiredOf(key, functionProcessor); 24129 const requiredArrayOf = (key, schema) => field(key, key, required(), arrOf(schema)); 24130 const optionOf = (key, schema) => field(key, key, asOption(), schema); 24131 const optionString = key => optionOf(key, string); 24132 const optionFunction = key => optionOf(key, functionProcessor); 24133 const defaulted = (key, fallback) => field(key, key, defaulted$1(fallback), anyValue()); 24134 const defaultedOf = (key, fallback, schema) => field(key, key, defaulted$1(fallback), schema); 24135 const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number); 24136 const defaultedString = (key, fallback) => defaultedOf(key, fallback, string); 24137 const defaultedStringEnum = (key, fallback, values) => defaultedOf(key, fallback, validateEnum(values)); 24138 const defaultedBoolean = (key, fallback) => defaultedOf(key, fallback, boolean); 24139 const defaultedFunction = (key, fallback) => defaultedOf(key, fallback, functionProcessor); 24140 const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema)); 24141 24142 const type = requiredString('type'); 24143 const fetch$1 = requiredFunction('fetch'); 24144 const onAction = requiredFunction('onAction'); 24145 const onSetup = defaultedFunction('onSetup', () => noop); 24146 const optionalText = optionString('text'); 24147 const optionalIcon = optionString('icon'); 24148 const optionalTooltip = optionString('tooltip'); 24149 const optionalLabel = optionString('label'); 24150 const active = defaultedBoolean('active', false); 24151 const enabled = defaultedBoolean('enabled', true); 24152 const primary = defaultedBoolean('primary', false); 24153 const defaultedColumns = num => defaulted('columns', num); 24154 const defaultedType = type => defaultedString('type', type); 24155 24156 const autocompleterSchema = objOf([ 24157 type, 24158 requiredString('trigger'), 24159 defaultedNumber('minChars', 1), 24160 defaultedColumns(1), 24161 defaultedNumber('maxResults', 10), 24162 optionFunction('matches'), 24163 fetch$1, 24164 onAction, 24165 defaultedArrayOf('highlightOn', [], string) 24166 ]); 24167 const createAutocompleter = spec => asRaw('Autocompleter', autocompleterSchema, spec); 24168 24169 const baseToolbarButtonFields = [ 24170 enabled, 24171 optionalTooltip, 24172 optionalIcon, 24173 optionalText, 24174 onSetup, 24175 defaultedString('context', 'mode:design') 24176 ]; 24177 24178 const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields); 24179 24180 const contextBarFields = [ 24181 defaultedFunction('predicate', never), 24182 defaultedStringEnum('scope', 'node', [ 24183 'node', 24184 'editor' 24185 ]), 24186 defaultedStringEnum('position', 'selection', [ 24187 'node', 24188 'selection', 24189 'line' 24190 ]) 24191 ]; 24192 24193 const contextButtonFields = baseToolbarButtonFields.concat([ 24194 defaultedType('contextformbutton'), 24195 defaultedString('align', 'end'), 24196 primary, 24197 onAction, 24198 customField('original', identity) 24199 ]); 24200 const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([ 24201 defaultedType('contextformbutton'), 24202 defaultedString('align', 'end'), 24203 primary, 24204 onAction, 24205 customField('original', identity) 24206 ]); 24207 const launchButtonFields = baseToolbarButtonFields.concat([defaultedType('contextformbutton')]); 24208 const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType('contextformtogglebutton')]); 24209 const toggleOrNormal = choose('type', { 24210 contextformbutton: contextButtonFields, 24211 contextformtogglebutton: contextToggleButtonFields 24212 }); 24213 const baseContextFormFields = [ 24214 optionalLabel, 24215 requiredArrayOf('commands', toggleOrNormal), 24216 optionOf('launch', choose('type', { 24217 contextformbutton: launchButtonFields, 24218 contextformtogglebutton: launchToggleButtonFields 24219 })), 24220 defaultedFunction('onInput', noop), 24221 defaultedFunction('onSetup', noop) 24222 ]; 24223 const contextFormFields = [ 24224 ...contextBarFields, 24225 ...baseContextFormFields, 24226 requiredStringEnum('type', ['contextform']), 24227 defaultedFunction('initValue', constant('')), 24228 optionString('placeholder') 24229 ]; 24230 const contextSliderFormFields = [ 24231 ...contextBarFields, 24232 ...baseContextFormFields, 24233 requiredStringEnum('type', ['contextsliderform']), 24234 defaultedFunction('initValue', constant(0)), 24235 defaultedFunction('min', constant(0)), 24236 defaultedFunction('max', constant(100)) 24237 ]; 24238 const contextSizeInputFormFields = [ 24239 ...contextBarFields, 24240 ...baseContextFormFields, 24241 requiredStringEnum('type', ['contextsizeinputform']), 24242 defaultedFunction('initValue', constant({ 24243 width: '', 24244 height: '' 24245 })) 24246 ];
24247 choose('type', { 24248 contextform: contextFormFields, 24249 contextsliderform: contextSliderFormFields, 24250 contextsizeinputform: contextSizeInputFormFields 24251 }); 24252 24253 objOf([ 24254 defaultedType('contexttoolbar'), 24255 requiredOf('items', oneOf([ 24256 string, 24257 arrOfObj([ 24258 optionString('name'), 24259 optionString('label'), 24260 requiredArrayOf('items', string) 24261 ]) 24262 ])) 24263 ].concat(contextBarFields)); 24264 24265 const register$2 = editor => { 24266 const popups = editor.ui.registry.getAll().popups; 24267 const dataset = map$2(popups, popup => createAutocompleter(popup).fold(err => { 24268 throw new Error(formatError(err)); 24269 }, identity)); 24270 const triggers = stringArray(mapToArray(dataset, v => v.trigger)); 24271 const datasetValues = values(dataset); 24272 const lookupByTrigger = trigger => filter$5(datasetValues, dv => dv.trigger === trigger); 24273 return { 24274 dataset, 24275 triggers, 24276 lookupByTrigger 24277 }; 24278 }; 24279 24280 const setupEditorInput = (editor, api) => { 24281 const update = last(api.load, 50); 24282 editor.on('input', e => { 24283 if (e.inputType === 'insertCompositionText' && !editor.composing) { 24284 return; 24285 } 24286 update.throttle(); 24287 }); 24288 editor.on('keydown', e => { 24289 const keyCode = e.which; 24290 if (keyCode === 8) { 24291 update.throttle(); 24292 } else if (keyCode === 27) { 24293 update.cancel(); 24294 api.cancelIfNecessary(); 24295 } else if (keyCode === 38 || keyCode === 40) { 24296 update.cancel(); 24297 } 24298 }, true); 24299 editor.on('remove', update.cancel); 24300 }; 24301 const setup$k = editor => { 24302 const activeAutocompleter = value$2(); 24303 const uiActive = Cell(false); 24304 const isActive = activeAutocompleter.isSet; 24305 const cancelIfNecessary = () => { 24306 if (isActive()) { 24307 fireAutocompleterEnd(editor); 24308 uiActive.set(false); 24309 activeAutocompleter.clear(); 24310 } 24311 }; 24312 const commenceIfNecessary = context => { 24313 if (!isActive()) { 24314 activeAutocompleter.set({ 24315 trigger: context.trigger, 24316 matchLength: context.text.length 24317 }); 24318 } 24319 }; 24320 const getAutocompleters = cached(() => register$2(editor)); 24321 const doLookup = fetchOptions => activeAutocompleter.get().map(ac => getContext(editor.dom, editor.selection.getRng(), ac.trigger, true).bind(newContext => lookupWithContext(editor, getAutocompleters, newContext, fetchOptions))).getOrThunk(() => lookup(editor, getAutocompleters)); 24322 const load = fetchOptions => { 24323 doLookup(fetchOptions).fold(cancelIfNecessary, lookupInfo => { 24324 commenceIfNecessary(lookupInfo.context); 24325 lookupInfo.lookupData.then(lookupData => { 24326 activeAutocompleter.get().map(ac => { 24327 const context = lookupInfo.context; 24328 if (ac.trigger !== context.trigger) { 24329 return; 24330 } 24331 activeAutocompleter.set({ 24332 ...ac, 24333 matchLength: context.text.length 24334 }); 24335 if (uiActive.get()) { 24336 fireAutocompleterUpdateActiveRange(editor, { range: context.range }); 24337 fireAutocompleterUpdate(editor, { lookupData }); 24338 } else { 24339 uiActive.set(true); 24340 fireAutocompleterUpdateActiveRange(editor, { range: context.range }); 24341 fireAutocompleterStart(editor, { lookupData });
vendor: 12,939 bytes, lines 24341-24606
24341 24342 } 24343 }); 24344 }); 24345 }); 24346 }; 24347 const isRangeInsideOrEqual = (innerRange, outerRange) => { 24348 const startComparison = innerRange.compareBoundaryPoints(window.Range.START_TO_START, outerRange); 24349 const endComparison = innerRange.compareBoundaryPoints(window.Range.END_TO_END, outerRange); 24350 return startComparison >= 0 && endComparison <= 0; 24351 }; 24352 const readActiveRange = () => { 24353 return activeAutocompleter.get().bind(({trigger}) => { 24354 const selRange = editor.selection.getRng(); 24355 return getContext(editor.dom, selRange, trigger, uiActive.get()).filter(({range}) => isRangeInsideOrEqual(selRange, range)).map(({range}) => range); 24356 }); 24357 }; 24358 editor.addCommand('mceAutocompleterReload', (_ui, value) => { 24359 const fetchOptions = isObject(value) ? value.fetchOptions : {}; 24360 load(fetchOptions); 24361 }); 24362 editor.addCommand('mceAutocompleterClose', cancelIfNecessary); 24363 editor.addCommand('mceAutocompleterRefreshActiveRange', () => { 24364 readActiveRange().each(range => { 24365 fireAutocompleterUpdateActiveRange(editor, { range }); 24366 }); 24367 }); 24368 editor.editorCommands.addQueryStateHandler('mceAutoCompleterInRange', () => readActiveRange().isSome()); 24369 setupEditorInput(editor, { 24370 cancelIfNecessary, 24371 load 24372 }); 24373 }; 24374 24375 const browser$1 = detect$1().browser; 24376 const isSafari = browser$1.isSafari(); 24377 const emptyNodeContents = node => fillWithPaddingBr(SugarElement.fromDom(node)); 24378 const isEntireNodeSelected = (rng, node) => { 24379 var _a; 24380 return rng.startOffset === 0 && rng.endOffset === ((_a = node.textContent) === null || _a === void 0 ? void 0 : _a.length); 24381 }; 24382 const getParentDetailsElementAtPos = (dom, pos) => Optional.from(dom.getParent(pos.container(), 'details')); 24383 const isInDetailsElement = (dom, pos) => getParentDetailsElementAtPos(dom, pos).isSome(); 24384 const getDetailsElements = (dom, rng) => { 24385 const startDetails = Optional.from(dom.getParent(rng.startContainer, 'details')); 24386 const endDetails = Optional.from(dom.getParent(rng.endContainer, 'details')); 24387 if (startDetails.isSome() || endDetails.isSome()) { 24388 const startSummary = startDetails.bind(details => Optional.from(dom.select('summary', details)[0])); 24389 return Optional.some({ 24390 startSummary, 24391 startDetails, 24392 endDetails 24393 }); 24394 } else { 24395 return Optional.none(); 24396 } 24397 }; 24398 const isCaretInTheBeginningOf = (caretPos, element) => firstPositionIn(element).exists(pos => pos.isEqual(caretPos)); 24399 const isCaretInTheEndOf = (caretPos, element) => { 24400 return lastPositionIn(element).exists(pos => { 24401 if (isBr$6(pos.getNode())) { 24402 return prevPosition(element, pos).exists(pos2 => pos2.isEqual(caretPos)) || pos.isEqual(caretPos); 24403 } else { 24404 return pos.isEqual(caretPos); 24405 } 24406 }); 24407 }; 24408 const isCaretAtStartOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheBeginningOf(caretPos, summary)); 24409 const isCaretAtEndOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheEndOf(caretPos, summary)); 24410 const isCaretInFirstPositionInBody = (caretPos, detailsElements) => detailsElements.startDetails.exists(details => prevPosition(details, caretPos).forall(pos => detailsElements.startSummary.exists(summary => !summary.contains(caretPos.container()) && summary.contains(pos.container())))); 24411 const isCaretInLastPositionInBody = (root, caretPos, detailsElements) => detailsElements.startDetails.exists(details => nextPosition(root, caretPos).forall(pos => !details.contains(pos.container()))); 24412 const setCaretToPosition = (editor, position) => { 24413 const node = position.getNode(); 24414 if (!isUndefined(node)) { 24415 editor.selection.setCursorLocation(node, position.offset()); 24416 } 24417 }; 24418 const moveCaretToDetailsPos = (editor, pos, forward) => { 24419 const details = editor.dom.getParent(pos.container(), 'details'); 24420 if (details && !details.open) { 24421 const summary = editor.dom.select('summary', details)[0]; 24422 if (summary) { 24423 const newPos = forward ? firstPositionIn(summary) : lastPositionIn(summary); 24424 newPos.each(pos => setCaretToPosition(editor, pos)); 24425 } 24426 } else { 24427 setCaretToPosition(editor, pos); 24428 } 24429 }; 24430 const isPartialDelete = (rng, detailsElements) => { 24431 const containsStart = element => element.contains(rng.startContainer); 24432 const containsEnd = element => element.contains(rng.endContainer); 24433 const startInSummary = detailsElements.startSummary.exists(containsStart); 24434 const endInSummary = detailsElements.startSummary.exists(containsEnd); 24435 const isPartiallySelectedDetailsElements = detailsElements.startDetails.forall(startDetails => detailsElements.endDetails.forall(endDetails => startDetails !== endDetails)); 24436 const isInPartiallySelectedSummary = (startInSummary || endInSummary) && !(startInSummary && endInSummary); 24437 return isInPartiallySelectedSummary || isPartiallySelectedDetailsElements; 24438 }; 24439 const shouldPreventDeleteIntoDetails = (editor, forward, granularity) => { 24440 const {dom, selection} = editor; 24441 const root = editor.getBody(); 24442 if (granularity === 'character') { 24443 const caretPos = CaretPosition.fromRangeStart(selection.getRng()); 24444 const parentBlock = dom.getParent(caretPos.container(), dom.isBlock); 24445 const parentDetailsAtCaret = getParentDetailsElementAtPos(dom, caretPos); 24446 const inEmptyParentBlock = parentBlock && dom.isEmpty(parentBlock); 24447 const isFirstBlock = isNull(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.previousSibling); 24448 const isLastBlock = isNull(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.nextSibling); 24449 if (inEmptyParentBlock) { 24450 const firstOrLast = forward ? isLastBlock : isFirstBlock; 24451 if (firstOrLast) { 24452 const isBeforeAfterDetails = navigate(!forward, root, caretPos).exists(pos => { 24453 return isInDetailsElement(dom, pos) && !equals(parentDetailsAtCaret, getParentDetailsElementAtPos(dom, pos)); 24454 }); 24455 if (isBeforeAfterDetails) { 24456 return true; 24457 } 24458 } 24459 } 24460 return navigate(forward, root, caretPos).fold(never, pos => { 24461 const parentDetailsAtNewPos = getParentDetailsElementAtPos(dom, pos); 24462 if (isInDetailsElement(dom, pos) && !equals(parentDetailsAtCaret, parentDetailsAtNewPos)) { 24463 if (!forward) { 24464 moveCaretToDetailsPos(editor, pos, false); 24465 } 24466 if (parentBlock && inEmptyParentBlock) { 24467 if (forward && isFirstBlock) { 24468 return true; 24469 } else if (!forward && isLastBlock) { 24470 return true; 24471 } 24472 moveCaretToDetailsPos(editor, pos, forward); 24473 editor.dom.remove(parentBlock); 24474 } 24475 return true; 24476 } else { 24477 return false; 24478 } 24479 }); 24480 } else { 24481 return false; 24482 } 24483 }; 24484 const shouldPreventDeleteSummaryAction = (editor, detailElements, forward, granularity) => { 24485 const selection = editor.selection; 24486 const rng = selection.getRng(); 24487 const caretPos = CaretPosition.fromRangeStart(rng); 24488 const root = editor.getBody(); 24489 if (granularity === 'selection') { 24490 return isPartialDelete(rng, detailElements); 24491 } else if (forward) { 24492 return isCaretAtEndOfSummary(caretPos, detailElements) || isCaretInLastPositionInBody(root, caretPos, detailElements); 24493 } else { 24494 return isCaretAtStartOfSummary(caretPos, detailElements) || isCaretInFirstPositionInBody(caretPos, detailElements); 24495 } 24496 }; 24497 const shouldPreventDeleteAction = (editor, forward, granularity) => getDetailsElements(editor.dom, editor.selection.getRng()).fold(() => shouldPreventDeleteIntoDetails(editor, forward, granularity), detailsElements => shouldPreventDeleteSummaryAction(editor, detailsElements, forward, granularity) || shouldPreventDeleteIntoDetails(editor, forward, granularity)); 24498 const handleDeleteActionSafari = (editor, forward, granularity) => { 24499 const selection = editor.selection; 24500 const node = selection.getNode(); 24501 const rng = selection.getRng(); 24502 const caretPos = CaretPosition.fromRangeStart(rng); 24503 if (isSummary$1(node)) { 24504 if (granularity === 'selection' && isEntireNodeSelected(rng, node) || willDeleteLastPositionInElement(forward, caretPos, node)) { 24505 emptyNodeContents(node); 24506 } else { 24507 editor.undoManager.transact(() => { 24508 const sel = selection.getSel(); 24509 let {anchorNode, anchorOffset, focusNode, focusOffset} = sel !== null && sel !== void 0 ? sel : {}; 24510 const applySelection = () => { 24511 if (isNonNullable(anchorNode) && isNonNullable(anchorOffset) && isNonNullable(focusNode) && isNonNullable(focusOffset)) { 24512 sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset); 24513 } 24514 }; 24515 const updateSelection = () => { 24516 anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode; 24517 anchorOffset = sel === null || sel === void 0 ? void 0 : sel.anchorOffset; 24518 focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode; 24519 focusOffset = sel === null || sel === void 0 ? void 0 : sel.focusOffset; 24520 }; 24521 const appendAllChildNodes = (from, to) => { 24522 each$e(from.childNodes, child => { 24523 if (isNode(child)) { 24524 to.appendChild(child); 24525 } 24526 }); 24527 }; 24528 const container = editor.dom.create('span', { 'data-mce-bogus': '1' }); 24529 appendAllChildNodes(node, container); 24530 node.appendChild(container); 24531 applySelection(); 24532 if (granularity === 'word' || granularity === 'line') { 24533 sel === null || sel === void 0 ? void 0 : sel.modify('extend', forward ? 'right' : 'left', granularity); 24534 } 24535 if (!selection.isCollapsed() && isEntireNodeSelected(selection.getRng(), container)) { 24536 emptyNodeContents(node); 24537 } else { 24538 editor.execCommand(forward ? 'ForwardDelete' : 'Delete'); 24539 updateSelection(); 24540 appendAllChildNodes(container, node); 24541 applySelection(); 24542 } 24543 editor.dom.remove(container); 24544 }); 24545 } 24546 return true; 24547 } else { 24548 return false; 24549 } 24550 }; 24551 const backspaceDelete = (editor, forward, granularity) => shouldPreventDeleteAction(editor, forward, granularity) || isSafari && handleDeleteActionSafari(editor, forward, granularity) ? Optional.some(noop) : Optional.none(); 24552 24553 const createAndFireInputEvent = eventType => (editor, inputType, specifics = {}) => { 24554 const target = editor.getBody(); 24555 const overrides = { 24556 bubbles: true, 24557 composed: true, 24558 data: null, 24559 isComposing: false, 24560 detail: 0, 24561 view: null, 24562 target, 24563 currentTarget: target, 24564 eventPhase: Event.AT_TARGET, 24565 originalTarget: target, 24566 explicitOriginalTarget: target, 24567 isTrusted: false, 24568 srcElement: target, 24569 cancelable: false, 24570 preventDefault: noop, 24571 inputType 24572 }; 24573 const input = clone$3(new InputEvent(eventType)); 24574 return editor.dispatch(eventType, { 24575 ...input, 24576 ...overrides, 24577 ...specifics 24578 }); 24579 }; 24580 const fireInputEvent = createAndFireInputEvent('input'); 24581 const fireBeforeInputEvent = createAndFireInputEvent('beforeinput'); 24582 24583 const platform$2 = detect$1(); 24584 const os = platform$2.os; 24585 const isMacOSOriOS = os.isMacOS() || os.isiOS(); 24586 const browser = platform$2.browser; 24587 const isFirefox = browser.isFirefox(); 24588 const executeKeydownOverride$3 = (editor, caret, evt) => { 24589 const inputType = evt.keyCode === VK.BACKSPACE ? 'deleteContentBackward' : 'deleteContentForward'; 24590 const isCollapsed = editor.selection.isCollapsed(); 24591 const unmodifiedGranularity = isCollapsed ? 'character' : 'selection'; 24592 const getModifiedGranularity = isWord => { 24593 if (isCollapsed) { 24594 return isWord ? 'word' : 'line'; 24595 } else { 24596 return 'selection'; 24597 } 24598 }; 24599 executeWithDelayedAction([ 24600 { 24601 keyCode: VK.BACKSPACE, 24602 action: action(backspaceDelete$1, editor) 24603 }, 24604 { 24605 keyCode: VK.BACKSPACE, 24606 action: action(backspaceDelete$
vendor: 3,309 bytes, lines 24606-24718
246067, editor, false) 24607 }, 24608 { 24609 keyCode: VK.DELETE, 24610 action: action(backspaceDelete$7, editor, true) 24611 }, 24612 { 24613 keyCode: VK.BACKSPACE, 24614 action: action(backspaceDelete$8, editor, false) 24615 }, 24616 { 24617 keyCode: VK.DELETE, 24618 action: action(backspaceDelete$8, editor, true) 24619 }, 24620 { 24621 keyCode: VK.BACKSPACE, 24622 action: action(backspaceDelete$4, editor, caret, false) 24623 }, 24624 { 24625 keyCode: VK.DELETE, 24626 action: action(backspaceDelete$4, editor, caret, true) 24627 }, 24628 { 24629 keyCode: VK.BACKSPACE, 24630 action: action(backspaceDelete$b, editor, false) 24631 }, 24632 { 24633 keyCode: VK.DELETE, 24634 action: action(backspaceDelete$b, editor, true) 24635 }, 24636 { 24637 keyCode: VK.BACKSPACE, 24638 action: action(backspaceDelete, editor, false, unmodifiedGranularity) 24639 }, 24640 { 24641 keyCode: VK.DELETE, 24642 action: action(backspaceDelete, editor, true, unmodifiedGranularity) 24643 }, 24644 ...isMacOSOriOS ? [ 24645 { 24646 keyCode: VK.BACKSPACE, 24647 altKey: true, 24648 action: action(backspaceDelete, editor, false, getModifiedGranularity(true)) 24649 }, 24650 { 24651 keyCode: VK.DELETE, 24652 altKey: true, 24653 action: action(backspaceDelete, editor, true, getModifiedGranularity(true)) 24654 }, 24655 { 24656 keyCode: VK.BACKSPACE, 24657 metaKey: true, 24658 action: action(backspaceDelete, editor, false, getModifiedGranularity(false)) 24659 } 24660 ] : [ 24661 { 24662 keyCode: VK.BACKSPACE, 24663 ctrlKey: true, 24664 action: action(backspaceDelete, editor, false, getModifiedGranularity(true)) 24665 }, 24666 { 24667 keyCode: VK.DELETE, 24668 ctrlKey: true, 24669 action: action(backspaceDelete, editor, true, getModifiedGranularity(true)) 24670 } 24671 ], 24672 { 24673 keyCode: VK.BACKSPACE, 24674 action: action(backspaceDelete$5, editor, false) 24675 }, 24676 { 24677 keyCode: VK.DELETE, 24678 action: action(backspaceDelete$5, editor, true) 24679 }, 24680 { 24681 keyCode: VK.BACKSPACE, 24682 action: action(backspaceDelete$2, editor, false) 24683 }, 24684 { 24685 keyCode: VK.DELETE, 24686 action: action(backspaceDelete$2, editor, true) 24687 }, 24688 { 24689 keyCode: VK.BACKSPACE, 24690 action: action(backspaceDelete$9, editor, false) 24691 }, 24692 { 24693 keyCode: VK.DELETE, 24694 action: action(backspaceDelete$9, editor, true) 24695 }, 24696 { 24697 keyCode: VK.BACKSPACE, 24698 action: action(backspaceDelete$a, editor, false) 24699 }, 24700 { 24701 keyCode: VK.DELETE, 24702 action: action(backspaceDelete$a, editor, true) 24703 }, 24704 { 24705 keyCode: VK.BACKSPACE, 24706 action: action(backspaceDelete$3, editor, false) 24707 }, 24708 { 24709 keyCode: VK.DELETE, 24710 action: action(backspaceDelete$3, editor, true) 24711 }, 24712 { 24713 keyCode: VK.BACKSPACE, 24714 action: action(backspaceDelete$6, editor, false) 24715 }, 24716 { 24717 keyCode: VK.DELETE, 24718 action: action(backspaceDelete$6
vendor: 14,095 bytes, lines 24718-25081
24718, editor, true) 24719 } 24720 ], evt).filter(_ => editor.selection.isEditable()).each(applyAction => { 24721 evt.preventDefault(); 24722 const beforeInput = fireBeforeInputEvent(editor, inputType); 24723 if (!beforeInput.isDefaultPrevented()) { 24724 applyAction(); 24725 fireInputEvent(editor, inputType); 24726 } 24727 }); 24728 }; 24729 const executeKeyupOverride = (editor, evt, isBackspaceKeydown) => execute([ 24730 { 24731 keyCode: VK.BACKSPACE, 24732 action: action(paddEmptyElement, editor) 24733 }, 24734 { 24735 keyCode: VK.DELETE, 24736 action: action(paddEmptyElement, editor) 24737 }, 24738 ...isMacOSOriOS ? [ 24739 { 24740 keyCode: VK.BACKSPACE, 24741 altKey: true, 24742 action: action(refreshCaret, editor) 24743 }, 24744 { 24745 keyCode: VK.DELETE, 24746 altKey: true, 24747 action: action(refreshCaret, editor) 24748 }, 24749 ...isBackspaceKeydown ? [{ 24750 keyCode: isFirefox ? 224 : 91, 24751 action: action(refreshCaret, editor) 24752 }] : [] 24753 ] : [ 24754 { 24755 keyCode: VK.BACKSPACE, 24756 ctrlKey: true, 24757 action: action(refreshCaret, editor) 24758 }, 24759 { 24760 keyCode: VK.DELETE, 24761 ctrlKey: true, 24762 action: action(refreshCaret, editor) 24763 } 24764 ] 24765 ], evt); 24766 const setup$j = (editor, caret) => { 24767 let isBackspaceKeydown = false; 24768 editor.on('keydown', evt => { 24769 isBackspaceKeydown = evt.keyCode === VK.BACKSPACE; 24770 if (!evt.isDefaultPrevented()) { 24771 executeKeydownOverride$3(editor, caret, evt); 24772 } 24773 }); 24774 editor.on('keyup', evt => { 24775 if (!evt.isDefaultPrevented()) { 24776 executeKeyupOverride(editor, evt, isBackspaceKeydown); 24777 } 24778 isBackspaceKeydown = false; 24779 }); 24780 }; 24781 24782 const firstNonWhiteSpaceNodeSibling = node => { 24783 while (node) { 24784 if (isElement$6(node) || isText$b(node) && node.data && /[\r\n\s]/.test(node.data)) { 24785 return node; 24786 } 24787 node = node.nextSibling; 24788 } 24789 return null; 24790 }; 24791 const moveToCaretPosition = (editor, root) => { 24792 const dom = editor.dom; 24793 const moveCaretBeforeOnEnterElementsMap = editor.schema.getMoveCaretBeforeOnEnterElements(); 24794 if (!root) { 24795 return; 24796 } 24797 if (/^(LI|DT|DD)$/.test(root.nodeName)) { 24798 const firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild); 24799 if (firstChild && /^(UL|OL|DL)$/.test(firstChild.nodeName)) { 24800 root.insertBefore(dom.doc.createTextNode(nbsp), root.firstChild); 24801 } 24802 } 24803 const rng = dom.createRng(); 24804 root.normalize(); 24805 if (root.hasChildNodes()) { 24806 const walker = new DomTreeWalker(root, root); 24807 let lastNode = root; 24808 let node; 24809 while (node = walker.current()) { 24810 if (isText$b(node)) { 24811 rng.setStart(node, 0); 24812 rng.setEnd(node, 0); 24813 break; 24814 } 24815 if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) { 24816 rng.setStartBefore(node); 24817 rng.setEndBefore(node); 24818 break; 24819 } 24820 lastNode = node; 24821 node = walker.next(); 24822 } 24823 if (!node) { 24824 rng.setStart(lastNode, 0); 24825 rng.setEnd(lastNode, 0); 24826 } 24827 } else { 24828 if (isBr$6(root)) { 24829 if (root.nextSibling && dom.isBlock(root.nextSibling)) { 24830 rng.setStartBefore(root); 24831 rng.setEndBefore(root); 24832 } else { 24833 rng.setStartAfter(root); 24834 rng.setEndAfter(root); 24835 } 24836 } else { 24837 rng.setStart(root, 0); 24838 rng.setEnd(root, 0); 24839 } 24840 } 24841 editor.selection.setRng(rng); 24842 scrollRangeIntoView(editor, rng); 24843 }; 24844 const getEditableRoot = (dom, node) => { 24845 const root = dom.getRoot(); 24846 let editableRoot; 24847 let parent = node; 24848 while (parent !== root && parent && dom.getContentEditable(parent) !== 'false') { 24849 if (dom.getContentEditable(parent) === 'true') { 24850 editableRoot = parent; 24851 break; 24852 } 24853 parent = parent.parentNode; 24854 } 24855 return parent !== root ? editableRoot : root; 24856 }; 24857 const getParentBlock$1 = editor => { 24858 return Optional.from(editor.dom.getParent(editor.selection.getStart(true), editor.dom.isBlock)); 24859 }; 24860 const getParentBlockName = editor => { 24861 return getParentBlock$1(editor).fold(constant(''), parentBlock => { 24862 return parentBlock.nodeName.toUpperCase(); 24863 }); 24864 }; 24865 const isListItemParentBlock = editor => { 24866 return getParentBlock$1(editor).filter(elm => { 24867 return isListItem$1(SugarElement.fromDom(elm)); 24868 }).isSome(); 24869 }; 24870 const emptyBlock = elm => { 24871 elm.innerHTML = '<br data-mce-bogus="1">'; 24872 }; 24873 const applyAttributes = (editor, node, forcedRootBlockAttrs) => { 24874 const dom = editor.dom; 24875 Optional.from(forcedRootBlockAttrs.style).map(dom.parseStyle).each(attrStyles => { 24876 const currentStyles = getAllRaw(SugarElement.fromDom(node)); 24877 const newStyles = { 24878 ...currentStyles, 24879 ...attrStyles 24880 }; 24881 dom.setStyles(node, newStyles); 24882 }); 24883 const attrClassesOpt = Optional.from(forcedRootBlockAttrs.class).map(attrClasses => attrClasses.split(/\s+/)); 24884 const currentClassesOpt = Optional.from(node.className).map(currentClasses => filter$5(currentClasses.split(/\s+/), clazz => clazz !== '')); 24885 lift2(attrClassesOpt, currentClassesOpt, (attrClasses, currentClasses) => { 24886 const filteredClasses = filter$5(currentClasses, clazz => !contains$2(attrClasses, clazz)); 24887 const newClasses = [ 24888 ...attrClasses, 24889 ...filteredClasses 24890 ]; 24891 dom.setAttrib(node, 'class', newClasses.join(' ')); 24892 }); 24893 const appliedAttrs = [ 24894 'style', 24895 'class' 24896 ]; 24897 const remainingAttrs = filter$4(forcedRootBlockAttrs, (_, attrs) => !contains$2(appliedAttrs, attrs)); 24898 dom.setAttribs(node, remainingAttrs); 24899 }; 24900 const setForcedBlockAttrs = (editor, node) => { 24901 const forcedRootBlockName = getForcedRootBlock(editor); 24902 if (forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) { 24903 const forcedRootBlockAttrs = getForcedRootBlockAttrs(editor); 24904 applyAttributes(editor, node, forcedRootBlockAttrs); 24905 } 24906 }; 24907 const createNewBlock = (editor, container, parentBlock, editableRoot, keepStyles = true, name, styles) => { 24908 const dom = editor.dom; 24909 const schema = editor.schema; 24910 const newBlockName = getForcedRootBlock(editor); 24911 const parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : ''; 24912 let node = container; 24913 const textInlineElements = schema.getTextInlineElements(); 24914 let block; 24915 if (name || parentBlockName === 'TABLE' || parentBlockName === 'HR') { 24916 block = dom.create(name || newBlockName, styles || {}); 24917 } else { 24918 block = parentBlock.cloneNode(false); 24919 } 24920 let caretNode = block; 24921 if (!keepStyles) { 24922 dom.setAttrib(block, 'style', null); 24923 dom.setAttrib(block, 'class', null); 24924 } else { 24925 do { 24926 if (textInlineElements[node.nodeName]) { 24927 if (isCaretNode(node) || isBookmarkNode$1(node)) { 24928 continue; 24929 } 24930 const clonedNode = node.cloneNode(false); 24931 dom.setAttrib(clonedNode, 'id', ''); 24932 if (block.hasChildNodes()) { 24933 clonedNode.appendChild(block.firstChild); 24934 block.appendChild(clonedNode); 24935 } else { 24936 caretNode = clonedNode; 24937 block.appendChild(clonedNode); 24938 } 24939 } 24940 } while ((node = node.parentNode) && node !== editableRoot); 24941 } 24942 setForcedBlockAttrs(editor, block); 24943 emptyBlock(caretNode); 24944 return block; 24945 }; 24946 24947 const getDetailsRoot = (editor, element) => editor.dom.getParent(element, isDetails); 24948 const isAtDetailsEdge = (root, element, isTextBlock) => { 24949 let node = element; 24950 while (node && node !== root && isNull(node.nextSibling)) { 24951 const parent = node.parentElement; 24952 if (!parent || !isTextBlock(parent)) { 24953 return isDetails(parent); 24954 } 24955 node = parent; 24956 } 24957 return false; 24958 }; 24959 const isLastEmptyBlockInDetails = (editor, shiftKey, element) => !shiftKey && element.nodeName.toLowerCase() === getForcedRootBlock(editor) && editor.dom.isEmpty(element) && isAtDetailsEdge(editor.getBody(), element, el => has$2(editor.schema.getTextBlockElements(), el.nodeName.toLowerCase())); 24960 const insertNewLine = (editor, createNewBlock, parentBlock) => { 24961 var _a, _b, _c; 24962 const newBlock = createNewBlock(getForcedRootBlock(editor)); 24963 const root = getDetailsRoot(editor, parentBlock); 24964 if (!root) { 24965 return; 24966 } 24967 editor.dom.insertAfter(newBlock, root); 24968 moveToCaretPosition(editor, newBlock); 24969 if (((_c = (_b = (_a = parentBlock.parentElement) === null || _a === void 0 ? void 0 : _a.childNodes) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) > 1) { 24970 editor.dom.remove(parentBlock); 24971 } 24972 }; 24973 24974 const hasFirstChild = (elm, name) => { 24975 return elm.firstChild && elm.firstChild.nodeName === name; 24976 }; 24977 const isFirstChild = elm => { 24978 var _a; 24979 return ((_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === elm; 24980 }; 24981 const hasParent = (elm, parentName) => { 24982 const parentNode = elm === null || elm === void 0 ? void 0 : elm.parentNode; 24983 return isNonNullable(parentNode) && parentNode.nodeName === parentName; 24984 }; 24985 const isListBlock = elm => { 24986 return isNonNullable(elm) && /^(OL|UL|LI)$/.test(elm.nodeName); 24987 }; 24988 const isListItem = elm => { 24989 return isNonNullable(elm) && /^(LI|DT|DD)$/.test(elm.nodeName); 24990 }; 24991 const isNestedList = elm => { 24992 return isListBlock(elm) && isListBlock(elm.parentNode); 24993 }; 24994 const getContainerBlock = containerBlock => { 24995 const containerBlockParent = containerBlock.parentNode; 24996 return isListItem(containerBlockParent) ? containerBlockParent : containerBlock; 24997 }; 24998 const isFirstOrLastLi = (containerBlock, parentBlock, first) => { 24999 let node = containerBlock[first ? 'firstChild' : 'lastChild']; 25000 while (node) { 25001 if (isElement$6(node)) { 25002 break; 25003 } 25004 node = node[first ? 'nextSibling' : 'previousSibling']; 25005 } 25006 return node === parentBlock; 25007 }; 25008 const getStyles = elm => foldl(mapToArray(getAllRaw(SugarElement.fromDom(elm)), (style, styleName) => `${ styleName }: ${ style };`), (acc, s) => acc + s, ''); 25009 const insert$4 = (editor, createNewBlock, containerBlock, parentBlock, newBlockName) => { 25010 const dom = editor.dom; 25011 const rng = editor.selection.getRng(); 25012 const containerParent = containerBlock.parentNode; 25013 if (containerBlock === editor.getBody() || !containerParent) { 25014 return; 25015 } 25016 if (isNestedList(containerBlock)) { 25017 newBlockName = 'LI'; 25018 } 25019 const parentBlockStyles = isListItem(parentBlock) ? getStyles(parentBlock) : undefined; 25020 let newBlock = isListItem(parentBlock) && parentBlockStyles ? createNewBlock(newBlockName, { style: getStyles(parentBlock) }) : createNewBlock(newBlockName); 25021 if (isFirstOrLastLi(containerBlock, parentBlock, true) && isFirstOrLastLi(containerBlock, parentBlock, false)) { 25022 if (hasParent(containerBlock, 'LI')) { 25023 const containerBlockParent = getContainerBlock(containerBlock); 25024 dom.insertAfter(newBlock, containerBlockParent); 25025 if (isFirstChild(containerBlock)) { 25026 dom.remove(containerBlockParent); 25027 } else { 25028 dom.remove(containerBlock); 25029 } 25030 } else { 25031 dom.replace(newBlock, containerBlock); 25032 } 25033 } else if (isFirstOrLastLi(containerBlock, parentBlock, true)) { 25034 if (hasParent(containerBlock, 'LI')) { 25035 dom.insertAfter(newBlock, getContainerBlock(containerBlock)); 25036 newBlock.appendChild(dom.doc.createTextNode(' ')); 25037 newBlock.appendChild(containerBlock); 25038 } else { 25039 containerParent.insertBefore(newBlock, containerBlock); 25040 } 25041 dom.remove(parentBlock); 25042 } else if (isFirstOrLastLi(containerBlock, parentBlock, false)) { 25043 dom.insertAfter(newBlock, getContainerBlock(containerBlock)); 25044 dom.remove(parentBlock); 25045 } else { 25046 containerBlock = getContainerBlock(containerBlock); 25047 const tmpRng = rng.cloneRange(); 25048 tmpRng.setStartAfter(parentBlock); 25049 tmpRng.setEndAfter(containerBlock); 25050 const fragment = tmpRng.extractContents(); 25051 if (newBlockName === 'LI' && hasFirstChild(fragment, 'LI')) { 25052 const previousChildren = filter$5(map$3(newBlock.children, SugarElement.fromDom), not(isTag('br'))); 25053 newBlock = fragment.firstChild; 25054 dom.insertAfter(fragment, containerBlock); 25055 each$e(previousChildren, child => prepend(SugarElement.fromDom(newBlock), child)); 25056 if (parentBlockStyles) { 25057 newBlock.setAttribute('style', parentBlockStyles); 25058 } 25059 } else { 25060 dom.insertAfter(fragment, containerBlock); 25061 dom.insertAfter(newBlock, containerBlock); 25062 } 25063 dom.remove(parentBlock); 25064 } 25065 moveToCaretPosition(editor, newBlock); 25066 }; 25067 25068 const trimZwsp = fragment => { 25069 each$e(descendants$1(SugarElement.fromDom(fragment), isText$c), text => { 25070 const rawNode = text.dom; 25071 rawNode.nodeValue = trim$2(rawNode.data); 25072 }); 25073 }; 25074 const isWithinNonEditableList = (editor, node) => { 25075 const parentList = editor.dom.getParent(node, 'ol,ul,dl'); 25076 return parentList !== null && editor.dom.getContentEditableParent(parentList) === 'false'; 25077 }; 25078 const isEmptyAnchor = (dom, elm) => { 25079 return elm && elm.nodeName === 'A' && dom.isEmpty(elm); 25080 }; 25081 const containerAnd
vendor: 7,404 bytes, lines 25081-25248
25081PreviousSiblingName = (container, nodeName) => { 25082 return container.nodeName === nodeName || container.previousSibling && container.previousSibling.nodeName === nodeName; 25083 }; 25084 const containerAndNextSiblingName = (container, nodeName) => { 25085 return container.nodeName === nodeName || container.nextSibling && container.nextSibling.nodeName === nodeName; 25086 }; 25087 const canSplitBlock = (dom, node) => { 25088 return isNonNullable(node) && dom.isBlock(node) && !/^(TD|TH|CAPTION|FORM)$/.test(node.nodeName) && !/^(fixed|absolute)/i.test(node.style.position) && dom.isEditable(node.parentNode) && dom.getContentEditable(node) !== 'false'; 25089 }; 25090 const trimInlineElementsOnLeftSideOfBlock = (dom, nonEmptyElementsMap, block) => { 25091 var _a; 25092 const firstChilds = []; 25093 if (!block) { 25094 return; 25095 } 25096 let currentNode = block; 25097 while (currentNode = currentNode.firstChild) { 25098 if (dom.isBlock(currentNode)) { 25099 return; 25100 } 25101 if (isElement$6(currentNode) && !nonEmptyElementsMap[currentNode.nodeName.toLowerCase()]) { 25102 firstChilds.push(currentNode); 25103 } 25104 } 25105 let i = firstChilds.length; 25106 while (i--) { 25107 currentNode = firstChilds[i]; 25108 if (!currentNode.hasChildNodes() || currentNode.firstChild === currentNode.lastChild && ((_a = currentNode.firstChild) === null || _a === void 0 ? void 0 : _a.nodeValue) === '') { 25109 dom.remove(currentNode); 25110 } else { 25111 if (isEmptyAnchor(dom, currentNode)) { 25112 dom.remove(currentNode); 25113 } 25114 } 25115 } 25116 }; 25117 const normalizeZwspOffset = (start, container, offset) => { 25118 if (!isText$b(container)) { 25119 return offset; 25120 } else if (start) { 25121 return offset === 1 && container.data.charAt(offset - 1) === ZWSP$1 ? 0 : offset; 25122 } else { 25123 return offset === container.data.length - 1 && container.data.charAt(offset) === ZWSP$1 ? container.data.length : offset; 25124 } 25125 }; 25126 const includeZwspInRange = rng => { 25127 const newRng = rng.cloneRange(); 25128 newRng.setStart(rng.startContainer, normalizeZwspOffset(true, rng.startContainer, rng.startOffset)); 25129 newRng.setEnd(rng.endContainer, normalizeZwspOffset(false, rng.endContainer, rng.endOffset)); 25130 return newRng; 25131 }; 25132 const trimLeadingLineBreaks = node => { 25133 let currentNode = node; 25134 do { 25135 if (isText$b(currentNode)) { 25136 currentNode.data = currentNode.data.replace(/^[\r\n]+/, ''); 25137 } 25138 currentNode = currentNode.firstChild; 25139 } while (currentNode); 25140 }; 25141 const wrapSelfAndSiblingsInDefaultBlock = (editor, newBlockName, rng, container, offset) => { 25142 var _a, _b; 25143 const dom = editor.dom; 25144 const editableRoot = (_a = getEditableRoot(dom, container)) !== null && _a !== void 0 ? _a : dom.getRoot(); 25145 let parentBlock = dom.getParent(container, dom.isBlock); 25146 if (!parentBlock || !canSplitBlock(dom, parentBlock)) { 25147 parentBlock = parentBlock || editableRoot; 25148 if (!parentBlock.hasChildNodes()) { 25149 const newBlock = dom.create(newBlockName); 25150 setForcedBlockAttrs(editor, newBlock); 25151 parentBlock.appendChild(newBlock); 25152 rng.setStart(newBlock, 0); 25153 rng.setEnd(newBlock, 0); 25154 return newBlock; 25155 } 25156 let node = container; 25157 while (node && node.parentNode !== parentBlock) { 25158 node = node.parentNode; 25159 } 25160 let startNode; 25161 while (node && !dom.isBlock(node)) { 25162 startNode = node; 25163 node = node.previousSibling; 25164 } 25165 const startNodeName = (_b = startNode === null || startNode === void 0 ? void 0 : startNode.parentElement) === null || _b === void 0 ? void 0 : _b.nodeName; 25166 if (startNode && startNodeName && editor.schema.isValidChild(startNodeName, newBlockName.toLowerCase())) { 25167 const startNodeParent = startNode.parentNode; 25168 const newBlock = dom.create(newBlockName); 25169 setForcedBlockAttrs(editor, newBlock); 25170 startNodeParent.insertBefore(newBlock, startNode); 25171 node = startNode; 25172 while (node && !dom.isBlock(node)) { 25173 const next = node.nextSibling; 25174 newBlock.appendChild(node); 25175 node = next; 25176 } 25177 rng.setStart(container, offset); 25178 rng.setEnd(container, offset); 25179 } 25180 } 25181 return container; 25182 }; 25183 const addBrToBlockIfNeeded = (dom, block) => { 25184 block.normalize(); 25185 const lastChild = block.lastChild; 25186 if (!lastChild || isElement$6(lastChild) && /^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true))) { 25187 dom.add(block, 'br'); 25188 } 25189 }; 25190 const shouldEndContainer = (editor, container) => { 25191 const optionValue = shouldEndContainerOnEmptyBlock(editor); 25192 if (isNullable(container)) { 25193 return false; 25194 } else if (isString(optionValue)) { 25195 return contains$2(Tools.explode(optionValue), container.nodeName.toLowerCase()); 25196 } else { 25197 return optionValue; 25198 } 25199 }; 25200 const insert$3 = (editor, evt) => { 25201 let container; 25202 let offset; 25203 let parentBlockName; 25204 let containerBlock; 25205 let isAfterLastNodeInContainer = false; 25206 const dom = editor.dom; 25207 const schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements(); 25208 const rng = editor.selection.getRng(); 25209 const newBlockName = getForcedRootBlock(editor); 25210 const start = SugarElement.fromDom(rng.startContainer); 25211 const child = child$1(start, rng.startOffset); 25212 const isCef = child.exists(element => isHTMLElement$1(element) && !isEditable$2(element)); 25213 const collapsedAndCef = rng.collapsed && isCef; 25214 const createNewBlock$1 = (name, styles) => { 25215 return createNewBlock(editor, container, parentBlock, editableRoot, shouldKeepStyles(editor), name, styles); 25216 }; 25217 const isCaretAtStartOrEndOfBlock = start => { 25218 const normalizedOffset = normalizeZwspOffset(start, container, offset); 25219 if (isText$b(container) && (start ? normalizedOffset > 0 : normalizedOffset < container.data.length)) { 25220 return false; 25221 } 25222 if ((container.parentNode === parentBlock || container === parentBlock) && isAfterLastNodeInContainer && !start) { 25223 return true; 25224 } 25225 if (start && isElement$6(container) && container === parentBlock.firstChild) { 25226 return true; 25227 } 25228 if (containerAndPreviousSiblingName(container, 'TABLE') || containerAndPreviousSiblingName(container, 'HR')) { 25229 if (containerAndNextSiblingName(container, 'BR')) { 25230 return !start; 25231 } 25232 return isAfterLastNodeInContainer && !start || !isAfterLastNodeInContainer && start; 25233 } 25234 const walker = new DomTreeWalker(container, parentBlock); 25235 if (isText$b(container)) { 25236 if (start && normalizedOffset === 0) { 25237 walker.prev(); 25238 } else if (!start && normalizedOffset === container.data.length) { 25239 walker.next(); 25240 } 25241 } 25242 let node; 25243 while (node = walker.current()) { 25244 if (isElement$6(node)) { 25245 if (!node.getAttribute('data-mce-bogus')) { 25246 const name = node.nodeName.toLowerCase(); 25247 if (nonEmptyElementsMap[name] && name !== 'br') { 25248 return false;
vendor: 4,723 bytes, lines 25249-25350
25249 } 25250 } 25251 } else if (isText$b(node) && !isWhitespaceText(node.data)) { 25252 return false; 25253 } 25254 if (start) { 25255 walker.prev(); 25256 } else { 25257 walker.next(); 25258 } 25259 } 25260 return true; 25261 }; 25262 const insertNewBlockAfter = () => { 25263 let block; 25264 if (/^(H[1-6]|PRE|FIGURE)$/.test(parentBlockName) && containerBlockName !== 'HGROUP') { 25265 block = createNewBlock$1(newBlockName); 25266 } else { 25267 block = createNewBlock$1(); 25268 } 25269 if (shouldEndContainer(editor, containerBlock) && canSplitBlock(dom, containerBlock) && dom.isEmpty(parentBlock, undefined, { includeZwsp: true })) { 25270 block = dom.split(containerBlock, parentBlock); 25271 } else { 25272 dom.insertAfter(block, parentBlock); 25273 } 25274 moveToCaretPosition(editor, block); 25275 return block; 25276 }; 25277 normalize$2(dom, rng).each(normRng => { 25278 rng.setStart(normRng.startContainer, normRng.startOffset); 25279 rng.setEnd(normRng.endContainer, normRng.endOffset); 25280 }); 25281 container = rng.startContainer; 25282 offset = rng.startOffset; 25283 const shiftKey = !!(evt && evt.shiftKey); 25284 const ctrlKey = !!(evt && evt.ctrlKey); 25285 if (isElement$6(container) && container.hasChildNodes() && !collapsedAndCef) { 25286 isAfterLastNodeInContainer = offset > container.childNodes.length - 1; 25287 container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container; 25288 if (isAfterLastNodeInContainer && isText$b(container)) { 25289 offset = container.data.length; 25290 } else { 25291 offset = 0; 25292 } 25293 } 25294 const editableRoot = getEditableRoot(dom, container); 25295 if (!editableRoot || isWithinNonEditableList(editor, container)) { 25296 return; 25297 } 25298 if (!shiftKey) { 25299 container = wrapSelfAndSiblingsInDefaultBlock(editor, newBlockName, rng, container, offset); 25300 } 25301 let parentBlock = dom.getParent(container, dom.isBlock) || dom.getRoot(); 25302 containerBlock = isNonNullable(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.parentNode) ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null; 25303 parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : ''; 25304 const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : ''; 25305 if (containerBlockName === 'LI' && !ctrlKey) { 25306 const liBlock = containerBlock; 25307 parentBlock = liBlock; 25308 containerBlock = liBlock.parentNode; 25309 parentBlockName = containerBlockName; 25310 } 25311 if (isElement$6(containerBlock) && isLastEmptyBlockInDetails(editor, shiftKey, parentBlock)) { 25312 return insertNewLine(editor, createNewBlock$1, parentBlock); 25313 } 25314 if (/^(LI|DT|DD)$/.test(parentBlockName) && isElement$6(containerBlock)) { 25315 if (dom.isEmpty(parentBlock)) { 25316 insert$4(editor, createNewBlock$1, containerBlock, parentBlock, newBlockName); 25317 return; 25318 } 25319 } 25320 if (!collapsedAndCef && (parentBlock === editor.getBody() || !canSplitBlock(dom, parentBlock))) { 25321 return; 25322 } 25323 const parentBlockParent = parentBlock.parentNode; 25324 let newBlock; 25325 if (collapsedAndCef) { 25326 newBlock = createNewBlock$1(newBlockName); 25327 child.fold(() => { 25328 append$1(start, SugarElement.fromDom(newBlock)); 25329 }, child => { 25330 before$3(child, SugarElement.fromDom(newBlock)); 25331 }); 25332 editor.selection.setCursorLocation(newBlock, 0); 25333 } else if (isCaretContainerBlock$1(parentBlock)) { 25334 newBlock = showCaretContainerBlock(parentBlock); 25335 if (dom.isEmpty(parentBlock)) { 25336 emptyBlock(parentBlock); 25337 } 25338 setForcedBlockAttrs(editor, newBlock); 25339 moveToCaretPosition(editor, newBlock); 25340 } else if (isCaretAtStartOrEndOfBlock(false)) { 25341 newBlock = insertNewBlockAfter(); 25342 } else if (isCaretAtStartOrEndOfBlock(true) && parentBlockParent) { 25343 const caretPos = CaretPosition.fromRangeStart(rng); 25344 const afterTable = isAfterTable(caretPos); 25345 const parentBlockSugar = SugarElement.fromDom(parentBlock); 25346 const afterBr = isAfterBr(parentBlockSugar, caretPos, editor.schema); 25347 const prevBrOpt = afterBr ? findPreviousBr(parentBlockSugar, caretPos, editor.schema).bind(pos => Optional.from(pos.getNode())) : Optional.none(); 25348 newBlock = parentBlockParent.insertBefore(createNewBlock$1(), parentBlock); 25349 const root = containerAndPreviousSiblingName(parentBlock, 'HR') || afterTable ? newBlock : prevBrOpt.getOr(parentBlock); 25350 moveToCaretPosition(editor, root
vendor: 9,600 bytes, lines 25350-25609
25350); 25351 } else { 25352 const tmpRng = includeZwspInRange(rng).cloneRange(); 25353 tmpRng.setEndAfter(parentBlock); 25354 const fragment = tmpRng.extractContents(); 25355 trimZwsp(fragment); 25356 trimLeadingLineBreaks(fragment); 25357 newBlock = fragment.firstChild; 25358 dom.insertAfter(fragment, parentBlock); 25359 trimInlineElementsOnLeftSideOfBlock(dom, nonEmptyElementsMap, newBlock); 25360 addBrToBlockIfNeeded(dom, parentBlock); 25361 if (dom.isEmpty(parentBlock)) { 25362 emptyBlock(parentBlock); 25363 } 25364 newBlock.normalize(); 25365 if (dom.isEmpty(newBlock)) { 25366 dom.remove(newBlock); 25367 insertNewBlockAfter(); 25368 } else { 25369 setForcedBlockAttrs(editor, newBlock); 25370 moveToCaretPosition(editor, newBlock); 25371 } 25372 } 25373 dom.setAttrib(newBlock, 'id', ''); 25374 editor.dispatch('NewBlock', { newBlock }); 25375 }; 25376 const fakeEventName$1 = 'insertParagraph'; 25377 const blockbreak = { 25378 insert: insert$3, 25379 fakeEventName: fakeEventName$1 25380 }; 25381 25382 const hasRightSideContent = (schema, container, parentBlock) => { 25383 const walker = new DomTreeWalker(container, parentBlock); 25384 let node; 25385 const nonEmptyElementsMap = schema.getNonEmptyElements(); 25386 while (node = walker.next()) { 25387 if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || isText$b(node) && node.length > 0) { 25388 return true; 25389 } 25390 } 25391 return false; 25392 }; 25393 const moveSelectionToBr = (editor, brElm, extraBr) => { 25394 const rng = editor.dom.createRng(); 25395 if (!extraBr) { 25396 rng.setStartAfter(brElm); 25397 rng.setEndAfter(brElm); 25398 } else { 25399 rng.setStartBefore(brElm); 25400 rng.setEndBefore(brElm); 25401 } 25402 editor.selection.setRng(rng); 25403 scrollRangeIntoView(editor, rng); 25404 }; 25405 const insertBrAtCaret = (editor, evt) => { 25406 const selection = editor.selection; 25407 const dom = editor.dom; 25408 const rng = selection.getRng(); 25409 let brElm; 25410 let extraBr = false; 25411 normalize$2(dom, rng).each(normRng => { 25412 rng.setStart(normRng.startContainer, normRng.startOffset); 25413 rng.setEnd(normRng.endContainer, normRng.endOffset); 25414 }); 25415 let offset = rng.startOffset; 25416 let container = rng.startContainer; 25417 if (isElement$6(container) && container.hasChildNodes()) { 25418 const isAfterLastNodeInContainer = offset > container.childNodes.length - 1; 25419 container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container; 25420 if (isAfterLastNodeInContainer && isText$b(container)) { 25421 offset = container.data.length; 25422 } else { 25423 offset = 0; 25424 } 25425 } 25426 let parentBlock = dom.getParent(container, dom.isBlock); 25427 const containerBlock = parentBlock && parentBlock.parentNode ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null; 25428 const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : ''; 25429 const isControlKey = !!(evt && evt.ctrlKey); 25430 if (containerBlockName === 'LI' && !isControlKey) { 25431 parentBlock = containerBlock; 25432 } 25433 if (isText$b(container) && offset >= container.data.length) { 25434 if (!hasRightSideContent(editor.schema, container, parentBlock || dom.getRoot())) { 25435 brElm = dom.create('br'); 25436 rng.insertNode(brElm); 25437 rng.setStartAfter(brElm); 25438 rng.setEndAfter(brElm); 25439 extraBr = true; 25440 } 25441 } 25442 brElm = dom.create('br'); 25443 rangeInsertNode(dom, rng, brElm); 25444 moveSelectionToBr(editor, brElm, extraBr); 25445 editor.undoManager.add(); 25446 }; 25447 const insertBrBefore = (editor, inline) => { 25448 const br = SugarElement.fromTag('br'); 25449 before$3(SugarElement.fromDom(inline), br); 25450 editor.undoManager.add(); 25451 }; 25452 const insertBrAfter = (editor, inline) => { 25453 if (!hasBrAfter(editor.getBody(), inline)) { 25454 after$4(SugarElement.fromDom(inline), SugarElement.fromTag('br')); 25455 } 25456 const br = SugarElement.fromTag('br'); 25457 after$4(SugarElement.fromDom(inline), br); 25458 moveSelectionToBr(editor, br.dom, false); 25459 editor.undoManager.add(); 25460 }; 25461 const isBeforeBr = pos => { 25462 return isBr$6(pos.getNode()); 25463 }; 25464 const hasBrAfter = (rootNode, startNode) => { 25465 if (isBeforeBr(CaretPosition.after(startNode))) { 25466 return true; 25467 } else { 25468 return nextPosition(rootNode, CaretPosition.after(startNode)).map(pos => { 25469 return isBr$6(pos.getNode()); 25470 }).getOr(false); 25471 } 25472 }; 25473 const isAnchorLink = elm => { 25474 return elm && elm.nodeName === 'A' && 'href' in elm; 25475 }; 25476 const isInsideAnchor = location => { 25477 return location.fold(never, isAnchorLink, isAnchorLink, never); 25478 }; 25479 const readInlineAnchorLocation = editor => { 25480 const isInlineTarget$1 = curry(isInlineTarget, editor); 25481 const position = CaretPosition.fromRangeStart(editor.selection.getRng()); 25482 return readLocation(isInlineTarget$1, editor.getBody(), position).filter(isInsideAnchor); 25483 }; 25484 const insertBrOutsideAnchor = (editor, location) => { 25485 location.fold(noop, curry(insertBrBefore, editor), curry(insertBrAfter, editor), noop); 25486 }; 25487 const insert$2 = (editor, evt) => { 25488 const anchorLocation = readInlineAnchorLocation(editor); 25489 if (anchorLocation.isSome()) { 25490 anchorLocation.each(curry(insertBrOutsideAnchor, editor)); 25491 } else { 25492 insertBrAtCaret(editor, evt); 25493 } 25494 }; 25495 const fakeEventName = 'insertLineBreak'; 25496 const linebreak = { 25497 insert: insert$2, 25498 fakeEventName 25499 }; 25500 25501 const matchesSelector = (editor, selector) => { 25502 return getParentBlock$1(editor).filter(parentBlock => { 25503 return selector.length > 0 && is$1(SugarElement.fromDom(parentBlock), selector); 25504 }).isSome(); 25505 }; 25506 const shouldInsertBr = editor => { 25507 return matchesSelector(editor, getBrNewLineSelector(editor)); 25508 }; 25509 const shouldBlockNewLine$1 = editor => { 25510 return matchesSelector(editor, getNoNewLineSelector(editor)); 25511 }; 25512 25513 const newLineAction = Adt.generate([ 25514 { br: [] }, 25515 { block: [] }, 25516 { none: [] } 25517 ]); 25518 const shouldBlockNewLine = (editor, _shiftKey) => { 25519 return shouldBlockNewLine$1(editor); 25520 }; 25521 const inListBlock = requiredState => { 25522 return (editor, _shiftKey) => { 25523 return isListItemParentBlock(editor) === requiredState; 25524 }; 25525 }; 25526 const inBlock = (blockName, requiredState) => (editor, _shiftKey) => { 25527 const state = getParentBlockName(editor) === blockName.toUpperCase(); 25528 return state === requiredState; 25529 }; 25530 const inCefBlock = editor => { 25531 const editableRoot = getEditableRoot(editor.dom, editor.selection.getStart()); 25532 return isNullable(editableRoot); 25533 }; 25534 const inPreBlock = requiredState => inBlock('pre', requiredState); 25535 const inSummaryBlock = () => inBlock('summary', true); 25536 const shouldPutBrInPre = requiredState => { 25537 return (editor, _shiftKey) => { 25538 return shouldPutBrInPre$1(editor) === requiredState; 25539 }; 25540 }; 25541 const inBrContext = (editor, _shiftKey) => { 25542 return shouldInsertBr(editor); 25543 }; 25544 const hasShiftKey = (_editor, shiftKey) => { 25545 return shiftKey; 25546 }; 25547 const canInsertIntoEditableRoot = editor => { 25548 const forcedRootBlock = getForcedRootBlock(editor); 25549 const rootEditable = getEditableRoot(editor.dom, editor.selection.getStart()); 25550 return isNonNullable(rootEditable) && editor.schema.isValidChild(rootEditable.nodeName, forcedRootBlock); 25551 }; 25552 const isInRootWithEmptyOrCEF = editor => { 25553 const rng = editor.selection.getRng(); 25554 const start = SugarElement.fromDom(rng.startContainer); 25555 const child = child$1(start, rng.startOffset); 25556 const isCefOpt = child.map(element => isHTMLElement$1(element) && !isEditable$2(element)); 25557 return rng.collapsed && isCefOpt.getOr(true); 25558 }; 25559 const match = (predicates, action) => { 25560 return (editor, shiftKey) => { 25561 const isMatch = foldl(predicates, (res, p) => { 25562 return res && p(editor, shiftKey); 25563 }, true); 25564 return isMatch ? Optional.some(action) : Optional.none(); 25565 }; 25566 }; 25567 const getAction = (editor, evt) => { 25568 return evaluateUntil([ 25569 match([shouldBlockNewLine], newLineAction.none()), 25570 match([ 25571 inPreBlock(true), 25572 inCefBlock 25573 ], newLineAction.none()), 25574 match([inSummaryBlock()], newLineAction.br()), 25575 match([ 25576 inPreBlock(true), 25577 shouldPutBrInPre(false), 25578 hasShiftKey 25579 ], newLineAction.br()), 25580 match([ 25581 inPreBlock(true), 25582 shouldPutBrInPre(false) 25583 ], newLineAction.block()), 25584 match([ 25585 inPreBlock(true), 25586 shouldPutBrInPre(true), 25587 hasShiftKey 25588 ], newLineAction.block()), 25589 match([ 25590 inPreBlock(true), 25591 shouldPutBrInPre(true) 25592 ], newLineAction.br()), 25593 match([ 25594 inListBlock(true), 25595 hasShiftKey 25596 ], newLineAction.br()), 25597 match([inListBlock(true)], newLineAction.block()), 25598 match([inBrContext], newLineAction.br()), 25599 match([hasShiftKey], newLineAction.br()), 25600 match([canInsertIntoEditableRoot], newLineAction.block()), 25601 match([isInRootWithEmptyOrCEF], newLineAction.block()) 25602 ], [ 25603 editor, 25604 !!(evt && evt.shiftKey) 25605 ]).getOr(newLineAction.none()); 25606 }; 25607 25608 const insertBreak = (breakType, editor, evt) => { 25609 if (
vendor: 6,635 bytes, lines 25609-25816
25609editor.mode.isReadOnly()) { 25610 return; 25611 } 25612 if (!editor.selection.isCollapsed()) { 25613 execEditorDeleteCommand(editor); 25614 } 25615 if (isNonNullable(evt)) { 25616 const event = fireBeforeInputEvent(editor, breakType.fakeEventName); 25617 if (event.isDefaultPrevented()) { 25618 return; 25619 } 25620 } 25621 breakType.insert(editor, evt); 25622 if (isNonNullable(evt)) { 25623 fireInputEvent(editor, breakType.fakeEventName); 25624 } 25625 }; 25626 const insert$1 = (editor, evt) => { 25627 if (editor.mode.isReadOnly()) { 25628 return; 25629 } 25630 const br = () => insertBreak(linebreak, editor, evt); 25631 const block = () => insertBreak(blockbreak, editor, evt); 25632 const logicalAction = getAction(editor, evt); 25633 switch (getNewlineBehavior(editor)) { 25634 case 'linebreak': 25635 logicalAction.fold(br, br, noop); 25636 break; 25637 case 'block': 25638 logicalAction.fold(block, block, noop); 25639 break; 25640 case 'invert': 25641 logicalAction.fold(block, br, noop); 25642 break; 25643 default: 25644 logicalAction.fold(br, block, noop); 25645 break; 25646 } 25647 }; 25648 25649 const platform$1 = detect$1(); 25650 const isIOSSafari = platform$1.os.isiOS() && platform$1.browser.isSafari(); 25651 const handleEnterKeyEvent = (editor, event) => { 25652 if (event.isDefaultPrevented()) { 25653 return; 25654 } 25655 event.preventDefault(); 25656 endTypingLevelIgnoreLocks(editor.undoManager); 25657 editor.undoManager.transact(() => { 25658 insert$1(editor, event); 25659 }); 25660 }; 25661 const isCaretAfterKoreanCharacter = rng => { 25662 if (!rng.collapsed) { 25663 return false; 25664 } 25665 const startContainer = rng.startContainer; 25666 if (isText$b(startContainer)) { 25667 const koreanCharRegex = /^[\uAC00-\uD7AF\u1100-\u11FF\u3130-\u318F\uA960-\uA97F\uD7B0-\uD7FF]$/; 25668 const char = startContainer.data.charAt(rng.startOffset - 1); 25669 return koreanCharRegex.test(char); 25670 } else { 25671 return false; 25672 } 25673 }; 25674 const setup$i = editor => { 25675 let iOSSafariKeydownBookmark = Optional.none(); 25676 const iOSSafariKeydownOverride = editor => { 25677 iOSSafariKeydownBookmark = Optional.some(editor.selection.getBookmark()); 25678 editor.undoManager.add(); 25679 }; 25680 const iOSSafariKeyupOverride = (editor, event) => { 25681 editor.undoManager.undo(); 25682 iOSSafariKeydownBookmark.fold(noop, b => editor.selection.moveToBookmark(b)); 25683 handleEnterKeyEvent(editor, event); 25684 iOSSafariKeydownBookmark = Optional.none(); 25685 }; 25686 editor.on('keydown', event => { 25687 if (event.keyCode === VK.ENTER) { 25688 if (isIOSSafari && isCaretAfterKoreanCharacter(editor.selection.getRng())) { 25689 iOSSafariKeydownOverride(editor); 25690 } else { 25691 handleEnterKeyEvent(editor, event); 25692 } 25693 } 25694 }); 25695 editor.on('keyup', event => { 25696 if (event.keyCode === VK.ENTER) { 25697 iOSSafariKeydownBookmark.each(() => iOSSafariKeyupOverride(editor, event)); 25698 } 25699 }); 25700 }; 25701 25702 const executeKeydownOverride$2 = (editor, caret, evt) => { 25703 const isMac = Env.os.isMacOS() || Env.os.isiOS(); 25704 execute([ 25705 { 25706 keyCode: VK.END, 25707 action: action(moveToLineEndPoint$1, editor, true) 25708 }, 25709 { 25710 keyCode: VK.HOME, 25711 action: action(moveToLineEndPoint$1, editor, false) 25712 }, 25713 ...!isMac ? [ 25714 { 25715 keyCode: VK.HOME, 25716 action: action(selectToEndPoint, editor, false), 25717 ctrlKey: true, 25718 shiftKey: true 25719 }, 25720 { 25721 keyCode: VK.END, 25722 action: action(selectToEndPoint, editor, true), 25723 ctrlKey: true, 25724 shiftKey: true 25725 } 25726 ] : [], 25727 { 25728 keyCode: VK.END, 25729 action: action(moveToLineEndPoint, editor, true) 25730 }, 25731 { 25732 keyCode: VK.HOME, 25733 action: action(moveToLineEndPoint, editor, false) 25734 }, 25735 { 25736 keyCode: VK.END, 25737 action: action(moveToLineEndPoint$2, editor, true, caret) 25738 }, 25739 { 25740 keyCode: VK.HOME, 25741 action: action(moveToLineEndPoint$2, editor, false, caret) 25742 } 25743 ], evt).each(_ => { 25744 evt.preventDefault(); 25745 }); 25746 }; 25747 const setup$h = (editor, caret) => { 25748 editor.on('keydown', evt => { 25749 if (!evt.isDefaultPrevented()) { 25750 executeKeydownOverride$2(editor, caret, evt); 25751 } 25752 }); 25753 }; 25754 25755 const setup$g = editor => { 25756 editor.on('input', e => { 25757 if (!e.isComposing) { 25758 normalizeNbspsInEditor(editor); 25759 } 25760 }); 25761 }; 25762 25763 const platform = detect$1(); 25764 const executeKeyupAction = (editor, caret, evt) => { 25765 execute([ 25766 { 25767 keyCode: VK.PAGE_UP, 25768 action: action(moveToLineEndPoint$2, editor, false, caret) 25769 }, 25770 { 25771 keyCode: VK.PAGE_DOWN, 25772 action: action(moveToLineEndPoint$2, editor, true, caret) 25773 } 25774 ], evt); 25775 }; 25776 const stopImmediatePropagation = e => e.stopImmediatePropagation(); 25777 const isPageUpDown = evt => evt.keyCode === VK.PAGE_UP || evt.keyCode === VK.PAGE_DOWN; 25778 const setNodeChangeBlocker = (blocked, editor, block) => { 25779 if (block && !blocked.get()) { 25780 editor.on('NodeChange', stopImmediatePropagation, true); 25781 } else if (!block && blocked.get()) { 25782 editor.off('NodeChange', stopImmediatePropagation); 25783 } 25784 blocked.set(block); 25785 }; 25786 const setup$f = (editor, caret) => { 25787 if (platform.os.isMacOS()) { 25788 return; 25789 } 25790 const blocked = Cell(false); 25791 editor.on('keydown', evt => { 25792 if (isPageUpDown(evt)) { 25793 setNodeChangeBlocker(blocked, editor, true); 25794 } 25795 }); 25796 editor.on('keyup', evt => { 25797 if (!evt.isDefaultPrevented()) { 25798 executeKeyupAction(editor, caret, evt); 25799 } 25800 if (isPageUpDown(evt) && blocked.get()) { 25801 setNodeChangeBlocker(blocked, editor, false); 25802 editor.nodeChanged(); 25803 } 25804 }); 25805 }; 25806 25807 const isValidContainer = (root, container) => root === container || root.contains(container); 25808 const isInEditableRange = (editor, range) => { 25809 if (!isValidContainer(editor.getBody(), range.startContainer) || !isValidContainer(editor.getBody(), range.endContainer)) { 25810 return true; 25811 } 25812 return isEditableRange(editor.dom, range); 25813 }; 25814 const setup$e = editor => { 25815 editor.on('beforeinput', e => { 25816 if (!editor.selection.isEditable() || exists(e.getTargetRanges(), rng => !isInEditableRange(editor
vendor: 6,792 bytes, lines 25816-25999
25816, rng))) { 25817 e.preventDefault(); 25818 } 25819 }); 25820 }; 25821 25822 const insertTextAtPosition = (text, pos) => { 25823 const container = pos.container(); 25824 const offset = pos.offset(); 25825 if (isText$b(container)) { 25826 container.insertData(offset, text); 25827 return Optional.some(CaretPosition(container, offset + text.length)); 25828 } else { 25829 return getElementFromPosition(pos).map(elm => { 25830 const textNode = SugarElement.fromText(text); 25831 if (pos.isAtEnd()) { 25832 after$4(elm, textNode); 25833 } else { 25834 before$3(elm, textNode); 25835 } 25836 return CaretPosition(textNode.dom, text.length); 25837 }); 25838 } 25839 }; 25840 const insertNbspAtPosition = curry(insertTextAtPosition, nbsp); 25841 const insertSpaceAtPosition = curry(insertTextAtPosition, ' '); 25842 25843 const insertSpaceOrNbspAtPosition = (root, pos, schema) => needsToHaveNbsp(root, pos, schema) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos); 25844 const locationToCaretPosition = root => location => location.fold(element => prevPosition(root.dom, CaretPosition.before(element)), element => firstPositionIn(element), element => lastPositionIn(element), element => nextPosition(root.dom, CaretPosition.after(element))); 25845 const insertInlineBoundarySpaceOrNbsp = (root, pos, schema) => checkPos => needsToHaveNbsp(root, checkPos, schema) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos); 25846 const setSelection = editor => pos => { 25847 editor.selection.setRng(pos.toRange()); 25848 editor.nodeChanged(); 25849 }; 25850 const isInsideSummary = (domUtils, node) => domUtils.isEditable(domUtils.getParent(node, 'summary')); 25851 const insertSpaceOrNbspAtSelection = editor => { 25852 const pos = CaretPosition.fromRangeStart(editor.selection.getRng()); 25853 const root = SugarElement.fromDom(editor.getBody()); 25854 if (editor.selection.isCollapsed()) { 25855 const isInlineTarget$1 = curry(isInlineTarget, editor); 25856 const caretPosition = CaretPosition.fromRangeStart(editor.selection.getRng()); 25857 return readLocation(isInlineTarget$1, editor.getBody(), caretPosition).bind(locationToCaretPosition(root)).map(checkPos => () => insertInlineBoundarySpaceOrNbsp(root, pos, editor.schema)(checkPos).each(setSelection(editor))); 25858 } else { 25859 return Optional.none(); 25860 } 25861 }; 25862 const insertSpaceInSummaryAtSelectionOnFirefox = editor => { 25863 const insertSpaceThunk = () => { 25864 const root = SugarElement.fromDom(editor.getBody()); 25865 if (!editor.selection.isCollapsed()) { 25866 editor.getDoc().execCommand('Delete'); 25867 } 25868 const pos = CaretPosition.fromRangeStart(editor.selection.getRng()); 25869 insertSpaceOrNbspAtPosition(root, pos, editor.schema).each(setSelection(editor)); 25870 }; 25871 return someIf(Env.browser.isFirefox() && editor.selection.isEditable() && isInsideSummary(editor.dom, editor.selection.getRng().startContainer), insertSpaceThunk); 25872 }; 25873 25874 const executeKeydownOverride$1 = (editor, evt) => { 25875 executeWithDelayedAction([ 25876 { 25877 keyCode: VK.SPACEBAR, 25878 action: action(insertSpaceOrNbspAtSelection, editor) 25879 }, 25880 { 25881 keyCode: VK.SPACEBAR, 25882 action: action(insertSpaceInSummaryAtSelectionOnFirefox, editor) 25883 } 25884 ], evt).each(applyAction => { 25885 evt.preventDefault(); 25886 const event = fireBeforeInputEvent(editor, 'insertText', { data: ' ' }); 25887 if (!event.isDefaultPrevented()) { 25888 applyAction(); 25889 fireInputEvent(editor, 'insertText', { data: ' ' }); 25890 } 25891 }); 25892 }; 25893 const setup$d = editor => { 25894 editor.on('keydown', evt => { 25895 if (!evt.isDefaultPrevented()) { 25896 executeKeydownOverride$1(editor, evt); 25897 } 25898 }); 25899 }; 25900 25901 const tableTabNavigation = editor => { 25902 if (hasTableTabNavigation(editor)) { 25903 return [ 25904 { 25905 keyCode: VK.TAB, 25906 action: action(handleTab, editor, true) 25907 }, 25908 { 25909 keyCode: VK.TAB, 25910 shiftKey: true, 25911 action: action(handleTab, editor, false) 25912 } 25913 ]; 25914 } else { 25915 return []; 25916 } 25917 }; 25918 const executeKeydownOverride = (editor, evt) => { 25919 execute([...tableTabNavigation(editor)], evt).each(_ => { 25920 evt.preventDefault(); 25921 }); 25922 }; 25923 const setup$c = editor => { 25924 editor.on('keydown', evt => { 25925 if (!evt.isDefaultPrevented()) { 25926 executeKeydownOverride(editor, evt); 25927 } 25928 }); 25929 }; 25930 25931 const setup$b = editor => { 25932 editor.addShortcut('Meta+P', '', 'mcePrint'); 25933 setup$k(editor); 25934 if (isRtc(editor)) { 25935 return Cell(null); 25936 } else { 25937 const caret = setupSelectedState(editor); 25938 setup$e(editor); 25939 setup$m(editor); 25940 setup$l(editor, caret); 25941 setup$j(editor, caret); 25942 setup$i(editor); 25943 setup$d(editor); 25944 setup$g(editor); 25945 setup$c(editor); 25946 setup$h(editor, caret); 25947 setup$f(editor, caret); 25948 return caret; 25949 } 25950 }; 25951 25952 class NodeChange { 25953 constructor(editor) { 25954 this.lastPath = []; 25955 this.editor = editor; 25956 let lastRng; 25957 const self = this; 25958 if (!('onselectionchange' in editor.getDoc())) { 25959 editor.on('NodeChange click mouseup keyup focus', e => { 25960 const nativeRng = editor.selection.getRng(); 25961 const fakeRng = { 25962 startContainer: nativeRng.startContainer, 25963 startOffset: nativeRng.startOffset, 25964 endContainer: nativeRng.endContainer, 25965 endOffset: nativeRng.endOffset 25966 }; 25967 if (e.type === 'nodechange' || !isEq$4(fakeRng, lastRng)) { 25968 editor.dispatch('SelectionChange'); 25969 } 25970 lastRng = fakeRng; 25971 }); 25972 } 25973 editor.on('contextmenu', () => { 25974 store(editor); 25975 editor.dispatch('SelectionChange'); 25976 }); 25977 editor.on('SelectionChange', () => { 25978 const startElm = editor.selection.getStart(true); 25979 if (!startElm) { 25980 return; 25981 } 25982 if (hasAnyRanges(editor) && !self.isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) { 25983 editor.nodeChanged({ selectionChange: true }); 25984 } 25985 }); 25986 editor.on('mouseup', e => { 25987 if (!e.isDefaultPrevented() && hasAnyRanges(editor)) { 25988 if (editor.selection.getNode().nodeName === 'IMG') { 25989 Delay.setEditorTimeout(editor, () => { 25990 editor.nodeChanged(); 25991 }); 25992 } else { 25993 editor.nodeChanged(); 25994 } 25995 } 25996 }); 25997 } 25998 nodeChanged(args = {}) { 25999 const
vendor: 5,103 bytes, lines 25999-26174
25999editor = this.editor; 26000 const selection = editor.selection; 26001 let node; 26002 if (editor.initialized && selection && !shouldDisableNodeChange(editor) && !isDisabled$1(editor)) { 26003 const root = editor.getBody(); 26004 node = selection.getStart(true) || root; 26005 if (node.ownerDocument !== editor.getDoc() || !editor.dom.isChildOf(node, root)) { 26006 node = root; 26007 } 26008 const parents = []; 26009 editor.dom.getParent(node, node => { 26010 if (node === root) { 26011 return true; 26012 } else { 26013 parents.push(node); 26014 return false; 26015 } 26016 }); 26017 editor.dispatch('NodeChange', { 26018 ...args, 26019 element: node, 26020 parents 26021 }); 26022 } 26023 } 26024 isSameElementPath(startElm) { 26025 let i; 26026 const editor = this.editor; 26027 const currentPath = reverse(editor.dom.getParents(startElm, always, editor.getBody())); 26028 if (currentPath.length === this.lastPath.length) { 26029 for (i = currentPath.length; i >= 0; i--) { 26030 if (currentPath[i] !== this.lastPath[i]) { 26031 break; 26032 } 26033 } 26034 if (i === -1) { 26035 this.lastPath = currentPath; 26036 return true; 26037 } 26038 } 26039 this.lastPath = currentPath; 26040 return false; 26041 } 26042 } 26043 26044 const imageId = generate$1('image'); 26045 const getDragImage = transfer => { 26046 const dt = transfer; 26047 return Optional.from(dt[imageId]); 26048 }; 26049 const setDragImage = (transfer, imageData) => { 26050 const dt = transfer; 26051 dt[imageId] = imageData; 26052 }; 26053 26054 const eventId = generate$1('event'); 26055 const getEvent = transfer => { 26056 const dt = transfer; 26057 return Optional.from(dt[eventId]); 26058 }; 26059 const mkSetEventFn = type => transfer => { 26060 const dt = transfer; 26061 dt[eventId] = type; 26062 }; 26063 const setEvent = (transfer, type) => mkSetEventFn(type)(transfer); 26064 const setDragstartEvent = mkSetEventFn(0); 26065 const setDropEvent = mkSetEventFn(2); 26066 const setDragendEvent = mkSetEventFn(1); 26067 const checkEvent = expectedType => transfer => { 26068 const dt = transfer; 26069 return Optional.from(dt[eventId]).exists(type => type === expectedType); 26070 }; 26071 const isInDragStartEvent = checkEvent(0); 26072 26073 const createEmptyFileList = () => Object.freeze({ 26074 length: 0, 26075 item: _ => null 26076 }); 26077 26078 const modeId = generate$1('mode'); 26079 const getMode = transfer => { 26080 const dt = transfer; 26081 return Optional.from(dt[modeId]); 26082 }; 26083 const mkSetModeFn = mode => transfer => { 26084 const dt = transfer; 26085 dt[modeId] = mode; 26086 }; 26087 const setMode$1 = (transfer, mode) => mkSetModeFn(mode)(transfer); 26088 const setReadWriteMode = mkSetModeFn(0); 26089 const setReadOnlyMode = mkSetModeFn(2); 26090 const setProtectedMode = mkSetModeFn(1); 26091 const checkMode = expectedMode => transfer => { 26092 const dt = transfer; 26093 return Optional.from(dt[modeId]).exists(mode => mode === expectedMode); 26094 }; 26095 const isInReadWriteMode = checkMode(0); 26096 const isInProtectedMode = checkMode(1); 26097 26098 const normalizeItems = (dataTransfer, itemsImpl) => ({ 26099 ...itemsImpl, 26100 get length() { 26101 return itemsImpl.length; 26102 }, 26103 add: (data, type) => { 26104 if (isInReadWriteMode(dataTransfer)) { 26105 if (isString(data)) { 26106 if (!isUndefined(type)) { 26107 return itemsImpl.add(data, type); 26108 } 26109 } else { 26110 return itemsImpl.add(data); 26111 } 26112 } 26113 return null; 26114 }, 26115 remove: idx => { 26116 if (isInReadWriteMode(dataTransfer)) { 26117 itemsImpl.remove(idx); 26118 } 26119 }, 26120 clear: () => { 26121 if (isInReadWriteMode(dataTransfer)) { 26122 itemsImpl.clear(); 26123 } 26124 } 26125 }); 26126 26127 const validDropEffects = [ 26128 'none', 26129 'copy', 26130 'link', 26131 'move' 26132 ]; 26133 const validEffectAlloweds = [ 26134 'none', 26135 'copy', 26136 'copyLink', 26137 'copyMove', 26138 'link', 26139 'linkMove', 26140 'move', 26141 'all', 26142 'uninitialized' 26143 ]; 26144 const createDataTransfer = () => { 26145 const dataTransferImpl = new window.DataTransfer(); 26146 let dropEffect = 'move'; 26147 let effectAllowed = 'all'; 26148 const dataTransfer = { 26149 get dropEffect() { 26150 return dropEffect; 26151 }, 26152 set dropEffect(effect) { 26153 if (contains$2(validDropEffects, effect)) { 26154 dropEffect = effect; 26155 } 26156 }, 26157 get effectAllowed() { 26158 return effectAllowed; 26159 }, 26160 set effectAllowed(allowed) { 26161 if (isInDragStartEvent(dataTransfer) && contains$2(validEffectAlloweds, allowed)) { 26162 effectAllowed = allowed; 26163 } 26164 }, 26165 get items() { 26166 return normalizeItems(dataTransfer, dataTransferImpl.items); 26167 }, 26168 get files() { 26169 if (isInProtectedMode(dataTransfer)) { 26170 return createEmptyFileList(); 26171 } else { 26172 return dataTransferImpl.files; 26173 } 26174 },
vendor: 7,829 bytes, lines 26175-26403
26175 get types() { 26176 return dataTransferImpl.types; 26177 }, 26178 setDragImage: (image, x, y) => { 26179 if (isInReadWriteMode(dataTransfer)) { 26180 setDragImage(dataTransfer, { 26181 image, 26182 x, 26183 y 26184 }); 26185 dataTransferImpl.setDragImage(image, x, y); 26186 } 26187 }, 26188 getData: format => { 26189 if (isInProtectedMode(dataTransfer)) { 26190 return ''; 26191 } else { 26192 return dataTransferImpl.getData(format); 26193 } 26194 }, 26195 setData: (format, data) => { 26196 if (isInReadWriteMode(dataTransfer)) { 26197 dataTransferImpl.setData(format, data); 26198 } 26199 }, 26200 clearData: format => { 26201 if (isInReadWriteMode(dataTransfer)) { 26202 dataTransferImpl.clearData(format); 26203 } 26204 } 26205 }; 26206 setReadWriteMode(dataTransfer); 26207 return dataTransfer; 26208 }; 26209 const cloneDataTransfer = original => { 26210 const clone = createDataTransfer(); 26211 const originalMode = getMode(original); 26212 setReadOnlyMode(original); 26213 setDragstartEvent(clone); 26214 clone.dropEffect = original.dropEffect; 26215 clone.effectAllowed = original.effectAllowed; 26216 getDragImage(original).each(imageData => clone.setDragImage(imageData.image, imageData.x, imageData.y)); 26217 each$e(original.types, type => { 26218 if (type !== 'Files') { 26219 clone.setData(type, original.getData(type)); 26220 } 26221 }); 26222 each$e(original.files, file => clone.items.add(file)); 26223 getEvent(original).each(type => { 26224 setEvent(clone, type); 26225 }); 26226 originalMode.each(mode => { 26227 setMode$1(original, mode); 26228 setMode$1(clone, mode); 26229 }); 26230 return clone; 26231 }; 26232 26233 const getHtmlData = dataTransfer => { 26234 const html = dataTransfer.getData('text/html'); 26235 return html === '' ? Optional.none() : Optional.some(html); 26236 }; 26237 const setHtmlData = (dataTransfer, html) => dataTransfer.setData('text/html', html); 26238 26239 const internalMimeType = 'x-tinymce/html'; 26240 const internalHtmlMime = constant(internalMimeType); 26241 const internalMark = '<!-- ' + internalMimeType + ' -->'; 26242 const mark = html => internalMark + html; 26243 const unmark = html => html.replace(internalMark, ''); 26244 const isMarked = html => html.indexOf(internalMark) !== -1; 26245 26246 const isPlainText = text => { 26247 return !/<(?:\/?(?!(?:div|p|br|span)>)\w+|(?:(?!(?:span style="white-space:\s?pre;?">)|br\s?\/>))\w+\s[^>]+)>/i.test(text); 26248 }; 26249 const openContainer = (rootTag, rootAttrs) => { 26250 let tag = '<' + rootTag; 26251 const attrs = mapToArray(rootAttrs, (value, key) => key + '="' + Entities.encodeAllRaw(value) + '"'); 26252 if (attrs.length) { 26253 tag += ' ' + attrs.join(' '); 26254 } 26255 return tag + '>'; 26256 }; 26257 const toBlockElements = (text, rootTag, rootAttrs) => { 26258 const blocks = text.split(/\n\n/); 26259 const tagOpen = openContainer(rootTag, rootAttrs); 26260 const tagClose = '</' + rootTag + '>'; 26261 const paragraphs = map$3(blocks, p => { 26262 return p.split(/\n/).join('<br />'); 26263 }); 26264 const stitch = p => { 26265 return tagOpen + p + tagClose; 26266 }; 26267 return paragraphs.length === 1 ? paragraphs[0] : map$3(paragraphs, stitch).join(''); 26268 }; 26269 26270 const pasteBinDefaultContent = '%MCEPASTEBIN%'; 26271 const create$6 = (editor, lastRngCell) => { 26272 const {dom, selection} = editor; 26273 const body = editor.getBody(); 26274 lastRngCell.set(selection.getRng()); 26275 const pasteBinElm = dom.add(editor.getBody(), 'div', { 26276 'id': 'mcepastebin', 26277 'class': 'mce-pastebin', 26278 'contentEditable': true, 26279 'data-mce-bogus': 'all', 26280 'style': 'position: fixed; top: 50%; width: 10px; height: 10px; overflow: hidden; opacity: 0' 26281 }, pasteBinDefaultContent); 26282 if (Env.browser.isFirefox()) { 26283 dom.setStyle(pasteBinElm, 'left', dom.getStyle(body, 'direction', true) === 'rtl' ? 65535 : -65535); 26284 } 26285 dom.bind(pasteBinElm, 'beforedeactivate focusin focusout', e => { 26286 e.stopPropagation(); 26287 }); 26288 pasteBinElm.focus(); 26289 selection.select(pasteBinElm, true); 26290 }; 26291 const remove = (editor, lastRngCell) => { 26292 const dom = editor.dom; 26293 if (getEl(editor)) { 26294 let pasteBinClone; 26295 const lastRng = lastRngCell.get(); 26296 while (pasteBinClone = getEl(editor)) { 26297 dom.remove(pasteBinClone); 26298 dom.unbind(pasteBinClone); 26299 } 26300 if (lastRng) { 26301 editor.selection.setRng(lastRng); 26302 } 26303 } 26304 lastRngCell.set(null); 26305 }; 26306 const getEl = editor => editor.dom.get('mcepastebin'); 26307 const isPasteBin = elm => isNonNullable(elm) && elm.id === 'mcepastebin'; 26308 const getHtml = editor => { 26309 const dom = editor.dom; 26310 const copyAndRemove = (toElm, fromElm) => { 26311 toElm.appendChild(fromElm); 26312 dom.remove(fromElm, true); 26313 }; 26314 const [pasteBinElm, ...pasteBinClones] = filter$5(editor.getBody().childNodes, isPasteBin); 26315 each$e(pasteBinClones, pasteBinClone => { 26316 copyAndRemove(pasteBinElm, pasteBinClone); 26317 }); 26318 const dirtyWrappers = dom.select('div[id=mcepastebin]', pasteBinElm); 26319 for (let i = dirtyWrappers.length - 1; i >= 0; i--) { 26320 const cleanWrapper = dom.create('div'); 26321 pasteBinElm.insertBefore(cleanWrapper, dirtyWrappers[i]); 26322 copyAndRemove(cleanWrapper, dirtyWrappers[i]); 26323 } 26324 return pasteBinElm ? pasteBinElm.innerHTML : ''; 26325 }; 26326 const isDefaultPasteBinContent = content => content === pasteBinDefaultContent; 26327 const PasteBin = editor => { 26328 const lastRng = Cell(null); 26329 return { 26330 create: () => create$6(editor, lastRng), 26331 remove: () => remove(editor, lastRng), 26332 getEl: () => getEl(editor), 26333 getHtml: () => getHtml(editor), 26334 getLastRng: lastRng.get 26335 }; 26336 }; 26337 26338 const filter$1 = (content, items) => { 26339 Tools.each(items, v => { 26340 if (is$4(v, RegExp)) { 26341 content = content.replace(v, ''); 26342 } else { 26343 content = content.replace(v[0], v[1]); 26344 } 26345 }); 26346 return content; 26347 }; 26348 const innerText = html => { 26349 const schema = Schema(); 26350 const domParser = DomParser({}, schema); 26351 let text = ''; 26352 const voidElements = schema.getVoidElements(); 26353 const ignoreElements = Tools.makeMap('script noscript style textarea video audio iframe object', ' '); 26354 const blockElements = schema.getBlockElements(); 26355 const walk = node => { 26356 const name = node.name, currentNode = node; 26357 if (name === 'br') { 26358 text += '\n'; 26359 return; 26360 } 26361 if (name === 'wbr') { 26362 return; 26363 } 26364 if (voidElements[name]) { 26365 text += ' '; 26366 } 26367 if (ignoreElements[name]) { 26368 text += ' '; 26369 return; 26370 } 26371 if (node.type === 3) { 26372 text += node.value; 26373 } 26374 if (!(node.name in schema.getVoidElements())) { 26375 let currentNode = node.firstChild; 26376 if (currentNode) { 26377 do { 26378 walk(currentNode); 26379 } while (currentNode = currentNode.next); 26380 } 26381 } 26382 if (blockElements[name] && currentNode.next) { 26383 text += '\n'; 26384 if (name === 'p') { 26385 text += '\n'; 26386 } 26387 } 26388 }; 26389 html = filter$1(html, [/<!\[[^\]]+\]>/g]); 26390 walk(domParser.parse(html)); 26391 return text; 26392 }; 26393 const trimHtml = html => { 26394 const trimSpaces = (all, s1, s2) => { 26395 if (!s1 && !s2) { 26396 return ' '; 26397 } 26398 return nbsp; 26399 }; 26400 html = filter$1(html, [ 26401 /^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/ig, 26402 /<!--StartFragment-->|<!--EndFragment-->/g, 26403 [
vendor: 7,665 bytes, lines 26404-26591
26404 /( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g, 26405 trimSpaces 26406 ], 26407 /<br class="Apple-interchange-newline">/g, 26408 /<br>$/i 26409 ]); 26410 return html; 26411 }; 26412 const createIdGenerator = prefix => { 26413 let count = 0; 26414 return () => { 26415 return prefix + count++; 26416 }; 26417 }; 26418 const getImageMimeType = ext => { 26419 const lowerExt = ext.toLowerCase(); 26420 const mimeOverrides = { 26421 jpg: 'jpeg', 26422 jpe: 'jpeg', 26423 jfi: 'jpeg', 26424 jif: 'jpeg', 26425 jfif: 'jpeg', 26426 pjpeg: 'jpeg', 26427 pjp: 'jpeg', 26428 svg: 'svg+xml' 26429 }; 26430 return Tools.hasOwn(mimeOverrides, lowerExt) ? 'image/' + mimeOverrides[lowerExt] : 'image/' + lowerExt; 26431 }; 26432 26433 const preProcess = (editor, html) => { 26434 const parser = DomParser({ 26435 sanitize: shouldSanitizeXss(editor), 26436 sandbox_iframes: shouldSandboxIframes(editor), 26437 sandbox_iframes_exclusions: getSandboxIframesExclusions(editor), 26438 convert_unsafe_embeds: shouldConvertUnsafeEmbeds(editor) 26439 }, editor.schema); 26440 parser.addNodeFilter('meta', nodes => { 26441 Tools.each(nodes, node => { 26442 node.remove(); 26443 }); 26444 }); 26445 const fragment = parser.parse(html, { 26446 forced_root_block: false, 26447 isRootContent: true 26448 }); 26449 return HtmlSerializer({ validate: true }, editor.schema).serialize(fragment); 26450 }; 26451 const processResult = (content, cancelled) => ({ 26452 content, 26453 cancelled 26454 }); 26455 const postProcessFilter = (editor, html, internal) => { 26456 const tempBody = editor.dom.create('div', { style: 'display:none' }, html); 26457 const postProcessArgs = firePastePostProcess(editor, tempBody, internal); 26458 return processResult(postProcessArgs.node.innerHTML, postProcessArgs.isDefaultPrevented()); 26459 }; 26460 const filterContent = (editor, content, internal) => { 26461 const preProcessArgs = firePastePreProcess(editor, content, internal); 26462 const filteredContent = preProcess(editor, preProcessArgs.content); 26463 if (editor.hasEventListeners('PastePostProcess') && !preProcessArgs.isDefaultPrevented()) { 26464 return postProcessFilter(editor, filteredContent, internal); 26465 } else { 26466 return processResult(filteredContent, preProcessArgs.isDefaultPrevented()); 26467 } 26468 }; 26469 const process = (editor, html, internal) => { 26470 return filterContent(editor, html, internal); 26471 }; 26472 26473 const pasteHtml$1 = (editor, html) => { 26474 editor.insertContent(html, { 26475 merge: shouldPasteMergeFormats(editor), 26476 paste: true 26477 }); 26478 return true; 26479 }; 26480 const isAbsoluteUrl = url => /^https?:\/\/[\w\-\/+=.,!;:&%@^~(){}?#]+$/i.test(url); 26481 const isImageUrl = (editor, url) => { 26482 return isAbsoluteUrl(url) && exists(getAllowedImageFileTypes(editor), type => endsWith(url.toLowerCase(), `.${ type.toLowerCase() }`)); 26483 }; 26484 const createImage = (editor, url, pasteHtmlFn) => { 26485 editor.undoManager.extra(() => { 26486 pasteHtmlFn(editor, url); 26487 }, () => { 26488 editor.insertContent('<img src="' + url + '">'); 26489 }); 26490 return true; 26491 }; 26492 const createLink = (editor, url, pasteHtmlFn) => { 26493 editor.undoManager.extra(() => { 26494 pasteHtmlFn(editor, url); 26495 }, () => { 26496 editor.execCommand('mceInsertLink', false, url); 26497 }); 26498 return true; 26499 }; 26500 const linkSelection = (editor, html, pasteHtmlFn) => !editor.selection.isCollapsed() && isAbsoluteUrl(html) ? createLink(editor, html, pasteHtmlFn) : false; 26501 const insertImage = (editor, html, pasteHtmlFn) => isImageUrl(editor, html) ? createImage(editor, html, pasteHtmlFn) : false; 26502 const smartInsertContent = (editor, html) => { 26503 Tools.each([ 26504 linkSelection, 26505 insertImage, 26506 pasteHtml$1 26507 ], action => { 26508 return !action(editor, html, pasteHtml$1); 26509 }); 26510 }; 26511 const insertContent = (editor, html, pasteAsText) => { 26512 if (pasteAsText || !isSmartPasteEnabled(editor)) { 26513 pasteHtml$1(editor, html); 26514 } else { 26515 smartInsertContent(editor, html); 26516 } 26517 }; 26518 26519 const uniqueId = createIdGenerator('mceclip'); 26520 const createPasteDataTransfer = html => { 26521 const dataTransfer = createDataTransfer(); 26522 setHtmlData(dataTransfer, html); 26523 setReadOnlyMode(dataTransfer); 26524 return dataTransfer; 26525 }; 26526 const doPaste = (editor, content, internal, pasteAsText, shouldSimulateInputEvent) => { 26527 const res = process(editor, content, internal); 26528 if (!res.cancelled) { 26529 const content = res.content; 26530 const doPasteAction = () => insertContent(editor, content, pasteAsText); 26531 if (shouldSimulateInputEvent) { 26532 const args = fireBeforeInputEvent(editor, 'insertFromPaste', { dataTransfer: createPasteDataTransfer(content) }); 26533 if (!args.isDefaultPrevented()) { 26534 doPasteAction(); 26535 fireInputEvent(editor, 'insertFromPaste'); 26536 } 26537 } else { 26538 doPasteAction(); 26539 } 26540 } 26541 }; 26542 const pasteHtml = (editor, html, internalFlag, shouldSimulateInputEvent) => { 26543 const internal = internalFlag ? internalFlag : isMarked(html); 26544 doPaste(editor, unmark(html), internal, false, shouldSimulateInputEvent); 26545 }; 26546 const pasteText = (editor, text, shouldSimulateInputEvent) => { 26547 const encodedText = editor.dom.encode(text).replace(/\r\n/g, '\n'); 26548 const normalizedText = normalize$4(encodedText, getPasteTabSpaces(editor)); 26549 const html = toBlockElements(normalizedText, getForcedRootBlock(editor), getForcedRootBlockAttrs(editor)); 26550 doPaste(editor, html, false, true, shouldSimulateInputEvent); 26551 }; 26552 const getDataTransferItems = dataTransfer => { 26553 const items = {}; 26554 if (dataTransfer && dataTransfer.types) { 26555 for (let i = 0; i < dataTransfer.types.length; i++) { 26556 const contentType = dataTransfer.types[i]; 26557 try { 26558 items[contentType] = dataTransfer.getData(contentType); 26559 } catch (_a) { 26560 items[contentType] = ''; 26561 } 26562 } 26563 } 26564 return items; 26565 }; 26566 const hasContentType = (clipboardContent, mimeType) => mimeType in clipboardContent && clipboardContent[mimeType].length > 0; 26567 const hasHtmlOrText = content => hasContentType(content, 'text/html') || hasContentType(content, 'text/plain'); 26568 const extractFilename = (editor, str) => { 26569 const m = str.match(/([\s\S]+?)(?:\.[a-z0-9.]+)$/i); 26570 return isNonNullable(m) ? editor.dom.encode(m[1]) : undefined; 26571 }; 26572 const createBlobInfo = (editor, blobCache, file, base64) => { 26573 const id = uniqueId(); 26574 const useFileName = shouldReuseFileName(editor) && isNonNullable(file.name); 26575 const name = useFileName ? extractFilename(editor, file.name) : id; 26576 const filename = useFileName ? file.name : undefined; 26577 const blobInfo = blobCache.create(id, file, base64, name, filename); 26578 blobCache.add(blobInfo); 26579 return blobInfo; 26580 }; 26581 const pasteImage = (editor, imageItem) => { 26582 parseDataUri(imageItem.uri).each(({data, type, base64Encoded}) => { 26583 const base64 = base64Encoded ? data : btoa(data); 26584 const file = imageItem.file; 26585 const blobCache = editor.editorUpload.blobCache; 26586 const existingBlobInfo = blobCache.getByData(base64, type); 26587 const blobInfo = existingBlobInfo !== null && existingBlobInfo !== void 0 ? existingBlobInfo : createBlobInfo(editor, blobCache, file, base64); 26588 pasteHtml(editor, `<img src="${ blobInfo.blobUri() }">`, false, true); 26589 }); 26590 }; 26591 const isClipboardEvent = event => event.type === 'paste';
vendor: 6,684 bytes, lines 26592-26753
26592 const readFilesAsDataUris = items => Promise.all(map$3(items, file => { 26593 return blobToDataUri(file).then(uri => ({ 26594 file, 26595 uri 26596 })); 26597 })); 26598 const isImage = editor => { 26599 const allowedExtensions = getAllowedImageFileTypes(editor); 26600 return file => startsWith(file.type, 'image/') && exists(allowedExtensions, extension => { 26601 return getImageMimeType(extension) === file.type; 26602 }); 26603 }; 26604 const getImagesFromDataTransfer = (editor, dataTransfer) => { 26605 const items = dataTransfer.items ? bind$3(from(dataTransfer.items), item => { 26606 return item.kind === 'file' ? [item.getAsFile()] : []; 26607 }) : []; 26608 const files = dataTransfer.files ? from(dataTransfer.files) : []; 26609 return filter$5(items.length > 0 ? items : files, isImage(editor)); 26610 }; 26611 const pasteImageData = (editor, e, rng) => { 26612 const dataTransfer = isClipboardEvent(e) ? e.clipboardData : e.dataTransfer; 26613 if (shouldPasteDataImages(editor) && dataTransfer) { 26614 const images = getImagesFromDataTransfer(editor, dataTransfer); 26615 if (images.length > 0) { 26616 e.preventDefault(); 26617 readFilesAsDataUris(images).then(fileResults => { 26618 if (rng) { 26619 editor.selection.setRng(rng); 26620 } 26621 each$e(fileResults, result => { 26622 pasteImage(editor, result); 26623 }); 26624 }); 26625 return true; 26626 } 26627 } 26628 return false; 26629 }; 26630 const isBrokenAndroidClipboardEvent = e => { 26631 var _a, _b; 26632 return Env.os.isAndroid() && ((_b = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.items) === null || _b === void 0 ? void 0 : _b.length) === 0; 26633 }; 26634 const isKeyboardPasteEvent = e => VK.metaKeyPressed(e) && e.keyCode === 86 || e.shiftKey && e.keyCode === 45; 26635 const insertClipboardContent = (editor, clipboardContent, html, plainTextMode, shouldSimulateInputEvent) => { 26636 let content = trimHtml(html); 26637 const isInternal = hasContentType(clipboardContent, internalHtmlMime()) || isMarked(html); 26638 const isPlainTextHtml = !isInternal && isPlainText(content); 26639 const isAbsoluteUrl$1 = isAbsoluteUrl(content); 26640 if (isDefaultPasteBinContent(content) || !content.length || isPlainTextHtml && !isAbsoluteUrl$1) { 26641 plainTextMode = true; 26642 } 26643 if (plainTextMode || isAbsoluteUrl$1) { 26644 if (hasContentType(clipboardContent, 'text/plain') && isPlainTextHtml) { 26645 content = clipboardContent['text/plain']; 26646 } else { 26647 content = innerText(content); 26648 } 26649 } 26650 if (isDefaultPasteBinContent(content)) { 26651 return; 26652 } 26653 if (plainTextMode) { 26654 pasteText(editor, content, shouldSimulateInputEvent); 26655 } else { 26656 pasteHtml(editor, content, isInternal, shouldSimulateInputEvent); 26657 } 26658 }; 26659 const registerEventHandlers = (editor, pasteBin, pasteFormat) => { 26660 let keyboardPastePlainTextState; 26661 const getLastRng = () => pasteBin.getLastRng() || editor.selection.getRng(); 26662 editor.on('keydown', e => { 26663 if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) { 26664 keyboardPastePlainTextState = e.shiftKey && e.keyCode === 86; 26665 } 26666 }); 26667 editor.on('paste', e => { 26668 if (e.isDefaultPrevented() || isBrokenAndroidClipboardEvent(e)) { 26669 return; 26670 } 26671 const plainTextMode = pasteFormat.get() === 'text' || keyboardPastePlainTextState; 26672 keyboardPastePlainTextState = false; 26673 const clipboardContent = getDataTransferItems(e.clipboardData); 26674 if (!hasHtmlOrText(clipboardContent) && pasteImageData(editor, e, getLastRng())) { 26675 return; 26676 } 26677 if (hasContentType(clipboardContent, 'text/html')) { 26678 e.preventDefault(); 26679 insertClipboardContent(editor, clipboardContent, clipboardContent['text/html'], plainTextMode, true); 26680 } else if (hasContentType(clipboardContent, 'text/plain') && hasContentType(clipboardContent, 'text/uri-list')) { 26681 e.preventDefault(); 26682 insertClipboardContent(editor, clipboardContent, clipboardContent['text/plain'], plainTextMode, true); 26683 } else { 26684 pasteBin.create(); 26685 Delay.setEditorTimeout(editor, () => { 26686 const html = pasteBin.getHtml(); 26687 pasteBin.remove(); 26688 insertClipboardContent(editor, clipboardContent, html, plainTextMode, false); 26689 }, 0); 26690 } 26691 }); 26692 }; 26693 const registerDataImageFilter = editor => { 26694 const isWebKitFakeUrl = src => startsWith(src, 'webkit-fake-url'); 26695 const isDataUri = src => startsWith(src, 'data:'); 26696 const isPasteInsert = args => { 26697 var _a; 26698 return ((_a = args.data) === null || _a === void 0 ? void 0 : _a.paste) === true; 26699 }; 26700 editor.parser.addNodeFilter('img', (nodes, name, args) => { 26701 if (!shouldPasteDataImages(editor) && isPasteInsert(args)) { 26702 for (const node of nodes) { 26703 const src = node.attr('src'); 26704 if (isString(src) && !node.attr('data-mce-object') && src !== Env.transparentSrc) { 26705 if (isWebKitFakeUrl(src)) { 26706 node.remove(); 26707 } else if (!shouldAllowHtmlDataUrls(editor) && isDataUri(src)) { 26708 node.remove(); 26709 } 26710 } 26711 } 26712 } 26713 }); 26714 }; 26715 const registerEventsAndFilters = (editor, pasteBin, pasteFormat) => { 26716 registerEventHandlers(editor, pasteBin, pasteFormat); 26717 registerDataImageFilter(editor); 26718 }; 26719 26720 const togglePlainTextPaste = (editor, pasteFormat) => { 26721 if (pasteFormat.get() === 'text') { 26722 pasteFormat.set('html'); 26723 firePastePlainTextToggle(editor, false); 26724 } else { 26725 pasteFormat.set('text'); 26726 firePastePlainTextToggle(editor, true); 26727 } 26728 editor.focus(); 26729 }; 26730 const register$1 = (editor, pasteFormat) => { 26731 editor.addCommand('mceTogglePlainTextPaste', () => { 26732 togglePlainTextPaste(editor, pasteFormat); 26733 }); 26734 editor.addCommand('mceInsertClipboardContent', (ui, value) => { 26735 if (value.html) { 26736 pasteHtml(editor, value.html, value.internal, false); 26737 } 26738 if (value.text) { 26739 pasteText(editor, value.text, false); 26740 } 26741 }); 26742 }; 26743 26744 const setHtml5Clipboard = (clipboardData, html, text) => { 26745 if (clipboardData) { 26746 try { 26747 clipboardData.clearData(); 26748 clipboardData.setData('text/html', html); 26749 clipboardData.setData('text/plain', text); 26750 clipboardData.setData(internalHtmlMime(), html); 26751 return true; 26752 } catch (_a) { 26753 return false;
vendor: 10,044 bytes, lines 26754-27007
26754 } 26755 } else { 26756 return false; 26757 } 26758 }; 26759 const setClipboardData = (evt, data, fallback, done) => { 26760 if (setHtml5Clipboard(evt.clipboardData, data.html, data.text)) { 26761 evt.preventDefault(); 26762 done(); 26763 } else { 26764 fallback(data.html, done); 26765 } 26766 }; 26767 const fallback = editor => (html, done) => { 26768 const {dom, selection} = editor; 26769 const outer = dom.create('div', { 26770 'contenteditable': 'false', 26771 'data-mce-bogus': 'all' 26772 }); 26773 const inner = dom.create('div', { contenteditable: 'true' }, html); 26774 dom.setStyles(outer, { 26775 position: 'fixed', 26776 top: '0', 26777 left: '-3000px', 26778 width: '1000px', 26779 overflow: 'hidden' 26780 }); 26781 outer.appendChild(inner); 26782 dom.add(editor.getBody(), outer); 26783 const range = selection.getRng(); 26784 inner.focus(); 26785 const offscreenRange = dom.createRng(); 26786 offscreenRange.selectNodeContents(inner); 26787 selection.setRng(offscreenRange); 26788 Delay.setEditorTimeout(editor, () => { 26789 selection.setRng(range); 26790 dom.remove(outer); 26791 done(); 26792 }, 0); 26793 }; 26794 const getData = editor => ({ 26795 html: mark(editor.selection.getContent({ contextual: true })), 26796 text: editor.selection.getContent({ format: 'text' }) 26797 }); 26798 const isTableSelection = editor => !!editor.dom.getParent(editor.selection.getStart(), 'td[data-mce-selected],th[data-mce-selected]', editor.getBody()); 26799 const hasSelectedContent = editor => !editor.selection.isCollapsed() || isTableSelection(editor); 26800 const cut = editor => evt => { 26801 if (!evt.isDefaultPrevented() && hasSelectedContent(editor) && editor.selection.isEditable()) { 26802 setClipboardData(evt, getData(editor), fallback(editor), () => { 26803 if (Env.browser.isChromium() || Env.browser.isFirefox()) { 26804 const rng = editor.selection.getRng(); 26805 Delay.setEditorTimeout(editor, () => { 26806 editor.selection.setRng(rng); 26807 editor.execCommand('Delete'); 26808 }, 0); 26809 } else { 26810 editor.execCommand('Delete'); 26811 } 26812 }); 26813 } 26814 }; 26815 const copy = editor => evt => { 26816 if (!evt.isDefaultPrevented() && hasSelectedContent(editor)) { 26817 setClipboardData(evt, getData(editor), fallback(editor), noop); 26818 } 26819 }; 26820 const register = editor => { 26821 editor.on('cut', cut(editor)); 26822 editor.on('copy', copy(editor)); 26823 }; 26824 26825 const getCaretRangeFromEvent = (editor, e) => { 26826 var _a, _b; 26827 return RangeUtils.getCaretRangeFromPoint((_a = e.clientX) !== null && _a !== void 0 ? _a : 0, (_b = e.clientY) !== null && _b !== void 0 ? _b : 0, editor.getDoc()); 26828 }; 26829 const isPlainTextFileUrl = content => { 26830 const plainTextContent = content['text/plain']; 26831 return plainTextContent ? plainTextContent.indexOf('file://') === 0 : false; 26832 }; 26833 const setFocusedRange = (editor, rng) => { 26834 editor.focus(); 26835 if (rng) { 26836 editor.selection.setRng(rng); 26837 } 26838 }; 26839 const hasImage = dataTransfer => exists(dataTransfer.files, file => /^image\//.test(file.type)); 26840 const needsCustomInternalDrop = (dom, schema, target, dropContent) => { 26841 const parentTransparent = dom.getParent(target, node => isTransparentBlock(schema, node)); 26842 const inSummary = !isNull(dom.getParent(target, 'summary')); 26843 if (inSummary) { 26844 return true; 26845 } else if (parentTransparent && has$2(dropContent, 'text/html')) { 26846 const fragment = new DOMParser().parseFromString(dropContent['text/html'], 'text/html').body; 26847 return !isNull(fragment.querySelector(parentTransparent.nodeName.toLowerCase())); 26848 } else { 26849 return false; 26850 } 26851 }; 26852 const setupSummaryDeleteByDragFix = editor => { 26853 editor.on('input', e => { 26854 const hasNoSummary = el => isNull(el.querySelector('summary')); 26855 if (e.inputType === 'deleteByDrag') { 26856 const brokenDetailElements = filter$5(editor.dom.select('details'), hasNoSummary); 26857 each$e(brokenDetailElements, details => { 26858 if (isBr$6(details.firstChild)) { 26859 details.firstChild.remove(); 26860 } 26861 const summary = editor.dom.create('summary'); 26862 summary.appendChild(createPaddingBr().dom); 26863 details.prepend(summary); 26864 }); 26865 } 26866 }); 26867 }; 26868 const setup$a = (editor, draggingInternallyState) => { 26869 if (shouldPasteBlockDrop(editor)) { 26870 editor.on('dragend dragover draggesture dragdrop drop drag', e => { 26871 e.preventDefault(); 26872 e.stopPropagation(); 26873 }); 26874 } 26875 if (!shouldPasteDataImages(editor)) { 26876 editor.on('drop', e => { 26877 const dataTransfer = e.dataTransfer; 26878 if (dataTransfer && hasImage(dataTransfer)) { 26879 e.preventDefault(); 26880 } 26881 }); 26882 } 26883 editor.on('drop', e => { 26884 if (e.isDefaultPrevented()) { 26885 return; 26886 } 26887 const rng = getCaretRangeFromEvent(editor, e); 26888 if (isNullable(rng)) { 26889 return; 26890 } 26891 const dropContent = getDataTransferItems(e.dataTransfer); 26892 const internal = hasContentType(dropContent, internalHtmlMime()); 26893 if ((!hasHtmlOrText(dropContent) || isPlainTextFileUrl(dropContent)) && pasteImageData(editor, e, rng)) { 26894 return; 26895 } 26896 const internalContent = dropContent[internalHtmlMime()]; 26897 const content = internalContent || dropContent['text/html'] || dropContent['text/plain']; 26898 const needsInternalDrop = needsCustomInternalDrop(editor.dom, editor.schema, rng.startContainer, dropContent); 26899 const isInternalDrop = draggingInternallyState.get(); 26900 if (isInternalDrop && !needsInternalDrop) { 26901 return; 26902 } 26903 if (content) { 26904 e.preventDefault(); 26905 Delay.setEditorTimeout(editor, () => { 26906 editor.undoManager.transact(() => { 26907 if (internalContent || isInternalDrop && needsInternalDrop) { 26908 editor.execCommand('Delete'); 26909 } 26910 setFocusedRange(editor, rng); 26911 const trimmedContent = trimHtml(content); 26912 if (dropContent['text/html']) { 26913 pasteHtml(editor, trimmedContent, internal, true); 26914 } else { 26915 pasteText(editor, trimmedContent, true); 26916 } 26917 }); 26918 }); 26919 } 26920 }); 26921 editor.on('dragstart', _e => { 26922 draggingInternallyState.set(true); 26923 }); 26924 editor.on('dragover dragend', e => { 26925 if (shouldPasteDataImages(editor) && !draggingInternallyState.get()) { 26926 e.preventDefault(); 26927 setFocusedRange(editor, getCaretRangeFromEvent(editor, e)); 26928 } 26929 if (e.type === 'dragend') { 26930 draggingInternallyState.set(false); 26931 } 26932 }); 26933 setupSummaryDeleteByDragFix(editor); 26934 }; 26935 26936 const setup$9 = editor => { 26937 const processEvent = f => e => { 26938 f(editor, e); 26939 }; 26940 const preProcess = getPastePreProcess(editor); 26941 if (isFunction(preProcess)) { 26942 editor.on('PastePreProcess', processEvent(preProcess)); 26943 } 26944 const postProcess = getPastePostProcess(editor); 26945 if (isFunction(postProcess)) { 26946 editor.on('PastePostProcess', processEvent(postProcess)); 26947 } 26948 }; 26949 26950 const addPreProcessFilter = (editor, filterFunc) => { 26951 editor.on('PastePreProcess', e => { 26952 e.content = filterFunc(editor, e.content, e.internal); 26953 }); 26954 }; 26955 const rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi; 26956 const rgbToHex = value => Tools.trim(value).replace(rgbRegExp, rgbaToHexString).toLowerCase(); 26957 const removeWebKitStyles = (editor, content, internal) => { 26958 const webKitStylesOption = getPasteWebkitStyles(editor); 26959 if (internal || webKitStylesOption === 'all' || !shouldPasteRemoveWebKitStyles(editor)) { 26960 return content; 26961 } 26962 const webKitStyles = webKitStylesOption ? webKitStylesOption.split(/[, ]/) : []; 26963 if (webKitStyles && webKitStylesOption !== 'none') { 26964 const dom = editor.dom, node = editor.selection.getNode(); 26965 content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, (all, before, value, after) => { 26966 const inputStyles = dom.parseStyle(dom.decode(value)); 26967 const outputStyles = {}; 26968 for (let i = 0; i < webKitStyles.length; i++) { 26969 const inputValue = inputStyles[webKitStyles[i]]; 26970 let compareInput = inputValue; 26971 let currentValue = dom.getStyle(node, webKitStyles[i], true); 26972 if (/color/.test(webKitStyles[i])) { 26973 compareInput = rgbToHex(compareInput); 26974 currentValue = rgbToHex(currentValue); 26975 } 26976 if (currentValue !== compareInput) { 26977 outputStyles[webKitStyles[i]] = inputValue; 26978 } 26979 } 26980 const outputStyle = dom.serializeStyle(outputStyles, 'span'); 26981 if (outputStyle) { 26982 return before + ' style="' + outputStyle + '"' + after; 26983 } 26984 return before + after; 26985 }); 26986 } else { 26987 content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, '$1$3'); 26988 } 26989 content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, (all, before, value, after) => { 26990 return before + ' style="' + value + '"' + after; 26991 }); 26992 return content; 26993 }; 26994 const setup$8 = editor => { 26995 if (Env.browser.isChromium() || Env.browser.isSafari()) { 26996 addPreProcessFilter(editor, removeWebKitStyles); 26997 } 26998 }; 26999 27000 const setup$7 = editor => { 27001 const draggingInternallyState = Cell(false); 27002 const pasteFormat = Cell(isPasteAsTextEnabled(editor) ? 'text' : 'html'); 27003 const pasteBin = PasteBin(editor); 27004 setup$8(editor); 27005 register$1(editor, pasteFormat); 27006 setup$9(editor); 27007 editor.addQueryStateHandler('mceTogglePlainTextPaste', () => pasteFormat.get() === 'text'
vendor: 12,057 bytes, lines 27007-27291
27007); 27008 editor.on('PreInit', () => { 27009 register(editor); 27010 setup$a(editor, draggingInternallyState); 27011 registerEventsAndFilters(editor, pasteBin, pasteFormat); 27012 }); 27013 }; 27014 27015 const preventSummaryToggle = editor => { 27016 editor.on('click', e => { 27017 if (editor.dom.getParent(e.target, 'details')) { 27018 e.preventDefault(); 27019 } 27020 }); 27021 }; 27022 const filterDetails = editor => { 27023 editor.parser.addNodeFilter('details', elms => { 27024 const initialStateOption = getDetailsInitialState(editor); 27025 each$e(elms, details => { 27026 if (initialStateOption === 'expanded') { 27027 details.attr('open', 'open'); 27028 } else if (initialStateOption === 'collapsed') { 27029 details.attr('open', null); 27030 } 27031 }); 27032 }); 27033 editor.serializer.addNodeFilter('details', elms => { 27034 const serializedStateOption = getDetailsSerializedState(editor); 27035 each$e(elms, details => { 27036 if (serializedStateOption === 'expanded') { 27037 details.attr('open', 'open'); 27038 } else if (serializedStateOption === 'collapsed') { 27039 details.attr('open', null); 27040 } 27041 }); 27042 }); 27043 }; 27044 const setup$6 = editor => { 27045 preventSummaryToggle(editor); 27046 filterDetails(editor); 27047 }; 27048 27049 const isBr = isBr$6; 27050 const isText = isText$b; 27051 const isContentEditableFalse$2 = elm => isContentEditableFalse$b(elm.dom); 27052 const isContentEditableTrue = elm => isContentEditableTrue$3(elm.dom); 27053 const isRoot = rootNode => elm => eq(SugarElement.fromDom(rootNode), elm); 27054 const getClosestScope = (node, rootNode, schema) => closest$4(SugarElement.fromDom(node), elm => isContentEditableTrue(elm) || schema.isBlock(name(elm)), isRoot(rootNode)).getOr(SugarElement.fromDom(rootNode)).dom; 27055 const getClosestCef = (node, rootNode) => closest$4(SugarElement.fromDom(node), isContentEditableFalse$2, isRoot(rootNode)); 27056 const findEdgeCaretCandidate = (startNode, scope, forward) => { 27057 const walker = new DomTreeWalker(startNode, scope); 27058 const next = forward ? walker.next.bind(walker) : walker.prev.bind(walker); 27059 let result = startNode; 27060 for (let current = forward ? startNode : next(); current && !isBr(current); current = next()) { 27061 if (isCaretCandidate$3(current)) { 27062 result = current; 27063 } 27064 } 27065 return result; 27066 }; 27067 const findClosestBlockRange = (startRng, rootNode, schema) => { 27068 const startPos = CaretPosition.fromRangeStart(startRng); 27069 const clickNode = startPos.getNode(); 27070 const scope = getClosestScope(clickNode, rootNode, schema); 27071 const startNode = findEdgeCaretCandidate(clickNode, scope, false); 27072 const endNode = findEdgeCaretCandidate(clickNode, scope, true); 27073 const rng = document.createRange(); 27074 getClosestCef(startNode, scope).fold(() => { 27075 if (isText(startNode)) { 27076 rng.setStart(startNode, 0); 27077 } else { 27078 rng.setStartBefore(startNode); 27079 } 27080 }, cef => rng.setStartBefore(cef.dom)); 27081 getClosestCef(endNode, scope).fold(() => { 27082 if (isText(endNode)) { 27083 rng.setEnd(endNode, endNode.data.length); 27084 } else { 27085 rng.setEndAfter(endNode); 27086 } 27087 }, cef => rng.setEndAfter(cef.dom)); 27088 return rng; 27089 }; 27090 const onTripleClickSelect = editor => { 27091 const rng = findClosestBlockRange(editor.selection.getRng(), editor.getBody(), editor.schema); 27092 editor.selection.setRng(normalize(rng)); 27093 }; 27094 const setup$5 = editor => { 27095 editor.on('mousedown', e => { 27096 if (e.detail >= 3) { 27097 e.preventDefault(); 27098 onTripleClickSelect(editor); 27099 } 27100 }); 27101 }; 27102 27103 var FakeCaretPosition; 27104 (function (FakeCaretPosition) { 27105 FakeCaretPosition['Before'] = 'before'; 27106 FakeCaretPosition['After'] = 'after'; 27107 }(FakeCaretPosition || (FakeCaretPosition = {}))); 27108 const distanceToRectLeft = (clientRect, clientX) => Math.abs(clientRect.left - clientX); 27109 const distanceToRectRight = (clientRect, clientX) => Math.abs(clientRect.right - clientX); 27110 const isInsideY = (clientY, clientRect) => clientY >= clientRect.top && clientY <= clientRect.bottom; 27111 const collidesY = (r1, r2) => r1.top < r2.bottom && r1.bottom > r2.top; 27112 const isOverlapping = (r1, r2) => { 27113 const overlap = overlapY(r1, r2) / Math.min(r1.height, r2.height); 27114 return collidesY(r1, r2) && overlap > 0.5; 27115 }; 27116 const splitRectsPerAxis = (rects, y) => { 27117 const intersectingRects = filter$5(rects, rect => isInsideY(y, rect)); 27118 return boundingClientRectFromRects(intersectingRects).fold(() => [ 27119 [], 27120 rects 27121 ], boundingRect => { 27122 const { 27123 pass: horizontal, 27124 fail: vertical 27125 } = partition$2(rects, rect => isOverlapping(rect, boundingRect)); 27126 return [ 27127 horizontal, 27128 vertical 27129 ]; 27130 }); 27131 }; 27132 const clientInfo = (rect, clientX) => { 27133 return { 27134 node: rect.node, 27135 position: distanceToRectLeft(rect, clientX) < distanceToRectRight(rect, clientX) ? FakeCaretPosition.Before : FakeCaretPosition.After 27136 }; 27137 }; 27138 const horizontalDistance = (rect, x, _y) => x > rect.left && x < rect.right ? 0 : Math.min(Math.abs(rect.left - x), Math.abs(rect.right - x)); 27139 const closestChildCaretCandidateNodeRect = (children, clientX, clientY, findCloserTextNode) => { 27140 const caretCandidateRect = rect => { 27141 if (isCaretCandidate$3(rect.node)) { 27142 return Optional.some(rect); 27143 } else if (isElement$6(rect.node)) { 27144 return closestChildCaretCandidateNodeRect(from(rect.node.childNodes), clientX, clientY, false); 27145 } else { 27146 return Optional.none(); 27147 } 27148 }; 27149 const tryFindSecondBestTextNode = (closest, sndClosest, distance) => { 27150 return caretCandidateRect(sndClosest).filter(rect => { 27151 const deltaDistance = Math.abs(distance(closest, clientX, clientY) - distance(rect, clientX, clientY)); 27152 return deltaDistance < 2 && isText$b(rect.node); 27153 }); 27154 }; 27155 const findClosestCaretCandidateNodeRect = (rects, distance) => { 27156 const sortedRects = sort(rects, (r1, r2) => distance(r1, clientX, clientY) - distance(r2, clientX, clientY)); 27157 return findMap(sortedRects, caretCandidateRect).map(closest => { 27158 if (findCloserTextNode && !isText$b(closest.node) && sortedRects.length > 1) { 27159 return tryFindSecondBestTextNode(closest, sortedRects[1], distance).getOr(closest); 27160 } else { 27161 return closest; 27162 } 27163 }); 27164 }; 27165 const [horizontalRects, verticalRects] = splitRectsPerAxis(getClientRects(children), clientY); 27166 const { 27167 pass: above, 27168 fail: below 27169 } = partition$2(verticalRects, rect => rect.top < clientY); 27170 return findClosestCaretCandidateNodeRect(horizontalRects, horizontalDistance).orThunk(() => findClosestCaretCandidateNodeRect(below, distanceToRectEdgeFromXY)).orThunk(() => findClosestCaretCandidateNodeRect(above, distanceToRectEdgeFromXY)); 27171 }; 27172 const traverseUp = (rootElm, scope, clientX, clientY) => { 27173 const helper = (scope, prevScope) => { 27174 const isDragGhostContainer = node => isElement$6(node) && node.classList.contains('mce-drag-container'); 27175 const childNodesWithoutGhost = filter$5(scope.dom.childNodes, not(isDragGhostContainer)); 27176 return prevScope.fold(() => closestChildCaretCandidateNodeRect(childNodesWithoutGhost, clientX, clientY, true), prevScope => { 27177 const uncheckedChildren = filter$5(childNodesWithoutGhost, node => node !== prevScope.dom); 27178 return closestChildCaretCandidateNodeRect(uncheckedChildren, clientX, clientY, true); 27179 }).orThunk(() => { 27180 const parent = eq(scope, rootElm) ? Optional.none() : parentElement(scope); 27181 return parent.bind(newScope => helper(newScope, Optional.some(scope))); 27182 }); 27183 }; 27184 return helper(scope, Optional.none()); 27185 }; 27186 const closestCaretCandidateNodeRect = (root, clientX, clientY) => { 27187 const rootElm = SugarElement.fromDom(root); 27188 const ownerDoc = documentOrOwner(rootElm); 27189 const elementAtPoint = SugarElement.fromPoint(ownerDoc, clientX, clientY).filter(elm => contains(rootElm, elm)); 27190 const element = elementAtPoint.getOr(rootElm); 27191 return traverseUp(rootElm, element, clientX, clientY); 27192 }; 27193 const closestFakeCaretCandidate = (root, clientX, clientY) => closestCaretCandidateNodeRect(root, clientX, clientY).filter(rect => isFakeCaretTarget(rect.node)).map(rect => clientInfo(rect, clientX)); 27194 27195 const getAbsolutePosition = elm => { 27196 var _a, _b; 27197 const clientRect = elm.getBoundingClientRect(); 27198 const doc = elm.ownerDocument; 27199 const docElem = doc.documentElement; 27200 const win = doc.defaultView; 27201 return { 27202 top: clientRect.top + ((_a = win === null || win === void 0 ? void 0 : win.scrollY) !== null && _a !== void 0 ? _a : 0) - docElem.clientTop, 27203 left: clientRect.left + ((_b = win === null || win === void 0 ? void 0 : win.scrollX) !== null && _b !== void 0 ? _b : 0) - docElem.clientLeft 27204 }; 27205 }; 27206 const getBodyPosition = editor => editor.inline ? getAbsolutePosition(editor.getBody()) : { 27207 left: 0, 27208 top: 0 27209 }; 27210 const getScrollPosition = editor => { 27211 const body = editor.getBody(); 27212 return editor.inline ? { 27213 left: body.scrollLeft, 27214 top: body.scrollTop 27215 } : { 27216 left: 0, 27217 top: 0 27218 }; 27219 }; 27220 const getBodyScroll = editor => { 27221 const body = editor.getBody(), docElm = editor.getDoc().documentElement; 27222 const inlineScroll = { 27223 left: body.scrollLeft, 27224 top: body.scrollTop 27225 }; 27226 const iframeScroll = { 27227 left: body.scrollLeft || docElm.scrollLeft, 27228 top: body.scrollTop || docElm.scrollTop 27229 }; 27230 return editor.inline ? inlineScroll : iframeScroll; 27231 }; 27232 const getMousePosition = (editor, event) => { 27233 if (event.target.ownerDocument !== editor.getDoc()) { 27234 const iframePosition = getAbsolutePosition(editor.getContentAreaContainer()); 27235 const scrollPosition = getBodyScroll(editor); 27236 return { 27237 left: event.pageX - iframePosition.left + scrollPosition.left, 27238 top: event.pageY - iframePosition.top + scrollPosition.top 27239 }; 27240 } 27241 return { 27242 left: event.pageX, 27243 top: event.pageY 27244 }; 27245 }; 27246 const calculatePosition = (bodyPosition, scrollPosition, mousePosition) => ({ 27247 pageX: mousePosition.left - bodyPosition.left + scrollPosition.left, 27248 pageY: mousePosition.top - bodyPosition.top + scrollPosition.top 27249 }); 27250 const calc = (editor, event) => calculatePosition(getBodyPosition(editor), getScrollPosition(editor), getMousePosition(editor, event)); 27251 27252 const getTargetProps = target => ({ 27253 target, 27254 srcElement: target 27255 }); 27256 const makeDndEventFromMouseEvent = (type, mouseEvent, target, dataTransfer) => ({ 27257 ...mouseEvent, 27258 dataTransfer, 27259 type, 27260 ...getTargetProps(target) 27261 }); 27262 const makeDndEvent = (type, target, dataTransfer) => { 27263 const fail = die('Function not supported on simulated event.'); 27264 const event = { 27265 bubbles: true, 27266 cancelBubble: false, 27267 cancelable: true, 27268 composed: false, 27269 currentTarget: null, 27270 defaultPrevented: false, 27271 eventPhase: 0, 27272 isTrusted: true, 27273 returnValue: false, 27274 timeStamp: 0, 27275 type, 27276 composedPath: fail, 27277 initEvent: fail, 27278 preventDefault: noop, 27279 stopImmediatePropagation: noop, 27280 stopPropagation: noop, 27281 AT_TARGET: window.Event.AT_TARGET, 27282 BUBBLING_PHASE: window.Event.BUBBLING_PHASE, 27283 CAPTURING_PHASE: window.Event.CAPTURING_PHASE, 27284 NONE: window.Event.NONE, 27285 altKey: false, 27286 button: 0, 27287 buttons: 0, 27288 clientX: 0, 27289 clientY: 0, 27290 ctrlKey: false, 27291
27291layerX: 0, 27292 layerY: 0
vendor: 7,989 bytes, lines 27292-27486
27292, 27293 metaKey: false, 27294 movementX: 0, 27295 movementY: 0, 27296 offsetX: 0, 27297 offsetY: 0, 27298 pageX: 0, 27299 pageY: 0, 27300 relatedTarget: null, 27301 screenX: 0, 27302 screenY: 0, 27303 shiftKey: false, 27304 x: 0, 27305 y: 0, 27306 detail: 0, 27307 view: null, 27308 which: 0, 27309 initUIEvent: fail, 27310 initMouseEvent: fail, 27311 getModifierState: fail, 27312 dataTransfer, 27313 ...getTargetProps(target) 27314 }; 27315 return event; 27316 }; 27317 const makeDataTransferCopyForDragEvent = (dataTransfer, eventType) => { 27318 const copy = cloneDataTransfer(dataTransfer); 27319 if (eventType === 'dragstart') { 27320 setDragstartEvent(copy); 27321 setReadWriteMode(copy); 27322 } else if (eventType === 'drop') { 27323 setDropEvent(copy); 27324 setReadOnlyMode(copy); 27325 } else { 27326 setDragendEvent(copy); 27327 setProtectedMode(copy); 27328 } 27329 return copy; 27330 }; 27331 const makeDragEvent = (type, target, dataTransfer, mouseEvent) => { 27332 const dataTransferForDispatch = makeDataTransferCopyForDragEvent(dataTransfer, type); 27333 return isUndefined(mouseEvent) ? makeDndEvent(type, target, dataTransferForDispatch) : makeDndEventFromMouseEvent(type, mouseEvent, target, dataTransferForDispatch); 27334 }; 27335 27336 const scrollPixelsPerInterval = 32; 27337 const scrollIntervalValue = 100; 27338 const mouseRangeToTriggerScrollInsideEditor = 8; 27339 const mouseRangeToTriggerScrollOutsideEditor = 16; 27340 const isContentEditableFalse$1 = isContentEditableFalse$b; 27341 const isContentEditable = or(isContentEditableFalse$1, isContentEditableTrue$3); 27342 const isDraggable = (dom, rootElm, elm) => isContentEditableFalse$1(elm) && elm !== rootElm && dom.isEditable(elm.parentElement); 27343 const isValidDropTarget = (editor, targetElement, dragElement) => { 27344 if (isNullable(targetElement)) { 27345 return false; 27346 } else if (targetElement === dragElement || editor.dom.isChildOf(targetElement, dragElement)) { 27347 return false; 27348 } else { 27349 return editor.dom.isEditable(targetElement); 27350 } 27351 }; 27352 const createGhost = (editor, elm, width, height) => { 27353 const dom = editor.dom; 27354 const clonedElm = elm.cloneNode(true); 27355 dom.setStyles(clonedElm, { 27356 width, 27357 height 27358 }); 27359 dom.setAttrib(clonedElm, 'data-mce-selected', null); 27360 const ghostElm = dom.create('div', { 27361 'class': 'mce-drag-container', 27362 'data-mce-bogus': 'all', 27363 'unselectable': 'on', 27364 'contenteditable': 'false' 27365 }); 27366 dom.setStyles(ghostElm, { 27367 position: 'absolute', 27368 opacity: 0.5, 27369 overflow: 'hidden', 27370 border: 0, 27371 padding: 0, 27372 margin: 0, 27373 width, 27374 height 27375 }); 27376 dom.setStyles(clonedElm, { 27377 margin: 0, 27378 boxSizing: 'border-box' 27379 }); 27380 ghostElm.appendChild(clonedElm); 27381 return ghostElm; 27382 }; 27383 const appendGhostToBody = (ghostElm, bodyElm) => { 27384 if (ghostElm.parentNode !== bodyElm) { 27385 bodyElm.appendChild(ghostElm); 27386 } 27387 }; 27388 const scrollEditor = (direction, amount) => win => () => { 27389 const current = direction === 'left' ? win.scrollX : win.scrollY; 27390 win.scroll({ 27391 [direction]: current + amount, 27392 behavior: 'smooth' 27393 }); 27394 }; 27395 const scrollLeft = scrollEditor('left', -scrollPixelsPerInterval); 27396 const scrollRight = scrollEditor('left', scrollPixelsPerInterval); 27397 const scrollUp = scrollEditor('top', -scrollPixelsPerInterval); 27398 const scrollDown = scrollEditor('top', scrollPixelsPerInterval); 27399 const moveGhost = (ghostElm, position, width, height, maxX, maxY, mouseY, mouseX, contentAreaContainer, win, state, mouseEventOriginatedFromWithinTheEditor) => { 27400 let overflowX = 0, overflowY = 0; 27401 ghostElm.style.left = position.pageX + 'px'; 27402 ghostElm.style.top = position.pageY + 'px'; 27403 if (position.pageX + width > maxX) { 27404 overflowX = position.pageX + width - maxX; 27405 } 27406 if (position.pageY + height > maxY) { 27407 overflowY = position.pageY + height - maxY; 27408 } 27409 ghostElm.style.width = width - overflowX + 'px'; 27410 ghostElm.style.height = height - overflowY + 'px'; 27411 const clientHeight = contentAreaContainer.clientHeight; 27412 const clientWidth = contentAreaContainer.clientWidth; 27413 const outerMouseY = mouseY + contentAreaContainer.getBoundingClientRect().top; 27414 const outerMouseX = mouseX + contentAreaContainer.getBoundingClientRect().left; 27415 state.on(state => { 27416 state.intervalId.clear(); 27417 if (state.dragging && mouseEventOriginatedFromWithinTheEditor) { 27418 if (mouseY + mouseRangeToTriggerScrollInsideEditor >= clientHeight) { 27419 state.intervalId.set(scrollDown(win)); 27420 } else if (mouseY - mouseRangeToTriggerScrollInsideEditor <= 0) { 27421 state.intervalId.set(scrollUp(win)); 27422 } else if (mouseX + mouseRangeToTriggerScrollInsideEditor >= clientWidth) { 27423 state.intervalId.set(scrollRight(win)); 27424 } else if (mouseX - mouseRangeToTriggerScrollInsideEditor <= 0) { 27425 state.intervalId.set(scrollLeft(win)); 27426 } else if (outerMouseY + mouseRangeToTriggerScrollOutsideEditor >= window.innerHeight) { 27427 state.intervalId.set(scrollDown(window)); 27428 } else if (outerMouseY - mouseRangeToTriggerScrollOutsideEditor <= 0) { 27429 state.intervalId.set(scrollUp(window)); 27430 } else if (outerMouseX + mouseRangeToTriggerScrollOutsideEditor >= window.innerWidth) { 27431 state.intervalId.set(scrollRight(window)); 27432 } else if (outerMouseX - mouseRangeToTriggerScrollOutsideEditor <= 0) { 27433 state.intervalId.set(scrollLeft(window)); 27434 } 27435 } 27436 }); 27437 }; 27438 const removeElement = elm => { 27439 if (elm && elm.parentNode) { 27440 elm.parentNode.removeChild(elm); 27441 } 27442 }; 27443 const removeElementWithPadding = (dom, elm) => { 27444 const parentBlock = dom.getParent(elm.parentNode, dom.isBlock); 27445 removeElement(elm); 27446 if (parentBlock && parentBlock !== dom.getRoot() && dom.isEmpty(parentBlock)) { 27447 fillWithPaddingBr(SugarElement.fromDom(parentBlock)); 27448 } 27449 }; 27450 const isLeftMouseButtonPressed = e => e.button === 0; 27451 const applyRelPos = (state, position) => ({ 27452 pageX: position.pageX - state.relX, 27453 pageY: position.pageY + 5 27454 }); 27455 const start = (state, editor) => e => { 27456 if (isLeftMouseButtonPressed(e)) { 27457 const ceElm = find$2(editor.dom.getParents(e.target), isContentEditable).getOr(null); 27458 if (isNonNullable(ceElm) && isDraggable(editor.dom, editor.getBody(), ceElm)) { 27459 const elmPos = editor.dom.getPos(ceElm); 27460 const bodyElm = editor.getBody(); 27461 const docElm = editor.getDoc().documentElement; 27462 state.set({ 27463 element: ceElm, 27464 dataTransfer: createDataTransfer(), 27465 dragging: false, 27466 screenX: e.screenX, 27467 screenY: e.screenY, 27468 maxX: (editor.inline ? bodyElm.scrollWidth : docElm.offsetWidth) - 2, 27469 maxY: (editor.inline ? bodyElm.scrollHeight : docElm.offsetHeight) - 2, 27470 relX: e.pageX - elmPos.x, 27471 relY: e.pageY - elmPos.y, 27472 width: ceElm.offsetWidth, 27473 height: ceElm.offsetHeight, 27474 ghost: createGhost(editor, ceElm, ceElm.offsetWidth, ceElm.offsetHeight), 27475 intervalId: repeatable(scrollIntervalValue) 27476 }); 27477 } 27478 } 27479 }; 27480 const placeCaretAt = (editor, clientX, clientY) => { 27481 editor._selectionOverrides.hideFakeCaret(); 27482 closestFakeCaretCandidate(editor.getBody(), clientX, clientY).fold(() => editor.selection.placeCaretAt(clientX, clientY), caretInfo => { 27483 const range = editor._selectionOverrides.showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false); 27484 if (range) { 27485 editor.selection.setRng(range); 27486 } else {
vendor: 13,997 bytes, lines 27487-27835
27487 editor.selection.placeCaretAt(clientX, clientY); 27488 } 27489 }); 27490 }; 27491 const dispatchDragEvent = (editor, type, target, dataTransfer, mouseEvent) => { 27492 if (type === 'dragstart') { 27493 setHtmlData(dataTransfer, editor.dom.getOuterHTML(target)); 27494 } 27495 const event = makeDragEvent(type, target, dataTransfer, mouseEvent); 27496 const args = editor.dispatch(type, event); 27497 return args; 27498 }; 27499 const move = (state, editor) => { 27500 const throttledPlaceCaretAt = first$1((clientX, clientY) => placeCaretAt(editor, clientX, clientY), 0); 27501 editor.on('remove', throttledPlaceCaretAt.cancel); 27502 const state_ = state; 27503 return e => state.on(state => { 27504 const movement = Math.max(Math.abs(e.screenX - state.screenX), Math.abs(e.screenY - state.screenY)); 27505 if (!state.dragging && movement > 10) { 27506 const args = dispatchDragEvent(editor, 'dragstart', state.element, state.dataTransfer, e); 27507 if (isNonNullable(args.dataTransfer)) { 27508 state.dataTransfer = args.dataTransfer; 27509 } 27510 if (args.isDefaultPrevented()) { 27511 return; 27512 } 27513 state.dragging = true; 27514 editor.focus(); 27515 } 27516 if (state.dragging) { 27517 const mouseEventOriginatedFromWithinTheEditor = e.currentTarget === editor.getDoc().documentElement; 27518 const targetPos = applyRelPos(state, calc(editor, e)); 27519 appendGhostToBody(state.ghost, editor.getBody()); 27520 moveGhost(state.ghost, targetPos, state.width, state.height, state.maxX, state.maxY, e.clientY, e.clientX, editor.getContentAreaContainer(), editor.getWin(), state_, mouseEventOriginatedFromWithinTheEditor); 27521 throttledPlaceCaretAt.throttle(e.clientX, e.clientY); 27522 } 27523 }); 27524 }; 27525 const getRawTarget = selection => { 27526 const sel = selection.getSel(); 27527 if (isNonNullable(sel)) { 27528 const rng = sel.getRangeAt(0); 27529 const startContainer = rng.startContainer; 27530 return isText$b(startContainer) ? startContainer.parentNode : startContainer; 27531 } else { 27532 return null; 27533 } 27534 }; 27535 const drop = (state, editor) => e => { 27536 state.on(state => { 27537 var _a; 27538 state.intervalId.clear(); 27539 if (state.dragging) { 27540 if (isValidDropTarget(editor, getRawTarget(editor.selection), state.element)) { 27541 const dropTarget = (_a = editor.getDoc().elementFromPoint(e.clientX, e.clientY)) !== null && _a !== void 0 ? _a : editor.getBody(); 27542 const args = dispatchDragEvent(editor, 'drop', dropTarget, state.dataTransfer, e); 27543 if (!args.isDefaultPrevented()) { 27544 editor.undoManager.transact(() => { 27545 removeElementWithPadding(editor.dom, state.element); 27546 getHtmlData(state.dataTransfer).each(content => editor.insertContent(content)); 27547 editor._selectionOverrides.hideFakeCaret(); 27548 }); 27549 } 27550 } 27551 dispatchDragEvent(editor, 'dragend', editor.getBody(), state.dataTransfer, e); 27552 } 27553 }); 27554 removeDragState(state); 27555 }; 27556 const stopDragging = (state, editor, e) => { 27557 state.on(state => { 27558 state.intervalId.clear(); 27559 if (state.dragging) { 27560 e.fold(() => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer), mouseEvent => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer, mouseEvent)); 27561 } 27562 }); 27563 removeDragState(state); 27564 }; 27565 const stop = (state, editor) => e => stopDragging(state, editor, Optional.some(e)); 27566 const removeDragState = state => { 27567 state.on(state => { 27568 state.intervalId.clear(); 27569 removeElement(state.ghost); 27570 }); 27571 state.clear(); 27572 }; 27573 const bindFakeDragEvents = editor => { 27574 const state = value$2(); 27575 const pageDom = DOMUtils.DOM; 27576 const rootDocument = document; 27577 const dragStartHandler = start(state, editor); 27578 const dragHandler = move(state, editor); 27579 const dropHandler = drop(state, editor); 27580 const dragEndHandler = stop(state, editor); 27581 editor.on('mousedown', dragStartHandler); 27582 editor.on('mousemove', dragHandler); 27583 editor.on('mouseup', dropHandler); 27584 pageDom.bind(rootDocument, 'mousemove', dragHandler); 27585 pageDom.bind(rootDocument, 'mouseup', dragEndHandler); 27586 editor.on('remove', () => { 27587 pageDom.unbind(rootDocument, 'mousemove', dragHandler); 27588 pageDom.unbind(rootDocument, 'mouseup', dragEndHandler); 27589 }); 27590 editor.on('keydown', e => { 27591 if (e.keyCode === VK.ESC) { 27592 stopDragging(state, editor, Optional.none()); 27593 } 27594 }); 27595 }; 27596 const blockUnsupportedFileDrop = editor => { 27597 const preventFileDrop = e => { 27598 if (!e.isDefaultPrevented()) { 27599 const dataTransfer = e.dataTransfer; 27600 if (dataTransfer && (contains$2(dataTransfer.types, 'Files') || dataTransfer.files.length > 0)) { 27601 e.preventDefault(); 27602 if (e.type === 'drop') { 27603 displayError(editor, 'Dropped file type is not supported'); 27604 } 27605 } 27606 } 27607 }; 27608 const preventFileDropIfUIElement = e => { 27609 if (isUIElement(editor, e.target)) { 27610 preventFileDrop(e); 27611 } 27612 }; 27613 const setup = () => { 27614 const pageDom = DOMUtils.DOM; 27615 const dom = editor.dom; 27616 const doc = document; 27617 const editorRoot = editor.inline ? editor.getBody() : editor.getDoc(); 27618 const eventNames = [ 27619 'drop', 27620 'dragover' 27621 ]; 27622 each$e(eventNames, name => { 27623 pageDom.bind(doc, name, preventFileDropIfUIElement); 27624 dom.bind(editorRoot, name, preventFileDrop); 27625 }); 27626 editor.on('remove', () => { 27627 each$e(eventNames, name => { 27628 pageDom.unbind(doc, name, preventFileDropIfUIElement); 27629 dom.unbind(editorRoot, name, preventFileDrop); 27630 }); 27631 }); 27632 }; 27633 editor.on('init', () => { 27634 Delay.setEditorTimeout(editor, setup, 0); 27635 }); 27636 }; 27637 const init$2 = editor => { 27638 bindFakeDragEvents(editor); 27639 if (shouldBlockUnsupportedDrop(editor)) { 27640 blockUnsupportedFileDrop(editor); 27641 } 27642 }; 27643 27644 const setup$4 = editor => { 27645 const renderFocusCaret = first$1(() => { 27646 if (!editor.removed && editor.getBody().contains(document.activeElement)) { 27647 const rng = editor.selection.getRng(); 27648 if (rng.collapsed) { 27649 const caretRange = renderRangeCaret(editor, rng, false); 27650 editor.selection.setRng(caretRange); 27651 } 27652 } 27653 }, 0); 27654 editor.on('focus', () => { 27655 renderFocusCaret.throttle(); 27656 }); 27657 editor.on('blur', () => { 27658 renderFocusCaret.cancel(); 27659 }); 27660 }; 27661 27662 const setup$3 = editor => { 27663 editor.on('init', () => { 27664 editor.on('focusin', e => { 27665 const target = e.target; 27666 if (isMedia$2(target)) { 27667 const ceRoot = getContentEditableRoot$1(editor.getBody(), target); 27668 const node = isContentEditableFalse$b(ceRoot) ? ceRoot : target; 27669 if (editor.selection.getNode() !== node) { 27670 selectNode(editor, node).each(rng => editor.selection.setRng(rng)); 27671 } 27672 } 27673 }); 27674 }); 27675 }; 27676 27677 const isContentEditableFalse = isContentEditableFalse$b; 27678 const getContentEditableRoot = (editor, node) => getContentEditableRoot$1(editor.getBody(), node); 27679 const SelectionOverrides = editor => { 27680 const selection = editor.selection, dom = editor.dom; 27681 const rootNode = editor.getBody(); 27682 const fakeCaret = FakeCaret(editor, rootNode, dom.isBlock, () => hasFocus(editor)); 27683 const realSelectionId = 'sel-' + dom.uniqueId(); 27684 const elementSelectionAttr = 'data-mce-selected'; 27685 let selectedElement; 27686 const isFakeSelectionElement = node => isNonNullable(node) && dom.hasClass(node, 'mce-offscreen-selection'); 27687 const isFakeSelectionTargetElement = node => node !== rootNode && (isContentEditableFalse(node) || isMedia$2(node)) && dom.isChildOf(node, rootNode) && dom.isEditable(node.parentNode); 27688 const setRange = range => { 27689 if (range) { 27690 selection.setRng(range); 27691 } 27692 }; 27693 const showCaret = (direction, node, before, scrollIntoView = true) => { 27694 const e = editor.dispatch('ShowCaret', { 27695 target: node, 27696 direction, 27697 before 27698 }); 27699 if (e.isDefaultPrevented()) { 27700 return null; 27701 } 27702 if (scrollIntoView) { 27703 selection.scrollIntoView(node, direction === -1); 27704 } 27705 return fakeCaret.show(before, node); 27706 }; 27707 const showBlockCaretContainer = blockCaretContainer => { 27708 if (blockCaretContainer.hasAttribute('data-mce-caret')) { 27709 showCaretContainerBlock(blockCaretContainer); 27710 selection.scrollIntoView(blockCaretContainer); 27711 } 27712 }; 27713 const registerEvents = () => { 27714 editor.on('click', e => { 27715 if (!dom.isEditable(e.target)) { 27716 e.preventDefault(); 27717 editor.focus(); 27718 } 27719 }); 27720 editor.on('blur NewBlock', removeElementSelection); 27721 editor.on('ResizeWindow FullscreenStateChanged', fakeCaret.reposition); 27722 editor.on('tap', e => { 27723 const targetElm = e.target; 27724 const contentEditableRoot = getContentEditableRoot(editor, targetElm); 27725 if (isContentEditableFalse(contentEditableRoot)) { 27726 e.preventDefault(); 27727 selectNode(editor, contentEditableRoot).each(setElementSelection); 27728 } else if (isFakeSelectionTargetElement(targetElm)) { 27729 selectNode(editor, targetElm).each(setElementSelection); 27730 } 27731 }, true); 27732 editor.on('mousedown', e => { 27733 const targetElm = e.target; 27734 if (targetElm !== rootNode && targetElm.nodeName !== 'HTML' && !dom.isChildOf(targetElm, rootNode)) { 27735 return; 27736 } 27737 if (!isXYInContentArea(editor, e.clientX, e.clientY)) { 27738 return; 27739 } 27740 removeElementSelection(); 27741 hideFakeCaret(); 27742 const closestContentEditable = getContentEditableRoot(editor, targetElm); 27743 if (isContentEditableFalse(closestContentEditable)) { 27744 e.preventDefault(); 27745 selectNode(editor, closestContentEditable).each(setElementSelection); 27746 } else { 27747 closestFakeCaretCandidate(rootNode, e.clientX, e.clientY).each(caretInfo => { 27748 e.preventDefault(); 27749 const range = showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false); 27750 setRange(range); 27751 if (isHTMLElement(closestContentEditable)) { 27752 closestContentEditable.focus(); 27753 } else { 27754 editor.getBody().focus(); 27755 } 27756 }); 27757 } 27758 }); 27759 editor.on('keypress', e => { 27760 if (VK.modifierPressed(e)) { 27761 return; 27762 } 27763 if (isContentEditableFalse(selection.getNode())) { 27764 e.preventDefault(); 27765 } 27766 }); 27767 editor.on('GetSelectionRange', e => { 27768 let rng = e.range; 27769 if (selectedElement) { 27770 if (!selectedElement.parentNode) { 27771 selectedElement = null; 27772 return; 27773 } 27774 rng = rng.cloneRange(); 27775 rng.selectNode(selectedElement); 27776 e.range = rng; 27777 } 27778 }); 27779 editor.on('SetSelectionRange', e => { 27780 e.range = normalizeVoidElementSelection(e.range); 27781 const rng = setElementSelection(e.range, e.forward); 27782 if (rng) { 27783 e.range = rng; 27784 } 27785 }); 27786 const isPasteBin = node => isElement$6(node) && node.id === 'mcepastebin'; 27787 editor.on('AfterSetSelectionRange', e => { 27788 const rng = e.range; 27789 const parent = rng.startContainer.parentElement; 27790 if (!isRangeInCaretContainer(rng) && !isPasteBin(parent)) { 27791 hideFakeCaret(); 27792 } 27793 if (!isFakeSelectionElement(parent)) { 27794 removeElementSelection(); 27795 } 27796 }); 27797 init$2(editor); 27798 setup$4(editor); 27799 setup$3(editor); 27800 }; 27801 const isWithinCaretContainer = node => isCaretContainer$2(node) || startsWithCaretContainer$1(node) || endsWithCaretContainer$1(node); 27802 const isRangeInCaretContainer = rng => isWithinCaretContainer(rng.startContainer) || isWithinCaretContainer(rng.endContainer); 27803 const normalizeVoidElementSelection = rng => { 27804 const voidElements = editor.schema.getVoidElements(); 27805 const newRng = dom.createRng(); 27806 const startContainer = rng.startContainer; 27807 const startOffset = rng.startOffset; 27808 const endContainer = rng.endContainer; 27809 const endOffset = rng.endOffset; 27810 if (has$2(voidElements, startContainer.nodeName.toLowerCase())) { 27811 if (startOffset === 0) { 27812 newRng.setStartBefore(startContainer); 27813 } else { 27814 newRng.setStartAfter(startContainer); 27815 } 27816 } else { 27817 newRng.setStart(startContainer, startOffset); 27818 } 27819 if (has$2(voidElements, endContainer.nodeName.toLowerCase())) { 27820 if (endOffset === 0) { 27821 newRng.setEndBefore(endContainer); 27822 } else { 27823 newRng.setEndAfter(endContainer); 27824 } 27825 } else { 27826 newRng.setEnd(endContainer, endOffset); 27827 } 27828 return newRng; 27829 }; 27830 const setupOffscreenSelection = (node, targetClone) => { 27831 const body = SugarElement.fromDom(editor.getBody()); 27832 const doc = editor.getDoc(); 27833 const realSelectionContainer = descendant$1(body, '#' + realSelectionId).getOrThunk(() => { 27834 const newContainer = SugarElement.fromHtml('<div data-mce-bogus="all" class="mce-offscreen-selection"></div>', doc); 27835 set$
278354
vendor: 27,222 bytes, lines 27835-28482
27835(newContainer, 'id', realSelectionId); 27836 append$1(body, newContainer); 27837 return newContainer; 27838 }); 27839 const newRange = dom.createRng(); 27840 empty(realSelectionContainer); 27841 append(realSelectionContainer, [ 27842 SugarElement.fromText(nbsp, doc), 27843 SugarElement.fromDom(targetClone), 27844 SugarElement.fromText(nbsp, doc) 27845 ]); 27846 newRange.setStart(realSelectionContainer.dom.firstChild, 1); 27847 newRange.setEnd(realSelectionContainer.dom.lastChild, 0); 27848 setAll(realSelectionContainer, { top: dom.getPos(node, editor.getBody()).y + 'px' }); 27849 focus$1(realSelectionContainer); 27850 const sel = selection.getSel(); 27851 if (sel) { 27852 sel.removeAllRanges(); 27853 sel.addRange(newRange); 27854 } 27855 return newRange; 27856 }; 27857 const selectElement = elm => { 27858 const targetClone = elm.cloneNode(true); 27859 const e = editor.dispatch('ObjectSelected', { 27860 target: elm, 27861 targetClone 27862 }); 27863 if (e.isDefaultPrevented()) { 27864 return null; 27865 } 27866 const range = setupOffscreenSelection(elm, e.targetClone); 27867 const nodeElm = SugarElement.fromDom(elm); 27868 each$e(descendants(SugarElement.fromDom(editor.getBody()), `*[${ elementSelectionAttr }]`), elm => { 27869 if (!eq(nodeElm, elm)) { 27870 remove$9(elm, elementSelectionAttr); 27871 } 27872 }); 27873 if (!dom.getAttrib(elm, elementSelectionAttr)) { 27874 elm.setAttribute(elementSelectionAttr, '1'); 27875 } 27876 selectedElement = elm; 27877 hideFakeCaret(); 27878 return range; 27879 }; 27880 const setElementSelection = (range, forward) => { 27881 if (!range) { 27882 return null; 27883 } 27884 if (range.collapsed) { 27885 if (!isRangeInCaretContainer(range)) { 27886 const dir = forward ? 1 : -1; 27887 const caretPosition = getNormalizedRangeEndPoint(dir, rootNode, range); 27888 const beforeNode = caretPosition.getNode(!forward); 27889 if (isNonNullable(beforeNode)) { 27890 if (isFakeCaretTarget(beforeNode)) { 27891 return showCaret(dir, beforeNode, forward ? !caretPosition.isAtEnd() : false, false); 27892 } 27893 if (isCaretContainerInline(beforeNode) && isContentEditableFalse$b(beforeNode.nextSibling)) { 27894 const rng = dom.createRng(); 27895 rng.setStart(beforeNode, 0); 27896 rng.setEnd(beforeNode, 0); 27897 return rng; 27898 } 27899 } 27900 const afterNode = caretPosition.getNode(forward); 27901 if (isNonNullable(afterNode)) { 27902 if (isFakeCaretTarget(afterNode)) { 27903 return showCaret(dir, afterNode, forward ? false : !caretPosition.isAtEnd(), false); 27904 } 27905 if (isCaretContainerInline(afterNode) && isContentEditableFalse$b(afterNode.previousSibling)) { 27906 const rng = dom.createRng(); 27907 rng.setStart(afterNode, 1); 27908 rng.setEnd(afterNode, 1); 27909 return rng; 27910 } 27911 } 27912 } 27913 return null; 27914 } 27915 let startContainer = range.startContainer; 27916 let startOffset = range.startOffset; 27917 const endOffset = range.endOffset; 27918 if (isText$b(startContainer) && startOffset === 0 && isContentEditableFalse(startContainer.parentNode)) { 27919 startContainer = startContainer.parentNode; 27920 startOffset = dom.nodeIndex(startContainer); 27921 startContainer = startContainer.parentNode; 27922 } 27923 if (!isElement$6(startContainer)) { 27924 return null; 27925 } 27926 if (endOffset === startOffset + 1 && startContainer === range.endContainer) { 27927 const node = startContainer.childNodes[startOffset]; 27928 if (isFakeSelectionTargetElement(node)) { 27929 return selectElement(node); 27930 } 27931 } 27932 return null; 27933 }; 27934 const removeElementSelection = () => { 27935 if (selectedElement) { 27936 selectedElement.removeAttribute(elementSelectionAttr); 27937 } 27938 descendant$1(SugarElement.fromDom(editor.getBody()), '#' + realSelectionId).each(remove$4); 27939 selectedElement = null; 27940 }; 27941 const destroy = () => { 27942 fakeCaret.destroy(); 27943 selectedElement = null; 27944 }; 27945 const hideFakeCaret = () => { 27946 fakeCaret.hide(); 27947 }; 27948 if (!isRtc(editor)) { 27949 registerEvents(); 27950 } 27951 return { 27952 showCaret, 27953 showBlockCaretContainer, 27954 hideFakeCaret, 27955 destroy 27956 }; 27957 }; 27958 27959 const getNormalizedTextOffset = (container, offset) => { 27960 let normalizedOffset = offset; 27961 for (let node = container.previousSibling; isText$b(node); node = node.previousSibling) { 27962 normalizedOffset += node.data.length; 27963 } 27964 return normalizedOffset; 27965 }; 27966 const generatePath = (dom, root, node, offset, normalized) => { 27967 if (isText$b(node) && (offset < 0 || offset > node.data.length)) { 27968 return []; 27969 } 27970 const p = normalized && isText$b(node) ? [getNormalizedTextOffset(node, offset)] : [offset]; 27971 let current = node; 27972 while (current !== root && current.parentNode) { 27973 p.push(dom.nodeIndex(current, normalized)); 27974 current = current.parentNode; 27975 } 27976 return current === root ? p.reverse() : []; 27977 }; 27978 const generatePathRange = (dom, root, startNode, startOffset, endNode, endOffset, normalized = false) => { 27979 const start = generatePath(dom, root, startNode, startOffset, normalized); 27980 const end = generatePath(dom, root, endNode, endOffset, normalized); 27981 return { 27982 start, 27983 end 27984 }; 27985 }; 27986 const resolvePath = (root, path) => { 27987 const nodePath = path.slice(); 27988 const offset = nodePath.pop(); 27989 if (!isNumber(offset)) { 27990 return Optional.none(); 27991 } else { 27992 const resolvedNode = foldl(nodePath, (optNode, index) => optNode.bind(node => Optional.from(node.childNodes[index])), Optional.some(root)); 27993 return resolvedNode.bind(node => { 27994 if (isText$b(node) && (offset < 0 || offset > node.data.length)) { 27995 return Optional.none(); 27996 } else { 27997 return Optional.some({ 27998 node, 27999 offset 28000 }); 28001 } 28002 }); 28003 } 28004 }; 28005 const resolvePathRange = (root, range) => resolvePath(root, range.start).bind(({ 28006 node: startNode, 28007 offset: startOffset 28008 }) => resolvePath(root, range.end).map(({ 28009 node: endNode, 28010 offset: endOffset 28011 }) => { 28012 const rng = document.createRange(); 28013 rng.setStart(startNode, startOffset); 28014 rng.setEnd(endNode, endOffset); 28015 return rng; 28016 })); 28017 const generatePathRangeFromRange = (dom, root, range, normalized = false) => generatePathRange(dom, root, range.startContainer, range.startOffset, range.endContainer, range.endOffset, normalized); 28018 28019 const cleanEmptyNodes = (dom, node, isRoot) => { 28020 if (node && dom.isEmpty(node) && !isRoot(node)) { 28021 const parent = node.parentNode; 28022 dom.remove(node, isText$b(node.firstChild) && isWhitespaceText(node.firstChild.data)); 28023 cleanEmptyNodes(dom, parent, isRoot); 28024 } 28025 }; 28026 const deleteRng = (dom, rng, isRoot, clean = true) => { 28027 const startParent = rng.startContainer.parentNode; 28028 const endParent = rng.endContainer.parentNode; 28029 rng.deleteContents(); 28030 if (clean && !isRoot(rng.startContainer)) { 28031 if (isText$b(rng.startContainer) && rng.startContainer.data.length === 0) { 28032 dom.remove(rng.startContainer); 28033 } 28034 if (isText$b(rng.endContainer) && rng.endContainer.data.length === 0) { 28035 dom.remove(rng.endContainer); 28036 } 28037 cleanEmptyNodes(dom, startParent, isRoot); 28038 if (startParent !== endParent) { 28039 cleanEmptyNodes(dom, endParent, isRoot); 28040 } 28041 } 28042 }; 28043 const getParentBlock = (editor, rng) => Optional.from(editor.dom.getParent(rng.startContainer, editor.dom.isBlock)); 28044 const resolveFromDynamicPatterns = (patternSet, block, beforeText) => { 28045 const dynamicPatterns = patternSet.dynamicPatternsLookup({ 28046 text: beforeText, 28047 block 28048 }); 28049 return { 28050 ...patternSet, 28051 blockPatterns: getBlockPatterns(dynamicPatterns).concat(patternSet.blockPatterns), 28052 inlinePatterns: getInlinePatterns(dynamicPatterns).concat(patternSet.inlinePatterns) 28053 }; 28054 }; 28055 const getBeforeText = (dom, block, node, offset) => { 28056 const rng = dom.createRng(); 28057 rng.setStart(block, 0); 28058 rng.setEnd(node, offset); 28059 return rng.toString(); 28060 }; 28061 28062 const newMarker = (dom, id) => dom.create('span', { 28063 'data-mce-type': 'bookmark', 28064 id 28065 }); 28066 const rangeFromMarker = (dom, marker) => { 28067 const rng = dom.createRng(); 28068 rng.setStartAfter(marker.start); 28069 rng.setEndBefore(marker.end); 28070 return rng; 28071 }; 28072 const createMarker = (dom, markerPrefix, pathRange) => { 28073 const rng = resolvePathRange(dom.getRoot(), pathRange).getOrDie('Unable to resolve path range'); 28074 const startNode = rng.startContainer; 28075 const endNode = rng.endContainer; 28076 const textEnd = rng.endOffset === 0 ? endNode : endNode.splitText(rng.endOffset); 28077 const textStart = rng.startOffset === 0 ? startNode : startNode.splitText(rng.startOffset); 28078 const startParentNode = textStart.parentNode; 28079 const endParentNode = textEnd.parentNode; 28080 return { 28081 prefix: markerPrefix, 28082 end: endParentNode.insertBefore(newMarker(dom, markerPrefix + '-end'), textEnd), 28083 start: startParentNode.insertBefore(newMarker(dom, markerPrefix + '-start'), textStart) 28084 }; 28085 }; 28086 const removeMarker = (dom, marker, isRoot) => { 28087 cleanEmptyNodes(dom, dom.get(marker.prefix + '-end'), isRoot); 28088 cleanEmptyNodes(dom, dom.get(marker.prefix + '-start'), isRoot); 28089 }; 28090 28091 const isReplacementPattern = pattern => pattern.start.length === 0; 28092 const matchesPattern = patternContent => (element, offset) => { 28093 const text = element.data; 28094 const searchText = text.substring(0, offset); 28095 const startEndIndex = searchText.lastIndexOf(patternContent.charAt(patternContent.length - 1)); 28096 const startIndex = searchText.lastIndexOf(patternContent); 28097 if (startIndex !== -1) { 28098 return startIndex + patternContent.length; 28099 } else if (startEndIndex !== -1) { 28100 return startEndIndex + 1; 28101 } else { 28102 return -1; 28103 } 28104 }; 28105 const findPatternStartFromSpot = (dom, pattern, block, spot) => { 28106 const startPattern = pattern.start; 28107 const startSpot = repeatLeft(dom, spot.container, spot.offset, matchesPattern(startPattern), block); 28108 return startSpot.bind(spot => { 28109 var _a, _b; 28110 const startPatternIndex = (_b = (_a = block.textContent) === null || _a === void 0 ? void 0 : _a.indexOf(startPattern)) !== null && _b !== void 0 ? _b : -1; 28111 const isCompleteMatch = startPatternIndex !== -1 && spot.offset >= startPatternIndex + startPattern.length; 28112 if (isCompleteMatch) { 28113 const rng = dom.createRng(); 28114 rng.setStart(spot.container, spot.offset - startPattern.length); 28115 rng.setEnd(spot.container, spot.offset); 28116 return Optional.some(rng); 28117 } else { 28118 const offset = spot.offset - startPattern.length; 28119 return scanLeft(spot.container, offset, block).map(nextSpot => { 28120 const rng = dom.createRng(); 28121 rng.setStart(nextSpot.container, nextSpot.offset); 28122 rng.setEnd(spot.container, spot.offset); 28123 return rng; 28124 }).filter(rng => rng.toString() === startPattern).orThunk(() => findPatternStartFromSpot(dom, pattern, block, point(spot.container, 0))); 28125 } 28126 }); 28127 }; 28128 const findPatternStart = (dom, pattern, node, offset, block, requireGap = false) => { 28129 if (pattern.start.length === 0 && !requireGap) { 28130 const rng = dom.createRng(); 28131 rng.setStart(node, offset); 28132 rng.setEnd(node, offset); 28133 return Optional.some(rng); 28134 } 28135 return textBefore(node, offset, block).bind(spot => { 28136 const start = findPatternStartFromSpot(dom, pattern, block, spot); 28137 return start.bind(startRange => { 28138 var _a; 28139 if (requireGap) { 28140 if (startRange.endContainer === spot.container && startRange.endOffset === spot.offset) { 28141 return Optional.none(); 28142 } else if (spot.offset === 0 && ((_a = startRange.endContainer.textContent) === null || _a === void 0 ? void 0 : _a.length) === startRange.endOffset) { 28143 return Optional.none(); 28144 } 28145 } 28146 return Optional.some(startRange); 28147 }); 28148 }); 28149 }; 28150 const findPattern$3 = (editor, block, details, normalizedMatches) => { 28151 const dom = editor.dom; 28152 const root = dom.getRoot(); 28153 const pattern = details.pattern; 28154 const endNode = details.position.container; 28155 const endOffset = details.position.offset; 28156 return scanLeft(endNode, endOffset - details.pattern.end.length, block).bind(spot => { 28157 const endPathRng = generatePathRange(dom, root, spot.container, spot.offset, endNode, endOffset, normalizedMatches); 28158 if (isReplacementPattern(pattern)) { 28159 return Optional.some({ 28160 matches: [{ 28161 pattern, 28162 startRng: endPathRng, 28163 endRng: endPathRng 28164 }], 28165 position: spot 28166 }); 28167 } else { 28168 const resultsOpt = findPatternsRec(editor, details.remainingPatterns, spot.container, spot.offset, block, normalizedMatches); 28169 const results = resultsOpt.getOr({ 28170 matches: [], 28171 position: spot 28172 }); 28173 const pos = results.position; 28174 const start = findPatternStart(dom, pattern, pos.container, pos.offset, block, resultsOpt.isNone()); 28175 return start.map(startRng => { 28176 const startPathRng = generatePathRangeFromRange(dom, root, startRng, normalizedMatches); 28177 return { 28178 matches: results.matches.concat([{ 28179 pattern, 28180 startRng: startPathRng, 28181 endRng: endPathRng 28182 }]), 28183 position: point(startRng.startContainer, startRng.startOffset) 28184 }; 28185 }); 28186 } 28187 }); 28188 }; 28189 const findPatternsRec = (editor, patterns, node, offset, block, normalizedMatches) => { 28190 const dom = editor.dom; 28191 return textBefore(node, offset, dom.getRoot()).bind(endSpot => { 28192 const text = getBeforeText(dom, block, node, offset); 28193 for (let i = 0; i < patterns.length; i++) { 28194 const pattern = patterns[i]; 28195 if (!endsWith(text, pattern.end)) { 28196 continue; 28197 } 28198 const patternsWithoutCurrent = patterns.slice(); 28199 patternsWithoutCurrent.splice(i, 1); 28200 const result = findPattern$3(editor, block, { 28201 pattern, 28202 remainingPatterns: patternsWithoutCurrent, 28203 position: endSpot 28204 }, normalizedMatches); 28205 if (result.isNone() && offset > 0) { 28206 return findPatternsRec(editor, patterns, node, offset - 1, block, normalizedMatches); 28207 } 28208 if (result.isSome()) { 28209 return result; 28210 } 28211 } 28212 return Optional.none(); 28213 }); 28214 }; 28215 const applyPattern$2 = (editor, pattern, patternRange) => { 28216 editor.selection.setRng(patternRange); 28217 if (pattern.type === 'inline-format') { 28218 each$e(pattern.format, format => { 28219 editor.formatter.apply(format); 28220 }); 28221 } else { 28222 editor.execCommand(pattern.cmd, false, pattern.value); 28223 } 28224 }; 28225 const applyReplacementPattern = (editor, pattern, marker, isRoot) => { 28226 const markerRange = rangeFromMarker(editor.dom, marker); 28227 deleteRng(editor.dom, markerRange, isRoot); 28228 applyPattern$2(editor, pattern, markerRange); 28229 }; 28230 const applyPatternWithContent = (editor, pattern, startMarker, endMarker, isRoot) => { 28231 const dom = editor.dom; 28232 const markerEndRange = rangeFromMarker(dom, endMarker); 28233 const markerStartRange = rangeFromMarker(dom, startMarker); 28234 deleteRng(dom, markerStartRange, isRoot); 28235 deleteRng(dom, markerEndRange, isRoot); 28236 const patternMarker = { 28237 prefix: startMarker.prefix, 28238 start: startMarker.end, 28239 end: endMarker.start 28240 }; 28241 const patternRange = rangeFromMarker(dom, patternMarker); 28242 applyPattern$2(editor, pattern, patternRange); 28243 }; 28244 const addMarkers = (dom, matches) => { 28245 const markerPrefix = generate$1('mce_textpattern'); 28246 const matchesWithEnds = foldr(matches, (acc, match) => { 28247 const endMarker = createMarker(dom, markerPrefix + `_end${ acc.length }`, match.endRng); 28248 return acc.concat([{ 28249 ...match, 28250 endMarker 28251 }]); 28252 }, []); 28253 return foldr(matchesWithEnds, (acc, match) => { 28254 const idx = matchesWithEnds.length - acc.length - 1; 28255 const startMarker = isReplacementPattern(match.pattern) ? match.endMarker : createMarker(dom, markerPrefix + `_start${ idx }`, match.startRng); 28256 return acc.concat([{ 28257 ...match, 28258 startMarker 28259 }]); 28260 }, []); 28261 }; 28262 const sortPatterns$1 = patterns => sort(patterns, (a, b) => b.end.length - a.end.length); 28263 const getBestMatches = (matches, matchesWithSortedPatterns) => { 28264 const hasSameMatches = forall(matches, match => exists(matchesWithSortedPatterns, sortedMatch => match.pattern.start === sortedMatch.pattern.start && match.pattern.end === sortedMatch.pattern.end)); 28265 if (matches.length === matchesWithSortedPatterns.length) { 28266 if (hasSameMatches) { 28267 return matches; 28268 } else { 28269 return matchesWithSortedPatterns; 28270 } 28271 } 28272 return matches.length > matchesWithSortedPatterns.length ? matches : matchesWithSortedPatterns; 28273 }; 28274 const findPatterns$2 = (editor, block, node, offset, patternSet, normalizedMatches) => { 28275 const matches = findPatternsRec(editor, patternSet.inlinePatterns, node, offset, block, normalizedMatches).fold(() => [], result => result.matches); 28276 const matchesWithSortedPatterns = findPatternsRec(editor, sortPatterns$1(patternSet.inlinePatterns), node, offset, block, normalizedMatches).fold(() => [], result => result.matches); 28277 return getBestMatches(matches, matchesWithSortedPatterns); 28278 }; 28279 const applyMatches$2 = (editor, matches) => { 28280 if (matches.length === 0) { 28281 return; 28282 } 28283 const dom = editor.dom; 28284 const bookmark = editor.selection.getBookmark(); 28285 const matchesWithMarkers = addMarkers(dom, matches); 28286 each$e(matchesWithMarkers, match => { 28287 const block = dom.getParent(match.startMarker.start, dom.isBlock); 28288 const isRoot = node => node === block; 28289 if (isReplacementPattern(match.pattern)) { 28290 applyReplacementPattern(editor, match.pattern, match.endMarker, isRoot); 28291 } else { 28292 applyPatternWithContent(editor, match.pattern, match.startMarker, match.endMarker, isRoot); 28293 } 28294 removeMarker(dom, match.endMarker, isRoot); 28295 removeMarker(dom, match.startMarker, isRoot); 28296 }); 28297 editor.selection.moveToBookmark(bookmark); 28298 }; 28299 28300 const stripPattern$1 = (dom, block, pattern) => { 28301 return textAfter(block, 0, block).map(spot => { 28302 const node = spot.container; 28303 scanRight(node, pattern.start.length, block).each(end => { 28304 const rng = dom.createRng(); 28305 rng.setStart(node, 0); 28306 rng.setEnd(end.container, end.offset); 28307 deleteRng(dom, rng, e => e === block); 28308 }); 28309 return node; 28310 }); 28311 }; 28312 const createApplyPattern = stripPattern => (editor, match) => { 28313 const dom = editor.dom; 28314 const pattern = match.pattern; 28315 const rng = resolvePathRange(dom.getRoot(), match.range).getOrDie('Unable to resolve path range'); 28316 const isBlockFormatName = (name, formatter) => { 28317 const formatSet = formatter.get(name); 28318 return isArray$1(formatSet) && head(formatSet).exists(format => has$2(format, 'block')); 28319 }; 28320 getParentBlock(editor, rng).each(block => { 28321 if (pattern.type === 'block-format') { 28322 if (isBlockFormatName(pattern.format, editor.formatter)) { 28323 editor.undoManager.transact(() => { 28324 stripPattern(editor.dom, block, pattern); 28325 editor.formatter.apply(pattern.format); 28326 }); 28327 } 28328 } else if (pattern.type === 'block-command') { 28329 editor.undoManager.transact(() => { 28330 stripPattern(editor.dom, block, pattern); 28331 editor.execCommand(pattern.cmd, false, pattern.value); 28332 }); 28333 } 28334 }); 28335 return true; 28336 }; 28337 const sortPatterns = patterns => sort(patterns, (a, b) => b.start.length - a.start.length); 28338 const findPattern$2 = predicate => (patterns, text) => { 28339 const sortedPatterns = sortPatterns(patterns); 28340 const nuText = text.replace(nbsp, ' '); 28341 return find$2(sortedPatterns, pattern => predicate(pattern, text, nuText)); 28342 }; 28343 const createFindPatterns = (findPattern, skipFullMatch) => (editor, block, patternSet, normalizedMatches, text) => { 28344 var _a; 28345 if (text === void 0) { 28346 text = (_a = block.textContent) !== null && _a !== void 0 ? _a : ''; 28347 } 28348 const dom = editor.dom; 28349 const forcedRootBlock = getForcedRootBlock(editor); 28350 if (!dom.is(block, forcedRootBlock)) { 28351 return []; 28352 } 28353 return findPattern(patternSet.blockPatterns, text).map(pattern => { 28354 if (skipFullMatch && Tools.trim(text).length === pattern.start.length) { 28355 return []; 28356 } 28357 return [{ 28358 pattern, 28359 range: generatePathRange(dom, dom.getRoot(), block, 0, block, 0, normalizedMatches) 28360 }]; 28361 }).getOr([]); 28362 }; 28363 28364 const startsWithSingleSpace = s => /^\s[^\s]/.test(s); 28365 const stripPattern = (dom, block, pattern) => { 28366 stripPattern$1(dom, block, pattern).each(node => { 28367 const text = SugarElement.fromDom(node); 28368 const textContent = get$3(text); 28369 if (startsWithSingleSpace(textContent)) { 28370 set(text, textContent.slice(1)); 28371 } 28372 }); 28373 }; 28374 const applyPattern$1 = createApplyPattern(stripPattern); 28375 const findPattern$1 = findPattern$2((pattern, text, nuText) => text.indexOf(pattern.start) === 0 || nuText.indexOf(pattern.start) === 0); 28376 const findPatterns$1 = createFindPatterns(findPattern$1, true); 28377 const getMatches$1 = (editor, patternSet) => { 28378 const rng = editor.selection.getRng(); 28379 return getParentBlock(editor, rng).map(block => { 28380 var _a; 28381 const offset = Math.max(0, rng.startOffset); 28382 const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, (_a = block.textContent) !== null && _a !== void 0 ? _a : ''); 28383 const inlineMatches = findPatterns$2(editor, block, rng.startContainer, offset, dynamicPatternSet, true); 28384 const blockMatches = findPatterns$1(editor, block, dynamicPatternSet, true); 28385 return { 28386 inlineMatches, 28387 blockMatches 28388 }; 28389 }).filter(({inlineMatches, blockMatches}) => blockMatches.length > 0 || inlineMatches.length > 0); 28390 }; 28391 const applyMatches$1 = (editor, matches) => { 28392 if (matches.length === 0) { 28393 return; 28394 } 28395 const bookmark = editor.selection.getBookmark(); 28396 each$e(matches, match => applyPattern$1(editor, match)); 28397 editor.selection.moveToBookmark(bookmark); 28398 }; 28399 28400 const applyPattern = createApplyPattern(stripPattern$1); 28401 const findPattern = findPattern$2((pattern, text, nuText) => text === pattern.start || nuText === pattern.start); 28402 const findPatterns = createFindPatterns(findPattern, false); 28403 const getMatches = (editor, patternSet) => { 28404 const rng = editor.selection.getRng(); 28405 return getParentBlock(editor, rng).map(block => { 28406 const offset = Math.max(0, rng.startOffset); 28407 const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset); 28408 const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText); 28409 return findPatterns(editor, block, dynamicPatternSet, false, beforeText); 28410 }).filter(matches => matches.length > 0); 28411 }; 28412 const applyMatches = (editor, matches) => { 28413 each$e(matches, match => applyPattern(editor, match)); 28414 }; 28415 28416 const handleEnter = (editor, patternSet) => getMatches$1(editor, patternSet).fold(never, ({inlineMatches, blockMatches}) => { 28417 editor.undoManager.add(); 28418 editor.undoManager.extra(() => { 28419 editor.execCommand('mceInsertNewLine'); 28420 }, () => { 28421 insert$5(editor); 28422 applyMatches$2(editor, inlineMatches); 28423 applyMatches$1(editor, blockMatches); 28424 const range = editor.selection.getRng(); 28425 const spot = textBefore(range.startContainer, range.startOffset, editor.dom.getRoot()); 28426 editor.execCommand('mceInsertNewLine'); 28427 spot.each(s => { 28428 const node = s.container; 28429 if (node.data.charAt(s.offset - 1) === zeroWidth) { 28430 node.deleteData(s.offset - 1, 1); 28431 cleanEmptyNodes(editor.dom, node.parentNode, e => e === editor.dom.getRoot()); 28432 } 28433 }); 28434 }); 28435 return true; 28436 }); 28437 const handleInlineKey = (editor, patternSet) => { 28438 const rng = editor.selection.getRng(); 28439 getParentBlock(editor, rng).map(block => { 28440 const offset = Math.max(0, rng.startOffset - 1); 28441 const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset); 28442 const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText); 28443 const inlineMatches = findPatterns$2(editor, block, rng.startContainer, offset, dynamicPatternSet, false); 28444 if (inlineMatches.length > 0) { 28445 editor.undoManager.transact(() => { 28446 applyMatches$2(editor, inlineMatches); 28447 }); 28448 } 28449 }); 28450 }; 28451 const handleBlockPatternOnSpace = (editor, patternSet) => getMatches(editor, patternSet).fold(never, matches => { 28452 editor.undoManager.transact(() => { 28453 applyMatches(editor, matches); 28454 }); 28455 return true; 28456 }); 28457 const checkKeyEvent = (codes, event, predicate) => { 28458 for (let i = 0; i < codes.length; i++) { 28459 if (predicate(codes[i], event)) { 28460 return true; 28461 } 28462 } 28463 return false; 28464 }; 28465 const checkKeyCode = (codes, event) => checkKeyEvent(codes, event, (code, event) => { 28466 return code === event.keyCode && !VK.modifierPressed(event); 28467 }); 28468 const checkCharCode = (chars, event) => checkKeyEvent(chars, event, (chr, event) => { 28469 return chr.charCodeAt(0) === event.charCode; 28470 }); 28471 28472 const setup$2 = editor => { 28473 const charCodes = [ 28474 ',', 28475 '.', 28476 ';', 28477 ':', 28478 '!', 28479 '?' 28480 ]; 28481 const keyCodes = [32]; 28482 const getPatternSet = () => createPatternSet(getTextPatterns(editor)
vendor: 2,621 bytes, lines 28482-28543
28482.filter(pattern => { 28483 if (pattern.type === 'inline-command' || pattern.type === 'block-command') { 28484 return editor.queryCommandSupported(pattern.cmd); 28485 } 28486 return true; 28487 }), getTextPatternsLookup(editor)); 28488 const hasDynamicPatterns = () => hasTextPatternsLookup(editor); 28489 editor.on('keydown', e => { 28490 if (e.keyCode === 13 && !VK.modifierPressed(e) && editor.selection.isCollapsed() && editor.selection.isEditable()) { 28491 const patternSet = filterByTrigger(getPatternSet(), 'enter'); 28492 const hasPatterns = patternSet.inlinePatterns.length > 0 || patternSet.blockPatterns.length > 0 || hasDynamicPatterns(); 28493 if (hasPatterns && handleEnter(editor, patternSet)) { 28494 e.preventDefault(); 28495 } 28496 } 28497 }, true); 28498 editor.on('keydown', e => { 28499 if (e.keyCode === 32 && editor.selection.isCollapsed() && editor.selection.isEditable()) { 28500 const patternSet = filterByTrigger(getPatternSet(), 'space'); 28501 const hasPatterns = patternSet.blockPatterns.length > 0 || hasDynamicPatterns(); 28502 if (hasPatterns && handleBlockPatternOnSpace(editor, patternSet)) { 28503 e.preventDefault(); 28504 } 28505 } 28506 }, true); 28507 const handleInlineTrigger = () => { 28508 if (editor.selection.isCollapsed() && editor.selection.isEditable()) { 28509 const patternSet = filterByTrigger(getPatternSet(), 'space'); 28510 const hasPatterns = patternSet.inlinePatterns.length > 0 || hasDynamicPatterns(); 28511 if (hasPatterns) { 28512 handleInlineKey(editor, patternSet); 28513 } 28514 } 28515 }; 28516 editor.on('keyup', e => { 28517 if (checkKeyCode(keyCodes, e)) { 28518 handleInlineTrigger(); 28519 } 28520 }); 28521 editor.on('keypress', e => { 28522 if (checkCharCode(charCodes, e)) { 28523 Delay.setEditorTimeout(editor, handleInlineTrigger); 28524 } 28525 }); 28526 }; 28527 28528 const setup$1 = editor => { 28529 setup$2(editor); 28530 }; 28531 28532 const Quirks = editor => { 28533 const each = Tools.each; 28534 const BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, parser = editor.parser; 28535 const browser = Env.browser; 28536 const isGecko = browser.isFirefox(); 28537 const isWebKit = browser.isChromium() || browser.isSafari(); 28538 const isiOS = Env.deviceType.isiPhone() || Env.deviceType.isiPad(); 28539 const isMac = Env.os.isMacOS() || Env.os.isiOS(); 28540 const setEditorCommandState = (cmd, state) => { 28541 try { 28542 editor.getDoc().execCommand(cmd, false, String(state)); 28543 } catch (_a
vendor: 13,582 bytes, lines 28543-28922
28543) { 28544 } 28545 }; 28546 const isDefaultPrevented = e => { 28547 return e.isDefaultPrevented(); 28548 }; 28549 const emptyEditorWhenDeleting = () => { 28550 const serializeRng = rng => { 28551 const body = dom.create('body'); 28552 const contents = rng.cloneContents(); 28553 body.appendChild(contents); 28554 return selection.serializer.serialize(body, { format: 'html' }); 28555 }; 28556 const allContentsSelected = rng => { 28557 const selection = serializeRng(rng); 28558 const allRng = dom.createRng(); 28559 allRng.selectNode(editor.getBody()); 28560 const allSelection = serializeRng(allRng); 28561 return selection === allSelection; 28562 }; 28563 editor.on('keydown', e => { 28564 const keyCode = e.keyCode; 28565 if (!isDefaultPrevented(e) && (keyCode === DELETE || keyCode === BACKSPACE) && editor.selection.isEditable()) { 28566 const isCollapsed = editor.selection.isCollapsed(); 28567 const body = editor.getBody(); 28568 if (isCollapsed && !isEmptyNode(editor.schema, body)) { 28569 return; 28570 } 28571 if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) { 28572 return; 28573 } 28574 e.preventDefault(); 28575 editor.setContent(''); 28576 if (body.firstChild && dom.isBlock(body.firstChild)) { 28577 editor.selection.setCursorLocation(body.firstChild, 0); 28578 } else { 28579 editor.selection.setCursorLocation(body, 0); 28580 } 28581 editor.nodeChanged(); 28582 } 28583 }); 28584 }; 28585 const selectAll = () => { 28586 editor.shortcuts.add('meta+a', null, 'SelectAll'); 28587 }; 28588 const documentElementEditingFocus = () => { 28589 if (!editor.inline) { 28590 dom.bind(editor.getDoc(), 'mousedown mouseup', e => { 28591 let rng; 28592 if (e.target === editor.getDoc().documentElement) { 28593 rng = selection.getRng(); 28594 editor.getBody().focus(); 28595 if (e.type === 'mousedown') { 28596 if (isCaretContainer$2(rng.startContainer)) { 28597 return; 28598 } 28599 selection.placeCaretAt(e.clientX, e.clientY); 28600 } else { 28601 selection.setRng(rng); 28602 } 28603 } 28604 }); 28605 } 28606 }; 28607 const removeHrOnBackspace = () => { 28608 editor.on('keydown', e => { 28609 if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) { 28610 if (!editor.getBody().getElementsByTagName('hr').length) { 28611 return; 28612 } 28613 if (selection.isCollapsed() && selection.getRng().startOffset === 0) { 28614 const node = selection.getNode(); 28615 const previousSibling = node.previousSibling; 28616 if (node.nodeName === 'HR') { 28617 dom.remove(node); 28618 e.preventDefault(); 28619 return; 28620 } 28621 if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'hr') { 28622 dom.remove(previousSibling); 28623 e.preventDefault(); 28624 } 28625 } 28626 } 28627 }); 28628 }; 28629 const focusBody = () => { 28630 if (!Range.prototype.getClientRects) { 28631 editor.on('mousedown', e => { 28632 if (!isDefaultPrevented(e) && e.target.nodeName === 'HTML') { 28633 const body = editor.getBody(); 28634 body.blur(); 28635 Delay.setEditorTimeout(editor, () => { 28636 body.focus(); 28637 }); 28638 } 28639 }); 28640 } 28641 }; 28642 const selectControlElements = () => { 28643 const visualAidsAnchorClass = getVisualAidsAnchorClass(editor); 28644 editor.on('click', e => { 28645 const target = e.target; 28646 if (/^(IMG|HR)$/.test(target.nodeName) && dom.isEditable(target)) { 28647 e.preventDefault(); 28648 editor.selection.select(target); 28649 editor.nodeChanged(); 28650 } 28651 if (target.nodeName === 'A' && dom.hasClass(target, visualAidsAnchorClass) && target.childNodes.length === 0 && dom.isEditable(target.parentNode)) { 28652 e.preventDefault(); 28653 selection.select(target); 28654 } 28655 }); 28656 }; 28657 const removeStylesWhenDeletingAcrossBlockElements = () => { 28658 const getAttributeApplyFunction = () => { 28659 const template = dom.getAttribs(selection.getStart().cloneNode(false)); 28660 return () => { 28661 const target = selection.getStart(); 28662 if (target !== editor.getBody()) { 28663 dom.setAttrib(target, 'style', null); 28664 each(template, attr => { 28665 target.setAttributeNode(attr.cloneNode(true)); 28666 }); 28667 } 28668 }; 28669 }; 28670 const isSelectionAcrossElements = () => { 28671 return !selection.isCollapsed() && dom.getParent(selection.getStart(), dom.isBlock) !== dom.getParent(selection.getEnd(), dom.isBlock); 28672 }; 28673 editor.on('keypress', e => { 28674 let applyAttributes; 28675 if (!isDefaultPrevented(e) && (e.keyCode === 8 || e.keyCode === 46) && isSelectionAcrossElements()) { 28676 applyAttributes = getAttributeApplyFunction(); 28677 editor.getDoc().execCommand('delete', false); 28678 applyAttributes(); 28679 e.preventDefault(); 28680 return false; 28681 } else { 28682 return true; 28683 } 28684 }); 28685 dom.bind(editor.getDoc(), 'cut', e => { 28686 if (!isDefaultPrevented(e) && isSelectionAcrossElements()) { 28687 const applyAttributes = getAttributeApplyFunction(); 28688 Delay.setEditorTimeout(editor, () => { 28689 applyAttributes(); 28690 }); 28691 } 28692 }); 28693 }; 28694 const disableBackspaceIntoATable = () => { 28695 editor.on('keydown', e => { 28696 if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) { 28697 if (selection.isCollapsed() && selection.getRng().startOffset === 0) { 28698 const previousSibling = selection.getNode().previousSibling; 28699 if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'table') { 28700 e.preventDefault(); 28701 return false; 28702 } 28703 } 28704 } 28705 return true; 28706 }); 28707 }; 28708 const removeBlockQuoteOnBackSpace = () => { 28709 editor.on('keydown', e => { 28710 if (isDefaultPrevented(e) || e.keyCode !== VK.BACKSPACE) { 28711 return; 28712 } 28713 let rng = selection.getRng(); 28714 const container = rng.startContainer; 28715 const offset = rng.startOffset; 28716 const root = dom.getRoot(); 28717 let parent = container; 28718 if (!rng.collapsed || offset !== 0) { 28719 return; 28720 } 28721 while (parent.parentNode && parent.parentNode.firstChild === parent && parent.parentNode !== root) { 28722 parent = parent.parentNode; 28723 } 28724 if (parent.nodeName === 'BLOCKQUOTE') { 28725 editor.formatter.toggle('blockquote', undefined, parent); 28726 rng = dom.createRng(); 28727 rng.setStart(container, 0); 28728 rng.setEnd(container, 0); 28729 selection.setRng(rng); 28730 } 28731 }); 28732 }; 28733 const setGeckoEditingOptions = () => { 28734 const setOpts = () => { 28735 setEditorCommandState('StyleWithCSS', false); 28736 setEditorCommandState('enableInlineTableEditing', false); 28737 if (!getObjectResizing(editor)) { 28738 setEditorCommandState('enableObjectResizing', false); 28739 } 28740 }; 28741 if (!isReadOnly$1(editor)) { 28742 editor.on('BeforeExecCommand mousedown', setOpts); 28743 } 28744 }; 28745 const addBrAfterLastLinks = () => { 28746 const fixLinks = () => { 28747 each(dom.select('a:not([data-mce-block])'), node => { 28748 var _a; 28749 let parentNode = node.parentNode; 28750 const root = dom.getRoot(); 28751 if ((parentNode === null || parentNode === void 0 ? void 0 : parentNode.lastChild) === node) { 28752 while (parentNode && !dom.isBlock(parentNode)) { 28753 if (((_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.lastChild) !== parentNode || parentNode === root) { 28754 return; 28755 } 28756 parentNode = parentNode.parentNode; 28757 } 28758 dom.add(parentNode, 'br', { 'data-mce-bogus': 1 }); 28759 } 28760 }); 28761 }; 28762 editor.on('SetContent ExecCommand', e => { 28763 if (e.type === 'setcontent' || e.command === 'mceInsertLink') { 28764 fixLinks(); 28765 } 28766 }); 28767 }; 28768 const setDefaultBlockType = () => { 28769 editor.on('init', () => { 28770 setEditorCommandState('DefaultParagraphSeparator', getForcedRootBlock(editor)); 28771 }); 28772 }; 28773 const isAllContentSelected = editor => { 28774 const body = editor.getBody(); 28775 const rng = editor.selection.getRng(); 28776 return rng.startContainer === rng.endContainer && rng.startContainer === body && rng.startOffset === 0 && rng.endOffset === body.childNodes.length; 28777 }; 28778 const normalizeSelection = () => { 28779 editor.on('keyup focusin mouseup', e => { 28780 if (!VK.modifierPressed(e) && !isAllContentSelected(editor)) { 28781 selection.normalize(); 28782 } 28783 }, true); 28784 }; 28785 const showBrokenImageIcon = () => { 28786 editor.contentStyles.push('img:-moz-broken {' + '-moz-force-broken-image-icon:1;' + 'min-width:24px;' + 'min-height:24px' + '}'); 28787 }; 28788 const restoreFocusOnKeyDown = () => { 28789 if (!editor.inline) { 28790 editor.on('keydown', () => { 28791 if (document.activeElement === document.body) { 28792 editor.getWin().focus(); 28793 } 28794 }); 28795 } 28796 }; 28797 const bodyHeight = () => { 28798 if (!editor.inline) { 28799 editor.contentStyles.push('body {min-height: 150px}'); 28800 editor.on('click', e => { 28801 let rng; 28802 if (e.target.nodeName === 'HTML') { 28803 rng = editor.selection.getRng(); 28804 editor.getBody().focus(); 28805 editor.selection.setRng(rng); 28806 editor.selection.normalize(); 28807 editor.nodeChanged(); 28808 } 28809 }); 28810 } 28811 }; 28812 const blockCmdArrowNavigation = () => { 28813 if (isMac) { 28814 editor.on('keydown', e => { 28815 if (VK.metaKeyPressed(e) && !e.shiftKey && (e.keyCode === 37 || e.keyCode === 39)) { 28816 e.preventDefault(); 28817 const selection = editor.selection.getSel(); 28818 selection.modify('move', e.keyCode === 37 ? 'backward' : 'forward', 'lineboundary'); 28819 } 28820 }); 28821 } 28822 }; 28823 const tapLinksAndImages = () => { 28824 editor.on('click', e => { 28825 let elm = e.target; 28826 do { 28827 if (elm.tagName === 'A') { 28828 e.preventDefault(); 28829 return; 28830 } 28831 } while (elm = elm.parentNode); 28832 }); 28833 editor.contentStyles.push('.mce-content-body {-webkit-touch-callout: none}'); 28834 }; 28835 const blockFormSubmitInsideEditor = () => { 28836 editor.on('init', () => { 28837 editor.dom.bind(editor.getBody(), 'submit', e => { 28838 e.preventDefault(); 28839 }); 28840 }); 28841 }; 28842 const removeAppleInterchangeBrs = () => { 28843 parser.addNodeFilter('br', nodes => { 28844 let i = nodes.length; 28845 while (i--) { 28846 if (nodes[i].attr('class') === 'Apple-interchange-newline') { 28847 nodes[i].remove(); 28848 } 28849 } 28850 }); 28851 }; 28852 const refreshContentEditable = noop; 28853 const isHidden = () => { 28854 if (!isGecko || editor.removed) { 28855 return false; 28856 } 28857 const sel = editor.selection.getSel(); 28858 return !sel || !sel.rangeCount || sel.rangeCount === 0; 28859 }; 28860 const setupRtc = () => { 28861 if (isWebKit) { 28862 documentElementEditingFocus(); 28863 selectControlElements(); 28864 blockFormSubmitInsideEditor(); 28865 selectAll(); 28866 if (isiOS) { 28867 restoreFocusOnKeyDown(); 28868 bodyHeight(); 28869 tapLinksAndImages(); 28870 } 28871 } 28872 if (isGecko) { 28873 focusBody(); 28874 setGeckoEditingOptions(); 28875 showBrokenImageIcon(); 28876 blockCmdArrowNavigation(); 28877 } 28878 }; 28879 const setup = () => { 28880 removeBlockQuoteOnBackSpace(); 28881 emptyEditorWhenDeleting(); 28882 if (!Env.windowsPhone) { 28883 normalizeSelection(); 28884 } 28885 if (isWebKit) { 28886 documentElementEditingFocus(); 28887 selectControlElements(); 28888 setDefaultBlockType(); 28889 blockFormSubmitInsideEditor(); 28890 disableBackspaceIntoATable(); 28891 removeAppleInterchangeBrs(); 28892 if (isiOS) { 28893 restoreFocusOnKeyDown(); 28894 bodyHeight(); 28895 tapLinksAndImages(); 28896 } else { 28897 selectAll(); 28898 } 28899 } 28900 if (isGecko) { 28901 removeHrOnBackspace(); 28902 focusBody(); 28903 removeStylesWhenDeletingAcrossBlockElements(); 28904 setGeckoEditingOptions(); 28905 addBrAfterLastLinks(); 28906 showBrokenImageIcon(); 28907 blockCmdArrowNavigation(); 28908 disableBackspaceIntoATable(); 28909 } 28910 }; 28911 if (isRtc(editor)) { 28912 setupRtc(); 28913 } else { 28914 setup(); 28915 } 28916 return { 28917 refreshContentEditable, 28918 isHidden 28919 }; 28920 }; 28921 28922 const
vendor: 15,561 bytes, lines 28922-29330
28922isGplKey = key => key.toLowerCase() === 'gpl'; 28923 const isValidGeneratedKey = key => key.length >= 64 && key.length <= 255; 28924 const validateLicenseKey = key => isGplKey(key) || isValidGeneratedKey(key) ? 'VALID' : 'INVALID'; 28925 const validateEditorLicenseKey = editor => { 28926 const licenseKey = getLicenseKey(editor); 28927 const hasApiKey = isString(getApiKey(editor)); 28928 if (!hasApiKey && (isUndefined(licenseKey) || validateLicenseKey(licenseKey) === 'INVALID')) { 28929 console.warn(`TinyMCE is running in evaluation mode. Provide a valid license key or add license_key: 'gpl' to the init config to agree to the open source license terms. Read more at https://www.tiny.cloud/license-key/`); 28930 } 28931 }; 28932 28933 const DOM$6 = DOMUtils.DOM; 28934 const appendStyle = (editor, text) => { 28935 const body = SugarElement.fromDom(editor.getBody()); 28936 const container = getStyleContainer(getRootNode(body)); 28937 const style = SugarElement.fromTag('style'); 28938 set$4(style, 'type', 'text/css'); 28939 append$1(style, SugarElement.fromText(text)); 28940 append$1(container, style); 28941 editor.on('remove', () => { 28942 remove$4(style); 28943 }); 28944 }; 28945 const getRootName = editor => editor.inline ? editor.getElement().nodeName.toLowerCase() : undefined; 28946 const removeUndefined = obj => filter$4(obj, v => isUndefined(v) === false); 28947 const mkParserSettings = editor => { 28948 const getOption = editor.options.get; 28949 const blobCache = editor.editorUpload.blobCache; 28950 return removeUndefined({ 28951 allow_conditional_comments: getOption('allow_conditional_comments'), 28952 allow_html_data_urls: getOption('allow_html_data_urls'), 28953 allow_svg_data_urls: getOption('allow_svg_data_urls'), 28954 allow_html_in_named_anchor: getOption('allow_html_in_named_anchor'), 28955 allow_script_urls: getOption('allow_script_urls'), 28956 allow_mathml_annotation_encodings: getOption('allow_mathml_annotation_encodings'), 28957 allow_unsafe_link_target: getOption('allow_unsafe_link_target'), 28958 convert_unsafe_embeds: getOption('convert_unsafe_embeds'), 28959 convert_fonts_to_spans: getOption('convert_fonts_to_spans'), 28960 fix_list_elements: getOption('fix_list_elements'), 28961 font_size_legacy_values: getOption('font_size_legacy_values'), 28962 forced_root_block: getOption('forced_root_block'), 28963 forced_root_block_attrs: getOption('forced_root_block_attrs'), 28964 preserve_cdata: getOption('preserve_cdata'), 28965 inline_styles: getOption('inline_styles'), 28966 root_name: getRootName(editor), 28967 sandbox_iframes: getOption('sandbox_iframes'), 28968 sandbox_iframes_exclusions: getSandboxIframesExclusions(editor), 28969 sanitize: getOption('xss_sanitization'), 28970 validate: true, 28971 blob_cache: blobCache, 28972 document: editor.getDoc() 28973 }); 28974 }; 28975 const mkSchemaSettings = editor => { 28976 const getOption = editor.options.get; 28977 return removeUndefined({ 28978 custom_elements: getOption('custom_elements'), 28979 extended_valid_elements: getOption('extended_valid_elements'), 28980 invalid_elements: getOption('invalid_elements'), 28981 invalid_styles: getOption('invalid_styles'), 28982 schema: getOption('schema'), 28983 valid_children: getOption('valid_children'), 28984 valid_classes: getOption('valid_classes'), 28985 valid_elements: getOption('valid_elements'), 28986 valid_styles: getOption('valid_styles'), 28987 verify_html: getOption('verify_html'), 28988 padd_empty_block_inline_children: getOption('format_empty_lines') 28989 }); 28990 }; 28991 const mkSerializerSettings = editor => { 28992 const getOption = editor.options.get; 28993 return { 28994 ...mkParserSettings(editor), 28995 ...mkSchemaSettings(editor), 28996 ...removeUndefined({ 28997 remove_trailing_brs: getOption('remove_trailing_brs'), 28998 pad_empty_with_br: getOption('pad_empty_with_br'), 28999 url_converter: getOption('url_converter'), 29000 url_converter_scope: getOption('url_converter_scope'), 29001 element_format: getOption('element_format'), 29002 entities: getOption('entities'), 29003 entity_encoding: getOption('entity_encoding'), 29004 indent: getOption('indent'), 29005 indent_after: getOption('indent_after'), 29006 indent_before: getOption('indent_before') 29007 }) 29008 }; 29009 }; 29010 const createParser = editor => { 29011 const parser = DomParser(mkParserSettings(editor), editor.schema); 29012 parser.addAttributeFilter('src,href,style,tabindex', (nodes, name) => { 29013 const dom = editor.dom; 29014 const internalName = 'data-mce-' + name; 29015 let i = nodes.length; 29016 while (i--) { 29017 const node = nodes[i]; 29018 let value = node.attr(name); 29019 if (value && !node.attr(internalName)) { 29020 if (value.indexOf('data:') === 0 || value.indexOf('blob:') === 0) { 29021 continue; 29022 } 29023 if (name === 'style') { 29024 value = dom.serializeStyle(dom.parseStyle(value), node.name); 29025 if (!value.length) { 29026 value = null; 29027 } 29028 node.attr(internalName, value); 29029 node.attr(name, value); 29030 } else if (name === 'tabindex') { 29031 node.attr(internalName, value); 29032 node.attr(name, null); 29033 } else { 29034 node.attr(internalName, editor.convertURL(value, name, node.name)); 29035 } 29036 } 29037 } 29038 }); 29039 parser.addNodeFilter('script', nodes => { 29040 let i = nodes.length; 29041 while (i--) { 29042 const node = nodes[i]; 29043 const type = node.attr('type') || 'no/type'; 29044 if (type.indexOf('mce-') !== 0) { 29045 node.attr('type', 'mce-' + type); 29046 } 29047 } 29048 }); 29049 if (shouldPreserveCData(editor)) { 29050 parser.addNodeFilter('#cdata', nodes => { 29051 var _a; 29052 let i = nodes.length; 29053 while (i--) { 29054 const node = nodes[i]; 29055 node.type = 8; 29056 node.name = '#comment'; 29057 node.value = '[CDATA[' + editor.dom.encode((_a = node.value) !== null && _a !== void 0 ? _a : '') + ']]'; 29058 } 29059 }); 29060 } 29061 parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', nodes => { 29062 let i = nodes.length; 29063 const nonEmptyElements = editor.schema.getNonEmptyElements(); 29064 while (i--) { 29065 const node = nodes[i]; 29066 if (node.isEmpty(nonEmptyElements) && node.getAll('br').length === 0) { 29067 node.append(new AstNode('br', 1)); 29068 } 29069 } 29070 }); 29071 return parser; 29072 }; 29073 const autoFocus = editor => { 29074 const autoFocus = getAutoFocus(editor); 29075 if (autoFocus) { 29076 Delay.setEditorTimeout(editor, () => { 29077 let focusEditor; 29078 if (autoFocus === true) { 29079 focusEditor = editor; 29080 } else { 29081 focusEditor = editor.editorManager.get(autoFocus); 29082 } 29083 if (focusEditor && !focusEditor.destroyed) { 29084 focusEditor.focus(); 29085 focusEditor.selection.scrollIntoView(); 29086 } 29087 }, 100); 29088 } 29089 }; 29090 const moveSelectionToFirstCaretPosition = editor => { 29091 const root = editor.dom.getRoot(); 29092 if (!editor.inline && (!hasAnyRanges(editor) || editor.selection.getStart(true) === root)) { 29093 firstPositionIn(root).each(pos => { 29094 const node = pos.getNode(); 29095 const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos; 29096 editor.selection.setRng(caretPos.toRange()); 29097 }); 29098 } 29099 }; 29100 const initEditor = editor => { 29101 editor.bindPendingEventDelegates(); 29102 editor.initialized = true; 29103 fireInit(editor); 29104 editor.focus(true); 29105 moveSelectionToFirstCaretPosition(editor); 29106 editor.nodeChanged({ initial: true }); 29107 const initInstanceCallback = getInitInstanceCallback(editor); 29108 if (isFunction(initInstanceCallback)) { 29109 initInstanceCallback.call(editor, editor); 29110 } 29111 autoFocus(editor); 29112 if (isDisabled(editor)) { 29113 toggleDisabled(editor, true); 29114 } 29115 }; 29116 const getStyleSheetLoader$1 = editor => editor.inline ? editor.ui.styleSheetLoader : editor.dom.styleSheetLoader; 29117 const makeStylesheetLoadingPromises = (editor, css, framedFonts) => { 29118 const { 29119 pass: bundledCss, 29120 fail: normalCss 29121 } = partition$2(css, name => tinymce.Resource.has(toContentSkinResourceName(name))); 29122 const bundledPromises = bundledCss.map(url => { 29123 const css = tinymce.Resource.get(toContentSkinResourceName(url)); 29124 if (isString(css)) { 29125 return Promise.resolve(getStyleSheetLoader$1(editor).loadRawCss(url, css)); 29126 } 29127 return Promise.resolve(); 29128 }); 29129 const promises = [ 29130 ...bundledPromises, 29131 getStyleSheetLoader$1(editor).loadAll(normalCss) 29132 ]; 29133 if (editor.inline) { 29134 return promises; 29135 } else { 29136 return promises.concat([editor.ui.styleSheetLoader.loadAll(framedFonts)]); 29137 } 29138 }; 29139 const loadContentCss = editor => { 29140 const styleSheetLoader = getStyleSheetLoader$1(editor); 29141 const fontCss = getFontCss(editor); 29142 const css = editor.contentCSS; 29143 const removeCss = () => { 29144 styleSheetLoader.unloadAll(css); 29145 if (!editor.inline) { 29146 editor.ui.styleSheetLoader.unloadAll(fontCss); 29147 } 29148 }; 29149 const loaded = () => { 29150 if (editor.removed) { 29151 removeCss(); 29152 } else { 29153 editor.on('remove', removeCss); 29154 } 29155 }; 29156 if (editor.contentStyles.length > 0) { 29157 let contentCssText = ''; 29158 Tools.each(editor.contentStyles, style => { 29159 contentCssText += style + '\r\n'; 29160 }); 29161 editor.dom.addStyle(contentCssText); 29162 } 29163 const allStylesheets = Promise.all(makeStylesheetLoadingPromises(editor, css, fontCss)).then(loaded).catch(loaded); 29164 const contentStyle = getContentStyle(editor); 29165 if (contentStyle) { 29166 appendStyle(editor, contentStyle); 29167 } 29168 return allStylesheets; 29169 }; 29170 const preInit = editor => { 29171 const doc = editor.getDoc(), body = editor.getBody(); 29172 firePreInit(editor); 29173 if (!shouldBrowserSpellcheck(editor)) { 29174 doc.body.spellcheck = false; 29175 DOM$6.setAttrib(body, 'spellcheck', 'false'); 29176 } 29177 editor.quirks = Quirks(editor); 29178 firePostRender(editor); 29179 const directionality = getDirectionality(editor); 29180 if (directionality !== undefined) { 29181 body.dir = directionality; 29182 } 29183 const protect = getProtect(editor); 29184 if (protect) { 29185 editor.on('BeforeSetContent', e => { 29186 Tools.each(protect, pattern => { 29187 e.content = e.content.replace(pattern, str => { 29188 return '<!--mce:protected ' + escape(str) + '-->'; 29189 }); 29190 }); 29191 }); 29192 } 29193 editor.on('SetContent', () => { 29194 editor.addVisual(editor.getBody()); 29195 }); 29196 editor.on('compositionstart compositionend', e => { 29197 editor.composing = e.type === 'compositionstart'; 29198 }); 29199 }; 29200 const loadInitialContent = editor => { 29201 if (!isRtc(editor)) { 29202 editor.load({ 29203 initial: true, 29204 format: 'html' 29205 }); 29206 } 29207 editor.startContent = editor.getContent({ format: 'raw' }); 29208 }; 29209 const initEditorWithInitialContent = editor => { 29210 if (editor.removed !== true) { 29211 loadInitialContent(editor); 29212 initEditor(editor); 29213 } 29214 }; 29215 const startProgress = editor => { 29216 let canceled = false; 29217 const progressTimeout = setTimeout(() => { 29218 if (!canceled) { 29219 editor.setProgressState(true); 29220 } 29221 }, 500); 29222 return () => { 29223 clearTimeout(progressTimeout); 29224 canceled = true; 29225 editor.setProgressState(false); 29226 }; 29227 }; 29228 const contentBodyLoaded = editor => { 29229 const targetElm = editor.getElement(); 29230 let doc = editor.getDoc(); 29231 if (editor.inline) { 29232 DOM$6.addClass(targetElm, 'mce-content-body'); 29233 editor.contentDocument = doc = document; 29234 editor.contentWindow = window; 29235 editor.bodyElement = targetElm; 29236 editor.contentAreaContainer = targetElm; 29237 } 29238 const body = editor.getBody(); 29239 body.disabled = true; 29240 editor.readonly = isReadOnly$1(editor); 29241 editor._editableRoot = hasEditableRoot$1(editor); 29242 if (!isDisabled$1(editor) && editor.hasEditableRoot()) { 29243 if (editor.inline && DOM$6.getStyle(body, 'position', true) === 'static') { 29244 body.style.position = 'relative'; 29245 } 29246 body.contentEditable = 'true'; 29247 } 29248 body.disabled = false; 29249 editor.editorUpload = EditorUpload(editor); 29250 editor.schema = Schema(mkSchemaSettings(editor)); 29251 editor.dom = DOMUtils(doc, { 29252 keep_values: true, 29253 url_converter: editor.convertURL, 29254 url_converter_scope: editor, 29255 update_styles: true, 29256 root_element: editor.inline ? editor.getBody() : null, 29257 collect: editor.inline, 29258 schema: editor.schema, 29259 contentCssCors: shouldUseContentCssCors(editor), 29260 referrerPolicy: getReferrerPolicy(editor), 29261 onSetAttrib: e => { 29262 editor.dispatch('SetAttrib', e); 29263 } 29264 }); 29265 editor.parser = createParser(editor); 29266 editor.serializer = DomSerializer(mkSerializerSettings(editor), editor); 29267 editor.selection = EditorSelection(editor.dom, editor.getWin(), editor.serializer, editor); 29268 editor.annotator = Annotator(editor); 29269 editor.formatter = Formatter(editor); 29270 editor.undoManager = UndoManager(editor); 29271 editor._nodeChangeDispatcher = new NodeChange(editor); 29272 editor._selectionOverrides = SelectionOverrides(editor); 29273 setup$p(editor); 29274 setup$6(editor); 29275 setup$n(editor); 29276 if (!isRtc(editor)) { 29277 setup$5(editor); 29278 setup$1(editor); 29279 } 29280 const caret = setup$b(editor); 29281 setup$q(editor, caret); 29282 setup$o(editor); 29283 setup$r(editor); 29284 setup$7(editor); 29285 const setupRtcThunk = setup$t(editor); 29286 preInit(editor); 29287 validateEditorLicenseKey(editor); 29288 setupRtcThunk.fold(() => { 29289 const cancelProgress = startProgress(editor); 29290 loadContentCss(editor).then(() => { 29291 initEditorWithInitialContent(editor); 29292 cancelProgress(); 29293 }); 29294 }, setupRtc => { 29295 editor.setProgressState(true); 29296 loadContentCss(editor).then(() => { 29297 setupRtc().then(_rtcMode => { 29298 editor.setProgressState(false); 29299 initEditorWithInitialContent(editor); 29300 bindEvents(editor); 29301 }, err => { 29302 editor.notificationManager.open({ 29303 type: 'error', 29304 text: String(err) 29305 }); 29306 initEditorWithInitialContent(editor); 29307 bindEvents(editor); 29308 }); 29309 }); 29310 }); 29311 }; 29312 29313 const filter = always; 29314 const bind = (element, event, handler) => bind$2(element, event, filter, handler); 29315 29316 const DOM$5 = DOMUtils.DOM; 29317 const createIframeElement = (id, title, customAttrs, tabindex) => { 29318 const iframe = SugarElement.fromTag('iframe'); 29319 tabindex.each(t => set$4(iframe, 'tabindex', t)); 29320 setAll$1(iframe, customAttrs); 29321 setAll$1(iframe, { 29322 id: id + '_ifr', 29323 frameBorder: '0', 29324 allowTransparency: 'true', 29325 title 29326 }); 29327 add$2(iframe, 'tox-edit-area__iframe'); 29328 return iframe; 29329 }; 29330 const getIframeHtml = editor => {
vendor: 5,279 bytes, lines 29331-29461
29331 let iframeHTML = getDocType(editor) + '<html><head>'; 29332 if (getDocumentBaseUrl(editor) !== editor.documentBaseUrl) { 29333 iframeHTML += '<base href="' + editor.documentBaseURI.getURI() + '" />'; 29334 } 29335 iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />'; 29336 const bodyId = getBodyId(editor); 29337 const bodyClass = getBodyClass(editor); 29338 const translatedAriaText = editor.translate(getIframeAriaText(editor)); 29339 if (getContentSecurityPolicy(editor)) { 29340 iframeHTML += '<meta http-equiv="Content-Security-Policy" content="' + getContentSecurityPolicy(editor) + '" />'; 29341 } 29342 iframeHTML += '</head>' + `<body id="${ bodyId }" class="mce-content-body ${ bodyClass }" data-id="${ editor.id }" aria-label="${ translatedAriaText }">` + '<br>' + '</body></html>'; 29343 return iframeHTML; 29344 }; 29345 const createIframe = (editor, boxInfo) => { 29346 const iframeTitle = Env.browser.isFirefox() ? getIframeAriaText(editor) : 'Rich Text Area'; 29347 const translatedTitle = editor.translate(iframeTitle); 29348 const tabindex = getOpt(SugarElement.fromDom(editor.getElement()), 'tabindex').bind(toInt); 29349 const ifr = createIframeElement(editor.id, translatedTitle, getIframeAttrs(editor), tabindex).dom; 29350 ifr.onload = () => { 29351 ifr.onload = null; 29352 editor.dispatch('load'); 29353 }; 29354 editor.contentAreaContainer = boxInfo.iframeContainer; 29355 editor.iframeElement = ifr; 29356 editor.iframeHTML = getIframeHtml(editor); 29357 DOM$5.add(boxInfo.iframeContainer, ifr); 29358 }; 29359 const setupIframeBody = editor => { 29360 const iframe = editor.iframeElement; 29361 const ready = () => { 29362 editor.contentDocument = iframe.contentDocument; 29363 contentBodyLoaded(editor); 29364 }; 29365 if (shouldUseDocumentWrite(editor) || Env.browser.isFirefox()) { 29366 const doc = editor.getDoc(); 29367 doc.open(); 29368 doc.write(editor.iframeHTML); 29369 doc.close(); 29370 ready(); 29371 } else { 29372 const binder = bind(SugarElement.fromDom(iframe), 'load', () => { 29373 binder.unbind(); 29374 ready(); 29375 }); 29376 iframe.srcdoc = editor.iframeHTML; 29377 } 29378 }; 29379 const init$1 = (editor, boxInfo) => { 29380 createIframe(editor, boxInfo); 29381 if (boxInfo.editorContainer) { 29382 boxInfo.editorContainer.style.display = editor.orgDisplay; 29383 editor.hidden = DOM$5.isHidden(boxInfo.editorContainer); 29384 } 29385 editor.getElement().style.display = 'none'; 29386 DOM$5.setAttrib(editor.id, 'aria-hidden', 'true'); 29387 editor.getElement().style.visibility = editor.orgVisibility; 29388 setupIframeBody(editor); 29389 }; 29390 29391 const DOM$4 = DOMUtils.DOM; 29392 const initPlugin = (editor, initializedPlugins, plugin) => { 29393 const Plugin = PluginManager.get(plugin); 29394 const pluginUrl = PluginManager.urls[plugin] || editor.documentBaseUrl.replace(/\/$/, ''); 29395 plugin = Tools.trim(plugin); 29396 if (Plugin && Tools.inArray(initializedPlugins, plugin) === -1) { 29397 if (editor.plugins[plugin]) { 29398 return; 29399 } 29400 try { 29401 const pluginInstance = Plugin(editor, pluginUrl) || {}; 29402 editor.plugins[plugin] = pluginInstance; 29403 if (isFunction(pluginInstance.init)) { 29404 pluginInstance.init(editor, pluginUrl); 29405 initializedPlugins.push(plugin); 29406 } 29407 } catch (e) { 29408 pluginInitError(editor, plugin, e); 29409 } 29410 } 29411 }; 29412 const trimLegacyPrefix = name => { 29413 return name.replace(/^\-/, ''); 29414 }; 29415 const initPlugins = editor => { 29416 const initializedPlugins = []; 29417 each$e(getPlugins(editor), name => { 29418 initPlugin(editor, initializedPlugins, trimLegacyPrefix(name)); 29419 }); 29420 }; 29421 const initIcons = editor => { 29422 const iconPackName = Tools.trim(getIconPackName(editor)); 29423 const currentIcons = editor.ui.registry.getAll().icons; 29424 const loadIcons = { 29425 ...IconManager.get('default').icons, 29426 ...IconManager.get(iconPackName).icons 29427 }; 29428 each$d(loadIcons, (svgData, icon) => { 29429 if (!has$2(currentIcons, icon)) { 29430 editor.ui.registry.addIcon(icon, svgData); 29431 } 29432 }); 29433 }; 29434 const initTheme = editor => { 29435 const theme = getTheme(editor); 29436 if (isString(theme)) { 29437 const Theme = ThemeManager.get(theme); 29438 editor.theme = Theme(editor, ThemeManager.urls[theme]) || {}; 29439 if (isFunction(editor.theme.init)) { 29440 editor.theme.init(editor, ThemeManager.urls[theme] || editor.documentBaseUrl.replace(/\/$/, '')); 29441 } 29442 } else { 29443 editor.theme = {}; 29444 } 29445 }; 29446 const initModel = editor => { 29447 const model = getModel(editor); 29448 const Model = ModelManager.get(model); 29449 editor.model = Model(editor, ModelManager.urls[model]); 29450 }; 29451 const renderFromLoadedTheme = editor => { 29452 const render = editor.theme.renderUI; 29453 return render ? render() : renderThemeFalse(editor); 29454 }; 29455 const renderFromThemeFunc = editor => { 29456 const elm = editor.getElement(); 29457 const theme = getTheme(editor); 29458 const info = theme(editor, elm); 29459 if (info.editorContainer.nodeType) { 29460 info.editorContainer.id = info.editorContainer.id || editor.id + '_parent'; 29461 }
29462 if (info.iframeContainer && info.iframeContainer.nodeType) { 29463 info.iframeContainer.id = info.iframeContainer.id || editor.id + '_iframecontainer'; 29464 } 29465 info.height = info.iframeHeight ? info.iframeHeight : elm.offsetHeight; 29466 return info; 29467 }; 29468 const createThemeFalseResult = (element, iframe) => { 29469 return { 29470 editorContainer: element, 29471 iframeContainer: iframe, 29472 api: {} 29473 }; 29474 }; 29475 const renderThemeFalseIframe = targetElement => { 29476 const iframeContainer = DOM$4.create('div'); 29477 DOM$4.insertAfter(iframeContainer, targetElement); 29478 return createThemeFalseResult(iframeContainer, iframeContainer); 29479 }; 29480 const renderThemeFalse = editor => { 29481 const targetElement = editor.getElement(); 29482 return editor.inline ? createThemeFalseResult(null) : renderThemeFalseIframe(targetElement); 29483 }; 29484 const renderThemeUi = editor => { 29485 const elm = editor.getElement(); 29486 editor.orgDisplay = elm.style.display; 29487 if (isString(getTheme(editor))) { 29488 return renderFromLoadedTheme(editor); 29489 } else if (isFunction(getTheme(editor))) { 29490 return renderFromThemeFunc(editor); 29491 } else { 29492 return renderThemeFalse(editor); 29493 } 29494 }; 29495 const augmentEditorUiApi = (editor, api) => { 29496 const uiApiFacade = { 29497 show: Optional.from(api.show).getOr(noop), 29498 hide: Optional.from(api.hide).getOr(noop), 29499 isEnabled: Optional.from(api.isEnabled).getOr(always), 29500 setEnabled: state => { 29501 const shouldSkip = state && (editor.mode.get() === 'readonly' || isDisabled(editor)); 29502 if (!shouldSkip
vendor: 5,510 bytes, lines 29502-29644
29502) { 29503 Optional.from(api.setEnabled).each(f => f(state)); 29504 } 29505 } 29506 }; 29507 editor.ui = { 29508 ...editor.ui, 29509 ...uiApiFacade 29510 }; 29511 }; 29512 const init = async editor => { 29513 editor.dispatch('ScriptsLoaded'); 29514 initIcons(editor); 29515 initTheme(editor); 29516 initModel(editor); 29517 initPlugins(editor); 29518 const renderInfo = await renderThemeUi(editor); 29519 augmentEditorUiApi(editor, Optional.from(renderInfo.api).getOr({})); 29520 editor.editorContainer = renderInfo.editorContainer; 29521 appendContentCssFromSettings(editor); 29522 if (editor.inline) { 29523 contentBodyLoaded(editor); 29524 } else { 29525 init$1(editor, { 29526 editorContainer: renderInfo.editorContainer, 29527 iframeContainer: renderInfo.iframeContainer 29528 }); 29529 } 29530 }; 29531 29532 const DOM$3 = DOMUtils.DOM; 29533 const hasSkipLoadPrefix = name => name.charAt(0) === '-'; 29534 const loadLanguage = (scriptLoader, editor) => { 29535 const languageCode = getLanguageCode(editor); 29536 const languageUrl = getLanguageUrl(editor); 29537 if (!I18n.hasCode(languageCode) && languageCode !== 'en') { 29538 const url = isNotEmpty(languageUrl) ? languageUrl : `${ editor.editorManager.baseURL }/langs/${ languageCode }.js`; 29539 scriptLoader.add(url).catch(() => { 29540 languageLoadError(editor, url, languageCode); 29541 }); 29542 } 29543 }; 29544 const loadTheme = (editor, suffix) => { 29545 const theme = getTheme(editor); 29546 if (isString(theme) && !hasSkipLoadPrefix(theme) && !has$2(ThemeManager.urls, theme)) { 29547 const themeUrl = getThemeUrl(editor); 29548 const url = themeUrl ? editor.documentBaseURI.toAbsolute(themeUrl) : `themes/${ theme }/theme${ suffix }.js`; 29549 ThemeManager.load(theme, url).catch(() => { 29550 themeLoadError(editor, url, theme); 29551 }); 29552 } 29553 }; 29554 const loadModel = (editor, suffix) => { 29555 const model = getModel(editor); 29556 if (model !== 'plugin' && !has$2(ModelManager.urls, model)) { 29557 const modelUrl = getModelUrl(editor); 29558 const url = isString(modelUrl) ? editor.documentBaseURI.toAbsolute(modelUrl) : `models/${ model }/model${ suffix }.js`; 29559 ModelManager.load(model, url).catch(() => { 29560 modelLoadError(editor, url, model); 29561 }); 29562 } 29563 }; 29564 const getIconsUrlMetaFromUrl = editor => Optional.from(getIconsUrl(editor)).filter(isNotEmpty).map(url => ({ 29565 url, 29566 name: Optional.none() 29567 })); 29568 const getIconsUrlMetaFromName = (editor, name, suffix) => Optional.from(name).filter(name => isNotEmpty(name) && !IconManager.has(name)).map(name => ({ 29569 url: `${ editor.editorManager.baseURL }/icons/${ name }/icons${ suffix }.js`, 29570 name: Optional.some(name) 29571 })); 29572 const loadIcons = (scriptLoader, editor, suffix) => { 29573 const defaultIconsUrl = getIconsUrlMetaFromName(editor, 'default', suffix); 29574 const customIconsUrl = getIconsUrlMetaFromUrl(editor).orThunk(() => getIconsUrlMetaFromName(editor, getIconPackName(editor), '')); 29575 each$e(cat([ 29576 defaultIconsUrl, 29577 customIconsUrl 29578 ]), urlMeta => { 29579 scriptLoader.add(urlMeta.url).catch(() => { 29580 iconsLoadError(editor, urlMeta.url, urlMeta.name.getOrUndefined()); 29581 }); 29582 }); 29583 }; 29584 const loadPlugins = (editor, suffix) => { 29585 const loadPlugin = (name, url) => { 29586 PluginManager.load(name, url).catch(() => { 29587 pluginLoadError(editor, url, name); 29588 }); 29589 }; 29590 each$d(getExternalPlugins$1(editor), (url, name) => { 29591 loadPlugin(name, url); 29592 editor.options.set('plugins', getPlugins(editor).concat(name)); 29593 }); 29594 each$e(getPlugins(editor), plugin => { 29595 plugin = Tools.trim(plugin); 29596 if (plugin && !PluginManager.urls[plugin] && !hasSkipLoadPrefix(plugin)) { 29597 loadPlugin(plugin, `plugins/${ plugin }/plugin${ suffix }.js`); 29598 } 29599 }); 29600 }; 29601 const isThemeLoaded = editor => { 29602 const theme = getTheme(editor); 29603 return !isString(theme) || isNonNullable(ThemeManager.get(theme)); 29604 }; 29605 const isModelLoaded = editor => { 29606 const model = getModel(editor); 29607 return isNonNullable(ModelManager.get(model)); 29608 }; 29609 const loadScripts = (editor, suffix) => { 29610 const scriptLoader = ScriptLoader.ScriptLoader; 29611 const initEditor = () => { 29612 if (!editor.removed && isThemeLoaded(editor) && isModelLoaded(editor)) { 29613 init(editor); 29614 } 29615 }; 29616 loadTheme(editor, suffix); 29617 loadModel(editor, suffix); 29618 loadLanguage(scriptLoader, editor); 29619 loadIcons(scriptLoader, editor, suffix); 29620 loadPlugins(editor, suffix); 29621 scriptLoader.loadQueue().then(initEditor, initEditor); 29622 }; 29623 const getStyleSheetLoader = (element, editor) => instance.forElement(element, { 29624 contentCssCors: hasContentCssCors(editor), 29625 referrerPolicy: getReferrerPolicy(editor) 29626 }); 29627 const render = editor => { 29628 const id = editor.id; 29629 I18n.setCode(getLanguageCode(editor)); 29630 const readyHandler = () => { 29631 DOM$3.unbind(window, 'ready', readyHandler); 29632 editor.render(); 29633 }; 29634 if (!EventUtils.Event.domLoaded) { 29635 DOM$3.bind(window, 'ready', readyHandler); 29636 return; 29637 } 29638 if (!editor.getElement()) { 29639 return; 29640 } 29641 const element = SugarElement.fromDom(editor.getElement()); 29642 const snapshot = clone$4(element); 29643 editor.on('remove', () => { 29644 eachr(element.dom.attributes, attr => remove$
vendor: 13,333 bytes, lines 29644-29993
296449(element, attr.name)); 29645 setAll$1(element, snapshot); 29646 }); 29647 editor.ui.styleSheetLoader = getStyleSheetLoader(element, editor); 29648 if (!isInline$1(editor)) { 29649 editor.orgVisibility = editor.getElement().style.visibility; 29650 editor.getElement().style.visibility = 'hidden'; 29651 } else { 29652 editor.inline = true; 29653 } 29654 const form = editor.getElement().form || DOM$3.getParent(id, 'form'); 29655 if (form) { 29656 editor.formElement = form; 29657 if (hasHiddenInput(editor) && !isTextareaOrInput(editor.getElement())) { 29658 DOM$3.insertAfter(DOM$3.create('input', { 29659 type: 'hidden', 29660 name: id 29661 }), id); 29662 editor.hasHiddenInput = true; 29663 } 29664 editor.formEventDelegate = e => { 29665 editor.dispatch(e.type, e); 29666 }; 29667 DOM$3.bind(form, 'submit reset', editor.formEventDelegate); 29668 editor.on('reset', () => { 29669 editor.resetContent(); 29670 }); 29671 if (shouldPatchSubmit(editor) && !form.submit.nodeType && !form.submit.length && !form._mceOldSubmit) { 29672 form._mceOldSubmit = form.submit; 29673 form.submit = () => { 29674 editor.editorManager.triggerSave(); 29675 editor.setDirty(false); 29676 return form._mceOldSubmit(form); 29677 }; 29678 } 29679 } 29680 editor.windowManager = WindowManager(editor); 29681 editor.notificationManager = NotificationManager(editor); 29682 if (isEncodingXml(editor)) { 29683 editor.on('GetContent', e => { 29684 if (e.save) { 29685 e.content = DOM$3.encode(e.content); 29686 } 29687 }); 29688 } 29689 if (shouldAddFormSubmitTrigger(editor)) { 29690 editor.on('submit', () => { 29691 if (editor.initialized) { 29692 editor.save(); 29693 } 29694 }); 29695 } 29696 if (shouldAddUnloadTrigger(editor)) { 29697 editor._beforeUnload = () => { 29698 if (editor.initialized && !editor.destroyed && !editor.isHidden()) { 29699 editor.save({ 29700 format: 'raw', 29701 no_events: true, 29702 set_dirty: false 29703 }); 29704 } 29705 }; 29706 editor.editorManager.on('BeforeUnload', editor._beforeUnload); 29707 } 29708 editor.editorManager.add(editor); 29709 loadScripts(editor, editor.suffix); 29710 }; 29711 29712 const setEditableRoot = (editor, state) => { 29713 if (editor._editableRoot !== state) { 29714 editor._editableRoot = state; 29715 if (!isDisabled(editor)) { 29716 editor.getBody().contentEditable = String(editor.hasEditableRoot()); 29717 editor.nodeChanged(); 29718 } 29719 fireEditableRootStateChange(editor, state); 29720 } 29721 }; 29722 const hasEditableRoot = editor => editor._editableRoot; 29723 29724 const sectionResult = (sections, settings) => ({ 29725 sections: constant(sections), 29726 options: constant(settings) 29727 }); 29728 const deviceDetection = detect$1().deviceType; 29729 const isPhone = deviceDetection.isPhone(); 29730 const isTablet = deviceDetection.isTablet(); 29731 const normalizePlugins = plugins => { 29732 if (isNullable(plugins)) { 29733 return []; 29734 } else { 29735 const pluginNames = isArray$1(plugins) ? plugins : plugins.split(/[ ,]/); 29736 const trimmedPlugins = map$3(pluginNames, trim$4); 29737 return filter$5(trimmedPlugins, isNotEmpty); 29738 } 29739 }; 29740 const extractSections = (keys, options) => { 29741 const result = bifilter(options, (value, key) => { 29742 return contains$2(keys, key); 29743 }); 29744 return sectionResult(result.t, result.f); 29745 }; 29746 const getSection = (sectionResult, name, defaults = {}) => { 29747 const sections = sectionResult.sections(); 29748 const sectionOptions = get$a(sections, name).getOr({}); 29749 return Tools.extend({}, defaults, sectionOptions); 29750 }; 29751 const hasSection = (sectionResult, name) => { 29752 return has$2(sectionResult.sections(), name); 29753 }; 29754 const getSectionConfig = (sectionResult, name) => { 29755 return hasSection(sectionResult, name) ? sectionResult.sections()[name] : {}; 29756 }; 29757 const getMobileOverrideOptions = (mobileOptions, isPhone) => { 29758 const defaultMobileOptions = { 29759 table_grid: false, 29760 object_resizing: false, 29761 resize: false, 29762 toolbar_mode: get$a(mobileOptions, 'toolbar_mode').getOr('scrolling'), 29763 toolbar_sticky: false 29764 }; 29765 const defaultPhoneOptions = { menubar: false }; 29766 return { 29767 ...defaultMobileOptions, 29768 ...isPhone ? defaultPhoneOptions : {} 29769 }; 29770 }; 29771 const getExternalPlugins = (overrideOptions, options) => { 29772 var _a; 29773 const userDefinedExternalPlugins = (_a = options.external_plugins) !== null && _a !== void 0 ? _a : {}; 29774 if (overrideOptions && overrideOptions.external_plugins) { 29775 return Tools.extend({}, overrideOptions.external_plugins, userDefinedExternalPlugins); 29776 } else { 29777 return userDefinedExternalPlugins; 29778 } 29779 }; 29780 const combinePlugins = (forcedPlugins, plugins) => [ 29781 ...normalizePlugins(forcedPlugins), 29782 ...normalizePlugins(plugins) 29783 ]; 29784 const getPlatformPlugins = (isMobileDevice, sectionResult, desktopPlugins, mobilePlugins) => { 29785 if (isMobileDevice && hasSection(sectionResult, 'mobile')) { 29786 return mobilePlugins; 29787 } else { 29788 return desktopPlugins; 29789 } 29790 }; 29791 const processPlugins = (isMobileDevice, sectionResult, defaultOverrideOptions, options) => { 29792 const forcedPlugins = normalizePlugins(defaultOverrideOptions.forced_plugins); 29793 const desktopPlugins = normalizePlugins(options.plugins); 29794 const mobileConfig = getSectionConfig(sectionResult, 'mobile'); 29795 const mobilePlugins = mobileConfig.plugins ? normalizePlugins(mobileConfig.plugins) : desktopPlugins; 29796 const platformPlugins = getPlatformPlugins(isMobileDevice, sectionResult, desktopPlugins, mobilePlugins); 29797 const combinedPlugins = combinePlugins(forcedPlugins, platformPlugins); 29798 return Tools.extend(options, { 29799 forced_plugins: forcedPlugins, 29800 plugins: combinedPlugins 29801 }); 29802 }; 29803 const isOnMobile = (isMobileDevice, sectionResult) => { 29804 return isMobileDevice && hasSection(sectionResult, 'mobile'); 29805 }; 29806 const combineOptions = (isMobileDevice, isPhone, defaultOptions, defaultOverrideOptions, options) => { 29807 var _a; 29808 const deviceOverrideOptions = isMobileDevice ? { mobile: getMobileOverrideOptions((_a = options.mobile) !== null && _a !== void 0 ? _a : {}, isPhone) } : {}; 29809 const sectionResult = extractSections(['mobile'], deepMerge(deviceOverrideOptions, options)); 29810 const extendedOptions = Tools.extend(defaultOptions, defaultOverrideOptions, sectionResult.options(), isOnMobile(isMobileDevice, sectionResult) ? getSection(sectionResult, 'mobile') : {}, { external_plugins: getExternalPlugins(defaultOverrideOptions, sectionResult.options()) }); 29811 return processPlugins(isMobileDevice, sectionResult, defaultOverrideOptions, extendedOptions); 29812 }; 29813 const normalizeOptions = (defaultOverrideOptions, options) => { 29814 const copiedOptions = merge(options); 29815 return combineOptions(isPhone || isTablet, isPhone, copiedOptions, defaultOverrideOptions, copiedOptions); 29816 }; 29817 29818 const addVisual = (editor, elm) => addVisual$1(editor, elm); 29819 29820 const registerExecCommands$2 = editor => { 29821 const toggleFormat = (name, value) => { 29822 editor.formatter.toggle(name, value); 29823 editor.nodeChanged(); 29824 }; 29825 const toggleAlign = align => () => { 29826 each$e('left,center,right,justify'.split(','), name => { 29827 if (align !== name) { 29828 editor.formatter.remove('align' + name); 29829 } 29830 }); 29831 if (align !== 'none') { 29832 toggleFormat('align' + align); 29833 } 29834 }; 29835 editor.editorCommands.addCommands({ 29836 JustifyLeft: toggleAlign('left'), 29837 JustifyCenter: toggleAlign('center'), 29838 JustifyRight: toggleAlign('right'), 29839 JustifyFull: toggleAlign('justify'), 29840 JustifyNone: toggleAlign('none') 29841 }); 29842 }; 29843 const registerQueryStateCommands = editor => { 29844 const alignStates = name => () => { 29845 const selection = editor.selection; 29846 const nodes = selection.isCollapsed() ? [editor.dom.getParent(selection.getNode(), editor.dom.isBlock)] : selection.getSelectedBlocks(); 29847 return exists(nodes, node => isNonNullable(editor.formatter.matchNode(node, name))); 29848 }; 29849 editor.editorCommands.addCommands({ 29850 JustifyLeft: alignStates('alignleft'), 29851 JustifyCenter: alignStates('aligncenter'), 29852 JustifyRight: alignStates('alignright'), 29853 JustifyFull: alignStates('alignjustify') 29854 }, 'state'); 29855 }; 29856 const registerCommands$a = editor => { 29857 registerExecCommands$2(editor); 29858 registerQueryStateCommands(editor); 29859 }; 29860 29861 const registerCommands$9 = editor => { 29862 editor.editorCommands.addCommands({ 29863 'Cut,Copy,Paste': command => { 29864 const doc = editor.getDoc(); 29865 let failed; 29866 try { 29867 doc.execCommand(command); 29868 } catch (_a) { 29869 failed = true; 29870 } 29871 if (command === 'paste' && !doc.queryCommandEnabled(command)) { 29872 failed = true; 29873 } 29874 if (failed || !doc.queryCommandSupported(command)) { 29875 let msg = editor.translate(`Your browser doesn't support direct access to the clipboard. ` + 'Please use the Ctrl+X/C/V keyboard shortcuts instead.'); 29876 if (Env.os.isMacOS() || Env.os.isiOS()) { 29877 msg = msg.replace(/Ctrl\+/g, '\u2318+'); 29878 } 29879 editor.notificationManager.open({ 29880 text: msg, 29881 type: 'error' 29882 }); 29883 } 29884 } 29885 }); 29886 }; 29887 29888 const trimOrPadLeftRight = (dom, rng, html, schema) => { 29889 const root = SugarElement.fromDom(dom.getRoot()); 29890 if (needsToBeNbspLeft(root, CaretPosition.fromRangeStart(rng), schema)) { 29891 html = html.replace(/^ /, ' '); 29892 } else { 29893 html = html.replace(/^ /, ' '); 29894 } 29895 if (needsToBeNbspRight(root, CaretPosition.fromRangeEnd(rng), schema)) { 29896 html = html.replace(/( | )(<br( \/)>)?$/, ' '); 29897 } else { 29898 html = html.replace(/ (<br( \/)?>)?$/, ' '); 29899 } 29900 return html; 29901 }; 29902 29903 const processValue$1 = value => { 29904 if (typeof value !== 'string') { 29905 const details = Tools.extend({ 29906 paste: value.paste, 29907 data: { paste: value.paste } 29908 }, value); 29909 return { 29910 content: value.content, 29911 details 29912 }; 29913 } 29914 return { 29915 content: value, 29916 details: {} 29917 }; 29918 }; 29919 const trimOrPad = (editor, value) => { 29920 const selection = editor.selection; 29921 const dom = editor.dom; 29922 if (/^ | $/.test(value)) { 29923 return trimOrPadLeftRight(dom, selection.getRng(), value, editor.schema); 29924 } else { 29925 return value; 29926 } 29927 }; 29928 const insertAtCaret = (editor, value) => { 29929 if (editor.selection.isEditable()) { 29930 const {content, details} = processValue$1(value); 29931 preProcessSetContent(editor, { 29932 ...details, 29933 content: trimOrPad(editor, content), 29934 format: 'html', 29935 set: false, 29936 selection: true 29937 }).each(args => { 29938 const insertedContent = insertContent$1(editor, args.content, details); 29939 postProcessSetContent(editor, insertedContent, args); 29940 editor.addVisual(); 29941 }); 29942 } 29943 }; 29944 29945 const registerCommands$8 = editor => { 29946 editor.editorCommands.addCommands({ 29947 mceCleanup: () => { 29948 const bm = editor.selection.getBookmark(); 29949 editor.setContent(editor.getContent()); 29950 editor.selection.moveToBookmark(bm); 29951 }, 29952 insertImage: (_command, _ui, value) => { 29953 insertAtCaret(editor, editor.dom.createHTML('img', { src: value })); 29954 }, 29955 insertHorizontalRule: () => { 29956 editor.execCommand('mceInsertContent', false, '<hr>'); 29957 }, 29958 insertText: (_command, _ui, value) => { 29959 insertAtCaret(editor, editor.dom.encode(value)); 29960 }, 29961 insertHTML: (_command, _ui, value) => { 29962 insertAtCaret(editor, value); 29963 }, 29964 mceInsertContent: (_command, _ui, value) => { 29965 insertAtCaret(editor, value); 29966 }, 29967 mceSetContent: (_command, _ui, value) => { 29968 editor.setContent(value); 29969 }, 29970 mceReplaceContent: (_command, _ui, value) => { 29971 editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, editor.selection.getContent({ format: 'text' }))); 29972 }, 29973 mceNewDocument: () => { 29974 editor.setContent(getNewDocumentContent(editor)); 29975 } 29976 }); 29977 }; 29978 29979 const legacyPropNames = { 29980 'font-size': 'size', 29981 'font-family': 'face' 29982 }; 29983 const isFont = isTag('font'); 29984 const getSpecifiedFontProp = (propName, rootElm, elm) => { 29985 const getProperty = elm => getRaw(elm, propName).orThunk(() => { 29986 if (isFont(elm)) { 29987 return get$a(legacyPropNames, propName).bind(legacyPropName => getOpt(elm, legacyPropName)); 29988 } else { 29989 return Optional.none(); 29990 } 29991 }); 29992 const isRoot = elm => eq(SugarElement.fromDom(rootElm), elm); 29993 return closest$1(SugarElement.fromDom(elm), elm =>
vendor: 6,507 bytes, lines 29993-30150
29993 getProperty(elm), isRoot); 29994 }; 29995 const normalizeFontFamily = fontFamily => fontFamily.replace(/[\'\"\\]/g, '').replace(/,\s+/g, ','); 29996 const getComputedFontProp = (propName, elm) => Optional.from(DOMUtils.DOM.getStyle(elm, propName, true)); 29997 const getFontProp = propName => (rootElm, elm) => Optional.from(elm).map(SugarElement.fromDom).filter(isElement$7).bind(element => getSpecifiedFontProp(propName, rootElm, element.dom).or(getComputedFontProp(propName, element.dom))).getOr(''); 29998 const getFontSize = getFontProp('font-size'); 29999 const getFontFamily = compose(normalizeFontFamily, getFontProp('font-family')); 30000 30001 const findFirstCaretElement = editor => firstPositionIn(editor.getBody()).bind(caret => { 30002 const container = caret.container(); 30003 return Optional.from(isText$b(container) ? container.parentNode : container); 30004 }); 30005 const getCaretElement = editor => Optional.from(editor.selection.getRng()).bind(rng => { 30006 const root = editor.getBody(); 30007 const atStartOfNode = rng.startContainer === root && rng.startOffset === 0; 30008 return atStartOfNode ? Optional.none() : Optional.from(editor.selection.getStart(true)); 30009 }); 30010 const bindRange = (editor, binder) => getCaretElement(editor).orThunk(curry(findFirstCaretElement, editor)).map(SugarElement.fromDom).filter(isElement$7).bind(binder); 30011 const mapRange = (editor, mapper) => bindRange(editor, compose1(Optional.some, mapper)); 30012 30013 const fromFontSizeNumber = (editor, value) => { 30014 if (/^[0-9.]+$/.test(value)) { 30015 const fontSizeNumber = parseInt(value, 10); 30016 if (fontSizeNumber >= 1 && fontSizeNumber <= 7) { 30017 const fontSizes = getFontStyleValues(editor); 30018 const fontClasses = getFontSizeClasses(editor); 30019 if (fontClasses.length > 0) { 30020 return fontClasses[fontSizeNumber - 1] || value; 30021 } else { 30022 return fontSizes[fontSizeNumber - 1] || value; 30023 } 30024 } else { 30025 return value; 30026 } 30027 } else { 30028 return value; 30029 } 30030 }; 30031 const normalizeFontNames = font => { 30032 const fonts = font.split(/\s*,\s*/); 30033 return map$3(fonts, font => { 30034 if (font.indexOf(' ') !== -1 && !(startsWith(font, '"') || startsWith(font, `'`))) { 30035 return `'${ font }'`; 30036 } else { 30037 return font; 30038 } 30039 }).join(','); 30040 }; 30041 const fontNameAction = (editor, value) => { 30042 const font = fromFontSizeNumber(editor, value); 30043 editor.formatter.toggle('fontname', { value: normalizeFontNames(font) }); 30044 editor.nodeChanged(); 30045 }; 30046 const fontNameQuery = editor => mapRange(editor, elm => getFontFamily(editor.getBody(), elm.dom)).getOr(''); 30047 const fontSizeAction = (editor, value) => { 30048 editor.formatter.toggle('fontsize', { value: fromFontSizeNumber(editor, value) }); 30049 editor.nodeChanged(); 30050 }; 30051 const fontSizeQuery = editor => mapRange(editor, elm => getFontSize(editor.getBody(), elm.dom)).getOr(''); 30052 30053 const lineHeightQuery = editor => mapRange(editor, elm => { 30054 const root = SugarElement.fromDom(editor.getBody()); 30055 const specifiedStyle = closest$1(elm, elm => getRaw(elm, 'line-height'), curry(eq, root)); 30056 const computedStyle = () => { 30057 const lineHeight = parseFloat(get$7(elm, 'line-height')); 30058 const fontSize = parseFloat(get$7(elm, 'font-size')); 30059 return String(lineHeight / fontSize); 30060 }; 30061 return specifiedStyle.getOrThunk(computedStyle); 30062 }).getOr(''); 30063 const lineHeightAction = (editor, lineHeight) => { 30064 editor.formatter.toggle('lineheight', { value: String(lineHeight) }); 30065 editor.nodeChanged(); 30066 }; 30067 30068 const registerExecCommands$1 = editor => { 30069 const toggleFormat = (name, value) => { 30070 editor.formatter.toggle(name, value); 30071 editor.nodeChanged(); 30072 }; 30073 editor.editorCommands.addCommands({ 30074 'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => { 30075 toggleFormat(command); 30076 }, 30077 'ForeColor,HiliteColor': (command, _ui, value) => { 30078 toggleFormat(command, { value }); 30079 }, 30080 'BackColor': (_command, _ui, value) => { 30081 toggleFormat('hilitecolor', { value }); 30082 }, 30083 'FontName': (_command, _ui, value) => { 30084 fontNameAction(editor, value); 30085 }, 30086 'FontSize': (_command, _ui, value) => { 30087 fontSizeAction(editor, value); 30088 }, 30089 'LineHeight': (_command, _ui, value) => { 30090 lineHeightAction(editor, value); 30091 }, 30092 'Lang': (command, _ui, lang) => { 30093 var _a; 30094 toggleFormat(command, { 30095 value: lang.code, 30096 customValue: (_a = lang.customCode) !== null && _a !== void 0 ? _a : null 30097 }); 30098 }, 30099 'RemoveFormat': command => { 30100 editor.formatter.remove(command); 30101 }, 30102 'mceBlockQuote': () => { 30103 toggleFormat('blockquote'); 30104 }, 30105 'FormatBlock': (_command, _ui, value) => { 30106 toggleFormat(isString(value) ? value : 'p'); 30107 }, 30108 'mceToggleFormat': (_command, _ui, value) => { 30109 toggleFormat(value); 30110 } 30111 }); 30112 }; 30113 const registerQueryValueCommands = editor => { 30114 const isFormatMatch = name => editor.formatter.match(name); 30115 editor.editorCommands.addCommands({ 30116 'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => isFormatMatch(command), 30117 'mceBlockQuote': () => isFormatMatch('blockquote') 30118 }, 'state'); 30119 editor.editorCommands.addQueryValueHandler('FontName', () => fontNameQuery(editor)); 30120 editor.editorCommands.addQueryValueHandler('FontSize', () => fontSizeQuery(editor)); 30121 editor.editorCommands.addQueryValueHandler('LineHeight', () => lineHeightQuery(editor)); 30122 }; 30123 const registerCommands$7 = editor => { 30124 registerExecCommands$1(editor); 30125 registerQueryValueCommands(editor); 30126 }; 30127 30128 const registerCommands$6 = editor => { 30129 editor.editorCommands.addCommands({ 30130 mceAddUndoLevel: () => { 30131 editor.undoManager.add(); 30132 }, 30133 mceEndUndoLevel: () => { 30134 editor.undoManager.add(); 30135 }, 30136 Undo: () => { 30137 editor.undoManager.undo(); 30138 }, 30139 Redo: () => { 30140 editor.undoManager.redo(); 30141 } 30142 }); 30143 }; 30144 30145 const registerCommands$5 = editor => { 30146 editor.editorCommands.addCommands({ 30147 Indent: () => { 30148 indent(editor); 30149 }, 30150 Outdent: () => {
vendor: 21,745 bytes, lines 30151-30790
30151 outdent(editor); 30152 } 30153 }); 30154 editor.editorCommands.addCommands({ Outdent: () => canOutdent(editor) }, 'state'); 30155 }; 30156 30157 const registerCommands$4 = editor => { 30158 const applyLinkToSelection = (_command, _ui, value) => { 30159 if (editor.mode.isReadOnly()) { 30160 return; 30161 } 30162 const linkDetails = isString(value) ? { href: value } : value; 30163 const anchor = editor.dom.getParent(editor.selection.getNode(), 'a'); 30164 if (isObject(linkDetails) && isString(linkDetails.href)) { 30165 linkDetails.href = linkDetails.href.replace(/ /g, '%20'); 30166 if (!anchor || !linkDetails.href) { 30167 editor.formatter.remove('link'); 30168 } 30169 if (linkDetails.href) { 30170 editor.formatter.apply('link', linkDetails, anchor); 30171 } 30172 } 30173 }; 30174 editor.editorCommands.addCommands({ 30175 unlink: () => { 30176 if (editor.selection.isEditable()) { 30177 if (editor.selection.isCollapsed()) { 30178 const elm = editor.dom.getParent(editor.selection.getStart(), 'a'); 30179 if (elm) { 30180 editor.dom.remove(elm, true); 30181 } 30182 return; 30183 } 30184 editor.formatter.remove('link'); 30185 } 30186 }, 30187 mceInsertLink: applyLinkToSelection, 30188 createLink: applyLinkToSelection 30189 }); 30190 }; 30191 30192 const getTopParentBlock = (editor, node, root, container) => { 30193 const dom = editor.dom; 30194 const selector = node => dom.isBlock(node) && node.parentElement === root; 30195 const topParentBlock = selector(node) ? node : dom.getParent(container, selector, root); 30196 return Optional.from(topParentBlock).map(SugarElement.fromDom); 30197 }; 30198 const insert = (editor, before) => { 30199 if (editor.mode.isReadOnly()) { 30200 return; 30201 } 30202 const dom = editor.dom; 30203 const rng = editor.selection.getRng(); 30204 const node = before ? editor.selection.getStart() : editor.selection.getEnd(); 30205 const container = before ? rng.startContainer : rng.endContainer; 30206 const root = getEditableRoot(dom, container); 30207 if (!root || !root.isContentEditable) { 30208 return; 30209 } 30210 const insertFn = before ? before$3 : after$4; 30211 const newBlockName = getForcedRootBlock(editor); 30212 getTopParentBlock(editor, node, root, container).each(parentBlock => { 30213 const newBlock = createNewBlock(editor, container, parentBlock.dom, root, false, newBlockName); 30214 insertFn(parentBlock, SugarElement.fromDom(newBlock)); 30215 editor.selection.setCursorLocation(newBlock, 0); 30216 editor.dispatch('NewBlock', { newBlock }); 30217 fireInputEvent(editor, 'insertParagraph'); 30218 }); 30219 }; 30220 const insertBefore = editor => insert(editor, true); 30221 const insertAfter = editor => insert(editor, false); 30222 30223 const registerCommands$3 = editor => { 30224 editor.editorCommands.addCommands({ 30225 InsertNewBlockBefore: () => { 30226 insertBefore(editor); 30227 }, 30228 InsertNewBlockAfter: () => { 30229 insertAfter(editor); 30230 } 30231 }); 30232 }; 30233 30234 const registerCommands$2 = editor => { 30235 editor.editorCommands.addCommands({ 30236 insertParagraph: () => { 30237 insertBreak(blockbreak, editor); 30238 }, 30239 mceInsertNewLine: (_command, _ui, value) => { 30240 insert$1(editor, value); 30241 }, 30242 InsertLineBreak: (_command, _ui, _value) => { 30243 insertBreak(linebreak, editor); 30244 } 30245 }); 30246 }; 30247 30248 const registerCommands$1 = editor => { 30249 editor.editorCommands.addCommands({ 30250 mceSelectNodeDepth: (_command, _ui, value) => { 30251 let counter = 0; 30252 editor.dom.getParent(editor.selection.getNode(), node => { 30253 if (isElement$6(node) && counter++ === value) { 30254 editor.selection.select(node); 30255 return false; 30256 } else { 30257 return true; 30258 } 30259 }, editor.getBody()); 30260 }, 30261 mceSelectNode: (_command, _ui, value) => { 30262 editor.selection.select(value); 30263 }, 30264 selectAll: () => { 30265 const editingHost = editor.dom.getParent(editor.selection.getStart(), isContentEditableTrue$3); 30266 if (editingHost) { 30267 const rng = editor.dom.createRng(); 30268 rng.selectNodeContents(editingHost); 30269 editor.selection.setRng(rng); 30270 } 30271 } 30272 }); 30273 }; 30274 30275 const registerExecCommands = editor => { 30276 editor.editorCommands.addCommands({ 30277 mceRemoveNode: (_command, _ui, value) => { 30278 const node = value !== null && value !== void 0 ? value : editor.selection.getNode(); 30279 if (node !== editor.getBody()) { 30280 const bm = editor.selection.getBookmark(); 30281 editor.dom.remove(node, true); 30282 editor.selection.moveToBookmark(bm); 30283 } 30284 }, 30285 mcePrint: () => { 30286 editor.getWin().print(); 30287 }, 30288 mceFocus: (_command, _ui, value) => { 30289 focus(editor, value === true); 30290 }, 30291 mceToggleVisualAid: () => { 30292 editor.hasVisual = !editor.hasVisual; 30293 editor.addVisual(); 30294 } 30295 }); 30296 }; 30297 const registerCommands = editor => { 30298 registerCommands$a(editor); 30299 registerCommands$9(editor); 30300 registerCommands$6(editor); 30301 registerCommands$1(editor); 30302 registerCommands$8(editor); 30303 registerCommands$4(editor); 30304 registerCommands$5(editor); 30305 registerCommands$3(editor); 30306 registerCommands$2(editor); 30307 registerCommands$7(editor); 30308 registerExecCommands(editor); 30309 }; 30310 30311 const selectionSafeCommands = ['toggleview']; 30312 const isSelectionSafeCommand = command => contains$2(selectionSafeCommands, command.toLowerCase()); 30313 class EditorCommands { 30314 constructor(editor) { 30315 this.commands = { 30316 state: {}, 30317 exec: {}, 30318 value: {} 30319 }; 30320 this.editor = editor; 30321 } 30322 execCommand(command, ui = false, value, args) { 30323 const editor = this.editor; 30324 const lowerCaseCommand = command.toLowerCase(); 30325 const skipFocus = args === null || args === void 0 ? void 0 : args.skip_focus; 30326 if (editor.removed) { 30327 return false; 30328 } 30329 if (lowerCaseCommand !== 'mcefocus') { 30330 if (!/^(mceAddUndoLevel|mceEndUndoLevel)$/i.test(lowerCaseCommand) && !skipFocus) { 30331 editor.focus(); 30332 } else { 30333 restore(editor); 30334 } 30335 } 30336 const eventArgs = editor.dispatch('BeforeExecCommand', { 30337 command, 30338 ui, 30339 value 30340 }); 30341 if (eventArgs.isDefaultPrevented()) { 30342 return false; 30343 } 30344 const func = this.commands.exec[lowerCaseCommand]; 30345 if (isFunction(func)) { 30346 func(lowerCaseCommand, ui, value); 30347 editor.dispatch('ExecCommand', { 30348 command, 30349 ui, 30350 value 30351 }); 30352 return true; 30353 } 30354 return false; 30355 } 30356 queryCommandState(command) { 30357 if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) { 30358 return false; 30359 } 30360 const lowerCaseCommand = command.toLowerCase(); 30361 const func = this.commands.state[lowerCaseCommand]; 30362 if (isFunction(func)) { 30363 return func(lowerCaseCommand); 30364 } 30365 return false; 30366 } 30367 queryCommandValue(command) { 30368 if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) { 30369 return ''; 30370 } 30371 const lowerCaseCommand = command.toLowerCase(); 30372 const func = this.commands.value[lowerCaseCommand]; 30373 if (isFunction(func)) { 30374 return func(lowerCaseCommand); 30375 } 30376 return ''; 30377 } 30378 addCommands(commandList, type = 'exec') { 30379 const commands = this.commands; 30380 each$d(commandList, (callback, command) => { 30381 each$e(command.toLowerCase().split(','), command => { 30382 commands[type][command] = callback; 30383 }); 30384 }); 30385 } 30386 addCommand(command, callback, scope) { 30387 const lowerCaseCommand = command.toLowerCase(); 30388 this.commands.exec[lowerCaseCommand] = (_command, ui, value) => callback.call(scope !== null && scope !== void 0 ? scope : this.editor, ui, value); 30389 } 30390 queryCommandSupported(command) { 30391 const lowerCaseCommand = command.toLowerCase(); 30392 if (this.commands.exec[lowerCaseCommand]) { 30393 return true; 30394 } else { 30395 return false; 30396 } 30397 } 30398 addQueryStateHandler(command, callback, scope) { 30399 this.commands.state[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor); 30400 } 30401 addQueryValueHandler(command, callback, scope) { 30402 this.commands.value[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor); 30403 } 30404 } 30405 30406 const nativeEvents = Tools.makeMap('focus blur focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange ' + 'mouseout mouseenter mouseleave wheel keydown keypress keyup input beforeinput contextmenu dragstart dragend dragover ' + 'draggesture dragdrop drop drag submit ' + 'compositionstart compositionend compositionupdate touchstart touchmove touchend touchcancel', ' '); 30407 class EventDispatcher { 30408 static isNative(name) { 30409 return !!nativeEvents[name.toLowerCase()]; 30410 } 30411 constructor(settings) { 30412 this.bindings = {}; 30413 this.settings = settings || {}; 30414 this.scope = this.settings.scope || this; 30415 this.toggleEvent = this.settings.toggleEvent || never; 30416 } 30417 fire(name, args) { 30418 return this.dispatch(name, args); 30419 } 30420 dispatch(name, args) { 30421 const lcName = name.toLowerCase(); 30422 const event = normalize$3(lcName, args !== null && args !== void 0 ? args : {}, this.scope); 30423 if (this.settings.beforeFire) { 30424 this.settings.beforeFire(event); 30425 } 30426 const handlers = this.bindings[lcName]; 30427 if (handlers) { 30428 for (let i = 0, l = handlers.length; i < l; i++) { 30429 const callback = handlers[i]; 30430 if (callback.removed) { 30431 continue; 30432 } 30433 if (callback.once) { 30434 this.off(lcName, callback.func); 30435 } 30436 if (event.isImmediatePropagationStopped()) { 30437 return event; 30438 } 30439 if (callback.func.call(this.scope, event) === false) { 30440 event.preventDefault(); 30441 return event; 30442 } 30443 } 30444 } 30445 return event; 30446 } 30447 on(name, callback, prepend, extra) { 30448 if (callback === false) { 30449 callback = never; 30450 } 30451 if (callback) { 30452 const wrappedCallback = { 30453 func: callback, 30454 removed: false 30455 }; 30456 if (extra) { 30457 Tools.extend(wrappedCallback, extra); 30458 } 30459 const names = name.toLowerCase().split(' '); 30460 let i = names.length; 30461 while (i--) { 30462 const currentName = names[i]; 30463 let handlers = this.bindings[currentName]; 30464 if (!handlers) { 30465 handlers = []; 30466 this.toggleEvent(currentName, true); 30467 } 30468 if (prepend) { 30469 handlers = [ 30470 wrappedCallback, 30471 ...handlers 30472 ]; 30473 } else { 30474 handlers = [ 30475 ...handlers, 30476 wrappedCallback 30477 ]; 30478 } 30479 this.bindings[currentName] = handlers; 30480 } 30481 } 30482 return this; 30483 } 30484 off(name, callback) { 30485 if (name) { 30486 const names = name.toLowerCase().split(' '); 30487 let i = names.length; 30488 while (i--) { 30489 const currentName = names[i]; 30490 let handlers = this.bindings[currentName]; 30491 if (!currentName) { 30492 each$d(this.bindings, (_value, bindingName) => { 30493 this.toggleEvent(bindingName, false); 30494 delete this.bindings[bindingName]; 30495 }); 30496 return this; 30497 } 30498 if (handlers) { 30499 if (!callback) { 30500 handlers.length = 0; 30501 } else { 30502 const filteredHandlers = partition$2(handlers, handler => handler.func === callback); 30503 handlers = filteredHandlers.fail; 30504 this.bindings[currentName] = handlers; 30505 each$e(filteredHandlers.pass, handler => { 30506 handler.removed = true; 30507 }); 30508 } 30509 if (!handlers.length) { 30510 this.toggleEvent(name, false); 30511 delete this.bindings[currentName]; 30512 } 30513 } 30514 } 30515 } else { 30516 each$d(this.bindings, (_value, name) => { 30517 this.toggleEvent(name, false); 30518 }); 30519 this.bindings = {}; 30520 } 30521 return this; 30522 } 30523 once(name, callback, prepend) { 30524 return this.on(name, callback, prepend, { once: true }); 30525 } 30526 has(name) { 30527 name = name.toLowerCase(); 30528 const binding = this.bindings[name]; 30529 return !(!binding || binding.length === 0); 30530 } 30531 } 30532 30533 const getEventDispatcher = obj => { 30534 if (!obj._eventDispatcher) { 30535 obj._eventDispatcher = new EventDispatcher({ 30536 scope: obj, 30537 toggleEvent: (name, state) => { 30538 if (EventDispatcher.isNative(name) && obj.toggleNativeEvent) { 30539 obj.toggleNativeEvent(name, state); 30540 } 30541 } 30542 }); 30543 } 30544 return obj._eventDispatcher; 30545 }; 30546 const Observable = { 30547 fire(name, args, bubble) { 30548 return this.dispatch(name, args, bubble); 30549 }, 30550 dispatch(name, args, bubble) { 30551 const self = this; 30552 if (self.removed && name !== 'remove' && name !== 'detach') { 30553 return normalize$3(name.toLowerCase(), args !== null && args !== void 0 ? args : {}, self); 30554 } 30555 const dispatcherArgs = getEventDispatcher(self).dispatch(name, args); 30556 if (bubble !== false && self.parent) { 30557 let parent = self.parent(); 30558 while (parent && !dispatcherArgs.isPropagationStopped()) { 30559 parent.dispatch(name, dispatcherArgs, false); 30560 parent = parent.parent ? parent.parent() : undefined; 30561 } 30562 } 30563 return dispatcherArgs; 30564 }, 30565 on(name, callback, prepend) { 30566 return getEventDispatcher(this).on(name, callback, prepend); 30567 }, 30568 off(name, callback) { 30569 return getEventDispatcher(this).off(name, callback); 30570 }, 30571 once(name, callback) { 30572 return getEventDispatcher(this).once(name, callback); 30573 }, 30574 hasEventListeners(name) { 30575 return getEventDispatcher(this).has(name); 30576 } 30577 }; 30578 30579 const DOM$2 = DOMUtils.DOM; 30580 let customEventRootDelegates; 30581 const getEventTarget = (editor, eventName) => { 30582 if (eventName === 'selectionchange') { 30583 return editor.getDoc(); 30584 } 30585 if (!editor.inline && /^(?:mouse|touch|click|contextmenu|drop|dragover|dragend)/.test(eventName)) { 30586 return editor.getDoc().documentElement; 30587 } 30588 const eventRoot = getEventRoot(editor); 30589 if (eventRoot) { 30590 if (!editor.eventRoot) { 30591 editor.eventRoot = DOM$2.select(eventRoot)[0]; 30592 } 30593 return editor.eventRoot; 30594 } 30595 return editor.getBody(); 30596 }; 30597 const isListening = editor => !editor.hidden && !isDisabled(editor); 30598 const fireEvent = (editor, eventName, e) => { 30599 if (isListening(editor)) { 30600 editor.dispatch(eventName, e); 30601 } else if (isDisabled(editor)) { 30602 processDisabledEvents(editor, e); 30603 } 30604 }; 30605 const bindEventDelegate = (editor, eventName) => { 30606 if (!editor.delegates) { 30607 editor.delegates = {}; 30608 } 30609 if (editor.delegates[eventName] || editor.removed) { 30610 return; 30611 } 30612 const eventRootElm = getEventTarget(editor, eventName); 30613 if (getEventRoot(editor)) { 30614 if (!customEventRootDelegates) { 30615 customEventRootDelegates = {}; 30616 editor.editorManager.on('removeEditor', () => { 30617 if (!editor.editorManager.activeEditor) { 30618 if (customEventRootDelegates) { 30619 each$d(customEventRootDelegates, (_value, name) => { 30620 editor.dom.unbind(getEventTarget(editor, name)); 30621 }); 30622 customEventRootDelegates = null; 30623 } 30624 } 30625 }); 30626 } 30627 if (customEventRootDelegates[eventName]) { 30628 return; 30629 } 30630 const delegate = e => { 30631 const target = e.target; 30632 const editors = editor.editorManager.get(); 30633 let i = editors.length; 30634 while (i--) { 30635 const body = editors[i].getBody(); 30636 if (body === target || DOM$2.isChildOf(target, body)) { 30637 fireEvent(editors[i], eventName, e); 30638 } 30639 } 30640 }; 30641 customEventRootDelegates[eventName] = delegate; 30642 DOM$2.bind(eventRootElm, eventName, delegate); 30643 } else { 30644 const delegate = e => { 30645 fireEvent(editor, eventName, e); 30646 }; 30647 DOM$2.bind(eventRootElm, eventName, delegate); 30648 editor.delegates[eventName] = delegate; 30649 } 30650 }; 30651 const EditorObservable = { 30652 ...Observable, 30653 bindPendingEventDelegates() { 30654 const self = this; 30655 Tools.each(self._pendingNativeEvents, name => { 30656 bindEventDelegate(self, name); 30657 }); 30658 }, 30659 toggleNativeEvent(name, state) { 30660 const self = this; 30661 if (name === 'focus' || name === 'blur') { 30662 return; 30663 } 30664 if (self.removed) { 30665 return; 30666 } 30667 if (state) { 30668 if (self.initialized) { 30669 bindEventDelegate(self, name); 30670 } else { 30671 if (!self._pendingNativeEvents) { 30672 self._pendingNativeEvents = [name]; 30673 } else { 30674 self._pendingNativeEvents.push(name); 30675 } 30676 } 30677 } else if (self.initialized && self.delegates) { 30678 self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]); 30679 delete self.delegates[name]; 30680 } 30681 }, 30682 unbindAllNativeEvents() { 30683 const self = this; 30684 const body = self.getBody(); 30685 const dom = self.dom; 30686 if (self.delegates) { 30687 each$d(self.delegates, (value, name) => { 30688 self.dom.unbind(getEventTarget(self, name), name, value); 30689 }); 30690 delete self.delegates; 30691 } 30692 if (!self.inline && body && dom) { 30693 body.onload = null; 30694 dom.unbind(self.getWin()); 30695 dom.unbind(self.getDoc()); 30696 } 30697 if (dom) { 30698 dom.unbind(body); 30699 dom.unbind(self.getContainer()); 30700 } 30701 } 30702 }; 30703 30704 const stringListProcessor = value => { 30705 if (isString(value)) { 30706 return { 30707 value: value.split(/[ ,]/), 30708 valid: true 30709 }; 30710 } else if (isArrayOf(value, isString)) { 30711 return { 30712 value, 30713 valid: true 30714 }; 30715 } else { 30716 return { 30717 valid: false, 30718 message: `The value must be a string[] or a comma/space separated string.` 30719 }; 30720 } 30721 }; 30722 const getBuiltInProcessor = type => { 30723 const validator = (() => { 30724 switch (type) { 30725 case 'array': 30726 return isArray$1; 30727 case 'boolean': 30728 return isBoolean; 30729 case 'function': 30730 return isFunction; 30731 case 'number': 30732 return isNumber; 30733 case 'object': 30734 return isObject; 30735 case 'string': 30736 return isString; 30737 case 'string[]': 30738 return stringListProcessor; 30739 case 'object[]': 30740 return val => isArrayOf(val, isObject); 30741 case 'regexp': 30742 return val => is$4(val, RegExp); 30743 default: 30744 return always; 30745 } 30746 })(); 30747 return value => processValue(value, validator, `The value must be a ${ type }.`); 30748 }; 30749 const isBuiltInSpec = spec => isString(spec.processor); 30750 const getErrorMessage = (message, result) => { 30751 const additionalText = isEmpty$3(result.message) ? '' : `. ${ result.message }`; 30752 return message + additionalText; 30753 }; 30754 const isValidResult = result => result.valid; 30755 const processValue = (value, processor, message = '') => { 30756 const result = processor(value); 30757 if (isBoolean(result)) { 30758 return result ? { 30759 value: value, 30760 valid: true 30761 } : { 30762 valid: false, 30763 message 30764 }; 30765 } else { 30766 return result; 30767 } 30768 }; 30769 const processDefaultValue = (name, defaultValue, processor) => { 30770 if (!isUndefined(defaultValue)) { 30771 const result = processValue(defaultValue, processor); 30772 if (isValidResult(result)) { 30773 return result.value; 30774 } else { 30775 console.error(getErrorMessage(`Invalid default value passed for the "${ name }" option`, result)); 30776 } 30777 } 30778 return undefined; 30779 }; 30780 const create$5 = (editor, initialOptions, rawInitialOptions = initialOptions) => { 30781 const registry = {}; 30782 const values = {}; 30783 const setValue = (name, value, processor) => { 30784 const result = processValue(value, processor); 30785 if (isValidResult(result)) { 30786 values[name] = result.value; 30787 return true; 30788 } else { 30789 console.warn(getErrorMessage(`Invalid value passed for the ${ name } option`, result)); 30790 return false;
30791 } 30792 }; 30793 const register = (name, spec) => { 30794 const processor = isBuiltInSpec(spec) ? getBuiltInProcessor(spec.processor) : spec.processor; 30795 const defaultValue = processDefaultValue(name, spec.default, processor); 30796 registry[name] = { 30797 ...spec, 30798 default: defaultValue, 30799 processor 30800 }; 30801 const initValue = get$a(values, name).orThunk(() => get$a(initialOptions, name)); 30802 initValue.each(value => setValue(name, value, processor)); 30803 }; 30804 const isRegistered = name => has$2(registry, name); 30805 const get = name => get$a(values, name).orThunk(() => get$a(registry, name).map(spec => spec.default)).getOrUndefined(); 30806 const set = (name, value) => { 30807 if (!isRegistered(name)) { 30808 console.warn(`"${ name }" is not a registered option. Ensure the option has been registered before setting a value.`); 30809 return false; 30810 } else { 30811 const spec = registry[name]; 30812 if (spec.immutable) { 30813 console.error(`"${ name }" is an immutable option and cannot be updated`); 30814 return false; 30815 } else { 30816 return setValue(name, value, spec.processor); 30817 } 30818 } 30819 }; 30820 const unset = name => { 30821 const registered = isRegistered(name); 30822 if (registered) { 30823 delete values[name]; 30824 } 30825 return registered; 30826 }; 30827 const isSet = name => has$2(values, name); 30828 const debug = () => { 30829 try { 30830 console.log(JSON.parse(JSON.stringify(rawInitialOptions, (_key, value) => { 30831 if (isBoolean(value) || isNumber(value) || isString(value) || isNull(value) || isArray$1(value) || isPlainObject(value)) { 30832 return value; 30833 } 30834 return Object.prototype.toString.call(value); 30835 }))); 30836 } catch (error) { 30837 console.error(error); 30838 } 30839 }; 30840 return { 30841 register, 30842 isRegistered, 30843 get, 30844 set, 30845 unset, 30846 isSet, 30847 debug 30848 }; 30849 }; 30850 30851 const setContentEditable = (elm, state) => { 30852 elm.dom.contentEditable = state ? 'true' : 'false'; 30853 }; 30854 const toggleReadOnly = (editor, state) => { 30855 const body = SugarElement.fromDom(editor.getBody()); 30856 if (state) { 30857 editor.readonly = true; 30858 if (editor.hasEditableRoot()) { 30859 setContentEditable(body, true); 30860 } 30861 disableEditor(editor); 30862 } else { 30863 editor.readonly = false; 30864 enableEditor(editor); 30865 } 30866 }; 30867 const isReadOnly = editor => editor.readonly; 30868 const registerReadOnlyInputBlockers = editor => { 30869 editor.on('beforeinput paste cut dragend dragover draggesture dragdrop drop drag', e => { 30870 if (isReadOnly(editor)) { 30871 e.preventDefault(); 30872 } 30873 }); 30874 editor.on('BeforeExecCommand', e => { 30875 if ((e.command === 'Undo' || e.command === 'Redo') && isReadOnly(editor)) { 30876 e.preventDefault(); 30877 } 30878 }); 30879 editor.on('input', e => { 30880 if (!e.isComposing && isReadOnly(editor)) { 30881 const undoLevel = editor.undoManager.add(); 30882 if (isNonNullable(undoLevel)) { 30883 editor.undoManager.undo(); 30884 } 30885 } 30886 }); 30887 editor.on('compositionend', () => { 30888 if (isReadOnly(editor)) { 30889 const undoLevel = editor.undoManager.add(); 30890 if (isNonNullable(undoLevel)) { 30891 editor.undoManager.undo(); 30892 } 30893 } 30894 }); 30895 }; 30896 30897 const defaultModes = [ 30898 'design', 30899 'readonly' 30900 ]; 30901 const switchToMode = (editor, activeMode, availableModes, mode) => { 30902 const oldMode = availableModes[activeMode.get()]; 30903 const newMode = availableModes[mode];
vendor: 5,293 bytes, lines 30904-31076
30904 try { 30905 newMode.activate(); 30906 } catch (e) { 30907 console.error(`problem while activating editor mode ${ mode }:`, e); 30908 return; 30909 } 30910 oldMode.deactivate(); 30911 if (oldMode.editorReadOnly !== newMode.editorReadOnly) { 30912 toggleReadOnly(editor, newMode.editorReadOnly); 30913 } 30914 activeMode.set(mode); 30915 fireSwitchMode(editor, mode); 30916 }; 30917 const setMode = (editor, availableModes, activeMode, mode) => { 30918 if (mode === activeMode.get() || editor.initialized && isDisabled(editor)) { 30919 return; 30920 } else if (!has$2(availableModes, mode)) { 30921 throw new Error(`Editor mode '${ mode }' is invalid`); 30922 } 30923 if (editor.initialized) { 30924 switchToMode(editor, activeMode, availableModes, mode); 30925 } else { 30926 editor.on('init', () => switchToMode(editor, activeMode, availableModes, mode)); 30927 } 30928 }; 30929 const registerMode = (availableModes, mode, api) => { 30930 if (contains$2(defaultModes, mode)) { 30931 throw new Error(`Cannot override default mode ${ mode }`); 30932 } 30933 return { 30934 ...availableModes, 30935 [mode]: { 30936 ...api, 30937 deactivate: () => { 30938 try { 30939 api.deactivate(); 30940 } catch (e) { 30941 console.error(`problem while deactivating editor mode ${ mode }:`, e); 30942 } 30943 } 30944 } 30945 }; 30946 }; 30947 30948 const create$4 = editor => { 30949 const activeMode = Cell('design'); 30950 const availableModes = Cell({ 30951 design: { 30952 activate: noop, 30953 deactivate: noop, 30954 editorReadOnly: false 30955 }, 30956 readonly: { 30957 activate: noop, 30958 deactivate: noop, 30959 editorReadOnly: true 30960 } 30961 }); 30962 registerReadOnlyInputBlockers(editor); 30963 registerEventsAndFilters$1(editor); 30964 return { 30965 isReadOnly: () => isReadOnly(editor), 30966 set: mode => setMode(editor, availableModes.get(), activeMode, mode), 30967 get: () => activeMode.get(), 30968 register: (mode, api) => { 30969 availableModes.set(registerMode(availableModes.get(), mode, api)); 30970 } 30971 }; 30972 }; 30973 30974 const each$2 = Tools.each, explode = Tools.explode; 30975 const keyCodeLookup = { 30976 f1: 112, 30977 f2: 113, 30978 f3: 114, 30979 f4: 115, 30980 f5: 116, 30981 f6: 117, 30982 f7: 118, 30983 f8: 119, 30984 f9: 120, 30985 f10: 121, 30986 f11: 122, 30987 f12: 123 30988 }; 30989 const modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access'); 30990 const isModifier = key => key in modifierNames; 30991 const parseShortcut = pattern => { 30992 const shortcut = {}; 30993 const isMac = Env.os.isMacOS() || Env.os.isiOS(); 30994 each$2(explode(pattern.toLowerCase(), '+'), value => { 30995 if (isModifier(value)) { 30996 shortcut[value] = true; 30997 } else { 30998 if (/^[0-9]{2,}$/.test(value)) { 30999 shortcut.keyCode = parseInt(value, 10); 31000 } else { 31001 shortcut.charCode = value.charCodeAt(0); 31002 shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0); 31003 } 31004 } 31005 }); 31006 const id = [shortcut.keyCode]; 31007 let key; 31008 for (key in modifierNames) { 31009 if (shortcut[key]) { 31010 id.push(key); 31011 } else { 31012 shortcut[key] = false; 31013 } 31014 } 31015 shortcut.id = id.join(','); 31016 if (shortcut.access) { 31017 shortcut.alt = true; 31018 if (isMac) { 31019 shortcut.ctrl = true; 31020 } else { 31021 shortcut.shift = true; 31022 } 31023 } 31024 if (shortcut.meta) { 31025 if (isMac) { 31026 shortcut.meta = true; 31027 } else { 31028 shortcut.ctrl = true; 31029 shortcut.meta = false; 31030 } 31031 } 31032 return shortcut; 31033 }; 31034 class Shortcuts { 31035 constructor(editor) { 31036 this.shortcuts = {}; 31037 this.pendingPatterns = []; 31038 this.editor = editor; 31039 const self = this; 31040 editor.on('keyup keypress keydown', e => { 31041 if ((self.hasModifier(e) || self.isFunctionKey(e)) && !e.isDefaultPrevented()) { 31042 each$2(self.shortcuts, shortcut => { 31043 if (self.matchShortcut(e, shortcut)) { 31044 self.pendingPatterns = shortcut.subpatterns.slice(0); 31045 if (e.type === 'keydown') { 31046 self.executeShortcutAction(shortcut); 31047 } 31048 } 31049 }); 31050 if (self.matchShortcut(e, self.pendingPatterns[0])) { 31051 if (self.pendingPatterns.length === 1) { 31052 if (e.type === 'keydown') { 31053 self.executeShortcutAction(self.pendingPatterns[0]); 31054 } 31055 } 31056 self.pendingPatterns.shift(); 31057 } 31058 } 31059 }); 31060 } 31061 add(pattern, desc, cmdFunc, scope) { 31062 const self = this; 31063 const func = self.normalizeCommandFunc(cmdFunc); 31064 each$2(explode(Tools.trim(pattern)), pattern => { 31065 const shortcut = self.createShortcut(pattern, desc, func, scope); 31066 self.shortcuts[shortcut.id] = shortcut; 31067 }); 31068 return true; 31069 } 31070 remove(pattern) { 31071 const shortcut = this.createShortcut(pattern); 31072 if (this.shortcuts[shortcut.id]) { 31073 delete this.shortcuts[shortcut.id]; 31074 return true; 31075 } 31076 return false;
vendor: 4,665 bytes, lines 31077-31217
31077 } 31078 normalizeCommandFunc(cmdFunc) { 31079 const self = this; 31080 const cmd = cmdFunc; 31081 if (typeof cmd === 'string') { 31082 return () => { 31083 self.editor.execCommand(cmd, false, null); 31084 }; 31085 } else if (Tools.isArray(cmd)) { 31086 return () => { 31087 self.editor.execCommand(cmd[0], cmd[1], cmd[2]); 31088 }; 31089 } else { 31090 return cmd; 31091 } 31092 } 31093 createShortcut(pattern, desc, cmdFunc, scope) { 31094 const shortcuts = Tools.map(explode(pattern, '>'), parseShortcut); 31095 shortcuts[shortcuts.length - 1] = Tools.extend(shortcuts[shortcuts.length - 1], { 31096 func: cmdFunc, 31097 scope: scope || this.editor 31098 }); 31099 return Tools.extend(shortcuts[0], { 31100 desc: this.editor.translate(desc), 31101 subpatterns: shortcuts.slice(1) 31102 }); 31103 } 31104 hasModifier(e) { 31105 return e.altKey || e.ctrlKey || e.metaKey; 31106 } 31107 isFunctionKey(e) { 31108 return e.type === 'keydown' && e.keyCode >= 112 && e.keyCode <= 123; 31109 } 31110 matchShortcut(e, shortcut) { 31111 if (!shortcut) { 31112 return false; 31113 } 31114 if (shortcut.ctrl !== e.ctrlKey || shortcut.meta !== e.metaKey) { 31115 return false; 31116 } 31117 if (shortcut.alt !== e.altKey || shortcut.shift !== e.shiftKey) { 31118 return false; 31119 } 31120 if (e.keyCode === shortcut.keyCode || e.charCode && e.charCode === shortcut.charCode) { 31121 e.preventDefault(); 31122 return true; 31123 } 31124 return false; 31125 } 31126 executeShortcutAction(shortcut) { 31127 return shortcut.func ? shortcut.func.call(shortcut.scope) : null; 31128 } 31129 } 31130 31131 const create$3 = () => { 31132 const buttons = {}; 31133 const menuItems = {}; 31134 const popups = {}; 31135 const icons = {}; 31136 const contextMenus = {}; 31137 const contextToolbars = {}; 31138 const contexts = {}; 31139 const sidebars = {}; 31140 const views = {}; 31141 const add = (collection, type) => (name, spec) => { 31142 collection[name.toLowerCase()] = { 31143 ...spec, 31144 type 31145 }; 31146 }; 31147 const addDefaulted = (collection, type) => (name, spec) => { 31148 collection[name.toLowerCase()] = { 31149 type, 31150 ...spec 31151 }; 31152 }; 31153 const addIcon = (name, svgData) => icons[name.toLowerCase()] = svgData; 31154 const addContext = (name, pred) => contexts[name.toLowerCase()] = pred; 31155 return { 31156 addButton: add(buttons, 'button'), 31157 addGroupToolbarButton: add(buttons, 'grouptoolbarbutton'), 31158 addToggleButton: add(buttons, 'togglebutton'), 31159 addMenuButton: add(buttons, 'menubutton'), 31160 addSplitButton: add(buttons, 'splitbutton'), 31161 addMenuItem: add(menuItems, 'menuitem'), 31162 addNestedMenuItem: add(menuItems, 'nestedmenuitem'), 31163 addToggleMenuItem: add(menuItems, 'togglemenuitem'), 31164 addAutocompleter: add(popups, 'autocompleter'), 31165 addContextMenu: add(contextMenus, 'contextmenu'), 31166 addContextToolbar: add(contextToolbars, 'contexttoolbar'), 31167 addContextForm: addDefaulted(contextToolbars, 'contextform'), 31168 addSidebar: add(sidebars, 'sidebar'), 31169 addView: add(views, 'views'), 31170 addIcon, 31171 addContext, 31172 getAll: () => ({ 31173 buttons, 31174 menuItems, 31175 icons, 31176 popups, 31177 contextMenus, 31178 contextToolbars, 31179 sidebars, 31180 views, 31181 contexts 31182 }) 31183 }; 31184 }; 31185 31186 const registry = () => { 31187 const bridge = create$3(); 31188 return { 31189 addAutocompleter: bridge.addAutocompleter, 31190 addButton: bridge.addButton, 31191 addContextForm: bridge.addContextForm, 31192 addContextMenu: bridge.addContextMenu, 31193 addContextToolbar: bridge.addContextToolbar, 31194 addIcon: bridge.addIcon, 31195 addMenuButton: bridge.addMenuButton, 31196 addMenuItem: bridge.addMenuItem, 31197 addNestedMenuItem: bridge.addNestedMenuItem, 31198 addSidebar: bridge.addSidebar, 31199 addSplitButton: bridge.addSplitButton, 31200 addToggleButton: bridge.addToggleButton, 31201 addGroupToolbarButton: bridge.addGroupToolbarButton, 31202 addToggleMenuItem: bridge.addToggleMenuItem, 31203 addView: bridge.addView, 31204 addContext: bridge.addContext, 31205 getAll: bridge.getAll 31206 }; 31207 }; 31208 31209 const DOM$1 = DOMUtils.DOM; 31210 const extend = Tools.extend, each$1 = Tools.each; 31211 class Editor { 31212 constructor(id, options, editorManager) { 31213 this.plugins = {}; 31214 this.contentCSS = []; 31215 this.contentStyles = []; 31216 this.loadedCSS = {}; 31217 this.isNotDirty = false;
vendor: 2,009 bytes, lines 31218-31266
31218 this.composing = false; 31219 this.destroyed = false; 31220 this.hasHiddenInput = false; 31221 this.iframeElement = null; 31222 this.initialized = false; 31223 this.readonly = false; 31224 this.removed = false; 31225 this.startContent = ''; 31226 this._pendingNativeEvents = []; 31227 this._skinLoaded = false; 31228 this._editableRoot = true; 31229 this.editorManager = editorManager; 31230 this.documentBaseUrl = editorManager.documentBaseURL; 31231 extend(this, EditorObservable); 31232 const self = this; 31233 this.id = id; 31234 this.hidden = false; 31235 const normalizedOptions = normalizeOptions(editorManager.defaultOptions, options); 31236 this.options = create$5(self, normalizedOptions, options); 31237 register$7(self); 31238 const getOption = this.options.get; 31239 if (getOption('deprecation_warnings')) { 31240 logWarnings(options, normalizedOptions); 31241 } 31242 const suffix = getOption('suffix'); 31243 if (suffix) { 31244 editorManager.suffix = suffix; 31245 } 31246 this.suffix = editorManager.suffix; 31247 const baseUrl = getOption('base_url'); 31248 if (baseUrl) { 31249 editorManager._setBaseUrl(baseUrl); 31250 } 31251 this.baseUri = editorManager.baseURI; 31252 const referrerPolicy = getReferrerPolicy(self); 31253 if (referrerPolicy) { 31254 ScriptLoader.ScriptLoader._setReferrerPolicy(referrerPolicy); 31255 DOMUtils.DOM.styleSheetLoader._setReferrerPolicy(referrerPolicy); 31256 } 31257 const contentCssCors = hasContentCssCors(self); 31258 if (isNonNullable(contentCssCors)) { 31259 DOMUtils.DOM.styleSheetLoader._setContentCssCors(contentCssCors); 31260 } 31261 AddOnManager.languageLoad = getOption('language_load'); 31262 AddOnManager.baseURL = editorManager.baseURL; 31263 this.setDirty(false); 31264 this.documentBaseURI = new URI(getDocumentBaseUrl(self), { base_uri: this.baseUri }); 31265 this.baseURI = this.baseUri; 31266 this.inline = isInline$1
vendor: 8,516 bytes, lines 31266-31547
31266(self); 31267 this.hasVisual = isVisualAidsEnabled(self); 31268 this.shortcuts = new Shortcuts(this); 31269 this.editorCommands = new EditorCommands(this); 31270 registerCommands(this); 31271 const cacheSuffix = getOption('cache_suffix'); 31272 if (cacheSuffix) { 31273 Env.cacheSuffix = cacheSuffix.replace(/^[\?\&]+/, ''); 31274 } 31275 this.ui = { 31276 registry: registry(), 31277 styleSheetLoader: undefined, 31278 show: noop, 31279 hide: noop, 31280 setEnabled: noop, 31281 isEnabled: always 31282 }; 31283 this.mode = create$4(self); 31284 editorManager.dispatch('SetupEditor', { editor: this }); 31285 const setupCallback = getSetupCallback(self); 31286 if (isFunction(setupCallback)) { 31287 setupCallback.call(self, self); 31288 } 31289 } 31290 render() { 31291 render(this); 31292 } 31293 focus(skipFocus) { 31294 this.execCommand('mceFocus', false, skipFocus); 31295 } 31296 hasFocus() { 31297 return hasFocus(this); 31298 } 31299 translate(text) { 31300 return I18n.translate(text); 31301 } 31302 getParam(name, defaultVal, type) { 31303 const options = this.options; 31304 if (!options.isRegistered(name)) { 31305 if (isNonNullable(type)) { 31306 options.register(name, { 31307 processor: type, 31308 default: defaultVal 31309 }); 31310 } else { 31311 options.register(name, { 31312 processor: always, 31313 default: defaultVal 31314 }); 31315 } 31316 } 31317 return !options.isSet(name) && !isUndefined(defaultVal) ? defaultVal : options.get(name); 31318 } 31319 hasPlugin(name, loaded) { 31320 const hasPlugin = contains$2(getPlugins(this), name); 31321 if (hasPlugin) { 31322 return loaded ? PluginManager.get(name) !== undefined : true; 31323 } else { 31324 return false; 31325 } 31326 } 31327 nodeChanged(args) { 31328 this._nodeChangeDispatcher.nodeChanged(args); 31329 } 31330 addCommand(name, callback, scope) { 31331 this.editorCommands.addCommand(name, callback, scope); 31332 } 31333 addQueryStateHandler(name, callback, scope) { 31334 this.editorCommands.addQueryStateHandler(name, callback, scope); 31335 } 31336 addQueryValueHandler(name, callback, scope) { 31337 this.editorCommands.addQueryValueHandler(name, callback, scope); 31338 } 31339 addShortcut(pattern, desc, cmdFunc, scope) { 31340 this.shortcuts.add(pattern, desc, cmdFunc, scope); 31341 } 31342 execCommand(cmd, ui, value, args) { 31343 return this.editorCommands.execCommand(cmd, ui, value, args); 31344 } 31345 queryCommandState(cmd) { 31346 return this.editorCommands.queryCommandState(cmd); 31347 } 31348 queryCommandValue(cmd) { 31349 return this.editorCommands.queryCommandValue(cmd); 31350 } 31351 queryCommandSupported(cmd) { 31352 return this.editorCommands.queryCommandSupported(cmd); 31353 } 31354 show() { 31355 const self = this; 31356 if (self.hidden) { 31357 self.hidden = false; 31358 if (self.inline) { 31359 self.getBody().contentEditable = 'true'; 31360 } else { 31361 DOM$1.show(self.getContainer()); 31362 DOM$1.hide(self.id); 31363 } 31364 self.load(); 31365 self.dispatch('show'); 31366 } 31367 } 31368 hide() { 31369 const self = this; 31370 if (!self.hidden) { 31371 self.save(); 31372 if (self.inline) { 31373 self.getBody().contentEditable = 'false'; 31374 if (self === self.editorManager.focusedEditor) { 31375 self.editorManager.focusedEditor = null; 31376 } 31377 } else { 31378 DOM$1.hide(self.getContainer()); 31379 DOM$1.setStyle(self.id, 'display', self.orgDisplay); 31380 } 31381 self.hidden = true; 31382 self.dispatch('hide'); 31383 } 31384 } 31385 isHidden() { 31386 return this.hidden; 31387 } 31388 setProgressState(state, time) { 31389 this.dispatch('ProgressState', { 31390 state, 31391 time 31392 }); 31393 } 31394 load(args = {}) { 31395 const self = this; 31396 const elm = self.getElement(); 31397 if (self.removed) { 31398 return ''; 31399 } 31400 if (elm) { 31401 const loadArgs = { 31402 ...args, 31403 load: true 31404 }; 31405 const value = isTextareaOrInput(elm) ? elm.value : elm.innerHTML; 31406 const html = self.setContent(value, loadArgs); 31407 if (!loadArgs.no_events) { 31408 self.dispatch('LoadContent', { 31409 ...loadArgs, 31410 element: elm 31411 }); 31412 } 31413 return html; 31414 } else { 31415 return ''; 31416 } 31417 } 31418 save(args = {}) { 31419 const self = this; 31420 let elm = self.getElement(); 31421 if (!elm || !self.initialized || self.removed) { 31422 return ''; 31423 } 31424 const getArgs = { 31425 ...args, 31426 save: true, 31427 element: elm 31428 }; 31429 let html = self.getContent(getArgs); 31430 const saveArgs = { 31431 ...getArgs, 31432 content: html 31433 }; 31434 if (!saveArgs.no_events) { 31435 self.dispatch('SaveContent', saveArgs); 31436 } 31437 if (saveArgs.format === 'raw') { 31438 self.dispatch('RawSaveContent', saveArgs); 31439 } 31440 html = saveArgs.content; 31441 if (!isTextareaOrInput(elm)) { 31442 if (args.is_removing || !self.inline) { 31443 elm.innerHTML = html; 31444 } 31445 const form = DOM$1.getParent(self.id, 'form'); 31446 if (form) { 31447 each$1(form.elements, elm => { 31448 if (elm.name === self.id) { 31449 elm.value = html; 31450 return false; 31451 } else { 31452 return true; 31453 } 31454 }); 31455 } 31456 } else { 31457 elm.value = html; 31458 } 31459 saveArgs.element = getArgs.element = elm = null; 31460 if (saveArgs.set_dirty !== false) { 31461 self.setDirty(false); 31462 } 31463 return html; 31464 } 31465 setContent(content, args) { 31466 return setContent(this, content, args); 31467 } 31468 getContent(args) { 31469 return getContent(this, args); 31470 } 31471 insertContent(content, args) { 31472 if (args) { 31473 content = extend({ content }, args); 31474 } 31475 this.execCommand('mceInsertContent', false, content); 31476 } 31477 resetContent(initialContent) { 31478 if (initialContent === undefined) { 31479 setContent(this, this.startContent, { format: 'raw' }); 31480 } else { 31481 setContent(this, initialContent); 31482 } 31483 this.undoManager.reset(); 31484 this.setDirty(false); 31485 this.nodeChanged(); 31486 } 31487 isDirty() { 31488 return !this.isNotDirty; 31489 } 31490 setDirty(state) { 31491 const oldState = !this.isNotDirty; 31492 this.isNotDirty = !state; 31493 if (state && state !== oldState) { 31494 this.dispatch('dirty'); 31495 } 31496 } 31497 getContainer() { 31498 const self = this; 31499 if (!self.container) { 31500 self.container = self.editorContainer || DOM$1.get(self.id + '_parent'); 31501 } 31502 return self.container; 31503 } 31504 getContentAreaContainer() { 31505 return this.contentAreaContainer; 31506 } 31507 getElement() { 31508 if (!this.targetElm) { 31509 this.targetElm = DOM$1.get(this.id); 31510 } 31511 return this.targetElm; 31512 } 31513 getWin() { 31514 const self = this; 31515 if (!self.contentWindow) { 31516 const elm = self.iframeElement; 31517 if (elm) { 31518 self.contentWindow = elm.contentWindow; 31519 } 31520 } 31521 return self.contentWindow; 31522 } 31523 getDoc() { 31524 const self = this; 31525 if (!self.contentDocument) { 31526 const win = self.getWin(); 31527 if (win) { 31528 self.contentDocument = win.document; 31529 } 31530 } 31531 return self.contentDocument; 31532 } 31533 getBody() { 31534 var _a, _b; 31535 const doc = this.getDoc(); 31536 return (_b = (_a = this.bodyElement) !== null && _a !== void 0 ? _a : doc === null || doc === void 0 ? void 0 : doc.body) !== null && _b !== void 0 ? _b : null; 31537 } 31538 convertURL(url, name, elm) { 31539 const self = this, getOption = self.options.get; 31540 const urlConverterCallback = getUrlConverterCallback(self); 31541 if (isFunction(urlConverterCallback)) { 31542 return urlConverterCallback.call(self, url, elm, true, name); 31543 } 31544 if (!getOption('convert_urls') || elm === 'link' || isObject(elm) && elm.nodeName === 'LINK' || url.indexOf('file:') === 0 || url.length === 0) { 31545 return url; 31546 } 31547
vendor: 6,496 bytes, lines 31547-31730
31547const urlObject = new URI(url); 31548 if (urlObject.protocol !== 'http' && urlObject.protocol !== 'https' && urlObject.protocol !== '') { 31549 return url; 31550 } 31551 if (getOption('relative_urls')) { 31552 return self.documentBaseURI.toRelative(url); 31553 } 31554 url = self.documentBaseURI.toAbsolute(url, getOption('remove_script_host')); 31555 return url; 31556 } 31557 addVisual(elm) { 31558 addVisual(this, elm); 31559 } 31560 setEditableRoot(state) { 31561 setEditableRoot(this, state); 31562 } 31563 hasEditableRoot() { 31564 return hasEditableRoot(this); 31565 } 31566 remove() { 31567 remove$1(this); 31568 } 31569 destroy(automatic) { 31570 destroy(this, automatic); 31571 } 31572 uploadImages() { 31573 return this.editorUpload.uploadImages(); 31574 } 31575 _scanForImages() { 31576 return this.editorUpload.scanForImages(); 31577 } 31578 } 31579 31580 const DOM = DOMUtils.DOM; 31581 const each = Tools.each; 31582 let boundGlobalEvents = false; 31583 let beforeUnloadDelegate; 31584 let editors = []; 31585 const globalEventDelegate = e => { 31586 const type = e.type; 31587 each(EditorManager.get(), editor => { 31588 switch (type) { 31589 case 'scroll': 31590 editor.dispatch('ScrollWindow', e); 31591 break; 31592 case 'resize': 31593 editor.dispatch('ResizeWindow', e); 31594 break; 31595 } 31596 }); 31597 }; 31598 const toggleGlobalEvents = state => { 31599 if (state !== boundGlobalEvents) { 31600 const DOM = DOMUtils.DOM; 31601 if (state) { 31602 DOM.bind(window, 'resize', globalEventDelegate); 31603 DOM.bind(window, 'scroll', globalEventDelegate); 31604 } else { 31605 DOM.unbind(window, 'resize', globalEventDelegate); 31606 DOM.unbind(window, 'scroll', globalEventDelegate); 31607 } 31608 boundGlobalEvents = state; 31609 } 31610 }; 31611 const removeEditorFromList = targetEditor => { 31612 const oldEditors = editors; 31613 editors = filter$5(editors, editor => { 31614 return targetEditor !== editor; 31615 }); 31616 if (EditorManager.activeEditor === targetEditor) { 31617 EditorManager.activeEditor = editors.length > 0 ? editors[0] : null; 31618 } 31619 if (EditorManager.focusedEditor === targetEditor) { 31620 EditorManager.focusedEditor = null; 31621 } 31622 return oldEditors.length !== editors.length; 31623 }; 31624 const purgeDestroyedEditor = editor => { 31625 if (editor && editor.initialized && !(editor.getContainer() || editor.getBody()).parentNode) { 31626 removeEditorFromList(editor); 31627 editor.unbindAllNativeEvents(); 31628 editor.destroy(true); 31629 editor.removed = true; 31630 } 31631 }; 31632 const isQuirksMode = document.compatMode !== 'CSS1Compat'; 31633 const EditorManager = { 31634 ...Observable, 31635 baseURI: null, 31636 baseURL: null, 31637 defaultOptions: {}, 31638 documentBaseURL: null, 31639 suffix: null, 31640 majorVersion: '7', 31641 minorVersion: '7.1', 31642 releaseDate: '2025-03-05', 31643 i18n: I18n, 31644 activeEditor: null, 31645 focusedEditor: null, 31646 setup() { 31647 const self = this; 31648 let baseURL = ''; 31649 let suffix = ''; 31650 let documentBaseURL = URI.getDocumentBaseUrl(document.location); 31651 if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) { 31652 documentBaseURL = documentBaseURL.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, ''); 31653 if (!/[\/\\]$/.test(documentBaseURL)) { 31654 documentBaseURL += '/'; 31655 } 31656 } 31657 const preInit = window.tinymce || window.tinyMCEPreInit; 31658 if (preInit) { 31659 baseURL = preInit.base || preInit.baseURL; 31660 suffix = preInit.suffix; 31661 } else { 31662 const scripts = document.getElementsByTagName('script'); 31663 for (let i = 0; i < scripts.length; i++) { 31664 const src = scripts[i].src || ''; 31665 if (src === '') { 31666 continue; 31667 } 31668 const srcScript = src.substring(src.lastIndexOf('/')); 31669 if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) { 31670 if (srcScript.indexOf('.min') !== -1) { 31671 suffix = '.min'; 31672 } 31673 baseURL = src.substring(0, src.lastIndexOf('/')); 31674 break; 31675 } 31676 } 31677 if (!baseURL && document.currentScript) { 31678 const src = document.currentScript.src; 31679 if (src.indexOf('.min') !== -1) { 31680 suffix = '.min'; 31681 } 31682 baseURL = src.substring(0, src.lastIndexOf('/')); 31683 } 31684 } 31685 self.baseURL = new URI(documentBaseURL).toAbsolute(baseURL); 31686 self.documentBaseURL = documentBaseURL; 31687 self.baseURI = new URI(self.baseURL); 31688 self.suffix = suffix; 31689 setup$w(self); 31690 }, 31691 overrideDefaults(defaultOptions) { 31692 const baseUrl = defaultOptions.base_url; 31693 if (baseUrl) { 31694 this._setBaseUrl(baseUrl); 31695 } 31696 const suffix = defaultOptions.suffix; 31697 if (suffix) { 31698 this.suffix = suffix; 31699 } 31700 this.defaultOptions = defaultOptions; 31701 const pluginBaseUrls = defaultOptions.plugin_base_urls; 31702 if (pluginBaseUrls !== undefined) { 31703 each$d(pluginBaseUrls, (pluginBaseUrl, pluginName) => { 31704 AddOnManager.PluginManager.urls[pluginName] = pluginBaseUrl; 31705 }); 31706 } 31707 }, 31708 init(options) { 31709 const self = this; 31710 let result; 31711 const invalidInlineTargets = Tools.makeMap('area base basefont br col frame hr img input isindex link meta param embed source wbr track ' + 'colgroup option table tbody tfoot thead tr th td script noscript style textarea video audio iframe object menu', ' '); 31712 const isInvalidInlineTarget = (options, elm) => options.inline && elm.tagName.toLowerCase() in invalidInlineTargets; 31713 const createId = elm => { 31714 let id = elm.id; 31715 if (!id) { 31716 id = get$a(elm, 'name').filter(name => !DOM.get(name)).getOrThunk(DOM.uniqueId); 31717 elm.setAttribute('id', id); 31718 } 31719 return id; 31720 }; 31721 const execCallback = name => { 31722 const callback = options[name]; 31723 if (!callback) { 31724 return; 31725 } 31726 return callback.apply(self, []); 31727 }; 31728 const findTargets = options => { 31729 if (Env.browser.isIE() || Env.browser.isEdge()) { 31730 initError('TinyMCE does not support the browser you are using. For a list of supported' + ' browsers please see: https://www.tiny.cloud/docs/tinymce/7
vendor: 10,689 bytes, lines 31730-32083
31730/support/#supportedwebbrowsers'); 31731 return []; 31732 } else if (isQuirksMode) { 31733 initError('Failed to initialize the editor as the document is not in standards mode. ' + 'TinyMCE requires standards mode.'); 31734 return []; 31735 } else if (isString(options.selector)) { 31736 return DOM.select(options.selector); 31737 } else if (isNonNullable(options.target)) { 31738 return [options.target]; 31739 } else { 31740 return []; 31741 } 31742 }; 31743 let provideResults = editors => { 31744 result = editors; 31745 }; 31746 const initEditors = () => { 31747 let initCount = 0; 31748 const editors = []; 31749 let targets; 31750 const createEditor = (id, options, targetElm) => { 31751 const editor = new Editor(id, options, self); 31752 editors.push(editor); 31753 editor.on('init', () => { 31754 if (++initCount === targets.length) { 31755 provideResults(editors); 31756 } 31757 }); 31758 editor.targetElm = editor.targetElm || targetElm; 31759 editor.render(); 31760 }; 31761 DOM.unbind(window, 'ready', initEditors); 31762 execCallback('onpageload'); 31763 targets = unique$1(findTargets(options)); 31764 Tools.each(targets, elm => { 31765 purgeDestroyedEditor(self.get(elm.id)); 31766 }); 31767 targets = Tools.grep(targets, elm => { 31768 return !self.get(elm.id); 31769 }); 31770 if (targets.length === 0) { 31771 provideResults([]); 31772 } else { 31773 each(targets, elm => { 31774 if (isInvalidInlineTarget(options, elm)) { 31775 initError('Could not initialize inline editor on invalid inline target element', elm); 31776 } else { 31777 createEditor(createId(elm), options, elm); 31778 } 31779 }); 31780 } 31781 }; 31782 DOM.bind(window, 'ready', initEditors); 31783 return new Promise(resolve => { 31784 if (result) { 31785 resolve(result); 31786 } else { 31787 provideResults = editors => { 31788 resolve(editors); 31789 }; 31790 } 31791 }); 31792 }, 31793 get(id) { 31794 if (arguments.length === 0) { 31795 return editors.slice(0); 31796 } else if (isString(id)) { 31797 return find$2(editors, editor => { 31798 return editor.id === id; 31799 }).getOr(null); 31800 } else if (isNumber(id)) { 31801 return editors[id] ? editors[id] : null; 31802 } else { 31803 return null; 31804 } 31805 }, 31806 add(editor) { 31807 const self = this; 31808 const existingEditor = self.get(editor.id); 31809 if (existingEditor === editor) { 31810 return editor; 31811 } 31812 if (existingEditor === null) { 31813 editors.push(editor); 31814 } 31815 toggleGlobalEvents(true); 31816 self.activeEditor = editor; 31817 self.dispatch('AddEditor', { editor }); 31818 if (!beforeUnloadDelegate) { 31819 beforeUnloadDelegate = e => { 31820 const event = self.dispatch('BeforeUnload'); 31821 if (event.returnValue) { 31822 e.preventDefault(); 31823 e.returnValue = event.returnValue; 31824 return event.returnValue; 31825 } 31826 }; 31827 window.addEventListener('beforeunload', beforeUnloadDelegate); 31828 } 31829 return editor; 31830 }, 31831 createEditor(id, options) { 31832 return this.add(new Editor(id, options, this)); 31833 }, 31834 remove(selector) { 31835 const self = this; 31836 let editor; 31837 if (!selector) { 31838 for (let i = editors.length - 1; i >= 0; i--) { 31839 self.remove(editors[i]); 31840 } 31841 return; 31842 } 31843 if (isString(selector)) { 31844 each(DOM.select(selector), elm => { 31845 editor = self.get(elm.id); 31846 if (editor) { 31847 self.remove(editor); 31848 } 31849 }); 31850 return; 31851 } 31852 editor = selector; 31853 if (isNull(self.get(editor.id))) { 31854 return null; 31855 } 31856 if (removeEditorFromList(editor)) { 31857 self.dispatch('RemoveEditor', { editor }); 31858 } 31859 if (editors.length === 0) { 31860 window.removeEventListener('beforeunload', beforeUnloadDelegate); 31861 } 31862 editor.remove(); 31863 toggleGlobalEvents(editors.length > 0); 31864 return editor; 31865 }, 31866 execCommand(cmd, ui, value) { 31867 var _a; 31868 const self = this; 31869 const editorId = isObject(value) ? (_a = value.id) !== null && _a !== void 0 ? _a : value.index : value; 31870 switch (cmd) { 31871 case 'mceAddEditor': { 31872 if (!self.get(editorId)) { 31873 const editorOptions = value.options; 31874 new Editor(editorId, editorOptions, self).render(); 31875 } 31876 return true; 31877 } 31878 case 'mceRemoveEditor': { 31879 const editor = self.get(editorId); 31880 if (editor) { 31881 editor.remove(); 31882 } 31883 return true; 31884 } 31885 case 'mceToggleEditor': { 31886 const editor = self.get(editorId); 31887 if (!editor) { 31888 self.execCommand('mceAddEditor', false, value); 31889 return true; 31890 } 31891 if (editor.isHidden()) { 31892 editor.show(); 31893 } else { 31894 editor.hide(); 31895 } 31896 return true; 31897 } 31898 } 31899 if (self.activeEditor) { 31900 return self.activeEditor.execCommand(cmd, ui, value); 31901 } 31902 return false; 31903 }, 31904 triggerSave: () => { 31905 each(editors, editor => { 31906 editor.save(); 31907 }); 31908 }, 31909 addI18n: (code, items) => { 31910 I18n.add(code, items); 31911 }, 31912 translate: text => { 31913 return I18n.translate(text); 31914 }, 31915 setActive(editor) { 31916 const activeEditor = this.activeEditor; 31917 if (this.activeEditor !== editor) { 31918 if (activeEditor) { 31919 activeEditor.dispatch('deactivate', { relatedTarget: editor }); 31920 } 31921 editor.dispatch('activate', { relatedTarget: activeEditor }); 31922 } 31923 this.activeEditor = editor; 31924 }, 31925 _setBaseUrl(baseUrl) { 31926 this.baseURL = new URI(this.documentBaseURL).toAbsolute(baseUrl.replace(/\/+$/, '')); 31927 this.baseURI = new URI(this.baseURL); 31928 } 31929 }; 31930 EditorManager.setup(); 31931 31932 const setup = () => { 31933 const dataValue = value$2(); 31934 const FakeClipboardItem = items => ({ 31935 items, 31936 types: keys(items), 31937 getType: type => get$a(items, type).getOrUndefined() 31938 }); 31939 const write = data => { 31940 dataValue.set(data); 31941 }; 31942 const read = () => dataValue.get().getOrUndefined(); 31943 const clear = dataValue.clear; 31944 return { 31945 FakeClipboardItem, 31946 write, 31947 read, 31948 clear 31949 }; 31950 }; 31951 const FakeClipboard = setup(); 31952 31953 const min = Math.min, max = Math.max, round = Math.round; 31954 const relativePosition = (rect, targetRect, rel) => { 31955 let x = targetRect.x; 31956 let y = targetRect.y; 31957 const w = rect.w; 31958 const h = rect.h; 31959 const targetW = targetRect.w; 31960 const targetH = targetRect.h; 31961 const relChars = (rel || '').split(''); 31962 if (relChars[0] === 'b') { 31963 y += targetH; 31964 } 31965 if (relChars[1] === 'r') { 31966 x += targetW; 31967 } 31968 if (relChars[0] === 'c') { 31969 y += round(targetH / 2); 31970 } 31971 if (relChars[1] === 'c') { 31972 x += round(targetW / 2); 31973 } 31974 if (relChars[3] === 'b') { 31975 y -= h; 31976 } 31977 if (relChars[4] === 'r') { 31978 x -= w; 31979 } 31980 if (relChars[3] === 'c') { 31981 y -= round(h / 2); 31982 } 31983 if (relChars[4] === 'c') { 31984 x -= round(w / 2); 31985 } 31986 return create$2(x, y, w, h); 31987 }; 31988 const findBestRelativePosition = (rect, targetRect, constrainRect, rels) => { 31989 for (let i = 0; i < rels.length; i++) { 31990 const pos = relativePosition(rect, targetRect, rels[i]); 31991 if (pos.x >= constrainRect.x && pos.x + pos.w <= constrainRect.w + constrainRect.x && pos.y >= constrainRect.y && pos.y + pos.h <= constrainRect.h + constrainRect.y) { 31992 return rels[i]; 31993 } 31994 } 31995 return null; 31996 }; 31997 const inflate = (rect, w, h) => { 31998 return create$2(rect.x - w, rect.y - h, rect.w + w * 2, rect.h + h * 2); 31999 }; 32000 const intersect = (rect, cropRect) => { 32001 const x1 = max(rect.x, cropRect.x); 32002 const y1 = max(rect.y, cropRect.y); 32003 const x2 = min(rect.x + rect.w, cropRect.x + cropRect.w); 32004 const y2 = min(rect.y + rect.h, cropRect.y + cropRect.h); 32005 if (x2 - x1 < 0 || y2 - y1 < 0) { 32006 return null; 32007 } 32008 return create$2(x1, y1, x2 - x1, y2 - y1); 32009 }; 32010 const clamp = (rect, clampRect, fixedSize) => { 32011 let x1 = rect.x; 32012 let y1 = rect.y; 32013 let x2 = rect.x + rect.w; 32014 let y2 = rect.y + rect.h; 32015 const cx2 = clampRect.x + clampRect.w; 32016 const cy2 = clampRect.y + clampRect.h; 32017 const underflowX1 = max(0, clampRect.x - x1); 32018 const underflowY1 = max(0, clampRect.y - y1); 32019 const overflowX2 = max(0, x2 - cx2); 32020 const overflowY2 = max(0, y2 - cy2); 32021 x1 += underflowX1; 32022 y1 += underflowY1; 32023 if (fixedSize) { 32024 x2 += underflowX1; 32025 y2 += underflowY1; 32026 x1 -= overflowX2; 32027 y1 -= overflowY2; 32028 } 32029 x2 -= overflowX2; 32030 y2 -= overflowY2; 32031 return create$2(x1, y1, x2 - x1, y2 - y1); 32032 }; 32033 const create$2 = (x, y, w, h) => { 32034 return { 32035 x, 32036 y, 32037 w, 32038 h 32039 }; 32040 }; 32041 const fromClientRect = clientRect => { 32042 return create$2(clientRect.left, clientRect.top, clientRect.width, clientRect.height); 32043 }; 32044 const Rect = { 32045 inflate, 32046 relativePosition, 32047 findBestRelativePosition, 32048 intersect, 32049 clamp, 32050 create: create$2, 32051 fromClientRect 32052 }; 32053 32054 const awaiter = (resolveCb, rejectCb, timeout = 1000) => { 32055 let done = false; 32056 let timer = null; 32057 const complete = completer => (...args) => { 32058 if (!done) { 32059 done = true; 32060 if (timer !== null) { 32061 clearTimeout(timer); 32062 timer = null; 32063 } 32064 completer.apply(null, args); 32065 } 32066 }; 32067 const resolve = complete(resolveCb); 32068 const reject = complete(rejectCb); 32069 const start = (...args) => { 32070 if (!done && timer === null) { 32071 timer = setTimeout(() => reject.apply(null, args), timeout); 32072 } 32073 }; 32074 return { 32075 start, 32076 resolve, 32077 reject 32078 }; 32079 }; 32080 const create$1 = () => { 32081 const tasks = {}; 32082 const resultFns = {}; 32083 const
vendor: 4,333 bytes, lines 32083-32258
32083resources = {}; 32084 const load = (id, url) => { 32085 const loadErrMsg = `Script at URL "${ url }" failed to load`; 32086 const runErrMsg = `Script at URL "${ url }" did not call \`tinymce.Resource.add('${ id }', data)\` within 1 second`; 32087 if (tasks[id] !== undefined) { 32088 return tasks[id]; 32089 } else { 32090 const task = new Promise((resolve, reject) => { 32091 const waiter = awaiter(resolve, reject); 32092 resultFns[id] = waiter.resolve; 32093 ScriptLoader.ScriptLoader.loadScript(url).then(() => waiter.start(runErrMsg), () => waiter.reject(loadErrMsg)); 32094 }); 32095 tasks[id] = task; 32096 return task; 32097 } 32098 }; 32099 const add = (id, data) => { 32100 if (resultFns[id] !== undefined) { 32101 resultFns[id](data); 32102 delete resultFns[id]; 32103 } 32104 tasks[id] = Promise.resolve(data); 32105 resources[id] = data; 32106 }; 32107 const has = id => { 32108 return id in resources; 32109 }; 32110 const unload = id => { 32111 delete tasks[id]; 32112 delete resources[id]; 32113 }; 32114 const get = id => resources[id]; 32115 return { 32116 load, 32117 add, 32118 has, 32119 get, 32120 unload 32121 }; 32122 }; 32123 const Resource = create$1(); 32124 32125 const create = () => (() => { 32126 let data = {}; 32127 let keys = []; 32128 const storage = { 32129 getItem: key => { 32130 const item = data[key]; 32131 return item ? item : null; 32132 }, 32133 setItem: (key, value) => { 32134 keys.push(key); 32135 data[key] = String(value); 32136 }, 32137 key: index => { 32138 return keys[index]; 32139 }, 32140 removeItem: key => { 32141 keys = keys.filter(k => k === key); 32142 delete data[key]; 32143 }, 32144 clear: () => { 32145 keys = []; 32146 data = {}; 32147 }, 32148 length: 0 32149 }; 32150 Object.defineProperty(storage, 'length', { 32151 get: () => keys.length, 32152 configurable: false, 32153 enumerable: false 32154 }); 32155 return storage; 32156 })(); 32157 32158 let localStorage; 32159 try { 32160 const test = '__storage_test__'; 32161 localStorage = window.localStorage; 32162 localStorage.setItem(test, test); 32163 localStorage.removeItem(test); 32164 } catch (_a) { 32165 localStorage = create(); 32166 } 32167 var LocalStorage = localStorage; 32168 32169 const publicApi = { 32170 geom: { Rect }, 32171 util: { 32172 Delay, 32173 Tools, 32174 VK, 32175 URI, 32176 EventDispatcher, 32177 Observable, 32178 I18n, 32179 LocalStorage, 32180 ImageUploader 32181 }, 32182 dom: { 32183 EventUtils, 32184 TreeWalker: DomTreeWalker, 32185 TextSeeker, 32186 DOMUtils, 32187 ScriptLoader, 32188 RangeUtils, 32189 Serializer: DomSerializer, 32190 StyleSheetLoader, 32191 ControlSelection, 32192 BookmarkManager, 32193 Selection: EditorSelection, 32194 Event: EventUtils.Event 32195 }, 32196 html: { 32197 Styles, 32198 Entities, 32199 Node: AstNode, 32200 Schema, 32201 DomParser, 32202 Writer, 32203 Serializer: HtmlSerializer 32204 }, 32205 Env, 32206 AddOnManager, 32207 Annotator, 32208 Formatter, 32209 UndoManager, 32210 EditorCommands, 32211 WindowManager, 32212 NotificationManager, 32213 EditorObservable, 32214 Shortcuts, 32215 Editor, 32216 FocusManager, 32217 EditorManager, 32218 DOM: DOMUtils.DOM, 32219 ScriptLoader: ScriptLoader.ScriptLoader, 32220 PluginManager, 32221 ThemeManager, 32222 ModelManager, 32223 IconManager, 32224 Resource, 32225 FakeClipboard, 32226 trim: Tools.trim, 32227 isArray: Tools.isArray, 32228 is: Tools.is, 32229 toArray: Tools.toArray, 32230 makeMap: Tools.makeMap, 32231 each: Tools.each, 32232 map: Tools.map, 32233 grep: Tools.grep, 32234 inArray: Tools.inArray, 32235 extend: Tools.extend, 32236 walk: Tools.walk, 32237 resolve: Tools.resolve, 32238 explode: Tools.explode, 32239 _addCacheSuffix: Tools._addCacheSuffix 32240 }; 32241 const tinymce$1 = Tools.extend(EditorManager, publicApi); 32242 32243 const exportToModuleLoaders = tinymce => { 32244 if (typeof module === 'object') { 32245 try { 32246 module.exports = tinymce; 32247 } catch (_a) { 32248 } 32249 } 32250 }; 32251 const exportToWindowGlobal = tinymce => { 32252 window.tinymce = tinymce; 32253 window.tinyMCE = tinymce; 32254 }; 32255 exportToWindowGlobal(tinymce$1); 32256 exportToModuleLoaders(tinymce$1); 32257 32258})();
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.