UNPKG

1.2 MBJavaScriptView Raw
1/**
2 * TinyMCE version 7.1.1 (2024-05-22)
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: ' + 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(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch));
959 const detect$1 = () => platform$4();
960
961 const userAgent = 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;
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$3 = (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$3(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$3(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 const hasChildNodes = element => element.dom.hasChildNodes();
1396
1397 const getHead = doc => {
1398 const b = doc.dom.head;
1399 if (b === null || b === undefined) {
1400 throw new Error('Head is not available yet');
1401 }
1402 return SugarElement.fromDom(b);
1403 };
1404
1405 const isShadowRoot = dos => isDocumentFragment$1(dos) && isNonNullable(dos.dom.host);
1406 const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
1407 const isSupported$1 = constant(supported);
1408 const getRootNode = supported ? e => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
1409 const getStyleContainer = dos => isShadowRoot(dos) ? dos : getHead(documentOrOwner(dos));
1410 const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
1411 const getShadowRoot = e => {
1412 const r = getRootNode(e);
1413 return isShadowRoot(r) ? Optional.some(r) : Optional.none();
1414 };
1415 const getShadowHost = e => SugarElement.fromDom(e.dom.host);
1416 const getOriginalEventTarget = event => {
1417 if (isSupported$1() && isNonNullable(event.target)) {
1418 const el = SugarElement.fromDom(event.target);
1419 if (isElement$7(el) && isOpenShadowHost(el)) {
1420 if (event.composed && event.composedPath) {
1421 const composedPath = event.composedPath();
1422 if (composedPath) {
1423 return head(composedPath);
1424 }
1425 }
1426 }
1427 }
1428 return Optional.from(event.target);
1429 };
1430 const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot);
1431
1432 const inBody = element => {
1433 const dom = isText$c(element) ? element.dom.parentNode : element.dom;
1434 if (dom === undefined || dom === null || dom.ownerDocument === null) {
1435 return false;
1436 }
1437 const doc = dom.ownerDocument;
1438 return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
1439 };
1440
1441 var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
1442 if (is(scope, a)) {
1443 return Optional.some(scope);
1444 } else if (isFunction(isRoot) && isRoot(scope)) {
1445 return Optional.none();
1446 } else {
1447 return ancestor(scope, a, isRoot);
1448 }
1449 };
1450
1451 const ancestor$4 = (scope, predicate, isRoot) => {
1452 let element = scope.dom;
1453 const stop = isFunction(isRoot) ? isRoot : never;
1454 while (element.parentNode) {
1455 element = element.parentNode;
1456 const el = SugarElement.fromDom(element);
1457 if (predicate(el)) {
1458 return Optional.some(el);
1459 } else if (stop(el)) {
1460 break;
1461 }
1462 }
1463 return Optional.none();
1464 };
1465 const closest$4 = (scope, predicate, isRoot) => {
1466 const is = (s, test) => test(s);
1467 return ClosestOrAncestor(is, ancestor$4, scope, predicate, isRoot);
1468 };
1469 const sibling$1 = (scope, predicate) => {
1470 const element = scope.dom;
1471 if (!element.parentNode) {
1472 return Optional.none();
1473 }
1474 return child(SugarElement.fromDom(element.parentNode), x => !eq(scope, x) && predicate(x));
1475 };
1476 const child = (scope, predicate) => {
1477 const pred = node => predicate(SugarElement.fromDom(node));
1478 const result = find$2(scope.dom.childNodes, pred);
1479 return result.map(SugarElement.fromDom);
1480 };
1481 const descendant$2 = (scope, predicate) => {
1482 const descend = node => {
1483 for (let i = 0; i < node.childNodes.length; i++) {
1484 const child = SugarElement.fromDom(node.childNodes[i]);
1485 if (predicate(child)) {
1486 return Optional.some(child);
1487 }
1488 const res = descend(node.childNodes[i]);
1489 if (res.isSome()) {
1490 return res;
1491 }
1492 }
1493 return Optional.none();
1494 };
1495 return descend(scope.dom);
1496 };
1497
1498 const ancestor$3 = (scope, selector, isRoot) => ancestor$4(scope, e => is$1(e, selector), isRoot);
1499 const descendant$1 = (scope, selector) => one(selector, scope);
1500 const closest$3 = (scope, selector, isRoot) => {
1501 const is = (element, selector) => is$1(element, selector);
1502 return ClosestOrAncestor(is, ancestor$3, scope, selector, isRoot);
1503 };
1504
1505 const closest$2 = target => closest$3(target, '[contenteditable]');
1506 const isEditable$2 = (element, assumeEditable = false) => {
1507 if (inBody(element)) {
1508 return element.dom.isContentEditable;
1509 } else {
1510 return closest$2(element).fold(constant(assumeEditable), editable => getRaw$1(editable) === 'true');
1511 }
1512 };
1513 const getRaw$1 = element => element.dom.contentEditable;
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 isTableCell$3 = matchNodeNames([
2003 'td',
2004 'th'
2005 ]);
2006 const isTableCellOrCaption = matchNodeNames([
2007 'td',
2008 'th',
2009 'caption'
2010 ]);
2011 const isMedia$2 = matchNodeNames([
2012 'video',
2013 'audio',
2014 'object',
2015 'embed'
2016 ]);
2017 const isListItem$2 = matchNodeName('li');
2018 const isDetails = matchNodeName('details');
2019 const isSummary$1 = matchNodeName('summary');
2020
2021 const defaultOptionValues = {
2022 skipBogus: true,
2023 includeZwsp: false,
2024 checkRootAsContent: false
2025 };
2026 const hasWhitespacePreserveParent = (node, rootNode, schema) => {
2027 const rootElement = SugarElement.fromDom(rootNode);
2028 const startNode = SugarElement.fromDom(node);
2029 const whitespaceElements = schema.getWhitespaceElements();
2030 const predicate = node => has$2(whitespaceElements, name(node));
2031 return ancestor$2(startNode, predicate, curry(eq, rootElement));
2032 };
2033 const isNamedAnchor = node => {
2034 return isElement$6(node) && node.nodeName === 'A' && !node.hasAttribute('href') && (node.hasAttribute('name') || node.hasAttribute('id'));
2035 };
2036 const isNonEmptyElement$1 = (node, schema) => {
2037 return isElement$6(node) && has$2(schema.getNonEmptyElements(), node.nodeName);
2038 };
2039 const isBookmark = hasAttribute('data-mce-bookmark');
2040 const hasNonEditableParent = node => parentElement(SugarElement.fromDom(node)).exists(parent => !isEditable$2(parent));
2041 const isWhitespace$1 = (node, rootNode, schema) => isWhitespaceText(node.data) && !hasWhitespacePreserveParent(node, rootNode, schema);
2042 const isText$a = (node, rootNode, schema, options) => isText$b(node) && !isWhitespace$1(node, rootNode, schema) && (!options.includeZwsp || !isZwsp$1(node.data));
2043 const isContentNode = (schema, node, rootNode, options) => {
2044 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);
2045 };
2046 const isEmptyNode = (schema, targetNode, opts) => {
2047 const options = {
2048 ...defaultOptionValues,
2049 ...opts
2050 };
2051 if (options.checkRootAsContent) {
2052 if (isContentNode(schema, targetNode, targetNode, options)) {
2053 return false;
2054 }
2055 }
2056 let node = targetNode.firstChild;
2057 let brCount = 0;
2058 if (!node) {
2059 return true;
2060 }
2061 const walker = new DomTreeWalker(node, targetNode);
2062 do {
2063 if (options.skipBogus && isElement$6(node)) {
2064 const bogusValue = node.getAttribute('data-mce-bogus');
2065 if (bogusValue) {
2066 node = walker.next(bogusValue === 'all');
2067 continue;
2068 }
2069 }
2070 if (isComment(node)) {
2071 node = walker.next(true);
2072 continue;
2073 }
2074 if (isBr$6(node)) {
2075 brCount++;
2076 node = walker.next();
2077 continue;
2078 }
2079 if (isContentNode(schema, node, targetNode, options)) {
2080 return false;
2081 }
2082 node = walker.next();
2083 } while (node);
2084 return brCount <= 1;
2085 };
2086 const isEmpty$2 = (schema, elm, options) => {
2087 return isEmptyNode(schema, elm.dom, {
2088 checkRootAsContent: true,
2089 ...options
2090 });
2091 };
2092 const isContent$1 = (schema, node, options) => {
2093 return isContentNode(schema, node, node, {
2094 includeZwsp: defaultOptionValues.includeZwsp,
2095 ...options
2096 });
2097 };
2098
2099 const Cell = initial => {
2100 let value = initial;
2101 const get = () => {
2102 return value;
2103 };
2104 const set = v => {
2105 value = v;
2106 };
2107 return {
2108 get,
2109 set
2110 };
2111 };
2112
2113 const singleton = doRevoke => {
2114 const subject = Cell(Optional.none());
2115 const revoke = () => subject.get().each(doRevoke);
2116 const clear = () => {
2117 revoke();
2118 subject.set(Optional.none());
2119 };
2120 const isSet = () => subject.get().isSome();
2121 const get = () => subject.get();
2122 const set = s => {
2123 revoke();
2124 subject.set(Optional.some(s));
2125 };
2126 return {
2127 clear,
2128 isSet,
2129 get,
2130 set
2131 };
2132 };
2133 const repeatable = delay => {
2134 const intervalId = Cell(Optional.none());
2135 const revoke = () => intervalId.get().each(id => clearInterval(id));
2136 const clear = () => {
2137 revoke();
2138 intervalId.set(Optional.none());
2139 };
2140 const isSet = () => intervalId.get().isSome();
2141 const get = () => intervalId.get();
2142 const set = functionToRepeat => {
2143 revoke();
2144 intervalId.set(Optional.some(setInterval(functionToRepeat, delay)));
2145 };
2146 return {
2147 clear,
2148 isSet,
2149 get,
2150 set
2151 };
2152 };
2153 const value$2 = () => {
2154 const subject = singleton(noop);
2155 const on = f => subject.get().each(f);
2156 return {
2157 ...subject,
2158 on
2159 };
2160 };
2161
2162 const nodeNameToNamespaceType = name => {
2163 const lowerCaseName = name.toLowerCase();
2164 if (lowerCaseName === 'svg') {
2165 return 'svg';
2166 } else if (lowerCaseName === 'math') {
2167 return 'math';
2168 } else {
2169 return 'html';
2170 }
2171 };
2172 const isNonHtmlElementRootName = name => nodeNameToNamespaceType(name) !== 'html';
2173 const isNonHtmlElementRoot = node => isNonHtmlElementRootName(node.nodeName);
2174 const toScopeType = node => nodeNameToNamespaceType(node.nodeName);
2175 const namespaceElements = [
2176 'svg',
2177 'math'
2178 ];
2179 const createNamespaceTracker = () => {
2180 const currentScope = value$2();
2181 const current = () => currentScope.get().map(toScopeType).getOr('html');
2182 const track = node => {
2183 if (isNonHtmlElementRoot(node)) {
2184 currentScope.set(node);
2185 } else if (currentScope.get().exists(scopeNode => !scopeNode.contains(node))) {
2186 currentScope.clear();
2187 }
2188 return current();
2189 };
2190 const reset = () => {
2191 currentScope.clear();
2192 };
2193 return {
2194 track,
2195 current,
2196 reset
2197 };
2198 };
2199
2200 const transparentBlockAttr = 'data-mce-block';
2201 const elementNames = map => filter$5(keys(map), key => !/[A-Z]/.test(key));
2202 const makeSelectorFromSchemaMap = map => map$3(elementNames(map), name => {
2203 const escapedName = CSS.escape(name);
2204 return `${ escapedName }:` + map$3(namespaceElements, ns => `not(${ ns } ${ escapedName })`).join(':');
2205 }).join(',');
2206 const updateTransparent = (blocksSelector, transparent) => {
2207 if (isNonNullable(transparent.querySelector(blocksSelector))) {
2208 transparent.setAttribute(transparentBlockAttr, 'true');
2209 if (transparent.getAttribute('data-mce-selected') === 'inline-boundary') {
2210 transparent.removeAttribute('data-mce-selected');
2211 }
2212 return true;
2213 } else {
2214 transparent.removeAttribute(transparentBlockAttr);
2215 return false;
2216 }
2217 };
2218 const updateBlockStateOnChildren = (schema, scope) => {
2219 const transparentSelector = makeSelectorFromSchemaMap(schema.getTransparentElements());
2220 const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
2221 return filter$5(scope.querySelectorAll(transparentSelector), transparent => updateTransparent(blocksSelector, transparent));
2222 };
2223 const trimEdge = (schema, el, leftSide) => {
2224 var _a;
2225 const childPropertyName = leftSide ? 'lastChild' : 'firstChild';
2226 for (let child = el[childPropertyName]; child; child = child[childPropertyName]) {
2227 if (isEmptyNode(schema, child, { checkRootAsContent: true })) {
2228 (_a = child.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(child);
2229 return;
2230 }
2231 }
2232 };
2233 const split$2 = (schema, parentElm, splitElm) => {
2234 const range = document.createRange();
2235 const parentNode = parentElm.parentNode;
2236 if (parentNode) {
2237 range.setStartBefore(parentElm);
2238 range.setEndBefore(splitElm);
2239 const beforeFragment = range.extractContents();
2240 trimEdge(schema, beforeFragment, true);
2241 range.setStartAfter(splitElm);
2242 range.setEndAfter(parentElm);
2243 const afterFragment = range.extractContents();
2244 trimEdge(schema, afterFragment, false);
2245 if (!isEmptyNode(schema, beforeFragment, { checkRootAsContent: true })) {
2246 parentNode.insertBefore(beforeFragment, parentElm);
2247 }
2248 if (!isEmptyNode(schema, splitElm, { checkRootAsContent: true })) {
2249 parentNode.insertBefore(splitElm, parentElm);
2250 }
2251 if (!isEmptyNode(schema, afterFragment, { checkRootAsContent: true })) {
2252 parentNode.insertBefore(afterFragment, parentElm);
2253 }
2254 parentNode.removeChild(parentElm);
2255 }
2256 };
2257 const splitInvalidChildren = (schema, scope, transparentBlocks) => {
2258 const blocksElements = schema.getBlockElements();
2259 const rootNode = SugarElement.fromDom(scope);
2260 const isBlock = el => name(el) in blocksElements;
2261 const isRoot = el => eq(el, rootNode);
2262 each$e(fromDom$1(transparentBlocks), transparentBlock => {
2263 ancestor$4(transparentBlock, isBlock, isRoot).each(parentBlock => {
2264 const invalidChildren = children(transparentBlock, el => isBlock(el) && !schema.isValidChild(name(parentBlock), name(el)));
2265 if (invalidChildren.length > 0) {
2266 const stateScope = parentElement(parentBlock);
2267 each$e(invalidChildren, child => {
2268 ancestor$4(child, isBlock, isRoot).each(parentBlock => {
2269 split$2(schema, parentBlock.dom, child.dom);
2270 });
2271 });
2272 stateScope.each(scope => updateBlockStateOnChildren(schema, scope.dom));
2273 }
2274 });
2275 });
2276 };
2277 const unwrapInvalidChildren = (schema, scope, transparentBlocks) => {
2278 each$e([
2279 ...transparentBlocks,
2280 ...isTransparentBlock(schema, scope) ? [scope] : []
2281 ], block => each$e(descendants(SugarElement.fromDom(block), block.nodeName.toLowerCase()), elm => {
2282 if (isTransparentInline(schema, elm.dom)) {
2283 unwrap(elm);
2284 }
2285 }));
2286 };
2287 const updateChildren = (schema, scope) => {
2288 const transparentBlocks = updateBlockStateOnChildren(schema, scope);
2289 splitInvalidChildren(schema, scope, transparentBlocks);
2290 unwrapInvalidChildren(schema, scope, transparentBlocks);
2291 };
2292 const updateElement = (schema, target) => {
2293 if (isTransparentElement(schema, target)) {
2294 const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
2295 updateTransparent(blocksSelector, target);
2296 }
2297 };
2298 const updateCaret = (schema, root, caretParent) => {
2299 const isRoot = el => eq(el, SugarElement.fromDom(root));
2300 const parents = parents$1(SugarElement.fromDom(caretParent), isRoot);
2301 get$b(parents, parents.length - 2).filter(isElement$7).fold(() => updateChildren(schema, root), scope => updateChildren(schema, scope.dom));
2302 };
2303 const hasBlockAttr = el => el.hasAttribute(transparentBlockAttr);
2304 const isTransparentElementName = (schema, name) => has$2(schema.getTransparentElements(), name);
2305 const isTransparentElement = (schema, node) => isElement$6(node) && isTransparentElementName(schema, node.nodeName);
2306 const isTransparentBlock = (schema, node) => isTransparentElement(schema, node) && hasBlockAttr(node);
2307 const isTransparentInline = (schema, node) => isTransparentElement(schema, node) && !hasBlockAttr(node);
2308 const isTransparentAstBlock = (schema, node) => node.type === 1 && isTransparentElementName(schema, node.name) && isString(node.attr(transparentBlockAttr));
2309
2310 const browser$2 = detect$1().browser;
2311 const firstElement = nodes => find$2(nodes, isElement$7);
2312 const getTableCaptionDeltaY = elm => {
2313 if (browser$2.isFirefox() && name(elm) === 'table') {
2314 return firstElement(children$1(elm)).filter(elm => {
2315 return name(elm) === 'caption';
2316 }).bind(caption => {
2317 return firstElement(nextSiblings(caption)).map(body => {
2318 const bodyTop = body.dom.offsetTop;
2319 const captionTop = caption.dom.offsetTop;
2320 const captionHeight = caption.dom.offsetHeight;
2321 return bodyTop <= captionTop ? -captionHeight : 0;
2322 });
2323 }).getOr(0);
2324 } else {
2325 return 0;
2326 }
2327 };
2328 const hasChild = (elm, child) => elm.children && contains$2(elm.children, child);
2329 const getPos = (body, elm, rootElm) => {
2330 let x = 0, y = 0;
2331 const doc = body.ownerDocument;
2332 rootElm = rootElm ? rootElm : body;
2333 if (elm) {
2334 if (rootElm === body && elm.getBoundingClientRect && get$7(SugarElement.fromDom(body), 'position') === 'static') {
2335 const pos = elm.getBoundingClientRect();
2336 x = pos.left + (doc.documentElement.scrollLeft || body.scrollLeft) - doc.documentElement.clientLeft;
2337 y = pos.top + (doc.documentElement.scrollTop || body.scrollTop) - doc.documentElement.clientTop;
2338 return {
2339 x,
2340 y
2341 };
2342 }
2343 let offsetParent = elm;
2344 while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
2345 const castOffsetParent = offsetParent;
2346 x += castOffsetParent.offsetLeft || 0;
2347 y += castOffsetParent.offsetTop || 0;
2348 offsetParent = castOffsetParent.offsetParent;
2349 }
2350 offsetParent = elm.parentNode;
2351 while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
2352 x -= offsetParent.scrollLeft || 0;
2353 y -= offsetParent.scrollTop || 0;
2354 offsetParent = offsetParent.parentNode;
2355 }
2356 y += getTableCaptionDeltaY(SugarElement.fromDom(elm));
2357 }
2358 return {
2359 x,
2360 y
2361 };
2362 };
2363
2364 const StyleSheetLoader = (documentOrShadowRoot, settings = {}) => {
2365 let idCount = 0;
2366 const loadedStates = {};
2367 const edos = SugarElement.fromDom(documentOrShadowRoot);
2368 const doc = documentOrOwner(edos);
2369 const _setReferrerPolicy = referrerPolicy => {
2370 settings.referrerPolicy = referrerPolicy;
2371 };
2372 const _setContentCssCors = contentCssCors => {
2373 settings.contentCssCors = contentCssCors;
2374 };
2375 const addStyle = element => {
2376 append$1(getStyleContainer(edos), element);
2377 };
2378 const removeStyle = id => {
2379 const styleContainer = getStyleContainer(edos);
2380 descendant$1(styleContainer, '#' + id).each(remove$4);
2381 };
2382 const getOrCreateState = url => get$a(loadedStates, url).getOrThunk(() => ({
2383 id: 'mce-u' + idCount++,
2384 passed: [],
2385 failed: [],
2386 count: 0
2387 }));
2388 const load = url => new Promise((success, failure) => {
2389 let link;
2390 const urlWithSuffix = Tools._addCacheSuffix(url);
2391 const state = getOrCreateState(urlWithSuffix);
2392 loadedStates[urlWithSuffix] = state;
2393 state.count++;
2394 const resolve = (callbacks, status) => {
2395 each$e(callbacks, call);
2396 state.status = status;
2397 state.passed = [];
2398 state.failed = [];
2399 if (link) {
2400 link.onload = null;
2401 link.onerror = null;
2402 link = null;
2403 }
2404 };
2405 const passed = () => resolve(state.passed, 2);
2406 const failed = () => resolve(state.failed, 3);
2407 if (success) {
2408 state.passed.push(success);
2409 }
2410 if (failure) {
2411 state.failed.push(failure);
2412 }
2413 if (state.status === 1) {
2414 return;
2415 }
2416 if (state.status === 2) {
2417 passed();
2418 return;
2419 }
2420 if (state.status === 3) {
2421 failed();
2422 return;
2423 }
2424 state.status = 1;
2425 const linkElem = SugarElement.fromTag('link', doc.dom);
2426 setAll$1(linkElem, {
2427 rel: 'stylesheet',
2428 type: 'text/css',
2429 id: state.id
2430 });
2431 if (settings.contentCssCors) {
2432 set$3(linkElem, 'crossOrigin', 'anonymous');
2433 }
2434 if (settings.referrerPolicy) {
2435 set$3(linkElem, 'referrerpolicy', settings.referrerPolicy);
2436 }
2437 link = linkElem.dom;
2438 link.onload = passed;
2439 link.onerror = failed;
2440 addStyle(linkElem);
2441 set$3(linkElem, 'href', urlWithSuffix);
2442 });
2443 const loadRawCss = (key, css) => {
2444 const state = getOrCreateState(key);
2445 loadedStates[key] = state;
2446 state.count++;
2447 const styleElem = SugarElement.fromTag('style', doc.dom);
2448 setAll$1(styleElem, {
2449 rel: 'stylesheet',
2450 type: 'text/css',
2451 id: state.id
2452 });
2453 styleElem.dom.innerHTML = css;
2454 addStyle(styleElem);
2455 };
2456 const loadAll = urls => {
2457 const loadedUrls = Promise.allSettled(map$3(urls, url => load(url).then(constant(url))));
2458 return loadedUrls.then(results => {
2459 const parts = partition$2(results, r => r.status === 'fulfilled');
2460 if (parts.fail.length > 0) {
2461 return Promise.reject(map$3(parts.fail, result => result.reason));
2462 } else {
2463 return map$3(parts.pass, result => result.value);
2464 }
2465 });
2466 };
2467 const unload = url => {
2468 const urlWithSuffix = Tools._addCacheSuffix(url);
2469 get$a(loadedStates, urlWithSuffix).each(state => {
2470 const count = --state.count;
2471 if (count === 0) {
2472 delete loadedStates[urlWithSuffix];
2473 removeStyle(state.id);
2474 }
2475 });
2476 };
2477 const unloadRawCss = key => {
2478 get$a(loadedStates, key).each(state => {
2479 const count = --state.count;
2480 if (count === 0) {
2481 delete loadedStates[key];
2482 removeStyle(state.id);
2483 }
2484 });
2485 };
2486 const unloadAll = urls => {
2487 each$e(urls, url => {
2488 unload(url);
2489 });
2490 };
2491 return {
2492 load,
2493 loadRawCss,
2494 loadAll,
2495 unload,
2496 unloadRawCss,
2497 unloadAll,
2498 _setReferrerPolicy,
2499 _setContentCssCors
2500 };
2501 };
2502
2503 const create$c = () => {
2504 const map = new WeakMap();
2505 const forElement = (referenceElement, settings) => {
2506 const root = getRootNode(referenceElement);
2507 const rootDom = root.dom;
2508 return Optional.from(map.get(rootDom)).getOrThunk(() => {
2509 const sl = StyleSheetLoader(rootDom, settings);
2510 map.set(rootDom, sl);
2511 return sl;
2512 });
2513 };
2514 return { forElement };
2515 };
2516 const instance = create$c();
2517
2518 const isSpan = node => node.nodeName.toLowerCase() === 'span';
2519 const isInlineContent = (node, schema) => isNonNullable(node) && (isContent$1(schema, node) || schema.isInline(node.nodeName.toLowerCase()));
2520 const surroundedByInlineContent = (node, root, schema) => {
2521 const prev = new DomTreeWalker(node, root).prev(false);
2522 const next = new DomTreeWalker(node, root).next(false);
2523 const prevIsInline = isUndefined(prev) || isInlineContent(prev, schema);
2524 const nextIsInline = isUndefined(next) || isInlineContent(next, schema);
2525 return prevIsInline && nextIsInline;
2526 };
2527 const isBookmarkNode$2 = node => isSpan(node) && node.getAttribute('data-mce-type') === 'bookmark';
2528 const isKeepTextNode = (node, root, schema) => isText$b(node) && node.data.length > 0 && surroundedByInlineContent(node, root, schema);
2529 const isKeepElement = node => isElement$6(node) ? node.childNodes.length > 0 : false;
2530 const isDocument = node => isDocumentFragment(node) || isDocument$1(node);
2531 const trimNode = (dom, node, schema, root) => {
2532 var _a;
2533 const rootNode = root || node;
2534 if (isElement$6(node) && isBookmarkNode$2(node)) {
2535 return node;
2536 }
2537 const children = node.childNodes;
2538 for (let i = children.length - 1; i >= 0; i--) {
2539 trimNode(dom, children[i], schema, rootNode);
2540 }
2541 if (isElement$6(node)) {
2542 const currentChildren = node.childNodes;
2543 if (currentChildren.length === 1 && isBookmarkNode$2(currentChildren[0])) {
2544 (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(currentChildren[0], node);
2545 }
2546 }
2547 if (!isDocument(node) && !isContent$1(schema, node) && !isKeepElement(node) && !isKeepTextNode(node, rootNode, schema)) {
2548 dom.remove(node);
2549 }
2550 return node;
2551 };
2552
2553 const makeMap$3 = Tools.makeMap;
2554 const attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
2555 const textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
2556 const rawCharsRegExp = /[<>&\"\']/g;
2557 const entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi;
2558 const asciiMap = {
2559 128: '\u20AC',
2560 130: '\u201A',
2561 131: '\u0192',
2562 132: '\u201E',
2563 133: '\u2026',
2564 134: '\u2020',
2565 135: '\u2021',
2566 136: '\u02c6',
2567 137: '\u2030',
2568 138: '\u0160',
2569 139: '\u2039',
2570 140: '\u0152',
2571 142: '\u017d',
2572 145: '\u2018',
2573 146: '\u2019',
2574 147: '\u201C',
2575 148: '\u201D',
2576 149: '\u2022',
2577 150: '\u2013',
2578 151: '\u2014',
2579 152: '\u02DC',
2580 153: '\u2122',
2581 154: '\u0161',
2582 155: '\u203A',
2583 156: '\u0153',
2584 158: '\u017e',
2585 159: '\u0178'
2586 };
2587 const baseEntities = {
2588 '"': '&quot;',
2589 '\'': '&#39;',
2590 '<': '&lt;',
2591 '>': '&gt;',
2592 '&': '&amp;',
2593 '`': '&#96;'
2594 };
2595 const reverseEntities = {
2596 '&lt;': '<',
2597 '&gt;': '>',
2598 '&amp;': '&',
2599 '&quot;': '"',
2600 '&apos;': `'`
2601 };
2602 const nativeDecode = text => {
2603 const elm = SugarElement.fromTag('div').dom;
2604 elm.innerHTML = text;
2605 return elm.textContent || elm.innerText || text;
2606 };
2607 const buildEntitiesLookup = (items, radix) => {
2608 const lookup = {};
2609 if (items) {
2610 const itemList = items.split(',');
2611 radix = radix || 10;
2612 for (let i = 0; i < itemList.length; i += 2) {
2613 const chr = String.fromCharCode(parseInt(itemList[i], radix));
2614 if (!baseEntities[chr]) {
2615 const entity = '&' + itemList[i + 1] + ';';
2616 lookup[chr] = entity;
2617 lookup[entity] = chr;
2618 }
2619 }
2620 return lookup;
2621 } else {
2622 return undefined;
2623 }
2624 };
2625 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);
2626 const encodeRaw = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
2627 return baseEntities[chr] || chr;
2628 });
2629 const encodeAllRaw = text => ('' + text).replace(rawCharsRegExp, chr => {
2630 return baseEntities[chr] || chr;
2631 });
2632 const encodeNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
2633 if (chr.length > 1) {
2634 return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
2635 }
2636 return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
2637 });
2638 const encodeNamed = (text, attr, entities) => {
2639 const resolveEntities = entities || namedEntities;
2640 return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
2641 return baseEntities[chr] || resolveEntities[chr] || chr;
2642 });
2643 };
2644 const getEncodeFunc = (name, entities) => {
2645 const entitiesMap = buildEntitiesLookup(entities) || namedEntities;
2646 const encodeNamedAndNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
2647 if (baseEntities[chr] !== undefined) {
2648 return baseEntities[chr];
2649 }
2650 if (entitiesMap[chr] !== undefined) {
2651 return entitiesMap[chr];
2652 }
2653 if (chr.length > 1) {
2654 return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
2655 }
2656 return '&#' + chr.charCodeAt(0) + ';';
2657 });
2658 const encodeCustomNamed = (text, attr) => {
2659 return encodeNamed(text, attr, entitiesMap);
2660 };
2661 const nameMap = makeMap$3(name.replace(/\+/g, ','));
2662 if (nameMap.named && nameMap.numeric) {
2663 return encodeNamedAndNumeric;
2664 }
2665 if (nameMap.named) {
2666 if (entities) {
2667 return encodeCustomNamed;
2668 }
2669 return encodeNamed;
2670 }
2671 if (nameMap.numeric) {
2672 return encodeNumeric;
2673 }
2674 return encodeRaw;
2675 };
2676 const decode = text => text.replace(entityRegExp, (all, numeric) => {
2677 if (numeric) {
2678 if (numeric.charAt(0).toLowerCase() === 'x') {
2679 numeric = parseInt(numeric.substr(1), 16);
2680 } else {
2681 numeric = parseInt(numeric, 10);
2682 }
2683 if (numeric > 65535) {
2684 numeric -= 65536;
2685 return String.fromCharCode(55296 + (numeric >> 10), 56320 + (numeric & 1023));
2686 }
2687 return asciiMap[numeric] || String.fromCharCode(numeric);
2688 }
2689 return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
2690 });
2691 const Entities = {
2692 encodeRaw,
2693 encodeAllRaw,
2694 encodeNumeric,
2695 encodeNamed,
2696 getEncodeFunc,
2697 decode
2698 };
2699
2700 const split$1 = (items, delim) => {
2701 items = Tools.trim(items);
2702 return items ? items.split(delim || ' ') : [];
2703 };
2704 const patternToRegExp = str => new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
2705 const isRegExp$1 = obj => isObject(obj) && obj.source && Object.prototype.toString.call(obj) === '[object RegExp]';
2706 const deepCloneElementRule = obj => {
2707 const helper = value => {
2708 if (isArray$1(value)) {
2709 return map$3(value, helper);
2710 } else if (isRegExp$1(value)) {
2711 return new RegExp(value.source, value.flags);
2712 } else if (isObject(value)) {
2713 return map$2(value, helper);
2714 } else {
2715 return value;
2716 }
2717 };
2718 return helper(obj);
2719 };
2720
2721 const parseCustomElementsRules = value => {
2722 const customElementRegExp = /^(~)?(.+)$/;
2723 return bind$3(split$1(value, ','), rule => {
2724 const matches = customElementRegExp.exec(rule);
2725 if (matches) {
2726 const inline = matches[1] === '~';
2727 const cloneName = inline ? 'span' : 'div';
2728 const name = matches[2];
2729 return [{
2730 cloneName,
2731 name
2732 }];
2733 } else {
2734 return [];
2735 }
2736 });
2737 };
2738
2739 const getGlobalAttributeSet = type => {
2740 return Object.freeze([
2741 'id',
2742 'accesskey',
2743 'class',
2744 'dir',
2745 'lang',
2746 'style',
2747 'tabindex',
2748 'title',
2749 'role',
2750 ...type !== 'html4' ? [
2751 'contenteditable',
2752 'contextmenu',
2753 'draggable',
2754 'dropzone',
2755 'hidden',
2756 'spellcheck',
2757 'translate',
2758 'itemprop',
2759 'itemscope',
2760 'itemtype'
2761 ] : [],
2762 ...type !== 'html5-strict' ? ['xml:lang'] : []
2763 ]);
2764 };
2765
2766 const getElementSetsAsStrings = type => {
2767 let blockContent;
2768 let phrasingContent;
2769 blockContent = 'address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul';
2770 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';
2771 if (type !== 'html4') {
2772 const transparentContent = 'a ins del canvas map';
2773 blockContent += ' article aside details dialog figure main header footer hgroup section nav ' + transparentContent;
2774 phrasingContent += ' audio canvas command data datalist mark meter output picture ' + 'progress time wbr video ruby bdi keygen svg';
2775 }
2776 if (type !== 'html5-strict') {
2777 const html4PhrasingContent = 'acronym applet basefont big font strike tt';
2778 phrasingContent = [
2779 phrasingContent,
2780 html4PhrasingContent
2781 ].join(' ');
2782 const html4BlockContent = 'center dir isindex noframes';
2783 blockContent = [
2784 blockContent,
2785 html4BlockContent
2786 ].join(' ');
2787 }
2788 const flowContent = [
2789 blockContent,
2790 phrasingContent
2791 ].join(' ');
2792 return {
2793 blockContent,
2794 phrasingContent,
2795 flowContent
2796 };
2797 };
2798 const getElementSets = type => {
2799 const {blockContent, phrasingContent, flowContent} = getElementSetsAsStrings(type);
2800 const toArr = value => {
2801 return Object.freeze(value.split(' '));
2802 };
2803 return Object.freeze({
2804 blockContent: toArr(blockContent),
2805 phrasingContent: toArr(phrasingContent),
2806 flowContent: toArr(flowContent)
2807 });
2808 };
2809
2810 const cachedSets = {
2811 'html4': cached(() => getElementSets('html4')),
2812 'html5': cached(() => getElementSets('html5')),
2813 'html5-strict': cached(() => getElementSets('html5-strict'))
2814 };
2815 const getElementsPreset = (type, name) => {
2816 const {blockContent, phrasingContent, flowContent} = cachedSets[type]();
2817 if (name === 'blocks') {
2818 return Optional.some(blockContent);
2819 } else if (name === 'phrasing') {
2820 return Optional.some(phrasingContent);
2821 } else if (name === 'flow') {
2822 return Optional.some(flowContent);
2823 } else {
2824 return Optional.none();
2825 }
2826 };
2827
2828 const makeSchema = type => {
2829 const globalAttributes = getGlobalAttributeSet(type);
2830 const {phrasingContent, flowContent} = getElementSetsAsStrings(type);
2831 const schema = {};
2832 const addElement = (name, attributes, children) => {
2833 schema[name] = {
2834 attributes: mapToObject(attributes, constant({})),
2835 attributesOrder: attributes,
2836 children: mapToObject(children, constant({}))
2837 };
2838 };
2839 const add = (name, attributes = '', children = '') => {
2840 const childNames = split$1(children);
2841 const names = split$1(name);
2842 let ni = names.length;
2843 const allAttributes = [
2844 ...globalAttributes,
2845 ...split$1(attributes)
2846 ];
2847 while (ni--) {
2848 addElement(names[ni], allAttributes.slice(), childNames);
2849 }
2850 };
2851 const addAttrs = (name, attributes) => {
2852 const names = split$1(name);
2853 const attrs = split$1(attributes);
2854 let ni = names.length;
2855 while (ni--) {
2856 const schemaItem = schema[names[ni]];
2857 for (let i = 0, l = attrs.length; i < l; i++) {
2858 schemaItem.attributes[attrs[i]] = {};
2859 schemaItem.attributesOrder.push(attrs[i]);
2860 }
2861 }
2862 };
2863 if (type !== 'html5-strict') {
2864 const html4PhrasingContent = 'acronym applet basefont big font strike tt';
2865 each$e(split$1(html4PhrasingContent), name => {
2866 add(name, '', phrasingContent);
2867 });
2868 const html4BlockContent = 'center dir isindex noframes';
2869 each$e(split$1(html4BlockContent), name => {
2870 add(name, '', flowContent);
2871 });
2872 }
2873 add('html', 'manifest', 'head body');
2874 add('head', '', 'base command link meta noscript script style title');
2875 add('title hr noscript br');
2876 add('base', 'href target');
2877 add('link', 'href rel media hreflang type sizes hreflang');
2878 add('meta', 'name http-equiv content charset');
2879 add('style', 'media type scoped');
2880 add('script', 'src async defer type charset');
2881 add('body', 'onafterprint onbeforeprint onbeforeunload onblur onerror onfocus ' + 'onhashchange onload onmessage onoffline ononline onpagehide onpageshow ' + 'onpopstate onresize onscroll onstorage onunload', flowContent);
2882 add('dd div', '', flowContent);
2883 add('address dt caption', '', type === 'html4' ? phrasingContent : flowContent);
2884 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);
2885 add('blockquote', 'cite', flowContent);
2886 add('ol', 'reversed start type', 'li');
2887 add('ul', '', 'li');
2888 add('li', 'value', flowContent);
2889 add('dl', '', 'dt dd');
2890 add('a', 'href target rel media hreflang type', type === 'html4' ? phrasingContent : flowContent);
2891 add('q', 'cite', phrasingContent);
2892 add('ins del', 'cite datetime', flowContent);
2893 add('img', 'src sizes srcset alt usemap ismap width height');
2894 add('iframe', 'src name width height', flowContent);
2895 add('embed', 'src type width height');
2896 add('object', 'data type typemustmatch name usemap form width height', [
2897 flowContent,
2898 'param'
2899 ].join(' '));
2900 add('param', 'name value');
2901 add('map', 'name', [
2902 flowContent,
2903 'area'
2904 ].join(' '));
2905 add('area', 'alt coords shape href target rel media hreflang type');
2906 add('table', 'border', 'caption colgroup thead tfoot tbody tr' + (type === 'html4' ? ' col' : ''));
2907 add('colgroup', 'span', 'col');
2908 add('col', 'span');
2909 add('tbody thead tfoot', '', 'tr');
2910 add('tr', '', 'td th');
2911 add('td', 'colspan rowspan headers', flowContent);
2912 add('th', 'colspan rowspan headers scope abbr', flowContent);
2913 add('form', 'accept-charset action autocomplete enctype method name novalidate target', flowContent);
2914 add('fieldset', 'disabled form name', [
2915 flowContent,
2916 'legend'
2917 ].join(' '));
2918 add('label', 'form for', phrasingContent);
2919 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');
2920 add('button', 'disabled form formaction formenctype formmethod formnovalidate formtarget name type value', type === 'html4' ? flowContent : phrasingContent);
2921 add('select', 'disabled form multiple name required size', 'option optgroup');
2922 add('optgroup', 'disabled label', 'option');
2923 add('option', 'disabled label selected value');
2924 add('textarea', 'cols dirname disabled form maxlength name readonly required rows wrap');
2925 add('menu', 'type label', [
2926 flowContent,
2927 'li'
2928 ].join(' '));
2929 add('noscript', '', flowContent);
2930 if (type !== 'html4') {
2931 add('wbr');
2932 add('ruby', '', [
2933 phrasingContent,
2934 'rt rp'
2935 ].join(' '));
2936 add('figcaption', '', flowContent);
2937 add('mark rt rp bdi', '', phrasingContent);
2938 add('summary', '', [
2939 phrasingContent,
2940 'h1 h2 h3 h4 h5 h6'
2941 ].join(' '));
2942 add('canvas', 'width height', flowContent);
2943 add('data', 'value', phrasingContent);
2944 add('video', 'src crossorigin poster preload autoplay mediagroup loop ' + 'muted controls width height buffered', [
2945 flowContent,
2946 'track source'
2947 ].join(' '));
2948 add('audio', 'src crossorigin preload autoplay mediagroup loop muted controls ' + 'buffered volume', [
2949 flowContent,
2950 'track source'
2951 ].join(' '));
2952 add('picture', '', 'img source');
2953 add('source', 'src srcset type media sizes');
2954 add('track', 'kind src srclang label default');
2955 add('datalist', '', [
2956 phrasingContent,
2957 'option'
2958 ].join(' '));
2959 add('article section nav aside main header footer', '', flowContent);
2960 add('hgroup', '', 'h1 h2 h3 h4 h5 h6');
2961 add('figure', '', [
2962 flowContent,
2963 'figcaption'
2964 ].join(' '));
2965 add('time', 'datetime', phrasingContent);
2966 add('dialog', 'open', flowContent);
2967 add('command', 'type label icon disabled checked radiogroup command');
2968 add('output', 'for form name', phrasingContent);
2969 add('progress', 'value max', phrasingContent);
2970 add('meter', 'value min max low high optimum', phrasingContent);
2971 add('details', 'open', [
2972 flowContent,
2973 'summary'
2974 ].join(' '));
2975 add('keygen', 'autofocus challenge disabled form keytype name');
2976 addElement('svg', 'id tabindex lang xml:space class style x y width height viewBox preserveAspectRatio zoomAndPan transform'.split(' '), []);
2977 }
2978 if (type !== 'html5-strict') {
2979 addAttrs('script', 'language xml:space');
2980 addAttrs('style', 'xml:space');
2981 addAttrs('object', 'declare classid code codebase codetype archive standby align border hspace vspace');
2982 addAttrs('embed', 'align name hspace vspace');
2983 addAttrs('param', 'valuetype type');
2984 addAttrs('a', 'charset name rev shape coords');
2985 addAttrs('br', 'clear');
2986 addAttrs('applet', 'codebase archive code object alt name width height align hspace vspace');
2987 addAttrs('img', 'name longdesc align border hspace vspace');
2988 addAttrs('iframe', 'longdesc frameborder marginwidth marginheight scrolling align');
2989 addAttrs('font basefont', 'size color face');
2990 addAttrs('input', 'usemap align');
2991 addAttrs('select');
2992 addAttrs('textarea');
2993 addAttrs('h1 h2 h3 h4 h5 h6 div p legend caption', 'align');
2994 addAttrs('ul', 'type compact');
2995 addAttrs('li', 'type');
2996 addAttrs('ol dl menu dir', 'compact');
2997 addAttrs('pre', 'width xml:space');
2998 addAttrs('hr', 'align noshade size width');
2999 addAttrs('isindex', 'prompt');
3000 addAttrs('table', 'summary width frame rules cellspacing cellpadding align bgcolor');
3001 addAttrs('col', 'width align char charoff valign');
3002 addAttrs('colgroup', 'width align char charoff valign');
3003 addAttrs('thead', 'align char charoff valign');
3004 addAttrs('tr', 'align char charoff valign bgcolor');
3005 addAttrs('th', 'axis align char charoff valign nowrap bgcolor width height');
3006 addAttrs('form', 'accept');
3007 addAttrs('td', 'abbr axis scope align char charoff valign nowrap bgcolor width height');
3008 addAttrs('tfoot', 'align char charoff valign');
3009 addAttrs('tbody', 'align char charoff valign');
3010 addAttrs('area', 'nohref');
3011 addAttrs('body', 'background bgcolor text link vlink alink');
3012 }
3013 if (type !== 'html4') {
3014 addAttrs('input button select textarea', 'autofocus');
3015 addAttrs('input textarea', 'placeholder');
3016 addAttrs('a', 'download');
3017 addAttrs('link script img', 'crossorigin');
3018 addAttrs('img', 'loading');
3019 addAttrs('iframe', 'sandbox seamless allow allowfullscreen loading');
3020 }
3021 if (type !== 'html4') {
3022 each$e([
3023 schema.video,
3024 schema.audio
3025 ], item => {
3026 delete item.children.audio;
3027 delete item.children.video;
3028 });
3029 }
3030 each$e(split$1('a form meter progress dfn'), name => {
3031 if (schema[name]) {
3032 delete schema[name].children[name];
3033 }
3034 });
3035 delete schema.caption.children.table;
3036 delete schema.script;
3037 return schema;
3038 };
3039
3040 const prefixToOperation = prefix => prefix === '-' ? 'remove' : 'add';
3041 const parseValidChild = name => {
3042 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]+)$/;
3043 return Optional.from(validChildRegExp.exec(name)).map(matches => ({
3044 preset: matches[1] === '@',
3045 name: matches[2]
3046 }));
3047 };
3048 const parseValidChildrenRules = value => {
3049 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]+)\[([^\]]+)]$/;
3050 return bind$3(split$1(value, ','), rule => {
3051 const matches = childRuleRegExp.exec(rule);
3052 if (matches) {
3053 const prefix = matches[1];
3054 const operation = prefix ? prefixToOperation(prefix) : 'replace';
3055 const name = matches[2];
3056 const validChildren = bind$3(split$1(matches[3], '|'), validChild => parseValidChild(validChild).toArray());
3057 return [{
3058 operation,
3059 name,
3060 validChildren
3061 }];
3062 } else {
3063 return [];
3064 }
3065 });
3066 };
3067
3068 const parseValidElementsAttrDataIntoElement = (attrData, targetElement) => {
3069 const attrRuleRegExp = /^([!\-])?(\w+[\\:]:\w+|[^=~<]+)?(?:([=~<])(.*))?$/;
3070 const hasPatternsRegExp = /[*?+]/;
3071 const {attributes, attributesOrder} = targetElement;
3072 return each$e(split$1(attrData, '|'), rule => {
3073 const matches = attrRuleRegExp.exec(rule);
3074 if (matches) {
3075 const attr = {};
3076 const attrType = matches[1];
3077 const attrName = matches[2].replace(/[\\:]:/g, ':');
3078 const attrPrefix = matches[3];
3079 const value = matches[4];
3080 if (attrType === '!') {
3081 targetElement.attributesRequired = targetElement.attributesRequired || [];
3082 targetElement.attributesRequired.push(attrName);
3083 attr.required = true;
3084 }
3085 if (attrType === '-') {
3086 delete attributes[attrName];
3087 attributesOrder.splice(Tools.inArray(attributesOrder, attrName), 1);
3088 return;
3089 }
3090 if (attrPrefix) {
3091 if (attrPrefix === '=') {
3092 targetElement.attributesDefault = targetElement.attributesDefault || [];
3093 targetElement.attributesDefault.push({
3094 name: attrName,
3095 value
3096 });
3097 attr.defaultValue = value;
3098 } else if (attrPrefix === '~') {
3099 targetElement.attributesForced = targetElement.attributesForced || [];
3100 targetElement.attributesForced.push({
3101 name: attrName,
3102 value
3103 });
3104 attr.forcedValue = value;
3105 } else if (attrPrefix === '<') {
3106 attr.validValues = Tools.makeMap(value, '?');
3107 }
3108 }
3109 if (hasPatternsRegExp.test(attrName)) {
3110 const attrPattern = attr;
3111 targetElement.attributePatterns = targetElement.attributePatterns || [];
3112 attrPattern.pattern = patternToRegExp(attrName);
3113 targetElement.attributePatterns.push(attrPattern);
3114 } else {
3115 if (!attributes[attrName]) {
3116 attributesOrder.push(attrName);
3117 }
3118 attributes[attrName] = attr;
3119 }
3120 }
3121 });
3122 };
3123 const cloneAttributesInto = (from, to) => {
3124 each$d(from.attributes, (value, key) => {
3125 to.attributes[key] = value;
3126 });
3127 to.attributesOrder.push(...from.attributesOrder);
3128 };
3129 const parseValidElementsRules = (globalElement, validElements) => {
3130 const elementRuleRegExp = /^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)])?$/;
3131 return bind$3(split$1(validElements, ','), rule => {
3132 const matches = elementRuleRegExp.exec(rule);
3133 if (matches) {
3134 const prefix = matches[1];
3135 const elementName = matches[2];
3136 const outputName = matches[3];
3137 const attrsPrefix = matches[4];
3138 const attrData = matches[5];
3139 const element = {
3140 attributes: {},
3141 attributesOrder: []
3142 };
3143 globalElement.each(el => cloneAttributesInto(el, element));
3144 if (prefix === '#') {
3145 element.paddEmpty = true;
3146 } else if (prefix === '-') {
3147 element.removeEmpty = true;
3148 }
3149 if (attrsPrefix === '!') {
3150 element.removeEmptyAttrs = true;
3151 }
3152 if (attrData) {
3153 parseValidElementsAttrDataIntoElement(attrData, element);
3154 }
3155 if (outputName) {
3156 element.outputName = elementName;
3157 }
3158 if (elementName === '@') {
3159 if (globalElement.isNone()) {
3160 globalElement = Optional.some(element);
3161 } else {
3162 return [];
3163 }
3164 }
3165 return [outputName ? {
3166 name: elementName,
3167 element,
3168 aliasName: outputName
3169 } : {
3170 name: elementName,
3171 element
3172 }];
3173 } else {
3174 return [];
3175 }
3176 });
3177 };
3178
3179 const mapCache = {};
3180 const makeMap$2 = Tools.makeMap, each$b = Tools.each, extend$2 = Tools.extend, explode$2 = Tools.explode;
3181 const createMap = (defaultValue, extendWith = {}) => {
3182 const value = makeMap$2(defaultValue, ' ', makeMap$2(defaultValue.toUpperCase(), ' '));
3183 return extend$2(value, extendWith);
3184 };
3185 const getTextRootBlockElements = schema => createMap('td th li dt dd figcaption caption details summary', schema.getTextBlockElements());
3186 const compileElementMap = (value, mode) => {
3187 if (value) {
3188 const styles = {};
3189 if (isString(value)) {
3190 value = { '*': value };
3191 }
3192 each$b(value, (value, key) => {
3193 styles[key] = styles[key.toUpperCase()] = mode === 'map' ? makeMap$2(value, /[, ]/) : explode$2(value, /[, ]/);
3194 });
3195 return styles;
3196 } else {
3197 return undefined;
3198 }
3199 };
3200 const Schema = (settings = {}) => {
3201 var _a;
3202 const elements = {};
3203 const children = {};
3204 let patternElements = [];
3205 const customElementsMap = {};
3206 const specialElements = {};
3207 const createLookupTable = (option, defaultValue, extendWith) => {
3208 const value = settings[option];
3209 if (!value) {
3210 let newValue = mapCache[option];
3211 if (!newValue) {
3212 newValue = createMap(defaultValue, extendWith);
3213 mapCache[option] = newValue;
3214 }
3215 return newValue;
3216 } else {
3217 return makeMap$2(value, /[, ]/, makeMap$2(value.toUpperCase(), /[, ]/));
3218 }
3219 };
3220 const schemaType = (_a = settings.schema) !== null && _a !== void 0 ? _a : 'html5';
3221 const schemaItems = makeSchema(schemaType);
3222 if (settings.verify_html === false) {
3223 settings.valid_elements = '*[*]';
3224 }
3225 const validStyles = compileElementMap(settings.valid_styles);
3226 const invalidStyles = compileElementMap(settings.invalid_styles, 'map');
3227 const validClasses = compileElementMap(settings.valid_classes, 'map');
3228 const whitespaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea video audio iframe object code');
3229 const selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
3230 const voidElementsMap = createLookupTable('void_elements', 'area base basefont br col frame hr img input isindex link ' + 'meta param embed source wbr track');
3231 const boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' + 'noshade nowrap readonly selected autoplay loop controls allowfullscreen');
3232 const nonEmptyOrMoveCaretBeforeOnEnter = 'td th iframe video audio object script code';
3233 const nonEmptyElementsMap = createLookupTable('non_empty_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' pre svg textarea summary', voidElementsMap);
3234 const moveCaretBeforeOnEnterElementsMap = createLookupTable('move_caret_before_on_enter_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' table', voidElementsMap);
3235 const headings = 'h1 h2 h3 h4 h5 h6';
3236 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');
3237 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);
3238 const textInlineElementsMap = createLookupTable('text_inline_elements', 'span strong b em i font s strike u var cite ' + 'dfn code mark q sup sub samp');
3239 const transparentElementsMap = createLookupTable('transparent_elements', 'a ins del canvas map');
3240 const wrapBlockElementsMap = createLookupTable('wrap_block_elements', 'pre ' + headings);
3241 each$b('script noscript iframe noframes noembed title style textarea xmp plaintext'.split(' '), name => {
3242 specialElements[name] = new RegExp('</' + name + '[^>]*>', 'gi');
3243 });
3244 const addValidElements = validElements => {
3245 const globalElement = Optional.from(elements['@']);
3246 const hasPatternsRegExp = /[*?+]/;
3247 each$e(parseValidElementsRules(globalElement, validElements !== null && validElements !== void 0 ? validElements : ''), ({name, element, aliasName}) => {
3248 if (aliasName) {
3249 elements[aliasName] = element;
3250 }
3251 if (hasPatternsRegExp.test(name)) {
3252 const patternElement = element;
3253 patternElement.pattern = patternToRegExp(name);
3254 patternElements.push(patternElement);
3255 } else {
3256 elements[name] = element;
3257 }
3258 });
3259 };
3260 const setValidElements = validElements => {
3261 patternElements = [];
3262 each$e(keys(elements), name => {
3263 delete elements[name];
3264 });
3265 addValidElements(validElements);
3266 };
3267 const addCustomElement = (name, spec) => {
3268 var _a, _b;
3269 delete mapCache.text_block_elements;
3270 delete mapCache.block_elements;
3271 const inline = spec.extends ? !isBlock(spec.extends) : false;
3272 const cloneName = spec.extends;
3273 children[name] = cloneName ? children[cloneName] : {};
3274 customElementsMap[name] = cloneName !== null && cloneName !== void 0 ? cloneName : name;
3275 nonEmptyElementsMap[name.toUpperCase()] = {};
3276 nonEmptyElementsMap[name] = {};
3277 if (!inline) {
3278 blockElementsMap[name.toUpperCase()] = {};
3279 blockElementsMap[name] = {};
3280 }
3281 if (cloneName && !elements[name] && elements[cloneName]) {
3282 const customRule = deepCloneElementRule(elements[cloneName]);
3283 delete customRule.removeEmptyAttrs;
3284 delete customRule.removeEmpty;
3285 elements[name] = customRule;
3286 } else {
3287 elements[name] = {
3288 attributesOrder: [],
3289 attributes: {}
3290 };
3291 }
3292 if (isArray$1(spec.attributes)) {
3293 const processAttrName = name => {
3294 customRule.attributesOrder.push(name);
3295 customRule.attributes[name] = {};
3296 };
3297 const customRule = (_a = elements[name]) !== null && _a !== void 0 ? _a : {};
3298 delete customRule.attributesDefault;
3299 delete customRule.attributesForced;
3300 delete customRule.attributePatterns;
3301 delete customRule.attributesRequired;
3302 customRule.attributesOrder = [];
3303 customRule.attributes = {};
3304 each$e(spec.attributes, attrName => {
3305 const globalAttrs = getGlobalAttributeSet(schemaType);
3306 parseValidChild(attrName).each(({preset, name}) => {
3307 if (preset) {
3308 if (name === 'global') {
3309 each$e(globalAttrs, processAttrName);
3310 }
3311 } else {
3312 processAttrName(name);
3313 }
3314 });
3315 });
3316 elements[name] = customRule;
3317 }
3318 if (isBoolean(spec.padEmpty)) {
3319 const customRule = (_b = elements[name]) !== null && _b !== void 0 ? _b : {};
3320 customRule.paddEmpty = spec.padEmpty;
3321 elements[name] = customRule;
3322 }
3323 if (isArray$1(spec.children)) {
3324 const customElementChildren = {};
3325 const processNodeName = name => {
3326 customElementChildren[name] = {};
3327 };
3328 const processPreset = name => {
3329 getElementsPreset(schemaType, name).each(names => {
3330 each$e(names, processNodeName);
3331 });
3332 };
3333 each$e(spec.children, child => {
3334 parseValidChild(child).each(({preset, name}) => {
3335 if (preset) {
3336 processPreset(name);
3337 } else {
3338 processNodeName(name);
3339 }
3340 });
3341 });
3342 children[name] = customElementChildren;
3343 }
3344 if (cloneName) {
3345 each$d(children, (element, elmName) => {
3346 if (element[cloneName]) {
3347 children[elmName] = element = extend$2({}, children[elmName]);
3348 element[name] = element[cloneName];
3349 }
3350 });
3351 }
3352 };
3353 const addCustomElementsFromString = customElements => {
3354 each$e(parseCustomElementsRules(customElements !== null && customElements !== void 0 ? customElements : ''), ({name, cloneName}) => {
3355 addCustomElement(name, { extends: cloneName });
3356 });
3357 };
3358 const addCustomElements = customElements => {
3359 if (isObject(customElements)) {
3360 each$d(customElements, (spec, name) => addCustomElement(name, spec));
3361 } else if (isString(customElements)) {
3362 addCustomElementsFromString(customElements);
3363 }
3364 };
3365 const addValidChildren = validChildren => {
3366 each$e(parseValidChildrenRules(validChildren !== null && validChildren !== void 0 ? validChildren : ''), ({operation, name, validChildren}) => {
3367 const parent = operation === 'replace' ? { '#comment': {} } : children[name];
3368 const processNodeName = name => {
3369 if (operation === 'remove') {
3370 delete parent[name];
3371 } else {
3372 parent[name] = {};
3373 }
3374 };
3375 const processPreset = name => {
3376 getElementsPreset(schemaType, name).each(names => {
3377 each$e(names, processNodeName);
3378 });
3379 };
3380 each$e(validChildren, ({preset, name}) => {
3381 if (preset) {
3382 processPreset(name);
3383 } else {
3384 processNodeName(name);
3385 }
3386 });
3387 children[name] = parent;
3388 });
3389 };
3390 const getElementRule = name => {
3391 const element = elements[name];
3392 if (element) {
3393 return element;
3394 }
3395 let i = patternElements.length;
3396 while (i--) {
3397 const patternElement = patternElements[i];
3398 if (patternElement.pattern.test(name)) {
3399 return patternElement;
3400 }
3401 }
3402 return undefined;
3403 };
3404 const setup = () => {
3405 if (!settings.valid_elements) {
3406 each$b(schemaItems, (element, name) => {
3407 elements[name] = {
3408 attributes: element.attributes,
3409 attributesOrder: element.attributesOrder
3410 };
3411 children[name] = element.children;
3412 });
3413 each$b(split$1('strong/b em/i'), item => {
3414 const items = split$1(item, '/');
3415 elements[items[1]].outputName = items[0];
3416 });
3417 each$b(textInlineElementsMap, (_val, name) => {
3418 if (elements[name]) {
3419 if (settings.padd_empty_block_inline_children) {
3420 elements[name].paddInEmptyBlock = true;
3421 }
3422 elements[name].removeEmpty = true;
3423 }
3424 });
3425 each$b(split$1('ol ul blockquote a table tbody'), name => {
3426 if (elements[name]) {
3427 elements[name].removeEmpty = true;
3428 }
3429 });
3430 each$b(split$1('p h1 h2 h3 h4 h5 h6 th td pre div address caption li summary'), name => {
3431 if (elements[name]) {
3432 elements[name].paddEmpty = true;
3433 }
3434 });
3435 each$b(split$1('span'), name => {
3436 elements[name].removeEmptyAttrs = true;
3437 });
3438 } else {
3439 setValidElements(settings.valid_elements);
3440 each$b(schemaItems, (element, name) => {
3441 children[name] = element.children;
3442 });
3443 }
3444 delete elements.svg;
3445 addCustomElements(settings.custom_elements);
3446 addValidChildren(settings.valid_children);
3447 addValidElements(settings.extended_valid_elements);
3448 addValidChildren('+ol[ul|ol],+ul[ul|ol]');
3449 each$b({
3450 dd: 'dl',
3451 dt: 'dl',
3452 li: 'ul ol',
3453 td: 'tr',
3454 th: 'tr',
3455 tr: 'tbody thead tfoot',
3456 tbody: 'table',
3457 thead: 'table',
3458 tfoot: 'table',
3459 legend: 'fieldset',
3460 area: 'map',
3461 param: 'video audio object'
3462 }, (parents, item) => {
3463 if (elements[item]) {
3464 elements[item].parentsRequired = split$1(parents);
3465 }
3466 });
3467 if (settings.invalid_elements) {
3468 each$b(explode$2(settings.invalid_elements), item => {
3469 if (elements[item]) {
3470 delete elements[item];
3471 }
3472 });
3473 }
3474 if (!getElementRule('span')) {
3475 addValidElements('span[!data-mce-type|*]');
3476 }
3477 };
3478 const getValidStyles = constant(validStyles);
3479 const getInvalidStyles = constant(invalidStyles);
3480 const getValidClasses = constant(validClasses);
3481 const getBoolAttrs = constant(boolAttrMap);
3482 const getBlockElements = constant(blockElementsMap);
3483 const getTextBlockElements = constant(textBlockElementsMap);
3484 const getTextInlineElements = constant(textInlineElementsMap);
3485 const getVoidElements = constant(Object.seal(voidElementsMap));
3486 const getSelfClosingElements = constant(selfClosingElementsMap);
3487 const getNonEmptyElements = constant(nonEmptyElementsMap);
3488 const getMoveCaretBeforeOnEnterElements = constant(moveCaretBeforeOnEnterElementsMap);
3489 const getWhitespaceElements = constant(whitespaceElementsMap);
3490 const getTransparentElements = constant(transparentElementsMap);
3491 const getWrapBlockElements = constant(wrapBlockElementsMap);
3492 const getSpecialElements = constant(Object.seal(specialElements));
3493 const isValidChild = (name, child) => {
3494 const parent = children[name.toLowerCase()];
3495 return !!(parent && parent[child.toLowerCase()]);
3496 };
3497 const isValid = (name, attr) => {
3498 const rule = getElementRule(name);
3499 if (rule) {
3500 if (attr) {
3501 if (rule.attributes[attr]) {
3502 return true;
3503 }
3504 const attrPatterns = rule.attributePatterns;
3505 if (attrPatterns) {
3506 let i = attrPatterns.length;
3507 while (i--) {
3508 if (attrPatterns[i].pattern.test(attr)) {
3509 return true;
3510 }
3511 }
3512 }
3513 } else {
3514 return true;
3515 }
3516 }
3517 return false;
3518 };
3519 const isBlock = name => has$2(getBlockElements(), name);
3520 const isInline = name => !startsWith(name, '#') && isValid(name) && !isBlock(name);
3521 const isWrapper = name => has$2(getWrapBlockElements(), name) || isInline(name);
3522 const getCustomElements = constant(customElementsMap);
3523 setup();
3524 return {
3525 type: schemaType,
3526 children,
3527 elements,
3528 getValidStyles,
3529 getValidClasses,
3530 getBlockElements,
3531 getInvalidStyles,
3532 getVoidElements,
3533 getTextBlockElements,
3534 getTextInlineElements,
3535 getBoolAttrs,
3536 getElementRule,
3537 getSelfClosingElements,
3538 getNonEmptyElements,
3539 getMoveCaretBeforeOnEnterElements,
3540 getWhitespaceElements,
3541 getTransparentElements,
3542 getSpecialElements,
3543 isValidChild,
3544 isValid,
3545 isBlock,
3546 isInline,
3547 isWrapper,
3548 getCustomElements,
3549 addValidElements,
3550 setValidElements,
3551 addCustomElements,
3552 addValidChildren
3553 };
3554 };
3555
3556 const hexColour = value => ({ value: normalizeHex(value) });
3557 const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();
3558 const toHex = component => {
3559 const hex = component.toString(16);
3560 return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
3561 };
3562 const fromRgba = rgbaColour => {
3563 const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
3564 return hexColour(value);
3565 };
3566
3567 const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/i;
3568 const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?(?:\.\d+)?)\s*\)\s*$/i;
3569 const rgbaColour = (red, green, blue, alpha) => ({
3570 red,
3571 green,
3572 blue,
3573 alpha
3574 });
3575 const fromStringValues = (red, green, blue, alpha) => {
3576 const r = parseInt(red, 10);
3577 const g = parseInt(green, 10);
3578 const b = parseInt(blue, 10);
3579 const a = parseFloat(alpha);
3580 return rgbaColour(r, g, b, a);
3581 };
3582 const fromString = rgbaString => {
3583 if (rgbaString === 'transparent') {
3584 return Optional.some(rgbaColour(0, 0, 0, 0));
3585 }
3586 const rgbMatch = rgbRegex.exec(rgbaString);
3587 if (rgbMatch !== null) {
3588 return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
3589 }
3590 const rgbaMatch = rgbaRegex.exec(rgbaString);
3591 if (rgbaMatch !== null) {
3592 return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
3593 }
3594 return Optional.none();
3595 };
3596 const toString = rgba => `rgba(${ rgba.red },${ rgba.green },${ rgba.blue },${ rgba.alpha })`;
3597
3598 const rgbaToHexString = color => fromString(color).map(fromRgba).map(h => '#' + h.value).getOr(color);
3599
3600 const Styles = (settings = {}, schema) => {
3601 const urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi;
3602 const styleRegExp = /\s*([^:]+):\s*([^;]+);?/g;
3603 const trimRightRegExp = /\s+$/;
3604 const rgbaRegExp = /rgba *\(/i;
3605 const encodingLookup = {};
3606 let validStyles;
3607 let invalidStyles;
3608 const invisibleChar = zeroWidth;
3609 if (schema) {
3610 validStyles = schema.getValidStyles();
3611 invalidStyles = schema.getInvalidStyles();
3612 }
3613 const encodingItems = (`\\" \\' \\; \\: ; : ` + invisibleChar).split(' ');
3614 for (let i = 0; i < encodingItems.length; i++) {
3615 encodingLookup[encodingItems[i]] = invisibleChar + i;
3616 encodingLookup[invisibleChar + i] = encodingItems[i];
3617 }
3618 const self = {
3619 parse: css => {
3620 const styles = {};
3621 let isEncoded = false;
3622 const urlConverter = settings.url_converter;
3623 const urlConverterScope = settings.url_converter_scope || self;
3624 const compress = (prefix, suffix, noJoin) => {
3625 const top = styles[prefix + '-top' + suffix];
3626 if (!top) {
3627 return;
3628 }
3629 const right = styles[prefix + '-right' + suffix];
3630 if (!right) {
3631 return;
3632 }
3633 const bottom = styles[prefix + '-bottom' + suffix];
3634 if (!bottom) {
3635 return;
3636 }
3637 const left = styles[prefix + '-left' + suffix];
3638 if (!left) {
3639 return;
3640 }
3641 const box = [
3642 top,
3643 right,
3644 bottom,
3645 left
3646 ];
3647 let i = box.length - 1;
3648 while (i--) {
3649 if (box[i] !== box[i + 1]) {
3650 break;
3651 }
3652 }
3653 if (i > -1 && noJoin) {
3654 return;
3655 }
3656 styles[prefix + suffix] = i === -1 ? box[0] : box.join(' ');
3657 delete styles[prefix + '-top' + suffix];
3658 delete styles[prefix + '-right' + suffix];
3659 delete styles[prefix + '-bottom' + suffix];
3660 delete styles[prefix + '-left' + suffix];
3661 };
3662 const canCompress = key => {
3663 const value = styles[key];
3664 if (!value) {
3665 return;
3666 }
3667 const values = value.indexOf(',') > -1 ? [value] : value.split(' ');
3668 let i = values.length;
3669 while (i--) {
3670 if (values[i] !== values[0]) {
3671 return false;
3672 }
3673 }
3674 styles[key] = values[0];
3675 return true;
3676 };
3677 const compress2 = (target, a, b, c) => {
3678 if (!canCompress(a)) {
3679 return;
3680 }
3681 if (!canCompress(b)) {
3682 return;
3683 }
3684 if (!canCompress(c)) {
3685 return;
3686 }
3687 styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
3688 delete styles[a];
3689 delete styles[b];
3690 delete styles[c];
3691 };
3692 const encode = str => {
3693 isEncoded = true;
3694 return encodingLookup[str];
3695 };
3696 const decode = (str, keepSlashes) => {
3697 if (isEncoded) {
3698 str = str.replace(/\uFEFF[0-9]/g, str => {
3699 return encodingLookup[str];
3700 });
3701 }
3702 if (!keepSlashes) {
3703 str = str.replace(/\\([\'\";:])/g, '$1');
3704 }
3705 return str;
3706 };
3707 const decodeSingleHexSequence = escSeq => {
3708 return String.fromCharCode(parseInt(escSeq.slice(1), 16));
3709 };
3710 const decodeHexSequences = value => {
3711 return value.replace(/\\[0-9a-f]+/gi, decodeSingleHexSequence);
3712 };
3713 const processUrl = (match, url, url2, url3, str, str2) => {
3714 str = str || str2;
3715 if (str) {
3716 str = decode(str);
3717 return `'` + str.replace(/\'/g, `\\'`) + `'`;
3718 }
3719 url = decode(url || url2 || url3 || '');
3720 if (!settings.allow_script_urls) {
3721 const scriptUrl = url.replace(/[\s\r\n]+/g, '');
3722 if (/(java|vb)script:/i.test(scriptUrl)) {
3723 return '';
3724 }
3725 if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
3726 return '';
3727 }
3728 }
3729 if (urlConverter) {
3730 url = urlConverter.call(urlConverterScope, url, 'style');
3731 }
3732 return `url('` + url.replace(/\'/g, `\\'`) + `')`;
3733 };
3734 if (css) {
3735 css = css.replace(/[\u0000-\u001F]/g, '');
3736 css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, str => {
3737 return str.replace(/[;:]/g, encode);
3738 });
3739 let matches;
3740 while (matches = styleRegExp.exec(css)) {
3741 styleRegExp.lastIndex = matches.index + matches[0].length;
3742 let name = matches[1].replace(trimRightRegExp, '').toLowerCase();
3743 let value = matches[2].replace(trimRightRegExp, '');
3744 if (name && value) {
3745 name = decodeHexSequences(name);
3746 value = decodeHexSequences(value);
3747 if (name.indexOf(invisibleChar) !== -1 || name.indexOf('"') !== -1) {
3748 continue;
3749 }
3750 if (!settings.allow_script_urls && (name === 'behavior' || /expression\s*\(|\/\*|\*\//.test(value))) {
3751 continue;
3752 }
3753 if (name === 'font-weight' && value === '700') {
3754 value = 'bold';
3755 } else if (name === 'color' || name === 'background-color') {
3756 value = value.toLowerCase();
3757 }
3758 if (!rgbaRegExp.test(value)) {
3759 fromString(value).each(rgba => {
3760 value = rgbaToHexString(toString(rgba)).toLowerCase();
3761 });
3762 }
3763 value = value.replace(urlOrStrRegExp, processUrl);
3764 styles[name] = isEncoded ? decode(value, true) : value;
3765 }
3766 }
3767 compress('border', '', true);
3768 compress('border', '-width');
3769 compress('border', '-color');
3770 compress('border', '-style');
3771 compress('padding', '');
3772 compress('margin', '');
3773 compress2('border', 'border-width', 'border-style', 'border-color');
3774 if (styles.border === 'medium none') {
3775 delete styles.border;
3776 }
3777 if (styles['border-image'] === 'none') {
3778 delete styles['border-image'];
3779 }
3780 }
3781 return styles;
3782 },
3783 serialize: (styles, elementName) => {
3784 let css = '';
3785 const serializeStyles = (elemName, validStyleList) => {
3786 const styleList = validStyleList[elemName];
3787 if (styleList) {
3788 for (let i = 0, l = styleList.length; i < l; i++) {
3789 const name = styleList[i];
3790 const value = styles[name];
3791 if (value) {
3792 css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
3793 }
3794 }
3795 }
3796 };
3797 const isValid = (name, elemName) => {
3798 if (!invalidStyles || !elemName) {
3799 return true;
3800 }
3801 let styleMap = invalidStyles['*'];
3802 if (styleMap && styleMap[name]) {
3803 return false;
3804 }
3805 styleMap = invalidStyles[elemName];
3806 return !(styleMap && styleMap[name]);
3807 };
3808 if (elementName && validStyles) {
3809 serializeStyles('*', validStyles);
3810 serializeStyles(elementName, validStyles);
3811 } else {
3812 each$d(styles, (value, name) => {
3813 if (value && isValid(name, elementName)) {
3814 css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
3815 }
3816 });
3817 }
3818 return css;
3819 }
3820 };
3821 return self;
3822 };
3823
3824 const deprecated = {
3825 keyLocation: true,
3826 layerX: true,
3827 layerY: true,
3828 returnValue: true,
3829 webkitMovementX: true,
3830 webkitMovementY: true,
3831 keyIdentifier: true,
3832 mozPressure: true
3833 };
3834 const isNativeEvent = event => event instanceof Event || isFunction(event.initEvent);
3835 const hasIsDefaultPrevented = event => event.isDefaultPrevented === always || event.isDefaultPrevented === never;
3836 const needsNormalizing = event => isNullable(event.preventDefault) || isNativeEvent(event);
3837 const clone$3 = (originalEvent, data) => {
3838 const event = data !== null && data !== void 0 ? data : {};
3839 for (const name in originalEvent) {
3840 if (!has$2(deprecated, name)) {
3841 event[name] = originalEvent[name];
3842 }
3843 }
3844 if (isNonNullable(originalEvent.composedPath)) {
3845 event.composedPath = () => originalEvent.composedPath();
3846 }
3847 if (isNonNullable(originalEvent.getModifierState)) {
3848 event.getModifierState = keyArg => originalEvent.getModifierState(keyArg);
3849 }
3850 if (isNonNullable(originalEvent.getTargetRanges)) {
3851 event.getTargetRanges = () => originalEvent.getTargetRanges();
3852 }
3853 return event;
3854 };
3855 const normalize$3 = (type, originalEvent, fallbackTarget, data) => {
3856 var _a;
3857 const event = clone$3(originalEvent, data);
3858 event.type = type;
3859 if (isNullable(event.target)) {
3860 event.target = (_a = event.srcElement) !== null && _a !== void 0 ? _a : fallbackTarget;
3861 }
3862 if (needsNormalizing(originalEvent)) {
3863 event.preventDefault = () => {
3864 event.defaultPrevented = true;
3865 event.isDefaultPrevented = always;
3866 if (isFunction(originalEvent.preventDefault)) {
3867 originalEvent.preventDefault();
3868 }
3869 };
3870 event.stopPropagation = () => {
3871 event.cancelBubble = true;
3872 event.isPropagationStopped = always;
3873 if (isFunction(originalEvent.stopPropagation)) {
3874 originalEvent.stopPropagation();
3875 }
3876 };
3877 event.stopImmediatePropagation = () => {
3878 event.isImmediatePropagationStopped = always;
3879 event.stopPropagation();
3880 };
3881 if (!hasIsDefaultPrevented(event)) {
3882 event.isDefaultPrevented = event.defaultPrevented === true ? always : never;
3883 event.isPropagationStopped = event.cancelBubble === true ? always : never;
3884 event.isImmediatePropagationStopped = never;
3885 }
3886 }
3887 return event;
3888 };
3889
3890 const eventExpandoPrefix = 'mce-data-';
3891 const mouseEventRe = /^(?:mouse|contextmenu)|click/;
3892 const addEvent = (target, name, callback, capture) => {
3893 target.addEventListener(name, callback, capture || false);
3894 };
3895 const removeEvent = (target, name, callback, capture) => {
3896 target.removeEventListener(name, callback, capture || false);
3897 };
3898 const isMouseEvent = event => isNonNullable(event) && mouseEventRe.test(event.type);
3899 const fix = (originalEvent, data) => {
3900 const event = normalize$3(originalEvent.type, originalEvent, document, data);
3901 if (isMouseEvent(originalEvent) && isUndefined(originalEvent.pageX) && !isUndefined(originalEvent.clientX)) {
3902 const eventDoc = event.target.ownerDocument || document;
3903 const doc = eventDoc.documentElement;
3904 const body = eventDoc.body;
3905 const mouseEvent = event;
3906 mouseEvent.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
3907 mouseEvent.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
3908 }
3909 return event;
3910 };
3911 const bindOnReady = (win, callback, eventUtils) => {
3912 const doc = win.document, event = { type: 'ready' };
3913 if (eventUtils.domLoaded) {
3914 callback(event);
3915 return;
3916 }
3917 const isDocReady = () => {
3918 return doc.readyState === 'complete' || doc.readyState === 'interactive' && doc.body;
3919 };
3920 const readyHandler = () => {
3921 removeEvent(win, 'DOMContentLoaded', readyHandler);
3922 removeEvent(win, 'load', readyHandler);
3923 if (!eventUtils.domLoaded) {
3924 eventUtils.domLoaded = true;
3925 callback(event);
3926 }
3927 win = null;
3928 };
3929 if (isDocReady()) {
3930 readyHandler();
3931 } else {
3932 addEvent(win, 'DOMContentLoaded', readyHandler);
3933 }
3934 if (!eventUtils.domLoaded) {
3935 addEvent(win, 'load', readyHandler);
3936 }
3937 };
3938 class EventUtils {
3939 constructor() {
3940 this.domLoaded = false;
3941 this.events = {};
3942 this.count = 1;
3943 this.expando = eventExpandoPrefix + (+new Date()).toString(32);
3944 this.hasFocusIn = 'onfocusin' in document.documentElement;
3945 this.count = 1;
3946 }
3947 bind(target, names, callback, scope) {
3948 const self = this;
3949 let callbackList;
3950 const win = window;
3951 const defaultNativeHandler = evt => {
3952 self.executeHandlers(fix(evt || win.event), id);
3953 };
3954 if (!target || isText$b(target) || isComment(target)) {
3955 return callback;
3956 }
3957 let id;
3958 if (!target[self.expando]) {
3959 id = self.count++;
3960 target[self.expando] = id;
3961 self.events[id] = {};
3962 } else {
3963 id = target[self.expando];
3964 }
3965 scope = scope || target;
3966 const namesList = names.split(' ');
3967 let i = namesList.length;
3968 while (i--) {
3969 let name = namesList[i];
3970 let nativeHandler = defaultNativeHandler;
3971 let capture = false;
3972 let fakeName = false;
3973 if (name === 'DOMContentLoaded') {
3974 name = 'ready';
3975 }
3976 if (self.domLoaded && name === 'ready' && target.readyState === 'complete') {
3977 callback.call(scope, fix({ type: name }));
3978 continue;
3979 }
3980 if (!self.hasFocusIn && (name === 'focusin' || name === 'focusout')) {
3981 capture = true;
3982 fakeName = name === 'focusin' ? 'focus' : 'blur';
3983 nativeHandler = evt => {
3984 const event = fix(evt || win.event);
3985 event.type = event.type === 'focus' ? 'focusin' : 'focusout';
3986 self.executeHandlers(event, id);
3987 };
3988 }
3989 callbackList = self.events[id][name];
3990 if (!callbackList) {
3991 self.events[id][name] = callbackList = [{
3992 func: callback,
3993 scope
3994 }];
3995 callbackList.fakeName = fakeName;
3996 callbackList.capture = capture;
3997 callbackList.nativeHandler = nativeHandler;
3998 if (name === 'ready') {
3999 bindOnReady(target, nativeHandler, self);
4000 } else {
4001 addEvent(target, fakeName || name, nativeHandler, capture);
4002 }
4003 } else {
4004 if (name === 'ready' && self.domLoaded) {
4005 callback(fix({ type: name }));
4006 } else {
4007 callbackList.push({
4008 func: callback,
4009 scope
4010 });
4011 }
4012 }
4013 }
4014 target = callbackList = null;
4015 return callback;
4016 }
4017 unbind(target, names, callback) {
4018 if (!target || isText$b(target) || isComment(target)) {
4019 return this;
4020 }
4021 const id = target[this.expando];
4022 if (id) {
4023 let eventMap = this.events[id];
4024 if (names) {
4025 const namesList = names.split(' ');
4026 let i = namesList.length;
4027 while (i--) {
4028 const name = namesList[i];
4029 const callbackList = eventMap[name];
4030 if (callbackList) {
4031 if (callback) {
4032 let ci = callbackList.length;
4033 while (ci--) {
4034 if (callbackList[ci].func === callback) {
4035 const nativeHandler = callbackList.nativeHandler;
4036 const fakeName = callbackList.fakeName, capture = callbackList.capture;
4037 const newCallbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
4038 newCallbackList.nativeHandler = nativeHandler;
4039 newCallbackList.fakeName = fakeName;
4040 newCallbackList.capture = capture;
4041 eventMap[name] = newCallbackList;
4042 }
4043 }
4044 }
4045 if (!callback || callbackList.length === 0) {
4046 delete eventMap[name];
4047 removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
4048 }
4049 }
4050 }
4051 } else {
4052 each$d(eventMap, (callbackList, name) => {
4053 removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
4054 });
4055 eventMap = {};
4056 }
4057 for (const name in eventMap) {
4058 if (has$2(eventMap, name)) {
4059 return this;
4060 }
4061 }
4062 delete this.events[id];
4063 try {
4064 delete target[this.expando];
4065 } catch (ex) {
4066 target[this.expando] = null;
4067 }
4068 }
4069 return this;
4070 }
4071 fire(target, name, args) {
4072 return this.dispatch(target, name, args);
4073 }
4074 dispatch(target, name, args) {
4075 if (!target || isText$b(target) || isComment(target)) {
4076 return this;
4077 }
4078 const event = fix({
4079 type: name,
4080 target
4081 }, args);
4082 do {
4083 const id = target[this.expando];
4084 if (id) {
4085 this.executeHandlers(event, id);
4086 }
4087 target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow;
4088 } while (target && !event.isPropagationStopped());
4089 return this;
4090 }
4091 clean(target) {
4092 if (!target || isText$b(target) || isComment(target)) {
4093 return this;
4094 }
4095 if (target[this.expando]) {
4096 this.unbind(target);
4097 }
4098 if (!target.getElementsByTagName) {
4099 target = target.document;
4100 }
4101 if (target && target.getElementsByTagName) {
4102 this.unbind(target);
4103 const children = target.getElementsByTagName('*');
4104 let i = children.length;
4105 while (i--) {
4106 target = children[i];
4107 if (target[this.expando]) {
4108 this.unbind(target);
4109 }
4110 }
4111 }
4112 return this;
4113 }
4114 destroy() {
4115 this.events = {};
4116 }
4117 cancel(e) {
4118 if (e) {
4119 e.preventDefault();
4120 e.stopImmediatePropagation();
4121 }
4122 return false;
4123 }
4124 executeHandlers(evt, id) {
4125 const container = this.events[id];
4126 const callbackList = container && container[evt.type];
4127 if (callbackList) {
4128 for (let i = 0, l = callbackList.length; i < l; i++) {
4129 const callback = callbackList[i];
4130 if (callback && callback.func.call(callback.scope, evt) === false) {
4131 evt.preventDefault();
4132 }
4133 if (evt.isImmediatePropagationStopped()) {
4134 return;
4135 }
4136 }
4137 }
4138 }
4139 }
4140 EventUtils.Event = new EventUtils();
4141
4142 const each$a = Tools.each;
4143 const grep = Tools.grep;
4144 const internalStyleName = 'data-mce-style';
4145 const numericalCssMap = Tools.makeMap('fill-opacity font-weight line-height opacity orphans widows z-index zoom', ' ');
4146 const legacySetAttribute = (elm, name, value) => {
4147 if (isNullable(value) || value === '') {
4148 remove$9(elm, name);
4149 } else {
4150 set$3(elm, name, value);
4151 }
4152 };
4153 const camelCaseToHyphens = name => name.replace(/[A-Z]/g, v => '-' + v.toLowerCase());
4154 const findNodeIndex = (node, normalized) => {
4155 let idx = 0;
4156 if (node) {
4157 for (let lastNodeType = node.nodeType, tempNode = node.previousSibling; tempNode; tempNode = tempNode.previousSibling) {
4158 const nodeType = tempNode.nodeType;
4159 if (normalized && isText$b(tempNode)) {
4160 if (nodeType === lastNodeType || !tempNode.data.length) {
4161 continue;
4162 }
4163 }
4164 idx++;
4165 lastNodeType = nodeType;
4166 }
4167 }
4168 return idx;
4169 };
4170 const updateInternalStyleAttr = (styles, elm) => {
4171 const rawValue = get$9(elm, 'style');
4172 const value = styles.serialize(styles.parse(rawValue), name(elm));
4173 legacySetAttribute(elm, internalStyleName, value);
4174 };
4175 const convertStyleToString = (cssValue, cssName) => {
4176 if (isNumber(cssValue)) {
4177 return has$2(numericalCssMap, cssName) ? cssValue + '' : cssValue + 'px';
4178 } else {
4179 return cssValue;
4180 }
4181 };
4182 const applyStyle$1 = ($elm, cssName, cssValue) => {
4183 const normalizedName = camelCaseToHyphens(cssName);
4184 if (isNullable(cssValue) || cssValue === '') {
4185 remove$5($elm, normalizedName);
4186 } else {
4187 set$2($elm, normalizedName, convertStyleToString(cssValue, normalizedName));
4188 }
4189 };
4190 const setupAttrHooks = (styles, settings, getContext) => {
4191 const keepValues = settings.keep_values;
4192 const keepUrlHook = {
4193 set: (elm, value, name) => {
4194 const sugarElm = SugarElement.fromDom(elm);
4195 if (isFunction(settings.url_converter) && isNonNullable(value)) {
4196 value = settings.url_converter.call(settings.url_converter_scope || getContext(), String(value), name, elm);
4197 }
4198 const internalName = 'data-mce-' + name;
4199 legacySetAttribute(sugarElm, internalName, value);
4200 legacySetAttribute(sugarElm, name, value);
4201 },
4202 get: (elm, name) => {
4203 const sugarElm = SugarElement.fromDom(elm);
4204 return get$9(sugarElm, 'data-mce-' + name) || get$9(sugarElm, name);
4205 }
4206 };
4207 const attrHooks = {
4208 style: {
4209 set: (elm, value) => {
4210 const sugarElm = SugarElement.fromDom(elm);
4211 if (keepValues) {
4212 legacySetAttribute(sugarElm, internalStyleName, value);
4213 }
4214 remove$9(sugarElm, 'style');
4215 if (isString(value)) {
4216 setAll(sugarElm, styles.parse(value));
4217 }
4218 },
4219 get: elm => {
4220 const sugarElm = SugarElement.fromDom(elm);
4221 const value = get$9(sugarElm, internalStyleName) || get$9(sugarElm, 'style');
4222 return styles.serialize(styles.parse(value), name(sugarElm));
4223 }
4224 }
4225 };
4226 if (keepValues) {
4227 attrHooks.href = attrHooks.src = keepUrlHook;
4228 }
4229 return attrHooks;
4230 };
4231 const DOMUtils = (doc, settings = {}) => {
4232 const addedStyles = {};
4233 const win = window;
4234 const files = {};
4235 let counter = 0;
4236 const stdMode = true;
4237 const boxModel = true;
4238 const styleSheetLoader = instance.forElement(SugarElement.fromDom(doc), {
4239 contentCssCors: settings.contentCssCors,
4240 referrerPolicy: settings.referrerPolicy
4241 });
4242 const boundEvents = [];
4243 const schema = settings.schema ? settings.schema : Schema({});
4244 const styles = Styles({
4245 url_converter: settings.url_converter,
4246 url_converter_scope: settings.url_converter_scope
4247 }, settings.schema);
4248 const events = settings.ownEvents ? new EventUtils() : EventUtils.Event;
4249 const blockElementsMap = schema.getBlockElements();
4250 const isBlock = node => {
4251 if (isString(node)) {
4252 return has$2(blockElementsMap, node);
4253 } else {
4254 return isElement$6(node) && (has$2(blockElementsMap, node.nodeName) || isTransparentBlock(schema, node));
4255 }
4256 };
4257 const get = elm => elm && doc && isString(elm) ? doc.getElementById(elm) : elm;
4258 const _get = elm => {
4259 const value = get(elm);
4260 return isNonNullable(value) ? SugarElement.fromDom(value) : null;
4261 };
4262 const getAttrib = (elm, name, defaultVal = '') => {
4263 let value;
4264 const $elm = _get(elm);
4265 if (isNonNullable($elm) && isElement$7($elm)) {
4266 const hook = attrHooks[name];
4267 if (hook && hook.get) {
4268 value = hook.get($elm.dom, name);
4269 } else {
4270 value = get$9($elm, name);
4271 }
4272 }
4273 return isNonNullable(value) ? value : defaultVal;
4274 };
4275 const getAttribs = elm => {
4276 const node = get(elm);
4277 return isNullable(node) ? [] : node.attributes;
4278 };
4279 const setAttrib = (elm, name, value) => {
4280 run(elm, e => {
4281 if (isElement$6(e)) {
4282 const $elm = SugarElement.fromDom(e);
4283 const val = value === '' ? null : value;
4284 const originalValue = get$9($elm, name);
4285 const hook = attrHooks[name];
4286 if (hook && hook.set) {
4287 hook.set($elm.dom, val, name);
4288 } else {
4289 legacySetAttribute($elm, name, val);
4290 }
4291 if (originalValue !== val && settings.onSetAttrib) {
4292 settings.onSetAttrib({
4293 attrElm: $elm.dom,
4294 attrName: name,
4295 attrValue: val
4296 });
4297 }
4298 }
4299 });
4300 };
4301 const clone = (node, deep) => {
4302 return node.cloneNode(deep);
4303 };
4304 const getRoot = () => settings.root_element || doc.body;
4305 const getViewPort = argWin => {
4306 const vp = getBounds(argWin);
4307 return {
4308 x: vp.x,
4309 y: vp.y,
4310 w: vp.width,
4311 h: vp.height
4312 };
4313 };
4314 const getPos$1 = (elm, rootElm) => getPos(doc.body, get(elm), rootElm);
4315 const setStyle = (elm, name, value) => {
4316 run(elm, e => {
4317 const $elm = SugarElement.fromDom(e);
4318 applyStyle$1($elm, name, value);
4319 if (settings.update_styles) {
4320 updateInternalStyleAttr(styles, $elm);
4321 }
4322 });
4323 };
4324 const setStyles = (elm, stylesArg) => {
4325 run(elm, e => {
4326 const $elm = SugarElement.fromDom(e);
4327 each$d(stylesArg, (v, n) => {
4328 applyStyle$1($elm, n, v);
4329 });
4330 if (settings.update_styles) {
4331 updateInternalStyleAttr(styles, $elm);
4332 }
4333 });
4334 };
4335 const getStyle = (elm, name, computed) => {
4336 const $elm = get(elm);
4337 if (isNullable($elm) || !isHTMLElement($elm) && !isSVGElement($elm)) {
4338 return undefined;
4339 }
4340 if (computed) {
4341 return get$7(SugarElement.fromDom($elm), camelCaseToHyphens(name));
4342 } else {
4343 name = name.replace(/-(\D)/g, (a, b) => b.toUpperCase());
4344 if (name === 'float') {
4345 name = 'cssFloat';
4346 }
4347 return $elm.style ? $elm.style[name] : undefined;
4348 }
4349 };
4350 const getSize = elm => {
4351 const $elm = get(elm);
4352 if (!$elm) {
4353 return {
4354 w: 0,
4355 h: 0
4356 };
4357 }
4358 let w = getStyle($elm, 'width');
4359 let h = getStyle($elm, 'height');
4360 if (!w || w.indexOf('px') === -1) {
4361 w = '0';
4362 }
4363 if (!h || h.indexOf('px') === -1) {
4364 h = '0';
4365 }
4366 return {
4367 w: parseInt(w, 10) || $elm.offsetWidth || $elm.clientWidth,
4368 h: parseInt(h, 10) || $elm.offsetHeight || $elm.clientHeight
4369 };
4370 };
4371 const getRect = elm => {
4372 const $elm = get(elm);
4373 const pos = getPos$1($elm);
4374 const size = getSize($elm);
4375 return {
4376 x: pos.x,
4377 y: pos.y,
4378 w: size.w,
4379 h: size.h
4380 };
4381 };
4382 const is = (elm, selector) => {
4383 if (!elm) {
4384 return false;
4385 }
4386 const elms = isArray$1(elm) ? elm : [elm];
4387 return exists(elms, e => {
4388 return is$1(SugarElement.fromDom(e), selector);
4389 });
4390 };
4391 const getParents = (elm, selector, root, collect) => {
4392 const result = [];
4393 let node = get(elm);
4394 collect = collect === undefined;
4395 const resolvedRoot = root || (getRoot().nodeName !== 'BODY' ? getRoot().parentNode : null);
4396 if (isString(selector)) {
4397 if (selector === '*') {
4398 selector = isElement$6;
4399 } else {
4400 const selectorVal = selector;
4401 selector = node => is(node, selectorVal);
4402 }
4403 }
4404 while (node) {
4405 if (node === resolvedRoot || isNullable(node.nodeType) || isDocument$1(node) || isDocumentFragment(node)) {
4406 break;
4407 }
4408 if (!selector || selector(node)) {
4409 if (collect) {
4410 result.push(node);
4411 } else {
4412 return [node];
4413 }
4414 }
4415 node = node.parentNode;
4416 }
4417 return collect ? result : null;
4418 };
4419 const getParent = (node, selector, root) => {
4420 const parents = getParents(node, selector, root, false);
4421 return parents && parents.length > 0 ? parents[0] : null;
4422 };
4423 const _findSib = (node, selector, name) => {
4424 let func = selector;
4425 if (node) {
4426 if (isString(selector)) {
4427 func = node => {
4428 return is(node, selector);
4429 };
4430 }
4431 for (let tempNode = node[name]; tempNode; tempNode = tempNode[name]) {
4432 if (isFunction(func) && func(tempNode)) {
4433 return tempNode;
4434 }
4435 }
4436 }
4437 return null;
4438 };
4439 const getNext = (node, selector) => _findSib(node, selector, 'nextSibling');
4440 const getPrev = (node, selector) => _findSib(node, selector, 'previousSibling');
4441 const isParentNode = node => isFunction(node.querySelectorAll);
4442 const select = (selector, scope) => {
4443 var _a, _b;
4444 const elm = (_b = (_a = get(scope)) !== null && _a !== void 0 ? _a : settings.root_element) !== null && _b !== void 0 ? _b : doc;
4445 return isParentNode(elm) ? from(elm.querySelectorAll(selector)) : [];
4446 };
4447 const run = function (elm, func, scope) {
4448 const context = scope !== null && scope !== void 0 ? scope : this;
4449 if (isArray$1(elm)) {
4450 const result = [];
4451 each$a(elm, (e, i) => {
4452 const node = get(e);
4453 if (node) {
4454 result.push(func.call(context, node, i));
4455 }
4456 });
4457 return result;
4458 } else {
4459 const node = get(elm);
4460 return !node ? false : func.call(context, node);
4461 }
4462 };
4463 const setAttribs = (elm, attrs) => {
4464 run(elm, $elm => {
4465 each$d(attrs, (value, name) => {
4466 setAttrib($elm, name, value);
4467 });
4468 });
4469 };
4470 const setHTML = (elm, html) => {
4471 run(elm, e => {
4472 const $elm = SugarElement.fromDom(e);
4473 set$1($elm, html);
4474 });
4475 };
4476 const add = (parentElm, name, attrs, html, create) => run(parentElm, parentElm => {
4477 const newElm = isString(name) ? doc.createElement(name) : name;
4478 if (isNonNullable(attrs)) {
4479 setAttribs(newElm, attrs);
4480 }
4481 if (html) {
4482 if (!isString(html) && html.nodeType) {
4483 newElm.appendChild(html);
4484 } else if (isString(html)) {
4485 setHTML(newElm, html);
4486 }
4487 }
4488 return !create ? parentElm.appendChild(newElm) : newElm;
4489 });
4490 const create = (name, attrs, html) => add(doc.createElement(name), name, attrs, html, true);
4491 const decode = Entities.decode;
4492 const encode = Entities.encodeAllRaw;
4493 const createHTML = (name, attrs, html = '') => {
4494 let outHtml = '<' + name;
4495 for (const key in attrs) {
4496 if (hasNonNullableKey(attrs, key)) {
4497 outHtml += ' ' + key + '="' + encode(attrs[key]) + '"';
4498 }
4499 }
4500 if (isEmpty$3(html) && has$2(schema.getVoidElements(), name)) {
4501 return outHtml + ' />';
4502 } else {
4503 return outHtml + '>' + html + '</' + name + '>';
4504 }
4505 };
4506 const createFragment = html => {
4507 const container = doc.createElement('div');
4508 const frag = doc.createDocumentFragment();
4509 frag.appendChild(container);
4510 if (html) {
4511 container.innerHTML = html;
4512 }
4513 let node;
4514 while (node = container.firstChild) {
4515 frag.appendChild(node);
4516 }
4517 frag.removeChild(container);
4518 return frag;
4519 };
4520 const remove = (node, keepChildren) => {
4521 return run(node, n => {
4522 const $node = SugarElement.fromDom(n);
4523 if (keepChildren) {
4524 each$e(children$1($node), child => {
4525 if (isText$c(child) && child.dom.length === 0) {
4526 remove$4(child);
4527 } else {
4528 before$3($node, child);
4529 }
4530 });
4531 }
4532 remove$4($node);
4533 return $node.dom;
4534 });
4535 };
4536 const removeAllAttribs = e => run(e, e => {
4537 const attrs = e.attributes;
4538 for (let i = attrs.length - 1; i >= 0; i--) {
4539 e.removeAttributeNode(attrs.item(i));
4540 }
4541 });
4542 const parseStyle = cssText => styles.parse(cssText);
4543 const serializeStyle = (stylesArg, name) => styles.serialize(stylesArg, name);
4544 const addStyle = cssText => {
4545 if (self !== DOMUtils.DOM && doc === document) {
4546 if (addedStyles[cssText]) {
4547 return;
4548 }
4549 addedStyles[cssText] = true;
4550 }
4551 let styleElm = doc.getElementById('mceDefaultStyles');
4552 if (!styleElm) {
4553 styleElm = doc.createElement('style');
4554 styleElm.id = 'mceDefaultStyles';
4555 styleElm.type = 'text/css';
4556 const head = doc.head;
4557 if (head.firstChild) {
4558 head.insertBefore(styleElm, head.firstChild);
4559 } else {
4560 head.appendChild(styleElm);
4561 }
4562 }
4563 if (styleElm.styleSheet) {
4564 styleElm.styleSheet.cssText += cssText;
4565 } else {
4566 styleElm.appendChild(doc.createTextNode(cssText));
4567 }
4568 };
4569 const loadCSS = urls => {
4570 if (!urls) {
4571 urls = '';
4572 }
4573 each$e(urls.split(','), url => {
4574 files[url] = true;
4575 styleSheetLoader.load(url).catch(noop);
4576 });
4577 };
4578 const toggleClass = (elm, cls, state) => {
4579 run(elm, e => {
4580 if (isElement$6(e)) {
4581 const $elm = SugarElement.fromDom(e);
4582 const classes = cls.split(' ');
4583 each$e(classes, c => {
4584 if (isNonNullable(state)) {
4585 const fn = state ? add$2 : remove$6;
4586 fn($elm, c);
4587 } else {
4588 toggle$1($elm, c);
4589 }
4590 });
4591 }
4592 });
4593 };
4594 const addClass = (elm, cls) => {
4595 toggleClass(elm, cls, true);
4596 };
4597 const removeClass = (elm, cls) => {
4598 toggleClass(elm, cls, false);
4599 };
4600 const hasClass = (elm, cls) => {
4601 const $elm = _get(elm);
4602 const classes = cls.split(' ');
4603 return isNonNullable($elm) && forall(classes, c => has($elm, c));
4604 };
4605 const show = elm => {
4606 run(elm, e => remove$5(SugarElement.fromDom(e), 'display'));
4607 };
4608 const hide = elm => {
4609 run(elm, e => set$2(SugarElement.fromDom(e), 'display', 'none'));
4610 };
4611 const isHidden = elm => {
4612 const $elm = _get(elm);
4613 return isNonNullable($elm) && is$2(getRaw($elm, 'display'), 'none');
4614 };
4615 const uniqueId = prefix => (!prefix ? 'mce_' : prefix) + counter++;
4616 const getOuterHTML = elm => {
4617 const $elm = _get(elm);
4618 if (isNonNullable($elm)) {
4619 return isElement$6($elm.dom) ? $elm.dom.outerHTML : getOuter($elm);
4620 } else {
4621 return '';
4622 }
4623 };
4624 const setOuterHTML = (elm, html) => {
4625 run(elm, $elm => {
4626 if (isElement$6($elm)) {
4627 $elm.outerHTML = html;
4628 }
4629 });
4630 };
4631 const insertAfter = (node, reference) => {
4632 const referenceNode = get(reference);
4633 return run(node, node => {
4634 const parent = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.parentNode;
4635 const nextSibling = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.nextSibling;
4636 if (parent) {
4637 if (nextSibling) {
4638 parent.insertBefore(node, nextSibling);
4639 } else {
4640 parent.appendChild(node);
4641 }
4642 }
4643 return node;
4644 });
4645 };
4646 const replace = (newElm, oldElm, keepChildren) => run(oldElm, elm => {
4647 var _a;
4648 const replacee = isArray$1(oldElm) ? newElm.cloneNode(true) : newElm;
4649 if (keepChildren) {
4650 each$a(grep(elm.childNodes), node => {
4651 replacee.appendChild(node);
4652 });
4653 }
4654 (_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(replacee, elm);
4655 return elm;
4656 });
4657 const rename = (elm, name) => {
4658 if (elm.nodeName !== name.toUpperCase()) {
4659 const newElm = create(name);
4660 each$a(getAttribs(elm), attrNode => {
4661 setAttrib(newElm, attrNode.nodeName, getAttrib(elm, attrNode.nodeName));
4662 });
4663 replace(newElm, elm, true);
4664 return newElm;
4665 } else {
4666 return elm;
4667 }
4668 };
4669 const findCommonAncestor = (a, b) => {
4670 let ps = a;
4671 while (ps) {
4672 let pe = b;
4673 while (pe && ps !== pe) {
4674 pe = pe.parentNode;
4675 }
4676 if (ps === pe) {
4677 break;
4678 }
4679 ps = ps.parentNode;
4680 }
4681 if (!ps && a.ownerDocument) {
4682 return a.ownerDocument.documentElement;
4683 } else {
4684 return ps;
4685 }
4686 };
4687 const isEmpty = (node, elements, options) => {
4688 if (isPlainObject(elements)) {
4689 const isContent = node => {
4690 const name = node.nodeName.toLowerCase();
4691 return Boolean(elements[name]);
4692 };
4693 return isEmptyNode(schema, node, {
4694 ...options,
4695 isContent
4696 });
4697 } else {
4698 return isEmptyNode(schema, node, options);
4699 }
4700 };
4701 const createRng = () => doc.createRange();
4702 const split = (parentElm, splitElm, replacementElm) => {
4703 let range = createRng();
4704 let beforeFragment;
4705 let afterFragment;
4706 if (parentElm && splitElm && parentElm.parentNode && splitElm.parentNode) {
4707 const parentNode = parentElm.parentNode;
4708 range.setStart(parentNode, findNodeIndex(parentElm));
4709 range.setEnd(splitElm.parentNode, findNodeIndex(splitElm));
4710 beforeFragment = range.extractContents();
4711 range = createRng();
4712 range.setStart(splitElm.parentNode, findNodeIndex(splitElm) + 1);
4713 range.setEnd(parentNode, findNodeIndex(parentElm) + 1);
4714 afterFragment = range.extractContents();
4715 parentNode.insertBefore(trimNode(self, beforeFragment, schema), parentElm);
4716 if (replacementElm) {
4717 parentNode.insertBefore(replacementElm, parentElm);
4718 } else {
4719 parentNode.insertBefore(splitElm, parentElm);
4720 }
4721 parentNode.insertBefore(trimNode(self, afterFragment, schema), parentElm);
4722 remove(parentElm);
4723 return replacementElm || splitElm;
4724 } else {
4725 return undefined;
4726 }
4727 };
4728 const bind = (target, name, func, scope) => {
4729 if (isArray$1(target)) {
4730 let i = target.length;
4731 const rv = [];
4732 while (i--) {
4733 rv[i] = bind(target[i], name, func, scope);
4734 }
4735 return rv;
4736 } else {
4737 if (settings.collect && (target === doc || target === win)) {
4738 boundEvents.push([
4739 target,
4740 name,
4741 func,
4742 scope
4743 ]);
4744 }
4745 return events.bind(target, name, func, scope || self);
4746 }
4747 };
4748 const unbind = (target, name, func) => {
4749 if (isArray$1(target)) {
4750 let i = target.length;
4751 const rv = [];
4752 while (i--) {
4753 rv[i] = unbind(target[i], name, func);
4754 }
4755 return rv;
4756 } else {
4757 if (boundEvents.length > 0 && (target === doc || target === win)) {
4758 let i = boundEvents.length;
4759 while (i--) {
4760 const [boundTarget, boundName, boundFunc] = boundEvents[i];
4761 if (target === boundTarget && (!name || name === boundName) && (!func || func === boundFunc)) {
4762 events.unbind(boundTarget, boundName, boundFunc);
4763 }
4764 }
4765 }
4766 return events.unbind(target, name, func);
4767 }
4768 };
4769 const dispatch = (target, name, evt) => events.dispatch(target, name, evt);
4770 const fire = (target, name, evt) => events.dispatch(target, name, evt);
4771 const getContentEditable = node => {
4772 if (node && isHTMLElement(node)) {
4773 const contentEditable = node.getAttribute('data-mce-contenteditable');
4774 if (contentEditable && contentEditable !== 'inherit') {
4775 return contentEditable;
4776 }
4777 return node.contentEditable !== 'inherit' ? node.contentEditable : null;
4778 } else {
4779 return null;
4780 }
4781 };
4782 const getContentEditableParent = node => {
4783 const root = getRoot();
4784 let state = null;
4785 for (let tempNode = node; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
4786 state = getContentEditable(tempNode);
4787 if (state !== null) {
4788 break;
4789 }
4790 }
4791 return state;
4792 };
4793 const isEditable = node => {
4794 if (isNonNullable(node)) {
4795 const scope = isElement$6(node) ? node : node.parentElement;
4796 return isNonNullable(scope) && isHTMLElement(scope) && isEditable$2(SugarElement.fromDom(scope));
4797 } else {
4798 return false;
4799 }
4800 };
4801 const destroy = () => {
4802 if (boundEvents.length > 0) {
4803 let i = boundEvents.length;
4804 while (i--) {
4805 const [boundTarget, boundName, boundFunc] = boundEvents[i];
4806 events.unbind(boundTarget, boundName, boundFunc);
4807 }
4808 }
4809 each$d(files, (_, url) => {
4810 styleSheetLoader.unload(url);
4811 delete files[url];
4812 });
4813 };
4814 const isChildOf = (node, parent) => {
4815 return node === parent || parent.contains(node);
4816 };
4817 const dumpRng = r => 'startContainer: ' + r.startContainer.nodeName + ', startOffset: ' + r.startOffset + ', endContainer: ' + r.endContainer.nodeName + ', endOffset: ' + r.endOffset;
4818 const self = {
4819 doc,
4820 settings,
4821 win,
4822 files,
4823 stdMode,
4824 boxModel,
4825 styleSheetLoader,
4826 boundEvents,
4827 styles,
4828 schema,
4829 events,
4830 isBlock: isBlock,
4831 root: null,
4832 clone,
4833 getRoot,
4834 getViewPort,
4835 getRect,
4836 getSize,
4837 getParent,
4838 getParents: getParents,
4839 get,
4840 getNext,
4841 getPrev,
4842 select,
4843 is,
4844 add,
4845 create,
4846 createHTML,
4847 createFragment,
4848 remove,
4849 setStyle,
4850 getStyle: getStyle,
4851 setStyles,
4852 removeAllAttribs,
4853 setAttrib,
4854 setAttribs,
4855 getAttrib,
4856 getPos: getPos$1,
4857 parseStyle,
4858 serializeStyle,
4859 addStyle,
4860 loadCSS,
4861 addClass,
4862 removeClass,
4863 hasClass,
4864 toggleClass,
4865 show,
4866 hide,
4867 isHidden,
4868 uniqueId,
4869 setHTML,
4870 getOuterHTML,
4871 setOuterHTML,
4872 decode,
4873 encode,
4874 insertAfter,
4875 replace,
4876 rename,
4877 findCommonAncestor,
4878 run,
4879 getAttribs,
4880 isEmpty,
4881 createRng,
4882 nodeIndex: findNodeIndex,
4883 split,
4884 bind: bind,
4885 unbind: unbind,
4886 fire,
4887 dispatch,
4888 getContentEditable,
4889 getContentEditableParent,
4890 isEditable,
4891 destroy,
4892 isChildOf,
4893 dumpRng
4894 };
4895 const attrHooks = setupAttrHooks(styles, settings, constant(self));
4896 return self;
4897 };
4898 DOMUtils.DOM = DOMUtils(document);
4899 DOMUtils.nodeIndex = findNodeIndex;
4900
4901 const DOM$b = DOMUtils.DOM;
4902 const QUEUED = 0;
4903 const LOADING = 1;
4904 const LOADED = 2;
4905 const FAILED = 3;
4906 class ScriptLoader {
4907 constructor(settings = {}) {
4908 this.states = {};
4909 this.queue = [];
4910 this.scriptLoadedCallbacks = {};
4911 this.queueLoadedCallbacks = [];
4912 this.loading = false;
4913 this.settings = settings;
4914 }
4915 _setReferrerPolicy(referrerPolicy) {
4916 this.settings.referrerPolicy = referrerPolicy;
4917 }
4918 loadScript(url) {
4919 return new Promise((resolve, reject) => {
4920 const dom = DOM$b;
4921 let elm;
4922 const cleanup = () => {
4923 dom.remove(id);
4924 if (elm) {
4925 elm.onerror = elm.onload = elm = null;
4926 }
4927 };
4928 const done = () => {
4929 cleanup();
4930 resolve();
4931 };
4932 const error = () => {
4933 cleanup();
4934 reject('Failed to load script: ' + url);
4935 };
4936 const id = dom.uniqueId();
4937 elm = document.createElement('script');
4938 elm.id = id;
4939 elm.type = 'text/javascript';
4940 elm.src = Tools._addCacheSuffix(url);
4941 if (this.settings.referrerPolicy) {
4942 dom.setAttrib(elm, 'referrerpolicy', this.settings.referrerPolicy);
4943 }
4944 elm.onload = done;
4945 elm.onerror = error;
4946 (document.getElementsByTagName('head')[0] || document.body).appendChild(elm);
4947 });
4948 }
4949 isDone(url) {
4950 return this.states[url] === LOADED;
4951 }
4952 markDone(url) {
4953 this.states[url] = LOADED;
4954 }
4955 add(url) {
4956 const self = this;
4957 self.queue.push(url);
4958 const state = self.states[url];
4959 if (state === undefined) {
4960 self.states[url] = QUEUED;
4961 }
4962 return new Promise((resolve, reject) => {
4963 if (!self.scriptLoadedCallbacks[url]) {
4964 self.scriptLoadedCallbacks[url] = [];
4965 }
4966 self.scriptLoadedCallbacks[url].push({
4967 resolve,
4968 reject
4969 });
4970 });
4971 }
4972 load(url) {
4973 return this.add(url);
4974 }
4975 remove(url) {
4976 delete this.states[url];
4977 delete this.scriptLoadedCallbacks[url];
4978 }
4979 loadQueue() {
4980 const queue = this.queue;
4981 this.queue = [];
4982 return this.loadScripts(queue);
4983 }
4984 loadScripts(scripts) {
4985 const self = this;
4986 const execCallbacks = (name, url) => {
4987 get$a(self.scriptLoadedCallbacks, url).each(callbacks => {
4988 each$e(callbacks, callback => callback[name](url));
4989 });
4990 delete self.scriptLoadedCallbacks[url];
4991 };
4992 const processResults = results => {
4993 const failures = filter$5(results, result => result.status === 'rejected');
4994 if (failures.length > 0) {
4995 return Promise.reject(bind$3(failures, ({reason}) => isArray$1(reason) ? reason : [reason]));
4996 } else {
4997 return Promise.resolve();
4998 }
4999 };
5000 const load = urls => Promise.allSettled(map$3(urls, url => {
5001 if (self.states[url] === LOADED) {
5002 execCallbacks('resolve', url);
5003 return Promise.resolve();
5004 } else if (self.states[url] === FAILED) {
5005 execCallbacks('reject', url);
5006 return Promise.reject(url);
5007 } else {
5008 self.states[url] = LOADING;
5009 return self.loadScript(url).then(() => {
5010 self.states[url] = LOADED;
5011 execCallbacks('resolve', url);
5012 const queue = self.queue;
5013 if (queue.length > 0) {
5014 self.queue = [];
5015 return load(queue).then(processResults);
5016 } else {
5017 return Promise.resolve();
5018 }
5019 }, () => {
5020 self.states[url] = FAILED;
5021 execCallbacks('reject', url);
5022 return Promise.reject(url);
5023 });
5024 }
5025 }));
5026 const processQueue = urls => {
5027 self.loading = true;
5028 return load(urls).then(results => {
5029 self.loading = false;
5030 const nextQueuedItem = self.queueLoadedCallbacks.shift();
5031 Optional.from(nextQueuedItem).each(call);
5032 return processResults(results);
5033 });
5034 };
5035 const uniqueScripts = stringArray(scripts);
5036 if (self.loading) {
5037 return new Promise((resolve, reject) => {
5038 self.queueLoadedCallbacks.push(() => {
5039 processQueue(uniqueScripts).then(resolve, reject);
5040 });
5041 });
5042 } else {
5043 return processQueue(uniqueScripts);
5044 }
5045 }
5046 }
5047 ScriptLoader.ScriptLoader = new ScriptLoader();
5048
5049 const isDuplicated = (items, item) => {
5050 const firstIndex = items.indexOf(item);
5051 return firstIndex !== -1 && items.indexOf(item, firstIndex + 1) > firstIndex;
5052 };
5053 const isRaw = str => isObject(str) && has$2(str, 'raw');
5054 const isTokenised = str => isArray$1(str) && str.length > 1;
5055 const data = {};
5056 const currentCode = Cell('en');
5057 const getLanguageData = () => get$a(data, currentCode.get());
5058 const getData$1 = () => map$2(data, value => ({ ...value }));
5059 const setCode = newCode => {
5060 if (newCode) {
5061 currentCode.set(newCode);
5062 }
5063 };
5064 const getCode = () => currentCode.get();
5065 const add$1 = (code, items) => {
5066 let langData = data[code];
5067 if (!langData) {
5068 data[code] = langData = {};
5069 }
5070 const lcNames = map$3(keys(items), name => name.toLowerCase());
5071 each$d(items, (translation, name) => {
5072 const lcName = name.toLowerCase();
5073 if (lcName !== name && isDuplicated(lcNames, lcName)) {
5074 if (!has$2(items, lcName)) {
5075 langData[lcName] = translation;
5076 }
5077 langData[name] = translation;
5078 } else {
5079 langData[lcName] = translation;
5080 }
5081 });
5082 };
5083 const translate = text => {
5084 const langData = getLanguageData().getOr({});
5085 const toString = obj => {
5086 if (isFunction(obj)) {
5087 return Object.prototype.toString.call(obj);
5088 }
5089 return !isEmpty(obj) ? '' + obj : '';
5090 };
5091 const isEmpty = text => text === '' || text === null || text === undefined;
5092 const getLangData = text => {
5093 const textStr = toString(text);
5094 return has$2(langData, textStr) ? toString(langData[textStr]) : get$a(langData, textStr.toLowerCase()).map(toString).getOr(textStr);
5095 };
5096 const removeContext = str => str.replace(/{context:\w+}$/, '');
5097 if (isEmpty(text)) {
5098 return '';
5099 }
5100 if (isRaw(text)) {
5101 return toString(text.raw);
5102 }
5103 if (isTokenised(text)) {
5104 const values = text.slice(1);
5105 const substitued = getLangData(text[0]).replace(/\{([0-9]+)\}/g, ($1, $2) => has$2(values, $2) ? toString(values[$2]) : $1);
5106 return removeContext(substitued);
5107 }
5108 return removeContext(getLangData(text));
5109 };
5110 const isRtl$1 = () => getLanguageData().bind(items => get$a(items, '_dir')).exists(dir => dir === 'rtl');
5111 const hasCode = code => has$2(data, code);
5112 const I18n = {
5113 getData: getData$1,
5114 setCode,
5115 getCode,
5116 add: add$1,
5117 translate,
5118 isRtl: isRtl$1,
5119 hasCode
5120 };
5121
5122 const AddOnManager = () => {
5123 const items = [];
5124 const urls = {};
5125 const lookup = {};
5126 const _listeners = [];
5127 const runListeners = (name, state) => {
5128 const matchedListeners = filter$5(_listeners, listener => listener.name === name && listener.state === state);
5129 each$e(matchedListeners, listener => listener.resolve());
5130 };
5131 const isLoaded = name => has$2(urls, name);
5132 const isAdded = name => has$2(lookup, name);
5133 const get = name => {
5134 if (lookup[name]) {
5135 return lookup[name].instance;
5136 }
5137 return undefined;
5138 };
5139 const loadLanguagePack = (name, languages) => {
5140 const language = I18n.getCode();
5141 const wrappedLanguages = ',' + (languages || '') + ',';
5142 if (!language || languages && wrappedLanguages.indexOf(',' + language + ',') === -1) {
5143 return;
5144 }
5145 ScriptLoader.ScriptLoader.add(urls[name] + '/langs/' + language + '.js');
5146 };
5147 const requireLangPack = (name, languages) => {
5148 if (AddOnManager.languageLoad !== false) {
5149 if (isLoaded(name)) {
5150 loadLanguagePack(name, languages);
5151 } else {
5152 waitFor(name, 'loaded').then(() => loadLanguagePack(name, languages));
5153 }
5154 }
5155 };
5156 const add = (id, addOn) => {
5157 items.push(addOn);
5158 lookup[id] = { instance: addOn };
5159 runListeners(id, 'added');
5160 return addOn;
5161 };
5162 const remove = name => {
5163 delete urls[name];
5164 delete lookup[name];
5165 };
5166 const createUrl = (baseUrl, dep) => {
5167 if (isString(dep)) {
5168 return isString(baseUrl) ? {
5169 prefix: '',
5170 resource: dep,
5171 suffix: ''
5172 } : {
5173 prefix: baseUrl.prefix,
5174 resource: dep,
5175 suffix: baseUrl.suffix
5176 };
5177 } else {
5178 return dep;
5179 }
5180 };
5181 const load = (name, addOnUrl) => {
5182 if (urls[name]) {
5183 return Promise.resolve();
5184 }
5185 let urlString = isString(addOnUrl) ? addOnUrl : addOnUrl.prefix + addOnUrl.resource + addOnUrl.suffix;
5186 if (urlString.indexOf('/') !== 0 && urlString.indexOf('://') === -1) {
5187 urlString = AddOnManager.baseURL + '/' + urlString;
5188 }
5189 urls[name] = urlString.substring(0, urlString.lastIndexOf('/'));
5190 const done = () => {
5191 runListeners(name, 'loaded');
5192 return Promise.resolve();
5193 };
5194 if (lookup[name]) {
5195 return done();
5196 } else {
5197 return ScriptLoader.ScriptLoader.add(urlString).then(done);
5198 }
5199 };
5200 const waitFor = (name, state = 'added') => {
5201 if (state === 'added' && isAdded(name)) {
5202 return Promise.resolve();
5203 } else if (state === 'loaded' && isLoaded(name)) {
5204 return Promise.resolve();
5205 } else {
5206 return new Promise(resolve => {
5207 _listeners.push({
5208 name,
5209 state,
5210 resolve
5211 });
5212 });
5213 }
5214 };
5215 return {
5216 items,
5217 urls,
5218 lookup,
5219 get,
5220 requireLangPack,
5221 add,
5222 remove,
5223 createUrl,
5224 load,
5225 waitFor
5226 };
5227 };
5228 AddOnManager.languageLoad = true;
5229 AddOnManager.baseURL = '';
5230 AddOnManager.PluginManager = AddOnManager();
5231 AddOnManager.ThemeManager = AddOnManager();
5232 AddOnManager.ModelManager = AddOnManager();
5233
5234 const first$1 = (fn, rate) => {
5235 let timer = null;
5236 const cancel = () => {
5237 if (!isNull(timer)) {
5238 clearTimeout(timer);
5239 timer = null;
5240 }
5241 };
5242 const throttle = (...args) => {
5243 if (isNull(timer)) {
5244 timer = setTimeout(() => {
5245 timer = null;
5246 fn.apply(null, args);
5247 }, rate);
5248 }
5249 };
5250 return {
5251 cancel,
5252 throttle
5253 };
5254 };
5255 const last = (fn, rate) => {
5256 let timer = null;
5257 const cancel = () => {
5258 if (!isNull(timer)) {
5259 clearTimeout(timer);
5260 timer = null;
5261 }
5262 };
5263 const throttle = (...args) => {
5264 cancel();
5265 timer = setTimeout(() => {
5266 timer = null;
5267 fn.apply(null, args);
5268 }, rate);
5269 };
5270 return {
5271 cancel,
5272 throttle
5273 };
5274 };
5275
5276 const ancestor$1 = (scope, selector, isRoot) => ancestor$3(scope, selector, isRoot).isSome();
5277
5278 const annotation = constant('mce-annotation');
5279 const dataAnnotation = constant('data-mce-annotation');
5280 const dataAnnotationId = constant('data-mce-annotation-uid');
5281 const dataAnnotationActive = constant('data-mce-annotation-active');
5282 const dataAnnotationClasses = constant('data-mce-annotation-classes');
5283 const dataAnnotationAttributes = constant('data-mce-annotation-attrs');
5284
5285 const isRoot$1 = root => node => eq(node, root);
5286 const identify = (editor, annotationName) => {
5287 const rng = editor.selection.getRng();
5288 const start = SugarElement.fromDom(rng.startContainer);
5289 const root = SugarElement.fromDom(editor.getBody());
5290 const selector = annotationName.fold(() => '.' + annotation(), an => `[${ dataAnnotation() }="${ an }"]`);
5291 const newStart = child$1(start, rng.startOffset).getOr(start);
5292 const closest = closest$3(newStart, selector, isRoot$1(root));
5293 return closest.bind(c => getOpt(c, `${ dataAnnotationId() }`).bind(uid => getOpt(c, `${ dataAnnotation() }`).map(name => {
5294 const elements = findMarkers(editor, uid);
5295 return {
5296 uid,
5297 name,
5298 elements
5299 };
5300 })));
5301 };
5302 const isAnnotation = elem => isElement$7(elem) && has(elem, annotation());
5303 const isBogusElement = (elem, root) => has$1(elem, 'data-mce-bogus') || ancestor$1(elem, '[data-mce-bogus="all"]', isRoot$1(root));
5304 const findMarkers = (editor, uid) => {
5305 const body = SugarElement.fromDom(editor.getBody());
5306 const descendants$1 = descendants(body, `[${ dataAnnotationId() }="${ uid }"]`);
5307 return filter$5(descendants$1, descendant => !isBogusElement(descendant, body));
5308 };
5309 const findAll = (editor, name) => {
5310 const body = SugarElement.fromDom(editor.getBody());
5311 const markers = descendants(body, `[${ dataAnnotation() }="${ name }"]`);
5312 const directory = {};
5313 each$e(markers, m => {
5314 if (!isBogusElement(m, body)) {
5315 const uid = get$9(m, dataAnnotationId());
5316 const nodesAlready = get$a(directory, uid).getOr([]);
5317 directory[uid] = nodesAlready.concat([m]);
5318 }
5319 });
5320 return directory;
5321 };
5322
5323 const setup$y = (editor, registry) => {
5324 const changeCallbacks = Cell({});
5325 const initData = () => ({
5326 listeners: [],
5327 previous: value$2()
5328 });
5329 const withCallbacks = (name, f) => {
5330 updateCallbacks(name, data => {
5331 f(data);
5332 return data;
5333 });
5334 };
5335 const updateCallbacks = (name, f) => {
5336 const callbackMap = changeCallbacks.get();
5337 const data = get$a(callbackMap, name).getOrThunk(initData);
5338 const outputData = f(data);
5339 callbackMap[name] = outputData;
5340 changeCallbacks.set(callbackMap);
5341 };
5342 const fireCallbacks = (name, uid, elements) => {
5343 withCallbacks(name, data => {
5344 each$e(data.listeners, f => f(true, name, {
5345 uid,
5346 nodes: map$3(elements, elem => elem.dom)
5347 }));
5348 });
5349 };
5350 const fireNoAnnotation = name => {
5351 withCallbacks(name, data => {
5352 each$e(data.listeners, f => f(false, name));
5353 });
5354 };
5355 const toggleActiveAttr = (uid, state) => {
5356 each$e(findMarkers(editor, uid), elem => {
5357 if (state) {
5358 set$3(elem, dataAnnotationActive(), 'true');
5359 } else {
5360 remove$9(elem, dataAnnotationActive());
5361 }
5362 });
5363 };
5364 const onNodeChange = last(() => {
5365 const annotations = sort(registry.getNames());
5366 each$e(annotations, name => {
5367 updateCallbacks(name, data => {
5368 const prev = data.previous.get();
5369 identify(editor, Optional.some(name)).fold(() => {
5370 prev.each(uid => {
5371 fireNoAnnotation(name);
5372 data.previous.clear();
5373 toggleActiveAttr(uid, false);
5374 });
5375 }, ({uid, name, elements}) => {
5376 if (!is$2(prev, uid)) {
5377 prev.each(uid => toggleActiveAttr(uid, false));
5378 fireCallbacks(name, uid, elements);
5379 data.previous.set(uid);
5380 toggleActiveAttr(uid, true);
5381 }
5382 });
5383 return {
5384 previous: data.previous,
5385 listeners: data.listeners
5386 };
5387 });
5388 });
5389 }, 30);
5390 editor.on('remove', () => {
5391 onNodeChange.cancel();
5392 });
5393 editor.on('NodeChange', () => {
5394 onNodeChange.throttle();
5395 });
5396 const addListener = (name, f) => {
5397 updateCallbacks(name, data => ({
5398 previous: data.previous,
5399 listeners: data.listeners.concat([f])
5400 }));
5401 };
5402 return { addListener };
5403 };
5404
5405 const setup$x = (editor, registry) => {
5406 const dataAnnotation$1 = dataAnnotation();
5407 const identifyParserNode = node => Optional.from(node.attr(dataAnnotation$1)).bind(registry.lookup);
5408 const removeDirectAnnotation = node => {
5409 var _a, _b;
5410 node.attr(dataAnnotationId(), null);
5411 node.attr(dataAnnotation(), null);
5412 node.attr(dataAnnotationActive(), null);
5413 const customAttrNames = Optional.from(node.attr(dataAnnotationAttributes())).map(names => names.split(',')).getOr([]);
5414 const customClasses = Optional.from(node.attr(dataAnnotationClasses())).map(names => names.split(',')).getOr([]);
5415 each$e(customAttrNames, name => node.attr(name, null));
5416 const classList = (_b = (_a = node.attr('class')) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : [];
5417 const newClassList = difference(classList, [annotation()].concat(customClasses));
5418 node.attr('class', newClassList.length > 0 ? newClassList.join(' ') : null);
5419 node.attr(dataAnnotationClasses(), null);
5420 node.attr(dataAnnotationAttributes(), null);
5421 };
5422 editor.serializer.addTempAttr(dataAnnotationActive());
5423 editor.serializer.addAttributeFilter(dataAnnotation$1, nodes => {
5424 for (const node of nodes) {
5425 identifyParserNode(node).each(settings => {
5426 if (settings.persistent === false) {
5427 if (node.name === 'span') {
5428 node.unwrap();
5429 } else {
5430 removeDirectAnnotation(node);
5431 }
5432 }
5433 });
5434 }
5435 });
5436 };
5437
5438 const create$b = () => {
5439 const annotations = {};
5440 const register = (name, settings) => {
5441 annotations[name] = {
5442 name,
5443 settings
5444 };
5445 };
5446 const lookup = name => get$a(annotations, name).map(a => a.settings);
5447 const getNames = () => keys(annotations);
5448 return {
5449 register,
5450 lookup,
5451 getNames
5452 };
5453 };
5454
5455 let unique = 0;
5456 const generate$1 = prefix => {
5457 const date = new Date();
5458 const time = date.getTime();
5459 const random = Math.floor(Math.random() * 1000000000);
5460 unique++;
5461 return prefix + '_' + random + unique + String(time);
5462 };
5463
5464 const add = (element, classes) => {
5465 each$e(classes, x => {
5466 add$2(element, x);
5467 });
5468 };
5469 const remove$3 = (element, classes) => {
5470 each$e(classes, x => {
5471 remove$6(element, x);
5472 });
5473 };
5474
5475 const clone$2 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
5476 const shallow$1 = original => clone$2(original, false);
5477 const deep$1 = original => clone$2(original, true);
5478 const shallowAs = (original, tag) => {
5479 const nu = SugarElement.fromTag(tag);
5480 const attributes = clone$4(original);
5481 setAll$1(nu, attributes);
5482 return nu;
5483 };
5484 const mutate = (original, tag) => {
5485 const nu = shallowAs(original, tag);
5486 after$4(original, nu);
5487 const children = children$1(original);
5488 append(nu, children);
5489 remove$4(original);
5490 return nu;
5491 };
5492
5493 const TextWalker = (startNode, rootNode, isBoundary = never) => {
5494 const walker = new DomTreeWalker(startNode, rootNode);
5495 const walk = direction => {
5496 let next;
5497 do {
5498 next = walker[direction]();
5499 } while (next && !isText$b(next) && !isBoundary(next));
5500 return Optional.from(next).filter(isText$b);
5501 };
5502 return {
5503 current: () => Optional.from(walker.current()).filter(isText$b),
5504 next: () => walk('next'),
5505 prev: () => walk('prev'),
5506 prev2: () => walk('prev2')
5507 };
5508 };
5509
5510 const TextSeeker = (dom, isBoundary) => {
5511 const isBlockBoundary = isBoundary ? isBoundary : node => dom.isBlock(node) || isBr$6(node) || isContentEditableFalse$b(node);
5512 const walk = (node, offset, walker, process) => {
5513 if (isText$b(node)) {
5514 const newOffset = process(node, offset, node.data);
5515 if (newOffset !== -1) {
5516 return Optional.some({
5517 container: node,
5518 offset: newOffset
5519 });
5520 }
5521 }
5522 return walker().bind(next => walk(next.container, next.offset, walker, process));
5523 };
5524 const backwards = (node, offset, process, root) => {
5525 const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
5526 return walk(node, offset, () => walker.prev().map(prev => ({
5527 container: prev,
5528 offset: prev.length
5529 })), process).getOrNull();
5530 };
5531 const forwards = (node, offset, process, root) => {
5532 const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
5533 return walk(node, offset, () => walker.next().map(next => ({
5534 container: next,
5535 offset: 0
5536 })), process).getOrNull();
5537 };
5538 return {
5539 backwards,
5540 forwards
5541 };
5542 };
5543
5544 const NodeValue = (is, name) => {
5545 const get = element => {
5546 if (!is(element)) {
5547 throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
5548 }
5549 return getOption(element).getOr('');
5550 };
5551 const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
5552 const set = (element, value) => {
5553 if (!is(element)) {
5554 throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
5555 }
5556 element.dom.nodeValue = value;
5557 };
5558 return {
5559 get,
5560 getOption,
5561 set
5562 };
5563 };
5564
5565 const api$1 = NodeValue(isText$c, 'text');
5566 const get$3 = element => api$1.get(element);
5567 const getOption = element => api$1.getOption(element);
5568 const set = (element, value) => api$1.set(element, value);
5569
5570 const tableCells = [
5571 'td',
5572 'th'
5573 ];
5574 const tableSections = [
5575 'thead',
5576 'tbody',
5577 'tfoot'
5578 ];
5579 const textBlocks = [
5580 'h1',
5581 'h2',
5582 'h3',
5583 'h4',
5584 'h5',
5585 'h6',
5586 'p',
5587 'div',
5588 'address',
5589 'pre',
5590 'form',
5591 'blockquote',
5592 'center',
5593 'dir',
5594 'fieldset',
5595 'header',
5596 'footer',
5597 'article',
5598 'section',
5599 'hgroup',
5600 'aside',
5601 'nav',
5602 'figure'
5603 ];
5604 const listItems$1 = [
5605 'li',
5606 'dd',
5607 'dt'
5608 ];
5609 const lists = [
5610 'ul',
5611 'ol',
5612 'dl'
5613 ];
5614 const wsElements = [
5615 'pre',
5616 'script',
5617 'textarea',
5618 'style'
5619 ];
5620 const lazyLookup = items => {
5621 let lookup;
5622 return node => {
5623 lookup = lookup ? lookup : mapToObject(items, always);
5624 return has$2(lookup, name(node));
5625 };
5626 };
5627 const isTable$1 = node => name(node) === 'table';
5628 const isBr$5 = node => isElement$7(node) && name(node) === 'br';
5629 const isTextBlock$2 = lazyLookup(textBlocks);
5630 const isList = lazyLookup(lists);
5631 const isListItem$1 = lazyLookup(listItems$1);
5632 const isTableSection = lazyLookup(tableSections);
5633 const isTableCell$2 = lazyLookup(tableCells);
5634 const isWsPreserveElement = lazyLookup(wsElements);
5635
5636 const getLastChildren$1 = elm => {
5637 const children = [];
5638 let rawNode = elm.dom;
5639 while (rawNode) {
5640 children.push(SugarElement.fromDom(rawNode));
5641 rawNode = rawNode.lastChild;
5642 }
5643 return children;
5644 };
5645 const removeTrailingBr = elm => {
5646 const allBrs = descendants(elm, 'br');
5647 const brs = filter$5(getLastChildren$1(elm).slice(-1), isBr$5);
5648 if (allBrs.length === brs.length) {
5649 each$e(brs, remove$4);
5650 }
5651 };
5652 const createPaddingBr = () => {
5653 const br = SugarElement.fromTag('br');
5654 set$3(br, 'data-mce-bogus', '1');
5655 return br;
5656 };
5657 const fillWithPaddingBr = elm => {
5658 empty(elm);
5659 append$1(elm, createPaddingBr());
5660 };
5661 const trimBlockTrailingBr = (elm, schema) => {
5662 lastChild(elm).each(lastChild => {
5663 prevSibling(lastChild).each(lastChildPrevSibling => {
5664 if (schema.isBlock(name(elm)) && isBr$5(lastChild) && schema.isBlock(name(lastChildPrevSibling))) {
5665 remove$4(lastChild);
5666 }
5667 });
5668 });
5669 };
5670
5671 const ZWSP$1 = zeroWidth;
5672 const isZwsp = isZwsp$2;
5673 const trim$2 = removeZwsp;
5674 const insert$5 = editor => editor.insertContent(ZWSP$1, { preserve_zwsp: true });
5675
5676 const isElement$5 = isElement$6;
5677 const isText$9 = isText$b;
5678 const isCaretContainerBlock$1 = node => {
5679 if (isText$9(node)) {
5680 node = node.parentNode;
5681 }
5682 return isElement$5(node) && node.hasAttribute('data-mce-caret');
5683 };
5684 const isCaretContainerInline = node => isText$9(node) && isZwsp(node.data);
5685 const isCaretContainer$2 = node => isCaretContainerBlock$1(node) || isCaretContainerInline(node);
5686 const hasContent = node => node.firstChild !== node.lastChild || !isBr$6(node.firstChild);
5687 const insertInline$1 = (node, before) => {
5688 var _a;
5689 const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
5690 const textNode = doc.createTextNode(ZWSP$1);
5691 const parentNode = node.parentNode;
5692 if (!before) {
5693 const sibling = node.nextSibling;
5694 if (isText$9(sibling)) {
5695 if (isCaretContainer$2(sibling)) {
5696 return sibling;
5697 }
5698 if (startsWithCaretContainer$1(sibling)) {
5699 sibling.splitText(1);
5700 return sibling;
5701 }
5702 }
5703 if (node.nextSibling) {
5704 parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node.nextSibling);
5705 } else {
5706 parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(textNode);
5707 }
5708 } else {
5709 const sibling = node.previousSibling;
5710 if (isText$9(sibling)) {
5711 if (isCaretContainer$2(sibling)) {
5712 return sibling;
5713 }
5714 if (endsWithCaretContainer$1(sibling)) {
5715 return sibling.splitText(sibling.data.length - 1);
5716 }
5717 }
5718 parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node);
5719 }
5720 return textNode;
5721 };
5722 const isBeforeInline = pos => {
5723 const container = pos.container();
5724 if (!isText$b(container)) {
5725 return false;
5726 }
5727 return container.data.charAt(pos.offset()) === ZWSP$1 || pos.isAtStart() && isCaretContainerInline(container.previousSibling);
5728 };
5729 const isAfterInline = pos => {
5730 const container = pos.container();
5731 if (!isText$b(container)) {
5732 return false;
5733 }
5734 return container.data.charAt(pos.offset() - 1) === ZWSP$1 || pos.isAtEnd() && isCaretContainerInline(container.nextSibling);
5735 };
5736 const insertBlock = (blockName, node, before) => {
5737 var _a;
5738 const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
5739 const blockNode = doc.createElement(blockName);
5740 blockNode.setAttribute('data-mce-caret', before ? 'before' : 'after');
5741 blockNode.setAttribute('data-mce-bogus', 'all');
5742 blockNode.appendChild(createPaddingBr().dom);
5743 const parentNode = node.parentNode;
5744 if (!before) {
5745 if (node.nextSibling) {
5746 parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node.nextSibling);
5747 } else {
5748 parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(blockNode);
5749 }
5750 } else {
5751 parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node);
5752 }
5753 return blockNode;
5754 };
5755 const startsWithCaretContainer$1 = node => isText$9(node) && node.data[0] === ZWSP$1;
5756 const endsWithCaretContainer$1 = node => isText$9(node) && node.data[node.data.length - 1] === ZWSP$1;
5757 const trimBogusBr = elm => {
5758 var _a;
5759 const brs = elm.getElementsByTagName('br');
5760 const lastBr = brs[brs.length - 1];
5761 if (isBogus$1(lastBr)) {
5762 (_a = lastBr.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(lastBr);
5763 }
5764 };
5765 const showCaretContainerBlock = caretContainer => {
5766 if (caretContainer && caretContainer.hasAttribute('data-mce-caret')) {
5767 trimBogusBr(caretContainer);
5768 caretContainer.removeAttribute('data-mce-caret');
5769 caretContainer.removeAttribute('data-mce-bogus');
5770 caretContainer.removeAttribute('style');
5771 caretContainer.removeAttribute('data-mce-style');
5772 caretContainer.removeAttribute('_moz_abspos');
5773 return caretContainer;
5774 }
5775 return null;
5776 };
5777 const isRangeInCaretContainerBlock = range => isCaretContainerBlock$1(range.startContainer);
5778
5779 const round$2 = Math.round;
5780 const clone$1 = rect => {
5781 if (!rect) {
5782 return {
5783 left: 0,
5784 top: 0,
5785 bottom: 0,
5786 right: 0,
5787 width: 0,
5788 height: 0
5789 };
5790 }
5791 return {
5792 left: round$2(rect.left),
5793 top: round$2(rect.top),
5794 bottom: round$2(rect.bottom),
5795 right: round$2(rect.right),
5796 width: round$2(rect.width),
5797 height: round$2(rect.height)
5798 };
5799 };
5800 const collapse = (rect, toStart) => {
5801 rect = clone$1(rect);
5802 if (toStart) {
5803 rect.right = rect.left;
5804 } else {
5805 rect.left = rect.left + rect.width;
5806 rect.right = rect.left;
5807 }
5808 rect.width = 0;
5809 return rect;
5810 };
5811 const isEqual = (rect1, rect2) => rect1.left === rect2.left && rect1.top === rect2.top && rect1.bottom === rect2.bottom && rect1.right === rect2.right;
5812 const isValidOverflow = (overflowY, rect1, rect2) => overflowY >= 0 && overflowY <= Math.min(rect1.height, rect2.height) / 2;
5813 const isAbove$1 = (rect1, rect2) => {
5814 const halfHeight = Math.min(rect2.height / 2, rect1.height / 2);
5815 if (rect1.bottom - halfHeight < rect2.top) {
5816 return true;
5817 }
5818 if (rect1.top > rect2.bottom) {
5819 return false;
5820 }
5821 return isValidOverflow(rect2.top - rect1.bottom, rect1, rect2);
5822 };
5823 const isBelow$1 = (rect1, rect2) => {
5824 if (rect1.top > rect2.bottom) {
5825 return true;
5826 }
5827 if (rect1.bottom < rect2.top) {
5828 return false;
5829 }
5830 return isValidOverflow(rect2.bottom - rect1.top, rect1, rect2);
5831 };
5832 const containsXY = (rect, clientX, clientY) => clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
5833 const boundingClientRectFromRects = rects => {
5834 return foldl(rects, (acc, rect) => {
5835 return acc.fold(() => Optional.some(rect), prevRect => {
5836 const left = Math.min(rect.left, prevRect.left);
5837 const top = Math.min(rect.top, prevRect.top);
5838 const right = Math.max(rect.right, prevRect.right);
5839 const bottom = Math.max(rect.bottom, prevRect.bottom);
5840 return Optional.some({
5841 top,
5842 right,
5843 bottom,
5844 left,
5845 width: right - left,
5846 height: bottom - top
5847 });
5848 });
5849 }, Optional.none());
5850 };
5851 const distanceToRectEdgeFromXY = (rect, x, y) => {
5852 const cx = Math.max(Math.min(x, rect.left + rect.width), rect.left);
5853 const cy = Math.max(Math.min(y, rect.top + rect.height), rect.top);
5854 return Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
5855 };
5856 const overlapY = (r1, r2) => Math.max(0, Math.min(r1.bottom, r2.bottom) - Math.max(r1.top, r2.top));
5857
5858 const clamp$2 = (value, min, max) => Math.min(Math.max(value, min), max);
5859
5860 const getSelectedNode = range => {
5861 const startContainer = range.startContainer, startOffset = range.startOffset;
5862 if (startContainer === range.endContainer && startContainer.hasChildNodes() && range.endOffset === startOffset + 1) {
5863 return startContainer.childNodes[startOffset];
5864 }
5865 return null;
5866 };
5867 const getNode$1 = (container, offset) => {
5868 if (isElement$6(container) && container.hasChildNodes()) {
5869 const childNodes = container.childNodes;
5870 const safeOffset = clamp$2(offset, 0, childNodes.length - 1);
5871 return childNodes[safeOffset];
5872 } else {
5873 return container;
5874 }
5875 };
5876 const getNodeUnsafe = (container, offset) => {
5877 if (offset < 0 && isElement$6(container) && container.hasChildNodes()) {
5878 return undefined;
5879 } else {
5880 return getNode$1(container, offset);
5881 }
5882 };
5883
5884 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]');
5885 const isExtendingChar = ch => isString(ch) && ch.charCodeAt(0) >= 768 && extendingChars.test(ch);
5886
5887 const or = (...args) => {
5888 return x => {
5889 for (let i = 0; i < args.length; i++) {
5890 if (args[i](x)) {
5891 return true;
5892 }
5893 }
5894 return false;
5895 };
5896 };
5897 const and = (...args) => {
5898 return x => {
5899 for (let i = 0; i < args.length; i++) {
5900 if (!args[i](x)) {
5901 return false;
5902 }
5903 }
5904 return true;
5905 };
5906 };
5907
5908 const isContentEditableTrue$2 = isContentEditableTrue$3;
5909 const isContentEditableFalse$a = isContentEditableFalse$b;
5910 const isBr$4 = isBr$6;
5911 const isText$8 = isText$b;
5912 const isInvalidTextElement = matchNodeNames([
5913 'script',
5914 'style',
5915 'textarea'
5916 ]);
5917 const isAtomicInline = matchNodeNames([
5918 'img',
5919 'input',
5920 'textarea',
5921 'hr',
5922 'iframe',
5923 'video',
5924 'audio',
5925 'object',
5926 'embed'
5927 ]);
5928 const isTable = matchNodeNames(['table']);
5929 const isCaretContainer$1 = isCaretContainer$2;
5930 const isCaretCandidate$3 = node => {
5931 if (isCaretContainer$1(node)) {
5932 return false;
5933 }
5934 if (isText$8(node)) {
5935 return !isInvalidTextElement(node.parentNode);
5936 }
5937 return isAtomicInline(node) || isBr$4(node) || isTable(node) || isNonUiContentEditableFalse(node);
5938 };
5939 const isUnselectable = node => isElement$6(node) && node.getAttribute('unselectable') === 'true';
5940 const isNonUiContentEditableFalse = node => !isUnselectable(node) && isContentEditableFalse$a(node);
5941 const isInEditable = (node, root) => {
5942 for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
5943 if (isNonUiContentEditableFalse(tempNode)) {
5944 return false;
5945 }
5946 if (isContentEditableTrue$2(tempNode)) {
5947 return true;
5948 }
5949 }
5950 return true;
5951 };
5952 const isAtomicContentEditableFalse = node => {
5953 if (!isNonUiContentEditableFalse(node)) {
5954 return false;
5955 }
5956 return !foldl(from(node.getElementsByTagName('*')), (result, elm) => {
5957 return result || isContentEditableTrue$2(elm);
5958 }, false);
5959 };
5960 const isAtomic$1 = node => isAtomicInline(node) || isAtomicContentEditableFalse(node);
5961 const isEditableCaretCandidate$1 = (node, root) => isCaretCandidate$3(node) && isInEditable(node, root);
5962
5963 const isElement$4 = isElement$6;
5964 const isCaretCandidate$2 = isCaretCandidate$3;
5965 const isBlock$2 = matchStyleValues('display', 'block table');
5966 const isFloated = matchStyleValues('float', 'left right');
5967 const isValidElementCaretCandidate = and(isElement$4, isCaretCandidate$2, not(isFloated));
5968 const isNotPre = not(matchStyleValues('white-space', 'pre pre-line pre-wrap'));
5969 const isText$7 = isText$b;
5970 const isBr$3 = isBr$6;
5971 const nodeIndex$1 = DOMUtils.nodeIndex;
5972 const resolveIndex$1 = getNodeUnsafe;
5973 const createRange$1 = doc => doc ? doc.createRange() : DOMUtils.DOM.createRng();
5974 const isWhiteSpace$1 = chr => isString(chr) && /[\r\n\t ]/.test(chr);
5975 const isRange = rng => !!rng.setStart && !!rng.setEnd;
5976 const isHiddenWhiteSpaceRange = range => {
5977 const container = range.startContainer;
5978 const offset = range.startOffset;
5979 if (isWhiteSpace$1(range.toString()) && isNotPre(container.parentNode) && isText$b(container)) {
5980 const text = container.data;
5981 if (isWhiteSpace$1(text[offset - 1]) || isWhiteSpace$1(text[offset + 1])) {
5982 return true;
5983 }
5984 }
5985 return false;
5986 };
5987 const getBrClientRect = brNode => {
5988 const doc = brNode.ownerDocument;
5989 const rng = createRange$1(doc);
5990 const nbsp$1 = doc.createTextNode(nbsp);
5991 const parentNode = brNode.parentNode;
5992 parentNode.insertBefore(nbsp$1, brNode);
5993 rng.setStart(nbsp$1, 0);
5994 rng.setEnd(nbsp$1, 1);
5995 const clientRect = clone$1(rng.getBoundingClientRect());
5996 parentNode.removeChild(nbsp$1);
5997 return clientRect;
5998 };
5999 const getBoundingClientRectWebKitText = rng => {
6000 const sc = rng.startContainer;
6001 const ec = rng.endContainer;
6002 const so = rng.startOffset;
6003 const eo = rng.endOffset;
6004 if (sc === ec && isText$b(ec) && so === 0 && eo === 1) {
6005 const newRng = rng.cloneRange();
6006 newRng.setEndAfter(ec);
6007 return getBoundingClientRect$1(newRng);
6008 } else {
6009 return null;
6010 }
6011 };
6012 const isZeroRect = r => r.left === 0 && r.right === 0 && r.top === 0 && r.bottom === 0;
6013 const getBoundingClientRect$1 = item => {
6014 var _a;
6015 let clientRect;
6016 const clientRects = item.getClientRects();
6017 if (clientRects.length > 0) {
6018 clientRect = clone$1(clientRects[0]);
6019 } else {
6020 clientRect = clone$1(item.getBoundingClientRect());
6021 }
6022 if (!isRange(item) && isBr$3(item) && isZeroRect(clientRect)) {
6023 return getBrClientRect(item);
6024 }
6025 if (isZeroRect(clientRect) && isRange(item)) {
6026 return (_a = getBoundingClientRectWebKitText(item)) !== null && _a !== void 0 ? _a : clientRect;
6027 }
6028 return clientRect;
6029 };
6030 const collapseAndInflateWidth = (clientRect, toStart) => {
6031 const newClientRect = collapse(clientRect, toStart);
6032 newClientRect.width = 1;
6033 newClientRect.right = newClientRect.left + 1;
6034 return newClientRect;
6035 };
6036 const getCaretPositionClientRects = caretPosition => {
6037 const clientRects = [];
6038 const addUniqueAndValidRect = clientRect => {
6039 if (clientRect.height === 0) {
6040 return;
6041 }
6042 if (clientRects.length > 0) {
6043 if (isEqual(clientRect, clientRects[clientRects.length - 1])) {
6044 return;
6045 }
6046 }
6047 clientRects.push(clientRect);
6048 };
6049 const addCharacterOffset = (container, offset) => {
6050 const range = createRange$1(container.ownerDocument);
6051 if (offset < container.data.length) {
6052 if (isExtendingChar(container.data[offset])) {
6053 return;
6054 }
6055 if (isExtendingChar(container.data[offset - 1])) {
6056 range.setStart(container, offset);
6057 range.setEnd(container, offset + 1);
6058 if (!isHiddenWhiteSpaceRange(range)) {
6059 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
6060 return;
6061 }
6062 }
6063 }
6064 if (offset > 0) {
6065 range.setStart(container, offset - 1);
6066 range.setEnd(container, offset);
6067 if (!isHiddenWhiteSpaceRange(range)) {
6068 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
6069 }
6070 }
6071 if (offset < container.data.length) {
6072 range.setStart(container, offset);
6073 range.setEnd(container, offset + 1);
6074 if (!isHiddenWhiteSpaceRange(range)) {
6075 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), true));
6076 }
6077 }
6078 };
6079 const container = caretPosition.container();
6080 const offset = caretPosition.offset();
6081 if (isText$7(container)) {
6082 addCharacterOffset(container, offset);
6083 return clientRects;
6084 }
6085 if (isElement$4(container)) {
6086 if (caretPosition.isAtEnd()) {
6087 const node = resolveIndex$1(container, offset);
6088 if (isText$7(node)) {
6089 addCharacterOffset(node, node.data.length);
6090 }
6091 if (isValidElementCaretCandidate(node) && !isBr$3(node)) {
6092 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
6093 }
6094 } else {
6095 const node = resolveIndex$1(container, offset);
6096 if (isText$7(node)) {
6097 addCharacterOffset(node, 0);
6098 }
6099 if (isValidElementCaretCandidate(node) && caretPosition.isAtEnd()) {
6100 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
6101 return clientRects;
6102 }
6103 const beforeNode = resolveIndex$1(caretPosition.container(), caretPosition.offset() - 1);
6104 if (isValidElementCaretCandidate(beforeNode) && !isBr$3(beforeNode)) {
6105 if (isBlock$2(beforeNode) || isBlock$2(node) || !isValidElementCaretCandidate(node)) {
6106 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(beforeNode), false));
6107 }
6108 }
6109 if (isValidElementCaretCandidate(node)) {
6110 addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), true));
6111 }
6112 }
6113 }
6114 return clientRects;
6115 };
6116 const CaretPosition = (container, offset, clientRects) => {
6117 const isAtStart = () => {
6118 if (isText$7(container)) {
6119 return offset === 0;
6120 }
6121 return offset === 0;
6122 };
6123 const isAtEnd = () => {
6124 if (isText$7(container)) {
6125 return offset >= container.data.length;
6126 }
6127 return offset >= container.childNodes.length;
6128 };
6129 const toRange = () => {
6130 const range = createRange$1(container.ownerDocument);
6131 range.setStart(container, offset);
6132 range.setEnd(container, offset);
6133 return range;
6134 };
6135 const getClientRects = () => {
6136 if (!clientRects) {
6137 clientRects = getCaretPositionClientRects(CaretPosition(container, offset));
6138 }
6139 return clientRects;
6140 };
6141 const isVisible = () => getClientRects().length > 0;
6142 const isEqual = caretPosition => caretPosition && container === caretPosition.container() && offset === caretPosition.offset();
6143 const getNode = before => resolveIndex$1(container, before ? offset - 1 : offset);
6144 return {
6145 container: constant(container),
6146 offset: constant(offset),
6147 toRange,
6148 getClientRects,
6149 isVisible,
6150 isAtStart,
6151 isAtEnd,
6152 isEqual,
6153 getNode
6154 };
6155 };
6156 CaretPosition.fromRangeStart = range => CaretPosition(range.startContainer, range.startOffset);
6157 CaretPosition.fromRangeEnd = range => CaretPosition(range.endContainer, range.endOffset);
6158 CaretPosition.after = node => CaretPosition(node.parentNode, nodeIndex$1(node) + 1);
6159 CaretPosition.before = node => CaretPosition(node.parentNode, nodeIndex$1(node));
6160 CaretPosition.isAbove = (pos1, pos2) => lift2(head(pos2.getClientRects()), last$2(pos1.getClientRects()), isAbove$1).getOr(false);
6161 CaretPosition.isBelow = (pos1, pos2) => lift2(last$2(pos2.getClientRects()), head(pos1.getClientRects()), isBelow$1).getOr(false);
6162 CaretPosition.isAtStart = pos => pos ? pos.isAtStart() : false;
6163 CaretPosition.isAtEnd = pos => pos ? pos.isAtEnd() : false;
6164 CaretPosition.isTextPosition = pos => pos ? isText$b(pos.container()) : false;
6165 CaretPosition.isElementPosition = pos => !CaretPosition.isTextPosition(pos);
6166
6167 const trimEmptyTextNode$1 = (dom, node) => {
6168 if (isText$b(node) && node.data.length === 0) {
6169 dom.remove(node);
6170 }
6171 };
6172 const insertNode = (dom, rng, node) => {
6173 rng.insertNode(node);
6174 trimEmptyTextNode$1(dom, node.previousSibling);
6175 trimEmptyTextNode$1(dom, node.nextSibling);
6176 };
6177 const insertFragment = (dom, rng, frag) => {
6178 const firstChild = Optional.from(frag.firstChild);
6179 const lastChild = Optional.from(frag.lastChild);
6180 rng.insertNode(frag);
6181 firstChild.each(child => trimEmptyTextNode$1(dom, child.previousSibling));
6182 lastChild.each(child => trimEmptyTextNode$1(dom, child.nextSibling));
6183 };
6184 const rangeInsertNode = (dom, rng, node) => {
6185 if (isDocumentFragment(node)) {
6186 insertFragment(dom, rng, node);
6187 } else {
6188 insertNode(dom, rng, node);
6189 }
6190 };
6191
6192 const isText$6 = isText$b;
6193 const isBogus = isBogus$1;
6194 const nodeIndex = DOMUtils.nodeIndex;
6195 const normalizedParent = node => {
6196 const parentNode = node.parentNode;
6197 if (isBogus(parentNode)) {
6198 return normalizedParent(parentNode);
6199 }
6200 return parentNode;
6201 };
6202 const getChildNodes = node => {
6203 if (!node) {
6204 return [];
6205 }
6206 return reduce(node.childNodes, (result, node) => {
6207 if (isBogus(node) && node.nodeName !== 'BR') {
6208 result = result.concat(getChildNodes(node));
6209 } else {
6210 result.push(node);
6211 }
6212 return result;
6213 }, []);
6214 };
6215 const normalizedTextOffset = (node, offset) => {
6216 let tempNode = node;
6217 while (tempNode = tempNode.previousSibling) {
6218 if (!isText$6(tempNode)) {
6219 break;
6220 }
6221 offset += tempNode.data.length;
6222 }
6223 return offset;
6224 };
6225 const equal = a => b => a === b;
6226 const normalizedNodeIndex = node => {
6227 let nodes, index;
6228 nodes = getChildNodes(normalizedParent(node));
6229 index = findIndex$1(nodes, equal(node), node);
6230 nodes = nodes.slice(0, index + 1);
6231 const numTextFragments = reduce(nodes, (result, node, i) => {
6232 if (isText$6(node) && isText$6(nodes[i - 1])) {
6233 result++;
6234 }
6235 return result;
6236 }, 0);
6237 nodes = filter$3(nodes, matchNodeNames([node.nodeName]));
6238 index = findIndex$1(nodes, equal(node), node);
6239 return index - numTextFragments;
6240 };
6241 const createPathItem = node => {
6242 const name = isText$6(node) ? 'text()' : node.nodeName.toLowerCase();
6243 return name + '[' + normalizedNodeIndex(node) + ']';
6244 };
6245 const parentsUntil$1 = (root, node, predicate) => {
6246 const parents = [];
6247 for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
6248 if (predicate && predicate(tempNode)) {
6249 break;
6250 }
6251 parents.push(tempNode);
6252 }
6253 return parents;
6254 };
6255 const create$a = (root, caretPosition) => {
6256 let path = [];
6257 let container = caretPosition.container();
6258 let offset = caretPosition.offset();
6259 let outputOffset;
6260 if (isText$6(container)) {
6261 outputOffset = normalizedTextOffset(container, offset);
6262 } else {
6263 const childNodes = container.childNodes;
6264 if (offset >= childNodes.length) {
6265 outputOffset = 'after';
6266 offset = childNodes.length - 1;
6267 } else {
6268 outputOffset = 'before';
6269 }
6270 container = childNodes[offset];
6271 }
6272 path.push(createPathItem(container));
6273 let parents = parentsUntil$1(root, container);
6274 parents = filter$3(parents, not(isBogus$1));
6275 path = path.concat(map$1(parents, node => {
6276 return createPathItem(node);
6277 }));
6278 return path.reverse().join('/') + ',' + outputOffset;
6279 };
6280 const resolvePathItem = (node, name, index) => {
6281 let nodes = getChildNodes(node);
6282 nodes = filter$3(nodes, (node, index) => {
6283 return !isText$6(node) || !isText$6(nodes[index - 1]);
6284 });
6285 nodes = filter$3(nodes, matchNodeNames([name]));
6286 return nodes[index];
6287 };
6288 const findTextPosition = (container, offset) => {
6289 let node = container;
6290 let targetOffset = 0;
6291 while (isText$6(node)) {
6292 const dataLen = node.data.length;
6293 if (offset >= targetOffset && offset <= targetOffset + dataLen) {
6294 container = node;
6295 offset = offset - targetOffset;
6296 break;
6297 }
6298 if (!isText$6(node.nextSibling)) {
6299 container = node;
6300 offset = dataLen;
6301 break;
6302 }
6303 targetOffset += dataLen;
6304 node = node.nextSibling;
6305 }
6306 if (isText$6(container) && offset > container.data.length) {
6307 offset = container.data.length;
6308 }
6309 return CaretPosition(container, offset);
6310 };
6311 const resolve$1 = (root, path) => {
6312 if (!path) {
6313 return null;
6314 }
6315 const parts = path.split(',');
6316 const paths = parts[0].split('/');
6317 const offset = parts.length > 1 ? parts[1] : 'before';
6318 const container = reduce(paths, (result, value) => {
6319 const match = /([\w\-\(\)]+)\[([0-9]+)\]/.exec(value);
6320 if (!match) {
6321 return null;
6322 }
6323 if (match[1] === 'text()') {
6324 match[1] = '#text';
6325 }
6326 return resolvePathItem(result, match[1], parseInt(match[2], 10));
6327 }, root);
6328 if (!container) {
6329 return null;
6330 }
6331 if (!isText$6(container) && container.parentNode) {
6332 let nodeOffset;
6333 if (offset === 'after') {
6334 nodeOffset = nodeIndex(container) + 1;
6335 } else {
6336 nodeOffset = nodeIndex(container);
6337 }
6338 return CaretPosition(container.parentNode, nodeOffset);
6339 }
6340 return findTextPosition(container, parseInt(offset, 10));
6341 };
6342
6343 const isContentEditableFalse$9 = isContentEditableFalse$b;
6344 const getNormalizedTextOffset$1 = (trim, container, offset) => {
6345 let trimmedOffset = trim(container.data.slice(0, offset)).length;
6346 for (let node = container.previousSibling; node && isText$b(node); node = node.previousSibling) {
6347 trimmedOffset += trim(node.data).length;
6348 }
6349 return trimmedOffset;
6350 };
6351 const getPoint = (dom, trim, normalized, rng, start) => {
6352 const container = start ? rng.startContainer : rng.endContainer;
6353 let offset = start ? rng.startOffset : rng.endOffset;
6354 const point = [];
6355 const root = dom.getRoot();
6356 if (isText$b(container)) {
6357 point.push(normalized ? getNormalizedTextOffset$1(trim, container, offset) : offset);
6358 } else {
6359 let after = 0;
6360 const childNodes = container.childNodes;
6361 if (offset >= childNodes.length && childNodes.length) {
6362 after = 1;
6363 offset = Math.max(0, childNodes.length - 1);
6364 }
6365 point.push(dom.nodeIndex(childNodes[offset], normalized) + after);
6366 }
6367 for (let node = container; node && node !== root; node = node.parentNode) {
6368 point.push(dom.nodeIndex(node, normalized));
6369 }
6370 return point;
6371 };
6372 const getLocation = (trim, selection, normalized, rng) => {
6373 const dom = selection.dom;
6374 const start = getPoint(dom, trim, normalized, rng, true);
6375 const forward = selection.isForward();
6376 const fakeCaret = isRangeInCaretContainerBlock(rng) ? { isFakeCaret: true } : {};
6377 if (!selection.isCollapsed()) {
6378 const end = getPoint(dom, trim, normalized, rng, false);
6379 return {
6380 start,
6381 end,
6382 forward,
6383 ...fakeCaret
6384 };
6385 } else {
6386 return {
6387 start,
6388 forward,
6389 ...fakeCaret
6390 };
6391 }
6392 };
6393 const findIndex = (dom, name, element) => {
6394 let count = 0;
6395 Tools.each(dom.select(name), node => {
6396 if (node.getAttribute('data-mce-bogus') === 'all') {
6397 return;
6398 } else if (node === element) {
6399 return false;
6400 } else {
6401 count++;
6402 return;
6403 }
6404 });
6405 return count;
6406 };
6407 const moveEndPoint$1 = (rng, start) => {
6408 let container = start ? rng.startContainer : rng.endContainer;
6409 let offset = start ? rng.startOffset : rng.endOffset;
6410 if (isElement$6(container) && container.nodeName === 'TR') {
6411 const childNodes = container.childNodes;
6412 container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)];
6413 if (container) {
6414 offset = start ? 0 : container.childNodes.length;
6415 if (start) {
6416 rng.setStart(container, offset);
6417 } else {
6418 rng.setEnd(container, offset);
6419 }
6420 }
6421 }
6422 };
6423 const normalizeTableCellSelection = rng => {
6424 moveEndPoint$1(rng, true);
6425 moveEndPoint$1(rng, false);
6426 return rng;
6427 };
6428 const findSibling = (node, offset) => {
6429 if (isElement$6(node)) {
6430 node = getNode$1(node, offset);
6431 if (isContentEditableFalse$9(node)) {
6432 return node;
6433 }
6434 }
6435 if (isCaretContainer$2(node)) {
6436 if (isText$b(node) && isCaretContainerBlock$1(node)) {
6437 node = node.parentNode;
6438 }
6439 let sibling = node.previousSibling;
6440 if (isContentEditableFalse$9(sibling)) {
6441 return sibling;
6442 }
6443 sibling = node.nextSibling;
6444 if (isContentEditableFalse$9(sibling)) {
6445 return sibling;
6446 }
6447 }
6448 return undefined;
6449 };
6450 const findAdjacentContentEditableFalseElm = rng => {
6451 return findSibling(rng.startContainer, rng.startOffset) || findSibling(rng.endContainer, rng.endOffset);
6452 };
6453 const getOffsetBookmark = (trim, normalized, selection) => {
6454 const element = selection.getNode();
6455 const rng = selection.getRng();
6456 if (element.nodeName === 'IMG' || isContentEditableFalse$9(element)) {
6457 const name = element.nodeName;
6458 return {
6459 name,
6460 index: findIndex(selection.dom, name, element)
6461 };
6462 }
6463 const sibling = findAdjacentContentEditableFalseElm(rng);
6464 if (sibling) {
6465 const name = sibling.tagName;
6466 return {
6467 name,
6468 index: findIndex(selection.dom, name, sibling)
6469 };
6470 }
6471 return getLocation(trim, selection, normalized, rng);
6472 };
6473 const getCaretBookmark = selection => {
6474 const rng = selection.getRng();
6475 return {
6476 start: create$a(selection.dom.getRoot(), CaretPosition.fromRangeStart(rng)),
6477 end: create$a(selection.dom.getRoot(), CaretPosition.fromRangeEnd(rng)),
6478 forward: selection.isForward()
6479 };
6480 };
6481 const getRangeBookmark = selection => {
6482 return {
6483 rng: selection.getRng(),
6484 forward: selection.isForward()
6485 };
6486 };
6487 const createBookmarkSpan = (dom, id, filled) => {
6488 const args = {
6489 'data-mce-type': 'bookmark',
6490 id,
6491 'style': 'overflow:hidden;line-height:0px'
6492 };
6493 return filled ? dom.create('span', args, '&#xFEFF;') : dom.create('span', args);
6494 };
6495 const getPersistentBookmark = (selection, filled) => {
6496 const dom = selection.dom;
6497 let rng = selection.getRng();
6498 const id = dom.uniqueId();
6499 const collapsed = selection.isCollapsed();
6500 const element = selection.getNode();
6501 const name = element.nodeName;
6502 const forward = selection.isForward();
6503 if (name === 'IMG') {
6504 return {
6505 name,
6506 index: findIndex(dom, name, element)
6507 };
6508 }
6509 const rng2 = normalizeTableCellSelection(rng.cloneRange());
6510 if (!collapsed) {
6511 rng2.collapse(false);
6512 const endBookmarkNode = createBookmarkSpan(dom, id + '_end', filled);
6513 rangeInsertNode(dom, rng2, endBookmarkNode);
6514 }
6515 rng = normalizeTableCellSelection(rng);
6516 rng.collapse(true);
6517 const startBookmarkNode = createBookmarkSpan(dom, id + '_start', filled);
6518 rangeInsertNode(dom, rng, startBookmarkNode);
6519 selection.moveToBookmark({
6520 id,
6521 keep: true,
6522 forward
6523 });
6524 return {
6525 id,
6526 forward
6527 };
6528 };
6529 const getBookmark$2 = (selection, type, normalized = false) => {
6530 if (type === 2) {
6531 return getOffsetBookmark(trim$2, normalized, selection);
6532 } else if (type === 3) {
6533 return getCaretBookmark(selection);
6534 } else if (type) {
6535 return getRangeBookmark(selection);
6536 } else {
6537 return getPersistentBookmark(selection, false);
6538 }
6539 };
6540 const getUndoBookmark = curry(getOffsetBookmark, identity, true);
6541
6542 const value$1 = value => {
6543 const applyHelper = fn => fn(value);
6544 const constHelper = constant(value);
6545 const outputHelper = () => output;
6546 const output = {
6547 tag: true,
6548 inner: value,
6549 fold: (_onError, onValue) => onValue(value),
6550 isValue: always,
6551 isError: never,
6552 map: mapper => Result.value(mapper(value)),
6553 mapError: outputHelper,
6554 bind: applyHelper,
6555 exists: applyHelper,
6556 forall: applyHelper,
6557 getOr: constHelper,
6558 or: outputHelper,
6559 getOrThunk: constHelper,
6560 orThunk: outputHelper,
6561 getOrDie: constHelper,
6562 each: fn => {
6563 fn(value);
6564 },
6565 toOptional: () => Optional.some(value)
6566 };
6567 return output;
6568 };
6569 const error = error => {
6570 const outputHelper = () => output;
6571 const output = {
6572 tag: false,
6573 inner: error,
6574 fold: (onError, _onValue) => onError(error),
6575 isValue: never,
6576 isError: always,
6577 map: outputHelper,
6578 mapError: mapper => Result.error(mapper(error)),
6579 bind: outputHelper,
6580 exists: never,
6581 forall: always,
6582 getOr: identity,
6583 or: identity,
6584 getOrThunk: apply$1,
6585 orThunk: apply$1,
6586 getOrDie: die(String(error)),
6587 each: noop,
6588 toOptional: Optional.none
6589 };
6590 return output;
6591 };
6592 const fromOption = (optional, err) => optional.fold(() => error(err), value$1);
6593 const Result = {
6594 value: value$1,
6595 error,
6596 fromOption
6597 };
6598
6599 const generate = cases => {
6600 if (!isArray$1(cases)) {
6601 throw new Error('cases must be an array');
6602 }
6603 if (cases.length === 0) {
6604 throw new Error('there must be at least one case');
6605 }
6606 const constructors = [];
6607 const adt = {};
6608 each$e(cases, (acase, count) => {
6609 const keys$1 = keys(acase);
6610 if (keys$1.length !== 1) {
6611 throw new Error('one and only one name per case');
6612 }
6613 const key = keys$1[0];
6614 const value = acase[key];
6615 if (adt[key] !== undefined) {
6616 throw new Error('duplicate key detected:' + key);
6617 } else if (key === 'cata') {
6618 throw new Error('cannot have a case named cata (sorry)');
6619 } else if (!isArray$1(value)) {
6620 throw new Error('case arguments must be an array');
6621 }
6622 constructors.push(key);
6623 adt[key] = (...args) => {
6624 const argLength = args.length;
6625 if (argLength !== value.length) {
6626 throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
6627 }
6628 const match = branches => {
6629 const branchKeys = keys(branches);
6630 if (constructors.length !== branchKeys.length) {
6631 throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
6632 }
6633 const allReqd = forall(constructors, reqKey => {
6634 return contains$2(branchKeys, reqKey);
6635 });
6636 if (!allReqd) {
6637 throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
6638 }
6639 return branches[key].apply(null, args);
6640 };
6641 return {
6642 fold: (...foldArgs) => {
6643 if (foldArgs.length !== cases.length) {
6644 throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
6645 }
6646 const target = foldArgs[count];
6647 return target.apply(null, args);
6648 },
6649 match,
6650 log: label => {
6651 console.log(label, {
6652 constructors,
6653 constructor: key,
6654 params: args
6655 });
6656 }
6657 };
6658 };
6659 });
6660 return adt;
6661 };
6662 const Adt = { generate };
6663
6664 Adt.generate([
6665 {
6666 bothErrors: [
6667 'error1',
6668 'error2'
6669 ]
6670 },
6671 {
6672 firstError: [
6673 'error1',
6674 'value2'
6675 ]
6676 },
6677 {
6678 secondError: [
6679 'value1',
6680 'error2'
6681 ]
6682 },
6683 {
6684 bothValues: [
6685 'value1',
6686 'value2'
6687 ]
6688 }
6689 ]);
6690 const partition$1 = results => {
6691 const errors = [];
6692 const values = [];
6693 each$e(results, result => {
6694 result.fold(err => {
6695 errors.push(err);
6696 }, value => {
6697 values.push(value);
6698 });
6699 });
6700 return {
6701 errors,
6702 values
6703 };
6704 };
6705
6706 const isInlinePattern = pattern => pattern.type === 'inline-command' || pattern.type === 'inline-format';
6707 const isBlockPattern = pattern => pattern.type === 'block-command' || pattern.type === 'block-format';
6708 const hasBlockTrigger = (pattern, trigger) => (pattern.type === 'block-command' || pattern.type === 'block-format') && pattern.trigger === trigger;
6709 const normalizePattern = pattern => {
6710 var _a;
6711 const err = message => Result.error({
6712 message,
6713 pattern
6714 });
6715 const formatOrCmd = (name, onFormat, onCommand) => {
6716 if (pattern.format !== undefined) {
6717 let formats;
6718 if (isArray$1(pattern.format)) {
6719 if (!forall(pattern.format, isString)) {
6720 return err(name + ' pattern has non-string items in the `format` array');
6721 }
6722 formats = pattern.format;
6723 } else if (isString(pattern.format)) {
6724 formats = [pattern.format];
6725 } else {
6726 return err(name + ' pattern has non-string `format` parameter');
6727 }
6728 return Result.value(onFormat(formats));
6729 } else if (pattern.cmd !== undefined) {
6730 if (!isString(pattern.cmd)) {
6731 return err(name + ' pattern has non-string `cmd` parameter');
6732 }
6733 return Result.value(onCommand(pattern.cmd, pattern.value));
6734 } else {
6735 return err(name + ' pattern is missing both `format` and `cmd` parameters');
6736 }
6737 };
6738 if (!isObject(pattern)) {
6739 return err('Raw pattern is not an object');
6740 }
6741 if (!isString(pattern.start)) {
6742 return err('Raw pattern is missing `start` parameter');
6743 }
6744 if (pattern.end !== undefined) {
6745 if (!isString(pattern.end)) {
6746 return err('Inline pattern has non-string `end` parameter');
6747 }
6748 if (pattern.start.length === 0 && pattern.end.length === 0) {
6749 return err('Inline pattern has empty `start` and `end` parameters');
6750 }
6751 let start = pattern.start;
6752 let end = pattern.end;
6753 if (end.length === 0) {
6754 end = start;
6755 start = '';
6756 }
6757 return formatOrCmd('Inline', format => ({
6758 type: 'inline-format',
6759 start,
6760 end,
6761 format
6762 }), (cmd, value) => ({
6763 type: 'inline-command',
6764 start,
6765 end,
6766 cmd,
6767 value
6768 }));
6769 } else if (pattern.replacement !== undefined) {
6770 if (!isString(pattern.replacement)) {
6771 return err('Replacement pattern has non-string `replacement` parameter');
6772 }
6773 if (pattern.start.length === 0) {
6774 return err('Replacement pattern has empty `start` parameter');
6775 }
6776 return Result.value({
6777 type: 'inline-command',
6778 start: '',
6779 end: pattern.start,
6780 cmd: 'mceInsertContent',
6781 value: pattern.replacement
6782 });
6783 } else {
6784 const trigger = (_a = pattern.trigger) !== null && _a !== void 0 ? _a : 'space';
6785 if (pattern.start.length === 0) {
6786 return err('Block pattern has empty `start` parameter');
6787 }
6788 return formatOrCmd('Block', formats => ({
6789 type: 'block-format',
6790 start: pattern.start,
6791 format: formats[0],
6792 trigger
6793 }), (command, commandValue) => ({
6794 type: 'block-command',
6795 start: pattern.start,
6796 cmd: command,
6797 value: commandValue,
6798 trigger
6799 }));
6800 }
6801 };
6802 const getBlockPatterns = patterns => filter$5(patterns, isBlockPattern);
6803 const getInlinePatterns = patterns => filter$5(patterns, isInlinePattern);
6804 const createPatternSet = (patterns, dynamicPatternsLookup) => ({
6805 inlinePatterns: getInlinePatterns(patterns),
6806 blockPatterns: getBlockPatterns(patterns),
6807 dynamicPatternsLookup
6808 });
6809 const filterByTrigger = (patterns, trigger) => {
6810 return {
6811 ...patterns,
6812 blockPatterns: filter$5(patterns.blockPatterns, pattern => hasBlockTrigger(pattern, trigger))
6813 };
6814 };
6815 const fromRawPatterns = patterns => {
6816 const normalized = partition$1(map$3(patterns, normalizePattern));
6817 each$e(normalized.errors, err => console.error(err.message, err.pattern));
6818 return normalized.values;
6819 };
6820 const fromRawPatternsLookup = lookupFn => {
6821 return ctx => {
6822 const rawPatterns = lookupFn(ctx);
6823 return fromRawPatterns(rawPatterns);
6824 };
6825 };
6826
6827 const deviceDetection$1 = detect$1().deviceType;
6828 const isTouch = deviceDetection$1.isTouch();
6829 const DOM$a = DOMUtils.DOM;
6830 const getHash = value => {
6831 const items = value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(',');
6832 return foldl(items, (output, item) => {
6833 const arr = item.split('=');
6834 const key = arr[0];
6835 const val = arr.length > 1 ? arr[1] : key;
6836 output[trim$4(key)] = trim$4(val);
6837 return output;
6838 }, {});
6839 };
6840 const isRegExp = x => is$4(x, RegExp);
6841 const option = name => editor => editor.options.get(name);
6842 const stringOrObjectProcessor = value => isString(value) || isObject(value);
6843 const bodyOptionProcessor = (editor, defaultValue = '') => value => {
6844 const valid = isString(value);
6845 if (valid) {
6846 if (value.indexOf('=') !== -1) {
6847 const bodyObj = getHash(value);
6848 return {
6849 value: get$a(bodyObj, editor.id).getOr(defaultValue),
6850 valid
6851 };
6852 } else {
6853 return {
6854 value,
6855 valid
6856 };
6857 }
6858 } else {
6859 return {
6860 valid: false,
6861 message: 'Must be a string.'
6862 };
6863 }
6864 };
6865 const register$7 = editor => {
6866 const registerOption = editor.options.register;
6867 registerOption('id', {
6868 processor: 'string',
6869 default: editor.id
6870 });
6871 registerOption('selector', { processor: 'string' });
6872 registerOption('target', { processor: 'object' });
6873 registerOption('suffix', { processor: 'string' });
6874 registerOption('cache_suffix', { processor: 'string' });
6875 registerOption('base_url', { processor: 'string' });
6876 registerOption('referrer_policy', {
6877 processor: 'string',
6878 default: ''
6879 });
6880 registerOption('language_load', {
6881 processor: 'boolean',
6882 default: true
6883 });
6884 registerOption('inline', {
6885 processor: 'boolean',
6886 default: false
6887 });
6888 registerOption('iframe_attrs', {
6889 processor: 'object',
6890 default: {}
6891 });
6892 registerOption('doctype', {
6893 processor: 'string',
6894 default: '<!DOCTYPE html>'
6895 });
6896 registerOption('document_base_url', {
6897 processor: 'string',
6898 default: editor.documentBaseUrl
6899 });
6900 registerOption('body_id', {
6901 processor: bodyOptionProcessor(editor, 'tinymce'),
6902 default: 'tinymce'
6903 });
6904 registerOption('body_class', {
6905 processor: bodyOptionProcessor(editor),
6906 default: ''
6907 });
6908 registerOption('content_security_policy', {
6909 processor: 'string',
6910 default: ''
6911 });
6912 registerOption('br_in_pre', {
6913 processor: 'boolean',
6914 default: true
6915 });
6916 registerOption('forced_root_block', {
6917 processor: value => {
6918 const valid = isString(value) && isNotEmpty(value);
6919 if (valid) {
6920 return {
6921 value,
6922 valid
6923 };
6924 } else {
6925 return {
6926 valid: false,
6927 message: 'Must be a non-empty string.'
6928 };
6929 }
6930 },
6931 default: 'p'
6932 });
6933 registerOption('forced_root_block_attrs', {
6934 processor: 'object',
6935 default: {}
6936 });
6937 registerOption('newline_behavior', {
6938 processor: value => {
6939 const valid = contains$2([
6940 'block',
6941 'linebreak',
6942 'invert',
6943 'default'
6944 ], value);
6945 return valid ? {
6946 value,
6947 valid
6948 } : {
6949 valid: false,
6950 message: 'Must be one of: block, linebreak, invert or default.'
6951 };
6952 },
6953 default: 'default'
6954 });
6955 registerOption('br_newline_selector', {
6956 processor: 'string',
6957 default: '.mce-toc h2,figcaption,caption'
6958 });
6959 registerOption('no_newline_selector', {
6960 processor: 'string',
6961 default: ''
6962 });
6963 registerOption('keep_styles', {
6964 processor: 'boolean',
6965 default: true
6966 });
6967 registerOption('end_container_on_empty_block', {
6968 processor: value => {
6969 if (isBoolean(value)) {
6970 return {
6971 valid: true,
6972 value
6973 };
6974 } else if (isString(value)) {
6975 return {
6976 valid: true,
6977 value
6978 };
6979 } else {
6980 return {
6981 valid: false,
6982 message: 'Must be boolean or a string'
6983 };
6984 }
6985 },
6986 default: 'blockquote'
6987 });
6988 registerOption('font_size_style_values', {
6989 processor: 'string',
6990 default: 'xx-small,x-small,small,medium,large,x-large,xx-large'
6991 });
6992 registerOption('font_size_legacy_values', {
6993 processor: 'string',
6994 default: 'xx-small,small,medium,large,x-large,xx-large,300%'
6995 });
6996 registerOption('font_size_classes', {
6997 processor: 'string',
6998 default: ''
6999 });
7000 registerOption('automatic_uploads', {
7001 processor: 'boolean',
7002 default: true
7003 });
7004 registerOption('images_reuse_filename', {
7005 processor: 'boolean',
7006 default: false
7007 });
7008 registerOption('images_replace_blob_uris', {
7009 processor: 'boolean',
7010 default: true
7011 });
7012 registerOption('icons', {
7013 processor: 'string',
7014 default: ''
7015 });
7016 registerOption('icons_url', {
7017 processor: 'string',
7018 default: ''
7019 });
7020 registerOption('images_upload_url', {
7021 processor: 'string',
7022 default: ''
7023 });
7024 registerOption('images_upload_base_path', {
7025 processor: 'string',
7026 default: ''
7027 });
7028 registerOption('images_upload_credentials', {
7029 processor: 'boolean',
7030 default: false
7031 });
7032 registerOption('images_upload_handler', { processor: 'function' });
7033 registerOption('language', {
7034 processor: 'string',
7035 default: 'en'
7036 });
7037 registerOption('language_url', {
7038 processor: 'string',
7039 default: ''
7040 });
7041 registerOption('entity_encoding', {
7042 processor: 'string',
7043 default: 'named'
7044 });
7045 registerOption('indent', {
7046 processor: 'boolean',
7047 default: true
7048 });
7049 registerOption('indent_before', {
7050 processor: 'string',
7051 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'
7052 });
7053 registerOption('indent_after', {
7054 processor: 'string',
7055 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'
7056 });
7057 registerOption('indent_use_margin', {
7058 processor: 'boolean',
7059 default: false
7060 });
7061 registerOption('indentation', {
7062 processor: 'string',
7063 default: '40px'
7064 });
7065 registerOption('content_css', {
7066 processor: value => {
7067 const valid = value === false || isString(value) || isArrayOf(value, isString);
7068 if (valid) {
7069 if (isString(value)) {
7070 return {
7071 value: map$3(value.split(','), trim$4),
7072 valid
7073 };
7074 } else if (isArray$1(value)) {
7075 return {
7076 value,
7077 valid
7078 };
7079 } else if (value === false) {
7080 return {
7081 value: [],
7082 valid
7083 };
7084 } else {
7085 return {
7086 value,
7087 valid
7088 };
7089 }
7090 } else {
7091 return {
7092 valid: false,
7093 message: 'Must be false, a string or an array of strings.'
7094 };
7095 }
7096 },
7097 default: isInline$1(editor) ? [] : ['default']
7098 });
7099 registerOption('content_style', { processor: 'string' });
7100 registerOption('content_css_cors', {
7101 processor: 'boolean',
7102 default: false
7103 });
7104 registerOption('font_css', {
7105 processor: value => {
7106 const valid = isString(value) || isArrayOf(value, isString);
7107 if (valid) {
7108 const newValue = isArray$1(value) ? value : map$3(value.split(','), trim$4);
7109 return {
7110 value: newValue,
7111 valid
7112 };
7113 } else {
7114 return {
7115 valid: false,
7116 message: 'Must be a string or an array of strings.'
7117 };
7118 }
7119 },
7120 default: []
7121 });
7122 registerOption('inline_boundaries', {
7123 processor: 'boolean',
7124 default: true
7125 });
7126 registerOption('inline_boundaries_selector', {
7127 processor: 'string',
7128 default: 'a[href],code,span.mce-annotation'
7129 });
7130 registerOption('object_resizing', {
7131 processor: value => {
7132 const valid = isBoolean(value) || isString(value);
7133 if (valid) {
7134 if (value === false || deviceDetection$1.isiPhone() || deviceDetection$1.isiPad()) {
7135 return {
7136 value: '',
7137 valid
7138 };
7139 } else {
7140 return {
7141 value: value === true ? 'table,img,figure.image,div,video,iframe' : value,
7142 valid
7143 };
7144 }
7145 } else {
7146 return {
7147 valid: false,
7148 message: 'Must be boolean or a string'
7149 };
7150 }
7151 },
7152 default: !isTouch
7153 });
7154 registerOption('resize_img_proportional', {
7155 processor: 'boolean',
7156 default: true
7157 });
7158 registerOption('event_root', { processor: 'string' });
7159 registerOption('service_message', { processor: 'string' });
7160 registerOption('theme', {
7161 processor: value => value === false || isString(value) || isFunction(value),
7162 default: 'silver'
7163 });
7164 registerOption('theme_url', { processor: 'string' });
7165 registerOption('formats', { processor: 'object' });
7166 registerOption('format_empty_lines', {
7167 processor: 'boolean',
7168 default: false
7169 });
7170 registerOption('format_noneditable_selector', {
7171 processor: 'string',
7172 default: ''
7173 });
7174 registerOption('preview_styles', {
7175 processor: value => {
7176 const valid = value === false || isString(value);
7177 if (valid) {
7178 return {
7179 value: value === false ? '' : value,
7180 valid
7181 };
7182 } else {
7183 return {
7184 valid: false,
7185 message: 'Must be false or a string'
7186 };
7187 }
7188 },
7189 default: 'font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow'
7190 });
7191 registerOption('custom_ui_selector', {
7192 processor: 'string',
7193 default: ''
7194 });
7195 registerOption('hidden_input', {
7196 processor: 'boolean',
7197 default: true
7198 });
7199 registerOption('submit_patch', {
7200 processor: 'boolean',
7201 default: true
7202 });
7203 registerOption('encoding', { processor: 'string' });
7204 registerOption('add_form_submit_trigger', {
7205 processor: 'boolean',
7206 default: true
7207 });
7208 registerOption('add_unload_trigger', {
7209 processor: 'boolean',
7210 default: true
7211 });
7212 registerOption('custom_undo_redo_levels', {
7213 processor: 'number',
7214 default: 0
7215 });
7216 registerOption('disable_nodechange', {
7217 processor: 'boolean',
7218 default: false
7219 });
7220 registerOption('readonly', {
7221 processor: 'boolean',
7222 default: false
7223 });
7224 registerOption('editable_root', {
7225 processor: 'boolean',
7226 default: true
7227 });
7228 registerOption('plugins', {
7229 processor: 'string[]',
7230 default: []
7231 });
7232 registerOption('external_plugins', { processor: 'object' });
7233 registerOption('forced_plugins', { processor: 'string[]' });
7234 registerOption('model', {
7235 processor: 'string',
7236 default: editor.hasPlugin('rtc') ? 'plugin' : 'dom'
7237 });
7238 registerOption('model_url', { processor: 'string' });
7239 registerOption('block_unsupported_drop', {
7240 processor: 'boolean',
7241 default: true
7242 });
7243 registerOption('visual', {
7244 processor: 'boolean',
7245 default: true
7246 });
7247 registerOption('visual_table_class', {
7248 processor: 'string',
7249 default: 'mce-item-table'
7250 });
7251 registerOption('visual_anchor_class', {
7252 processor: 'string',
7253 default: 'mce-item-anchor'
7254 });
7255 registerOption('iframe_aria_text', {
7256 processor: 'string',
7257 default: 'Rich Text Area. Press ALT-0 for help.'
7258 });
7259 registerOption('setup', { processor: 'function' });
7260 registerOption('init_instance_callback', { processor: 'function' });
7261 registerOption('url_converter', {
7262 processor: 'function',
7263 default: editor.convertURL
7264 });
7265 registerOption('url_converter_scope', {
7266 processor: 'object',
7267 default: editor
7268 });
7269 registerOption('urlconverter_callback', { processor: 'function' });
7270 registerOption('allow_conditional_comments', {
7271 processor: 'boolean',
7272 default: false
7273 });
7274 registerOption('allow_html_data_urls', {
7275 processor: 'boolean',
7276 default: false
7277 });
7278 registerOption('allow_svg_data_urls', { processor: 'boolean' });
7279 registerOption('allow_html_in_named_anchor', {
7280 processor: 'boolean',
7281 default: false
7282 });
7283 registerOption('allow_script_urls', {
7284 processor: 'boolean',
7285 default: false
7286 });
7287 registerOption('allow_unsafe_link_target', {
7288 processor: 'boolean',
7289 default: false
7290 });
7291 registerOption('convert_fonts_to_spans', {
7292 processor: 'boolean',
7293 default: true,
7294 deprecated: true
7295 });
7296 registerOption('fix_list_elements', {
7297 processor: 'boolean',
7298 default: false
7299 });
7300 registerOption('preserve_cdata', {
7301 processor: 'boolean',
7302 default: false
7303 });
7304 registerOption('remove_trailing_brs', {
7305 processor: 'boolean',
7306 default: true
7307 });
7308 registerOption('pad_empty_with_br', {
7309 processor: 'boolean',
7310 default: false
7311 });
7312 registerOption('inline_styles', {
7313 processor: 'boolean',
7314 default: true,
7315 deprecated: true
7316 });
7317 registerOption('element_format', {
7318 processor: 'string',
7319 default: 'html'
7320 });
7321 registerOption('entities', { processor: 'string' });
7322 registerOption('schema', {
7323 processor: 'string',
7324 default: 'html5'
7325 });
7326 registerOption('convert_urls', {
7327 processor: 'boolean',
7328 default: true
7329 });
7330 registerOption('relative_urls', {
7331 processor: 'boolean',
7332 default: true
7333 });
7334 registerOption('remove_script_host', {
7335 processor: 'boolean',
7336 default: true
7337 });
7338 registerOption('custom_elements', { processor: stringOrObjectProcessor });
7339 registerOption('extended_valid_elements', { processor: 'string' });
7340 registerOption('invalid_elements', { processor: 'string' });
7341 registerOption('invalid_styles', { processor: stringOrObjectProcessor });
7342 registerOption('valid_children', { processor: 'string' });
7343 registerOption('valid_classes', { processor: stringOrObjectProcessor });
7344 registerOption('valid_elements', { processor: 'string' });
7345 registerOption('valid_styles', { processor: stringOrObjectProcessor });
7346 registerOption('verify_html', {
7347 processor: 'boolean',
7348 default: true
7349 });
7350 registerOption('auto_focus', { processor: value => isString(value) || value === true });
7351 registerOption('browser_spellcheck', {
7352 processor: 'boolean',
7353 default: false
7354 });
7355 registerOption('protect', { processor: 'array' });
7356 registerOption('images_file_types', {
7357 processor: 'string',
7358 default: 'jpeg,jpg,jpe,jfi,jif,jfif,png,gif,bmp,webp'
7359 });
7360 registerOption('deprecation_warnings', {
7361 processor: 'boolean',
7362 default: true
7363 });
7364 registerOption('a11y_advanced_options', {
7365 processor: 'boolean',
7366 default: false
7367 });
7368 registerOption('api_key', { processor: 'string' });
7369 registerOption('license_key', { processor: 'string' });
7370 registerOption('paste_block_drop', {
7371 processor: 'boolean',
7372 default: false
7373 });
7374 registerOption('paste_data_images', {
7375 processor: 'boolean',
7376 default: true
7377 });
7378 registerOption('paste_preprocess', { processor: 'function' });
7379 registerOption('paste_postprocess', { processor: 'function' });
7380 registerOption('paste_webkit_styles', {
7381 processor: 'string',
7382 default: 'none'
7383 });
7384 registerOption('paste_remove_styles_if_webkit', {
7385 processor: 'boolean',
7386 default: true
7387 });
7388 registerOption('paste_merge_formats', {
7389 processor: 'boolean',
7390 default: true
7391 });
7392 registerOption('smart_paste', {
7393 processor: 'boolean',
7394 default: true
7395 });
7396 registerOption('paste_as_text', {
7397 processor: 'boolean',
7398 default: false
7399 });
7400 registerOption('paste_tab_spaces', {
7401 processor: 'number',
7402 default: 4
7403 });
7404 registerOption('text_patterns', {
7405 processor: value => {
7406 if (isArrayOf(value, isObject) || value === false) {
7407 const patterns = value === false ? [] : value;
7408 return {
7409 value: fromRawPatterns(patterns),
7410 valid: true
7411 };
7412 } else {
7413 return {
7414 valid: false,
7415 message: 'Must be an array of objects or false.'
7416 };
7417 }
7418 },
7419 default: [
7420 {
7421 start: '*',
7422 end: '*',
7423 format: 'italic'
7424 },
7425 {
7426 start: '**',
7427 end: '**',
7428 format: 'bold'
7429 },
7430 {
7431 start: '#',
7432 format: 'h1',
7433 trigger: 'space'
7434 },
7435 {
7436 start: '##',
7437 format: 'h2',
7438 trigger: 'space'
7439 },
7440 {
7441 start: '###',
7442 format: 'h3',
7443 trigger: 'space'
7444 },
7445 {
7446 start: '####',
7447 format: 'h4',
7448 trigger: 'space'
7449 },
7450 {
7451 start: '#####',
7452 format: 'h5',
7453 trigger: 'space'
7454 },
7455 {
7456 start: '######',
7457 format: 'h6',
7458 trigger: 'space'
7459 },
7460 {
7461 start: '1.',
7462 cmd: 'InsertOrderedList',
7463 trigger: 'space'
7464 },
7465 {
7466 start: '*',
7467 cmd: 'InsertUnorderedList',
7468 trigger: 'space'
7469 },
7470 {
7471 start: '-',
7472 cmd: 'InsertUnorderedList',
7473 trigger: 'space'
7474 },
7475 {
7476 start: '>',
7477 cmd: 'mceBlockQuote',
7478 trigger: 'space'
7479 },
7480 {
7481 start: '---',
7482 cmd: 'InsertHorizontalRule',
7483 trigger: 'space'
7484 }
7485 ]
7486 });
7487 registerOption('text_patterns_lookup', {
7488 processor: value => {
7489 if (isFunction(value)) {
7490 return {
7491 value: fromRawPatternsLookup(value),
7492 valid: true
7493 };
7494 } else {
7495 return {
7496 valid: false,
7497 message: 'Must be a single function'
7498 };
7499 }
7500 },
7501 default: _ctx => []
7502 });
7503 registerOption('noneditable_class', {
7504 processor: 'string',
7505 default: 'mceNonEditable'
7506 });
7507 registerOption('editable_class', {
7508 processor: 'string',
7509 default: 'mceEditable'
7510 });
7511 registerOption('noneditable_regexp', {
7512 processor: value => {
7513 if (isArrayOf(value, isRegExp)) {
7514 return {
7515 value,
7516 valid: true
7517 };
7518 } else if (isRegExp(value)) {
7519 return {
7520 value: [value],
7521 valid: true
7522 };
7523 } else {
7524 return {
7525 valid: false,
7526 message: 'Must be a RegExp or an array of RegExp.'
7527 };
7528 }
7529 },
7530 default: []
7531 });
7532 registerOption('table_tab_navigation', {
7533 processor: 'boolean',
7534 default: true
7535 });
7536 registerOption('highlight_on_focus', {
7537 processor: 'boolean',
7538 default: true
7539 });
7540 registerOption('xss_sanitization', {
7541 processor: 'boolean',
7542 default: true
7543 });
7544 registerOption('details_initial_state', {
7545 processor: value => {
7546 const valid = contains$2([
7547 'inherited',
7548 'collapsed',
7549 'expanded'
7550 ], value);
7551 return valid ? {
7552 value,
7553 valid
7554 } : {
7555 valid: false,
7556 message: 'Must be one of: inherited, collapsed, or expanded.'
7557 };
7558 },
7559 default: 'inherited'
7560 });
7561 registerOption('details_serialized_state', {
7562 processor: value => {
7563 const valid = contains$2([
7564 'inherited',
7565 'collapsed',
7566 'expanded'
7567 ], value);
7568 return valid ? {
7569 value,
7570 valid
7571 } : {
7572 valid: false,
7573 message: 'Must be one of: inherited, collapsed, or expanded.'
7574 };
7575 },
7576 default: 'inherited'
7577 });
7578 registerOption('init_content_sync', {
7579 processor: 'boolean',
7580 default: false
7581 });
7582 registerOption('newdocument_content', {
7583 processor: 'string',
7584 default: ''
7585 });
7586 registerOption('sandbox_iframes', {
7587 processor: 'boolean',
7588 default: true
7589 });
7590 registerOption('sandbox_iframes_exclusions', {
7591 processor: 'string[]',
7592 default: [
7593 'youtube.com',
7594 'youtu.be',
7595 'vimeo.com',
7596 'player.vimeo.com',
7597 'dailymotion.com',
7598 'embed.music.apple.com',
7599 'open.spotify.com',
7600 'giphy.com',
7601 'dai.ly',
7602 'codepen.io'
7603 ]
7604 });
7605 registerOption('convert_unsafe_embeds', {
7606 processor: 'boolean',
7607 default: true
7608 });
7609 editor.on('ScriptsLoaded', () => {
7610 registerOption('directionality', {
7611 processor: 'string',
7612 default: I18n.isRtl() ? 'rtl' : undefined
7613 });
7614 registerOption('placeholder', {
7615 processor: 'string',
7616 default: DOM$a.getAttrib(editor.getElement(), 'placeholder')
7617 });
7618 });
7619 };
7620 const getIframeAttrs = option('iframe_attrs');
7621 const getDocType = option('doctype');
7622 const getDocumentBaseUrl = option('document_base_url');
7623 const getBodyId = option('body_id');
7624 const getBodyClass = option('body_class');
7625 const getContentSecurityPolicy = option('content_security_policy');
7626 const shouldPutBrInPre$1 = option('br_in_pre');
7627 const getForcedRootBlock = option('forced_root_block');
7628 const getForcedRootBlockAttrs = option('forced_root_block_attrs');
7629 const getNewlineBehavior = option('newline_behavior');
7630 const getBrNewLineSelector = option('br_newline_selector');
7631 const getNoNewLineSelector = option('no_newline_selector');
7632 const shouldKeepStyles = option('keep_styles');
7633 const shouldEndContainerOnEmptyBlock = option('end_container_on_empty_block');
7634 const isAutomaticUploadsEnabled = option('automatic_uploads');
7635 const shouldReuseFileName = option('images_reuse_filename');
7636 const shouldReplaceBlobUris = option('images_replace_blob_uris');
7637 const getIconPackName = option('icons');
7638 const getIconsUrl = option('icons_url');
7639 const getImageUploadUrl = option('images_upload_url');
7640 const getImageUploadBasePath = option('images_upload_base_path');
7641 const getImagesUploadCredentials = option('images_upload_credentials');
7642 const getImagesUploadHandler = option('images_upload_handler');
7643 const shouldUseContentCssCors = option('content_css_cors');
7644 const getReferrerPolicy = option('referrer_policy');
7645 const getLanguageCode = option('language');
7646 const getLanguageUrl = option('language_url');
7647 const shouldIndentUseMargin = option('indent_use_margin');
7648 const getIndentation = option('indentation');
7649 const getContentCss = option('content_css');
7650 const getContentStyle = option('content_style');
7651 const getFontCss = option('font_css');
7652 const getDirectionality = option('directionality');
7653 const getInlineBoundarySelector = option('inline_boundaries_selector');
7654 const getObjectResizing = option('object_resizing');
7655 const getResizeImgProportional = option('resize_img_proportional');
7656 const getPlaceholder = option('placeholder');
7657 const getEventRoot = option('event_root');
7658 const getServiceMessage = option('service_message');
7659 const getTheme = option('theme');
7660 const getThemeUrl = option('theme_url');
7661 const getModel = option('model');
7662 const getModelUrl = option('model_url');
7663 const isInlineBoundariesEnabled = option('inline_boundaries');
7664 const getFormats = option('formats');
7665 const getPreviewStyles = option('preview_styles');
7666 const canFormatEmptyLines = option('format_empty_lines');
7667 const getFormatNoneditableSelector = option('format_noneditable_selector');
7668 const getCustomUiSelector = option('custom_ui_selector');
7669 const isInline$1 = option('inline');
7670 const hasHiddenInput = option('hidden_input');
7671 const shouldPatchSubmit = option('submit_patch');
7672 const shouldAddFormSubmitTrigger = option('add_form_submit_trigger');
7673 const shouldAddUnloadTrigger = option('add_unload_trigger');
7674 const getCustomUndoRedoLevels = option('custom_undo_redo_levels');
7675 const shouldDisableNodeChange = option('disable_nodechange');
7676 const isReadOnly$1 = option('readonly');
7677 const hasEditableRoot$1 = option('editable_root');
7678 const hasContentCssCors = option('content_css_cors');
7679 const getPlugins = option('plugins');
7680 const getExternalPlugins$1 = option('external_plugins');
7681 const shouldBlockUnsupportedDrop = option('block_unsupported_drop');
7682 const isVisualAidsEnabled = option('visual');
7683 const getVisualAidsTableClass = option('visual_table_class');
7684 const getVisualAidsAnchorClass = option('visual_anchor_class');
7685 const getIframeAriaText = option('iframe_aria_text');
7686 const getSetupCallback = option('setup');
7687 const getInitInstanceCallback = option('init_instance_callback');
7688 const getUrlConverterCallback = option('urlconverter_callback');
7689 const getAutoFocus = option('auto_focus');
7690 const shouldBrowserSpellcheck = option('browser_spellcheck');
7691 const getProtect = option('protect');
7692 const shouldPasteBlockDrop = option('paste_block_drop');
7693 const shouldPasteDataImages = option('paste_data_images');
7694 const getPastePreProcess = option('paste_preprocess');
7695 const getPastePostProcess = option('paste_postprocess');
7696 const getNewDocumentContent = option('newdocument_content');
7697 const getPasteWebkitStyles = option('paste_webkit_styles');
7698 const shouldPasteRemoveWebKitStyles = option('paste_remove_styles_if_webkit');
7699 const shouldPasteMergeFormats = option('paste_merge_formats');
7700 const isSmartPasteEnabled = option('smart_paste');
7701 const isPasteAsTextEnabled = option('paste_as_text');
7702 const getPasteTabSpaces = option('paste_tab_spaces');
7703 const shouldAllowHtmlDataUrls = option('allow_html_data_urls');
7704 const getTextPatterns = option('text_patterns');
7705 const getTextPatternsLookup = option('text_patterns_lookup');
7706 const getNonEditableClass = option('noneditable_class');
7707 const getEditableClass = option('editable_class');
7708 const getNonEditableRegExps = option('noneditable_regexp');
7709 const shouldPreserveCData = option('preserve_cdata');
7710 const shouldHighlightOnFocus = option('highlight_on_focus');
7711 const shouldSanitizeXss = option('xss_sanitization');
7712 const shouldUseDocumentWrite = option('init_content_sync');
7713 const hasTextPatternsLookup = editor => editor.options.isSet('text_patterns_lookup');
7714 const getFontStyleValues = editor => Tools.explode(editor.options.get('font_size_style_values'));
7715 const getFontSizeClasses = editor => Tools.explode(editor.options.get('font_size_classes'));
7716 const isEncodingXml = editor => editor.options.get('encoding') === 'xml';
7717 const getAllowedImageFileTypes = editor => Tools.explode(editor.options.get('images_file_types'));
7718 const hasTableTabNavigation = option('table_tab_navigation');
7719 const getDetailsInitialState = option('details_initial_state');
7720 const getDetailsSerializedState = option('details_serialized_state');
7721 const shouldSandboxIframes = option('sandbox_iframes');
7722 const getSandboxIframesExclusions = editor => editor.options.get('sandbox_iframes_exclusions');
7723 const shouldConvertUnsafeEmbeds = option('convert_unsafe_embeds');
7724 const getLicenseKey = option('license_key');
7725 const getApiKey = option('api_key');
7726
7727 const isElement$3 = isElement$6;
7728 const isText$5 = isText$b;
7729 const removeNode$1 = node => {
7730 const parentNode = node.parentNode;
7731 if (parentNode) {
7732 parentNode.removeChild(node);
7733 }
7734 };
7735 const trimCount = text => {
7736 const trimmedText = trim$2(text);
7737 return {
7738 count: text.length - trimmedText.length,
7739 text: trimmedText
7740 };
7741 };
7742 const deleteZwspChars = caretContainer => {
7743 let idx;
7744 while ((idx = caretContainer.data.lastIndexOf(ZWSP$1)) !== -1) {
7745 caretContainer.deleteData(idx, 1);
7746 }
7747 };
7748 const removeUnchanged = (caretContainer, pos) => {
7749 remove$2(caretContainer);
7750 return pos;
7751 };
7752 const removeTextAndReposition = (caretContainer, pos) => {
7753 const before = trimCount(caretContainer.data.substr(0, pos.offset()));
7754 const after = trimCount(caretContainer.data.substr(pos.offset()));
7755 const text = before.text + after.text;
7756 if (text.length > 0) {
7757 deleteZwspChars(caretContainer);
7758 return CaretPosition(caretContainer, pos.offset() - before.count);
7759 } else {
7760 return pos;
7761 }
7762 };
7763 const removeElementAndReposition = (caretContainer, pos) => {
7764 const parentNode = pos.container();
7765 const newPosition = indexOf$1(from(parentNode.childNodes), caretContainer).map(index => {
7766 return index < pos.offset() ? CaretPosition(parentNode, pos.offset() - 1) : pos;
7767 }).getOr(pos);
7768 remove$2(caretContainer);
7769 return newPosition;
7770 };
7771 const removeTextCaretContainer = (caretContainer, pos) => isText$5(caretContainer) && pos.container() === caretContainer ? removeTextAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
7772 const removeElementCaretContainer = (caretContainer, pos) => pos.container() === caretContainer.parentNode ? removeElementAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
7773 const removeAndReposition = (container, pos) => CaretPosition.isTextPosition(pos) ? removeTextCaretContainer(container, pos) : removeElementCaretContainer(container, pos);
7774 const remove$2 = caretContainerNode => {
7775 if (isElement$3(caretContainerNode) && isCaretContainer$2(caretContainerNode)) {
7776 if (hasContent(caretContainerNode)) {
7777 caretContainerNode.removeAttribute('data-mce-caret');
7778 } else {
7779 removeNode$1(caretContainerNode);
7780 }
7781 }
7782 if (isText$5(caretContainerNode)) {
7783 deleteZwspChars(caretContainerNode);
7784 if (caretContainerNode.data.length === 0) {
7785 removeNode$1(caretContainerNode);
7786 }
7787 }
7788 };
7789
7790 const isContentEditableFalse$8 = isContentEditableFalse$b;
7791 const isMedia$1 = isMedia$2;
7792 const isTableCell$1 = isTableCell$3;
7793 const inlineFakeCaretSelector = '*[contentEditable=false],video,audio,embed,object';
7794 const getAbsoluteClientRect = (root, element, before) => {
7795 const clientRect = collapse(element.getBoundingClientRect(), before);
7796 let scrollX;
7797 let scrollY;
7798 if (root.tagName === 'BODY') {
7799 const docElm = root.ownerDocument.documentElement;
7800 scrollX = root.scrollLeft || docElm.scrollLeft;
7801 scrollY = root.scrollTop || docElm.scrollTop;
7802 } else {
7803 const rootRect = root.getBoundingClientRect();
7804 scrollX = root.scrollLeft - rootRect.left;
7805 scrollY = root.scrollTop - rootRect.top;
7806 }
7807 clientRect.left += scrollX;
7808 clientRect.right += scrollX;
7809 clientRect.top += scrollY;
7810 clientRect.bottom += scrollY;
7811 clientRect.width = 1;
7812 let margin = element.offsetWidth - element.clientWidth;
7813 if (margin > 0) {
7814 if (before) {
7815 margin *= -1;
7816 }
7817 clientRect.left += margin;
7818 clientRect.right += margin;
7819 }
7820 return clientRect;
7821 };
7822 const trimInlineCaretContainers = root => {
7823 var _a, _b;
7824 const fakeCaretTargetNodes = descendants(SugarElement.fromDom(root), inlineFakeCaretSelector);
7825 for (let i = 0; i < fakeCaretTargetNodes.length; i++) {
7826 const node = fakeCaretTargetNodes[i].dom;
7827 let sibling = node.previousSibling;
7828 if (endsWithCaretContainer$1(sibling)) {
7829 const data = sibling.data;
7830 if (data.length === 1) {
7831 (_a = sibling.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(sibling);
7832 } else {
7833 sibling.deleteData(data.length - 1, 1);
7834 }
7835 }
7836 sibling = node.nextSibling;
7837 if (startsWithCaretContainer$1(sibling)) {
7838 const data = sibling.data;
7839 if (data.length === 1) {
7840 (_b = sibling.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(sibling);
7841 } else {
7842 sibling.deleteData(0, 1);
7843 }
7844 }
7845 }
7846 };
7847 const FakeCaret = (editor, root, isBlock, hasFocus) => {
7848 const lastVisualCaret = value$2();
7849 let cursorInterval;
7850 let caretContainerNode;
7851 const caretBlock = getForcedRootBlock(editor);
7852 const dom = editor.dom;
7853 const show = (before, element) => {
7854 let rng;
7855 hide();
7856 if (isTableCell$1(element)) {
7857 return null;
7858 }
7859 if (isBlock(element)) {
7860 const caretContainer = insertBlock(caretBlock, element, before);
7861 const clientRect = getAbsoluteClientRect(root, element, before);
7862 dom.setStyle(caretContainer, 'top', clientRect.top);
7863 dom.setStyle(caretContainer, 'caret-color', 'transparent');
7864 caretContainerNode = caretContainer;
7865 const caret = dom.create('div', {
7866 'class': 'mce-visual-caret',
7867 'data-mce-bogus': 'all'
7868 });
7869 dom.setStyles(caret, { ...clientRect });
7870 dom.add(root, caret);
7871 lastVisualCaret.set({
7872 caret,
7873 element,
7874 before
7875 });
7876 if (before) {
7877 dom.addClass(caret, 'mce-visual-caret-before');
7878 }
7879 startBlink();
7880 rng = element.ownerDocument.createRange();
7881 rng.setStart(caretContainer, 0);
7882 rng.setEnd(caretContainer, 0);
7883 } else {
7884 caretContainerNode = insertInline$1(element, before);
7885 rng = element.ownerDocument.createRange();
7886 if (isInlineFakeCaretTarget(caretContainerNode.nextSibling)) {
7887 rng.setStart(caretContainerNode, 0);
7888 rng.setEnd(caretContainerNode, 0);
7889 } else {
7890 rng.setStart(caretContainerNode, 1);
7891 rng.setEnd(caretContainerNode, 1);
7892 }
7893 return rng;
7894 }
7895 return rng;
7896 };
7897 const hide = () => {
7898 trimInlineCaretContainers(root);
7899 if (caretContainerNode) {
7900 remove$2(caretContainerNode);
7901 caretContainerNode = null;
7902 }
7903 lastVisualCaret.on(caretState => {
7904 dom.remove(caretState.caret);
7905 lastVisualCaret.clear();
7906 });
7907 if (cursorInterval) {
7908 clearInterval(cursorInterval);
7909 cursorInterval = undefined;
7910 }
7911 };
7912 const startBlink = () => {
7913 cursorInterval = setInterval(() => {
7914 lastVisualCaret.on(caretState => {
7915 if (hasFocus()) {
7916 dom.toggleClass(caretState.caret, 'mce-visual-caret-hidden');
7917 } else {
7918 dom.addClass(caretState.caret, 'mce-visual-caret-hidden');
7919 }
7920 });
7921 }, 500);
7922 };
7923 const reposition = () => {
7924 lastVisualCaret.on(caretState => {
7925 const clientRect = getAbsoluteClientRect(root, caretState.element, caretState.before);
7926 dom.setStyles(caretState.caret, { ...clientRect });
7927 });
7928 };
7929 const destroy = () => clearInterval(cursorInterval);
7930 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;' + '}';
7931 return {
7932 show,
7933 hide,
7934 getCss,
7935 reposition,
7936 destroy
7937 };
7938 };
7939 const isFakeCaretTableBrowser = () => Env.browser.isFirefox();
7940 const isInlineFakeCaretTarget = node => isContentEditableFalse$8(node) || isMedia$1(node);
7941 const isFakeCaretTarget = node => {
7942 const isTarget = isInlineFakeCaretTarget(node) || isTable$2(node) && isFakeCaretTableBrowser();
7943 return isTarget && parentElement(SugarElement.fromDom(node)).exists(isEditable$2);
7944 };
7945
7946 const isContentEditableTrue$1 = isContentEditableTrue$3;
7947 const isContentEditableFalse$7 = isContentEditableFalse$b;
7948 const isMedia = isMedia$2;
7949 const isBlockLike = matchStyleValues('display', 'block table table-cell table-caption list-item');
7950 const isCaretContainer = isCaretContainer$2;
7951 const isCaretContainerBlock = isCaretContainerBlock$1;
7952 const isElement$2 = isElement$6;
7953 const isText$4 = isText$b;
7954 const isCaretCandidate$1 = isCaretCandidate$3;
7955 const isForwards = direction => direction > 0;
7956 const isBackwards = direction => direction < 0;
7957 const skipCaretContainers = (walk, shallow) => {
7958 let node;
7959 while (node = walk(shallow)) {
7960 if (!isCaretContainerBlock(node)) {
7961 return node;
7962 }
7963 }
7964 return null;
7965 };
7966 const findNode = (node, direction, predicateFn, rootNode, shallow) => {
7967 const walker = new DomTreeWalker(node, rootNode);
7968 const isCefOrCaretContainer = isContentEditableFalse$7(node) || isCaretContainerBlock(node);
7969 let tempNode;
7970 if (isBackwards(direction)) {
7971 if (isCefOrCaretContainer) {
7972 tempNode = skipCaretContainers(walker.prev.bind(walker), true);
7973 if (predicateFn(tempNode)) {
7974 return tempNode;
7975 }
7976 }
7977 while (tempNode = skipCaretContainers(walker.prev.bind(walker), shallow)) {
7978 if (predicateFn(tempNode)) {
7979 return tempNode;
7980 }
7981 }
7982 }
7983 if (isForwards(direction)) {
7984 if (isCefOrCaretContainer) {
7985 tempNode = skipCaretContainers(walker.next.bind(walker), true);
7986 if (predicateFn(tempNode)) {
7987 return tempNode;
7988 }
7989 }
7990 while (tempNode = skipCaretContainers(walker.next.bind(walker), shallow)) {
7991 if (predicateFn(tempNode)) {
7992 return tempNode;
7993 }
7994 }
7995 }
7996 return null;
7997 };
7998 const getEditingHost = (node, rootNode) => {
7999 const isCETrue = node => isContentEditableTrue$1(node.dom);
8000 const isRoot = node => node.dom === rootNode;
8001 return ancestor$4(SugarElement.fromDom(node), isCETrue, isRoot).map(elm => elm.dom).getOr(rootNode);
8002 };
8003 const getParentBlock$3 = (node, rootNode) => {
8004 while (node && node !== rootNode) {
8005 if (isBlockLike(node)) {
8006 return node;
8007 }
8008 node = node.parentNode;
8009 }
8010 return null;
8011 };
8012 const isInSameBlock = (caretPosition1, caretPosition2, rootNode) => getParentBlock$3(caretPosition1.container(), rootNode) === getParentBlock$3(caretPosition2.container(), rootNode);
8013 const getChildNodeAtRelativeOffset = (relativeOffset, caretPosition) => {
8014 if (!caretPosition) {
8015 return Optional.none();
8016 }
8017 const container = caretPosition.container();
8018 const offset = caretPosition.offset();
8019 if (!isElement$2(container)) {
8020 return Optional.none();
8021 }
8022 return Optional.from(container.childNodes[offset + relativeOffset]);
8023 };
8024 const beforeAfter = (before, node) => {
8025 var _a;
8026 const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
8027 const range = doc.createRange();
8028 if (before) {
8029 range.setStartBefore(node);
8030 range.setEndBefore(node);
8031 } else {
8032 range.setStartAfter(node);
8033 range.setEndAfter(node);
8034 }
8035 return range;
8036 };
8037 const isNodesInSameBlock = (root, node1, node2) => getParentBlock$3(node1, root) === getParentBlock$3(node2, root);
8038 const lean = (left, root, node) => {
8039 const siblingName = left ? 'previousSibling' : 'nextSibling';
8040 let tempNode = node;
8041 while (tempNode && tempNode !== root) {
8042 let sibling = tempNode[siblingName];
8043 if (sibling && isCaretContainer(sibling)) {
8044 sibling = sibling[siblingName];
8045 }
8046 if (isContentEditableFalse$7(sibling) || isMedia(sibling)) {
8047 if (isNodesInSameBlock(root, sibling, tempNode)) {
8048 return sibling;
8049 }
8050 break;
8051 }
8052 if (isCaretCandidate$1(sibling)) {
8053 break;
8054 }
8055 tempNode = tempNode.parentNode;
8056 }
8057 return null;
8058 };
8059 const before$2 = curry(beforeAfter, true);
8060 const after$2 = curry(beforeAfter, false);
8061 const normalizeRange = (direction, root, range) => {
8062 let node;
8063 const leanLeft = curry(lean, true, root);
8064 const leanRight = curry(lean, false, root);
8065 const container = range.startContainer;
8066 const offset = range.startOffset;
8067 if (isCaretContainerBlock$1(container)) {
8068 const block = isText$4(container) ? container.parentNode : container;
8069 const location = block.getAttribute('data-mce-caret');
8070 if (location === 'before') {
8071 node = block.nextSibling;
8072 if (isFakeCaretTarget(node)) {
8073 return before$2(node);
8074 }
8075 }
8076 if (location === 'after') {
8077 node = block.previousSibling;
8078 if (isFakeCaretTarget(node)) {
8079 return after$2(node);
8080 }
8081 }
8082 }
8083 if (!range.collapsed) {
8084 return range;
8085 }
8086 if (isText$b(container)) {
8087 if (isCaretContainer(container)) {
8088 if (direction === 1) {
8089 node = leanRight(container);
8090 if (node) {
8091 return before$2(node);
8092 }
8093 node = leanLeft(container);
8094 if (node) {
8095 return after$2(node);
8096 }
8097 }
8098 if (direction === -1) {
8099 node = leanLeft(container);
8100 if (node) {
8101 return after$2(node);
8102 }
8103 node = leanRight(container);
8104 if (node) {
8105 return before$2(node);
8106 }
8107 }
8108 return range;
8109 }
8110 if (endsWithCaretContainer$1(container) && offset >= container.data.length - 1) {
8111 if (direction === 1) {
8112 node = leanRight(container);
8113 if (node) {
8114 return before$2(node);
8115 }
8116 }
8117 return range;
8118 }
8119 if (startsWithCaretContainer$1(container) && offset <= 1) {
8120 if (direction === -1) {
8121 node = leanLeft(container);
8122 if (node) {
8123 return after$2(node);
8124 }
8125 }
8126 return range;
8127 }
8128 if (offset === container.data.length) {
8129 node = leanRight(container);
8130 if (node) {
8131 return before$2(node);
8132 }
8133 return range;
8134 }
8135 if (offset === 0) {
8136 node = leanLeft(container);
8137 if (node) {
8138 return after$2(node);
8139 }
8140 return range;
8141 }
8142 }
8143 return range;
8144 };
8145 const getRelativeCefElm = (forward, caretPosition) => getChildNodeAtRelativeOffset(forward ? 0 : -1, caretPosition).filter(isContentEditableFalse$7);
8146 const getNormalizedRangeEndPoint = (direction, root, range) => {
8147 const normalizedRange = normalizeRange(direction, root, range);
8148 return direction === -1 ? CaretPosition.fromRangeStart(normalizedRange) : CaretPosition.fromRangeEnd(normalizedRange);
8149 };
8150 const getElementFromPosition = pos => Optional.from(pos.getNode()).map(SugarElement.fromDom);
8151 const getElementFromPrevPosition = pos => Optional.from(pos.getNode(true)).map(SugarElement.fromDom);
8152 const getVisualCaretPosition = (walkFn, caretPosition) => {
8153 let pos = caretPosition;
8154 while (pos = walkFn(pos)) {
8155 if (pos.isVisible()) {
8156 return pos;
8157 }
8158 }
8159 return pos;
8160 };
8161 const isMoveInsideSameBlock = (from, to) => {
8162 const inSameBlock = isInSameBlock(from, to);
8163 if (!inSameBlock && isBr$6(from.getNode())) {
8164 return true;
8165 }
8166 return inSameBlock;
8167 };
8168
8169 var HDirection;
8170 (function (HDirection) {
8171 HDirection[HDirection['Backwards'] = -1] = 'Backwards';
8172 HDirection[HDirection['Forwards'] = 1] = 'Forwards';
8173 }(HDirection || (HDirection = {})));
8174 const isContentEditableFalse$6 = isContentEditableFalse$b;
8175 const isText$3 = isText$b;
8176 const isElement$1 = isElement$6;
8177 const isBr$2 = isBr$6;
8178 const isCaretCandidate = isCaretCandidate$3;
8179 const isAtomic = isAtomic$1;
8180 const isEditableCaretCandidate = isEditableCaretCandidate$1;
8181 const getParents$3 = (node, root) => {
8182 const parents = [];
8183 let tempNode = node;
8184 while (tempNode && tempNode !== root) {
8185 parents.push(tempNode);
8186 tempNode = tempNode.parentNode;
8187 }
8188 return parents;
8189 };
8190 const nodeAtIndex = (container, offset) => {
8191 if (container.hasChildNodes() && offset < container.childNodes.length) {
8192 return container.childNodes[offset];
8193 }
8194 return null;
8195 };
8196 const getCaretCandidatePosition = (direction, node) => {
8197 if (isForwards(direction)) {
8198 if (isCaretCandidate(node.previousSibling) && !isText$3(node.previousSibling)) {
8199 return CaretPosition.before(node);
8200 }
8201 if (isText$3(node)) {
8202 return CaretPosition(node, 0);
8203 }
8204 }
8205 if (isBackwards(direction)) {
8206 if (isCaretCandidate(node.nextSibling) && !isText$3(node.nextSibling)) {
8207 return CaretPosition.after(node);
8208 }
8209 if (isText$3(node)) {
8210 return CaretPosition(node, node.data.length);
8211 }
8212 }
8213 if (isBackwards(direction)) {
8214 if (isBr$2(node)) {
8215 return CaretPosition.before(node);
8216 }
8217 return CaretPosition.after(node);
8218 }
8219 return CaretPosition.before(node);
8220 };
8221 const moveForwardFromBr = (root, nextNode) => {
8222 const nextSibling = nextNode.nextSibling;
8223 if (nextSibling && isCaretCandidate(nextSibling)) {
8224 if (isText$3(nextSibling)) {
8225 return CaretPosition(nextSibling, 0);
8226 } else {
8227 return CaretPosition.before(nextSibling);
8228 }
8229 } else {
8230 return findCaretPosition$1(HDirection.Forwards, CaretPosition.after(nextNode), root);
8231 }
8232 };
8233 const findCaretPosition$1 = (direction, startPos, root) => {
8234 let node;
8235 let nextNode;
8236 let innerNode;
8237 let caretPosition;
8238 if (!isElement$1(root) || !startPos) {
8239 return null;
8240 }
8241 if (startPos.isEqual(CaretPosition.after(root)) && root.lastChild) {
8242 caretPosition = CaretPosition.after(root.lastChild);
8243 if (isBackwards(direction) && isCaretCandidate(root.lastChild) && isElement$1(root.lastChild)) {
8244 return isBr$2(root.lastChild) ? CaretPosition.before(root.lastChild) : caretPosition;
8245 }
8246 } else {
8247 caretPosition = startPos;
8248 }
8249 const container = caretPosition.container();
8250 let offset = caretPosition.offset();
8251 if (isText$3(container)) {
8252 if (isBackwards(direction) && offset > 0) {
8253 return CaretPosition(container, --offset);
8254 }
8255 if (isForwards(direction) && offset < container.length) {
8256 return CaretPosition(container, ++offset);
8257 }
8258 node = container;
8259 } else {
8260 if (isBackwards(direction) && offset > 0) {
8261 nextNode = nodeAtIndex(container, offset - 1);
8262 if (isCaretCandidate(nextNode)) {
8263 if (!isAtomic(nextNode)) {
8264 innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
8265 if (innerNode) {
8266 if (isText$3(innerNode)) {
8267 return CaretPosition(innerNode, innerNode.data.length);
8268 }
8269 return CaretPosition.after(innerNode);
8270 }
8271 }
8272 if (isText$3(nextNode)) {
8273 return CaretPosition(nextNode, nextNode.data.length);
8274 }
8275 return CaretPosition.before(nextNode);
8276 }
8277 }
8278 if (isForwards(direction) && offset < container.childNodes.length) {
8279 nextNode = nodeAtIndex(container, offset);
8280 if (isCaretCandidate(nextNode)) {
8281 if (isBr$2(nextNode)) {
8282 return moveForwardFromBr(root, nextNode);
8283 }
8284 if (!isAtomic(nextNode)) {
8285 innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
8286 if (innerNode) {
8287 if (isText$3(innerNode)) {
8288 return CaretPosition(innerNode, 0);
8289 }
8290 return CaretPosition.before(innerNode);
8291 }
8292 }
8293 if (isText$3(nextNode)) {
8294 return CaretPosition(nextNode, 0);
8295 }
8296 return CaretPosition.after(nextNode);
8297 }
8298 }
8299 node = nextNode ? nextNode : caretPosition.getNode();
8300 }
8301 if (node && (isForwards(direction) && caretPosition.isAtEnd() || isBackwards(direction) && caretPosition.isAtStart())) {
8302 node = findNode(node, direction, always, root, true);
8303 if (isEditableCaretCandidate(node, root)) {
8304 return getCaretCandidatePosition(direction, node);
8305 }
8306 }
8307 nextNode = node ? findNode(node, direction, isEditableCaretCandidate, root) : node;
8308 const rootContentEditableFalseElm = last$1(filter$5(getParents$3(container, root), isContentEditableFalse$6));
8309 if (rootContentEditableFalseElm && (!nextNode || !rootContentEditableFalseElm.contains(nextNode))) {
8310 if (isForwards(direction)) {
8311 caretPosition = CaretPosition.after(rootContentEditableFalseElm);
8312 } else {
8313 caretPosition = CaretPosition.before(rootContentEditableFalseElm);
8314 }
8315 return caretPosition;
8316 }
8317 if (nextNode) {
8318 return getCaretCandidatePosition(direction, nextNode);
8319 }
8320 return null;
8321 };
8322 const CaretWalker = root => ({
8323 next: caretPosition => {
8324 return findCaretPosition$1(HDirection.Forwards, caretPosition, root);
8325 },
8326 prev: caretPosition => {
8327 return findCaretPosition$1(HDirection.Backwards, caretPosition, root);
8328 }
8329 });
8330
8331 const walkToPositionIn = (forward, root, start) => {
8332 const position = forward ? CaretPosition.before(start) : CaretPosition.after(start);
8333 return fromPosition(forward, root, position);
8334 };
8335 const afterElement = node => isBr$6(node) ? CaretPosition.before(node) : CaretPosition.after(node);
8336 const isBeforeOrStart = position => {
8337 if (CaretPosition.isTextPosition(position)) {
8338 return position.offset() === 0;
8339 } else {
8340 return isCaretCandidate$3(position.getNode());
8341 }
8342 };
8343 const isAfterOrEnd = position => {
8344 if (CaretPosition.isTextPosition(position)) {
8345 const container = position.container();
8346 return position.offset() === container.data.length;
8347 } else {
8348 return isCaretCandidate$3(position.getNode(true));
8349 }
8350 };
8351 const isBeforeAfterSameElement = (from, to) => !CaretPosition.isTextPosition(from) && !CaretPosition.isTextPosition(to) && from.getNode() === to.getNode(true);
8352 const isAtBr = position => !CaretPosition.isTextPosition(position) && isBr$6(position.getNode());
8353 const shouldSkipPosition = (forward, from, to) => {
8354 if (forward) {
8355 return !isBeforeAfterSameElement(from, to) && !isAtBr(from) && isAfterOrEnd(from) && isBeforeOrStart(to);
8356 } else {
8357 return !isBeforeAfterSameElement(to, from) && isBeforeOrStart(from) && isAfterOrEnd(to);
8358 }
8359 };
8360 const fromPosition = (forward, root, pos) => {
8361 const walker = CaretWalker(root);
8362 return Optional.from(forward ? walker.next(pos) : walker.prev(pos));
8363 };
8364 const navigate = (forward, root, from) => fromPosition(forward, root, from).bind(to => {
8365 if (isInSameBlock(from, to, root) && shouldSkipPosition(forward, from, to)) {
8366 return fromPosition(forward, root, to);
8367 } else {
8368 return Optional.some(to);
8369 }
8370 });
8371 const navigateIgnore = (forward, root, from, ignoreFilter) => navigate(forward, root, from).bind(pos => ignoreFilter(pos) ? navigateIgnore(forward, root, pos, ignoreFilter) : Optional.some(pos));
8372 const positionIn = (forward, element) => {
8373 const startNode = forward ? element.firstChild : element.lastChild;
8374 if (isText$b(startNode)) {
8375 return Optional.some(CaretPosition(startNode, forward ? 0 : startNode.data.length));
8376 } else if (startNode) {
8377 if (isCaretCandidate$3(startNode)) {
8378 return Optional.some(forward ? CaretPosition.before(startNode) : afterElement(startNode));
8379 } else {
8380 return walkToPositionIn(forward, element, startNode);
8381 }
8382 } else {
8383 return Optional.none();
8384 }
8385 };
8386 const nextPosition = curry(fromPosition, true);
8387 const prevPosition = curry(fromPosition, false);
8388 const firstPositionIn = curry(positionIn, true);
8389 const lastPositionIn = curry(positionIn, false);
8390
8391 const CARET_ID = '_mce_caret';
8392 const isCaretNode = node => isElement$6(node) && node.id === CARET_ID;
8393 const getParentCaretContainer = (body, node) => {
8394 let currentNode = node;
8395 while (currentNode && currentNode !== body) {
8396 if (isCaretNode(currentNode)) {
8397 return currentNode;
8398 }
8399 currentNode = currentNode.parentNode;
8400 }
8401 return null;
8402 };
8403
8404 const isStringPathBookmark = bookmark => isString(bookmark.start);
8405 const isRangeBookmark = bookmark => has$2(bookmark, 'rng');
8406 const isIdBookmark = bookmark => has$2(bookmark, 'id');
8407 const isIndexBookmark = bookmark => has$2(bookmark, 'name');
8408 const isPathBookmark = bookmark => Tools.isArray(bookmark.start);
8409
8410 const isForwardBookmark = bookmark => !isIndexBookmark(bookmark) && isBoolean(bookmark.forward) ? bookmark.forward : true;
8411 const addBogus = (dom, node) => {
8412 if (isElement$6(node) && dom.isBlock(node) && !node.innerHTML) {
8413 node.innerHTML = '<br data-mce-bogus="1" />';
8414 }
8415 return node;
8416 };
8417 const resolveCaretPositionBookmark = (dom, bookmark) => {
8418 const startPos = Optional.from(resolve$1(dom.getRoot(), bookmark.start));
8419 const endPos = Optional.from(resolve$1(dom.getRoot(), bookmark.end));
8420 return lift2(startPos, endPos, (start, end) => {
8421 const range = dom.createRng();
8422 range.setStart(start.container(), start.offset());
8423 range.setEnd(end.container(), end.offset());
8424 return {
8425 range,
8426 forward: isForwardBookmark(bookmark)
8427 };
8428 });
8429 };
8430 const insertZwsp = (node, rng) => {
8431 var _a;
8432 const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
8433 const textNode = doc.createTextNode(ZWSP$1);
8434 node.appendChild(textNode);
8435 rng.setStart(textNode, 0);
8436 rng.setEnd(textNode, 0);
8437 };
8438 const isEmpty$1 = node => !node.hasChildNodes();
8439 const tryFindRangePosition = (node, rng) => lastPositionIn(node).fold(never, pos => {
8440 rng.setStart(pos.container(), pos.offset());
8441 rng.setEnd(pos.container(), pos.offset());
8442 return true;
8443 });
8444 const padEmptyCaretContainer = (root, node, rng) => {
8445 if (isEmpty$1(node) && getParentCaretContainer(root, node)) {
8446 insertZwsp(node, rng);
8447 return true;
8448 } else {
8449 return false;
8450 }
8451 };
8452 const setEndPoint = (dom, start, bookmark, rng) => {
8453 const point = bookmark[start ? 'start' : 'end'];
8454 const root = dom.getRoot();
8455 if (point) {
8456 let node = root;
8457 let offset = point[0];
8458 for (let i = point.length - 1; node && i >= 1; i--) {
8459 const children = node.childNodes;
8460 if (padEmptyCaretContainer(root, node, rng)) {
8461 return true;
8462 }
8463 if (point[i] > children.length - 1) {
8464 if (padEmptyCaretContainer(root, node, rng)) {
8465 return true;
8466 }
8467 return tryFindRangePosition(node, rng);
8468 }
8469 node = children[point[i]];
8470 }
8471 if (isText$b(node)) {
8472 offset = Math.min(point[0], node.data.length);
8473 }
8474 if (isElement$6(node)) {
8475 offset = Math.min(point[0], node.childNodes.length);
8476 }
8477 if (start) {
8478 rng.setStart(node, offset);
8479 } else {
8480 rng.setEnd(node, offset);
8481 }
8482 }
8483 return true;
8484 };
8485 const isValidTextNode = node => isText$b(node) && node.data.length > 0;
8486 const restoreEndPoint = (dom, suffix, bookmark) => {
8487 const marker = dom.get(bookmark.id + '_' + suffix);
8488 const markerParent = marker === null || marker === void 0 ? void 0 : marker.parentNode;
8489 const keep = bookmark.keep;
8490 if (marker && markerParent) {
8491 let container;
8492 let offset;
8493 if (suffix === 'start') {
8494 if (!keep) {
8495 container = markerParent;
8496 offset = dom.nodeIndex(marker);
8497 } else {
8498 if (marker.hasChildNodes()) {
8499 container = marker.firstChild;
8500 offset = 1;
8501 } else if (isValidTextNode(marker.nextSibling)) {
8502 container = marker.nextSibling;
8503 offset = 0;
8504 } else if (isValidTextNode(marker.previousSibling)) {
8505 container = marker.previousSibling;
8506 offset = marker.previousSibling.data.length;
8507 } else {
8508 container = markerParent;
8509 offset = dom.nodeIndex(marker) + 1;
8510 }
8511 }
8512 } else {
8513 if (!keep) {
8514 container = markerParent;
8515 offset = dom.nodeIndex(marker);
8516 } else {
8517 if (marker.hasChildNodes()) {
8518 container = marker.firstChild;
8519 offset = 1;
8520 } else if (isValidTextNode(marker.previousSibling)) {
8521 container = marker.previousSibling;
8522 offset = marker.previousSibling.data.length;
8523 } else {
8524 container = markerParent;
8525 offset = dom.nodeIndex(marker);
8526 }
8527 }
8528 }
8529 if (!keep) {
8530 const prev = marker.previousSibling;
8531 const next = marker.nextSibling;
8532 Tools.each(Tools.grep(marker.childNodes), node => {
8533 if (isText$b(node)) {
8534 node.data = node.data.replace(/\uFEFF/g, '');
8535 }
8536 });
8537 let otherMarker;
8538 while (otherMarker = dom.get(bookmark.id + '_' + suffix)) {
8539 dom.remove(otherMarker, true);
8540 }
8541 if (isText$b(next) && isText$b(prev) && !Env.browser.isOpera()) {
8542 const idx = prev.data.length;
8543 prev.appendData(next.data);
8544 dom.remove(next);
8545 container = prev;
8546 offset = idx;
8547 }
8548 }
8549 return Optional.some(CaretPosition(container, offset));
8550 } else {
8551 return Optional.none();
8552 }
8553 };
8554 const resolvePaths = (dom, bookmark) => {
8555 const range = dom.createRng();
8556 if (setEndPoint(dom, true, bookmark, range) && setEndPoint(dom, false, bookmark, range)) {
8557 return Optional.some({
8558 range,
8559 forward: isForwardBookmark(bookmark)
8560 });
8561 } else {
8562 return Optional.none();
8563 }
8564 };
8565 const resolveId = (dom, bookmark) => {
8566 const startPos = restoreEndPoint(dom, 'start', bookmark);
8567 const endPos = restoreEndPoint(dom, 'end', bookmark);
8568 return lift2(startPos, endPos.or(startPos), (spos, epos) => {
8569 const range = dom.createRng();
8570 range.setStart(addBogus(dom, spos.container()), spos.offset());
8571 range.setEnd(addBogus(dom, epos.container()), epos.offset());
8572 return {
8573 range,
8574 forward: isForwardBookmark(bookmark)
8575 };
8576 });
8577 };
8578 const resolveIndex = (dom, bookmark) => Optional.from(dom.select(bookmark.name)[bookmark.index]).map(elm => {
8579 const range = dom.createRng();
8580 range.selectNode(elm);
8581 return {
8582 range,
8583 forward: true
8584 };
8585 });
8586 const resolve = (selection, bookmark) => {
8587 const dom = selection.dom;
8588 if (bookmark) {
8589 if (isPathBookmark(bookmark)) {
8590 return resolvePaths(dom, bookmark);
8591 } else if (isStringPathBookmark(bookmark)) {
8592 return resolveCaretPositionBookmark(dom, bookmark);
8593 } else if (isIdBookmark(bookmark)) {
8594 return resolveId(dom, bookmark);
8595 } else if (isIndexBookmark(bookmark)) {
8596 return resolveIndex(dom, bookmark);
8597 } else if (isRangeBookmark(bookmark)) {
8598 return Optional.some({
8599 range: bookmark.rng,
8600 forward: isForwardBookmark(bookmark)
8601 });
8602 }
8603 }
8604 return Optional.none();
8605 };
8606
8607 const getBookmark$1 = (selection, type, normalized) => {
8608 return getBookmark$2(selection, type, normalized);
8609 };
8610 const moveToBookmark = (selection, bookmark) => {
8611 resolve(selection, bookmark).each(({range, forward}) => {
8612 selection.setRng(range, forward);
8613 });
8614 };
8615 const isBookmarkNode$1 = node => {
8616 return isElement$6(node) && node.tagName === 'SPAN' && node.getAttribute('data-mce-type') === 'bookmark';
8617 };
8618
8619 const is = expected => actual => expected === actual;
8620 const isNbsp = is(nbsp);
8621 const isWhiteSpace = chr => chr !== '' && ' \f\n\r\t\x0B'.indexOf(chr) !== -1;
8622 const isContent = chr => !isWhiteSpace(chr) && !isNbsp(chr) && !isZwsp$2(chr);
8623
8624 const getRanges$1 = selection => {
8625 const ranges = [];
8626 if (selection) {
8627 for (let i = 0; i < selection.rangeCount; i++) {
8628 ranges.push(selection.getRangeAt(i));
8629 }
8630 }
8631 return ranges;
8632 };
8633 const getSelectedNodes = ranges => {
8634 return bind$3(ranges, range => {
8635 const node = getSelectedNode(range);
8636 return node ? [SugarElement.fromDom(node)] : [];
8637 });
8638 };
8639 const hasMultipleRanges = selection => {
8640 return getRanges$1(selection).length > 1;
8641 };
8642
8643 const getCellsFromRanges = ranges => filter$5(getSelectedNodes(ranges), isTableCell$2);
8644 const getCellsFromElement = elm => descendants(elm, 'td[data-mce-selected],th[data-mce-selected]');
8645 const getCellsFromElementOrRanges = (ranges, element) => {
8646 const selectedCells = getCellsFromElement(element);
8647 return selectedCells.length > 0 ? selectedCells : getCellsFromRanges(ranges);
8648 };
8649 const getCellsFromEditor = editor => getCellsFromElementOrRanges(getRanges$1(editor.selection.getSel()), SugarElement.fromDom(editor.getBody()));
8650 const getClosestTable = (cell, isRoot) => ancestor$3(cell, 'table', isRoot);
8651
8652 const getStartNode = rng => {
8653 const sc = rng.startContainer, so = rng.startOffset;
8654 if (isText$b(sc)) {
8655 return so === 0 ? Optional.some(SugarElement.fromDom(sc)) : Optional.none();
8656 } else {
8657 return Optional.from(sc.childNodes[so]).map(SugarElement.fromDom);
8658 }
8659 };
8660 const getEndNode = rng => {
8661 const ec = rng.endContainer, eo = rng.endOffset;
8662 if (isText$b(ec)) {
8663 return eo === ec.data.length ? Optional.some(SugarElement.fromDom(ec)) : Optional.none();
8664 } else {
8665 return Optional.from(ec.childNodes[eo - 1]).map(SugarElement.fromDom);
8666 }
8667 };
8668 const getFirstChildren = node => {
8669 return firstChild(node).fold(constant([node]), child => {
8670 return [node].concat(getFirstChildren(child));
8671 });
8672 };
8673 const getLastChildren = node => {
8674 return lastChild(node).fold(constant([node]), child => {
8675 if (name(child) === 'br') {
8676 return prevSibling(child).map(sibling => {
8677 return [node].concat(getLastChildren(sibling));
8678 }).getOr([]);
8679 } else {
8680 return [node].concat(getLastChildren(child));
8681 }
8682 });
8683 };
8684 const hasAllContentsSelected = (elm, rng) => {
8685 return lift2(getStartNode(rng), getEndNode(rng), (startNode, endNode) => {
8686 const start = find$2(getFirstChildren(elm), curry(eq, startNode));
8687 const end = find$2(getLastChildren(elm), curry(eq, endNode));
8688 return start.isSome() && end.isSome();
8689 }).getOr(false);
8690 };
8691 const moveEndPoint = (dom, rng, node, start) => {
8692 const root = node;
8693 const walker = new DomTreeWalker(node, root);
8694 const moveCaretBeforeOnEnterElementsMap = filter$4(dom.schema.getMoveCaretBeforeOnEnterElements(), (_, name) => !contains$2([
8695 'td',
8696 'th',
8697 'table'
8698 ], name.toLowerCase()));
8699 let currentNode = node;
8700 do {
8701 if (isText$b(currentNode) && Tools.trim(currentNode.data).length !== 0) {
8702 if (start) {
8703 rng.setStart(currentNode, 0);
8704 } else {
8705 rng.setEnd(currentNode, currentNode.data.length);
8706 }
8707 return;
8708 }
8709 if (moveCaretBeforeOnEnterElementsMap[currentNode.nodeName]) {
8710 if (start) {
8711 rng.setStartBefore(currentNode);
8712 } else {
8713 if (currentNode.nodeName === 'BR') {
8714 rng.setEndBefore(currentNode);
8715 } else {
8716 rng.setEndAfter(currentNode);
8717 }
8718 }
8719 return;
8720 }
8721 } while (currentNode = start ? walker.next() : walker.prev());
8722 if (root.nodeName === 'BODY') {
8723 if (start) {
8724 rng.setStart(root, 0);
8725 } else {
8726 rng.setEnd(root, root.childNodes.length);
8727 }
8728 }
8729 };
8730 const hasAnyRanges = editor => {
8731 const sel = editor.selection.getSel();
8732 return isNonNullable(sel) && sel.rangeCount > 0;
8733 };
8734 const runOnRanges = (editor, executor) => {
8735 const fakeSelectionNodes = getCellsFromEditor(editor);
8736 if (fakeSelectionNodes.length > 0) {
8737 each$e(fakeSelectionNodes, elem => {
8738 const node = elem.dom;
8739 const fakeNodeRng = editor.dom.createRng();
8740 fakeNodeRng.setStartBefore(node);
8741 fakeNodeRng.setEndAfter(node);
8742 executor(fakeNodeRng, true);
8743 });
8744 } else {
8745 executor(editor.selection.getRng(), false);
8746 }
8747 };
8748 const preserve = (selection, fillBookmark, executor) => {
8749 const bookmark = getPersistentBookmark(selection, fillBookmark);
8750 executor(bookmark);
8751 selection.moveToBookmark(bookmark);
8752 };
8753
8754 const isNode = node => isNumber(node === null || node === void 0 ? void 0 : node.nodeType);
8755 const isElementNode$1 = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node);
8756 const isElementDirectlySelected = (dom, node) => {
8757 if (isElementNode$1(node) && !/^(TD|TH)$/.test(node.nodeName)) {
8758 const selectedAttr = dom.getAttrib(node, 'data-mce-selected');
8759 const value = parseInt(selectedAttr, 10);
8760 return !isNaN(value) && value > 0;
8761 } else {
8762 return false;
8763 }
8764 };
8765 const preserveSelection = (editor, action, shouldMoveStart) => {
8766 const {selection, dom} = editor;
8767 const selectedNodeBeforeAction = selection.getNode();
8768 const isSelectedBeforeNodeNoneditable = isContentEditableFalse$b(selectedNodeBeforeAction);
8769 preserve(selection, true, () => {
8770 action();
8771 });
8772 const isBeforeNodeStillNoneditable = isSelectedBeforeNodeNoneditable && isContentEditableFalse$b(selectedNodeBeforeAction);
8773 if (isBeforeNodeStillNoneditable && dom.isChildOf(selectedNodeBeforeAction, editor.getBody())) {
8774 editor.selection.select(selectedNodeBeforeAction);
8775 } else if (shouldMoveStart(selection.getStart())) {
8776 moveStartToNearestText(dom, selection);
8777 }
8778 };
8779 const moveStartToNearestText = (dom, selection) => {
8780 var _a, _b;
8781 const rng = selection.getRng();
8782 const {startContainer, startOffset} = rng;
8783 const selectedNode = selection.getNode();
8784 if (isElementDirectlySelected(dom, selectedNode)) {
8785 return;
8786 }
8787 if (isElement$6(startContainer)) {
8788 const nodes = startContainer.childNodes;
8789 const root = dom.getRoot();
8790 let walker;
8791 if (startOffset < nodes.length) {
8792 const startNode = nodes[startOffset];
8793 walker = new DomTreeWalker(startNode, (_a = dom.getParent(startNode, dom.isBlock)) !== null && _a !== void 0 ? _a : root);
8794 } else {
8795 const startNode = nodes[nodes.length - 1];
8796 walker = new DomTreeWalker(startNode, (_b = dom.getParent(startNode, dom.isBlock)) !== null && _b !== void 0 ? _b : root);
8797 walker.next(true);
8798 }
8799 for (let node = walker.current(); node; node = walker.next()) {
8800 if (dom.getContentEditable(node) === 'false') {
8801 return;
8802 } else if (isText$b(node) && !isWhiteSpaceNode$1(node)) {
8803 rng.setStart(node, 0);
8804 selection.setRng(rng);
8805 return;
8806 }
8807 }
8808 }
8809 };
8810 const getNonWhiteSpaceSibling = (node, next, inc) => {
8811 if (node) {
8812 const nextName = next ? 'nextSibling' : 'previousSibling';
8813 for (node = inc ? node : node[nextName]; node; node = node[nextName]) {
8814 if (isElement$6(node) || !isWhiteSpaceNode$1(node)) {
8815 return node;
8816 }
8817 }
8818 }
8819 return undefined;
8820 };
8821 const isTextBlock$1 = (schema, node) => !!schema.getTextBlockElements()[node.nodeName.toLowerCase()] || isTransparentBlock(schema, node);
8822 const isValid = (ed, parent, child) => {
8823 return ed.schema.isValidChild(parent, child);
8824 };
8825 const isWhiteSpaceNode$1 = (node, allowSpaces = false) => {
8826 if (isNonNullable(node) && isText$b(node)) {
8827 const data = allowSpaces ? node.data.replace(/ /g, '\xA0') : node.data;
8828 return isWhitespaceText(data);
8829 } else {
8830 return false;
8831 }
8832 };
8833 const isEmptyTextNode$1 = node => {
8834 return isNonNullable(node) && isText$b(node) && node.length === 0;
8835 };
8836 const isWrapNoneditableTarget = (editor, node) => {
8837 const baseDataSelector = '[data-mce-cef-wrappable]';
8838 const formatNoneditableSelector = getFormatNoneditableSelector(editor);
8839 const selector = isEmpty$3(formatNoneditableSelector) ? baseDataSelector : `${ baseDataSelector },${ formatNoneditableSelector }`;
8840 return is$1(SugarElement.fromDom(node), selector);
8841 };
8842 const isWrappableNoneditable = (editor, node) => {
8843 const dom = editor.dom;
8844 return isElementNode$1(node) && dom.getContentEditable(node) === 'false' && isWrapNoneditableTarget(editor, node) && dom.select('[contenteditable="true"]', node).length === 0;
8845 };
8846 const replaceVars = (value, vars) => {
8847 if (isFunction(value)) {
8848 return value(vars);
8849 } else if (isNonNullable(vars)) {
8850 value = value.replace(/%(\w+)/g, (str, name) => {
8851 return vars[name] || str;
8852 });
8853 }
8854 return value;
8855 };
8856 const isEq$5 = (str1, str2) => {
8857 str1 = str1 || '';
8858 str2 = str2 || '';
8859 str1 = '' + (str1.nodeName || str1);
8860 str2 = '' + (str2.nodeName || str2);
8861 return str1.toLowerCase() === str2.toLowerCase();
8862 };
8863 const normalizeStyleValue = (value, name) => {
8864 if (isNullable(value)) {
8865 return null;
8866 } else {
8867 let strValue = String(value);
8868 if (name === 'color' || name === 'backgroundColor') {
8869 strValue = rgbaToHexString(strValue);
8870 }
8871 if (name === 'fontWeight' && value === 700) {
8872 strValue = 'bold';
8873 }
8874 if (name === 'fontFamily') {
8875 strValue = strValue.replace(/[\'\"]/g, '').replace(/,\s+/g, ',');
8876 }
8877 return strValue;
8878 }
8879 };
8880 const getStyle = (dom, node, name) => {
8881 const style = dom.getStyle(node, name);
8882 return normalizeStyleValue(style, name);
8883 };
8884 const getTextDecoration = (dom, node) => {
8885 let decoration;
8886 dom.getParent(node, n => {
8887 if (isElement$6(n)) {
8888 decoration = dom.getStyle(n, 'text-decoration');
8889 return !!decoration && decoration !== 'none';
8890 } else {
8891 return false;
8892 }
8893 });
8894 return decoration;
8895 };
8896 const getParents$2 = (dom, node, selector) => {
8897 return dom.getParents(node, selector, dom.getRoot());
8898 };
8899 const isFormatPredicate = (editor, formatName, predicate) => {
8900 const formats = editor.formatter.get(formatName);
8901 return isNonNullable(formats) && exists(formats, predicate);
8902 };
8903 const isVariableFormatName = (editor, formatName) => {
8904 const hasVariableValues = format => {
8905 const isVariableValue = val => isFunction(val) || val.length > 1 && val.charAt(0) === '%';
8906 return exists([
8907 'styles',
8908 'attributes'
8909 ], key => get$a(format, key).exists(field => {
8910 const fieldValues = isArray$1(field) ? field : values(field);
8911 return exists(fieldValues, isVariableValue);
8912 }));
8913 };
8914 return isFormatPredicate(editor, formatName, hasVariableValues);
8915 };
8916 const areSimilarFormats = (editor, formatName, otherFormatName) => {
8917 const validKeys = [
8918 'inline',
8919 'block',
8920 'selector',
8921 'attributes',
8922 'styles',
8923 'classes'
8924 ];
8925 const filterObj = format => filter$4(format, (_, key) => exists(validKeys, validKey => validKey === key));
8926 return isFormatPredicate(editor, formatName, fmt1 => {
8927 const filteredFmt1 = filterObj(fmt1);
8928 return isFormatPredicate(editor, otherFormatName, fmt2 => {
8929 const filteredFmt2 = filterObj(fmt2);
8930 return equal$1(filteredFmt1, filteredFmt2);
8931 });
8932 });
8933 };
8934 const isBlockFormat = format => hasNonNullableKey(format, 'block');
8935 const isWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper === true;
8936 const isNonWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper !== true;
8937 const isSelectorFormat = format => hasNonNullableKey(format, 'selector');
8938 const isInlineFormat = format => hasNonNullableKey(format, 'inline');
8939 const isMixedFormat = format => isSelectorFormat(format) && isInlineFormat(format) && is$2(get$a(format, 'mixed'), true);
8940 const shouldExpandToSelector = format => isSelectorFormat(format) && format.expand !== false && !isInlineFormat(format);
8941 const getEmptyCaretContainers = node => {
8942 const nodes = [];
8943 let tempNode = node;
8944 while (tempNode) {
8945 if (isText$b(tempNode) && tempNode.data !== ZWSP$1 || tempNode.childNodes.length > 1) {
8946 return [];
8947 }
8948 if (isElement$6(tempNode)) {
8949 nodes.push(tempNode);
8950 }
8951 tempNode = tempNode.firstChild;
8952 }
8953 return nodes;
8954 };
8955 const isCaretContainerEmpty = node => {
8956 return getEmptyCaretContainers(node).length > 0;
8957 };
8958 const isEmptyCaretFormatElement = element => {
8959 return isCaretNode(element.dom) && isCaretContainerEmpty(element.dom);
8960 };
8961
8962 const isBookmarkNode = isBookmarkNode$1;
8963 const getParents$1 = getParents$2;
8964 const isWhiteSpaceNode = isWhiteSpaceNode$1;
8965 const isTextBlock = isTextBlock$1;
8966 const isBogusBr = node => {
8967 return isBr$6(node) && node.getAttribute('data-mce-bogus') && !node.nextSibling;
8968 };
8969 const findParentContentEditable = (dom, node) => {
8970 let parent = node;
8971 while (parent) {
8972 if (isElement$6(parent) && dom.getContentEditable(parent)) {
8973 return dom.getContentEditable(parent) === 'false' ? parent : node;
8974 }
8975 parent = parent.parentNode;
8976 }
8977 return node;
8978 };
8979 const walkText = (start, node, offset, predicate) => {
8980 const str = node.data;
8981 if (start) {
8982 for (let i = offset; i > 0; i--) {
8983 if (predicate(str.charAt(i - 1))) {
8984 return i;
8985 }
8986 }
8987 } else {
8988 for (let i = offset; i < str.length; i++) {
8989 if (predicate(str.charAt(i))) {
8990 return i;
8991 }
8992 }
8993 }
8994 return -1;
8995 };
8996 const findSpace = (start, node, offset) => walkText(start, node, offset, c => isNbsp(c) || isWhiteSpace(c));
8997 const findContent = (start, node, offset) => walkText(start, node, offset, isContent);
8998 const findWordEndPoint = (dom, body, container, offset, start, includeTrailingSpaces) => {
8999 let lastTextNode;
9000 const rootNode = dom.getParent(container, dom.isBlock) || body;
9001 const walk = (container, offset, pred) => {
9002 const textSeeker = TextSeeker(dom);
9003 const walker = start ? textSeeker.backwards : textSeeker.forwards;
9004 return Optional.from(walker(container, offset, (text, textOffset) => {
9005 if (isBookmarkNode(text.parentNode)) {
9006 return -1;
9007 } else {
9008 lastTextNode = text;
9009 return pred(start, text, textOffset);
9010 }
9011 }, rootNode));
9012 };
9013 const spaceResult = walk(container, offset, findSpace);
9014 return spaceResult.bind(result => includeTrailingSpaces ? walk(result.container, result.offset + (start ? -1 : 0), findContent) : Optional.some(result)).orThunk(() => lastTextNode ? Optional.some({
9015 container: lastTextNode,
9016 offset: start ? 0 : lastTextNode.length
9017 }) : Optional.none());
9018 };
9019 const findSelectorEndPoint = (dom, formatList, rng, container, siblingName) => {
9020 const sibling = container[siblingName];
9021 if (isText$b(container) && isEmpty$3(container.data) && sibling) {
9022 container = sibling;
9023 }
9024 const parents = getParents$1(dom, container);
9025 for (let i = 0; i < parents.length; i++) {
9026 for (let y = 0; y < formatList.length; y++) {
9027 const curFormat = formatList[y];
9028 if (isNonNullable(curFormat.collapsed) && curFormat.collapsed !== rng.collapsed) {
9029 continue;
9030 }
9031 if (isSelectorFormat(curFormat) && dom.is(parents[i], curFormat.selector)) {
9032 return parents[i];
9033 }
9034 }
9035 }
9036 return container;
9037 };
9038 const findBlockEndPoint = (dom, formatList, container, siblingName) => {
9039 var _a;
9040 let node = container;
9041 const root = dom.getRoot();
9042 const format = formatList[0];
9043 if (isBlockFormat(format)) {
9044 node = format.wrapper ? null : dom.getParent(container, format.block, root);
9045 }
9046 if (!node) {
9047 const scopeRoot = (_a = dom.getParent(container, 'LI,TD,TH,SUMMARY')) !== null && _a !== void 0 ? _a : root;
9048 node = dom.getParent(isText$b(container) ? container.parentNode : container, node => node !== root && isTextBlock(dom.schema, node), scopeRoot);
9049 }
9050 if (node && isBlockFormat(format) && format.wrapper) {
9051 node = getParents$1(dom, node, 'ul,ol').reverse()[0] || node;
9052 }
9053 if (!node) {
9054 node = container;
9055 while (node && node[siblingName] && !dom.isBlock(node[siblingName])) {
9056 node = node[siblingName];
9057 if (isEq$5(node, 'br')) {
9058 break;
9059 }
9060 }
9061 }
9062 return node || container;
9063 };
9064 const isAtBlockBoundary$1 = (dom, root, container, siblingName) => {
9065 const parent = container.parentNode;
9066 if (isNonNullable(container[siblingName])) {
9067 return false;
9068 } else if (parent === root || isNullable(parent) || dom.isBlock(parent)) {
9069 return true;
9070 } else {
9071 return isAtBlockBoundary$1(dom, root, parent, siblingName);
9072 }
9073 };
9074 const findParentContainer = (dom, formatList, container, offset, start) => {
9075 let parent = container;
9076 const siblingName = start ? 'previousSibling' : 'nextSibling';
9077 const root = dom.getRoot();
9078 if (isText$b(container) && !isWhiteSpaceNode(container)) {
9079 if (start ? offset > 0 : offset < container.data.length) {
9080 return container;
9081 }
9082 }
9083 while (parent) {
9084 if (!formatList[0].block_expand && dom.isBlock(parent)) {
9085 return parent;
9086 }
9087 for (let sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
9088 const allowSpaces = isText$b(sibling) && !isAtBlockBoundary$1(dom, root, sibling, siblingName);
9089 if (!isBookmarkNode(sibling) && !isBogusBr(sibling) && !isWhiteSpaceNode(sibling, allowSpaces)) {
9090 return parent;
9091 }
9092 }
9093 if (parent === root || parent.parentNode === root) {
9094 container = parent;
9095 break;
9096 }
9097 parent = parent.parentNode;
9098 }
9099 return container;
9100 };
9101 const isSelfOrParentBookmark = container => isBookmarkNode(container.parentNode) || isBookmarkNode(container);
9102 const expandRng = (dom, rng, formatList, includeTrailingSpace = false) => {
9103 let {startContainer, startOffset, endContainer, endOffset} = rng;
9104 const format = formatList[0];
9105 if (isElement$6(startContainer) && startContainer.hasChildNodes()) {
9106 startContainer = getNode$1(startContainer, startOffset);
9107 if (isText$b(startContainer)) {
9108 startOffset = 0;
9109 }
9110 }
9111 if (isElement$6(endContainer) && endContainer.hasChildNodes()) {
9112 endContainer = getNode$1(endContainer, rng.collapsed ? endOffset : endOffset - 1);
9113 if (isText$b(endContainer)) {
9114 endOffset = endContainer.data.length;
9115 }
9116 }
9117 startContainer = findParentContentEditable(dom, startContainer);
9118 endContainer = findParentContentEditable(dom, endContainer);
9119 if (isSelfOrParentBookmark(startContainer)) {
9120 startContainer = isBookmarkNode(startContainer) ? startContainer : startContainer.parentNode;
9121 if (rng.collapsed) {
9122 startContainer = startContainer.previousSibling || startContainer;
9123 } else {
9124 startContainer = startContainer.nextSibling || startContainer;
9125 }
9126 if (isText$b(startContainer)) {
9127 startOffset = rng.collapsed ? startContainer.length : 0;
9128 }
9129 }
9130 if (isSelfOrParentBookmark(endContainer)) {
9131 endContainer = isBookmarkNode(endContainer) ? endContainer : endContainer.parentNode;
9132 if (rng.collapsed) {
9133 endContainer = endContainer.nextSibling || endContainer;
9134 } else {
9135 endContainer = endContainer.previousSibling || endContainer;
9136 }
9137 if (isText$b(endContainer)) {
9138 endOffset = rng.collapsed ? 0 : endContainer.length;
9139 }
9140 }
9141 if (rng.collapsed) {
9142 const startPoint = findWordEndPoint(dom, dom.getRoot(), startContainer, startOffset, true, includeTrailingSpace);
9143 startPoint.each(({container, offset}) => {
9144 startContainer = container;
9145 startOffset = offset;
9146 });
9147 const endPoint = findWordEndPoint(dom, dom.getRoot(), endContainer, endOffset, false, includeTrailingSpace);
9148 endPoint.each(({container, offset}) => {
9149 endContainer = container;
9150 endOffset = offset;
9151 });
9152 }
9153 if (isInlineFormat(format) || format.block_expand) {
9154 if (!isInlineFormat(format) || (!isText$b(startContainer) || startOffset === 0)) {
9155 startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true);
9156 }
9157 if (!isInlineFormat(format) || (!isText$b(endContainer) || endOffset === endContainer.data.length)) {
9158 endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false);
9159 }
9160 }
9161 if (shouldExpandToSelector(format)) {
9162 startContainer = findSelectorEndPoint(dom, formatList, rng, startContainer, 'previousSibling');
9163 endContainer = findSelectorEndPoint(dom, formatList, rng, endContainer, 'nextSibling');
9164 }
9165 if (isBlockFormat(format) || isSelectorFormat(format)) {
9166 startContainer = findBlockEndPoint(dom, formatList, startContainer, 'previousSibling');
9167 endContainer = findBlockEndPoint(dom, formatList, endContainer, 'nextSibling');
9168 if (isBlockFormat(format)) {
9169 if (!dom.isBlock(startContainer)) {
9170 startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true);
9171 if (isText$b(startContainer)) {
9172 startOffset = 0;
9173 }
9174 }
9175 if (!dom.isBlock(endContainer)) {
9176 endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false);
9177 if (isText$b(endContainer)) {
9178 endOffset = endContainer.data.length;
9179 }
9180 }
9181 }
9182 }
9183 if (isElement$6(startContainer) && startContainer.parentNode) {
9184 startOffset = dom.nodeIndex(startContainer);
9185 startContainer = startContainer.parentNode;
9186 }
9187 if (isElement$6(endContainer) && endContainer.parentNode) {
9188 endOffset = dom.nodeIndex(endContainer) + 1;
9189 endContainer = endContainer.parentNode;
9190 }
9191 return {
9192 startContainer,
9193 startOffset,
9194 endContainer,
9195 endOffset
9196 };
9197 };
9198
9199 const walk$3 = (dom, rng, callback) => {
9200 var _a;
9201 const startOffset = rng.startOffset;
9202 const startContainer = getNode$1(rng.startContainer, startOffset);
9203 const endOffset = rng.endOffset;
9204 const endContainer = getNode$1(rng.endContainer, endOffset - 1);
9205 const exclude = nodes => {
9206 const firstNode = nodes[0];
9207 if (isText$b(firstNode) && firstNode === startContainer && startOffset >= firstNode.data.length) {
9208 nodes.splice(0, 1);
9209 }
9210 const lastNode = nodes[nodes.length - 1];
9211 if (endOffset === 0 && nodes.length > 0 && lastNode === endContainer && isText$b(lastNode)) {
9212 nodes.splice(nodes.length - 1, 1);
9213 }
9214 return nodes;
9215 };
9216 const collectSiblings = (node, name, endNode) => {
9217 const siblings = [];
9218 for (; node && node !== endNode; node = node[name]) {
9219 siblings.push(node);
9220 }
9221 return siblings;
9222 };
9223 const findEndPoint = (node, root) => dom.getParent(node, node => node.parentNode === root, root);
9224 const walkBoundary = (startNode, endNode, next) => {
9225 const siblingName = next ? 'nextSibling' : 'previousSibling';
9226 for (let node = startNode, parent = node.parentNode; node && node !== endNode; node = parent) {
9227 parent = node.parentNode;
9228 const siblings = collectSiblings(node === startNode ? node : node[siblingName], siblingName);
9229 if (siblings.length) {
9230 if (!next) {
9231 siblings.reverse();
9232 }
9233 callback(exclude(siblings));
9234 }
9235 }
9236 };
9237 if (startContainer === endContainer) {
9238 return callback(exclude([startContainer]));
9239 }
9240 const ancestor = (_a = dom.findCommonAncestor(startContainer, endContainer)) !== null && _a !== void 0 ? _a : dom.getRoot();
9241 if (dom.isChildOf(startContainer, endContainer)) {
9242 return walkBoundary(startContainer, ancestor, true);
9243 }
9244 if (dom.isChildOf(endContainer, startContainer)) {
9245 return walkBoundary(endContainer, ancestor);
9246 }
9247 const startPoint = findEndPoint(startContainer, ancestor) || startContainer;
9248 const endPoint = findEndPoint(endContainer, ancestor) || endContainer;
9249 walkBoundary(startContainer, startPoint, true);
9250 const siblings = collectSiblings(startPoint === startContainer ? startPoint : startPoint.nextSibling, 'nextSibling', endPoint === endContainer ? endPoint.nextSibling : endPoint);
9251 if (siblings.length) {
9252 callback(exclude(siblings));
9253 }
9254 walkBoundary(endContainer, endPoint);
9255 };
9256
9257 const validBlocks = [
9258 'pre[class*=language-][contenteditable="false"]',
9259 'figure.image',
9260 'div[data-ephox-embed-iri]',
9261 'div.tiny-pageembed',
9262 'div.mce-toc',
9263 'div[data-mce-toc]'
9264 ];
9265 const isZeroWidth = elem => isText$c(elem) && get$3(elem) === ZWSP$1;
9266 const context = (editor, elem, wrapName, nodeName) => parent(elem).fold(() => 'skipping', parent => {
9267 if (nodeName === 'br' || isZeroWidth(elem)) {
9268 return 'valid';
9269 } else if (isAnnotation(elem)) {
9270 return 'existing';
9271 } else if (isCaretNode(elem.dom)) {
9272 return 'caret';
9273 } else if (exists(validBlocks, selector => is$1(elem, selector))) {
9274 return 'valid-block';
9275 } else if (!isValid(editor, wrapName, nodeName) || !isValid(editor, name(parent), wrapName)) {
9276 return 'invalid-child';
9277 } else {
9278 return 'valid';
9279 }
9280 });
9281
9282 const applyWordGrab = (editor, rng) => {
9283 const r = expandRng(editor.dom, rng, [{ inline: 'span' }]);
9284 rng.setStart(r.startContainer, r.startOffset);
9285 rng.setEnd(r.endContainer, r.endOffset);
9286 editor.selection.setRng(rng);
9287 };
9288 const applyAnnotation = (elem, masterUId, data, annotationName, decorate, directAnnotation) => {
9289 const {uid = masterUId, ...otherData} = data;
9290 add$2(elem, annotation());
9291 set$3(elem, `${ dataAnnotationId() }`, uid);
9292 set$3(elem, `${ dataAnnotation() }`, annotationName);
9293 const {attributes = {}, classes = []} = decorate(uid, otherData);
9294 setAll$1(elem, attributes);
9295 add(elem, classes);
9296 if (directAnnotation) {
9297 if (classes.length > 0) {
9298 set$3(elem, `${ dataAnnotationClasses() }`, classes.join(','));
9299 }
9300 const attributeNames = keys(attributes);
9301 if (attributeNames.length > 0) {
9302 set$3(elem, `${ dataAnnotationAttributes() }`, attributeNames.join(','));
9303 }
9304 }
9305 };
9306 const removeDirectAnnotation = elem => {
9307 remove$6(elem, annotation());
9308 remove$9(elem, `${ dataAnnotationId() }`);
9309 remove$9(elem, `${ dataAnnotation() }`);
9310 remove$9(elem, `${ dataAnnotationActive() }`);
9311 const customAttrNames = getOpt(elem, `${ dataAnnotationAttributes() }`).map(names => names.split(',')).getOr([]);
9312 const customClasses = getOpt(elem, `${ dataAnnotationClasses() }`).map(names => names.split(',')).getOr([]);
9313 each$e(customAttrNames, name => remove$9(elem, name));
9314 remove$3(elem, customClasses);
9315 remove$9(elem, `${ dataAnnotationClasses() }`);
9316 remove$9(elem, `${ dataAnnotationAttributes() }`);
9317 };
9318 const makeAnnotation = (eDoc, uid, data, annotationName, decorate) => {
9319 const master = SugarElement.fromTag('span', eDoc);
9320 applyAnnotation(master, uid, data, annotationName, decorate, false);
9321 return master;
9322 };
9323 const annotate = (editor, rng, uid, annotationName, decorate, data) => {
9324 const newWrappers = [];
9325 const master = makeAnnotation(editor.getDoc(), uid, data, annotationName, decorate);
9326 const wrapper = value$2();
9327 const finishWrapper = () => {
9328 wrapper.clear();
9329 };
9330 const getOrOpenWrapper = () => wrapper.get().getOrThunk(() => {
9331 const nu = shallow$1(master);
9332 newWrappers.push(nu);
9333 wrapper.set(nu);
9334 return nu;
9335 });
9336 const processElements = elems => {
9337 each$e(elems, processElement);
9338 };
9339 const processElement = elem => {
9340 const ctx = context(editor, elem, 'span', name(elem));
9341 switch (ctx) {
9342 case 'invalid-child': {
9343 finishWrapper();
9344 const children = children$1(elem);
9345 processElements(children);
9346 finishWrapper();
9347 break;
9348 }
9349 case 'valid-block': {
9350 finishWrapper();
9351 applyAnnotation(elem, uid, data, annotationName, decorate, true);
9352 break;
9353 }
9354 case 'valid': {
9355 const w = getOrOpenWrapper();
9356 wrap$2(elem, w);
9357 break;
9358 }
9359 }
9360 };
9361 const processNodes = nodes => {
9362 const elems = map$3(nodes, SugarElement.fromDom);
9363 processElements(elems);
9364 };
9365 walk$3(editor.dom, rng, nodes => {
9366 finishWrapper();
9367 processNodes(nodes);
9368 });
9369 return newWrappers;
9370 };
9371 const annotateWithBookmark = (editor, name, settings, data) => {
9372 editor.undoManager.transact(() => {
9373 const selection = editor.selection;
9374 const initialRng = selection.getRng();
9375 const hasFakeSelection = getCellsFromEditor(editor).length > 0;
9376 const masterUid = generate$1('mce-annotation');
9377 if (initialRng.collapsed && !hasFakeSelection) {
9378 applyWordGrab(editor, initialRng);
9379 }
9380 if (selection.getRng().collapsed && !hasFakeSelection) {
9381 const wrapper = makeAnnotation(editor.getDoc(), masterUid, data, name, settings.decorate);
9382 set$1(wrapper, nbsp);
9383 selection.getRng().insertNode(wrapper.dom);
9384 selection.select(wrapper.dom);
9385 } else {
9386 preserve(selection, false, () => {
9387 runOnRanges(editor, selectionRng => {
9388 annotate(editor, selectionRng, masterUid, name, settings.decorate, data);
9389 });
9390 });
9391 }
9392 });
9393 };
9394
9395 const Annotator = editor => {
9396 const registry = create$b();
9397 setup$x(editor, registry);
9398 const changes = setup$y(editor, registry);
9399 const isSpan = isTag('span');
9400 const removeAnnotations = elements => {
9401 each$e(elements, element => {
9402 if (isSpan(element)) {
9403 unwrap(element);
9404 } else {
9405 removeDirectAnnotation(element);
9406 }
9407 });
9408 };
9409 return {
9410 register: (name, settings) => {
9411 registry.register(name, settings);
9412 },
9413 annotate: (name, data) => {
9414 registry.lookup(name).each(settings => {
9415 annotateWithBookmark(editor, name, settings, data);
9416 });
9417 },
9418 annotationChanged: (name, callback) => {
9419 changes.addListener(name, callback);
9420 },
9421 remove: name => {
9422 identify(editor, Optional.some(name)).each(({elements}) => {
9423 const bookmark = editor.selection.getBookmark();
9424 removeAnnotations(elements);
9425 editor.selection.moveToBookmark(bookmark);
9426 });
9427 },
9428 removeAll: name => {
9429 const bookmark = editor.selection.getBookmark();
9430 each$d(findAll(editor, name), (elements, _) => {
9431 removeAnnotations(elements);
9432 });
9433 editor.selection.moveToBookmark(bookmark);
9434 },
9435 getAll: name => {
9436 const directory = findAll(editor, name);
9437 return map$2(directory, elems => map$3(elems, elem => elem.dom));
9438 }
9439 };
9440 };
9441
9442 const BookmarkManager = selection => {
9443 return {
9444 getBookmark: curry(getBookmark$1, selection),
9445 moveToBookmark: curry(moveToBookmark, selection)
9446 };
9447 };
9448 BookmarkManager.isBookmarkNode = isBookmarkNode$1;
9449
9450 const isXYWithinRange = (clientX, clientY, range) => {
9451 if (range.collapsed) {
9452 return false;
9453 } else {
9454 return exists(range.getClientRects(), rect => containsXY(rect, clientX, clientY));
9455 }
9456 };
9457
9458 const firePreProcess = (editor, args) => editor.dispatch('PreProcess', args);
9459 const firePostProcess = (editor, args) => editor.dispatch('PostProcess', args);
9460 const fireRemove = editor => {
9461 editor.dispatch('remove');
9462 };
9463 const fireDetach = editor => {
9464 editor.dispatch('detach');
9465 };
9466 const fireSwitchMode = (editor, mode) => {
9467 editor.dispatch('SwitchMode', { mode });
9468 };
9469 const fireObjectResizeStart = (editor, target, width, height, origin) => {
9470 editor.dispatch('ObjectResizeStart', {
9471 target,
9472 width,
9473 height,
9474 origin
9475 });
9476 };
9477 const fireObjectResized = (editor, target, width, height, origin) => {
9478 editor.dispatch('ObjectResized', {
9479 target,
9480 width,
9481 height,
9482 origin
9483 });
9484 };
9485 const firePreInit = editor => {
9486 editor.dispatch('PreInit');
9487 };
9488 const firePostRender = editor => {
9489 editor.dispatch('PostRender');
9490 };
9491 const fireInit = editor => {
9492 editor.dispatch('Init');
9493 };
9494 const firePlaceholderToggle = (editor, state) => {
9495 editor.dispatch('PlaceholderToggle', { state });
9496 };
9497 const fireError = (editor, errorType, error) => {
9498 editor.dispatch(errorType, error);
9499 };
9500 const fireFormatApply = (editor, format, node, vars) => {
9501 editor.dispatch('FormatApply', {
9502 format,
9503 node,
9504 vars
9505 });
9506 };
9507 const fireFormatRemove = (editor, format, node, vars) => {
9508 editor.dispatch('FormatRemove', {
9509 format,
9510 node,
9511 vars
9512 });
9513 };
9514 const fireBeforeSetContent = (editor, args) => editor.dispatch('BeforeSetContent', args);
9515 const fireSetContent = (editor, args) => editor.dispatch('SetContent', args);
9516 const fireBeforeGetContent = (editor, args) => editor.dispatch('BeforeGetContent', args);
9517 const fireGetContent = (editor, args) => editor.dispatch('GetContent', args);
9518 const fireAutocompleterStart = (editor, args) => {
9519 editor.dispatch('AutocompleterStart', args);
9520 };
9521 const fireAutocompleterUpdate = (editor, args) => {
9522 editor.dispatch('AutocompleterUpdate', args);
9523 };
9524 const fireAutocompleterUpdateActiveRange = (editor, args) => {
9525 editor.dispatch('AutocompleterUpdateActiveRange', args);
9526 };
9527 const fireAutocompleterEnd = editor => {
9528 editor.dispatch('AutocompleterEnd');
9529 };
9530 const firePastePreProcess = (editor, html, internal) => editor.dispatch('PastePreProcess', {
9531 content: html,
9532 internal
9533 });
9534 const firePastePostProcess = (editor, node, internal) => editor.dispatch('PastePostProcess', {
9535 node,
9536 internal
9537 });
9538 const firePastePlainTextToggle = (editor, state) => editor.dispatch('PastePlainTextToggle', { state });
9539 const fireEditableRootStateChange = (editor, state) => editor.dispatch('EditableRootStateChange', { state });
9540
9541 const VK = {
9542 BACKSPACE: 8,
9543 DELETE: 46,
9544 DOWN: 40,
9545 ENTER: 13,
9546 ESC: 27,
9547 LEFT: 37,
9548 RIGHT: 39,
9549 SPACEBAR: 32,
9550 TAB: 9,
9551 UP: 38,
9552 PAGE_UP: 33,
9553 PAGE_DOWN: 34,
9554 END: 35,
9555 HOME: 36,
9556 modifierPressed: e => {
9557 return e.shiftKey || e.ctrlKey || e.altKey || VK.metaKeyPressed(e);
9558 },
9559 metaKeyPressed: e => {
9560 return Env.os.isMacOS() || Env.os.isiOS() ? e.metaKey : e.ctrlKey && !e.altKey;
9561 }
9562 };
9563
9564 const elementSelectionAttr = 'data-mce-selected';
9565 const controlElmSelector = 'table,img,figure.image,hr,video,span.mce-preview-object,details';
9566 const abs = Math.abs;
9567 const round$1 = Math.round;
9568 const resizeHandles = {
9569 nw: [
9570 0,
9571 0,
9572 -1,
9573 -1
9574 ],
9575 ne: [
9576 1,
9577 0,
9578 1,
9579 -1
9580 ],
9581 se: [
9582 1,
9583 1,
9584 1,
9585 1
9586 ],
9587 sw: [
9588 0,
9589 1,
9590 -1,
9591 1
9592 ]
9593 };
9594 const isTouchEvent = evt => evt.type === 'longpress' || evt.type.indexOf('touch') === 0;
9595 const ControlSelection = (selection, editor) => {
9596 const dom = editor.dom;
9597 const editableDoc = editor.getDoc();
9598 const rootDocument = document;
9599 const rootElement = editor.getBody();
9600 let selectedElm, selectedElmGhost, resizeHelper, selectedHandle, resizeBackdrop;
9601 let startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted;
9602 let width;
9603 let height;
9604 let startScrollWidth;
9605 let startScrollHeight;
9606 const isImage = elm => isNonNullable(elm) && (isImg(elm) || dom.is(elm, 'figure.image'));
9607 const isMedia = elm => isMedia$2(elm) || dom.hasClass(elm, 'mce-preview-object');
9608 const isEventOnImageOutsideRange = (evt, range) => {
9609 if (isTouchEvent(evt)) {
9610 const touch = evt.touches[0];
9611 return isImage(evt.target) && !isXYWithinRange(touch.clientX, touch.clientY, range);
9612 } else {
9613 return isImage(evt.target) && !isXYWithinRange(evt.clientX, evt.clientY, range);
9614 }
9615 };
9616 const contextMenuSelectImage = evt => {
9617 const target = evt.target;
9618 if (isEventOnImageOutsideRange(evt, editor.selection.getRng()) && !evt.isDefaultPrevented()) {
9619 editor.selection.select(target);
9620 }
9621 };
9622 const getResizeTargets = elm => {
9623 if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
9624 return [
9625 elm,
9626 elm.firstElementChild
9627 ];
9628 } else if (dom.is(elm, 'figure.image')) {
9629 return [elm.querySelector('img')];
9630 } else {
9631 return [elm];
9632 }
9633 };
9634 const isResizable = elm => {
9635 const selector = getObjectResizing(editor);
9636 if (!selector) {
9637 return false;
9638 }
9639 if (elm.getAttribute('data-mce-resize') === 'false') {
9640 return false;
9641 }
9642 if (elm === editor.getBody()) {
9643 return false;
9644 }
9645 if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
9646 return is$1(SugarElement.fromDom(elm.firstElementChild), selector);
9647 } else {
9648 return is$1(SugarElement.fromDom(elm), selector);
9649 }
9650 };
9651 const createGhostElement = (dom, elm) => {
9652 if (isMedia(elm)) {
9653 return dom.create('img', { src: Env.transparentSrc });
9654 } else if (isTable$2(elm)) {
9655 const isNorth = startsWith(selectedHandle.name, 'n');
9656 const rowSelect = isNorth ? head : last$2;
9657 const tableElm = elm.cloneNode(true);
9658 rowSelect(dom.select('tr', tableElm)).each(tr => {
9659 const cells = dom.select('td,th', tr);
9660 dom.setStyle(tr, 'height', null);
9661 each$e(cells, cell => dom.setStyle(cell, 'height', null));
9662 });
9663 return tableElm;
9664 } else {
9665 return elm.cloneNode(true);
9666 }
9667 };
9668 const setSizeProp = (element, name, value) => {
9669 if (isNonNullable(value)) {
9670 const targets = getResizeTargets(element);
9671 each$e(targets, target => {
9672 if (target.style[name] || !editor.schema.isValid(target.nodeName.toLowerCase(), name)) {
9673 dom.setStyle(target, name, value);
9674 } else {
9675 dom.setAttrib(target, name, '' + value);
9676 }
9677 });
9678 }
9679 };
9680 const setGhostElmSize = (ghostElm, width, height) => {
9681 setSizeProp(ghostElm, 'width', width);
9682 setSizeProp(ghostElm, 'height', height);
9683 };
9684 const resizeGhostElement = e => {
9685 let deltaX, deltaY, proportional;
9686 let resizeHelperX, resizeHelperY;
9687 deltaX = e.screenX - startX;
9688 deltaY = e.screenY - startY;
9689 width = deltaX * selectedHandle[2] + startW;
9690 height = deltaY * selectedHandle[3] + startH;
9691 width = width < 5 ? 5 : width;
9692 height = height < 5 ? 5 : height;
9693 if ((isImage(selectedElm) || isMedia(selectedElm)) && getResizeImgProportional(editor) !== false) {
9694 proportional = !VK.modifierPressed(e);
9695 } else {
9696 proportional = VK.modifierPressed(e);
9697 }
9698 if (proportional) {
9699 if (abs(deltaX) > abs(deltaY)) {
9700 height = round$1(width * ratio);
9701 width = round$1(height / ratio);
9702 } else {
9703 width = round$1(height / ratio);
9704 height = round$1(width * ratio);
9705 }
9706 }
9707 setGhostElmSize(selectedElmGhost, width, height);
9708 resizeHelperX = selectedHandle.startPos.x + deltaX;
9709 resizeHelperY = selectedHandle.startPos.y + deltaY;
9710 resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0;
9711 resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0;
9712 dom.setStyles(resizeHelper, {
9713 left: resizeHelperX,
9714 top: resizeHelperY,
9715 display: 'block'
9716 });
9717 resizeHelper.innerHTML = width + ' &times; ' + height;
9718 if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) {
9719 dom.setStyle(selectedElmGhost, 'left', selectedElmX + (startW - width));
9720 }
9721 if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) {
9722 dom.setStyle(selectedElmGhost, 'top', selectedElmY + (startH - height));
9723 }
9724 deltaX = rootElement.scrollWidth - startScrollWidth;
9725 deltaY = rootElement.scrollHeight - startScrollHeight;
9726 if (deltaX + deltaY !== 0) {
9727 dom.setStyles(resizeHelper, {
9728 left: resizeHelperX - deltaX,
9729 top: resizeHelperY - deltaY
9730 });
9731 }
9732 if (!resizeStarted) {
9733 fireObjectResizeStart(editor, selectedElm, startW, startH, 'corner-' + selectedHandle.name);
9734 resizeStarted = true;
9735 }
9736 };
9737 const endGhostResize = () => {
9738 const wasResizeStarted = resizeStarted;
9739 resizeStarted = false;
9740 if (wasResizeStarted) {
9741 setSizeProp(selectedElm, 'width', width);
9742 setSizeProp(selectedElm, 'height', height);
9743 }
9744 dom.unbind(editableDoc, 'mousemove', resizeGhostElement);
9745 dom.unbind(editableDoc, 'mouseup', endGhostResize);
9746 if (rootDocument !== editableDoc) {
9747 dom.unbind(rootDocument, 'mousemove', resizeGhostElement);
9748 dom.unbind(rootDocument, 'mouseup', endGhostResize);
9749 }
9750 dom.remove(selectedElmGhost);
9751 dom.remove(resizeHelper);
9752 dom.remove(resizeBackdrop);
9753 showResizeRect(selectedElm);
9754 if (wasResizeStarted) {
9755 fireObjectResized(editor, selectedElm, width, height, 'corner-' + selectedHandle.name);
9756 dom.setAttrib(selectedElm, 'style', dom.getAttrib(selectedElm, 'style'));
9757 }
9758 editor.nodeChanged();
9759 };
9760 const showResizeRect = targetElm => {
9761 unbindResizeHandleEvents();
9762 const position = dom.getPos(targetElm, rootElement);
9763 const selectedElmX = position.x;
9764 const selectedElmY = position.y;
9765 const rect = targetElm.getBoundingClientRect();
9766 const targetWidth = rect.width || rect.right - rect.left;
9767 const targetHeight = rect.height || rect.bottom - rect.top;
9768 if (selectedElm !== targetElm) {
9769 hideResizeRect();
9770 selectedElm = targetElm;
9771 width = height = 0;
9772 }
9773 const e = editor.dispatch('ObjectSelected', { target: targetElm });
9774 if (isResizable(targetElm) && !e.isDefaultPrevented()) {
9775 each$d(resizeHandles, (handle, name) => {
9776 const startDrag = e => {
9777 const target = getResizeTargets(selectedElm)[0];
9778 startX = e.screenX;
9779 startY = e.screenY;
9780 startW = target.clientWidth;
9781 startH = target.clientHeight;
9782 ratio = startH / startW;
9783 selectedHandle = handle;
9784 selectedHandle.name = name;
9785 selectedHandle.startPos = {
9786 x: targetWidth * handle[0] + selectedElmX,
9787 y: targetHeight * handle[1] + selectedElmY
9788 };
9789 startScrollWidth = rootElement.scrollWidth;
9790 startScrollHeight = rootElement.scrollHeight;
9791 resizeBackdrop = dom.add(rootElement, 'div', {
9792 'class': 'mce-resize-backdrop',
9793 'data-mce-bogus': 'all'
9794 });
9795 dom.setStyles(resizeBackdrop, {
9796 position: 'fixed',
9797 left: '0',
9798 top: '0',
9799 width: '100%',
9800 height: '100%'
9801 });
9802 selectedElmGhost = createGhostElement(dom, selectedElm);
9803 dom.addClass(selectedElmGhost, 'mce-clonedresizable');
9804 dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all');
9805 selectedElmGhost.contentEditable = 'false';
9806 dom.setStyles(selectedElmGhost, {
9807 left: selectedElmX,
9808 top: selectedElmY,
9809 margin: 0
9810 });
9811 setGhostElmSize(selectedElmGhost, targetWidth, targetHeight);
9812 selectedElmGhost.removeAttribute(elementSelectionAttr);
9813 rootElement.appendChild(selectedElmGhost);
9814 dom.bind(editableDoc, 'mousemove', resizeGhostElement);
9815 dom.bind(editableDoc, 'mouseup', endGhostResize);
9816 if (rootDocument !== editableDoc) {
9817 dom.bind(rootDocument, 'mousemove', resizeGhostElement);
9818 dom.bind(rootDocument, 'mouseup', endGhostResize);
9819 }
9820 resizeHelper = dom.add(rootElement, 'div', {
9821 'class': 'mce-resize-helper',
9822 'data-mce-bogus': 'all'
9823 }, startW + ' &times; ' + startH);
9824 };
9825 let handleElm = dom.get('mceResizeHandle' + name);
9826 if (handleElm) {
9827 dom.remove(handleElm);
9828 }
9829 handleElm = dom.add(rootElement, 'div', {
9830 'id': 'mceResizeHandle' + name,
9831 'data-mce-bogus': 'all',
9832 'class': 'mce-resizehandle',
9833 'unselectable': true,
9834 'style': 'cursor:' + name + '-resize; margin:0; padding:0'
9835 });
9836 dom.bind(handleElm, 'mousedown', e => {
9837 e.stopImmediatePropagation();
9838 e.preventDefault();
9839 startDrag(e);
9840 });
9841 handle.elm = handleElm;
9842 dom.setStyles(handleElm, {
9843 left: targetWidth * handle[0] + selectedElmX - handleElm.offsetWidth / 2,
9844 top: targetHeight * handle[1] + selectedElmY - handleElm.offsetHeight / 2
9845 });
9846 });
9847 } else {
9848 hideResizeRect(false);
9849 }
9850 };
9851 const throttledShowResizeRect = first$1(showResizeRect, 0);
9852 const hideResizeRect = (removeSelected = true) => {
9853 throttledShowResizeRect.cancel();
9854 unbindResizeHandleEvents();
9855 if (selectedElm && removeSelected) {
9856 selectedElm.removeAttribute(elementSelectionAttr);
9857 }
9858 each$d(resizeHandles, (value, name) => {
9859 const handleElm = dom.get('mceResizeHandle' + name);
9860 if (handleElm) {
9861 dom.unbind(handleElm);
9862 dom.remove(handleElm);
9863 }
9864 });
9865 };
9866 const isChildOrEqual = (node, parent) => dom.isChildOf(node, parent);
9867 const updateResizeRect = e => {
9868 if (resizeStarted || editor.removed || editor.composing) {
9869 return;
9870 }
9871 const targetElm = e.type === 'mousedown' ? e.target : selection.getNode();
9872 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();
9873 const selectedValue = isNonNullable(controlElm) ? dom.getAttrib(controlElm, elementSelectionAttr, '1') : '1';
9874 each$e(dom.select(`img[${ elementSelectionAttr }],hr[${ elementSelectionAttr }]`), img => {
9875 img.removeAttribute(elementSelectionAttr);
9876 });
9877 if (isNonNullable(controlElm) && isChildOrEqual(controlElm, rootElement) && editor.hasFocus()) {
9878 disableGeckoResize();
9879 const startElm = selection.getStart(true);
9880 if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) {
9881 dom.setAttrib(controlElm, elementSelectionAttr, selectedValue);
9882 throttledShowResizeRect.throttle(controlElm);
9883 return;
9884 }
9885 }
9886 hideResizeRect();
9887 };
9888 const unbindResizeHandleEvents = () => {
9889 each$d(resizeHandles, handle => {
9890 if (handle.elm) {
9891 dom.unbind(handle.elm);
9892 delete handle.elm;
9893 }
9894 });
9895 };
9896 const disableGeckoResize = () => {
9897 try {
9898 editor.getDoc().execCommand('enableObjectResizing', false, 'false');
9899 } catch (ex) {
9900 }
9901 };
9902 editor.on('init', () => {
9903 disableGeckoResize();
9904 editor.on('NodeChange ResizeEditor ResizeWindow ResizeContent drop', updateResizeRect);
9905 editor.on('keyup compositionend', e => {
9906 if (selectedElm && selectedElm.nodeName === 'TABLE') {
9907 updateResizeRect(e);
9908 }
9909 });
9910 editor.on('hide blur', hideResizeRect);
9911 editor.on('contextmenu longpress', contextMenuSelectImage, true);
9912 });
9913 editor.on('remove', unbindResizeHandleEvents);
9914 const destroy = () => {
9915 throttledShowResizeRect.cancel();
9916 selectedElm = selectedElmGhost = resizeBackdrop = null;
9917 };
9918 return {
9919 isResizable,
9920 showResizeRect,
9921 hideResizeRect,
9922 updateResizeRect,
9923 destroy
9924 };
9925 };
9926
9927 const setStart = (rng, situ) => {
9928 situ.fold(e => {
9929 rng.setStartBefore(e.dom);
9930 }, (e, o) => {
9931 rng.setStart(e.dom, o);
9932 }, e => {
9933 rng.setStartAfter(e.dom);
9934 });
9935 };
9936 const setFinish = (rng, situ) => {
9937 situ.fold(e => {
9938 rng.setEndBefore(e.dom);
9939 }, (e, o) => {
9940 rng.setEnd(e.dom, o);
9941 }, e => {
9942 rng.setEndAfter(e.dom);
9943 });
9944 };
9945 const relativeToNative = (win, startSitu, finishSitu) => {
9946 const range = win.document.createRange();
9947 setStart(range, startSitu);
9948 setFinish(range, finishSitu);
9949 return range;
9950 };
9951 const exactToNative = (win, start, soffset, finish, foffset) => {
9952 const rng = win.document.createRange();
9953 rng.setStart(start.dom, soffset);
9954 rng.setEnd(finish.dom, foffset);
9955 return rng;
9956 };
9957
9958 const adt$3 = Adt.generate([
9959 {
9960 ltr: [
9961 'start',
9962 'soffset',
9963 'finish',
9964 'foffset'
9965 ]
9966 },
9967 {
9968 rtl: [
9969 'start',
9970 'soffset',
9971 'finish',
9972 'foffset'
9973 ]
9974 }
9975 ]);
9976 const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset);
9977 const getRanges = (win, selection) => selection.match({
9978 domRange: rng => {
9979 return {
9980 ltr: constant(rng),
9981 rtl: Optional.none
9982 };
9983 },
9984 relative: (startSitu, finishSitu) => {
9985 return {
9986 ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
9987 rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
9988 };
9989 },
9990 exact: (start, soffset, finish, foffset) => {
9991 return {
9992 ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)),
9993 rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset)))
9994 };
9995 }
9996 });
9997 const doDiagnose = (win, ranges) => {
9998 const rng = ranges.ltr();
9999 if (rng.collapsed) {
10000 const reversed = ranges.rtl().filter(rev => rev.collapsed === false);
10001 return reversed.map(rev => adt$3.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$3.ltr, rng));
10002 } else {
10003 return fromRange(win, adt$3.ltr, rng);
10004 }
10005 };
10006 const diagnose = (win, selection) => {
10007 const ranges = getRanges(win, selection);
10008 return doDiagnose(win, ranges);
10009 };
10010 adt$3.ltr;
10011 adt$3.rtl;
10012
10013 const create$9 = (start, soffset, finish, foffset) => ({
10014 start,
10015 soffset,
10016 finish,
10017 foffset
10018 });
10019 const SimRange = { create: create$9 };
10020
10021 const caretPositionFromPoint = (doc, x, y) => {
10022 var _a, _b;
10023 return Optional.from((_b = (_a = doc.dom).caretPositionFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y)).bind(pos => {
10024 if (pos.offsetNode === null) {
10025 return Optional.none();
10026 }
10027 const r = doc.dom.createRange();
10028 r.setStart(pos.offsetNode, pos.offset);
10029 r.collapse();
10030 return Optional.some(r);
10031 });
10032 };
10033 const caretRangeFromPoint = (doc, x, y) => {
10034 var _a, _b;
10035 return Optional.from((_b = (_a = doc.dom).caretRangeFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y));
10036 };
10037 const availableSearch = (() => {
10038 if (document.caretPositionFromPoint) {
10039 return caretPositionFromPoint;
10040 } else if (document.caretRangeFromPoint) {
10041 return caretRangeFromPoint;
10042 } else {
10043 return Optional.none;
10044 }
10045 })();
10046 const fromPoint$1 = (win, x, y) => {
10047 const doc = SugarElement.fromDom(win.document);
10048 return availableSearch(doc, x, y).map(rng => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
10049 };
10050
10051 const adt$2 = Adt.generate([
10052 { before: ['element'] },
10053 {
10054 on: [
10055 'element',
10056 'offset'
10057 ]
10058 },
10059 { after: ['element'] }
10060 ]);
10061 const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
10062 const getStart$2 = situ => situ.fold(identity, identity, identity);
10063 const before$1 = adt$2.before;
10064 const on = adt$2.on;
10065 const after$1 = adt$2.after;
10066 const Situ = {
10067 before: before$1,
10068 on,
10069 after: after$1,
10070 cata,
10071 getStart: getStart$2
10072 };
10073
10074 const adt$1 = Adt.generate([
10075 { domRange: ['rng'] },
10076 {
10077 relative: [
10078 'startSitu',
10079 'finishSitu'
10080 ]
10081 },
10082 {
10083 exact: [
10084 'start',
10085 'soffset',
10086 'finish',
10087 'foffset'
10088 ]
10089 }
10090 ]);
10091 const exactFromRange = simRange => adt$1.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
10092 const getStart$1 = selection => selection.match({
10093 domRange: rng => SugarElement.fromDom(rng.startContainer),
10094 relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
10095 exact: (start, _soffset, _finish, _foffset) => start
10096 });
10097 const domRange = adt$1.domRange;
10098 const relative = adt$1.relative;
10099 const exact = adt$1.exact;
10100 const getWin = selection => {
10101 const start = getStart$1(selection);
10102 return defaultView(start);
10103 };
10104 const range = SimRange.create;
10105 const SimSelection = {
10106 domRange,
10107 relative,
10108 exact,
10109 exactFromRange,
10110 getWin,
10111 range
10112 };
10113
10114 const beforeSpecial = (element, offset) => {
10115 const name$1 = name(element);
10116 if ('input' === name$1) {
10117 return Situ.after(element);
10118 } else if (!contains$2([
10119 'br',
10120 'img'
10121 ], name$1)) {
10122 return Situ.on(element, offset);
10123 } else {
10124 return offset === 0 ? Situ.before(element) : Situ.after(element);
10125 }
10126 };
10127 const preprocessRelative = (startSitu, finishSitu) => {
10128 const start = startSitu.fold(Situ.before, beforeSpecial, Situ.after);
10129 const finish = finishSitu.fold(Situ.before, beforeSpecial, Situ.after);
10130 return SimSelection.relative(start, finish);
10131 };
10132 const preprocessExact = (start, soffset, finish, foffset) => {
10133 const startSitu = beforeSpecial(start, soffset);
10134 const finishSitu = beforeSpecial(finish, foffset);
10135 return SimSelection.relative(startSitu, finishSitu);
10136 };
10137 const preprocess = selection => selection.match({
10138 domRange: rng => {
10139 const start = SugarElement.fromDom(rng.startContainer);
10140 const finish = SugarElement.fromDom(rng.endContainer);
10141 return preprocessExact(start, rng.startOffset, finish, rng.endOffset);
10142 },
10143 relative: preprocessRelative,
10144 exact: preprocessExact
10145 });
10146
10147 const fromElements = (elements, scope) => {
10148 const doc = scope || document;
10149 const fragment = doc.createDocumentFragment();
10150 each$e(elements, element => {
10151 fragment.appendChild(element.dom);
10152 });
10153 return SugarElement.fromDom(fragment);
10154 };
10155
10156 const toNative = selection => {
10157 const win = SimSelection.getWin(selection).dom;
10158 const getDomRange = (start, soffset, finish, foffset) => exactToNative(win, start, soffset, finish, foffset);
10159 const filtered = preprocess(selection);
10160 return diagnose(win, filtered).match({
10161 ltr: getDomRange,
10162 rtl: getDomRange
10163 });
10164 };
10165 const getAtPoint = (win, x, y) => fromPoint$1(win, x, y);
10166
10167 const fromPoint = (clientX, clientY, doc) => {
10168 const win = defaultView(SugarElement.fromDom(doc));
10169 return getAtPoint(win.dom, clientX, clientY).map(simRange => {
10170 const rng = doc.createRange();
10171 rng.setStart(simRange.start.dom, simRange.soffset);
10172 rng.setEnd(simRange.finish.dom, simRange.foffset);
10173 return rng;
10174 }).getOrUndefined();
10175 };
10176
10177 const isEq$4 = (rng1, rng2) => {
10178 return isNonNullable(rng1) && isNonNullable(rng2) && (rng1.startContainer === rng2.startContainer && rng1.startOffset === rng2.startOffset) && (rng1.endContainer === rng2.endContainer && rng1.endOffset === rng2.endOffset);
10179 };
10180
10181 const findParent = (node, rootNode, predicate) => {
10182 let currentNode = node;
10183 while (currentNode && currentNode !== rootNode) {
10184 if (predicate(currentNode)) {
10185 return currentNode;
10186 }
10187 currentNode = currentNode.parentNode;
10188 }
10189 return null;
10190 };
10191 const hasParent$1 = (node, rootNode, predicate) => findParent(node, rootNode, predicate) !== null;
10192 const hasParentWithName = (node, rootNode, name) => hasParent$1(node, rootNode, node => node.nodeName === name);
10193 const isCeFalseCaretContainer = (node, rootNode) => isCaretContainer$2(node) && !hasParent$1(node, rootNode, isCaretNode);
10194 const hasBrBeforeAfter = (dom, node, left) => {
10195 const parentNode = node.parentNode;
10196 if (parentNode) {
10197 const walker = new DomTreeWalker(node, dom.getParent(parentNode, dom.isBlock) || dom.getRoot());
10198 let currentNode;
10199 while (currentNode = walker[left ? 'prev' : 'next']()) {
10200 if (isBr$6(currentNode)) {
10201 return true;
10202 }
10203 }
10204 }
10205 return false;
10206 };
10207 const isPrevNode = (node, name) => {
10208 var _a;
10209 return ((_a = node.previousSibling) === null || _a === void 0 ? void 0 : _a.nodeName) === name;
10210 };
10211 const hasContentEditableFalseParent = (root, node) => {
10212 let currentNode = node;
10213 while (currentNode && currentNode !== root) {
10214 if (isContentEditableFalse$b(currentNode)) {
10215 return true;
10216 }
10217 currentNode = currentNode.parentNode;
10218 }
10219 return false;
10220 };
10221 const findTextNodeRelative = (dom, isAfterNode, collapsed, left, startNode) => {
10222 const body = dom.getRoot();
10223 const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
10224 const parentNode = startNode.parentNode;
10225 let lastInlineElement;
10226 let node;
10227 if (!parentNode) {
10228 return Optional.none();
10229 }
10230 const parentBlockContainer = dom.getParent(parentNode, dom.isBlock) || body;
10231 if (left && isBr$6(startNode) && isAfterNode && dom.isEmpty(parentBlockContainer)) {
10232 return Optional.some(CaretPosition(parentNode, dom.nodeIndex(startNode)));
10233 }
10234 const walker = new DomTreeWalker(startNode, parentBlockContainer);
10235 while (node = walker[left ? 'prev' : 'next']()) {
10236 if (dom.getContentEditableParent(node) === 'false' || isCeFalseCaretContainer(node, body)) {
10237 return Optional.none();
10238 }
10239 if (isText$b(node) && node.data.length > 0) {
10240 if (!hasParentWithName(node, body, 'A')) {
10241 return Optional.some(CaretPosition(node, left ? node.data.length : 0));
10242 }
10243 return Optional.none();
10244 }
10245 if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
10246 return Optional.none();
10247 }
10248 lastInlineElement = node;
10249 }
10250 if (isComment(lastInlineElement)) {
10251 return Optional.none();
10252 }
10253 if (collapsed && lastInlineElement) {
10254 return Optional.some(CaretPosition(lastInlineElement, 0));
10255 }
10256 return Optional.none();
10257 };
10258 const normalizeEndPoint = (dom, collapsed, start, rng) => {
10259 const body = dom.getRoot();
10260 let node;
10261 let normalized = false;
10262 let container = start ? rng.startContainer : rng.endContainer;
10263 let offset = start ? rng.startOffset : rng.endOffset;
10264 const isAfterNode = isElement$6(container) && offset === container.childNodes.length;
10265 const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
10266 let directionLeft = start;
10267 if (isCaretContainer$2(container)) {
10268 return Optional.none();
10269 }
10270 if (isElement$6(container) && offset > container.childNodes.length - 1) {
10271 directionLeft = false;
10272 }
10273 if (isDocument$1(container)) {
10274 container = body;
10275 offset = 0;
10276 }
10277 if (container === body) {
10278 if (directionLeft) {
10279 node = container.childNodes[offset > 0 ? offset - 1 : 0];
10280 if (node) {
10281 if (isCaretContainer$2(node)) {
10282 return Optional.none();
10283 }
10284 if (nonEmptyElementsMap[node.nodeName] || isTable$2(node)) {
10285 return Optional.none();
10286 }
10287 }
10288 }
10289 if (container.hasChildNodes()) {
10290 offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
10291 container = container.childNodes[offset];
10292 offset = isText$b(container) && isAfterNode ? container.data.length : 0;
10293 if (!collapsed && container === body.lastChild && isTable$2(container)) {
10294 return Optional.none();
10295 }
10296 if (hasContentEditableFalseParent(body, container) || isCaretContainer$2(container)) {
10297 return Optional.none();
10298 }
10299 if (isDetails(container)) {
10300 return Optional.none();
10301 }
10302 if (container.hasChildNodes() && !isTable$2(container)) {
10303 node = container;
10304 const walker = new DomTreeWalker(container, body);
10305 do {
10306 if (isContentEditableFalse$b(node) || isCaretContainer$2(node)) {
10307 normalized = false;
10308 break;
10309 }
10310 if (isText$b(node) && node.data.length > 0) {
10311 offset = directionLeft ? 0 : node.data.length;
10312 container = node;
10313 normalized = true;
10314 break;
10315 }
10316 if (nonEmptyElementsMap[node.nodeName.toLowerCase()] && !isTableCellOrCaption(node)) {
10317 offset = dom.nodeIndex(node);
10318 container = node.parentNode;
10319 if (!directionLeft) {
10320 offset++;
10321 }
10322 normalized = true;
10323 break;
10324 }
10325 } while (node = directionLeft ? walker.next() : walker.prev());
10326 }
10327 }
10328 }
10329 if (collapsed) {
10330 if (isText$b(container) && offset === 0) {
10331 findTextNodeRelative(dom, isAfterNode, collapsed, true, container).each(pos => {
10332 container = pos.container();
10333 offset = pos.offset();
10334 normalized = true;
10335 });
10336 }
10337 if (isElement$6(container)) {
10338 node = container.childNodes[offset];
10339 if (!node) {
10340 node = container.childNodes[offset - 1];
10341 }
10342 if (node && isBr$6(node) && !isPrevNode(node, 'A') && !hasBrBeforeAfter(dom, node, false) && !hasBrBeforeAfter(dom, node, true)) {
10343 findTextNodeRelative(dom, isAfterNode, collapsed, true, node).each(pos => {
10344 container = pos.container();
10345 offset = pos.offset();
10346 normalized = true;
10347 });
10348 }
10349 }
10350 }
10351 if (directionLeft && !collapsed && isText$b(container) && offset === container.data.length) {
10352 findTextNodeRelative(dom, isAfterNode, collapsed, false, container).each(pos => {
10353 container = pos.container();
10354 offset = pos.offset();
10355 normalized = true;
10356 });
10357 }
10358 return normalized && container ? Optional.some(CaretPosition(container, offset)) : Optional.none();
10359 };
10360 const normalize$2 = (dom, rng) => {
10361 const collapsed = rng.collapsed, normRng = rng.cloneRange();
10362 const startPos = CaretPosition.fromRangeStart(rng);
10363 normalizeEndPoint(dom, collapsed, true, normRng).each(pos => {
10364 if (!collapsed || !CaretPosition.isAbove(startPos, pos)) {
10365 normRng.setStart(pos.container(), pos.offset());
10366 }
10367 });
10368 if (!collapsed) {
10369 normalizeEndPoint(dom, collapsed, false, normRng).each(pos => {
10370 normRng.setEnd(pos.container(), pos.offset());
10371 });
10372 }
10373 if (collapsed) {
10374 normRng.collapse(true);
10375 }
10376 return isEq$4(rng, normRng) ? Optional.none() : Optional.some(normRng);
10377 };
10378
10379 const splitText = (node, offset) => {
10380 return node.splitText(offset);
10381 };
10382 const split = rng => {
10383 let startContainer = rng.startContainer, startOffset = rng.startOffset, endContainer = rng.endContainer, endOffset = rng.endOffset;
10384 if (startContainer === endContainer && isText$b(startContainer)) {
10385 if (startOffset > 0 && startOffset < startContainer.data.length) {
10386 endContainer = splitText(startContainer, startOffset);
10387 startContainer = endContainer.previousSibling;
10388 if (endOffset > startOffset) {
10389 endOffset = endOffset - startOffset;
10390 const newContainer = splitText(endContainer, endOffset).previousSibling;
10391 startContainer = endContainer = newContainer;
10392 endOffset = newContainer.data.length;
10393 startOffset = 0;
10394 } else {
10395 endOffset = 0;
10396 }
10397 }
10398 } else {
10399 if (isText$b(startContainer) && startOffset > 0 && startOffset < startContainer.data.length) {
10400 startContainer = splitText(startContainer, startOffset);
10401 startOffset = 0;
10402 }
10403 if (isText$b(endContainer) && endOffset > 0 && endOffset < endContainer.data.length) {
10404 const newContainer = splitText(endContainer, endOffset).previousSibling;
10405 endContainer = newContainer;
10406 endOffset = newContainer.data.length;
10407 }
10408 }
10409 return {
10410 startContainer,
10411 startOffset,
10412 endContainer,
10413 endOffset
10414 };
10415 };
10416
10417 const RangeUtils = dom => {
10418 const walk = (rng, callback) => {
10419 return walk$3(dom, rng, callback);
10420 };
10421 const split$1 = split;
10422 const normalize = rng => {
10423 return normalize$2(dom, rng).fold(never, normalizedRng => {
10424 rng.setStart(normalizedRng.startContainer, normalizedRng.startOffset);
10425 rng.setEnd(normalizedRng.endContainer, normalizedRng.endOffset);
10426 return true;
10427 });
10428 };
10429 const expand = (rng, options = { type: 'word' }) => {
10430 if (options.type === 'word') {
10431 const rangeLike = expandRng(dom, rng, [{ inline: 'span' }]);
10432 const newRange = dom.createRng();
10433 newRange.setStart(rangeLike.startContainer, rangeLike.startOffset);
10434 newRange.setEnd(rangeLike.endContainer, rangeLike.endOffset);
10435 return newRange;
10436 }
10437 return rng;
10438 };
10439 return {
10440 walk,
10441 split: split$1,
10442 expand,
10443 normalize
10444 };
10445 };
10446 RangeUtils.compareRanges = isEq$4;
10447 RangeUtils.getCaretRangeFromPoint = fromPoint;
10448 RangeUtils.getSelectedNode = getSelectedNode;
10449 RangeUtils.getNode = getNode$1;
10450
10451 const Dimension = (name, getOffset) => {
10452 const set = (element, h) => {
10453 if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
10454 throw new Error(name + '.set accepts only positive integer values. Value was ' + h);
10455 }
10456 const dom = element.dom;
10457 if (isSupported(dom)) {
10458 dom.style[name] = h + 'px';
10459 }
10460 };
10461 const get = element => {
10462 const r = getOffset(element);
10463 if (r <= 0 || r === null) {
10464 const css = get$7(element, name);
10465 return parseFloat(css) || 0;
10466 }
10467 return r;
10468 };
10469 const getOuter = get;
10470 const aggregate = (element, properties) => foldl(properties, (acc, property) => {
10471 const val = get$7(element, property);
10472 const value = val === undefined ? 0 : parseInt(val, 10);
10473 return isNaN(value) ? acc : acc + value;
10474 }, 0);
10475 const max = (element, value, properties) => {
10476 const cumulativeInclusions = aggregate(element, properties);
10477 const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0;
10478 return absoluteMax;
10479 };
10480 return {
10481 set,
10482 get,
10483 getOuter,
10484 aggregate,
10485 max
10486 };
10487 };
10488
10489 const api = Dimension('height', element => {
10490 const dom = element.dom;
10491 return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
10492 });
10493 const get$2 = element => api.get(element);
10494
10495 const getDocument = () => SugarElement.fromDom(document);
10496
10497 const walkUp = (navigation, doc) => {
10498 const frame = navigation.view(doc);
10499 return frame.fold(constant([]), f => {
10500 const parent = navigation.owner(f);
10501 const rest = walkUp(navigation, parent);
10502 return [f].concat(rest);
10503 });
10504 };
10505 const pathTo = (element, navigation) => {
10506 const d = navigation.owner(element);
10507 return walkUp(navigation, d);
10508 };
10509
10510 const view = doc => {
10511 var _a;
10512 const element = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement);
10513 return element.map(SugarElement.fromDom);
10514 };
10515 const owner = element => documentOrOwner(element);
10516
10517 var Navigation = /*#__PURE__*/Object.freeze({
10518 __proto__: null,
10519 view: view,
10520 owner: owner
10521 });
10522
10523 const find = element => {
10524 const doc = getDocument();
10525 const scroll = get$5(doc);
10526 const frames = pathTo(element, Navigation);
10527 const offset = viewport(element);
10528 const r = foldr(frames, (b, a) => {
10529 const loc = viewport(a);
10530 return {
10531 left: b.left + loc.left,
10532 top: b.top + loc.top
10533 };
10534 }, {
10535 left: 0,
10536 top: 0
10537 });
10538 return SugarPosition(r.left + offset.left + scroll.left, r.top + offset.top + scroll.top);
10539 };
10540
10541 const excludeFromDescend = element => name(element) === 'textarea';
10542 const fireScrollIntoViewEvent = (editor, data) => {
10543 const scrollEvent = editor.dispatch('ScrollIntoView', data);
10544 return scrollEvent.isDefaultPrevented();
10545 };
10546 const fireAfterScrollIntoViewEvent = (editor, data) => {
10547 editor.dispatch('AfterScrollIntoView', data);
10548 };
10549 const descend = (element, offset) => {
10550 const children = children$1(element);
10551 if (children.length === 0 || excludeFromDescend(element)) {
10552 return {
10553 element,
10554 offset
10555 };
10556 } else if (offset < children.length && !excludeFromDescend(children[offset])) {
10557 return {
10558 element: children[offset],
10559 offset: 0
10560 };
10561 } else {
10562 const last = children[children.length - 1];
10563 if (excludeFromDescend(last)) {
10564 return {
10565 element,
10566 offset
10567 };
10568 } else {
10569 if (name(last) === 'img') {
10570 return {
10571 element: last,
10572 offset: 1
10573 };
10574 } else if (isText$c(last)) {
10575 return {
10576 element: last,
10577 offset: get$3(last).length
10578 };
10579 } else {
10580 return {
10581 element: last,
10582 offset: children$1(last).length
10583 };
10584 }
10585 }
10586 }
10587 };
10588 const markerInfo = (element, cleanupFun) => {
10589 const pos = absolute(element);
10590 const height = get$2(element);
10591 return {
10592 element,
10593 bottom: pos.top + height,
10594 height,
10595 pos,
10596 cleanup: cleanupFun
10597 };
10598 };
10599 const createMarker$1 = (element, offset) => {
10600 const startPoint = descend(element, offset);
10601 const span = SugarElement.fromHtml('<span data-mce-bogus="all" style="display: inline-block;">' + ZWSP$1 + '</span>');
10602 before$3(startPoint.element, span);
10603 return markerInfo(span, () => remove$4(span));
10604 };
10605 const elementMarker = element => markerInfo(SugarElement.fromDom(element), noop);
10606 const withMarker = (editor, f, rng, alignToTop) => {
10607 preserveWith(editor, (_s, _e) => applyWithMarker(editor, f, rng, alignToTop), rng);
10608 };
10609 const withScrollEvents = (editor, doc, f, marker, alignToTop) => {
10610 const data = {
10611 elm: marker.element.dom,
10612 alignToTop
10613 };
10614 if (fireScrollIntoViewEvent(editor, data)) {
10615 return;
10616 }
10617 const scrollTop = get$5(doc).top;
10618 f(editor, doc, scrollTop, marker, alignToTop);
10619 fireAfterScrollIntoViewEvent(editor, data);
10620 };
10621 const applyWithMarker = (editor, f, rng, alignToTop) => {
10622 const body = SugarElement.fromDom(editor.getBody());
10623 const doc = SugarElement.fromDom(editor.getDoc());
10624 reflow(body);
10625 const marker = createMarker$1(SugarElement.fromDom(rng.startContainer), rng.startOffset);
10626 withScrollEvents(editor, doc, f, marker, alignToTop);
10627 marker.cleanup();
10628 };
10629 const withElement = (editor, element, f, alignToTop) => {
10630 const doc = SugarElement.fromDom(editor.getDoc());
10631 withScrollEvents(editor, doc, f, elementMarker(element), alignToTop);
10632 };
10633 const preserveWith = (editor, f, rng) => {
10634 const startElement = rng.startContainer;
10635 const startOffset = rng.startOffset;
10636 const endElement = rng.endContainer;
10637 const endOffset = rng.endOffset;
10638 f(SugarElement.fromDom(startElement), SugarElement.fromDom(endElement));
10639 const newRng = editor.dom.createRng();
10640 newRng.setStart(startElement, startOffset);
10641 newRng.setEnd(endElement, endOffset);
10642 editor.selection.setRng(rng);
10643 };
10644 const scrollToMarker = (editor, marker, viewHeight, alignToTop, doc) => {
10645 const pos = marker.pos;
10646 if (alignToTop) {
10647 to(pos.left, pos.top, doc);
10648 } else {
10649 const y = pos.top - viewHeight + marker.height;
10650 to(-editor.getBody().getBoundingClientRect().left, y, doc);
10651 }
10652 };
10653 const intoWindowIfNeeded = (editor, doc, scrollTop, viewHeight, marker, alignToTop) => {
10654 const viewportBottom = viewHeight + scrollTop;
10655 const markerTop = marker.pos.top;
10656 const markerBottom = marker.bottom;
10657 const largerThanViewport = markerBottom - markerTop >= viewHeight;
10658 if (markerTop < scrollTop) {
10659 scrollToMarker(editor, marker, viewHeight, alignToTop !== false, doc);
10660 } else if (markerTop > viewportBottom) {
10661 const align = largerThanViewport ? alignToTop !== false : alignToTop === true;
10662 scrollToMarker(editor, marker, viewHeight, align, doc);
10663 } else if (markerBottom > viewportBottom && !largerThanViewport) {
10664 scrollToMarker(editor, marker, viewHeight, alignToTop === true, doc);
10665 }
10666 };
10667 const intoWindow = (editor, doc, scrollTop, marker, alignToTop) => {
10668 const viewHeight = defaultView(doc).dom.innerHeight;
10669 intoWindowIfNeeded(editor, doc, scrollTop, viewHeight, marker, alignToTop);
10670 };
10671 const intoFrame = (editor, doc, scrollTop, marker, alignToTop) => {
10672 const frameViewHeight = defaultView(doc).dom.innerHeight;
10673 intoWindowIfNeeded(editor, doc, scrollTop, frameViewHeight, marker, alignToTop);
10674 const op = find(marker.element);
10675 const viewportBounds = getBounds(window);
10676 if (op.top < viewportBounds.y) {
10677 intoView(marker.element, alignToTop !== false);
10678 } else if (op.top > viewportBounds.bottom) {
10679 intoView(marker.element, alignToTop === true);
10680 }
10681 };
10682 const rangeIntoWindow = (editor, rng, alignToTop) => withMarker(editor, intoWindow, rng, alignToTop);
10683 const elementIntoWindow = (editor, element, alignToTop) => withElement(editor, element, intoWindow, alignToTop);
10684 const rangeIntoFrame = (editor, rng, alignToTop) => withMarker(editor, intoFrame, rng, alignToTop);
10685 const elementIntoFrame = (editor, element, alignToTop) => withElement(editor, element, intoFrame, alignToTop);
10686 const scrollElementIntoView = (editor, element, alignToTop) => {
10687 const scroller = editor.inline ? elementIntoWindow : elementIntoFrame;
10688 scroller(editor, element, alignToTop);
10689 };
10690 const scrollRangeIntoView = (editor, rng, alignToTop) => {
10691 const scroller = editor.inline ? rangeIntoWindow : rangeIntoFrame;
10692 scroller(editor, rng, alignToTop);
10693 };
10694
10695 const focus$1 = (element, preventScroll = false) => element.dom.focus({ preventScroll });
10696 const hasFocus$1 = element => {
10697 const root = getRootNode(element).dom;
10698 return element.dom === root.activeElement;
10699 };
10700 const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
10701 const search = element => active$1(getRootNode(element)).filter(e => element.dom.contains(e.dom));
10702
10703 const clamp$1 = (offset, element) => {
10704 const max = isText$c(element) ? get$3(element).length : children$1(element).length + 1;
10705 if (offset > max) {
10706 return max;
10707 } else if (offset < 0) {
10708 return 0;
10709 }
10710 return offset;
10711 };
10712 const normalizeRng = rng => SimSelection.range(rng.start, clamp$1(rng.soffset, rng.start), rng.finish, clamp$1(rng.foffset, rng.finish));
10713 const isOrContains = (root, elm) => !isRestrictedNode(elm.dom) && (contains(root, elm) || eq(root, elm));
10714 const isRngInRoot = root => rng => isOrContains(root, rng.start) && isOrContains(root, rng.finish);
10715 const shouldStore = editor => editor.inline || Env.browser.isFirefox();
10716 const nativeRangeToSelectionRange = r => SimSelection.range(SugarElement.fromDom(r.startContainer), r.startOffset, SugarElement.fromDom(r.endContainer), r.endOffset);
10717 const readRange = win => {
10718 const selection = win.getSelection();
10719 const rng = !selection || selection.rangeCount === 0 ? Optional.none() : Optional.from(selection.getRangeAt(0));
10720 return rng.map(nativeRangeToSelectionRange);
10721 };
10722 const getBookmark = root => {
10723 const win = defaultView(root);
10724 return readRange(win.dom).filter(isRngInRoot(root));
10725 };
10726 const validate = (root, bookmark) => Optional.from(bookmark).filter(isRngInRoot(root)).map(normalizeRng);
10727 const bookmarkToNativeRng = bookmark => {
10728 const rng = document.createRange();
10729 try {
10730 rng.setStart(bookmark.start.dom, bookmark.soffset);
10731 rng.setEnd(bookmark.finish.dom, bookmark.foffset);
10732 return Optional.some(rng);
10733 } catch (_) {
10734 return Optional.none();
10735 }
10736 };
10737 const store = editor => {
10738 const newBookmark = shouldStore(editor) ? getBookmark(SugarElement.fromDom(editor.getBody())) : Optional.none();
10739 editor.bookmark = newBookmark.isSome() ? newBookmark : editor.bookmark;
10740 };
10741 const getRng = editor => {
10742 const bookmark = editor.bookmark ? editor.bookmark : Optional.none();
10743 return bookmark.bind(x => validate(SugarElement.fromDom(editor.getBody()), x)).bind(bookmarkToNativeRng);
10744 };
10745 const restore = editor => {
10746 getRng(editor).each(rng => editor.selection.setRng(rng));
10747 };
10748
10749 const isEditorUIElement$1 = elm => {
10750 const className = elm.className.toString();
10751 return className.indexOf('tox-') !== -1 || className.indexOf('mce-') !== -1;
10752 };
10753 const FocusManager = { isEditorUIElement: isEditorUIElement$1 };
10754
10755 const wrappedSetTimeout = (callback, time) => {
10756 if (!isNumber(time)) {
10757 time = 0;
10758 }
10759 return setTimeout(callback, time);
10760 };
10761 const wrappedSetInterval = (callback, time) => {
10762 if (!isNumber(time)) {
10763 time = 0;
10764 }
10765 return setInterval(callback, time);
10766 };
10767 const Delay = {
10768 setEditorTimeout: (editor, callback, time) => {
10769 return wrappedSetTimeout(() => {
10770 if (!editor.removed) {
10771 callback();
10772 }
10773 }, time);
10774 },
10775 setEditorInterval: (editor, callback, time) => {
10776 const timer = wrappedSetInterval(() => {
10777 if (!editor.removed) {
10778 callback();
10779 } else {
10780 clearInterval(timer);
10781 }
10782 }, time);
10783 return timer;
10784 }
10785 };
10786
10787 const isManualNodeChange = e => {
10788 return e.type === 'nodechange' && e.selectionChange;
10789 };
10790 const registerPageMouseUp = (editor, throttledStore) => {
10791 const mouseUpPage = () => {
10792 throttledStore.throttle();
10793 };
10794 DOMUtils.DOM.bind(document, 'mouseup', mouseUpPage);
10795 editor.on('remove', () => {
10796 DOMUtils.DOM.unbind(document, 'mouseup', mouseUpPage);
10797 });
10798 };
10799 const registerMouseUp = (editor, throttledStore) => {
10800 editor.on('mouseup touchend', _e => {
10801 throttledStore.throttle();
10802 });
10803 };
10804 const registerEditorEvents = (editor, throttledStore) => {
10805 registerMouseUp(editor, throttledStore);
10806 editor.on('keyup NodeChange AfterSetSelectionRange', e => {
10807 if (!isManualNodeChange(e)) {
10808 store(editor);
10809 }
10810 });
10811 };
10812 const register$6 = editor => {
10813 const throttledStore = first$1(() => {
10814 store(editor);
10815 }, 0);
10816 editor.on('init', () => {
10817 if (editor.inline) {
10818 registerPageMouseUp(editor, throttledStore);
10819 }
10820 registerEditorEvents(editor, throttledStore);
10821 });
10822 editor.on('remove', () => {
10823 throttledStore.cancel();
10824 });
10825 };
10826
10827 let documentFocusInHandler;
10828 const DOM$9 = DOMUtils.DOM;
10829 const isEditorUIElement = elm => {
10830 return isElement$6(elm) && FocusManager.isEditorUIElement(elm);
10831 };
10832 const isEditorContentAreaElement = elm => {
10833 const classList = elm.classList;
10834 if (classList !== undefined) {
10835 return classList.contains('tox-edit-area') || classList.contains('tox-edit-area__iframe') || classList.contains('mce-content-body');
10836 } else {
10837 return false;
10838 }
10839 };
10840 const isUIElement = (editor, elm) => {
10841 const customSelector = getCustomUiSelector(editor);
10842 const parent = DOM$9.getParent(elm, elm => {
10843 return isEditorUIElement(elm) || (customSelector ? editor.dom.is(elm, customSelector) : false);
10844 });
10845 return parent !== null;
10846 };
10847 const getActiveElement = editor => {
10848 try {
10849 const root = getRootNode(SugarElement.fromDom(editor.getElement()));
10850 return active$1(root).fold(() => document.body, x => x.dom);
10851 } catch (ex) {
10852 return document.body;
10853 }
10854 };
10855 const registerEvents$1 = (editorManager, e) => {
10856 const editor = e.editor;
10857 register$6(editor);
10858 const toggleContentAreaOnFocus = (editor, fn) => {
10859 if (shouldHighlightOnFocus(editor) && editor.inline !== true) {
10860 const contentArea = SugarElement.fromDom(editor.getContainer());
10861 fn(contentArea, 'tox-edit-focus');
10862 }
10863 };
10864 editor.on('focusin', () => {
10865 const focusedEditor = editorManager.focusedEditor;
10866 if (isEditorContentAreaElement(getActiveElement(editor))) {
10867 toggleContentAreaOnFocus(editor, add$2);
10868 }
10869 if (focusedEditor !== editor) {
10870 if (focusedEditor) {
10871 focusedEditor.dispatch('blur', { focusedEditor: editor });
10872 }
10873 editorManager.setActive(editor);
10874 editorManager.focusedEditor = editor;
10875 editor.dispatch('focus', { blurredEditor: focusedEditor });
10876 editor.focus(true);
10877 }
10878 });
10879 editor.on('focusout', () => {
10880 Delay.setEditorTimeout(editor, () => {
10881 const focusedEditor = editorManager.focusedEditor;
10882 if (!isEditorContentAreaElement(getActiveElement(editor)) || focusedEditor !== editor) {
10883 toggleContentAreaOnFocus(editor, remove$6);
10884 }
10885 if (!isUIElement(editor, getActiveElement(editor)) && focusedEditor === editor) {
10886 editor.dispatch('blur', { focusedEditor: null });
10887 editorManager.focusedEditor = null;
10888 }
10889 });
10890 });
10891 if (!documentFocusInHandler) {
10892 documentFocusInHandler = e => {
10893 const activeEditor = editorManager.activeEditor;
10894 if (activeEditor) {
10895 getOriginalEventTarget(e).each(target => {
10896 const elem = target;
10897 if (elem.ownerDocument === document) {
10898 if (elem !== document.body && !isUIElement(activeEditor, elem) && editorManager.focusedEditor === activeEditor) {
10899 activeEditor.dispatch('blur', { focusedEditor: null });
10900 editorManager.focusedEditor = null;
10901 }
10902 }
10903 });
10904 }
10905 };
10906 DOM$9.bind(document, 'focusin', documentFocusInHandler);
10907 }
10908 };
10909 const unregisterDocumentEvents = (editorManager, e) => {
10910 if (editorManager.focusedEditor === e.editor) {
10911 editorManager.focusedEditor = null;
10912 }
10913 if (!editorManager.activeEditor && documentFocusInHandler) {
10914 DOM$9.unbind(document, 'focusin', documentFocusInHandler);
10915 documentFocusInHandler = null;
10916 }
10917 };
10918 const setup$w = editorManager => {
10919 editorManager.on('AddEditor', curry(registerEvents$1, editorManager));
10920 editorManager.on('RemoveEditor', curry(unregisterDocumentEvents, editorManager));
10921 };
10922
10923 const getContentEditableHost = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'true');
10924 const getCollapsedNode = rng => rng.collapsed ? Optional.from(getNode$1(rng.startContainer, rng.startOffset)).map(SugarElement.fromDom) : Optional.none();
10925 const getFocusInElement = (root, rng) => getCollapsedNode(rng).bind(node => {
10926 if (isTableSection(node)) {
10927 return Optional.some(node);
10928 } else if (!contains(root, node)) {
10929 return Optional.some(root);
10930 } else {
10931 return Optional.none();
10932 }
10933 });
10934 const normalizeSelection = (editor, rng) => {
10935 getFocusInElement(SugarElement.fromDom(editor.getBody()), rng).bind(elm => {
10936 return firstPositionIn(elm.dom);
10937 }).fold(() => {
10938 editor.selection.normalize();
10939 }, caretPos => editor.selection.setRng(caretPos.toRange()));
10940 };
10941 const focusBody = body => {
10942 if (body.setActive) {
10943 try {
10944 body.setActive();
10945 } catch (ex) {
10946 body.focus();
10947 }
10948 } else {
10949 body.focus();
10950 }
10951 };
10952 const hasElementFocus = elm => hasFocus$1(elm) || search(elm).isSome();
10953 const hasIframeFocus = editor => isNonNullable(editor.iframeElement) && hasFocus$1(SugarElement.fromDom(editor.iframeElement));
10954 const hasInlineFocus = editor => {
10955 const rawBody = editor.getBody();
10956 return rawBody && hasElementFocus(SugarElement.fromDom(rawBody));
10957 };
10958 const hasUiFocus = editor => {
10959 const dos = getRootNode(SugarElement.fromDom(editor.getElement()));
10960 return active$1(dos).filter(elem => !isEditorContentAreaElement(elem.dom) && isUIElement(editor, elem.dom)).isSome();
10961 };
10962 const hasFocus = editor => editor.inline ? hasInlineFocus(editor) : hasIframeFocus(editor);
10963 const hasEditorOrUiFocus = editor => hasFocus(editor) || hasUiFocus(editor);
10964 const focusEditor = editor => {
10965 const selection = editor.selection;
10966 const body = editor.getBody();
10967 let rng = selection.getRng();
10968 editor.quirks.refreshContentEditable();
10969 if (isNonNullable(editor.bookmark) && !hasFocus(editor)) {
10970 getRng(editor).each(bookmarkRng => {
10971 editor.selection.setRng(bookmarkRng);
10972 rng = bookmarkRng;
10973 });
10974 }
10975 const contentEditableHost = getContentEditableHost(editor, selection.getNode());
10976 if (contentEditableHost && editor.dom.isChildOf(contentEditableHost, body)) {
10977 focusBody(contentEditableHost);
10978 normalizeSelection(editor, rng);
10979 activateEditor(editor);
10980 return;
10981 }
10982 if (!editor.inline) {
10983 if (!Env.browser.isOpera()) {
10984 focusBody(body);
10985 }
10986 editor.getWin().focus();
10987 }
10988 if (Env.browser.isFirefox() || editor.inline) {
10989 focusBody(body);
10990 normalizeSelection(editor, rng);
10991 }
10992 activateEditor(editor);
10993 };
10994 const activateEditor = editor => editor.editorManager.setActive(editor);
10995 const focus = (editor, skipFocus) => {
10996 if (editor.removed) {
10997 return;
10998 }
10999 if (skipFocus) {
11000 activateEditor(editor);
11001 } else {
11002 focusEditor(editor);
11003 }
11004 };
11005
11006 const isEditableRange = (dom, rng) => {
11007 if (rng.collapsed) {
11008 return dom.isEditable(rng.startContainer);
11009 } else {
11010 return dom.isEditable(rng.startContainer) && dom.isEditable(rng.endContainer);
11011 }
11012 };
11013
11014 const getEndpointElement = (root, rng, start, real, resolve) => {
11015 const container = start ? rng.startContainer : rng.endContainer;
11016 const offset = start ? rng.startOffset : rng.endOffset;
11017 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);
11018 };
11019 const getStart = (root, rng, real = false) => getEndpointElement(root, rng, true, real, (elm, offset) => Math.min(childNodesCount(elm), offset));
11020 const getEnd = (root, rng, real = false) => getEndpointElement(root, rng, false, real, (elm, offset) => offset > 0 ? offset - 1 : offset);
11021 const skipEmptyTextNodes = (node, forwards) => {
11022 const orig = node;
11023 while (node && isText$b(node) && node.length === 0) {
11024 node = forwards ? node.nextSibling : node.previousSibling;
11025 }
11026 return node || orig;
11027 };
11028 const getNode = (root, rng) => {
11029 if (!rng) {
11030 return root;
11031 }
11032 let startContainer = rng.startContainer;
11033 let endContainer = rng.endContainer;
11034 const startOffset = rng.startOffset;
11035 const endOffset = rng.endOffset;
11036 let node = rng.commonAncestorContainer;
11037 if (!rng.collapsed) {
11038 if (startContainer === endContainer) {
11039 if (endOffset - startOffset < 2) {
11040 if (startContainer.hasChildNodes()) {
11041 node = startContainer.childNodes[startOffset];
11042 }
11043 }
11044 }
11045 if (isText$b(startContainer) && isText$b(endContainer)) {
11046 if (startContainer.length === startOffset) {
11047 startContainer = skipEmptyTextNodes(startContainer.nextSibling, true);
11048 } else {
11049 startContainer = startContainer.parentNode;
11050 }
11051 if (endOffset === 0) {
11052 endContainer = skipEmptyTextNodes(endContainer.previousSibling, false);
11053 } else {
11054 endContainer = endContainer.parentNode;
11055 }
11056 if (startContainer && startContainer === endContainer) {
11057 node = startContainer;
11058 }
11059 }
11060 }
11061 const elm = isText$b(node) ? node.parentNode : node;
11062 return isHTMLElement(elm) ? elm : root;
11063 };
11064 const getSelectedBlocks = (dom, rng, startElm, endElm) => {
11065 const selectedBlocks = [];
11066 const root = dom.getRoot();
11067 const start = dom.getParent(startElm || getStart(root, rng, rng.collapsed), dom.isBlock);
11068 const end = dom.getParent(endElm || getEnd(root, rng, rng.collapsed), dom.isBlock);
11069 if (start && start !== root) {
11070 selectedBlocks.push(start);
11071 }
11072 if (start && end && start !== end) {
11073 let node;
11074 const walker = new DomTreeWalker(start, root);
11075 while ((node = walker.next()) && node !== end) {
11076 if (dom.isBlock(node)) {
11077 selectedBlocks.push(node);
11078 }
11079 }
11080 }
11081 if (end && start !== end && end !== root) {
11082 selectedBlocks.push(end);
11083 }
11084 return selectedBlocks;
11085 };
11086 const select = (dom, node, content) => Optional.from(node).bind(node => Optional.from(node.parentNode).map(parent => {
11087 const idx = dom.nodeIndex(node);
11088 const rng = dom.createRng();
11089 rng.setStart(parent, idx);
11090 rng.setEnd(parent, idx + 1);
11091 if (content) {
11092 moveEndPoint(dom, rng, node, true);
11093 moveEndPoint(dom, rng, node, false);
11094 }
11095 return rng;
11096 }));
11097
11098 const processRanges = (editor, ranges) => map$3(ranges, range => {
11099 const evt = editor.dispatch('GetSelectionRange', { range });
11100 return evt.range !== range ? evt.range : range;
11101 });
11102
11103 const typeLookup = {
11104 '#text': 3,
11105 '#comment': 8,
11106 '#cdata': 4,
11107 '#pi': 7,
11108 '#doctype': 10,
11109 '#document-fragment': 11
11110 };
11111 const walk$2 = (node, root, prev) => {
11112 const startName = prev ? 'lastChild' : 'firstChild';
11113 const siblingName = prev ? 'prev' : 'next';
11114 if (node[startName]) {
11115 return node[startName];
11116 }
11117 if (node !== root) {
11118 let sibling = node[siblingName];
11119 if (sibling) {
11120 return sibling;
11121 }
11122 for (let parent = node.parent; parent && parent !== root; parent = parent.parent) {
11123 sibling = parent[siblingName];
11124 if (sibling) {
11125 return sibling;
11126 }
11127 }
11128 }
11129 return undefined;
11130 };
11131 const isEmptyTextNode = node => {
11132 var _a;
11133 const text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
11134 if (!isWhitespaceText(text)) {
11135 return false;
11136 }
11137 const parentNode = node.parent;
11138 if (parentNode && (parentNode.name !== 'span' || parentNode.attr('style')) && /^[ ]+$/.test(text)) {
11139 return false;
11140 }
11141 return true;
11142 };
11143 const isNonEmptyElement = node => {
11144 const isNamedAnchor = node.name === 'a' && !node.attr('href') && node.attr('id');
11145 return node.attr('name') || node.attr('id') && !node.firstChild || node.attr('data-mce-bookmark') || isNamedAnchor;
11146 };
11147 class AstNode {
11148 static create(name, attrs) {
11149 const node = new AstNode(name, typeLookup[name] || 1);
11150 if (attrs) {
11151 each$d(attrs, (value, attrName) => {
11152 node.attr(attrName, value);
11153 });
11154 }
11155 return node;
11156 }
11157 constructor(name, type) {
11158 this.name = name;
11159 this.type = type;
11160 if (type === 1) {
11161 this.attributes = [];
11162 this.attributes.map = {};
11163 }
11164 }
11165 replace(node) {
11166 const self = this;
11167 if (node.parent) {
11168 node.remove();
11169 }
11170 self.insert(node, self);
11171 self.remove();
11172 return self;
11173 }
11174 attr(name, value) {
11175 const self = this;
11176 if (!isString(name)) {
11177 if (isNonNullable(name)) {
11178 each$d(name, (value, key) => {
11179 self.attr(key, value);
11180 });
11181 }
11182 return self;
11183 }
11184 const attrs = self.attributes;
11185 if (attrs) {
11186 if (value !== undefined) {
11187 if (value === null) {
11188 if (name in attrs.map) {
11189 delete attrs.map[name];
11190 let i = attrs.length;
11191 while (i--) {
11192 if (attrs[i].name === name) {
11193 attrs.splice(i, 1);
11194 return self;
11195 }
11196 }
11197 }
11198 return self;
11199 }
11200 if (name in attrs.map) {
11201 let i = attrs.length;
11202 while (i--) {
11203 if (attrs[i].name === name) {
11204 attrs[i].value = value;
11205 break;
11206 }
11207 }
11208 } else {
11209 attrs.push({
11210 name,
11211 value
11212 });
11213 }
11214 attrs.map[name] = value;
11215 return self;
11216 }
11217 return attrs.map[name];
11218 }
11219 return undefined;
11220 }
11221 clone() {
11222 const self = this;
11223 const clone = new AstNode(self.name, self.type);
11224 const selfAttrs = self.attributes;
11225 if (selfAttrs) {
11226 const cloneAttrs = [];
11227 cloneAttrs.map = {};
11228 for (let i = 0, l = selfAttrs.length; i < l; i++) {
11229 const selfAttr = selfAttrs[i];
11230 if (selfAttr.name !== 'id') {
11231 cloneAttrs[cloneAttrs.length] = {
11232 name: selfAttr.name,
11233 value: selfAttr.value
11234 };
11235 cloneAttrs.map[selfAttr.name] = selfAttr.value;
11236 }
11237 }
11238 clone.attributes = cloneAttrs;
11239 }
11240 clone.value = self.value;
11241 return clone;
11242 }
11243 wrap(wrapper) {
11244 const self = this;
11245 if (self.parent) {
11246 self.parent.insert(wrapper, self);
11247 wrapper.append(self);
11248 }
11249 return self;
11250 }
11251 unwrap() {
11252 const self = this;
11253 for (let node = self.firstChild; node;) {
11254 const next = node.next;
11255 self.insert(node, self, true);
11256 node = next;
11257 }
11258 self.remove();
11259 }
11260 remove() {
11261 const self = this, parent = self.parent, next = self.next, prev = self.prev;
11262 if (parent) {
11263 if (parent.firstChild === self) {
11264 parent.firstChild = next;
11265 if (next) {
11266 next.prev = null;
11267 }
11268 } else if (prev) {
11269 prev.next = next;
11270 }
11271 if (parent.lastChild === self) {
11272 parent.lastChild = prev;
11273 if (prev) {
11274 prev.next = null;
11275 }
11276 } else if (next) {
11277 next.prev = prev;
11278 }
11279 self.parent = self.next = self.prev = null;
11280 }
11281 return self;
11282 }
11283 append(node) {
11284 const self = this;
11285 if (node.parent) {
11286 node.remove();
11287 }
11288 const last = self.lastChild;
11289 if (last) {
11290 last.next = node;
11291 node.prev = last;
11292 self.lastChild = node;
11293 } else {
11294 self.lastChild = self.firstChild = node;
11295 }
11296 node.parent = self;
11297 return node;
11298 }
11299 insert(node, refNode, before) {
11300 if (node.parent) {
11301 node.remove();
11302 }
11303 const parent = refNode.parent || this;
11304 if (before) {
11305 if (refNode === parent.firstChild) {
11306 parent.firstChild = node;
11307 } else if (refNode.prev) {
11308 refNode.prev.next = node;
11309 }
11310 node.prev = refNode.prev;
11311 node.next = refNode;
11312 refNode.prev = node;
11313 } else {
11314 if (refNode === parent.lastChild) {
11315 parent.lastChild = node;
11316 } else if (refNode.next) {
11317 refNode.next.prev = node;
11318 }
11319 node.next = refNode.next;
11320 node.prev = refNode;
11321 refNode.next = node;
11322 }
11323 node.parent = parent;
11324 return node;
11325 }
11326 getAll(name) {
11327 const self = this;
11328 const collection = [];
11329 for (let node = self.firstChild; node; node = walk$2(node, self)) {
11330 if (node.name === name) {
11331 collection.push(node);
11332 }
11333 }
11334 return collection;
11335 }
11336 children() {
11337 const self = this;
11338 const collection = [];
11339 for (let node = self.firstChild; node; node = node.next) {
11340 collection.push(node);
11341 }
11342 return collection;
11343 }
11344 empty() {
11345 const self = this;
11346 if (self.firstChild) {
11347 const nodes = [];
11348 for (let node = self.firstChild; node; node = walk$2(node, self)) {
11349 nodes.push(node);
11350 }
11351 let i = nodes.length;
11352 while (i--) {
11353 const node = nodes[i];
11354 node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
11355 }
11356 }
11357 self.firstChild = self.lastChild = null;
11358 return self;
11359 }
11360 isEmpty(elements, whitespace = {}, predicate) {
11361 var _a;
11362 const self = this;
11363 let node = self.firstChild;
11364 if (isNonEmptyElement(self)) {
11365 return false;
11366 }
11367 if (node) {
11368 do {
11369 if (node.type === 1) {
11370 if (node.attr('data-mce-bogus')) {
11371 continue;
11372 }
11373 if (elements[node.name]) {
11374 return false;
11375 }
11376 if (isNonEmptyElement(node)) {
11377 return false;
11378 }
11379 }
11380 if (node.type === 8) {
11381 return false;
11382 }
11383 if (node.type === 3 && !isEmptyTextNode(node)) {
11384 return false;
11385 }
11386 if (node.type === 3 && node.parent && whitespace[node.parent.name] && isWhitespaceText((_a = node.value) !== null && _a !== void 0 ? _a : '')) {
11387 return false;
11388 }
11389 if (predicate && predicate(node)) {
11390 return false;
11391 }
11392 } while (node = walk$2(node, self));
11393 }
11394 return true;
11395 }
11396 walk(prev) {
11397 return walk$2(this, null, prev);
11398 }
11399 }
11400
11401 const unescapedTextParents = Tools.makeMap('NOSCRIPT STYLE SCRIPT XMP IFRAME NOEMBED NOFRAMES PLAINTEXT', ' ');
11402 const containsZwsp = node => isString(node.nodeValue) && node.nodeValue.includes(ZWSP$1);
11403 const getTemporaryNodeSelector = tempAttrs => `${ tempAttrs.length === 0 ? '' : `${ map$3(tempAttrs, attr => `[${ attr }]`).join(',') },` }[data-mce-bogus="all"]`;
11404 const getTemporaryNodes = (tempAttrs, body) => body.querySelectorAll(getTemporaryNodeSelector(tempAttrs));
11405 const createZwspCommentWalker = body => document.createTreeWalker(body, NodeFilter.SHOW_COMMENT, node => containsZwsp(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP);
11406 const createUnescapedZwspTextWalker = body => document.createTreeWalker(body, NodeFilter.SHOW_TEXT, node => {
11407 if (containsZwsp(node)) {
11408 const parent = node.parentNode;
11409 return parent && has$2(unescapedTextParents, parent.nodeName) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
11410 } else {
11411 return NodeFilter.FILTER_SKIP;
11412 }
11413 });
11414 const hasZwspComment = body => createZwspCommentWalker(body).nextNode() !== null;
11415 const hasUnescapedZwspText = body => createUnescapedZwspTextWalker(body).nextNode() !== null;
11416 const hasTemporaryNode = (tempAttrs, body) => body.querySelector(getTemporaryNodeSelector(tempAttrs)) !== null;
11417 const trimTemporaryNodes = (tempAttrs, body) => {
11418 each$e(getTemporaryNodes(tempAttrs, body), elm => {
11419 const element = SugarElement.fromDom(elm);
11420 if (get$9(element, 'data-mce-bogus') === 'all') {
11421 remove$4(element);
11422 } else {
11423 each$e(tempAttrs, attr => {
11424 if (has$1(element, attr)) {
11425 remove$9(element, attr);
11426 }
11427 });
11428 }
11429 });
11430 };
11431 const emptyAllNodeValuesInWalker = walker => {
11432 let curr = walker.nextNode();
11433 while (curr !== null) {
11434 curr.nodeValue = null;
11435 curr = walker.nextNode();
11436 }
11437 };
11438 const emptyZwspComments = compose(emptyAllNodeValuesInWalker, createZwspCommentWalker);
11439 const emptyUnescapedZwspTexts = compose(emptyAllNodeValuesInWalker, createUnescapedZwspTextWalker);
11440 const trim$1 = (body, tempAttrs) => {
11441 const conditionalTrims = [
11442 {
11443 condition: curry(hasTemporaryNode, tempAttrs),
11444 action: curry(trimTemporaryNodes, tempAttrs)
11445 },
11446 {
11447 condition: hasZwspComment,
11448 action: emptyZwspComments
11449 },
11450 {
11451 condition: hasUnescapedZwspText,
11452 action: emptyUnescapedZwspTexts
11453 }
11454 ];
11455 let trimmed = body;
11456 let cloned = false;
11457 each$e(conditionalTrims, ({condition, action}) => {
11458 if (condition(trimmed)) {
11459 if (!cloned) {
11460 trimmed = body.cloneNode(true);
11461 cloned = true;
11462 }
11463 action(trimmed);
11464 }
11465 });
11466 return trimmed;
11467 };
11468
11469 const cleanupBogusElements = parent => {
11470 const bogusElements = descendants(parent, '[data-mce-bogus]');
11471 each$e(bogusElements, elem => {
11472 const bogusValue = get$9(elem, 'data-mce-bogus');
11473 if (bogusValue === 'all') {
11474 remove$4(elem);
11475 } else if (isBr$5(elem)) {
11476 before$3(elem, SugarElement.fromText(zeroWidth));
11477 remove$4(elem);
11478 } else {
11479 unwrap(elem);
11480 }
11481 });
11482 };
11483 const cleanupInputNames = parent => {
11484 const inputs = descendants(parent, 'input');
11485 each$e(inputs, input => {
11486 remove$9(input, 'name');
11487 });
11488 };
11489
11490 const trimEmptyContents = (editor, html) => {
11491 const blockName = getForcedRootBlock(editor);
11492 const emptyRegExp = new RegExp(`^(<${ blockName }[^>]*>(&nbsp;|&#160;|\\s|\u00a0|<br \\/>|)<\\/${ blockName }>[\r\n]*|<br \\/>[\r\n]*)$`);
11493 return html.replace(emptyRegExp, '');
11494 };
11495 const getPlainTextContent = (editor, body) => {
11496 const doc = editor.getDoc();
11497 const dos = getRootNode(SugarElement.fromDom(editor.getBody()));
11498 const offscreenDiv = SugarElement.fromTag('div', doc);
11499 set$3(offscreenDiv, 'data-mce-bogus', 'all');
11500 setAll(offscreenDiv, {
11501 position: 'fixed',
11502 left: '-9999999px',
11503 top: '0'
11504 });
11505 set$1(offscreenDiv, body.innerHTML);
11506 cleanupBogusElements(offscreenDiv);
11507 cleanupInputNames(offscreenDiv);
11508 const root = getContentContainer(dos);
11509 append$1(root, offscreenDiv);
11510 const content = trim$2(offscreenDiv.dom.innerText);
11511 remove$4(offscreenDiv);
11512 return content;
11513 };
11514 const getContentFromBody = (editor, args, body) => {
11515 let content;
11516 if (args.format === 'raw') {
11517 content = Tools.trim(trim$2(trim$1(body, editor.serializer.getTempAttrs()).innerHTML));
11518 } else if (args.format === 'text') {
11519 content = getPlainTextContent(editor, body);
11520 } else if (args.format === 'tree') {
11521 content = editor.serializer.serialize(body, args);
11522 } else {
11523 content = trimEmptyContents(editor, editor.serializer.serialize(body, args));
11524 }
11525 const shouldTrim = args.format !== 'text' && !isWsPreserveElement(SugarElement.fromDom(body));
11526 return shouldTrim && isString(content) ? Tools.trim(content) : content;
11527 };
11528 const getContentInternal = (editor, args) => Optional.from(editor.getBody()).fold(constant(args.format === 'tree' ? new AstNode('body', 11) : ''), body => getContentFromBody(editor, args, body));
11529
11530 const makeMap$1 = Tools.makeMap;
11531 const Writer = settings => {
11532 const html = [];
11533 settings = settings || {};
11534 const indent = settings.indent;
11535 const indentBefore = makeMap$1(settings.indent_before || '');
11536 const indentAfter = makeMap$1(settings.indent_after || '');
11537 const encode = Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
11538 const htmlOutput = settings.element_format !== 'xhtml';
11539 return {
11540 start: (name, attrs, empty) => {
11541 if (indent && indentBefore[name] && html.length > 0) {
11542 const value = html[html.length - 1];
11543 if (value.length > 0 && value !== '\n') {
11544 html.push('\n');
11545 }
11546 }
11547 html.push('<', name);
11548 if (attrs) {
11549 for (let i = 0, l = attrs.length; i < l; i++) {
11550 const attr = attrs[i];
11551 html.push(' ', attr.name, '="', encode(attr.value, true), '"');
11552 }
11553 }
11554 if (!empty || htmlOutput) {
11555 html[html.length] = '>';
11556 } else {
11557 html[html.length] = ' />';
11558 }
11559 if (empty && indent && indentAfter[name] && html.length > 0) {
11560 const value = html[html.length - 1];
11561 if (value.length > 0 && value !== '\n') {
11562 html.push('\n');
11563 }
11564 }
11565 },
11566 end: name => {
11567 let value;
11568 html.push('</', name, '>');
11569 if (indent && indentAfter[name] && html.length > 0) {
11570 value = html[html.length - 1];
11571 if (value.length > 0 && value !== '\n') {
11572 html.push('\n');
11573 }
11574 }
11575 },
11576 text: (text, raw) => {
11577 if (text.length > 0) {
11578 html[html.length] = raw ? text : encode(text);
11579 }
11580 },
11581 cdata: text => {
11582 html.push('<![CDATA[', text, ']]>');
11583 },
11584 comment: text => {
11585 html.push('<!--', text, '-->');
11586 },
11587 pi: (name, text) => {
11588 if (text) {
11589 html.push('<?', name, ' ', encode(text), '?>');
11590 } else {
11591 html.push('<?', name, '?>');
11592 }
11593 if (indent) {
11594 html.push('\n');
11595 }
11596 },
11597 doctype: text => {
11598 html.push('<!DOCTYPE', text, '>', indent ? '\n' : '');
11599 },
11600 reset: () => {
11601 html.length = 0;
11602 },
11603 getContent: () => {
11604 return html.join('').replace(/\n$/, '');
11605 }
11606 };
11607 };
11608
11609 const HtmlSerializer = (settings = {}, schema = Schema()) => {
11610 const writer = Writer(settings);
11611 settings.validate = 'validate' in settings ? settings.validate : true;
11612 const serialize = node => {
11613 const validate = settings.validate;
11614 const handlers = {
11615 3: node => {
11616 var _a;
11617 writer.text((_a = node.value) !== null && _a !== void 0 ? _a : '', node.raw);
11618 },
11619 8: node => {
11620 var _a;
11621 writer.comment((_a = node.value) !== null && _a !== void 0 ? _a : '');
11622 },
11623 7: node => {
11624 writer.pi(node.name, node.value);
11625 },
11626 10: node => {
11627 var _a;
11628 writer.doctype((_a = node.value) !== null && _a !== void 0 ? _a : '');
11629 },
11630 4: node => {
11631 var _a;
11632 writer.cdata((_a = node.value) !== null && _a !== void 0 ? _a : '');
11633 },
11634 11: node => {
11635 let tempNode = node;
11636 if (tempNode = tempNode.firstChild) {
11637 do {
11638 walk(tempNode);
11639 } while (tempNode = tempNode.next);
11640 }
11641 }
11642 };
11643 writer.reset();
11644 const walk = node => {
11645 var _a;
11646 const handler = handlers[node.type];
11647 if (!handler) {
11648 const name = node.name;
11649 const isEmpty = name in schema.getVoidElements();
11650 let attrs = node.attributes;
11651 if (validate && attrs && attrs.length > 1) {
11652 const sortedAttrs = [];
11653 sortedAttrs.map = {};
11654 const elementRule = schema.getElementRule(node.name);
11655 if (elementRule) {
11656 for (let i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
11657 const attrName = elementRule.attributesOrder[i];
11658 if (attrName in attrs.map) {
11659 const attrValue = attrs.map[attrName];
11660 sortedAttrs.map[attrName] = attrValue;
11661 sortedAttrs.push({
11662 name: attrName,
11663 value: attrValue
11664 });
11665 }
11666 }
11667 for (let i = 0, l = attrs.length; i < l; i++) {
11668 const attrName = attrs[i].name;
11669 if (!(attrName in sortedAttrs.map)) {
11670 const attrValue = attrs.map[attrName];
11671 sortedAttrs.map[attrName] = attrValue;
11672 sortedAttrs.push({
11673 name: attrName,
11674 value: attrValue
11675 });
11676 }
11677 }
11678 attrs = sortedAttrs;
11679 }
11680 }
11681 writer.start(name, attrs, isEmpty);
11682 if (isNonHtmlElementRootName(name)) {
11683 if (isString(node.value)) {
11684 writer.text(node.value, true);
11685 }
11686 writer.end(name);
11687 } else {
11688 if (!isEmpty) {
11689 let child = node.firstChild;
11690 if (child) {
11691 if ((name === 'pre' || name === 'textarea') && child.type === 3 && ((_a = child.value) === null || _a === void 0 ? void 0 : _a[0]) === '\n') {
11692 writer.text('\n', true);
11693 }
11694 do {
11695 walk(child);
11696 } while (child = child.next);
11697 }
11698 writer.end(name);
11699 }
11700 }
11701 } else {
11702 handler(node);
11703 }
11704 };
11705 if (node.type === 1 && !settings.inner) {
11706 walk(node);
11707 } else if (node.type === 3) {
11708 handlers[3](node);
11709 } else {
11710 handlers[11](node);
11711 }
11712 return writer.getContent();
11713 };
11714 return { serialize };
11715 };
11716
11717 const nonInheritableStyles = new Set();
11718 (() => {
11719 const nonInheritableStylesArr = [
11720 'margin',
11721 'margin-left',
11722 'margin-right',
11723 'margin-top',
11724 'margin-bottom',
11725 'padding',
11726 'padding-left',
11727 'padding-right',
11728 'padding-top',
11729 'padding-bottom',
11730 'border',
11731 'border-width',
11732 'border-style',
11733 'border-color',
11734 'background',
11735 'background-attachment',
11736 'background-clip',
11737 'background-color',
11738 'background-image',
11739 'background-origin',
11740 'background-position',
11741 'background-repeat',
11742 'background-size',
11743 'float',
11744 'position',
11745 'left',
11746 'right',
11747 'top',
11748 'bottom',
11749 'z-index',
11750 'display',
11751 'transform',
11752 'width',
11753 'max-width',
11754 'min-width',
11755 'height',
11756 'max-height',
11757 'min-height',
11758 'overflow',
11759 'overflow-x',
11760 'overflow-y',
11761 'text-overflow',
11762 'vertical-align',
11763 'transition',
11764 'transition-delay',
11765 'transition-duration',
11766 'transition-property',
11767 'transition-timing-function'
11768 ];
11769 each$e(nonInheritableStylesArr, style => {
11770 nonInheritableStyles.add(style);
11771 });
11772 })();
11773 const shorthandStyleProps = [
11774 'font',
11775 'text-decoration',
11776 'text-emphasis'
11777 ];
11778 const getStyleProps = (dom, node) => keys(dom.parseStyle(dom.getAttrib(node, 'style')));
11779 const isNonInheritableStyle = style => nonInheritableStyles.has(style);
11780 const hasInheritableStyles = (dom, node) => forall(getStyleProps(dom, node), style => !isNonInheritableStyle(style));
11781 const getLonghandStyleProps = styles => filter$5(styles, style => exists(shorthandStyleProps, prop => startsWith(style, prop)));
11782 const hasStyleConflict = (dom, node, parentNode) => {
11783 const nodeStyleProps = getStyleProps(dom, node);
11784 const parentNodeStyleProps = getStyleProps(dom, parentNode);
11785 const valueMismatch = prop => {
11786 var _a, _b;
11787 const nodeValue = (_a = dom.getStyle(node, prop)) !== null && _a !== void 0 ? _a : '';
11788 const parentValue = (_b = dom.getStyle(parentNode, prop)) !== null && _b !== void 0 ? _b : '';
11789 return isNotEmpty(nodeValue) && isNotEmpty(parentValue) && nodeValue !== parentValue;
11790 };
11791 return exists(nodeStyleProps, nodeStyleProp => {
11792 const propExists = props => exists(props, prop => prop === nodeStyleProp);
11793 if (!propExists(parentNodeStyleProps) && propExists(shorthandStyleProps)) {
11794 const longhandProps = getLonghandStyleProps(parentNodeStyleProps);
11795 return exists(longhandProps, valueMismatch);
11796 } else {
11797 return valueMismatch(nodeStyleProp);
11798 }
11799 });
11800 };
11801
11802 const isChar = (forward, predicate, pos) => Optional.from(pos.container()).filter(isText$b).exists(text => {
11803 const delta = forward ? 0 : -1;
11804 return predicate(text.data.charAt(pos.offset() + delta));
11805 });
11806 const isBeforeSpace = curry(isChar, true, isWhiteSpace);
11807 const isAfterSpace = curry(isChar, false, isWhiteSpace);
11808 const isEmptyText = pos => {
11809 const container = pos.container();
11810 return isText$b(container) && (container.data.length === 0 || isZwsp(container.data) && BookmarkManager.isBookmarkNode(container.parentNode));
11811 };
11812 const matchesElementPosition = (before, predicate) => pos => getChildNodeAtRelativeOffset(before ? 0 : -1, pos).filter(predicate).isSome();
11813 const isImageBlock = node => isImg(node) && get$7(SugarElement.fromDom(node), 'display') === 'block';
11814 const isCefNode = node => isContentEditableFalse$b(node) && !isBogusAll(node);
11815 const isBeforeImageBlock = matchesElementPosition(true, isImageBlock);
11816 const isAfterImageBlock = matchesElementPosition(false, isImageBlock);
11817 const isBeforeMedia = matchesElementPosition(true, isMedia$2);
11818 const isAfterMedia = matchesElementPosition(false, isMedia$2);
11819 const isBeforeTable = matchesElementPosition(true, isTable$2);
11820 const isAfterTable = matchesElementPosition(false, isTable$2);
11821 const isBeforeContentEditableFalse = matchesElementPosition(true, isCefNode);
11822 const isAfterContentEditableFalse = matchesElementPosition(false, isCefNode);
11823
11824 const dropLast = xs => xs.slice(0, -1);
11825 const parentsUntil = (start, root, predicate) => {
11826 if (contains(root, start)) {
11827 return dropLast(parents$1(start, elm => {
11828 return predicate(elm) || eq(elm, root);
11829 }));
11830 } else {
11831 return [];
11832 }
11833 };
11834 const parents = (start, root) => parentsUntil(start, root, never);
11835 const parentsAndSelf = (start, root) => [start].concat(parents(start, root));
11836
11837 const navigateIgnoreEmptyTextNodes = (forward, root, from) => navigateIgnore(forward, root, from, isEmptyText);
11838 const isBlock$1 = schema => el => schema.isBlock(name(el));
11839 const getClosestBlock$1 = (root, pos, schema) => find$2(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$1(schema));
11840 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()))));
11841 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());
11842 const isAtStartOfBlock = curry(isAtBlockBoundary, false);
11843 const isAtEndOfBlock = curry(isAtBlockBoundary, true);
11844 const isBeforeBlock = curry(isAtBeforeAfterBlockBoundary, false);
11845 const isAfterBlock = curry(isAtBeforeAfterBlockBoundary, true);
11846
11847 const isBr$1 = pos => getElementFromPosition(pos).exists(isBr$5);
11848 const findBr = (forward, root, pos, schema) => {
11849 const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), el => schema.isBlock(name(el)));
11850 const scope = head(parentBlocks).getOr(root);
11851 return fromPosition(forward, scope.dom, pos).filter(isBr$1);
11852 };
11853 const isBeforeBr$1 = (root, pos, schema) => getElementFromPosition(pos).exists(isBr$5) || findBr(true, root, pos, schema).isSome();
11854 const isAfterBr = (root, pos, schema) => getElementFromPrevPosition(pos).exists(isBr$5) || findBr(false, root, pos, schema).isSome();
11855 const findPreviousBr = curry(findBr, false);
11856 const findNextBr = curry(findBr, true);
11857
11858 const isInMiddleOfText = pos => CaretPosition.isTextPosition(pos) && !pos.isAtStart() && !pos.isAtEnd();
11859 const getClosestBlock = (root, pos, schema) => {
11860 const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), el => schema.isBlock(name(el)));
11861 return head(parentBlocks).getOr(root);
11862 };
11863 const hasSpaceBefore = (root, pos, schema) => {
11864 if (isInMiddleOfText(pos)) {
11865 return isAfterSpace(pos);
11866 } else {
11867 return isAfterSpace(pos) || prevPosition(getClosestBlock(root, pos, schema).dom, pos).exists(isAfterSpace);
11868 }
11869 };
11870 const hasSpaceAfter = (root, pos, schema) => {
11871 if (isInMiddleOfText(pos)) {
11872 return isBeforeSpace(pos);
11873 } else {
11874 return isBeforeSpace(pos) || nextPosition(getClosestBlock(root, pos, schema).dom, pos).exists(isBeforeSpace);
11875 }
11876 };
11877 const isPreValue = value => contains$2([
11878 'pre',
11879 'pre-wrap'
11880 ], value);
11881 const isInPre = pos => getElementFromPosition(pos).bind(elm => closest$4(elm, isElement$7)).exists(elm => isPreValue(get$7(elm, 'white-space')));
11882 const isAtBeginningOfBody = (root, pos) => prevPosition(root.dom, pos).isNone();
11883 const isAtEndOfBody = (root, pos) => nextPosition(root.dom, pos).isNone();
11884 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);
11885 const isCefBlock = node => isNonNullable(node) && isContentEditableFalse$b(node) && isBlockLike(node);
11886 const isSiblingCefBlock = (root, direction) => container => {
11887 return isCefBlock(new DomTreeWalker(container, root)[direction]());
11888 };
11889 const isBeforeCefBlock = (root, pos) => {
11890 const nextPos = nextPosition(root.dom, pos).getOr(pos);
11891 const isNextCefBlock = isSiblingCefBlock(root.dom, 'next');
11892 return pos.isAtEnd() && (isNextCefBlock(pos.container()) || isNextCefBlock(nextPos.container()));
11893 };
11894 const isAfterCefBlock = (root, pos) => {
11895 const prevPos = prevPosition(root.dom, pos).getOr(pos);
11896 const isPrevCefBlock = isSiblingCefBlock(root.dom, 'prev');
11897 return pos.isAtStart() && (isPrevCefBlock(pos.container()) || isPrevCefBlock(prevPos.container()));
11898 };
11899 const needsToHaveNbsp = (root, pos, schema) => {
11900 if (isInPre(pos)) {
11901 return false;
11902 } else {
11903 return isAtLineBoundary(root, pos, schema) || hasSpaceBefore(root, pos, schema) || hasSpaceAfter(root, pos, schema);
11904 }
11905 };
11906 const needsToBeNbspLeft = (root, pos, schema) => {
11907 if (isInPre(pos)) {
11908 return false;
11909 } else {
11910 return isAtStartOfBlock(root, pos, schema) || isBeforeBlock(root, pos, schema) || isAfterBr(root, pos, schema) || hasSpaceBefore(root, pos, schema) || isAfterCefBlock(root, pos);
11911 }
11912 };
11913 const leanRight = pos => {
11914 const container = pos.container();
11915 const offset = pos.offset();
11916 if (isText$b(container) && offset < container.data.length) {
11917 return CaretPosition(container, offset + 1);
11918 } else {
11919 return pos;
11920 }
11921 };
11922 const needsToBeNbspRight = (root, pos, schema) => {
11923 if (isInPre(pos)) {
11924 return false;
11925 } else {
11926 return isAtEndOfBlock(root, pos, schema) || isAfterBlock(root, pos, schema) || isBeforeBr$1(root, pos, schema) || hasSpaceAfter(root, pos, schema) || isBeforeCefBlock(root, pos);
11927 }
11928 };
11929 const needsToBeNbsp = (root, pos, schema) => needsToBeNbspLeft(root, pos, schema) || needsToBeNbspRight(root, leanRight(pos), schema);
11930 const isNbspAt = (text, offset) => isNbsp(text.charAt(offset));
11931 const isWhiteSpaceAt = (text, offset) => isWhiteSpace(text.charAt(offset));
11932 const hasNbsp = pos => {
11933 const container = pos.container();
11934 return isText$b(container) && contains$1(container.data, nbsp);
11935 };
11936 const normalizeNbspMiddle = text => {
11937 const chars = text.split('');
11938 return map$3(chars, (chr, i) => {
11939 if (isNbsp(chr) && i > 0 && i < chars.length - 1 && isContent(chars[i - 1]) && isContent(chars[i + 1])) {
11940 return ' ';
11941 } else {
11942 return chr;
11943 }
11944 }).join('');
11945 };
11946 const normalizeNbspAtStart = (root, node, makeNbsp, schema) => {
11947 const text = node.data;
11948 const firstPos = CaretPosition(node, 0);
11949 if (!makeNbsp && isNbspAt(text, 0) && !needsToBeNbsp(root, firstPos, schema)) {
11950 node.data = ' ' + text.slice(1);
11951 return true;
11952 } else if (makeNbsp && isWhiteSpaceAt(text, 0) && needsToBeNbspLeft(root, firstPos, schema)) {
11953 node.data = nbsp + text.slice(1);
11954 return true;
11955 } else {
11956 return false;
11957 }
11958 };
11959 const normalizeNbspInMiddleOfTextNode = node => {
11960 const text = node.data;
11961 const newText = normalizeNbspMiddle(text);
11962 if (newText !== text) {
11963 node.data = newText;
11964 return true;
11965 } else {
11966 return false;
11967 }
11968 };
11969 const normalizeNbspAtEnd = (root, node, makeNbsp, schema) => {
11970 const text = node.data;
11971 const lastPos = CaretPosition(node, text.length - 1);
11972 if (!makeNbsp && isNbspAt(text, text.length - 1) && !needsToBeNbsp(root, lastPos, schema)) {
11973 node.data = text.slice(0, -1) + ' ';
11974 return true;
11975 } else if (makeNbsp && isWhiteSpaceAt(text, text.length - 1) && needsToBeNbspRight(root, lastPos, schema)) {
11976 node.data = text.slice(0, -1) + nbsp;
11977 return true;
11978 } else {
11979 return false;
11980 }
11981 };
11982 const normalizeNbsps = (root, pos, schema) => {
11983 const container = pos.container();
11984 if (!isText$b(container)) {
11985 return Optional.none();
11986 }
11987 if (hasNbsp(pos)) {
11988 const normalized = normalizeNbspAtStart(root, container, false, schema) || normalizeNbspInMiddleOfTextNode(container) || normalizeNbspAtEnd(root, container, false, schema);
11989 return someIf(normalized, pos);
11990 } else if (needsToBeNbsp(root, pos, schema)) {
11991 const normalized = normalizeNbspAtStart(root, container, true, schema) || normalizeNbspAtEnd(root, container, true, schema);
11992 return someIf(normalized, pos);
11993 } else {
11994 return Optional.none();
11995 }
11996 };
11997 const normalizeNbspsInEditor = editor => {
11998 const root = SugarElement.fromDom(editor.getBody());
11999 if (editor.selection.isCollapsed()) {
12000 normalizeNbsps(root, CaretPosition.fromRangeStart(editor.selection.getRng()), editor.schema).each(pos => {
12001 editor.selection.setRng(pos.toRange());
12002 });
12003 }
12004 };
12005
12006 const normalize$1 = (node, offset, count, schema) => {
12007 if (count === 0) {
12008 return;
12009 }
12010 const elm = SugarElement.fromDom(node);
12011 const root = ancestor$4(elm, el => schema.isBlock(name(el))).getOr(elm);
12012 const whitespace = node.data.slice(offset, offset + count);
12013 const isEndOfContent = offset + count >= node.data.length && needsToBeNbspRight(root, CaretPosition(node, node.data.length), schema);
12014 const isStartOfContent = offset === 0 && needsToBeNbspLeft(root, CaretPosition(node, 0), schema);
12015 node.replaceData(offset, count, normalize$4(whitespace, 4, isStartOfContent, isEndOfContent));
12016 };
12017 const normalizeWhitespaceAfter = (node, offset, schema) => {
12018 const content = node.data.slice(offset);
12019 const whitespaceCount = content.length - lTrim(content).length;
12020 normalize$1(node, offset, whitespaceCount, schema);
12021 };
12022 const normalizeWhitespaceBefore = (node, offset, schema) => {
12023 const content = node.data.slice(0, offset);
12024 const whitespaceCount = content.length - rTrim(content).length;
12025 normalize$1(node, offset - whitespaceCount, whitespaceCount, schema);
12026 };
12027 const mergeTextNodes = (prevNode, nextNode, schema, normalizeWhitespace, mergeToPrev = true) => {
12028 const whitespaceOffset = rTrim(prevNode.data).length;
12029 const newNode = mergeToPrev ? prevNode : nextNode;
12030 const removeNode = mergeToPrev ? nextNode : prevNode;
12031 if (mergeToPrev) {
12032 newNode.appendData(removeNode.data);
12033 } else {
12034 newNode.insertData(0, removeNode.data);
12035 }
12036 remove$4(SugarElement.fromDom(removeNode));
12037 if (normalizeWhitespace) {
12038 normalizeWhitespaceAfter(newNode, whitespaceOffset, schema);
12039 }
12040 return newNode;
12041 };
12042
12043 const needsReposition = (pos, elm) => {
12044 const container = pos.container();
12045 const offset = pos.offset();
12046 return !CaretPosition.isTextPosition(pos) && container === elm.parentNode && offset > CaretPosition.before(elm).offset();
12047 };
12048 const reposition = (elm, pos) => needsReposition(pos, elm) ? CaretPosition(pos.container(), pos.offset() - 1) : pos;
12049 const beforeOrStartOf = node => isText$b(node) ? CaretPosition(node, 0) : CaretPosition.before(node);
12050 const afterOrEndOf = node => isText$b(node) ? CaretPosition(node, node.data.length) : CaretPosition.after(node);
12051 const getPreviousSiblingCaretPosition = elm => {
12052 if (isCaretCandidate$3(elm.previousSibling)) {
12053 return Optional.some(afterOrEndOf(elm.previousSibling));
12054 } else {
12055 return elm.previousSibling ? lastPositionIn(elm.previousSibling) : Optional.none();
12056 }
12057 };
12058 const getNextSiblingCaretPosition = elm => {
12059 if (isCaretCandidate$3(elm.nextSibling)) {
12060 return Optional.some(beforeOrStartOf(elm.nextSibling));
12061 } else {
12062 return elm.nextSibling ? firstPositionIn(elm.nextSibling) : Optional.none();
12063 }
12064 };
12065 const findCaretPositionBackwardsFromElm = (rootElement, elm) => {
12066 return Optional.from(elm.previousSibling ? elm.previousSibling : elm.parentNode).bind(node => prevPosition(rootElement, CaretPosition.before(node))).orThunk(() => nextPosition(rootElement, CaretPosition.after(elm)));
12067 };
12068 const findCaretPositionForwardsFromElm = (rootElement, elm) => nextPosition(rootElement, CaretPosition.after(elm)).orThunk(() => prevPosition(rootElement, CaretPosition.before(elm)));
12069 const findCaretPositionBackwards = (rootElement, elm) => getPreviousSiblingCaretPosition(elm).orThunk(() => getNextSiblingCaretPosition(elm)).orThunk(() => findCaretPositionBackwardsFromElm(rootElement, elm));
12070 const findCaretPositionForward = (rootElement, elm) => getNextSiblingCaretPosition(elm).orThunk(() => getPreviousSiblingCaretPosition(elm)).orThunk(() => findCaretPositionForwardsFromElm(rootElement, elm));
12071 const findCaretPosition = (forward, rootElement, elm) => forward ? findCaretPositionForward(rootElement, elm) : findCaretPositionBackwards(rootElement, elm);
12072 const findCaretPosOutsideElmAfterDelete = (forward, rootElement, elm) => findCaretPosition(forward, rootElement, elm).map(curry(reposition, elm));
12073 const setSelection$1 = (editor, forward, pos) => {
12074 pos.fold(() => {
12075 editor.focus();
12076 }, pos => {
12077 editor.selection.setRng(pos.toRange(), forward);
12078 });
12079 };
12080 const eqRawNode = rawNode => elm => elm.dom === rawNode;
12081 const isBlock = (editor, elm) => elm && has$2(editor.schema.getBlockElements(), name(elm));
12082 const paddEmptyBlock = (schema, elm, preserveEmptyCaret) => {
12083 if (isEmpty$2(schema, elm)) {
12084 const br = SugarElement.fromHtml('<br data-mce-bogus="1">');
12085 if (preserveEmptyCaret) {
12086 each$e(children$1(elm), node => {
12087 if (!isEmptyCaretFormatElement(node)) {
12088 remove$4(node);
12089 }
12090 });
12091 } else {
12092 empty(elm);
12093 }
12094 append$1(elm, br);
12095 return Optional.some(CaretPosition.before(br.dom));
12096 } else {
12097 return Optional.none();
12098 }
12099 };
12100 const deleteNormalized = (elm, afterDeletePosOpt, schema, normalizeWhitespace) => {
12101 const prevTextOpt = prevSibling(elm).filter(isText$c);
12102 const nextTextOpt = nextSibling(elm).filter(isText$c);
12103 remove$4(elm);
12104 return lift3(prevTextOpt, nextTextOpt, afterDeletePosOpt, (prev, next, pos) => {
12105 const prevNode = prev.dom, nextNode = next.dom;
12106 const offset = prevNode.data.length;
12107 mergeTextNodes(prevNode, nextNode, schema, normalizeWhitespace);
12108 return pos.container() === nextNode ? CaretPosition(prevNode, offset) : pos;
12109 }).orThunk(() => {
12110 if (normalizeWhitespace) {
12111 prevTextOpt.each(elm => normalizeWhitespaceBefore(elm.dom, elm.dom.length, schema));
12112 nextTextOpt.each(elm => normalizeWhitespaceAfter(elm.dom, 0, schema));
12113 }
12114 return afterDeletePosOpt;
12115 });
12116 };
12117 const isInlineElement = (editor, element) => has$2(editor.schema.getTextInlineElements(), name(element));
12118 const deleteElement$2 = (editor, forward, elm, moveCaret = true, preserveEmptyCaret = false) => {
12119 const afterDeletePos = findCaretPosOutsideElmAfterDelete(forward, editor.getBody(), elm.dom);
12120 const parentBlock = ancestor$4(elm, curry(isBlock, editor), eqRawNode(editor.getBody()));
12121 const normalizedAfterDeletePos = deleteNormalized(elm, afterDeletePos, editor.schema, isInlineElement(editor, elm));
12122 if (editor.dom.isEmpty(editor.getBody())) {
12123 editor.setContent('');
12124 editor.selection.setCursorLocation();
12125 } else {
12126 parentBlock.bind(elm => paddEmptyBlock(editor.schema, elm, preserveEmptyCaret)).fold(() => {
12127 if (moveCaret) {
12128 setSelection$1(editor, forward, normalizedAfterDeletePos);
12129 }
12130 }, paddPos => {
12131 if (moveCaret) {
12132 setSelection$1(editor, forward, Optional.some(paddPos));
12133 }
12134 });
12135 }
12136 };
12137
12138 const strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/;
12139 const hasStrongRtl = text => strongRtl.test(text);
12140
12141 const isInlineTarget = (editor, elm) => is$1(SugarElement.fromDom(elm), getInlineBoundarySelector(editor)) && !isTransparentBlock(editor.schema, elm) && editor.dom.isEditable(elm);
12142 const isRtl = element => {
12143 var _a;
12144 return DOMUtils.DOM.getStyle(element, 'direction', true) === 'rtl' || hasStrongRtl((_a = element.textContent) !== null && _a !== void 0 ? _a : '');
12145 };
12146 const findInlineParents = (isInlineTarget, rootNode, pos) => filter$5(DOMUtils.DOM.getParents(pos.container(), '*', rootNode), isInlineTarget);
12147 const findRootInline = (isInlineTarget, rootNode, pos) => {
12148 const parents = findInlineParents(isInlineTarget, rootNode, pos);
12149 return Optional.from(parents[parents.length - 1]);
12150 };
12151 const hasSameParentBlock = (rootNode, node1, node2) => {
12152 const block1 = getParentBlock$3(node1, rootNode);
12153 const block2 = getParentBlock$3(node2, rootNode);
12154 return isNonNullable(block1) && block1 === block2;
12155 };
12156 const isAtZwsp = pos => isBeforeInline(pos) || isAfterInline(pos);
12157 const normalizePosition = (forward, pos) => {
12158 const container = pos.container(), offset = pos.offset();
12159 if (forward) {
12160 if (isCaretContainerInline(container)) {
12161 if (isText$b(container.nextSibling)) {
12162 return CaretPosition(container.nextSibling, 0);
12163 } else {
12164 return CaretPosition.after(container);
12165 }
12166 } else {
12167 return isBeforeInline(pos) ? CaretPosition(container, offset + 1) : pos;
12168 }
12169 } else {
12170 if (isCaretContainerInline(container)) {
12171 if (isText$b(container.previousSibling)) {
12172 return CaretPosition(container.previousSibling, container.previousSibling.data.length);
12173 } else {
12174 return CaretPosition.before(container);
12175 }
12176 } else {
12177 return isAfterInline(pos) ? CaretPosition(container, offset - 1) : pos;
12178 }
12179 }
12180 };
12181 const normalizeForwards = curry(normalizePosition, true);
12182 const normalizeBackwards = curry(normalizePosition, false);
12183
12184 const execCommandIgnoreInputEvents = (editor, command) => {
12185 const inputBlocker = e => e.stopImmediatePropagation();
12186 editor.on('beforeinput input', inputBlocker, true);
12187 editor.getDoc().execCommand(command);
12188 editor.off('beforeinput input', inputBlocker);
12189 };
12190 const execEditorDeleteCommand = editor => {
12191 editor.execCommand('delete');
12192 };
12193 const execNativeDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'Delete');
12194 const execNativeForwardDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'ForwardDelete');
12195 const isBeforeRoot = rootNode => elm => is$2(parent(elm), rootNode, eq);
12196 const isTextBlockOrListItem = element => isTextBlock$2(element) || isListItem$1(element);
12197 const getParentBlock$2 = (rootNode, elm) => {
12198 if (contains(rootNode, elm)) {
12199 return closest$4(elm, isTextBlockOrListItem, isBeforeRoot(rootNode));
12200 } else {
12201 return Optional.none();
12202 }
12203 };
12204 const paddEmptyBody = (editor, moveSelection = true) => {
12205 if (editor.dom.isEmpty(editor.getBody())) {
12206 editor.setContent('', { no_selection: !moveSelection });
12207 }
12208 };
12209 const willDeleteLastPositionInElement = (forward, fromPos, elm) => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
12210 const normalizedFirstPos = normalizePosition(true, firstPos);
12211 const normalizedLastPos = normalizePosition(false, lastPos);
12212 const normalizedFromPos = normalizePosition(false, fromPos);
12213 if (forward) {
12214 return nextPosition(elm, normalizedFromPos).exists(nextPos => nextPos.isEqual(normalizedLastPos) && fromPos.isEqual(normalizedFirstPos));
12215 } else {
12216 return prevPosition(elm, normalizedFromPos).exists(prevPos => prevPos.isEqual(normalizedFirstPos) && fromPos.isEqual(normalizedLastPos));
12217 }
12218 }).getOr(true);
12219 const freefallRtl = root => {
12220 const child = isComment$1(root) ? prevSibling(root) : lastChild(root);
12221 return child.bind(freefallRtl).orThunk(() => Optional.some(root));
12222 };
12223 const deleteRangeContents = (editor, rng, root, moveSelection = true) => {
12224 var _a;
12225 rng.deleteContents();
12226 const lastNode = freefallRtl(root).getOr(root);
12227 const lastBlock = SugarElement.fromDom((_a = editor.dom.getParent(lastNode.dom, editor.dom.isBlock)) !== null && _a !== void 0 ? _a : root.dom);
12228 if (lastBlock.dom === editor.getBody()) {
12229 paddEmptyBody(editor, moveSelection);
12230 } else if (isEmpty$2(editor.schema, lastBlock, { checkRootAsContent: false })) {
12231 fillWithPaddingBr(lastBlock);
12232 if (moveSelection) {
12233 editor.selection.setCursorLocation(lastBlock.dom, 0);
12234 }
12235 }
12236 if (!eq(root, lastBlock)) {
12237 const additionalCleanupNodes = is$2(parent(lastBlock), root) ? [] : siblings(lastBlock);
12238 each$e(additionalCleanupNodes.concat(children$1(root)), node => {
12239 if (!eq(node, lastBlock) && !contains(node, lastBlock) && isEmpty$2(editor.schema, node)) {
12240 remove$4(node);
12241 }
12242 });
12243 }
12244 };
12245
12246 const isRootFromElement = root => cur => eq(root, cur);
12247 const getTableCells = table => descendants(table, 'td,th');
12248 const getTable$1 = (node, isRoot) => getClosestTable(SugarElement.fromDom(node), isRoot);
12249 const selectionInTableWithNestedTable = details => {
12250 return lift2(details.startTable, details.endTable, (startTable, endTable) => {
12251 const isStartTableParentOfEndTable = descendant(startTable, t => eq(t, endTable));
12252 const isEndTableParentOfStartTable = descendant(endTable, t => eq(t, startTable));
12253 return !isStartTableParentOfEndTable && !isEndTableParentOfStartTable ? details : {
12254 ...details,
12255 startTable: isStartTableParentOfEndTable ? Optional.none() : details.startTable,
12256 endTable: isEndTableParentOfStartTable ? Optional.none() : details.endTable,
12257 isSameTable: false,
12258 isMultiTable: false
12259 };
12260 }).getOr(details);
12261 };
12262 const adjustQuirksInDetails = details => {
12263 return selectionInTableWithNestedTable(details);
12264 };
12265 const getTableDetailsFromRange = (rng, isRoot) => {
12266 const startTable = getTable$1(rng.startContainer, isRoot);
12267 const endTable = getTable$1(rng.endContainer, isRoot);
12268 const isStartInTable = startTable.isSome();
12269 const isEndInTable = endTable.isSome();
12270 const isSameTable = lift2(startTable, endTable, eq).getOr(false);
12271 const isMultiTable = !isSameTable && isStartInTable && isEndInTable;
12272 return adjustQuirksInDetails({
12273 startTable,
12274 endTable,
12275 isStartInTable,
12276 isEndInTable,
12277 isSameTable,
12278 isMultiTable
12279 });
12280 };
12281
12282 const tableCellRng = (start, end) => ({
12283 start,
12284 end
12285 });
12286 const tableSelection = (rng, table, cells) => ({
12287 rng,
12288 table,
12289 cells
12290 });
12291 const deleteAction = Adt.generate([
12292 {
12293 singleCellTable: [
12294 'rng',
12295 'cell'
12296 ]
12297 },
12298 { fullTable: ['table'] },
12299 {
12300 partialTable: [
12301 'cells',
12302 'outsideDetails'
12303 ]
12304 },
12305 {
12306 multiTable: [
12307 'startTableCells',
12308 'endTableCells',
12309 'betweenRng'
12310 ]
12311 }
12312 ]);
12313 const getClosestCell$1 = (container, isRoot) => closest$3(SugarElement.fromDom(container), 'td,th', isRoot);
12314 const isExpandedCellRng = cellRng => !eq(cellRng.start, cellRng.end);
12315 const getTableFromCellRng = (cellRng, isRoot) => getClosestTable(cellRng.start, isRoot).bind(startParentTable => getClosestTable(cellRng.end, isRoot).bind(endParentTable => someIf(eq(startParentTable, endParentTable), startParentTable)));
12316 const isSingleCellTable = (cellRng, isRoot) => !isExpandedCellRng(cellRng) && getTableFromCellRng(cellRng, isRoot).exists(table => {
12317 const rows = table.dom.rows;
12318 return rows.length === 1 && rows[0].cells.length === 1;
12319 });
12320 const getCellRng = (rng, isRoot) => {
12321 const startCell = getClosestCell$1(rng.startContainer, isRoot);
12322 const endCell = getClosestCell$1(rng.endContainer, isRoot);
12323 return lift2(startCell, endCell, tableCellRng);
12324 };
12325 const getCellRangeFromStartTable = isRoot => startCell => getClosestTable(startCell, isRoot).bind(table => last$2(getTableCells(table)).map(endCell => tableCellRng(startCell, endCell)));
12326 const getCellRangeFromEndTable = isRoot => endCell => getClosestTable(endCell, isRoot).bind(table => head(getTableCells(table)).map(startCell => tableCellRng(startCell, endCell)));
12327 const getTableSelectionFromCellRng = isRoot => cellRng => getTableFromCellRng(cellRng, isRoot).map(table => tableSelection(cellRng, table, getTableCells(table)));
12328 const getTableSelections = (cellRng, selectionDetails, rng, isRoot) => {
12329 if (rng.collapsed || !cellRng.forall(isExpandedCellRng)) {
12330 return Optional.none();
12331 } else if (selectionDetails.isSameTable) {
12332 const sameTableSelection = cellRng.bind(getTableSelectionFromCellRng(isRoot));
12333 return Optional.some({
12334 start: sameTableSelection,
12335 end: sameTableSelection
12336 });
12337 } else {
12338 const startCell = getClosestCell$1(rng.startContainer, isRoot);
12339 const endCell = getClosestCell$1(rng.endContainer, isRoot);
12340 const startTableSelection = startCell.bind(getCellRangeFromStartTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
12341 const endTableSelection = endCell.bind(getCellRangeFromEndTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
12342 return Optional.some({
12343 start: startTableSelection,
12344 end: endTableSelection
12345 });
12346 }
12347 };
12348 const getCellIndex = (cells, cell) => findIndex$2(cells, x => eq(x, cell));
12349 const getSelectedCells = tableSelection => lift2(getCellIndex(tableSelection.cells, tableSelection.rng.start), getCellIndex(tableSelection.cells, tableSelection.rng.end), (startIndex, endIndex) => tableSelection.cells.slice(startIndex, endIndex + 1));
12350 const isSingleCellTableContentSelected = (optCellRng, rng, isRoot) => optCellRng.exists(cellRng => isSingleCellTable(cellRng, isRoot) && hasAllContentsSelected(cellRng.start, rng));
12351 const unselectCells = (rng, selectionDetails) => {
12352 const {startTable, endTable} = selectionDetails;
12353 const otherContentRng = rng.cloneRange();
12354 startTable.each(table => otherContentRng.setStartAfter(table.dom));
12355 endTable.each(table => otherContentRng.setEndBefore(table.dom));
12356 return otherContentRng;
12357 };
12358 const handleSingleTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => start.or(end)).bind(tableSelection => {
12359 const {isSameTable} = selectionDetails;
12360 const selectedCells = getSelectedCells(tableSelection).getOr([]);
12361 if (isSameTable && tableSelection.cells.length === selectedCells.length) {
12362 return Optional.some(deleteAction.fullTable(tableSelection.table));
12363 } else if (selectedCells.length > 0) {
12364 if (isSameTable) {
12365 return Optional.some(deleteAction.partialTable(selectedCells, Optional.none()));
12366 } else {
12367 const otherContentRng = unselectCells(rng, selectionDetails);
12368 return Optional.some(deleteAction.partialTable(selectedCells, Optional.some({
12369 ...selectionDetails,
12370 rng: otherContentRng
12371 })));
12372 }
12373 } else {
12374 return Optional.none();
12375 }
12376 });
12377 const handleMultiTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => {
12378 const startTableSelectedCells = start.bind(getSelectedCells).getOr([]);
12379 const endTableSelectedCells = end.bind(getSelectedCells).getOr([]);
12380 if (startTableSelectedCells.length > 0 && endTableSelectedCells.length > 0) {
12381 const otherContentRng = unselectCells(rng, selectionDetails);
12382 return Optional.some(deleteAction.multiTable(startTableSelectedCells, endTableSelectedCells, otherContentRng));
12383 } else {
12384 return Optional.none();
12385 }
12386 });
12387 const getActionFromRange = (root, rng) => {
12388 const isRoot = isRootFromElement(root);
12389 const optCellRng = getCellRng(rng, isRoot);
12390 const selectionDetails = getTableDetailsFromRange(rng, isRoot);
12391 if (isSingleCellTableContentSelected(optCellRng, rng, isRoot)) {
12392 return optCellRng.map(cellRng => deleteAction.singleCellTable(rng, cellRng.start));
12393 } else if (selectionDetails.isMultiTable) {
12394 return handleMultiTable(optCellRng, selectionDetails, rng, isRoot);
12395 } else {
12396 return handleSingleTable(optCellRng, selectionDetails, rng, isRoot);
12397 }
12398 };
12399
12400 const cleanCells = cells => each$e(cells, cell => {
12401 remove$9(cell, 'contenteditable');
12402 fillWithPaddingBr(cell);
12403 });
12404 const getOutsideBlock = (editor, container) => Optional.from(editor.dom.getParent(container, editor.dom.isBlock)).map(SugarElement.fromDom);
12405 const handleEmptyBlock = (editor, startInTable, emptyBlock) => {
12406 emptyBlock.each(block => {
12407 if (startInTable) {
12408 remove$4(block);
12409 } else {
12410 fillWithPaddingBr(block);
12411 editor.selection.setCursorLocation(block.dom, 0);
12412 }
12413 });
12414 };
12415 const deleteContentInsideCell = (editor, cell, rng, isFirstCellInSelection) => {
12416 const insideTableRng = rng.cloneRange();
12417 if (isFirstCellInSelection) {
12418 insideTableRng.setStart(rng.startContainer, rng.startOffset);
12419 insideTableRng.setEndAfter(cell.dom.lastChild);
12420 } else {
12421 insideTableRng.setStartBefore(cell.dom.firstChild);
12422 insideTableRng.setEnd(rng.endContainer, rng.endOffset);
12423 }
12424 deleteCellContents(editor, insideTableRng, cell, false).each(action => action());
12425 };
12426 const collapseAndRestoreCellSelection = editor => {
12427 const selectedCells = getCellsFromEditor(editor);
12428 const selectedNode = SugarElement.fromDom(editor.selection.getNode());
12429 if (isTableCell$3(selectedNode.dom) && isEmpty$2(editor.schema, selectedNode)) {
12430 editor.selection.setCursorLocation(selectedNode.dom, 0);
12431 } else {
12432 editor.selection.collapse(true);
12433 }
12434 if (selectedCells.length > 1 && exists(selectedCells, cell => eq(cell, selectedNode))) {
12435 set$3(selectedNode, 'data-mce-selected', '1');
12436 }
12437 };
12438 const emptySingleTableCells = (editor, cells, outsideDetails) => Optional.some(() => {
12439 const editorRng = editor.selection.getRng();
12440 const cellsToClean = outsideDetails.bind(({rng, isStartInTable}) => {
12441 const outsideBlock = getOutsideBlock(editor, isStartInTable ? rng.endContainer : rng.startContainer);
12442 rng.deleteContents();
12443 handleEmptyBlock(editor, isStartInTable, outsideBlock.filter(curry(isEmpty$2, editor.schema)));
12444 const endPointCell = isStartInTable ? cells[0] : cells[cells.length - 1];
12445 deleteContentInsideCell(editor, endPointCell, editorRng, isStartInTable);
12446 if (!isEmpty$2(editor.schema, endPointCell)) {
12447 return Optional.some(isStartInTable ? cells.slice(1) : cells.slice(0, -1));
12448 } else {
12449 return Optional.none();
12450 }
12451 }).getOr(cells);
12452 cleanCells(cellsToClean);
12453 collapseAndRestoreCellSelection(editor);
12454 });
12455 const emptyMultiTableCells = (editor, startTableCells, endTableCells, betweenRng) => Optional.some(() => {
12456 const rng = editor.selection.getRng();
12457 const startCell = startTableCells[0];
12458 const endCell = endTableCells[endTableCells.length - 1];
12459 deleteContentInsideCell(editor, startCell, rng, true);
12460 deleteContentInsideCell(editor, endCell, rng, false);
12461 const startTableCellsToClean = isEmpty$2(editor.schema, startCell) ? startTableCells : startTableCells.slice(1);
12462 const endTableCellsToClean = isEmpty$2(editor.schema, endCell) ? endTableCells : endTableCells.slice(0, -1);
12463 cleanCells(startTableCellsToClean.concat(endTableCellsToClean));
12464 betweenRng.deleteContents();
12465 collapseAndRestoreCellSelection(editor);
12466 });
12467 const deleteCellContents = (editor, rng, cell, moveSelection = true) => Optional.some(() => {
12468 deleteRangeContents(editor, rng, cell, moveSelection);
12469 });
12470 const deleteTableElement = (editor, table) => Optional.some(() => deleteElement$2(editor, false, table));
12471 const deleteCellRange = (editor, rootElm, rng) => getActionFromRange(rootElm, rng).bind(action => action.fold(curry(deleteCellContents, editor), curry(deleteTableElement, editor), curry(emptySingleTableCells, editor), curry(emptyMultiTableCells, editor)));
12472 const deleteCaptionRange = (editor, caption) => emptyElement(editor, caption);
12473 const deleteTableRange = (editor, rootElm, rng, startElm) => getParentCaption(rootElm, startElm).fold(() => deleteCellRange(editor, rootElm, rng), caption => deleteCaptionRange(editor, caption));
12474 const deleteRange$3 = (editor, startElm, selectedCells) => {
12475 const rootNode = SugarElement.fromDom(editor.getBody());
12476 const rng = editor.selection.getRng();
12477 return selectedCells.length !== 0 ? emptySingleTableCells(editor, selectedCells, Optional.none()) : deleteTableRange(editor, rootNode, rng, startElm);
12478 };
12479 const getParentCell = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTableCell$2);
12480 const getParentCaption = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTag('caption'));
12481 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)));
12482 const emptyElement = (editor, elm) => Optional.some(() => {
12483 fillWithPaddingBr(elm);
12484 editor.selection.setCursorLocation(elm.dom, 0);
12485 });
12486 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);
12487 const emptyCaretCaption = (editor, elm) => emptyElement(editor, elm);
12488 const validateCaretCaption = (rootElm, fromCaption, to) => getParentCaption(rootElm, SugarElement.fromDom(to.getNode())).fold(() => Optional.some(noop), toCaption => someIf(!eq(toCaption, fromCaption), noop));
12489 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));
12490 const deleteCaretCells = (editor, forward, rootElm, startElm) => {
12491 const from = CaretPosition.fromRangeStart(editor.selection.getRng());
12492 return getParentCell(rootElm, startElm).bind(fromCell => isEmpty$2(editor.schema, fromCell, { checkRootAsContent: false }) ? emptyElement(editor, fromCell) : deleteBetweenCells(editor, rootElm, forward, fromCell, from));
12493 };
12494 const deleteCaretCaption = (editor, forward, rootElm, fromCaption) => {
12495 const from = CaretPosition.fromRangeStart(editor.selection.getRng());
12496 return isEmpty$2(editor.schema, fromCaption) ? emptyElement(editor, fromCaption) : deleteCaretInsideCaption(editor, rootElm, forward, fromCaption, from);
12497 };
12498 const isNearTable = (forward, pos) => forward ? isBeforeTable(pos) : isAfterTable(pos);
12499 const isBeforeOrAfterTable = (editor, forward) => {
12500 const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
12501 return isNearTable(forward, fromPos) || fromPosition(forward, editor.getBody(), fromPos).exists(pos => isNearTable(forward, pos));
12502 };
12503 const deleteCaret$3 = (editor, forward, startElm) => {
12504 const rootElm = SugarElement.fromDom(editor.getBody());
12505 return getParentCaption(rootElm, startElm).fold(() => deleteCaretCells(editor, forward, rootElm, startElm).orThunk(() => someIf(isBeforeOrAfterTable(editor, forward), noop)), fromCaption => deleteCaretCaption(editor, forward, rootElm, fromCaption));
12506 };
12507 const backspaceDelete$a = (editor, forward) => {
12508 const startElm = SugarElement.fromDom(editor.selection.getStart(true));
12509 const cells = getCellsFromEditor(editor);
12510 return editor.selection.isCollapsed() && cells.length === 0 ? deleteCaret$3(editor, forward, startElm) : deleteRange$3(editor, startElm, cells);
12511 };
12512
12513 const getContentEditableRoot$1 = (root, node) => {
12514 let tempNode = node;
12515 while (tempNode && tempNode !== root) {
12516 if (isContentEditableTrue$3(tempNode) || isContentEditableFalse$b(tempNode)) {
12517 return tempNode;
12518 }
12519 tempNode = tempNode.parentNode;
12520 }
12521 return null;
12522 };
12523
12524 const internalAttributesPrefixes = [
12525 'data-ephox-',
12526 'data-mce-',
12527 'data-alloy-',
12528 'data-snooker-',
12529 '_'
12530 ];
12531 const each$9 = Tools.each;
12532 const ElementUtils = editor => {
12533 const dom = editor.dom;
12534 const internalAttributes = new Set(editor.serializer.getTempAttrs());
12535 const compare = (node1, node2) => {
12536 if (node1.nodeName !== node2.nodeName || node1.nodeType !== node2.nodeType) {
12537 return false;
12538 }
12539 const getAttribs = node => {
12540 const attribs = {};
12541 each$9(dom.getAttribs(node), attr => {
12542 const name = attr.nodeName.toLowerCase();
12543 if (name !== 'style' && !isAttributeInternal(name)) {
12544 attribs[name] = dom.getAttrib(node, name);
12545 }
12546 });
12547 return attribs;
12548 };
12549 const compareObjects = (obj1, obj2) => {
12550 for (const name in obj1) {
12551 if (has$2(obj1, name)) {
12552 const value = obj2[name];
12553 if (isUndefined(value)) {
12554 return false;
12555 }
12556 if (obj1[name] !== value) {
12557 return false;
12558 }
12559 delete obj2[name];
12560 }
12561 }
12562 for (const name in obj2) {
12563 if (has$2(obj2, name)) {
12564 return false;
12565 }
12566 }
12567 return true;
12568 };
12569 if (isElement$6(node1) && isElement$6(node2)) {
12570 if (!compareObjects(getAttribs(node1), getAttribs(node2))) {
12571 return false;
12572 }
12573 if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style')))) {
12574 return false;
12575 }
12576 }
12577 return !isBookmarkNode$1(node1) && !isBookmarkNode$1(node2);
12578 };
12579 const isAttributeInternal = attributeName => exists(internalAttributesPrefixes, value => startsWith(attributeName, value)) || internalAttributes.has(attributeName);
12580 return {
12581 compare,
12582 isAttributeInternal
12583 };
12584 };
12585
12586 const isHeading = node => [
12587 'h1',
12588 'h2',
12589 'h3',
12590 'h4',
12591 'h5',
12592 'h6'
12593 ].includes(node.name);
12594 const isSummary = node => node.name === 'summary';
12595
12596 const traverse = (root, fn) => {
12597 let node = root;
12598 while (node = node.walk()) {
12599 fn(node);
12600 }
12601 };
12602 const matchNode$1 = (nodeFilters, attributeFilters, node, matches) => {
12603 const name = node.name;
12604 for (let ni = 0, nl = nodeFilters.length; ni < nl; ni++) {
12605 const filter = nodeFilters[ni];
12606 if (filter.name === name) {
12607 const match = matches.nodes[name];
12608 if (match) {
12609 match.nodes.push(node);
12610 } else {
12611 matches.nodes[name] = {
12612 filter,
12613 nodes: [node]
12614 };
12615 }
12616 }
12617 }
12618 if (node.attributes) {
12619 for (let ai = 0, al = attributeFilters.length; ai < al; ai++) {
12620 const filter = attributeFilters[ai];
12621 const attrName = filter.name;
12622 if (attrName in node.attributes.map) {
12623 const match = matches.attributes[attrName];
12624 if (match) {
12625 match.nodes.push(node);
12626 } else {
12627 matches.attributes[attrName] = {
12628 filter,
12629 nodes: [node]
12630 };
12631 }
12632 }
12633 }
12634 }
12635 };
12636 const findMatchingNodes = (nodeFilters, attributeFilters, node) => {
12637 const matches = {
12638 nodes: {},
12639 attributes: {}
12640 };
12641 if (node.firstChild) {
12642 traverse(node, childNode => {
12643 matchNode$1(nodeFilters, attributeFilters, childNode, matches);
12644 });
12645 }
12646 return matches;
12647 };
12648 const runFilters = (matches, args) => {
12649 const run = (matchRecord, filteringAttributes) => {
12650 each$d(matchRecord, match => {
12651 const nodes = from(match.nodes);
12652 each$e(match.filter.callbacks, callback => {
12653 for (let i = nodes.length - 1; i >= 0; i--) {
12654 const node = nodes[i];
12655 const valueMatches = filteringAttributes ? node.attr(match.filter.name) !== undefined : node.name === match.filter.name;
12656 if (!valueMatches || isNullable(node.parent)) {
12657 nodes.splice(i, 1);
12658 }
12659 }
12660 if (nodes.length > 0) {
12661 callback(nodes, match.filter.name, args);
12662 }
12663 });
12664 });
12665 };
12666 run(matches.nodes, false);
12667 run(matches.attributes, true);
12668 };
12669 const filter$2 = (nodeFilters, attributeFilters, node, args = {}) => {
12670 const matches = findMatchingNodes(nodeFilters, attributeFilters, node);
12671 runFilters(matches, args);
12672 };
12673
12674 const paddEmptyNode = (settings, args, isBlock, node) => {
12675 const brPreferred = settings.pad_empty_with_br || args.insert;
12676 if (brPreferred && isBlock(node)) {
12677 const astNode = new AstNode('br', 1);
12678 if (args.insert) {
12679 astNode.attr('data-mce-bogus', '1');
12680 }
12681 node.empty().append(astNode);
12682 } else {
12683 node.empty().append(new AstNode('#text', 3)).value = nbsp;
12684 }
12685 };
12686 const isPaddedWithNbsp = node => {
12687 var _a;
12688 return hasOnlyChild(node, '#text') && ((_a = node === null || node === void 0 ? void 0 : node.firstChild) === null || _a === void 0 ? void 0 : _a.value) === nbsp;
12689 };
12690 const hasOnlyChild = (node, name) => {
12691 const firstChild = node === null || node === void 0 ? void 0 : node.firstChild;
12692 return isNonNullable(firstChild) && firstChild === node.lastChild && firstChild.name === name;
12693 };
12694 const isPadded = (schema, node) => {
12695 const rule = schema.getElementRule(node.name);
12696 return (rule === null || rule === void 0 ? void 0 : rule.paddEmpty) === true;
12697 };
12698 const isEmpty = (schema, nonEmptyElements, whitespaceElements, node) => node.isEmpty(nonEmptyElements, whitespaceElements, node => isPadded(schema, node));
12699 const isLineBreakNode = (node, isBlock) => isNonNullable(node) && (isBlock(node) || node.name === 'br');
12700 const findClosestEditingHost = scope => {
12701 let editableNode;
12702 for (let node = scope; node; node = node.parent) {
12703 const contentEditable = node.attr('contenteditable');
12704 if (contentEditable === 'false') {
12705 break;
12706 } else if (contentEditable === 'true') {
12707 editableNode = node;
12708 }
12709 }
12710 return Optional.from(editableNode);
12711 };
12712
12713 const removeOrUnwrapInvalidNode = (node, schema, originalNodeParent = node.parent) => {
12714 if (schema.getSpecialElements()[node.name]) {
12715 node.empty().remove();
12716 } else {
12717 const children = node.children();
12718 for (const childNode of children) {
12719 if (originalNodeParent && !schema.isValidChild(originalNodeParent.name, childNode.name)) {
12720 removeOrUnwrapInvalidNode(childNode, schema, originalNodeParent);
12721 }
12722 }
12723 node.unwrap();
12724 }
12725 };
12726 const cleanInvalidNodes = (nodes, schema, rootNode, onCreate = noop) => {
12727 const textBlockElements = schema.getTextBlockElements();
12728 const nonEmptyElements = schema.getNonEmptyElements();
12729 const whitespaceElements = schema.getWhitespaceElements();
12730 const nonSplittableElements = Tools.makeMap('tr,td,th,tbody,thead,tfoot,table,summary');
12731 const fixed = new Set();
12732 const isSplittableElement = node => node !== rootNode && !nonSplittableElements[node.name];
12733 for (let ni = 0; ni < nodes.length; ni++) {
12734 const node = nodes[ni];
12735 let parent;
12736 let newParent;
12737 let tempNode;
12738 if (!node.parent || fixed.has(node)) {
12739 continue;
12740 }
12741 if (textBlockElements[node.name] && node.parent.name === 'li') {
12742 let sibling = node.next;
12743 while (sibling) {
12744 if (textBlockElements[sibling.name]) {
12745 sibling.name = 'li';
12746 fixed.add(sibling);
12747 node.parent.insert(sibling, node.parent);
12748 } else {
12749 break;
12750 }
12751 sibling = sibling.next;
12752 }
12753 node.unwrap();
12754 continue;
12755 }
12756 const parents = [node];
12757 for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && isSplittableElement(parent); parent = parent.parent) {
12758 parents.push(parent);
12759 }
12760 if (parent && parents.length > 1) {
12761 if (!isInvalid(schema, node, parent)) {
12762 parents.reverse();
12763 newParent = parents[0].clone();
12764 onCreate(newParent);
12765 let currentNode = newParent;
12766 for (let i = 0; i < parents.length - 1; i++) {
12767 if (schema.isValidChild(currentNode.name, parents[i].name) && i > 0) {
12768 tempNode = parents[i].clone();
12769 onCreate(tempNode);
12770 currentNode.append(tempNode);
12771 } else {
12772 tempNode = currentNode;
12773 }
12774 for (let childNode = parents[i].firstChild; childNode && childNode !== parents[i + 1];) {
12775 const nextNode = childNode.next;
12776 tempNode.append(childNode);
12777 childNode = nextNode;
12778 }
12779 currentNode = tempNode;
12780 }
12781 if (!isEmpty(schema, nonEmptyElements, whitespaceElements, newParent)) {
12782 parent.insert(newParent, parents[0], true);
12783 parent.insert(node, newParent);
12784 } else {
12785 parent.insert(node, parents[0], true);
12786 }
12787 parent = parents[0];
12788 if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent) || hasOnlyChild(parent, 'br')) {
12789 parent.empty().remove();
12790 }
12791 } else {
12792 removeOrUnwrapInvalidNode(node, schema);
12793 }
12794 } else if (node.parent) {
12795 if (node.name === 'li') {
12796 let sibling = node.prev;
12797 if (sibling && (sibling.name === 'ul' || sibling.name === 'ol')) {
12798 sibling.append(node);
12799 continue;
12800 }
12801 sibling = node.next;
12802 if (sibling && (sibling.name === 'ul' || sibling.name === 'ol') && sibling.firstChild) {
12803 sibling.insert(node, sibling.firstChild, true);
12804 continue;
12805 }
12806 const wrapper = new AstNode('ul', 1);
12807 onCreate(wrapper);
12808 node.wrap(wrapper);
12809 continue;
12810 }
12811 if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) {
12812 const wrapper = new AstNode('div', 1);
12813 onCreate(wrapper);
12814 node.wrap(wrapper);
12815 } else {
12816 removeOrUnwrapInvalidNode(node, schema);
12817 }
12818 }
12819 }
12820 };
12821 const hasClosest = (node, parentName) => {
12822 let tempNode = node;
12823 while (tempNode) {
12824 if (tempNode.name === parentName) {
12825 return true;
12826 }
12827 tempNode = tempNode.parent;
12828 }
12829 return false;
12830 };
12831 const isInvalid = (schema, node, parent = node.parent) => {
12832 if (!parent) {
12833 return false;
12834 }
12835 if (schema.children[node.name] && !schema.isValidChild(parent.name, node.name)) {
12836 return true;
12837 }
12838 if (node.name === 'a' && hasClosest(parent, 'a')) {
12839 return true;
12840 }
12841 if (isSummary(parent) && isHeading(node)) {
12842 return !((parent === null || parent === void 0 ? void 0 : parent.firstChild) === node && (parent === null || parent === void 0 ? void 0 : parent.lastChild) === node);
12843 }
12844 return false;
12845 };
12846
12847 const createRange = (sc, so, ec, eo) => {
12848 const rng = document.createRange();
12849 rng.setStart(sc, so);
12850 rng.setEnd(ec, eo);
12851 return rng;
12852 };
12853 const normalizeBlockSelectionRange = rng => {
12854 const startPos = CaretPosition.fromRangeStart(rng);
12855 const endPos = CaretPosition.fromRangeEnd(rng);
12856 const rootNode = rng.commonAncestorContainer;
12857 return fromPosition(false, rootNode, endPos).map(newEndPos => {
12858 if (!isInSameBlock(startPos, endPos, rootNode) && isInSameBlock(startPos, newEndPos, rootNode)) {
12859 return createRange(startPos.container(), startPos.offset(), newEndPos.container(), newEndPos.offset());
12860 } else {
12861 return rng;
12862 }
12863 }).getOr(rng);
12864 };
12865 const normalize = rng => rng.collapsed ? rng : normalizeBlockSelectionRange(rng);
12866
12867 const hasOnlyOneChild$1 = node => {
12868 return isNonNullable(node.firstChild) && node.firstChild === node.lastChild;
12869 };
12870 const isPaddingNode = node => {
12871 return node.name === 'br' || node.value === nbsp;
12872 };
12873 const isPaddedEmptyBlock = (schema, node) => {
12874 const blockElements = schema.getBlockElements();
12875 return blockElements[node.name] && hasOnlyOneChild$1(node) && isPaddingNode(node.firstChild);
12876 };
12877 const isEmptyFragmentElement = (schema, node) => {
12878 const nonEmptyElements = schema.getNonEmptyElements();
12879 return isNonNullable(node) && (node.isEmpty(nonEmptyElements) || isPaddedEmptyBlock(schema, node));
12880 };
12881 const isListFragment = (schema, fragment) => {
12882 let firstChild = fragment.firstChild;
12883 let lastChild = fragment.lastChild;
12884 if (firstChild && firstChild.name === 'meta') {
12885 firstChild = firstChild.next;
12886 }
12887 if (lastChild && lastChild.attr('id') === 'mce_marker') {
12888 lastChild = lastChild.prev;
12889 }
12890 if (isEmptyFragmentElement(schema, lastChild)) {
12891 lastChild = lastChild === null || lastChild === void 0 ? void 0 : lastChild.prev;
12892 }
12893 if (!firstChild || firstChild !== lastChild) {
12894 return false;
12895 }
12896 return firstChild.name === 'ul' || firstChild.name === 'ol';
12897 };
12898 const cleanupDomFragment = domFragment => {
12899 var _a, _b;
12900 const firstChild = domFragment.firstChild;
12901 const lastChild = domFragment.lastChild;
12902 if (firstChild && firstChild.nodeName === 'META') {
12903 (_a = firstChild.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(firstChild);
12904 }
12905 if (lastChild && lastChild.id === 'mce_marker') {
12906 (_b = lastChild.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(lastChild);
12907 }
12908 return domFragment;
12909 };
12910 const toDomFragment = (dom, serializer, fragment) => {
12911 const html = serializer.serialize(fragment);
12912 const domFragment = dom.createFragment(html);
12913 return cleanupDomFragment(domFragment);
12914 };
12915 const listItems = elm => {
12916 var _a;
12917 return filter$5((_a = elm === null || elm === void 0 ? void 0 : elm.childNodes) !== null && _a !== void 0 ? _a : [], child => {
12918 return child.nodeName === 'LI';
12919 });
12920 };
12921 const isPadding = node => {
12922 return node.data === nbsp || isBr$6(node);
12923 };
12924 const isListItemPadded = node => {
12925 return isNonNullable(node === null || node === void 0 ? void 0 : node.firstChild) && node.firstChild === node.lastChild && isPadding(node.firstChild);
12926 };
12927 const isEmptyOrPadded = elm => {
12928 return !elm.firstChild || isListItemPadded(elm);
12929 };
12930 const trimListItems = elms => {
12931 return elms.length > 0 && isEmptyOrPadded(elms[elms.length - 1]) ? elms.slice(0, -1) : elms;
12932 };
12933 const getParentLi = (dom, node) => {
12934 const parentBlock = dom.getParent(node, dom.isBlock);
12935 return parentBlock && parentBlock.nodeName === 'LI' ? parentBlock : null;
12936 };
12937 const isParentBlockLi = (dom, node) => {
12938 return !!getParentLi(dom, node);
12939 };
12940 const getSplit = (parentNode, rng) => {
12941 const beforeRng = rng.cloneRange();
12942 const afterRng = rng.cloneRange();
12943 beforeRng.setStartBefore(parentNode);
12944 afterRng.setEndAfter(parentNode);
12945 return [
12946 beforeRng.cloneContents(),
12947 afterRng.cloneContents()
12948 ];
12949 };
12950 const findFirstIn = (node, rootNode) => {
12951 const caretPos = CaretPosition.before(node);
12952 const caretWalker = CaretWalker(rootNode);
12953 const newCaretPos = caretWalker.next(caretPos);
12954 return newCaretPos ? newCaretPos.toRange() : null;
12955 };
12956 const findLastOf = (node, rootNode) => {
12957 const caretPos = CaretPosition.after(node);
12958 const caretWalker = CaretWalker(rootNode);
12959 const newCaretPos = caretWalker.prev(caretPos);
12960 return newCaretPos ? newCaretPos.toRange() : null;
12961 };
12962 const insertMiddle = (target, elms, rootNode, rng) => {
12963 const parts = getSplit(target, rng);
12964 const parentElm = target.parentNode;
12965 if (parentElm) {
12966 parentElm.insertBefore(parts[0], target);
12967 Tools.each(elms, li => {
12968 parentElm.insertBefore(li, target);
12969 });
12970 parentElm.insertBefore(parts[1], target);
12971 parentElm.removeChild(target);
12972 }
12973 return findLastOf(elms[elms.length - 1], rootNode);
12974 };
12975 const insertBefore$2 = (target, elms, rootNode) => {
12976 const parentElm = target.parentNode;
12977 if (parentElm) {
12978 Tools.each(elms, elm => {
12979 parentElm.insertBefore(elm, target);
12980 });
12981 }
12982 return findFirstIn(target, rootNode);
12983 };
12984 const insertAfter$2 = (target, elms, rootNode, dom) => {
12985 dom.insertAfter(elms.reverse(), target);
12986 return findLastOf(elms[0], rootNode);
12987 };
12988 const insertAtCaret$1 = (serializer, dom, rng, fragment) => {
12989 const domFragment = toDomFragment(dom, serializer, fragment);
12990 const liTarget = getParentLi(dom, rng.startContainer);
12991 const liElms = trimListItems(listItems(domFragment.firstChild));
12992 const BEGINNING = 1, END = 2;
12993 const rootNode = dom.getRoot();
12994 const isAt = location => {
12995 const caretPos = CaretPosition.fromRangeStart(rng);
12996 const caretWalker = CaretWalker(dom.getRoot());
12997 const newPos = location === BEGINNING ? caretWalker.prev(caretPos) : caretWalker.next(caretPos);
12998 const newPosNode = newPos === null || newPos === void 0 ? void 0 : newPos.getNode();
12999 return newPosNode ? getParentLi(dom, newPosNode) !== liTarget : true;
13000 };
13001 if (!liTarget) {
13002 return null;
13003 } else if (isAt(BEGINNING)) {
13004 return insertBefore$2(liTarget, liElms, rootNode);
13005 } else if (isAt(END)) {
13006 return insertAfter$2(liTarget, liElms, rootNode, dom);
13007 } else {
13008 return insertMiddle(liTarget, liElms, rootNode, rng);
13009 }
13010 };
13011
13012 const mergeableWrappedElements = ['pre'];
13013 const shouldPasteContentOnly = (dom, fragment, parentNode, root) => {
13014 var _a;
13015 const firstNode = fragment.firstChild;
13016 const lastNode = fragment.lastChild;
13017 const last = lastNode.attr('data-mce-type') === 'bookmark' ? lastNode.prev : lastNode;
13018 const isPastingSingleElement = firstNode === last;
13019 const isWrappedElement = contains$2(mergeableWrappedElements, firstNode.name);
13020 if (isPastingSingleElement && isWrappedElement) {
13021 const isContentEditable = firstNode.attr('contenteditable') !== 'false';
13022 const isPastingInTheSameBlockTag = ((_a = dom.getParent(parentNode, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName.toLowerCase()) === firstNode.name;
13023 const isPastingInContentEditable = Optional.from(getContentEditableRoot$1(root, parentNode)).forall(isContentEditableTrue$3);
13024 return isContentEditable && isPastingInTheSameBlockTag && isPastingInContentEditable;
13025 } else {
13026 return false;
13027 }
13028 };
13029 const isTableCell = isTableCell$3;
13030 const isTableCellContentSelected = (dom, rng, cell) => {
13031 if (isNonNullable(cell)) {
13032 const endCell = dom.getParent(rng.endContainer, isTableCell);
13033 return cell === endCell && hasAllContentsSelected(SugarElement.fromDom(cell), rng);
13034 } else {
13035 return false;
13036 }
13037 };
13038 const validInsertion = (editor, value, parentNode) => {
13039 var _a;
13040 if (parentNode.getAttribute('data-mce-bogus') === 'all') {
13041 (_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(editor.dom.createFragment(value), parentNode);
13042 } else {
13043 const node = parentNode.firstChild;
13044 const node2 = parentNode.lastChild;
13045 if (!node || node === node2 && node.nodeName === 'BR') {
13046 editor.dom.setHTML(parentNode, value);
13047 } else {
13048 editor.selection.setContent(value, { no_events: true });
13049 }
13050 }
13051 };
13052 const trimBrsFromTableCell = (dom, elm, schema) => {
13053 Optional.from(dom.getParent(elm, 'td,th')).map(SugarElement.fromDom).each(el => trimBlockTrailingBr(el, schema));
13054 };
13055 const reduceInlineTextElements = (editor, merge) => {
13056 const textInlineElements = editor.schema.getTextInlineElements();
13057 const dom = editor.dom;
13058 if (merge) {
13059 const root = editor.getBody();
13060 const elementUtils = ElementUtils(editor);
13061 Tools.each(dom.select('*[data-mce-fragment]'), node => {
13062 const isInline = isNonNullable(textInlineElements[node.nodeName.toLowerCase()]);
13063 if (isInline && hasInheritableStyles(dom, node)) {
13064 for (let parentNode = node.parentElement; isNonNullable(parentNode) && parentNode !== root; parentNode = parentNode.parentElement) {
13065 const styleConflict = hasStyleConflict(dom, node, parentNode);
13066 if (styleConflict) {
13067 break;
13068 }
13069 if (elementUtils.compare(parentNode, node)) {
13070 dom.remove(node, true);
13071 break;
13072 }
13073 }
13074 }
13075 });
13076 }
13077 };
13078 const markFragmentElements = fragment => {
13079 let node = fragment;
13080 while (node = node.walk()) {
13081 if (node.type === 1) {
13082 node.attr('data-mce-fragment', '1');
13083 }
13084 }
13085 };
13086 const unmarkFragmentElements = elm => {
13087 Tools.each(elm.getElementsByTagName('*'), elm => {
13088 elm.removeAttribute('data-mce-fragment');
13089 });
13090 };
13091 const isPartOfFragment = node => {
13092 return !!node.getAttribute('data-mce-fragment');
13093 };
13094 const canHaveChildren = (editor, node) => {
13095 return isNonNullable(node) && !editor.schema.getVoidElements()[node.nodeName];
13096 };
13097 const moveSelectionToMarker = (editor, marker) => {
13098 var _a, _b, _c;
13099 let nextRng;
13100 const dom = editor.dom;
13101 const selection = editor.selection;
13102 if (!marker) {
13103 return;
13104 }
13105 selection.scrollIntoView(marker);
13106 const parentEditableElm = getContentEditableRoot$1(editor.getBody(), marker);
13107 if (parentEditableElm && dom.getContentEditable(parentEditableElm) === 'false') {
13108 dom.remove(marker);
13109 selection.select(parentEditableElm);
13110 return;
13111 }
13112 let rng = dom.createRng();
13113 const node = marker.previousSibling;
13114 if (isText$b(node)) {
13115 rng.setStart(node, (_b = (_a = node.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
13116 const node2 = marker.nextSibling;
13117 if (isText$b(node2)) {
13118 node.appendData(node2.data);
13119 (_c = node2.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(node2);
13120 }
13121 } else {
13122 rng.setStartBefore(marker);
13123 rng.setEndBefore(marker);
13124 }
13125 const findNextCaretRng = rng => {
13126 let caretPos = CaretPosition.fromRangeStart(rng);
13127 const caretWalker = CaretWalker(editor.getBody());
13128 caretPos = caretWalker.next(caretPos);
13129 return caretPos === null || caretPos === void 0 ? void 0 : caretPos.toRange();
13130 };
13131 const parentBlock = dom.getParent(marker, dom.isBlock);
13132 dom.remove(marker);
13133 if (parentBlock && dom.isEmpty(parentBlock)) {
13134 const isCell = isTableCell(parentBlock);
13135 empty(SugarElement.fromDom(parentBlock));
13136 rng.setStart(parentBlock, 0);
13137 rng.setEnd(parentBlock, 0);
13138 if (!isCell && !isPartOfFragment(parentBlock) && (nextRng = findNextCaretRng(rng))) {
13139 rng = nextRng;
13140 dom.remove(parentBlock);
13141 } else {
13142 dom.add(parentBlock, dom.create('br', isCell ? {} : { 'data-mce-bogus': '1' }));
13143 }
13144 }
13145 selection.setRng(rng);
13146 };
13147 const deleteSelectedContent = editor => {
13148 const dom = editor.dom;
13149 const rng = normalize(editor.selection.getRng());
13150 editor.selection.setRng(rng);
13151 const startCell = dom.getParent(rng.startContainer, isTableCell);
13152 if (isTableCellContentSelected(dom, rng, startCell)) {
13153 deleteCellContents(editor, rng, SugarElement.fromDom(startCell));
13154 } else if (rng.startContainer === rng.endContainer && rng.endOffset - rng.startOffset === 1 && isText$b(rng.startContainer.childNodes[rng.startOffset])) {
13155 rng.deleteContents();
13156 } else {
13157 editor.getDoc().execCommand('Delete', false);
13158 }
13159 };
13160 const findMarkerNode = scope => {
13161 for (let markerNode = scope; markerNode; markerNode = markerNode.walk()) {
13162 if (markerNode.attr('id') === 'mce_marker') {
13163 return Optional.some(markerNode);
13164 }
13165 }
13166 return Optional.none();
13167 };
13168 const notHeadingsInSummary = (dom, node, fragment) => {
13169 var _a;
13170 return exists(fragment.children(), isHeading) && ((_a = dom.getParent(node, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName) === 'SUMMARY';
13171 };
13172 const insertHtmlAtCaret = (editor, value, details) => {
13173 var _a, _b;
13174 const selection = editor.selection;
13175 const dom = editor.dom;
13176 const parser = editor.parser;
13177 const merge = details.merge;
13178 const serializer = HtmlSerializer({ validate: true }, editor.schema);
13179 const bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;</span>';
13180 if (!details.preserve_zwsp) {
13181 value = trim$2(value);
13182 }
13183 if (value.indexOf('{$caret}') === -1) {
13184 value += '{$caret}';
13185 }
13186 value = value.replace(/\{\$caret\}/, bookmarkHtml);
13187 let rng = selection.getRng();
13188 const caretElement = rng.startContainer;
13189 const body = editor.getBody();
13190 if (caretElement === body && selection.isCollapsed()) {
13191 if (dom.isBlock(body.firstChild) && canHaveChildren(editor, body.firstChild) && dom.isEmpty(body.firstChild)) {
13192 rng = dom.createRng();
13193 rng.setStart(body.firstChild, 0);
13194 rng.setEnd(body.firstChild, 0);
13195 selection.setRng(rng);
13196 }
13197 }
13198 if (!selection.isCollapsed()) {
13199 deleteSelectedContent(editor);
13200 }
13201 const parentNode = selection.getNode();
13202 const parserArgs = {
13203 context: parentNode.nodeName.toLowerCase(),
13204 data: details.data,
13205 insert: true
13206 };
13207 const fragment = parser.parse(value, parserArgs);
13208 if (details.paste === true && isListFragment(editor.schema, fragment) && isParentBlockLi(dom, parentNode)) {
13209 rng = insertAtCaret$1(serializer, dom, selection.getRng(), fragment);
13210 if (rng) {
13211 selection.setRng(rng);
13212 }
13213 return value;
13214 }
13215 if (details.paste === true && shouldPasteContentOnly(dom, fragment, parentNode, editor.getBody())) {
13216 (_a = fragment.firstChild) === null || _a === void 0 ? void 0 : _a.unwrap();
13217 }
13218 markFragmentElements(fragment);
13219 let node = fragment.lastChild;
13220 if (node && node.attr('id') === 'mce_marker') {
13221 const marker = node;
13222 for (node = node.prev; node; node = node.walk(true)) {
13223 if (node.type === 3 || !dom.isBlock(node.name)) {
13224 if (node.parent && editor.schema.isValidChild(node.parent.name, 'span')) {
13225 node.parent.insert(marker, node, node.name === 'br');
13226 }
13227 break;
13228 }
13229 }
13230 }
13231 editor._selectionOverrides.showBlockCaretContainer(parentNode);
13232 if (!parserArgs.invalid && !notHeadingsInSummary(dom, parentNode, fragment)) {
13233 value = serializer.serialize(fragment);
13234 validInsertion(editor, value, parentNode);
13235 } else {
13236 editor.selection.setContent(bookmarkHtml);
13237 let parentNode = selection.getNode();
13238 let tempNode;
13239 const rootNode = editor.getBody();
13240 if (isDocument$1(parentNode)) {
13241 parentNode = tempNode = rootNode;
13242 } else {
13243 tempNode = parentNode;
13244 }
13245 while (tempNode && tempNode !== rootNode) {
13246 parentNode = tempNode;
13247 tempNode = tempNode.parentNode;
13248 }
13249 value = parentNode === rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode);
13250 const root = parser.parse(value);
13251 const markerNode = findMarkerNode(root);
13252 const editingHost = markerNode.bind(findClosestEditingHost).getOr(root);
13253 markerNode.each(marker => marker.replace(fragment));
13254 const toExtract = fragment.children();
13255 const parent = (_b = fragment.parent) !== null && _b !== void 0 ? _b : root;
13256 fragment.unwrap();
13257 const invalidChildren = filter$5(toExtract, node => isInvalid(editor.schema, node, parent));
13258 cleanInvalidNodes(invalidChildren, editor.schema, editingHost);
13259 filter$2(parser.getNodeFilters(), parser.getAttributeFilters(), root);
13260 value = serializer.serialize(root);
13261 if (parentNode === rootNode) {
13262 dom.setHTML(rootNode, value);
13263 } else {
13264 dom.setOuterHTML(parentNode, value);
13265 }
13266 }
13267 reduceInlineTextElements(editor, merge);
13268 moveSelectionToMarker(editor, dom.get('mce_marker'));
13269 unmarkFragmentElements(editor.getBody());
13270 trimBrsFromTableCell(dom, selection.getStart(), editor.schema);
13271 updateCaret(editor.schema, editor.getBody(), selection.getStart());
13272 return value;
13273 };
13274
13275 const isTreeNode = content => content instanceof AstNode;
13276
13277 const moveSelection = editor => {
13278 if (hasFocus(editor)) {
13279 firstPositionIn(editor.getBody()).each(pos => {
13280 const node = pos.getNode();
13281 const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
13282 editor.selection.setRng(caretPos.toRange());
13283 });
13284 }
13285 };
13286 const setEditorHtml = (editor, html, noSelection) => {
13287 editor.dom.setHTML(editor.getBody(), html);
13288 if (noSelection !== true) {
13289 moveSelection(editor);
13290 }
13291 };
13292 const setContentString = (editor, body, content, args) => {
13293 content = trim$2(content);
13294 if (content.length === 0 || /^\s+$/.test(content)) {
13295 const padd = '<br data-mce-bogus="1">';
13296 if (body.nodeName === 'TABLE') {
13297 content = '<tr><td>' + padd + '</td></tr>';
13298 } else if (/^(UL|OL)$/.test(body.nodeName)) {
13299 content = '<li>' + padd + '</li>';
13300 }
13301 const forcedRootBlockName = getForcedRootBlock(editor);
13302 if (editor.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
13303 content = padd;
13304 content = editor.dom.createHTML(forcedRootBlockName, getForcedRootBlockAttrs(editor), content);
13305 } else if (!content) {
13306 content = padd;
13307 }
13308 setEditorHtml(editor, content, args.no_selection);
13309 return {
13310 content,
13311 html: content
13312 };
13313 } else {
13314 if (args.format !== 'raw') {
13315 content = HtmlSerializer({ validate: false }, editor.schema).serialize(editor.parser.parse(content, {
13316 isRootContent: true,
13317 insert: true
13318 }));
13319 }
13320 const trimmedHtml = isWsPreserveElement(SugarElement.fromDom(body)) ? content : Tools.trim(content);
13321 setEditorHtml(editor, trimmedHtml, args.no_selection);
13322 return {
13323 content: trimmedHtml,
13324 html: trimmedHtml
13325 };
13326 }
13327 };
13328 const setContentTree = (editor, body, content, args) => {
13329 filter$2(editor.parser.getNodeFilters(), editor.parser.getAttributeFilters(), content);
13330 const html = HtmlSerializer({ validate: false }, editor.schema).serialize(content);
13331 const trimmedHtml = trim$2(isWsPreserveElement(SugarElement.fromDom(body)) ? html : Tools.trim(html));
13332 setEditorHtml(editor, trimmedHtml, args.no_selection);
13333 return {
13334 content,
13335 html: trimmedHtml
13336 };
13337 };
13338 const setContentInternal = (editor, content, args) => {
13339 return Optional.from(editor.getBody()).map(body => {
13340 if (isTreeNode(content)) {
13341 return setContentTree(editor, body, content, args);
13342 } else {
13343 return setContentString(editor, body, content, args);
13344 }
13345 }).getOr({
13346 content,
13347 html: isTreeNode(args.content) ? '' : args.content
13348 });
13349 };
13350
13351 const ensureIsRoot = isRoot => isFunction(isRoot) ? isRoot : never;
13352 const ancestor = (scope, transform, isRoot) => {
13353 let element = scope.dom;
13354 const stop = ensureIsRoot(isRoot);
13355 while (element.parentNode) {
13356 element = element.parentNode;
13357 const el = SugarElement.fromDom(element);
13358 const transformed = transform(el);
13359 if (transformed.isSome()) {
13360 return transformed;
13361 } else if (stop(el)) {
13362 break;
13363 }
13364 }
13365 return Optional.none();
13366 };
13367 const closest$1 = (scope, transform, isRoot) => {
13368 const current = transform(scope);
13369 const stop = ensureIsRoot(isRoot);
13370 return current.orThunk(() => stop(scope) ? Optional.none() : ancestor(scope, transform, stop));
13371 };
13372
13373 const isEq$3 = isEq$5;
13374 const matchesUnInheritedFormatSelector = (ed, node, name) => {
13375 const formatList = ed.formatter.get(name);
13376 if (formatList) {
13377 for (let i = 0; i < formatList.length; i++) {
13378 const format = formatList[i];
13379 if (isSelectorFormat(format) && format.inherit === false && ed.dom.is(node, format.selector)) {
13380 return true;
13381 }
13382 }
13383 }
13384 return false;
13385 };
13386 const matchParents = (editor, node, name, vars, similar) => {
13387 const root = editor.dom.getRoot();
13388 if (node === root) {
13389 return false;
13390 }
13391 const matchedNode = editor.dom.getParent(node, elm => {
13392 if (matchesUnInheritedFormatSelector(editor, elm, name)) {
13393 return true;
13394 }
13395 return elm.parentNode === root || !!matchNode(editor, elm, name, vars, true);
13396 });
13397 return !!matchNode(editor, matchedNode, name, vars, similar);
13398 };
13399 const matchName = (dom, node, format) => {
13400 if (isInlineFormat(format) && isEq$3(node, format.inline)) {
13401 return true;
13402 }
13403 if (isBlockFormat(format) && isEq$3(node, format.block)) {
13404 return true;
13405 }
13406 if (isSelectorFormat(format)) {
13407 return isElement$6(node) && dom.is(node, format.selector);
13408 }
13409 return false;
13410 };
13411 const matchItems = (dom, node, format, itemName, similar, vars) => {
13412 const items = format[itemName];
13413 const matchAttributes = itemName === 'attributes';
13414 if (isFunction(format.onmatch)) {
13415 return format.onmatch(node, format, itemName);
13416 }
13417 if (items) {
13418 if (!isArrayLike(items)) {
13419 for (const key in items) {
13420 if (has$2(items, key)) {
13421 const value = matchAttributes ? dom.getAttrib(node, key) : getStyle(dom, node, key);
13422 const expectedValue = replaceVars(items[key], vars);
13423 const isEmptyValue = isNullable(value) || isEmpty$3(value);
13424 if (isEmptyValue && isNullable(expectedValue)) {
13425 continue;
13426 }
13427 if (similar && isEmptyValue && !format.exact) {
13428 return false;
13429 }
13430 if ((!similar || format.exact) && !isEq$3(value, normalizeStyleValue(expectedValue, key))) {
13431 return false;
13432 }
13433 }
13434 }
13435 } else {
13436 for (let i = 0; i < items.length; i++) {
13437 if (matchAttributes ? dom.getAttrib(node, items[i]) : getStyle(dom, node, items[i])) {
13438 return true;
13439 }
13440 }
13441 }
13442 }
13443 return true;
13444 };
13445 const matchNode = (ed, node, name, vars, similar) => {
13446 const formatList = ed.formatter.get(name);
13447 const dom = ed.dom;
13448 if (formatList && isElement$6(node)) {
13449 for (let i = 0; i < formatList.length; i++) {
13450 const format = formatList[i];
13451 if (matchName(ed.dom, node, format) && matchItems(dom, node, format, 'attributes', similar, vars) && matchItems(dom, node, format, 'styles', similar, vars)) {
13452 const classes = format.classes;
13453 if (classes) {
13454 for (let x = 0; x < classes.length; x++) {
13455 if (!ed.dom.hasClass(node, replaceVars(classes[x], vars))) {
13456 return;
13457 }
13458 }
13459 }
13460 return format;
13461 }
13462 }
13463 }
13464 return undefined;
13465 };
13466 const match$2 = (editor, name, vars, node, similar) => {
13467 if (node) {
13468 return matchParents(editor, node, name, vars, similar);
13469 }
13470 node = editor.selection.getNode();
13471 if (matchParents(editor, node, name, vars, similar)) {
13472 return true;
13473 }
13474 const startNode = editor.selection.getStart();
13475 if (startNode !== node) {
13476 if (matchParents(editor, startNode, name, vars, similar)) {
13477 return true;
13478 }
13479 }
13480 return false;
13481 };
13482 const matchAll = (editor, names, vars) => {
13483 const matchedFormatNames = [];
13484 const checkedMap = {};
13485 const startElement = editor.selection.getStart();
13486 editor.dom.getParent(startElement, node => {
13487 for (let i = 0; i < names.length; i++) {
13488 const name = names[i];
13489 if (!checkedMap[name] && matchNode(editor, node, name, vars)) {
13490 checkedMap[name] = true;
13491 matchedFormatNames.push(name);
13492 }
13493 }
13494 }, editor.dom.getRoot());
13495 return matchedFormatNames;
13496 };
13497 const closest = (editor, names) => {
13498 const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
13499 const match = (elm, name) => matchNode(editor, elm.dom, name) ? Optional.some(name) : Optional.none();
13500 return Optional.from(editor.selection.getStart(true)).bind(rawElm => closest$1(SugarElement.fromDom(rawElm), elm => findMap(names, name => match(elm, name)), isRoot)).getOrNull();
13501 };
13502 const canApply = (editor, name) => {
13503 const formatList = editor.formatter.get(name);
13504 const dom = editor.dom;
13505 if (formatList && editor.selection.isEditable()) {
13506 const startNode = editor.selection.getStart();
13507 const parents = getParents$2(dom, startNode);
13508 for (let x = formatList.length - 1; x >= 0; x--) {
13509 const format = formatList[x];
13510 if (!isSelectorFormat(format)) {
13511 return true;
13512 }
13513 for (let i = parents.length - 1; i >= 0; i--) {
13514 if (dom.is(parents[i], format.selector)) {
13515 return true;
13516 }
13517 }
13518 }
13519 }
13520 return false;
13521 };
13522 const matchAllOnNode = (editor, node, formatNames) => foldl(formatNames, (acc, name) => {
13523 const matchSimilar = isVariableFormatName(editor, name);
13524 if (editor.formatter.matchNode(node, name, {}, matchSimilar)) {
13525 return acc.concat([name]);
13526 } else {
13527 return acc;
13528 }
13529 }, []);
13530
13531 const ZWSP = ZWSP$1;
13532 const importNode = (ownerDocument, node) => {
13533 return ownerDocument.importNode(node, true);
13534 };
13535 const findFirstTextNode = node => {
13536 if (node) {
13537 const walker = new DomTreeWalker(node, node);
13538 for (let tempNode = walker.current(); tempNode; tempNode = walker.next()) {
13539 if (isText$b(tempNode)) {
13540 return tempNode;
13541 }
13542 }
13543 }
13544 return null;
13545 };
13546 const createCaretContainer = fill => {
13547 const caretContainer = SugarElement.fromTag('span');
13548 setAll$1(caretContainer, {
13549 'id': CARET_ID,
13550 'data-mce-bogus': '1',
13551 'data-mce-type': 'format-caret'
13552 });
13553 if (fill) {
13554 append$1(caretContainer, SugarElement.fromText(ZWSP));
13555 }
13556 return caretContainer;
13557 };
13558 const trimZwspFromCaretContainer = caretContainerNode => {
13559 const textNode = findFirstTextNode(caretContainerNode);
13560 if (textNode && textNode.data.charAt(0) === ZWSP) {
13561 textNode.deleteData(0, 1);
13562 }
13563 return textNode;
13564 };
13565 const removeCaretContainerNode = (editor, node, moveCaret) => {
13566 const dom = editor.dom, selection = editor.selection;
13567 if (isCaretContainerEmpty(node)) {
13568 deleteElement$2(editor, false, SugarElement.fromDom(node), moveCaret, true);
13569 } else {
13570 const rng = selection.getRng();
13571 const block = dom.getParent(node, dom.isBlock);
13572 const startContainer = rng.startContainer;
13573 const startOffset = rng.startOffset;
13574 const endContainer = rng.endContainer;
13575 const endOffset = rng.endOffset;
13576 const textNode = trimZwspFromCaretContainer(node);
13577 dom.remove(node, true);
13578 if (startContainer === textNode && startOffset > 0) {
13579 rng.setStart(textNode, startOffset - 1);
13580 }
13581 if (endContainer === textNode && endOffset > 0) {
13582 rng.setEnd(textNode, endOffset - 1);
13583 }
13584 if (block && dom.isEmpty(block)) {
13585 fillWithPaddingBr(SugarElement.fromDom(block));
13586 }
13587 selection.setRng(rng);
13588 }
13589 };
13590 const removeCaretContainer = (editor, node, moveCaret) => {
13591 const dom = editor.dom, selection = editor.selection;
13592 if (!node) {
13593 node = getParentCaretContainer(editor.getBody(), selection.getStart());
13594 if (!node) {
13595 while (node = dom.get(CARET_ID)) {
13596 removeCaretContainerNode(editor, node, moveCaret);
13597 }
13598 }
13599 } else {
13600 removeCaretContainerNode(editor, node, moveCaret);
13601 }
13602 };
13603 const insertCaretContainerNode = (editor, caretContainer, formatNode) => {
13604 var _a, _b;
13605 const dom = editor.dom;
13606 const block = dom.getParent(formatNode, curry(isTextBlock$1, editor.schema));
13607 if (block && dom.isEmpty(block)) {
13608 (_a = formatNode.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(caretContainer, formatNode);
13609 } else {
13610 removeTrailingBr(SugarElement.fromDom(formatNode));
13611 if (dom.isEmpty(formatNode)) {
13612 (_b = formatNode.parentNode) === null || _b === void 0 ? void 0 : _b.replaceChild(caretContainer, formatNode);
13613 } else {
13614 dom.insertAfter(caretContainer, formatNode);
13615 }
13616 }
13617 };
13618 const appendNode = (parentNode, node) => {
13619 parentNode.appendChild(node);
13620 return node;
13621 };
13622 const insertFormatNodesIntoCaretContainer = (formatNodes, caretContainer) => {
13623 var _a;
13624 const innerMostFormatNode = foldr(formatNodes, (parentNode, formatNode) => {
13625 return appendNode(parentNode, formatNode.cloneNode(false));
13626 }, caretContainer);
13627 const doc = (_a = innerMostFormatNode.ownerDocument) !== null && _a !== void 0 ? _a : document;
13628 return appendNode(innerMostFormatNode, doc.createTextNode(ZWSP));
13629 };
13630 const cleanFormatNode = (editor, caretContainer, formatNode, name, vars, similar) => {
13631 const formatter = editor.formatter;
13632 const dom = editor.dom;
13633 const validFormats = filter$5(keys(formatter.get()), formatName => formatName !== name && !contains$1(formatName, 'removeformat'));
13634 const matchedFormats = matchAllOnNode(editor, formatNode, validFormats);
13635 const uniqueFormats = filter$5(matchedFormats, fmtName => !areSimilarFormats(editor, fmtName, name));
13636 if (uniqueFormats.length > 0) {
13637 const clonedFormatNode = formatNode.cloneNode(false);
13638 dom.add(caretContainer, clonedFormatNode);
13639 formatter.remove(name, vars, clonedFormatNode, similar);
13640 dom.remove(clonedFormatNode);
13641 return Optional.some(clonedFormatNode);
13642 } else {
13643 return Optional.none();
13644 }
13645 };
13646 const applyCaretFormat = (editor, name, vars) => {
13647 let caretContainer;
13648 const selection = editor.selection;
13649 const formatList = editor.formatter.get(name);
13650 if (!formatList) {
13651 return;
13652 }
13653 const selectionRng = selection.getRng();
13654 let offset = selectionRng.startOffset;
13655 const container = selectionRng.startContainer;
13656 const text = container.nodeValue;
13657 caretContainer = getParentCaretContainer(editor.getBody(), selection.getStart());
13658 const wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
13659 if (text && offset > 0 && offset < text.length && wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) {
13660 const bookmark = selection.getBookmark();
13661 selectionRng.collapse(true);
13662 let rng = expandRng(editor.dom, selectionRng, formatList);
13663 rng = split(rng);
13664 editor.formatter.apply(name, vars, rng);
13665 selection.moveToBookmark(bookmark);
13666 } else {
13667 let textNode = caretContainer ? findFirstTextNode(caretContainer) : null;
13668 if (!caretContainer || (textNode === null || textNode === void 0 ? void 0 : textNode.data) !== ZWSP) {
13669 caretContainer = importNode(editor.getDoc(), createCaretContainer(true).dom);
13670 textNode = caretContainer.firstChild;
13671 selectionRng.insertNode(caretContainer);
13672 offset = 1;
13673 editor.formatter.apply(name, vars, caretContainer);
13674 } else {
13675 editor.formatter.apply(name, vars, caretContainer);
13676 }
13677 selection.setCursorLocation(textNode, offset);
13678 }
13679 };
13680 const removeCaretFormat = (editor, name, vars, similar) => {
13681 const dom = editor.dom;
13682 const selection = editor.selection;
13683 let hasContentAfter = false;
13684 const formatList = editor.formatter.get(name);
13685 if (!formatList) {
13686 return;
13687 }
13688 const rng = selection.getRng();
13689 const container = rng.startContainer;
13690 const offset = rng.startOffset;
13691 let node = container;
13692 if (isText$b(container)) {
13693 if (offset !== container.data.length) {
13694 hasContentAfter = true;
13695 }
13696 node = node.parentNode;
13697 }
13698 const parents = [];
13699 let formatNode;
13700 while (node) {
13701 if (matchNode(editor, node, name, vars, similar)) {
13702 formatNode = node;
13703 break;
13704 }
13705 if (node.nextSibling) {
13706 hasContentAfter = true;
13707 }
13708 parents.push(node);
13709 node = node.parentNode;
13710 }
13711 if (!formatNode) {
13712 return;
13713 }
13714 if (hasContentAfter) {
13715 const bookmark = selection.getBookmark();
13716 rng.collapse(true);
13717 let expandedRng = expandRng(dom, rng, formatList, true);
13718 expandedRng = split(expandedRng);
13719 editor.formatter.remove(name, vars, expandedRng, similar);
13720 selection.moveToBookmark(bookmark);
13721 } else {
13722 const caretContainer = getParentCaretContainer(editor.getBody(), formatNode);
13723 const parentsAfter = isNonNullable(caretContainer) ? dom.getParents(formatNode.parentNode, always, caretContainer) : [];
13724 const newCaretContainer = createCaretContainer(false).dom;
13725 insertCaretContainerNode(editor, newCaretContainer, caretContainer !== null && caretContainer !== void 0 ? caretContainer : formatNode);
13726 const cleanedFormatNode = cleanFormatNode(editor, newCaretContainer, formatNode, name, vars, similar);
13727 const caretTextNode = insertFormatNodesIntoCaretContainer([
13728 ...parents,
13729 ...cleanedFormatNode.toArray(),
13730 ...parentsAfter
13731 ], newCaretContainer);
13732 if (caretContainer) {
13733 removeCaretContainerNode(editor, caretContainer, isNonNullable(caretContainer));
13734 }
13735 selection.setCursorLocation(caretTextNode, 1);
13736 if (dom.isEmpty(formatNode)) {
13737 dom.remove(formatNode);
13738 }
13739 }
13740 };
13741 const disableCaretContainer = (editor, keyCode, moveCaret) => {
13742 const selection = editor.selection, body = editor.getBody();
13743 removeCaretContainer(editor, null, moveCaret);
13744 if ((keyCode === 8 || keyCode === 46) && selection.isCollapsed() && selection.getStart().innerHTML === ZWSP) {
13745 removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()), true);
13746 }
13747 if (keyCode === 37 || keyCode === 39) {
13748 removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()), true);
13749 }
13750 };
13751 const endsWithNbsp = element => isText$b(element) && endsWith(element.data, nbsp);
13752 const setup$v = editor => {
13753 editor.on('mouseup keydown', e => {
13754 disableCaretContainer(editor, e.keyCode, endsWithNbsp(editor.selection.getRng().endContainer));
13755 });
13756 };
13757 const createCaretFormat = formatNodes => {
13758 const caretContainer = createCaretContainer(false);
13759 const innerMost = insertFormatNodesIntoCaretContainer(formatNodes, caretContainer.dom);
13760 return {
13761 caretContainer,
13762 caretPosition: CaretPosition(innerMost, 0)
13763 };
13764 };
13765 const replaceWithCaretFormat = (targetNode, formatNodes) => {
13766 const {caretContainer, caretPosition} = createCaretFormat(formatNodes);
13767 before$3(SugarElement.fromDom(targetNode), caretContainer);
13768 remove$4(SugarElement.fromDom(targetNode));
13769 return caretPosition;
13770 };
13771 const createCaretFormatAtStart$1 = (rng, formatNodes) => {
13772 const {caretContainer, caretPosition} = createCaretFormat(formatNodes);
13773 rng.insertNode(caretContainer.dom);
13774 return caretPosition;
13775 };
13776 const isFormatElement = (editor, element) => {
13777 if (isCaretNode(element.dom)) {
13778 return false;
13779 }
13780 const inlineElements = editor.schema.getTextInlineElements();
13781 return has$2(inlineElements, name(element)) && !isCaretNode(element.dom) && !isBogus$1(element.dom);
13782 };
13783
13784 const postProcessHooks = {};
13785 const isPre = matchNodeNames(['pre']);
13786 const addPostProcessHook = (name, hook) => {
13787 const hooks = postProcessHooks[name];
13788 if (!hooks) {
13789 postProcessHooks[name] = [];
13790 }
13791 postProcessHooks[name].push(hook);
13792 };
13793 const postProcess$1 = (name, editor) => {
13794 if (has$2(postProcessHooks, name)) {
13795 each$e(postProcessHooks[name], hook => {
13796 hook(editor);
13797 });
13798 }
13799 };
13800 addPostProcessHook('pre', editor => {
13801 const rng = editor.selection.getRng();
13802 const hasPreSibling = blocks => pre => {
13803 const prev = pre.previousSibling;
13804 return isPre(prev) && contains$2(blocks, prev);
13805 };
13806 const joinPre = (pre1, pre2) => {
13807 const sPre2 = SugarElement.fromDom(pre2);
13808 const doc = documentOrOwner(sPre2).dom;
13809 remove$4(sPre2);
13810 append(SugarElement.fromDom(pre1), [
13811 SugarElement.fromTag('br', doc),
13812 SugarElement.fromTag('br', doc),
13813 ...children$1(sPre2)
13814 ]);
13815 };
13816 if (!rng.collapsed) {
13817 const blocks = editor.selection.getSelectedBlocks();
13818 const preBlocks = filter$5(filter$5(blocks, isPre), hasPreSibling(blocks));
13819 each$e(preBlocks, pre => {
13820 joinPre(pre.previousSibling, pre);
13821 });
13822 }
13823 });
13824
13825 const listItemStyles = [
13826 'fontWeight',
13827 'fontStyle',
13828 'color',
13829 'fontSize',
13830 'fontFamily'
13831 ];
13832 const hasListStyles = fmt => isObject(fmt.styles) && exists(keys(fmt.styles), name => contains$2(listItemStyles, name));
13833 const findExpandedListItemFormat = formats => find$2(formats, fmt => isInlineFormat(fmt) && fmt.inline === 'span' && hasListStyles(fmt));
13834 const getExpandedListItemFormat = (formatter, format) => {
13835 const formatList = formatter.get(format);
13836 return isArray$1(formatList) ? findExpandedListItemFormat(formatList) : Optional.none();
13837 };
13838 const isRngStartAtStartOfElement = (rng, elm) => prevPosition(elm, CaretPosition.fromRangeStart(rng)).isNone();
13839 const isRngEndAtEndOfElement = (rng, elm) => {
13840 return nextPosition(elm, CaretPosition.fromRangeEnd(rng)).exists(pos => !isBr$6(pos.getNode()) || nextPosition(elm, pos).isSome()) === false;
13841 };
13842 const isEditableListItem = dom => elm => isListItem$2(elm) && dom.isEditable(elm);
13843 const getFullySelectedBlocks = selection => {
13844 const blocks = selection.getSelectedBlocks();
13845 const rng = selection.getRng();
13846 if (selection.isCollapsed()) {
13847 return [];
13848 }
13849 if (blocks.length === 1) {
13850 return isRngStartAtStartOfElement(rng, blocks[0]) && isRngEndAtEndOfElement(rng, blocks[0]) ? blocks : [];
13851 } else {
13852 const first = head(blocks).filter(elm => isRngStartAtStartOfElement(rng, elm)).toArray();
13853 const last = last$2(blocks).filter(elm => isRngEndAtEndOfElement(rng, elm)).toArray();
13854 const middle = blocks.slice(1, -1);
13855 return first.concat(middle).concat(last);
13856 }
13857 };
13858 const getFullySelectedListItems = selection => filter$5(getFullySelectedBlocks(selection), isEditableListItem(selection.dom));
13859 const getPartiallySelectedListItems = selection => filter$5(selection.getSelectedBlocks(), isEditableListItem(selection.dom));
13860
13861 const each$8 = Tools.each;
13862 const isElementNode = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node);
13863 const findElementSibling = (node, siblingName) => {
13864 for (let sibling = node; sibling; sibling = sibling[siblingName]) {
13865 if (isText$b(sibling) && isNotEmpty(sibling.data)) {
13866 return node;
13867 }
13868 if (isElement$6(sibling) && !isBookmarkNode$1(sibling)) {
13869 return sibling;
13870 }
13871 }
13872 return node;
13873 };
13874 const mergeSiblingsNodes = (editor, prev, next) => {
13875 const elementUtils = ElementUtils(editor);
13876 const isPrevEditable = isHTMLElement(prev) && editor.dom.isEditable(prev);
13877 const isNextEditable = isHTMLElement(next) && editor.dom.isEditable(next);
13878 if (isPrevEditable && isNextEditable) {
13879 const prevSibling = findElementSibling(prev, 'previousSibling');
13880 const nextSibling = findElementSibling(next, 'nextSibling');
13881 if (elementUtils.compare(prevSibling, nextSibling)) {
13882 for (let sibling = prevSibling.nextSibling; sibling && sibling !== nextSibling;) {
13883 const tmpSibling = sibling;
13884 sibling = sibling.nextSibling;
13885 prevSibling.appendChild(tmpSibling);
13886 }
13887 editor.dom.remove(nextSibling);
13888 Tools.each(Tools.grep(nextSibling.childNodes), node => {
13889 prevSibling.appendChild(node);
13890 });
13891 return prevSibling;
13892 }
13893 }
13894 return next;
13895 };
13896 const mergeSiblings = (editor, format, vars, node) => {
13897 var _a;
13898 if (node && format.merge_siblings !== false) {
13899 const newNode = (_a = mergeSiblingsNodes(editor, getNonWhiteSpaceSibling(node), node)) !== null && _a !== void 0 ? _a : node;
13900 mergeSiblingsNodes(editor, newNode, getNonWhiteSpaceSibling(newNode, true));
13901 }
13902 };
13903 const clearChildStyles = (dom, format, node) => {
13904 if (format.clear_child_styles) {
13905 const selector = format.links ? '*:not(a)' : '*';
13906 each$8(dom.select(selector, node), childNode => {
13907 if (isElementNode(childNode) && dom.isEditable(childNode)) {
13908 each$8(format.styles, (_value, name) => {
13909 dom.setStyle(childNode, name, '');
13910 });
13911 }
13912 });
13913 }
13914 };
13915 const processChildElements = (node, filter, process) => {
13916 each$8(node.childNodes, node => {
13917 if (isElementNode(node)) {
13918 if (filter(node)) {
13919 process(node);
13920 }
13921 if (node.hasChildNodes()) {
13922 processChildElements(node, filter, process);
13923 }
13924 }
13925 });
13926 };
13927 const unwrapEmptySpan = (dom, node) => {
13928 if (node.nodeName === 'SPAN' && dom.getAttribs(node).length === 0) {
13929 dom.remove(node, true);
13930 }
13931 };
13932 const hasStyle = (dom, name) => node => !!(node && getStyle(dom, node, name));
13933 const applyStyle = (dom, name, value) => node => {
13934 dom.setStyle(node, name, value);
13935 if (node.getAttribute('style') === '') {
13936 node.removeAttribute('style');
13937 }
13938 unwrapEmptySpan(dom, node);
13939 };
13940
13941 const removeResult = Adt.generate([
13942 { keep: [] },
13943 { rename: ['name'] },
13944 { removed: [] }
13945 ]);
13946 const MCE_ATTR_RE = /^(src|href|style)$/;
13947 const each$7 = Tools.each;
13948 const isEq$2 = isEq$5;
13949 const isTableCellOrRow = node => /^(TR|TH|TD)$/.test(node.nodeName);
13950 const isChildOfInlineParent = (dom, node, parent) => dom.isChildOf(node, parent) && node !== parent && !dom.isBlock(parent);
13951 const getContainer = (ed, rng, start) => {
13952 let container = rng[start ? 'startContainer' : 'endContainer'];
13953 let offset = rng[start ? 'startOffset' : 'endOffset'];
13954 if (isElement$6(container)) {
13955 const lastIdx = container.childNodes.length - 1;
13956 if (!start && offset) {
13957 offset--;
13958 }
13959 container = container.childNodes[offset > lastIdx ? lastIdx : offset];
13960 }
13961 if (isText$b(container) && start && offset >= container.data.length) {
13962 container = new DomTreeWalker(container, ed.getBody()).next() || container;
13963 }
13964 if (isText$b(container) && !start && offset === 0) {
13965 container = new DomTreeWalker(container, ed.getBody()).prev() || container;
13966 }
13967 return container;
13968 };
13969 const normalizeTableSelection = (node, start) => {
13970 const prop = start ? 'firstChild' : 'lastChild';
13971 const childNode = node[prop];
13972 if (isTableCellOrRow(node) && childNode) {
13973 if (node.nodeName === 'TR') {
13974 return childNode[prop] || childNode;
13975 } else {
13976 return childNode;
13977 }
13978 }
13979 return node;
13980 };
13981 const wrap$1 = (dom, node, name, attrs) => {
13982 var _a;
13983 const wrapper = dom.create(name, attrs);
13984 (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(wrapper, node);
13985 wrapper.appendChild(node);
13986 return wrapper;
13987 };
13988 const wrapWithSiblings = (dom, node, next, name, attrs) => {
13989 const start = SugarElement.fromDom(node);
13990 const wrapper = SugarElement.fromDom(dom.create(name, attrs));
13991 const siblings = next ? nextSiblings(start) : prevSiblings(start);
13992 append(wrapper, siblings);
13993 if (next) {
13994 before$3(start, wrapper);
13995 prepend(wrapper, start);
13996 } else {
13997 after$4(start, wrapper);
13998 append$1(wrapper, start);
13999 }
14000 return wrapper.dom;
14001 };
14002 const isColorFormatAndAnchor = (node, format) => format.links && node.nodeName === 'A';
14003 const removeNode = (ed, node, format) => {
14004 const parentNode = node.parentNode;
14005 let rootBlockElm;
14006 const dom = ed.dom;
14007 const forcedRootBlock = getForcedRootBlock(ed);
14008 if (isBlockFormat(format)) {
14009 if (parentNode === dom.getRoot()) {
14010 if (!format.list_block || !isEq$2(node, format.list_block)) {
14011 each$e(from(node.childNodes), node => {
14012 if (isValid(ed, forcedRootBlock, node.nodeName.toLowerCase())) {
14013 if (!rootBlockElm) {
14014 rootBlockElm = wrap$1(dom, node, forcedRootBlock);
14015 dom.setAttribs(rootBlockElm, getForcedRootBlockAttrs(ed));
14016 } else {
14017 rootBlockElm.appendChild(node);
14018 }
14019 } else {
14020 rootBlockElm = null;
14021 }
14022 });
14023 }
14024 }
14025 }
14026 if (isMixedFormat(format) && !isEq$2(format.inline, node)) {
14027 return;
14028 }
14029 dom.remove(node, true);
14030 };
14031 const processFormatAttrOrStyle = (name, value, vars) => {
14032 if (isNumber(name)) {
14033 return {
14034 name: value,
14035 value: null
14036 };
14037 } else {
14038 return {
14039 name,
14040 value: replaceVars(value, vars)
14041 };
14042 }
14043 };
14044 const removeEmptyStyleAttributeIfNeeded = (dom, elm) => {
14045 if (dom.getAttrib(elm, 'style') === '') {
14046 elm.removeAttribute('style');
14047 elm.removeAttribute('data-mce-style');
14048 }
14049 };
14050 const removeStyles = (dom, elm, format, vars, compareNode) => {
14051 let stylesModified = false;
14052 each$7(format.styles, (value, name) => {
14053 const {
14054 name: styleName,
14055 value: styleValue
14056 } = processFormatAttrOrStyle(name, value, vars);
14057 const normalizedStyleValue = normalizeStyleValue(styleValue, styleName);
14058 if (format.remove_similar || isNull(styleValue) || !isElement$6(compareNode) || isEq$2(getStyle(dom, compareNode, styleName), normalizedStyleValue)) {
14059 dom.setStyle(elm, styleName, '');
14060 }
14061 stylesModified = true;
14062 });
14063 if (stylesModified) {
14064 removeEmptyStyleAttributeIfNeeded(dom, elm);
14065 }
14066 };
14067 const removeListStyleFormats = (editor, name, vars) => {
14068 if (name === 'removeformat') {
14069 each$e(getPartiallySelectedListItems(editor.selection), li => {
14070 each$e(listItemStyles, name => editor.dom.setStyle(li, name, ''));
14071 removeEmptyStyleAttributeIfNeeded(editor.dom, li);
14072 });
14073 } else {
14074 getExpandedListItemFormat(editor.formatter, name).each(liFmt => {
14075 each$e(getPartiallySelectedListItems(editor.selection), li => removeStyles(editor.dom, li, liFmt, vars, null));
14076 });
14077 }
14078 };
14079 const removeNodeFormatInternal = (ed, format, vars, node, compareNode) => {
14080 const dom = ed.dom;
14081 const elementUtils = ElementUtils(ed);
14082 const schema = ed.schema;
14083 if (isInlineFormat(format) && isTransparentElementName(schema, format.inline) && isTransparentBlock(schema, node) && node.parentElement === ed.getBody()) {
14084 removeNode(ed, node, format);
14085 return removeResult.removed();
14086 }
14087 if (!format.ceFalseOverride && node && dom.getContentEditableParent(node) === 'false') {
14088 return removeResult.keep();
14089 }
14090 if (node && !matchName(dom, node, format) && !isColorFormatAndAnchor(node, format)) {
14091 return removeResult.keep();
14092 }
14093 const elm = node;
14094 const preserveAttributes = format.preserve_attributes;
14095 if (isInlineFormat(format) && format.remove === 'all' && isArray$1(preserveAttributes)) {
14096 const attrsToPreserve = filter$5(dom.getAttribs(elm), attr => contains$2(preserveAttributes, attr.name.toLowerCase()));
14097 dom.removeAllAttribs(elm);
14098 each$e(attrsToPreserve, attr => dom.setAttrib(elm, attr.name, attr.value));
14099 if (attrsToPreserve.length > 0) {
14100 return removeResult.rename('span');
14101 }
14102 }
14103 if (format.remove !== 'all') {
14104 removeStyles(dom, elm, format, vars, compareNode);
14105 each$7(format.attributes, (value, name) => {
14106 const {
14107 name: attrName,
14108 value: attrValue
14109 } = processFormatAttrOrStyle(name, value, vars);
14110 if (format.remove_similar || isNull(attrValue) || !isElement$6(compareNode) || isEq$2(dom.getAttrib(compareNode, attrName), attrValue)) {
14111 if (attrName === 'class') {
14112 const currentValue = dom.getAttrib(elm, attrName);
14113 if (currentValue) {
14114 let valueOut = '';
14115 each$e(currentValue.split(/\s+/), cls => {
14116 if (/mce\-\w+/.test(cls)) {
14117 valueOut += (valueOut ? ' ' : '') + cls;
14118 }
14119 });
14120 if (valueOut) {
14121 dom.setAttrib(elm, attrName, valueOut);
14122 return;
14123 }
14124 }
14125 }
14126 if (MCE_ATTR_RE.test(attrName)) {
14127 elm.removeAttribute('data-mce-' + attrName);
14128 }
14129 if (attrName === 'style' && matchNodeNames(['li'])(elm) && dom.getStyle(elm, 'list-style-type') === 'none') {
14130 elm.removeAttribute(attrName);
14131 dom.setStyle(elm, 'list-style-type', 'none');
14132 return;
14133 }
14134 if (attrName === 'class') {
14135 elm.removeAttribute('className');
14136 }
14137 elm.removeAttribute(attrName);
14138 }
14139 });
14140 each$7(format.classes, value => {
14141 value = replaceVars(value, vars);
14142 if (!isElement$6(compareNode) || dom.hasClass(compareNode, value)) {
14143 dom.removeClass(elm, value);
14144 }
14145 });
14146 const attrs = dom.getAttribs(elm);
14147 for (let i = 0; i < attrs.length; i++) {
14148 const attrName = attrs[i].nodeName;
14149 if (!elementUtils.isAttributeInternal(attrName)) {
14150 return removeResult.keep();
14151 }
14152 }
14153 }
14154 if (format.remove !== 'none') {
14155 removeNode(ed, elm, format);
14156 return removeResult.removed();
14157 }
14158 return removeResult.keep();
14159 };
14160 const findFormatRoot = (editor, container, name, vars, similar) => {
14161 let formatRoot;
14162 if (container.parentNode) {
14163 each$e(getParents$2(editor.dom, container.parentNode).reverse(), parent => {
14164 if (!formatRoot && isElement$6(parent) && parent.id !== '_start' && parent.id !== '_end') {
14165 const format = matchNode(editor, parent, name, vars, similar);
14166 if (format && format.split !== false) {
14167 formatRoot = parent;
14168 }
14169 }
14170 });
14171 }
14172 return formatRoot;
14173 };
14174 const removeNodeFormatFromClone = (editor, format, vars, clone) => removeNodeFormatInternal(editor, format, vars, clone, clone).fold(constant(clone), newName => {
14175 const fragment = editor.dom.createFragment();
14176 fragment.appendChild(clone);
14177 return editor.dom.rename(clone, newName);
14178 }, constant(null));
14179 const wrapAndSplit = (editor, formatList, formatRoot, container, target, split, format, vars) => {
14180 var _a, _b;
14181 let lastClone;
14182 let firstClone;
14183 const dom = editor.dom;
14184 if (formatRoot) {
14185 const formatRootParent = formatRoot.parentNode;
14186 for (let parent = container.parentNode; parent && parent !== formatRootParent; parent = parent.parentNode) {
14187 let clone = dom.clone(parent, false);
14188 for (let i = 0; i < formatList.length; i++) {
14189 clone = removeNodeFormatFromClone(editor, formatList[i], vars, clone);
14190 if (clone === null) {
14191 break;
14192 }
14193 }
14194 if (clone) {
14195 if (lastClone) {
14196 clone.appendChild(lastClone);
14197 }
14198 if (!firstClone) {
14199 firstClone = clone;
14200 }
14201 lastClone = clone;
14202 }
14203 }
14204 if (split && (!format.mixed || !dom.isBlock(formatRoot))) {
14205 container = (_a = dom.split(formatRoot, container)) !== null && _a !== void 0 ? _a : container;
14206 }
14207 if (lastClone && firstClone) {
14208 (_b = target.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(lastClone, target);
14209 firstClone.appendChild(target);
14210 if (isInlineFormat(format)) {
14211 mergeSiblings(editor, format, vars, lastClone);
14212 }
14213 }
14214 }
14215 return container;
14216 };
14217 const removeFormatInternal = (ed, name, vars, node, similar) => {
14218 const formatList = ed.formatter.get(name);
14219 const format = formatList[0];
14220 const dom = ed.dom;
14221 const selection = ed.selection;
14222 const splitToFormatRoot = container => {
14223 const formatRoot = findFormatRoot(ed, container, name, vars, similar);
14224 return wrapAndSplit(ed, formatList, formatRoot, container, container, true, format, vars);
14225 };
14226 const isRemoveBookmarkNode = node => isBookmarkNode$1(node) && isElement$6(node) && (node.id === '_start' || node.id === '_end');
14227 const removeFormatOnNode = node => exists(formatList, fmt => removeNodeFormat(ed, fmt, vars, node, node));
14228 const process = node => {
14229 const children = from(node.childNodes);
14230 const removed = removeFormatOnNode(node);
14231 const currentNodeMatches = removed || exists(formatList, f => matchName(dom, node, f));
14232 const parentNode = node.parentNode;
14233 if (!currentNodeMatches && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
14234 removeFormatOnNode(parentNode);
14235 }
14236 if (format.deep) {
14237 if (children.length) {
14238 for (let i = 0; i < children.length; i++) {
14239 process(children[i]);
14240 }
14241 }
14242 }
14243 const textDecorations = [
14244 'underline',
14245 'line-through',
14246 'overline'
14247 ];
14248 each$e(textDecorations, decoration => {
14249 if (isElement$6(node) && ed.dom.getStyle(node, 'text-decoration') === decoration && node.parentNode && getTextDecoration(dom, node.parentNode) === decoration) {
14250 removeNodeFormat(ed, {
14251 deep: false,
14252 exact: true,
14253 inline: 'span',
14254 styles: { textDecoration: decoration }
14255 }, undefined, node);
14256 }
14257 });
14258 };
14259 const unwrap = start => {
14260 const node = dom.get(start ? '_start' : '_end');
14261 if (node) {
14262 let out = node[start ? 'firstChild' : 'lastChild'];
14263 if (isRemoveBookmarkNode(out)) {
14264 out = out[start ? 'firstChild' : 'lastChild'];
14265 }
14266 if (isText$b(out) && out.data.length === 0) {
14267 out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling;
14268 }
14269 dom.remove(node, true);
14270 return out;
14271 } else {
14272 return null;
14273 }
14274 };
14275 const removeRngStyle = rng => {
14276 let startContainer;
14277 let endContainer;
14278 let expandedRng = expandRng(dom, rng, formatList, rng.collapsed);
14279 if (format.split) {
14280 expandedRng = split(expandedRng);
14281 startContainer = getContainer(ed, expandedRng, true);
14282 endContainer = getContainer(ed, expandedRng);
14283 if (startContainer !== endContainer) {
14284 startContainer = normalizeTableSelection(startContainer, true);
14285 endContainer = normalizeTableSelection(endContainer, false);
14286 if (isChildOfInlineParent(dom, startContainer, endContainer)) {
14287 const marker = Optional.from(startContainer.firstChild).getOr(startContainer);
14288 splitToFormatRoot(wrapWithSiblings(dom, marker, true, 'span', {
14289 'id': '_start',
14290 'data-mce-type': 'bookmark'
14291 }));
14292 unwrap(true);
14293 return;
14294 }
14295 if (isChildOfInlineParent(dom, endContainer, startContainer)) {
14296 const marker = Optional.from(endContainer.lastChild).getOr(endContainer);
14297 splitToFormatRoot(wrapWithSiblings(dom, marker, false, 'span', {
14298 'id': '_end',
14299 'data-mce-type': 'bookmark'
14300 }));
14301 unwrap(false);
14302 return;
14303 }
14304 startContainer = wrap$1(dom, startContainer, 'span', {
14305 'id': '_start',
14306 'data-mce-type': 'bookmark'
14307 });
14308 endContainer = wrap$1(dom, endContainer, 'span', {
14309 'id': '_end',
14310 'data-mce-type': 'bookmark'
14311 });
14312 const newRng = dom.createRng();
14313 newRng.setStartAfter(startContainer);
14314 newRng.setEndBefore(endContainer);
14315 walk$3(dom, newRng, nodes => {
14316 each$e(nodes, n => {
14317 if (!isBookmarkNode$1(n) && !isBookmarkNode$1(n.parentNode)) {
14318 splitToFormatRoot(n);
14319 }
14320 });
14321 });
14322 splitToFormatRoot(startContainer);
14323 splitToFormatRoot(endContainer);
14324 startContainer = unwrap(true);
14325 endContainer = unwrap();
14326 } else {
14327 startContainer = endContainer = splitToFormatRoot(startContainer);
14328 }
14329 expandedRng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
14330 expandedRng.startOffset = dom.nodeIndex(startContainer);
14331 expandedRng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
14332 expandedRng.endOffset = dom.nodeIndex(endContainer) + 1;
14333 }
14334 walk$3(dom, expandedRng, nodes => {
14335 each$e(nodes, process);
14336 });
14337 };
14338 if (node) {
14339 if (isNode(node)) {
14340 const rng = dom.createRng();
14341 rng.setStartBefore(node);
14342 rng.setEndAfter(node);
14343 removeRngStyle(rng);
14344 } else {
14345 removeRngStyle(node);
14346 }
14347 fireFormatRemove(ed, name, node, vars);
14348 return;
14349 }
14350 if (!selection.isCollapsed() || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
14351 preserveSelection(ed, () => runOnRanges(ed, removeRngStyle), startNode => isInlineFormat(format) && match$2(ed, name, vars, startNode));
14352 ed.nodeChanged();
14353 } else {
14354 removeCaretFormat(ed, name, vars, similar);
14355 }
14356 removeListStyleFormats(ed, name, vars);
14357 fireFormatRemove(ed, name, node, vars);
14358 };
14359 const removeFormat$1 = (ed, name, vars, node, similar) => {
14360 if (node || ed.selection.isEditable()) {
14361 removeFormatInternal(ed, name, vars, node, similar);
14362 }
14363 };
14364 const removeNodeFormat = (editor, format, vars, node, compareNode) => {
14365 return removeNodeFormatInternal(editor, format, vars, node, compareNode).fold(never, newName => {
14366 editor.dom.rename(node, newName);
14367 return true;
14368 }, always);
14369 };
14370
14371 const each$6 = Tools.each;
14372 const mergeTextDecorationsAndColor = (dom, format, vars, node) => {
14373 const processTextDecorationsAndColor = n => {
14374 if (isHTMLElement(n) && isElement$6(n.parentNode) && dom.isEditable(n)) {
14375 const parentTextDecoration = getTextDecoration(dom, n.parentNode);
14376 if (dom.getStyle(n, 'color') && parentTextDecoration) {
14377 dom.setStyle(n, 'text-decoration', parentTextDecoration);
14378 } else if (dom.getStyle(n, 'text-decoration') === parentTextDecoration) {
14379 dom.setStyle(n, 'text-decoration', null);
14380 }
14381 }
14382 };
14383 if (format.styles && (format.styles.color || format.styles.textDecoration)) {
14384 Tools.walk(node, processTextDecorationsAndColor, 'childNodes');
14385 processTextDecorationsAndColor(node);
14386 }
14387 };
14388 const mergeBackgroundColorAndFontSize = (dom, format, vars, node) => {
14389 if (format.styles && format.styles.backgroundColor) {
14390 const hasFontSize = hasStyle(dom, 'fontSize');
14391 processChildElements(node, elm => hasFontSize(elm) && dom.isEditable(elm), applyStyle(dom, 'backgroundColor', replaceVars(format.styles.backgroundColor, vars)));
14392 }
14393 };
14394 const mergeSubSup = (dom, format, vars, node) => {
14395 if (isInlineFormat(format) && (format.inline === 'sub' || format.inline === 'sup')) {
14396 const hasFontSize = hasStyle(dom, 'fontSize');
14397 processChildElements(node, elm => hasFontSize(elm) && dom.isEditable(elm), applyStyle(dom, 'fontSize', ''));
14398 const inverseTagDescendants = filter$5(dom.select(format.inline === 'sup' ? 'sub' : 'sup', node), dom.isEditable);
14399 dom.remove(inverseTagDescendants, true);
14400 }
14401 };
14402 const mergeWithChildren = (editor, formatList, vars, node) => {
14403 each$6(formatList, format => {
14404 if (isInlineFormat(format)) {
14405 each$6(editor.dom.select(format.inline, node), child => {
14406 if (isElementNode(child)) {
14407 removeNodeFormat(editor, format, vars, child, format.exact ? child : null);
14408 }
14409 });
14410 }
14411 clearChildStyles(editor.dom, format, node);
14412 });
14413 };
14414 const mergeWithParents = (editor, format, name, vars, node) => {
14415 const parentNode = node.parentNode;
14416 if (matchNode(editor, parentNode, name, vars)) {
14417 if (removeNodeFormat(editor, format, vars, node)) {
14418 return;
14419 }
14420 }
14421 if (format.merge_with_parents && parentNode) {
14422 editor.dom.getParent(parentNode, parent => {
14423 if (matchNode(editor, parent, name, vars)) {
14424 removeNodeFormat(editor, format, vars, node);
14425 return true;
14426 } else {
14427 return false;
14428 }
14429 });
14430 }
14431 };
14432
14433 const each$5 = Tools.each;
14434 const canFormatBR = (editor, format, node, parentName) => {
14435 if (canFormatEmptyLines(editor) && isInlineFormat(format) && node.parentNode) {
14436 const validBRParentElements = getTextRootBlockElements(editor.schema);
14437 const hasCaretNodeSibling = sibling(SugarElement.fromDom(node), sibling => isCaretNode(sibling.dom));
14438 return hasNonNullableKey(validBRParentElements, parentName) && isEmptyNode(editor.schema, node.parentNode, {
14439 skipBogus: false,
14440 includeZwsp: true
14441 }) && !hasCaretNodeSibling;
14442 } else {
14443 return false;
14444 }
14445 };
14446 const applyStyles = (dom, elm, format, vars) => {
14447 each$5(format.styles, (value, name) => {
14448 dom.setStyle(elm, name, replaceVars(value, vars));
14449 });
14450 if (format.styles) {
14451 const styleVal = dom.getAttrib(elm, 'style');
14452 if (styleVal) {
14453 dom.setAttrib(elm, 'data-mce-style', styleVal);
14454 }
14455 }
14456 };
14457 const applyFormatAction = (ed, name, vars, node) => {
14458 const formatList = ed.formatter.get(name);
14459 const format = formatList[0];
14460 const isCollapsed = !node && ed.selection.isCollapsed();
14461 const dom = ed.dom;
14462 const selection = ed.selection;
14463 const setElementFormat = (elm, fmt = format) => {
14464 if (isFunction(fmt.onformat)) {
14465 fmt.onformat(elm, fmt, vars, node);
14466 }
14467 applyStyles(dom, elm, fmt, vars);
14468 each$5(fmt.attributes, (value, name) => {
14469 dom.setAttrib(elm, name, replaceVars(value, vars));
14470 });
14471 each$5(fmt.classes, value => {
14472 const newValue = replaceVars(value, vars);
14473 if (!dom.hasClass(elm, newValue)) {
14474 dom.addClass(elm, newValue);
14475 }
14476 });
14477 };
14478 const applyNodeStyle = (formatList, node) => {
14479 let found = false;
14480 each$5(formatList, format => {
14481 if (!isSelectorFormat(format)) {
14482 return false;
14483 }
14484 if (dom.getContentEditable(node) === 'false' && !format.ceFalseOverride) {
14485 return true;
14486 }
14487 if (isNonNullable(format.collapsed) && format.collapsed !== isCollapsed) {
14488 return true;
14489 }
14490 if (dom.is(node, format.selector) && !isCaretNode(node)) {
14491 setElementFormat(node, format);
14492 found = true;
14493 return false;
14494 }
14495 return true;
14496 });
14497 return found;
14498 };
14499 const createWrapElement = wrapName => {
14500 if (isString(wrapName)) {
14501 const wrapElm = dom.create(wrapName);
14502 setElementFormat(wrapElm);
14503 return wrapElm;
14504 } else {
14505 return null;
14506 }
14507 };
14508 const applyRngStyle = (dom, rng, nodeSpecific) => {
14509 const newWrappers = [];
14510 let contentEditable = true;
14511 const wrapName = format.inline || format.block;
14512 const wrapElm = createWrapElement(wrapName);
14513 const isMatchingWrappingBlock = node => isWrappingBlockFormat(format) && matchNode(ed, node, name, vars);
14514 const canRenameBlock = (node, parentName, isEditableDescendant) => {
14515 const isValidBlockFormatForNode = isNonWrappingBlockFormat(format) && isTextBlock$1(ed.schema, node) && isValid(ed, parentName, wrapName);
14516 return isEditableDescendant && isValidBlockFormatForNode;
14517 };
14518 const canWrapNode = (node, parentName, isEditableDescendant, isWrappableNoneditableElm) => {
14519 const nodeName = node.nodeName.toLowerCase();
14520 const isValidWrapNode = isValid(ed, wrapName, nodeName) && isValid(ed, parentName, wrapName);
14521 const isZwsp$1 = !nodeSpecific && isText$b(node) && isZwsp(node.data);
14522 const isCaret = isCaretNode(node);
14523 const isCorrectFormatForNode = !isInlineFormat(format) || !dom.isBlock(node);
14524 return (isEditableDescendant || isWrappableNoneditableElm) && isValidWrapNode && !isZwsp$1 && !isCaret && isCorrectFormatForNode;
14525 };
14526 walk$3(dom, rng, nodes => {
14527 let currentWrapElm;
14528 const process = node => {
14529 let hasContentEditableState = false;
14530 let lastContentEditable = contentEditable;
14531 let isWrappableNoneditableElm = false;
14532 const parentNode = node.parentNode;
14533 const parentName = parentNode.nodeName.toLowerCase();
14534 const contentEditableValue = dom.getContentEditable(node);
14535 if (isNonNullable(contentEditableValue)) {
14536 lastContentEditable = contentEditable;
14537 contentEditable = contentEditableValue === 'true';
14538 hasContentEditableState = true;
14539 isWrappableNoneditableElm = isWrappableNoneditable(ed, node);
14540 }
14541 const isEditableDescendant = contentEditable && !hasContentEditableState;
14542 if (isBr$6(node) && !canFormatBR(ed, format, node, parentName)) {
14543 currentWrapElm = null;
14544 if (isBlockFormat(format)) {
14545 dom.remove(node);
14546 }
14547 return;
14548 }
14549 if (isMatchingWrappingBlock(node)) {
14550 currentWrapElm = null;
14551 return;
14552 }
14553 if (canRenameBlock(node, parentName, isEditableDescendant)) {
14554 const elm = dom.rename(node, wrapName);
14555 setElementFormat(elm);
14556 newWrappers.push(elm);
14557 currentWrapElm = null;
14558 return;
14559 }
14560 if (isSelectorFormat(format)) {
14561 let found = applyNodeStyle(formatList, node);
14562 if (!found && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
14563 found = applyNodeStyle(formatList, parentNode);
14564 }
14565 if (!isInlineFormat(format) || found) {
14566 currentWrapElm = null;
14567 return;
14568 }
14569 }
14570 if (isNonNullable(wrapElm) && canWrapNode(node, parentName, isEditableDescendant, isWrappableNoneditableElm)) {
14571 if (!currentWrapElm) {
14572 currentWrapElm = dom.clone(wrapElm, false);
14573 parentNode.insertBefore(currentWrapElm, node);
14574 newWrappers.push(currentWrapElm);
14575 }
14576 if (isWrappableNoneditableElm && hasContentEditableState) {
14577 contentEditable = lastContentEditable;
14578 }
14579 currentWrapElm.appendChild(node);
14580 } else {
14581 currentWrapElm = null;
14582 each$e(from(node.childNodes), process);
14583 if (hasContentEditableState) {
14584 contentEditable = lastContentEditable;
14585 }
14586 currentWrapElm = null;
14587 }
14588 };
14589 each$e(nodes, process);
14590 });
14591 if (format.links === true) {
14592 each$e(newWrappers, node => {
14593 const process = node => {
14594 if (node.nodeName === 'A') {
14595 setElementFormat(node, format);
14596 }
14597 each$e(from(node.childNodes), process);
14598 };
14599 process(node);
14600 });
14601 }
14602 each$e(newWrappers, node => {
14603 const getChildCount = node => {
14604 let count = 0;
14605 each$e(node.childNodes, node => {
14606 if (!isEmptyTextNode$1(node) && !isBookmarkNode$1(node)) {
14607 count++;
14608 }
14609 });
14610 return count;
14611 };
14612 const mergeStyles = node => {
14613 const childElement = find$2(node.childNodes, isElementNode$1).filter(child => dom.getContentEditable(child) !== 'false' && matchName(dom, child, format));
14614 return childElement.map(child => {
14615 const clone = dom.clone(child, false);
14616 setElementFormat(clone);
14617 dom.replace(clone, node, true);
14618 dom.remove(child, true);
14619 return clone;
14620 }).getOr(node);
14621 };
14622 const childCount = getChildCount(node);
14623 if ((newWrappers.length > 1 || !dom.isBlock(node)) && childCount === 0) {
14624 dom.remove(node, true);
14625 return;
14626 }
14627 if (isInlineFormat(format) || isBlockFormat(format) && format.wrapper) {
14628 if (!format.exact && childCount === 1) {
14629 node = mergeStyles(node);
14630 }
14631 mergeWithChildren(ed, formatList, vars, node);
14632 mergeWithParents(ed, format, name, vars, node);
14633 mergeBackgroundColorAndFontSize(dom, format, vars, node);
14634 mergeTextDecorationsAndColor(dom, format, vars, node);
14635 mergeSubSup(dom, format, vars, node);
14636 mergeSiblings(ed, format, vars, node);
14637 }
14638 });
14639 };
14640 const targetNode = isNode(node) ? node : selection.getNode();
14641 if (dom.getContentEditable(targetNode) === 'false' && !isWrappableNoneditable(ed, targetNode)) {
14642 node = targetNode;
14643 applyNodeStyle(formatList, node);
14644 fireFormatApply(ed, name, node, vars);
14645 return;
14646 }
14647 if (format) {
14648 if (node) {
14649 if (isNode(node)) {
14650 if (!applyNodeStyle(formatList, node)) {
14651 const rng = dom.createRng();
14652 rng.setStartBefore(node);
14653 rng.setEndAfter(node);
14654 applyRngStyle(dom, expandRng(dom, rng, formatList), true);
14655 }
14656 } else {
14657 applyRngStyle(dom, node, true);
14658 }
14659 } else {
14660 if (!isCollapsed || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
14661 selection.setRng(normalize(selection.getRng()));
14662 preserveSelection(ed, () => {
14663 runOnRanges(ed, (selectionRng, fake) => {
14664 const expandedRng = fake ? selectionRng : expandRng(dom, selectionRng, formatList);
14665 applyRngStyle(dom, expandedRng, false);
14666 });
14667 }, always);
14668 ed.nodeChanged();
14669 } else {
14670 applyCaretFormat(ed, name, vars);
14671 }
14672 getExpandedListItemFormat(ed.formatter, name).each(liFmt => {
14673 each$e(getFullySelectedListItems(ed.selection), li => applyStyles(dom, li, liFmt, vars));
14674 });
14675 }
14676 postProcess$1(name, ed);
14677 }
14678 fireFormatApply(ed, name, node, vars);
14679 };
14680 const applyFormat$1 = (editor, name, vars, node) => {
14681 if (node || editor.selection.isEditable()) {
14682 applyFormatAction(editor, name, vars, node);
14683 }
14684 };
14685
14686 const hasVars = value => has$2(value, 'vars');
14687 const setup$u = (registeredFormatListeners, editor) => {
14688 registeredFormatListeners.set({});
14689 editor.on('NodeChange', e => {
14690 updateAndFireChangeCallbacks(editor, e.element, registeredFormatListeners.get());
14691 });
14692 editor.on('FormatApply FormatRemove', e => {
14693 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));
14694 updateAndFireChangeCallbacks(editor, element, registeredFormatListeners.get());
14695 });
14696 };
14697 const fallbackElement = editor => editor.selection.getStart();
14698 const matchingNode = (editor, parents, format, similar, vars) => {
14699 const isMatchingNode = node => {
14700 const matchingFormat = editor.formatter.matchNode(node, format, vars !== null && vars !== void 0 ? vars : {}, similar);
14701 return !isUndefined(matchingFormat);
14702 };
14703 const isUnableToMatch = node => {
14704 if (matchesUnInheritedFormatSelector(editor, node, format)) {
14705 return true;
14706 } else {
14707 if (!similar) {
14708 return isNonNullable(editor.formatter.matchNode(node, format, vars, true));
14709 } else {
14710 return false;
14711 }
14712 }
14713 };
14714 return findUntil$1(parents, isMatchingNode, isUnableToMatch);
14715 };
14716 const getParents = (editor, elm) => {
14717 const element = elm !== null && elm !== void 0 ? elm : fallbackElement(editor);
14718 return filter$5(getParents$2(editor.dom, element), node => isElement$6(node) && !isBogus$1(node));
14719 };
14720 const updateAndFireChangeCallbacks = (editor, elm, registeredCallbacks) => {
14721 const parents = getParents(editor, elm);
14722 each$d(registeredCallbacks, (data, format) => {
14723 const runIfChanged = spec => {
14724 const match = matchingNode(editor, parents, format, spec.similar, hasVars(spec) ? spec.vars : undefined);
14725 const isSet = match.isSome();
14726 if (spec.state.get() !== isSet) {
14727 spec.state.set(isSet);
14728 const node = match.getOr(elm);
14729 if (hasVars(spec)) {
14730 spec.callback(isSet, {
14731 node,
14732 format,
14733 parents
14734 });
14735 } else {
14736 each$e(spec.callbacks, callback => callback(isSet, {
14737 node,
14738 format,
14739 parents
14740 }));
14741 }
14742 }
14743 };
14744 each$e([
14745 data.withSimilar,
14746 data.withoutSimilar
14747 ], runIfChanged);
14748 each$e(data.withVars, runIfChanged);
14749 });
14750 };
14751 const addListeners = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
14752 const formatChangeItems = registeredFormatListeners.get();
14753 each$e(formats.split(','), format => {
14754 const group = get$a(formatChangeItems, format).getOrThunk(() => {
14755 const base = {
14756 withSimilar: {
14757 state: Cell(false),
14758 similar: true,
14759 callbacks: []
14760 },
14761 withoutSimilar: {
14762 state: Cell(false),
14763 similar: false,
14764 callbacks: []
14765 },
14766 withVars: []
14767 };
14768 formatChangeItems[format] = base;
14769 return base;
14770 });
14771 const getCurrent = () => {
14772 const parents = getParents(editor);
14773 return matchingNode(editor, parents, format, similar, vars).isSome();
14774 };
14775 if (isUndefined(vars)) {
14776 const toAppendTo = similar ? group.withSimilar : group.withoutSimilar;
14777 toAppendTo.callbacks.push(callback);
14778 if (toAppendTo.callbacks.length === 1) {
14779 toAppendTo.state.set(getCurrent());
14780 }
14781 } else {
14782 group.withVars.push({
14783 state: Cell(getCurrent()),
14784 similar,
14785 vars,
14786 callback
14787 });
14788 }
14789 });
14790 registeredFormatListeners.set(formatChangeItems);
14791 };
14792 const removeListeners = (registeredFormatListeners, formats, callback) => {
14793 const formatChangeItems = registeredFormatListeners.get();
14794 each$e(formats.split(','), format => get$a(formatChangeItems, format).each(group => {
14795 formatChangeItems[format] = {
14796 withSimilar: {
14797 ...group.withSimilar,
14798 callbacks: filter$5(group.withSimilar.callbacks, cb => cb !== callback)
14799 },
14800 withoutSimilar: {
14801 ...group.withoutSimilar,
14802 callbacks: filter$5(group.withoutSimilar.callbacks, cb => cb !== callback)
14803 },
14804 withVars: filter$5(group.withVars, item => item.callback !== callback)
14805 };
14806 }));
14807 registeredFormatListeners.set(formatChangeItems);
14808 };
14809 const formatChangedInternal = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
14810 addListeners(editor, registeredFormatListeners, formats, callback, similar, vars);
14811 return { unbind: () => removeListeners(registeredFormatListeners, formats, callback) };
14812 };
14813
14814 const toggle = (editor, name, vars, node) => {
14815 const fmt = editor.formatter.get(name);
14816 if (fmt) {
14817 if (match$2(editor, name, vars, node) && (!('toggle' in fmt[0]) || fmt[0].toggle)) {
14818 removeFormat$1(editor, name, vars, node);
14819 } else {
14820 applyFormat$1(editor, name, vars, node);
14821 }
14822 }
14823 };
14824
14825 const explode$1 = Tools.explode;
14826 const create$8 = () => {
14827 const filters = {};
14828 const addFilter = (name, callback) => {
14829 each$e(explode$1(name), name => {
14830 if (!has$2(filters, name)) {
14831 filters[name] = {
14832 name,
14833 callbacks: []
14834 };
14835 }
14836 filters[name].callbacks.push(callback);
14837 });
14838 };
14839 const getFilters = () => values(filters);
14840 const removeFilter = (name, callback) => {
14841 each$e(explode$1(name), name => {
14842 if (has$2(filters, name)) {
14843 if (isNonNullable(callback)) {
14844 const filter = filters[name];
14845 const newCallbacks = filter$5(filter.callbacks, c => c !== callback);
14846 if (newCallbacks.length > 0) {
14847 filter.callbacks = newCallbacks;
14848 } else {
14849 delete filters[name];
14850 }
14851 } else {
14852 delete filters[name];
14853 }
14854 }
14855 });
14856 };
14857 return {
14858 addFilter,
14859 getFilters,
14860 removeFilter
14861 };
14862 };
14863
14864 const removeAttrs = (node, names) => {
14865 each$e(names, name => {
14866 node.attr(name, null);
14867 });
14868 };
14869 const addFontToSpansFilter = (domParser, styles, fontSizes) => {
14870 domParser.addNodeFilter('font', nodes => {
14871 each$e(nodes, node => {
14872 const props = styles.parse(node.attr('style'));
14873 const color = node.attr('color');
14874 const face = node.attr('face');
14875 const size = node.attr('size');
14876 if (color) {
14877 props.color = color;
14878 }
14879 if (face) {
14880 props['font-family'] = face;
14881 }
14882 if (size) {
14883 toInt(size).each(num => {
14884 props['font-size'] = fontSizes[num - 1];
14885 });
14886 }
14887 node.name = 'span';
14888 node.attr('style', styles.serialize(props));
14889 removeAttrs(node, [
14890 'color',
14891 'face',
14892 'size'
14893 ]);
14894 });
14895 });
14896 };
14897 const addStrikeFilter = (domParser, schema, styles) => {
14898 domParser.addNodeFilter('strike', nodes => {
14899 const convertToSTag = schema.type !== 'html4';
14900 each$e(nodes, node => {
14901 if (convertToSTag) {
14902 node.name = 's';
14903 } else {
14904 const props = styles.parse(node.attr('style'));
14905 props['text-decoration'] = 'line-through';
14906 node.name = 'span';
14907 node.attr('style', styles.serialize(props));
14908 }
14909 });
14910 });
14911 };
14912 const addFilters = (domParser, settings, schema) => {
14913 var _a;
14914 const styles = Styles();
14915 if (settings.convert_fonts_to_spans) {
14916 addFontToSpansFilter(domParser, styles, Tools.explode((_a = settings.font_size_legacy_values) !== null && _a !== void 0 ? _a : ''));
14917 }
14918 addStrikeFilter(domParser, schema, styles);
14919 };
14920 const register$5 = (domParser, settings, schema) => {
14921 if (settings.inline_styles) {
14922 addFilters(domParser, settings, schema);
14923 }
14924 };
14925
14926 const blobUriToBlob = url => fetch(url).then(res => res.ok ? res.blob() : Promise.reject()).catch(() => Promise.reject({
14927 message: `Cannot convert ${ url } to Blob. Resource might not exist or is inaccessible.`,
14928 uriType: 'blob'
14929 }));
14930 const extractBase64Data = data => {
14931 const matches = /([a-z0-9+\/=\s]+)/i.exec(data);
14932 return matches ? matches[1] : '';
14933 };
14934 const parseDataUri = uri => {
14935 const [type, ...rest] = uri.split(',');
14936 const data = rest.join(',');
14937 const matches = /data:([^/]+\/[^;]+)(;.+)?/.exec(type);
14938 if (matches) {
14939 const base64Encoded = matches[2] === ';base64';
14940 const extractedData = base64Encoded ? extractBase64Data(data) : decodeURIComponent(data);
14941 return Optional.some({
14942 type: matches[1],
14943 data: extractedData,
14944 base64Encoded
14945 });
14946 } else {
14947 return Optional.none();
14948 }
14949 };
14950 const buildBlob = (type, data, base64Encoded = true) => {
14951 let str = data;
14952 if (base64Encoded) {
14953 try {
14954 str = atob(data);
14955 } catch (e) {
14956 return Optional.none();
14957 }
14958 }
14959 const arr = new Uint8Array(str.length);
14960 for (let i = 0; i < arr.length; i++) {
14961 arr[i] = str.charCodeAt(i);
14962 }
14963 return Optional.some(new Blob([arr], { type }));
14964 };
14965 const dataUriToBlob = uri => {
14966 return new Promise((resolve, reject) => {
14967 parseDataUri(uri).bind(({type, data, base64Encoded}) => buildBlob(type, data, base64Encoded)).fold(() => reject('Invalid data URI'), resolve);
14968 });
14969 };
14970 const uriToBlob = url => {
14971 if (startsWith(url, 'blob:')) {
14972 return blobUriToBlob(url);
14973 } else if (startsWith(url, 'data:')) {
14974 return dataUriToBlob(url);
14975 } else {
14976 return Promise.reject('Unknown URI format');
14977 }
14978 };
14979 const blobToDataUri = blob => {
14980 return new Promise((resolve, reject) => {
14981 const reader = new FileReader();
14982 reader.onloadend = () => {
14983 resolve(reader.result);
14984 };
14985 reader.onerror = () => {
14986 var _a;
14987 reject((_a = reader.error) === null || _a === void 0 ? void 0 : _a.message);
14988 };
14989 reader.readAsDataURL(blob);
14990 });
14991 };
14992
14993 let count$1 = 0;
14994 const uniqueId$1 = prefix => {
14995 return (prefix || 'blobid') + count$1++;
14996 };
14997 const processDataUri = (dataUri, base64Only, generateBlobInfo) => {
14998 return parseDataUri(dataUri).bind(({data, type, base64Encoded}) => {
14999 if (base64Only && !base64Encoded) {
15000 return Optional.none();
15001 } else {
15002 const base64 = base64Encoded ? data : btoa(data);
15003 return generateBlobInfo(base64, type);
15004 }
15005 });
15006 };
15007 const createBlobInfo$1 = (blobCache, blob, base64) => {
15008 const blobInfo = blobCache.create(uniqueId$1(), blob, base64);
15009 blobCache.add(blobInfo);
15010 return blobInfo;
15011 };
15012 const dataUriToBlobInfo = (blobCache, dataUri, base64Only = false) => {
15013 return processDataUri(dataUri, base64Only, (base64, type) => Optional.from(blobCache.getByData(base64, type)).orThunk(() => buildBlob(type, base64).map(blob => createBlobInfo$1(blobCache, blob, base64))));
15014 };
15015 const imageToBlobInfo = (blobCache, imageSrc) => {
15016 const invalidDataUri = () => Promise.reject('Invalid data URI');
15017 if (startsWith(imageSrc, 'blob:')) {
15018 const blobInfo = blobCache.getByUri(imageSrc);
15019 if (isNonNullable(blobInfo)) {
15020 return Promise.resolve(blobInfo);
15021 } else {
15022 return uriToBlob(imageSrc).then(blob => {
15023 return blobToDataUri(blob).then(dataUri => {
15024 return processDataUri(dataUri, false, base64 => {
15025 return Optional.some(createBlobInfo$1(blobCache, blob, base64));
15026 }).getOrThunk(invalidDataUri);
15027 });
15028 });
15029 }
15030 } else if (startsWith(imageSrc, 'data:')) {
15031 return dataUriToBlobInfo(blobCache, imageSrc).fold(invalidDataUri, blobInfo => Promise.resolve(blobInfo));
15032 } else {
15033 return Promise.reject('Unknown image data format');
15034 }
15035 };
15036
15037 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]+)?)?)$/;
15038 const extractHost = url => Optional.from(url.match(hostCaptureRegex)).bind(ms => get$b(ms, 1)).map(h => startsWith(h, 'www.') ? h.substring(4) : h);
15039
15040 const sandboxIframe = (iframeNode, exclusions) => {
15041 if (Optional.from(iframeNode.attr('src')).bind(extractHost).forall(host => !contains$2(exclusions, host))) {
15042 iframeNode.attr('sandbox', '');
15043 }
15044 };
15045 const isMimeType = (mime, type) => startsWith(mime, `${ type }/`);
15046 const getEmbedType = type => {
15047 if (isUndefined(type)) {
15048 return 'iframe';
15049 } else if (isMimeType(type, 'image')) {
15050 return 'img';
15051 } else if (isMimeType(type, 'video')) {
15052 return 'video';
15053 } else if (isMimeType(type, 'audio')) {
15054 return 'audio';
15055 } else {
15056 return 'iframe';
15057 }
15058 };
15059 const createSafeEmbed = ({type, src, width, height} = {}, sandboxIframes, sandboxIframesExclusions) => {
15060 const name = getEmbedType(type);
15061 const embed = new AstNode(name, 1);
15062 embed.attr(name === 'audio' ? { src } : {
15063 src,
15064 width,
15065 height
15066 });
15067 if (name === 'audio' || name === 'video') {
15068 embed.attr('controls', '');
15069 }
15070 if (name === 'iframe' && sandboxIframes) {
15071 sandboxIframe(embed, sandboxIframesExclusions);
15072 }
15073 return embed;
15074 };
15075
15076 const isBogusImage = img => isNonNullable(img.attr('data-mce-bogus'));
15077 const isInternalImageSource = img => img.attr('src') === Env.transparentSrc || isNonNullable(img.attr('data-mce-placeholder'));
15078 const registerBase64ImageFilter = (parser, settings) => {
15079 const {blob_cache: blobCache} = settings;
15080 if (blobCache) {
15081 const processImage = img => {
15082 const inputSrc = img.attr('src');
15083 if (isInternalImageSource(img) || isBogusImage(img) || isNullable(inputSrc)) {
15084 return;
15085 }
15086 dataUriToBlobInfo(blobCache, inputSrc, true).each(blobInfo => {
15087 img.attr('src', blobInfo.blobUri());
15088 });
15089 };
15090 parser.addAttributeFilter('src', nodes => each$e(nodes, processImage));
15091 }
15092 };
15093 const register$4 = (parser, settings) => {
15094 var _a, _b;
15095 const schema = parser.schema;
15096 parser.addAttributeFilter('href', nodes => {
15097 let i = nodes.length;
15098 const appendRel = rel => {
15099 const parts = rel.split(' ').filter(p => p.length > 0);
15100 return parts.concat(['noopener']).sort().join(' ');
15101 };
15102 const addNoOpener = rel => {
15103 const newRel = rel ? Tools.trim(rel) : '';
15104 if (!/\b(noopener)\b/g.test(newRel)) {
15105 return appendRel(newRel);
15106 } else {
15107 return newRel;
15108 }
15109 };
15110 if (!settings.allow_unsafe_link_target) {
15111 while (i--) {
15112 const node = nodes[i];
15113 if (node.name === 'a' && node.attr('target') === '_blank') {
15114 node.attr('rel', addNoOpener(node.attr('rel')));
15115 }
15116 }
15117 }
15118 });
15119 if (!settings.allow_html_in_named_anchor) {
15120 parser.addAttributeFilter('id,name', nodes => {
15121 let i = nodes.length, sibling, prevSibling, parent, node;
15122 while (i--) {
15123 node = nodes[i];
15124 if (node.name === 'a' && node.firstChild && !node.attr('href')) {
15125 parent = node.parent;
15126 sibling = node.lastChild;
15127 while (sibling && parent) {
15128 prevSibling = sibling.prev;
15129 parent.insert(sibling, node);
15130 sibling = prevSibling;
15131 }
15132 }
15133 }
15134 });
15135 }
15136 if (settings.fix_list_elements) {
15137 parser.addNodeFilter('ul,ol', nodes => {
15138 let i = nodes.length, node, parentNode;
15139 while (i--) {
15140 node = nodes[i];
15141 parentNode = node.parent;
15142 if (parentNode && (parentNode.name === 'ul' || parentNode.name === 'ol')) {
15143 if (node.prev && node.prev.name === 'li') {
15144 node.prev.append(node);
15145 } else {
15146 const li = new AstNode('li', 1);
15147 li.attr('style', 'list-style-type: none');
15148 node.wrap(li);
15149 }
15150 }
15151 }
15152 });
15153 }
15154 const validClasses = schema.getValidClasses();
15155 if (settings.validate && validClasses) {
15156 parser.addAttributeFilter('class', nodes => {
15157 var _a;
15158 let i = nodes.length;
15159 while (i--) {
15160 const node = nodes[i];
15161 const clazz = (_a = node.attr('class')) !== null && _a !== void 0 ? _a : '';
15162 const classList = Tools.explode(clazz, ' ');
15163 let classValue = '';
15164 for (let ci = 0; ci < classList.length; ci++) {
15165 const className = classList[ci];
15166 let valid = false;
15167 let validClassesMap = validClasses['*'];
15168 if (validClassesMap && validClassesMap[className]) {
15169 valid = true;
15170 }
15171 validClassesMap = validClasses[node.name];
15172 if (!valid && validClassesMap && validClassesMap[className]) {
15173 valid = true;
15174 }
15175 if (valid) {
15176 if (classValue) {
15177 classValue += ' ';
15178 }
15179 classValue += className;
15180 }
15181 }
15182 if (!classValue.length) {
15183 classValue = null;
15184 }
15185 node.attr('class', classValue);
15186 }
15187 });
15188 }
15189 registerBase64ImageFilter(parser, settings);
15190 const shouldSandboxIframes = (_a = settings.sandbox_iframes) !== null && _a !== void 0 ? _a : false;
15191 const sandboxIframesExclusions = unique$1((_b = settings.sandbox_iframes_exclusions) !== null && _b !== void 0 ? _b : []);
15192 if (settings.convert_unsafe_embeds) {
15193 parser.addNodeFilter('object,embed', nodes => each$e(nodes, node => {
15194 node.replace(createSafeEmbed({
15195 type: node.attr('type'),
15196 src: node.name === 'object' ? node.attr('data') : node.attr('src'),
15197 width: node.attr('width'),
15198 height: node.attr('height')
15199 }, shouldSandboxIframes, sandboxIframesExclusions));
15200 }));
15201 }
15202 if (shouldSandboxIframes) {
15203 parser.addNodeFilter('iframe', nodes => each$e(nodes, node => sandboxIframe(node, sandboxIframesExclusions)));
15204 }
15205 };
15206
15207 const {entries, setPrototypeOf, isFrozen, getPrototypeOf, getOwnPropertyDescriptor} = Object;
15208 let {freeze, seal, create: create$7} = Object;
15209 let {apply, construct} = typeof Reflect !== 'undefined' && Reflect;
15210 if (!apply) {
15211 apply = function apply(fun, thisValue, args) {
15212 return fun.apply(thisValue, args);
15213 };
15214 }
15215 if (!freeze) {
15216 freeze = function freeze(x) {
15217 return x;
15218 };
15219 }
15220 if (!seal) {
15221 seal = function seal(x) {
15222 return x;
15223 };
15224 }
15225 if (!construct) {
15226 construct = function construct(Func, args) {
15227 return new Func(...args);
15228 };
15229 }
15230 const arrayForEach = unapply(Array.prototype.forEach);
15231 const arrayPop = unapply(Array.prototype.pop);
15232 const arrayPush = unapply(Array.prototype.push);
15233 const stringToLowerCase = unapply(String.prototype.toLowerCase);
15234 const stringToString = unapply(String.prototype.toString);
15235 const stringMatch = unapply(String.prototype.match);
15236 const stringReplace = unapply(String.prototype.replace);
15237 const stringIndexOf = unapply(String.prototype.indexOf);
15238 const stringTrim = unapply(String.prototype.trim);
15239 const regExpTest = unapply(RegExp.prototype.test);
15240 const typeErrorCreate = unconstruct(TypeError);
15241 function unapply(func) {
15242 return function (thisArg) {
15243 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
15244 args[_key - 1] = arguments[_key];
15245 }
15246 return apply(func, thisArg, args);
15247 };
15248 }
15249 function unconstruct(func) {
15250 return function () {
15251 for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
15252 args[_key2] = arguments[_key2];
15253 }
15254 return construct(func, args);
15255 };
15256 }
15257 function addToSet(set, array, transformCaseFunc) {
15258 var _transformCaseFunc;
15259 transformCaseFunc = (_transformCaseFunc = transformCaseFunc) !== null && _transformCaseFunc !== void 0 ? _transformCaseFunc : stringToLowerCase;
15260 if (setPrototypeOf) {
15261 setPrototypeOf(set, null);
15262 }
15263 let l = array.length;
15264 while (l--) {
15265 let element = array[l];
15266 if (typeof element === 'string') {
15267 const lcElement = transformCaseFunc(element);
15268 if (lcElement !== element) {
15269 if (!isFrozen(array)) {
15270 array[l] = lcElement;
15271 }
15272 element = lcElement;
15273 }
15274 }
15275 set[element] = true;
15276 }
15277 return set;
15278 }
15279 function clone(object) {
15280 const newObject = create$7(null);
15281 for (const [property, value] of entries(object)) {
15282 newObject[property] = value;
15283 }
15284 return newObject;
15285 }
15286 function lookupGetter(object, prop) {
15287 while (object !== null) {
15288 const desc = getOwnPropertyDescriptor(object, prop);
15289 if (desc) {
15290 if (desc.get) {
15291 return unapply(desc.get);
15292 }
15293 if (typeof desc.value === 'function') {
15294 return unapply(desc.value);
15295 }
15296 }
15297 object = getPrototypeOf(object);
15298 }
15299 function fallbackValue(element) {
15300 console.warn('fallback value for', element);
15301 return null;
15302 }
15303 return fallbackValue;
15304 }
15305 const html$1 = freeze([
15306 'a',
15307 'abbr',
15308 'acronym',
15309 'address',
15310 'area',
15311 'article',
15312 'aside',
15313 'audio',
15314 'b',
15315 'bdi',
15316 'bdo',
15317 'big',
15318 'blink',
15319 'blockquote',
15320 'body',
15321 'br',
15322 'button',
15323 'canvas',
15324 'caption',
15325 'center',
15326 'cite',
15327 'code',
15328 'col',
15329 'colgroup',
15330 'content',
15331 'data',
15332 'datalist',
15333 'dd',
15334 'decorator',
15335 'del',
15336 'details',
15337 'dfn',
15338 'dialog',
15339 'dir',
15340 'div',
15341 'dl',
15342 'dt',
15343 'element',
15344 'em',
15345 'fieldset',
15346 'figcaption',
15347 'figure',
15348 'font',
15349 'footer',
15350 'form',
15351 'h1',
15352 'h2',
15353 'h3',
15354 'h4',
15355 'h5',
15356 'h6',
15357 'head',
15358 'header',
15359 'hgroup',
15360 'hr',
15361 'html',
15362 'i',
15363 'img',
15364 'input',
15365 'ins',
15366 'kbd',
15367 'label',
15368 'legend',
15369 'li',
15370 'main',
15371 'map',
15372 'mark',
15373 'marquee',
15374 'menu',
15375 'menuitem',
15376 'meter',
15377 'nav',
15378 'nobr',
15379 'ol',
15380 'optgroup',
15381 'option',
15382 'output',
15383 'p',
15384 'picture',
15385 'pre',
15386 'progress',
15387 'q',
15388 'rp',
15389 'rt',
15390 'ruby',
15391 's',
15392 'samp',
15393 'section',
15394 'select',
15395 'shadow',
15396 'small',
15397 'source',
15398 'spacer',
15399 'span',
15400 'strike',
15401 'strong',
15402 'style',
15403 'sub',
15404 'summary',
15405 'sup',
15406 'table',
15407 'tbody',
15408 'td',
15409 'template',
15410 'textarea',
15411 'tfoot',
15412 'th',
15413 'thead',
15414 'time',
15415 'tr',
15416 'track',
15417 'tt',
15418 'u',
15419 'ul',
15420 'var',
15421 'video',
15422 'wbr'
15423 ]);
15424 const svg$1 = freeze([
15425 'svg',
15426 'a',
15427 'altglyph',
15428 'altglyphdef',
15429 'altglyphitem',
15430 'animatecolor',
15431 'animatemotion',
15432 'animatetransform',
15433 'circle',
15434 'clippath',
15435 'defs',
15436 'desc',
15437 'ellipse',
15438 'filter',
15439 'font',
15440 'g',
15441 'glyph',
15442 'glyphref',
15443 'hkern',
15444 'image',
15445 'line',
15446 'lineargradient',
15447 'marker',
15448 'mask',
15449 'metadata',
15450 'mpath',
15451 'path',
15452 'pattern',
15453 'polygon',
15454 'polyline',
15455 'radialgradient',
15456 'rect',
15457 'stop',
15458 'style',
15459 'switch',
15460 'symbol',
15461 'text',
15462 'textpath',
15463 'title',
15464 'tref',
15465 'tspan',
15466 'view',
15467 'vkern'
15468 ]);
15469 const svgFilters = freeze([
15470 'feBlend',
15471 'feColorMatrix',
15472 'feComponentTransfer',
15473 'feComposite',
15474 'feConvolveMatrix',
15475 'feDiffuseLighting',
15476 'feDisplacementMap',
15477 'feDistantLight',
15478 'feDropShadow',
15479 'feFlood',
15480 'feFuncA',
15481 'feFuncB',
15482 'feFuncG',
15483 'feFuncR',
15484 'feGaussianBlur',
15485 'feImage',
15486 'feMerge',
15487 'feMergeNode',
15488 'feMorphology',
15489 'feOffset',
15490 'fePointLight',
15491 'feSpecularLighting',
15492 'feSpotLight',
15493 'feTile',
15494 'feTurbulence'
15495 ]);
15496 const svgDisallowed = freeze([
15497 'animate',
15498 'color-profile',
15499 'cursor',
15500 'discard',
15501 'font-face',
15502 'font-face-format',
15503 'font-face-name',
15504 'font-face-src',
15505 'font-face-uri',
15506 'foreignobject',
15507 'hatch',
15508 'hatchpath',
15509 'mesh',
15510 'meshgradient',
15511 'meshpatch',
15512 'meshrow',
15513 'missing-glyph',
15514 'script',
15515 'set',
15516 'solidcolor',
15517 'unknown',
15518 'use'
15519 ]);
15520 const mathMl$1 = freeze([
15521 'math',
15522 'menclose',
15523 'merror',
15524 'mfenced',
15525 'mfrac',
15526 'mglyph',
15527 'mi',
15528 'mlabeledtr',
15529 'mmultiscripts',
15530 'mn',
15531 'mo',
15532 'mover',
15533 'mpadded',
15534 'mphantom',
15535 'mroot',
15536 'mrow',
15537 'ms',
15538 'mspace',
15539 'msqrt',
15540 'mstyle',
15541 'msub',
15542 'msup',
15543 'msubsup',
15544 'mtable',
15545 'mtd',
15546 'mtext',
15547 'mtr',
15548 'munder',
15549 'munderover',
15550 'mprescripts'
15551 ]);
15552 const mathMlDisallowed = freeze([
15553 'maction',
15554 'maligngroup',
15555 'malignmark',
15556 'mlongdiv',
15557 'mscarries',
15558 'mscarry',
15559 'msgroup',
15560 'mstack',
15561 'msline',
15562 'msrow',
15563 'semantics',
15564 'annotation',
15565 'annotation-xml',
15566 'mprescripts',
15567 'none'
15568 ]);
15569 const text = freeze(['#text']);
15570 const html = freeze([
15571 'accept',
15572 'action',
15573 'align',
15574 'alt',
15575 'autocapitalize',
15576 'autocomplete',
15577 'autopictureinpicture',
15578 'autoplay',
15579 'background',
15580 'bgcolor',
15581 'border',
15582 'capture',
15583 'cellpadding',
15584 'cellspacing',
15585 'checked',
15586 'cite',
15587 'class',
15588 'clear',
15589 'color',
15590 'cols',
15591 'colspan',
15592 'controls',
15593 'controlslist',
15594 'coords',
15595 'crossorigin',
15596 'datetime',
15597 'decoding',
15598 'default',
15599 'dir',
15600 'disabled',
15601 'disablepictureinpicture',
15602 'disableremoteplayback',
15603 'download',
15604 'draggable',
15605 'enctype',
15606 'enterkeyhint',
15607 'face',
15608 'for',
15609 'headers',
15610 'height',
15611 'hidden',
15612 'high',
15613 'href',
15614 'hreflang',
15615 'id',
15616 'inputmode',
15617 'integrity',
15618 'ismap',
15619 'kind',
15620 'label',
15621 'lang',
15622 'list',
15623 'loading',
15624 'loop',
15625 'low',
15626 'max',
15627 'maxlength',
15628 'media',
15629 'method',
15630 'min',
15631 'minlength',
15632 'multiple',
15633 'muted',
15634 'name',
15635 'nonce',
15636 'noshade',
15637 'novalidate',
15638 'nowrap',
15639 'open',
15640 'optimum',
15641 'pattern',
15642 'placeholder',
15643 'playsinline',
15644 'poster',
15645 'preload',
15646 'pubdate',
15647 'radiogroup',
15648 'readonly',
15649 'rel',
15650 'required',
15651 'rev',
15652 'reversed',
15653 'role',
15654 'rows',
15655 'rowspan',
15656 'spellcheck',
15657 'scope',
15658 'selected',
15659 'shape',
15660 'size',
15661 'sizes',
15662 'span',
15663 'srclang',
15664 'start',
15665 'src',
15666 'srcset',
15667 'step',
15668 'style',
15669 'summary',
15670 'tabindex',
15671 'title',
15672 'translate',
15673 'type',
15674 'usemap',
15675 'valign',
15676 'value',
15677 'width',
15678 'xmlns',
15679 'slot'
15680 ]);
15681 const svg = freeze([
15682 'accent-height',
15683 'accumulate',
15684 'additive',
15685 'alignment-baseline',
15686 'ascent',
15687 'attributename',
15688 'attributetype',
15689 'azimuth',
15690 'basefrequency',
15691 'baseline-shift',
15692 'begin',
15693 'bias',
15694 'by',
15695 'class',
15696 'clip',
15697 'clippathunits',
15698 'clip-path',
15699 'clip-rule',
15700 'color',
15701 'color-interpolation',
15702 'color-interpolation-filters',
15703 'color-profile',
15704 'color-rendering',
15705 'cx',
15706 'cy',
15707 'd',
15708 'dx',
15709 'dy',
15710 'diffuseconstant',
15711 'direction',
15712 'display',
15713 'divisor',
15714 'dur',
15715 'edgemode',
15716 'elevation',
15717 'end',
15718 'fill',
15719 'fill-opacity',
15720 'fill-rule',
15721 'filter',
15722 'filterunits',
15723 'flood-color',
15724 'flood-opacity',
15725 'font-family',
15726 'font-size',
15727 'font-size-adjust',
15728 'font-stretch',
15729 'font-style',
15730 'font-variant',
15731 'font-weight',
15732 'fx',
15733 'fy',
15734 'g1',
15735 'g2',
15736 'glyph-name',
15737 'glyphref',
15738 'gradientunits',
15739 'gradienttransform',
15740 'height',
15741 'href',
15742 'id',
15743 'image-rendering',
15744 'in',
15745 'in2',
15746 'k',
15747 'k1',
15748 'k2',
15749 'k3',
15750 'k4',
15751 'kerning',
15752 'keypoints',
15753 'keysplines',
15754 'keytimes',
15755 'lang',
15756 'lengthadjust',
15757 'letter-spacing',
15758 'kernelmatrix',
15759 'kernelunitlength',
15760 'lighting-color',
15761 'local',
15762 'marker-end',
15763 'marker-mid',
15764 'marker-start',
15765 'markerheight',
15766 'markerunits',
15767 'markerwidth',
15768 'maskcontentunits',
15769 'maskunits',
15770 'max',
15771 'mask',
15772 'media',
15773 'method',
15774 'mode',
15775 'min',
15776 'name',
15777 'numoctaves',
15778 'offset',
15779 'operator',
15780 'opacity',
15781 'order',
15782 'orient',
15783 'orientation',
15784 'origin',
15785 'overflow',
15786 'paint-order',
15787 'path',
15788 'pathlength',
15789 'patterncontentunits',
15790 'patterntransform',
15791 'patternunits',
15792 'points',
15793 'preservealpha',
15794 'preserveaspectratio',
15795 'primitiveunits',
15796 'r',
15797 'rx',
15798 'ry',
15799 'radius',
15800 'refx',
15801 'refy',
15802 'repeatcount',
15803 'repeatdur',
15804 'restart',
15805 'result',
15806 'rotate',
15807 'scale',
15808 'seed',
15809 'shape-rendering',
15810 'specularconstant',
15811 'specularexponent',
15812 'spreadmethod',
15813 'startoffset',
15814 'stddeviation',
15815 'stitchtiles',
15816 'stop-color',
15817 'stop-opacity',
15818 'stroke-dasharray',
15819 'stroke-dashoffset',
15820 'stroke-linecap',
15821 'stroke-linejoin',
15822 'stroke-miterlimit',
15823 'stroke-opacity',
15824 'stroke',
15825 'stroke-width',
15826 'style',
15827 'surfacescale',
15828 'systemlanguage',
15829 'tabindex',
15830 'targetx',
15831 'targety',
15832 'transform',
15833 'transform-origin',
15834 'text-anchor',
15835 'text-decoration',
15836 'text-rendering',
15837 'textlength',
15838 'type',
15839 'u1',
15840 'u2',
15841 'unicode',
15842 'values',
15843 'viewbox',
15844 'visibility',
15845 'version',
15846 'vert-adv-y',
15847 'vert-origin-x',
15848 'vert-origin-y',
15849 'width',
15850 'word-spacing',
15851 'wrap',
15852 'writing-mode',
15853 'xchannelselector',
15854 'ychannelselector',
15855 'x',
15856 'x1',
15857 'x2',
15858 'xmlns',
15859 'y',
15860 'y1',
15861 'y2',
15862 'z',
15863 'zoomandpan'
15864 ]);
15865 const mathMl = freeze([
15866 'accent',
15867 'accentunder',
15868 'align',
15869 'bevelled',
15870 'close',
15871 'columnsalign',
15872 'columnlines',
15873 'columnspan',
15874 'denomalign',
15875 'depth',
15876 'dir',
15877 'display',
15878 'displaystyle',
15879 'encoding',
15880 'fence',
15881 'frame',
15882 'height',
15883 'href',
15884 'id',
15885 'largeop',
15886 'length',
15887 'linethickness',
15888 'lspace',
15889 'lquote',
15890 'mathbackground',
15891 'mathcolor',
15892 'mathsize',
15893 'mathvariant',
15894 'maxsize',
15895 'minsize',
15896 'movablelimits',
15897 'notation',
15898 'numalign',
15899 'open',
15900 'rowalign',
15901 'rowlines',
15902 'rowspacing',
15903 'rowspan',
15904 'rspace',
15905 'rquote',
15906 'scriptlevel',
15907 'scriptminsize',
15908 'scriptsizemultiplier',
15909 'selection',
15910 'separator',
15911 'separators',
15912 'stretchy',
15913 'subscriptshift',
15914 'supscriptshift',
15915 'symmetric',
15916 'voffset',
15917 'width',
15918 'xmlns'
15919 ]);
15920 const xml = freeze([
15921 'xlink:href',
15922 'xml:id',
15923 'xlink:title',
15924 'xml:space',
15925 'xmlns:xlink'
15926 ]);
15927 const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm);
15928 const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
15929 const TMPLIT_EXPR = seal(/\${[\w\W]*}/gm);
15930 const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/);
15931 const ARIA_ATTR = seal(/^aria-[\-\w]+$/);
15932 const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i);
15933 const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
15934 const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g);
15935 const DOCTYPE_NAME = seal(/^html$/i);
15936 var EXPRESSIONS = Object.freeze({
15937 __proto__: null,
15938 MUSTACHE_EXPR: MUSTACHE_EXPR,
15939 ERB_EXPR: ERB_EXPR,
15940 TMPLIT_EXPR: TMPLIT_EXPR,
15941 DATA_ATTR: DATA_ATTR,
15942 ARIA_ATTR: ARIA_ATTR,
15943 IS_ALLOWED_URI: IS_ALLOWED_URI,
15944 IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
15945 ATTR_WHITESPACE: ATTR_WHITESPACE,
15946 DOCTYPE_NAME: DOCTYPE_NAME
15947 });
15948 const getGlobal = () => typeof window === 'undefined' ? null : window;
15949 const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
15950 if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
15951 return null;
15952 }
15953 let suffix = null;
15954 const ATTR_NAME = 'data-tt-policy-suffix';
15955 if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
15956 suffix = purifyHostElement.getAttribute(ATTR_NAME);
15957 }
15958 const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
15959 try {
15960 return trustedTypes.createPolicy(policyName, {
15961 createHTML(html) {
15962 return html;
15963 },
15964 createScriptURL(scriptUrl) {
15965 return scriptUrl;
15966 }
15967 });
15968 } catch (_) {
15969 console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
15970 return null;
15971 }
15972 };
15973 function createDOMPurify() {
15974 let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
15975 const DOMPurify = root => createDOMPurify(root);
15976 DOMPurify.version = '3.0.5';
15977 DOMPurify.removed = [];
15978 if (!window || !window.document || window.document.nodeType !== 9) {
15979 DOMPurify.isSupported = false;
15980 return DOMPurify;
15981 }
15982 const originalDocument = window.document;
15983 const currentScript = originalDocument.currentScript;
15984 let {document} = window;
15985 const {DocumentFragment, HTMLTemplateElement, Node, Element, NodeFilter, NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap, HTMLFormElement, DOMParser, trustedTypes} = window;
15986 const ElementPrototype = Element.prototype;
15987 const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
15988 const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
15989 const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
15990 const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
15991 if (typeof HTMLTemplateElement === 'function') {
15992 const template = document.createElement('template');
15993 if (template.content && template.content.ownerDocument) {
15994 document = template.content.ownerDocument;
15995 }
15996 }
15997 let trustedTypesPolicy;
15998 let emptyHTML = '';
15999 const {implementation, createNodeIterator, createDocumentFragment, getElementsByTagName} = document;
16000 const {importNode} = originalDocument;
16001 let hooks = {};
16002 DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
16003 const {MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR, DATA_ATTR, ARIA_ATTR, IS_SCRIPT_OR_DATA, ATTR_WHITESPACE} = EXPRESSIONS;
16004 let {IS_ALLOWED_URI: IS_ALLOWED_URI$1} = EXPRESSIONS;
16005 let ALLOWED_TAGS = null;
16006 const DEFAULT_ALLOWED_TAGS = addToSet({}, [
16007 ...html$1,
16008 ...svg$1,
16009 ...svgFilters,
16010 ...mathMl$1,
16011 ...text
16012 ]);
16013 let ALLOWED_ATTR = null;
16014 const DEFAULT_ALLOWED_ATTR = addToSet({}, [
16015 ...html,
16016 ...svg,
16017 ...mathMl,
16018 ...xml
16019 ]);
16020 let CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
16021 tagNameCheck: {
16022 writable: true,
16023 configurable: false,
16024 enumerable: true,
16025 value: null
16026 },
16027 attributeNameCheck: {
16028 writable: true,
16029 configurable: false,
16030 enumerable: true,
16031 value: null
16032 },
16033 allowCustomizedBuiltInElements: {
16034 writable: true,
16035 configurable: false,
16036 enumerable: true,
16037 value: false
16038 }
16039 }));
16040 let FORBID_TAGS = null;
16041 let FORBID_ATTR = null;
16042 let ALLOW_ARIA_ATTR = true;
16043 let ALLOW_DATA_ATTR = true;
16044 let ALLOW_UNKNOWN_PROTOCOLS = false;
16045 let ALLOW_SELF_CLOSE_IN_ATTR = true;
16046 let SAFE_FOR_TEMPLATES = false;
16047 let WHOLE_DOCUMENT = false;
16048 let SET_CONFIG = false;
16049 let FORCE_BODY = false;
16050 let RETURN_DOM = false;
16051 let RETURN_DOM_FRAGMENT = false;
16052 let RETURN_TRUSTED_TYPE = false;
16053 let SANITIZE_DOM = true;
16054 let SANITIZE_NAMED_PROPS = false;
16055 const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
16056 let KEEP_CONTENT = true;
16057 let IN_PLACE = false;
16058 let USE_PROFILES = {};
16059 let FORBID_CONTENTS = null;
16060 const DEFAULT_FORBID_CONTENTS = addToSet({}, [
16061 'annotation-xml',
16062 'audio',
16063 'colgroup',
16064 'desc',
16065 'foreignobject',
16066 'head',
16067 'iframe',
16068 'math',
16069 'mi',
16070 'mn',
16071 'mo',
16072 'ms',
16073 'mtext',
16074 'noembed',
16075 'noframes',
16076 'noscript',
16077 'plaintext',
16078 'script',
16079 'style',
16080 'svg',
16081 'template',
16082 'thead',
16083 'title',
16084 'video',
16085 'xmp'
16086 ]);
16087 let DATA_URI_TAGS = null;
16088 const DEFAULT_DATA_URI_TAGS = addToSet({}, [
16089 'audio',
16090 'video',
16091 'img',
16092 'source',
16093 'image',
16094 'track'
16095 ]);
16096 let URI_SAFE_ATTRIBUTES = null;
16097 const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [
16098 'alt',
16099 'class',
16100 'for',
16101 'id',
16102 'label',
16103 'name',
16104 'pattern',
16105 'placeholder',
16106 'role',
16107 'summary',
16108 'title',
16109 'value',
16110 'style',
16111 'xmlns'
16112 ]);
16113 const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
16114 const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
16115 const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
16116 let NAMESPACE = HTML_NAMESPACE;
16117 let IS_EMPTY_INPUT = false;
16118 let ALLOWED_NAMESPACES = null;
16119 const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [
16120 MATHML_NAMESPACE,
16121 SVG_NAMESPACE,
16122 HTML_NAMESPACE
16123 ], stringToString);
16124 let PARSER_MEDIA_TYPE;
16125 const SUPPORTED_PARSER_MEDIA_TYPES = [
16126 'application/xhtml+xml',
16127 'text/html'
16128 ];
16129 const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
16130 let transformCaseFunc;
16131 let CONFIG = null;
16132 const formElement = document.createElement('form');
16133 const isRegexOrFunction = function isRegexOrFunction(testValue) {
16134 return testValue instanceof RegExp || testValue instanceof Function;
16135 };
16136 const _parseConfig = function _parseConfig(cfg) {
16137 if (CONFIG && CONFIG === cfg) {
16138 return;
16139 }
16140 if (!cfg || typeof cfg !== 'object') {
16141 cfg = {};
16142 }
16143 cfg = clone(cfg);
16144 PARSER_MEDIA_TYPE = SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
16145 transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
16146 ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
16147 ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
16148 ALLOWED_NAMESPACES = 'ALLOWED_NAMESPACES' in cfg ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
16149 URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
16150 DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
16151 FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
16152 FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
16153 FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
16154 USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
16155 ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false;
16156 ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false;
16157 ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false;
16158 ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false;
16159 SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false;
16160 WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false;
16161 RETURN_DOM = cfg.RETURN_DOM || false;
16162 RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false;
16163 RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false;
16164 FORCE_BODY = cfg.FORCE_BODY || false;
16165 SANITIZE_DOM = cfg.SANITIZE_DOM !== false;
16166 SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false;
16167 KEEP_CONTENT = cfg.KEEP_CONTENT !== false;
16168 IN_PLACE = cfg.IN_PLACE || false;
16169 IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
16170 NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
16171 CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
16172 if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
16173 CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
16174 }
16175 if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
16176 CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
16177 }
16178 if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
16179 CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
16180 }
16181 if (SAFE_FOR_TEMPLATES) {
16182 ALLOW_DATA_ATTR = false;
16183 }
16184 if (RETURN_DOM_FRAGMENT) {
16185 RETURN_DOM = true;
16186 }
16187 if (USE_PROFILES) {
16188 ALLOWED_TAGS = addToSet({}, [...text]);
16189 ALLOWED_ATTR = [];
16190 if (USE_PROFILES.html === true) {
16191 addToSet(ALLOWED_TAGS, html$1);
16192 addToSet(ALLOWED_ATTR, html);
16193 }
16194 if (USE_PROFILES.svg === true) {
16195 addToSet(ALLOWED_TAGS, svg$1);
16196 addToSet(ALLOWED_ATTR, svg);
16197 addToSet(ALLOWED_ATTR, xml);
16198 }
16199 if (USE_PROFILES.svgFilters === true) {
16200 addToSet(ALLOWED_TAGS, svgFilters);
16201 addToSet(ALLOWED_ATTR, svg);
16202 addToSet(ALLOWED_ATTR, xml);
16203 }
16204 if (USE_PROFILES.mathMl === true) {
16205 addToSet(ALLOWED_TAGS, mathMl$1);
16206 addToSet(ALLOWED_ATTR, mathMl);
16207 addToSet(ALLOWED_ATTR, xml);
16208 }
16209 }
16210 if (cfg.ADD_TAGS) {
16211 if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
16212 ALLOWED_TAGS = clone(ALLOWED_TAGS);
16213 }
16214 addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
16215 }
16216 if (cfg.ADD_ATTR) {
16217 if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
16218 ALLOWED_ATTR = clone(ALLOWED_ATTR);
16219 }
16220 addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
16221 }
16222 if (cfg.ADD_URI_SAFE_ATTR) {
16223 addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
16224 }
16225 if (cfg.FORBID_CONTENTS) {
16226 if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
16227 FORBID_CONTENTS = clone(FORBID_CONTENTS);
16228 }
16229 addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
16230 }
16231 if (KEEP_CONTENT) {
16232 ALLOWED_TAGS['#text'] = true;
16233 }
16234 if (WHOLE_DOCUMENT) {
16235 addToSet(ALLOWED_TAGS, [
16236 'html',
16237 'head',
16238 'body'
16239 ]);
16240 }
16241 if (ALLOWED_TAGS.table) {
16242 addToSet(ALLOWED_TAGS, ['tbody']);
16243 delete FORBID_TAGS.tbody;
16244 }
16245 if (cfg.TRUSTED_TYPES_POLICY) {
16246 if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
16247 throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
16248 }
16249 if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
16250 throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
16251 }
16252 trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
16253 emptyHTML = trustedTypesPolicy.createHTML('');
16254 } else {
16255 if (trustedTypesPolicy === undefined) {
16256 trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
16257 }
16258 if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
16259 emptyHTML = trustedTypesPolicy.createHTML('');
16260 }
16261 }
16262 if (freeze) {
16263 freeze(cfg);
16264 }
16265 CONFIG = cfg;
16266 };
16267 const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [
16268 'mi',
16269 'mo',
16270 'mn',
16271 'ms',
16272 'mtext'
16273 ]);
16274 const HTML_INTEGRATION_POINTS = addToSet({}, [
16275 'foreignobject',
16276 'desc',
16277 'title',
16278 'annotation-xml'
16279 ]);
16280 const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [
16281 'title',
16282 'style',
16283 'font',
16284 'a',
16285 'script'
16286 ]);
16287 const ALL_SVG_TAGS = addToSet({}, svg$1);
16288 addToSet(ALL_SVG_TAGS, svgFilters);
16289 addToSet(ALL_SVG_TAGS, svgDisallowed);
16290 const ALL_MATHML_TAGS = addToSet({}, mathMl$1);
16291 addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
16292 const _checkValidNamespace = function _checkValidNamespace(element) {
16293 let parent = getParentNode(element);
16294 if (!parent || !parent.tagName) {
16295 parent = {
16296 namespaceURI: NAMESPACE,
16297 tagName: 'template'
16298 };
16299 }
16300 const tagName = stringToLowerCase(element.tagName);
16301 const parentTagName = stringToLowerCase(parent.tagName);
16302 if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
16303 return false;
16304 }
16305 if (element.namespaceURI === SVG_NAMESPACE) {
16306 if (parent.namespaceURI === HTML_NAMESPACE) {
16307 return tagName === 'svg';
16308 }
16309 if (parent.namespaceURI === MATHML_NAMESPACE) {
16310 return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
16311 }
16312 return Boolean(ALL_SVG_TAGS[tagName]);
16313 }
16314 if (element.namespaceURI === MATHML_NAMESPACE) {
16315 if (parent.namespaceURI === HTML_NAMESPACE) {
16316 return tagName === 'math';
16317 }
16318 if (parent.namespaceURI === SVG_NAMESPACE) {
16319 return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
16320 }
16321 return Boolean(ALL_MATHML_TAGS[tagName]);
16322 }
16323 if (element.namespaceURI === HTML_NAMESPACE) {
16324 if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
16325 return false;
16326 }
16327 if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
16328 return false;
16329 }
16330 return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
16331 }
16332 if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
16333 return true;
16334 }
16335 return false;
16336 };
16337 const _forceRemove = function _forceRemove(node) {
16338 arrayPush(DOMPurify.removed, { element: node });
16339 try {
16340 node.parentNode.removeChild(node);
16341 } catch (_) {
16342 node.remove();
16343 }
16344 };
16345 const _removeAttribute = function _removeAttribute(name, node) {
16346 try {
16347 arrayPush(DOMPurify.removed, {
16348 attribute: node.getAttributeNode(name),
16349 from: node
16350 });
16351 } catch (_) {
16352 arrayPush(DOMPurify.removed, {
16353 attribute: null,
16354 from: node
16355 });
16356 }
16357 node.removeAttribute(name);
16358 if (name === 'is' && !ALLOWED_ATTR[name]) {
16359 if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
16360 try {
16361 _forceRemove(node);
16362 } catch (_) {
16363 }
16364 } else {
16365 try {
16366 node.setAttribute(name, '');
16367 } catch (_) {
16368 }
16369 }
16370 }
16371 };
16372 const _initDocument = function _initDocument(dirty) {
16373 let doc;
16374 let leadingWhitespace;
16375 if (FORCE_BODY) {
16376 dirty = '<remove></remove>' + dirty;
16377 } else {
16378 const matches = stringMatch(dirty, /^[\r\n\t ]+/);
16379 leadingWhitespace = matches && matches[0];
16380 }
16381 if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
16382 dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
16383 }
16384 const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
16385 if (NAMESPACE === HTML_NAMESPACE) {
16386 try {
16387 doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
16388 } catch (_) {
16389 }
16390 }
16391 if (!doc || !doc.documentElement) {
16392 doc = implementation.createDocument(NAMESPACE, 'template', null);
16393 try {
16394 doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
16395 } catch (_) {
16396 }
16397 }
16398 const body = doc.body || doc.documentElement;
16399 if (dirty && leadingWhitespace) {
16400 body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
16401 }
16402 if (NAMESPACE === HTML_NAMESPACE) {
16403 return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
16404 }
16405 return WHOLE_DOCUMENT ? doc.documentElement : body;
16406 };
16407 const _createIterator = function _createIterator(root) {
16408 return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
16409 };
16410 const _isClobbered = function _isClobbered(elm) {
16411 return elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function');
16412 };
16413 const _isNode = function _isNode(object) {
16414 return typeof Node === 'object' ? object instanceof Node : object && typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
16415 };
16416 const _executeHook = function _executeHook(entryPoint, currentNode, data) {
16417 if (!hooks[entryPoint]) {
16418 return;
16419 }
16420 arrayForEach(hooks[entryPoint], hook => {
16421 hook.call(DOMPurify, currentNode, data, CONFIG);
16422 });
16423 };
16424 const _sanitizeElements = function _sanitizeElements(currentNode) {
16425 let content;
16426 _executeHook('beforeSanitizeElements', currentNode, null);
16427 if (_isClobbered(currentNode)) {
16428 _forceRemove(currentNode);
16429 return true;
16430 }
16431 const tagName = transformCaseFunc(currentNode.nodeName);
16432 _executeHook('uponSanitizeElement', currentNode, {
16433 tagName,
16434 allowedTags: ALLOWED_TAGS
16435 });
16436 if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
16437 _forceRemove(currentNode);
16438 return true;
16439 }
16440 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
16441 if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
16442 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName))
16443 return false;
16444 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName))
16445 return false;
16446 }
16447 if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
16448 const parentNode = getParentNode(currentNode) || currentNode.parentNode;
16449 const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
16450 if (childNodes && parentNode) {
16451 const childCount = childNodes.length;
16452 for (let i = childCount - 1; i >= 0; --i) {
16453 parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
16454 }
16455 }
16456 }
16457 _forceRemove(currentNode);
16458 return true;
16459 }
16460 if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
16461 _forceRemove(currentNode);
16462 return true;
16463 }
16464 if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
16465 _forceRemove(currentNode);
16466 return true;
16467 }
16468 if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
16469 content = currentNode.textContent;
16470 content = stringReplace(content, MUSTACHE_EXPR, ' ');
16471 content = stringReplace(content, ERB_EXPR, ' ');
16472 content = stringReplace(content, TMPLIT_EXPR, ' ');
16473 if (currentNode.textContent !== content) {
16474 arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
16475 currentNode.textContent = content;
16476 }
16477 }
16478 _executeHook('afterSanitizeElements', currentNode, null);
16479 return false;
16480 };
16481 const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
16482 if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
16483 return false;
16484 }
16485 if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName));
16486 else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName));
16487 else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
16488 if (_basicCustomElementTest(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)) || 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)));
16489 else {
16490 return false;
16491 }
16492 } else if (URI_SAFE_ATTRIBUTES[lcName]);
16493 else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, '')));
16494 else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]);
16495 else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, '')));
16496 else if (value) {
16497 return false;
16498 } else ;
16499 return true;
16500 };
16501 const _basicCustomElementTest = function _basicCustomElementTest(tagName) {
16502 return tagName.indexOf('-') > 0;
16503 };
16504 const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
16505 let attr;
16506 let value;
16507 let lcName;
16508 let l;
16509 _executeHook('beforeSanitizeAttributes', currentNode, null);
16510 const {attributes} = currentNode;
16511 if (!attributes) {
16512 return;
16513 }
16514 const hookEvent = {
16515 attrName: '',
16516 attrValue: '',
16517 keepAttr: true,
16518 allowedAttributes: ALLOWED_ATTR
16519 };
16520 l = attributes.length;
16521 while (l--) {
16522 attr = attributes[l];
16523 const {name, namespaceURI} = attr;
16524 value = name === 'value' ? attr.value : stringTrim(attr.value);
16525 const initValue = value;
16526 lcName = transformCaseFunc(name);
16527 hookEvent.attrName = lcName;
16528 hookEvent.attrValue = value;
16529 hookEvent.keepAttr = true;
16530 hookEvent.forceKeepAttr = undefined;
16531 _executeHook('uponSanitizeAttribute', currentNode, hookEvent);
16532 value = hookEvent.attrValue;
16533 if (hookEvent.forceKeepAttr) {
16534 continue;
16535 }
16536 if (!hookEvent.keepAttr) {
16537 _removeAttribute(name, currentNode);
16538 continue;
16539 }
16540 if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
16541 _removeAttribute(name, currentNode);
16542 continue;
16543 }
16544 if (SAFE_FOR_TEMPLATES) {
16545 value = stringReplace(value, MUSTACHE_EXPR, ' ');
16546 value = stringReplace(value, ERB_EXPR, ' ');
16547 value = stringReplace(value, TMPLIT_EXPR, ' ');
16548 }
16549 const lcTag = transformCaseFunc(currentNode.nodeName);
16550 if (!_isValidAttribute(lcTag, lcName, value)) {
16551 _removeAttribute(name, currentNode);
16552 continue;
16553 }
16554 if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
16555 _removeAttribute(name, currentNode);
16556 value = SANITIZE_NAMED_PROPS_PREFIX + value;
16557 }
16558 if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
16559 if (namespaceURI);
16560 else {
16561 switch (trustedTypes.getAttributeType(lcTag, lcName)) {
16562 case 'TrustedHTML': {
16563 value = trustedTypesPolicy.createHTML(value);
16564 break;
16565 }
16566 case 'TrustedScriptURL': {
16567 value = trustedTypesPolicy.createScriptURL(value);
16568 break;
16569 }
16570 }
16571 }
16572 }
16573 if (value !== initValue) {
16574 try {
16575 if (namespaceURI) {
16576 currentNode.setAttributeNS(namespaceURI, name, value);
16577 } else {
16578 currentNode.setAttribute(name, value);
16579 }
16580 } catch (_) {
16581 _removeAttribute(name, currentNode);
16582 }
16583 }
16584 }
16585 _executeHook('afterSanitizeAttributes', currentNode, null);
16586 };
16587 const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
16588 let shadowNode;
16589 const shadowIterator = _createIterator(fragment);
16590 _executeHook('beforeSanitizeShadowDOM', fragment, null);
16591 while (shadowNode = shadowIterator.nextNode()) {
16592 _executeHook('uponSanitizeShadowNode', shadowNode, null);
16593 if (_sanitizeElements(shadowNode)) {
16594 continue;
16595 }
16596 if (shadowNode.content instanceof DocumentFragment) {
16597 _sanitizeShadowDOM(shadowNode.content);
16598 }
16599 _sanitizeAttributes(shadowNode);
16600 }
16601 _executeHook('afterSanitizeShadowDOM', fragment, null);
16602 };
16603 DOMPurify.sanitize = function (dirty) {
16604 let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
16605 let body;
16606 let importedNode;
16607 let currentNode;
16608 let returnNode;
16609 IS_EMPTY_INPUT = !dirty;
16610 if (IS_EMPTY_INPUT) {
16611 dirty = '<!-->';
16612 }
16613 if (typeof dirty !== 'string' && !_isNode(dirty)) {
16614 if (typeof dirty.toString === 'function') {
16615 dirty = dirty.toString();
16616 if (typeof dirty !== 'string') {
16617 throw typeErrorCreate('dirty is not a string, aborting');
16618 }
16619 } else {
16620 throw typeErrorCreate('toString is not a function');
16621 }
16622 }
16623 if (!DOMPurify.isSupported) {
16624 return dirty;
16625 }
16626 if (!SET_CONFIG) {
16627 _parseConfig(cfg);
16628 }
16629 DOMPurify.removed = [];
16630 if (typeof dirty === 'string') {
16631 IN_PLACE = false;
16632 }
16633 if (IN_PLACE) {
16634 if (dirty.nodeName) {
16635 const tagName = transformCaseFunc(dirty.nodeName);
16636 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
16637 throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
16638 }
16639 }
16640 } else if (dirty instanceof Node) {
16641 body = _initDocument('<!---->');
16642 importedNode = body.ownerDocument.importNode(dirty, true);
16643 if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
16644 body = importedNode;
16645 } else if (importedNode.nodeName === 'HTML') {
16646 body = importedNode;
16647 } else {
16648 body.appendChild(importedNode);
16649 }
16650 } else {
16651 if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf('<') === -1) {
16652 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
16653 }
16654 body = _initDocument(dirty);
16655 if (!body) {
16656 return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
16657 }
16658 }
16659 if (body && FORCE_BODY) {
16660 _forceRemove(body.firstChild);
16661 }
16662 const nodeIterator = _createIterator(IN_PLACE ? dirty : body);
16663 while (currentNode = nodeIterator.nextNode()) {
16664 if (_sanitizeElements(currentNode)) {
16665 continue;
16666 }
16667 if (currentNode.content instanceof DocumentFragment) {
16668 _sanitizeShadowDOM(currentNode.content);
16669 }
16670 _sanitizeAttributes(currentNode);
16671 }
16672 if (IN_PLACE) {
16673 return dirty;
16674 }
16675 if (RETURN_DOM) {
16676 if (RETURN_DOM_FRAGMENT) {
16677 returnNode = createDocumentFragment.call(body.ownerDocument);
16678 while (body.firstChild) {
16679 returnNode.appendChild(body.firstChild);
16680 }
16681 } else {
16682 returnNode = body;
16683 }
16684 if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
16685 returnNode = importNode.call(originalDocument, returnNode, true);
16686 }
16687 return returnNode;
16688 }
16689 let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
16690 if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
16691 serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
16692 }
16693 if (SAFE_FOR_TEMPLATES) {
16694 serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR, ' ');
16695 serializedHTML = stringReplace(serializedHTML, ERB_EXPR, ' ');
16696 serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR, ' ');
16697 }
16698 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
16699 };
16700 DOMPurify.setConfig = function (cfg) {
16701 _parseConfig(cfg);
16702 SET_CONFIG = true;
16703 };
16704 DOMPurify.clearConfig = function () {
16705 CONFIG = null;
16706 SET_CONFIG = false;
16707 };
16708 DOMPurify.isValidAttribute = function (tag, attr, value) {
16709 if (!CONFIG) {
16710 _parseConfig({});
16711 }
16712 const lcTag = transformCaseFunc(tag);
16713 const lcName = transformCaseFunc(attr);
16714 return _isValidAttribute(lcTag, lcName, value);
16715 };
16716 DOMPurify.addHook = function (entryPoint, hookFunction) {
16717 if (typeof hookFunction !== 'function') {
16718 return;
16719 }
16720 hooks[entryPoint] = hooks[entryPoint] || [];
16721 arrayPush(hooks[entryPoint], hookFunction);
16722 };
16723 DOMPurify.removeHook = function (entryPoint) {
16724 if (hooks[entryPoint]) {
16725 return arrayPop(hooks[entryPoint]);
16726 }
16727 };
16728 DOMPurify.removeHooks = function (entryPoint) {
16729 if (hooks[entryPoint]) {
16730 hooks[entryPoint] = [];
16731 }
16732 };
16733 DOMPurify.removeAllHooks = function () {
16734 hooks = {};
16735 };
16736 return DOMPurify;
16737 }
16738 var purify = createDOMPurify();
16739
16740 const each$4 = Tools.each, trim = Tools.trim;
16741 const queryParts = [
16742 'source',
16743 'protocol',
16744 'authority',
16745 'userInfo',
16746 'user',
16747 'password',
16748 'host',
16749 'port',
16750 'relative',
16751 'path',
16752 'directory',
16753 'file',
16754 'query',
16755 'anchor'
16756 ];
16757 const DEFAULT_PORTS = {
16758 ftp: 21,
16759 http: 80,
16760 https: 443,
16761 mailto: 25
16762 };
16763 const safeSvgDataUrlElements = [
16764 'img',
16765 'video'
16766 ];
16767 const blockSvgDataUris = (allowSvgDataUrls, tagName) => {
16768 if (isNonNullable(allowSvgDataUrls)) {
16769 return !allowSvgDataUrls;
16770 } else {
16771 return isNonNullable(tagName) ? !contains$2(safeSvgDataUrlElements, tagName) : true;
16772 }
16773 };
16774 const decodeUri = encodedUri => {
16775 try {
16776 return decodeURIComponent(encodedUri);
16777 } catch (ex) {
16778 return unescape(encodedUri);
16779 }
16780 };
16781 const isInvalidUri = (settings, uri, tagName) => {
16782 const decodedUri = decodeUri(uri).replace(/\s/g, '');
16783 if (settings.allow_script_urls) {
16784 return false;
16785 } else if (/((java|vb)script|mhtml):/i.test(decodedUri)) {
16786 return true;
16787 } else if (settings.allow_html_data_urls) {
16788 return false;
16789 } else if (/^data:image\//i.test(decodedUri)) {
16790 return blockSvgDataUris(settings.allow_svg_data_urls, tagName) && /^data:image\/svg\+xml/i.test(decodedUri);
16791 } else {
16792 return /^data:/i.test(decodedUri);
16793 }
16794 };
16795 class URI {
16796 static parseDataUri(uri) {
16797 let type;
16798 const uriComponents = decodeURIComponent(uri).split(',');
16799 const matches = /data:([^;]+)/.exec(uriComponents[0]);
16800 if (matches) {
16801 type = matches[1];
16802 }
16803 return {
16804 type,
16805 data: uriComponents[1]
16806 };
16807 }
16808 static isDomSafe(uri, context, options = {}) {
16809 if (options.allow_script_urls) {
16810 return true;
16811 } else {
16812 const decodedUri = Entities.decode(uri).replace(/[\s\u0000-\u001F]+/g, '');
16813 return !isInvalidUri(options, decodedUri, context);
16814 }
16815 }
16816 static getDocumentBaseUrl(loc) {
16817 var _a;
16818 let baseUrl;
16819 if (loc.protocol.indexOf('http') !== 0 && loc.protocol !== 'file:') {
16820 baseUrl = (_a = loc.href) !== null && _a !== void 0 ? _a : '';
16821 } else {
16822 baseUrl = loc.protocol + '//' + loc.host + loc.pathname;
16823 }
16824 if (/^[^:]+:\/\/\/?[^\/]+\//.test(baseUrl)) {
16825 baseUrl = baseUrl.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
16826 if (!/[\/\\]$/.test(baseUrl)) {
16827 baseUrl += '/';
16828 }
16829 }
16830 return baseUrl;
16831 }
16832 constructor(url, settings = {}) {
16833 this.path = '';
16834 this.directory = '';
16835 url = trim(url);
16836 this.settings = settings;
16837 const baseUri = settings.base_uri;
16838 const self = this;
16839 if (/^([\w\-]+):([^\/]{2})/i.test(url) || /^\s*#/.test(url)) {
16840 self.source = url;
16841 return;
16842 }
16843 const isProtocolRelative = url.indexOf('//') === 0;
16844 if (url.indexOf('/') === 0 && !isProtocolRelative) {
16845 url = (baseUri ? baseUri.protocol || 'http' : 'http') + '://mce_host' + url;
16846 }
16847 if (!/^[\w\-]*:?\/\//.test(url)) {
16848 const baseUrl = baseUri ? baseUri.path : new URI(document.location.href).directory;
16849 if ((baseUri === null || baseUri === void 0 ? void 0 : baseUri.protocol) === '') {
16850 url = '//mce_host' + self.toAbsPath(baseUrl, url);
16851 } else {
16852 const match = /([^#?]*)([#?]?.*)/.exec(url);
16853 if (match) {
16854 url = (baseUri && baseUri.protocol || 'http') + '://mce_host' + self.toAbsPath(baseUrl, match[1]) + match[2];
16855 }
16856 }
16857 }
16858 url = url.replace(/@@/g, '(mce_at)');
16859 const urlMatch = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?(\[[a-zA-Z0-9:.%]+\]|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url);
16860 if (urlMatch) {
16861 each$4(queryParts, (v, i) => {
16862 let part = urlMatch[i];
16863 if (part) {
16864 part = part.replace(/\(mce_at\)/g, '@@');
16865 }
16866 self[v] = part;
16867 });
16868 }
16869 if (baseUri) {
16870 if (!self.protocol) {
16871 self.protocol = baseUri.protocol;
16872 }
16873 if (!self.userInfo) {
16874 self.userInfo = baseUri.userInfo;
16875 }
16876 if (!self.port && self.host === 'mce_host') {
16877 self.port = baseUri.port;
16878 }
16879 if (!self.host || self.host === 'mce_host') {
16880 self.host = baseUri.host;
16881 }
16882 self.source = '';
16883 }
16884 if (isProtocolRelative) {
16885 self.protocol = '';
16886 }
16887 }
16888 setPath(path) {
16889 const pathMatch = /^(.*?)\/?(\w+)?$/.exec(path);
16890 if (pathMatch) {
16891 this.path = pathMatch[0];
16892 this.directory = pathMatch[1];
16893 this.file = pathMatch[2];
16894 }
16895 this.source = '';
16896 this.getURI();
16897 }
16898 toRelative(uri) {
16899 if (uri === './') {
16900 return uri;
16901 }
16902 const relativeUri = new URI(uri, { base_uri: this });
16903 if (relativeUri.host !== 'mce_host' && this.host !== relativeUri.host && relativeUri.host || this.port !== relativeUri.port || this.protocol !== relativeUri.protocol && relativeUri.protocol !== '') {
16904 return relativeUri.getURI();
16905 }
16906 const tu = this.getURI(), uu = relativeUri.getURI();
16907 if (tu === uu || tu.charAt(tu.length - 1) === '/' && tu.substr(0, tu.length - 1) === uu) {
16908 return tu;
16909 }
16910 let output = this.toRelPath(this.path, relativeUri.path);
16911 if (relativeUri.query) {
16912 output += '?' + relativeUri.query;
16913 }
16914 if (relativeUri.anchor) {
16915 output += '#' + relativeUri.anchor;
16916 }
16917 return output;
16918 }
16919 toAbsolute(uri, noHost) {
16920 const absoluteUri = new URI(uri, { base_uri: this });
16921 return absoluteUri.getURI(noHost && this.isSameOrigin(absoluteUri));
16922 }
16923 isSameOrigin(uri) {
16924 if (this.host == uri.host && this.protocol == uri.protocol) {
16925 if (this.port == uri.port) {
16926 return true;
16927 }
16928 const defaultPort = this.protocol ? DEFAULT_PORTS[this.protocol] : null;
16929 if (defaultPort && (this.port || defaultPort) == (uri.port || defaultPort)) {
16930 return true;
16931 }
16932 }
16933 return false;
16934 }
16935 toRelPath(base, path) {
16936 let breakPoint = 0, out = '', i, l;
16937 const normalizedBase = base.substring(0, base.lastIndexOf('/')).split('/');
16938 const items = path.split('/');
16939 if (normalizedBase.length >= items.length) {
16940 for (i = 0, l = normalizedBase.length; i < l; i++) {
16941 if (i >= items.length || normalizedBase[i] !== items[i]) {
16942 breakPoint = i + 1;
16943 break;
16944 }
16945 }
16946 }
16947 if (normalizedBase.length < items.length) {
16948 for (i = 0, l = items.length; i < l; i++) {
16949 if (i >= normalizedBase.length || normalizedBase[i] !== items[i]) {
16950 breakPoint = i + 1;
16951 break;
16952 }
16953 }
16954 }
16955 if (breakPoint === 1) {
16956 return path;
16957 }
16958 for (i = 0, l = normalizedBase.length - (breakPoint - 1); i < l; i++) {
16959 out += '../';
16960 }
16961 for (i = breakPoint - 1, l = items.length; i < l; i++) {
16962 if (i !== breakPoint - 1) {
16963 out += '/' + items[i];
16964 } else {
16965 out += items[i];
16966 }
16967 }
16968 return out;
16969 }
16970 toAbsPath(base, path) {
16971 let nb = 0;
16972 const tr = /\/$/.test(path) ? '/' : '';
16973 const normalizedBase = base.split('/');
16974 const normalizedPath = path.split('/');
16975 const baseParts = [];
16976 each$4(normalizedBase, k => {
16977 if (k) {
16978 baseParts.push(k);
16979 }
16980 });
16981 const pathParts = [];
16982 for (let i = normalizedPath.length - 1; i >= 0; i--) {
16983 if (normalizedPath[i].length === 0 || normalizedPath[i] === '.') {
16984 continue;
16985 }
16986 if (normalizedPath[i] === '..') {
16987 nb++;
16988 continue;
16989 }
16990 if (nb > 0) {
16991 nb--;
16992 continue;
16993 }
16994 pathParts.push(normalizedPath[i]);
16995 }
16996 const i = baseParts.length - nb;
16997 let outPath;
16998 if (i <= 0) {
16999 outPath = reverse(pathParts).join('/');
17000 } else {
17001 outPath = baseParts.slice(0, i).join('/') + '/' + reverse(pathParts).join('/');
17002 }
17003 if (outPath.indexOf('/') !== 0) {
17004 outPath = '/' + outPath;
17005 }
17006 if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) {
17007 outPath += tr;
17008 }
17009 return outPath;
17010 }
17011 getURI(noProtoHost = false) {
17012 let s;
17013 if (!this.source || noProtoHost) {
17014 s = '';
17015 if (!noProtoHost) {
17016 if (this.protocol) {
17017 s += this.protocol + '://';
17018 } else {
17019 s += '//';
17020 }
17021 if (this.userInfo) {
17022 s += this.userInfo + '@';
17023 }
17024 if (this.host) {
17025 s += this.host;
17026 }
17027 if (this.port) {
17028 s += ':' + this.port;
17029 }
17030 }
17031 if (this.path) {
17032 s += this.path;
17033 }
17034 if (this.query) {
17035 s += '?' + this.query;
17036 }
17037 if (this.anchor) {
17038 s += '#' + this.anchor;
17039 }
17040 this.source = s;
17041 }
17042 return this.source;
17043 }
17044 }
17045
17046 const filteredUrlAttrs = Tools.makeMap('src,href,data,background,action,formaction,poster,xlink:href');
17047 const internalElementAttr = 'data-mce-type';
17048 let uid = 0;
17049 const processNode = (node, settings, schema, scope, evt) => {
17050 var _a, _b, _c, _d;
17051 const validate = settings.validate;
17052 const specialElements = schema.getSpecialElements();
17053 if (node.nodeType === COMMENT && !settings.allow_conditional_comments && /^\[if/i.test((_a = node.nodeValue) !== null && _a !== void 0 ? _a : '')) {
17054 node.nodeValue = ' ' + node.nodeValue;
17055 }
17056 const lcTagName = (_b = evt === null || evt === void 0 ? void 0 : evt.tagName) !== null && _b !== void 0 ? _b : node.nodeName.toLowerCase();
17057 if (scope !== 'html' && schema.isValid(scope)) {
17058 if (isNonNullable(evt)) {
17059 evt.allowedTags[lcTagName] = true;
17060 }
17061 return;
17062 }
17063 if (node.nodeType !== ELEMENT || lcTagName === 'body') {
17064 return;
17065 }
17066 const element = SugarElement.fromDom(node);
17067 const isInternalElement = has$1(element, internalElementAttr);
17068 const bogus = get$9(element, 'data-mce-bogus');
17069 if (!isInternalElement && isString(bogus)) {
17070 if (bogus === 'all') {
17071 remove$4(element);
17072 } else {
17073 unwrap(element);
17074 }
17075 return;
17076 }
17077 const rule = schema.getElementRule(lcTagName);
17078 if (validate && !rule) {
17079 if (has$2(specialElements, lcTagName)) {
17080 remove$4(element);
17081 } else {
17082 unwrap(element);
17083 }
17084 return;
17085 } else {
17086 if (isNonNullable(evt)) {
17087 evt.allowedTags[lcTagName] = true;
17088 }
17089 }
17090 if (validate && rule && !isInternalElement) {
17091 each$e((_c = rule.attributesForced) !== null && _c !== void 0 ? _c : [], attr => {
17092 set$3(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
17093 });
17094 each$e((_d = rule.attributesDefault) !== null && _d !== void 0 ? _d : [], attr => {
17095 if (!has$1(element, attr.name)) {
17096 set$3(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
17097 }
17098 });
17099 if (rule.attributesRequired && !exists(rule.attributesRequired, attr => has$1(element, attr))) {
17100 unwrap(element);
17101 return;
17102 }
17103 if (rule.removeEmptyAttrs && hasNone(element)) {
17104 unwrap(element);
17105 return;
17106 }
17107 if (rule.outputName && rule.outputName !== lcTagName) {
17108 mutate(element, rule.outputName);
17109 }
17110 }
17111 };
17112 const processAttr = (ele, settings, schema, scope, evt) => {
17113 const tagName = ele.tagName.toLowerCase();
17114 const {attrName, attrValue} = evt;
17115 evt.keepAttr = shouldKeepAttribute(settings, schema, scope, tagName, attrName, attrValue);
17116 if (evt.keepAttr) {
17117 evt.allowedAttributes[attrName] = true;
17118 if (isBooleanAttribute(attrName, schema)) {
17119 evt.attrValue = attrName;
17120 }
17121 if (settings.allow_svg_data_urls && startsWith(attrValue, 'data:image/svg+xml')) {
17122 evt.forceKeepAttr = true;
17123 }
17124 } else if (isRequiredAttributeOfInternalElement(ele, attrName)) {
17125 evt.forceKeepAttr = true;
17126 }
17127 };
17128 const shouldKeepAttribute = (settings, schema, scope, tagName, attrName, attrValue) => {
17129 if (scope !== 'html' && !isNonHtmlElementRootName(tagName)) {
17130 return true;
17131 }
17132 return !(attrName in filteredUrlAttrs && isInvalidUri(settings, attrValue, tagName)) && (!settings.validate || schema.isValid(tagName, attrName) || startsWith(attrName, 'data-') || startsWith(attrName, 'aria-'));
17133 };
17134 const isRequiredAttributeOfInternalElement = (ele, attrName) => ele.hasAttribute(internalElementAttr) && (attrName === 'id' || attrName === 'class' || attrName === 'style');
17135 const isBooleanAttribute = (attrName, schema) => attrName in schema.getBoolAttrs();
17136 const filterAttributes = (ele, settings, schema, scope) => {
17137 const {attributes} = ele;
17138 for (let i = attributes.length - 1; i >= 0; i--) {
17139 const attr = attributes[i];
17140 const attrName = attr.name;
17141 const attrValue = attr.value;
17142 if (!shouldKeepAttribute(settings, schema, scope, ele.tagName.toLowerCase(), attrName, attrValue) && !isRequiredAttributeOfInternalElement(ele, attrName)) {
17143 ele.removeAttribute(attrName);
17144 } else if (isBooleanAttribute(attrName, schema)) {
17145 ele.setAttribute(attrName, attrName);
17146 }
17147 }
17148 };
17149 const setupPurify = (settings, schema, namespaceTracker) => {
17150 const purify$1 = purify();
17151 purify$1.addHook('uponSanitizeElement', (ele, evt) => {
17152 processNode(ele, settings, schema, namespaceTracker.track(ele), evt);
17153 });
17154 purify$1.addHook('uponSanitizeAttribute', (ele, evt) => {
17155 processAttr(ele, settings, schema, namespaceTracker.current(), evt);
17156 });
17157 return purify$1;
17158 };
17159 const getPurifyConfig = (settings, mimeType) => {
17160 const basePurifyConfig = {
17161 IN_PLACE: true,
17162 ALLOW_UNKNOWN_PROTOCOLS: true,
17163 ALLOWED_TAGS: [
17164 '#comment',
17165 '#cdata-section',
17166 'body'
17167 ],
17168 ALLOWED_ATTR: []
17169 };
17170 const config = { ...basePurifyConfig };
17171 config.PARSER_MEDIA_TYPE = mimeType;
17172 if (settings.allow_script_urls) {
17173 config.ALLOWED_URI_REGEXP = /.*/;
17174 } else if (settings.allow_html_data_urls) {
17175 config.ALLOWED_URI_REGEXP = /^(?!(\w+script|mhtml):)/i;
17176 }
17177 return config;
17178 };
17179 const sanitizeNamespaceElement = ele => {
17180 const namespaceType = toScopeType(ele);
17181 if (namespaceType === 'svg') {
17182 const xlinkAttrs = [
17183 'type',
17184 'href',
17185 'role',
17186 'arcrole',
17187 'title',
17188 'show',
17189 'actuate',
17190 'label',
17191 'from',
17192 'to'
17193 ].map(name => `xlink:${ name }`);
17194 const config = {
17195 IN_PLACE: true,
17196 USE_PROFILES: {
17197 html: true,
17198 svg: true,
17199 svgFilters: true
17200 },
17201 ALLOWED_ATTR: xlinkAttrs
17202 };
17203 purify().sanitize(ele, config);
17204 } else if (namespaceType === 'math') {
17205 const config = {
17206 IN_PLACE: true,
17207 USE_PROFILES: { mathMl: true }
17208 };
17209 purify().sanitize(ele, config);
17210 } else {
17211 throw new Error('Not a namespace element');
17212 }
17213 };
17214 const getSanitizer = (settings, schema) => {
17215 const namespaceTracker = createNamespaceTracker();
17216 if (settings.sanitize) {
17217 const purify = setupPurify(settings, schema, namespaceTracker);
17218 const sanitizeHtmlElement = (body, mimeType) => {
17219 purify.sanitize(body, getPurifyConfig(settings, mimeType));
17220 purify.removed = [];
17221 namespaceTracker.reset();
17222 };
17223 return {
17224 sanitizeHtmlElement,
17225 sanitizeNamespaceElement
17226 };
17227 } else {
17228 const sanitizeHtmlElement = (body, _mimeType) => {
17229 const nodeIterator = document.createNodeIterator(body, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT);
17230 let node;
17231 while (node = nodeIterator.nextNode()) {
17232 const currentScope = namespaceTracker.track(node);
17233 processNode(node, settings, schema, currentScope);
17234 if (isElement$6(node)) {
17235 filterAttributes(node, settings, schema, currentScope);
17236 }
17237 }
17238 namespaceTracker.reset();
17239 };
17240 const sanitizeNamespaceElement = noop;
17241 return {
17242 sanitizeHtmlElement,
17243 sanitizeNamespaceElement
17244 };
17245 }
17246 };
17247
17248 const makeMap = Tools.makeMap, extend$1 = Tools.extend;
17249 const transferChildren = (parent, nativeParent, specialElements, nsSanitizer) => {
17250 const parentName = parent.name;
17251 const isSpecial = parentName in specialElements && parentName !== 'title' && parentName !== 'textarea';
17252 const childNodes = nativeParent.childNodes;
17253 for (let ni = 0, nl = childNodes.length; ni < nl; ni++) {
17254 const nativeChild = childNodes[ni];
17255 const child = new AstNode(nativeChild.nodeName.toLowerCase(), nativeChild.nodeType);
17256 if (isElement$6(nativeChild)) {
17257 const attributes = nativeChild.attributes;
17258 for (let ai = 0, al = attributes.length; ai < al; ai++) {
17259 const attr = attributes[ai];
17260 child.attr(attr.name, attr.value);
17261 }
17262 if (isNonHtmlElementRootName(child.name)) {
17263 nsSanitizer(nativeChild);
17264 child.value = nativeChild.innerHTML;
17265 }
17266 } else if (isText$b(nativeChild)) {
17267 child.value = nativeChild.data;
17268 if (isSpecial) {
17269 child.raw = true;
17270 }
17271 } else if (isComment(nativeChild) || isCData(nativeChild) || isPi(nativeChild)) {
17272 child.value = nativeChild.data;
17273 }
17274 if (!isNonHtmlElementRootName(child.name)) {
17275 transferChildren(child, nativeChild, specialElements, nsSanitizer);
17276 }
17277 parent.append(child);
17278 }
17279 };
17280 const walkTree = (root, preprocessors, postprocessors) => {
17281 const traverseOrder = [];
17282 for (let node = root, lastNode = node; node; lastNode = node, node = node.walk()) {
17283 const tempNode = node;
17284 each$e(preprocessors, preprocess => preprocess(tempNode));
17285 if (isNullable(tempNode.parent) && tempNode !== root) {
17286 node = lastNode;
17287 } else {
17288 traverseOrder.push(tempNode);
17289 }
17290 }
17291 for (let i = traverseOrder.length - 1; i >= 0; i--) {
17292 const node = traverseOrder[i];
17293 each$e(postprocessors, postprocess => postprocess(node));
17294 }
17295 };
17296 const whitespaceCleaner = (root, schema, settings, args) => {
17297 const validate = settings.validate;
17298 const nonEmptyElements = schema.getNonEmptyElements();
17299 const whitespaceElements = schema.getWhitespaceElements();
17300 const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
17301 const textRootBlockElements = getTextRootBlockElements(schema);
17302 const allWhiteSpaceRegExp = /[ \t\r\n]+/g;
17303 const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
17304 const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
17305 const hasWhitespaceParent = node => {
17306 let tempNode = node.parent;
17307 while (isNonNullable(tempNode)) {
17308 if (tempNode.name in whitespaceElements) {
17309 return true;
17310 } else {
17311 tempNode = tempNode.parent;
17312 }
17313 }
17314 return false;
17315 };
17316 const isTextRootBlockEmpty = node => {
17317 let tempNode = node;
17318 while (isNonNullable(tempNode)) {
17319 if (tempNode.name in textRootBlockElements) {
17320 return isEmpty(schema, nonEmptyElements, whitespaceElements, tempNode);
17321 } else {
17322 tempNode = tempNode.parent;
17323 }
17324 }
17325 return false;
17326 };
17327 const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node) || isNonHtmlElementRootName(node.name) && node.parent === root;
17328 const isAtEdgeOfBlock = (node, start) => {
17329 const neighbour = start ? node.prev : node.next;
17330 if (isNonNullable(neighbour) || isNullable(node.parent)) {
17331 return false;
17332 }
17333 return isBlock(node.parent) && (node.parent !== root || args.isRootContent === true);
17334 };
17335 const preprocess = node => {
17336 var _a;
17337 if (node.type === 3) {
17338 if (!hasWhitespaceParent(node)) {
17339 let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
17340 text = text.replace(allWhiteSpaceRegExp, ' ');
17341 if (isLineBreakNode(node.prev, isBlock) || isAtEdgeOfBlock(node, true)) {
17342 text = text.replace(startWhiteSpaceRegExp, '');
17343 }
17344 if (text.length === 0) {
17345 node.remove();
17346 } else {
17347 node.value = text;
17348 }
17349 }
17350 }
17351 };
17352 const postprocess = node => {
17353 var _a;
17354 if (node.type === 1) {
17355 const elementRule = schema.getElementRule(node.name);
17356 if (validate && elementRule) {
17357 const isNodeEmpty = isEmpty(schema, nonEmptyElements, whitespaceElements, node);
17358 if (elementRule.paddInEmptyBlock && isNodeEmpty && isTextRootBlockEmpty(node)) {
17359 paddEmptyNode(settings, args, isBlock, node);
17360 } else if (elementRule.removeEmpty && isNodeEmpty) {
17361 if (isBlock(node)) {
17362 node.remove();
17363 } else {
17364 node.unwrap();
17365 }
17366 } else if (elementRule.paddEmpty && (isNodeEmpty || isPaddedWithNbsp(node))) {
17367 paddEmptyNode(settings, args, isBlock, node);
17368 }
17369 }
17370 } else if (node.type === 3) {
17371 if (!hasWhitespaceParent(node)) {
17372 let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
17373 if (node.next && isBlock(node.next) || isAtEdgeOfBlock(node, false)) {
17374 text = text.replace(endWhiteSpaceRegExp, '');
17375 }
17376 if (text.length === 0) {
17377 node.remove();
17378 } else {
17379 node.value = text;
17380 }
17381 }
17382 }
17383 };
17384 return [
17385 preprocess,
17386 postprocess
17387 ];
17388 };
17389 const getRootBlockName = (settings, args) => {
17390 var _a;
17391 const name = (_a = args.forced_root_block) !== null && _a !== void 0 ? _a : settings.forced_root_block;
17392 if (name === false) {
17393 return '';
17394 } else if (name === true) {
17395 return 'p';
17396 } else {
17397 return name;
17398 }
17399 };
17400 const DomParser = (settings = {}, schema = Schema()) => {
17401 const nodeFilterRegistry = create$8();
17402 const attributeFilterRegistry = create$8();
17403 const defaultedSettings = {
17404 validate: true,
17405 root_name: 'body',
17406 sanitize: true,
17407 ...settings
17408 };
17409 const parser = new DOMParser();
17410 const sanitizer = getSanitizer(defaultedSettings, schema);
17411 const parseAndSanitizeWithContext = (html, rootName, format = 'html') => {
17412 const mimeType = format === 'xhtml' ? 'application/xhtml+xml' : 'text/html';
17413 const isSpecialRoot = has$2(schema.getSpecialElements(), rootName.toLowerCase());
17414 const content = isSpecialRoot ? `<${ rootName }>${ html }</${ rootName }>` : html;
17415 const wrappedHtml = format === 'xhtml' ? `<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>${ content }</body></html>` : `<body>${ content }</body>`;
17416 const body = parser.parseFromString(wrappedHtml, mimeType).body;
17417 sanitizer.sanitizeHtmlElement(body, mimeType);
17418 return isSpecialRoot ? body.firstChild : body;
17419 };
17420 const addNodeFilter = nodeFilterRegistry.addFilter;
17421 const getNodeFilters = nodeFilterRegistry.getFilters;
17422 const removeNodeFilter = nodeFilterRegistry.removeFilter;
17423 const addAttributeFilter = attributeFilterRegistry.addFilter;
17424 const getAttributeFilters = attributeFilterRegistry.getFilters;
17425 const removeAttributeFilter = attributeFilterRegistry.removeFilter;
17426 const findInvalidChildren = (node, invalidChildren) => {
17427 if (isInvalid(schema, node)) {
17428 invalidChildren.push(node);
17429 }
17430 };
17431 const isWrappableNode = (blockElements, node) => {
17432 const isInternalElement = isString(node.attr(internalElementAttr));
17433 const isInlineElement = node.type === 1 && (!has$2(blockElements, node.name) && !isTransparentAstBlock(schema, node)) && !isNonHtmlElementRootName(node.name);
17434 return node.type === 3 || isInlineElement && !isInternalElement;
17435 };
17436 const addRootBlocks = (rootNode, rootBlockName) => {
17437 const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
17438 const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
17439 const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
17440 let node = rootNode.firstChild, rootBlockNode = null;
17441 const trim = rootBlock => {
17442 var _a, _b;
17443 if (rootBlock) {
17444 node = rootBlock.firstChild;
17445 if (node && node.type === 3) {
17446 node.value = (_a = node.value) === null || _a === void 0 ? void 0 : _a.replace(startWhiteSpaceRegExp, '');
17447 }
17448 node = rootBlock.lastChild;
17449 if (node && node.type === 3) {
17450 node.value = (_b = node.value) === null || _b === void 0 ? void 0 : _b.replace(endWhiteSpaceRegExp, '');
17451 }
17452 }
17453 };
17454 if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) {
17455 return;
17456 }
17457 while (node) {
17458 const next = node.next;
17459 if (isWrappableNode(blockElements, node)) {
17460 if (!rootBlockNode) {
17461 rootBlockNode = new AstNode(rootBlockName, 1);
17462 rootBlockNode.attr(defaultedSettings.forced_root_block_attrs);
17463 rootNode.insert(rootBlockNode, node);
17464 rootBlockNode.append(node);
17465 } else {
17466 rootBlockNode.append(node);
17467 }
17468 } else {
17469 trim(rootBlockNode);
17470 rootBlockNode = null;
17471 }
17472 node = next;
17473 }
17474 trim(rootBlockNode);
17475 };
17476 const parse = (html, args = {}) => {
17477 var _a;
17478 const validate = defaultedSettings.validate;
17479 const rootName = (_a = args.context) !== null && _a !== void 0 ? _a : defaultedSettings.root_name;
17480 const element = parseAndSanitizeWithContext(html, rootName, args.format);
17481 updateChildren(schema, element);
17482 const rootNode = new AstNode(rootName, 11);
17483 transferChildren(rootNode, element, schema.getSpecialElements(), sanitizer.sanitizeNamespaceElement);
17484 element.innerHTML = '';
17485 const [whitespacePre, whitespacePost] = whitespaceCleaner(rootNode, schema, defaultedSettings, args);
17486 const invalidChildren = [];
17487 const invalidFinder = validate ? node => findInvalidChildren(node, invalidChildren) : noop;
17488 const matches = {
17489 nodes: {},
17490 attributes: {}
17491 };
17492 const matchFinder = node => matchNode$1(getNodeFilters(), getAttributeFilters(), node, matches);
17493 walkTree(rootNode, [
17494 whitespacePre,
17495 matchFinder
17496 ], [
17497 whitespacePost,
17498 invalidFinder
17499 ]);
17500 invalidChildren.reverse();
17501 if (validate && invalidChildren.length > 0) {
17502 if (args.context) {
17503 const {
17504 pass: topLevelChildren,
17505 fail: otherChildren
17506 } = partition$2(invalidChildren, child => child.parent === rootNode);
17507 cleanInvalidNodes(otherChildren, schema, rootNode, matchFinder);
17508 args.invalid = topLevelChildren.length > 0;
17509 } else {
17510 cleanInvalidNodes(invalidChildren, schema, rootNode, matchFinder);
17511 }
17512 }
17513 const rootBlockName = getRootBlockName(defaultedSettings, args);
17514 if (rootBlockName && (rootNode.name === 'body' || args.isRootContent)) {
17515 addRootBlocks(rootNode, rootBlockName);
17516 }
17517 if (!args.invalid) {
17518 runFilters(matches, args);
17519 }
17520 return rootNode;
17521 };
17522 const exports = {
17523 schema,
17524 addAttributeFilter,
17525 getAttributeFilters,
17526 removeAttributeFilter,
17527 addNodeFilter,
17528 getNodeFilters,
17529 removeNodeFilter,
17530 parse
17531 };
17532 register$4(exports, defaultedSettings);
17533 register$5(exports, defaultedSettings, schema);
17534 return exports;
17535 };
17536
17537 const serializeContent = content => isTreeNode(content) ? HtmlSerializer({ validate: false }).serialize(content) : content;
17538 const withSerializedContent = (content, fireEvent, parserSettings) => {
17539 const serializedContent = serializeContent(content);
17540 const eventArgs = fireEvent(serializedContent);
17541 if (eventArgs.isDefaultPrevented()) {
17542 return eventArgs;
17543 } else if (isTreeNode(content)) {
17544 if (eventArgs.content !== serializedContent) {
17545 const rootNode = DomParser({
17546 validate: false,
17547 forced_root_block: false,
17548 ...parserSettings
17549 }).parse(eventArgs.content, { context: content.name });
17550 return {
17551 ...eventArgs,
17552 content: rootNode
17553 };
17554 } else {
17555 return {
17556 ...eventArgs,
17557 content
17558 };
17559 }
17560 } else {
17561 return eventArgs;
17562 }
17563 };
17564 const makeParserSettings = editor => ({
17565 sanitize: shouldSanitizeXss(editor),
17566 sandbox_iframes: shouldSandboxIframes(editor),
17567 sandbox_iframes_exclusions: getSandboxIframesExclusions(editor)
17568 });
17569 const preProcessGetContent = (editor, args) => {
17570 if (args.no_events) {
17571 return Result.value(args);
17572 } else {
17573 const eventArgs = fireBeforeGetContent(editor, args);
17574 if (eventArgs.isDefaultPrevented()) {
17575 return Result.error(fireGetContent(editor, {
17576 content: '',
17577 ...eventArgs
17578 }).content);
17579 } else {
17580 return Result.value(eventArgs);
17581 }
17582 }
17583 };
17584 const postProcessGetContent = (editor, content, args) => {
17585 if (args.no_events) {
17586 return content;
17587 } else {
17588 const processedEventArgs = withSerializedContent(content, content => fireGetContent(editor, {
17589 ...args,
17590 content
17591 }), makeParserSettings(editor));
17592 return processedEventArgs.content;
17593 }
17594 };
17595 const preProcessSetContent = (editor, args) => {
17596 if (args.no_events) {
17597 return Result.value(args);
17598 } else {
17599 const processedEventArgs = withSerializedContent(args.content, content => fireBeforeSetContent(editor, {
17600 ...args,
17601 content
17602 }), makeParserSettings(editor));
17603 if (processedEventArgs.isDefaultPrevented()) {
17604 fireSetContent(editor, processedEventArgs);
17605 return Result.error(undefined);
17606 } else {
17607 return Result.value(processedEventArgs);
17608 }
17609 }
17610 };
17611 const postProcessSetContent = (editor, content, args) => {
17612 if (!args.no_events) {
17613 fireSetContent(editor, {
17614 ...args,
17615 content
17616 });
17617 }
17618 };
17619
17620 const tableModel = (element, width, rows) => ({
17621 element,
17622 width,
17623 rows
17624 });
17625 const tableRow = (element, cells) => ({
17626 element,
17627 cells
17628 });
17629 const cellPosition = (x, y) => ({
17630 x,
17631 y
17632 });
17633 const getSpan = (td, key) => {
17634 return getOpt(td, key).bind(toInt).getOr(1);
17635 };
17636 const fillout = (table, x, y, tr, td) => {
17637 const rowspan = getSpan(td, 'rowspan');
17638 const colspan = getSpan(td, 'colspan');
17639 const rows = table.rows;
17640 for (let y2 = y; y2 < y + rowspan; y2++) {
17641 if (!rows[y2]) {
17642 rows[y2] = tableRow(deep$1(tr), []);
17643 }
17644 for (let x2 = x; x2 < x + colspan; x2++) {
17645 const cells = rows[y2].cells;
17646 cells[x2] = y2 === y && x2 === x ? td : shallow$1(td);
17647 }
17648 }
17649 };
17650 const cellExists = (table, x, y) => {
17651 const rows = table.rows;
17652 const cells = rows[y] ? rows[y].cells : [];
17653 return !!cells[x];
17654 };
17655 const skipCellsX = (table, x, y) => {
17656 while (cellExists(table, x, y)) {
17657 x++;
17658 }
17659 return x;
17660 };
17661 const getWidth = rows => {
17662 return foldl(rows, (acc, row) => {
17663 return row.cells.length > acc ? row.cells.length : acc;
17664 }, 0);
17665 };
17666 const findElementPos = (table, element) => {
17667 const rows = table.rows;
17668 for (let y = 0; y < rows.length; y++) {
17669 const cells = rows[y].cells;
17670 for (let x = 0; x < cells.length; x++) {
17671 if (eq(cells[x], element)) {
17672 return Optional.some(cellPosition(x, y));
17673 }
17674 }
17675 }
17676 return Optional.none();
17677 };
17678 const extractRows = (table, sx, sy, ex, ey) => {
17679 const newRows = [];
17680 const rows = table.rows;
17681 for (let y = sy; y <= ey; y++) {
17682 const cells = rows[y].cells;
17683 const slice = sx < ex ? cells.slice(sx, ex + 1) : cells.slice(ex, sx + 1);
17684 newRows.push(tableRow(rows[y].element, slice));
17685 }
17686 return newRows;
17687 };
17688 const subTable = (table, startPos, endPos) => {
17689 const sx = startPos.x, sy = startPos.y;
17690 const ex = endPos.x, ey = endPos.y;
17691 const newRows = sy < ey ? extractRows(table, sx, sy, ex, ey) : extractRows(table, sx, ey, ex, sy);
17692 return tableModel(table.element, getWidth(newRows), newRows);
17693 };
17694 const createDomTable = (table, rows) => {
17695 const tableElement = shallow$1(table.element);
17696 const tableBody = SugarElement.fromTag('tbody');
17697 append(tableBody, rows);
17698 append$1(tableElement, tableBody);
17699 return tableElement;
17700 };
17701 const modelRowsToDomRows = table => {
17702 return map$3(table.rows, row => {
17703 const cells = map$3(row.cells, cell => {
17704 const td = deep$1(cell);
17705 remove$9(td, 'colspan');
17706 remove$9(td, 'rowspan');
17707 return td;
17708 });
17709 const tr = shallow$1(row.element);
17710 append(tr, cells);
17711 return tr;
17712 });
17713 };
17714 const fromDom = tableElm => {
17715 const table = tableModel(shallow$1(tableElm), 0, []);
17716 each$e(descendants(tableElm, 'tr'), (tr, y) => {
17717 each$e(descendants(tr, 'td,th'), (td, x) => {
17718 fillout(table, skipCellsX(table, x, y), y, tr, td);
17719 });
17720 });
17721 return tableModel(table.element, getWidth(table.rows), table.rows);
17722 };
17723 const toDom = table => {
17724 return createDomTable(table, modelRowsToDomRows(table));
17725 };
17726 const subsection = (table, startElement, endElement) => {
17727 return findElementPos(table, startElement).bind(startPos => {
17728 return findElementPos(table, endElement).map(endPos => {
17729 return subTable(table, startPos, endPos);
17730 });
17731 });
17732 };
17733
17734 const findParentListContainer = parents => find$2(parents, elm => name(elm) === 'ul' || name(elm) === 'ol');
17735 const getFullySelectedListWrappers = (parents, rng) => find$2(parents, elm => name(elm) === 'li' && hasAllContentsSelected(elm, rng)).fold(constant([]), _li => findParentListContainer(parents).map(listCont => {
17736 const listElm = SugarElement.fromTag(name(listCont));
17737 const listStyles = filter$4(getAllRaw(listCont), (_style, name) => startsWith(name, 'list-style'));
17738 setAll(listElm, listStyles);
17739 return [
17740 SugarElement.fromTag('li'),
17741 listElm
17742 ];
17743 }).getOr([]));
17744 const wrap = (innerElm, elms) => {
17745 const wrapped = foldl(elms, (acc, elm) => {
17746 append$1(elm, acc);
17747 return elm;
17748 }, innerElm);
17749 return elms.length > 0 ? fromElements([wrapped]) : wrapped;
17750 };
17751 const directListWrappers = commonAnchorContainer => {
17752 if (isListItem$1(commonAnchorContainer)) {
17753 return parent(commonAnchorContainer).filter(isList).fold(constant([]), listElm => [
17754 commonAnchorContainer,
17755 listElm
17756 ]);
17757 } else {
17758 return isList(commonAnchorContainer) ? [commonAnchorContainer] : [];
17759 }
17760 };
17761 const getWrapElements = (rootNode, rng, schema) => {
17762 const commonAnchorContainer = SugarElement.fromDom(rng.commonAncestorContainer);
17763 const parents = parentsAndSelf(commonAnchorContainer, rootNode);
17764 const wrapElements = filter$5(parents, el => schema.isWrapper(name(el)));
17765 const listWrappers = getFullySelectedListWrappers(parents, rng);
17766 const allWrappers = wrapElements.concat(listWrappers.length ? listWrappers : directListWrappers(commonAnchorContainer));
17767 return map$3(allWrappers, shallow$1);
17768 };
17769 const emptyFragment = () => fromElements([]);
17770 const getFragmentFromRange = (rootNode, rng, schema) => wrap(SugarElement.fromDom(rng.cloneContents()), getWrapElements(rootNode, rng, schema));
17771 const getParentTable = (rootElm, cell) => ancestor$3(cell, 'table', curry(eq, rootElm));
17772 const getTableFragment = (rootNode, selectedTableCells) => getParentTable(rootNode, selectedTableCells[0]).bind(tableElm => {
17773 const firstCell = selectedTableCells[0];
17774 const lastCell = selectedTableCells[selectedTableCells.length - 1];
17775 const fullTableModel = fromDom(tableElm);
17776 return subsection(fullTableModel, firstCell, lastCell).map(sectionedTableModel => fromElements([toDom(sectionedTableModel)]));
17777 }).getOrThunk(emptyFragment);
17778 const getSelectionFragment = (rootNode, ranges, schema) => ranges.length > 0 && ranges[0].collapsed ? emptyFragment() : getFragmentFromRange(rootNode, ranges[0], schema);
17779 const read$3 = (rootNode, ranges, schema) => {
17780 const selectedCells = getCellsFromElementOrRanges(ranges, rootNode);
17781 return selectedCells.length > 0 ? getTableFragment(rootNode, selectedCells) : getSelectionFragment(rootNode, ranges, schema);
17782 };
17783
17784 const isCollapsibleWhitespace = (text, index) => index >= 0 && index < text.length && isWhiteSpace(text.charAt(index));
17785 const getInnerText = bin => {
17786 return trim$2(bin.innerText);
17787 };
17788 const getContextNodeName = parentBlockOpt => parentBlockOpt.map(block => block.nodeName).getOr('div').toLowerCase();
17789 const getTextContent = editor => Optional.from(editor.selection.getRng()).map(rng => {
17790 var _a;
17791 const parentBlockOpt = Optional.from(editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock));
17792 const body = editor.getBody();
17793 const contextNodeName = getContextNodeName(parentBlockOpt);
17794 const rangeContentClone = SugarElement.fromDom(rng.cloneContents());
17795 cleanupBogusElements(rangeContentClone);
17796 cleanupInputNames(rangeContentClone);
17797 const bin = editor.dom.add(body, contextNodeName, {
17798 'data-mce-bogus': 'all',
17799 'style': 'overflow: hidden; opacity: 0;'
17800 }, rangeContentClone.dom);
17801 const text = getInnerText(bin);
17802 const nonRenderedText = trim$2((_a = bin.textContent) !== null && _a !== void 0 ? _a : '');
17803 editor.dom.remove(bin);
17804 if (isCollapsibleWhitespace(nonRenderedText, 0) || isCollapsibleWhitespace(nonRenderedText, nonRenderedText.length - 1)) {
17805 const parentBlock = parentBlockOpt.getOr(body);
17806 const parentBlockText = getInnerText(parentBlock);
17807 const textIndex = parentBlockText.indexOf(text);
17808 if (textIndex === -1) {
17809 return text;
17810 } else {
17811 const hasProceedingSpace = isCollapsibleWhitespace(parentBlockText, textIndex - 1);
17812 const hasTrailingSpace = isCollapsibleWhitespace(parentBlockText, textIndex + text.length);
17813 return (hasProceedingSpace ? ' ' : '') + text + (hasTrailingSpace ? ' ' : '');
17814 }
17815 } else {
17816 return text;
17817 }
17818 }).getOr('');
17819 const getSerializedContent = (editor, args) => {
17820 const rng = editor.selection.getRng(), tmpElm = editor.dom.create('body');
17821 const sel = editor.selection.getSel();
17822 const ranges = processRanges(editor, getRanges$1(sel));
17823 const fragment = args.contextual ? read$3(SugarElement.fromDom(editor.getBody()), ranges, editor.schema).dom : rng.cloneContents();
17824 if (fragment) {
17825 tmpElm.appendChild(fragment);
17826 }
17827 return editor.selection.serializer.serialize(tmpElm, args);
17828 };
17829 const extractSelectedContent = (editor, args) => {
17830 if (args.format === 'text') {
17831 return getTextContent(editor);
17832 } else {
17833 const content = getSerializedContent(editor, args);
17834 if (args.format === 'tree') {
17835 return content;
17836 } else {
17837 return editor.selection.isCollapsed() ? '' : content;
17838 }
17839 }
17840 };
17841 const setupArgs$3 = (args, format) => ({
17842 ...args,
17843 format,
17844 get: true,
17845 selection: true,
17846 getInner: true
17847 });
17848 const getSelectedContentInternal = (editor, format, args = {}) => {
17849 const defaultedArgs = setupArgs$3(args, format);
17850 return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
17851 const content = extractSelectedContent(editor, updatedArgs);
17852 return postProcessGetContent(editor, content, updatedArgs);
17853 });
17854 };
17855
17856 const KEEP = 0, INSERT = 1, DELETE = 2;
17857 const diff = (left, right) => {
17858 const size = left.length + right.length + 2;
17859 const vDown = new Array(size);
17860 const vUp = new Array(size);
17861 const snake = (start, end, diag) => {
17862 return {
17863 start,
17864 end,
17865 diag
17866 };
17867 };
17868 const buildScript = (start1, end1, start2, end2, script) => {
17869 const middle = getMiddleSnake(start1, end1, start2, end2);
17870 if (middle === null || middle.start === end1 && middle.diag === end1 - end2 || middle.end === start1 && middle.diag === start1 - start2) {
17871 let i = start1;
17872 let j = start2;
17873 while (i < end1 || j < end2) {
17874 if (i < end1 && j < end2 && left[i] === right[j]) {
17875 script.push([
17876 KEEP,
17877 left[i]
17878 ]);
17879 ++i;
17880 ++j;
17881 } else {
17882 if (end1 - start1 > end2 - start2) {
17883 script.push([
17884 DELETE,
17885 left[i]
17886 ]);
17887 ++i;
17888 } else {
17889 script.push([
17890 INSERT,
17891 right[j]
17892 ]);
17893 ++j;
17894 }
17895 }
17896 }
17897 } else {
17898 buildScript(start1, middle.start, start2, middle.start - middle.diag, script);
17899 for (let i2 = middle.start; i2 < middle.end; ++i2) {
17900 script.push([
17901 KEEP,
17902 left[i2]
17903 ]);
17904 }
17905 buildScript(middle.end, end1, middle.end - middle.diag, end2, script);
17906 }
17907 };
17908 const buildSnake = (start, diag, end1, end2) => {
17909 let end = start;
17910 while (end - diag < end2 && end < end1 && left[end] === right[end - diag]) {
17911 ++end;
17912 }
17913 return snake(start, end, diag);
17914 };
17915 const getMiddleSnake = (start1, end1, start2, end2) => {
17916 const m = end1 - start1;
17917 const n = end2 - start2;
17918 if (m === 0 || n === 0) {
17919 return null;
17920 }
17921 const delta = m - n;
17922 const sum = n + m;
17923 const offset = (sum % 2 === 0 ? sum : sum + 1) / 2;
17924 vDown[1 + offset] = start1;
17925 vUp[1 + offset] = end1 + 1;
17926 let d, k, i, x, y;
17927 for (d = 0; d <= offset; ++d) {
17928 for (k = -d; k <= d; k += 2) {
17929 i = k + offset;
17930 if (k === -d || k !== d && vDown[i - 1] < vDown[i + 1]) {
17931 vDown[i] = vDown[i + 1];
17932 } else {
17933 vDown[i] = vDown[i - 1] + 1;
17934 }
17935 x = vDown[i];
17936 y = x - start1 + start2 - k;
17937 while (x < end1 && y < end2 && left[x] === right[y]) {
17938 vDown[i] = ++x;
17939 ++y;
17940 }
17941 if (delta % 2 !== 0 && delta - d <= k && k <= delta + d) {
17942 if (vUp[i - delta] <= vDown[i]) {
17943 return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
17944 }
17945 }
17946 }
17947 for (k = delta - d; k <= delta + d; k += 2) {
17948 i = k + offset - delta;
17949 if (k === delta - d || k !== delta + d && vUp[i + 1] <= vUp[i - 1]) {
17950 vUp[i] = vUp[i + 1] - 1;
17951 } else {
17952 vUp[i] = vUp[i - 1];
17953 }
17954 x = vUp[i] - 1;
17955 y = x - start1 + start2 - k;
17956 while (x >= start1 && y >= start2 && left[x] === right[y]) {
17957 vUp[i] = x--;
17958 y--;
17959 }
17960 if (delta % 2 === 0 && -d <= k && k <= d) {
17961 if (vUp[i] <= vDown[i + delta]) {
17962 return buildSnake(vUp[i], k + start1 - start2, end1, end2);
17963 }
17964 }
17965 }
17966 }
17967 return null;
17968 };
17969 const script = [];
17970 buildScript(0, left.length, 0, right.length, script);
17971 return script;
17972 };
17973
17974 const getOuterHtml = elm => {
17975 if (isElement$6(elm)) {
17976 return elm.outerHTML;
17977 } else if (isText$b(elm)) {
17978 return Entities.encodeRaw(elm.data, false);
17979 } else if (isComment(elm)) {
17980 return '<!--' + elm.data + '-->';
17981 }
17982 return '';
17983 };
17984 const createFragment = html => {
17985 let node;
17986 const container = document.createElement('div');
17987 const frag = document.createDocumentFragment();
17988 if (html) {
17989 container.innerHTML = html;
17990 }
17991 while (node = container.firstChild) {
17992 frag.appendChild(node);
17993 }
17994 return frag;
17995 };
17996 const insertAt = (elm, html, index) => {
17997 const fragment = createFragment(html);
17998 if (elm.hasChildNodes() && index < elm.childNodes.length) {
17999 const target = elm.childNodes[index];
18000 elm.insertBefore(fragment, target);
18001 } else {
18002 elm.appendChild(fragment);
18003 }
18004 };
18005 const removeAt = (elm, index) => {
18006 if (elm.hasChildNodes() && index < elm.childNodes.length) {
18007 const target = elm.childNodes[index];
18008 elm.removeChild(target);
18009 }
18010 };
18011 const applyDiff = (diff, elm) => {
18012 let index = 0;
18013 each$e(diff, action => {
18014 if (action[0] === KEEP) {
18015 index++;
18016 } else if (action[0] === INSERT) {
18017 insertAt(elm, action[1], index);
18018 index++;
18019 } else if (action[0] === DELETE) {
18020 removeAt(elm, index);
18021 }
18022 });
18023 };
18024 const read$2 = (elm, trimZwsp) => filter$5(map$3(from(elm.childNodes), trimZwsp ? compose(trim$2, getOuterHtml) : getOuterHtml), item => {
18025 return item.length > 0;
18026 });
18027 const write = (fragments, elm) => {
18028 const currentFragments = map$3(from(elm.childNodes), getOuterHtml);
18029 applyDiff(diff(currentFragments, fragments), elm);
18030 return elm;
18031 };
18032
18033 const lazyTempDocument = cached(() => document.implementation.createHTMLDocument('undo'));
18034 const hasIframes = body => body.querySelector('iframe') !== null;
18035 const createFragmentedLevel = fragments => {
18036 return {
18037 type: 'fragmented',
18038 fragments,
18039 content: '',
18040 bookmark: null,
18041 beforeBookmark: null
18042 };
18043 };
18044 const createCompleteLevel = content => {
18045 return {
18046 type: 'complete',
18047 fragments: null,
18048 content,
18049 bookmark: null,
18050 beforeBookmark: null
18051 };
18052 };
18053 const createFromEditor = editor => {
18054 const tempAttrs = editor.serializer.getTempAttrs();
18055 const body = trim$1(editor.getBody(), tempAttrs);
18056 return hasIframes(body) ? createFragmentedLevel(read$2(body, true)) : createCompleteLevel(trim$2(body.innerHTML));
18057 };
18058 const applyToEditor = (editor, level, before) => {
18059 const bookmark = before ? level.beforeBookmark : level.bookmark;
18060 if (level.type === 'fragmented') {
18061 write(level.fragments, editor.getBody());
18062 } else {
18063 editor.setContent(level.content, {
18064 format: 'raw',
18065 no_selection: isNonNullable(bookmark) && isPathBookmark(bookmark) ? !bookmark.isFakeCaret : true
18066 });
18067 }
18068 if (bookmark) {
18069 editor.selection.moveToBookmark(bookmark);
18070 editor.selection.scrollIntoView();
18071 }
18072 };
18073 const getLevelContent = level => {
18074 return level.type === 'fragmented' ? level.fragments.join('') : level.content;
18075 };
18076 const getCleanLevelContent = level => {
18077 const elm = SugarElement.fromTag('body', lazyTempDocument());
18078 set$1(elm, getLevelContent(level));
18079 each$e(descendants(elm, '*[data-mce-bogus]'), unwrap);
18080 return get$6(elm);
18081 };
18082 const hasEqualContent = (level1, level2) => getLevelContent(level1) === getLevelContent(level2);
18083 const hasEqualCleanedContent = (level1, level2) => getCleanLevelContent(level1) === getCleanLevelContent(level2);
18084 const isEq$1 = (level1, level2) => {
18085 if (!level1 || !level2) {
18086 return false;
18087 } else if (hasEqualContent(level1, level2)) {
18088 return true;
18089 } else {
18090 return hasEqualCleanedContent(level1, level2);
18091 }
18092 };
18093
18094 const isUnlocked = locks => locks.get() === 0;
18095
18096 const setTyping = (undoManager, typing, locks) => {
18097 if (isUnlocked(locks)) {
18098 undoManager.typing = typing;
18099 }
18100 };
18101 const endTyping = (undoManager, locks) => {
18102 if (undoManager.typing) {
18103 setTyping(undoManager, false, locks);
18104 undoManager.add();
18105 }
18106 };
18107 const endTypingLevelIgnoreLocks = undoManager => {
18108 if (undoManager.typing) {
18109 undoManager.typing = false;
18110 undoManager.add();
18111 }
18112 };
18113
18114 const beforeChange$1 = (editor, locks, beforeBookmark) => {
18115 if (isUnlocked(locks)) {
18116 beforeBookmark.set(getUndoBookmark(editor.selection));
18117 }
18118 };
18119 const addUndoLevel$1 = (editor, undoManager, index, locks, beforeBookmark, level, event) => {
18120 const currentLevel = createFromEditor(editor);
18121 const newLevel = Tools.extend(level || {}, currentLevel);
18122 if (!isUnlocked(locks) || editor.removed) {
18123 return null;
18124 }
18125 const lastLevel = undoManager.data[index.get()];
18126 if (editor.dispatch('BeforeAddUndo', {
18127 level: newLevel,
18128 lastLevel,
18129 originalEvent: event
18130 }).isDefaultPrevented()) {
18131 return null;
18132 }
18133 if (lastLevel && isEq$1(lastLevel, newLevel)) {
18134 return null;
18135 }
18136 if (undoManager.data[index.get()]) {
18137 beforeBookmark.get().each(bm => {
18138 undoManager.data[index.get()].beforeBookmark = bm;
18139 });
18140 }
18141 const customUndoRedoLevels = getCustomUndoRedoLevels(editor);
18142 if (customUndoRedoLevels) {
18143 if (undoManager.data.length > customUndoRedoLevels) {
18144 for (let i = 0; i < undoManager.data.length - 1; i++) {
18145 undoManager.data[i] = undoManager.data[i + 1];
18146 }
18147 undoManager.data.length--;
18148 index.set(undoManager.data.length);
18149 }
18150 }
18151 newLevel.bookmark = getUndoBookmark(editor.selection);
18152 if (index.get() < undoManager.data.length - 1) {
18153 undoManager.data.length = index.get() + 1;
18154 }
18155 undoManager.data.push(newLevel);
18156 index.set(undoManager.data.length - 1);
18157 const args = {
18158 level: newLevel,
18159 lastLevel,
18160 originalEvent: event
18161 };
18162 if (index.get() > 0) {
18163 editor.setDirty(true);
18164 editor.dispatch('AddUndo', args);
18165 editor.dispatch('change', args);
18166 } else {
18167 editor.dispatch('AddUndo', args);
18168 }
18169 return newLevel;
18170 };
18171 const clear$1 = (editor, undoManager, index) => {
18172 undoManager.data = [];
18173 index.set(0);
18174 undoManager.typing = false;
18175 editor.dispatch('ClearUndos');
18176 };
18177 const extra$1 = (editor, undoManager, index, callback1, callback2) => {
18178 if (undoManager.transact(callback1)) {
18179 const bookmark = undoManager.data[index.get()].bookmark;
18180 const lastLevel = undoManager.data[index.get() - 1];
18181 applyToEditor(editor, lastLevel, true);
18182 if (undoManager.transact(callback2)) {
18183 undoManager.data[index.get() - 1].beforeBookmark = bookmark;
18184 }
18185 }
18186 };
18187 const redo$1 = (editor, index, data) => {
18188 let level;
18189 if (index.get() < data.length - 1) {
18190 index.set(index.get() + 1);
18191 level = data[index.get()];
18192 applyToEditor(editor, level, false);
18193 editor.setDirty(true);
18194 editor.dispatch('Redo', { level });
18195 }
18196 return level;
18197 };
18198 const undo$1 = (editor, undoManager, locks, index) => {
18199 let level;
18200 if (undoManager.typing) {
18201 undoManager.add();
18202 undoManager.typing = false;
18203 setTyping(undoManager, false, locks);
18204 }
18205 if (index.get() > 0) {
18206 index.set(index.get() - 1);
18207 level = undoManager.data[index.get()];
18208 applyToEditor(editor, level, true);
18209 editor.setDirty(true);
18210 editor.dispatch('Undo', { level });
18211 }
18212 return level;
18213 };
18214 const reset$1 = undoManager => {
18215 undoManager.clear();
18216 undoManager.add();
18217 };
18218 const hasUndo$1 = (editor, undoManager, index) => index.get() > 0 || undoManager.typing && undoManager.data[0] && !isEq$1(createFromEditor(editor), undoManager.data[0]);
18219 const hasRedo$1 = (undoManager, index) => index.get() < undoManager.data.length - 1 && !undoManager.typing;
18220 const transact$1 = (undoManager, locks, callback) => {
18221 endTyping(undoManager, locks);
18222 undoManager.beforeChange();
18223 undoManager.ignore(callback);
18224 return undoManager.add();
18225 };
18226 const ignore$1 = (locks, callback) => {
18227 try {
18228 locks.set(locks.get() + 1);
18229 callback();
18230 } finally {
18231 locks.set(locks.get() - 1);
18232 }
18233 };
18234
18235 const addVisualInternal = (editor, elm) => {
18236 const dom = editor.dom;
18237 const scope = isNonNullable(elm) ? elm : editor.getBody();
18238 each$e(dom.select('table,a', scope), matchedElm => {
18239 switch (matchedElm.nodeName) {
18240 case 'TABLE':
18241 const cls = getVisualAidsTableClass(editor);
18242 const value = dom.getAttrib(matchedElm, 'border');
18243 if ((!value || value === '0') && editor.hasVisual) {
18244 dom.addClass(matchedElm, cls);
18245 } else {
18246 dom.removeClass(matchedElm, cls);
18247 }
18248 break;
18249 case 'A':
18250 if (!dom.getAttrib(matchedElm, 'href')) {
18251 const value = dom.getAttrib(matchedElm, 'name') || matchedElm.id;
18252 const cls = getVisualAidsAnchorClass(editor);
18253 if (value && editor.hasVisual) {
18254 dom.addClass(matchedElm, cls);
18255 } else {
18256 dom.removeClass(matchedElm, cls);
18257 }
18258 }
18259 break;
18260 }
18261 });
18262 editor.dispatch('VisualAid', {
18263 element: elm,
18264 hasVisual: editor.hasVisual
18265 });
18266 };
18267
18268 const makePlainAdaptor = editor => ({
18269 init: { bindEvents: noop },
18270 undoManager: {
18271 beforeChange: (locks, beforeBookmark) => beforeChange$1(editor, locks, beforeBookmark),
18272 add: (undoManager, index, locks, beforeBookmark, level, event) => addUndoLevel$1(editor, undoManager, index, locks, beforeBookmark, level, event),
18273 undo: (undoManager, locks, index) => undo$1(editor, undoManager, locks, index),
18274 redo: (index, data) => redo$1(editor, index, data),
18275 clear: (undoManager, index) => clear$1(editor, undoManager, index),
18276 reset: undoManager => reset$1(undoManager),
18277 hasUndo: (undoManager, index) => hasUndo$1(editor, undoManager, index),
18278 hasRedo: (undoManager, index) => hasRedo$1(undoManager, index),
18279 transact: (undoManager, locks, callback) => transact$1(undoManager, locks, callback),
18280 ignore: (locks, callback) => ignore$1(locks, callback),
18281 extra: (undoManager, index, callback1, callback2) => extra$1(editor, undoManager, index, callback1, callback2)
18282 },
18283 formatter: {
18284 match: (name, vars, node, similar) => match$2(editor, name, vars, node, similar),
18285 matchAll: (names, vars) => matchAll(editor, names, vars),
18286 matchNode: (node, name, vars, similar) => matchNode(editor, node, name, vars, similar),
18287 canApply: name => canApply(editor, name),
18288 closest: names => closest(editor, names),
18289 apply: (name, vars, node) => applyFormat$1(editor, name, vars, node),
18290 remove: (name, vars, node, similar) => removeFormat$1(editor, name, vars, node, similar),
18291 toggle: (name, vars, node) => toggle(editor, name, vars, node),
18292 formatChanged: (registeredFormatListeners, formats, callback, similar, vars) => formatChangedInternal(editor, registeredFormatListeners, formats, callback, similar, vars)
18293 },
18294 editor: {
18295 getContent: args => getContentInternal(editor, args),
18296 setContent: (content, args) => setContentInternal(editor, content, args),
18297 insertContent: (value, details) => insertHtmlAtCaret(editor, value, details),
18298 addVisual: elm => addVisualInternal(editor, elm)
18299 },
18300 selection: { getContent: (format, args) => getSelectedContentInternal(editor, format, args) },
18301 autocompleter: {
18302 addDecoration: noop,
18303 removeDecoration: noop
18304 },
18305 raw: { getModel: () => Optional.none() }
18306 });
18307 const makeRtcAdaptor = rtcEditor => {
18308 const defaultVars = vars => isObject(vars) ? vars : {};
18309 const {init, undoManager, formatter, editor, selection, autocompleter, raw} = rtcEditor;
18310 return {
18311 init: { bindEvents: init.bindEvents },
18312 undoManager: {
18313 beforeChange: undoManager.beforeChange,
18314 add: undoManager.add,
18315 undo: undoManager.undo,
18316 redo: undoManager.redo,
18317 clear: undoManager.clear,
18318 reset: undoManager.reset,
18319 hasUndo: undoManager.hasUndo,
18320 hasRedo: undoManager.hasRedo,
18321 transact: (_undoManager, _locks, fn) => undoManager.transact(fn),
18322 ignore: (_locks, callback) => undoManager.ignore(callback),
18323 extra: (_undoManager, _index, callback1, callback2) => undoManager.extra(callback1, callback2)
18324 },
18325 formatter: {
18326 match: (name, vars, _node, similar) => formatter.match(name, defaultVars(vars), similar),
18327 matchAll: formatter.matchAll,
18328 matchNode: formatter.matchNode,
18329 canApply: name => formatter.canApply(name),
18330 closest: names => formatter.closest(names),
18331 apply: (name, vars, _node) => formatter.apply(name, defaultVars(vars)),
18332 remove: (name, vars, _node, _similar) => formatter.remove(name, defaultVars(vars)),
18333 toggle: (name, vars, _node) => formatter.toggle(name, defaultVars(vars)),
18334 formatChanged: (_rfl, formats, callback, similar, vars) => formatter.formatChanged(formats, callback, similar, vars)
18335 },
18336 editor: {
18337 getContent: args => editor.getContent(args),
18338 setContent: (content, args) => {
18339 return {
18340 content: editor.setContent(content, args),
18341 html: ''
18342 };
18343 },
18344 insertContent: (content, _details) => {
18345 editor.insertContent(content);
18346 return '';
18347 },
18348 addVisual: editor.addVisual
18349 },
18350 selection: { getContent: (_format, args) => selection.getContent(args) },
18351 autocompleter: {
18352 addDecoration: autocompleter.addDecoration,
18353 removeDecoration: autocompleter.removeDecoration
18354 },
18355 raw: { getModel: () => Optional.some(raw.getRawModel()) }
18356 };
18357 };
18358 const makeNoopAdaptor = () => {
18359 const nul = constant(null);
18360 const empty = constant('');
18361 return {
18362 init: { bindEvents: noop },
18363 undoManager: {
18364 beforeChange: noop,
18365 add: nul,
18366 undo: nul,
18367 redo: nul,
18368 clear: noop,
18369 reset: noop,
18370 hasUndo: never,
18371 hasRedo: never,
18372 transact: nul,
18373 ignore: noop,
18374 extra: noop
18375 },
18376 formatter: {
18377 match: never,
18378 matchAll: constant([]),
18379 matchNode: constant(undefined),
18380 canApply: never,
18381 closest: empty,
18382 apply: noop,
18383 remove: noop,
18384 toggle: noop,
18385 formatChanged: constant({ unbind: noop })
18386 },
18387 editor: {
18388 getContent: empty,
18389 setContent: constant({
18390 content: '',
18391 html: ''
18392 }),
18393 insertContent: constant(''),
18394 addVisual: noop
18395 },
18396 selection: { getContent: empty },
18397 autocompleter: {
18398 addDecoration: noop,
18399 removeDecoration: noop
18400 },
18401 raw: { getModel: constant(Optional.none()) }
18402 };
18403 };
18404 const isRtc = editor => has$2(editor.plugins, 'rtc');
18405 const getRtcSetup = editor => get$a(editor.plugins, 'rtc').bind(rtcPlugin => Optional.from(rtcPlugin.setup));
18406 const setup$t = editor => {
18407 const editorCast = editor;
18408 return getRtcSetup(editor).fold(() => {
18409 editorCast.rtcInstance = makePlainAdaptor(editor);
18410 return Optional.none();
18411 }, setup => {
18412 editorCast.rtcInstance = makeNoopAdaptor();
18413 return Optional.some(() => setup().then(rtcEditor => {
18414 editorCast.rtcInstance = makeRtcAdaptor(rtcEditor);
18415 return rtcEditor.rtc.isRemote;
18416 }));
18417 });
18418 };
18419 const getRtcInstanceWithFallback = editor => editor.rtcInstance ? editor.rtcInstance : makePlainAdaptor(editor);
18420 const getRtcInstanceWithError = editor => {
18421 const rtcInstance = editor.rtcInstance;
18422 if (!rtcInstance) {
18423 throw new Error('Failed to get RTC instance not yet initialized.');
18424 } else {
18425 return rtcInstance;
18426 }
18427 };
18428 const beforeChange = (editor, locks, beforeBookmark) => {
18429 getRtcInstanceWithError(editor).undoManager.beforeChange(locks, beforeBookmark);
18430 };
18431 const addUndoLevel = (editor, undoManager, index, locks, beforeBookmark, level, event) => getRtcInstanceWithError(editor).undoManager.add(undoManager, index, locks, beforeBookmark, level, event);
18432 const undo = (editor, undoManager, locks, index) => getRtcInstanceWithError(editor).undoManager.undo(undoManager, locks, index);
18433 const redo = (editor, index, data) => getRtcInstanceWithError(editor).undoManager.redo(index, data);
18434 const clear = (editor, undoManager, index) => {
18435 getRtcInstanceWithError(editor).undoManager.clear(undoManager, index);
18436 };
18437 const reset = (editor, undoManager) => {
18438 getRtcInstanceWithError(editor).undoManager.reset(undoManager);
18439 };
18440 const hasUndo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasUndo(undoManager, index);
18441 const hasRedo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasRedo(undoManager, index);
18442 const transact = (editor, undoManager, locks, callback) => getRtcInstanceWithError(editor).undoManager.transact(undoManager, locks, callback);
18443 const ignore = (editor, locks, callback) => {
18444 getRtcInstanceWithError(editor).undoManager.ignore(locks, callback);
18445 };
18446 const extra = (editor, undoManager, index, callback1, callback2) => {
18447 getRtcInstanceWithError(editor).undoManager.extra(undoManager, index, callback1, callback2);
18448 };
18449 const matchFormat = (editor, name, vars, node, similar) => getRtcInstanceWithError(editor).formatter.match(name, vars, node, similar);
18450 const matchAllFormats = (editor, names, vars) => getRtcInstanceWithError(editor).formatter.matchAll(names, vars);
18451 const matchNodeFormat = (editor, node, name, vars, similar) => getRtcInstanceWithError(editor).formatter.matchNode(node, name, vars, similar);
18452 const canApplyFormat = (editor, name) => getRtcInstanceWithError(editor).formatter.canApply(name);
18453 const closestFormat = (editor, names) => getRtcInstanceWithError(editor).formatter.closest(names);
18454 const applyFormat = (editor, name, vars, node) => {
18455 getRtcInstanceWithError(editor).formatter.apply(name, vars, node);
18456 };
18457 const removeFormat = (editor, name, vars, node, similar) => {
18458 getRtcInstanceWithError(editor).formatter.remove(name, vars, node, similar);
18459 };
18460 const toggleFormat = (editor, name, vars, node) => {
18461 getRtcInstanceWithError(editor).formatter.toggle(name, vars, node);
18462 };
18463 const formatChanged = (editor, registeredFormatListeners, formats, callback, similar, vars) => getRtcInstanceWithError(editor).formatter.formatChanged(registeredFormatListeners, formats, callback, similar, vars);
18464 const getContent$2 = (editor, args) => getRtcInstanceWithFallback(editor).editor.getContent(args);
18465 const setContent$2 = (editor, content, args) => getRtcInstanceWithFallback(editor).editor.setContent(content, args);
18466 const insertContent$1 = (editor, value, details) => getRtcInstanceWithFallback(editor).editor.insertContent(value, details);
18467 const getSelectedContent = (editor, format, args) => getRtcInstanceWithError(editor).selection.getContent(format, args);
18468 const addVisual$1 = (editor, elm) => getRtcInstanceWithError(editor).editor.addVisual(elm);
18469 const bindEvents = editor => getRtcInstanceWithError(editor).init.bindEvents();
18470
18471 const getContent$1 = (editor, args = {}) => {
18472 const format = args.format ? args.format : 'html';
18473 return getSelectedContent(editor, format, args);
18474 };
18475
18476 const removeEmpty = text => {
18477 if (text.dom.length === 0) {
18478 remove$4(text);
18479 return Optional.none();
18480 } else {
18481 return Optional.some(text);
18482 }
18483 };
18484 const walkPastBookmark = (node, start) => node.filter(elm => BookmarkManager.isBookmarkNode(elm.dom)).bind(start ? nextSibling : prevSibling);
18485 const merge$1 = (outer, inner, rng, start, schema) => {
18486 const outerElm = outer.dom;
18487 const innerElm = inner.dom;
18488 const oldLength = start ? outerElm.length : innerElm.length;
18489 if (start) {
18490 mergeTextNodes(outerElm, innerElm, schema, false, !start);
18491 rng.setStart(innerElm, oldLength);
18492 } else {
18493 mergeTextNodes(innerElm, outerElm, schema, false, !start);
18494 rng.setEnd(innerElm, oldLength);
18495 }
18496 };
18497 const normalizeTextIfRequired = (inner, start, schema) => {
18498 parent(inner).each(root => {
18499 const text = inner.dom;
18500 if (start && needsToBeNbspLeft(root, CaretPosition(text, 0), schema)) {
18501 normalizeWhitespaceAfter(text, 0, schema);
18502 } else if (!start && needsToBeNbspRight(root, CaretPosition(text, text.length), schema)) {
18503 normalizeWhitespaceBefore(text, text.length, schema);
18504 }
18505 });
18506 };
18507 const mergeAndNormalizeText = (outerNode, innerNode, rng, start, schema) => {
18508 outerNode.bind(outer => {
18509 const normalizer = start ? normalizeWhitespaceBefore : normalizeWhitespaceAfter;
18510 normalizer(outer.dom, start ? outer.dom.length : 0, schema);
18511 return innerNode.filter(isText$c).map(inner => merge$1(outer, inner, rng, start, schema));
18512 }).orThunk(() => {
18513 const innerTextNode = walkPastBookmark(innerNode, start).or(innerNode).filter(isText$c);
18514 return innerTextNode.map(inner => normalizeTextIfRequired(inner, start, schema));
18515 });
18516 };
18517 const rngSetContent = (rng, fragment, schema) => {
18518 const firstChild = Optional.from(fragment.firstChild).map(SugarElement.fromDom);
18519 const lastChild = Optional.from(fragment.lastChild).map(SugarElement.fromDom);
18520 rng.deleteContents();
18521 rng.insertNode(fragment);
18522 const prevText = firstChild.bind(prevSibling).filter(isText$c).bind(removeEmpty);
18523 const nextText = lastChild.bind(nextSibling).filter(isText$c).bind(removeEmpty);
18524 mergeAndNormalizeText(prevText, firstChild, rng, true, schema);
18525 mergeAndNormalizeText(nextText, lastChild, rng, false, schema);
18526 rng.collapse(false);
18527 };
18528 const setupArgs$2 = (args, content) => ({
18529 format: 'html',
18530 ...args,
18531 set: true,
18532 selection: true,
18533 content
18534 });
18535 const cleanContent = (editor, args) => {
18536 if (args.format !== 'raw') {
18537 const rng = editor.selection.getRng();
18538 const contextBlock = editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock);
18539 const contextArgs = contextBlock ? { context: contextBlock.nodeName.toLowerCase() } : {};
18540 const node = editor.parser.parse(args.content, {
18541 forced_root_block: false,
18542 ...contextArgs,
18543 ...args
18544 });
18545 return HtmlSerializer({ validate: false }, editor.schema).serialize(node);
18546 } else {
18547 return args.content;
18548 }
18549 };
18550 const setContent$1 = (editor, content, args = {}) => {
18551 const defaultedArgs = setupArgs$2(args, content);
18552 preProcessSetContent(editor, defaultedArgs).each(updatedArgs => {
18553 const cleanedContent = cleanContent(editor, updatedArgs);
18554 const rng = editor.selection.getRng();
18555 rngSetContent(rng, rng.createContextualFragment(cleanedContent), editor.schema);
18556 editor.selection.setRng(rng);
18557 scrollRangeIntoView(editor, rng);
18558 postProcessSetContent(editor, cleanedContent, updatedArgs);
18559 });
18560 };
18561
18562 const deleteFromCallbackMap = (callbackMap, selector, callback) => {
18563 if (has$2(callbackMap, selector)) {
18564 const newCallbacks = filter$5(callbackMap[selector], cb => cb !== callback);
18565 if (newCallbacks.length === 0) {
18566 delete callbackMap[selector];
18567 } else {
18568 callbackMap[selector] = newCallbacks;
18569 }
18570 }
18571 };
18572 var SelectorChanged = (dom, editor) => {
18573 let selectorChangedData;
18574 let currentSelectors;
18575 const findMatchingNode = (selector, nodes) => find$2(nodes, node => dom.is(node, selector));
18576 const getParents = elem => dom.getParents(elem, undefined, dom.getRoot());
18577 const setup = () => {
18578 selectorChangedData = {};
18579 currentSelectors = {};
18580 editor.on('NodeChange', e => {
18581 const node = e.element;
18582 const parents = getParents(node);
18583 const matchedSelectors = {};
18584 each$d(selectorChangedData, (callbacks, selector) => {
18585 findMatchingNode(selector, parents).each(node => {
18586 if (!currentSelectors[selector]) {
18587 each$e(callbacks, callback => {
18588 callback(true, {
18589 node,
18590 selector,
18591 parents
18592 });
18593 });
18594 currentSelectors[selector] = callbacks;
18595 }
18596 matchedSelectors[selector] = callbacks;
18597 });
18598 });
18599 each$d(currentSelectors, (callbacks, selector) => {
18600 if (!matchedSelectors[selector]) {
18601 delete currentSelectors[selector];
18602 each$e(callbacks, callback => {
18603 callback(false, {
18604 node,
18605 selector,
18606 parents
18607 });
18608 });
18609 }
18610 });
18611 });
18612 };
18613 return {
18614 selectorChangedWithUnbind: (selector, callback) => {
18615 if (!selectorChangedData) {
18616 setup();
18617 }
18618 if (!selectorChangedData[selector]) {
18619 selectorChangedData[selector] = [];
18620 }
18621 selectorChangedData[selector].push(callback);
18622 findMatchingNode(selector, getParents(editor.selection.getStart())).each(() => {
18623 currentSelectors[selector] = selectorChangedData[selector];
18624 });
18625 return {
18626 unbind: () => {
18627 deleteFromCallbackMap(selectorChangedData, selector, callback);
18628 deleteFromCallbackMap(currentSelectors, selector, callback);
18629 }
18630 };
18631 }
18632 };
18633 };
18634
18635 const isAttachedToDom = node => {
18636 return !!(node && node.ownerDocument) && contains(SugarElement.fromDom(node.ownerDocument), SugarElement.fromDom(node));
18637 };
18638 const isValidRange = rng => {
18639 if (!rng) {
18640 return false;
18641 } else {
18642 return isAttachedToDom(rng.startContainer) && isAttachedToDom(rng.endContainer);
18643 }
18644 };
18645 const EditorSelection = (dom, win, serializer, editor) => {
18646 let selectedRange;
18647 let explicitRange;
18648 const {selectorChangedWithUnbind} = SelectorChanged(dom, editor);
18649 const setCursorLocation = (node, offset) => {
18650 const rng = dom.createRng();
18651 if (isNonNullable(node) && isNonNullable(offset)) {
18652 rng.setStart(node, offset);
18653 rng.setEnd(node, offset);
18654 setRng(rng);
18655 collapse(false);
18656 } else {
18657 moveEndPoint(dom, rng, editor.getBody(), true);
18658 setRng(rng);
18659 }
18660 };
18661 const getContent = args => getContent$1(editor, args);
18662 const setContent = (content, args) => setContent$1(editor, content, args);
18663 const getStart$1 = real => getStart(editor.getBody(), getRng$1(), real);
18664 const getEnd$1 = real => getEnd(editor.getBody(), getRng$1(), real);
18665 const getBookmark = (type, normalized) => bookmarkManager.getBookmark(type, normalized);
18666 const moveToBookmark = bookmark => bookmarkManager.moveToBookmark(bookmark);
18667 const select$1 = (node, content) => {
18668 select(dom, node, content).each(setRng);
18669 return node;
18670 };
18671 const isCollapsed = () => {
18672 const rng = getRng$1(), sel = getSel();
18673 if (!rng || rng.item) {
18674 return false;
18675 }
18676 if (rng.compareEndPoints) {
18677 return rng.compareEndPoints('StartToEnd', rng) === 0;
18678 }
18679 return !sel || rng.collapsed;
18680 };
18681 const isEditable = () => {
18682 const rng = getRng$1();
18683 const fakeSelectedElements = editor.getBody().querySelectorAll('[data-mce-selected="1"]');
18684 if (fakeSelectedElements.length > 0) {
18685 return forall(fakeSelectedElements, el => dom.isEditable(el.parentElement));
18686 } else {
18687 return isEditableRange(dom, rng);
18688 }
18689 };
18690 const collapse = toStart => {
18691 const rng = getRng$1();
18692 rng.collapse(!!toStart);
18693 setRng(rng);
18694 };
18695 const getSel = () => win.getSelection ? win.getSelection() : win.document.selection;
18696 const getRng$1 = () => {
18697 let rng;
18698 const tryCompareBoundaryPoints = (how, sourceRange, destinationRange) => {
18699 try {
18700 return sourceRange.compareBoundaryPoints(how, destinationRange);
18701 } catch (ex) {
18702 return -1;
18703 }
18704 };
18705 const doc = win.document;
18706 if (isNonNullable(editor.bookmark) && !hasFocus(editor)) {
18707 const bookmark = getRng(editor);
18708 if (bookmark.isSome()) {
18709 return bookmark.map(r => processRanges(editor, [r])[0]).getOr(doc.createRange());
18710 }
18711 }
18712 try {
18713 const selection = getSel();
18714 if (selection && !isRestrictedNode(selection.anchorNode)) {
18715 if (selection.rangeCount > 0) {
18716 rng = selection.getRangeAt(0);
18717 } else {
18718 rng = doc.createRange();
18719 }
18720 rng = processRanges(editor, [rng])[0];
18721 }
18722 } catch (ex) {
18723 }
18724 if (!rng) {
18725 rng = doc.createRange();
18726 }
18727 if (isDocument$1(rng.startContainer) && rng.collapsed) {
18728 const elm = dom.getRoot();
18729 rng.setStart(elm, 0);
18730 rng.setEnd(elm, 0);
18731 }
18732 if (selectedRange && explicitRange) {
18733 if (tryCompareBoundaryPoints(rng.START_TO_START, rng, selectedRange) === 0 && tryCompareBoundaryPoints(rng.END_TO_END, rng, selectedRange) === 0) {
18734 rng = explicitRange;
18735 } else {
18736 selectedRange = null;
18737 explicitRange = null;
18738 }
18739 }
18740 return rng;
18741 };
18742 const setRng = (rng, forward) => {
18743 if (!isValidRange(rng)) {
18744 return;
18745 }
18746 const sel = getSel();
18747 const evt = editor.dispatch('SetSelectionRange', {
18748 range: rng,
18749 forward
18750 });
18751 rng = evt.range;
18752 if (sel) {
18753 explicitRange = rng;
18754 try {
18755 sel.removeAllRanges();
18756 sel.addRange(rng);
18757 } catch (ex) {
18758 }
18759 if (forward === false && sel.extend) {
18760 sel.collapse(rng.endContainer, rng.endOffset);
18761 sel.extend(rng.startContainer, rng.startOffset);
18762 }
18763 selectedRange = sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
18764 }
18765 if (!rng.collapsed && rng.startContainer === rng.endContainer && (sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent)) {
18766 if (rng.endOffset - rng.startOffset < 2) {
18767 if (rng.startContainer.hasChildNodes()) {
18768 const node = rng.startContainer.childNodes[rng.startOffset];
18769 if (node && node.nodeName === 'IMG') {
18770 sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset);
18771 if (sel.anchorNode !== rng.startContainer || sel.focusNode !== rng.endContainer) {
18772 sel.setBaseAndExtent(node, 0, node, 1);
18773 }
18774 }
18775 }
18776 }
18777 }
18778 editor.dispatch('AfterSetSelectionRange', {
18779 range: rng,
18780 forward
18781 });
18782 };
18783 const setNode = elm => {
18784 setContent(dom.getOuterHTML(elm));
18785 return elm;
18786 };
18787 const getNode$1 = () => getNode(editor.getBody(), getRng$1());
18788 const getSelectedBlocks$1 = (startElm, endElm) => getSelectedBlocks(dom, getRng$1(), startElm, endElm);
18789 const isForward = () => {
18790 const sel = getSel();
18791 const anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
18792 const focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
18793 if (!sel || !anchorNode || !focusNode || isRestrictedNode(anchorNode) || isRestrictedNode(focusNode)) {
18794 return true;
18795 }
18796 const anchorRange = dom.createRng();
18797 const focusRange = dom.createRng();
18798 try {
18799 anchorRange.setStart(anchorNode, sel.anchorOffset);
18800 anchorRange.collapse(true);
18801 focusRange.setStart(focusNode, sel.focusOffset);
18802 focusRange.collapse(true);
18803 } catch (e) {
18804 return true;
18805 }
18806 return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
18807 };
18808 const normalize = () => {
18809 const rng = getRng$1();
18810 const sel = getSel();
18811 if (!hasMultipleRanges(sel) && hasAnyRanges(editor)) {
18812 const normRng = normalize$2(dom, rng);
18813 normRng.each(normRng => {
18814 setRng(normRng, isForward());
18815 });
18816 return normRng.getOr(rng);
18817 }
18818 return rng;
18819 };
18820 const selectorChanged = (selector, callback) => {
18821 selectorChangedWithUnbind(selector, callback);
18822 return exports;
18823 };
18824 const getScrollContainer = () => {
18825 let scrollContainer;
18826 let node = dom.getRoot();
18827 while (node && node.nodeName !== 'BODY') {
18828 if (node.scrollHeight > node.clientHeight) {
18829 scrollContainer = node;
18830 break;
18831 }
18832 node = node.parentNode;
18833 }
18834 return scrollContainer;
18835 };
18836 const scrollIntoView = (elm, alignToTop) => {
18837 if (isNonNullable(elm)) {
18838 scrollElementIntoView(editor, elm, alignToTop);
18839 } else {
18840 scrollRangeIntoView(editor, getRng$1(), alignToTop);
18841 }
18842 };
18843 const placeCaretAt = (clientX, clientY) => setRng(fromPoint(clientX, clientY, editor.getDoc()));
18844 const getBoundingClientRect = () => {
18845 const rng = getRng$1();
18846 return rng.collapsed ? CaretPosition.fromRangeStart(rng).getClientRects()[0] : rng.getBoundingClientRect();
18847 };
18848 const destroy = () => {
18849 win = selectedRange = explicitRange = null;
18850 controlSelection.destroy();
18851 };
18852 const expand = (options = { type: 'word' }) => setRng(RangeUtils(dom).expand(getRng$1(), options));
18853 const exports = {
18854 dom,
18855 win,
18856 serializer,
18857 editor,
18858 expand,
18859 collapse,
18860 setCursorLocation,
18861 getContent,
18862 setContent,
18863 getBookmark,
18864 moveToBookmark,
18865 select: select$1,
18866 isCollapsed,
18867 isEditable,
18868 isForward,
18869 setNode,
18870 getNode: getNode$1,
18871 getSel,
18872 setRng,
18873 getRng: getRng$1,
18874 getStart: getStart$1,
18875 getEnd: getEnd$1,
18876 getSelectedBlocks: getSelectedBlocks$1,
18877 normalize,
18878 selectorChanged,
18879 selectorChangedWithUnbind,
18880 getScrollContainer,
18881 scrollIntoView,
18882 placeCaretAt,
18883 getBoundingClientRect,
18884 destroy
18885 };
18886 const bookmarkManager = BookmarkManager(exports);
18887 const controlSelection = ControlSelection(exports, editor);
18888 exports.bookmarkManager = bookmarkManager;
18889 exports.controlSelection = controlSelection;
18890 return exports;
18891 };
18892
18893 const addNodeFilter = (settings, htmlParser, schema) => {
18894 htmlParser.addNodeFilter('br', (nodes, _, args) => {
18895 const blockElements = Tools.extend({}, schema.getBlockElements());
18896 const nonEmptyElements = schema.getNonEmptyElements();
18897 const whitespaceElements = schema.getWhitespaceElements();
18898 blockElements.body = 1;
18899 const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node);
18900 for (let i = 0, l = nodes.length; i < l; i++) {
18901 let node = nodes[i];
18902 let parent = node.parent;
18903 if (parent && isBlock(parent) && node === parent.lastChild) {
18904 let prev = node.prev;
18905 while (prev) {
18906 const prevName = prev.name;
18907 if (prevName !== 'span' || prev.attr('data-mce-type') !== 'bookmark') {
18908 if (prevName === 'br') {
18909 node = null;
18910 }
18911 break;
18912 }
18913 prev = prev.prev;
18914 }
18915 if (node) {
18916 node.remove();
18917 if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent)) {
18918 const elementRule = schema.getElementRule(parent.name);
18919 if (elementRule) {
18920 if (elementRule.removeEmpty) {
18921 parent.remove();
18922 } else if (elementRule.paddEmpty) {
18923 paddEmptyNode(settings, args, isBlock, parent);
18924 }
18925 }
18926 }
18927 }
18928 } else {
18929 let lastParent = node;
18930 while (parent && parent.firstChild === lastParent && parent.lastChild === lastParent) {
18931 lastParent = parent;
18932 if (blockElements[parent.name]) {
18933 break;
18934 }
18935 parent = parent.parent;
18936 }
18937 if (lastParent === parent) {
18938 const textNode = new AstNode('#text', 3);
18939 textNode.value = nbsp;
18940 node.replace(textNode);
18941 }
18942 }
18943 }
18944 });
18945 };
18946
18947 const register$3 = (htmlParser, settings, dom) => {
18948 htmlParser.addAttributeFilter('data-mce-tabindex', (nodes, name) => {
18949 let i = nodes.length;
18950 while (i--) {
18951 const node = nodes[i];
18952 node.attr('tabindex', node.attr('data-mce-tabindex'));
18953 node.attr(name, null);
18954 }
18955 });
18956 htmlParser.addAttributeFilter('src,href,style', (nodes, name) => {
18957 const internalName = 'data-mce-' + name;
18958 const urlConverter = settings.url_converter;
18959 const urlConverterScope = settings.url_converter_scope;
18960 let i = nodes.length;
18961 while (i--) {
18962 const node = nodes[i];
18963 let value = node.attr(internalName);
18964 if (value !== undefined) {
18965 node.attr(name, value.length > 0 ? value : null);
18966 node.attr(internalName, null);
18967 } else {
18968 value = node.attr(name);
18969 if (name === 'style') {
18970 value = dom.serializeStyle(dom.parseStyle(value), node.name);
18971 } else if (urlConverter) {
18972 value = urlConverter.call(urlConverterScope, value, name, node.name);
18973 }
18974 node.attr(name, value.length > 0 ? value : null);
18975 }
18976 }
18977 });
18978 htmlParser.addAttributeFilter('class', nodes => {
18979 let i = nodes.length;
18980 while (i--) {
18981 const node = nodes[i];
18982 let value = node.attr('class');
18983 if (value) {
18984 value = value.replace(/(?:^|\s)mce-item-\w+(?!\S)/g, '');
18985 node.attr('class', value.length > 0 ? value : null);
18986 }
18987 }
18988 });
18989 htmlParser.addAttributeFilter('data-mce-type', (nodes, name, args) => {
18990 let i = nodes.length;
18991 while (i--) {
18992 const node = nodes[i];
18993 if (node.attr('data-mce-type') === 'bookmark' && !args.cleanup) {
18994 const hasChildren = Optional.from(node.firstChild).exists(firstChild => {
18995 var _a;
18996 return !isZwsp((_a = firstChild.value) !== null && _a !== void 0 ? _a : '');
18997 });
18998 if (hasChildren) {
18999 node.unwrap();
19000 } else {
19001 node.remove();
19002 }
19003 }
19004 }
19005 });
19006 htmlParser.addNodeFilter('noscript', nodes => {
19007 var _a;
19008 let i = nodes.length;
19009 while (i--) {
19010 const node = nodes[i].firstChild;
19011 if (node) {
19012 node.value = Entities.decode((_a = node.value) !== null && _a !== void 0 ? _a : '');
19013 }
19014 }
19015 });
19016 htmlParser.addNodeFilter('script,style', (nodes, name) => {
19017 var _a;
19018 const trim = value => {
19019 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, '');
19020 };
19021 let i = nodes.length;
19022 while (i--) {
19023 const node = nodes[i];
19024 const firstChild = node.firstChild;
19025 const value = (_a = firstChild === null || firstChild === void 0 ? void 0 : firstChild.value) !== null && _a !== void 0 ? _a : '';
19026 if (name === 'script') {
19027 const type = node.attr('type');
19028 if (type) {
19029 node.attr('type', type === 'mce-no/type' ? null : type.replace(/^mce\-/, ''));
19030 }
19031 if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
19032 firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
19033 }
19034 } else {
19035 if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
19036 firstChild.value = '<!--\n' + trim(value) + '\n-->';
19037 }
19038 }
19039 }
19040 });
19041 htmlParser.addNodeFilter('#comment', nodes => {
19042 let i = nodes.length;
19043 while (i--) {
19044 const node = nodes[i];
19045 const value = node.value;
19046 if (settings.preserve_cdata && (value === null || value === void 0 ? void 0 : value.indexOf('[CDATA[')) === 0) {
19047 node.name = '#cdata';
19048 node.type = 4;
19049 node.value = dom.decode(value.replace(/^\[CDATA\[|\]\]$/g, ''));
19050 } else if ((value === null || value === void 0 ? void 0 : value.indexOf('mce:protected ')) === 0) {
19051 node.name = '#text';
19052 node.type = 3;
19053 node.raw = true;
19054 node.value = unescape(value).substr(14);
19055 }
19056 }
19057 });
19058 htmlParser.addNodeFilter('xml:namespace,input', (nodes, name) => {
19059 let i = nodes.length;
19060 while (i--) {
19061 const node = nodes[i];
19062 if (node.type === 7) {
19063 node.remove();
19064 } else if (node.type === 1) {
19065 if (name === 'input' && !node.attr('type')) {
19066 node.attr('type', 'text');
19067 }
19068 }
19069 }
19070 });
19071 htmlParser.addAttributeFilter('data-mce-type', nodes => {
19072 each$e(nodes, node => {
19073 if (node.attr('data-mce-type') === 'format-caret') {
19074 if (node.isEmpty(htmlParser.schema.getNonEmptyElements())) {
19075 node.remove();
19076 } else {
19077 node.unwrap();
19078 }
19079 }
19080 });
19081 });
19082 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) => {
19083 let i = nodes.length;
19084 while (i--) {
19085 nodes[i].attr(name, null);
19086 }
19087 });
19088 if (settings.remove_trailing_brs) {
19089 addNodeFilter(settings, htmlParser, htmlParser.schema);
19090 }
19091 };
19092 const trimTrailingBr = rootNode => {
19093 const isBr = node => {
19094 return (node === null || node === void 0 ? void 0 : node.name) === 'br';
19095 };
19096 const brNode1 = rootNode.lastChild;
19097 if (isBr(brNode1)) {
19098 const brNode2 = brNode1.prev;
19099 if (isBr(brNode2)) {
19100 brNode1.remove();
19101 brNode2.remove();
19102 }
19103 }
19104 };
19105
19106 const preProcess$1 = (editor, node, args) => {
19107 let oldDoc;
19108 const dom = editor.dom;
19109 let clonedNode = node.cloneNode(true);
19110 const impl = document.implementation;
19111 if (impl.createHTMLDocument) {
19112 const doc = impl.createHTMLDocument('');
19113 Tools.each(clonedNode.nodeName === 'BODY' ? clonedNode.childNodes : [clonedNode], node => {
19114 doc.body.appendChild(doc.importNode(node, true));
19115 });
19116 if (clonedNode.nodeName !== 'BODY') {
19117 clonedNode = doc.body.firstChild;
19118 } else {
19119 clonedNode = doc.body;
19120 }
19121 oldDoc = dom.doc;
19122 dom.doc = doc;
19123 }
19124 firePreProcess(editor, {
19125 ...args,
19126 node: clonedNode
19127 });
19128 if (oldDoc) {
19129 dom.doc = oldDoc;
19130 }
19131 return clonedNode;
19132 };
19133 const shouldFireEvent = (editor, args) => {
19134 return isNonNullable(editor) && editor.hasEventListeners('PreProcess') && !args.no_events;
19135 };
19136 const process$1 = (editor, node, args) => {
19137 return shouldFireEvent(editor, args) ? preProcess$1(editor, node, args) : node;
19138 };
19139
19140 const addTempAttr = (htmlParser, tempAttrs, name) => {
19141 if (Tools.inArray(tempAttrs, name) === -1) {
19142 htmlParser.addAttributeFilter(name, (nodes, name) => {
19143 let i = nodes.length;
19144 while (i--) {
19145 nodes[i].attr(name, null);
19146 }
19147 });
19148 tempAttrs.push(name);
19149 }
19150 };
19151 const postProcess = (editor, args, content) => {
19152 if (!args.no_events && editor) {
19153 const outArgs = firePostProcess(editor, {
19154 ...args,
19155 content
19156 });
19157 return outArgs.content;
19158 } else {
19159 return content;
19160 }
19161 };
19162 const getHtmlFromNode = (dom, node, args) => {
19163 const html = trim$2(args.getInner ? node.innerHTML : dom.getOuterHTML(node));
19164 return args.selection || isWsPreserveElement(SugarElement.fromDom(node)) ? html : Tools.trim(html);
19165 };
19166 const parseHtml = (htmlParser, html, args) => {
19167 const parserArgs = args.selection ? {
19168 forced_root_block: false,
19169 ...args
19170 } : args;
19171 const rootNode = htmlParser.parse(html, parserArgs);
19172 trimTrailingBr(rootNode);
19173 return rootNode;
19174 };
19175 const serializeNode = (settings, schema, node) => {
19176 const htmlSerializer = HtmlSerializer(settings, schema);
19177 return htmlSerializer.serialize(node);
19178 };
19179 const toHtml = (editor, settings, schema, rootNode, args) => {
19180 const content = serializeNode(settings, schema, rootNode);
19181 return postProcess(editor, args, content);
19182 };
19183 const DomSerializerImpl = (settings, editor) => {
19184 const tempAttrs = ['data-mce-selected'];
19185 const defaultedSettings = {
19186 entity_encoding: 'named',
19187 remove_trailing_brs: true,
19188 pad_empty_with_br: false,
19189 ...settings
19190 };
19191 const dom = editor && editor.dom ? editor.dom : DOMUtils.DOM;
19192 const schema = editor && editor.schema ? editor.schema : Schema(defaultedSettings);
19193 const htmlParser = DomParser(defaultedSettings, schema);
19194 register$3(htmlParser, defaultedSettings, dom);
19195 const serialize = (node, parserArgs = {}) => {
19196 const args = {
19197 format: 'html',
19198 ...parserArgs
19199 };
19200 const targetNode = process$1(editor, node, args);
19201 const html = getHtmlFromNode(dom, targetNode, args);
19202 const rootNode = parseHtml(htmlParser, html, args);
19203 return args.format === 'tree' ? rootNode : toHtml(editor, defaultedSettings, schema, rootNode, args);
19204 };
19205 return {
19206 schema,
19207 addNodeFilter: htmlParser.addNodeFilter,
19208 addAttributeFilter: htmlParser.addAttributeFilter,
19209 serialize: serialize,
19210 addRules: schema.addValidElements,
19211 setRules: schema.setValidElements,
19212 addTempAttr: curry(addTempAttr, htmlParser, tempAttrs),
19213 getTempAttrs: constant(tempAttrs),
19214 getNodeFilters: htmlParser.getNodeFilters,
19215 getAttributeFilters: htmlParser.getAttributeFilters,
19216 removeNodeFilter: htmlParser.removeNodeFilter,
19217 removeAttributeFilter: htmlParser.removeAttributeFilter
19218 };
19219 };
19220
19221 const DomSerializer = (settings, editor) => {
19222 const domSerializer = DomSerializerImpl(settings, editor);
19223 return {
19224 schema: domSerializer.schema,
19225 addNodeFilter: domSerializer.addNodeFilter,
19226 addAttributeFilter: domSerializer.addAttributeFilter,
19227 serialize: domSerializer.serialize,
19228 addRules: domSerializer.addRules,
19229 setRules: domSerializer.setRules,
19230 addTempAttr: domSerializer.addTempAttr,
19231 getTempAttrs: domSerializer.getTempAttrs,
19232 getNodeFilters: domSerializer.getNodeFilters,
19233 getAttributeFilters: domSerializer.getAttributeFilters,
19234 removeNodeFilter: domSerializer.removeNodeFilter,
19235 removeAttributeFilter: domSerializer.removeAttributeFilter
19236 };
19237 };
19238
19239 const defaultFormat$1 = 'html';
19240 const setupArgs$1 = (args, format) => ({
19241 ...args,
19242 format,
19243 get: true,
19244 getInner: true
19245 });
19246 const getContent = (editor, args = {}) => {
19247 const format = args.format ? args.format : defaultFormat$1;
19248 const defaultedArgs = setupArgs$1(args, format);
19249 return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
19250 const content = getContent$2(editor, updatedArgs);
19251 return postProcessGetContent(editor, content, updatedArgs);
19252 });
19253 };
19254
19255 const defaultFormat = 'html';
19256 const setupArgs = (args, content) => ({
19257 format: defaultFormat,
19258 ...args,
19259 set: true,
19260 content
19261 });
19262 const setContent = (editor, content, args = {}) => {
19263 const defaultedArgs = setupArgs(args, content);
19264 return preProcessSetContent(editor, defaultedArgs).map(updatedArgs => {
19265 const result = setContent$2(editor, updatedArgs.content, updatedArgs);
19266 postProcessSetContent(editor, result.html, updatedArgs);
19267 return result.content;
19268 }).getOr(content);
19269 };
19270
19271 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(',');
19272 const deprecatedOptions = [];
19273 const removedPlugins = 'bbcode,colorpicker,contextmenu,fullpage,legacyoutput,spellchecker,template,textcolor,rtc'.split(',');
19274 const deprecatedPlugins = [];
19275 const getMatchingOptions = (options, searchingFor) => {
19276 const settingNames = filter$5(searchingFor, setting => has$2(options, setting));
19277 return sort(settingNames);
19278 };
19279 const getRemovedOptions = options => {
19280 const settingNames = getMatchingOptions(options, removedOptions);
19281 const forcedRootBlock = options.forced_root_block;
19282 if (forcedRootBlock === false || forcedRootBlock === '') {
19283 settingNames.push('forced_root_block (false only)');
19284 }
19285 return sort(settingNames);
19286 };
19287 const getDeprecatedOptions = options => getMatchingOptions(options, deprecatedOptions);
19288 const getMatchingPlugins = (options, searchingFor) => {
19289 const plugins = Tools.makeMap(options.plugins, ' ');
19290 const hasPlugin = plugin => has$2(plugins, plugin);
19291 const pluginNames = filter$5(searchingFor, hasPlugin);
19292 return sort(pluginNames);
19293 };
19294 const getRemovedPlugins = options => getMatchingPlugins(options, removedPlugins);
19295 const getDeprecatedPlugins = options => getMatchingPlugins(options, deprecatedPlugins.map(entry => entry.name));
19296 const logRemovedWarnings = (rawOptions, normalizedOptions) => {
19297 const removedOptions = getRemovedOptions(rawOptions);
19298 const removedPlugins = getRemovedPlugins(normalizedOptions);
19299 const hasRemovedPlugins = removedPlugins.length > 0;
19300 const hasRemovedOptions = removedOptions.length > 0;
19301 const isLegacyMobileTheme = normalizedOptions.theme === 'mobile';
19302 if (hasRemovedPlugins || hasRemovedOptions || isLegacyMobileTheme) {
19303 const listJoiner = '\n- ';
19304 const themesMessage = isLegacyMobileTheme ? `\n\nThemes:${ listJoiner }mobile` : '';
19305 const pluginsMessage = hasRemovedPlugins ? `\n\nPlugins:${ listJoiner }${ removedPlugins.join(listJoiner) }` : '';
19306 const optionsMessage = hasRemovedOptions ? `\n\nOptions:${ listJoiner }${ removedOptions.join(listJoiner) }` : '';
19307 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);
19308 }
19309 };
19310 const getPluginDescription = name => find$2(deprecatedPlugins, entry => entry.name === name).fold(() => name, entry => {
19311 if (entry.replacedWith) {
19312 return `${ name }, replaced by ${ entry.replacedWith }`;
19313 } else {
19314 return name;
19315 }
19316 });
19317 const logDeprecatedWarnings = (rawOptions, normalizedOptions) => {
19318 const deprecatedOptions = getDeprecatedOptions(rawOptions);
19319 const deprecatedPlugins = getDeprecatedPlugins(normalizedOptions);
19320 const hasDeprecatedPlugins = deprecatedPlugins.length > 0;
19321 const hasDeprecatedOptions = deprecatedOptions.length > 0;
19322 if (hasDeprecatedPlugins || hasDeprecatedOptions) {
19323 const listJoiner = '\n- ';
19324 const pluginsMessage = hasDeprecatedPlugins ? `\n\nPlugins:${ listJoiner }${ deprecatedPlugins.map(getPluginDescription).join(listJoiner) }` : '';
19325 const optionsMessage = hasDeprecatedOptions ? `\n\nOptions:${ listJoiner }${ deprecatedOptions.join(listJoiner) }` : '';
19326 console.warn('The following deprecated features are currently enabled but will be removed soon.' + pluginsMessage + optionsMessage);
19327 }
19328 };
19329 const logWarnings = (rawOptions, normalizedOptions) => {
19330 logRemovedWarnings(rawOptions, normalizedOptions);
19331 logDeprecatedWarnings(rawOptions, normalizedOptions);
19332 };
19333
19334 const DOM$8 = DOMUtils.DOM;
19335 const restoreOriginalStyles = editor => {
19336 DOM$8.setStyle(editor.id, 'display', editor.orgDisplay);
19337 };
19338 const safeDestroy = x => Optional.from(x).each(x => x.destroy());
19339 const clearDomReferences = editor => {
19340 const ed = editor;
19341 ed.contentAreaContainer = ed.formElement = ed.container = ed.editorContainer = null;
19342 ed.bodyElement = ed.contentDocument = ed.contentWindow = null;
19343 ed.iframeElement = ed.targetElm = null;
19344 const selection = editor.selection;
19345 if (selection) {
19346 const dom = selection.dom;
19347 ed.selection = selection.win = selection.dom = dom.doc = null;
19348 }
19349 };
19350 const restoreForm = editor => {
19351 const form = editor.formElement;
19352 if (form) {
19353 if (form._mceOldSubmit) {
19354 form.submit = form._mceOldSubmit;
19355 delete form._mceOldSubmit;
19356 }
19357 DOM$8.unbind(form, 'submit reset', editor.formEventDelegate);
19358 }
19359 };
19360 const remove$1 = editor => {
19361 if (!editor.removed) {
19362 const {_selectionOverrides, editorUpload} = editor;
19363 const body = editor.getBody();
19364 const element = editor.getElement();
19365 if (body) {
19366 editor.save({ is_removing: true });
19367 }
19368 editor.removed = true;
19369 editor.unbindAllNativeEvents();
19370 if (editor.hasHiddenInput && isNonNullable(element === null || element === void 0 ? void 0 : element.nextSibling)) {
19371 DOM$8.remove(element.nextSibling);
19372 }
19373 fireRemove(editor);
19374 editor.editorManager.remove(editor);
19375 if (!editor.inline && body) {
19376 restoreOriginalStyles(editor);
19377 }
19378 fireDetach(editor);
19379 DOM$8.remove(editor.getContainer());
19380 safeDestroy(_selectionOverrides);
19381 safeDestroy(editorUpload);
19382 editor.destroy();
19383 }
19384 };
19385 const destroy = (editor, automatic) => {
19386 const {selection, dom} = editor;
19387 if (editor.destroyed) {
19388 return;
19389 }
19390 if (!automatic && !editor.removed) {
19391 editor.remove();
19392 return;
19393 }
19394 if (!automatic) {
19395 editor.editorManager.off('beforeunload', editor._beforeUnload);
19396 if (editor.theme && editor.theme.destroy) {
19397 editor.theme.destroy();
19398 }
19399 safeDestroy(selection);
19400 safeDestroy(dom);
19401 }
19402 restoreForm(editor);
19403 clearDomReferences(editor);
19404 editor.destroyed = true;
19405 };
19406
19407 const CreateIconManager = () => {
19408 const lookup = {};
19409 const add = (id, iconPack) => {
19410 lookup[id] = iconPack;
19411 };
19412 const get = id => {
19413 if (lookup[id]) {
19414 return lookup[id];
19415 } else {
19416 return { icons: {} };
19417 }
19418 };
19419 const has = id => has$2(lookup, id);
19420 return {
19421 add,
19422 get,
19423 has
19424 };
19425 };
19426 const IconManager = CreateIconManager();
19427
19428 const ModelManager = AddOnManager.ModelManager;
19429
19430 const getProp = (propName, elm) => {
19431 const rawElm = elm.dom;
19432 return rawElm[propName];
19433 };
19434 const getComputedSizeProp = (propName, elm) => parseInt(get$7(elm, propName), 10);
19435 const getClientWidth = curry(getProp, 'clientWidth');
19436 const getClientHeight = curry(getProp, 'clientHeight');
19437 const getMarginTop = curry(getComputedSizeProp, 'margin-top');
19438 const getMarginLeft = curry(getComputedSizeProp, 'margin-left');
19439 const getBoundingClientRect = elm => elm.dom.getBoundingClientRect();
19440 const isInsideElementContentArea = (bodyElm, clientX, clientY) => {
19441 const clientWidth = getClientWidth(bodyElm);
19442 const clientHeight = getClientHeight(bodyElm);
19443 return clientX >= 0 && clientY >= 0 && clientX <= clientWidth && clientY <= clientHeight;
19444 };
19445 const transpose = (inline, elm, clientX, clientY) => {
19446 const clientRect = getBoundingClientRect(elm);
19447 const deltaX = inline ? clientRect.left + elm.dom.clientLeft + getMarginLeft(elm) : 0;
19448 const deltaY = inline ? clientRect.top + elm.dom.clientTop + getMarginTop(elm) : 0;
19449 const x = clientX - deltaX;
19450 const y = clientY - deltaY;
19451 return {
19452 x,
19453 y
19454 };
19455 };
19456 const isXYInContentArea = (editor, clientX, clientY) => {
19457 const bodyElm = SugarElement.fromDom(editor.getBody());
19458 const targetElm = editor.inline ? bodyElm : documentElement(bodyElm);
19459 const transposedPoint = transpose(editor.inline, targetElm, clientX, clientY);
19460 return isInsideElementContentArea(targetElm, transposedPoint.x, transposedPoint.y);
19461 };
19462 const fromDomSafe = node => Optional.from(node).map(SugarElement.fromDom);
19463 const isEditorAttachedToDom = editor => {
19464 const rawContainer = editor.inline ? editor.getBody() : editor.getContentAreaContainer();
19465 return fromDomSafe(rawContainer).map(inBody).getOr(false);
19466 };
19467
19468 var NotificationManagerImpl = () => {
19469 const unimplemented = () => {
19470 throw new Error('Theme did not provide a NotificationManager implementation.');
19471 };
19472 return {
19473 open: unimplemented,
19474 close: unimplemented,
19475 getArgs: unimplemented
19476 };
19477 };
19478
19479 const NotificationManager = editor => {
19480 const notifications = [];
19481 const getImplementation = () => {
19482 const theme = editor.theme;
19483 return theme && theme.getNotificationManagerImpl ? theme.getNotificationManagerImpl() : NotificationManagerImpl();
19484 };
19485 const getTopNotification = () => {
19486 return Optional.from(notifications[0]);
19487 };
19488 const isEqual = (a, b) => {
19489 return a.type === b.type && a.text === b.text && !a.progressBar && !a.timeout && !b.progressBar && !b.timeout;
19490 };
19491 const reposition = () => {
19492 getTopNotification().each(notification => {
19493 notification.reposition();
19494 });
19495 };
19496 const addNotification = notification => {
19497 notifications.push(notification);
19498 };
19499 const closeNotification = notification => {
19500 findIndex$2(notifications, otherNotification => {
19501 return otherNotification === notification;
19502 }).each(index => {
19503 notifications.splice(index, 1);
19504 });
19505 };
19506 const open = (spec, fireEvent = true) => {
19507 if (editor.removed || !isEditorAttachedToDom(editor)) {
19508 return {};
19509 }
19510 if (fireEvent) {
19511 editor.dispatch('BeforeOpenNotification', { notification: spec });
19512 }
19513 return find$2(notifications, notification => {
19514 return isEqual(getImplementation().getArgs(notification), spec);
19515 }).getOrThunk(() => {
19516 editor.editorManager.setActive(editor);
19517 const notification = getImplementation().open(spec, () => {
19518 closeNotification(notification);
19519 }, () => hasEditorOrUiFocus(editor));
19520 addNotification(notification);
19521 reposition();
19522 editor.dispatch('OpenNotification', { notification: { ...notification } });
19523 return notification;
19524 });
19525 };
19526 const close = () => {
19527 getTopNotification().each(notification => {
19528 getImplementation().close(notification);
19529 closeNotification(notification);
19530 reposition();
19531 });
19532 };
19533 const getNotifications = constant(notifications);
19534 const registerEvents = editor => {
19535 editor.on('SkinLoaded', () => {
19536 const serviceMessage = getServiceMessage(editor);
19537 if (serviceMessage) {
19538 open({
19539 text: serviceMessage,
19540 type: 'warning',
19541 timeout: 0
19542 }, false);
19543 }
19544 reposition();
19545 });
19546 editor.on('show ResizeEditor NodeChange', () => {
19547 requestAnimationFrame(reposition);
19548 });
19549 editor.on('remove', () => {
19550 each$e(notifications.slice(), notification => {
19551 getImplementation().close(notification);
19552 });
19553 });
19554 editor.addShortcut('alt+F12', 'Focus to notification', () => getTopNotification().map(notificationApi => SugarElement.fromDom(notificationApi.getEl())).each(elm => focus$1(elm)));
19555 };
19556 registerEvents(editor);
19557 return {
19558 open,
19559 close,
19560 getNotifications
19561 };
19562 };
19563
19564 const PluginManager = AddOnManager.PluginManager;
19565
19566 const ThemeManager = AddOnManager.ThemeManager;
19567
19568 var WindowManagerImpl = () => {
19569 const unimplemented = () => {
19570 throw new Error('Theme did not provide a WindowManager implementation.');
19571 };
19572 return {
19573 open: unimplemented,
19574 openUrl: unimplemented,
19575 alert: unimplemented,
19576 confirm: unimplemented,
19577 close: unimplemented
19578 };
19579 };
19580
19581 const WindowManager = editor => {
19582 let dialogs = [];
19583 const getImplementation = () => {
19584 const theme = editor.theme;
19585 return theme && theme.getWindowManagerImpl ? theme.getWindowManagerImpl() : WindowManagerImpl();
19586 };
19587 const funcBind = (scope, f) => {
19588 return (...args) => {
19589 return f ? f.apply(scope, args) : undefined;
19590 };
19591 };
19592 const fireOpenEvent = dialog => {
19593 editor.dispatch('OpenWindow', { dialog });
19594 };
19595 const fireCloseEvent = dialog => {
19596 editor.dispatch('CloseWindow', { dialog });
19597 };
19598 const addDialog = dialog => {
19599 dialogs.push(dialog);
19600 fireOpenEvent(dialog);
19601 };
19602 const closeDialog = dialog => {
19603 fireCloseEvent(dialog);
19604 dialogs = filter$5(dialogs, otherDialog => {
19605 return otherDialog !== dialog;
19606 });
19607 if (dialogs.length === 0) {
19608 editor.focus();
19609 }
19610 };
19611 const getTopDialog = () => {
19612 return Optional.from(dialogs[dialogs.length - 1]);
19613 };
19614 const storeSelectionAndOpenDialog = openDialog => {
19615 editor.editorManager.setActive(editor);
19616 store(editor);
19617 editor.ui.show();
19618 const dialog = openDialog();
19619 addDialog(dialog);
19620 return dialog;
19621 };
19622 const open = (args, params) => {
19623 return storeSelectionAndOpenDialog(() => getImplementation().open(args, params, closeDialog));
19624 };
19625 const openUrl = args => {
19626 return storeSelectionAndOpenDialog(() => getImplementation().openUrl(args, closeDialog));
19627 };
19628 const alert = (message, callback, scope) => {
19629 const windowManagerImpl = getImplementation();
19630 windowManagerImpl.alert(message, funcBind(scope ? scope : windowManagerImpl, callback));
19631 };
19632 const confirm = (message, callback, scope) => {
19633 const windowManagerImpl = getImplementation();
19634 windowManagerImpl.confirm(message, funcBind(scope ? scope : windowManagerImpl, callback));
19635 };
19636 const close = () => {
19637 getTopDialog().each(dialog => {
19638 getImplementation().close(dialog);
19639 closeDialog(dialog);
19640 });
19641 };
19642 editor.on('remove', () => {
19643 each$e(dialogs, dialog => {
19644 getImplementation().close(dialog);
19645 });
19646 });
19647 return {
19648 open,
19649 openUrl,
19650 alert,
19651 confirm,
19652 close
19653 };
19654 };
19655
19656 const displayNotification = (editor, message) => {
19657 editor.notificationManager.open({
19658 type: 'error',
19659 text: message
19660 });
19661 };
19662 const displayError = (editor, message) => {
19663 if (editor._skinLoaded) {
19664 displayNotification(editor, message);
19665 } else {
19666 editor.on('SkinLoaded', () => {
19667 displayNotification(editor, message);
19668 });
19669 }
19670 };
19671 const uploadError = (editor, message) => {
19672 displayError(editor, I18n.translate([
19673 'Failed to upload image: {0}',
19674 message
19675 ]));
19676 };
19677 const logError = (editor, errorType, msg) => {
19678 fireError(editor, errorType, { message: msg });
19679 console.error(msg);
19680 };
19681 const createLoadError = (type, url, name) => name ? `Failed to load ${ type }: ${ name } from url ${ url }` : `Failed to load ${ type } url: ${ url }`;
19682 const pluginLoadError = (editor, url, name) => {
19683 logError(editor, 'PluginLoadError', createLoadError('plugin', url, name));
19684 };
19685 const iconsLoadError = (editor, url, name) => {
19686 logError(editor, 'IconsLoadError', createLoadError('icons', url, name));
19687 };
19688 const languageLoadError = (editor, url, name) => {
19689 logError(editor, 'LanguageLoadError', createLoadError('language', url, name));
19690 };
19691 const themeLoadError = (editor, url, name) => {
19692 logError(editor, 'ThemeLoadError', createLoadError('theme', url, name));
19693 };
19694 const modelLoadError = (editor, url, name) => {
19695 logError(editor, 'ModelLoadError', createLoadError('model', url, name));
19696 };
19697 const pluginInitError = (editor, name, err) => {
19698 const message = I18n.translate([
19699 'Failed to initialize plugin: {0}',
19700 name
19701 ]);
19702 fireError(editor, 'PluginLoadError', { message });
19703 initError(message, err);
19704 displayError(editor, message);
19705 };
19706 const initError = (message, ...x) => {
19707 const console = window.console;
19708 if (console) {
19709 if (console.error) {
19710 console.error(message, ...x);
19711 } else {
19712 console.log(message, ...x);
19713 }
19714 }
19715 };
19716
19717 const isContentCssSkinName = url => /^[a-z0-9\-]+$/i.test(url);
19718 const toContentSkinResourceName = url => 'content/' + url + '/content.css';
19719 const isBundledCssSkinName = url => tinymce.Resource.has(toContentSkinResourceName(url));
19720 const getContentCssUrls = editor => {
19721 return transformToUrls(editor, getContentCss(editor));
19722 };
19723 const getFontCssUrls = editor => {
19724 return transformToUrls(editor, getFontCss(editor));
19725 };
19726 const transformToUrls = (editor, cssLinks) => {
19727 const skinUrl = editor.editorManager.baseURL + '/skins/content';
19728 const suffix = editor.editorManager.suffix;
19729 const contentCssFile = `content${ suffix }.css`;
19730 return map$3(cssLinks, url => {
19731 if (isBundledCssSkinName(url)) {
19732 return url;
19733 } else if (isContentCssSkinName(url) && !editor.inline) {
19734 return `${ skinUrl }/${ url }/${ contentCssFile }`;
19735 } else {
19736 return editor.documentBaseURI.toAbsolute(url);
19737 }
19738 });
19739 };
19740 const appendContentCssFromSettings = editor => {
19741 editor.contentCSS = editor.contentCSS.concat(getContentCssUrls(editor), getFontCssUrls(editor));
19742 };
19743
19744 const getAllImages = elm => {
19745 return elm ? from(elm.getElementsByTagName('img')) : [];
19746 };
19747 const ImageScanner = (uploadStatus, blobCache) => {
19748 const cachedPromises = {};
19749 const findAll = (elm, predicate = always) => {
19750 const images = filter$5(getAllImages(elm), img => {
19751 const src = img.src;
19752 if (img.hasAttribute('data-mce-bogus')) {
19753 return false;
19754 }
19755 if (img.hasAttribute('data-mce-placeholder')) {
19756 return false;
19757 }
19758 if (!src || src === Env.transparentSrc) {
19759 return false;
19760 }
19761 if (startsWith(src, 'blob:')) {
19762 return !uploadStatus.isUploaded(src) && predicate(img);
19763 }
19764 if (startsWith(src, 'data:')) {
19765 return predicate(img);
19766 }
19767 return false;
19768 });
19769 const promises = map$3(images, img => {
19770 const imageSrc = img.src;
19771 if (has$2(cachedPromises, imageSrc)) {
19772 return cachedPromises[imageSrc].then(imageInfo => {
19773 if (isString(imageInfo)) {
19774 return imageInfo;
19775 } else {
19776 return {
19777 image: img,
19778 blobInfo: imageInfo.blobInfo
19779 };
19780 }
19781 });
19782 } else {
19783 const newPromise = imageToBlobInfo(blobCache, imageSrc).then(blobInfo => {
19784 delete cachedPromises[imageSrc];
19785 return {
19786 image: img,
19787 blobInfo
19788 };
19789 }).catch(error => {
19790 delete cachedPromises[imageSrc];
19791 return error;
19792 });
19793 cachedPromises[imageSrc] = newPromise;
19794 return newPromise;
19795 }
19796 });
19797 return Promise.all(promises);
19798 };
19799 return { findAll };
19800 };
19801
19802 const UploadStatus = () => {
19803 const PENDING = 1, UPLOADED = 2;
19804 let blobUriStatuses = {};
19805 const createStatus = (status, resultUri) => {
19806 return {
19807 status,
19808 resultUri
19809 };
19810 };
19811 const hasBlobUri = blobUri => {
19812 return blobUri in blobUriStatuses;
19813 };
19814 const getResultUri = blobUri => {
19815 const result = blobUriStatuses[blobUri];
19816 return result ? result.resultUri : null;
19817 };
19818 const isPending = blobUri => {
19819 return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === PENDING : false;
19820 };
19821 const isUploaded = blobUri => {
19822 return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === UPLOADED : false;
19823 };
19824 const markPending = blobUri => {
19825 blobUriStatuses[blobUri] = createStatus(PENDING, null);
19826 };
19827 const markUploaded = (blobUri, resultUri) => {
19828 blobUriStatuses[blobUri] = createStatus(UPLOADED, resultUri);
19829 };
19830 const removeFailed = blobUri => {
19831 delete blobUriStatuses[blobUri];
19832 };
19833 const destroy = () => {
19834 blobUriStatuses = {};
19835 };
19836 return {
19837 hasBlobUri,
19838 getResultUri,
19839 isPending,
19840 isUploaded,
19841 markPending,
19842 markUploaded,
19843 removeFailed,
19844 destroy
19845 };
19846 };
19847
19848 let count = 0;
19849 const seed = () => {
19850 const rnd = () => {
19851 return Math.round(Math.random() * 4294967295).toString(36);
19852 };
19853 const now = new Date().getTime();
19854 return 's' + now.toString(36) + rnd() + rnd() + rnd();
19855 };
19856 const uuid = prefix => {
19857 return prefix + count++ + seed();
19858 };
19859
19860 const BlobCache = () => {
19861 let cache = [];
19862 const mimeToExt = mime => {
19863 const mimes = {
19864 'image/jpeg': 'jpg',
19865 'image/jpg': 'jpg',
19866 'image/gif': 'gif',
19867 'image/png': 'png',
19868 'image/apng': 'apng',
19869 'image/avif': 'avif',
19870 'image/svg+xml': 'svg',
19871 'image/webp': 'webp',
19872 'image/bmp': 'bmp',
19873 'image/tiff': 'tiff'
19874 };
19875 return mimes[mime.toLowerCase()] || 'dat';
19876 };
19877 const create = (o, blob, base64, name, filename) => {
19878 if (isString(o)) {
19879 const id = o;
19880 return toBlobInfo({
19881 id,
19882 name,
19883 filename,
19884 blob: blob,
19885 base64: base64
19886 });
19887 } else if (isObject(o)) {
19888 return toBlobInfo(o);
19889 } else {
19890 throw new Error('Unknown input type');
19891 }
19892 };
19893 const toBlobInfo = o => {
19894 if (!o.blob || !o.base64) {
19895 throw new Error('blob and base64 representations of the image are required for BlobInfo to be created');
19896 }
19897 const id = o.id || uuid('blobid');
19898 const name = o.name || id;
19899 const blob = o.blob;
19900 return {
19901 id: constant(id),
19902 name: constant(name),
19903 filename: constant(o.filename || name + '.' + mimeToExt(blob.type)),
19904 blob: constant(blob),
19905 base64: constant(o.base64),
19906 blobUri: constant(o.blobUri || URL.createObjectURL(blob)),
19907 uri: constant(o.uri)
19908 };
19909 };
19910 const add = blobInfo => {
19911 if (!get(blobInfo.id())) {
19912 cache.push(blobInfo);
19913 }
19914 };
19915 const findFirst = predicate => find$2(cache, predicate).getOrUndefined();
19916 const get = id => findFirst(cachedBlobInfo => cachedBlobInfo.id() === id);
19917 const getByUri = blobUri => findFirst(blobInfo => blobInfo.blobUri() === blobUri);
19918 const getByData = (base64, type) => findFirst(blobInfo => blobInfo.base64() === base64 && blobInfo.blob().type === type);
19919 const removeByUri = blobUri => {
19920 cache = filter$5(cache, blobInfo => {
19921 if (blobInfo.blobUri() === blobUri) {
19922 URL.revokeObjectURL(blobInfo.blobUri());
19923 return false;
19924 }
19925 return true;
19926 });
19927 };
19928 const destroy = () => {
19929 each$e(cache, cachedBlobInfo => {
19930 URL.revokeObjectURL(cachedBlobInfo.blobUri());
19931 });
19932 cache = [];
19933 };
19934 return {
19935 create,
19936 add,
19937 get,
19938 getByUri,
19939 getByData,
19940 findFirst,
19941 removeByUri,
19942 destroy
19943 };
19944 };
19945
19946 const Uploader = (uploadStatus, settings) => {
19947 const pendingPromises = {};
19948 const pathJoin = (path1, path2) => {
19949 if (path1) {
19950 return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, '');
19951 }
19952 return path2;
19953 };
19954 const defaultHandler = (blobInfo, progress) => new Promise((success, failure) => {
19955 const xhr = new XMLHttpRequest();
19956 xhr.open('POST', settings.url);
19957 xhr.withCredentials = settings.credentials;
19958 xhr.upload.onprogress = e => {
19959 progress(e.loaded / e.total * 100);
19960 };
19961 xhr.onerror = () => {
19962 failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
19963 };
19964 xhr.onload = () => {
19965 if (xhr.status < 200 || xhr.status >= 300) {
19966 failure('HTTP Error: ' + xhr.status);
19967 return;
19968 }
19969 const json = JSON.parse(xhr.responseText);
19970 if (!json || !isString(json.location)) {
19971 failure('Invalid JSON: ' + xhr.responseText);
19972 return;
19973 }
19974 success(pathJoin(settings.basePath, json.location));
19975 };
19976 const formData = new FormData();
19977 formData.append('file', blobInfo.blob(), blobInfo.filename());
19978 xhr.send(formData);
19979 });
19980 const uploadHandler = isFunction(settings.handler) ? settings.handler : defaultHandler;
19981 const noUpload = () => new Promise(resolve => {
19982 resolve([]);
19983 });
19984 const handlerSuccess = (blobInfo, url) => ({
19985 url,
19986 blobInfo,
19987 status: true
19988 });
19989 const handlerFailure = (blobInfo, error) => ({
19990 url: '',
19991 blobInfo,
19992 status: false,
19993 error
19994 });
19995 const resolvePending = (blobUri, result) => {
19996 Tools.each(pendingPromises[blobUri], resolve => {
19997 resolve(result);
19998 });
19999 delete pendingPromises[blobUri];
20000 };
20001 const uploadBlobInfo = (blobInfo, handler, openNotification) => {
20002 uploadStatus.markPending(blobInfo.blobUri());
20003 return new Promise(resolve => {
20004 let notification;
20005 let progress;
20006 try {
20007 const closeNotification = () => {
20008 if (notification) {
20009 notification.close();
20010 progress = noop;
20011 }
20012 };
20013 const success = url => {
20014 closeNotification();
20015 uploadStatus.markUploaded(blobInfo.blobUri(), url);
20016 resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url));
20017 resolve(handlerSuccess(blobInfo, url));
20018 };
20019 const failure = error => {
20020 closeNotification();
20021 uploadStatus.removeFailed(blobInfo.blobUri());
20022 resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, error));
20023 resolve(handlerFailure(blobInfo, error));
20024 };
20025 progress = percent => {
20026 if (percent < 0 || percent > 100) {
20027 return;
20028 }
20029 Optional.from(notification).orThunk(() => Optional.from(openNotification).map(apply$1)).each(n => {
20030 notification = n;
20031 n.progressBar.value(percent);
20032 });
20033 };
20034 handler(blobInfo, progress).then(success, err => {
20035 failure(isString(err) ? { message: err } : err);
20036 });
20037 } catch (ex) {
20038 resolve(handlerFailure(blobInfo, ex));
20039 }
20040 });
20041 };
20042 const isDefaultHandler = handler => handler === defaultHandler;
20043 const pendingUploadBlobInfo = blobInfo => {
20044 const blobUri = blobInfo.blobUri();
20045 return new Promise(resolve => {
20046 pendingPromises[blobUri] = pendingPromises[blobUri] || [];
20047 pendingPromises[blobUri].push(resolve);
20048 });
20049 };
20050 const uploadBlobs = (blobInfos, openNotification) => {
20051 blobInfos = Tools.grep(blobInfos, blobInfo => !uploadStatus.isUploaded(blobInfo.blobUri()));
20052 return Promise.all(Tools.map(blobInfos, blobInfo => uploadStatus.isPending(blobInfo.blobUri()) ? pendingUploadBlobInfo(blobInfo) : uploadBlobInfo(blobInfo, uploadHandler, openNotification)));
20053 };
20054 const upload = (blobInfos, openNotification) => !settings.url && isDefaultHandler(uploadHandler) ? noUpload() : uploadBlobs(blobInfos, openNotification);
20055 return { upload };
20056 };
20057
20058 const openNotification = editor => () => editor.notificationManager.open({
20059 text: editor.translate('Image uploading...'),
20060 type: 'info',
20061 timeout: -1,
20062 progressBar: true
20063 });
20064 const createUploader = (editor, uploadStatus) => Uploader(uploadStatus, {
20065 url: getImageUploadUrl(editor),
20066 basePath: getImageUploadBasePath(editor),
20067 credentials: getImagesUploadCredentials(editor),
20068 handler: getImagesUploadHandler(editor)
20069 });
20070 const ImageUploader = editor => {
20071 const uploadStatus = UploadStatus();
20072 const uploader = createUploader(editor, uploadStatus);
20073 return { upload: (blobInfos, showNotification = true) => uploader.upload(blobInfos, showNotification ? openNotification(editor) : undefined) };
20074 };
20075
20076 const isEmptyForPadding = (editor, element) => editor.dom.isEmpty(element.dom) && isNonNullable(editor.schema.getTextBlockElements()[name(element)]);
20077 const addPaddingToEmpty = editor => element => {
20078 if (isEmptyForPadding(editor, element)) {
20079 append$1(element, SugarElement.fromHtml('<br data-mce-bogus="1" />'));
20080 }
20081 };
20082 const EditorUpload = editor => {
20083 const blobCache = BlobCache();
20084 let uploader, imageScanner;
20085 const uploadStatus = UploadStatus();
20086 const urlFilters = [];
20087 const aliveGuard = callback => {
20088 return result => {
20089 if (editor.selection) {
20090 return callback(result);
20091 }
20092 return [];
20093 };
20094 };
20095 const cacheInvalidator = url => url + (url.indexOf('?') === -1 ? '?' : '&') + new Date().getTime();
20096 const replaceString = (content, search, replace) => {
20097 let index = 0;
20098 do {
20099 index = content.indexOf(search, index);
20100 if (index !== -1) {
20101 content = content.substring(0, index) + replace + content.substr(index + search.length);
20102 index += replace.length - search.length + 1;
20103 }
20104 } while (index !== -1);
20105 return content;
20106 };
20107 const replaceImageUrl = (content, targetUrl, replacementUrl) => {
20108 const replacementString = `src="${ replacementUrl }"${ replacementUrl === Env.transparentSrc ? ' data-mce-placeholder="1"' : '' }`;
20109 content = replaceString(content, `src="${ targetUrl }"`, replacementString);
20110 content = replaceString(content, 'data-mce-src="' + targetUrl + '"', 'data-mce-src="' + replacementUrl + '"');
20111 return content;
20112 };
20113 const replaceUrlInUndoStack = (targetUrl, replacementUrl) => {
20114 each$e(editor.undoManager.data, level => {
20115 if (level.type === 'fragmented') {
20116 level.fragments = map$3(level.fragments, fragment => replaceImageUrl(fragment, targetUrl, replacementUrl));
20117 } else {
20118 level.content = replaceImageUrl(level.content, targetUrl, replacementUrl);
20119 }
20120 });
20121 };
20122 const replaceImageUriInView = (image, resultUri) => {
20123 const src = editor.convertURL(resultUri, 'src');
20124 replaceUrlInUndoStack(image.src, resultUri);
20125 setAll$1(SugarElement.fromDom(image), {
20126 'src': shouldReuseFileName(editor) ? cacheInvalidator(resultUri) : resultUri,
20127 'data-mce-src': src
20128 });
20129 };
20130 const uploadImages = () => {
20131 if (!uploader) {
20132 uploader = createUploader(editor, uploadStatus);
20133 }
20134 return scanForImages().then(aliveGuard(imageInfos => {
20135 const blobInfos = map$3(imageInfos, imageInfo => imageInfo.blobInfo);
20136 return uploader.upload(blobInfos, openNotification(editor)).then(aliveGuard(result => {
20137 const imagesToRemove = [];
20138 let shouldDispatchChange = false;
20139 const filteredResult = map$3(result, (uploadInfo, index) => {
20140 const {blobInfo, image} = imageInfos[index];
20141 let removed = false;
20142 if (uploadInfo.status && shouldReplaceBlobUris(editor)) {
20143 if (uploadInfo.url && !contains$1(image.src, uploadInfo.url)) {
20144 shouldDispatchChange = true;
20145 }
20146 blobCache.removeByUri(image.src);
20147 if (isRtc(editor)) ; else {
20148 replaceImageUriInView(image, uploadInfo.url);
20149 }
20150 } else if (uploadInfo.error) {
20151 if (uploadInfo.error.remove) {
20152 replaceUrlInUndoStack(image.src, Env.transparentSrc);
20153 imagesToRemove.push(image);
20154 removed = true;
20155 }
20156 uploadError(editor, uploadInfo.error.message);
20157 }
20158 return {
20159 element: image,
20160 status: uploadInfo.status,
20161 uploadUri: uploadInfo.url,
20162 blobInfo,
20163 removed
20164 };
20165 });
20166 if (imagesToRemove.length > 0 && !isRtc(editor)) {
20167 editor.undoManager.transact(() => {
20168 each$e(fromDom$1(imagesToRemove), sugarElement => {
20169 const parentOpt = parent(sugarElement);
20170 remove$4(sugarElement);
20171 parentOpt.each(addPaddingToEmpty(editor));
20172 blobCache.removeByUri(sugarElement.dom.src);
20173 });
20174 });
20175 } else if (shouldDispatchChange) {
20176 editor.undoManager.dispatchChange();
20177 }
20178 return filteredResult;
20179 }));
20180 }));
20181 };
20182 const uploadImagesAuto = () => isAutomaticUploadsEnabled(editor) ? uploadImages() : Promise.resolve([]);
20183 const isValidDataUriImage = imgElm => forall(urlFilters, filter => filter(imgElm));
20184 const addFilter = filter => {
20185 urlFilters.push(filter);
20186 };
20187 const scanForImages = () => {
20188 if (!imageScanner) {
20189 imageScanner = ImageScanner(uploadStatus, blobCache);
20190 }
20191 return imageScanner.findAll(editor.getBody(), isValidDataUriImage).then(aliveGuard(result => {
20192 const filteredResult = filter$5(result, resultItem => {
20193 if (isString(resultItem)) {
20194 displayError(editor, resultItem);
20195 return false;
20196 } else if (resultItem.uriType === 'blob') {
20197 return false;
20198 } else {
20199 return true;
20200 }
20201 });
20202 if (isRtc(editor)) ; else {
20203 each$e(filteredResult, resultItem => {
20204 replaceUrlInUndoStack(resultItem.image.src, resultItem.blobInfo.blobUri());
20205 resultItem.image.src = resultItem.blobInfo.blobUri();
20206 resultItem.image.removeAttribute('data-mce-src');
20207 });
20208 }
20209 return filteredResult;
20210 }));
20211 };
20212 const destroy = () => {
20213 blobCache.destroy();
20214 uploadStatus.destroy();
20215 imageScanner = uploader = null;
20216 };
20217 const replaceBlobUris = content => {
20218 return content.replace(/src="(blob:[^"]+)"/g, (match, blobUri) => {
20219 const resultUri = uploadStatus.getResultUri(blobUri);
20220 if (resultUri) {
20221 return 'src="' + resultUri + '"';
20222 }
20223 let blobInfo = blobCache.getByUri(blobUri);
20224 if (!blobInfo) {
20225 blobInfo = foldl(editor.editorManager.get(), (result, editor) => {
20226 return result || editor.editorUpload && editor.editorUpload.blobCache.getByUri(blobUri);
20227 }, undefined);
20228 }
20229 if (blobInfo) {
20230 const blob = blobInfo.blob();
20231 return 'src="data:' + blob.type + ';base64,' + blobInfo.base64() + '"';
20232 }
20233 return match;
20234 });
20235 };
20236 editor.on('SetContent', () => {
20237 if (isAutomaticUploadsEnabled(editor)) {
20238 uploadImagesAuto();
20239 } else {
20240 scanForImages();
20241 }
20242 });
20243 editor.on('RawSaveContent', e => {
20244 e.content = replaceBlobUris(e.content);
20245 });
20246 editor.on('GetContent', e => {
20247 if (e.source_view || e.format === 'raw' || e.format === 'tree') {
20248 return;
20249 }
20250 e.content = replaceBlobUris(e.content);
20251 });
20252 editor.on('PostRender', () => {
20253 editor.parser.addNodeFilter('img', images => {
20254 each$e(images, img => {
20255 const src = img.attr('src');
20256 if (!src || blobCache.getByUri(src)) {
20257 return;
20258 }
20259 const resultUri = uploadStatus.getResultUri(src);
20260 if (resultUri) {
20261 img.attr('src', resultUri);
20262 }
20263 });
20264 });
20265 });
20266 return {
20267 blobCache,
20268 addFilter,
20269 uploadImages,
20270 uploadImagesAuto,
20271 scanForImages,
20272 destroy
20273 };
20274 };
20275
20276 const get$1 = editor => {
20277 const dom = editor.dom;
20278 const schemaType = editor.schema.type;
20279 const formats = {
20280 valigntop: [{
20281 selector: 'td,th',
20282 styles: { verticalAlign: 'top' }
20283 }],
20284 valignmiddle: [{
20285 selector: 'td,th',
20286 styles: { verticalAlign: 'middle' }
20287 }],
20288 valignbottom: [{
20289 selector: 'td,th',
20290 styles: { verticalAlign: 'bottom' }
20291 }],
20292 alignleft: [
20293 {
20294 selector: 'figure.image',
20295 collapsed: false,
20296 classes: 'align-left',
20297 ceFalseOverride: true,
20298 preview: 'font-family font-size'
20299 },
20300 {
20301 selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
20302 styles: { textAlign: 'left' },
20303 inherit: false,
20304 preview: false
20305 },
20306 {
20307 selector: 'img,audio,video',
20308 collapsed: false,
20309 styles: { float: 'left' },
20310 preview: 'font-family font-size'
20311 },
20312 {
20313 selector: 'table',
20314 collapsed: false,
20315 styles: {
20316 marginLeft: '0px',
20317 marginRight: 'auto'
20318 },
20319 onformat: table => {
20320 dom.setStyle(table, 'float', null);
20321 },
20322 preview: 'font-family font-size'
20323 },
20324 {
20325 selector: '.mce-preview-object,[data-ephox-embed-iri]',
20326 ceFalseOverride: true,
20327 styles: { float: 'left' }
20328 }
20329 ],
20330 aligncenter: [
20331 {
20332 selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
20333 styles: { textAlign: 'center' },
20334 inherit: false,
20335 preview: 'font-family font-size'
20336 },
20337 {
20338 selector: 'figure.image',
20339 collapsed: false,
20340 classes: 'align-center',
20341 ceFalseOverride: true,
20342 preview: 'font-family font-size'
20343 },
20344 {
20345 selector: 'img,audio,video',
20346 collapsed: false,
20347 styles: {
20348 display: 'block',
20349 marginLeft: 'auto',
20350 marginRight: 'auto'
20351 },
20352 preview: false
20353 },
20354 {
20355 selector: 'table',
20356 collapsed: false,
20357 styles: {
20358 marginLeft: 'auto',
20359 marginRight: 'auto'
20360 },
20361 preview: 'font-family font-size'
20362 },
20363 {
20364 selector: '.mce-preview-object',
20365 ceFalseOverride: true,
20366 styles: {
20367 display: 'table',
20368 marginLeft: 'auto',
20369 marginRight: 'auto'
20370 },
20371 preview: false
20372 },
20373 {
20374 selector: '[data-ephox-embed-iri]',
20375 ceFalseOverride: true,
20376 styles: {
20377 marginLeft: 'auto',
20378 marginRight: 'auto'
20379 },
20380 preview: false
20381 }
20382 ],
20383 alignright: [
20384 {
20385 selector: 'figure.image',
20386 collapsed: false,
20387 classes: 'align-right',
20388 ceFalseOverride: true,
20389 preview: 'font-family font-size'
20390 },
20391 {
20392 selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
20393 styles: { textAlign: 'right' },
20394 inherit: false,
20395 preview: 'font-family font-size'
20396 },
20397 {
20398 selector: 'img,audio,video',
20399 collapsed: false,
20400 styles: { float: 'right' },
20401 preview: 'font-family font-size'
20402 },
20403 {
20404 selector: 'table',
20405 collapsed: false,
20406 styles: {
20407 marginRight: '0px',
20408 marginLeft: 'auto'
20409 },
20410 onformat: table => {
20411 dom.setStyle(table, 'float', null);
20412 },
20413 preview: 'font-family font-size'
20414 },
20415 {
20416 selector: '.mce-preview-object,[data-ephox-embed-iri]',
20417 ceFalseOverride: true,
20418 styles: { float: 'right' },
20419 preview: false
20420 }
20421 ],
20422 alignjustify: [{
20423 selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
20424 styles: { textAlign: 'justify' },
20425 inherit: false,
20426 preview: 'font-family font-size'
20427 }],
20428 bold: [
20429 {
20430 inline: 'strong',
20431 remove: 'all',
20432 preserve_attributes: [
20433 'class',
20434 'style'
20435 ]
20436 },
20437 {
20438 inline: 'span',
20439 styles: { fontWeight: 'bold' }
20440 },
20441 {
20442 inline: 'b',
20443 remove: 'all',
20444 preserve_attributes: [
20445 'class',
20446 'style'
20447 ]
20448 }
20449 ],
20450 italic: [
20451 {
20452 inline: 'em',
20453 remove: 'all',
20454 preserve_attributes: [
20455 'class',
20456 'style'
20457 ]
20458 },
20459 {
20460 inline: 'span',
20461 styles: { fontStyle: 'italic' }
20462 },
20463 {
20464 inline: 'i',
20465 remove: 'all',
20466 preserve_attributes: [
20467 'class',
20468 'style'
20469 ]
20470 }
20471 ],
20472 underline: [
20473 {
20474 inline: 'span',
20475 styles: { textDecoration: 'underline' },
20476 exact: true
20477 },
20478 {
20479 inline: 'u',
20480 remove: 'all',
20481 preserve_attributes: [
20482 'class',
20483 'style'
20484 ]
20485 }
20486 ],
20487 strikethrough: (() => {
20488 const span = {
20489 inline: 'span',
20490 styles: { textDecoration: 'line-through' },
20491 exact: true
20492 };
20493 const strike = {
20494 inline: 'strike',
20495 remove: 'all',
20496 preserve_attributes: [
20497 'class',
20498 'style'
20499 ]
20500 };
20501 const s = {
20502 inline: 's',
20503 remove: 'all',
20504 preserve_attributes: [
20505 'class',
20506 'style'
20507 ]
20508 };
20509 return schemaType !== 'html4' ? [
20510 s,
20511 span,
20512 strike
20513 ] : [
20514 span,
20515 s,
20516 strike
20517 ];
20518 })(),
20519 forecolor: {
20520 inline: 'span',
20521 styles: { color: '%value' },
20522 links: true,
20523 remove_similar: true,
20524 clear_child_styles: true
20525 },
20526 hilitecolor: {
20527 inline: 'span',
20528 styles: { backgroundColor: '%value' },
20529 links: true,
20530 remove_similar: true,
20531 clear_child_styles: true
20532 },
20533 fontname: {
20534 inline: 'span',
20535 toggle: false,
20536 styles: { fontFamily: '%value' },
20537 clear_child_styles: true
20538 },
20539 fontsize: {
20540 inline: 'span',
20541 toggle: false,
20542 styles: { fontSize: '%value' },
20543 clear_child_styles: true
20544 },
20545 lineheight: {
20546 selector: 'h1,h2,h3,h4,h5,h6,p,li,td,th,div',
20547 styles: { lineHeight: '%value' }
20548 },
20549 fontsize_class: {
20550 inline: 'span',
20551 attributes: { class: '%value' }
20552 },
20553 blockquote: {
20554 block: 'blockquote',
20555 wrapper: true,
20556 remove: 'all'
20557 },
20558 subscript: { inline: 'sub' },
20559 superscript: { inline: 'sup' },
20560 code: { inline: 'code' },
20561 link: {
20562 inline: 'a',
20563 selector: 'a',
20564 remove: 'all',
20565 split: true,
20566 deep: true,
20567 onmatch: (node, _fmt, _itemName) => {
20568 return isElement$6(node) && node.hasAttribute('href');
20569 },
20570 onformat: (elm, _fmt, vars) => {
20571 Tools.each(vars, (value, key) => {
20572 dom.setAttrib(elm, key, value);
20573 });
20574 }
20575 },
20576 lang: {
20577 inline: 'span',
20578 clear_child_styles: true,
20579 remove_similar: true,
20580 attributes: {
20581 'lang': '%value',
20582 'data-mce-lang': vars => {
20583 var _a;
20584 return (_a = vars === null || vars === void 0 ? void 0 : vars.customValue) !== null && _a !== void 0 ? _a : null;
20585 }
20586 }
20587 },
20588 removeformat: [
20589 {
20590 selector: 'b,strong,em,i,font,u,strike,s,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins,small',
20591 remove: 'all',
20592 split: true,
20593 expand: false,
20594 block_expand: true,
20595 deep: true
20596 },
20597 {
20598 selector: 'span',
20599 attributes: [
20600 'style',
20601 'class'
20602 ],
20603 remove: 'empty',
20604 split: true,
20605 expand: false,
20606 deep: true
20607 },
20608 {
20609 selector: '*',
20610 attributes: [
20611 'style',
20612 'class'
20613 ],
20614 split: false,
20615 expand: false,
20616 deep: true
20617 }
20618 ]
20619 };
20620 Tools.each('p h1 h2 h3 h4 h5 h6 div address pre dt dd samp'.split(/\s/), name => {
20621 formats[name] = {
20622 block: name,
20623 remove: 'all'
20624 };
20625 });
20626 return formats;
20627 };
20628
20629 const genericBase = {
20630 remove_similar: true,
20631 inherit: false
20632 };
20633 const cellBase = {
20634 selector: 'td,th',
20635 ...genericBase
20636 };
20637 const cellFormats = {
20638 tablecellbackgroundcolor: {
20639 styles: { backgroundColor: '%value' },
20640 ...cellBase
20641 },
20642 tablecellverticalalign: {
20643 styles: { 'vertical-align': '%value' },
20644 ...cellBase
20645 },
20646 tablecellbordercolor: {
20647 styles: { borderColor: '%value' },
20648 ...cellBase
20649 },
20650 tablecellclass: {
20651 classes: ['%value'],
20652 ...cellBase
20653 },
20654 tableclass: {
20655 selector: 'table',
20656 classes: ['%value'],
20657 ...genericBase
20658 },
20659 tablecellborderstyle: {
20660 styles: { borderStyle: '%value' },
20661 ...cellBase
20662 },
20663 tablecellborderwidth: {
20664 styles: { borderWidth: '%value' },
20665 ...cellBase
20666 }
20667 };
20668 const get = constant(cellFormats);
20669
20670 const FormatRegistry = editor => {
20671 const formats = {};
20672 const get$2 = name => isNonNullable(name) ? formats[name] : formats;
20673 const has = name => has$2(formats, name);
20674 const register = (name, format) => {
20675 if (name) {
20676 if (!isString(name)) {
20677 each$d(name, (format, name) => {
20678 register(name, format);
20679 });
20680 } else {
20681 if (!isArray$1(format)) {
20682 format = [format];
20683 }
20684 each$e(format, format => {
20685 if (isUndefined(format.deep)) {
20686 format.deep = !isSelectorFormat(format);
20687 }
20688 if (isUndefined(format.split)) {
20689 format.split = !isSelectorFormat(format) || isInlineFormat(format);
20690 }
20691 if (isUndefined(format.remove) && isSelectorFormat(format) && !isInlineFormat(format)) {
20692 format.remove = 'none';
20693 }
20694 if (isSelectorFormat(format) && isInlineFormat(format)) {
20695 format.mixed = true;
20696 format.block_expand = true;
20697 }
20698 if (isString(format.classes)) {
20699 format.classes = format.classes.split(/\s+/);
20700 }
20701 });
20702 formats[name] = format;
20703 }
20704 }
20705 };
20706 const unregister = name => {
20707 if (name && formats[name]) {
20708 delete formats[name];
20709 }
20710 return formats;
20711 };
20712 register(get$1(editor));
20713 register(get());
20714 register(getFormats(editor));
20715 return {
20716 get: get$2,
20717 has,
20718 register,
20719 unregister
20720 };
20721 };
20722
20723 const each$3 = Tools.each;
20724 const dom = DOMUtils.DOM;
20725 const isPreviewItem = item => isNonNullable(item) && isObject(item);
20726 const parsedSelectorToHtml = (ancestry, editor) => {
20727 const schema = editor && editor.schema || Schema({});
20728 const decorate = (elm, item) => {
20729 if (item.classes.length > 0) {
20730 dom.addClass(elm, item.classes.join(' '));
20731 }
20732 dom.setAttribs(elm, item.attrs);
20733 };
20734 const createElement = sItem => {
20735 const item = isString(sItem) ? {
20736 name: sItem,
20737 classes: [],
20738 attrs: {}
20739 } : sItem;
20740 const elm = dom.create(item.name);
20741 decorate(elm, item);
20742 return elm;
20743 };
20744 const getRequiredParent = (elm, candidate) => {
20745 const elmRule = schema.getElementRule(elm.nodeName.toLowerCase());
20746 const parentsRequired = elmRule === null || elmRule === void 0 ? void 0 : elmRule.parentsRequired;
20747 if (parentsRequired && parentsRequired.length) {
20748 return candidate && contains$2(parentsRequired, candidate) ? candidate : parentsRequired[0];
20749 } else {
20750 return false;
20751 }
20752 };
20753 const wrapInHtml = (elm, ancestors, siblings) => {
20754 let parentCandidate;
20755 const ancestor = ancestors[0];
20756 const ancestorName = isPreviewItem(ancestor) ? ancestor.name : undefined;
20757 const parentRequired = getRequiredParent(elm, ancestorName);
20758 if (parentRequired) {
20759 if (ancestorName === parentRequired) {
20760 parentCandidate = ancestor;
20761 ancestors = ancestors.slice(1);
20762 } else {
20763 parentCandidate = parentRequired;
20764 }
20765 } else if (ancestor) {
20766 parentCandidate = ancestor;
20767 ancestors = ancestors.slice(1);
20768 } else if (!siblings) {
20769 return elm;
20770 }
20771 const parent = parentCandidate ? createElement(parentCandidate) : dom.create('div');
20772 parent.appendChild(elm);
20773 if (siblings) {
20774 Tools.each(siblings, sibling => {
20775 const siblingElm = createElement(sibling);
20776 parent.insertBefore(siblingElm, elm);
20777 });
20778 }
20779 const parentSiblings = isPreviewItem(parentCandidate) ? parentCandidate.siblings : undefined;
20780 return wrapInHtml(parent, ancestors, parentSiblings);
20781 };
20782 const fragment = dom.create('div');
20783 if (ancestry.length > 0) {
20784 const item = ancestry[0];
20785 const elm = createElement(item);
20786 const siblings = isPreviewItem(item) ? item.siblings : undefined;
20787 fragment.appendChild(wrapInHtml(elm, ancestry.slice(1), siblings));
20788 }
20789 return fragment;
20790 };
20791 const parseSelectorItem = item => {
20792 item = Tools.trim(item);
20793 let tagName = 'div';
20794 const obj = {
20795 name: tagName,
20796 classes: [],
20797 attrs: {},
20798 selector: item
20799 };
20800 if (item !== '*') {
20801 tagName = item.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g, ($0, $1, $2, $3, $4) => {
20802 switch ($1) {
20803 case '#':
20804 obj.attrs.id = $2;
20805 break;
20806 case '.':
20807 obj.classes.push($2);
20808 break;
20809 case ':':
20810 if (Tools.inArray('checked disabled enabled read-only required'.split(' '), $2) !== -1) {
20811 obj.attrs[$2] = $2;
20812 }
20813 break;
20814 }
20815 if ($3 === '[') {
20816 const m = $4.match(/([\w\-]+)(?:\=\"([^\"]+))?/);
20817 if (m) {
20818 obj.attrs[m[1]] = m[2];
20819 }
20820 }
20821 return '';
20822 });
20823 }
20824 obj.name = tagName || 'div';
20825 return obj;
20826 };
20827 const parseSelector = selector => {
20828 if (!isString(selector)) {
20829 return [];
20830 }
20831 selector = selector.split(/\s*,\s*/)[0];
20832 selector = selector.replace(/\s*(~\+|~|\+|>)\s*/g, '$1');
20833 return Tools.map(selector.split(/(?:>|\s+(?![^\[\]]+\]))/), item => {
20834 const siblings = Tools.map(item.split(/(?:~\+|~|\+)/), parseSelectorItem);
20835 const obj = siblings.pop();
20836 if (siblings.length) {
20837 obj.siblings = siblings;
20838 }
20839 return obj;
20840 }).reverse();
20841 };
20842 const getCssText = (editor, format) => {
20843 let previewCss = '';
20844 let previewStyles = getPreviewStyles(editor);
20845 if (previewStyles === '') {
20846 return '';
20847 }
20848 const removeVars = val => {
20849 return isString(val) ? val.replace(/%(\w+)/g, '') : '';
20850 };
20851 const getComputedStyle = (name, elm) => {
20852 return dom.getStyle(elm !== null && elm !== void 0 ? elm : editor.getBody(), name, true);
20853 };
20854 if (isString(format)) {
20855 const formats = editor.formatter.get(format);
20856 if (!formats) {
20857 return '';
20858 }
20859 format = formats[0];
20860 }
20861 if ('preview' in format) {
20862 const preview = format.preview;
20863 if (preview === false) {
20864 return '';
20865 } else {
20866 previewStyles = preview || previewStyles;
20867 }
20868 }
20869 let name = format.block || format.inline || 'span';
20870 let previewFrag;
20871 const items = parseSelector(format.selector);
20872 if (items.length > 0) {
20873 if (!items[0].name) {
20874 items[0].name = name;
20875 }
20876 name = format.selector;
20877 previewFrag = parsedSelectorToHtml(items, editor);
20878 } else {
20879 previewFrag = parsedSelectorToHtml([name], editor);
20880 }
20881 const previewElm = dom.select(name, previewFrag)[0] || previewFrag.firstChild;
20882 each$3(format.styles, (value, name) => {
20883 const newValue = removeVars(value);
20884 if (newValue) {
20885 dom.setStyle(previewElm, name, newValue);
20886 }
20887 });
20888 each$3(format.attributes, (value, name) => {
20889 const newValue = removeVars(value);
20890 if (newValue) {
20891 dom.setAttrib(previewElm, name, newValue);
20892 }
20893 });
20894 each$3(format.classes, value => {
20895 const newValue = removeVars(value);
20896 if (!dom.hasClass(previewElm, newValue)) {
20897 dom.addClass(previewElm, newValue);
20898 }
20899 });
20900 editor.dispatch('PreviewFormats');
20901 dom.setStyles(previewFrag, {
20902 position: 'absolute',
20903 left: -65535
20904 });
20905 editor.getBody().appendChild(previewFrag);
20906 const rawParentFontSize = getComputedStyle('fontSize');
20907 const parentFontSize = /px$/.test(rawParentFontSize) ? parseInt(rawParentFontSize, 10) : 0;
20908 each$3(previewStyles.split(' '), name => {
20909 let value = getComputedStyle(name, previewElm);
20910 if (name === 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
20911 value = getComputedStyle(name);
20912 if (rgbaToHexString(value).toLowerCase() === '#ffffff') {
20913 return;
20914 }
20915 }
20916 if (name === 'color') {
20917 if (rgbaToHexString(value).toLowerCase() === '#000000') {
20918 return;
20919 }
20920 }
20921 if (name === 'font-size') {
20922 if (/em|%$/.test(value)) {
20923 if (parentFontSize === 0) {
20924 return;
20925 }
20926 const numValue = parseFloat(value) / (/%$/.test(value) ? 100 : 1);
20927 value = numValue * parentFontSize + 'px';
20928 }
20929 }
20930 if (name === 'border' && value) {
20931 previewCss += 'padding:0 2px;';
20932 }
20933 previewCss += name + ':' + value + ';';
20934 });
20935 editor.dispatch('AfterPreviewFormats');
20936 dom.remove(previewFrag);
20937 return previewCss;
20938 };
20939
20940 const setup$s = editor => {
20941 editor.addShortcut('meta+b', '', 'Bold');
20942 editor.addShortcut('meta+i', '', 'Italic');
20943 editor.addShortcut('meta+u', '', 'Underline');
20944 for (let i = 1; i <= 6; i++) {
20945 editor.addShortcut('access+' + i, '', [
20946 'FormatBlock',
20947 false,
20948 'h' + i
20949 ]);
20950 }
20951 editor.addShortcut('access+7', '', [
20952 'FormatBlock',
20953 false,
20954 'p'
20955 ]);
20956 editor.addShortcut('access+8', '', [
20957 'FormatBlock',
20958 false,
20959 'div'
20960 ]);
20961 editor.addShortcut('access+9', '', [
20962 'FormatBlock',
20963 false,
20964 'address'
20965 ]);
20966 };
20967
20968 const Formatter = editor => {
20969 const formats = FormatRegistry(editor);
20970 const formatChangeState = Cell({});
20971 setup$s(editor);
20972 setup$v(editor);
20973 if (!isRtc(editor)) {
20974 setup$u(formatChangeState, editor);
20975 }
20976 return {
20977 get: formats.get,
20978 has: formats.has,
20979 register: formats.register,
20980 unregister: formats.unregister,
20981 apply: (name, vars, node) => {
20982 applyFormat(editor, name, vars, node);
20983 },
20984 remove: (name, vars, node, similar) => {
20985 removeFormat(editor, name, vars, node, similar);
20986 },
20987 toggle: (name, vars, node) => {
20988 toggleFormat(editor, name, vars, node);
20989 },
20990 match: (name, vars, node, similar) => matchFormat(editor, name, vars, node, similar),
20991 closest: names => closestFormat(editor, names),
20992 matchAll: (names, vars) => matchAllFormats(editor, names, vars),
20993 matchNode: (node, name, vars, similar) => matchNodeFormat(editor, node, name, vars, similar),
20994 canApply: name => canApplyFormat(editor, name),
20995 formatChanged: (formats, callback, similar, vars) => formatChanged(editor, formatChangeState, formats, callback, similar, vars),
20996 getCssText: curry(getCssText, editor)
20997 };
20998 };
20999
21000 const shouldIgnoreCommand = cmd => {
21001 switch (cmd.toLowerCase()) {
21002 case 'undo':
21003 case 'redo':
21004 case 'mcefocus':
21005 return true;
21006 default:
21007 return false;
21008 }
21009 };
21010 const registerEvents = (editor, undoManager, locks) => {
21011 const isFirstTypedCharacter = Cell(false);
21012 const addNonTypingUndoLevel = e => {
21013 setTyping(undoManager, false, locks);
21014 undoManager.add({}, e);
21015 };
21016 editor.on('init', () => {
21017 undoManager.add();
21018 });
21019 editor.on('BeforeExecCommand', e => {
21020 const cmd = e.command;
21021 if (!shouldIgnoreCommand(cmd)) {
21022 endTyping(undoManager, locks);
21023 undoManager.beforeChange();
21024 }
21025 });
21026 editor.on('ExecCommand', e => {
21027 const cmd = e.command;
21028 if (!shouldIgnoreCommand(cmd)) {
21029 addNonTypingUndoLevel(e);
21030 }
21031 });
21032 editor.on('ObjectResizeStart cut', () => {
21033 undoManager.beforeChange();
21034 });
21035 editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
21036 editor.on('dragend', addNonTypingUndoLevel);
21037 editor.on('keyup', e => {
21038 const keyCode = e.keyCode;
21039 if (e.isDefaultPrevented()) {
21040 return;
21041 }
21042 const isMeta = Env.os.isMacOS() && e.key === 'Meta';
21043 if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45 || e.ctrlKey || isMeta) {
21044 addNonTypingUndoLevel();
21045 editor.nodeChanged();
21046 }
21047 if (keyCode === 46 || keyCode === 8) {
21048 editor.nodeChanged();
21049 }
21050 if (isFirstTypedCharacter.get() && undoManager.typing && !isEq$1(createFromEditor(editor), undoManager.data[0])) {
21051 if (!editor.isDirty()) {
21052 editor.setDirty(true);
21053 }
21054 editor.dispatch('TypingUndo');
21055 isFirstTypedCharacter.set(false);
21056 editor.nodeChanged();
21057 }
21058 });
21059 editor.on('keydown', e => {
21060 const keyCode = e.keyCode;
21061 if (e.isDefaultPrevented()) {
21062 return;
21063 }
21064 if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45) {
21065 if (undoManager.typing) {
21066 addNonTypingUndoLevel(e);
21067 }
21068 return;
21069 }
21070 const modKey = e.ctrlKey && !e.altKey || e.metaKey;
21071 if ((keyCode < 16 || keyCode > 20) && keyCode !== 224 && keyCode !== 91 && !undoManager.typing && !modKey) {
21072 undoManager.beforeChange();
21073 setTyping(undoManager, true, locks);
21074 undoManager.add({}, e);
21075 isFirstTypedCharacter.set(true);
21076 return;
21077 }
21078 const hasOnlyMetaOrCtrlModifier = Env.os.isMacOS() ? e.metaKey : e.ctrlKey && !e.altKey;
21079 if (hasOnlyMetaOrCtrlModifier) {
21080 undoManager.beforeChange();
21081 }
21082 });
21083 editor.on('mousedown', e => {
21084 if (undoManager.typing) {
21085 addNonTypingUndoLevel(e);
21086 }
21087 });
21088 const isInsertReplacementText = event => event.inputType === 'insertReplacementText';
21089 const isInsertTextDataNull = event => event.inputType === 'insertText' && event.data === null;
21090 const isInsertFromPasteOrDrop = event => event.inputType === 'insertFromPaste' || event.inputType === 'insertFromDrop';
21091 editor.on('input', e => {
21092 if (e.inputType && (isInsertReplacementText(e) || isInsertTextDataNull(e) || isInsertFromPasteOrDrop(e))) {
21093 addNonTypingUndoLevel(e);
21094 }
21095 });
21096 editor.on('AddUndo Undo Redo ClearUndos', e => {
21097 if (!e.isDefaultPrevented()) {
21098 editor.nodeChanged();
21099 }
21100 });
21101 };
21102 const addKeyboardShortcuts = editor => {
21103 editor.addShortcut('meta+z', '', 'Undo');
21104 editor.addShortcut('meta+y,meta+shift+z', '', 'Redo');
21105 };
21106
21107 const UndoManager = editor => {
21108 const beforeBookmark = value$2();
21109 const locks = Cell(0);
21110 const index = Cell(0);
21111 const undoManager = {
21112 data: [],
21113 typing: false,
21114 beforeChange: () => {
21115 beforeChange(editor, locks, beforeBookmark);
21116 },
21117 add: (level, event) => {
21118 return addUndoLevel(editor, undoManager, index, locks, beforeBookmark, level, event);
21119 },
21120 dispatchChange: () => {
21121 editor.setDirty(true);
21122 const level = createFromEditor(editor);
21123 level.bookmark = getUndoBookmark(editor.selection);
21124 editor.dispatch('change', {
21125 level,
21126 lastLevel: get$b(undoManager.data, index.get()).getOrUndefined()
21127 });
21128 },
21129 undo: () => {
21130 return undo(editor, undoManager, locks, index);
21131 },
21132 redo: () => {
21133 return redo(editor, index, undoManager.data);
21134 },
21135 clear: () => {
21136 clear(editor, undoManager, index);
21137 },
21138 reset: () => {
21139 reset(editor, undoManager);
21140 },
21141 hasUndo: () => {
21142 return hasUndo(editor, undoManager, index);
21143 },
21144 hasRedo: () => {
21145 return hasRedo(editor, undoManager, index);
21146 },
21147 transact: callback => {
21148 return transact(editor, undoManager, locks, callback);
21149 },
21150 ignore: callback => {
21151 ignore(editor, locks, callback);
21152 },
21153 extra: (callback1, callback2) => {
21154 extra(editor, undoManager, index, callback1, callback2);
21155 }
21156 };
21157 if (!isRtc(editor)) {
21158 registerEvents(editor, undoManager, locks);
21159 }
21160 addKeyboardShortcuts(editor);
21161 return undoManager;
21162 };
21163
21164 const nonTypingKeycodes = [
21165 9,
21166 27,
21167 VK.HOME,
21168 VK.END,
21169 19,
21170 20,
21171 44,
21172 144,
21173 145,
21174 33,
21175 34,
21176 45,
21177 16,
21178 17,
21179 18,
21180 91,
21181 92,
21182 93,
21183 VK.DOWN,
21184 VK.UP,
21185 VK.LEFT,
21186 VK.RIGHT
21187 ].concat(Env.browser.isFirefox() ? [224] : []);
21188 const placeholderAttr = 'data-mce-placeholder';
21189 const isKeyboardEvent = e => e.type === 'keydown' || e.type === 'keyup';
21190 const isDeleteEvent = e => {
21191 const keyCode = e.keyCode;
21192 return keyCode === VK.BACKSPACE || keyCode === VK.DELETE;
21193 };
21194 const isNonTypingKeyboardEvent = e => {
21195 if (isKeyboardEvent(e)) {
21196 const keyCode = e.keyCode;
21197 return !isDeleteEvent(e) && (VK.metaKeyPressed(e) || e.altKey || keyCode >= 112 && keyCode <= 123 || contains$2(nonTypingKeycodes, keyCode));
21198 } else {
21199 return false;
21200 }
21201 };
21202 const isTypingKeyboardEvent = e => isKeyboardEvent(e) && !(isDeleteEvent(e) || e.type === 'keyup' && e.keyCode === 229);
21203 const isVisuallyEmpty = (dom, rootElm, forcedRootBlock) => {
21204 if (dom.isEmpty(rootElm, undefined, {
21205 skipBogus: false,
21206 includeZwsp: true
21207 })) {
21208 const firstElement = rootElm.firstElementChild;
21209 if (!firstElement) {
21210 return true;
21211 } else if (dom.getStyle(rootElm.firstElementChild, 'padding-left') || dom.getStyle(rootElm.firstElementChild, 'padding-right')) {
21212 return false;
21213 } else {
21214 return forcedRootBlock === firstElement.nodeName.toLowerCase();
21215 }
21216 } else {
21217 return false;
21218 }
21219 };
21220 const setup$r = editor => {
21221 var _a;
21222 const dom = editor.dom;
21223 const rootBlock = getForcedRootBlock(editor);
21224 const placeholder = (_a = getPlaceholder(editor)) !== null && _a !== void 0 ? _a : '';
21225 const updatePlaceholder = (e, initial) => {
21226 if (isNonTypingKeyboardEvent(e)) {
21227 return;
21228 }
21229 const body = editor.getBody();
21230 const showPlaceholder = isTypingKeyboardEvent(e) ? false : isVisuallyEmpty(dom, body, rootBlock);
21231 const isPlaceholderShown = dom.getAttrib(body, placeholderAttr) !== '';
21232 if (isPlaceholderShown !== showPlaceholder || initial) {
21233 dom.setAttrib(body, placeholderAttr, showPlaceholder ? placeholder : null);
21234 firePlaceholderToggle(editor, showPlaceholder);
21235 editor.on(showPlaceholder ? 'keydown' : 'keyup', updatePlaceholder);
21236 editor.off(showPlaceholder ? 'keyup' : 'keydown', updatePlaceholder);
21237 }
21238 };
21239 if (isNotEmpty(placeholder)) {
21240 editor.on('init', e => {
21241 updatePlaceholder(e, true);
21242 editor.on('change SetContent ExecCommand', updatePlaceholder);
21243 editor.on('paste', e => Delay.setEditorTimeout(editor, () => updatePlaceholder(e)));
21244 });
21245 }
21246 };
21247
21248 const blockPosition = (block, position) => ({
21249 block,
21250 position
21251 });
21252 const blockBoundary = (from, to) => ({
21253 from,
21254 to
21255 });
21256 const getBlockPosition = (rootNode, pos) => {
21257 const rootElm = SugarElement.fromDom(rootNode);
21258 const containerElm = SugarElement.fromDom(pos.container());
21259 return getParentBlock$2(rootElm, containerElm).map(block => blockPosition(block, pos));
21260 };
21261 const isNotAncestorial = blockBoundary => !(contains(blockBoundary.to.block, blockBoundary.from.block) || contains(blockBoundary.from.block, blockBoundary.to.block));
21262 const isDifferentBlocks = blockBoundary => !eq(blockBoundary.from.block, blockBoundary.to.block);
21263 const getClosestHost = (root, scope) => {
21264 const isRoot = node => eq(node, root);
21265 const isHost = node => isTableCell$2(node) || isContentEditableTrue$3(node.dom);
21266 return closest$4(scope, isHost, isRoot).filter(isElement$7).getOr(root);
21267 };
21268 const hasSameHost = (rootNode, blockBoundary) => {
21269 const root = SugarElement.fromDom(rootNode);
21270 return eq(getClosestHost(root, blockBoundary.from.block), getClosestHost(root, blockBoundary.to.block));
21271 };
21272 const isEditable$1 = blockBoundary => isContentEditableFalse$b(blockBoundary.from.block.dom) === false && isContentEditableFalse$b(blockBoundary.to.block.dom) === false;
21273 const hasValidBlocks = blockBoundary => {
21274 const isValidBlock = block => isTextBlock$2(block) || hasBlockAttr(block.dom) || isListItem$1(block);
21275 return isValidBlock(blockBoundary.from.block) && isValidBlock(blockBoundary.to.block);
21276 };
21277 const skipLastBr = (schema, rootNode, forward, blockPosition) => {
21278 if (isBr$6(blockPosition.position.getNode()) && !isEmpty$2(schema, blockPosition.block)) {
21279 return positionIn(false, blockPosition.block.dom).bind(lastPositionInBlock => {
21280 if (lastPositionInBlock.isEqual(blockPosition.position)) {
21281 return fromPosition(forward, rootNode, lastPositionInBlock).bind(to => getBlockPosition(rootNode, to));
21282 } else {
21283 return Optional.some(blockPosition);
21284 }
21285 }).getOr(blockPosition);
21286 } else {
21287 return blockPosition;
21288 }
21289 };
21290 const readFromRange = (schema, rootNode, forward, rng) => {
21291 const fromBlockPos = getBlockPosition(rootNode, CaretPosition.fromRangeStart(rng));
21292 const toBlockPos = fromBlockPos.bind(blockPos => fromPosition(forward, rootNode, blockPos.position).bind(to => getBlockPosition(rootNode, to).map(blockPos => skipLastBr(schema, rootNode, forward, blockPos))));
21293 return lift2(fromBlockPos, toBlockPos, blockBoundary).filter(blockBoundary => isDifferentBlocks(blockBoundary) && hasSameHost(rootNode, blockBoundary) && isEditable$1(blockBoundary) && hasValidBlocks(blockBoundary) && isNotAncestorial(blockBoundary));
21294 };
21295 const read$1 = (schema, rootNode, forward, rng) => rng.collapsed ? readFromRange(schema, rootNode, forward, rng) : Optional.none();
21296
21297 const getChildrenUntilBlockBoundary = (block, schema) => {
21298 const children = children$1(block);
21299 return findIndex$2(children, el => schema.isBlock(name(el))).fold(constant(children), index => children.slice(0, index));
21300 };
21301 const extractChildren = (block, schema) => {
21302 const children = getChildrenUntilBlockBoundary(block, schema);
21303 each$e(children, remove$4);
21304 return children;
21305 };
21306 const removeEmptyRoot = (schema, rootNode, block) => {
21307 const parents = parentsAndSelf(block, rootNode);
21308 return find$2(parents.reverse(), element => isEmpty$2(schema, element)).each(remove$4);
21309 };
21310 const isEmptyBefore = (schema, el) => filter$5(prevSiblings(el), el => !isEmpty$2(schema, el)).length === 0;
21311 const nestedBlockMerge = (rootNode, fromBlock, toBlock, schema, insertionPoint) => {
21312 if (isEmpty$2(schema, toBlock)) {
21313 fillWithPaddingBr(toBlock);
21314 return firstPositionIn(toBlock.dom);
21315 }
21316 if (isEmptyBefore(schema, insertionPoint) && isEmpty$2(schema, fromBlock)) {
21317 before$3(insertionPoint, SugarElement.fromTag('br'));
21318 }
21319 const position = prevPosition(toBlock.dom, CaretPosition.before(insertionPoint.dom));
21320 each$e(extractChildren(fromBlock, schema), child => {
21321 before$3(insertionPoint, child);
21322 });
21323 removeEmptyRoot(schema, rootNode, fromBlock);
21324 return position;
21325 };
21326 const isInline = (schema, node) => schema.isInline(name(node));
21327 const sidelongBlockMerge = (rootNode, fromBlock, toBlock, schema) => {
21328 if (isEmpty$2(schema, toBlock)) {
21329 if (isEmpty$2(schema, fromBlock)) {
21330 const getInlineToBlockDescendants = el => {
21331 const helper = (node, elements) => firstChild(node).fold(() => elements, child => isInline(schema, child) ? helper(child, elements.concat(shallow$1(child))) : elements);
21332 return helper(el, []);
21333 };
21334 const newFromBlockDescendants = foldr(getInlineToBlockDescendants(toBlock), (element, descendant) => {
21335 wrap$2(element, descendant);
21336 return descendant;
21337 }, createPaddingBr());
21338 empty(fromBlock);
21339 append$1(fromBlock, newFromBlockDescendants);
21340 }
21341 remove$4(toBlock);
21342 return firstPositionIn(fromBlock.dom);
21343 }
21344 const position = lastPositionIn(toBlock.dom);
21345 each$e(extractChildren(fromBlock, schema), child => {
21346 append$1(toBlock, child);
21347 });
21348 removeEmptyRoot(schema, rootNode, fromBlock);
21349 return position;
21350 };
21351 const findInsertionPoint = (toBlock, block) => {
21352 const parentsAndSelf$1 = parentsAndSelf(block, toBlock);
21353 return Optional.from(parentsAndSelf$1[parentsAndSelf$1.length - 1]);
21354 };
21355 const getInsertionPoint = (fromBlock, toBlock) => contains(toBlock, fromBlock) ? findInsertionPoint(toBlock, fromBlock) : Optional.none();
21356 const trimBr = (first, block) => {
21357 positionIn(first, block.dom).bind(position => Optional.from(position.getNode())).map(SugarElement.fromDom).filter(isBr$5).each(remove$4);
21358 };
21359 const mergeBlockInto = (rootNode, fromBlock, toBlock, schema) => {
21360 trimBr(true, fromBlock);
21361 trimBr(false, toBlock);
21362 return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock, schema), curry(nestedBlockMerge, rootNode, fromBlock, toBlock, schema));
21363 };
21364 const mergeBlocks = (rootNode, forward, block1, block2, schema) => forward ? mergeBlockInto(rootNode, block2, block1, schema) : mergeBlockInto(rootNode, block1, block2, schema);
21365
21366 const backspaceDelete$9 = (editor, forward) => {
21367 const rootNode = SugarElement.fromDom(editor.getBody());
21368 const position = read$1(editor.schema, rootNode.dom, forward, editor.selection.getRng()).map(blockBoundary => () => {
21369 mergeBlocks(rootNode, forward, blockBoundary.from.block, blockBoundary.to.block, editor.schema).each(pos => {
21370 editor.selection.setRng(pos.toRange());
21371 });
21372 });
21373 return position;
21374 };
21375
21376 const deleteRangeMergeBlocks = (rootNode, selection, schema) => {
21377 const rng = selection.getRng();
21378 return lift2(getParentBlock$2(rootNode, SugarElement.fromDom(rng.startContainer)), getParentBlock$2(rootNode, SugarElement.fromDom(rng.endContainer)), (block1, block2) => {
21379 if (!eq(block1, block2)) {
21380 return Optional.some(() => {
21381 rng.deleteContents();
21382 mergeBlocks(rootNode, true, block1, block2, schema).each(pos => {
21383 selection.setRng(pos.toRange());
21384 });
21385 });
21386 } else {
21387 return Optional.none();
21388 }
21389 }).getOr(Optional.none());
21390 };
21391 const isRawNodeInTable = (root, rawNode) => {
21392 const node = SugarElement.fromDom(rawNode);
21393 const isRoot = curry(eq, root);
21394 return ancestor$4(node, isTableCell$2, isRoot).isSome();
21395 };
21396 const isSelectionInTable = (root, rng) => isRawNodeInTable(root, rng.startContainer) || isRawNodeInTable(root, rng.endContainer);
21397 const isEverythingSelected = (root, rng) => {
21398 const noPrevious = prevPosition(root.dom, CaretPosition.fromRangeStart(rng)).isNone();
21399 const noNext = nextPosition(root.dom, CaretPosition.fromRangeEnd(rng)).isNone();
21400 return !isSelectionInTable(root, rng) && noPrevious && noNext;
21401 };
21402 const emptyEditor = editor => {
21403 return Optional.some(() => {
21404 editor.setContent('');
21405 editor.selection.setCursorLocation();
21406 });
21407 };
21408 const deleteRange$2 = editor => {
21409 const rootNode = SugarElement.fromDom(editor.getBody());
21410 const rng = editor.selection.getRng();
21411 return isEverythingSelected(rootNode, rng) ? emptyEditor(editor) : deleteRangeMergeBlocks(rootNode, editor.selection, editor.schema);
21412 };
21413 const backspaceDelete$8 = (editor, _forward) => editor.selection.isCollapsed() ? Optional.none() : deleteRange$2(editor);
21414
21415 const showCaret = (direction, editor, node, before, scrollIntoView) => Optional.from(editor._selectionOverrides.showCaret(direction, node, before, scrollIntoView));
21416 const getNodeRange = node => {
21417 const rng = node.ownerDocument.createRange();
21418 rng.selectNode(node);
21419 return rng;
21420 };
21421 const selectNode = (editor, node) => {
21422 const e = editor.dispatch('BeforeObjectSelected', { target: node });
21423 if (e.isDefaultPrevented()) {
21424 return Optional.none();
21425 }
21426 return Optional.some(getNodeRange(node));
21427 };
21428 const renderCaretAtRange = (editor, range, scrollIntoView) => {
21429 const normalizedRange = normalizeRange(1, editor.getBody(), range);
21430 const caretPosition = CaretPosition.fromRangeStart(normalizedRange);
21431 const caretPositionNode = caretPosition.getNode();
21432 if (isInlineFakeCaretTarget(caretPositionNode)) {
21433 return showCaret(1, editor, caretPositionNode, !caretPosition.isAtEnd(), false);
21434 }
21435 const caretPositionBeforeNode = caretPosition.getNode(true);
21436 if (isInlineFakeCaretTarget(caretPositionBeforeNode)) {
21437 return showCaret(1, editor, caretPositionBeforeNode, false, false);
21438 }
21439 const ceRoot = getContentEditableRoot$1(editor.dom.getRoot(), caretPosition.getNode());
21440 if (isInlineFakeCaretTarget(ceRoot)) {
21441 return showCaret(1, editor, ceRoot, false, scrollIntoView);
21442 }
21443 return Optional.none();
21444 };
21445 const renderRangeCaret = (editor, range, scrollIntoView) => range.collapsed ? renderCaretAtRange(editor, range, scrollIntoView).getOr(range) : range;
21446
21447 const isBeforeBoundary = pos => isBeforeContentEditableFalse(pos) || isBeforeMedia(pos);
21448 const isAfterBoundary = pos => isAfterContentEditableFalse(pos) || isAfterMedia(pos);
21449 const trimEmptyTextNode = (dom, node) => {
21450 if (isText$b(node) && node.data.length === 0) {
21451 dom.remove(node);
21452 }
21453 };
21454 const deleteContentAndShowCaret = (editor, range, node, direction, forward, peekCaretPosition) => {
21455 showCaret(direction, editor, peekCaretPosition.getNode(!forward), forward, true).each(caretRange => {
21456 if (range.collapsed) {
21457 const deleteRange = range.cloneRange();
21458 if (forward) {
21459 deleteRange.setEnd(caretRange.startContainer, caretRange.startOffset);
21460 } else {
21461 deleteRange.setStart(caretRange.endContainer, caretRange.endOffset);
21462 }
21463 deleteRange.deleteContents();
21464 } else {
21465 range.deleteContents();
21466 }
21467 editor.selection.setRng(caretRange);
21468 });
21469 trimEmptyTextNode(editor.dom, node);
21470 };
21471 const deleteBoundaryText = (editor, forward) => {
21472 const range = editor.selection.getRng();
21473 if (!isText$b(range.commonAncestorContainer)) {
21474 return Optional.none();
21475 }
21476 const direction = forward ? HDirection.Forwards : HDirection.Backwards;
21477 const caretWalker = CaretWalker(editor.getBody());
21478 const getNextPosFn = curry(getVisualCaretPosition, forward ? caretWalker.next : caretWalker.prev);
21479 const isBeforeFn = forward ? isBeforeBoundary : isAfterBoundary;
21480 const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
21481 const nextCaretPosition = getNextPosFn(caretPosition);
21482 const normalizedNextCaretPosition = nextCaretPosition ? normalizePosition(forward, nextCaretPosition) : nextCaretPosition;
21483 if (!normalizedNextCaretPosition || !isMoveInsideSameBlock(caretPosition, normalizedNextCaretPosition)) {
21484 return Optional.none();
21485 } else if (isBeforeFn(normalizedNextCaretPosition)) {
21486 return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, normalizedNextCaretPosition));
21487 }
21488 const peekCaretPosition = getNextPosFn(normalizedNextCaretPosition);
21489 if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
21490 if (isMoveInsideSameBlock(normalizedNextCaretPosition, peekCaretPosition)) {
21491 return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, peekCaretPosition));
21492 }
21493 }
21494 return Optional.none();
21495 };
21496 const backspaceDelete$7 = (editor, forward) => deleteBoundaryText(editor, forward);
21497
21498 const getEdgeCefPosition = (editor, atStart) => {
21499 const root = editor.getBody();
21500 return atStart ? firstPositionIn(root).filter(isBeforeContentEditableFalse) : lastPositionIn(root).filter(isAfterContentEditableFalse);
21501 };
21502 const isCefAtEdgeSelected = editor => {
21503 const rng = editor.selection.getRng();
21504 return !rng.collapsed && (getEdgeCefPosition(editor, true).exists(pos => pos.isEqual(CaretPosition.fromRangeStart(rng))) || getEdgeCefPosition(editor, false).exists(pos => pos.isEqual(CaretPosition.fromRangeEnd(rng))));
21505 };
21506
21507 const isCompoundElement = node => isNonNullable(node) && (isTableCell$2(SugarElement.fromDom(node)) || isListItem$1(SugarElement.fromDom(node)));
21508 const DeleteAction = Adt.generate([
21509 { remove: ['element'] },
21510 { moveToElement: ['element'] },
21511 { moveToPosition: ['position'] }
21512 ]);
21513 const isAtContentEditableBlockCaret = (forward, from) => {
21514 const elm = from.getNode(!forward);
21515 const caretLocation = forward ? 'after' : 'before';
21516 return isElement$6(elm) && elm.getAttribute('data-mce-caret') === caretLocation;
21517 };
21518 const isDeleteFromCefDifferentBlocks = (root, forward, from, to, schema) => {
21519 const inSameBlock = elm => schema.isInline(elm.nodeName.toLowerCase()) && !isInSameBlock(from, to, root);
21520 return getRelativeCefElm(!forward, from).fold(() => getRelativeCefElm(forward, to).fold(never, inSameBlock), inSameBlock);
21521 };
21522 const deleteEmptyBlockOrMoveToCef = (schema, root, forward, from, to) => {
21523 const toCefElm = to.getNode(!forward);
21524 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)));
21525 };
21526 const findCefPosition = (root, forward, from, schema) => fromPosition(forward, root, from).bind(to => {
21527 if (isCompoundElement(to.getNode())) {
21528 return Optional.none();
21529 } else if (isDeleteFromCefDifferentBlocks(root, forward, from, to, schema)) {
21530 return Optional.none();
21531 } else if (forward && isContentEditableFalse$b(to.getNode())) {
21532 return deleteEmptyBlockOrMoveToCef(schema, root, forward, from, to);
21533 } else if (!forward && isContentEditableFalse$b(to.getNode(true))) {
21534 return deleteEmptyBlockOrMoveToCef(schema, root, forward, from, to);
21535 } else if (forward && isAfterContentEditableFalse(from)) {
21536 return Optional.some(DeleteAction.moveToPosition(to));
21537 } else if (!forward && isBeforeContentEditableFalse(from)) {
21538 return Optional.some(DeleteAction.moveToPosition(to));
21539 } else {
21540 return Optional.none();
21541 }
21542 });
21543 const getContentEditableBlockAction = (forward, elm) => {
21544 if (isNullable(elm)) {
21545 return Optional.none();
21546 } else if (forward && isContentEditableFalse$b(elm.nextSibling)) {
21547 return Optional.some(DeleteAction.moveToElement(elm.nextSibling));
21548 } else if (!forward && isContentEditableFalse$b(elm.previousSibling)) {
21549 return Optional.some(DeleteAction.moveToElement(elm.previousSibling));
21550 } else {
21551 return Optional.none();
21552 }
21553 };
21554 const skipMoveToActionFromInlineCefToContent = (root, from, deleteAction) => deleteAction.fold(elm => Optional.some(DeleteAction.remove(elm)), elm => Optional.some(DeleteAction.moveToElement(elm)), to => {
21555 if (isInSameBlock(from, to, root)) {
21556 return Optional.none();
21557 } else {
21558 return Optional.some(DeleteAction.moveToPosition(to));
21559 }
21560 });
21561 const getContentEditableAction = (root, forward, from, schema) => {
21562 if (isAtContentEditableBlockCaret(forward, from)) {
21563 return getContentEditableBlockAction(forward, from.getNode(!forward)).orThunk(() => findCefPosition(root, forward, from, schema));
21564 } else {
21565 return findCefPosition(root, forward, from, schema).bind(deleteAction => skipMoveToActionFromInlineCefToContent(root, from, deleteAction));
21566 }
21567 };
21568 const read = (root, forward, rng, schema) => {
21569 const normalizedRange = normalizeRange(forward ? 1 : -1, root, rng);
21570 const from = CaretPosition.fromRangeStart(normalizedRange);
21571 const rootElement = SugarElement.fromDom(root);
21572 if (!forward && isAfterContentEditableFalse(from)) {
21573 return Optional.some(DeleteAction.remove(from.getNode(true)));
21574 } else if (forward && isBeforeContentEditableFalse(from)) {
21575 return Optional.some(DeleteAction.remove(from.getNode()));
21576 } else if (!forward && isBeforeContentEditableFalse(from) && isAfterBr(rootElement, from, schema)) {
21577 return findPreviousBr(rootElement, from, schema).map(br => DeleteAction.remove(br.getNode()));
21578 } else if (forward && isAfterContentEditableFalse(from) && isBeforeBr$1(rootElement, from, schema)) {
21579 return findNextBr(rootElement, from, schema).map(br => DeleteAction.remove(br.getNode()));
21580 } else {
21581 return getContentEditableAction(root, forward, from, schema);
21582 }
21583 };
21584
21585 const deleteElement$1 = (editor, forward) => element => {
21586 editor._selectionOverrides.hideFakeCaret();
21587 deleteElement$2(editor, forward, SugarElement.fromDom(element));
21588 return true;
21589 };
21590 const moveToElement = (editor, forward) => element => {
21591 const pos = forward ? CaretPosition.before(element) : CaretPosition.after(element);
21592 editor.selection.setRng(pos.toRange());
21593 return true;
21594 };
21595 const moveToPosition = editor => pos => {
21596 editor.selection.setRng(pos.toRange());
21597 return true;
21598 };
21599 const getAncestorCe = (editor, node) => Optional.from(getContentEditableRoot$1(editor.getBody(), node));
21600 const backspaceDeleteCaret = (editor, forward) => {
21601 const selectedNode = editor.selection.getNode();
21602 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));
21603 };
21604 const deleteOffscreenSelection = rootElement => {
21605 each$e(descendants(rootElement, '.mce-offscreen-selection'), remove$4);
21606 };
21607 const backspaceDeleteRange = (editor, forward) => {
21608 const selectedNode = editor.selection.getNode();
21609 if (isContentEditableFalse$b(selectedNode) && !isTableCell$3(selectedNode)) {
21610 const hasCefAncestor = getAncestorCe(editor, selectedNode.parentNode).filter(isContentEditableFalse$b);
21611 return hasCefAncestor.fold(() => Optional.some(() => {
21612 deleteOffscreenSelection(SugarElement.fromDom(editor.getBody()));
21613 deleteElement$2(editor, forward, SugarElement.fromDom(editor.selection.getNode()));
21614 paddEmptyBody(editor);
21615 }), () => Optional.some(noop));
21616 }
21617 if (isCefAtEdgeSelected(editor)) {
21618 return Optional.some(() => {
21619 deleteRangeContents(editor, editor.selection.getRng(), SugarElement.fromDom(editor.getBody()));
21620 });
21621 }
21622 return Optional.none();
21623 };
21624 const paddEmptyElement = editor => {
21625 const dom = editor.dom, selection = editor.selection;
21626 const ceRoot = getContentEditableRoot$1(editor.getBody(), selection.getNode());
21627 if (isContentEditableTrue$3(ceRoot) && dom.isBlock(ceRoot) && dom.isEmpty(ceRoot)) {
21628 const br = dom.create('br', { 'data-mce-bogus': '1' });
21629 dom.setHTML(ceRoot, '');
21630 ceRoot.appendChild(br);
21631 selection.setRng(CaretPosition.before(br).toRange());
21632 }
21633 return true;
21634 };
21635 const backspaceDelete$6 = (editor, forward) => {
21636 if (editor.selection.isCollapsed()) {
21637 return backspaceDeleteCaret(editor, forward);
21638 } else {
21639 return backspaceDeleteRange(editor, forward);
21640 }
21641 };
21642
21643 const deleteCaret$2 = (editor, forward) => {
21644 const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
21645 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));
21646 };
21647 const backspaceDelete$5 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$2(editor, forward) : Optional.none();
21648
21649 const isText$2 = isText$b;
21650 const startsWithCaretContainer = node => isText$2(node) && node.data[0] === ZWSP$1;
21651 const endsWithCaretContainer = node => isText$2(node) && node.data[node.data.length - 1] === ZWSP$1;
21652 const createZwsp = node => {
21653 var _a;
21654 const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
21655 return doc.createTextNode(ZWSP$1);
21656 };
21657 const insertBefore$1 = node => {
21658 var _a;
21659 if (isText$2(node.previousSibling)) {
21660 if (endsWithCaretContainer(node.previousSibling)) {
21661 return node.previousSibling;
21662 } else {
21663 node.previousSibling.appendData(ZWSP$1);
21664 return node.previousSibling;
21665 }
21666 } else if (isText$2(node)) {
21667 if (startsWithCaretContainer(node)) {
21668 return node;
21669 } else {
21670 node.insertData(0, ZWSP$1);
21671 return node;
21672 }
21673 } else {
21674 const newNode = createZwsp(node);
21675 (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node);
21676 return newNode;
21677 }
21678 };
21679 const insertAfter$1 = node => {
21680 var _a, _b;
21681 if (isText$2(node.nextSibling)) {
21682 if (startsWithCaretContainer(node.nextSibling)) {
21683 return node.nextSibling;
21684 } else {
21685 node.nextSibling.insertData(0, ZWSP$1);
21686 return node.nextSibling;
21687 }
21688 } else if (isText$2(node)) {
21689 if (endsWithCaretContainer(node)) {
21690 return node;
21691 } else {
21692 node.appendData(ZWSP$1);
21693 return node;
21694 }
21695 } else {
21696 const newNode = createZwsp(node);
21697 if (node.nextSibling) {
21698 (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node.nextSibling);
21699 } else {
21700 (_b = node.parentNode) === null || _b === void 0 ? void 0 : _b.appendChild(newNode);
21701 }
21702 return newNode;
21703 }
21704 };
21705 const insertInline = (before, node) => before ? insertBefore$1(node) : insertAfter$1(node);
21706 const insertInlineBefore = curry(insertInline, true);
21707 const insertInlineAfter = curry(insertInline, false);
21708
21709 const insertInlinePos = (pos, before) => {
21710 if (isText$b(pos.container())) {
21711 return insertInline(before, pos.container());
21712 } else {
21713 return insertInline(before, pos.getNode());
21714 }
21715 };
21716 const isPosCaretContainer = (pos, caret) => {
21717 const caretNode = caret.get();
21718 return caretNode && pos.container() === caretNode && isCaretContainerInline(caretNode);
21719 };
21720 const renderCaret = (caret, location) => location.fold(element => {
21721 remove$2(caret.get());
21722 const text = insertInlineBefore(element);
21723 caret.set(text);
21724 return Optional.some(CaretPosition(text, text.length - 1));
21725 }, element => firstPositionIn(element).map(pos => {
21726 if (!isPosCaretContainer(pos, caret)) {
21727 remove$2(caret.get());
21728 const text = insertInlinePos(pos, true);
21729 caret.set(text);
21730 return CaretPosition(text, 1);
21731 } else {
21732 const node = caret.get();
21733 return CaretPosition(node, 1);
21734 }
21735 }), element => lastPositionIn(element).map(pos => {
21736 if (!isPosCaretContainer(pos, caret)) {
21737 remove$2(caret.get());
21738 const text = insertInlinePos(pos, false);
21739 caret.set(text);
21740 return CaretPosition(text, text.length - 1);
21741 } else {
21742 const node = caret.get();
21743 return CaretPosition(node, node.length - 1);
21744 }
21745 }), element => {
21746 remove$2(caret.get());
21747 const text = insertInlineAfter(element);
21748 caret.set(text);
21749 return Optional.some(CaretPosition(text, 1));
21750 });
21751
21752 const evaluateUntil = (fns, args) => {
21753 for (let i = 0; i < fns.length; i++) {
21754 const result = fns[i].apply(null, args);
21755 if (result.isSome()) {
21756 return result;
21757 }
21758 }
21759 return Optional.none();
21760 };
21761
21762 const Location = Adt.generate([
21763 { before: ['element'] },
21764 { start: ['element'] },
21765 { end: ['element'] },
21766 { after: ['element'] }
21767 ]);
21768 const rescope$1 = (rootNode, node) => {
21769 const parentBlock = getParentBlock$3(node, rootNode);
21770 return parentBlock ? parentBlock : rootNode;
21771 };
21772 const before = (isInlineTarget, rootNode, pos) => {
21773 const nPos = normalizeForwards(pos);
21774 const scope = rescope$1(rootNode, nPos.container());
21775 return findRootInline(isInlineTarget, scope, nPos).fold(() => nextPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.before(inline)), Optional.none);
21776 };
21777 const isNotInsideFormatCaretContainer = (rootNode, elm) => getParentCaretContainer(rootNode, elm) === null;
21778 const findInsideRootInline = (isInlineTarget, rootNode, pos) => findRootInline(isInlineTarget, rootNode, pos).filter(curry(isNotInsideFormatCaretContainer, rootNode));
21779 const start$1 = (isInlineTarget, rootNode, pos) => {
21780 const nPos = normalizeBackwards(pos);
21781 return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
21782 const prevPos = prevPosition(inline, nPos);
21783 return prevPos.isNone() ? Optional.some(Location.start(inline)) : Optional.none();
21784 });
21785 };
21786 const end = (isInlineTarget, rootNode, pos) => {
21787 const nPos = normalizeForwards(pos);
21788 return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
21789 const nextPos = nextPosition(inline, nPos);
21790 return nextPos.isNone() ? Optional.some(Location.end(inline)) : Optional.none();
21791 });
21792 };
21793 const after = (isInlineTarget, rootNode, pos) => {
21794 const nPos = normalizeBackwards(pos);
21795 const scope = rescope$1(rootNode, nPos.container());
21796 return findRootInline(isInlineTarget, scope, nPos).fold(() => prevPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.after(inline)), Optional.none);
21797 };
21798 const isValidLocation = location => !isRtl(getElement(location));
21799 const readLocation = (isInlineTarget, rootNode, pos) => {
21800 const location = evaluateUntil([
21801 before,
21802 start$1,
21803 end,
21804 after
21805 ], [
21806 isInlineTarget,
21807 rootNode,
21808 pos
21809 ]);
21810 return location.filter(isValidLocation);
21811 };
21812 const getElement = location => location.fold(identity, identity, identity, identity);
21813 const getName = location => location.fold(constant('before'), constant('start'), constant('end'), constant('after'));
21814 const outside = location => location.fold(Location.before, Location.before, Location.after, Location.after);
21815 const inside = location => location.fold(Location.start, Location.start, Location.end, Location.end);
21816 const isEq = (location1, location2) => getName(location1) === getName(location2) && getElement(location1) === getElement(location2);
21817 const betweenInlines = (forward, isInlineTarget, rootNode, from, to, location) => lift2(findRootInline(isInlineTarget, rootNode, from), findRootInline(isInlineTarget, rootNode, to), (fromInline, toInline) => {
21818 if (fromInline !== toInline && hasSameParentBlock(rootNode, fromInline, toInline)) {
21819 return Location.after(forward ? fromInline : toInline);
21820 } else {
21821 return location;
21822 }
21823 }).getOr(location);
21824 const skipNoMovement = (fromLocation, toLocation) => fromLocation.fold(always, fromLocation => !isEq(fromLocation, toLocation));
21825 const findLocationTraverse = (forward, isInlineTarget, rootNode, fromLocation, pos) => {
21826 const from = normalizePosition(forward, pos);
21827 const to = fromPosition(forward, rootNode, from).map(curry(normalizePosition, forward));
21828 const location = to.fold(() => fromLocation.map(outside), to => readLocation(isInlineTarget, rootNode, to).map(curry(betweenInlines, forward, isInlineTarget, rootNode, from, to)).filter(curry(skipNoMovement, fromLocation)));
21829 return location.filter(isValidLocation);
21830 };
21831 const findLocationSimple = (forward, location) => {
21832 if (forward) {
21833 return location.fold(compose(Optional.some, Location.start), Optional.none, compose(Optional.some, Location.after), Optional.none);
21834 } else {
21835 return location.fold(Optional.none, compose(Optional.some, Location.before), Optional.none, compose(Optional.some, Location.end));
21836 }
21837 };
21838 const findLocation$1 = (forward, isInlineTarget, rootNode, pos) => {
21839 const from = normalizePosition(forward, pos);
21840 const fromLocation = readLocation(isInlineTarget, rootNode, from);
21841 return readLocation(isInlineTarget, rootNode, from).bind(curry(findLocationSimple, forward)).orThunk(() => findLocationTraverse(forward, isInlineTarget, rootNode, fromLocation, pos));
21842 };
21843
21844 const hasSelectionModifyApi = editor => {
21845 return isFunction(editor.selection.getSel().modify);
21846 };
21847 const moveRel = (forward, selection, pos) => {
21848 const delta = forward ? 1 : -1;
21849 selection.setRng(CaretPosition(pos.container(), pos.offset() + delta).toRange());
21850 selection.getSel().modify('move', forward ? 'forward' : 'backward', 'word');
21851 return true;
21852 };
21853 const moveByWord = (forward, editor) => {
21854 const rng = editor.selection.getRng();
21855 const pos = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
21856 if (!hasSelectionModifyApi(editor)) {
21857 return false;
21858 } else if (forward && isBeforeInline(pos)) {
21859 return moveRel(true, editor.selection, pos);
21860 } else if (!forward && isAfterInline(pos)) {
21861 return moveRel(false, editor.selection, pos);
21862 } else {
21863 return false;
21864 }
21865 };
21866
21867 var BreakType;
21868 (function (BreakType) {
21869 BreakType[BreakType['Br'] = 0] = 'Br';
21870 BreakType[BreakType['Block'] = 1] = 'Block';
21871 BreakType[BreakType['Wrap'] = 2] = 'Wrap';
21872 BreakType[BreakType['Eol'] = 3] = 'Eol';
21873 }(BreakType || (BreakType = {})));
21874 const flip = (direction, positions) => direction === HDirection.Backwards ? reverse(positions) : positions;
21875 const walk$1 = (direction, caretWalker, pos) => direction === HDirection.Forwards ? caretWalker.next(pos) : caretWalker.prev(pos);
21876 const getBreakType = (scope, direction, currentPos, nextPos) => {
21877 if (isBr$6(nextPos.getNode(direction === HDirection.Forwards))) {
21878 return BreakType.Br;
21879 } else if (isInSameBlock(currentPos, nextPos) === false) {
21880 return BreakType.Block;
21881 } else {
21882 return BreakType.Wrap;
21883 }
21884 };
21885 const getPositionsUntil = (predicate, direction, scope, start) => {
21886 const caretWalker = CaretWalker(scope);
21887 let currentPos = start;
21888 const positions = [];
21889 while (currentPos) {
21890 const nextPos = walk$1(direction, caretWalker, currentPos);
21891 if (!nextPos) {
21892 break;
21893 }
21894 if (isBr$6(nextPos.getNode(false))) {
21895 if (direction === HDirection.Forwards) {
21896 return {
21897 positions: flip(direction, positions).concat([nextPos]),
21898 breakType: BreakType.Br,
21899 breakAt: Optional.some(nextPos)
21900 };
21901 } else {
21902 return {
21903 positions: flip(direction, positions),
21904 breakType: BreakType.Br,
21905 breakAt: Optional.some(nextPos)
21906 };
21907 }
21908 }
21909 if (!nextPos.isVisible()) {
21910 currentPos = nextPos;
21911 continue;
21912 }
21913 if (predicate(currentPos, nextPos)) {
21914 const breakType = getBreakType(scope, direction, currentPos, nextPos);
21915 return {
21916 positions: flip(direction, positions),
21917 breakType,
21918 breakAt: Optional.some(nextPos)
21919 };
21920 }
21921 positions.push(nextPos);
21922 currentPos = nextPos;
21923 }
21924 return {
21925 positions: flip(direction, positions),
21926 breakType: BreakType.Eol,
21927 breakAt: Optional.none()
21928 };
21929 };
21930 const getAdjacentLinePositions = (direction, getPositionsUntilBreak, scope, start) => getPositionsUntilBreak(scope, start).breakAt.map(pos => {
21931 const positions = getPositionsUntilBreak(scope, pos).positions;
21932 return direction === HDirection.Backwards ? positions.concat(pos) : [pos].concat(positions);
21933 }).getOr([]);
21934 const findClosestHorizontalPositionFromPoint = (positions, x) => foldl(positions, (acc, newPos) => acc.fold(() => Optional.some(newPos), lastPos => lift2(head(lastPos.getClientRects()), head(newPos.getClientRects()), (lastRect, newRect) => {
21935 const lastDist = Math.abs(x - lastRect.left);
21936 const newDist = Math.abs(x - newRect.left);
21937 return newDist <= lastDist ? newPos : lastPos;
21938 }).or(acc)), Optional.none());
21939 const findClosestHorizontalPosition = (positions, pos) => head(pos.getClientRects()).bind(targetRect => findClosestHorizontalPositionFromPoint(positions, targetRect.left));
21940 const getPositionsUntilPreviousLine = curry(getPositionsUntil, CaretPosition.isAbove, -1);
21941 const getPositionsUntilNextLine = curry(getPositionsUntil, CaretPosition.isBelow, 1);
21942 const getPositionsAbove = curry(getAdjacentLinePositions, -1, getPositionsUntilPreviousLine);
21943 const getPositionsBelow = curry(getAdjacentLinePositions, 1, getPositionsUntilNextLine);
21944 const isAtFirstLine = (scope, pos) => getPositionsUntilPreviousLine(scope, pos).breakAt.isNone();
21945 const isAtLastLine = (scope, pos) => getPositionsUntilNextLine(scope, pos).breakAt.isNone();
21946 const getFirstLinePositions = scope => firstPositionIn(scope).map(pos => [pos].concat(getPositionsUntilNextLine(scope, pos).positions)).getOr([]);
21947 const getLastLinePositions = scope => lastPositionIn(scope).map(pos => getPositionsUntilPreviousLine(scope, pos).positions.concat(pos)).getOr([]);
21948 const getClosestPositionAbove = (scope, pos) => findClosestHorizontalPosition(getPositionsAbove(scope, pos), pos);
21949 const getClosestPositionBelow = (scope, pos) => findClosestHorizontalPosition(getPositionsBelow(scope, pos), pos);
21950
21951 const isContentEditableFalse$5 = isContentEditableFalse$b;
21952 const distanceToRectLeft$1 = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
21953 const distanceToRectRight$1 = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
21954 const isNodeClientRect = rect => hasNonNullableKey(rect, 'node');
21955 const findClosestClientRect = (clientRects, clientX) => reduce(clientRects, (oldClientRect, clientRect) => {
21956 const oldDistance = Math.min(distanceToRectLeft$1(oldClientRect, clientX), distanceToRectRight$1(oldClientRect, clientX));
21957 const newDistance = Math.min(distanceToRectLeft$1(clientRect, clientX), distanceToRectRight$1(clientRect, clientX));
21958 if (newDistance === oldDistance && isNodeClientRect(clientRect) && isContentEditableFalse$5(clientRect.node)) {
21959 return clientRect;
21960 }
21961 if (newDistance < oldDistance) {
21962 return clientRect;
21963 }
21964 return oldClientRect;
21965 });
21966
21967 const getNodeClientRects = node => {
21968 const toArrayWithNode = clientRects => {
21969 return map$3(clientRects, rect => {
21970 const clientRect = clone$1(rect);
21971 clientRect.node = node;
21972 return clientRect;
21973 });
21974 };
21975 if (isElement$6(node)) {
21976 return toArrayWithNode(node.getClientRects());
21977 } else if (isText$b(node)) {
21978 const rng = node.ownerDocument.createRange();
21979 rng.setStart(node, 0);
21980 rng.setEnd(node, node.data.length);
21981 return toArrayWithNode(rng.getClientRects());
21982 } else {
21983 return [];
21984 }
21985 };
21986 const getClientRects = nodes => bind$3(nodes, getNodeClientRects);
21987
21988 var VDirection;
21989 (function (VDirection) {
21990 VDirection[VDirection['Up'] = -1] = 'Up';
21991 VDirection[VDirection['Down'] = 1] = 'Down';
21992 }(VDirection || (VDirection = {})));
21993 const findUntil = (direction, root, predicateFn, node) => {
21994 let currentNode = node;
21995 while (currentNode = findNode(currentNode, direction, isEditableCaretCandidate$1, root)) {
21996 if (predicateFn(currentNode)) {
21997 return;
21998 }
21999 }
22000 };
22001 const walkUntil = (direction, isAboveFn, isBeflowFn, root, predicateFn, caretPosition) => {
22002 let line = 0;
22003 const result = [];
22004 const add = node => {
22005 let clientRects = getClientRects([node]);
22006 if (direction === -1) {
22007 clientRects = clientRects.reverse();
22008 }
22009 for (let i = 0; i < clientRects.length; i++) {
22010 const clientRect = clientRects[i];
22011 if (isBeflowFn(clientRect, targetClientRect)) {
22012 continue;
22013 }
22014 if (result.length > 0 && isAboveFn(clientRect, last$1(result))) {
22015 line++;
22016 }
22017 clientRect.line = line;
22018 if (predicateFn(clientRect)) {
22019 return true;
22020 }
22021 result.push(clientRect);
22022 }
22023 return false;
22024 };
22025 const targetClientRect = last$1(caretPosition.getClientRects());
22026 if (!targetClientRect) {
22027 return result;
22028 }
22029 const node = caretPosition.getNode();
22030 if (node) {
22031 add(node);
22032 findUntil(direction, root, add, node);
22033 }
22034 return result;
22035 };
22036 const aboveLineNumber = (lineNumber, clientRect) => clientRect.line > lineNumber;
22037 const isLineNumber = (lineNumber, clientRect) => clientRect.line === lineNumber;
22038 const upUntil = curry(walkUntil, VDirection.Up, isAbove$1, isBelow$1);
22039 const downUntil = curry(walkUntil, VDirection.Down, isBelow$1, isAbove$1);
22040 const getLastClientRect = caretPosition => {
22041 return last$1(caretPosition.getClientRects());
22042 };
22043 const positionsUntil = (direction, root, predicateFn, node) => {
22044 const caretWalker = CaretWalker(root);
22045 let walkFn;
22046 let isBelowFn;
22047 let isAboveFn;
22048 let caretPosition;
22049 const result = [];
22050 let line = 0;
22051 if (direction === 1) {
22052 walkFn = caretWalker.next;
22053 isBelowFn = isBelow$1;
22054 isAboveFn = isAbove$1;
22055 caretPosition = CaretPosition.after(node);
22056 } else {
22057 walkFn = caretWalker.prev;
22058 isBelowFn = isAbove$1;
22059 isAboveFn = isBelow$1;
22060 caretPosition = CaretPosition.before(node);
22061 }
22062 const targetClientRect = getLastClientRect(caretPosition);
22063 do {
22064 if (!caretPosition.isVisible()) {
22065 continue;
22066 }
22067 const rect = getLastClientRect(caretPosition);
22068 if (isAboveFn(rect, targetClientRect)) {
22069 continue;
22070 }
22071 if (result.length > 0 && isBelowFn(rect, last$1(result))) {
22072 line++;
22073 }
22074 const clientRect = clone$1(rect);
22075 clientRect.position = caretPosition;
22076 clientRect.line = line;
22077 if (predicateFn(clientRect)) {
22078 return result;
22079 }
22080 result.push(clientRect);
22081 } while (caretPosition = walkFn(caretPosition));
22082 return result;
22083 };
22084 const isAboveLine = lineNumber => clientRect => aboveLineNumber(lineNumber, clientRect);
22085 const isLine = lineNumber => clientRect => isLineNumber(lineNumber, clientRect);
22086
22087 const moveToRange = (editor, rng) => {
22088 editor.selection.setRng(rng);
22089 scrollRangeIntoView(editor, editor.selection.getRng());
22090 };
22091 const renderRangeCaretOpt = (editor, range, scrollIntoView) => Optional.some(renderRangeCaret(editor, range, scrollIntoView));
22092 const moveHorizontally = (editor, direction, range, isBefore, isAfter, isElement) => {
22093 const forwards = direction === HDirection.Forwards;
22094 const caretWalker = CaretWalker(editor.getBody());
22095 const getNextPosFn = curry(getVisualCaretPosition, forwards ? caretWalker.next : caretWalker.prev);
22096 const isBeforeFn = forwards ? isBefore : isAfter;
22097 if (!range.collapsed) {
22098 const node = getSelectedNode(range);
22099 if (isElement(node)) {
22100 return showCaret(direction, editor, node, direction === HDirection.Backwards, false);
22101 } else if (isCefAtEdgeSelected(editor)) {
22102 const newRange = range.cloneRange();
22103 newRange.collapse(direction === HDirection.Backwards);
22104 return Optional.from(newRange);
22105 }
22106 }
22107 const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
22108 if (isBeforeFn(caretPosition)) {
22109 return selectNode(editor, caretPosition.getNode(!forwards));
22110 }
22111 let nextCaretPosition = getNextPosFn(caretPosition);
22112 const rangeIsInContainerBlock = isRangeInCaretContainerBlock(range);
22113 if (!nextCaretPosition) {
22114 return rangeIsInContainerBlock ? Optional.some(range) : Optional.none();
22115 } else {
22116 nextCaretPosition = normalizePosition(forwards, nextCaretPosition);
22117 }
22118 if (isBeforeFn(nextCaretPosition)) {
22119 return showCaret(direction, editor, nextCaretPosition.getNode(!forwards), forwards, false);
22120 }
22121 const peekCaretPosition = getNextPosFn(nextCaretPosition);
22122 if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
22123 if (isMoveInsideSameBlock(nextCaretPosition, peekCaretPosition)) {
22124 return showCaret(direction, editor, peekCaretPosition.getNode(!forwards), forwards, false);
22125 }
22126 }
22127 if (rangeIsInContainerBlock) {
22128 return renderRangeCaretOpt(editor, nextCaretPosition.toRange(), false);
22129 }
22130 return Optional.none();
22131 };
22132 const moveVertically = (editor, direction, range, isBefore, isAfter, isElement) => {
22133 const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
22134 const caretClientRect = last$1(caretPosition.getClientRects());
22135 const forwards = direction === VDirection.Down;
22136 const root = editor.getBody();
22137 if (!caretClientRect) {
22138 return Optional.none();
22139 }
22140 if (isCefAtEdgeSelected(editor)) {
22141 const caretPosition = forwards ? CaretPosition.fromRangeEnd(range) : CaretPosition.fromRangeStart(range);
22142 const getClosestFn = !forwards ? getClosestPositionAbove : getClosestPositionBelow;
22143 return getClosestFn(root, caretPosition).orThunk(() => Optional.from(caretPosition)).map(pos => pos.toRange());
22144 }
22145 const walkerFn = forwards ? downUntil : upUntil;
22146 const linePositions = walkerFn(root, isAboveLine(1), caretPosition);
22147 const nextLinePositions = filter$5(linePositions, isLine(1));
22148 const clientX = caretClientRect.left;
22149 const nextLineRect = findClosestClientRect(nextLinePositions, clientX);
22150 if (nextLineRect && isElement(nextLineRect.node)) {
22151 const dist1 = Math.abs(clientX - nextLineRect.left);
22152 const dist2 = Math.abs(clientX - nextLineRect.right);
22153 return showCaret(direction, editor, nextLineRect.node, dist1 < dist2, false);
22154 }
22155 let currentNode;
22156 if (isBefore(caretPosition)) {
22157 currentNode = caretPosition.getNode();
22158 } else if (isAfter(caretPosition)) {
22159 currentNode = caretPosition.getNode(true);
22160 } else {
22161 currentNode = getSelectedNode(range);
22162 }
22163 if (currentNode) {
22164 const caretPositions = positionsUntil(direction, root, isAboveLine(1), currentNode);
22165 let closestNextLineRect = findClosestClientRect(filter$5(caretPositions, isLine(1)), clientX);
22166 if (closestNextLineRect) {
22167 return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
22168 }
22169 closestNextLineRect = last$1(filter$5(caretPositions, isLine(0)));
22170 if (closestNextLineRect) {
22171 return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
22172 }
22173 }
22174 if (nextLinePositions.length === 0) {
22175 return getLineEndPoint(editor, forwards).filter(forwards ? isAfter : isBefore).map(pos => renderRangeCaret(editor, pos.toRange(), false));
22176 }
22177 return Optional.none();
22178 };
22179 const getLineEndPoint = (editor, forward) => {
22180 const rng = editor.selection.getRng();
22181 const from = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
22182 const host = getEditingHost(from.container(), editor.getBody());
22183 if (forward) {
22184 const lineInfo = getPositionsUntilNextLine(host, from);
22185 return last$2(lineInfo.positions);
22186 } else {
22187 const lineInfo = getPositionsUntilPreviousLine(host, from);
22188 return head(lineInfo.positions);
22189 }
22190 };
22191 const moveToLineEndPoint$3 = (editor, forward, isElementPosition) => getLineEndPoint(editor, forward).filter(isElementPosition).exists(pos => {
22192 editor.selection.setRng(pos.toRange());
22193 return true;
22194 });
22195
22196 const setCaretPosition = (editor, pos) => {
22197 const rng = editor.dom.createRng();
22198 rng.setStart(pos.container(), pos.offset());
22199 rng.setEnd(pos.container(), pos.offset());
22200 editor.selection.setRng(rng);
22201 };
22202 const setSelected = (state, elm) => {
22203 if (state) {
22204 elm.setAttribute('data-mce-selected', 'inline-boundary');
22205 } else {
22206 elm.removeAttribute('data-mce-selected');
22207 }
22208 };
22209 const renderCaretLocation = (editor, caret, location) => renderCaret(caret, location).map(pos => {
22210 setCaretPosition(editor, pos);
22211 return location;
22212 });
22213 const getPositionFromRange = (range, root, forward) => {
22214 const start = CaretPosition.fromRangeStart(range);
22215 if (range.collapsed) {
22216 return start;
22217 } else {
22218 const end = CaretPosition.fromRangeEnd(range);
22219 return forward ? prevPosition(root, end).getOr(end) : nextPosition(root, start).getOr(start);
22220 }
22221 };
22222 const findLocation = (editor, caret, forward) => {
22223 const rootNode = editor.getBody();
22224 const from = getPositionFromRange(editor.selection.getRng(), rootNode, forward);
22225 const isInlineTarget$1 = curry(isInlineTarget, editor);
22226 const location = findLocation$1(forward, isInlineTarget$1, rootNode, from);
22227 return location.bind(location => renderCaretLocation(editor, caret, location));
22228 };
22229 const toggleInlines = (isInlineTarget, dom, elms) => {
22230 const inlineBoundaries = map$3(descendants(SugarElement.fromDom(dom.getRoot()), '*[data-mce-selected="inline-boundary"]'), e => e.dom);
22231 const selectedInlines = filter$5(inlineBoundaries, isInlineTarget);
22232 const targetInlines = filter$5(elms, isInlineTarget);
22233 each$e(difference(selectedInlines, targetInlines), curry(setSelected, false));
22234 each$e(difference(targetInlines, selectedInlines), curry(setSelected, true));
22235 };
22236 const safeRemoveCaretContainer = (editor, caret) => {
22237 const caretValue = caret.get();
22238 if (editor.selection.isCollapsed() && !editor.composing && caretValue) {
22239 const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
22240 if (CaretPosition.isTextPosition(pos) && !isAtZwsp(pos)) {
22241 setCaretPosition(editor, removeAndReposition(caretValue, pos));
22242 caret.set(null);
22243 }
22244 }
22245 };
22246 const renderInsideInlineCaret = (isInlineTarget, editor, caret, elms) => {
22247 if (editor.selection.isCollapsed()) {
22248 const inlines = filter$5(elms, isInlineTarget);
22249 each$e(inlines, _inline => {
22250 const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
22251 readLocation(isInlineTarget, editor.getBody(), pos).bind(location => renderCaretLocation(editor, caret, location));
22252 });
22253 }
22254 };
22255 const move$3 = (editor, caret, forward) => isInlineBoundariesEnabled(editor) ? findLocation(editor, caret, forward).isSome() : false;
22256 const moveWord = (forward, editor, _caret) => isInlineBoundariesEnabled(editor) ? moveByWord(forward, editor) : false;
22257 const setupSelectedState = editor => {
22258 const caret = Cell(null);
22259 const isInlineTarget$1 = curry(isInlineTarget, editor);
22260 editor.on('NodeChange', e => {
22261 if (isInlineBoundariesEnabled(editor)) {
22262 toggleInlines(isInlineTarget$1, editor.dom, e.parents);
22263 safeRemoveCaretContainer(editor, caret);
22264 renderInsideInlineCaret(isInlineTarget$1, editor, caret, e.parents);
22265 }
22266 });
22267 return caret;
22268 };
22269 const moveNextWord = curry(moveWord, true);
22270 const movePrevWord = curry(moveWord, false);
22271 const moveToLineEndPoint$2 = (editor, forward, caret) => {
22272 if (isInlineBoundariesEnabled(editor)) {
22273 const linePoint = getLineEndPoint(editor, forward).getOrThunk(() => {
22274 const rng = editor.selection.getRng();
22275 return forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
22276 });
22277 return readLocation(curry(isInlineTarget, editor), editor.getBody(), linePoint).exists(loc => {
22278 const outsideLoc = outside(loc);
22279 return renderCaret(caret, outsideLoc).exists(pos => {
22280 setCaretPosition(editor, pos);
22281 return true;
22282 });
22283 });
22284 } else {
22285 return false;
22286 }
22287 };
22288
22289 const rangeFromPositions = (from, to) => {
22290 const range = document.createRange();
22291 range.setStart(from.container(), from.offset());
22292 range.setEnd(to.container(), to.offset());
22293 return range;
22294 };
22295 const hasOnlyTwoOrLessPositionsLeft = elm => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
22296 const normalizedFirstPos = normalizePosition(true, firstPos);
22297 const normalizedLastPos = normalizePosition(false, lastPos);
22298 return nextPosition(elm, normalizedFirstPos).forall(pos => pos.isEqual(normalizedLastPos));
22299 }).getOr(true);
22300 const setCaretLocation = (editor, caret) => location => renderCaret(caret, location).map(pos => () => setCaretPosition(editor, pos));
22301 const deleteFromTo = (editor, caret, from, to) => {
22302 const rootNode = editor.getBody();
22303 const isInlineTarget$1 = curry(isInlineTarget, editor);
22304 editor.undoManager.ignore(() => {
22305 editor.selection.setRng(rangeFromPositions(from, to));
22306 execNativeDeleteCommand(editor);
22307 readLocation(isInlineTarget$1, rootNode, CaretPosition.fromRangeStart(editor.selection.getRng())).map(inside).bind(setCaretLocation(editor, caret)).each(call);
22308 });
22309 editor.nodeChanged();
22310 };
22311 const rescope = (rootNode, node) => {
22312 const parentBlock = getParentBlock$3(node, rootNode);
22313 return parentBlock ? parentBlock : rootNode;
22314 };
22315 const backspaceDeleteCollapsed = (editor, caret, forward, from) => {
22316 const rootNode = rescope(editor.getBody(), from.container());
22317 const isInlineTarget$1 = curry(isInlineTarget, editor);
22318 const fromLocation = readLocation(isInlineTarget$1, rootNode, from);
22319 const location = fromLocation.bind(location => {
22320 if (forward) {
22321 return location.fold(constant(Optional.some(inside(location))), Optional.none, constant(Optional.some(outside(location))), Optional.none);
22322 } else {
22323 return location.fold(Optional.none, constant(Optional.some(outside(location))), Optional.none, constant(Optional.some(inside(location))));
22324 }
22325 });
22326 return location.map(setCaretLocation(editor, caret)).getOrThunk(() => {
22327 const toPosition = navigate(forward, rootNode, from);
22328 const toLocation = toPosition.bind(pos => readLocation(isInlineTarget$1, rootNode, pos));
22329 return lift2(fromLocation, toLocation, () => findRootInline(isInlineTarget$1, rootNode, from).bind(elm => {
22330 if (hasOnlyTwoOrLessPositionsLeft(elm)) {
22331 return Optional.some(() => {
22332 deleteElement$2(editor, forward, SugarElement.fromDom(elm));
22333 });
22334 } else {
22335 return Optional.none();
22336 }
22337 })).getOrThunk(() => toLocation.bind(() => toPosition.map(to => {
22338 return () => {
22339 if (forward) {
22340 deleteFromTo(editor, caret, from, to);
22341 } else {
22342 deleteFromTo(editor, caret, to, from);
22343 }
22344 };
22345 })));
22346 });
22347 };
22348 const backspaceDelete$4 = (editor, caret, forward) => {
22349 if (editor.selection.isCollapsed() && isInlineBoundariesEnabled(editor)) {
22350 const from = CaretPosition.fromRangeStart(editor.selection.getRng());
22351 return backspaceDeleteCollapsed(editor, caret, forward, from);
22352 }
22353 return Optional.none();
22354 };
22355
22356 const hasMultipleChildren = elm => childNodesCount(elm) > 1;
22357 const getParentsUntil = (editor, pred) => {
22358 const rootElm = SugarElement.fromDom(editor.getBody());
22359 const startElm = SugarElement.fromDom(editor.selection.getStart());
22360 const parents = parentsAndSelf(startElm, rootElm);
22361 return findIndex$2(parents, pred).fold(constant(parents), index => parents.slice(0, index));
22362 };
22363 const hasOnlyOneChild = elm => childNodesCount(elm) === 1;
22364 const getParentInlinesUntilMultichildInline = editor => getParentsUntil(editor, elm => editor.schema.isBlock(name(elm)) || hasMultipleChildren(elm));
22365 const getParentInlines = editor => getParentsUntil(editor, el => editor.schema.isBlock(name(el)));
22366 const getFormatNodes = (editor, parentInlines) => {
22367 const isFormatElement$1 = curry(isFormatElement, editor);
22368 return bind$3(parentInlines, elm => isFormatElement$1(elm) ? [elm.dom] : []);
22369 };
22370 const getFormatNodesAtStart = editor => {
22371 const parentInlines = getParentInlines(editor);
22372 return getFormatNodes(editor, parentInlines);
22373 };
22374 const deleteLastPosition = (forward, editor, target, parentInlines) => {
22375 const formatNodes = getFormatNodes(editor, parentInlines);
22376 if (formatNodes.length === 0) {
22377 deleteElement$2(editor, forward, target);
22378 } else {
22379 const pos = replaceWithCaretFormat(target.dom, formatNodes);
22380 editor.selection.setRng(pos.toRange());
22381 }
22382 };
22383 const deleteCaret$1 = (editor, forward) => {
22384 const parentInlines = filter$5(getParentInlinesUntilMultichildInline(editor), hasOnlyOneChild);
22385 return last$2(parentInlines).bind(target => {
22386 const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
22387 if (willDeleteLastPositionInElement(forward, fromPos, target.dom) && !isEmptyCaretFormatElement(target)) {
22388 return Optional.some(() => deleteLastPosition(forward, editor, target, parentInlines));
22389 } else {
22390 return Optional.none();
22391 }
22392 });
22393 };
22394 const isBrInEmptyElement = (editor, elm) => {
22395 const parentElm = elm.parentElement;
22396 return isBr$6(elm) && !isNull(parentElm) && editor.dom.isEmpty(parentElm);
22397 };
22398 const isEmptyCaret = elm => isEmptyCaretFormatElement(SugarElement.fromDom(elm));
22399 const createCaretFormatAtStart = (editor, formatNodes) => {
22400 const startElm = editor.selection.getStart();
22401 const pos = isBrInEmptyElement(editor, startElm) || isEmptyCaret(startElm) ? replaceWithCaretFormat(startElm, formatNodes) : createCaretFormatAtStart$1(editor.selection.getRng(), formatNodes);
22402 editor.selection.setRng(pos.toRange());
22403 };
22404 const updateCaretFormat = (editor, updateFormats) => {
22405 const missingFormats = difference(updateFormats, getFormatNodesAtStart(editor));
22406 if (missingFormats.length > 0) {
22407 createCaretFormatAtStart(editor, missingFormats);
22408 }
22409 };
22410 const rangeStartsAtTextContainer = rng => isText$b(rng.startContainer);
22411 const rangeStartsAtStartOfTextContainer = rng => rng.startOffset === 0 && rangeStartsAtTextContainer(rng);
22412 const rangeStartParentIsFormatElement = (editor, rng) => {
22413 const startParent = rng.startContainer.parentElement;
22414 return !isNull(startParent) && isFormatElement(editor, SugarElement.fromDom(startParent));
22415 };
22416 const rangeStartAndEndHaveSameParent = rng => {
22417 const startParent = rng.startContainer.parentNode;
22418 const endParent = rng.endContainer.parentNode;
22419 return !isNull(startParent) && !isNull(endParent) && startParent.isEqualNode(endParent);
22420 };
22421 const rangeEndsAtEndOfEndContainer = rng => {
22422 const endContainer = rng.endContainer;
22423 return rng.endOffset === (isText$b(endContainer) ? endContainer.length : endContainer.childNodes.length);
22424 };
22425 const rangeEndsAtEndOfStartContainer = rng => rangeStartAndEndHaveSameParent(rng) && rangeEndsAtEndOfEndContainer(rng);
22426 const rangeEndsAfterEndOfStartContainer = rng => !rng.endContainer.isEqualNode(rng.commonAncestorContainer);
22427 const rangeEndsAtOrAfterEndOfStartContainer = rng => rangeEndsAtEndOfStartContainer(rng) || rangeEndsAfterEndOfStartContainer(rng);
22428 const requiresDeleteRangeOverride = editor => {
22429 const rng = editor.selection.getRng();
22430 return rangeStartsAtStartOfTextContainer(rng) && rangeStartParentIsFormatElement(editor, rng) && rangeEndsAtOrAfterEndOfStartContainer(rng);
22431 };
22432 const deleteRange$1 = editor => {
22433 if (requiresDeleteRangeOverride(editor)) {
22434 const formatNodes = getFormatNodesAtStart(editor);
22435 return Optional.some(() => {
22436 execNativeDeleteCommand(editor);
22437 updateCaretFormat(editor, formatNodes);
22438 });
22439 } else {
22440 return Optional.none();
22441 }
22442 };
22443 const backspaceDelete$3 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$1(editor, forward) : deleteRange$1(editor);
22444 const hasAncestorInlineCaret = (elm, schema) => ancestor$2(elm, node => isCaretNode(node.dom), el => schema.isBlock(name(el)));
22445 const hasAncestorInlineCaretAtStart = editor => hasAncestorInlineCaret(SugarElement.fromDom(editor.selection.getStart()), editor.schema);
22446 const requiresRefreshCaretOverride = editor => {
22447 const rng = editor.selection.getRng();
22448 return rng.collapsed && (rangeStartsAtTextContainer(rng) || editor.dom.isEmpty(rng.startContainer)) && !hasAncestorInlineCaretAtStart(editor);
22449 };
22450 const refreshCaret = editor => {
22451 if (requiresRefreshCaretOverride(editor)) {
22452 createCaretFormatAtStart(editor, []);
22453 }
22454 return true;
22455 };
22456
22457 const deleteElement = (editor, forward, element) => {
22458 if (isNonNullable(element)) {
22459 return Optional.some(() => {
22460 editor._selectionOverrides.hideFakeCaret();
22461 deleteElement$2(editor, forward, SugarElement.fromDom(element));
22462 });
22463 } else {
22464 return Optional.none();
22465 }
22466 };
22467 const deleteCaret = (editor, forward) => {
22468 const isNearMedia = forward ? isBeforeMedia : isAfterMedia;
22469 const direction = forward ? HDirection.Forwards : HDirection.Backwards;
22470 const fromPos = getNormalizedRangeEndPoint(direction, editor.getBody(), editor.selection.getRng());
22471 if (isNearMedia(fromPos)) {
22472 return deleteElement(editor, forward, fromPos.getNode(!forward));
22473 } else {
22474 return Optional.from(normalizePosition(forward, fromPos)).filter(pos => isNearMedia(pos) && isMoveInsideSameBlock(fromPos, pos)).bind(pos => deleteElement(editor, forward, pos.getNode(!forward)));
22475 }
22476 };
22477 const deleteRange = (editor, forward) => {
22478 const selectedNode = editor.selection.getNode();
22479 return isMedia$2(selectedNode) ? deleteElement(editor, forward, selectedNode) : Optional.none();
22480 };
22481 const backspaceDelete$2 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret(editor, forward) : deleteRange(editor, forward);
22482
22483 const isEditable = target => closest$4(target, elm => isContentEditableTrue$3(elm.dom) || isContentEditableFalse$b(elm.dom)).exists(elm => isContentEditableTrue$3(elm.dom));
22484 const parseIndentValue = value => toInt(value !== null && value !== void 0 ? value : '').getOr(0);
22485 const getIndentStyleName = (useMargin, element) => {
22486 const indentStyleName = useMargin || isTable$1(element) ? 'margin' : 'padding';
22487 const suffix = get$7(element, 'direction') === 'rtl' ? '-right' : '-left';
22488 return indentStyleName + suffix;
22489 };
22490 const indentElement = (dom, command, useMargin, value, unit, element) => {
22491 const indentStyleName = getIndentStyleName(useMargin, SugarElement.fromDom(element));
22492 const parsedValue = parseIndentValue(dom.getStyle(element, indentStyleName));
22493 if (command === 'outdent') {
22494 const styleValue = Math.max(0, parsedValue - value);
22495 dom.setStyle(element, indentStyleName, styleValue ? styleValue + unit : '');
22496 } else {
22497 const styleValue = parsedValue + value + unit;
22498 dom.setStyle(element, indentStyleName, styleValue);
22499 }
22500 };
22501 const validateBlocks = (editor, blocks) => forall(blocks, block => {
22502 const indentStyleName = getIndentStyleName(shouldIndentUseMargin(editor), block);
22503 const intentValue = getRaw(block, indentStyleName).map(parseIndentValue).getOr(0);
22504 const contentEditable = editor.dom.getContentEditable(block.dom);
22505 return contentEditable !== 'false' && intentValue > 0;
22506 });
22507 const canOutdent = editor => {
22508 const blocks = getBlocksToIndent(editor);
22509 return !editor.mode.isReadOnly() && (blocks.length > 1 || validateBlocks(editor, blocks));
22510 };
22511 const isListComponent = el => isList(el) || isListItem$1(el);
22512 const parentIsListComponent = el => parent(el).exists(isListComponent);
22513 const getBlocksToIndent = editor => filter$5(fromDom$1(editor.selection.getSelectedBlocks()), el => !isListComponent(el) && !parentIsListComponent(el) && isEditable(el));
22514 const handle = (editor, command) => {
22515 var _a, _b;
22516 const {dom} = editor;
22517 const indentation = getIndentation(editor);
22518 const indentUnit = (_b = (_a = /[a-z%]+$/i.exec(indentation)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 'px';
22519 const indentValue = parseIndentValue(indentation);
22520 const useMargin = shouldIndentUseMargin(editor);
22521 each$e(getBlocksToIndent(editor), block => {
22522 indentElement(dom, command, useMargin, indentValue, indentUnit, block.dom);
22523 });
22524 };
22525 const indent = editor => handle(editor, 'indent');
22526 const outdent = editor => handle(editor, 'outdent');
22527
22528 const backspaceDelete$1 = editor => {
22529 if (editor.selection.isCollapsed() && canOutdent(editor)) {
22530 const dom = editor.dom;
22531 const rng = editor.selection.getRng();
22532 const pos = CaretPosition.fromRangeStart(rng);
22533 const block = dom.getParent(rng.startContainer, dom.isBlock);
22534 if (block !== null && isAtStartOfBlock(SugarElement.fromDom(block), pos, editor.schema)) {
22535 return Optional.some(() => outdent(editor));
22536 }
22537 }
22538 return Optional.none();
22539 };
22540
22541 const findAction = (editor, caret, forward) => findMap([
22542 backspaceDelete$1,
22543 backspaceDelete$6,
22544 backspaceDelete$7,
22545 (editor, forward) => backspaceDelete$4(editor, caret, forward),
22546 backspaceDelete$9,
22547 backspaceDelete$a,
22548 backspaceDelete$5,
22549 backspaceDelete$2,
22550 backspaceDelete$8,
22551 backspaceDelete$3
22552 ], item => item(editor, forward)).filter(_ => editor.selection.isEditable());
22553 const deleteCommand = (editor, caret) => {
22554 const result = findAction(editor, caret, false);
22555 result.fold(() => {
22556 if (editor.selection.isEditable()) {
22557 execNativeDeleteCommand(editor);
22558 paddEmptyBody(editor);
22559 }
22560 }, call);
22561 };
22562 const forwardDeleteCommand = (editor, caret) => {
22563 const result = findAction(editor, caret, true);
22564 result.fold(() => {
22565 if (editor.selection.isEditable()) {
22566 execNativeForwardDeleteCommand(editor);
22567 }
22568 }, call);
22569 };
22570 const setup$q = (editor, caret) => {
22571 editor.addCommand('delete', () => {
22572 deleteCommand(editor, caret);
22573 });
22574 editor.addCommand('forwardDelete', () => {
22575 forwardDeleteCommand(editor, caret);
22576 });
22577 };
22578
22579 const SIGNIFICANT_MOVE = 5;
22580 const LONGPRESS_DELAY = 400;
22581 const getTouch = event => {
22582 if (event.touches === undefined || event.touches.length !== 1) {
22583 return Optional.none();
22584 }
22585 return Optional.some(event.touches[0]);
22586 };
22587 const isFarEnough = (touch, data) => {
22588 const distX = Math.abs(touch.clientX - data.x);
22589 const distY = Math.abs(touch.clientY - data.y);
22590 return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
22591 };
22592 const setup$p = editor => {
22593 const startData = value$2();
22594 const longpressFired = Cell(false);
22595 const debounceLongpress = last(e => {
22596 editor.dispatch('longpress', {
22597 ...e,
22598 type: 'longpress'
22599 });
22600 longpressFired.set(true);
22601 }, LONGPRESS_DELAY);
22602 editor.on('touchstart', e => {
22603 getTouch(e).each(touch => {
22604 debounceLongpress.cancel();
22605 const data = {
22606 x: touch.clientX,
22607 y: touch.clientY,
22608 target: e.target
22609 };
22610 debounceLongpress.throttle(e);
22611 longpressFired.set(false);
22612 startData.set(data);
22613 });
22614 }, true);
22615 editor.on('touchmove', e => {
22616 debounceLongpress.cancel();
22617 getTouch(e).each(touch => {
22618 startData.on(data => {
22619 if (isFarEnough(touch, data)) {
22620 startData.clear();
22621 longpressFired.set(false);
22622 editor.dispatch('longpresscancel');
22623 }
22624 });
22625 });
22626 }, true);
22627 editor.on('touchend touchcancel', e => {
22628 debounceLongpress.cancel();
22629 if (e.type === 'touchcancel') {
22630 return;
22631 }
22632 startData.get().filter(data => data.target.isEqualNode(e.target)).each(() => {
22633 if (longpressFired.get()) {
22634 e.preventDefault();
22635 } else {
22636 editor.dispatch('tap', {
22637 ...e,
22638 type: 'tap'
22639 });
22640 }
22641 });
22642 }, true);
22643 };
22644
22645 const isBlockElement = (blockElements, node) => has$2(blockElements, node.nodeName);
22646 const isValidTarget = (schema, node) => {
22647 if (isText$b(node)) {
22648 return true;
22649 } else if (isElement$6(node)) {
22650 return !isBlockElement(schema.getBlockElements(), node) && !isBookmarkNode$1(node) && !isTransparentBlock(schema, node) && !isNonHtmlElementRoot(node);
22651 } else {
22652 return false;
22653 }
22654 };
22655 const hasBlockParent = (blockElements, root, node) => {
22656 return exists(parents(SugarElement.fromDom(node), SugarElement.fromDom(root)), elm => {
22657 return isBlockElement(blockElements, elm.dom);
22658 });
22659 };
22660 const shouldRemoveTextNode = (blockElements, node) => {
22661 if (isText$b(node)) {
22662 if (node.data.length === 0) {
22663 return true;
22664 } else if (/^\s+$/.test(node.data)) {
22665 return !node.nextSibling || isBlockElement(blockElements, node.nextSibling) || isNonHtmlElementRoot(node.nextSibling);
22666 }
22667 }
22668 return false;
22669 };
22670 const createRootBlock = editor => editor.dom.create(getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
22671 const addRootBlocks = editor => {
22672 const dom = editor.dom, selection = editor.selection;
22673 const schema = editor.schema;
22674 const blockElements = schema.getBlockElements();
22675 const startNode = selection.getStart();
22676 const rootNode = editor.getBody();
22677 let rootBlockNode;
22678 let tempNode;
22679 let wrapped = false;
22680 const forcedRootBlock = getForcedRootBlock(editor);
22681 if (!startNode || !isElement$6(startNode)) {
22682 return;
22683 }
22684 const rootNodeName = rootNode.nodeName.toLowerCase();
22685 if (!schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase()) || hasBlockParent(blockElements, rootNode, startNode)) {
22686 return;
22687 }
22688 const rng = selection.getRng();
22689 const {startContainer, startOffset, endContainer, endOffset} = rng;
22690 const restoreSelection = hasFocus(editor);
22691 let node = rootNode.firstChild;
22692 while (node) {
22693 if (isElement$6(node)) {
22694 updateElement(schema, node);
22695 }
22696 if (isValidTarget(schema, node)) {
22697 if (shouldRemoveTextNode(blockElements, node)) {
22698 tempNode = node;
22699 node = node.nextSibling;
22700 dom.remove(tempNode);
22701 continue;
22702 }
22703 if (!rootBlockNode) {
22704 rootBlockNode = createRootBlock(editor);
22705 rootNode.insertBefore(rootBlockNode, node);
22706 wrapped = true;
22707 }
22708 tempNode = node;
22709 node = node.nextSibling;
22710 rootBlockNode.appendChild(tempNode);
22711 } else {
22712 rootBlockNode = null;
22713 node = node.nextSibling;
22714 }
22715 }
22716 if (wrapped && restoreSelection) {
22717 rng.setStart(startContainer, startOffset);
22718 rng.setEnd(endContainer, endOffset);
22719 selection.setRng(rng);
22720 editor.nodeChanged();
22721 }
22722 };
22723 const insertEmptyLine = (editor, root, insertBlock) => {
22724 const block = SugarElement.fromDom(createRootBlock(editor));
22725 const br = createPaddingBr();
22726 append$1(block, br);
22727 insertBlock(root, block);
22728 const rng = document.createRange();
22729 rng.setStartBefore(br.dom);
22730 rng.setEndBefore(br.dom);
22731 return rng;
22732 };
22733 const setup$o = editor => {
22734 editor.on('NodeChange', curry(addRootBlocks, editor));
22735 };
22736
22737 const hasClass = checkClassName => node => (' ' + node.attr('class') + ' ').indexOf(checkClassName) !== -1;
22738 const replaceMatchWithSpan = (editor, content, cls) => {
22739 return function (match) {
22740 const args = arguments, index = args[args.length - 2];
22741 const prevChar = index > 0 ? content.charAt(index - 1) : '';
22742 if (prevChar === '"') {
22743 return match;
22744 }
22745 if (prevChar === '>') {
22746 const findStartTagIndex = content.lastIndexOf('<', index);
22747 if (findStartTagIndex !== -1) {
22748 const tagHtml = content.substring(findStartTagIndex, index);
22749 if (tagHtml.indexOf('contenteditable="false"') !== -1) {
22750 return match;
22751 }
22752 }
22753 }
22754 return '<span class="' + cls + '" data-mce-content="' + editor.dom.encode(args[0]) + '">' + editor.dom.encode(typeof args[1] === 'string' ? args[1] : args[0]) + '</span>';
22755 };
22756 };
22757 const convertRegExpsToNonEditable = (editor, nonEditableRegExps, e) => {
22758 let i = nonEditableRegExps.length, content = e.content;
22759 if (e.format === 'raw') {
22760 return;
22761 }
22762 while (i--) {
22763 content = content.replace(nonEditableRegExps[i], replaceMatchWithSpan(editor, content, getNonEditableClass(editor)));
22764 }
22765 e.content = content;
22766 };
22767 const setup$n = editor => {
22768 const contentEditableAttrName = 'contenteditable';
22769 const editClass = ' ' + Tools.trim(getEditableClass(editor)) + ' ';
22770 const nonEditClass = ' ' + Tools.trim(getNonEditableClass(editor)) + ' ';
22771 const hasEditClass = hasClass(editClass);
22772 const hasNonEditClass = hasClass(nonEditClass);
22773 const nonEditableRegExps = getNonEditableRegExps(editor);
22774 if (nonEditableRegExps.length > 0) {
22775 editor.on('BeforeSetContent', e => {
22776 convertRegExpsToNonEditable(editor, nonEditableRegExps, e);
22777 });
22778 }
22779 editor.parser.addAttributeFilter('class', nodes => {
22780 let i = nodes.length;
22781 while (i--) {
22782 const node = nodes[i];
22783 if (hasEditClass(node)) {
22784 node.attr(contentEditableAttrName, 'true');
22785 } else if (hasNonEditClass(node)) {
22786 node.attr(contentEditableAttrName, 'false');
22787 }
22788 }
22789 });
22790 editor.serializer.addAttributeFilter(contentEditableAttrName, nodes => {
22791 let i = nodes.length;
22792 while (i--) {
22793 const node = nodes[i];
22794 if (!hasEditClass(node) && !hasNonEditClass(node)) {
22795 continue;
22796 }
22797 if (nonEditableRegExps.length > 0 && node.attr('data-mce-content')) {
22798 node.name = '#text';
22799 node.type = 3;
22800 node.raw = true;
22801 node.value = node.attr('data-mce-content');
22802 } else {
22803 node.attr(contentEditableAttrName, null);
22804 }
22805 }
22806 });
22807 };
22808
22809 const findBlockCaretContainer = editor => descendant$1(SugarElement.fromDom(editor.getBody()), '*[data-mce-caret]').map(elm => elm.dom).getOrNull();
22810 const showBlockCaretContainer = (editor, blockCaretContainer) => {
22811 if (blockCaretContainer.hasAttribute('data-mce-caret')) {
22812 showCaretContainerBlock(blockCaretContainer);
22813 editor.selection.setRng(editor.selection.getRng());
22814 editor.selection.scrollIntoView(blockCaretContainer);
22815 }
22816 };
22817 const handleBlockContainer = (editor, e) => {
22818 const blockCaretContainer = findBlockCaretContainer(editor);
22819 if (!blockCaretContainer) {
22820 return;
22821 }
22822 if (e.type === 'compositionstart') {
22823 e.preventDefault();
22824 e.stopPropagation();
22825 showBlockCaretContainer(editor, blockCaretContainer);
22826 return;
22827 }
22828 if (hasContent(blockCaretContainer)) {
22829 showBlockCaretContainer(editor, blockCaretContainer);
22830 editor.undoManager.add();
22831 }
22832 };
22833 const setup$m = editor => {
22834 editor.on('keyup compositionstart', curry(handleBlockContainer, editor));
22835 };
22836
22837 const isContentEditableFalse$4 = isContentEditableFalse$b;
22838 const moveToCeFalseHorizontally = (direction, editor, range) => moveHorizontally(editor, direction, range, isBeforeContentEditableFalse, isAfterContentEditableFalse, isContentEditableFalse$4);
22839 const moveToCeFalseVertically = (direction, editor, range) => {
22840 const isBefore = caretPosition => isBeforeContentEditableFalse(caretPosition) || isBeforeTable(caretPosition);
22841 const isAfter = caretPosition => isAfterContentEditableFalse(caretPosition) || isAfterTable(caretPosition);
22842 return moveVertically(editor, direction, range, isBefore, isAfter, isContentEditableFalse$4);
22843 };
22844 const createTextBlock = editor => {
22845 const textBlock = editor.dom.create(getForcedRootBlock(editor));
22846 textBlock.innerHTML = '<br data-mce-bogus="1">';
22847 return textBlock;
22848 };
22849 const exitPreBlock = (editor, direction, range) => {
22850 const caretWalker = CaretWalker(editor.getBody());
22851 const getVisualCaretPosition$1 = curry(getVisualCaretPosition, direction === 1 ? caretWalker.next : caretWalker.prev);
22852 if (range.collapsed) {
22853 const pre = editor.dom.getParent(range.startContainer, 'PRE');
22854 if (!pre) {
22855 return;
22856 }
22857 const caretPos = getVisualCaretPosition$1(CaretPosition.fromRangeStart(range));
22858 if (!caretPos) {
22859 const newBlock = SugarElement.fromDom(createTextBlock(editor));
22860 if (direction === 1) {
22861 after$4(SugarElement.fromDom(pre), newBlock);
22862 } else {
22863 before$3(SugarElement.fromDom(pre), newBlock);
22864 }
22865 editor.selection.select(newBlock.dom, true);
22866 editor.selection.collapse();
22867 }
22868 }
22869 };
22870 const getHorizontalRange = (editor, forward) => {
22871 const direction = forward ? HDirection.Forwards : HDirection.Backwards;
22872 const range = editor.selection.getRng();
22873 return moveToCeFalseHorizontally(direction, editor, range).orThunk(() => {
22874 exitPreBlock(editor, direction, range);
22875 return Optional.none();
22876 });
22877 };
22878 const getVerticalRange = (editor, down) => {
22879 const direction = down ? 1 : -1;
22880 const range = editor.selection.getRng();
22881 return moveToCeFalseVertically(direction, editor, range).orThunk(() => {
22882 exitPreBlock(editor, direction, range);
22883 return Optional.none();
22884 });
22885 };
22886 const flipDirection = (selection, forward) => {
22887 const elm = forward ? selection.getEnd(true) : selection.getStart(true);
22888 return isRtl(elm) ? !forward : forward;
22889 };
22890 const moveH$2 = (editor, forward) => getHorizontalRange(editor, flipDirection(editor.selection, forward)).exists(newRange => {
22891 moveToRange(editor, newRange);
22892 return true;
22893 });
22894 const moveV$4 = (editor, down) => getVerticalRange(editor, down).exists(newRange => {
22895 moveToRange(editor, newRange);
22896 return true;
22897 });
22898 const moveToLineEndPoint$1 = (editor, forward) => {
22899 const isCefPosition = forward ? isAfterContentEditableFalse : isBeforeContentEditableFalse;
22900 return moveToLineEndPoint$3(editor, forward, isCefPosition);
22901 };
22902 const selectToEndPoint = (editor, forward) => getEdgeCefPosition(editor, !forward).map(pos => {
22903 const rng = pos.toRange();
22904 const curRng = editor.selection.getRng();
22905 if (forward) {
22906 rng.setStart(curRng.startContainer, curRng.startOffset);
22907 } else {
22908 rng.setEnd(curRng.endContainer, curRng.endOffset);
22909 }
22910 return rng;
22911 }).exists(rng => {
22912 moveToRange(editor, rng);
22913 return true;
22914 });
22915
22916 const isTarget = node => contains$2(['figcaption'], name(node));
22917 const getClosestTargetBlock = (pos, root, schema) => {
22918 const isRoot = curry(eq, root);
22919 return closest$4(SugarElement.fromDom(pos.container()), el => schema.isBlock(name(el)), isRoot).filter(isTarget);
22920 };
22921 const isAtFirstOrLastLine = (root, forward, pos) => forward ? isAtLastLine(root.dom, pos) : isAtFirstLine(root.dom, pos);
22922 const moveCaretToNewEmptyLine = (editor, forward) => {
22923 const root = SugarElement.fromDom(editor.getBody());
22924 const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
22925 return getClosestTargetBlock(pos, root, editor.schema).exists(() => {
22926 if (isAtFirstOrLastLine(root, forward, pos)) {
22927 const insertFn = forward ? append$1 : prepend;
22928 const rng = insertEmptyLine(editor, root, insertFn);
22929 editor.selection.setRng(rng);
22930 return true;
22931 } else {
22932 return false;
22933 }
22934 });
22935 };
22936 const moveV$3 = (editor, forward) => {
22937 if (editor.selection.isCollapsed()) {
22938 return moveCaretToNewEmptyLine(editor, forward);
22939 } else {
22940 return false;
22941 }
22942 };
22943
22944 const moveUp = (editor, details, summary) => {
22945 const rng = editor.selection.getRng();
22946 const pos = CaretPosition.fromRangeStart(rng);
22947 const root = editor.getBody();
22948 if (root.firstChild === details && isAtFirstLine(summary, pos)) {
22949 editor.execCommand('InsertNewBlockBefore');
22950 return true;
22951 } else {
22952 return false;
22953 }
22954 };
22955 const moveDown = (editor, details) => {
22956 const rng = editor.selection.getRng();
22957 const pos = CaretPosition.fromRangeStart(rng);
22958 const root = editor.getBody();
22959 if (root.lastChild === details && isAtLastLine(details, pos)) {
22960 editor.execCommand('InsertNewBlockAfter');
22961 return true;
22962 } else {
22963 return false;
22964 }
22965 };
22966 const move$2 = (editor, forward) => {
22967 if (forward) {
22968 return Optional.from(editor.dom.getParent(editor.selection.getNode(), 'details')).map(details => moveDown(editor, details)).getOr(false);
22969 } else {
22970 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);
22971 }
22972 };
22973 const moveV$2 = (editor, forward) => move$2(editor, forward);
22974
22975 const baseKeyPattern = {
22976 shiftKey: false,
22977 altKey: false,
22978 ctrlKey: false,
22979 metaKey: false,
22980 keyCode: 0
22981 };
22982 const defaultPatterns = patterns => map$3(patterns, pattern => ({
22983 ...baseKeyPattern,
22984 ...pattern
22985 }));
22986 const defaultDelayedPatterns = patterns => map$3(patterns, pattern => ({
22987 ...baseKeyPattern,
22988 ...pattern
22989 }));
22990 const matchesEvent = (pattern, evt) => evt.keyCode === pattern.keyCode && evt.shiftKey === pattern.shiftKey && evt.altKey === pattern.altKey && evt.ctrlKey === pattern.ctrlKey && evt.metaKey === pattern.metaKey;
22991 const match$1 = (patterns, evt) => bind$3(defaultPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
22992 const matchDelayed = (patterns, evt) => bind$3(defaultDelayedPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
22993 const action = (f, ...x) => () => f.apply(null, x);
22994 const execute = (patterns, evt) => find$2(match$1(patterns, evt), pattern => pattern.action());
22995 const executeWithDelayedAction = (patterns, evt) => findMap(matchDelayed(patterns, evt), pattern => pattern.action());
22996
22997 const moveH$1 = (editor, forward) => {
22998 const direction = forward ? HDirection.Forwards : HDirection.Backwards;
22999 const range = editor.selection.getRng();
23000 return moveHorizontally(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
23001 moveToRange(editor, newRange);
23002 return true;
23003 });
23004 };
23005 const moveV$1 = (editor, down) => {
23006 const direction = down ? 1 : -1;
23007 const range = editor.selection.getRng();
23008 return moveVertically(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
23009 moveToRange(editor, newRange);
23010 return true;
23011 });
23012 };
23013 const moveToLineEndPoint = (editor, forward) => {
23014 const isNearMedia = forward ? isAfterMedia : isBeforeMedia;
23015 return moveToLineEndPoint$3(editor, forward, isNearMedia);
23016 };
23017
23018 const adt = Adt.generate([
23019 { none: ['current'] },
23020 { first: ['current'] },
23021 {
23022 middle: [
23023 'current',
23024 'target'
23025 ]
23026 },
23027 { last: ['current'] }
23028 ]);
23029 const none = current => adt.none(current);
23030 const CellLocation = {
23031 ...adt,
23032 none
23033 };
23034
23035 const firstLayer = (scope, selector) => {
23036 return filterFirstLayer(scope, selector, always);
23037 };
23038 const filterFirstLayer = (scope, selector, predicate) => {
23039 return bind$3(children$1(scope), x => {
23040 if (is$1(x, selector)) {
23041 return predicate(x) ? [x] : [];
23042 } else {
23043 return filterFirstLayer(x, selector, predicate);
23044 }
23045 });
23046 };
23047
23048 const lookup$1 = (tags, element, isRoot = never) => {
23049 if (isRoot(element)) {
23050 return Optional.none();
23051 }
23052 if (contains$2(tags, name(element))) {
23053 return Optional.some(element);
23054 }
23055 const isRootOrUpperTable = elm => is$1(elm, 'table') || isRoot(elm);
23056 return ancestor$3(element, tags.join(','), isRootOrUpperTable);
23057 };
23058 const cell = (element, isRoot) => lookup$1([
23059 'td',
23060 'th'
23061 ], element, isRoot);
23062 const cells = ancestor => firstLayer(ancestor, 'th,td');
23063 const table = (element, isRoot) => closest$3(element, 'table', isRoot);
23064
23065 const walk = (all, current, index, direction, isEligible = always) => {
23066 const forwards = direction === 1;
23067 if (!forwards && index <= 0) {
23068 return CellLocation.first(all[0]);
23069 } else if (forwards && index >= all.length - 1) {
23070 return CellLocation.last(all[all.length - 1]);
23071 } else {
23072 const newIndex = index + direction;
23073 const elem = all[newIndex];
23074 return isEligible(elem) ? CellLocation.middle(current, elem) : walk(all, current, newIndex, direction, isEligible);
23075 }
23076 };
23077 const detect = (current, isRoot) => {
23078 return table(current, isRoot).bind(table => {
23079 const all = cells(table);
23080 const index = findIndex$2(all, x => eq(current, x));
23081 return index.map(index => ({
23082 index,
23083 all
23084 }));
23085 });
23086 };
23087 const next = (current, isEligible, isRoot) => {
23088 const detection = detect(current, isRoot);
23089 return detection.fold(() => {
23090 return CellLocation.none(current);
23091 }, info => {
23092 return walk(info.all, current, info.index, 1, isEligible);
23093 });
23094 };
23095 const prev = (current, isEligible, isRoot) => {
23096 const detection = detect(current, isRoot);
23097 return detection.fold(() => {
23098 return CellLocation.none();
23099 }, info => {
23100 return walk(info.all, current, info.index, -1, isEligible);
23101 });
23102 };
23103
23104 const isTextNodeWithCursorPosition = el => getOption(el).filter(text => text.trim().length !== 0 || text.indexOf(nbsp) > -1).isSome();
23105 const isContentEditableFalse$3 = elem => isHTMLElement$1(elem) && get$9(elem, 'contenteditable') === 'false';
23106 const elementsWithCursorPosition = [
23107 'img',
23108 'br'
23109 ];
23110 const isCursorPosition = elem => {
23111 const hasCursorPosition = isTextNodeWithCursorPosition(elem);
23112 return hasCursorPosition || contains$2(elementsWithCursorPosition, name(elem)) || isContentEditableFalse$3(elem);
23113 };
23114
23115 const first = element => descendant$2(element, isCursorPosition);
23116
23117 const deflate = (rect, delta) => ({
23118 left: rect.left - delta,
23119 top: rect.top - delta,
23120 right: rect.right + delta * 2,
23121 bottom: rect.bottom + delta * 2,
23122 width: rect.width + delta,
23123 height: rect.height + delta
23124 });
23125 const getCorners = (getYAxisValue, tds) => bind$3(tds, td => {
23126 const rect = deflate(clone$1(td.getBoundingClientRect()), -1);
23127 return [
23128 {
23129 x: rect.left,
23130 y: getYAxisValue(rect),
23131 cell: td
23132 },
23133 {
23134 x: rect.right,
23135 y: getYAxisValue(rect),
23136 cell: td
23137 }
23138 ];
23139 });
23140 const findClosestCorner = (corners, x, y) => foldl(corners, (acc, newCorner) => acc.fold(() => Optional.some(newCorner), oldCorner => {
23141 const oldDist = Math.sqrt(Math.abs(oldCorner.x - x) + Math.abs(oldCorner.y - y));
23142 const newDist = Math.sqrt(Math.abs(newCorner.x - x) + Math.abs(newCorner.y - y));
23143 return Optional.some(newDist < oldDist ? newCorner : oldCorner);
23144 }), Optional.none());
23145 const getClosestCell = (getYAxisValue, isTargetCorner, table, x, y) => {
23146 const cells = descendants(SugarElement.fromDom(table), 'td,th,caption').map(e => e.dom);
23147 const corners = filter$5(getCorners(getYAxisValue, cells), corner => isTargetCorner(corner, y));
23148 return findClosestCorner(corners, x, y).map(corner => corner.cell);
23149 };
23150 const getBottomValue = rect => rect.bottom;
23151 const getTopValue = rect => rect.top;
23152 const isAbove = (corner, y) => corner.y < y;
23153 const isBelow = (corner, y) => corner.y > y;
23154 const getClosestCellAbove = curry(getClosestCell, getBottomValue, isAbove);
23155 const getClosestCellBelow = curry(getClosestCell, getTopValue, isBelow);
23156 const findClosestPositionInAboveCell = (table, pos) => head(pos.getClientRects()).bind(rect => getClosestCellAbove(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getLastLinePositions(cell), pos));
23157 const findClosestPositionInBelowCell = (table, pos) => last$2(pos.getClientRects()).bind(rect => getClosestCellBelow(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getFirstLinePositions(cell), pos));
23158
23159 const hasNextBreak = (getPositionsUntil, scope, lineInfo) => lineInfo.breakAt.exists(breakPos => getPositionsUntil(scope, breakPos).breakAt.isSome());
23160 const startsWithWrapBreak = lineInfo => lineInfo.breakType === BreakType.Wrap && lineInfo.positions.length === 0;
23161 const startsWithBrBreak = lineInfo => lineInfo.breakType === BreakType.Br && lineInfo.positions.length === 1;
23162 const isAtTableCellLine = (getPositionsUntil, scope, pos) => {
23163 const lineInfo = getPositionsUntil(scope, pos);
23164 if (startsWithWrapBreak(lineInfo) || !isBr$6(pos.getNode()) && startsWithBrBreak(lineInfo)) {
23165 return !hasNextBreak(getPositionsUntil, scope, lineInfo);
23166 } else {
23167 return lineInfo.breakAt.isNone();
23168 }
23169 };
23170 const isAtFirstTableCellLine = curry(isAtTableCellLine, getPositionsUntilPreviousLine);
23171 const isAtLastTableCellLine = curry(isAtTableCellLine, getPositionsUntilNextLine);
23172 const isCaretAtStartOrEndOfTable = (forward, rng, table) => {
23173 const caretPos = CaretPosition.fromRangeStart(rng);
23174 return positionIn(!forward, table).exists(pos => pos.isEqual(caretPos));
23175 };
23176 const navigateHorizontally = (editor, forward, table, _td) => {
23177 const rng = editor.selection.getRng();
23178 const direction = forward ? 1 : -1;
23179 if (isFakeCaretTableBrowser() && isCaretAtStartOrEndOfTable(forward, rng, table)) {
23180 showCaret(direction, editor, table, !forward, false).each(newRng => {
23181 moveToRange(editor, newRng);
23182 });
23183 return true;
23184 }
23185 return false;
23186 };
23187 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));
23188 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));
23189 const getTable = (previous, pos) => {
23190 const node = pos.getNode(previous);
23191 return isTable$2(node) ? Optional.some(node) : Optional.none();
23192 };
23193 const renderBlock = (down, editor, table) => {
23194 editor.undoManager.transact(() => {
23195 const insertFn = down ? after$4 : before$3;
23196 const rng = insertEmptyLine(editor, SugarElement.fromDom(table), insertFn);
23197 moveToRange(editor, rng);
23198 });
23199 };
23200 const moveCaret = (editor, down, pos) => {
23201 const table = down ? getTable(true, pos) : getTable(false, pos);
23202 const last = down === false;
23203 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)));
23204 };
23205 const navigateVertically = (editor, down, table, td) => {
23206 const rng = editor.selection.getRng();
23207 const pos = CaretPosition.fromRangeStart(rng);
23208 const root = editor.getBody();
23209 if (!down && isAtFirstTableCellLine(td, pos)) {
23210 const newPos = getClosestAbovePosition(root, table, pos);
23211 moveCaret(editor, down, newPos);
23212 return true;
23213 } else if (down && isAtLastTableCellLine(td, pos)) {
23214 const newPos = getClosestBelowPosition(root, table, pos);
23215 moveCaret(editor, down, newPos);
23216 return true;
23217 } else {
23218 return false;
23219 }
23220 };
23221 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);
23222 const moveH = (editor, forward) => move$1(editor, forward, navigateHorizontally);
23223 const moveV = (editor, forward) => move$1(editor, forward, navigateVertically);
23224 const getCellFirstCursorPosition = cell => {
23225 const selection = SimSelection.exact(cell, 0, cell, 0);
23226 return toNative(selection);
23227 };
23228 const tabGo = (editor, isRoot, cell) => {
23229 return cell.fold(Optional.none, Optional.none, (_current, next) => {
23230 return first(next).map(cell => {
23231 return getCellFirstCursorPosition(cell);
23232 });
23233 }, current => {
23234 editor.execCommand('mceTableInsertRowAfter');
23235 return tabForward(editor, isRoot, current);
23236 });
23237 };
23238 const tabForward = (editor, isRoot, cell) => tabGo(editor, isRoot, next(cell, isEditable$2));
23239 const tabBackward = (editor, isRoot, cell) => tabGo(editor, isRoot, prev(cell, isEditable$2));
23240 const handleTab = (editor, forward) => {
23241 const rootElements = [
23242 'table',
23243 'li',
23244 'dl'
23245 ];
23246 const body = SugarElement.fromDom(editor.getBody());
23247 const isRoot = element => {
23248 const name$1 = name(element);
23249 return eq(element, body) || contains$2(rootElements, name$1);
23250 };
23251 const rng = editor.selection.getRng();
23252 const container = SugarElement.fromDom(!forward ? rng.startContainer : rng.endContainer);
23253 return cell(container, isRoot).map(cell => {
23254 table(cell, isRoot).each(table => {
23255 editor.model.table.clearSelectedCells(table.dom);
23256 });
23257 editor.selection.collapse(!forward);
23258 const navigation = !forward ? tabBackward : tabForward;
23259 const rng = navigation(editor, isRoot, cell);
23260 rng.each(range => {
23261 editor.selection.setRng(range);
23262 });
23263 return true;
23264 }).getOr(false);
23265 };
23266
23267 const executeKeydownOverride$4 = (editor, caret, evt) => {
23268 const isMac = Env.os.isMacOS() || Env.os.isiOS();
23269 execute([
23270 {
23271 keyCode: VK.RIGHT,
23272 action: action(moveH$2, editor, true)
23273 },
23274 {
23275 keyCode: VK.LEFT,
23276 action: action(moveH$2, editor, false)
23277 },
23278 {
23279 keyCode: VK.UP,
23280 action: action(moveV$4, editor, false)
23281 },
23282 {
23283 keyCode: VK.DOWN,
23284 action: action(moveV$4, editor, true)
23285 },
23286 ...isMac ? [
23287 {
23288 keyCode: VK.UP,
23289 action: action(selectToEndPoint, editor, false),
23290 metaKey: true,
23291 shiftKey: true
23292 },
23293 {
23294 keyCode: VK.DOWN,
23295 action: action(selectToEndPoint, editor, true),
23296 metaKey: true,
23297 shiftKey: true
23298 }
23299 ] : [],
23300 {
23301 keyCode: VK.RIGHT,
23302 action: action(moveH, editor, true)
23303 },
23304 {
23305 keyCode: VK.LEFT,
23306 action: action(moveH, editor, false)
23307 },
23308 {
23309 keyCode: VK.UP,
23310 action: action(moveV, editor, false)
23311 },
23312 {
23313 keyCode: VK.DOWN,
23314 action: action(moveV, editor, true)
23315 },
23316 {
23317 keyCode: VK.UP,
23318 action: action(moveV, editor, false)
23319 },
23320 {
23321 keyCode: VK.UP,
23322 action: action(moveV$2, editor, false)
23323 },
23324 {
23325 keyCode: VK.DOWN,
23326 action: action(moveV$2, editor, true)
23327 },
23328 {
23329 keyCode: VK.RIGHT,
23330 action: action(moveH$1, editor, true)
23331 },
23332 {
23333 keyCode: VK.LEFT,
23334 action: action(moveH$1, editor, false)
23335 },
23336 {
23337 keyCode: VK.UP,
23338 action: action(moveV$1, editor, false)
23339 },
23340 {
23341 keyCode: VK.DOWN,
23342 action: action(moveV$1, editor, true)
23343 },
23344 {
23345 keyCode: VK.RIGHT,
23346 action: action(move$3, editor, caret, true)
23347 },
23348 {
23349 keyCode: VK.LEFT,
23350 action: action(move$3, editor, caret, false)
23351 },
23352 {
23353 keyCode: VK.RIGHT,
23354 ctrlKey: !isMac,
23355 altKey: isMac,
23356 action: action(moveNextWord, editor, caret)
23357 },
23358 {
23359 keyCode: VK.LEFT,
23360 ctrlKey: !isMac,
23361 altKey: isMac,
23362 action: action(movePrevWord, editor, caret)
23363 },
23364 {
23365 keyCode: VK.UP,
23366 action: action(moveV$3, editor, false)
23367 },
23368 {
23369 keyCode: VK.DOWN,
23370 action: action(moveV$3, editor, true)
23371 }
23372 ], evt).each(_ => {
23373 evt.preventDefault();
23374 });
23375 };
23376 const setup$l = (editor, caret) => {
23377 editor.on('keydown', evt => {
23378 if (!evt.isDefaultPrevented()) {
23379 executeKeydownOverride$4(editor, caret, evt);
23380 }
23381 });
23382 };
23383
23384 const point = (container, offset) => ({
23385 container,
23386 offset
23387 });
23388
23389 const DOM$7 = DOMUtils.DOM;
23390 const alwaysNext = startNode => node => startNode === node ? -1 : 0;
23391 const isBoundary = dom => node => dom.isBlock(node) || contains$2([
23392 'BR',
23393 'IMG',
23394 'HR',
23395 'INPUT'
23396 ], node.nodeName) || dom.getContentEditable(node) === 'false';
23397 const textBefore = (node, offset, rootNode) => {
23398 if (isText$b(node) && offset >= 0) {
23399 return Optional.some(point(node, offset));
23400 } else {
23401 const textSeeker = TextSeeker(DOM$7);
23402 return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, prev.container.data.length));
23403 }
23404 };
23405 const textAfter = (node, offset, rootNode) => {
23406 if (isText$b(node) && offset >= node.length) {
23407 return Optional.some(point(node, offset));
23408 } else {
23409 const textSeeker = TextSeeker(DOM$7);
23410 return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, 0));
23411 }
23412 };
23413 const scanLeft = (node, offset, rootNode) => {
23414 if (!isText$b(node)) {
23415 return Optional.none();
23416 }
23417 const text = node.data;
23418 if (offset >= 0 && offset <= text.length) {
23419 return Optional.some(point(node, offset));
23420 } else {
23421 const textSeeker = TextSeeker(DOM$7);
23422 return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).bind(prev => {
23423 const prevText = prev.container.data;
23424 return scanLeft(prev.container, offset + prevText.length, rootNode);
23425 });
23426 }
23427 };
23428 const scanRight = (node, offset, rootNode) => {
23429 if (!isText$b(node)) {
23430 return Optional.none();
23431 }
23432 const text = node.data;
23433 if (offset <= text.length) {
23434 return Optional.some(point(node, offset));
23435 } else {
23436 const textSeeker = TextSeeker(DOM$7);
23437 return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).bind(next => scanRight(next.container, offset - text.length, rootNode));
23438 }
23439 };
23440 const repeatLeft = (dom, node, offset, process, rootNode) => {
23441 const search = TextSeeker(dom, isBoundary(dom));
23442 return Optional.from(search.backwards(node, offset, process, rootNode));
23443 };
23444
23445 const isValidTextRange = rng => rng.collapsed && isText$b(rng.startContainer);
23446 const getText = rng => trim$2(rng.toString().replace(/\u00A0/g, ' '));
23447 const isWhitespace = chr => chr !== '' && ' \xA0\f\n\r\t\x0B'.indexOf(chr) !== -1;
23448
23449 const stripTrigger = (text, trigger) => text.substring(trigger.length);
23450 const findTrigger = (text, index, trigger, includeWhitespace = false) => {
23451 let i;
23452 const firstChar = trigger.charAt(0);
23453 for (i = index - 1; i >= 0; i--) {
23454 const char = text.charAt(i);
23455 if (!includeWhitespace && isWhitespace(char)) {
23456 return Optional.none();
23457 }
23458 if (firstChar === char && contains$1(text, trigger, i, index)) {
23459 break;
23460 }
23461 }
23462 return Optional.some(i);
23463 };
23464 const getContext = (dom, initRange, trigger, includeWhitespace = false) => {
23465 if (!isValidTextRange(initRange)) {
23466 return Optional.none();
23467 }
23468 const buffer = {
23469 text: '',
23470 offset: 0
23471 };
23472 const findTriggerIndex = (element, offset, text) => {
23473 buffer.text = text + buffer.text;
23474 buffer.offset += offset;
23475 return findTrigger(buffer.text, buffer.offset, trigger, includeWhitespace).getOr(offset);
23476 };
23477 const root = dom.getParent(initRange.startContainer, dom.isBlock) || dom.getRoot();
23478 return repeatLeft(dom, initRange.startContainer, initRange.startOffset, findTriggerIndex, root).bind(spot => {
23479 const range = initRange.cloneRange();
23480 range.setStart(spot.container, spot.offset);
23481 range.setEnd(initRange.endContainer, initRange.endOffset);
23482 if (range.collapsed) {
23483 return Optional.none();
23484 }
23485 const text = getText(range);
23486 const triggerIndex = text.lastIndexOf(trigger);
23487 if (triggerIndex !== 0) {
23488 return Optional.none();
23489 } else {
23490 return Optional.some({
23491 text: stripTrigger(text, trigger),
23492 range,
23493 trigger
23494 });
23495 }
23496 });
23497 };
23498
23499 const isText$1 = node => node.nodeType === TEXT;
23500 const isElement = node => node.nodeType === ELEMENT;
23501 const toLast = node => {
23502 if (isText$1(node)) {
23503 return point(node, node.data.length);
23504 } else {
23505 const children = node.childNodes;
23506 return children.length > 0 ? toLast(children[children.length - 1]) : point(node, children.length);
23507 }
23508 };
23509 const toLeaf = (node, offset) => {
23510 const children = node.childNodes;
23511 if (children.length > 0 && offset < children.length) {
23512 return toLeaf(children[offset], 0);
23513 } else if (children.length > 0 && isElement(node) && children.length === offset) {
23514 return toLast(children[children.length - 1]);
23515 } else {
23516 return point(node, offset);
23517 }
23518 };
23519
23520 const isPreviousCharContent = (dom, leaf) => {
23521 var _a;
23522 const root = (_a = dom.getParent(leaf.container, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot();
23523 return repeatLeft(dom, leaf.container, leaf.offset, (_element, offset) => offset === 0 ? -1 : offset, root).filter(spot => {
23524 const char = spot.container.data.charAt(spot.offset - 1);
23525 return !isWhitespace(char);
23526 }).isSome();
23527 };
23528 const isStartOfWord = dom => rng => {
23529 const leaf = toLeaf(rng.startContainer, rng.startOffset);
23530 return !isPreviousCharContent(dom, leaf);
23531 };
23532 const getTriggerContext = (dom, initRange, database) => findMap(database.triggers, trigger => getContext(dom, initRange, trigger));
23533 const lookup = (editor, getDatabase) => {
23534 const database = getDatabase();
23535 const rng = editor.selection.getRng();
23536 return getTriggerContext(editor.dom, rng, database).bind(context => lookupWithContext(editor, getDatabase, context));
23537 };
23538 const lookupWithContext = (editor, getDatabase, context, fetchOptions = {}) => {
23539 var _a;
23540 const database = getDatabase();
23541 const rng = editor.selection.getRng();
23542 const startText = (_a = rng.startContainer.nodeValue) !== null && _a !== void 0 ? _a : '';
23543 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));
23544 if (autocompleters.length === 0) {
23545 return Optional.none();
23546 }
23547 const lookupData = Promise.all(map$3(autocompleters, ac => {
23548 const fetchResult = ac.fetch(context.text, ac.maxResults, fetchOptions);
23549 return fetchResult.then(results => ({
23550 matchText: context.text,
23551 items: results,
23552 columns: ac.columns,
23553 onAction: ac.onAction,
23554 highlightOn: ac.highlightOn
23555 }));
23556 }));
23557 return Optional.some({
23558 lookupData,
23559 context
23560 });
23561 };
23562
23563 var SimpleResultType;
23564 (function (SimpleResultType) {
23565 SimpleResultType[SimpleResultType['Error'] = 0] = 'Error';
23566 SimpleResultType[SimpleResultType['Value'] = 1] = 'Value';
23567 }(SimpleResultType || (SimpleResultType = {})));
23568 const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
23569 const partition = results => {
23570 const values = [];
23571 const errors = [];
23572 each$e(results, obj => {
23573 fold$1(obj, err => errors.push(err), val => values.push(val));
23574 });
23575 return {
23576 values,
23577 errors
23578 };
23579 };
23580 const mapError = (res, f) => {
23581 if (res.stype === SimpleResultType.Error) {
23582 return {
23583 stype: SimpleResultType.Error,
23584 serror: f(res.serror)
23585 };
23586 } else {
23587 return res;
23588 }
23589 };
23590 const map = (res, f) => {
23591 if (res.stype === SimpleResultType.Value) {
23592 return {
23593 stype: SimpleResultType.Value,
23594 svalue: f(res.svalue)
23595 };
23596 } else {
23597 return res;
23598 }
23599 };
23600 const bind$1 = (res, f) => {
23601 if (res.stype === SimpleResultType.Value) {
23602 return f(res.svalue);
23603 } else {
23604 return res;
23605 }
23606 };
23607 const bindError = (res, f) => {
23608 if (res.stype === SimpleResultType.Error) {
23609 return f(res.serror);
23610 } else {
23611 return res;
23612 }
23613 };
23614 const svalue = v => ({
23615 stype: SimpleResultType.Value,
23616 svalue: v
23617 });
23618 const serror = e => ({
23619 stype: SimpleResultType.Error,
23620 serror: e
23621 });
23622 const toResult = res => fold$1(res, Result.error, Result.value);
23623 const fromResult = res => res.fold(serror, svalue);
23624 const SimpleResult = {
23625 fromResult,
23626 toResult,
23627 svalue,
23628 partition,
23629 serror,
23630 bind: bind$1,
23631 bindError,
23632 map,
23633 mapError,
23634 fold: fold$1
23635 };
23636
23637 const formatObj = input => {
23638 return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
23639 };
23640 const formatErrors = errors => {
23641 const es = errors.length > 10 ? errors.slice(0, 10).concat([{
23642 path: [],
23643 getErrorInfo: constant('... (only showing first ten failures)')
23644 }]) : errors;
23645 return map$3(es, e => {
23646 return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
23647 });
23648 };
23649
23650 const nu = (path, getErrorInfo) => {
23651 return SimpleResult.serror([{
23652 path,
23653 getErrorInfo
23654 }]);
23655 };
23656 const missingRequired = (path, key, obj) => nu(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
23657 const missingKey = (path, key) => nu(path, () => 'Choice schema did not contain choice key: "' + key + '"');
23658 const missingBranch = (path, branches, branch) => nu(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
23659 const custom = (path, err) => nu(path, constant(err));
23660
23661 const chooseFrom = (path, input, branches, ch) => {
23662 const fields = get$a(branches, ch);
23663 return fields.fold(() => missingBranch(path, branches, ch), vp => vp.extract(path.concat(['branch: ' + ch]), input));
23664 };
23665 const choose$1 = (key, branches) => {
23666 const extract = (path, input) => {
23667 const choice = get$a(input, key);
23668 return choice.fold(() => missingKey(path, key), chosen => chooseFrom(path, input, branches, chosen));
23669 };
23670 const toString = () => 'chooseOn(' + key + '). Possible values: ' + keys(branches);
23671 return {
23672 extract,
23673 toString
23674 };
23675 };
23676
23677 const shallow = (old, nu) => {
23678 return nu;
23679 };
23680 const deep = (old, nu) => {
23681 const bothObjects = isPlainObject(old) && isPlainObject(nu);
23682 return bothObjects ? deepMerge(old, nu) : nu;
23683 };
23684 const baseMerge = merger => {
23685 return (...objects) => {
23686 if (objects.length === 0) {
23687 throw new Error(`Can't merge zero objects`);
23688 }
23689 const ret = {};
23690 for (let j = 0; j < objects.length; j++) {
23691 const curObject = objects[j];
23692 for (const key in curObject) {
23693 if (has$2(curObject, key)) {
23694 ret[key] = merger(ret[key], curObject[key]);
23695 }
23696 }
23697 }
23698 return ret;
23699 };
23700 };
23701 const deepMerge = baseMerge(deep);
23702 const merge = baseMerge(shallow);
23703
23704 const required = () => ({
23705 tag: 'required',
23706 process: {}
23707 });
23708 const defaultedThunk = fallbackThunk => ({
23709 tag: 'defaultedThunk',
23710 process: fallbackThunk
23711 });
23712 const defaulted$1 = fallback => defaultedThunk(constant(fallback));
23713 const asOption = () => ({
23714 tag: 'option',
23715 process: {}
23716 });
23717
23718 const mergeValues = (values, base) => values.length > 0 ? SimpleResult.svalue(deepMerge(base, merge.apply(undefined, values))) : SimpleResult.svalue(base);
23719 const mergeErrors = errors => compose(SimpleResult.serror, flatten)(errors);
23720 const consolidateObj = (objects, base) => {
23721 const partition = SimpleResult.partition(objects);
23722 return partition.errors.length > 0 ? mergeErrors(partition.errors) : mergeValues(partition.values, base);
23723 };
23724 const consolidateArr = objects => {
23725 const partitions = SimpleResult.partition(objects);
23726 return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : SimpleResult.svalue(partitions.values);
23727 };
23728 const ResultCombine = {
23729 consolidateObj,
23730 consolidateArr
23731 };
23732
23733 const field$1 = (key, newKey, presence, prop) => ({
23734 tag: 'field',
23735 key,
23736 newKey,
23737 presence,
23738 prop
23739 });
23740 const customField$1 = (newKey, instantiator) => ({
23741 tag: 'custom',
23742 newKey,
23743 instantiator
23744 });
23745 const fold = (value, ifField, ifCustom) => {
23746 switch (value.tag) {
23747 case 'field':
23748 return ifField(value.key, value.newKey, value.presence, value.prop);
23749 case 'custom':
23750 return ifCustom(value.newKey, value.instantiator);
23751 }
23752 };
23753
23754 const value = validator => {
23755 const extract = (path, val) => {
23756 return SimpleResult.bindError(validator(val), err => custom(path, err));
23757 };
23758 const toString = constant('val');
23759 return {
23760 extract,
23761 toString
23762 };
23763 };
23764 const anyValue$1 = value(SimpleResult.svalue);
23765
23766 const requiredAccess = (path, obj, key, bundle) => get$a(obj, key).fold(() => missingRequired(path, key, obj), bundle);
23767 const fallbackAccess = (obj, key, fallback, bundle) => {
23768 const v = get$a(obj, key).getOrThunk(() => fallback(obj));
23769 return bundle(v);
23770 };
23771 const optionAccess = (obj, key, bundle) => bundle(get$a(obj, key));
23772 const optionDefaultedAccess = (obj, key, fallback, bundle) => {
23773 const opt = get$a(obj, key).map(val => val === true ? fallback(obj) : val);
23774 return bundle(opt);
23775 };
23776 const extractField = (field, path, obj, key, prop) => {
23777 const bundle = av => prop.extract(path.concat([key]), av);
23778 const bundleAsOption = optValue => optValue.fold(() => SimpleResult.svalue(Optional.none()), ov => {
23779 const result = prop.extract(path.concat([key]), ov);
23780 return SimpleResult.map(result, Optional.some);
23781 });
23782 switch (field.tag) {
23783 case 'required':
23784 return requiredAccess(path, obj, key, bundle);
23785 case 'defaultedThunk':
23786 return fallbackAccess(obj, key, field.process, bundle);
23787 case 'option':
23788 return optionAccess(obj, key, bundleAsOption);
23789 case 'defaultedOptionThunk':
23790 return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
23791 case 'mergeWithThunk': {
23792 return fallbackAccess(obj, key, constant({}), v => {
23793 const result = deepMerge(field.process(obj), v);
23794 return bundle(result);
23795 });
23796 }
23797 }
23798 };
23799 const extractFields = (path, obj, fields) => {
23800 const success = {};
23801 const errors = [];
23802 for (const field of fields) {
23803 fold(field, (key, newKey, presence, prop) => {
23804 const result = extractField(presence, path, obj, key, prop);
23805 SimpleResult.fold(result, err => {
23806 errors.push(...err);
23807 }, res => {
23808 success[newKey] = res;
23809 });
23810 }, (newKey, instantiator) => {
23811 success[newKey] = instantiator(obj);
23812 });
23813 }
23814 return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
23815 };
23816 const objOf = values => {
23817 const extract = (path, o) => extractFields(path, o, values);
23818 const toString = () => {
23819 const fieldStrings = map$3(values, value => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
23820 return 'obj{\n' + fieldStrings.join('\n') + '}';
23821 };
23822 return {
23823 extract,
23824 toString
23825 };
23826 };
23827 const arrOf = prop => {
23828 const extract = (path, array) => {
23829 const results = map$3(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
23830 return ResultCombine.consolidateArr(results);
23831 };
23832 const toString = () => 'array(' + prop.toString() + ')';
23833 return {
23834 extract,
23835 toString
23836 };
23837 };
23838
23839 const valueOf = validator => value(v => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
23840 const extractValue = (label, prop, obj) => {
23841 const res = prop.extract([label], obj);
23842 return SimpleResult.mapError(res, errs => ({
23843 input: obj,
23844 errors: errs
23845 }));
23846 };
23847 const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
23848 const formatError = errInfo => {
23849 return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input);
23850 };
23851 const choose = (key, branches) => choose$1(key, map$2(branches, objOf));
23852
23853 const anyValue = constant(anyValue$1);
23854 const typedValue = (validator, expectedType) => value(a => {
23855 const actualType = typeof a;
23856 return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${ expectedType } but got: ${ actualType }`);
23857 });
23858 const number = typedValue(isNumber, 'number');
23859 const string = typedValue(isString, 'string');
23860 const boolean = typedValue(isBoolean, 'boolean');
23861 const functionProcessor = typedValue(isFunction, 'function');
23862
23863 const field = field$1;
23864 const customField = customField$1;
23865 const validateEnum = values => valueOf(value => contains$2(values, value) ? Result.value(value) : Result.error(`Unsupported value: "${ value }", choose one of "${ values.join(', ') }".`));
23866 const requiredOf = (key, schema) => field(key, key, required(), schema);
23867 const requiredString = key => requiredOf(key, string);
23868 const requiredFunction = key => requiredOf(key, functionProcessor);
23869 const requiredArrayOf = (key, schema) => field(key, key, required(), arrOf(schema));
23870 const optionOf = (key, schema) => field(key, key, asOption(), schema);
23871 const optionString = key => optionOf(key, string);
23872 const optionFunction = key => optionOf(key, functionProcessor);
23873 const defaulted = (key, fallback) => field(key, key, defaulted$1(fallback), anyValue());
23874 const defaultedOf = (key, fallback, schema) => field(key, key, defaulted$1(fallback), schema);
23875 const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
23876 const defaultedString = (key, fallback) => defaultedOf(key, fallback, string);
23877 const defaultedStringEnum = (key, fallback, values) => defaultedOf(key, fallback, validateEnum(values));
23878 const defaultedBoolean = (key, fallback) => defaultedOf(key, fallback, boolean);
23879 const defaultedFunction = (key, fallback) => defaultedOf(key, fallback, functionProcessor);
23880 const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
23881
23882 const type = requiredString('type');
23883 const fetch$1 = requiredFunction('fetch');
23884 const onAction = requiredFunction('onAction');
23885 const onSetup = defaultedFunction('onSetup', () => noop);
23886 const optionalText = optionString('text');
23887 const optionalIcon = optionString('icon');
23888 const optionalTooltip = optionString('tooltip');
23889 const optionalLabel = optionString('label');
23890 const active = defaultedBoolean('active', false);
23891 const enabled = defaultedBoolean('enabled', true);
23892 const primary = defaultedBoolean('primary', false);
23893 const defaultedColumns = num => defaulted('columns', num);
23894 const defaultedType = type => defaultedString('type', type);
23895
23896 const autocompleterSchema = objOf([
23897 type,
23898 requiredString('trigger'),
23899 defaultedNumber('minChars', 1),
23900 defaultedColumns(1),
23901 defaultedNumber('maxResults', 10),
23902 optionFunction('matches'),
23903 fetch$1,
23904 onAction,
23905 defaultedArrayOf('highlightOn', [], string)
23906 ]);
23907 const createAutocompleter = spec => asRaw('Autocompleter', autocompleterSchema, spec);
23908
23909 const baseToolbarButtonFields = [
23910 enabled,
23911 optionalTooltip,
23912 optionalIcon,
23913 optionalText,
23914 onSetup
23915 ];
23916
23917 const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
23918
23919 const contextBarFields = [
23920 defaultedFunction('predicate', never),
23921 defaultedStringEnum('scope', 'node', [
23922 'node',
23923 'editor'
23924 ]),
23925 defaultedStringEnum('position', 'selection', [
23926 'node',
23927 'selection',
23928 'line'
23929 ])
23930 ];
23931
23932 const contextButtonFields = baseToolbarButtonFields.concat([
23933 defaultedType('contextformbutton'),
23934 primary,
23935 onAction,
23936 customField('original', identity)
23937 ]);
23938 const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
23939 defaultedType('contextformbutton'),
23940 primary,
23941 onAction,
23942 customField('original', identity)
23943 ]);
23944 const launchButtonFields = baseToolbarButtonFields.concat([defaultedType('contextformbutton')]);
23945 const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType('contextformtogglebutton')]);
23946 const toggleOrNormal = choose('type', {
23947 contextformbutton: contextButtonFields,
23948 contextformtogglebutton: contextToggleButtonFields
23949 });
23950 objOf([
23951 defaultedType('contextform'),
23952 defaultedFunction('initValue', constant('')),
23953 optionalLabel,
23954 requiredArrayOf('commands', toggleOrNormal),
23955 optionOf('launch', choose('type', {
23956 contextformbutton: launchButtonFields,
23957 contextformtogglebutton: launchToggleButtonFields
23958 }))
23959 ].concat(contextBarFields));
23960
23961 const register$2 = editor => {
23962 const popups = editor.ui.registry.getAll().popups;
23963 const dataset = map$2(popups, popup => createAutocompleter(popup).fold(err => {
23964 throw new Error(formatError(err));
23965 }, identity));
23966 const triggers = stringArray(mapToArray(dataset, v => v.trigger));
23967 const datasetValues = values(dataset);
23968 const lookupByTrigger = trigger => filter$5(datasetValues, dv => dv.trigger === trigger);
23969 return {
23970 dataset,
23971 triggers,
23972 lookupByTrigger
23973 };
23974 };
23975
23976 const setupEditorInput = (editor, api) => {
23977 const update = last(api.load, 50);
23978 editor.on('input', e => {
23979 if (e.inputType === 'insertCompositionText' && !editor.composing) {
23980 return;
23981 }
23982 update.throttle();
23983 });
23984 editor.on('keydown', e => {
23985 const keyCode = e.which;
23986 if (keyCode === 8) {
23987 update.throttle();
23988 } else if (keyCode === 27) {
23989 update.cancel();
23990 api.cancelIfNecessary();
23991 } else if (keyCode === 38 || keyCode === 40) {
23992 update.cancel();
23993 }
23994 }, true);
23995 editor.on('remove', update.cancel);
23996 };
23997 const setup$k = editor => {
23998 const activeAutocompleter = value$2();
23999 const uiActive = Cell(false);
24000 const isActive = activeAutocompleter.isSet;
24001 const cancelIfNecessary = () => {
24002 if (isActive()) {
24003 fireAutocompleterEnd(editor);
24004 uiActive.set(false);
24005 activeAutocompleter.clear();
24006 }
24007 };
24008 const commenceIfNecessary = context => {
24009 if (!isActive()) {
24010 activeAutocompleter.set({
24011 trigger: context.trigger,
24012 matchLength: context.text.length
24013 });
24014 }
24015 };
24016 const getAutocompleters = cached(() => register$2(editor));
24017 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));
24018 const load = fetchOptions => {
24019 doLookup(fetchOptions).fold(cancelIfNecessary, lookupInfo => {
24020 commenceIfNecessary(lookupInfo.context);
24021 lookupInfo.lookupData.then(lookupData => {
24022 activeAutocompleter.get().map(ac => {
24023 const context = lookupInfo.context;
24024 if (ac.trigger !== context.trigger) {
24025 return;
24026 }
24027 activeAutocompleter.set({
24028 ...ac,
24029 matchLength: context.text.length
24030 });
24031 if (uiActive.get()) {
24032 fireAutocompleterUpdateActiveRange(editor, { range: context.range });
24033 fireAutocompleterUpdate(editor, { lookupData });
24034 } else {
24035 uiActive.set(true);
24036 fireAutocompleterUpdateActiveRange(editor, { range: context.range });
24037 fireAutocompleterStart(editor, { lookupData });
24038 }
24039 });
24040 });
24041 });
24042 };
24043 const isRangeInsideOrEqual = (innerRange, outerRange) => {
24044 const startComparison = innerRange.compareBoundaryPoints(window.Range.START_TO_START, outerRange);
24045 const endComparison = innerRange.compareBoundaryPoints(window.Range.END_TO_END, outerRange);
24046 return startComparison >= 0 && endComparison <= 0;
24047 };
24048 const readActiveRange = () => {
24049 return activeAutocompleter.get().bind(({trigger}) => {
24050 const selRange = editor.selection.getRng();
24051 return getContext(editor.dom, selRange, trigger, uiActive.get()).filter(({range}) => isRangeInsideOrEqual(selRange, range)).map(({range}) => range);
24052 });
24053 };
24054 editor.addCommand('mceAutocompleterReload', (_ui, value) => {
24055 const fetchOptions = isObject(value) ? value.fetchOptions : {};
24056 load(fetchOptions);
24057 });
24058 editor.addCommand('mceAutocompleterClose', cancelIfNecessary);
24059 editor.addCommand('mceAutocompleterRefreshActiveRange', () => {
24060 readActiveRange().each(range => {
24061 fireAutocompleterUpdateActiveRange(editor, { range });
24062 });
24063 });
24064 editor.editorCommands.addQueryStateHandler('mceAutoCompleterInRange', () => readActiveRange().isSome());
24065 setupEditorInput(editor, {
24066 cancelIfNecessary,
24067 load
24068 });
24069 };
24070
24071 const browser$1 = detect$1().browser;
24072 const isSafari = browser$1.isSafari();
24073 const emptyNodeContents = node => fillWithPaddingBr(SugarElement.fromDom(node));
24074 const isEntireNodeSelected = (rng, node) => {
24075 var _a;
24076 return rng.startOffset === 0 && rng.endOffset === ((_a = node.textContent) === null || _a === void 0 ? void 0 : _a.length);
24077 };
24078 const getParentDetailsElementAtPos = (dom, pos) => Optional.from(dom.getParent(pos.container(), 'details'));
24079 const isInDetailsElement = (dom, pos) => getParentDetailsElementAtPos(dom, pos).isSome();
24080 const getDetailsElements = (dom, rng) => {
24081 const startDetails = Optional.from(dom.getParent(rng.startContainer, 'details'));
24082 const endDetails = Optional.from(dom.getParent(rng.endContainer, 'details'));
24083 if (startDetails.isSome() || endDetails.isSome()) {
24084 const startSummary = startDetails.bind(details => Optional.from(dom.select('summary', details)[0]));
24085 return Optional.some({
24086 startSummary,
24087 startDetails,
24088 endDetails
24089 });
24090 } else {
24091 return Optional.none();
24092 }
24093 };
24094 const isCaretInTheBeginningOf = (caretPos, element) => firstPositionIn(element).exists(pos => pos.isEqual(caretPos));
24095 const isCaretInTheEndOf = (caretPos, element) => {
24096 return lastPositionIn(element).exists(pos => {
24097 if (isBr$6(pos.getNode())) {
24098 return prevPosition(element, pos).exists(pos2 => pos2.isEqual(caretPos)) || pos.isEqual(caretPos);
24099 } else {
24100 return pos.isEqual(caretPos);
24101 }
24102 });
24103 };
24104 const isCaretAtStartOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheBeginningOf(caretPos, summary));
24105 const isCaretAtEndOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheEndOf(caretPos, summary));
24106 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()))));
24107 const isCaretInLastPositionInBody = (root, caretPos, detailsElements) => detailsElements.startDetails.exists(details => nextPosition(root, caretPos).forall(pos => !details.contains(pos.container())));
24108 const setCaretToPosition = (editor, position) => {
24109 const node = position.getNode();
24110 if (!isUndefined(node)) {
24111 editor.selection.setCursorLocation(node, position.offset());
24112 }
24113 };
24114 const moveCaretToDetailsPos = (editor, pos, forward) => {
24115 const details = editor.dom.getParent(pos.container(), 'details');
24116 if (details && !details.open) {
24117 const summary = editor.dom.select('summary', details)[0];
24118 if (summary) {
24119 const newPos = forward ? firstPositionIn(summary) : lastPositionIn(summary);
24120 newPos.each(pos => setCaretToPosition(editor, pos));
24121 }
24122 } else {
24123 setCaretToPosition(editor, pos);
24124 }
24125 };
24126 const isPartialDelete = (rng, detailsElements) => {
24127 const containsStart = element => element.contains(rng.startContainer);
24128 const containsEnd = element => element.contains(rng.endContainer);
24129 const startInSummary = detailsElements.startSummary.exists(containsStart);
24130 const endInSummary = detailsElements.startSummary.exists(containsEnd);
24131 const isPartiallySelectedDetailsElements = detailsElements.startDetails.forall(startDetails => detailsElements.endDetails.forall(endDetails => startDetails !== endDetails));
24132 const isInPartiallySelectedSummary = (startInSummary || endInSummary) && !(startInSummary && endInSummary);
24133 return isInPartiallySelectedSummary || isPartiallySelectedDetailsElements;
24134 };
24135 const shouldPreventDeleteIntoDetails = (editor, forward, granularity) => {
24136 const {dom, selection} = editor;
24137 const root = editor.getBody();
24138 if (granularity === 'character') {
24139 const caretPos = CaretPosition.fromRangeStart(selection.getRng());
24140 const parentBlock = dom.getParent(caretPos.container(), dom.isBlock);
24141 const parentDetailsAtCaret = getParentDetailsElementAtPos(dom, caretPos);
24142 const inEmptyParentBlock = parentBlock && dom.isEmpty(parentBlock);
24143 const isFirstBlock = isNull(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.previousSibling);
24144 const isLastBlock = isNull(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.nextSibling);
24145 if (inEmptyParentBlock) {
24146 const firstOrLast = forward ? isLastBlock : isFirstBlock;
24147 if (firstOrLast) {
24148 const isBeforeAfterDetails = navigate(!forward, root, caretPos).exists(pos => {
24149 return isInDetailsElement(dom, pos) && !equals(parentDetailsAtCaret, getParentDetailsElementAtPos(dom, pos));
24150 });
24151 if (isBeforeAfterDetails) {
24152 return true;
24153 }
24154 }
24155 }
24156 return navigate(forward, root, caretPos).fold(never, pos => {
24157 const parentDetailsAtNewPos = getParentDetailsElementAtPos(dom, pos);
24158 if (isInDetailsElement(dom, pos) && !equals(parentDetailsAtCaret, parentDetailsAtNewPos)) {
24159 if (!forward) {
24160 moveCaretToDetailsPos(editor, pos, false);
24161 }
24162 if (parentBlock && inEmptyParentBlock) {
24163 if (forward && isFirstBlock) {
24164 return true;
24165 } else if (!forward && isLastBlock) {
24166 return true;
24167 }
24168 moveCaretToDetailsPos(editor, pos, forward);
24169 editor.dom.remove(parentBlock);
24170 }
24171 return true;
24172 } else {
24173 return false;
24174 }
24175 });
24176 } else {
24177 return false;
24178 }
24179 };
24180 const shouldPreventDeleteSummaryAction = (editor, detailElements, forward, granularity) => {
24181 const selection = editor.selection;
24182 const rng = selection.getRng();
24183 const caretPos = CaretPosition.fromRangeStart(rng);
24184 const root = editor.getBody();
24185 if (granularity === 'selection') {
24186 return isPartialDelete(rng, detailElements);
24187 } else if (forward) {
24188 return isCaretAtEndOfSummary(caretPos, detailElements) || isCaretInLastPositionInBody(root, caretPos, detailElements);
24189 } else {
24190 return isCaretAtStartOfSummary(caretPos, detailElements) || isCaretInFirstPositionInBody(caretPos, detailElements);
24191 }
24192 };
24193 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));
24194 const handleDeleteActionSafari = (editor, forward, granularity) => {
24195 const selection = editor.selection;
24196 const node = selection.getNode();
24197 const rng = selection.getRng();
24198 const caretPos = CaretPosition.fromRangeStart(rng);
24199 if (isSummary$1(node)) {
24200 if (granularity === 'selection' && isEntireNodeSelected(rng, node) || willDeleteLastPositionInElement(forward, caretPos, node)) {
24201 emptyNodeContents(node);
24202 } else {
24203 editor.undoManager.transact(() => {
24204 const sel = selection.getSel();
24205 let {anchorNode, anchorOffset, focusNode, focusOffset} = sel !== null && sel !== void 0 ? sel : {};
24206 const applySelection = () => {
24207 if (isNonNullable(anchorNode) && isNonNullable(anchorOffset) && isNonNullable(focusNode) && isNonNullable(focusOffset)) {
24208 sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
24209 }
24210 };
24211 const updateSelection = () => {
24212 anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
24213 anchorOffset = sel === null || sel === void 0 ? void 0 : sel.anchorOffset;
24214 focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
24215 focusOffset = sel === null || sel === void 0 ? void 0 : sel.focusOffset;
24216 };
24217 const appendAllChildNodes = (from, to) => {
24218 each$e(from.childNodes, child => {
24219 if (isNode(child)) {
24220 to.appendChild(child);
24221 }
24222 });
24223 };
24224 const container = editor.dom.create('span', { 'data-mce-bogus': '1' });
24225 appendAllChildNodes(node, container);
24226 node.appendChild(container);
24227 applySelection();
24228 if (granularity === 'word' || granularity === 'line') {
24229 sel === null || sel === void 0 ? void 0 : sel.modify('extend', forward ? 'right' : 'left', granularity);
24230 }
24231 if (!selection.isCollapsed() && isEntireNodeSelected(selection.getRng(), container)) {
24232 emptyNodeContents(node);
24233 } else {
24234 editor.execCommand(forward ? 'ForwardDelete' : 'Delete');
24235 updateSelection();
24236 appendAllChildNodes(container, node);
24237 applySelection();
24238 }
24239 editor.dom.remove(container);
24240 });
24241 }
24242 return true;
24243 } else {
24244 return false;
24245 }
24246 };
24247 const backspaceDelete = (editor, forward, granularity) => shouldPreventDeleteAction(editor, forward, granularity) || isSafari && handleDeleteActionSafari(editor, forward, granularity) ? Optional.some(noop) : Optional.none();
24248
24249 const createAndFireInputEvent = eventType => (editor, inputType, specifics = {}) => {
24250 const target = editor.getBody();
24251 const overrides = {
24252 bubbles: true,
24253 composed: true,
24254 data: null,
24255 isComposing: false,
24256 detail: 0,
24257 view: null,
24258 target,
24259 currentTarget: target,
24260 eventPhase: Event.AT_TARGET,
24261 originalTarget: target,
24262 explicitOriginalTarget: target,
24263 isTrusted: false,
24264 srcElement: target,
24265 cancelable: false,
24266 preventDefault: noop,
24267 inputType
24268 };
24269 const input = clone$3(new InputEvent(eventType));
24270 return editor.dispatch(eventType, {
24271 ...input,
24272 ...overrides,
24273 ...specifics
24274 });
24275 };
24276 const fireInputEvent = createAndFireInputEvent('input');
24277 const fireBeforeInputEvent = createAndFireInputEvent('beforeinput');
24278
24279 const platform$2 = detect$1();
24280 const os = platform$2.os;
24281 const isMacOSOriOS = os.isMacOS() || os.isiOS();
24282 const browser = platform$2.browser;
24283 const isFirefox = browser.isFirefox();
24284 const executeKeydownOverride$3 = (editor, caret, evt) => {
24285 const inputType = evt.keyCode === VK.BACKSPACE ? 'deleteContentBackward' : 'deleteContentForward';
24286 const isCollapsed = editor.selection.isCollapsed();
24287 const unmodifiedGranularity = isCollapsed ? 'character' : 'selection';
24288 const getModifiedGranularity = isWord => {
24289 if (isCollapsed) {
24290 return isWord ? 'word' : 'line';
24291 } else {
24292 return 'selection';
24293 }
24294 };
24295 executeWithDelayedAction([
24296 {
24297 keyCode: VK.BACKSPACE,
24298 action: action(backspaceDelete$1, editor)
24299 },
24300 {
24301 keyCode: VK.BACKSPACE,
24302 action: action(backspaceDelete$6, editor, false)
24303 },
24304 {
24305 keyCode: VK.DELETE,
24306 action: action(backspaceDelete$6, editor, true)
24307 },
24308 {
24309 keyCode: VK.BACKSPACE,
24310 action: action(backspaceDelete$7, editor, false)
24311 },
24312 {
24313 keyCode: VK.DELETE,
24314 action: action(backspaceDelete$7, editor, true)
24315 },
24316 {
24317 keyCode: VK.BACKSPACE,
24318 action: action(backspaceDelete$4, editor, caret, false)
24319 },
24320 {
24321 keyCode: VK.DELETE,
24322 action: action(backspaceDelete$4, editor, caret, true)
24323 },
24324 {
24325 keyCode: VK.BACKSPACE,
24326 action: action(backspaceDelete$a, editor, false)
24327 },
24328 {
24329 keyCode: VK.DELETE,
24330 action: action(backspaceDelete$a, editor, true)
24331 },
24332 {
24333 keyCode: VK.BACKSPACE,
24334 action: action(backspaceDelete, editor, false, unmodifiedGranularity)
24335 },
24336 {
24337 keyCode: VK.DELETE,
24338 action: action(backspaceDelete, editor, true, unmodifiedGranularity)
24339 },
24340 ...isMacOSOriOS ? [
24341 {
24342 keyCode: VK.BACKSPACE,
24343 altKey: true,
24344 action: action(backspaceDelete, editor, false, getModifiedGranularity(true))
24345 },
24346 {
24347 keyCode: VK.DELETE,
24348 altKey: true,
24349 action: action(backspaceDelete, editor, true, getModifiedGranularity(true))
24350 },
24351 {
24352 keyCode: VK.BACKSPACE,
24353 metaKey: true,
24354 action: action(backspaceDelete, editor, false, getModifiedGranularity(false))
24355 }
24356 ] : [
24357 {
24358 keyCode: VK.BACKSPACE,
24359 ctrlKey: true,
24360 action: action(backspaceDelete, editor, false, getModifiedGranularity(true))
24361 },
24362 {
24363 keyCode: VK.DELETE,
24364 ctrlKey: true,
24365 action: action(backspaceDelete, editor, true, getModifiedGranularity(true))
24366 }
24367 ],
24368 {
24369 keyCode: VK.BACKSPACE,
24370 action: action(backspaceDelete$5, editor, false)
24371 },
24372 {
24373 keyCode: VK.DELETE,
24374 action: action(backspaceDelete$5, editor, true)
24375 },
24376 {
24377 keyCode: VK.BACKSPACE,
24378 action: action(backspaceDelete$2, editor, false)
24379 },
24380 {
24381 keyCode: VK.DELETE,
24382 action: action(backspaceDelete$2, editor, true)
24383 },
24384 {
24385 keyCode: VK.BACKSPACE,
24386 action: action(backspaceDelete$8, editor, false)
24387 },
24388 {
24389 keyCode: VK.DELETE,
24390 action: action(backspaceDelete$8, editor, true)
24391 },
24392 {
24393 keyCode: VK.BACKSPACE,
24394 action: action(backspaceDelete$9, editor, false)
24395 },
24396 {
24397 keyCode: VK.DELETE,
24398 action: action(backspaceDelete$9, editor, true)
24399 },
24400 {
24401 keyCode: VK.BACKSPACE,
24402 action: action(backspaceDelete$3, editor, false)
24403 },
24404 {
24405 keyCode: VK.DELETE,
24406 action: action(backspaceDelete$3, editor, true)
24407 }
24408 ], evt).filter(_ => editor.selection.isEditable()).each(applyAction => {
24409 evt.preventDefault();
24410 const beforeInput = fireBeforeInputEvent(editor, inputType);
24411 if (!beforeInput.isDefaultPrevented()) {
24412 applyAction();
24413 fireInputEvent(editor, inputType);
24414 }
24415 });
24416 };
24417 const executeKeyupOverride = (editor, evt, isBackspaceKeydown) => execute([
24418 {
24419 keyCode: VK.BACKSPACE,
24420 action: action(paddEmptyElement, editor)
24421 },
24422 {
24423 keyCode: VK.DELETE,
24424 action: action(paddEmptyElement, editor)
24425 },
24426 ...isMacOSOriOS ? [
24427 {
24428 keyCode: VK.BACKSPACE,
24429 altKey: true,
24430 action: action(refreshCaret, editor)
24431 },
24432 {
24433 keyCode: VK.DELETE,
24434 altKey: true,
24435 action: action(refreshCaret, editor)
24436 },
24437 ...isBackspaceKeydown ? [{
24438 keyCode: isFirefox ? 224 : 91,
24439 action: action(refreshCaret, editor)
24440 }] : []
24441 ] : [
24442 {
24443 keyCode: VK.BACKSPACE,
24444 ctrlKey: true,
24445 action: action(refreshCaret, editor)
24446 },
24447 {
24448 keyCode: VK.DELETE,
24449 ctrlKey: true,
24450 action: action(refreshCaret, editor)
24451 }
24452 ]
24453 ], evt);
24454 const setup$j = (editor, caret) => {
24455 let isBackspaceKeydown = false;
24456 editor.on('keydown', evt => {
24457 isBackspaceKeydown = evt.keyCode === VK.BACKSPACE;
24458 if (!evt.isDefaultPrevented()) {
24459 executeKeydownOverride$3(editor, caret, evt);
24460 }
24461 });
24462 editor.on('keyup', evt => {
24463 if (!evt.isDefaultPrevented()) {
24464 executeKeyupOverride(editor, evt, isBackspaceKeydown);
24465 }
24466 isBackspaceKeydown = false;
24467 });
24468 };
24469
24470 const firstNonWhiteSpaceNodeSibling = node => {
24471 while (node) {
24472 if (isElement$6(node) || isText$b(node) && node.data && /[\r\n\s]/.test(node.data)) {
24473 return node;
24474 }
24475 node = node.nextSibling;
24476 }
24477 return null;
24478 };
24479 const moveToCaretPosition = (editor, root) => {
24480 const dom = editor.dom;
24481 const moveCaretBeforeOnEnterElementsMap = editor.schema.getMoveCaretBeforeOnEnterElements();
24482 if (!root) {
24483 return;
24484 }
24485 if (/^(LI|DT|DD)$/.test(root.nodeName)) {
24486 const firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild);
24487 if (firstChild && /^(UL|OL|DL)$/.test(firstChild.nodeName)) {
24488 root.insertBefore(dom.doc.createTextNode(nbsp), root.firstChild);
24489 }
24490 }
24491 const rng = dom.createRng();
24492 root.normalize();
24493 if (root.hasChildNodes()) {
24494 const walker = new DomTreeWalker(root, root);
24495 let lastNode = root;
24496 let node;
24497 while (node = walker.current()) {
24498 if (isText$b(node)) {
24499 rng.setStart(node, 0);
24500 rng.setEnd(node, 0);
24501 break;
24502 }
24503 if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
24504 rng.setStartBefore(node);
24505 rng.setEndBefore(node);
24506 break;
24507 }
24508 lastNode = node;
24509 node = walker.next();
24510 }
24511 if (!node) {
24512 rng.setStart(lastNode, 0);
24513 rng.setEnd(lastNode, 0);
24514 }
24515 } else {
24516 if (isBr$6(root)) {
24517 if (root.nextSibling && dom.isBlock(root.nextSibling)) {
24518 rng.setStartBefore(root);
24519 rng.setEndBefore(root);
24520 } else {
24521 rng.setStartAfter(root);
24522 rng.setEndAfter(root);
24523 }
24524 } else {
24525 rng.setStart(root, 0);
24526 rng.setEnd(root, 0);
24527 }
24528 }
24529 editor.selection.setRng(rng);
24530 scrollRangeIntoView(editor, rng);
24531 };
24532 const getEditableRoot = (dom, node) => {
24533 const root = dom.getRoot();
24534 let editableRoot;
24535 let parent = node;
24536 while (parent !== root && parent && dom.getContentEditable(parent) !== 'false') {
24537 if (dom.getContentEditable(parent) === 'true') {
24538 editableRoot = parent;
24539 break;
24540 }
24541 parent = parent.parentNode;
24542 }
24543 return parent !== root ? editableRoot : root;
24544 };
24545 const getParentBlock$1 = editor => {
24546 return Optional.from(editor.dom.getParent(editor.selection.getStart(true), editor.dom.isBlock));
24547 };
24548 const getParentBlockName = editor => {
24549 return getParentBlock$1(editor).fold(constant(''), parentBlock => {
24550 return parentBlock.nodeName.toUpperCase();
24551 });
24552 };
24553 const isListItemParentBlock = editor => {
24554 return getParentBlock$1(editor).filter(elm => {
24555 return isListItem$1(SugarElement.fromDom(elm));
24556 }).isSome();
24557 };
24558 const emptyBlock = elm => {
24559 elm.innerHTML = '<br data-mce-bogus="1">';
24560 };
24561 const applyAttributes = (editor, node, forcedRootBlockAttrs) => {
24562 const dom = editor.dom;
24563 Optional.from(forcedRootBlockAttrs.style).map(dom.parseStyle).each(attrStyles => {
24564 const currentStyles = getAllRaw(SugarElement.fromDom(node));
24565 const newStyles = {
24566 ...currentStyles,
24567 ...attrStyles
24568 };
24569 dom.setStyles(node, newStyles);
24570 });
24571 const attrClassesOpt = Optional.from(forcedRootBlockAttrs.class).map(attrClasses => attrClasses.split(/\s+/));
24572 const currentClassesOpt = Optional.from(node.className).map(currentClasses => filter$5(currentClasses.split(/\s+/), clazz => clazz !== ''));
24573 lift2(attrClassesOpt, currentClassesOpt, (attrClasses, currentClasses) => {
24574 const filteredClasses = filter$5(currentClasses, clazz => !contains$2(attrClasses, clazz));
24575 const newClasses = [
24576 ...attrClasses,
24577 ...filteredClasses
24578 ];
24579 dom.setAttrib(node, 'class', newClasses.join(' '));
24580 });
24581 const appliedAttrs = [
24582 'style',
24583 'class'
24584 ];
24585 const remainingAttrs = filter$4(forcedRootBlockAttrs, (_, attrs) => !contains$2(appliedAttrs, attrs));
24586 dom.setAttribs(node, remainingAttrs);
24587 };
24588 const setForcedBlockAttrs = (editor, node) => {
24589 const forcedRootBlockName = getForcedRootBlock(editor);
24590 if (forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) {
24591 const forcedRootBlockAttrs = getForcedRootBlockAttrs(editor);
24592 applyAttributes(editor, node, forcedRootBlockAttrs);
24593 }
24594 };
24595 const createNewBlock = (editor, container, parentBlock, editableRoot, keepStyles = true, name, styles) => {
24596 const dom = editor.dom;
24597 const schema = editor.schema;
24598 const newBlockName = getForcedRootBlock(editor);
24599 const parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
24600 let node = container;
24601 const textInlineElements = schema.getTextInlineElements();
24602 let block;
24603 if (name || parentBlockName === 'TABLE' || parentBlockName === 'HR') {
24604 block = dom.create(name || newBlockName, styles || {});
24605 } else {
24606 block = parentBlock.cloneNode(false);
24607 }
24608 let caretNode = block;
24609 if (!keepStyles) {
24610 dom.setAttrib(block, 'style', null);
24611 dom.setAttrib(block, 'class', null);
24612 } else {
24613 do {
24614 if (textInlineElements[node.nodeName]) {
24615 if (isCaretNode(node) || isBookmarkNode$1(node)) {
24616 continue;
24617 }
24618 const clonedNode = node.cloneNode(false);
24619 dom.setAttrib(clonedNode, 'id', '');
24620 if (block.hasChildNodes()) {
24621 clonedNode.appendChild(block.firstChild);
24622 block.appendChild(clonedNode);
24623 } else {
24624 caretNode = clonedNode;
24625 block.appendChild(clonedNode);
24626 }
24627 }
24628 } while ((node = node.parentNode) && node !== editableRoot);
24629 }
24630 setForcedBlockAttrs(editor, block);
24631 emptyBlock(caretNode);
24632 return block;
24633 };
24634
24635 const getDetailsRoot = (editor, element) => editor.dom.getParent(element, isDetails);
24636 const isAtDetailsEdge = (root, element, isTextBlock) => {
24637 let node = element;
24638 while (node && node !== root && isNull(node.nextSibling)) {
24639 const parent = node.parentElement;
24640 if (!parent || !isTextBlock(parent)) {
24641 return isDetails(parent);
24642 }
24643 node = parent;
24644 }
24645 return false;
24646 };
24647 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()));
24648 const insertNewLine = (editor, createNewBlock, parentBlock) => {
24649 var _a, _b, _c;
24650 const newBlock = createNewBlock(getForcedRootBlock(editor));
24651 const root = getDetailsRoot(editor, parentBlock);
24652 if (!root) {
24653 return;
24654 }
24655 editor.dom.insertAfter(newBlock, root);
24656 moveToCaretPosition(editor, newBlock);
24657 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) {
24658 editor.dom.remove(parentBlock);
24659 }
24660 };
24661
24662 const hasFirstChild = (elm, name) => {
24663 return elm.firstChild && elm.firstChild.nodeName === name;
24664 };
24665 const isFirstChild = elm => {
24666 var _a;
24667 return ((_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === elm;
24668 };
24669 const hasParent = (elm, parentName) => {
24670 const parentNode = elm === null || elm === void 0 ? void 0 : elm.parentNode;
24671 return isNonNullable(parentNode) && parentNode.nodeName === parentName;
24672 };
24673 const isListBlock = elm => {
24674 return isNonNullable(elm) && /^(OL|UL|LI)$/.test(elm.nodeName);
24675 };
24676 const isListItem = elm => {
24677 return isNonNullable(elm) && /^(LI|DT|DD)$/.test(elm.nodeName);
24678 };
24679 const isNestedList = elm => {
24680 return isListBlock(elm) && isListBlock(elm.parentNode);
24681 };
24682 const getContainerBlock = containerBlock => {
24683 const containerBlockParent = containerBlock.parentNode;
24684 return isListItem(containerBlockParent) ? containerBlockParent : containerBlock;
24685 };
24686 const isFirstOrLastLi = (containerBlock, parentBlock, first) => {
24687 let node = containerBlock[first ? 'firstChild' : 'lastChild'];
24688 while (node) {
24689 if (isElement$6(node)) {
24690 break;
24691 }
24692 node = node[first ? 'nextSibling' : 'previousSibling'];
24693 }
24694 return node === parentBlock;
24695 };
24696 const getStyles = elm => foldl(mapToArray(getAllRaw(SugarElement.fromDom(elm)), (style, styleName) => `${ styleName }: ${ style };`), (acc, s) => acc + s, '');
24697 const insert$4 = (editor, createNewBlock, containerBlock, parentBlock, newBlockName) => {
24698 const dom = editor.dom;
24699 const rng = editor.selection.getRng();
24700 const containerParent = containerBlock.parentNode;
24701 if (containerBlock === editor.getBody() || !containerParent) {
24702 return;
24703 }
24704 if (isNestedList(containerBlock)) {
24705 newBlockName = 'LI';
24706 }
24707 const parentBlockStyles = isListItem(parentBlock) ? getStyles(parentBlock) : undefined;
24708 let newBlock = isListItem(parentBlock) && parentBlockStyles ? createNewBlock(newBlockName, { style: getStyles(parentBlock) }) : createNewBlock(newBlockName);
24709 if (isFirstOrLastLi(containerBlock, parentBlock, true) && isFirstOrLastLi(containerBlock, parentBlock, false)) {
24710 if (hasParent(containerBlock, 'LI')) {
24711 const containerBlockParent = getContainerBlock(containerBlock);
24712 dom.insertAfter(newBlock, containerBlockParent);
24713 if (isFirstChild(containerBlock)) {
24714 dom.remove(containerBlockParent);
24715 } else {
24716 dom.remove(containerBlock);
24717 }
24718 } else {
24719 dom.replace(newBlock, containerBlock);
24720 }
24721 } else if (isFirstOrLastLi(containerBlock, parentBlock, true)) {
24722 if (hasParent(containerBlock, 'LI')) {
24723 dom.insertAfter(newBlock, getContainerBlock(containerBlock));
24724 newBlock.appendChild(dom.doc.createTextNode(' '));
24725 newBlock.appendChild(containerBlock);
24726 } else {
24727 containerParent.insertBefore(newBlock, containerBlock);
24728 }
24729 dom.remove(parentBlock);
24730 } else if (isFirstOrLastLi(containerBlock, parentBlock, false)) {
24731 dom.insertAfter(newBlock, getContainerBlock(containerBlock));
24732 dom.remove(parentBlock);
24733 } else {
24734 containerBlock = getContainerBlock(containerBlock);
24735 const tmpRng = rng.cloneRange();
24736 tmpRng.setStartAfter(parentBlock);
24737 tmpRng.setEndAfter(containerBlock);
24738 const fragment = tmpRng.extractContents();
24739 if (newBlockName === 'LI' && hasFirstChild(fragment, 'LI')) {
24740 const previousChildren = filter$5(map$3(newBlock.children, SugarElement.fromDom), not(isTag('br')));
24741 newBlock = fragment.firstChild;
24742 dom.insertAfter(fragment, containerBlock);
24743 each$e(previousChildren, child => prepend(SugarElement.fromDom(newBlock), child));
24744 if (parentBlockStyles) {
24745 newBlock.setAttribute('style', parentBlockStyles);
24746 }
24747 } else {
24748 dom.insertAfter(fragment, containerBlock);
24749 dom.insertAfter(newBlock, containerBlock);
24750 }
24751 dom.remove(parentBlock);
24752 }
24753 moveToCaretPosition(editor, newBlock);
24754 };
24755
24756 const trimZwsp = fragment => {
24757 each$e(descendants$1(SugarElement.fromDom(fragment), isText$c), text => {
24758 const rawNode = text.dom;
24759 rawNode.nodeValue = trim$2(rawNode.data);
24760 });
24761 };
24762 const isWithinNonEditableList = (editor, node) => {
24763 const parentList = editor.dom.getParent(node, 'ol,ul,dl');
24764 return parentList !== null && editor.dom.getContentEditableParent(parentList) === 'false';
24765 };
24766 const isEmptyAnchor = (dom, elm) => {
24767 return elm && elm.nodeName === 'A' && dom.isEmpty(elm);
24768 };
24769 const containerAndSiblingName = (container, nodeName) => {
24770 return container.nodeName === nodeName || container.previousSibling && container.previousSibling.nodeName === nodeName;
24771 };
24772 const canSplitBlock = (dom, node) => {
24773 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';
24774 };
24775 const trimInlineElementsOnLeftSideOfBlock = (dom, nonEmptyElementsMap, block) => {
24776 var _a;
24777 const firstChilds = [];
24778 if (!block) {
24779 return;
24780 }
24781 let currentNode = block;
24782 while (currentNode = currentNode.firstChild) {
24783 if (dom.isBlock(currentNode)) {
24784 return;
24785 }
24786 if (isElement$6(currentNode) && !nonEmptyElementsMap[currentNode.nodeName.toLowerCase()]) {
24787 firstChilds.push(currentNode);
24788 }
24789 }
24790 let i = firstChilds.length;
24791 while (i--) {
24792 currentNode = firstChilds[i];
24793 if (!currentNode.hasChildNodes() || currentNode.firstChild === currentNode.lastChild && ((_a = currentNode.firstChild) === null || _a === void 0 ? void 0 : _a.nodeValue) === '') {
24794 dom.remove(currentNode);
24795 } else {
24796 if (isEmptyAnchor(dom, currentNode)) {
24797 dom.remove(currentNode);
24798 }
24799 }
24800 }
24801 };
24802 const normalizeZwspOffset = (start, container, offset) => {
24803 if (!isText$b(container)) {
24804 return offset;
24805 } else if (start) {
24806 return offset === 1 && container.data.charAt(offset - 1) === ZWSP$1 ? 0 : offset;
24807 } else {
24808 return offset === container.data.length - 1 && container.data.charAt(offset) === ZWSP$1 ? container.data.length : offset;
24809 }
24810 };
24811 const includeZwspInRange = rng => {
24812 const newRng = rng.cloneRange();
24813 newRng.setStart(rng.startContainer, normalizeZwspOffset(true, rng.startContainer, rng.startOffset));
24814 newRng.setEnd(rng.endContainer, normalizeZwspOffset(false, rng.endContainer, rng.endOffset));
24815 return newRng;
24816 };
24817 const trimLeadingLineBreaks = node => {
24818 let currentNode = node;
24819 do {
24820 if (isText$b(currentNode)) {
24821 currentNode.data = currentNode.data.replace(/^[\r\n]+/, '');
24822 }
24823 currentNode = currentNode.firstChild;
24824 } while (currentNode);
24825 };
24826 const wrapSelfAndSiblingsInDefaultBlock = (editor, newBlockName, rng, container, offset) => {
24827 var _a, _b;
24828 const dom = editor.dom;
24829 const editableRoot = (_a = getEditableRoot(dom, container)) !== null && _a !== void 0 ? _a : dom.getRoot();
24830 let parentBlock = dom.getParent(container, dom.isBlock);
24831 if (!parentBlock || !canSplitBlock(dom, parentBlock)) {
24832 parentBlock = parentBlock || editableRoot;
24833 if (!parentBlock.hasChildNodes()) {
24834 const newBlock = dom.create(newBlockName);
24835 setForcedBlockAttrs(editor, newBlock);
24836 parentBlock.appendChild(newBlock);
24837 rng.setStart(newBlock, 0);
24838 rng.setEnd(newBlock, 0);
24839 return newBlock;
24840 }
24841 let node = container;
24842 while (node && node.parentNode !== parentBlock) {
24843 node = node.parentNode;
24844 }
24845 let startNode;
24846 while (node && !dom.isBlock(node)) {
24847 startNode = node;
24848 node = node.previousSibling;
24849 }
24850 const startNodeName = (_b = startNode === null || startNode === void 0 ? void 0 : startNode.parentElement) === null || _b === void 0 ? void 0 : _b.nodeName;
24851 if (startNode && startNodeName && editor.schema.isValidChild(startNodeName, newBlockName.toLowerCase())) {
24852 const startNodeParent = startNode.parentNode;
24853 const newBlock = dom.create(newBlockName);
24854 setForcedBlockAttrs(editor, newBlock);
24855 startNodeParent.insertBefore(newBlock, startNode);
24856 node = startNode;
24857 while (node && !dom.isBlock(node)) {
24858 const next = node.nextSibling;
24859 newBlock.appendChild(node);
24860 node = next;
24861 }
24862 rng.setStart(container, offset);
24863 rng.setEnd(container, offset);
24864 }
24865 }
24866 return container;
24867 };
24868 const addBrToBlockIfNeeded = (dom, block) => {
24869 block.normalize();
24870 const lastChild = block.lastChild;
24871 if (!lastChild || isElement$6(lastChild) && /^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true))) {
24872 dom.add(block, 'br');
24873 }
24874 };
24875 const shouldEndContainer = (editor, container) => {
24876 const optionValue = shouldEndContainerOnEmptyBlock(editor);
24877 if (isNullable(container)) {
24878 return false;
24879 } else if (isString(optionValue)) {
24880 return contains$2(Tools.explode(optionValue), container.nodeName.toLowerCase());
24881 } else {
24882 return optionValue;
24883 }
24884 };
24885 const insert$3 = (editor, evt) => {
24886 let container;
24887 let offset;
24888 let parentBlockName;
24889 let containerBlock;
24890 let isAfterLastNodeInContainer = false;
24891 const dom = editor.dom;
24892 const schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
24893 const rng = editor.selection.getRng();
24894 const newBlockName = getForcedRootBlock(editor);
24895 const start = SugarElement.fromDom(rng.startContainer);
24896 const child = child$1(start, rng.startOffset);
24897 const isCef = child.exists(element => isHTMLElement$1(element) && !isEditable$2(element));
24898 const collapsedAndCef = rng.collapsed && isCef;
24899 const createNewBlock$1 = (name, styles) => {
24900 return createNewBlock(editor, container, parentBlock, editableRoot, shouldKeepStyles(editor), name, styles);
24901 };
24902 const isCaretAtStartOrEndOfBlock = start => {
24903 const normalizedOffset = normalizeZwspOffset(start, container, offset);
24904 if (isText$b(container) && (start ? normalizedOffset > 0 : normalizedOffset < container.data.length)) {
24905 return false;
24906 }
24907 if ((container.parentNode === parentBlock || container === parentBlock) && isAfterLastNodeInContainer && !start) {
24908 return true;
24909 }
24910 if (start && isElement$6(container) && container === parentBlock.firstChild) {
24911 return true;
24912 }
24913 if (containerAndSiblingName(container, 'TABLE') || containerAndSiblingName(container, 'HR')) {
24914 return isAfterLastNodeInContainer && !start || !isAfterLastNodeInContainer && start;
24915 }
24916 const walker = new DomTreeWalker(container, parentBlock);
24917 if (isText$b(container)) {
24918 if (start && normalizedOffset === 0) {
24919 walker.prev();
24920 } else if (!start && normalizedOffset === container.data.length) {
24921 walker.next();
24922 }
24923 }
24924 let node;
24925 while (node = walker.current()) {
24926 if (isElement$6(node)) {
24927 if (!node.getAttribute('data-mce-bogus')) {
24928 const name = node.nodeName.toLowerCase();
24929 if (nonEmptyElementsMap[name] && name !== 'br') {
24930 return false;
24931 }
24932 }
24933 } else if (isText$b(node) && !isWhitespaceText(node.data)) {
24934 return false;
24935 }
24936 if (start) {
24937 walker.prev();
24938 } else {
24939 walker.next();
24940 }
24941 }
24942 return true;
24943 };
24944 const insertNewBlockAfter = () => {
24945 let block;
24946 if (/^(H[1-6]|PRE|FIGURE)$/.test(parentBlockName) && containerBlockName !== 'HGROUP') {
24947 block = createNewBlock$1(newBlockName);
24948 } else {
24949 block = createNewBlock$1();
24950 }
24951 if (shouldEndContainer(editor, containerBlock) && canSplitBlock(dom, containerBlock) && dom.isEmpty(parentBlock, undefined, { includeZwsp: true })) {
24952 block = dom.split(containerBlock, parentBlock);
24953 } else {
24954 dom.insertAfter(block, parentBlock);
24955 }
24956 moveToCaretPosition(editor, block);
24957 return block;
24958 };
24959 normalize$2(dom, rng).each(normRng => {
24960 rng.setStart(normRng.startContainer, normRng.startOffset);
24961 rng.setEnd(normRng.endContainer, normRng.endOffset);
24962 });
24963 container = rng.startContainer;
24964 offset = rng.startOffset;
24965 const shiftKey = !!(evt && evt.shiftKey);
24966 const ctrlKey = !!(evt && evt.ctrlKey);
24967 if (isElement$6(container) && container.hasChildNodes() && !collapsedAndCef) {
24968 isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
24969 container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
24970 if (isAfterLastNodeInContainer && isText$b(container)) {
24971 offset = container.data.length;
24972 } else {
24973 offset = 0;
24974 }
24975 }
24976 const editableRoot = getEditableRoot(dom, container);
24977 if (!editableRoot || isWithinNonEditableList(editor, container)) {
24978 return;
24979 }
24980 if (!shiftKey) {
24981 container = wrapSelfAndSiblingsInDefaultBlock(editor, newBlockName, rng, container, offset);
24982 }
24983 let parentBlock = dom.getParent(container, dom.isBlock) || dom.getRoot();
24984 containerBlock = isNonNullable(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.parentNode) ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
24985 parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
24986 const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
24987 if (containerBlockName === 'LI' && !ctrlKey) {
24988 const liBlock = containerBlock;
24989 parentBlock = liBlock;
24990 containerBlock = liBlock.parentNode;
24991 parentBlockName = containerBlockName;
24992 }
24993 if (isElement$6(containerBlock) && isLastEmptyBlockInDetails(editor, shiftKey, parentBlock)) {
24994 return insertNewLine(editor, createNewBlock$1, parentBlock);
24995 }
24996 if (/^(LI|DT|DD)$/.test(parentBlockName) && isElement$6(containerBlock)) {
24997 if (dom.isEmpty(parentBlock)) {
24998 insert$4(editor, createNewBlock$1, containerBlock, parentBlock, newBlockName);
24999 return;
25000 }
25001 }
25002 if (!collapsedAndCef && (parentBlock === editor.getBody() || !canSplitBlock(dom, parentBlock))) {
25003 return;
25004 }
25005 const parentBlockParent = parentBlock.parentNode;
25006 let newBlock;
25007 if (collapsedAndCef) {
25008 newBlock = createNewBlock$1(newBlockName);
25009 child.fold(() => {
25010 append$1(start, SugarElement.fromDom(newBlock));
25011 }, child => {
25012 before$3(child, SugarElement.fromDom(newBlock));
25013 });
25014 editor.selection.setCursorLocation(newBlock, 0);
25015 } else if (isCaretContainerBlock$1(parentBlock)) {
25016 newBlock = showCaretContainerBlock(parentBlock);
25017 if (dom.isEmpty(parentBlock)) {
25018 emptyBlock(parentBlock);
25019 }
25020 setForcedBlockAttrs(editor, newBlock);
25021 moveToCaretPosition(editor, newBlock);
25022 } else if (isCaretAtStartOrEndOfBlock(false)) {
25023 newBlock = insertNewBlockAfter();
25024 } else if (isCaretAtStartOrEndOfBlock(true) && parentBlockParent) {
25025 newBlock = parentBlockParent.insertBefore(createNewBlock$1(), parentBlock);
25026 const isNearChildren = hasChildNodes(SugarElement.fromDom(rng.startContainer)) && rng.collapsed;
25027 moveToCaretPosition(editor, containerAndSiblingName(parentBlock, 'HR') || isNearChildren ? newBlock : parentBlock);
25028 } else {
25029 const tmpRng = includeZwspInRange(rng).cloneRange();
25030 tmpRng.setEndAfter(parentBlock);
25031 const fragment = tmpRng.extractContents();
25032 trimZwsp(fragment);
25033 trimLeadingLineBreaks(fragment);
25034 newBlock = fragment.firstChild;
25035 dom.insertAfter(fragment, parentBlock);
25036 trimInlineElementsOnLeftSideOfBlock(dom, nonEmptyElementsMap, newBlock);
25037 addBrToBlockIfNeeded(dom, parentBlock);
25038 if (dom.isEmpty(parentBlock)) {
25039 emptyBlock(parentBlock);
25040 }
25041 newBlock.normalize();
25042 if (dom.isEmpty(newBlock)) {
25043 dom.remove(newBlock);
25044 insertNewBlockAfter();
25045 } else {
25046 setForcedBlockAttrs(editor, newBlock);
25047 moveToCaretPosition(editor, newBlock);
25048 }
25049 }
25050 dom.setAttrib(newBlock, 'id', '');
25051 editor.dispatch('NewBlock', { newBlock });
25052 };
25053 const fakeEventName$1 = 'insertParagraph';
25054 const blockbreak = {
25055 insert: insert$3,
25056 fakeEventName: fakeEventName$1
25057 };
25058
25059 const hasRightSideContent = (schema, container, parentBlock) => {
25060 const walker = new DomTreeWalker(container, parentBlock);
25061 let node;
25062 const nonEmptyElementsMap = schema.getNonEmptyElements();
25063 while (node = walker.next()) {
25064 if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || isText$b(node) && node.length > 0) {
25065 return true;
25066 }
25067 }
25068 return false;
25069 };
25070 const moveSelectionToBr = (editor, brElm, extraBr) => {
25071 const rng = editor.dom.createRng();
25072 if (!extraBr) {
25073 rng.setStartAfter(brElm);
25074 rng.setEndAfter(brElm);
25075 } else {
25076 rng.setStartBefore(brElm);
25077 rng.setEndBefore(brElm);
25078 }
25079 editor.selection.setRng(rng);
25080 scrollRangeIntoView(editor, rng);
25081 };
25082 const insertBrAtCaret = (editor, evt) => {
25083 const selection = editor.selection;
25084 const dom = editor.dom;
25085 const rng = selection.getRng();
25086 let brElm;
25087 let extraBr = false;
25088 normalize$2(dom, rng).each(normRng => {
25089 rng.setStart(normRng.startContainer, normRng.startOffset);
25090 rng.setEnd(normRng.endContainer, normRng.endOffset);
25091 });
25092 let offset = rng.startOffset;
25093 let container = rng.startContainer;
25094 if (isElement$6(container) && container.hasChildNodes()) {
25095 const isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
25096 container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
25097 if (isAfterLastNodeInContainer && isText$b(container)) {
25098 offset = container.data.length;
25099 } else {
25100 offset = 0;
25101 }
25102 }
25103 let parentBlock = dom.getParent(container, dom.isBlock);
25104 const containerBlock = parentBlock && parentBlock.parentNode ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
25105 const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
25106 const isControlKey = !!(evt && evt.ctrlKey);
25107 if (containerBlockName === 'LI' && !isControlKey) {
25108 parentBlock = containerBlock;
25109 }
25110 if (isText$b(container) && offset >= container.data.length) {
25111 if (!hasRightSideContent(editor.schema, container, parentBlock || dom.getRoot())) {
25112 brElm = dom.create('br');
25113 rng.insertNode(brElm);
25114 rng.setStartAfter(brElm);
25115 rng.setEndAfter(brElm);
25116 extraBr = true;
25117 }
25118 }
25119 brElm = dom.create('br');
25120 rangeInsertNode(dom, rng, brElm);
25121 moveSelectionToBr(editor, brElm, extraBr);
25122 editor.undoManager.add();
25123 };
25124 const insertBrBefore = (editor, inline) => {
25125 const br = SugarElement.fromTag('br');
25126 before$3(SugarElement.fromDom(inline), br);
25127 editor.undoManager.add();
25128 };
25129 const insertBrAfter = (editor, inline) => {
25130 if (!hasBrAfter(editor.getBody(), inline)) {
25131 after$4(SugarElement.fromDom(inline), SugarElement.fromTag('br'));
25132 }
25133 const br = SugarElement.fromTag('br');
25134 after$4(SugarElement.fromDom(inline), br);
25135 moveSelectionToBr(editor, br.dom, false);
25136 editor.undoManager.add();
25137 };
25138 const isBeforeBr = pos => {
25139 return isBr$6(pos.getNode());
25140 };
25141 const hasBrAfter = (rootNode, startNode) => {
25142 if (isBeforeBr(CaretPosition.after(startNode))) {
25143 return true;
25144 } else {
25145 return nextPosition(rootNode, CaretPosition.after(startNode)).map(pos => {
25146 return isBr$6(pos.getNode());
25147 }).getOr(false);
25148 }
25149 };
25150 const isAnchorLink = elm => {
25151 return elm && elm.nodeName === 'A' && 'href' in elm;
25152 };
25153 const isInsideAnchor = location => {
25154 return location.fold(never, isAnchorLink, isAnchorLink, never);
25155 };
25156 const readInlineAnchorLocation = editor => {
25157 const isInlineTarget$1 = curry(isInlineTarget, editor);
25158 const position = CaretPosition.fromRangeStart(editor.selection.getRng());
25159 return readLocation(isInlineTarget$1, editor.getBody(), position).filter(isInsideAnchor);
25160 };
25161 const insertBrOutsideAnchor = (editor, location) => {
25162 location.fold(noop, curry(insertBrBefore, editor), curry(insertBrAfter, editor), noop);
25163 };
25164 const insert$2 = (editor, evt) => {
25165 const anchorLocation = readInlineAnchorLocation(editor);
25166 if (anchorLocation.isSome()) {
25167 anchorLocation.each(curry(insertBrOutsideAnchor, editor));
25168 } else {
25169 insertBrAtCaret(editor, evt);
25170 }
25171 };
25172 const fakeEventName = 'insertLineBreak';
25173 const linebreak = {
25174 insert: insert$2,
25175 fakeEventName
25176 };
25177
25178 const matchesSelector = (editor, selector) => {
25179 return getParentBlock$1(editor).filter(parentBlock => {
25180 return selector.length > 0 && is$1(SugarElement.fromDom(parentBlock), selector);
25181 }).isSome();
25182 };
25183 const shouldInsertBr = editor => {
25184 return matchesSelector(editor, getBrNewLineSelector(editor));
25185 };
25186 const shouldBlockNewLine$1 = editor => {
25187 return matchesSelector(editor, getNoNewLineSelector(editor));
25188 };
25189
25190 const newLineAction = Adt.generate([
25191 { br: [] },
25192 { block: [] },
25193 { none: [] }
25194 ]);
25195 const shouldBlockNewLine = (editor, _shiftKey) => {
25196 return shouldBlockNewLine$1(editor);
25197 };
25198 const inListBlock = requiredState => {
25199 return (editor, _shiftKey) => {
25200 return isListItemParentBlock(editor) === requiredState;
25201 };
25202 };
25203 const inBlock = (blockName, requiredState) => (editor, _shiftKey) => {
25204 const state = getParentBlockName(editor) === blockName.toUpperCase();
25205 return state === requiredState;
25206 };
25207 const inCefBlock = editor => {
25208 const editableRoot = getEditableRoot(editor.dom, editor.selection.getStart());
25209 return isNullable(editableRoot);
25210 };
25211 const inPreBlock = requiredState => inBlock('pre', requiredState);
25212 const inSummaryBlock = () => inBlock('summary', true);
25213 const shouldPutBrInPre = requiredState => {
25214 return (editor, _shiftKey) => {
25215 return shouldPutBrInPre$1(editor) === requiredState;
25216 };
25217 };
25218 const inBrContext = (editor, _shiftKey) => {
25219 return shouldInsertBr(editor);
25220 };
25221 const hasShiftKey = (_editor, shiftKey) => {
25222 return shiftKey;
25223 };
25224 const canInsertIntoEditableRoot = editor => {
25225 const forcedRootBlock = getForcedRootBlock(editor);
25226 const rootEditable = getEditableRoot(editor.dom, editor.selection.getStart());
25227 return isNonNullable(rootEditable) && editor.schema.isValidChild(rootEditable.nodeName, forcedRootBlock);
25228 };
25229 const isInRootWithEmptyOrCEF = editor => {
25230 const rng = editor.selection.getRng();
25231 const start = SugarElement.fromDom(rng.startContainer);
25232 const child = child$1(start, rng.startOffset);
25233 const isCefOpt = child.map(element => isHTMLElement$1(element) && !isEditable$2(element));
25234 return rng.collapsed && isCefOpt.getOr(true);
25235 };
25236 const match = (predicates, action) => {
25237 return (editor, shiftKey) => {
25238 const isMatch = foldl(predicates, (res, p) => {
25239 return res && p(editor, shiftKey);
25240 }, true);
25241 return isMatch ? Optional.some(action) : Optional.none();
25242 };
25243 };
25244 const getAction = (editor, evt) => {
25245 return evaluateUntil([
25246 match([shouldBlockNewLine], newLineAction.none()),
25247 match([
25248 inPreBlock(true),
25249 inCefBlock
25250 ], newLineAction.none()),
25251 match([inSummaryBlock()], newLineAction.br()),
25252 match([
25253 inPreBlock(true),
25254 shouldPutBrInPre(false),
25255 hasShiftKey
25256 ], newLineAction.br()),
25257 match([
25258 inPreBlock(true),
25259 shouldPutBrInPre(false)
25260 ], newLineAction.block()),
25261 match([
25262 inPreBlock(true),
25263 shouldPutBrInPre(true),
25264 hasShiftKey
25265 ], newLineAction.block()),
25266 match([
25267 inPreBlock(true),
25268 shouldPutBrInPre(true)
25269 ], newLineAction.br()),
25270 match([
25271 inListBlock(true),
25272 hasShiftKey
25273 ], newLineAction.br()),
25274 match([inListBlock(true)], newLineAction.block()),
25275 match([inBrContext], newLineAction.br()),
25276 match([hasShiftKey], newLineAction.br()),
25277 match([canInsertIntoEditableRoot], newLineAction.block()),
25278 match([isInRootWithEmptyOrCEF], newLineAction.block())
25279 ], [
25280 editor,
25281 !!(evt && evt.shiftKey)
25282 ]).getOr(newLineAction.none());
25283 };
25284
25285 const insertBreak = (breakType, editor, evt) => {
25286 if (!editor.selection.isCollapsed()) {
25287 execEditorDeleteCommand(editor);
25288 }
25289 if (isNonNullable(evt)) {
25290 const event = fireBeforeInputEvent(editor, breakType.fakeEventName);
25291 if (event.isDefaultPrevented()) {
25292 return;
25293 }
25294 }
25295 breakType.insert(editor, evt);
25296 if (isNonNullable(evt)) {
25297 fireInputEvent(editor, breakType.fakeEventName);
25298 }
25299 };
25300 const insert$1 = (editor, evt) => {
25301 const br = () => insertBreak(linebreak, editor, evt);
25302 const block = () => insertBreak(blockbreak, editor, evt);
25303 const logicalAction = getAction(editor, evt);
25304 switch (getNewlineBehavior(editor)) {
25305 case 'linebreak':
25306 logicalAction.fold(br, br, noop);
25307 break;
25308 case 'block':
25309 logicalAction.fold(block, block, noop);
25310 break;
25311 case 'invert':
25312 logicalAction.fold(block, br, noop);
25313 break;
25314 default:
25315 logicalAction.fold(br, block, noop);
25316 break;
25317 }
25318 };
25319
25320 const platform$1 = detect$1();
25321 const isIOSSafari = platform$1.os.isiOS() && platform$1.browser.isSafari();
25322 const handleEnterKeyEvent = (editor, event) => {
25323 if (event.isDefaultPrevented()) {
25324 return;
25325 }
25326 event.preventDefault();
25327 endTypingLevelIgnoreLocks(editor.undoManager);
25328 editor.undoManager.transact(() => {
25329 insert$1(editor, event);
25330 });
25331 };
25332 const isCaretAfterKoreanCharacter = rng => {
25333 if (!rng.collapsed) {
25334 return false;
25335 }
25336 const startContainer = rng.startContainer;
25337 if (isText$b(startContainer)) {
25338 const koreanCharRegex = /^[\uAC00-\uD7AF\u1100-\u11FF\u3130-\u318F\uA960-\uA97F\uD7B0-\uD7FF]$/;
25339 const char = startContainer.data.charAt(rng.startOffset - 1);
25340 return koreanCharRegex.test(char);
25341 } else {
25342 return false;
25343 }
25344 };
25345 const setup$i = editor => {
25346 let iOSSafariKeydownBookmark = Optional.none();
25347 const iOSSafariKeydownOverride = editor => {
25348 iOSSafariKeydownBookmark = Optional.some(editor.selection.getBookmark());
25349 editor.undoManager.add();
25350 };
25351 const iOSSafariKeyupOverride = (editor, event) => {
25352 editor.undoManager.undo();
25353 iOSSafariKeydownBookmark.fold(noop, b => editor.selection.moveToBookmark(b));
25354 handleEnterKeyEvent(editor, event);
25355 iOSSafariKeydownBookmark = Optional.none();
25356 };
25357 editor.on('keydown', event => {
25358 if (event.keyCode === VK.ENTER) {
25359 if (isIOSSafari && isCaretAfterKoreanCharacter(editor.selection.getRng())) {
25360 iOSSafariKeydownOverride(editor);
25361 } else {
25362 handleEnterKeyEvent(editor, event);
25363 }
25364 }
25365 });
25366 editor.on('keyup', event => {
25367 if (event.keyCode === VK.ENTER) {
25368 iOSSafariKeydownBookmark.each(() => iOSSafariKeyupOverride(editor, event));
25369 }
25370 });
25371 };
25372
25373 const executeKeydownOverride$2 = (editor, caret, evt) => {
25374 const isMac = Env.os.isMacOS() || Env.os.isiOS();
25375 execute([
25376 {
25377 keyCode: VK.END,
25378 action: action(moveToLineEndPoint$1, editor, true)
25379 },
25380 {
25381 keyCode: VK.HOME,
25382 action: action(moveToLineEndPoint$1, editor, false)
25383 },
25384 ...!isMac ? [
25385 {
25386 keyCode: VK.HOME,
25387 action: action(selectToEndPoint, editor, false),
25388 ctrlKey: true,
25389 shiftKey: true
25390 },
25391 {
25392 keyCode: VK.END,
25393 action: action(selectToEndPoint, editor, true),
25394 ctrlKey: true,
25395 shiftKey: true
25396 }
25397 ] : [],
25398 {
25399 keyCode: VK.END,
25400 action: action(moveToLineEndPoint, editor, true)
25401 },
25402 {
25403 keyCode: VK.HOME,
25404 action: action(moveToLineEndPoint, editor, false)
25405 },
25406 {
25407 keyCode: VK.END,
25408 action: action(moveToLineEndPoint$2, editor, true, caret)
25409 },
25410 {
25411 keyCode: VK.HOME,
25412 action: action(moveToLineEndPoint$2, editor, false, caret)
25413 }
25414 ], evt).each(_ => {
25415 evt.preventDefault();
25416 });
25417 };
25418 const setup$h = (editor, caret) => {
25419 editor.on('keydown', evt => {
25420 if (!evt.isDefaultPrevented()) {
25421 executeKeydownOverride$2(editor, caret, evt);
25422 }
25423 });
25424 };
25425
25426 const setup$g = editor => {
25427 editor.on('input', e => {
25428 if (!e.isComposing) {
25429 normalizeNbspsInEditor(editor);
25430 }
25431 });
25432 };
25433
25434 const platform = detect$1();
25435 const executeKeyupAction = (editor, caret, evt) => {
25436 execute([
25437 {
25438 keyCode: VK.PAGE_UP,
25439 action: action(moveToLineEndPoint$2, editor, false, caret)
25440 },
25441 {
25442 keyCode: VK.PAGE_DOWN,
25443 action: action(moveToLineEndPoint$2, editor, true, caret)
25444 }
25445 ], evt);
25446 };
25447 const stopImmediatePropagation = e => e.stopImmediatePropagation();
25448 const isPageUpDown = evt => evt.keyCode === VK.PAGE_UP || evt.keyCode === VK.PAGE_DOWN;
25449 const setNodeChangeBlocker = (blocked, editor, block) => {
25450 if (block && !blocked.get()) {
25451 editor.on('NodeChange', stopImmediatePropagation, true);
25452 } else if (!block && blocked.get()) {
25453 editor.off('NodeChange', stopImmediatePropagation);
25454 }
25455 blocked.set(block);
25456 };
25457 const setup$f = (editor, caret) => {
25458 if (platform.os.isMacOS()) {
25459 return;
25460 }
25461 const blocked = Cell(false);
25462 editor.on('keydown', evt => {
25463 if (isPageUpDown(evt)) {
25464 setNodeChangeBlocker(blocked, editor, true);
25465 }
25466 });
25467 editor.on('keyup', evt => {
25468 if (!evt.isDefaultPrevented()) {
25469 executeKeyupAction(editor, caret, evt);
25470 }
25471 if (isPageUpDown(evt) && blocked.get()) {
25472 setNodeChangeBlocker(blocked, editor, false);
25473 editor.nodeChanged();
25474 }
25475 });
25476 };
25477
25478 const setup$e = editor => {
25479 editor.on('beforeinput', e => {
25480 if (!editor.selection.isEditable() || exists(e.getTargetRanges(), rng => !isEditableRange(editor.dom, rng))) {
25481 e.preventDefault();
25482 }
25483 });
25484 };
25485
25486 const insertTextAtPosition = (text, pos) => {
25487 const container = pos.container();
25488 const offset = pos.offset();
25489 if (isText$b(container)) {
25490 container.insertData(offset, text);
25491 return Optional.some(CaretPosition(container, offset + text.length));
25492 } else {
25493 return getElementFromPosition(pos).map(elm => {
25494 const textNode = SugarElement.fromText(text);
25495 if (pos.isAtEnd()) {
25496 after$4(elm, textNode);
25497 } else {
25498 before$3(elm, textNode);
25499 }
25500 return CaretPosition(textNode.dom, text.length);
25501 });
25502 }
25503 };
25504 const insertNbspAtPosition = curry(insertTextAtPosition, nbsp);
25505 const insertSpaceAtPosition = curry(insertTextAtPosition, ' ');
25506
25507 const insertSpaceOrNbspAtPosition = (root, pos, schema) => needsToHaveNbsp(root, pos, schema) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
25508 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)));
25509 const insertInlineBoundarySpaceOrNbsp = (root, pos, schema) => checkPos => needsToHaveNbsp(root, checkPos, schema) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
25510 const setSelection = editor => pos => {
25511 editor.selection.setRng(pos.toRange());
25512 editor.nodeChanged();
25513 };
25514 const isInsideSummary = (domUtils, node) => domUtils.isEditable(domUtils.getParent(node, 'summary'));
25515 const insertSpaceOrNbspAtSelection = editor => {
25516 const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
25517 const root = SugarElement.fromDom(editor.getBody());
25518 if (editor.selection.isCollapsed()) {
25519 const isInlineTarget$1 = curry(isInlineTarget, editor);
25520 const caretPosition = CaretPosition.fromRangeStart(editor.selection.getRng());
25521 return readLocation(isInlineTarget$1, editor.getBody(), caretPosition).bind(locationToCaretPosition(root)).map(checkPos => () => insertInlineBoundarySpaceOrNbsp(root, pos, editor.schema)(checkPos).each(setSelection(editor)));
25522 } else {
25523 return Optional.none();
25524 }
25525 };
25526 const insertSpaceInSummaryAtSelectionOnFirefox = editor => {
25527 const insertSpaceThunk = () => {
25528 const root = SugarElement.fromDom(editor.getBody());
25529 if (!editor.selection.isCollapsed()) {
25530 editor.getDoc().execCommand('Delete');
25531 }
25532 const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
25533 insertSpaceOrNbspAtPosition(root, pos, editor.schema).each(setSelection(editor));
25534 };
25535 return someIf(Env.browser.isFirefox() && editor.selection.isEditable() && isInsideSummary(editor.dom, editor.selection.getRng().startContainer), insertSpaceThunk);
25536 };
25537
25538 const executeKeydownOverride$1 = (editor, evt) => {
25539 executeWithDelayedAction([
25540 {
25541 keyCode: VK.SPACEBAR,
25542 action: action(insertSpaceOrNbspAtSelection, editor)
25543 },
25544 {
25545 keyCode: VK.SPACEBAR,
25546 action: action(insertSpaceInSummaryAtSelectionOnFirefox, editor)
25547 }
25548 ], evt).each(applyAction => {
25549 evt.preventDefault();
25550 const event = fireBeforeInputEvent(editor, 'insertText', { data: ' ' });
25551 if (!event.isDefaultPrevented()) {
25552 applyAction();
25553 fireInputEvent(editor, 'insertText', { data: ' ' });
25554 }
25555 });
25556 };
25557 const setup$d = editor => {
25558 editor.on('keydown', evt => {
25559 if (!evt.isDefaultPrevented()) {
25560 executeKeydownOverride$1(editor, evt);
25561 }
25562 });
25563 };
25564
25565 const tableTabNavigation = editor => {
25566 if (hasTableTabNavigation(editor)) {
25567 return [
25568 {
25569 keyCode: VK.TAB,
25570 action: action(handleTab, editor, true)
25571 },
25572 {
25573 keyCode: VK.TAB,
25574 shiftKey: true,
25575 action: action(handleTab, editor, false)
25576 }
25577 ];
25578 } else {
25579 return [];
25580 }
25581 };
25582 const executeKeydownOverride = (editor, evt) => {
25583 execute([...tableTabNavigation(editor)], evt).each(_ => {
25584 evt.preventDefault();
25585 });
25586 };
25587 const setup$c = editor => {
25588 editor.on('keydown', evt => {
25589 if (!evt.isDefaultPrevented()) {
25590 executeKeydownOverride(editor, evt);
25591 }
25592 });
25593 };
25594
25595 const setup$b = editor => {
25596 editor.addShortcut('Meta+P', '', 'mcePrint');
25597 setup$k(editor);
25598 if (isRtc(editor)) {
25599 return Cell(null);
25600 } else {
25601 const caret = setupSelectedState(editor);
25602 setup$e(editor);
25603 setup$m(editor);
25604 setup$l(editor, caret);
25605 setup$j(editor, caret);
25606 setup$i(editor);
25607 setup$d(editor);
25608 setup$g(editor);
25609 setup$c(editor);
25610 setup$h(editor, caret);
25611 setup$f(editor, caret);
25612 return caret;
25613 }
25614 };
25615
25616 class NodeChange {
25617 constructor(editor) {
25618 this.lastPath = [];
25619 this.editor = editor;
25620 let lastRng;
25621 const self = this;
25622 if (!('onselectionchange' in editor.getDoc())) {
25623 editor.on('NodeChange click mouseup keyup focus', e => {
25624 const nativeRng = editor.selection.getRng();
25625 const fakeRng = {
25626 startContainer: nativeRng.startContainer,
25627 startOffset: nativeRng.startOffset,
25628 endContainer: nativeRng.endContainer,
25629 endOffset: nativeRng.endOffset
25630 };
25631 if (e.type === 'nodechange' || !isEq$4(fakeRng, lastRng)) {
25632 editor.dispatch('SelectionChange');
25633 }
25634 lastRng = fakeRng;
25635 });
25636 }
25637 editor.on('contextmenu', () => {
25638 store(editor);
25639 editor.dispatch('SelectionChange');
25640 });
25641 editor.on('SelectionChange', () => {
25642 const startElm = editor.selection.getStart(true);
25643 if (!startElm) {
25644 return;
25645 }
25646 if (hasAnyRanges(editor) && !self.isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
25647 editor.nodeChanged({ selectionChange: true });
25648 }
25649 });
25650 editor.on('mouseup', e => {
25651 if (!e.isDefaultPrevented() && hasAnyRanges(editor)) {
25652 if (editor.selection.getNode().nodeName === 'IMG') {
25653 Delay.setEditorTimeout(editor, () => {
25654 editor.nodeChanged();
25655 });
25656 } else {
25657 editor.nodeChanged();
25658 }
25659 }
25660 });
25661 }
25662 nodeChanged(args = {}) {
25663 const selection = this.editor.selection;
25664 let node;
25665 if (this.editor.initialized && selection && !shouldDisableNodeChange(this.editor) && !this.editor.mode.isReadOnly()) {
25666 const root = this.editor.getBody();
25667 node = selection.getStart(true) || root;
25668 if (node.ownerDocument !== this.editor.getDoc() || !this.editor.dom.isChildOf(node, root)) {
25669 node = root;
25670 }
25671 const parents = [];
25672 this.editor.dom.getParent(node, node => {
25673 if (node === root) {
25674 return true;
25675 } else {
25676 parents.push(node);
25677 return false;
25678 }
25679 });
25680 this.editor.dispatch('NodeChange', {
25681 ...args,
25682 element: node,
25683 parents
25684 });
25685 }
25686 }
25687 isSameElementPath(startElm) {
25688 let i;
25689 const editor = this.editor;
25690 const currentPath = reverse(editor.dom.getParents(startElm, always, editor.getBody()));
25691 if (currentPath.length === this.lastPath.length) {
25692 for (i = currentPath.length; i >= 0; i--) {
25693 if (currentPath[i] !== this.lastPath[i]) {
25694 break;
25695 }
25696 }
25697 if (i === -1) {
25698 this.lastPath = currentPath;
25699 return true;
25700 }
25701 }
25702 this.lastPath = currentPath;
25703 return false;
25704 }
25705 }
25706
25707 const imageId = generate$1('image');
25708 const getDragImage = transfer => {
25709 const dt = transfer;
25710 return Optional.from(dt[imageId]);
25711 };
25712 const setDragImage = (transfer, imageData) => {
25713 const dt = transfer;
25714 dt[imageId] = imageData;
25715 };
25716
25717 const eventId = generate$1('event');
25718 const getEvent = transfer => {
25719 const dt = transfer;
25720 return Optional.from(dt[eventId]);
25721 };
25722 const mkSetEventFn = type => transfer => {
25723 const dt = transfer;
25724 dt[eventId] = type;
25725 };
25726 const setEvent = (transfer, type) => mkSetEventFn(type)(transfer);
25727 const setDragstartEvent = mkSetEventFn(0);
25728 const setDropEvent = mkSetEventFn(2);
25729 const setDragendEvent = mkSetEventFn(1);
25730 const checkEvent = expectedType => transfer => {
25731 const dt = transfer;
25732 return Optional.from(dt[eventId]).exists(type => type === expectedType);
25733 };
25734 const isInDragStartEvent = checkEvent(0);
25735
25736 const createEmptyFileList = () => Object.freeze({
25737 length: 0,
25738 item: _ => null
25739 });
25740
25741 const modeId = generate$1('mode');
25742 const getMode = transfer => {
25743 const dt = transfer;
25744 return Optional.from(dt[modeId]);
25745 };
25746 const mkSetModeFn = mode => transfer => {
25747 const dt = transfer;
25748 dt[modeId] = mode;
25749 };
25750 const setMode$1 = (transfer, mode) => mkSetModeFn(mode)(transfer);
25751 const setReadWriteMode = mkSetModeFn(0);
25752 const setReadOnlyMode = mkSetModeFn(2);
25753 const setProtectedMode = mkSetModeFn(1);
25754 const checkMode = expectedMode => transfer => {
25755 const dt = transfer;
25756 return Optional.from(dt[modeId]).exists(mode => mode === expectedMode);
25757 };
25758 const isInReadWriteMode = checkMode(0);
25759 const isInProtectedMode = checkMode(1);
25760
25761 const normalizeItems = (dataTransfer, itemsImpl) => ({
25762 ...itemsImpl,
25763 get length() {
25764 return itemsImpl.length;
25765 },
25766 add: (data, type) => {
25767 if (isInReadWriteMode(dataTransfer)) {
25768 if (isString(data)) {
25769 if (!isUndefined(type)) {
25770 return itemsImpl.add(data, type);
25771 }
25772 } else {
25773 return itemsImpl.add(data);
25774 }
25775 }
25776 return null;
25777 },
25778 remove: idx => {
25779 if (isInReadWriteMode(dataTransfer)) {
25780 itemsImpl.remove(idx);
25781 }
25782 },
25783 clear: () => {
25784 if (isInReadWriteMode(dataTransfer)) {
25785 itemsImpl.clear();
25786 }
25787 }
25788 });
25789
25790 const validDropEffects = [
25791 'none',
25792 'copy',
25793 'link',
25794 'move'
25795 ];
25796 const validEffectAlloweds = [
25797 'none',
25798 'copy',
25799 'copyLink',
25800 'copyMove',
25801 'link',
25802 'linkMove',
25803 'move',
25804 'all',
25805 'uninitialized'
25806 ];
25807 const createDataTransfer = () => {
25808 const dataTransferImpl = new window.DataTransfer();
25809 let dropEffect = 'move';
25810 let effectAllowed = 'all';
25811 const dataTransfer = {
25812 get dropEffect() {
25813 return dropEffect;
25814 },
25815 set dropEffect(effect) {
25816 if (contains$2(validDropEffects, effect)) {
25817 dropEffect = effect;
25818 }
25819 },
25820 get effectAllowed() {
25821 return effectAllowed;
25822 },
25823 set effectAllowed(allowed) {
25824 if (isInDragStartEvent(dataTransfer) && contains$2(validEffectAlloweds, allowed)) {
25825 effectAllowed = allowed;
25826 }
25827 },
25828 get items() {
25829 return normalizeItems(dataTransfer, dataTransferImpl.items);
25830 },
25831 get files() {
25832 if (isInProtectedMode(dataTransfer)) {
25833 return createEmptyFileList();
25834 } else {
25835 return dataTransferImpl.files;
25836 }
25837 },
25838 get types() {
25839 return dataTransferImpl.types;
25840 },
25841 setDragImage: (image, x, y) => {
25842 if (isInReadWriteMode(dataTransfer)) {
25843 setDragImage(dataTransfer, {
25844 image,
25845 x,
25846 y
25847 });
25848 dataTransferImpl.setDragImage(image, x, y);
25849 }
25850 },
25851 getData: format => {
25852 if (isInProtectedMode(dataTransfer)) {
25853 return '';
25854 } else {
25855 return dataTransferImpl.getData(format);
25856 }
25857 },
25858 setData: (format, data) => {
25859 if (isInReadWriteMode(dataTransfer)) {
25860 dataTransferImpl.setData(format, data);
25861 }
25862 },
25863 clearData: format => {
25864 if (isInReadWriteMode(dataTransfer)) {
25865 dataTransferImpl.clearData(format);
25866 }
25867 }
25868 };
25869 setReadWriteMode(dataTransfer);
25870 return dataTransfer;
25871 };
25872 const cloneDataTransfer = original => {
25873 const clone = createDataTransfer();
25874 const originalMode = getMode(original);
25875 setReadOnlyMode(original);
25876 setDragstartEvent(clone);
25877 clone.dropEffect = original.dropEffect;
25878 clone.effectAllowed = original.effectAllowed;
25879 getDragImage(original).each(imageData => clone.setDragImage(imageData.image, imageData.x, imageData.y));
25880 each$e(original.types, type => {
25881 if (type !== 'Files') {
25882 clone.setData(type, original.getData(type));
25883 }
25884 });
25885 each$e(original.files, file => clone.items.add(file));
25886 getEvent(original).each(type => {
25887 setEvent(clone, type);
25888 });
25889 originalMode.each(mode => {
25890 setMode$1(original, mode);
25891 setMode$1(clone, mode);
25892 });
25893 return clone;
25894 };
25895
25896 const getHtmlData = dataTransfer => {
25897 const html = dataTransfer.getData('text/html');
25898 return html === '' ? Optional.none() : Optional.some(html);
25899 };
25900 const setHtmlData = (dataTransfer, html) => dataTransfer.setData('text/html', html);
25901
25902 const internalMimeType = 'x-tinymce/html';
25903 const internalHtmlMime = constant(internalMimeType);
25904 const internalMark = '<!-- ' + internalMimeType + ' -->';
25905 const mark = html => internalMark + html;
25906 const unmark = html => html.replace(internalMark, '');
25907 const isMarked = html => html.indexOf(internalMark) !== -1;
25908
25909 const isPlainText = text => {
25910 return !/<(?:\/?(?!(?:div|p|br|span)>)\w+|(?:(?!(?:span style="white-space:\s?pre;?">)|br\s?\/>))\w+\s[^>]+)>/i.test(text);
25911 };
25912 const openContainer = (rootTag, rootAttrs) => {
25913 let tag = '<' + rootTag;
25914 const attrs = mapToArray(rootAttrs, (value, key) => key + '="' + Entities.encodeAllRaw(value) + '"');
25915 if (attrs.length) {
25916 tag += ' ' + attrs.join(' ');
25917 }
25918 return tag + '>';
25919 };
25920 const toBlockElements = (text, rootTag, rootAttrs) => {
25921 const blocks = text.split(/\n\n/);
25922 const tagOpen = openContainer(rootTag, rootAttrs);
25923 const tagClose = '</' + rootTag + '>';
25924 const paragraphs = map$3(blocks, p => {
25925 return p.split(/\n/).join('<br />');
25926 });
25927 const stitch = p => {
25928 return tagOpen + p + tagClose;
25929 };
25930 return paragraphs.length === 1 ? paragraphs[0] : map$3(paragraphs, stitch).join('');
25931 };
25932
25933 const pasteBinDefaultContent = '%MCEPASTEBIN%';
25934 const create$6 = (editor, lastRngCell) => {
25935 const {dom, selection} = editor;
25936 const body = editor.getBody();
25937 lastRngCell.set(selection.getRng());
25938 const pasteBinElm = dom.add(editor.getBody(), 'div', {
25939 'id': 'mcepastebin',
25940 'class': 'mce-pastebin',
25941 'contentEditable': true,
25942 'data-mce-bogus': 'all',
25943 'style': 'position: fixed; top: 50%; width: 10px; height: 10px; overflow: hidden; opacity: 0'
25944 }, pasteBinDefaultContent);
25945 if (Env.browser.isFirefox()) {
25946 dom.setStyle(pasteBinElm, 'left', dom.getStyle(body, 'direction', true) === 'rtl' ? 65535 : -65535);
25947 }
25948 dom.bind(pasteBinElm, 'beforedeactivate focusin focusout', e => {
25949 e.stopPropagation();
25950 });
25951 pasteBinElm.focus();
25952 selection.select(pasteBinElm, true);
25953 };
25954 const remove = (editor, lastRngCell) => {
25955 const dom = editor.dom;
25956 if (getEl(editor)) {
25957 let pasteBinClone;
25958 const lastRng = lastRngCell.get();
25959 while (pasteBinClone = getEl(editor)) {
25960 dom.remove(pasteBinClone);
25961 dom.unbind(pasteBinClone);
25962 }
25963 if (lastRng) {
25964 editor.selection.setRng(lastRng);
25965 }
25966 }
25967 lastRngCell.set(null);
25968 };
25969 const getEl = editor => editor.dom.get('mcepastebin');
25970 const isPasteBin = elm => isNonNullable(elm) && elm.id === 'mcepastebin';
25971 const getHtml = editor => {
25972 const dom = editor.dom;
25973 const copyAndRemove = (toElm, fromElm) => {
25974 toElm.appendChild(fromElm);
25975 dom.remove(fromElm, true);
25976 };
25977 const [pasteBinElm, ...pasteBinClones] = filter$5(editor.getBody().childNodes, isPasteBin);
25978 each$e(pasteBinClones, pasteBinClone => {
25979 copyAndRemove(pasteBinElm, pasteBinClone);
25980 });
25981 const dirtyWrappers = dom.select('div[id=mcepastebin]', pasteBinElm);
25982 for (let i = dirtyWrappers.length - 1; i >= 0; i--) {
25983 const cleanWrapper = dom.create('div');
25984 pasteBinElm.insertBefore(cleanWrapper, dirtyWrappers[i]);
25985 copyAndRemove(cleanWrapper, dirtyWrappers[i]);
25986 }
25987 return pasteBinElm ? pasteBinElm.innerHTML : '';
25988 };
25989 const isDefaultPasteBinContent = content => content === pasteBinDefaultContent;
25990 const PasteBin = editor => {
25991 const lastRng = Cell(null);
25992 return {
25993 create: () => create$6(editor, lastRng),
25994 remove: () => remove(editor, lastRng),
25995 getEl: () => getEl(editor),
25996 getHtml: () => getHtml(editor),
25997 getLastRng: lastRng.get
25998 };
25999 };
26000
26001 const filter$1 = (content, items) => {
26002 Tools.each(items, v => {
26003 if (is$4(v, RegExp)) {
26004 content = content.replace(v, '');
26005 } else {
26006 content = content.replace(v[0], v[1]);
26007 }
26008 });
26009 return content;
26010 };
26011 const innerText = html => {
26012 const schema = Schema();
26013 const domParser = DomParser({}, schema);
26014 let text = '';
26015 const voidElements = schema.getVoidElements();
26016 const ignoreElements = Tools.makeMap('script noscript style textarea video audio iframe object', ' ');
26017 const blockElements = schema.getBlockElements();
26018 const walk = node => {
26019 const name = node.name, currentNode = node;
26020 if (name === 'br') {
26021 text += '\n';
26022 return;
26023 }
26024 if (name === 'wbr') {
26025 return;
26026 }
26027 if (voidElements[name]) {
26028 text += ' ';
26029 }
26030 if (ignoreElements[name]) {
26031 text += ' ';
26032 return;
26033 }
26034 if (node.type === 3) {
26035 text += node.value;
26036 }
26037 if (!(node.name in schema.getVoidElements())) {
26038 let currentNode = node.firstChild;
26039 if (currentNode) {
26040 do {
26041 walk(currentNode);
26042 } while (currentNode = currentNode.next);
26043 }
26044 }
26045 if (blockElements[name] && currentNode.next) {
26046 text += '\n';
26047 if (name === 'p') {
26048 text += '\n';
26049 }
26050 }
26051 };
26052 html = filter$1(html, [/<!\[[^\]]+\]>/g]);
26053 walk(domParser.parse(html));
26054 return text;
26055 };
26056 const trimHtml = html => {
26057 const trimSpaces = (all, s1, s2) => {
26058 if (!s1 && !s2) {
26059 return ' ';
26060 }
26061 return nbsp;
26062 };
26063 html = filter$1(html, [
26064 /^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/ig,
26065 /<!--StartFragment-->|<!--EndFragment-->/g,
26066 [
26067 /( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g,
26068 trimSpaces
26069 ],
26070 /<br class="Apple-interchange-newline">/g,
26071 /<br>$/i
26072 ]);
26073 return html;
26074 };
26075 const createIdGenerator = prefix => {
26076 let count = 0;
26077 return () => {
26078 return prefix + count++;
26079 };
26080 };
26081 const getImageMimeType = ext => {
26082 const lowerExt = ext.toLowerCase();
26083 const mimeOverrides = {
26084 jpg: 'jpeg',
26085 jpe: 'jpeg',
26086 jfi: 'jpeg',
26087 jif: 'jpeg',
26088 jfif: 'jpeg',
26089 pjpeg: 'jpeg',
26090 pjp: 'jpeg',
26091 svg: 'svg+xml'
26092 };
26093 return Tools.hasOwn(mimeOverrides, lowerExt) ? 'image/' + mimeOverrides[lowerExt] : 'image/' + lowerExt;
26094 };
26095
26096 const preProcess = (editor, html) => {
26097 const parser = DomParser({
26098 sanitize: shouldSanitizeXss(editor),
26099 sandbox_iframes: shouldSandboxIframes(editor),
26100 sandbox_iframes_exclusions: getSandboxIframesExclusions(editor),
26101 convert_unsafe_embeds: shouldConvertUnsafeEmbeds(editor)
26102 }, editor.schema);
26103 parser.addNodeFilter('meta', nodes => {
26104 Tools.each(nodes, node => {
26105 node.remove();
26106 });
26107 });
26108 const fragment = parser.parse(html, {
26109 forced_root_block: false,
26110 isRootContent: true
26111 });
26112 return HtmlSerializer({ validate: true }, editor.schema).serialize(fragment);
26113 };
26114 const processResult = (content, cancelled) => ({
26115 content,
26116 cancelled
26117 });
26118 const postProcessFilter = (editor, html, internal) => {
26119 const tempBody = editor.dom.create('div', { style: 'display:none' }, html);
26120 const postProcessArgs = firePastePostProcess(editor, tempBody, internal);
26121 return processResult(postProcessArgs.node.innerHTML, postProcessArgs.isDefaultPrevented());
26122 };
26123 const filterContent = (editor, content, internal) => {
26124 const preProcessArgs = firePastePreProcess(editor, content, internal);
26125 const filteredContent = preProcess(editor, preProcessArgs.content);
26126 if (editor.hasEventListeners('PastePostProcess') && !preProcessArgs.isDefaultPrevented()) {
26127 return postProcessFilter(editor, filteredContent, internal);
26128 } else {
26129 return processResult(filteredContent, preProcessArgs.isDefaultPrevented());
26130 }
26131 };
26132 const process = (editor, html, internal) => {
26133 return filterContent(editor, html, internal);
26134 };
26135
26136 const pasteHtml$1 = (editor, html) => {
26137 editor.insertContent(html, {
26138 merge: shouldPasteMergeFormats(editor),
26139 paste: true
26140 });
26141 return true;
26142 };
26143 const isAbsoluteUrl = url => /^https?:\/\/[\w\-\/+=.,!;:&%@^~(){}?#]+$/i.test(url);
26144 const isImageUrl = (editor, url) => {
26145 return isAbsoluteUrl(url) && exists(getAllowedImageFileTypes(editor), type => endsWith(url.toLowerCase(), `.${ type.toLowerCase() }`));
26146 };
26147 const createImage = (editor, url, pasteHtmlFn) => {
26148 editor.undoManager.extra(() => {
26149 pasteHtmlFn(editor, url);
26150 }, () => {
26151 editor.insertContent('<img src="' + url + '">');
26152 });
26153 return true;
26154 };
26155 const createLink = (editor, url, pasteHtmlFn) => {
26156 editor.undoManager.extra(() => {
26157 pasteHtmlFn(editor, url);
26158 }, () => {
26159 editor.execCommand('mceInsertLink', false, url);
26160 });
26161 return true;
26162 };
26163 const linkSelection = (editor, html, pasteHtmlFn) => !editor.selection.isCollapsed() && isAbsoluteUrl(html) ? createLink(editor, html, pasteHtmlFn) : false;
26164 const insertImage = (editor, html, pasteHtmlFn) => isImageUrl(editor, html) ? createImage(editor, html, pasteHtmlFn) : false;
26165 const smartInsertContent = (editor, html) => {
26166 Tools.each([
26167 linkSelection,
26168 insertImage,
26169 pasteHtml$1
26170 ], action => {
26171 return !action(editor, html, pasteHtml$1);
26172 });
26173 };
26174 const insertContent = (editor, html, pasteAsText) => {
26175 if (pasteAsText || !isSmartPasteEnabled(editor)) {
26176 pasteHtml$1(editor, html);
26177 } else {
26178 smartInsertContent(editor, html);
26179 }
26180 };
26181
26182 const uniqueId = createIdGenerator('mceclip');
26183 const createPasteDataTransfer = html => {
26184 const dataTransfer = createDataTransfer();
26185 setHtmlData(dataTransfer, html);
26186 setReadOnlyMode(dataTransfer);
26187 return dataTransfer;
26188 };
26189 const doPaste = (editor, content, internal, pasteAsText, shouldSimulateInputEvent) => {
26190 const res = process(editor, content, internal);
26191 if (!res.cancelled) {
26192 const content = res.content;
26193 const doPasteAction = () => insertContent(editor, content, pasteAsText);
26194 if (shouldSimulateInputEvent) {
26195 const args = fireBeforeInputEvent(editor, 'insertFromPaste', { dataTransfer: createPasteDataTransfer(content) });
26196 if (!args.isDefaultPrevented()) {
26197 doPasteAction();
26198 fireInputEvent(editor, 'insertFromPaste');
26199 }
26200 } else {
26201 doPasteAction();
26202 }
26203 }
26204 };
26205 const pasteHtml = (editor, html, internalFlag, shouldSimulateInputEvent) => {
26206 const internal = internalFlag ? internalFlag : isMarked(html);
26207 doPaste(editor, unmark(html), internal, false, shouldSimulateInputEvent);
26208 };
26209 const pasteText = (editor, text, shouldSimulateInputEvent) => {
26210 const encodedText = editor.dom.encode(text).replace(/\r\n/g, '\n');
26211 const normalizedText = normalize$4(encodedText, getPasteTabSpaces(editor));
26212 const html = toBlockElements(normalizedText, getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
26213 doPaste(editor, html, false, true, shouldSimulateInputEvent);
26214 };
26215 const getDataTransferItems = dataTransfer => {
26216 const items = {};
26217 if (dataTransfer && dataTransfer.types) {
26218 for (let i = 0; i < dataTransfer.types.length; i++) {
26219 const contentType = dataTransfer.types[i];
26220 try {
26221 items[contentType] = dataTransfer.getData(contentType);
26222 } catch (ex) {
26223 items[contentType] = '';
26224 }
26225 }
26226 }
26227 return items;
26228 };
26229 const hasContentType = (clipboardContent, mimeType) => mimeType in clipboardContent && clipboardContent[mimeType].length > 0;
26230 const hasHtmlOrText = content => hasContentType(content, 'text/html') || hasContentType(content, 'text/plain');
26231 const extractFilename = (editor, str) => {
26232 const m = str.match(/([\s\S]+?)(?:\.[a-z0-9.]+)$/i);
26233 return isNonNullable(m) ? editor.dom.encode(m[1]) : undefined;
26234 };
26235 const createBlobInfo = (editor, blobCache, file, base64) => {
26236 const id = uniqueId();
26237 const useFileName = shouldReuseFileName(editor) && isNonNullable(file.name);
26238 const name = useFileName ? extractFilename(editor, file.name) : id;
26239 const filename = useFileName ? file.name : undefined;
26240 const blobInfo = blobCache.create(id, file, base64, name, filename);
26241 blobCache.add(blobInfo);
26242 return blobInfo;
26243 };
26244 const pasteImage = (editor, imageItem) => {
26245 parseDataUri(imageItem.uri).each(({data, type, base64Encoded}) => {
26246 const base64 = base64Encoded ? data : btoa(data);
26247 const file = imageItem.file;
26248 const blobCache = editor.editorUpload.blobCache;
26249 const existingBlobInfo = blobCache.getByData(base64, type);
26250 const blobInfo = existingBlobInfo !== null && existingBlobInfo !== void 0 ? existingBlobInfo : createBlobInfo(editor, blobCache, file, base64);
26251 pasteHtml(editor, `<img src="${ blobInfo.blobUri() }">`, false, true);
26252 });
26253 };
26254 const isClipboardEvent = event => event.type === 'paste';
26255 const readFilesAsDataUris = items => Promise.all(map$3(items, file => {
26256 return blobToDataUri(file).then(uri => ({
26257 file,
26258 uri
26259 }));
26260 }));
26261 const isImage = editor => {
26262 const allowedExtensions = getAllowedImageFileTypes(editor);
26263 return file => startsWith(file.type, 'image/') && exists(allowedExtensions, extension => {
26264 return getImageMimeType(extension) === file.type;
26265 });
26266 };
26267 const getImagesFromDataTransfer = (editor, dataTransfer) => {
26268 const items = dataTransfer.items ? bind$3(from(dataTransfer.items), item => {
26269 return item.kind === 'file' ? [item.getAsFile()] : [];
26270 }) : [];
26271 const files = dataTransfer.files ? from(dataTransfer.files) : [];
26272 return filter$5(items.length > 0 ? items : files, isImage(editor));
26273 };
26274 const pasteImageData = (editor, e, rng) => {
26275 const dataTransfer = isClipboardEvent(e) ? e.clipboardData : e.dataTransfer;
26276 if (shouldPasteDataImages(editor) && dataTransfer) {
26277 const images = getImagesFromDataTransfer(editor, dataTransfer);
26278 if (images.length > 0) {
26279 e.preventDefault();
26280 readFilesAsDataUris(images).then(fileResults => {
26281 if (rng) {
26282 editor.selection.setRng(rng);
26283 }
26284 each$e(fileResults, result => {
26285 pasteImage(editor, result);
26286 });
26287 });
26288 return true;
26289 }
26290 }
26291 return false;
26292 };
26293 const isBrokenAndroidClipboardEvent = e => {
26294 var _a, _b;
26295 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;
26296 };
26297 const isKeyboardPasteEvent = e => VK.metaKeyPressed(e) && e.keyCode === 86 || e.shiftKey && e.keyCode === 45;
26298 const insertClipboardContent = (editor, clipboardContent, html, plainTextMode, shouldSimulateInputEvent) => {
26299 let content = trimHtml(html);
26300 const isInternal = hasContentType(clipboardContent, internalHtmlMime()) || isMarked(html);
26301 const isPlainTextHtml = !isInternal && isPlainText(content);
26302 const isAbsoluteUrl$1 = isAbsoluteUrl(content);
26303 if (isDefaultPasteBinContent(content) || !content.length || isPlainTextHtml && !isAbsoluteUrl$1) {
26304 plainTextMode = true;
26305 }
26306 if (plainTextMode || isAbsoluteUrl$1) {
26307 if (hasContentType(clipboardContent, 'text/plain') && isPlainTextHtml) {
26308 content = clipboardContent['text/plain'];
26309 } else {
26310 content = innerText(content);
26311 }
26312 }
26313 if (isDefaultPasteBinContent(content)) {
26314 return;
26315 }
26316 if (plainTextMode) {
26317 pasteText(editor, content, shouldSimulateInputEvent);
26318 } else {
26319 pasteHtml(editor, content, isInternal, shouldSimulateInputEvent);
26320 }
26321 };
26322 const registerEventHandlers = (editor, pasteBin, pasteFormat) => {
26323 let keyboardPastePlainTextState;
26324 const getLastRng = () => pasteBin.getLastRng() || editor.selection.getRng();
26325 editor.on('keydown', e => {
26326 if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
26327 keyboardPastePlainTextState = e.shiftKey && e.keyCode === 86;
26328 }
26329 });
26330 editor.on('paste', e => {
26331 if (e.isDefaultPrevented() || isBrokenAndroidClipboardEvent(e)) {
26332 return;
26333 }
26334 const plainTextMode = pasteFormat.get() === 'text' || keyboardPastePlainTextState;
26335 keyboardPastePlainTextState = false;
26336 const clipboardContent = getDataTransferItems(e.clipboardData);
26337 if (!hasHtmlOrText(clipboardContent) && pasteImageData(editor, e, getLastRng())) {
26338 return;
26339 }
26340 if (hasContentType(clipboardContent, 'text/html')) {
26341 e.preventDefault();
26342 insertClipboardContent(editor, clipboardContent, clipboardContent['text/html'], plainTextMode, true);
26343 } else if (hasContentType(clipboardContent, 'text/plain') && hasContentType(clipboardContent, 'text/uri-list')) {
26344 e.preventDefault();
26345 insertClipboardContent(editor, clipboardContent, clipboardContent['text/plain'], plainTextMode, true);
26346 } else {
26347 pasteBin.create();
26348 Delay.setEditorTimeout(editor, () => {
26349 const html = pasteBin.getHtml();
26350 pasteBin.remove();
26351 insertClipboardContent(editor, clipboardContent, html, plainTextMode, false);
26352 }, 0);
26353 }
26354 });
26355 };
26356 const registerDataImageFilter = editor => {
26357 const isWebKitFakeUrl = src => startsWith(src, 'webkit-fake-url');
26358 const isDataUri = src => startsWith(src, 'data:');
26359 const isPasteInsert = args => {
26360 var _a;
26361 return ((_a = args.data) === null || _a === void 0 ? void 0 : _a.paste) === true;
26362 };
26363 editor.parser.addNodeFilter('img', (nodes, name, args) => {
26364 if (!shouldPasteDataImages(editor) && isPasteInsert(args)) {
26365 for (const node of nodes) {
26366 const src = node.attr('src');
26367 if (isString(src) && !node.attr('data-mce-object') && src !== Env.transparentSrc) {
26368 if (isWebKitFakeUrl(src)) {
26369 node.remove();
26370 } else if (!shouldAllowHtmlDataUrls(editor) && isDataUri(src)) {
26371 node.remove();
26372 }
26373 }
26374 }
26375 }
26376 });
26377 };
26378 const registerEventsAndFilters = (editor, pasteBin, pasteFormat) => {
26379 registerEventHandlers(editor, pasteBin, pasteFormat);
26380 registerDataImageFilter(editor);
26381 };
26382
26383 const togglePlainTextPaste = (editor, pasteFormat) => {
26384 if (pasteFormat.get() === 'text') {
26385 pasteFormat.set('html');
26386 firePastePlainTextToggle(editor, false);
26387 } else {
26388 pasteFormat.set('text');
26389 firePastePlainTextToggle(editor, true);
26390 }
26391 editor.focus();
26392 };
26393 const register$1 = (editor, pasteFormat) => {
26394 editor.addCommand('mceTogglePlainTextPaste', () => {
26395 togglePlainTextPaste(editor, pasteFormat);
26396 });
26397 editor.addCommand('mceInsertClipboardContent', (ui, value) => {
26398 if (value.html) {
26399 pasteHtml(editor, value.html, value.internal, false);
26400 }
26401 if (value.text) {
26402 pasteText(editor, value.text, false);
26403 }
26404 });
26405 };
26406
26407 const setHtml5Clipboard = (clipboardData, html, text) => {
26408 if (clipboardData) {
26409 try {
26410 clipboardData.clearData();
26411 clipboardData.setData('text/html', html);
26412 clipboardData.setData('text/plain', text);
26413 clipboardData.setData(internalHtmlMime(), html);
26414 return true;
26415 } catch (e) {
26416 return false;
26417 }
26418 } else {
26419 return false;
26420 }
26421 };
26422 const setClipboardData = (evt, data, fallback, done) => {
26423 if (setHtml5Clipboard(evt.clipboardData, data.html, data.text)) {
26424 evt.preventDefault();
26425 done();
26426 } else {
26427 fallback(data.html, done);
26428 }
26429 };
26430 const fallback = editor => (html, done) => {
26431 const {dom, selection} = editor;
26432 const outer = dom.create('div', {
26433 'contenteditable': 'false',
26434 'data-mce-bogus': 'all'
26435 });
26436 const inner = dom.create('div', { contenteditable: 'true' }, html);
26437 dom.setStyles(outer, {
26438 position: 'fixed',
26439 top: '0',
26440 left: '-3000px',
26441 width: '1000px',
26442 overflow: 'hidden'
26443 });
26444 outer.appendChild(inner);
26445 dom.add(editor.getBody(), outer);
26446 const range = selection.getRng();
26447 inner.focus();
26448 const offscreenRange = dom.createRng();
26449 offscreenRange.selectNodeContents(inner);
26450 selection.setRng(offscreenRange);
26451 Delay.setEditorTimeout(editor, () => {
26452 selection.setRng(range);
26453 dom.remove(outer);
26454 done();
26455 }, 0);
26456 };
26457 const getData = editor => ({
26458 html: mark(editor.selection.getContent({ contextual: true })),
26459 text: editor.selection.getContent({ format: 'text' })
26460 });
26461 const isTableSelection = editor => !!editor.dom.getParent(editor.selection.getStart(), 'td[data-mce-selected],th[data-mce-selected]', editor.getBody());
26462 const hasSelectedContent = editor => !editor.selection.isCollapsed() || isTableSelection(editor);
26463 const cut = editor => evt => {
26464 if (!evt.isDefaultPrevented() && hasSelectedContent(editor) && editor.selection.isEditable()) {
26465 setClipboardData(evt, getData(editor), fallback(editor), () => {
26466 if (Env.browser.isChromium() || Env.browser.isFirefox()) {
26467 const rng = editor.selection.getRng();
26468 Delay.setEditorTimeout(editor, () => {
26469 editor.selection.setRng(rng);
26470 editor.execCommand('Delete');
26471 }, 0);
26472 } else {
26473 editor.execCommand('Delete');
26474 }
26475 });
26476 }
26477 };
26478 const copy = editor => evt => {
26479 if (!evt.isDefaultPrevented() && hasSelectedContent(editor)) {
26480 setClipboardData(evt, getData(editor), fallback(editor), noop);
26481 }
26482 };
26483 const register = editor => {
26484 editor.on('cut', cut(editor));
26485 editor.on('copy', copy(editor));
26486 };
26487
26488 const getCaretRangeFromEvent = (editor, e) => {
26489 var _a, _b;
26490 return RangeUtils.getCaretRangeFromPoint((_a = e.clientX) !== null && _a !== void 0 ? _a : 0, (_b = e.clientY) !== null && _b !== void 0 ? _b : 0, editor.getDoc());
26491 };
26492 const isPlainTextFileUrl = content => {
26493 const plainTextContent = content['text/plain'];
26494 return plainTextContent ? plainTextContent.indexOf('file://') === 0 : false;
26495 };
26496 const setFocusedRange = (editor, rng) => {
26497 editor.focus();
26498 if (rng) {
26499 editor.selection.setRng(rng);
26500 }
26501 };
26502 const hasImage = dataTransfer => exists(dataTransfer.files, file => /^image\//.test(file.type));
26503 const needsCustomInternalDrop = (dom, schema, target, dropContent) => {
26504 const parentTransparent = dom.getParent(target, node => isTransparentBlock(schema, node));
26505 const inSummary = !isNull(dom.getParent(target, 'summary'));
26506 if (inSummary) {
26507 return true;
26508 } else if (parentTransparent && has$2(dropContent, 'text/html')) {
26509 const fragment = new DOMParser().parseFromString(dropContent['text/html'], 'text/html').body;
26510 return !isNull(fragment.querySelector(parentTransparent.nodeName.toLowerCase()));
26511 } else {
26512 return false;
26513 }
26514 };
26515 const setupSummaryDeleteByDragFix = editor => {
26516 editor.on('input', e => {
26517 const hasNoSummary = el => isNull(el.querySelector('summary'));
26518 if (e.inputType === 'deleteByDrag') {
26519 const brokenDetailElements = filter$5(editor.dom.select('details'), hasNoSummary);
26520 each$e(brokenDetailElements, details => {
26521 if (isBr$6(details.firstChild)) {
26522 details.firstChild.remove();
26523 }
26524 const summary = editor.dom.create('summary');
26525 summary.appendChild(createPaddingBr().dom);
26526 details.prepend(summary);
26527 });
26528 }
26529 });
26530 };
26531 const setup$a = (editor, draggingInternallyState) => {
26532 if (shouldPasteBlockDrop(editor)) {
26533 editor.on('dragend dragover draggesture dragdrop drop drag', e => {
26534 e.preventDefault();
26535 e.stopPropagation();
26536 });
26537 }
26538 if (!shouldPasteDataImages(editor)) {
26539 editor.on('drop', e => {
26540 const dataTransfer = e.dataTransfer;
26541 if (dataTransfer && hasImage(dataTransfer)) {
26542 e.preventDefault();
26543 }
26544 });
26545 }
26546 editor.on('drop', e => {
26547 if (e.isDefaultPrevented()) {
26548 return;
26549 }
26550 const rng = getCaretRangeFromEvent(editor, e);
26551 if (isNullable(rng)) {
26552 return;
26553 }
26554 const dropContent = getDataTransferItems(e.dataTransfer);
26555 const internal = hasContentType(dropContent, internalHtmlMime());
26556 if ((!hasHtmlOrText(dropContent) || isPlainTextFileUrl(dropContent)) && pasteImageData(editor, e, rng)) {
26557 return;
26558 }
26559 const internalContent = dropContent[internalHtmlMime()];
26560 const content = internalContent || dropContent['text/html'] || dropContent['text/plain'];
26561 const needsInternalDrop = needsCustomInternalDrop(editor.dom, editor.schema, rng.startContainer, dropContent);
26562 const isInternalDrop = draggingInternallyState.get();
26563 if (isInternalDrop && !needsInternalDrop) {
26564 return;
26565 }
26566 if (content) {
26567 e.preventDefault();
26568 Delay.setEditorTimeout(editor, () => {
26569 editor.undoManager.transact(() => {
26570 if (internalContent || isInternalDrop && needsInternalDrop) {
26571 editor.execCommand('Delete');
26572 }
26573 setFocusedRange(editor, rng);
26574 const trimmedContent = trimHtml(content);
26575 if (dropContent['text/html']) {
26576 pasteHtml(editor, trimmedContent, internal, true);
26577 } else {
26578 pasteText(editor, trimmedContent, true);
26579 }
26580 });
26581 });
26582 }
26583 });
26584 editor.on('dragstart', _e => {
26585 draggingInternallyState.set(true);
26586 });
26587 editor.on('dragover dragend', e => {
26588 if (shouldPasteDataImages(editor) && !draggingInternallyState.get()) {
26589 e.preventDefault();
26590 setFocusedRange(editor, getCaretRangeFromEvent(editor, e));
26591 }
26592 if (e.type === 'dragend') {
26593 draggingInternallyState.set(false);
26594 }
26595 });
26596 setupSummaryDeleteByDragFix(editor);
26597 };
26598
26599 const setup$9 = editor => {
26600 const processEvent = f => e => {
26601 f(editor, e);
26602 };
26603 const preProcess = getPastePreProcess(editor);
26604 if (isFunction(preProcess)) {
26605 editor.on('PastePreProcess', processEvent(preProcess));
26606 }
26607 const postProcess = getPastePostProcess(editor);
26608 if (isFunction(postProcess)) {
26609 editor.on('PastePostProcess', processEvent(postProcess));
26610 }
26611 };
26612
26613 const addPreProcessFilter = (editor, filterFunc) => {
26614 editor.on('PastePreProcess', e => {
26615 e.content = filterFunc(editor, e.content, e.internal);
26616 });
26617 };
26618 const rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi;
26619 const rgbToHex = value => Tools.trim(value).replace(rgbRegExp, rgbaToHexString).toLowerCase();
26620 const removeWebKitStyles = (editor, content, internal) => {
26621 const webKitStylesOption = getPasteWebkitStyles(editor);
26622 if (internal || webKitStylesOption === 'all' || !shouldPasteRemoveWebKitStyles(editor)) {
26623 return content;
26624 }
26625 const webKitStyles = webKitStylesOption ? webKitStylesOption.split(/[, ]/) : [];
26626 if (webKitStyles && webKitStylesOption !== 'none') {
26627 const dom = editor.dom, node = editor.selection.getNode();
26628 content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, (all, before, value, after) => {
26629 const inputStyles = dom.parseStyle(dom.decode(value));
26630 const outputStyles = {};
26631 for (let i = 0; i < webKitStyles.length; i++) {
26632 const inputValue = inputStyles[webKitStyles[i]];
26633 let compareInput = inputValue;
26634 let currentValue = dom.getStyle(node, webKitStyles[i], true);
26635 if (/color/.test(webKitStyles[i])) {
26636 compareInput = rgbToHex(compareInput);
26637 currentValue = rgbToHex(currentValue);
26638 }
26639 if (currentValue !== compareInput) {
26640 outputStyles[webKitStyles[i]] = inputValue;
26641 }
26642 }
26643 const outputStyle = dom.serializeStyle(outputStyles, 'span');
26644 if (outputStyle) {
26645 return before + ' style="' + outputStyle + '"' + after;
26646 }
26647 return before + after;
26648 });
26649 } else {
26650 content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, '$1$3');
26651 }
26652 content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, (all, before, value, after) => {
26653 return before + ' style="' + value + '"' + after;
26654 });
26655 return content;
26656 };
26657 const setup$8 = editor => {
26658 if (Env.browser.isChromium() || Env.browser.isSafari()) {
26659 addPreProcessFilter(editor, removeWebKitStyles);
26660 }
26661 };
26662
26663 const setup$7 = editor => {
26664 const draggingInternallyState = Cell(false);
26665 const pasteFormat = Cell(isPasteAsTextEnabled(editor) ? 'text' : 'html');
26666 const pasteBin = PasteBin(editor);
26667 setup$8(editor);
26668 register$1(editor, pasteFormat);
26669 setup$9(editor);
26670 editor.on('PreInit', () => {
26671 register(editor);
26672 setup$a(editor, draggingInternallyState);
26673 registerEventsAndFilters(editor, pasteBin, pasteFormat);
26674 });
26675 };
26676
26677 const preventSummaryToggle = editor => {
26678 editor.on('click', e => {
26679 if (editor.dom.getParent(e.target, 'details')) {
26680 e.preventDefault();
26681 }
26682 });
26683 };
26684 const filterDetails = editor => {
26685 editor.parser.addNodeFilter('details', elms => {
26686 const initialStateOption = getDetailsInitialState(editor);
26687 each$e(elms, details => {
26688 if (initialStateOption === 'expanded') {
26689 details.attr('open', 'open');
26690 } else if (initialStateOption === 'collapsed') {
26691 details.attr('open', null);
26692 }
26693 });
26694 });
26695 editor.serializer.addNodeFilter('details', elms => {
26696 const serializedStateOption = getDetailsSerializedState(editor);
26697 each$e(elms, details => {
26698 if (serializedStateOption === 'expanded') {
26699 details.attr('open', 'open');
26700 } else if (serializedStateOption === 'collapsed') {
26701 details.attr('open', null);
26702 }
26703 });
26704 });
26705 };
26706 const setup$6 = editor => {
26707 preventSummaryToggle(editor);
26708 filterDetails(editor);
26709 };
26710
26711 const isBr = isBr$6;
26712 const isText = isText$b;
26713 const isContentEditableFalse$2 = elm => isContentEditableFalse$b(elm.dom);
26714 const isContentEditableTrue = elm => isContentEditableTrue$3(elm.dom);
26715 const isRoot = rootNode => elm => eq(SugarElement.fromDom(rootNode), elm);
26716 const getClosestScope = (node, rootNode, schema) => closest$4(SugarElement.fromDom(node), elm => isContentEditableTrue(elm) || schema.isBlock(name(elm)), isRoot(rootNode)).getOr(SugarElement.fromDom(rootNode)).dom;
26717 const getClosestCef = (node, rootNode) => closest$4(SugarElement.fromDom(node), isContentEditableFalse$2, isRoot(rootNode));
26718 const findEdgeCaretCandidate = (startNode, scope, forward) => {
26719 const walker = new DomTreeWalker(startNode, scope);
26720 const next = forward ? walker.next.bind(walker) : walker.prev.bind(walker);
26721 let result = startNode;
26722 for (let current = forward ? startNode : next(); current && !isBr(current); current = next()) {
26723 if (isCaretCandidate$3(current)) {
26724 result = current;
26725 }
26726 }
26727 return result;
26728 };
26729 const findClosestBlockRange = (startRng, rootNode, schema) => {
26730 const startPos = CaretPosition.fromRangeStart(startRng);
26731 const clickNode = startPos.getNode();
26732 const scope = getClosestScope(clickNode, rootNode, schema);
26733 const startNode = findEdgeCaretCandidate(clickNode, scope, false);
26734 const endNode = findEdgeCaretCandidate(clickNode, scope, true);
26735 const rng = document.createRange();
26736 getClosestCef(startNode, scope).fold(() => {
26737 if (isText(startNode)) {
26738 rng.setStart(startNode, 0);
26739 } else {
26740 rng.setStartBefore(startNode);
26741 }
26742 }, cef => rng.setStartBefore(cef.dom));
26743 getClosestCef(endNode, scope).fold(() => {
26744 if (isText(endNode)) {
26745 rng.setEnd(endNode, endNode.data.length);
26746 } else {
26747 rng.setEndAfter(endNode);
26748 }
26749 }, cef => rng.setEndAfter(cef.dom));
26750 return rng;
26751 };
26752 const onTripleClickSelect = editor => {
26753 const rng = findClosestBlockRange(editor.selection.getRng(), editor.getBody(), editor.schema);
26754 editor.selection.setRng(normalize(rng));
26755 };
26756 const setup$5 = editor => {
26757 editor.on('mousedown', e => {
26758 if (e.detail >= 3) {
26759 e.preventDefault();
26760 onTripleClickSelect(editor);
26761 }
26762 });
26763 };
26764
26765 var FakeCaretPosition;
26766 (function (FakeCaretPosition) {
26767 FakeCaretPosition['Before'] = 'before';
26768 FakeCaretPosition['After'] = 'after';
26769 }(FakeCaretPosition || (FakeCaretPosition = {})));
26770 const distanceToRectLeft = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
26771 const distanceToRectRight = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
26772 const isInsideY = (clientY, clientRect) => clientY >= clientRect.top && clientY <= clientRect.bottom;
26773 const collidesY = (r1, r2) => r1.top < r2.bottom && r1.bottom > r2.top;
26774 const isOverlapping = (r1, r2) => {
26775 const overlap = overlapY(r1, r2) / Math.min(r1.height, r2.height);
26776 return collidesY(r1, r2) && overlap > 0.5;
26777 };
26778 const splitRectsPerAxis = (rects, y) => {
26779 const intersectingRects = filter$5(rects, rect => isInsideY(y, rect));
26780 return boundingClientRectFromRects(intersectingRects).fold(() => [
26781 [],
26782 rects
26783 ], boundingRect => {
26784 const {
26785 pass: horizontal,
26786 fail: vertical
26787 } = partition$2(rects, rect => isOverlapping(rect, boundingRect));
26788 return [
26789 horizontal,
26790 vertical
26791 ];
26792 });
26793 };
26794 const clientInfo = (rect, clientX) => {
26795 return {
26796 node: rect.node,
26797 position: distanceToRectLeft(rect, clientX) < distanceToRectRight(rect, clientX) ? FakeCaretPosition.Before : FakeCaretPosition.After
26798 };
26799 };
26800 const horizontalDistance = (rect, x, _y) => x > rect.left && x < rect.right ? 0 : Math.min(Math.abs(rect.left - x), Math.abs(rect.right - x));
26801 const closestChildCaretCandidateNodeRect = (children, clientX, clientY, findCloserTextNode) => {
26802 const caretCandidateRect = rect => {
26803 if (isCaretCandidate$3(rect.node)) {
26804 return Optional.some(rect);
26805 } else if (isElement$6(rect.node)) {
26806 return closestChildCaretCandidateNodeRect(from(rect.node.childNodes), clientX, clientY, false);
26807 } else {
26808 return Optional.none();
26809 }
26810 };
26811 const tryFindSecondBestTextNode = (closest, sndClosest, distance) => {
26812 return caretCandidateRect(sndClosest).filter(rect => {
26813 const deltaDistance = Math.abs(distance(closest, clientX, clientY) - distance(rect, clientX, clientY));
26814 return deltaDistance < 2 && isText$b(rect.node);
26815 });
26816 };
26817 const findClosestCaretCandidateNodeRect = (rects, distance) => {
26818 const sortedRects = sort(rects, (r1, r2) => distance(r1, clientX, clientY) - distance(r2, clientX, clientY));
26819 return findMap(sortedRects, caretCandidateRect).map(closest => {
26820 if (findCloserTextNode && !isText$b(closest.node) && sortedRects.length > 1) {
26821 return tryFindSecondBestTextNode(closest, sortedRects[1], distance).getOr(closest);
26822 } else {
26823 return closest;
26824 }
26825 });
26826 };
26827 const [horizontalRects, verticalRects] = splitRectsPerAxis(getClientRects(children), clientY);
26828 const {
26829 pass: above,
26830 fail: below
26831 } = partition$2(verticalRects, rect => rect.top < clientY);
26832 return findClosestCaretCandidateNodeRect(horizontalRects, horizontalDistance).orThunk(() => findClosestCaretCandidateNodeRect(below, distanceToRectEdgeFromXY)).orThunk(() => findClosestCaretCandidateNodeRect(above, distanceToRectEdgeFromXY));
26833 };
26834 const traverseUp = (rootElm, scope, clientX, clientY) => {
26835 const helper = (scope, prevScope) => {
26836 const isDragGhostContainer = node => isElement$6(node) && node.classList.contains('mce-drag-container');
26837 const childNodesWithoutGhost = filter$5(scope.dom.childNodes, not(isDragGhostContainer));
26838 return prevScope.fold(() => closestChildCaretCandidateNodeRect(childNodesWithoutGhost, clientX, clientY, true), prevScope => {
26839 const uncheckedChildren = filter$5(childNodesWithoutGhost, node => node !== prevScope.dom);
26840 return closestChildCaretCandidateNodeRect(uncheckedChildren, clientX, clientY, true);
26841 }).orThunk(() => {
26842 const parent = eq(scope, rootElm) ? Optional.none() : parentElement(scope);
26843 return parent.bind(newScope => helper(newScope, Optional.some(scope)));
26844 });
26845 };
26846 return helper(scope, Optional.none());
26847 };
26848 const closestCaretCandidateNodeRect = (root, clientX, clientY) => {
26849 const rootElm = SugarElement.fromDom(root);
26850 const ownerDoc = documentOrOwner(rootElm);
26851 const elementAtPoint = SugarElement.fromPoint(ownerDoc, clientX, clientY).filter(elm => contains(rootElm, elm));
26852 const element = elementAtPoint.getOr(rootElm);
26853 return traverseUp(rootElm, element, clientX, clientY);
26854 };
26855 const closestFakeCaretCandidate = (root, clientX, clientY) => closestCaretCandidateNodeRect(root, clientX, clientY).filter(rect => isFakeCaretTarget(rect.node)).map(rect => clientInfo(rect, clientX));
26856
26857 const getAbsolutePosition = elm => {
26858 var _a, _b;
26859 const clientRect = elm.getBoundingClientRect();
26860 const doc = elm.ownerDocument;
26861 const docElem = doc.documentElement;
26862 const win = doc.defaultView;
26863 return {
26864 top: clientRect.top + ((_a = win === null || win === void 0 ? void 0 : win.scrollY) !== null && _a !== void 0 ? _a : 0) - docElem.clientTop,
26865 left: clientRect.left + ((_b = win === null || win === void 0 ? void 0 : win.scrollX) !== null && _b !== void 0 ? _b : 0) - docElem.clientLeft
26866 };
26867 };
26868 const getBodyPosition = editor => editor.inline ? getAbsolutePosition(editor.getBody()) : {
26869 left: 0,
26870 top: 0
26871 };
26872 const getScrollPosition = editor => {
26873 const body = editor.getBody();
26874 return editor.inline ? {
26875 left: body.scrollLeft,
26876 top: body.scrollTop
26877 } : {
26878 left: 0,
26879 top: 0
26880 };
26881 };
26882 const getBodyScroll = editor => {
26883 const body = editor.getBody(), docElm = editor.getDoc().documentElement;
26884 const inlineScroll = {
26885 left: body.scrollLeft,
26886 top: body.scrollTop
26887 };
26888 const iframeScroll = {
26889 left: body.scrollLeft || docElm.scrollLeft,
26890 top: body.scrollTop || docElm.scrollTop
26891 };
26892 return editor.inline ? inlineScroll : iframeScroll;
26893 };
26894 const getMousePosition = (editor, event) => {
26895 if (event.target.ownerDocument !== editor.getDoc()) {
26896 const iframePosition = getAbsolutePosition(editor.getContentAreaContainer());
26897 const scrollPosition = getBodyScroll(editor);
26898 return {
26899 left: event.pageX - iframePosition.left + scrollPosition.left,
26900 top: event.pageY - iframePosition.top + scrollPosition.top
26901 };
26902 }
26903 return {
26904 left: event.pageX,
26905 top: event.pageY
26906 };
26907 };
26908 const calculatePosition = (bodyPosition, scrollPosition, mousePosition) => ({
26909 pageX: mousePosition.left - bodyPosition.left + scrollPosition.left,
26910 pageY: mousePosition.top - bodyPosition.top + scrollPosition.top
26911 });
26912 const calc = (editor, event) => calculatePosition(getBodyPosition(editor), getScrollPosition(editor), getMousePosition(editor, event));
26913
26914 const getTargetProps = target => ({
26915 target,
26916 srcElement: target
26917 });
26918 const makeDndEventFromMouseEvent = (type, mouseEvent, target, dataTransfer) => ({
26919 ...mouseEvent,
26920 dataTransfer,
26921 type,
26922 ...getTargetProps(target)
26923 });
26924 const makeDndEvent = (type, target, dataTransfer) => {
26925 const fail = die('Function not supported on simulated event.');
26926 const event = {
26927 bubbles: true,
26928 cancelBubble: false,
26929 cancelable: true,
26930 composed: false,
26931 currentTarget: null,
26932 defaultPrevented: false,
26933 eventPhase: 0,
26934 isTrusted: true,
26935 returnValue: false,
26936 timeStamp: 0,
26937 type,
26938 composedPath: fail,
26939 initEvent: fail,
26940 preventDefault: noop,
26941 stopImmediatePropagation: noop,
26942 stopPropagation: noop,
26943 AT_TARGET: window.Event.AT_TARGET,
26944 BUBBLING_PHASE: window.Event.BUBBLING_PHASE,
26945 CAPTURING_PHASE: window.Event.CAPTURING_PHASE,
26946 NONE: window.Event.NONE,
26947 altKey: false,
26948 button: 0,
26949 buttons: 0,
26950 clientX: 0,
26951 clientY: 0,
26952 ctrlKey: false,
26953 metaKey: false,
26954 movementX: 0,
26955 movementY: 0,
26956 offsetX: 0,
26957 offsetY: 0,
26958 pageX: 0,
26959 pageY: 0,
26960 relatedTarget: null,
26961 screenX: 0,
26962 screenY: 0,
26963 shiftKey: false,
26964 x: 0,
26965 y: 0,
26966 detail: 0,
26967 view: null,
26968 which: 0,
26969 initUIEvent: fail,
26970 initMouseEvent: fail,
26971 getModifierState: fail,
26972 dataTransfer,
26973 ...getTargetProps(target)
26974 };
26975 return event;
26976 };
26977 const makeDataTransferCopyForDragEvent = (dataTransfer, eventType) => {
26978 const copy = cloneDataTransfer(dataTransfer);
26979 if (eventType === 'dragstart') {
26980 setDragstartEvent(copy);
26981 setReadWriteMode(copy);
26982 } else if (eventType === 'drop') {
26983 setDropEvent(copy);
26984 setReadOnlyMode(copy);
26985 } else {
26986 setDragendEvent(copy);
26987 setProtectedMode(copy);
26988 }
26989 return copy;
26990 };
26991 const makeDragEvent = (type, target, dataTransfer, mouseEvent) => {
26992 const dataTransferForDispatch = makeDataTransferCopyForDragEvent(dataTransfer, type);
26993 return isUndefined(mouseEvent) ? makeDndEvent(type, target, dataTransferForDispatch) : makeDndEventFromMouseEvent(type, mouseEvent, target, dataTransferForDispatch);
26994 };
26995
26996 const scrollPixelsPerInterval = 32;
26997 const scrollIntervalValue = 100;
26998 const mouseRangeToTriggerScrollInsideEditor = 8;
26999 const mouseRangeToTriggerScrollOutsideEditor = 16;
27000 const isContentEditableFalse$1 = isContentEditableFalse$b;
27001 const isContentEditable = or(isContentEditableFalse$1, isContentEditableTrue$3);
27002 const isDraggable = (dom, rootElm, elm) => isContentEditableFalse$1(elm) && elm !== rootElm && dom.isEditable(elm.parentElement);
27003 const isValidDropTarget = (editor, targetElement, dragElement) => {
27004 if (isNullable(targetElement)) {
27005 return false;
27006 } else if (targetElement === dragElement || editor.dom.isChildOf(targetElement, dragElement)) {
27007 return false;
27008 } else {
27009 return editor.dom.isEditable(targetElement);
27010 }
27011 };
27012 const createGhost = (editor, elm, width, height) => {
27013 const dom = editor.dom;
27014 const clonedElm = elm.cloneNode(true);
27015 dom.setStyles(clonedElm, {
27016 width,
27017 height
27018 });
27019 dom.setAttrib(clonedElm, 'data-mce-selected', null);
27020 const ghostElm = dom.create('div', {
27021 'class': 'mce-drag-container',
27022 'data-mce-bogus': 'all',
27023 'unselectable': 'on',
27024 'contenteditable': 'false'
27025 });
27026 dom.setStyles(ghostElm, {
27027 position: 'absolute',
27028 opacity: 0.5,
27029 overflow: 'hidden',
27030 border: 0,
27031 padding: 0,
27032 margin: 0,
27033 width,
27034 height
27035 });
27036 dom.setStyles(clonedElm, {
27037 margin: 0,
27038 boxSizing: 'border-box'
27039 });
27040 ghostElm.appendChild(clonedElm);
27041 return ghostElm;
27042 };
27043 const appendGhostToBody = (ghostElm, bodyElm) => {
27044 if (ghostElm.parentNode !== bodyElm) {
27045 bodyElm.appendChild(ghostElm);
27046 }
27047 };
27048 const scrollEditor = (direction, amount) => win => () => {
27049 const current = direction === 'left' ? win.scrollX : win.scrollY;
27050 win.scroll({
27051 [direction]: current + amount,
27052 behavior: 'smooth'
27053 });
27054 };
27055 const scrollLeft = scrollEditor('left', -scrollPixelsPerInterval);
27056 const scrollRight = scrollEditor('left', scrollPixelsPerInterval);
27057 const scrollUp = scrollEditor('top', -scrollPixelsPerInterval);
27058 const scrollDown = scrollEditor('top', scrollPixelsPerInterval);
27059 const moveGhost = (ghostElm, position, width, height, maxX, maxY, mouseY, mouseX, contentAreaContainer, win, state, mouseEventOriginatedFromWithinTheEditor) => {
27060 let overflowX = 0, overflowY = 0;
27061 ghostElm.style.left = position.pageX + 'px';
27062 ghostElm.style.top = position.pageY + 'px';
27063 if (position.pageX + width > maxX) {
27064 overflowX = position.pageX + width - maxX;
27065 }
27066 if (position.pageY + height > maxY) {
27067 overflowY = position.pageY + height - maxY;
27068 }
27069 ghostElm.style.width = width - overflowX + 'px';
27070 ghostElm.style.height = height - overflowY + 'px';
27071 const clientHeight = contentAreaContainer.clientHeight;
27072 const clientWidth = contentAreaContainer.clientWidth;
27073 const outerMouseY = mouseY + contentAreaContainer.getBoundingClientRect().top;
27074 const outerMouseX = mouseX + contentAreaContainer.getBoundingClientRect().left;
27075 state.on(state => {
27076 state.intervalId.clear();
27077 if (state.dragging && mouseEventOriginatedFromWithinTheEditor) {
27078 if (mouseY + mouseRangeToTriggerScrollInsideEditor >= clientHeight) {
27079 state.intervalId.set(scrollDown(win));
27080 } else if (mouseY - mouseRangeToTriggerScrollInsideEditor <= 0) {
27081 state.intervalId.set(scrollUp(win));
27082 } else if (mouseX + mouseRangeToTriggerScrollInsideEditor >= clientWidth) {
27083 state.intervalId.set(scrollRight(win));
27084 } else if (mouseX - mouseRangeToTriggerScrollInsideEditor <= 0) {
27085 state.intervalId.set(scrollLeft(win));
27086 } else if (outerMouseY + mouseRangeToTriggerScrollOutsideEditor >= window.innerHeight) {
27087 state.intervalId.set(scrollDown(window));
27088 } else if (outerMouseY - mouseRangeToTriggerScrollOutsideEditor <= 0) {
27089 state.intervalId.set(scrollUp(window));
27090 } else if (outerMouseX + mouseRangeToTriggerScrollOutsideEditor >= window.innerWidth) {
27091 state.intervalId.set(scrollRight(window));
27092 } else if (outerMouseX - mouseRangeToTriggerScrollOutsideEditor <= 0) {
27093 state.intervalId.set(scrollLeft(window));
27094 }
27095 }
27096 });
27097 };
27098 const removeElement = elm => {
27099 if (elm && elm.parentNode) {
27100 elm.parentNode.removeChild(elm);
27101 }
27102 };
27103 const removeElementWithPadding = (dom, elm) => {
27104 const parentBlock = dom.getParent(elm.parentNode, dom.isBlock);
27105 removeElement(elm);
27106 if (parentBlock && parentBlock !== dom.getRoot() && dom.isEmpty(parentBlock)) {
27107 fillWithPaddingBr(SugarElement.fromDom(parentBlock));
27108 }
27109 };
27110 const isLeftMouseButtonPressed = e => e.button === 0;
27111 const applyRelPos = (state, position) => ({
27112 pageX: position.pageX - state.relX,
27113 pageY: position.pageY + 5
27114 });
27115 const start = (state, editor) => e => {
27116 if (isLeftMouseButtonPressed(e)) {
27117 const ceElm = find$2(editor.dom.getParents(e.target), isContentEditable).getOr(null);
27118 if (isNonNullable(ceElm) && isDraggable(editor.dom, editor.getBody(), ceElm)) {
27119 const elmPos = editor.dom.getPos(ceElm);
27120 const bodyElm = editor.getBody();
27121 const docElm = editor.getDoc().documentElement;
27122 state.set({
27123 element: ceElm,
27124 dataTransfer: createDataTransfer(),
27125 dragging: false,
27126 screenX: e.screenX,
27127 screenY: e.screenY,
27128 maxX: (editor.inline ? bodyElm.scrollWidth : docElm.offsetWidth) - 2,
27129 maxY: (editor.inline ? bodyElm.scrollHeight : docElm.offsetHeight) - 2,
27130 relX: e.pageX - elmPos.x,
27131 relY: e.pageY - elmPos.y,
27132 width: ceElm.offsetWidth,
27133 height: ceElm.offsetHeight,
27134 ghost: createGhost(editor, ceElm, ceElm.offsetWidth, ceElm.offsetHeight),
27135 intervalId: repeatable(scrollIntervalValue)
27136 });
27137 }
27138 }
27139 };
27140 const placeCaretAt = (editor, clientX, clientY) => {
27141 editor._selectionOverrides.hideFakeCaret();
27142 closestFakeCaretCandidate(editor.getBody(), clientX, clientY).fold(() => editor.selection.placeCaretAt(clientX, clientY), caretInfo => {
27143 const range = editor._selectionOverrides.showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
27144 if (range) {
27145 editor.selection.setRng(range);
27146 } else {
27147 editor.selection.placeCaretAt(clientX, clientY);
27148 }
27149 });
27150 };
27151 const dispatchDragEvent = (editor, type, target, dataTransfer, mouseEvent) => {
27152 if (type === 'dragstart') {
27153 setHtmlData(dataTransfer, editor.dom.getOuterHTML(target));
27154 }
27155 const event = makeDragEvent(type, target, dataTransfer, mouseEvent);
27156 const args = editor.dispatch(type, event);
27157 return args;
27158 };
27159 const move = (state, editor) => {
27160 const throttledPlaceCaretAt = first$1((clientX, clientY) => placeCaretAt(editor, clientX, clientY), 0);
27161 editor.on('remove', throttledPlaceCaretAt.cancel);
27162 const state_ = state;
27163 return e => state.on(state => {
27164 const movement = Math.max(Math.abs(e.screenX - state.screenX), Math.abs(e.screenY - state.screenY));
27165 if (!state.dragging && movement > 10) {
27166 const args = dispatchDragEvent(editor, 'dragstart', state.element, state.dataTransfer, e);
27167 if (isNonNullable(args.dataTransfer)) {
27168 state.dataTransfer = args.dataTransfer;
27169 }
27170 if (args.isDefaultPrevented()) {
27171 return;
27172 }
27173 state.dragging = true;
27174 editor.focus();
27175 }
27176 if (state.dragging) {
27177 const mouseEventOriginatedFromWithinTheEditor = e.currentTarget === editor.getDoc().documentElement;
27178 const targetPos = applyRelPos(state, calc(editor, e));
27179 appendGhostToBody(state.ghost, editor.getBody());
27180 moveGhost(state.ghost, targetPos, state.width, state.height, state.maxX, state.maxY, e.clientY, e.clientX, editor.getContentAreaContainer(), editor.getWin(), state_, mouseEventOriginatedFromWithinTheEditor);
27181 throttledPlaceCaretAt.throttle(e.clientX, e.clientY);
27182 }
27183 });
27184 };
27185 const getRawTarget = selection => {
27186 const sel = selection.getSel();
27187 if (isNonNullable(sel)) {
27188 const rng = sel.getRangeAt(0);
27189 const startContainer = rng.startContainer;
27190 return isText$b(startContainer) ? startContainer.parentNode : startContainer;
27191 } else {
27192 return null;
27193 }
27194 };
27195 const drop = (state, editor) => e => {
27196 state.on(state => {
27197 var _a;
27198 state.intervalId.clear();
27199 if (state.dragging) {
27200 if (isValidDropTarget(editor, getRawTarget(editor.selection), state.element)) {
27201 const dropTarget = (_a = editor.getDoc().elementFromPoint(e.clientX, e.clientY)) !== null && _a !== void 0 ? _a : editor.getBody();
27202 const args = dispatchDragEvent(editor, 'drop', dropTarget, state.dataTransfer, e);
27203 if (!args.isDefaultPrevented()) {
27204 editor.undoManager.transact(() => {
27205 removeElementWithPadding(editor.dom, state.element);
27206 getHtmlData(state.dataTransfer).each(content => editor.insertContent(content));
27207 editor._selectionOverrides.hideFakeCaret();
27208 });
27209 }
27210 }
27211 dispatchDragEvent(editor, 'dragend', editor.getBody(), state.dataTransfer, e);
27212 }
27213 });
27214 removeDragState(state);
27215 };
27216 const stopDragging = (state, editor, e) => {
27217 state.on(state => {
27218 state.intervalId.clear();
27219 if (state.dragging) {
27220 e.fold(() => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer), mouseEvent => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer, mouseEvent));
27221 }
27222 });
27223 removeDragState(state);
27224 };
27225 const stop = (state, editor) => e => stopDragging(state, editor, Optional.some(e));
27226 const removeDragState = state => {
27227 state.on(state => {
27228 state.intervalId.clear();
27229 removeElement(state.ghost);
27230 });
27231 state.clear();
27232 };
27233 const bindFakeDragEvents = editor => {
27234 const state = value$2();
27235 const pageDom = DOMUtils.DOM;
27236 const rootDocument = document;
27237 const dragStartHandler = start(state, editor);
27238 const dragHandler = move(state, editor);
27239 const dropHandler = drop(state, editor);
27240 const dragEndHandler = stop(state, editor);
27241 editor.on('mousedown', dragStartHandler);
27242 editor.on('mousemove', dragHandler);
27243 editor.on('mouseup', dropHandler);
27244 pageDom.bind(rootDocument, 'mousemove', dragHandler);
27245 pageDom.bind(rootDocument, 'mouseup', dragEndHandler);
27246 editor.on('remove', () => {
27247 pageDom.unbind(rootDocument, 'mousemove', dragHandler);
27248 pageDom.unbind(rootDocument, 'mouseup', dragEndHandler);
27249 });
27250 editor.on('keydown', e => {
27251 if (e.keyCode === VK.ESC) {
27252 stopDragging(state, editor, Optional.none());
27253 }
27254 });
27255 };
27256 const blockUnsupportedFileDrop = editor => {
27257 const preventFileDrop = e => {
27258 if (!e.isDefaultPrevented()) {
27259 const dataTransfer = e.dataTransfer;
27260 if (dataTransfer && (contains$2(dataTransfer.types, 'Files') || dataTransfer.files.length > 0)) {
27261 e.preventDefault();
27262 if (e.type === 'drop') {
27263 displayError(editor, 'Dropped file type is not supported');
27264 }
27265 }
27266 }
27267 };
27268 const preventFileDropIfUIElement = e => {
27269 if (isUIElement(editor, e.target)) {
27270 preventFileDrop(e);
27271 }
27272 };
27273 const setup = () => {
27274 const pageDom = DOMUtils.DOM;
27275 const dom = editor.dom;
27276 const doc = document;
27277 const editorRoot = editor.inline ? editor.getBody() : editor.getDoc();
27278 const eventNames = [
27279 'drop',
27280 'dragover'
27281 ];
27282 each$e(eventNames, name => {
27283 pageDom.bind(doc, name, preventFileDropIfUIElement);
27284 dom.bind(editorRoot, name, preventFileDrop);
27285 });
27286 editor.on('remove', () => {
27287 each$e(eventNames, name => {
27288 pageDom.unbind(doc, name, preventFileDropIfUIElement);
27289 dom.unbind(editorRoot, name, preventFileDrop);
27290 });
27291 });
27292 };
27293 editor.on('init', () => {
27294 Delay.setEditorTimeout(editor, setup, 0);
27295 });
27296 };
27297 const init$2 = editor => {
27298 bindFakeDragEvents(editor);
27299 if (shouldBlockUnsupportedDrop(editor)) {
27300 blockUnsupportedFileDrop(editor);
27301 }
27302 };
27303
27304 const setup$4 = editor => {
27305 const renderFocusCaret = first$1(() => {
27306 if (!editor.removed && editor.getBody().contains(document.activeElement)) {
27307 const rng = editor.selection.getRng();
27308 if (rng.collapsed) {
27309 const caretRange = renderRangeCaret(editor, rng, false);
27310 editor.selection.setRng(caretRange);
27311 }
27312 }
27313 }, 0);
27314 editor.on('focus', () => {
27315 renderFocusCaret.throttle();
27316 });
27317 editor.on('blur', () => {
27318 renderFocusCaret.cancel();
27319 });
27320 };
27321
27322 const setup$3 = editor => {
27323 editor.on('init', () => {
27324 editor.on('focusin', e => {
27325 const target = e.target;
27326 if (isMedia$2(target)) {
27327 const ceRoot = getContentEditableRoot$1(editor.getBody(), target);
27328 const node = isContentEditableFalse$b(ceRoot) ? ceRoot : target;
27329 if (editor.selection.getNode() !== node) {
27330 selectNode(editor, node).each(rng => editor.selection.setRng(rng));
27331 }
27332 }
27333 });
27334 });
27335 };
27336
27337 const isContentEditableFalse = isContentEditableFalse$b;
27338 const getContentEditableRoot = (editor, node) => getContentEditableRoot$1(editor.getBody(), node);
27339 const SelectionOverrides = editor => {
27340 const selection = editor.selection, dom = editor.dom;
27341 const rootNode = editor.getBody();
27342 const fakeCaret = FakeCaret(editor, rootNode, dom.isBlock, () => hasFocus(editor));
27343 const realSelectionId = 'sel-' + dom.uniqueId();
27344 const elementSelectionAttr = 'data-mce-selected';
27345 let selectedElement;
27346 const isFakeSelectionElement = node => isNonNullable(node) && dom.hasClass(node, 'mce-offscreen-selection');
27347 const isFakeSelectionTargetElement = node => node !== rootNode && (isContentEditableFalse(node) || isMedia$2(node)) && dom.isChildOf(node, rootNode) && dom.isEditable(node.parentNode);
27348 const setRange = range => {
27349 if (range) {
27350 selection.setRng(range);
27351 }
27352 };
27353 const showCaret = (direction, node, before, scrollIntoView = true) => {
27354 const e = editor.dispatch('ShowCaret', {
27355 target: node,
27356 direction,
27357 before
27358 });
27359 if (e.isDefaultPrevented()) {
27360 return null;
27361 }
27362 if (scrollIntoView) {
27363 selection.scrollIntoView(node, direction === -1);
27364 }
27365 return fakeCaret.show(before, node);
27366 };
27367 const showBlockCaretContainer = blockCaretContainer => {
27368 if (blockCaretContainer.hasAttribute('data-mce-caret')) {
27369 showCaretContainerBlock(blockCaretContainer);
27370 selection.scrollIntoView(blockCaretContainer);
27371 }
27372 };
27373 const registerEvents = () => {
27374 editor.on('click', e => {
27375 if (!dom.isEditable(e.target)) {
27376 e.preventDefault();
27377 editor.focus();
27378 }
27379 });
27380 editor.on('blur NewBlock', removeElementSelection);
27381 editor.on('ResizeWindow FullscreenStateChanged', fakeCaret.reposition);
27382 editor.on('tap', e => {
27383 const targetElm = e.target;
27384 const contentEditableRoot = getContentEditableRoot(editor, targetElm);
27385 if (isContentEditableFalse(contentEditableRoot)) {
27386 e.preventDefault();
27387 selectNode(editor, contentEditableRoot).each(setElementSelection);
27388 } else if (isFakeSelectionTargetElement(targetElm)) {
27389 selectNode(editor, targetElm).each(setElementSelection);
27390 }
27391 }, true);
27392 editor.on('mousedown', e => {
27393 const targetElm = e.target;
27394 if (targetElm !== rootNode && targetElm.nodeName !== 'HTML' && !dom.isChildOf(targetElm, rootNode)) {
27395 return;
27396 }
27397 if (!isXYInContentArea(editor, e.clientX, e.clientY)) {
27398 return;
27399 }
27400 removeElementSelection();
27401 hideFakeCaret();
27402 const closestContentEditable = getContentEditableRoot(editor, targetElm);
27403 if (isContentEditableFalse(closestContentEditable)) {
27404 e.preventDefault();
27405 selectNode(editor, closestContentEditable).each(setElementSelection);
27406 } else {
27407 closestFakeCaretCandidate(rootNode, e.clientX, e.clientY).each(caretInfo => {
27408 e.preventDefault();
27409 const range = showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
27410 setRange(range);
27411 if (isHTMLElement(closestContentEditable)) {
27412 closestContentEditable.focus();
27413 } else {
27414 editor.getBody().focus();
27415 }
27416 });
27417 }
27418 });
27419 editor.on('keypress', e => {
27420 if (VK.modifierPressed(e)) {
27421 return;
27422 }
27423 if (isContentEditableFalse(selection.getNode())) {
27424 e.preventDefault();
27425 }
27426 });
27427 editor.on('GetSelectionRange', e => {
27428 let rng = e.range;
27429 if (selectedElement) {
27430 if (!selectedElement.parentNode) {
27431 selectedElement = null;
27432 return;
27433 }
27434 rng = rng.cloneRange();
27435 rng.selectNode(selectedElement);
27436 e.range = rng;
27437 }
27438 });
27439 editor.on('SetSelectionRange', e => {
27440 e.range = normalizeVoidElementSelection(e.range);
27441 const rng = setElementSelection(e.range, e.forward);
27442 if (rng) {
27443 e.range = rng;
27444 }
27445 });
27446 const isPasteBin = node => isElement$6(node) && node.id === 'mcepastebin';
27447 editor.on('AfterSetSelectionRange', e => {
27448 const rng = e.range;
27449 const parent = rng.startContainer.parentElement;
27450 if (!isRangeInCaretContainer(rng) && !isPasteBin(parent)) {
27451 hideFakeCaret();
27452 }
27453 if (!isFakeSelectionElement(parent)) {
27454 removeElementSelection();
27455 }
27456 });
27457 init$2(editor);
27458 setup$4(editor);
27459 setup$3(editor);
27460 };
27461 const isWithinCaretContainer = node => isCaretContainer$2(node) || startsWithCaretContainer$1(node) || endsWithCaretContainer$1(node);
27462 const isRangeInCaretContainer = rng => isWithinCaretContainer(rng.startContainer) || isWithinCaretContainer(rng.endContainer);
27463 const normalizeVoidElementSelection = rng => {
27464 const voidElements = editor.schema.getVoidElements();
27465 const newRng = dom.createRng();
27466 const startContainer = rng.startContainer;
27467 const startOffset = rng.startOffset;
27468 const endContainer = rng.endContainer;
27469 const endOffset = rng.endOffset;
27470 if (has$2(voidElements, startContainer.nodeName.toLowerCase())) {
27471 if (startOffset === 0) {
27472 newRng.setStartBefore(startContainer);
27473 } else {
27474 newRng.setStartAfter(startContainer);
27475 }
27476 } else {
27477 newRng.setStart(startContainer, startOffset);
27478 }
27479 if (has$2(voidElements, endContainer.nodeName.toLowerCase())) {
27480 if (endOffset === 0) {
27481 newRng.setEndBefore(endContainer);
27482 } else {
27483 newRng.setEndAfter(endContainer);
27484 }
27485 } else {
27486 newRng.setEnd(endContainer, endOffset);
27487 }
27488 return newRng;
27489 };
27490 const setupOffscreenSelection = (node, targetClone) => {
27491 const body = SugarElement.fromDom(editor.getBody());
27492 const doc = editor.getDoc();
27493 const realSelectionContainer = descendant$1(body, '#' + realSelectionId).getOrThunk(() => {
27494 const newContainer = SugarElement.fromHtml('<div data-mce-bogus="all" class="mce-offscreen-selection"></div>', doc);
27495 set$3(newContainer, 'id', realSelectionId);
27496 append$1(body, newContainer);
27497 return newContainer;
27498 });
27499 const newRange = dom.createRng();
27500 empty(realSelectionContainer);
27501 append(realSelectionContainer, [
27502 SugarElement.fromText(nbsp, doc),
27503 SugarElement.fromDom(targetClone),
27504 SugarElement.fromText(nbsp, doc)
27505 ]);
27506 newRange.setStart(realSelectionContainer.dom.firstChild, 1);
27507 newRange.setEnd(realSelectionContainer.dom.lastChild, 0);
27508 setAll(realSelectionContainer, { top: dom.getPos(node, editor.getBody()).y + 'px' });
27509 focus$1(realSelectionContainer);
27510 const sel = selection.getSel();
27511 if (sel) {
27512 sel.removeAllRanges();
27513 sel.addRange(newRange);
27514 }
27515 return newRange;
27516 };
27517 const selectElement = elm => {
27518 const targetClone = elm.cloneNode(true);
27519 const e = editor.dispatch('ObjectSelected', {
27520 target: elm,
27521 targetClone
27522 });
27523 if (e.isDefaultPrevented()) {
27524 return null;
27525 }
27526 const range = setupOffscreenSelection(elm, e.targetClone);
27527 const nodeElm = SugarElement.fromDom(elm);
27528 each$e(descendants(SugarElement.fromDom(editor.getBody()), `*[${ elementSelectionAttr }]`), elm => {
27529 if (!eq(nodeElm, elm)) {
27530 remove$9(elm, elementSelectionAttr);
27531 }
27532 });
27533 if (!dom.getAttrib(elm, elementSelectionAttr)) {
27534 elm.setAttribute(elementSelectionAttr, '1');
27535 }
27536 selectedElement = elm;
27537 hideFakeCaret();
27538 return range;
27539 };
27540 const setElementSelection = (range, forward) => {
27541 if (!range) {
27542 return null;
27543 }
27544 if (range.collapsed) {
27545 if (!isRangeInCaretContainer(range)) {
27546 const dir = forward ? 1 : -1;
27547 const caretPosition = getNormalizedRangeEndPoint(dir, rootNode, range);
27548 const beforeNode = caretPosition.getNode(!forward);
27549 if (isNonNullable(beforeNode)) {
27550 if (isFakeCaretTarget(beforeNode)) {
27551 return showCaret(dir, beforeNode, forward ? !caretPosition.isAtEnd() : false, false);
27552 }
27553 if (isCaretContainerInline(beforeNode) && isContentEditableFalse$b(beforeNode.nextSibling)) {
27554 const rng = dom.createRng();
27555 rng.setStart(beforeNode, 0);
27556 rng.setEnd(beforeNode, 0);
27557 return rng;
27558 }
27559 }
27560 const afterNode = caretPosition.getNode(forward);
27561 if (isNonNullable(afterNode)) {
27562 if (isFakeCaretTarget(afterNode)) {
27563 return showCaret(dir, afterNode, forward ? false : !caretPosition.isAtEnd(), false);
27564 }
27565 if (isCaretContainerInline(afterNode) && isContentEditableFalse$b(afterNode.previousSibling)) {
27566 const rng = dom.createRng();
27567 rng.setStart(afterNode, 1);
27568 rng.setEnd(afterNode, 1);
27569 return rng;
27570 }
27571 }
27572 }
27573 return null;
27574 }
27575 let startContainer = range.startContainer;
27576 let startOffset = range.startOffset;
27577 const endOffset = range.endOffset;
27578 if (isText$b(startContainer) && startOffset === 0 && isContentEditableFalse(startContainer.parentNode)) {
27579 startContainer = startContainer.parentNode;
27580 startOffset = dom.nodeIndex(startContainer);
27581 startContainer = startContainer.parentNode;
27582 }
27583 if (!isElement$6(startContainer)) {
27584 return null;
27585 }
27586 if (endOffset === startOffset + 1 && startContainer === range.endContainer) {
27587 const node = startContainer.childNodes[startOffset];
27588 if (isFakeSelectionTargetElement(node)) {
27589 return selectElement(node);
27590 }
27591 }
27592 return null;
27593 };
27594 const removeElementSelection = () => {
27595 if (selectedElement) {
27596 selectedElement.removeAttribute(elementSelectionAttr);
27597 }
27598 descendant$1(SugarElement.fromDom(editor.getBody()), '#' + realSelectionId).each(remove$4);
27599 selectedElement = null;
27600 };
27601 const destroy = () => {
27602 fakeCaret.destroy();
27603 selectedElement = null;
27604 };
27605 const hideFakeCaret = () => {
27606 fakeCaret.hide();
27607 };
27608 if (!isRtc(editor)) {
27609 registerEvents();
27610 }
27611 return {
27612 showCaret,
27613 showBlockCaretContainer,
27614 hideFakeCaret,
27615 destroy
27616 };
27617 };
27618
27619 const getNormalizedTextOffset = (container, offset) => {
27620 let normalizedOffset = offset;
27621 for (let node = container.previousSibling; isText$b(node); node = node.previousSibling) {
27622 normalizedOffset += node.data.length;
27623 }
27624 return normalizedOffset;
27625 };
27626 const generatePath = (dom, root, node, offset, normalized) => {
27627 if (isText$b(node) && (offset < 0 || offset > node.data.length)) {
27628 return [];
27629 }
27630 const p = normalized && isText$b(node) ? [getNormalizedTextOffset(node, offset)] : [offset];
27631 let current = node;
27632 while (current !== root && current.parentNode) {
27633 p.push(dom.nodeIndex(current, normalized));
27634 current = current.parentNode;
27635 }
27636 return current === root ? p.reverse() : [];
27637 };
27638 const generatePathRange = (dom, root, startNode, startOffset, endNode, endOffset, normalized = false) => {
27639 const start = generatePath(dom, root, startNode, startOffset, normalized);
27640 const end = generatePath(dom, root, endNode, endOffset, normalized);
27641 return {
27642 start,
27643 end
27644 };
27645 };
27646 const resolvePath = (root, path) => {
27647 const nodePath = path.slice();
27648 const offset = nodePath.pop();
27649 if (!isNumber(offset)) {
27650 return Optional.none();
27651 } else {
27652 const resolvedNode = foldl(nodePath, (optNode, index) => optNode.bind(node => Optional.from(node.childNodes[index])), Optional.some(root));
27653 return resolvedNode.bind(node => {
27654 if (isText$b(node) && (offset < 0 || offset > node.data.length)) {
27655 return Optional.none();
27656 } else {
27657 return Optional.some({
27658 node,
27659 offset
27660 });
27661 }
27662 });
27663 }
27664 };
27665 const resolvePathRange = (root, range) => resolvePath(root, range.start).bind(({
27666 node: startNode,
27667 offset: startOffset
27668 }) => resolvePath(root, range.end).map(({
27669 node: endNode,
27670 offset: endOffset
27671 }) => {
27672 const rng = document.createRange();
27673 rng.setStart(startNode, startOffset);
27674 rng.setEnd(endNode, endOffset);
27675 return rng;
27676 }));
27677 const generatePathRangeFromRange = (dom, root, range, normalized = false) => generatePathRange(dom, root, range.startContainer, range.startOffset, range.endContainer, range.endOffset, normalized);
27678
27679 const cleanEmptyNodes = (dom, node, isRoot) => {
27680 if (node && dom.isEmpty(node) && !isRoot(node)) {
27681 const parent = node.parentNode;
27682 dom.remove(node, isText$b(node.firstChild) && isWhitespaceText(node.firstChild.data));
27683 cleanEmptyNodes(dom, parent, isRoot);
27684 }
27685 };
27686 const deleteRng = (dom, rng, isRoot, clean = true) => {
27687 const startParent = rng.startContainer.parentNode;
27688 const endParent = rng.endContainer.parentNode;
27689 rng.deleteContents();
27690 if (clean && !isRoot(rng.startContainer)) {
27691 if (isText$b(rng.startContainer) && rng.startContainer.data.length === 0) {
27692 dom.remove(rng.startContainer);
27693 }
27694 if (isText$b(rng.endContainer) && rng.endContainer.data.length === 0) {
27695 dom.remove(rng.endContainer);
27696 }
27697 cleanEmptyNodes(dom, startParent, isRoot);
27698 if (startParent !== endParent) {
27699 cleanEmptyNodes(dom, endParent, isRoot);
27700 }
27701 }
27702 };
27703 const getParentBlock = (editor, rng) => Optional.from(editor.dom.getParent(rng.startContainer, editor.dom.isBlock));
27704 const resolveFromDynamicPatterns = (patternSet, block, beforeText) => {
27705 const dynamicPatterns = patternSet.dynamicPatternsLookup({
27706 text: beforeText,
27707 block
27708 });
27709 return {
27710 ...patternSet,
27711 blockPatterns: getBlockPatterns(dynamicPatterns).concat(patternSet.blockPatterns),
27712 inlinePatterns: getInlinePatterns(dynamicPatterns).concat(patternSet.inlinePatterns)
27713 };
27714 };
27715 const getBeforeText = (dom, block, node, offset) => {
27716 const rng = dom.createRng();
27717 rng.setStart(block, 0);
27718 rng.setEnd(node, offset);
27719 return rng.toString();
27720 };
27721
27722 const newMarker = (dom, id) => dom.create('span', {
27723 'data-mce-type': 'bookmark',
27724 id
27725 });
27726 const rangeFromMarker = (dom, marker) => {
27727 const rng = dom.createRng();
27728 rng.setStartAfter(marker.start);
27729 rng.setEndBefore(marker.end);
27730 return rng;
27731 };
27732 const createMarker = (dom, markerPrefix, pathRange) => {
27733 const rng = resolvePathRange(dom.getRoot(), pathRange).getOrDie('Unable to resolve path range');
27734 const startNode = rng.startContainer;
27735 const endNode = rng.endContainer;
27736 const textEnd = rng.endOffset === 0 ? endNode : endNode.splitText(rng.endOffset);
27737 const textStart = rng.startOffset === 0 ? startNode : startNode.splitText(rng.startOffset);
27738 const startParentNode = textStart.parentNode;
27739 const endParentNode = textEnd.parentNode;
27740 return {
27741 prefix: markerPrefix,
27742 end: endParentNode.insertBefore(newMarker(dom, markerPrefix + '-end'), textEnd),
27743 start: startParentNode.insertBefore(newMarker(dom, markerPrefix + '-start'), textStart)
27744 };
27745 };
27746 const removeMarker = (dom, marker, isRoot) => {
27747 cleanEmptyNodes(dom, dom.get(marker.prefix + '-end'), isRoot);
27748 cleanEmptyNodes(dom, dom.get(marker.prefix + '-start'), isRoot);
27749 };
27750
27751 const isReplacementPattern = pattern => pattern.start.length === 0;
27752 const matchesPattern = patternContent => (element, offset) => {
27753 const text = element.data;
27754 const searchText = text.substring(0, offset);
27755 const startEndIndex = searchText.lastIndexOf(patternContent.charAt(patternContent.length - 1));
27756 const startIndex = searchText.lastIndexOf(patternContent);
27757 if (startIndex !== -1) {
27758 return startIndex + patternContent.length;
27759 } else if (startEndIndex !== -1) {
27760 return startEndIndex + 1;
27761 } else {
27762 return -1;
27763 }
27764 };
27765 const findPatternStartFromSpot = (dom, pattern, block, spot) => {
27766 const startPattern = pattern.start;
27767 const startSpot = repeatLeft(dom, spot.container, spot.offset, matchesPattern(startPattern), block);
27768 return startSpot.bind(spot => {
27769 var _a, _b;
27770 const startPatternIndex = (_b = (_a = block.textContent) === null || _a === void 0 ? void 0 : _a.indexOf(startPattern)) !== null && _b !== void 0 ? _b : -1;
27771 const isCompleteMatch = startPatternIndex !== -1 && spot.offset >= startPatternIndex + startPattern.length;
27772 if (isCompleteMatch) {
27773 const rng = dom.createRng();
27774 rng.setStart(spot.container, spot.offset - startPattern.length);
27775 rng.setEnd(spot.container, spot.offset);
27776 return Optional.some(rng);
27777 } else {
27778 const offset = spot.offset - startPattern.length;
27779 return scanLeft(spot.container, offset, block).map(nextSpot => {
27780 const rng = dom.createRng();
27781 rng.setStart(nextSpot.container, nextSpot.offset);
27782 rng.setEnd(spot.container, spot.offset);
27783 return rng;
27784 }).filter(rng => rng.toString() === startPattern).orThunk(() => findPatternStartFromSpot(dom, pattern, block, point(spot.container, 0)));
27785 }
27786 });
27787 };
27788 const findPatternStart = (dom, pattern, node, offset, block, requireGap = false) => {
27789 if (pattern.start.length === 0 && !requireGap) {
27790 const rng = dom.createRng();
27791 rng.setStart(node, offset);
27792 rng.setEnd(node, offset);
27793 return Optional.some(rng);
27794 }
27795 return textBefore(node, offset, block).bind(spot => {
27796 const start = findPatternStartFromSpot(dom, pattern, block, spot);
27797 return start.bind(startRange => {
27798 var _a;
27799 if (requireGap) {
27800 if (startRange.endContainer === spot.container && startRange.endOffset === spot.offset) {
27801 return Optional.none();
27802 } else if (spot.offset === 0 && ((_a = startRange.endContainer.textContent) === null || _a === void 0 ? void 0 : _a.length) === startRange.endOffset) {
27803 return Optional.none();
27804 }
27805 }
27806 return Optional.some(startRange);
27807 });
27808 });
27809 };
27810 const findPattern$3 = (editor, block, details, normalizedMatches) => {
27811 const dom = editor.dom;
27812 const root = dom.getRoot();
27813 const pattern = details.pattern;
27814 const endNode = details.position.container;
27815 const endOffset = details.position.offset;
27816 return scanLeft(endNode, endOffset - details.pattern.end.length, block).bind(spot => {
27817 const endPathRng = generatePathRange(dom, root, spot.container, spot.offset, endNode, endOffset, normalizedMatches);
27818 if (isReplacementPattern(pattern)) {
27819 return Optional.some({
27820 matches: [{
27821 pattern,
27822 startRng: endPathRng,
27823 endRng: endPathRng
27824 }],
27825 position: spot
27826 });
27827 } else {
27828 const resultsOpt = findPatternsRec(editor, details.remainingPatterns, spot.container, spot.offset, block, normalizedMatches);
27829 const results = resultsOpt.getOr({
27830 matches: [],
27831 position: spot
27832 });
27833 const pos = results.position;
27834 const start = findPatternStart(dom, pattern, pos.container, pos.offset, block, resultsOpt.isNone());
27835 return start.map(startRng => {
27836 const startPathRng = generatePathRangeFromRange(dom, root, startRng, normalizedMatches);
27837 return {
27838 matches: results.matches.concat([{
27839 pattern,
27840 startRng: startPathRng,
27841 endRng: endPathRng
27842 }]),
27843 position: point(startRng.startContainer, startRng.startOffset)
27844 };
27845 });
27846 }
27847 });
27848 };
27849 const findPatternsRec = (editor, patterns, node, offset, block, normalizedMatches) => {
27850 const dom = editor.dom;
27851 return textBefore(node, offset, dom.getRoot()).bind(endSpot => {
27852 const text = getBeforeText(dom, block, node, offset);
27853 for (let i = 0; i < patterns.length; i++) {
27854 const pattern = patterns[i];
27855 if (!endsWith(text, pattern.end)) {
27856 continue;
27857 }
27858 const patternsWithoutCurrent = patterns.slice();
27859 patternsWithoutCurrent.splice(i, 1);
27860 const result = findPattern$3(editor, block, {
27861 pattern,
27862 remainingPatterns: patternsWithoutCurrent,
27863 position: endSpot
27864 }, normalizedMatches);
27865 if (result.isNone() && offset > 0) {
27866 return findPatternsRec(editor, patterns, node, offset - 1, block, normalizedMatches);
27867 }
27868 if (result.isSome()) {
27869 return result;
27870 }
27871 }
27872 return Optional.none();
27873 });
27874 };
27875 const applyPattern$2 = (editor, pattern, patternRange) => {
27876 editor.selection.setRng(patternRange);
27877 if (pattern.type === 'inline-format') {
27878 each$e(pattern.format, format => {
27879 editor.formatter.apply(format);
27880 });
27881 } else {
27882 editor.execCommand(pattern.cmd, false, pattern.value);
27883 }
27884 };
27885 const applyReplacementPattern = (editor, pattern, marker, isRoot) => {
27886 const markerRange = rangeFromMarker(editor.dom, marker);
27887 deleteRng(editor.dom, markerRange, isRoot);
27888 applyPattern$2(editor, pattern, markerRange);
27889 };
27890 const applyPatternWithContent = (editor, pattern, startMarker, endMarker, isRoot) => {
27891 const dom = editor.dom;
27892 const markerEndRange = rangeFromMarker(dom, endMarker);
27893 const markerStartRange = rangeFromMarker(dom, startMarker);
27894 deleteRng(dom, markerStartRange, isRoot);
27895 deleteRng(dom, markerEndRange, isRoot);
27896 const patternMarker = {
27897 prefix: startMarker.prefix,
27898 start: startMarker.end,
27899 end: endMarker.start
27900 };
27901 const patternRange = rangeFromMarker(dom, patternMarker);
27902 applyPattern$2(editor, pattern, patternRange);
27903 };
27904 const addMarkers = (dom, matches) => {
27905 const markerPrefix = generate$1('mce_textpattern');
27906 const matchesWithEnds = foldr(matches, (acc, match) => {
27907 const endMarker = createMarker(dom, markerPrefix + `_end${ acc.length }`, match.endRng);
27908 return acc.concat([{
27909 ...match,
27910 endMarker
27911 }]);
27912 }, []);
27913 return foldr(matchesWithEnds, (acc, match) => {
27914 const idx = matchesWithEnds.length - acc.length - 1;
27915 const startMarker = isReplacementPattern(match.pattern) ? match.endMarker : createMarker(dom, markerPrefix + `_start${ idx }`, match.startRng);
27916 return acc.concat([{
27917 ...match,
27918 startMarker
27919 }]);
27920 }, []);
27921 };
27922 const sortPatterns$1 = patterns => sort(patterns, (a, b) => b.end.length - a.end.length);
27923 const getBestMatches = (matches, matchesWithSortedPatterns) => {
27924 const hasSameMatches = forall(matches, match => exists(matchesWithSortedPatterns, sortedMatch => match.pattern.start === sortedMatch.pattern.start && match.pattern.end === sortedMatch.pattern.end));
27925 if (matches.length === matchesWithSortedPatterns.length) {
27926 if (hasSameMatches) {
27927 return matches;
27928 } else {
27929 return matchesWithSortedPatterns;
27930 }
27931 }
27932 return matches.length > matchesWithSortedPatterns.length ? matches : matchesWithSortedPatterns;
27933 };
27934 const findPatterns$2 = (editor, block, node, offset, patternSet, normalizedMatches) => {
27935 const matches = findPatternsRec(editor, patternSet.inlinePatterns, node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
27936 const matchesWithSortedPatterns = findPatternsRec(editor, sortPatterns$1(patternSet.inlinePatterns), node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
27937 return getBestMatches(matches, matchesWithSortedPatterns);
27938 };
27939 const applyMatches$2 = (editor, matches) => {
27940 if (matches.length === 0) {
27941 return;
27942 }
27943 const dom = editor.dom;
27944 const bookmark = editor.selection.getBookmark();
27945 const matchesWithMarkers = addMarkers(dom, matches);
27946 each$e(matchesWithMarkers, match => {
27947 const block = dom.getParent(match.startMarker.start, dom.isBlock);
27948 const isRoot = node => node === block;
27949 if (isReplacementPattern(match.pattern)) {
27950 applyReplacementPattern(editor, match.pattern, match.endMarker, isRoot);
27951 } else {
27952 applyPatternWithContent(editor, match.pattern, match.startMarker, match.endMarker, isRoot);
27953 }
27954 removeMarker(dom, match.endMarker, isRoot);
27955 removeMarker(dom, match.startMarker, isRoot);
27956 });
27957 editor.selection.moveToBookmark(bookmark);
27958 };
27959
27960 const stripPattern$1 = (dom, block, pattern) => {
27961 return textAfter(block, 0, block).map(spot => {
27962 const node = spot.container;
27963 scanRight(node, pattern.start.length, block).each(end => {
27964 const rng = dom.createRng();
27965 rng.setStart(node, 0);
27966 rng.setEnd(end.container, end.offset);
27967 deleteRng(dom, rng, e => e === block);
27968 });
27969 return node;
27970 });
27971 };
27972 const createApplyPattern = stripPattern => (editor, match) => {
27973 const dom = editor.dom;
27974 const pattern = match.pattern;
27975 const rng = resolvePathRange(dom.getRoot(), match.range).getOrDie('Unable to resolve path range');
27976 const isBlockFormatName = (name, formatter) => {
27977 const formatSet = formatter.get(name);
27978 return isArray$1(formatSet) && head(formatSet).exists(format => has$2(format, 'block'));
27979 };
27980 getParentBlock(editor, rng).each(block => {
27981 if (pattern.type === 'block-format') {
27982 if (isBlockFormatName(pattern.format, editor.formatter)) {
27983 editor.undoManager.transact(() => {
27984 stripPattern(editor.dom, block, pattern);
27985 editor.formatter.apply(pattern.format);
27986 });
27987 }
27988 } else if (pattern.type === 'block-command') {
27989 editor.undoManager.transact(() => {
27990 stripPattern(editor.dom, block, pattern);
27991 editor.execCommand(pattern.cmd, false, pattern.value);
27992 });
27993 }
27994 });
27995 return true;
27996 };
27997 const sortPatterns = patterns => sort(patterns, (a, b) => b.start.length - a.start.length);
27998 const findPattern$2 = predicate => (patterns, text) => {
27999 const sortedPatterns = sortPatterns(patterns);
28000 const nuText = text.replace(nbsp, ' ');
28001 return find$2(sortedPatterns, pattern => predicate(pattern, text, nuText));
28002 };
28003 const createFindPatterns = (findPattern, skipFullMatch) => (editor, block, patternSet, normalizedMatches, text) => {
28004 var _a;
28005 if (text === void 0) {
28006 text = (_a = block.textContent) !== null && _a !== void 0 ? _a : '';
28007 }
28008 const dom = editor.dom;
28009 const forcedRootBlock = getForcedRootBlock(editor);
28010 if (!dom.is(block, forcedRootBlock)) {
28011 return [];
28012 }
28013 return findPattern(patternSet.blockPatterns, text).map(pattern => {
28014 if (skipFullMatch && Tools.trim(text).length === pattern.start.length) {
28015 return [];
28016 }
28017 return [{
28018 pattern,
28019 range: generatePathRange(dom, dom.getRoot(), block, 0, block, 0, normalizedMatches)
28020 }];
28021 }).getOr([]);
28022 };
28023
28024 const startsWithSingleSpace = s => /^\s[^\s]/.test(s);
28025 const stripPattern = (dom, block, pattern) => {
28026 stripPattern$1(dom, block, pattern).each(node => {
28027 const text = SugarElement.fromDom(node);
28028 const textContent = get$3(text);
28029 if (startsWithSingleSpace(textContent)) {
28030 set(text, textContent.slice(1));
28031 }
28032 });
28033 };
28034 const applyPattern$1 = createApplyPattern(stripPattern);
28035 const findPattern$1 = findPattern$2((pattern, text, nuText) => text.indexOf(pattern.start) === 0 || nuText.indexOf(pattern.start) === 0);
28036 const findPatterns$1 = createFindPatterns(findPattern$1, true);
28037 const getMatches$1 = (editor, patternSet) => {
28038 const rng = editor.selection.getRng();
28039 return getParentBlock(editor, rng).map(block => {
28040 var _a;
28041 const offset = Math.max(0, rng.startOffset);
28042 const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, (_a = block.textContent) !== null && _a !== void 0 ? _a : '');
28043 const inlineMatches = findPatterns$2(editor, block, rng.startContainer, offset, dynamicPatternSet, true);
28044 const blockMatches = findPatterns$1(editor, block, dynamicPatternSet, true);
28045 return {
28046 inlineMatches,
28047 blockMatches
28048 };
28049 }).filter(({inlineMatches, blockMatches}) => blockMatches.length > 0 || inlineMatches.length > 0);
28050 };
28051 const applyMatches$1 = (editor, matches) => {
28052 if (matches.length === 0) {
28053 return;
28054 }
28055 const bookmark = editor.selection.getBookmark();
28056 each$e(matches, match => applyPattern$1(editor, match));
28057 editor.selection.moveToBookmark(bookmark);
28058 };
28059
28060 const applyPattern = createApplyPattern(stripPattern$1);
28061 const findPattern = findPattern$2((pattern, text, nuText) => text === pattern.start || nuText === pattern.start);
28062 const findPatterns = createFindPatterns(findPattern, false);
28063 const getMatches = (editor, patternSet) => {
28064 const rng = editor.selection.getRng();
28065 return getParentBlock(editor, rng).map(block => {
28066 const offset = Math.max(0, rng.startOffset);
28067 const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset);
28068 const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText);
28069 return findPatterns(editor, block, dynamicPatternSet, false, beforeText);
28070 }).filter(matches => matches.length > 0);
28071 };
28072 const applyMatches = (editor, matches) => {
28073 each$e(matches, match => applyPattern(editor, match));
28074 };
28075
28076 const handleEnter = (editor, patternSet) => getMatches$1(editor, patternSet).fold(never, ({inlineMatches, blockMatches}) => {
28077 editor.undoManager.add();
28078 editor.undoManager.extra(() => {
28079 editor.execCommand('mceInsertNewLine');
28080 }, () => {
28081 insert$5(editor);
28082 applyMatches$2(editor, inlineMatches);
28083 applyMatches$1(editor, blockMatches);
28084 const range = editor.selection.getRng();
28085 const spot = textBefore(range.startContainer, range.startOffset, editor.dom.getRoot());
28086 editor.execCommand('mceInsertNewLine');
28087 spot.each(s => {
28088 const node = s.container;
28089 if (node.data.charAt(s.offset - 1) === zeroWidth) {
28090 node.deleteData(s.offset - 1, 1);
28091 cleanEmptyNodes(editor.dom, node.parentNode, e => e === editor.dom.getRoot());
28092 }
28093 });
28094 });
28095 return true;
28096 });
28097 const handleInlineKey = (editor, patternSet) => {
28098 const rng = editor.selection.getRng();
28099 getParentBlock(editor, rng).map(block => {
28100 const offset = Math.max(0, rng.startOffset - 1);
28101 const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset);
28102 const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText);
28103 const inlineMatches = findPatterns$2(editor, block, rng.startContainer, offset, dynamicPatternSet, false);
28104 if (inlineMatches.length > 0) {
28105 editor.undoManager.transact(() => {
28106 applyMatches$2(editor, inlineMatches);
28107 });
28108 }
28109 });
28110 };
28111 const handleBlockPatternOnSpace = (editor, patternSet) => getMatches(editor, patternSet).fold(never, matches => {
28112 editor.undoManager.transact(() => {
28113 applyMatches(editor, matches);
28114 });
28115 return true;
28116 });
28117 const checkKeyEvent = (codes, event, predicate) => {
28118 for (let i = 0; i < codes.length; i++) {
28119 if (predicate(codes[i], event)) {
28120 return true;
28121 }
28122 }
28123 return false;
28124 };
28125 const checkKeyCode = (codes, event) => checkKeyEvent(codes, event, (code, event) => {
28126 return code === event.keyCode && !VK.modifierPressed(event);
28127 });
28128 const checkCharCode = (chars, event) => checkKeyEvent(chars, event, (chr, event) => {
28129 return chr.charCodeAt(0) === event.charCode;
28130 });
28131
28132 const setup$2 = editor => {
28133 const charCodes = [
28134 ',',
28135 '.',
28136 ';',
28137 ':',
28138 '!',
28139 '?'
28140 ];
28141 const keyCodes = [32];
28142 const getPatternSet = () => createPatternSet(getTextPatterns(editor), getTextPatternsLookup(editor));
28143 const hasDynamicPatterns = () => hasTextPatternsLookup(editor);
28144 editor.on('keydown', e => {
28145 if (e.keyCode === 13 && !VK.modifierPressed(e) && editor.selection.isCollapsed()) {
28146 const patternSet = filterByTrigger(getPatternSet(), 'enter');
28147 const hasPatterns = patternSet.inlinePatterns.length > 0 || patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
28148 if (hasPatterns && handleEnter(editor, patternSet)) {
28149 e.preventDefault();
28150 }
28151 }
28152 }, true);
28153 editor.on('keydown', e => {
28154 if (e.keyCode === 32 && editor.selection.isCollapsed()) {
28155 const patternSet = filterByTrigger(getPatternSet(), 'space');
28156 const hasPatterns = patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
28157 if (hasPatterns && handleBlockPatternOnSpace(editor, patternSet)) {
28158 e.preventDefault();
28159 }
28160 }
28161 }, true);
28162 const handleInlineTrigger = () => {
28163 if (editor.selection.isCollapsed()) {
28164 const patternSet = filterByTrigger(getPatternSet(), 'space');
28165 const hasPatterns = patternSet.inlinePatterns.length > 0 || hasDynamicPatterns();
28166 if (hasPatterns) {
28167 handleInlineKey(editor, patternSet);
28168 }
28169 }
28170 };
28171 editor.on('keyup', e => {
28172 if (checkKeyCode(keyCodes, e)) {
28173 handleInlineTrigger();
28174 }
28175 });
28176 editor.on('keypress', e => {
28177 if (checkCharCode(charCodes, e)) {
28178 Delay.setEditorTimeout(editor, handleInlineTrigger);
28179 }
28180 });
28181 };
28182
28183 const setup$1 = editor => {
28184 setup$2(editor);
28185 };
28186
28187 const Quirks = editor => {
28188 const each = Tools.each;
28189 const BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, parser = editor.parser;
28190 const browser = Env.browser;
28191 const isGecko = browser.isFirefox();
28192 const isWebKit = browser.isChromium() || browser.isSafari();
28193 const isiOS = Env.deviceType.isiPhone() || Env.deviceType.isiPad();
28194 const isMac = Env.os.isMacOS() || Env.os.isiOS();
28195 const setEditorCommandState = (cmd, state) => {
28196 try {
28197 editor.getDoc().execCommand(cmd, false, String(state));
28198 } catch (ex) {
28199 }
28200 };
28201 const isDefaultPrevented = e => {
28202 return e.isDefaultPrevented();
28203 };
28204 const emptyEditorWhenDeleting = () => {
28205 const serializeRng = rng => {
28206 const body = dom.create('body');
28207 const contents = rng.cloneContents();
28208 body.appendChild(contents);
28209 return selection.serializer.serialize(body, { format: 'html' });
28210 };
28211 const allContentsSelected = rng => {
28212 const selection = serializeRng(rng);
28213 const allRng = dom.createRng();
28214 allRng.selectNode(editor.getBody());
28215 const allSelection = serializeRng(allRng);
28216 return selection === allSelection;
28217 };
28218 editor.on('keydown', e => {
28219 const keyCode = e.keyCode;
28220 if (!isDefaultPrevented(e) && (keyCode === DELETE || keyCode === BACKSPACE) && editor.selection.isEditable()) {
28221 const isCollapsed = editor.selection.isCollapsed();
28222 const body = editor.getBody();
28223 if (isCollapsed && !isEmptyNode(editor.schema, body)) {
28224 return;
28225 }
28226 if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) {
28227 return;
28228 }
28229 e.preventDefault();
28230 editor.setContent('');
28231 if (body.firstChild && dom.isBlock(body.firstChild)) {
28232 editor.selection.setCursorLocation(body.firstChild, 0);
28233 } else {
28234 editor.selection.setCursorLocation(body, 0);
28235 }
28236 editor.nodeChanged();
28237 }
28238 });
28239 };
28240 const selectAll = () => {
28241 editor.shortcuts.add('meta+a', null, 'SelectAll');
28242 };
28243 const documentElementEditingFocus = () => {
28244 if (!editor.inline) {
28245 dom.bind(editor.getDoc(), 'mousedown mouseup', e => {
28246 let rng;
28247 if (e.target === editor.getDoc().documentElement) {
28248 rng = selection.getRng();
28249 editor.getBody().focus();
28250 if (e.type === 'mousedown') {
28251 if (isCaretContainer$2(rng.startContainer)) {
28252 return;
28253 }
28254 selection.placeCaretAt(e.clientX, e.clientY);
28255 } else {
28256 selection.setRng(rng);
28257 }
28258 }
28259 });
28260 }
28261 };
28262 const removeHrOnBackspace = () => {
28263 editor.on('keydown', e => {
28264 if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
28265 if (!editor.getBody().getElementsByTagName('hr').length) {
28266 return;
28267 }
28268 if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
28269 const node = selection.getNode();
28270 const previousSibling = node.previousSibling;
28271 if (node.nodeName === 'HR') {
28272 dom.remove(node);
28273 e.preventDefault();
28274 return;
28275 }
28276 if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'hr') {
28277 dom.remove(previousSibling);
28278 e.preventDefault();
28279 }
28280 }
28281 }
28282 });
28283 };
28284 const focusBody = () => {
28285 if (!Range.prototype.getClientRects) {
28286 editor.on('mousedown', e => {
28287 if (!isDefaultPrevented(e) && e.target.nodeName === 'HTML') {
28288 const body = editor.getBody();
28289 body.blur();
28290 Delay.setEditorTimeout(editor, () => {
28291 body.focus();
28292 });
28293 }
28294 });
28295 }
28296 };
28297 const selectControlElements = () => {
28298 const visualAidsAnchorClass = getVisualAidsAnchorClass(editor);
28299 editor.on('click', e => {
28300 const target = e.target;
28301 if (/^(IMG|HR)$/.test(target.nodeName) && dom.isEditable(target)) {
28302 e.preventDefault();
28303 editor.selection.select(target);
28304 editor.nodeChanged();
28305 }
28306 if (target.nodeName === 'A' && dom.hasClass(target, visualAidsAnchorClass) && target.childNodes.length === 0 && dom.isEditable(target.parentNode)) {
28307 e.preventDefault();
28308 selection.select(target);
28309 }
28310 });
28311 };
28312 const removeStylesWhenDeletingAcrossBlockElements = () => {
28313 const getAttributeApplyFunction = () => {
28314 const template = dom.getAttribs(selection.getStart().cloneNode(false));
28315 return () => {
28316 const target = selection.getStart();
28317 if (target !== editor.getBody()) {
28318 dom.setAttrib(target, 'style', null);
28319 each(template, attr => {
28320 target.setAttributeNode(attr.cloneNode(true));
28321 });
28322 }
28323 };
28324 };
28325 const isSelectionAcrossElements = () => {
28326 return !selection.isCollapsed() && dom.getParent(selection.getStart(), dom.isBlock) !== dom.getParent(selection.getEnd(), dom.isBlock);
28327 };
28328 editor.on('keypress', e => {
28329 let applyAttributes;
28330 if (!isDefaultPrevented(e) && (e.keyCode === 8 || e.keyCode === 46) && isSelectionAcrossElements()) {
28331 applyAttributes = getAttributeApplyFunction();
28332 editor.getDoc().execCommand('delete', false);
28333 applyAttributes();
28334 e.preventDefault();
28335 return false;
28336 } else {
28337 return true;
28338 }
28339 });
28340 dom.bind(editor.getDoc(), 'cut', e => {
28341 if (!isDefaultPrevented(e) && isSelectionAcrossElements()) {
28342 const applyAttributes = getAttributeApplyFunction();
28343 Delay.setEditorTimeout(editor, () => {
28344 applyAttributes();
28345 });
28346 }
28347 });
28348 };
28349 const disableBackspaceIntoATable = () => {
28350 editor.on('keydown', e => {
28351 if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
28352 if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
28353 const previousSibling = selection.getNode().previousSibling;
28354 if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'table') {
28355 e.preventDefault();
28356 return false;
28357 }
28358 }
28359 }
28360 return true;
28361 });
28362 };
28363 const removeBlockQuoteOnBackSpace = () => {
28364 editor.on('keydown', e => {
28365 if (isDefaultPrevented(e) || e.keyCode !== VK.BACKSPACE) {
28366 return;
28367 }
28368 let rng = selection.getRng();
28369 const container = rng.startContainer;
28370 const offset = rng.startOffset;
28371 const root = dom.getRoot();
28372 let parent = container;
28373 if (!rng.collapsed || offset !== 0) {
28374 return;
28375 }
28376 while (parent.parentNode && parent.parentNode.firstChild === parent && parent.parentNode !== root) {
28377 parent = parent.parentNode;
28378 }
28379 if (parent.nodeName === 'BLOCKQUOTE') {
28380 editor.formatter.toggle('blockquote', undefined, parent);
28381 rng = dom.createRng();
28382 rng.setStart(container, 0);
28383 rng.setEnd(container, 0);
28384 selection.setRng(rng);
28385 }
28386 });
28387 };
28388 const setGeckoEditingOptions = () => {
28389 const setOpts = () => {
28390 setEditorCommandState('StyleWithCSS', false);
28391 setEditorCommandState('enableInlineTableEditing', false);
28392 if (!getObjectResizing(editor)) {
28393 setEditorCommandState('enableObjectResizing', false);
28394 }
28395 };
28396 if (!isReadOnly$1(editor)) {
28397 editor.on('BeforeExecCommand mousedown', setOpts);
28398 }
28399 };
28400 const addBrAfterLastLinks = () => {
28401 const fixLinks = () => {
28402 each(dom.select('a:not([data-mce-block])'), node => {
28403 var _a;
28404 let parentNode = node.parentNode;
28405 const root = dom.getRoot();
28406 if ((parentNode === null || parentNode === void 0 ? void 0 : parentNode.lastChild) === node) {
28407 while (parentNode && !dom.isBlock(parentNode)) {
28408 if (((_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.lastChild) !== parentNode || parentNode === root) {
28409 return;
28410 }
28411 parentNode = parentNode.parentNode;
28412 }
28413 dom.add(parentNode, 'br', { 'data-mce-bogus': 1 });
28414 }
28415 });
28416 };
28417 editor.on('SetContent ExecCommand', e => {
28418 if (e.type === 'setcontent' || e.command === 'mceInsertLink') {
28419 fixLinks();
28420 }
28421 });
28422 };
28423 const setDefaultBlockType = () => {
28424 editor.on('init', () => {
28425 setEditorCommandState('DefaultParagraphSeparator', getForcedRootBlock(editor));
28426 });
28427 };
28428 const isAllContentSelected = editor => {
28429 const body = editor.getBody();
28430 const rng = editor.selection.getRng();
28431 return rng.startContainer === rng.endContainer && rng.startContainer === body && rng.startOffset === 0 && rng.endOffset === body.childNodes.length;
28432 };
28433 const normalizeSelection = () => {
28434 editor.on('keyup focusin mouseup', e => {
28435 if (!VK.modifierPressed(e) && !isAllContentSelected(editor)) {
28436 selection.normalize();
28437 }
28438 }, true);
28439 };
28440 const showBrokenImageIcon = () => {
28441 editor.contentStyles.push('img:-moz-broken {' + '-moz-force-broken-image-icon:1;' + 'min-width:24px;' + 'min-height:24px' + '}');
28442 };
28443 const restoreFocusOnKeyDown = () => {
28444 if (!editor.inline) {
28445 editor.on('keydown', () => {
28446 if (document.activeElement === document.body) {
28447 editor.getWin().focus();
28448 }
28449 });
28450 }
28451 };
28452 const bodyHeight = () => {
28453 if (!editor.inline) {
28454 editor.contentStyles.push('body {min-height: 150px}');
28455 editor.on('click', e => {
28456 let rng;
28457 if (e.target.nodeName === 'HTML') {
28458 rng = editor.selection.getRng();
28459 editor.getBody().focus();
28460 editor.selection.setRng(rng);
28461 editor.selection.normalize();
28462 editor.nodeChanged();
28463 }
28464 });
28465 }
28466 };
28467 const blockCmdArrowNavigation = () => {
28468 if (isMac) {
28469 editor.on('keydown', e => {
28470 if (VK.metaKeyPressed(e) && !e.shiftKey && (e.keyCode === 37 || e.keyCode === 39)) {
28471 e.preventDefault();
28472 const selection = editor.selection.getSel();
28473 selection.modify('move', e.keyCode === 37 ? 'backward' : 'forward', 'lineboundary');
28474 }
28475 });
28476 }
28477 };
28478 const tapLinksAndImages = () => {
28479 editor.on('click', e => {
28480 let elm = e.target;
28481 do {
28482 if (elm.tagName === 'A') {
28483 e.preventDefault();
28484 return;
28485 }
28486 } while (elm = elm.parentNode);
28487 });
28488 editor.contentStyles.push('.mce-content-body {-webkit-touch-callout: none}');
28489 };
28490 const blockFormSubmitInsideEditor = () => {
28491 editor.on('init', () => {
28492 editor.dom.bind(editor.getBody(), 'submit', e => {
28493 e.preventDefault();
28494 });
28495 });
28496 };
28497 const removeAppleInterchangeBrs = () => {
28498 parser.addNodeFilter('br', nodes => {
28499 let i = nodes.length;
28500 while (i--) {
28501 if (nodes[i].attr('class') === 'Apple-interchange-newline') {
28502 nodes[i].remove();
28503 }
28504 }
28505 });
28506 };
28507 const refreshContentEditable = noop;
28508 const isHidden = () => {
28509 if (!isGecko || editor.removed) {
28510 return false;
28511 }
28512 const sel = editor.selection.getSel();
28513 return !sel || !sel.rangeCount || sel.rangeCount === 0;
28514 };
28515 const setupRtc = () => {
28516 if (isWebKit) {
28517 documentElementEditingFocus();
28518 selectControlElements();
28519 blockFormSubmitInsideEditor();
28520 selectAll();
28521 if (isiOS) {
28522 restoreFocusOnKeyDown();
28523 bodyHeight();
28524 tapLinksAndImages();
28525 }
28526 }
28527 if (isGecko) {
28528 focusBody();
28529 setGeckoEditingOptions();
28530 showBrokenImageIcon();
28531 blockCmdArrowNavigation();
28532 }
28533 };
28534 const setup = () => {
28535 removeBlockQuoteOnBackSpace();
28536 emptyEditorWhenDeleting();
28537 if (!Env.windowsPhone) {
28538 normalizeSelection();
28539 }
28540 if (isWebKit) {
28541 documentElementEditingFocus();
28542 selectControlElements();
28543 setDefaultBlockType();
28544 blockFormSubmitInsideEditor();
28545 disableBackspaceIntoATable();
28546 removeAppleInterchangeBrs();
28547 if (isiOS) {
28548 restoreFocusOnKeyDown();
28549 bodyHeight();
28550 tapLinksAndImages();
28551 } else {
28552 selectAll();
28553 }
28554 }
28555 if (isGecko) {
28556 removeHrOnBackspace();
28557 focusBody();
28558 removeStylesWhenDeletingAcrossBlockElements();
28559 setGeckoEditingOptions();
28560 addBrAfterLastLinks();
28561 showBrokenImageIcon();
28562 blockCmdArrowNavigation();
28563 disableBackspaceIntoATable();
28564 }
28565 };
28566 if (isRtc(editor)) {
28567 setupRtc();
28568 } else {
28569 setup();
28570 }
28571 return {
28572 refreshContentEditable,
28573 isHidden
28574 };
28575 };
28576
28577 const isGplKey = key => key.toLowerCase() === 'gpl';
28578 const isValidGeneratedKey = key => key.length >= 64 && key.length <= 255;
28579 const validateLicenseKey = key => isGplKey(key) || isValidGeneratedKey(key) ? 'VALID' : 'INVALID';
28580 const validateEditorLicenseKey = editor => {
28581 const licenseKey = getLicenseKey(editor);
28582 const hasApiKey = isString(getApiKey(editor));
28583 if (!hasApiKey && (isUndefined(licenseKey) || validateLicenseKey(licenseKey) === 'INVALID')) {
28584 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/`);
28585 }
28586 };
28587
28588 const DOM$6 = DOMUtils.DOM;
28589 const appendStyle = (editor, text) => {
28590 const body = SugarElement.fromDom(editor.getBody());
28591 const container = getStyleContainer(getRootNode(body));
28592 const style = SugarElement.fromTag('style');
28593 set$3(style, 'type', 'text/css');
28594 append$1(style, SugarElement.fromText(text));
28595 append$1(container, style);
28596 editor.on('remove', () => {
28597 remove$4(style);
28598 });
28599 };
28600 const getRootName = editor => editor.inline ? editor.getElement().nodeName.toLowerCase() : undefined;
28601 const removeUndefined = obj => filter$4(obj, v => isUndefined(v) === false);
28602 const mkParserSettings = editor => {
28603 const getOption = editor.options.get;
28604 const blobCache = editor.editorUpload.blobCache;
28605 return removeUndefined({
28606 allow_conditional_comments: getOption('allow_conditional_comments'),
28607 allow_html_data_urls: getOption('allow_html_data_urls'),
28608 allow_svg_data_urls: getOption('allow_svg_data_urls'),
28609 allow_html_in_named_anchor: getOption('allow_html_in_named_anchor'),
28610 allow_script_urls: getOption('allow_script_urls'),
28611 allow_unsafe_link_target: getOption('allow_unsafe_link_target'),
28612 convert_unsafe_embeds: getOption('convert_unsafe_embeds'),
28613 convert_fonts_to_spans: getOption('convert_fonts_to_spans'),
28614 fix_list_elements: getOption('fix_list_elements'),
28615 font_size_legacy_values: getOption('font_size_legacy_values'),
28616 forced_root_block: getOption('forced_root_block'),
28617 forced_root_block_attrs: getOption('forced_root_block_attrs'),
28618 preserve_cdata: getOption('preserve_cdata'),
28619 inline_styles: getOption('inline_styles'),
28620 root_name: getRootName(editor),
28621 sandbox_iframes: getOption('sandbox_iframes'),
28622 sandbox_iframes_exclusions: getSandboxIframesExclusions(editor),
28623 sanitize: getOption('xss_sanitization'),
28624 validate: true,
28625 blob_cache: blobCache,
28626 document: editor.getDoc()
28627 });
28628 };
28629 const mkSchemaSettings = editor => {
28630 const getOption = editor.options.get;
28631 return removeUndefined({
28632 custom_elements: getOption('custom_elements'),
28633 extended_valid_elements: getOption('extended_valid_elements'),
28634 invalid_elements: getOption('invalid_elements'),
28635 invalid_styles: getOption('invalid_styles'),
28636 schema: getOption('schema'),
28637 valid_children: getOption('valid_children'),
28638 valid_classes: getOption('valid_classes'),
28639 valid_elements: getOption('valid_elements'),
28640 valid_styles: getOption('valid_styles'),
28641 verify_html: getOption('verify_html'),
28642 padd_empty_block_inline_children: getOption('format_empty_lines')
28643 });
28644 };
28645 const mkSerializerSettings = editor => {
28646 const getOption = editor.options.get;
28647 return {
28648 ...mkParserSettings(editor),
28649 ...mkSchemaSettings(editor),
28650 ...removeUndefined({
28651 remove_trailing_brs: getOption('remove_trailing_brs'),
28652 pad_empty_with_br: getOption('pad_empty_with_br'),
28653 url_converter: getOption('url_converter'),
28654 url_converter_scope: getOption('url_converter_scope'),
28655 element_format: getOption('element_format'),
28656 entities: getOption('entities'),
28657 entity_encoding: getOption('entity_encoding'),
28658 indent: getOption('indent'),
28659 indent_after: getOption('indent_after'),
28660 indent_before: getOption('indent_before')
28661 })
28662 };
28663 };
28664 const createParser = editor => {
28665 const parser = DomParser(mkParserSettings(editor), editor.schema);
28666 parser.addAttributeFilter('src,href,style,tabindex', (nodes, name) => {
28667 const dom = editor.dom;
28668 const internalName = 'data-mce-' + name;
28669 let i = nodes.length;
28670 while (i--) {
28671 const node = nodes[i];
28672 let value = node.attr(name);
28673 if (value && !node.attr(internalName)) {
28674 if (value.indexOf('data:') === 0 || value.indexOf('blob:') === 0) {
28675 continue;
28676 }
28677 if (name === 'style') {
28678 value = dom.serializeStyle(dom.parseStyle(value), node.name);
28679 if (!value.length) {
28680 value = null;
28681 }
28682 node.attr(internalName, value);
28683 node.attr(name, value);
28684 } else if (name === 'tabindex') {
28685 node.attr(internalName, value);
28686 node.attr(name, null);
28687 } else {
28688 node.attr(internalName, editor.convertURL(value, name, node.name));
28689 }
28690 }
28691 }
28692 });
28693 parser.addNodeFilter('script', nodes => {
28694 let i = nodes.length;
28695 while (i--) {
28696 const node = nodes[i];
28697 const type = node.attr('type') || 'no/type';
28698 if (type.indexOf('mce-') !== 0) {
28699 node.attr('type', 'mce-' + type);
28700 }
28701 }
28702 });
28703 if (shouldPreserveCData(editor)) {
28704 parser.addNodeFilter('#cdata', nodes => {
28705 var _a;
28706 let i = nodes.length;
28707 while (i--) {
28708 const node = nodes[i];
28709 node.type = 8;
28710 node.name = '#comment';
28711 node.value = '[CDATA[' + editor.dom.encode((_a = node.value) !== null && _a !== void 0 ? _a : '') + ']]';
28712 }
28713 });
28714 }
28715 parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', nodes => {
28716 let i = nodes.length;
28717 const nonEmptyElements = editor.schema.getNonEmptyElements();
28718 while (i--) {
28719 const node = nodes[i];
28720 if (node.isEmpty(nonEmptyElements) && node.getAll('br').length === 0) {
28721 node.append(new AstNode('br', 1));
28722 }
28723 }
28724 });
28725 return parser;
28726 };
28727 const autoFocus = editor => {
28728 const autoFocus = getAutoFocus(editor);
28729 if (autoFocus) {
28730 Delay.setEditorTimeout(editor, () => {
28731 let focusEditor;
28732 if (autoFocus === true) {
28733 focusEditor = editor;
28734 } else {
28735 focusEditor = editor.editorManager.get(autoFocus);
28736 }
28737 if (focusEditor && !focusEditor.destroyed) {
28738 focusEditor.focus();
28739 focusEditor.selection.scrollIntoView();
28740 }
28741 }, 100);
28742 }
28743 };
28744 const moveSelectionToFirstCaretPosition = editor => {
28745 const root = editor.dom.getRoot();
28746 if (!editor.inline && (!hasAnyRanges(editor) || editor.selection.getStart(true) === root)) {
28747 firstPositionIn(root).each(pos => {
28748 const node = pos.getNode();
28749 const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
28750 editor.selection.setRng(caretPos.toRange());
28751 });
28752 }
28753 };
28754 const initEditor = editor => {
28755 editor.bindPendingEventDelegates();
28756 editor.initialized = true;
28757 fireInit(editor);
28758 editor.focus(true);
28759 moveSelectionToFirstCaretPosition(editor);
28760 editor.nodeChanged({ initial: true });
28761 const initInstanceCallback = getInitInstanceCallback(editor);
28762 if (isFunction(initInstanceCallback)) {
28763 initInstanceCallback.call(editor, editor);
28764 }
28765 autoFocus(editor);
28766 };
28767 const getStyleSheetLoader$1 = editor => editor.inline ? editor.ui.styleSheetLoader : editor.dom.styleSheetLoader;
28768 const makeStylesheetLoadingPromises = (editor, css, framedFonts) => {
28769 const {
28770 pass: bundledCss,
28771 fail: normalCss
28772 } = partition$2(css, name => tinymce.Resource.has(toContentSkinResourceName(name)));
28773 const bundledPromises = bundledCss.map(url => {
28774 const css = tinymce.Resource.get(toContentSkinResourceName(url));
28775 if (isString(css)) {
28776 return Promise.resolve(getStyleSheetLoader$1(editor).loadRawCss(url, css));
28777 }
28778 return Promise.resolve();
28779 });
28780 const promises = [
28781 ...bundledPromises,
28782 getStyleSheetLoader$1(editor).loadAll(normalCss)
28783 ];
28784 if (editor.inline) {
28785 return promises;
28786 } else {
28787 return promises.concat([editor.ui.styleSheetLoader.loadAll(framedFonts)]);
28788 }
28789 };
28790 const loadContentCss = editor => {
28791 const styleSheetLoader = getStyleSheetLoader$1(editor);
28792 const fontCss = getFontCss(editor);
28793 const css = editor.contentCSS;
28794 const removeCss = () => {
28795 styleSheetLoader.unloadAll(css);
28796 if (!editor.inline) {
28797 editor.ui.styleSheetLoader.unloadAll(fontCss);
28798 }
28799 };
28800 const loaded = () => {
28801 if (editor.removed) {
28802 removeCss();
28803 } else {
28804 editor.on('remove', removeCss);
28805 }
28806 };
28807 if (editor.contentStyles.length > 0) {
28808 let contentCssText = '';
28809 Tools.each(editor.contentStyles, style => {
28810 contentCssText += style + '\r\n';
28811 });
28812 editor.dom.addStyle(contentCssText);
28813 }
28814 const allStylesheets = Promise.all(makeStylesheetLoadingPromises(editor, css, fontCss)).then(loaded).catch(loaded);
28815 const contentStyle = getContentStyle(editor);
28816 if (contentStyle) {
28817 appendStyle(editor, contentStyle);
28818 }
28819 return allStylesheets;
28820 };
28821 const preInit = editor => {
28822 const doc = editor.getDoc(), body = editor.getBody();
28823 firePreInit(editor);
28824 if (!shouldBrowserSpellcheck(editor)) {
28825 doc.body.spellcheck = false;
28826 DOM$6.setAttrib(body, 'spellcheck', 'false');
28827 }
28828 editor.quirks = Quirks(editor);
28829 firePostRender(editor);
28830 const directionality = getDirectionality(editor);
28831 if (directionality !== undefined) {
28832 body.dir = directionality;
28833 }
28834 const protect = getProtect(editor);
28835 if (protect) {
28836 editor.on('BeforeSetContent', e => {
28837 Tools.each(protect, pattern => {
28838 e.content = e.content.replace(pattern, str => {
28839 return '<!--mce:protected ' + escape(str) + '-->';
28840 });
28841 });
28842 });
28843 }
28844 editor.on('SetContent', () => {
28845 editor.addVisual(editor.getBody());
28846 });
28847 editor.on('compositionstart compositionend', e => {
28848 editor.composing = e.type === 'compositionstart';
28849 });
28850 };
28851 const loadInitialContent = editor => {
28852 if (!isRtc(editor)) {
28853 editor.load({
28854 initial: true,
28855 format: 'html'
28856 });
28857 }
28858 editor.startContent = editor.getContent({ format: 'raw' });
28859 };
28860 const initEditorWithInitialContent = editor => {
28861 if (editor.removed !== true) {
28862 loadInitialContent(editor);
28863 initEditor(editor);
28864 }
28865 };
28866 const startProgress = editor => {
28867 let canceled = false;
28868 const progressTimeout = setTimeout(() => {
28869 if (!canceled) {
28870 editor.setProgressState(true);
28871 }
28872 }, 500);
28873 return () => {
28874 clearTimeout(progressTimeout);
28875 canceled = true;
28876 editor.setProgressState(false);
28877 };
28878 };
28879 const contentBodyLoaded = editor => {
28880 const targetElm = editor.getElement();
28881 let doc = editor.getDoc();
28882 if (editor.inline) {
28883 DOM$6.addClass(targetElm, 'mce-content-body');
28884 editor.contentDocument = doc = document;
28885 editor.contentWindow = window;
28886 editor.bodyElement = targetElm;
28887 editor.contentAreaContainer = targetElm;
28888 }
28889 const body = editor.getBody();
28890 body.disabled = true;
28891 editor.readonly = isReadOnly$1(editor);
28892 editor._editableRoot = hasEditableRoot$1(editor);
28893 if (!editor.readonly && editor.hasEditableRoot()) {
28894 if (editor.inline && DOM$6.getStyle(body, 'position', true) === 'static') {
28895 body.style.position = 'relative';
28896 }
28897 body.contentEditable = 'true';
28898 }
28899 body.disabled = false;
28900 editor.editorUpload = EditorUpload(editor);
28901 editor.schema = Schema(mkSchemaSettings(editor));
28902 editor.dom = DOMUtils(doc, {
28903 keep_values: true,
28904 url_converter: editor.convertURL,
28905 url_converter_scope: editor,
28906 update_styles: true,
28907 root_element: editor.inline ? editor.getBody() : null,
28908 collect: editor.inline,
28909 schema: editor.schema,
28910 contentCssCors: shouldUseContentCssCors(editor),
28911 referrerPolicy: getReferrerPolicy(editor),
28912 onSetAttrib: e => {
28913 editor.dispatch('SetAttrib', e);
28914 }
28915 });
28916 editor.parser = createParser(editor);
28917 editor.serializer = DomSerializer(mkSerializerSettings(editor), editor);
28918 editor.selection = EditorSelection(editor.dom, editor.getWin(), editor.serializer, editor);
28919 editor.annotator = Annotator(editor);
28920 editor.formatter = Formatter(editor);
28921 editor.undoManager = UndoManager(editor);
28922 editor._nodeChangeDispatcher = new NodeChange(editor);
28923 editor._selectionOverrides = SelectionOverrides(editor);
28924 setup$p(editor);
28925 setup$6(editor);
28926 setup$n(editor);
28927 if (!isRtc(editor)) {
28928 setup$5(editor);
28929 setup$1(editor);
28930 }
28931 const caret = setup$b(editor);
28932 setup$q(editor, caret);
28933 setup$o(editor);
28934 setup$r(editor);
28935 setup$7(editor);
28936 const setupRtcThunk = setup$t(editor);
28937 preInit(editor);
28938 validateEditorLicenseKey(editor);
28939 setupRtcThunk.fold(() => {
28940 const cancelProgress = startProgress(editor);
28941 loadContentCss(editor).then(() => {
28942 initEditorWithInitialContent(editor);
28943 cancelProgress();
28944 });
28945 }, setupRtc => {
28946 editor.setProgressState(true);
28947 loadContentCss(editor).then(() => {
28948 setupRtc().then(_rtcMode => {
28949 editor.setProgressState(false);
28950 initEditorWithInitialContent(editor);
28951 bindEvents(editor);
28952 }, err => {
28953 editor.notificationManager.open({
28954 type: 'error',
28955 text: String(err)
28956 });
28957 initEditorWithInitialContent(editor);
28958 bindEvents(editor);
28959 });
28960 });
28961 });
28962 };
28963
28964 const filter = always;
28965 const bind = (element, event, handler) => bind$2(element, event, filter, handler);
28966
28967 const DOM$5 = DOMUtils.DOM;
28968 const createIframeElement = (id, title, customAttrs, tabindex) => {
28969 const iframe = SugarElement.fromTag('iframe');
28970 tabindex.each(t => set$3(iframe, 'tabindex', t));
28971 setAll$1(iframe, customAttrs);
28972 setAll$1(iframe, {
28973 id: id + '_ifr',
28974 frameBorder: '0',
28975 allowTransparency: 'true',
28976 title
28977 });
28978 add$2(iframe, 'tox-edit-area__iframe');
28979 return iframe;
28980 };
28981 const getIframeHtml = editor => {
28982 let iframeHTML = getDocType(editor) + '<html><head>';
28983 if (getDocumentBaseUrl(editor) !== editor.documentBaseUrl) {
28984 iframeHTML += '<base href="' + editor.documentBaseURI.getURI() + '" />';
28985 }
28986 iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
28987 const bodyId = getBodyId(editor);
28988 const bodyClass = getBodyClass(editor);
28989 const translatedAriaText = editor.translate(getIframeAriaText(editor));
28990 if (getContentSecurityPolicy(editor)) {
28991 iframeHTML += '<meta http-equiv="Content-Security-Policy" content="' + getContentSecurityPolicy(editor) + '" />';
28992 }
28993 iframeHTML += '</head>' + `<body id="${ bodyId }" class="mce-content-body ${ bodyClass }" data-id="${ editor.id }" aria-label="${ translatedAriaText }">` + '<br>' + '</body></html>';
28994 return iframeHTML;
28995 };
28996 const createIframe = (editor, boxInfo) => {
28997 const iframeTitle = Env.browser.isFirefox() ? getIframeAriaText(editor) : 'Rich Text Area';
28998 const translatedTitle = editor.translate(iframeTitle);
28999 const tabindex = getOpt(SugarElement.fromDom(editor.getElement()), 'tabindex').bind(toInt);
29000 const ifr = createIframeElement(editor.id, translatedTitle, getIframeAttrs(editor), tabindex).dom;
29001 ifr.onload = () => {
29002 ifr.onload = null;
29003 editor.dispatch('load');
29004 };
29005 editor.contentAreaContainer = boxInfo.iframeContainer;
29006 editor.iframeElement = ifr;
29007 editor.iframeHTML = getIframeHtml(editor);
29008 DOM$5.add(boxInfo.iframeContainer, ifr);
29009 };
29010 const setupIframeBody = editor => {
29011 const iframe = editor.iframeElement;
29012 const ready = () => {
29013 editor.contentDocument = iframe.contentDocument;
29014 contentBodyLoaded(editor);
29015 };
29016 if (shouldUseDocumentWrite(editor) || Env.browser.isFirefox()) {
29017 const doc = editor.getDoc();
29018 doc.open();
29019 doc.write(editor.iframeHTML);
29020 doc.close();
29021 ready();
29022 } else {
29023 const binder = bind(SugarElement.fromDom(iframe), 'load', () => {
29024 binder.unbind();
29025 ready();
29026 });
29027 iframe.srcdoc = editor.iframeHTML;
29028 }
29029 };
29030 const init$1 = (editor, boxInfo) => {
29031 createIframe(editor, boxInfo);
29032 if (boxInfo.editorContainer) {
29033 boxInfo.editorContainer.style.display = editor.orgDisplay;
29034 editor.hidden = DOM$5.isHidden(boxInfo.editorContainer);
29035 }
29036 editor.getElement().style.display = 'none';
29037 DOM$5.setAttrib(editor.id, 'aria-hidden', 'true');
29038 editor.getElement().style.visibility = editor.orgVisibility;
29039 setupIframeBody(editor);
29040 };
29041
29042 const DOM$4 = DOMUtils.DOM;
29043 const initPlugin = (editor, initializedPlugins, plugin) => {
29044 const Plugin = PluginManager.get(plugin);
29045 const pluginUrl = PluginManager.urls[plugin] || editor.documentBaseUrl.replace(/\/$/, '');
29046 plugin = Tools.trim(plugin);
29047 if (Plugin && Tools.inArray(initializedPlugins, plugin) === -1) {
29048 if (editor.plugins[plugin]) {
29049 return;
29050 }
29051 try {
29052 const pluginInstance = Plugin(editor, pluginUrl) || {};
29053 editor.plugins[plugin] = pluginInstance;
29054 if (isFunction(pluginInstance.init)) {
29055 pluginInstance.init(editor, pluginUrl);
29056 initializedPlugins.push(plugin);
29057 }
29058 } catch (e) {
29059 pluginInitError(editor, plugin, e);
29060 }
29061 }
29062 };
29063 const trimLegacyPrefix = name => {
29064 return name.replace(/^\-/, '');
29065 };
29066 const initPlugins = editor => {
29067 const initializedPlugins = [];
29068 each$e(getPlugins(editor), name => {
29069 initPlugin(editor, initializedPlugins, trimLegacyPrefix(name));
29070 });
29071 };
29072 const initIcons = editor => {
29073 const iconPackName = Tools.trim(getIconPackName(editor));
29074 const currentIcons = editor.ui.registry.getAll().icons;
29075 const loadIcons = {
29076 ...IconManager.get('default').icons,
29077 ...IconManager.get(iconPackName).icons
29078 };
29079 each$d(loadIcons, (svgData, icon) => {
29080 if (!has$2(currentIcons, icon)) {
29081 editor.ui.registry.addIcon(icon, svgData);
29082 }
29083 });
29084 };
29085 const initTheme = editor => {
29086 const theme = getTheme(editor);
29087 if (isString(theme)) {
29088 const Theme = ThemeManager.get(theme);
29089 editor.theme = Theme(editor, ThemeManager.urls[theme]) || {};
29090 if (isFunction(editor.theme.init)) {
29091 editor.theme.init(editor, ThemeManager.urls[theme] || editor.documentBaseUrl.replace(/\/$/, ''));
29092 }
29093 } else {
29094 editor.theme = {};
29095 }
29096 };
29097 const initModel = editor => {
29098 const model = getModel(editor);
29099 const Model = ModelManager.get(model);
29100 editor.model = Model(editor, ModelManager.urls[model]);
29101 };
29102 const renderFromLoadedTheme = editor => {
29103 const render = editor.theme.renderUI;
29104 return render ? render() : renderThemeFalse(editor);
29105 };
29106 const renderFromThemeFunc = editor => {
29107 const elm = editor.getElement();
29108 const theme = getTheme(editor);
29109 const info = theme(editor, elm);
29110 if (info.editorContainer.nodeType) {
29111 info.editorContainer.id = info.editorContainer.id || editor.id + '_parent';
29112 }
29113 if (info.iframeContainer && info.iframeContainer.nodeType) {
29114 info.iframeContainer.id = info.iframeContainer.id || editor.id + '_iframecontainer';
29115 }
29116 info.height = info.iframeHeight ? info.iframeHeight : elm.offsetHeight;
29117 return info;
29118 };
29119 const createThemeFalseResult = (element, iframe) => {
29120 return {
29121 editorContainer: element,
29122 iframeContainer: iframe,
29123 api: {}
29124 };
29125 };
29126 const renderThemeFalseIframe = targetElement => {
29127 const iframeContainer = DOM$4.create('div');
29128 DOM$4.insertAfter(iframeContainer, targetElement);
29129 return createThemeFalseResult(iframeContainer, iframeContainer);
29130 };
29131 const renderThemeFalse = editor => {
29132 const targetElement = editor.getElement();
29133 return editor.inline ? createThemeFalseResult(null) : renderThemeFalseIframe(targetElement);
29134 };
29135 const renderThemeUi = editor => {
29136 const elm = editor.getElement();
29137 editor.orgDisplay = elm.style.display;
29138 if (isString(getTheme(editor))) {
29139 return renderFromLoadedTheme(editor);
29140 } else if (isFunction(getTheme(editor))) {
29141 return renderFromThemeFunc(editor);
29142 } else {
29143 return renderThemeFalse(editor);
29144 }
29145 };
29146 const augmentEditorUiApi = (editor, api) => {
29147 const uiApiFacade = {
29148 show: Optional.from(api.show).getOr(noop),
29149 hide: Optional.from(api.hide).getOr(noop),
29150 isEnabled: Optional.from(api.isEnabled).getOr(always),
29151 setEnabled: state => {
29152 if (!editor.mode.isReadOnly()) {
29153 Optional.from(api.setEnabled).each(f => f(state));
29154 }
29155 }
29156 };
29157 editor.ui = {
29158 ...editor.ui,
29159 ...uiApiFacade
29160 };
29161 };
29162 const init = async editor => {
29163 editor.dispatch('ScriptsLoaded');
29164 initIcons(editor);
29165 initTheme(editor);
29166 initModel(editor);
29167 initPlugins(editor);
29168 const renderInfo = await renderThemeUi(editor);
29169 augmentEditorUiApi(editor, Optional.from(renderInfo.api).getOr({}));
29170 editor.editorContainer = renderInfo.editorContainer;
29171 appendContentCssFromSettings(editor);
29172 if (editor.inline) {
29173 contentBodyLoaded(editor);
29174 } else {
29175 init$1(editor, {
29176 editorContainer: renderInfo.editorContainer,
29177 iframeContainer: renderInfo.iframeContainer
29178 });
29179 }
29180 };
29181
29182 const DOM$3 = DOMUtils.DOM;
29183 const hasSkipLoadPrefix = name => name.charAt(0) === '-';
29184 const loadLanguage = (scriptLoader, editor) => {
29185 const languageCode = getLanguageCode(editor);
29186 const languageUrl = getLanguageUrl(editor);
29187 if (!I18n.hasCode(languageCode) && languageCode !== 'en') {
29188 const url = isNotEmpty(languageUrl) ? languageUrl : `${ editor.editorManager.baseURL }/langs/${ languageCode }.js`;
29189 scriptLoader.add(url).catch(() => {
29190 languageLoadError(editor, url, languageCode);
29191 });
29192 }
29193 };
29194 const loadTheme = (editor, suffix) => {
29195 const theme = getTheme(editor);
29196 if (isString(theme) && !hasSkipLoadPrefix(theme) && !has$2(ThemeManager.urls, theme)) {
29197 const themeUrl = getThemeUrl(editor);
29198 const url = themeUrl ? editor.documentBaseURI.toAbsolute(themeUrl) : `themes/${ theme }/theme${ suffix }.js`;
29199 ThemeManager.load(theme, url).catch(() => {
29200 themeLoadError(editor, url, theme);
29201 });
29202 }
29203 };
29204 const loadModel = (editor, suffix) => {
29205 const model = getModel(editor);
29206 if (model !== 'plugin' && !has$2(ModelManager.urls, model)) {
29207 const modelUrl = getModelUrl(editor);
29208 const url = isString(modelUrl) ? editor.documentBaseURI.toAbsolute(modelUrl) : `models/${ model }/model${ suffix }.js`;
29209 ModelManager.load(model, url).catch(() => {
29210 modelLoadError(editor, url, model);
29211 });
29212 }
29213 };
29214 const getIconsUrlMetaFromUrl = editor => Optional.from(getIconsUrl(editor)).filter(isNotEmpty).map(url => ({
29215 url,
29216 name: Optional.none()
29217 }));
29218 const getIconsUrlMetaFromName = (editor, name, suffix) => Optional.from(name).filter(name => isNotEmpty(name) && !IconManager.has(name)).map(name => ({
29219 url: `${ editor.editorManager.baseURL }/icons/${ name }/icons${ suffix }.js`,
29220 name: Optional.some(name)
29221 }));
29222 const loadIcons = (scriptLoader, editor, suffix) => {
29223 const defaultIconsUrl = getIconsUrlMetaFromName(editor, 'default', suffix);
29224 const customIconsUrl = getIconsUrlMetaFromUrl(editor).orThunk(() => getIconsUrlMetaFromName(editor, getIconPackName(editor), ''));
29225 each$e(cat([
29226 defaultIconsUrl,
29227 customIconsUrl
29228 ]), urlMeta => {
29229 scriptLoader.add(urlMeta.url).catch(() => {
29230 iconsLoadError(editor, urlMeta.url, urlMeta.name.getOrUndefined());
29231 });
29232 });
29233 };
29234 const loadPlugins = (editor, suffix) => {
29235 const loadPlugin = (name, url) => {
29236 PluginManager.load(name, url).catch(() => {
29237 pluginLoadError(editor, url, name);
29238 });
29239 };
29240 each$d(getExternalPlugins$1(editor), (url, name) => {
29241 loadPlugin(name, url);
29242 editor.options.set('plugins', getPlugins(editor).concat(name));
29243 });
29244 each$e(getPlugins(editor), plugin => {
29245 plugin = Tools.trim(plugin);
29246 if (plugin && !PluginManager.urls[plugin] && !hasSkipLoadPrefix(plugin)) {
29247 loadPlugin(plugin, `plugins/${ plugin }/plugin${ suffix }.js`);
29248 }
29249 });
29250 };
29251 const isThemeLoaded = editor => {
29252 const theme = getTheme(editor);
29253 return !isString(theme) || isNonNullable(ThemeManager.get(theme));
29254 };
29255 const isModelLoaded = editor => {
29256 const model = getModel(editor);
29257 return isNonNullable(ModelManager.get(model));
29258 };
29259 const loadScripts = (editor, suffix) => {
29260 const scriptLoader = ScriptLoader.ScriptLoader;
29261 const initEditor = () => {
29262 if (!editor.removed && isThemeLoaded(editor) && isModelLoaded(editor)) {
29263 init(editor);
29264 }
29265 };
29266 loadTheme(editor, suffix);
29267 loadModel(editor, suffix);
29268 loadLanguage(scriptLoader, editor);
29269 loadIcons(scriptLoader, editor, suffix);
29270 loadPlugins(editor, suffix);
29271 scriptLoader.loadQueue().then(initEditor, initEditor);
29272 };
29273 const getStyleSheetLoader = (element, editor) => instance.forElement(element, {
29274 contentCssCors: hasContentCssCors(editor),
29275 referrerPolicy: getReferrerPolicy(editor)
29276 });
29277 const render = editor => {
29278 const id = editor.id;
29279 I18n.setCode(getLanguageCode(editor));
29280 const readyHandler = () => {
29281 DOM$3.unbind(window, 'ready', readyHandler);
29282 editor.render();
29283 };
29284 if (!EventUtils.Event.domLoaded) {
29285 DOM$3.bind(window, 'ready', readyHandler);
29286 return;
29287 }
29288 if (!editor.getElement()) {
29289 return;
29290 }
29291 const element = SugarElement.fromDom(editor.getElement());
29292 const snapshot = clone$4(element);
29293 editor.on('remove', () => {
29294 eachr(element.dom.attributes, attr => remove$9(element, attr.name));
29295 setAll$1(element, snapshot);
29296 });
29297 editor.ui.styleSheetLoader = getStyleSheetLoader(element, editor);
29298 if (!isInline$1(editor)) {
29299 editor.orgVisibility = editor.getElement().style.visibility;
29300 editor.getElement().style.visibility = 'hidden';
29301 } else {
29302 editor.inline = true;
29303 }
29304 const form = editor.getElement().form || DOM$3.getParent(id, 'form');
29305 if (form) {
29306 editor.formElement = form;
29307 if (hasHiddenInput(editor) && !isTextareaOrInput(editor.getElement())) {
29308 DOM$3.insertAfter(DOM$3.create('input', {
29309 type: 'hidden',
29310 name: id
29311 }), id);
29312 editor.hasHiddenInput = true;
29313 }
29314 editor.formEventDelegate = e => {
29315 editor.dispatch(e.type, e);
29316 };
29317 DOM$3.bind(form, 'submit reset', editor.formEventDelegate);
29318 editor.on('reset', () => {
29319 editor.resetContent();
29320 });
29321 if (shouldPatchSubmit(editor) && !form.submit.nodeType && !form.submit.length && !form._mceOldSubmit) {
29322 form._mceOldSubmit = form.submit;
29323 form.submit = () => {
29324 editor.editorManager.triggerSave();
29325 editor.setDirty(false);
29326 return form._mceOldSubmit(form);
29327 };
29328 }
29329 }
29330 editor.windowManager = WindowManager(editor);
29331 editor.notificationManager = NotificationManager(editor);
29332 if (isEncodingXml(editor)) {
29333 editor.on('GetContent', e => {
29334 if (e.save) {
29335 e.content = DOM$3.encode(e.content);
29336 }
29337 });
29338 }
29339 if (shouldAddFormSubmitTrigger(editor)) {
29340 editor.on('submit', () => {
29341 if (editor.initialized) {
29342 editor.save();
29343 }
29344 });
29345 }
29346 if (shouldAddUnloadTrigger(editor)) {
29347 editor._beforeUnload = () => {
29348 if (editor.initialized && !editor.destroyed && !editor.isHidden()) {
29349 editor.save({
29350 format: 'raw',
29351 no_events: true,
29352 set_dirty: false
29353 });
29354 }
29355 };
29356 editor.editorManager.on('BeforeUnload', editor._beforeUnload);
29357 }
29358 editor.editorManager.add(editor);
29359 loadScripts(editor, editor.suffix);
29360 };
29361
29362 const setEditableRoot = (editor, state) => {
29363 if (editor._editableRoot !== state) {
29364 editor._editableRoot = state;
29365 if (!editor.readonly) {
29366 editor.getBody().contentEditable = String(editor.hasEditableRoot());
29367 editor.nodeChanged();
29368 }
29369 fireEditableRootStateChange(editor, state);
29370 }
29371 };
29372 const hasEditableRoot = editor => editor._editableRoot;
29373
29374 const sectionResult = (sections, settings) => ({
29375 sections: constant(sections),
29376 options: constant(settings)
29377 });
29378 const deviceDetection = detect$1().deviceType;
29379 const isPhone = deviceDetection.isPhone();
29380 const isTablet = deviceDetection.isTablet();
29381 const normalizePlugins = plugins => {
29382 if (isNullable(plugins)) {
29383 return [];
29384 } else {
29385 const pluginNames = isArray$1(plugins) ? plugins : plugins.split(/[ ,]/);
29386 const trimmedPlugins = map$3(pluginNames, trim$4);
29387 return filter$5(trimmedPlugins, isNotEmpty);
29388 }
29389 };
29390 const extractSections = (keys, options) => {
29391 const result = bifilter(options, (value, key) => {
29392 return contains$2(keys, key);
29393 });
29394 return sectionResult(result.t, result.f);
29395 };
29396 const getSection = (sectionResult, name, defaults = {}) => {
29397 const sections = sectionResult.sections();
29398 const sectionOptions = get$a(sections, name).getOr({});
29399 return Tools.extend({}, defaults, sectionOptions);
29400 };
29401 const hasSection = (sectionResult, name) => {
29402 return has$2(sectionResult.sections(), name);
29403 };
29404 const getSectionConfig = (sectionResult, name) => {
29405 return hasSection(sectionResult, name) ? sectionResult.sections()[name] : {};
29406 };
29407 const getMobileOverrideOptions = (mobileOptions, isPhone) => {
29408 const defaultMobileOptions = {
29409 table_grid: false,
29410 object_resizing: false,
29411 resize: false,
29412 toolbar_mode: get$a(mobileOptions, 'toolbar_mode').getOr('scrolling'),
29413 toolbar_sticky: false
29414 };
29415 const defaultPhoneOptions = { menubar: false };
29416 return {
29417 ...defaultMobileOptions,
29418 ...isPhone ? defaultPhoneOptions : {}
29419 };
29420 };
29421 const getExternalPlugins = (overrideOptions, options) => {
29422 var _a;
29423 const userDefinedExternalPlugins = (_a = options.external_plugins) !== null && _a !== void 0 ? _a : {};
29424 if (overrideOptions && overrideOptions.external_plugins) {
29425 return Tools.extend({}, overrideOptions.external_plugins, userDefinedExternalPlugins);
29426 } else {
29427 return userDefinedExternalPlugins;
29428 }
29429 };
29430 const combinePlugins = (forcedPlugins, plugins) => [
29431 ...normalizePlugins(forcedPlugins),
29432 ...normalizePlugins(plugins)
29433 ];
29434 const getPlatformPlugins = (isMobileDevice, sectionResult, desktopPlugins, mobilePlugins) => {
29435 if (isMobileDevice && hasSection(sectionResult, 'mobile')) {
29436 return mobilePlugins;
29437 } else {
29438 return desktopPlugins;
29439 }
29440 };
29441 const processPlugins = (isMobileDevice, sectionResult, defaultOverrideOptions, options) => {
29442 const forcedPlugins = normalizePlugins(defaultOverrideOptions.forced_plugins);
29443 const desktopPlugins = normalizePlugins(options.plugins);
29444 const mobileConfig = getSectionConfig(sectionResult, 'mobile');
29445 const mobilePlugins = mobileConfig.plugins ? normalizePlugins(mobileConfig.plugins) : desktopPlugins;
29446 const platformPlugins = getPlatformPlugins(isMobileDevice, sectionResult, desktopPlugins, mobilePlugins);
29447 const combinedPlugins = combinePlugins(forcedPlugins, platformPlugins);
29448 return Tools.extend(options, {
29449 forced_plugins: forcedPlugins,
29450 plugins: combinedPlugins
29451 });
29452 };
29453 const isOnMobile = (isMobileDevice, sectionResult) => {
29454 return isMobileDevice && hasSection(sectionResult, 'mobile');
29455 };
29456 const combineOptions = (isMobileDevice, isPhone, defaultOptions, defaultOverrideOptions, options) => {
29457 var _a;
29458 const deviceOverrideOptions = isMobileDevice ? { mobile: getMobileOverrideOptions((_a = options.mobile) !== null && _a !== void 0 ? _a : {}, isPhone) } : {};
29459 const sectionResult = extractSections(['mobile'], deepMerge(deviceOverrideOptions, options));
29460 const extendedOptions = Tools.extend(defaultOptions, defaultOverrideOptions, sectionResult.options(), isOnMobile(isMobileDevice, sectionResult) ? getSection(sectionResult, 'mobile') : {}, { external_plugins: getExternalPlugins(defaultOverrideOptions, sectionResult.options()) });
29461 return processPlugins(isMobileDevice, sectionResult, defaultOverrideOptions, extendedOptions);
29462 };
29463 const normalizeOptions = (defaultOverrideOptions, options) => combineOptions(isPhone || isTablet, isPhone, options, defaultOverrideOptions, options);
29464
29465 const addVisual = (editor, elm) => addVisual$1(editor, elm);
29466
29467 const registerExecCommands$2 = editor => {
29468 const toggleFormat = (name, value) => {
29469 editor.formatter.toggle(name, value);
29470 editor.nodeChanged();
29471 };
29472 const toggleAlign = align => () => {
29473 each$e('left,center,right,justify'.split(','), name => {
29474 if (align !== name) {
29475 editor.formatter.remove('align' + name);
29476 }
29477 });
29478 if (align !== 'none') {
29479 toggleFormat('align' + align);
29480 }
29481 };
29482 editor.editorCommands.addCommands({
29483 JustifyLeft: toggleAlign('left'),
29484 JustifyCenter: toggleAlign('center'),
29485 JustifyRight: toggleAlign('right'),
29486 JustifyFull: toggleAlign('justify'),
29487 JustifyNone: toggleAlign('none')
29488 });
29489 };
29490 const registerQueryStateCommands = editor => {
29491 const alignStates = name => () => {
29492 const selection = editor.selection;
29493 const nodes = selection.isCollapsed() ? [editor.dom.getParent(selection.getNode(), editor.dom.isBlock)] : selection.getSelectedBlocks();
29494 return exists(nodes, node => isNonNullable(editor.formatter.matchNode(node, name)));
29495 };
29496 editor.editorCommands.addCommands({
29497 JustifyLeft: alignStates('alignleft'),
29498 JustifyCenter: alignStates('aligncenter'),
29499 JustifyRight: alignStates('alignright'),
29500 JustifyFull: alignStates('alignjustify')
29501 }, 'state');
29502 };
29503 const registerCommands$a = editor => {
29504 registerExecCommands$2(editor);
29505 registerQueryStateCommands(editor);
29506 };
29507
29508 const registerCommands$9 = editor => {
29509 editor.editorCommands.addCommands({
29510 'Cut,Copy,Paste': command => {
29511 const doc = editor.getDoc();
29512 let failed;
29513 try {
29514 doc.execCommand(command);
29515 } catch (ex) {
29516 failed = true;
29517 }
29518 if (command === 'paste' && !doc.queryCommandEnabled(command)) {
29519 failed = true;
29520 }
29521 if (failed || !doc.queryCommandSupported(command)) {
29522 let msg = editor.translate(`Your browser doesn't support direct access to the clipboard. ` + 'Please use the Ctrl+X/C/V keyboard shortcuts instead.');
29523 if (Env.os.isMacOS() || Env.os.isiOS()) {
29524 msg = msg.replace(/Ctrl\+/g, '\u2318+');
29525 }
29526 editor.notificationManager.open({
29527 text: msg,
29528 type: 'error'
29529 });
29530 }
29531 }
29532 });
29533 };
29534
29535 const trimOrPadLeftRight = (dom, rng, html, schema) => {
29536 const root = SugarElement.fromDom(dom.getRoot());
29537 if (needsToBeNbspLeft(root, CaretPosition.fromRangeStart(rng), schema)) {
29538 html = html.replace(/^ /, '&nbsp;');
29539 } else {
29540 html = html.replace(/^&nbsp;/, ' ');
29541 }
29542 if (needsToBeNbspRight(root, CaretPosition.fromRangeEnd(rng), schema)) {
29543 html = html.replace(/(&nbsp;| )(<br( \/)>)?$/, '&nbsp;');
29544 } else {
29545 html = html.replace(/&nbsp;(<br( \/)?>)?$/, ' ');
29546 }
29547 return html;
29548 };
29549
29550 const processValue$1 = value => {
29551 if (typeof value !== 'string') {
29552 const details = Tools.extend({
29553 paste: value.paste,
29554 data: { paste: value.paste }
29555 }, value);
29556 return {
29557 content: value.content,
29558 details
29559 };
29560 }
29561 return {
29562 content: value,
29563 details: {}
29564 };
29565 };
29566 const trimOrPad = (editor, value) => {
29567 const selection = editor.selection;
29568 const dom = editor.dom;
29569 if (/^ | $/.test(value)) {
29570 return trimOrPadLeftRight(dom, selection.getRng(), value, editor.schema);
29571 } else {
29572 return value;
29573 }
29574 };
29575 const insertAtCaret = (editor, value) => {
29576 if (editor.selection.isEditable()) {
29577 const {content, details} = processValue$1(value);
29578 preProcessSetContent(editor, {
29579 ...details,
29580 content: trimOrPad(editor, content),
29581 format: 'html',
29582 set: false,
29583 selection: true
29584 }).each(args => {
29585 const insertedContent = insertContent$1(editor, args.content, details);
29586 postProcessSetContent(editor, insertedContent, args);
29587 editor.addVisual();
29588 });
29589 }
29590 };
29591
29592 const registerCommands$8 = editor => {
29593 editor.editorCommands.addCommands({
29594 mceCleanup: () => {
29595 const bm = editor.selection.getBookmark();
29596 editor.setContent(editor.getContent());
29597 editor.selection.moveToBookmark(bm);
29598 },
29599 insertImage: (_command, _ui, value) => {
29600 insertAtCaret(editor, editor.dom.createHTML('img', { src: value }));
29601 },
29602 insertHorizontalRule: () => {
29603 editor.execCommand('mceInsertContent', false, '<hr>');
29604 },
29605 insertText: (_command, _ui, value) => {
29606 insertAtCaret(editor, editor.dom.encode(value));
29607 },
29608 insertHTML: (_command, _ui, value) => {
29609 insertAtCaret(editor, value);
29610 },
29611 mceInsertContent: (_command, _ui, value) => {
29612 insertAtCaret(editor, value);
29613 },
29614 mceSetContent: (_command, _ui, value) => {
29615 editor.setContent(value);
29616 },
29617 mceReplaceContent: (_command, _ui, value) => {
29618 editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, editor.selection.getContent({ format: 'text' })));
29619 },
29620 mceNewDocument: () => {
29621 editor.setContent(getNewDocumentContent(editor));
29622 }
29623 });
29624 };
29625
29626 const legacyPropNames = {
29627 'font-size': 'size',
29628 'font-family': 'face'
29629 };
29630 const isFont = isTag('font');
29631 const getSpecifiedFontProp = (propName, rootElm, elm) => {
29632 const getProperty = elm => getRaw(elm, propName).orThunk(() => {
29633 if (isFont(elm)) {
29634 return get$a(legacyPropNames, propName).bind(legacyPropName => getOpt(elm, legacyPropName));
29635 } else {
29636 return Optional.none();
29637 }
29638 });
29639 const isRoot = elm => eq(SugarElement.fromDom(rootElm), elm);
29640 return closest$1(SugarElement.fromDom(elm), elm => getProperty(elm), isRoot);
29641 };
29642 const normalizeFontFamily = fontFamily => fontFamily.replace(/[\'\"\\]/g, '').replace(/,\s+/g, ',');
29643 const getComputedFontProp = (propName, elm) => Optional.from(DOMUtils.DOM.getStyle(elm, propName, true));
29644 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('');
29645 const getFontSize = getFontProp('font-size');
29646 const getFontFamily = compose(normalizeFontFamily, getFontProp('font-family'));
29647
29648 const findFirstCaretElement = editor => firstPositionIn(editor.getBody()).bind(caret => {
29649 const container = caret.container();
29650 return Optional.from(isText$b(container) ? container.parentNode : container);
29651 });
29652 const getCaretElement = editor => Optional.from(editor.selection.getRng()).bind(rng => {
29653 const root = editor.getBody();
29654 const atStartOfNode = rng.startContainer === root && rng.startOffset === 0;
29655 return atStartOfNode ? Optional.none() : Optional.from(editor.selection.getStart(true));
29656 });
29657 const bindRange = (editor, binder) => getCaretElement(editor).orThunk(curry(findFirstCaretElement, editor)).map(SugarElement.fromDom).filter(isElement$7).bind(binder);
29658 const mapRange = (editor, mapper) => bindRange(editor, compose1(Optional.some, mapper));
29659
29660 const fromFontSizeNumber = (editor, value) => {
29661 if (/^[0-9.]+$/.test(value)) {
29662 const fontSizeNumber = parseInt(value, 10);
29663 if (fontSizeNumber >= 1 && fontSizeNumber <= 7) {
29664 const fontSizes = getFontStyleValues(editor);
29665 const fontClasses = getFontSizeClasses(editor);
29666 if (fontClasses.length > 0) {
29667 return fontClasses[fontSizeNumber - 1] || value;
29668 } else {
29669 return fontSizes[fontSizeNumber - 1] || value;
29670 }
29671 } else {
29672 return value;
29673 }
29674 } else {
29675 return value;
29676 }
29677 };
29678 const normalizeFontNames = font => {
29679 const fonts = font.split(/\s*,\s*/);
29680 return map$3(fonts, font => {
29681 if (font.indexOf(' ') !== -1 && !(startsWith(font, '"') || startsWith(font, `'`))) {
29682 return `'${ font }'`;
29683 } else {
29684 return font;
29685 }
29686 }).join(',');
29687 };
29688 const fontNameAction = (editor, value) => {
29689 const font = fromFontSizeNumber(editor, value);
29690 editor.formatter.toggle('fontname', { value: normalizeFontNames(font) });
29691 editor.nodeChanged();
29692 };
29693 const fontNameQuery = editor => mapRange(editor, elm => getFontFamily(editor.getBody(), elm.dom)).getOr('');
29694 const fontSizeAction = (editor, value) => {
29695 editor.formatter.toggle('fontsize', { value: fromFontSizeNumber(editor, value) });
29696 editor.nodeChanged();
29697 };
29698 const fontSizeQuery = editor => mapRange(editor, elm => getFontSize(editor.getBody(), elm.dom)).getOr('');
29699
29700 const lineHeightQuery = editor => mapRange(editor, elm => {
29701 const root = SugarElement.fromDom(editor.getBody());
29702 const specifiedStyle = closest$1(elm, elm => getRaw(elm, 'line-height'), curry(eq, root));
29703 const computedStyle = () => {
29704 const lineHeight = parseFloat(get$7(elm, 'line-height'));
29705 const fontSize = parseFloat(get$7(elm, 'font-size'));
29706 return String(lineHeight / fontSize);
29707 };
29708 return specifiedStyle.getOrThunk(computedStyle);
29709 }).getOr('');
29710 const lineHeightAction = (editor, lineHeight) => {
29711 editor.formatter.toggle('lineheight', { value: String(lineHeight) });
29712 editor.nodeChanged();
29713 };
29714
29715 const registerExecCommands$1 = editor => {
29716 const toggleFormat = (name, value) => {
29717 editor.formatter.toggle(name, value);
29718 editor.nodeChanged();
29719 };
29720 editor.editorCommands.addCommands({
29721 'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => {
29722 toggleFormat(command);
29723 },
29724 'ForeColor,HiliteColor': (command, _ui, value) => {
29725 toggleFormat(command, { value });
29726 },
29727 'BackColor': (_command, _ui, value) => {
29728 toggleFormat('hilitecolor', { value });
29729 },
29730 'FontName': (_command, _ui, value) => {
29731 fontNameAction(editor, value);
29732 },
29733 'FontSize': (_command, _ui, value) => {
29734 fontSizeAction(editor, value);
29735 },
29736 'LineHeight': (_command, _ui, value) => {
29737 lineHeightAction(editor, value);
29738 },
29739 'Lang': (command, _ui, lang) => {
29740 var _a;
29741 toggleFormat(command, {
29742 value: lang.code,
29743 customValue: (_a = lang.customCode) !== null && _a !== void 0 ? _a : null
29744 });
29745 },
29746 'RemoveFormat': command => {
29747 editor.formatter.remove(command);
29748 },
29749 'mceBlockQuote': () => {
29750 toggleFormat('blockquote');
29751 },
29752 'FormatBlock': (_command, _ui, value) => {
29753 toggleFormat(isString(value) ? value : 'p');
29754 },
29755 'mceToggleFormat': (_command, _ui, value) => {
29756 toggleFormat(value);
29757 }
29758 });
29759 };
29760 const registerQueryValueCommands = editor => {
29761 const isFormatMatch = name => editor.formatter.match(name);
29762 editor.editorCommands.addCommands({
29763 'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => isFormatMatch(command),
29764 'mceBlockQuote': () => isFormatMatch('blockquote')
29765 }, 'state');
29766 editor.editorCommands.addQueryValueHandler('FontName', () => fontNameQuery(editor));
29767 editor.editorCommands.addQueryValueHandler('FontSize', () => fontSizeQuery(editor));
29768 editor.editorCommands.addQueryValueHandler('LineHeight', () => lineHeightQuery(editor));
29769 };
29770 const registerCommands$7 = editor => {
29771 registerExecCommands$1(editor);
29772 registerQueryValueCommands(editor);
29773 };
29774
29775 const registerCommands$6 = editor => {
29776 editor.editorCommands.addCommands({
29777 mceAddUndoLevel: () => {
29778 editor.undoManager.add();
29779 },
29780 mceEndUndoLevel: () => {
29781 editor.undoManager.add();
29782 },
29783 Undo: () => {
29784 editor.undoManager.undo();
29785 },
29786 Redo: () => {
29787 editor.undoManager.redo();
29788 }
29789 });
29790 };
29791
29792 const registerCommands$5 = editor => {
29793 editor.editorCommands.addCommands({
29794 Indent: () => {
29795 indent(editor);
29796 },
29797 Outdent: () => {
29798 outdent(editor);
29799 }
29800 });
29801 editor.editorCommands.addCommands({ Outdent: () => canOutdent(editor) }, 'state');
29802 };
29803
29804 const registerCommands$4 = editor => {
29805 const applyLinkToSelection = (_command, _ui, value) => {
29806 const linkDetails = isString(value) ? { href: value } : value;
29807 const anchor = editor.dom.getParent(editor.selection.getNode(), 'a');
29808 if (isObject(linkDetails) && isString(linkDetails.href)) {
29809 linkDetails.href = linkDetails.href.replace(/ /g, '%20');
29810 if (!anchor || !linkDetails.href) {
29811 editor.formatter.remove('link');
29812 }
29813 if (linkDetails.href) {
29814 editor.formatter.apply('link', linkDetails, anchor);
29815 }
29816 }
29817 };
29818 editor.editorCommands.addCommands({
29819 unlink: () => {
29820 if (editor.selection.isEditable()) {
29821 if (editor.selection.isCollapsed()) {
29822 const elm = editor.dom.getParent(editor.selection.getStart(), 'a');
29823 if (elm) {
29824 editor.dom.remove(elm, true);
29825 }
29826 return;
29827 }
29828 editor.formatter.remove('link');
29829 }
29830 },
29831 mceInsertLink: applyLinkToSelection,
29832 createLink: applyLinkToSelection
29833 });
29834 };
29835
29836 const getTopParentBlock = (editor, node, root, container) => {
29837 const dom = editor.dom;
29838 const selector = node => dom.isBlock(node) && node.parentElement === root;
29839 const topParentBlock = selector(node) ? node : dom.getParent(container, selector, root);
29840 return Optional.from(topParentBlock).map(SugarElement.fromDom);
29841 };
29842 const insert = (editor, before) => {
29843 const dom = editor.dom;
29844 const rng = editor.selection.getRng();
29845 const node = before ? editor.selection.getStart() : editor.selection.getEnd();
29846 const container = before ? rng.startContainer : rng.endContainer;
29847 const root = getEditableRoot(dom, container);
29848 if (!root || !root.isContentEditable) {
29849 return;
29850 }
29851 const insertFn = before ? before$3 : after$4;
29852 const newBlockName = getForcedRootBlock(editor);
29853 getTopParentBlock(editor, node, root, container).each(parentBlock => {
29854 const newBlock = createNewBlock(editor, container, parentBlock.dom, root, false, newBlockName);
29855 insertFn(parentBlock, SugarElement.fromDom(newBlock));
29856 editor.selection.setCursorLocation(newBlock, 0);
29857 editor.dispatch('NewBlock', { newBlock });
29858 fireInputEvent(editor, 'insertParagraph');
29859 });
29860 };
29861 const insertBefore = editor => insert(editor, true);
29862 const insertAfter = editor => insert(editor, false);
29863
29864 const registerCommands$3 = editor => {
29865 editor.editorCommands.addCommands({
29866 InsertNewBlockBefore: () => {
29867 insertBefore(editor);
29868 },
29869 InsertNewBlockAfter: () => {
29870 insertAfter(editor);
29871 }
29872 });
29873 };
29874
29875 const registerCommands$2 = editor => {
29876 editor.editorCommands.addCommands({
29877 insertParagraph: () => {
29878 insertBreak(blockbreak, editor);
29879 },
29880 mceInsertNewLine: (_command, _ui, value) => {
29881 insert$1(editor, value);
29882 },
29883 InsertLineBreak: (_command, _ui, _value) => {
29884 insertBreak(linebreak, editor);
29885 }
29886 });
29887 };
29888
29889 const registerCommands$1 = editor => {
29890 editor.editorCommands.addCommands({
29891 mceSelectNodeDepth: (_command, _ui, value) => {
29892 let counter = 0;
29893 editor.dom.getParent(editor.selection.getNode(), node => {
29894 if (isElement$6(node) && counter++ === value) {
29895 editor.selection.select(node);
29896 return false;
29897 } else {
29898 return true;
29899 }
29900 }, editor.getBody());
29901 },
29902 mceSelectNode: (_command, _ui, value) => {
29903 editor.selection.select(value);
29904 },
29905 selectAll: () => {
29906 const editingHost = editor.dom.getParent(editor.selection.getStart(), isContentEditableTrue$3);
29907 if (editingHost) {
29908 const rng = editor.dom.createRng();
29909 rng.selectNodeContents(editingHost);
29910 editor.selection.setRng(rng);
29911 }
29912 }
29913 });
29914 };
29915
29916 const registerExecCommands = editor => {
29917 editor.editorCommands.addCommands({
29918 mceRemoveNode: (_command, _ui, value) => {
29919 const node = value !== null && value !== void 0 ? value : editor.selection.getNode();
29920 if (node !== editor.getBody()) {
29921 const bm = editor.selection.getBookmark();
29922 editor.dom.remove(node, true);
29923 editor.selection.moveToBookmark(bm);
29924 }
29925 },
29926 mcePrint: () => {
29927 editor.getWin().print();
29928 },
29929 mceFocus: (_command, _ui, value) => {
29930 focus(editor, value === true);
29931 },
29932 mceToggleVisualAid: () => {
29933 editor.hasVisual = !editor.hasVisual;
29934 editor.addVisual();
29935 }
29936 });
29937 };
29938 const registerCommands = editor => {
29939 registerCommands$a(editor);
29940 registerCommands$9(editor);
29941 registerCommands$6(editor);
29942 registerCommands$1(editor);
29943 registerCommands$8(editor);
29944 registerCommands$4(editor);
29945 registerCommands$5(editor);
29946 registerCommands$3(editor);
29947 registerCommands$2(editor);
29948 registerCommands$7(editor);
29949 registerExecCommands(editor);
29950 };
29951
29952 const selectionSafeCommands = ['toggleview'];
29953 const isSelectionSafeCommand = command => contains$2(selectionSafeCommands, command.toLowerCase());
29954 class EditorCommands {
29955 constructor(editor) {
29956 this.commands = {
29957 state: {},
29958 exec: {},
29959 value: {}
29960 };
29961 this.editor = editor;
29962 }
29963 execCommand(command, ui = false, value, args) {
29964 const editor = this.editor;
29965 const lowerCaseCommand = command.toLowerCase();
29966 const skipFocus = args === null || args === void 0 ? void 0 : args.skip_focus;
29967 if (editor.removed) {
29968 return false;
29969 }
29970 if (lowerCaseCommand !== 'mcefocus') {
29971 if (!/^(mceAddUndoLevel|mceEndUndoLevel)$/i.test(lowerCaseCommand) && !skipFocus) {
29972 editor.focus();
29973 } else {
29974 restore(editor);
29975 }
29976 }
29977 const eventArgs = editor.dispatch('BeforeExecCommand', {
29978 command,
29979 ui,
29980 value
29981 });
29982 if (eventArgs.isDefaultPrevented()) {
29983 return false;
29984 }
29985 const func = this.commands.exec[lowerCaseCommand];
29986 if (isFunction(func)) {
29987 func(lowerCaseCommand, ui, value);
29988 editor.dispatch('ExecCommand', {
29989 command,
29990 ui,
29991 value
29992 });
29993 return true;
29994 }
29995 return false;
29996 }
29997 queryCommandState(command) {
29998 if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
29999 return false;
30000 }
30001 const lowerCaseCommand = command.toLowerCase();
30002 const func = this.commands.state[lowerCaseCommand];
30003 if (isFunction(func)) {
30004 return func(lowerCaseCommand);
30005 }
30006 return false;
30007 }
30008 queryCommandValue(command) {
30009 if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
30010 return '';
30011 }
30012 const lowerCaseCommand = command.toLowerCase();
30013 const func = this.commands.value[lowerCaseCommand];
30014 if (isFunction(func)) {
30015 return func(lowerCaseCommand);
30016 }
30017 return '';
30018 }
30019 addCommands(commandList, type = 'exec') {
30020 const commands = this.commands;
30021 each$d(commandList, (callback, command) => {
30022 each$e(command.toLowerCase().split(','), command => {
30023 commands[type][command] = callback;
30024 });
30025 });
30026 }
30027 addCommand(command, callback, scope) {
30028 const lowerCaseCommand = command.toLowerCase();
30029 this.commands.exec[lowerCaseCommand] = (_command, ui, value) => callback.call(scope !== null && scope !== void 0 ? scope : this.editor, ui, value);
30030 }
30031 queryCommandSupported(command) {
30032 const lowerCaseCommand = command.toLowerCase();
30033 if (this.commands.exec[lowerCaseCommand]) {
30034 return true;
30035 } else {
30036 return false;
30037 }
30038 }
30039 addQueryStateHandler(command, callback, scope) {
30040 this.commands.state[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
30041 }
30042 addQueryValueHandler(command, callback, scope) {
30043 this.commands.value[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
30044 }
30045 }
30046
30047 const internalContentEditableAttr = 'data-mce-contenteditable';
30048 const toggleClass = (elm, cls, state) => {
30049 if (has(elm, cls) && !state) {
30050 remove$6(elm, cls);
30051 } else if (state) {
30052 add$2(elm, cls);
30053 }
30054 };
30055 const setEditorCommandState = (editor, cmd, state) => {
30056 try {
30057 editor.getDoc().execCommand(cmd, false, String(state));
30058 } catch (ex) {
30059 }
30060 };
30061 const setContentEditable = (elm, state) => {
30062 elm.dom.contentEditable = state ? 'true' : 'false';
30063 };
30064 const switchOffContentEditableTrue = elm => {
30065 each$e(descendants(elm, '*[contenteditable="true"]'), elm => {
30066 set$3(elm, internalContentEditableAttr, 'true');
30067 setContentEditable(elm, false);
30068 });
30069 };
30070 const switchOnContentEditableTrue = elm => {
30071 each$e(descendants(elm, `*[${ internalContentEditableAttr }="true"]`), elm => {
30072 remove$9(elm, internalContentEditableAttr);
30073 setContentEditable(elm, true);
30074 });
30075 };
30076 const removeFakeSelection = editor => {
30077 Optional.from(editor.selection.getNode()).each(elm => {
30078 elm.removeAttribute('data-mce-selected');
30079 });
30080 };
30081 const restoreFakeSelection = editor => {
30082 editor.selection.setRng(editor.selection.getRng());
30083 };
30084 const toggleReadOnly = (editor, state) => {
30085 const body = SugarElement.fromDom(editor.getBody());
30086 toggleClass(body, 'mce-content-readonly', state);
30087 if (state) {
30088 editor.selection.controlSelection.hideResizeRect();
30089 editor._selectionOverrides.hideFakeCaret();
30090 removeFakeSelection(editor);
30091 editor.readonly = true;
30092 setContentEditable(body, false);
30093 switchOffContentEditableTrue(body);
30094 } else {
30095 editor.readonly = false;
30096 if (editor.hasEditableRoot()) {
30097 setContentEditable(body, true);
30098 }
30099 switchOnContentEditableTrue(body);
30100 setEditorCommandState(editor, 'StyleWithCSS', false);
30101 setEditorCommandState(editor, 'enableInlineTableEditing', false);
30102 setEditorCommandState(editor, 'enableObjectResizing', false);
30103 if (hasEditorOrUiFocus(editor)) {
30104 editor.focus();
30105 }
30106 restoreFakeSelection(editor);
30107 editor.nodeChanged();
30108 }
30109 };
30110 const isReadOnly = editor => editor.readonly;
30111 const registerFilters = editor => {
30112 editor.parser.addAttributeFilter('contenteditable', nodes => {
30113 if (isReadOnly(editor)) {
30114 each$e(nodes, node => {
30115 node.attr(internalContentEditableAttr, node.attr('contenteditable'));
30116 node.attr('contenteditable', 'false');
30117 });
30118 }
30119 });
30120 editor.serializer.addAttributeFilter(internalContentEditableAttr, nodes => {
30121 if (isReadOnly(editor)) {
30122 each$e(nodes, node => {
30123 node.attr('contenteditable', node.attr(internalContentEditableAttr));
30124 });
30125 }
30126 });
30127 editor.serializer.addTempAttr(internalContentEditableAttr);
30128 };
30129 const registerReadOnlyContentFilters = editor => {
30130 if (editor.serializer) {
30131 registerFilters(editor);
30132 } else {
30133 editor.on('PreInit', () => {
30134 registerFilters(editor);
30135 });
30136 }
30137 };
30138 const isClickEvent = e => e.type === 'click';
30139 const allowedEvents = ['copy'];
30140 const isReadOnlyAllowedEvent = e => contains$2(allowedEvents, e.type);
30141 const getAnchorHrefOpt = (editor, elm) => {
30142 const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
30143 return closest$3(elm, 'a', isRoot).bind(a => getOpt(a, 'href'));
30144 };
30145 const processReadonlyEvents = (editor, e) => {
30146 if (isClickEvent(e) && !VK.metaKeyPressed(e)) {
30147 const elm = SugarElement.fromDom(e.target);
30148 getAnchorHrefOpt(editor, elm).each(href => {
30149 e.preventDefault();
30150 if (/^#/.test(href)) {
30151 const targetEl = editor.dom.select(`${ href },[name="${ removeLeading(href, '#') }"]`);
30152 if (targetEl.length) {
30153 editor.selection.scrollIntoView(targetEl[0], true);
30154 }
30155 } else {
30156 window.open(href, '_blank', 'rel=noopener noreferrer,menubar=yes,toolbar=yes,location=yes,status=yes,resizable=yes,scrollbars=yes');
30157 }
30158 });
30159 } else if (isReadOnlyAllowedEvent(e)) {
30160 editor.dispatch(e.type, e);
30161 }
30162 };
30163 const registerReadOnlySelectionBlockers = editor => {
30164 editor.on('ShowCaret', e => {
30165 if (isReadOnly(editor)) {
30166 e.preventDefault();
30167 }
30168 });
30169 editor.on('ObjectSelected', e => {
30170 if (isReadOnly(editor)) {
30171 e.preventDefault();
30172 }
30173 });
30174 };
30175
30176 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', ' ');
30177 class EventDispatcher {
30178 static isNative(name) {
30179 return !!nativeEvents[name.toLowerCase()];
30180 }
30181 constructor(settings) {
30182 this.bindings = {};
30183 this.settings = settings || {};
30184 this.scope = this.settings.scope || this;
30185 this.toggleEvent = this.settings.toggleEvent || never;
30186 }
30187 fire(name, args) {
30188 return this.dispatch(name, args);
30189 }
30190 dispatch(name, args) {
30191 const lcName = name.toLowerCase();
30192 const event = normalize$3(lcName, args !== null && args !== void 0 ? args : {}, this.scope);
30193 if (this.settings.beforeFire) {
30194 this.settings.beforeFire(event);
30195 }
30196 const handlers = this.bindings[lcName];
30197 if (handlers) {
30198 for (let i = 0, l = handlers.length; i < l; i++) {
30199 const callback = handlers[i];
30200 if (callback.removed) {
30201 continue;
30202 }
30203 if (callback.once) {
30204 this.off(lcName, callback.func);
30205 }
30206 if (event.isImmediatePropagationStopped()) {
30207 return event;
30208 }
30209 if (callback.func.call(this.scope, event) === false) {
30210 event.preventDefault();
30211 return event;
30212 }
30213 }
30214 }
30215 return event;
30216 }
30217 on(name, callback, prepend, extra) {
30218 if (callback === false) {
30219 callback = never;
30220 }
30221 if (callback) {
30222 const wrappedCallback = {
30223 func: callback,
30224 removed: false
30225 };
30226 if (extra) {
30227 Tools.extend(wrappedCallback, extra);
30228 }
30229 const names = name.toLowerCase().split(' ');
30230 let i = names.length;
30231 while (i--) {
30232 const currentName = names[i];
30233 let handlers = this.bindings[currentName];
30234 if (!handlers) {
30235 handlers = [];
30236 this.toggleEvent(currentName, true);
30237 }
30238 if (prepend) {
30239 handlers = [
30240 wrappedCallback,
30241 ...handlers
30242 ];
30243 } else {
30244 handlers = [
30245 ...handlers,
30246 wrappedCallback
30247 ];
30248 }
30249 this.bindings[currentName] = handlers;
30250 }
30251 }
30252 return this;
30253 }
30254 off(name, callback) {
30255 if (name) {
30256 const names = name.toLowerCase().split(' ');
30257 let i = names.length;
30258 while (i--) {
30259 const currentName = names[i];
30260 let handlers = this.bindings[currentName];
30261 if (!currentName) {
30262 each$d(this.bindings, (_value, bindingName) => {
30263 this.toggleEvent(bindingName, false);
30264 delete this.bindings[bindingName];
30265 });
30266 return this;
30267 }
30268 if (handlers) {
30269 if (!callback) {
30270 handlers.length = 0;
30271 } else {
30272 const filteredHandlers = partition$2(handlers, handler => handler.func === callback);
30273 handlers = filteredHandlers.fail;
30274 this.bindings[currentName] = handlers;
30275 each$e(filteredHandlers.pass, handler => {
30276 handler.removed = true;
30277 });
30278 }
30279 if (!handlers.length) {
30280 this.toggleEvent(name, false);
30281 delete this.bindings[currentName];
30282 }
30283 }
30284 }
30285 } else {
30286 each$d(this.bindings, (_value, name) => {
30287 this.toggleEvent(name, false);
30288 });
30289 this.bindings = {};
30290 }
30291 return this;
30292 }
30293 once(name, callback, prepend) {
30294 return this.on(name, callback, prepend, { once: true });
30295 }
30296 has(name) {
30297 name = name.toLowerCase();
30298 const binding = this.bindings[name];
30299 return !(!binding || binding.length === 0);
30300 }
30301 }
30302
30303 const getEventDispatcher = obj => {
30304 if (!obj._eventDispatcher) {
30305 obj._eventDispatcher = new EventDispatcher({
30306 scope: obj,
30307 toggleEvent: (name, state) => {
30308 if (EventDispatcher.isNative(name) && obj.toggleNativeEvent) {
30309 obj.toggleNativeEvent(name, state);
30310 }
30311 }
30312 });
30313 }
30314 return obj._eventDispatcher;
30315 };
30316 const Observable = {
30317 fire(name, args, bubble) {
30318 return this.dispatch(name, args, bubble);
30319 },
30320 dispatch(name, args, bubble) {
30321 const self = this;
30322 if (self.removed && name !== 'remove' && name !== 'detach') {
30323 return normalize$3(name.toLowerCase(), args !== null && args !== void 0 ? args : {}, self);
30324 }
30325 const dispatcherArgs = getEventDispatcher(self).dispatch(name, args);
30326 if (bubble !== false && self.parent) {
30327 let parent = self.parent();
30328 while (parent && !dispatcherArgs.isPropagationStopped()) {
30329 parent.dispatch(name, dispatcherArgs, false);
30330 parent = parent.parent ? parent.parent() : undefined;
30331 }
30332 }
30333 return dispatcherArgs;
30334 },
30335 on(name, callback, prepend) {
30336 return getEventDispatcher(this).on(name, callback, prepend);
30337 },
30338 off(name, callback) {
30339 return getEventDispatcher(this).off(name, callback);
30340 },
30341 once(name, callback) {
30342 return getEventDispatcher(this).once(name, callback);
30343 },
30344 hasEventListeners(name) {
30345 return getEventDispatcher(this).has(name);
30346 }
30347 };
30348
30349 const DOM$2 = DOMUtils.DOM;
30350 let customEventRootDelegates;
30351 const getEventTarget = (editor, eventName) => {
30352 if (eventName === 'selectionchange') {
30353 return editor.getDoc();
30354 }
30355 if (!editor.inline && /^(?:mouse|touch|click|contextmenu|drop|dragover|dragend)/.test(eventName)) {
30356 return editor.getDoc().documentElement;
30357 }
30358 const eventRoot = getEventRoot(editor);
30359 if (eventRoot) {
30360 if (!editor.eventRoot) {
30361 editor.eventRoot = DOM$2.select(eventRoot)[0];
30362 }
30363 return editor.eventRoot;
30364 }
30365 return editor.getBody();
30366 };
30367 const isListening = editor => !editor.hidden && !isReadOnly(editor);
30368 const fireEvent = (editor, eventName, e) => {
30369 if (isListening(editor)) {
30370 editor.dispatch(eventName, e);
30371 } else if (isReadOnly(editor)) {
30372 processReadonlyEvents(editor, e);
30373 }
30374 };
30375 const bindEventDelegate = (editor, eventName) => {
30376 if (!editor.delegates) {
30377 editor.delegates = {};
30378 }
30379 if (editor.delegates[eventName] || editor.removed) {
30380 return;
30381 }
30382 const eventRootElm = getEventTarget(editor, eventName);
30383 if (getEventRoot(editor)) {
30384 if (!customEventRootDelegates) {
30385 customEventRootDelegates = {};
30386 editor.editorManager.on('removeEditor', () => {
30387 if (!editor.editorManager.activeEditor) {
30388 if (customEventRootDelegates) {
30389 each$d(customEventRootDelegates, (_value, name) => {
30390 editor.dom.unbind(getEventTarget(editor, name));
30391 });
30392 customEventRootDelegates = null;
30393 }
30394 }
30395 });
30396 }
30397 if (customEventRootDelegates[eventName]) {
30398 return;
30399 }
30400 const delegate = e => {
30401 const target = e.target;
30402 const editors = editor.editorManager.get();
30403 let i = editors.length;
30404 while (i--) {
30405 const body = editors[i].getBody();
30406 if (body === target || DOM$2.isChildOf(target, body)) {
30407 fireEvent(editors[i], eventName, e);
30408 }
30409 }
30410 };
30411 customEventRootDelegates[eventName] = delegate;
30412 DOM$2.bind(eventRootElm, eventName, delegate);
30413 } else {
30414 const delegate = e => {
30415 fireEvent(editor, eventName, e);
30416 };
30417 DOM$2.bind(eventRootElm, eventName, delegate);
30418 editor.delegates[eventName] = delegate;
30419 }
30420 };
30421 const EditorObservable = {
30422 ...Observable,
30423 bindPendingEventDelegates() {
30424 const self = this;
30425 Tools.each(self._pendingNativeEvents, name => {
30426 bindEventDelegate(self, name);
30427 });
30428 },
30429 toggleNativeEvent(name, state) {
30430 const self = this;
30431 if (name === 'focus' || name === 'blur') {
30432 return;
30433 }
30434 if (self.removed) {
30435 return;
30436 }
30437 if (state) {
30438 if (self.initialized) {
30439 bindEventDelegate(self, name);
30440 } else {
30441 if (!self._pendingNativeEvents) {
30442 self._pendingNativeEvents = [name];
30443 } else {
30444 self._pendingNativeEvents.push(name);
30445 }
30446 }
30447 } else if (self.initialized && self.delegates) {
30448 self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]);
30449 delete self.delegates[name];
30450 }
30451 },
30452 unbindAllNativeEvents() {
30453 const self = this;
30454 const body = self.getBody();
30455 const dom = self.dom;
30456 if (self.delegates) {
30457 each$d(self.delegates, (value, name) => {
30458 self.dom.unbind(getEventTarget(self, name), name, value);
30459 });
30460 delete self.delegates;
30461 }
30462 if (!self.inline && body && dom) {
30463 body.onload = null;
30464 dom.unbind(self.getWin());
30465 dom.unbind(self.getDoc());
30466 }
30467 if (dom) {
30468 dom.unbind(body);
30469 dom.unbind(self.getContainer());
30470 }
30471 }
30472 };
30473
30474 const stringListProcessor = value => {
30475 if (isString(value)) {
30476 return {
30477 value: value.split(/[ ,]/),
30478 valid: true
30479 };
30480 } else if (isArrayOf(value, isString)) {
30481 return {
30482 value,
30483 valid: true
30484 };
30485 } else {
30486 return {
30487 valid: false,
30488 message: `The value must be a string[] or a comma/space separated string.`
30489 };
30490 }
30491 };
30492 const getBuiltInProcessor = type => {
30493 const validator = (() => {
30494 switch (type) {
30495 case 'array':
30496 return isArray$1;
30497 case 'boolean':
30498 return isBoolean;
30499 case 'function':
30500 return isFunction;
30501 case 'number':
30502 return isNumber;
30503 case 'object':
30504 return isObject;
30505 case 'string':
30506 return isString;
30507 case 'string[]':
30508 return stringListProcessor;
30509 case 'object[]':
30510 return val => isArrayOf(val, isObject);
30511 case 'regexp':
30512 return val => is$4(val, RegExp);
30513 default:
30514 return always;
30515 }
30516 })();
30517 return value => processValue(value, validator, `The value must be a ${ type }.`);
30518 };
30519 const isBuiltInSpec = spec => isString(spec.processor);
30520 const getErrorMessage = (message, result) => {
30521 const additionalText = isEmpty$3(result.message) ? '' : `. ${ result.message }`;
30522 return message + additionalText;
30523 };
30524 const isValidResult = result => result.valid;
30525 const processValue = (value, processor, message = '') => {
30526 const result = processor(value);
30527 if (isBoolean(result)) {
30528 return result ? {
30529 value: value,
30530 valid: true
30531 } : {
30532 valid: false,
30533 message
30534 };
30535 } else {
30536 return result;
30537 }
30538 };
30539 const processDefaultValue = (name, defaultValue, processor) => {
30540 if (!isUndefined(defaultValue)) {
30541 const result = processValue(defaultValue, processor);
30542 if (isValidResult(result)) {
30543 return result.value;
30544 } else {
30545 console.error(getErrorMessage(`Invalid default value passed for the "${ name }" option`, result));
30546 }
30547 }
30548 return undefined;
30549 };
30550 const create$5 = (editor, initialOptions) => {
30551 const registry = {};
30552 const values = {};
30553 const setValue = (name, value, processor) => {
30554 const result = processValue(value, processor);
30555 if (isValidResult(result)) {
30556 values[name] = result.value;
30557 return true;
30558 } else {
30559 console.warn(getErrorMessage(`Invalid value passed for the ${ name } option`, result));
30560 return false;
30561 }
30562 };
30563 const register = (name, spec) => {
30564 const processor = isBuiltInSpec(spec) ? getBuiltInProcessor(spec.processor) : spec.processor;
30565 const defaultValue = processDefaultValue(name, spec.default, processor);
30566 registry[name] = {
30567 ...spec,
30568 default: defaultValue,
30569 processor
30570 };
30571 const initValue = get$a(values, name).orThunk(() => get$a(initialOptions, name));
30572 initValue.each(value => setValue(name, value, processor));
30573 };
30574 const isRegistered = name => has$2(registry, name);
30575 const get = name => get$a(values, name).orThunk(() => get$a(registry, name).map(spec => spec.default)).getOrUndefined();
30576 const set = (name, value) => {
30577 if (!isRegistered(name)) {
30578 console.warn(`"${ name }" is not a registered option. Ensure the option has been registered before setting a value.`);
30579 return false;
30580 } else {
30581 const spec = registry[name];
30582 if (spec.immutable) {
30583 console.error(`"${ name }" is an immutable option and cannot be updated`);
30584 return false;
30585 } else {
30586 return setValue(name, value, spec.processor);
30587 }
30588 }
30589 };
30590 const unset = name => {
30591 const registered = isRegistered(name);
30592 if (registered) {
30593 delete values[name];
30594 }
30595 return registered;
30596 };
30597 const isSet = name => has$2(values, name);
30598 return {
30599 register,
30600 isRegistered,
30601 get,
30602 set,
30603 unset,
30604 isSet
30605 };
30606 };
30607
30608 const defaultModes = [
30609 'design',
30610 'readonly'
30611 ];
30612 const switchToMode = (editor, activeMode, availableModes, mode) => {
30613 const oldMode = availableModes[activeMode.get()];
30614 const newMode = availableModes[mode];
30615 try {
30616 newMode.activate();
30617 } catch (e) {
30618 console.error(`problem while activating editor mode ${ mode }:`, e);
30619 return;
30620 }
30621 oldMode.deactivate();
30622 if (oldMode.editorReadOnly !== newMode.editorReadOnly) {
30623 toggleReadOnly(editor, newMode.editorReadOnly);
30624 }
30625 activeMode.set(mode);
30626 fireSwitchMode(editor, mode);
30627 };
30628 const setMode = (editor, availableModes, activeMode, mode) => {
30629 if (mode === activeMode.get()) {
30630 return;
30631 } else if (!has$2(availableModes, mode)) {
30632 throw new Error(`Editor mode '${ mode }' is invalid`);
30633 }
30634 if (editor.initialized) {
30635 switchToMode(editor, activeMode, availableModes, mode);
30636 } else {
30637 editor.on('init', () => switchToMode(editor, activeMode, availableModes, mode));
30638 }
30639 };
30640 const registerMode = (availableModes, mode, api) => {
30641 if (contains$2(defaultModes, mode)) {
30642 throw new Error(`Cannot override default mode ${ mode }`);
30643 }
30644 return {
30645 ...availableModes,
30646 [mode]: {
30647 ...api,
30648 deactivate: () => {
30649 try {
30650 api.deactivate();
30651 } catch (e) {
30652 console.error(`problem while deactivating editor mode ${ mode }:`, e);
30653 }
30654 }
30655 }
30656 };
30657 };
30658
30659 const create$4 = editor => {
30660 const activeMode = Cell('design');
30661 const availableModes = Cell({
30662 design: {
30663 activate: noop,
30664 deactivate: noop,
30665 editorReadOnly: false
30666 },
30667 readonly: {
30668 activate: noop,
30669 deactivate: noop,
30670 editorReadOnly: true
30671 }
30672 });
30673 registerReadOnlyContentFilters(editor);
30674 registerReadOnlySelectionBlockers(editor);
30675 return {
30676 isReadOnly: () => isReadOnly(editor),
30677 set: mode => setMode(editor, availableModes.get(), activeMode, mode),
30678 get: () => activeMode.get(),
30679 register: (mode, api) => {
30680 availableModes.set(registerMode(availableModes.get(), mode, api));
30681 }
30682 };
30683 };
30684
30685 const each$2 = Tools.each, explode = Tools.explode;
30686 const keyCodeLookup = {
30687 f1: 112,
30688 f2: 113,
30689 f3: 114,
30690 f4: 115,
30691 f5: 116,
30692 f6: 117,
30693 f7: 118,
30694 f8: 119,
30695 f9: 120,
30696 f10: 121,
30697 f11: 122,
30698 f12: 123
30699 };
30700 const modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access');
30701 const isModifier = key => key in modifierNames;
30702 const parseShortcut = pattern => {
30703 const shortcut = {};
30704 const isMac = Env.os.isMacOS() || Env.os.isiOS();
30705 each$2(explode(pattern.toLowerCase(), '+'), value => {
30706 if (isModifier(value)) {
30707 shortcut[value] = true;
30708 } else {
30709 if (/^[0-9]{2,}$/.test(value)) {
30710 shortcut.keyCode = parseInt(value, 10);
30711 } else {
30712 shortcut.charCode = value.charCodeAt(0);
30713 shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
30714 }
30715 }
30716 });
30717 const id = [shortcut.keyCode];
30718 let key;
30719 for (key in modifierNames) {
30720 if (shortcut[key]) {
30721 id.push(key);
30722 } else {
30723 shortcut[key] = false;
30724 }
30725 }
30726 shortcut.id = id.join(',');
30727 if (shortcut.access) {
30728 shortcut.alt = true;
30729 if (isMac) {
30730 shortcut.ctrl = true;
30731 } else {
30732 shortcut.shift = true;
30733 }
30734 }
30735 if (shortcut.meta) {
30736 if (isMac) {
30737 shortcut.meta = true;
30738 } else {
30739 shortcut.ctrl = true;
30740 shortcut.meta = false;
30741 }
30742 }
30743 return shortcut;
30744 };
30745 class Shortcuts {
30746 constructor(editor) {
30747 this.shortcuts = {};
30748 this.pendingPatterns = [];
30749 this.editor = editor;
30750 const self = this;
30751 editor.on('keyup keypress keydown', e => {
30752 if ((self.hasModifier(e) || self.isFunctionKey(e)) && !e.isDefaultPrevented()) {
30753 each$2(self.shortcuts, shortcut => {
30754 if (self.matchShortcut(e, shortcut)) {
30755 self.pendingPatterns = shortcut.subpatterns.slice(0);
30756 if (e.type === 'keydown') {
30757 self.executeShortcutAction(shortcut);
30758 }
30759 }
30760 });
30761 if (self.matchShortcut(e, self.pendingPatterns[0])) {
30762 if (self.pendingPatterns.length === 1) {
30763 if (e.type === 'keydown') {
30764 self.executeShortcutAction(self.pendingPatterns[0]);
30765 }
30766 }
30767 self.pendingPatterns.shift();
30768 }
30769 }
30770 });
30771 }
30772 add(pattern, desc, cmdFunc, scope) {
30773 const self = this;
30774 const func = self.normalizeCommandFunc(cmdFunc);
30775 each$2(explode(Tools.trim(pattern)), pattern => {
30776 const shortcut = self.createShortcut(pattern, desc, func, scope);
30777 self.shortcuts[shortcut.id] = shortcut;
30778 });
30779 return true;
30780 }
30781 remove(pattern) {
30782 const shortcut = this.createShortcut(pattern);
30783 if (this.shortcuts[shortcut.id]) {
30784 delete this.shortcuts[shortcut.id];
30785 return true;
30786 }
30787 return false;
30788 }
30789 normalizeCommandFunc(cmdFunc) {
30790 const self = this;
30791 const cmd = cmdFunc;
30792 if (typeof cmd === 'string') {
30793 return () => {
30794 self.editor.execCommand(cmd, false, null);
30795 };
30796 } else if (Tools.isArray(cmd)) {
30797 return () => {
30798 self.editor.execCommand(cmd[0], cmd[1], cmd[2]);
30799 };
30800 } else {
30801 return cmd;
30802 }
30803 }
30804 createShortcut(pattern, desc, cmdFunc, scope) {
30805 const shortcuts = Tools.map(explode(pattern, '>'), parseShortcut);
30806 shortcuts[shortcuts.length - 1] = Tools.extend(shortcuts[shortcuts.length - 1], {
30807 func: cmdFunc,
30808 scope: scope || this.editor
30809 });
30810 return Tools.extend(shortcuts[0], {
30811 desc: this.editor.translate(desc),
30812 subpatterns: shortcuts.slice(1)
30813 });
30814 }
30815 hasModifier(e) {
30816 return e.altKey || e.ctrlKey || e.metaKey;
30817 }
30818 isFunctionKey(e) {
30819 return e.type === 'keydown' && e.keyCode >= 112 && e.keyCode <= 123;
30820 }
30821 matchShortcut(e, shortcut) {
30822 if (!shortcut) {
30823 return false;
30824 }
30825 if (shortcut.ctrl !== e.ctrlKey || shortcut.meta !== e.metaKey) {
30826 return false;
30827 }
30828 if (shortcut.alt !== e.altKey || shortcut.shift !== e.shiftKey) {
30829 return false;
30830 }
30831 if (e.keyCode === shortcut.keyCode || e.charCode && e.charCode === shortcut.charCode) {
30832 e.preventDefault();
30833 return true;
30834 }
30835 return false;
30836 }
30837 executeShortcutAction(shortcut) {
30838 return shortcut.func ? shortcut.func.call(shortcut.scope) : null;
30839 }
30840 }
30841
30842 const create$3 = () => {
30843 const buttons = {};
30844 const menuItems = {};
30845 const popups = {};
30846 const icons = {};
30847 const contextMenus = {};
30848 const contextToolbars = {};
30849 const sidebars = {};
30850 const views = {};
30851 const add = (collection, type) => (name, spec) => {
30852 collection[name.toLowerCase()] = {
30853 ...spec,
30854 type
30855 };
30856 };
30857 const addIcon = (name, svgData) => icons[name.toLowerCase()] = svgData;
30858 return {
30859 addButton: add(buttons, 'button'),
30860 addGroupToolbarButton: add(buttons, 'grouptoolbarbutton'),
30861 addToggleButton: add(buttons, 'togglebutton'),
30862 addMenuButton: add(buttons, 'menubutton'),
30863 addSplitButton: add(buttons, 'splitbutton'),
30864 addMenuItem: add(menuItems, 'menuitem'),
30865 addNestedMenuItem: add(menuItems, 'nestedmenuitem'),
30866 addToggleMenuItem: add(menuItems, 'togglemenuitem'),
30867 addAutocompleter: add(popups, 'autocompleter'),
30868 addContextMenu: add(contextMenus, 'contextmenu'),
30869 addContextToolbar: add(contextToolbars, 'contexttoolbar'),
30870 addContextForm: add(contextToolbars, 'contextform'),
30871 addSidebar: add(sidebars, 'sidebar'),
30872 addView: add(views, 'views'),
30873 addIcon,
30874 getAll: () => ({
30875 buttons,
30876 menuItems,
30877 icons,
30878 popups,
30879 contextMenus,
30880 contextToolbars,
30881 sidebars,
30882 views
30883 })
30884 };
30885 };
30886
30887 const registry = () => {
30888 const bridge = create$3();
30889 return {
30890 addAutocompleter: bridge.addAutocompleter,
30891 addButton: bridge.addButton,
30892 addContextForm: bridge.addContextForm,
30893 addContextMenu: bridge.addContextMenu,
30894 addContextToolbar: bridge.addContextToolbar,
30895 addIcon: bridge.addIcon,
30896 addMenuButton: bridge.addMenuButton,
30897 addMenuItem: bridge.addMenuItem,
30898 addNestedMenuItem: bridge.addNestedMenuItem,
30899 addSidebar: bridge.addSidebar,
30900 addSplitButton: bridge.addSplitButton,
30901 addToggleButton: bridge.addToggleButton,
30902 addGroupToolbarButton: bridge.addGroupToolbarButton,
30903 addToggleMenuItem: bridge.addToggleMenuItem,
30904 addView: bridge.addView,
30905 getAll: bridge.getAll
30906 };
30907 };
30908
30909 const DOM$1 = DOMUtils.DOM;
30910 const extend = Tools.extend, each$1 = Tools.each;
30911 class Editor {
30912 constructor(id, options, editorManager) {
30913 this.plugins = {};
30914 this.contentCSS = [];
30915 this.contentStyles = [];
30916 this.loadedCSS = {};
30917 this.isNotDirty = false;
30918 this.composing = false;
30919 this.destroyed = false;
30920 this.hasHiddenInput = false;
30921 this.iframeElement = null;
30922 this.initialized = false;
30923 this.readonly = false;
30924 this.removed = false;
30925 this.startContent = '';
30926 this._pendingNativeEvents = [];
30927 this._skinLoaded = false;
30928 this._editableRoot = true;
30929 this.editorManager = editorManager;
30930 this.documentBaseUrl = editorManager.documentBaseURL;
30931 extend(this, EditorObservable);
30932 const self = this;
30933 this.id = id;
30934 this.hidden = false;
30935 const normalizedOptions = normalizeOptions(editorManager.defaultOptions, options);
30936 this.options = create$5(self, normalizedOptions);
30937 register$7(self);
30938 const getOption = this.options.get;
30939 if (getOption('deprecation_warnings')) {
30940 logWarnings(options, normalizedOptions);
30941 }
30942 const suffix = getOption('suffix');
30943 if (suffix) {
30944 editorManager.suffix = suffix;
30945 }
30946 this.suffix = editorManager.suffix;
30947 const baseUrl = getOption('base_url');
30948 if (baseUrl) {
30949 editorManager._setBaseUrl(baseUrl);
30950 }
30951 this.baseUri = editorManager.baseURI;
30952 const referrerPolicy = getReferrerPolicy(self);
30953 if (referrerPolicy) {
30954 ScriptLoader.ScriptLoader._setReferrerPolicy(referrerPolicy);
30955 DOMUtils.DOM.styleSheetLoader._setReferrerPolicy(referrerPolicy);
30956 }
30957 const contentCssCors = hasContentCssCors(self);
30958 if (isNonNullable(contentCssCors)) {
30959 DOMUtils.DOM.styleSheetLoader._setContentCssCors(contentCssCors);
30960 }
30961 AddOnManager.languageLoad = getOption('language_load');
30962 AddOnManager.baseURL = editorManager.baseURL;
30963 this.setDirty(false);
30964 this.documentBaseURI = new URI(getDocumentBaseUrl(self), { base_uri: this.baseUri });
30965 this.baseURI = this.baseUri;
30966 this.inline = isInline$1(self);
30967 this.hasVisual = isVisualAidsEnabled(self);
30968 this.shortcuts = new Shortcuts(this);
30969 this.editorCommands = new EditorCommands(this);
30970 registerCommands(this);
30971 const cacheSuffix = getOption('cache_suffix');
30972 if (cacheSuffix) {
30973 Env.cacheSuffix = cacheSuffix.replace(/^[\?\&]+/, '');
30974 }
30975 this.ui = {
30976 registry: registry(),
30977 styleSheetLoader: undefined,
30978 show: noop,
30979 hide: noop,
30980 setEnabled: noop,
30981 isEnabled: always
30982 };
30983 this.mode = create$4(self);
30984 editorManager.dispatch('SetupEditor', { editor: this });
30985 const setupCallback = getSetupCallback(self);
30986 if (isFunction(setupCallback)) {
30987 setupCallback.call(self, self);
30988 }
30989 }
30990 render() {
30991 render(this);
30992 }
30993 focus(skipFocus) {
30994 this.execCommand('mceFocus', false, skipFocus);
30995 }
30996 hasFocus() {
30997 return hasFocus(this);
30998 }
30999 translate(text) {
31000 return I18n.translate(text);
31001 }
31002 getParam(name, defaultVal, type) {
31003 const options = this.options;
31004 if (!options.isRegistered(name)) {
31005 if (isNonNullable(type)) {
31006 options.register(name, {
31007 processor: type,
31008 default: defaultVal
31009 });
31010 } else {
31011 options.register(name, {
31012 processor: always,
31013 default: defaultVal
31014 });
31015 }
31016 }
31017 return !options.isSet(name) && !isUndefined(defaultVal) ? defaultVal : options.get(name);
31018 }
31019 hasPlugin(name, loaded) {
31020 const hasPlugin = contains$2(getPlugins(this), name);
31021 if (hasPlugin) {
31022 return loaded ? PluginManager.get(name) !== undefined : true;
31023 } else {
31024 return false;
31025 }
31026 }
31027 nodeChanged(args) {
31028 this._nodeChangeDispatcher.nodeChanged(args);
31029 }
31030 addCommand(name, callback, scope) {
31031 this.editorCommands.addCommand(name, callback, scope);
31032 }
31033 addQueryStateHandler(name, callback, scope) {
31034 this.editorCommands.addQueryStateHandler(name, callback, scope);
31035 }
31036 addQueryValueHandler(name, callback, scope) {
31037 this.editorCommands.addQueryValueHandler(name, callback, scope);
31038 }
31039 addShortcut(pattern, desc, cmdFunc, scope) {
31040 this.shortcuts.add(pattern, desc, cmdFunc, scope);
31041 }
31042 execCommand(cmd, ui, value, args) {
31043 return this.editorCommands.execCommand(cmd, ui, value, args);
31044 }
31045 queryCommandState(cmd) {
31046 return this.editorCommands.queryCommandState(cmd);
31047 }
31048 queryCommandValue(cmd) {
31049 return this.editorCommands.queryCommandValue(cmd);
31050 }
31051 queryCommandSupported(cmd) {
31052 return this.editorCommands.queryCommandSupported(cmd);
31053 }
31054 show() {
31055 const self = this;
31056 if (self.hidden) {
31057 self.hidden = false;
31058 if (self.inline) {
31059 self.getBody().contentEditable = 'true';
31060 } else {
31061 DOM$1.show(self.getContainer());
31062 DOM$1.hide(self.id);
31063 }
31064 self.load();
31065 self.dispatch('show');
31066 }
31067 }
31068 hide() {
31069 const self = this;
31070 if (!self.hidden) {
31071 self.save();
31072 if (self.inline) {
31073 self.getBody().contentEditable = 'false';
31074 if (self === self.editorManager.focusedEditor) {
31075 self.editorManager.focusedEditor = null;
31076 }
31077 } else {
31078 DOM$1.hide(self.getContainer());
31079 DOM$1.setStyle(self.id, 'display', self.orgDisplay);
31080 }
31081 self.hidden = true;
31082 self.dispatch('hide');
31083 }
31084 }
31085 isHidden() {
31086 return this.hidden;
31087 }
31088 setProgressState(state, time) {
31089 this.dispatch('ProgressState', {
31090 state,
31091 time
31092 });
31093 }
31094 load(args = {}) {
31095 const self = this;
31096 const elm = self.getElement();
31097 if (self.removed) {
31098 return '';
31099 }
31100 if (elm) {
31101 const loadArgs = {
31102 ...args,
31103 load: true
31104 };
31105 const value = isTextareaOrInput(elm) ? elm.value : elm.innerHTML;
31106 const html = self.setContent(value, loadArgs);
31107 if (!loadArgs.no_events) {
31108 self.dispatch('LoadContent', {
31109 ...loadArgs,
31110 element: elm
31111 });
31112 }
31113 return html;
31114 } else {
31115 return '';
31116 }
31117 }
31118 save(args = {}) {
31119 const self = this;
31120 let elm = self.getElement();
31121 if (!elm || !self.initialized || self.removed) {
31122 return '';
31123 }
31124 const getArgs = {
31125 ...args,
31126 save: true,
31127 element: elm
31128 };
31129 let html = self.getContent(getArgs);
31130 const saveArgs = {
31131 ...getArgs,
31132 content: html
31133 };
31134 if (!saveArgs.no_events) {
31135 self.dispatch('SaveContent', saveArgs);
31136 }
31137 if (saveArgs.format === 'raw') {
31138 self.dispatch('RawSaveContent', saveArgs);
31139 }
31140 html = saveArgs.content;
31141 if (!isTextareaOrInput(elm)) {
31142 if (args.is_removing || !self.inline) {
31143 elm.innerHTML = html;
31144 }
31145 const form = DOM$1.getParent(self.id, 'form');
31146 if (form) {
31147 each$1(form.elements, elm => {
31148 if (elm.name === self.id) {
31149 elm.value = html;
31150 return false;
31151 } else {
31152 return true;
31153 }
31154 });
31155 }
31156 } else {
31157 elm.value = html;
31158 }
31159 saveArgs.element = getArgs.element = elm = null;
31160 if (saveArgs.set_dirty !== false) {
31161 self.setDirty(false);
31162 }
31163 return html;
31164 }
31165 setContent(content, args) {
31166 return setContent(this, content, args);
31167 }
31168 getContent(args) {
31169 return getContent(this, args);
31170 }
31171 insertContent(content, args) {
31172 if (args) {
31173 content = extend({ content }, args);
31174 }
31175 this.execCommand('mceInsertContent', false, content);
31176 }
31177 resetContent(initialContent) {
31178 if (initialContent === undefined) {
31179 setContent(this, this.startContent, { format: 'raw' });
31180 } else {
31181 setContent(this, initialContent);
31182 }
31183 this.undoManager.reset();
31184 this.setDirty(false);
31185 this.nodeChanged();
31186 }
31187 isDirty() {
31188 return !this.isNotDirty;
31189 }
31190 setDirty(state) {
31191 const oldState = !this.isNotDirty;
31192 this.isNotDirty = !state;
31193 if (state && state !== oldState) {
31194 this.dispatch('dirty');
31195 }
31196 }
31197 getContainer() {
31198 const self = this;
31199 if (!self.container) {
31200 self.container = self.editorContainer || DOM$1.get(self.id + '_parent');
31201 }
31202 return self.container;
31203 }
31204 getContentAreaContainer() {
31205 return this.contentAreaContainer;
31206 }
31207 getElement() {
31208 if (!this.targetElm) {
31209 this.targetElm = DOM$1.get(this.id);
31210 }
31211 return this.targetElm;
31212 }
31213 getWin() {
31214 const self = this;
31215 if (!self.contentWindow) {
31216 const elm = self.iframeElement;
31217 if (elm) {
31218 self.contentWindow = elm.contentWindow;
31219 }
31220 }
31221 return self.contentWindow;
31222 }
31223 getDoc() {
31224 const self = this;
31225 if (!self.contentDocument) {
31226 const win = self.getWin();
31227 if (win) {
31228 self.contentDocument = win.document;
31229 }
31230 }
31231 return self.contentDocument;
31232 }
31233 getBody() {
31234 var _a, _b;
31235 const doc = this.getDoc();
31236 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;
31237 }
31238 convertURL(url, name, elm) {
31239 const self = this, getOption = self.options.get;
31240 const urlConverterCallback = getUrlConverterCallback(self);
31241 if (isFunction(urlConverterCallback)) {
31242 return urlConverterCallback.call(self, url, elm, true, name);
31243 }
31244 if (!getOption('convert_urls') || elm === 'link' || isObject(elm) && elm.nodeName === 'LINK' || url.indexOf('file:') === 0 || url.length === 0) {
31245 return url;
31246 }
31247 const urlObject = new URI(url);
31248 if (urlObject.protocol !== 'http' && urlObject.protocol !== 'https' && urlObject.protocol !== '') {
31249 return url;
31250 }
31251 if (getOption('relative_urls')) {
31252 return self.documentBaseURI.toRelative(url);
31253 }
31254 url = self.documentBaseURI.toAbsolute(url, getOption('remove_script_host'));
31255 return url;
31256 }
31257 addVisual(elm) {
31258 addVisual(this, elm);
31259 }
31260 setEditableRoot(state) {
31261 setEditableRoot(this, state);
31262 }
31263 hasEditableRoot() {
31264 return hasEditableRoot(this);
31265 }
31266 remove() {
31267 remove$1(this);
31268 }
31269 destroy(automatic) {
31270 destroy(this, automatic);
31271 }
31272 uploadImages() {
31273 return this.editorUpload.uploadImages();
31274 }
31275 _scanForImages() {
31276 return this.editorUpload.scanForImages();
31277 }
31278 }
31279
31280 const DOM = DOMUtils.DOM;
31281 const each = Tools.each;
31282 let boundGlobalEvents = false;
31283 let beforeUnloadDelegate;
31284 let editors = [];
31285 const globalEventDelegate = e => {
31286 const type = e.type;
31287 each(EditorManager.get(), editor => {
31288 switch (type) {
31289 case 'scroll':
31290 editor.dispatch('ScrollWindow', e);
31291 break;
31292 case 'resize':
31293 editor.dispatch('ResizeWindow', e);
31294 break;
31295 }
31296 });
31297 };
31298 const toggleGlobalEvents = state => {
31299 if (state !== boundGlobalEvents) {
31300 const DOM = DOMUtils.DOM;
31301 if (state) {
31302 DOM.bind(window, 'resize', globalEventDelegate);
31303 DOM.bind(window, 'scroll', globalEventDelegate);
31304 } else {
31305 DOM.unbind(window, 'resize', globalEventDelegate);
31306 DOM.unbind(window, 'scroll', globalEventDelegate);
31307 }
31308 boundGlobalEvents = state;
31309 }
31310 };
31311 const removeEditorFromList = targetEditor => {
31312 const oldEditors = editors;
31313 editors = filter$5(editors, editor => {
31314 return targetEditor !== editor;
31315 });
31316 if (EditorManager.activeEditor === targetEditor) {
31317 EditorManager.activeEditor = editors.length > 0 ? editors[0] : null;
31318 }
31319 if (EditorManager.focusedEditor === targetEditor) {
31320 EditorManager.focusedEditor = null;
31321 }
31322 return oldEditors.length !== editors.length;
31323 };
31324 const purgeDestroyedEditor = editor => {
31325 if (editor && editor.initialized && !(editor.getContainer() || editor.getBody()).parentNode) {
31326 removeEditorFromList(editor);
31327 editor.unbindAllNativeEvents();
31328 editor.destroy(true);
31329 editor.removed = true;
31330 }
31331 };
31332 const isQuirksMode = document.compatMode !== 'CSS1Compat';
31333 const EditorManager = {
31334 ...Observable,
31335 baseURI: null,
31336 baseURL: null,
31337 defaultOptions: {},
31338 documentBaseURL: null,
31339 suffix: null,
31340 majorVersion: '7',
31341 minorVersion: '1.1',
31342 releaseDate: '2024-05-22',
31343 i18n: I18n,
31344 activeEditor: null,
31345 focusedEditor: null,
31346 setup() {
31347 const self = this;
31348 let baseURL = '';
31349 let suffix = '';
31350 let documentBaseURL = URI.getDocumentBaseUrl(document.location);
31351 if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) {
31352 documentBaseURL = documentBaseURL.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
31353 if (!/[\/\\]$/.test(documentBaseURL)) {
31354 documentBaseURL += '/';
31355 }
31356 }
31357 const preInit = window.tinymce || window.tinyMCEPreInit;
31358 if (preInit) {
31359 baseURL = preInit.base || preInit.baseURL;
31360 suffix = preInit.suffix;
31361 } else {
31362 const scripts = document.getElementsByTagName('script');
31363 for (let i = 0; i < scripts.length; i++) {
31364 const src = scripts[i].src || '';
31365 if (src === '') {
31366 continue;
31367 }
31368 const srcScript = src.substring(src.lastIndexOf('/'));
31369 if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
31370 if (srcScript.indexOf('.min') !== -1) {
31371 suffix = '.min';
31372 }
31373 baseURL = src.substring(0, src.lastIndexOf('/'));
31374 break;
31375 }
31376 }
31377 if (!baseURL && document.currentScript) {
31378 const src = document.currentScript.src;
31379 if (src.indexOf('.min') !== -1) {
31380 suffix = '.min';
31381 }
31382 baseURL = src.substring(0, src.lastIndexOf('/'));
31383 }
31384 }
31385 self.baseURL = new URI(documentBaseURL).toAbsolute(baseURL);
31386 self.documentBaseURL = documentBaseURL;
31387 self.baseURI = new URI(self.baseURL);
31388 self.suffix = suffix;
31389 setup$w(self);
31390 },
31391 overrideDefaults(defaultOptions) {
31392 const baseUrl = defaultOptions.base_url;
31393 if (baseUrl) {
31394 this._setBaseUrl(baseUrl);
31395 }
31396 const suffix = defaultOptions.suffix;
31397 if (suffix) {
31398 this.suffix = suffix;
31399 }
31400 this.defaultOptions = defaultOptions;
31401 const pluginBaseUrls = defaultOptions.plugin_base_urls;
31402 if (pluginBaseUrls !== undefined) {
31403 each$d(pluginBaseUrls, (pluginBaseUrl, pluginName) => {
31404 AddOnManager.PluginManager.urls[pluginName] = pluginBaseUrl;
31405 });
31406 }
31407 },
31408 init(options) {
31409 const self = this;
31410 let result;
31411 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', ' ');
31412 const isInvalidInlineTarget = (options, elm) => options.inline && elm.tagName.toLowerCase() in invalidInlineTargets;
31413 const createId = elm => {
31414 let id = elm.id;
31415 if (!id) {
31416 id = get$a(elm, 'name').filter(name => !DOM.get(name)).getOrThunk(DOM.uniqueId);
31417 elm.setAttribute('id', id);
31418 }
31419 return id;
31420 };
31421 const execCallback = name => {
31422 const callback = options[name];
31423 if (!callback) {
31424 return;
31425 }
31426 return callback.apply(self, []);
31427 };
31428 const findTargets = options => {
31429 if (Env.browser.isIE() || Env.browser.isEdge()) {
31430 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/support/#supportedwebbrowsers');
31431 return [];
31432 } else if (isQuirksMode) {
31433 initError('Failed to initialize the editor as the document is not in standards mode. ' + 'TinyMCE requires standards mode.');
31434 return [];
31435 } else if (isString(options.selector)) {
31436 return DOM.select(options.selector);
31437 } else if (isNonNullable(options.target)) {
31438 return [options.target];
31439 } else {
31440 return [];
31441 }
31442 };
31443 let provideResults = editors => {
31444 result = editors;
31445 };
31446 const initEditors = () => {
31447 let initCount = 0;
31448 const editors = [];
31449 let targets;
31450 const createEditor = (id, options, targetElm) => {
31451 const editor = new Editor(id, options, self);
31452 editors.push(editor);
31453 editor.on('init', () => {
31454 if (++initCount === targets.length) {
31455 provideResults(editors);
31456 }
31457 });
31458 editor.targetElm = editor.targetElm || targetElm;
31459 editor.render();
31460 };
31461 DOM.unbind(window, 'ready', initEditors);
31462 execCallback('onpageload');
31463 targets = unique$1(findTargets(options));
31464 Tools.each(targets, elm => {
31465 purgeDestroyedEditor(self.get(elm.id));
31466 });
31467 targets = Tools.grep(targets, elm => {
31468 return !self.get(elm.id);
31469 });
31470 if (targets.length === 0) {
31471 provideResults([]);
31472 } else {
31473 each(targets, elm => {
31474 if (isInvalidInlineTarget(options, elm)) {
31475 initError('Could not initialize inline editor on invalid inline target element', elm);
31476 } else {
31477 createEditor(createId(elm), options, elm);
31478 }
31479 });
31480 }
31481 };
31482 DOM.bind(window, 'ready', initEditors);
31483 return new Promise(resolve => {
31484 if (result) {
31485 resolve(result);
31486 } else {
31487 provideResults = editors => {
31488 resolve(editors);
31489 };
31490 }
31491 });
31492 },
31493 get(id) {
31494 if (arguments.length === 0) {
31495 return editors.slice(0);
31496 } else if (isString(id)) {
31497 return find$2(editors, editor => {
31498 return editor.id === id;
31499 }).getOr(null);
31500 } else if (isNumber(id)) {
31501 return editors[id] ? editors[id] : null;
31502 } else {
31503 return null;
31504 }
31505 },
31506 add(editor) {
31507 const self = this;
31508 const existingEditor = self.get(editor.id);
31509 if (existingEditor === editor) {
31510 return editor;
31511 }
31512 if (existingEditor === null) {
31513 editors.push(editor);
31514 }
31515 toggleGlobalEvents(true);
31516 self.activeEditor = editor;
31517 self.dispatch('AddEditor', { editor });
31518 if (!beforeUnloadDelegate) {
31519 beforeUnloadDelegate = e => {
31520 const event = self.dispatch('BeforeUnload');
31521 if (event.returnValue) {
31522 e.preventDefault();
31523 e.returnValue = event.returnValue;
31524 return event.returnValue;
31525 }
31526 };
31527 window.addEventListener('beforeunload', beforeUnloadDelegate);
31528 }
31529 return editor;
31530 },
31531 createEditor(id, options) {
31532 return this.add(new Editor(id, options, this));
31533 },
31534 remove(selector) {
31535 const self = this;
31536 let editor;
31537 if (!selector) {
31538 for (let i = editors.length - 1; i >= 0; i--) {
31539 self.remove(editors[i]);
31540 }
31541 return;
31542 }
31543 if (isString(selector)) {
31544 each(DOM.select(selector), elm => {
31545 editor = self.get(elm.id);
31546 if (editor) {
31547 self.remove(editor);
31548 }
31549 });
31550 return;
31551 }
31552 editor = selector;
31553 if (isNull(self.get(editor.id))) {
31554 return null;
31555 }
31556 if (removeEditorFromList(editor)) {
31557 self.dispatch('RemoveEditor', { editor });
31558 }
31559 if (editors.length === 0) {
31560 window.removeEventListener('beforeunload', beforeUnloadDelegate);
31561 }
31562 editor.remove();
31563 toggleGlobalEvents(editors.length > 0);
31564 return editor;
31565 },
31566 execCommand(cmd, ui, value) {
31567 var _a;
31568 const self = this;
31569 const editorId = isObject(value) ? (_a = value.id) !== null && _a !== void 0 ? _a : value.index : value;
31570 switch (cmd) {
31571 case 'mceAddEditor': {
31572 if (!self.get(editorId)) {
31573 const editorOptions = value.options;
31574 new Editor(editorId, editorOptions, self).render();
31575 }
31576 return true;
31577 }
31578 case 'mceRemoveEditor': {
31579 const editor = self.get(editorId);
31580 if (editor) {
31581 editor.remove();
31582 }
31583 return true;
31584 }
31585 case 'mceToggleEditor': {
31586 const editor = self.get(editorId);
31587 if (!editor) {
31588 self.execCommand('mceAddEditor', false, value);
31589 return true;
31590 }
31591 if (editor.isHidden()) {
31592 editor.show();
31593 } else {
31594 editor.hide();
31595 }
31596 return true;
31597 }
31598 }
31599 if (self.activeEditor) {
31600 return self.activeEditor.execCommand(cmd, ui, value);
31601 }
31602 return false;
31603 },
31604 triggerSave: () => {
31605 each(editors, editor => {
31606 editor.save();
31607 });
31608 },
31609 addI18n: (code, items) => {
31610 I18n.add(code, items);
31611 },
31612 translate: text => {
31613 return I18n.translate(text);
31614 },
31615 setActive(editor) {
31616 const activeEditor = this.activeEditor;
31617 if (this.activeEditor !== editor) {
31618 if (activeEditor) {
31619 activeEditor.dispatch('deactivate', { relatedTarget: editor });
31620 }
31621 editor.dispatch('activate', { relatedTarget: activeEditor });
31622 }
31623 this.activeEditor = editor;
31624 },
31625 _setBaseUrl(baseUrl) {
31626 this.baseURL = new URI(this.documentBaseURL).toAbsolute(baseUrl.replace(/\/+$/, ''));
31627 this.baseURI = new URI(this.baseURL);
31628 }
31629 };
31630 EditorManager.setup();
31631
31632 const setup = () => {
31633 const dataValue = value$2();
31634 const FakeClipboardItem = items => ({
31635 items,
31636 types: keys(items),
31637 getType: type => get$a(items, type).getOrUndefined()
31638 });
31639 const write = data => {
31640 dataValue.set(data);
31641 };
31642 const read = () => dataValue.get().getOrUndefined();
31643 const clear = dataValue.clear;
31644 return {
31645 FakeClipboardItem,
31646 write,
31647 read,
31648 clear
31649 };
31650 };
31651 const FakeClipboard = setup();
31652
31653 const min = Math.min, max = Math.max, round = Math.round;
31654 const relativePosition = (rect, targetRect, rel) => {
31655 let x = targetRect.x;
31656 let y = targetRect.y;
31657 const w = rect.w;
31658 const h = rect.h;
31659 const targetW = targetRect.w;
31660 const targetH = targetRect.h;
31661 const relChars = (rel || '').split('');
31662 if (relChars[0] === 'b') {
31663 y += targetH;
31664 }
31665 if (relChars[1] === 'r') {
31666 x += targetW;
31667 }
31668 if (relChars[0] === 'c') {
31669 y += round(targetH / 2);
31670 }
31671 if (relChars[1] === 'c') {
31672 x += round(targetW / 2);
31673 }
31674 if (relChars[3] === 'b') {
31675 y -= h;
31676 }
31677 if (relChars[4] === 'r') {
31678 x -= w;
31679 }
31680 if (relChars[3] === 'c') {
31681 y -= round(h / 2);
31682 }
31683 if (relChars[4] === 'c') {
31684 x -= round(w / 2);
31685 }
31686 return create$2(x, y, w, h);
31687 };
31688 const findBestRelativePosition = (rect, targetRect, constrainRect, rels) => {
31689 for (let i = 0; i < rels.length; i++) {
31690 const pos = relativePosition(rect, targetRect, rels[i]);
31691 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) {
31692 return rels[i];
31693 }
31694 }
31695 return null;
31696 };
31697 const inflate = (rect, w, h) => {
31698 return create$2(rect.x - w, rect.y - h, rect.w + w * 2, rect.h + h * 2);
31699 };
31700 const intersect = (rect, cropRect) => {
31701 const x1 = max(rect.x, cropRect.x);
31702 const y1 = max(rect.y, cropRect.y);
31703 const x2 = min(rect.x + rect.w, cropRect.x + cropRect.w);
31704 const y2 = min(rect.y + rect.h, cropRect.y + cropRect.h);
31705 if (x2 - x1 < 0 || y2 - y1 < 0) {
31706 return null;
31707 }
31708 return create$2(x1, y1, x2 - x1, y2 - y1);
31709 };
31710 const clamp = (rect, clampRect, fixedSize) => {
31711 let x1 = rect.x;
31712 let y1 = rect.y;
31713 let x2 = rect.x + rect.w;
31714 let y2 = rect.y + rect.h;
31715 const cx2 = clampRect.x + clampRect.w;
31716 const cy2 = clampRect.y + clampRect.h;
31717 const underflowX1 = max(0, clampRect.x - x1);
31718 const underflowY1 = max(0, clampRect.y - y1);
31719 const overflowX2 = max(0, x2 - cx2);
31720 const overflowY2 = max(0, y2 - cy2);
31721 x1 += underflowX1;
31722 y1 += underflowY1;
31723 if (fixedSize) {
31724 x2 += underflowX1;
31725 y2 += underflowY1;
31726 x1 -= overflowX2;
31727 y1 -= overflowY2;
31728 }
31729 x2 -= overflowX2;
31730 y2 -= overflowY2;
31731 return create$2(x1, y1, x2 - x1, y2 - y1);
31732 };
31733 const create$2 = (x, y, w, h) => {
31734 return {
31735 x,
31736 y,
31737 w,
31738 h
31739 };
31740 };
31741 const fromClientRect = clientRect => {
31742 return create$2(clientRect.left, clientRect.top, clientRect.width, clientRect.height);
31743 };
31744 const Rect = {
31745 inflate,
31746 relativePosition,
31747 findBestRelativePosition,
31748 intersect,
31749 clamp,
31750 create: create$2,
31751 fromClientRect
31752 };
31753
31754 const awaiter = (resolveCb, rejectCb, timeout = 1000) => {
31755 let done = false;
31756 let timer = null;
31757 const complete = completer => (...args) => {
31758 if (!done) {
31759 done = true;
31760 if (timer !== null) {
31761 clearTimeout(timer);
31762 timer = null;
31763 }
31764 completer.apply(null, args);
31765 }
31766 };
31767 const resolve = complete(resolveCb);
31768 const reject = complete(rejectCb);
31769 const start = (...args) => {
31770 if (!done && timer === null) {
31771 timer = setTimeout(() => reject.apply(null, args), timeout);
31772 }
31773 };
31774 return {
31775 start,
31776 resolve,
31777 reject
31778 };
31779 };
31780 const create$1 = () => {
31781 const tasks = {};
31782 const resultFns = {};
31783 const resources = {};
31784 const load = (id, url) => {
31785 const loadErrMsg = `Script at URL "${ url }" failed to load`;
31786 const runErrMsg = `Script at URL "${ url }" did not call \`tinymce.Resource.add('${ id }', data)\` within 1 second`;
31787 if (tasks[id] !== undefined) {
31788 return tasks[id];
31789 } else {
31790 const task = new Promise((resolve, reject) => {
31791 const waiter = awaiter(resolve, reject);
31792 resultFns[id] = waiter.resolve;
31793 ScriptLoader.ScriptLoader.loadScript(url).then(() => waiter.start(runErrMsg), () => waiter.reject(loadErrMsg));
31794 });
31795 tasks[id] = task;
31796 return task;
31797 }
31798 };
31799 const add = (id, data) => {
31800 if (resultFns[id] !== undefined) {
31801 resultFns[id](data);
31802 delete resultFns[id];
31803 }
31804 tasks[id] = Promise.resolve(data);
31805 resources[id] = data;
31806 };
31807 const has = id => {
31808 return id in resources;
31809 };
31810 const unload = id => {
31811 delete tasks[id];
31812 delete resources[id];
31813 };
31814 const get = id => resources[id];
31815 return {
31816 load,
31817 add,
31818 has,
31819 get,
31820 unload
31821 };
31822 };
31823 const Resource = create$1();
31824
31825 const create = () => (() => {
31826 let data = {};
31827 let keys = [];
31828 const storage = {
31829 getItem: key => {
31830 const item = data[key];
31831 return item ? item : null;
31832 },
31833 setItem: (key, value) => {
31834 keys.push(key);
31835 data[key] = String(value);
31836 },
31837 key: index => {
31838 return keys[index];
31839 },
31840 removeItem: key => {
31841 keys = keys.filter(k => k === key);
31842 delete data[key];
31843 },
31844 clear: () => {
31845 keys = [];
31846 data = {};
31847 },
31848 length: 0
31849 };
31850 Object.defineProperty(storage, 'length', {
31851 get: () => keys.length,
31852 configurable: false,
31853 enumerable: false
31854 });
31855 return storage;
31856 })();
31857
31858 let localStorage;
31859 try {
31860 const test = '__storage_test__';
31861 localStorage = window.localStorage;
31862 localStorage.setItem(test, test);
31863 localStorage.removeItem(test);
31864 } catch (e) {
31865 localStorage = create();
31866 }
31867 var LocalStorage = localStorage;
31868
31869 const publicApi = {
31870 geom: { Rect },
31871 util: {
31872 Delay,
31873 Tools,
31874 VK,
31875 URI,
31876 EventDispatcher,
31877 Observable,
31878 I18n,
31879 LocalStorage,
31880 ImageUploader
31881 },
31882 dom: {
31883 EventUtils,
31884 TreeWalker: DomTreeWalker,
31885 TextSeeker,
31886 DOMUtils,
31887 ScriptLoader,
31888 RangeUtils,
31889 Serializer: DomSerializer,
31890 StyleSheetLoader,
31891 ControlSelection,
31892 BookmarkManager,
31893 Selection: EditorSelection,
31894 Event: EventUtils.Event
31895 },
31896 html: {
31897 Styles,
31898 Entities,
31899 Node: AstNode,
31900 Schema,
31901 DomParser,
31902 Writer,
31903 Serializer: HtmlSerializer
31904 },
31905 Env,
31906 AddOnManager,
31907 Annotator,
31908 Formatter,
31909 UndoManager,
31910 EditorCommands,
31911 WindowManager,
31912 NotificationManager,
31913 EditorObservable,
31914 Shortcuts,
31915 Editor,
31916 FocusManager,
31917 EditorManager,
31918 DOM: DOMUtils.DOM,
31919 ScriptLoader: ScriptLoader.ScriptLoader,
31920 PluginManager,
31921 ThemeManager,
31922 ModelManager,
31923 IconManager,
31924 Resource,
31925 FakeClipboard,
31926 trim: Tools.trim,
31927 isArray: Tools.isArray,
31928 is: Tools.is,
31929 toArray: Tools.toArray,
31930 makeMap: Tools.makeMap,
31931 each: Tools.each,
31932 map: Tools.map,
31933 grep: Tools.grep,
31934 inArray: Tools.inArray,
31935 extend: Tools.extend,
31936 walk: Tools.walk,
31937 resolve: Tools.resolve,
31938 explode: Tools.explode,
31939 _addCacheSuffix: Tools._addCacheSuffix
31940 };
31941 const tinymce$1 = Tools.extend(EditorManager, publicApi);
31942
31943 const exportToModuleLoaders = tinymce => {
31944 if (typeof module === 'object') {
31945 try {
31946 module.exports = tinymce;
31947 } catch (_) {
31948 }
31949 }
31950 };
31951 const exportToWindowGlobal = tinymce => {
31952 window.tinymce = tinymce;
31953 window.tinyMCE = tinymce;
31954 };
31955 exportToWindowGlobal(tinymce$1);
31956 exportToModuleLoaders(tinymce$1);
31957
31958})();