PageSourceSearch

https://meihualake.com/assets/vendor/tinymce/tinymce.js

js meihualake.com collected 2026-09-30 23:36:07 UTC 1,169,998 bytes, 31,305 lines download raw bytes

1/**
2 * TinyMCE version 6.6.2 (2023-08-0
vendor: 243,886 bytes, lines 2-7018
29)
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$3 = 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$2 = 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$2.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$2 = 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$5 = (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$5,
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$4 = (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$4(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$4(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$3 = 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$3 = (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$3 };
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$2 = () => platform$4();
960
961    const userAgent = navigator.userAgent;
962    const platform$3 = detect$2();
963    const browser$2 = 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$2.isIE() ? document.documentMode || 7 : 10,
970      cacheSuffix: null,
971      container: null,
972      canHaveCSP: !browser$2.isIE(),
973      windowsPhone,
974      browser: {
975        current: browser$2.current,
976        version: browser$2.version,
977        isChromium: browser$2.isChromium,
978        isEdge: browser$2.isEdge,
979        isFirefox: browser$2.isFirefox,
980        isIE: browser$2.isIE,
981        isOpera: browser$2.isOpera,
982        isSafari: browser$2.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$2 = 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$1 = 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$2);
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$2,
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$1,
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 cat = arr => {
1105      const r = [];
1106      const push = x => {
1107        r.push(x);
1108      };
1109      for (let i = 0; i < arr.length; i++) {
1110        arr[i].each(push);
1111      }
1112      return r;
1113    };
1114    const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
1115    const lift3 = (oa, ob, oc, f) => oa.isSome() && ob.isSome() && oc.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Optional.none();
1116    const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
1117
1118    const Global = typeof window !== 'undefined' ? window : Function('return this;')();
1119
1120    const path = (parts, scope) => {
1121      let o = scope !== undefined && scope !== null ? scope : Global;
1122      for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) {
1123        o = o[parts[i]];
1124      }
1125      return o;
1126    };
1127    const resolve$2 = (p, scope) => {
1128      const parts = p.split('.');
1129      return path(parts, scope);
1130    };
1131
1132    const unsafe = (name, scope) => {
1133      return resolve$2(name, scope);
1134    };
1135    const getOrDie = (name, scope) => {
1136      const actual = unsafe(name, scope);
1137      if (actual === undefined || actual === null) {
1138        throw new Error(name + ' not available on this browser');
1139      }
1140      return actual;
1141    };
1142
1143    const getPrototypeOf$1 = Object.getPrototypeOf;
1144    const sandHTMLElement = scope => {
1145      return getOrDie('HTMLElement', scope);
1146    };
1147    const isPrototypeOf = x => {
1148      const scope = resolve$2('ownerDocument.defaultView', x);
1149      return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf$1(x).constructor.name));
1150    };
1151
1152    const COMMENT = 8;
1153    const DOCUMENT = 9;
1154    const DOCUMENT_FRAGMENT = 11;
1155    const ELEMENT = 1;
1156    const TEXT = 3;
1157
1158    const name = element => {
1159      const r = element.dom.nodeName;
1160      return r.toLowerCase();
1161    };
1162    const type$1 = element => element.dom.nodeType;
1163    const isType = t => element => type$1(element) === t;
1164    const isComment$1 = element => type$1(element) === COMMENT || name(element) === '#comment';
1165    const isHTMLElement = element => isElement$7(element) && isPrototypeOf(element.dom);
1166    const isElement$7 = isType(ELEMENT);
1167    const isText$b = isType(TEXT);
1168    const isDocument$2 = isType(DOCUMENT);
1169    const isDocumentFragment$1 = isType(DOCUMENT_FRAGMENT);
1170    const isTag = tag => e => isElement$7(e) && name(e) === tag;
1171
1172    const rawSet = (dom, key, value) => {
1173      if (isString(value) || isBoolean(value) || isNumber(value)) {
1174        dom.setAttribute(key, value + '');
1175      } else {
1176        console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
1177        throw new Error('Attribute value was not simple');
1178      }
1179    };
1180    const set$3 = (element, key, value) => {
1181      rawSet(element.dom, key, value);
1182    };
1183    const setAll$1 = (element, attrs) => {
1184      const dom = element.dom;
1185      each$d(attrs, (v, k) => {
1186        rawSet(dom, k, v);
1187      });
1188    };
1189    const get$9 = (element, key) => {
1190      const v = element.dom.getAttribute(key);
1191      return v === null ? undefined : v;
1192    };
1193    const getOpt = (element, key) => Optional.from(get$9(element, key));
1194    const has$1 = (element, key) => {
1195      const dom = element.dom;
1196      return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
1197    };
1198    const remove$a = (element, key) => {
1199      element.dom.removeAttribute(key);
1200    };
1201    const hasNone = element => {
1202      const attrs = element.dom.attributes;
1203      return attrs === undefined || attrs === null || attrs.length === 0;
1204    };
1205    const clone$4 = element => foldl(element.dom.attributes, (acc, attr) => {
1206      acc[attr.name] = attr.value;
1207      return acc;
1208    }, {});
1209
1210    const read$4 = (element, attr) => {
1211      const value = get$9(element, attr);
1212      return value === undefined || value === '' ? [] : value.split(' ');
1213    };
1214    const add$4 = (element, attr, id) => {
1215      const old = read$4(element, attr);
1216      const nu = old.concat([id]);
1217      set$3(element, attr, nu.join(' '));
1218      return true;
1219    };
1220    const remove$9 = (element, attr, id) => {
1221      const nu = filter$5(read$4(element, attr), v => v !== id);
1222      if (nu.length > 0) {
1223        set$3(element, attr, nu.join(' '));
1224      } else {
1225        remove$a(element, attr);
1226      }
1227      return false;
1228    };
1229
1230    const supports = element => element.dom.classList !== undefined;
1231    const get$8 = element => read$4(element, 'class');
1232    const add$3 = (element, clazz) => add$4(element, 'class', clazz);
1233    const remove$8 = (element, clazz) => remove$9(element, 'class', clazz);
1234    const toggle$2 = (element, clazz) => {
1235      if (contains$2(get$8(element), clazz)) {
1236        return remove$8(element, clazz);
1237      } else {
1238        return add$3(element, clazz);
1239      }
1240    };
1241
1242    const add$2 = (element, clazz) => {
1243      if (supports(element)) {
1244        element.dom.classList.add(clazz);
1245      } else {
1246        add$3(element, clazz);
1247      }
1248    };
1249    const cleanClass = element => {
1250      const classList = supports(element) ? element.dom.classList : get$8(element);
1251      if (classList.length === 0) {
1252        remove$a(element, 'class');
1253      }
1254    };
1255    const remove$7 = (element, clazz) => {
1256      if (supports(element)) {
1257        const classList = element.dom.classList;
1258        classList.remove(clazz);
1259      } else {
1260        remove$8(element, clazz);
1261      }
1262      cleanClass(element);
1263    };
1264    const toggle$1 = (element, clazz) => {
1265      const result = supports(element) ? element.dom.classList.toggle(clazz) : toggle$2(element, clazz);
1266      cleanClass(element);
1267      return result;
1268    };
1269    const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz);
1270
1271    const fromHtml$1 = (html, scope) => {
1272      const doc = scope || document;
1273      const div = doc.createElement('div');
1274      div.innerHTML = html;
1275      if (!div.hasChildNodes() || div.childNodes.length > 1) {
1276        const message = 'HTML does not have a single root node';
1277        console.error(message, html);
1278        throw new Error(message);
1279      }
1280      return fromDom$2(div.childNodes[0]);
1281    };
1282    const fromTag = (tag, scope) => {
1283      const doc = scope || document;
1284      const node = doc.createElement(tag);
1285      return fromDom$2(node);
1286    };
1287    const fromText = (text, scope) => {
1288      const doc = scope || document;
1289      const node = doc.createTextNode(text);
1290      return fromDom$2(node);
1291    };
1292    const fromDom$2 = node => {
1293      if (node === null || node === undefined) {
1294        throw new Error('Node cannot be null or undefined');
1295      }
1296      return { dom: node };
1297    };
1298    const fromPoint$2 = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$2);
1299    const SugarElement = {
1300      fromHtml: fromHtml$1,
1301      fromTag,
1302      fromText,
1303      fromDom: fromDom$2,
1304      fromPoint: fromPoint$2
1305    };
1306
1307    const toArray = (target, f) => {
1308      const r = [];
1309      const recurse = e => {
1310        r.push(e);
1311        return f(e);
1312      };
1313      let cur = f(target);
1314      do {
1315        cur = cur.bind(recurse);
1316      } while (cur.isSome());
1317      return r;
1318    };
1319
1320    const is$1 = (element, selector) => {
1321      const dom = element.dom;
1322      if (dom.nodeType !== ELEMENT) {
1323        return false;
1324      } else {
1325        const elem = dom;
1326        if (elem.matches !== undefined) {
1327          return elem.matches(selector);
1328        } else if (elem.msMatchesSelector !== undefined) {
1329          return elem.msMatchesSelector(selector);
1330        } else if (elem.webkitMatchesSelector !== undefined) {
1331          return elem.webkitMatchesSelector(selector);
1332        } else if (elem.mozMatchesSelector !== undefined) {
1333          return elem.mozMatchesSelector(selector);
1334        } else {
1335          throw new Error('Browser lacks native selectors');
1336        }
1337      }
1338    };
1339    const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
1340    const all = (selector, scope) => {
1341      const base = scope === undefined ? document : scope.dom;
1342      return bypassSelector(base) ? [] : map$3(base.querySelectorAll(selector), SugarElement.fromDom);
1343    };
1344    const one = (selector, scope) => {
1345      const base = scope === undefined ? document : scope.dom;
1346      return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
1347    };
1348
1349    const eq = (e1, e2) => e1.dom === e2.dom;
1350    const contains = (e1, e2) => {
1351      const d1 = e1.dom;
1352      const d2 = e2.dom;
1353      return d1 === d2 ? false : d1.contains(d2);
1354    };
1355
1356    const owner$1 = element => SugarElement.fromDom(element.dom.ownerDocument);
1357    const documentOrOwner = dos => isDocument$2(dos) ? dos : owner$1(dos);
1358    const documentElement = element => SugarElement.fromDom(documentOrOwner(element).dom.documentElement);
1359    const defaultView = element => SugarElement.fromDom(documentOrOwner(element).dom.defaultView);
1360    const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
1361    const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
1362    const parents$1 = (element, isRoot) => {
1363      const stop = isFunction(isRoot) ? isRoot : never;
1364      let dom = element.dom;
1365      const ret = [];
1366      while (dom.parentNode !== null && dom.parentNode !== undefined) {
1367        const rawParent = dom.parentNode;
1368        const p = SugarElement.fromDom(rawParent);
1369        ret.push(p);
1370        if (stop(p) === true) {
1371          break;
1372        } else {
1373          dom = rawParent;
1374        }
1375      }
1376      return ret;
1377    };
1378    const siblings = element => {
1379      const filterSelf = elements => filter$5(elements, x => !eq(element, x));
1380      return parent(element).map(children$1).map(filterSelf).getOr([]);
1381    };
1382    const prevSibling = element => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom);
1383    const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
1384    const prevSiblings = element => reverse(toArray(element, prevSibling));
1385    const nextSiblings = element => toArray(element, nextSibling);
1386    const children$1 = element => map$3(element.dom.childNodes, SugarElement.fromDom);
1387    const child$1 = (element, index) => {
1388      const cs = element.dom.childNodes;
1389      return Optional.from(cs[index]).map(SugarElement.fromDom);
1390    };
1391    const firstChild = element => child$1(element, 0);
1392    const lastChild = element => child$1(element, element.dom.childNodes.length - 1);
1393    const childNodesCount = element => element.dom.childNodes.length;
1394    const hasChildNodes = element => element.dom.hasChildNodes();
1395
1396    const getHead = doc => {
1397      const b = doc.dom.head;
1398      if (b === null || b === undefined) {
1399        throw new Error('Head is not available yet');
1400      }
1401      return SugarElement.fromDom(b);
1402    };
1403
1404    const isShadowRoot = dos => isDocumentFragment$1(dos) && isNonNullable(dos.dom.host);
1405    const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
1406    const isSupported$1 = constant(supported);
1407    const getRootNode = supported ? e => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
1408    const getStyleContainer = dos => isShadowRoot(dos) ? dos : getHead(documentOrOwner(dos));
1409    const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
1410    const getShadowRoot = e => {
1411      const r = getRootNode(e);
1412      return isShadowRoot(r) ? Optional.some(r) : Optional.none();
1413    };
1414    const getShadowHost = e => SugarElement.fromDom(e.dom.host);
1415    const getOriginalEventTarget = event => {
1416      if (isSupported$1() && isNonNullable(event.target)) {
1417        const el = SugarElement.fromDom(event.target);
1418        if (isElement$7(el) && isOpenShadowHost(el)) {
1419          if (event.composed && event.composedPath) {
1420            const composedPath = event.composedPath();
1421            if (composedPath) {
1422              return head(composedPath);
1423            }
1424          }
1425        }
1426      }
1427      return Optional.from(event.target);
1428    };
1429    const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot);
1430
1431    const inBody = element => {
1432      const dom = isText$b(element) ? element.dom.parentNode : element.dom;
1433      if (dom === undefined || dom === null || dom.ownerDocument === null) {
1434        return false;
1435      }
1436      const doc = dom.ownerDocument;
1437      return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
1438    };
1439
1440    var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
1441      if (is(scope, a)) {
1442        return Optional.some(scope);
1443      } else if (isFunction(isRoot) && isRoot(scope)) {
1444        return Optional.none();
1445      } else {
1446        return ancestor(scope, a, isRoot);
1447      }
1448    };
1449
1450    const ancestor$4 = (scope, predicate, isRoot) => {
1451      let element = scope.dom;
1452      const stop = isFunction(isRoot) ? isRoot : never;
1453      while (element.parentNode) {
1454        element = element.parentNode;
1455        const el = SugarElement.fromDom(element);
1456        if (predicate(el)) {
1457          return Optional.some(el);
1458        } else if (stop(el)) {
1459          break;
1460        }
1461      }
1462      return Optional.none();
1463    };
1464    const closest$4 = (scope, predicate, isRoot) => {
1465      const is = (s, test) => test(s);
1466      return ClosestOrAncestor(is, ancestor$4, scope, predicate, isRoot);
1467    };
1468    const sibling$1 = (scope, predicate) => {
1469      const element = scope.dom;
1470      if (!element.parentNode) {
1471        return Optional.none();
1472      }
1473      return child(SugarElement.fromDom(element.parentNode), x => !eq(scope, x) && predicate(x));
1474    };
1475    const child = (scope, predicate) => {
1476      const pred = node => predicate(SugarElement.fromDom(node));
1477      const result = find$2(scope.dom.childNodes, pred);
1478      return result.map(SugarElement.fromDom);
1479    };
1480    const descendant$1 = (scope, predicate) => {
1481      const descend = node => {
1482        for (let i = 0; i < node.childNodes.length; i++) {
1483          const child = SugarElement.fromDom(node.childNodes[i]);
1484          if (predicate(child)) {
1485            return Optional.some(child);
1486          }
1487          const res = descend(node.childNodes[i]);
1488          if (res.isSome()) {
1489            return res;
1490          }
1491        }
1492        return Optional.none();
1493      };
1494      return descend(scope.dom);
1495    };
1496
1497    const ancestor$3 = (scope, selector, isRoot) => ancestor$4(scope, e => is$1(e, selector), isRoot);
1498    const descendant = (scope, selector) => one(selector, scope);
1499    const closest$3 = (scope, selector, isRoot) => {
1500      const is = (element, selector) => is$1(element, selector);
1501      return ClosestOrAncestor(is, ancestor$3, scope, selector, isRoot);
1502    };
1503
1504    const closest$2 = target => closest$3(target, '[contenteditable]');
1505    const isEditable$3 = (element, assumeEditable = false) => {
1506      if (inBody(element)) {
1507        return element.dom.isContentEditable;
1508      } else {
1509        return closest$2(element).fold(constant(assumeEditable), editable => getRaw$1(editable) === 'true');
1510      }
1511    };
1512    const getRaw$1 = element => element.dom.contentEditable;
1513
1514    const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
1515
1516    const internalSet = (dom, property, value) => {
1517      if (!isString(value)) {
1518        console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
1519        throw new Error('CSS value must be a string: ' + value);
1520      }
1521      if (isSupported(dom)) {
1522        dom.style.setProperty(property, value);
1523      }
1524    };
1525    const internalRemove = (dom, property) => {
1526      if (isSupported(dom)) {
1527        dom.style.removeProperty(property);
1528      }
1529    };
1530    const set$2 = (element, property, value) => {
1531      const dom = element.dom;
1532      internalSet(dom, property, value);
1533    };
1534    const setAll = (element, css) => {
1535      const dom = element.dom;
1536      each$d(css, (v, k) => {
1537        internalSet(dom, k, v);
1538      });
1539    };
1540    const get$7 = (element, property) => {
1541      const dom = element.dom;
1542      const styles = window.getComputedStyle(dom);
1543      const r = styles.getPropertyValue(property);
1544      return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
1545    };
1546    const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : '';
1547    const getRaw = (element, property) => {
1548      const dom = element.dom;
1549      const raw = getUnsafeProperty(dom, property);
1550      return Optional.from(raw).filter(r => r.length > 0);
1551    };
1552    const getAllRaw = element => {
1553      const css = {};
1554      const dom = element.dom;
1555      if (isSupported(dom)) {
1556        for (let i = 0; i < dom.style.length; i++) {
1557          const ruleName = dom.style.item(i);
1558          css[ruleName] = dom.style[ruleName];
1559        }
1560      }
1561      return css;
1562    };
1563    const remove$6 = (element, property) => {
1564      const dom = element.dom;
1565      internalRemove(dom, property);
1566      if (is$2(getOpt(element, 'style').map(trim$3), '')) {
1567        remove$a(element, 'style');
1568      }
1569    };
1570    const reflow = e => e.dom.offsetWidth;
1571
1572    const before$3 = (marker, element) => {
1573      const parent$1 = parent(marker);
1574      parent$1.each(v => {
1575        v.dom.insertBefore(element.dom, marker.dom);
1576      });
1577    };
1578    const after$4 = (marker, element) => {
1579      const sibling = nextSibling(marker);
1580      sibling.fold(() => {
1581        const parent$1 = parent(marker);
1582        parent$1.each(v => {
1583          append$1(v, element);
1584        });
1585      }, v => {
1586        before$3(v, element);
1587      });
1588    };
1589    const prepend = (parent, element) => {
1590      const firstChild$1 = firstChild(parent);
1591      firstChild$1.fold(() => {
1592        append$1(parent, element);
1593      }, v => {
1594        parent.dom.insertBefore(element.dom, v.dom);
1595      });
1596    };
1597    const append$1 = (parent, element) => {
1598      parent.dom.appendChild(element.dom);
1599    };
1600    const wrap$2 = (element, wrapper) => {
1601      before$3(element, wrapper);
1602      append$1(wrapper, element);
1603    };
1604
1605    const after$3 = (marker, elements) => {
1606      each$e(elements, (x, i) => {
1607        const e = i === 0 ? marker : elements[i - 1];
1608        after$4(e, x);
1609      });
1610    };
1611    const append = (parent, elements) => {
1612      each$e(elements, x => {
1613        append$1(parent, x);
1614      });
1615    };
1616
1617    const empty = element => {
1618      element.dom.textContent = '';
1619      each$e(children$1(element), rogue => {
1620        remove$5(rogue);
1621      });
1622    };
1623    const remove$5 = element => {
1624      const dom = element.dom;
1625      if (dom.parentNode !== null) {
1626        dom.parentNode.removeChild(dom);
1627      }
1628    };
1629    const unwrap = wrapper => {
1630      const children = children$1(wrapper);
1631      if (children.length > 0) {
1632        after$3(wrapper, children);
1633      }
1634      remove$5(wrapper);
1635    };
1636
1637    const fromHtml = (html, scope) => {
1638      const doc = scope || document;
1639      const div = doc.createElement('div');
1640      div.innerHTML = html;
1641      return children$1(SugarElement.fromDom(div));
1642    };
1643    const fromDom$1 = nodes => map$3(nodes, SugarElement.fromDom);
1644
1645    const get$6 = element => element.dom.innerHTML;
1646    const set$1 = (element, content) => {
1647      const owner = owner$1(element);
1648      const docDom = owner.dom;
1649      const fragment = SugarElement.fromDom(docDom.createDocumentFragment());
1650      const contentElements = fromHtml(content, docDom);
1651      append(fragment, contentElements);
1652      empty(element);
1653      append$1(element, fragment);
1654    };
1655    const getOuter = element => {
1656      const container = SugarElement.fromTag('div');
1657      const clone = SugarElement.fromDom(element.dom.cloneNode(true));
1658      append$1(container, clone);
1659      return get$6(container);
1660    };
1661
1662    const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({
1663      target,
1664      x,
1665      y,
1666      stop,
1667      prevent,
1668      kill,
1669      raw
1670    });
1671    const fromRawEvent = rawEvent => {
1672      const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
1673      const stop = () => rawEvent.stopPropagation();
1674      const prevent = () => rawEvent.preventDefault();
1675      const kill = compose(prevent, stop);
1676      return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent);
1677    };
1678    const handle$1 = (filter, handler) => rawEvent => {
1679      if (filter(rawEvent)) {
1680        handler(fromRawEvent(rawEvent));
1681      }
1682    };
1683    const binder = (element, event, filter, handler, useCapture) => {
1684      const wrapped = handle$1(filter, handler);
1685      element.dom.addEventListener(event, wrapped, useCapture);
1686      return { unbind: curry(unbind, element, event, wrapped, useCapture) };
1687    };
1688    const bind$2 = (element, event, filter, handler) => binder(element, event, filter, handler, false);
1689    const unbind = (element, event, handler, useCapture) => {
1690      element.dom.removeEventListener(event, handler, useCapture);
1691    };
1692
1693    const r = (left, top) => {
1694      const translate = (x, y) => r(left + x, top + y);
1695      return {
1696        left,
1697        top,
1698        translate
1699      };
1700    };
1701    const SugarPosition = r;
1702
1703    const boxPosition = dom => {
1704      const box = dom.getBoundingClientRect();
1705      return SugarPosition(box.left, box.top);
1706    };
1707    const firstDefinedOrZero = (a, b) => {
1708      if (a !== undefined) {
1709        return a;
1710      } else {
1711        return b !== undefined ? b : 0;
1712      }
1713    };
1714    const absolute = element => {
1715      const doc = element.dom.ownerDocument;
1716      const body = doc.body;
1717      const win = doc.defaultView;
1718      const html = doc.documentElement;
1719      if (body === element.dom) {
1720        return SugarPosition(body.offsetLeft, body.offsetTop);
1721      }
1722      const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html.scrollTop);
1723      const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html.scrollLeft);
1724      const clientTop = firstDefinedOrZero(html.clientTop, body.clientTop);
1725      const clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft);
1726      return viewport(element).translate(scrollLeft - clientLeft, scrollTop - clientTop);
1727    };
1728    const viewport = element => {
1729      const dom = element.dom;
1730      const doc = dom.ownerDocument;
1731      const body = doc.body;
1732      if (body === dom) {
1733        return SugarPosition(body.offsetLeft, body.offsetTop);
1734      }
1735      if (!inBody(element)) {
1736        return SugarPosition(0, 0);
1737      }
1738      return boxPosition(dom);
1739    };
1740
1741    const get$5 = _DOC => {
1742      const doc = _DOC !== undefined ? _DOC.dom : document;
1743      const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
1744      const y = doc.body.scrollTop || doc.documentElement.scrollTop;
1745      return SugarPosition(x, y);
1746    };
1747    const intoView = (element, alignToTop) => {
1748      const isSafari = detect$2().browser.isSafari();
1749      if (isSafari && isFunction(element.dom.scrollIntoViewIfNeeded)) {
1750        element.dom.scrollIntoViewIfNeeded(false);
1751      } else {
1752        element.dom.scrollIntoView(alignToTop);
1753      }
1754    };
1755
1756    const get$4 = _win => {
1757      const win = _win === undefined ? window : _win;
1758      if (detect$2().browser.isFirefox()) {
1759        return Optional.none();
1760      } else {
1761        return Optional.from(win.visualViewport);
1762      }
1763    };
1764    const bounds = (x, y, width, height) => ({
1765      x,
1766      y,
1767      width,
1768      height,
1769      right: x + width,
1770      bottom: y + height
1771    });
1772    const getBounds = _win => {
1773      const win = _win === undefined ? window : _win;
1774      const doc = win.document;
1775      const scroll = get$5(SugarElement.fromDom(doc));
1776      return get$4(win).fold(() => {
1777        const html = win.document.documentElement;
1778        const width = html.clientWidth;
1779        const height = html.clientHeight;
1780        return bounds(scroll.left, scroll.top, width, height);
1781      }, visualViewport => bounds(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
1782    };
1783
1784    const children = (scope, predicate) => filter$5(children$1(scope), predicate);
1785    const descendants$1 = (scope, predicate) => {
1786      let result = [];
1787      each$e(children$1(scope), x => {
1788        if (predicate(x)) {
1789          result = result.concat([x]);
1790        }
1791        result = result.concat(descendants$1(x, predicate));
1792      });
1793      return result;
1794    };
1795
1796    const descendants = (scope, selector) => all(selector, scope);
1797
1798    const ancestor$2 = (scope, selector, isRoot) => ancestor$3(scope, selector, isRoot).isSome();
1799
1800    class DomTreeWalker {
1801      constructor(startNode, rootNode) {
1802        this.node = startNode;
1803        this.rootNode = rootNode;
1804        this.current = this.current.bind(this);
1805        this.next = this.next.bind(this);
1806        this.prev = this.prev.bind(this);
1807        this.prev2 = this.prev2.bind(this);
1808      }
1809      current() {
1810        return this.node;
1811      }
1812      next(shallow) {
1813        this.node = this.findSibling(this.node, 'firstChild', 'nextSibling', shallow);
1814        return this.node;
1815      }
1816      prev(shallow) {
1817        this.node = this.findSibling(this.node, 'lastChild', 'previousSibling', shallow);
1818        return this.node;
1819      }
1820      prev2(shallow) {
1821        this.node = this.findPreviousNode(this.node, shallow);
1822        return this.node;
1823      }
1824      findSibling(node, startName, siblingName, shallow) {
1825        if (node) {
1826          if (!shallow && node[startName]) {
1827            return node[startName];
1828          }
1829          if (node !== this.rootNode) {
1830            let sibling = node[siblingName];
1831            if (sibling) {
1832              return sibling;
1833            }
1834            for (let parent = node.parentNode; parent && parent !== this.rootNode; parent = parent.parentNode) {
1835              sibling = parent[siblingName];
1836              if (sibling) {
1837                return sibling;
1838              }
1839            }
1840          }
1841        }
1842        return undefined;
1843      }
1844      findPreviousNode(node, shallow) {
1845        if (node) {
1846          const sibling = node.previousSibling;
1847          if (this.rootNode && sibling === this.rootNode) {
1848            return;
1849          }
1850          if (sibling) {
1851            if (!shallow) {
1852              for (let child = sibling.lastChild; child; child = child.lastChild) {
1853                if (!child.lastChild) {
1854                  return child;
1855                }
1856              }
1857            }
1858            return sibling;
1859          }
1860          const parent = node.parentNode;
1861          if (parent && parent !== this.rootNode) {
1862            return parent;
1863          }
1864        }
1865        return undefined;
1866      }
1867    }
1868
1869    const isNodeType = type => {
1870      return node => {
1871        return !!node && node.nodeType === type;
1872      };
1873    };
1874    const isRestrictedNode = node => !!node && !Object.getPrototypeOf(node);
1875    const isElement$6 = isNodeType(1);
1876    const matchNodeName = name => {
1877      const lowerCasedName = name.toLowerCase();
1878      return node => isNonNullable(node) && node.nodeName.toLowerCase() === lowerCasedName;
1879    };
1880    const matchNodeNames = names => {
1881      const lowerCasedNames = names.map(s => s.toLowerCase());
1882      return node => {
1883        if (node && node.nodeName) {
1884          const nodeName = node.nodeName.toLowerCase();
1885          return contains$2(lowerCasedNames, nodeName);
1886        }
1887        return false;
1888      };
1889    };
1890    const matchStyleValues = (name, values) => {
1891      const items = values.toLowerCase().split(' ');
1892      return node => {
1893        if (isElement$6(node)) {
1894          const win = node.ownerDocument.defaultView;
1895          if (win) {
1896            for (let i = 0; i < items.length; i++) {
1897              const computed = win.getComputedStyle(node, null);
1898              const cssValue = computed ? computed.getPropertyValue(name) : null;
1899              if (cssValue === items[i]) {
1900                return true;
1901              }
1902            }
1903          }
1904        }
1905        return false;
1906      };
1907    };
1908    const hasAttribute = attrName => {
1909      return node => {
1910        return isElement$6(node) && node.hasAttribute(attrName);
1911      };
1912    };
1913    const hasAttributeValue = (attrName, attrValue) => {
1914      return node => {
1915        return isElement$6(node) && node.getAttribute(attrName) === attrValue;
1916      };
1917    };
1918    const isBogus$2 = node => isElement$6(node) && node.hasAttribute('data-mce-bogus');
1919    const isBogusAll$1 = node => isElement$6(node) && node.getAttribute('data-mce-bogus') === 'all';
1920    const isTable$2 = node => isElement$6(node) && node.tagName === 'TABLE';
1921    const hasContentEditableState = value => {
1922      return node => {
1923        if (isElement$6(node)) {
1924          if (node.contentEditable === value) {
1925            return true;
1926          }
1927          if (node.getAttribute('data-mce-contenteditable') === value) {
1928            return true;
1929          }
1930        }
1931        return false;
1932      };
1933    };
1934    const isTextareaOrInput = matchNodeNames([
1935      'textarea',
1936      'input'
1937    ]);
1938    const isText$a = isNodeType(3);
1939    const isCData = isNodeType(4);
1940    const isPi = isNodeType(7);
1941    const isComment = isNodeType(8);
1942    const isDocument$1 = isNodeType(9);
1943    const isDocumentFragment = isNodeType(11);
1944    const isBr$6 = matchNodeName('br');
1945    const isImg = matchNodeName('img');
1946    const isContentEditableTrue$3 = hasContentEditableState('true');
1947    const isContentEditableFalse$b = hasContentEditableState('false');
1948    const isTableCell$3 = matchNodeNames([
1949      'td',
1950      'th'
1951    ]);
1952    const isTableCellOrCaption = matchNodeNames([
1953      'td',
1954      'th',
1955      'caption'
1956    ]);
1957    const isMedia$2 = matchNodeNames([
1958      'video',
1959      'audio',
1960      'object',
1961      'embed'
1962    ]);
1963    const isListItem$2 = matchNodeName('li');
1964    const isDetails = matchNodeName('details');
1965    const isSummary = matchNodeName('summary');
1966
1967    const zeroWidth = '\uFEFF';
1968    const nbsp = '\xA0';
1969    const isZwsp$2 = char => char === zeroWidth;
1970    const removeZwsp = s => s.replace(/\uFEFF/g, '');
1971
1972    const NodeValue = (is, name) => {
1973      const get = element => {
1974        if (!is(element)) {
1975          throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
1976        }
1977        return getOption(element).getOr('');
1978      };
1979      const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
1980      const set = (element, value) => {
1981        if (!is(element)) {
1982          throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
1983        }
1984        element.dom.nodeValue = value;
1985      };
1986      return {
1987        get,
1988        getOption,
1989        set
1990      };
1991    };
1992
1993    const api$1 = NodeValue(isText$b, 'text');
1994    const get$3 = element => api$1.get(element);
1995    const getOption = element => api$1.getOption(element);
1996    const set = (element, value) => api$1.set(element, value);
1997
1998    const blocks = [
1999      'article',
2000      'aside',
2001      'details',
2002      'div',
2003      'dt',
2004      'figcaption',
2005      'footer',
2006      'form',
2007      'fieldset',
2008      'header',
2009      'hgroup',
2010      'html',
2011      'main',
2012      'nav',
2013      'section',
2014      'summary',
2015      'body',
2016      'p',
2017      'dl',
2018      'multicol',
2019      'dd',
2020      'figure',
2021      'address',
2022      'center',
2023      'blockquote',
2024      'h1',
2025      'h2',
2026      'h3',
2027      'h4',
2028      'h5',
2029      'h6',
2030      'listing',
2031      'xmp',
2032      'pre',
2033      'plaintext',
2034      'menu',
2035      'dir',
2036      'ul',
2037      'ol',
2038      'li',
2039      'hr',
2040      'table',
2041      'tbody',
2042      'thead',
2043      'tfoot',
2044      'th',
2045      'tr',
2046      'td',
2047      'caption'
2048    ];
2049    const tableCells = [
2050      'td',
2051      'th'
2052    ];
2053    const tableSections = [
2054      'thead',
2055      'tbody',
2056      'tfoot'
2057    ];
2058    const textBlocks = [
2059      'h1',
2060      'h2',
2061      'h3',
2062      'h4',
2063      'h5',
2064      'h6',
2065      'p',
2066      'div',
2067      'address',
2068      'pre',
2069      'form',
2070      'blockquote',
2071      'center',
2072      'dir',
2073      'fieldset',
2074      'header',
2075      'footer',
2076      'article',
2077      'section',
2078      'hgroup',
2079      'aside',
2080      'nav',
2081      'figure'
2082    ];
2083    const headings = [
2084      'h1',
2085      'h2',
2086      'h3',
2087      'h4',
2088      'h5',
2089      'h6'
2090    ];
2091    const listItems$1 = [
2092      'li',
2093      'dd',
2094      'dt'
2095    ];
2096    const lists = [
2097      'ul',
2098      'ol',
2099      'dl'
2100    ];
2101    const wsElements = [
2102      'pre',
2103      'script',
2104      'textarea',
2105      'style'
2106    ];
2107    const wrapBlockElements = ['pre'].concat(headings);
2108    const lazyLookup = items => {
2109      let lookup;
2110      return node => {
2111        lookup = lookup ? lookup : mapToObject(items, always);
2112        return has$2(lookup, name(node));
2113      };
2114    };
2115    const isBlock$2 = lazyLookup(blocks);
2116    const isTable$1 = node => name(node) === 'table';
2117    const isInline$1 = node => isElement$7(node) && !isBlock$2(node);
2118    const isBr$5 = node => isElement$7(node) && name(node) === 'br';
2119    const isTextBlock$2 = lazyLookup(textBlocks);
2120    const isList = lazyLookup(lists);
2121    const isListItem$1 = lazyLookup(listItems$1);
2122    const isTableSection = lazyLookup(tableSections);
2123    const isTableCell$2 = lazyLookup(tableCells);
2124    const isWsPreserveElement = lazyLookup(wsElements);
2125    const isWrapBlockElement = lazyLookup(wrapBlockElements);
2126    const isWrapElement = node => isWrapBlockElement(node) || isInline$1(node);
2127
2128    const getLastChildren$1 = elm => {
2129      const children = [];
2130      let rawNode = elm.dom;
2131      while (rawNode) {
2132        children.push(SugarElement.fromDom(rawNode));
2133        rawNode = rawNode.lastChild;
2134      }
2135      return children;
2136    };
2137    const removeTrailingBr = elm => {
2138      const allBrs = descendants(elm, 'br');
2139      const brs = filter$5(getLastChildren$1(elm).slice(-1), isBr$5);
2140      if (allBrs.length === brs.length) {
2141        each$e(brs, remove$5);
2142      }
2143    };
2144    const createPaddingBr = () => {
2145      const br = SugarElement.fromTag('br');
2146      set$3(br, 'data-mce-bogus', '1');
2147      return br;
2148    };
2149    const fillWithPaddingBr = elm => {
2150      empty(elm);
2151      append$1(elm, createPaddingBr());
2152    };
2153    const trimBlockTrailingBr = elm => {
2154      lastChild(elm).each(lastChild => {
2155        prevSibling(lastChild).each(lastChildPrevSibling => {
2156          if (isBlock$2(elm) && isBr$5(lastChild) && isBlock$2(lastChildPrevSibling)) {
2157            remove$5(lastChild);
2158          }
2159        });
2160      });
2161    };
2162
2163    const ZWSP$1 = zeroWidth;
2164    const isZwsp$1 = isZwsp$2;
2165    const trim$1 = removeZwsp;
2166
2167    const isElement$5 = isElement$6;
2168    const isText$9 = isText$a;
2169    const isCaretContainerBlock$1 = node => {
2170      if (isText$9(node)) {
2171        node = node.parentNode;
2172      }
2173      return isElement$5(node) && node.hasAttribute('data-mce-caret');
2174    };
2175    const isCaretContainerInline = node => isText$9(node) && isZwsp$1(node.data);
2176    const isCaretContainer$2 = node => isCaretContainerBlock$1(node) || isCaretContainerInline(node);
2177    const hasContent = node => node.firstChild !== node.lastChild || !isBr$6(node.firstChild);
2178    const insertInline$1 = (node, before) => {
2179      var _a;
2180      const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
2181      const textNode = doc.createTextNode(ZWSP$1);
2182      const parentNode = node.parentNode;
2183      if (!before) {
2184        const sibling = node.nextSibling;
2185        if (isText$9(sibling)) {
2186          if (isCaretContainer$2(sibling)) {
2187            return sibling;
2188          }
2189          if (startsWithCaretContainer$1(sibling)) {
2190            sibling.splitText(1);
2191            return sibling;
2192          }
2193        }
2194        if (node.nextSibling) {
2195          parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node.nextSibling);
2196        } else {
2197          parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(textNode);
2198        }
2199      } else {
2200        const sibling = node.previousSibling;
2201        if (isText$9(sibling)) {
2202          if (isCaretContainer$2(sibling)) {
2203            return sibling;
2204          }
2205          if (endsWithCaretContainer$1(sibling)) {
2206            return sibling.splitText(sibling.data.length - 1);
2207          }
2208        }
2209        parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node);
2210      }
2211      return textNode;
2212    };
2213    const isBeforeInline = pos => {
2214      const container = pos.container();
2215      if (!isText$a(container)) {
2216        return false;
2217      }
2218      return container.data.charAt(pos.offset()) === ZWSP$1 || pos.isAtStart() && isCaretContainerInline(container.previousSibling);
2219    };
2220    const isAfterInline = pos => {
2221      const container = pos.container();
2222      if (!isText$a(container)) {
2223        return false;
2224      }
2225      return container.data.charAt(pos.offset() - 1) === ZWSP$1 || pos.isAtEnd() && isCaretContainerInline(container.nextSibling);
2226    };
2227    const insertBlock = (blockName, node, before) => {
2228      var _a;
2229      const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
2230      const blockNode = doc.createElement(blockName);
2231      blockNode.setAttribute('data-mce-caret', before ? 'before' : 'after');
2232      blockNode.setAttribute('data-mce-bogus', 'all');
2233      blockNode.appendChild(createPaddingBr().dom);
2234      const parentNode = node.parentNode;
2235      if (!before) {
2236        if (node.nextSibling) {
2237          parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node.nextSibling);
2238        } else {
2239          parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(blockNode);
2240        }
2241      } else {
2242        parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node);
2243      }
2244      return blockNode;
2245    };
2246    const startsWithCaretContainer$1 = node => isText$9(node) && node.data[0] === ZWSP$1;
2247    const endsWithCaretContainer$1 = node => isText$9(node) && node.data[node.data.length - 1] === ZWSP$1;
2248    const trimBogusBr = elm => {
2249      var _a;
2250      const brs = elm.getElementsByTagName('br');
2251      const lastBr = brs[brs.length - 1];
2252      if (isBogus$2(lastBr)) {
2253        (_a = lastBr.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(lastBr);
2254      }
2255    };
2256    const showCaretContainerBlock = caretContainer => {
2257      if (caretContainer && caretContainer.hasAttribute('data-mce-caret')) {
2258        trimBogusBr(caretContainer);
2259        caretContainer.removeAttribute('data-mce-caret');
2260        caretContainer.removeAttribute('data-mce-bogus');
2261        caretContainer.removeAttribute('style');
2262        caretContainer.removeAttribute('data-mce-style');
2263        caretContainer.removeAttribute('_moz_abspos');
2264        return caretContainer;
2265      }
2266      return null;
2267    };
2268    const isRangeInCaretContainerBlock = range => isCaretContainerBlock$1(range.startContainer);
2269
2270    const isContentEditableTrue$2 = isContentEditableTrue$3;
2271    const isContentEditableFalse$a = isContentEditableFalse$b;
2272    const isBr$4 = isBr$6;
2273    const isText$8 = isText$a;
2274    const isInvalidTextElement = matchNodeNames([
2275      'script',
2276      'style',
2277      'textarea'
2278    ]);
2279    const isAtomicInline = matchNodeNames([
2280      'img',
2281      'input',
2282      'textarea',
2283      'hr',
2284      'iframe',
2285      'video',
2286      'audio',
2287      'object',
2288      'embed'
2289    ]);
2290    const isTable = matchNodeNames(['table']);
2291    const isCaretContainer$1 = isCaretContainer$2;
2292    const isCaretCandidate$3 = node => {
2293      if (isCaretContainer$1(node)) {
2294        return false;
2295      }
2296      if (isText$8(node)) {
2297        return !isInvalidTextElement(node.parentNode);
2298      }
2299      return isAtomicInline(node) || isBr$4(node) || isTable(node) || isNonUiContentEditableFalse(node);
2300    };
2301    const isUnselectable = node => isElement$6(node) && node.getAttribute('unselectable') === 'true';
2302    const isNonUiContentEditableFalse = node => !isUnselectable(node) && isContentEditableFalse$a(node);
2303    const isInEditable = (node, root) => {
2304      for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
2305        if (isNonUiContentEditableFalse(tempNode)) {
2306          return false;
2307        }
2308        if (isContentEditableTrue$2(tempNode)) {
2309          return true;
2310        }
2311      }
2312      return true;
2313    };
2314    const isAtomicContentEditableFalse = node => {
2315      if (!isNonUiContentEditableFalse(node)) {
2316        return false;
2317      }
2318      return !foldl(from(node.getElementsByTagName('*')), (result, elm) => {
2319        return result || isContentEditableTrue$2(elm);
2320      }, false);
2321    };
2322    const isAtomic$1 = node => isAtomicInline(node) || isAtomicContentEditableFalse(node);
2323    const isEditableCaretCandidate$1 = (node, root) => isCaretCandidate$3(node) && isInEditable(node, root);
2324
2325    const whiteSpaceRegExp = /^[ \t\r\n]*$/;
2326    const isWhitespaceText = text => whiteSpaceRegExp.test(text);
2327    const isZwsp = text => {
2328      for (const c of text) {
2329        if (!isZwsp$2(c)) {
2330          return false;
2331        }
2332      }
2333      return true;
2334    };
2335    const isCollapsibleWhitespace$1 = c => ' \f\t\x0B'.indexOf(c) !== -1;
2336    const isNewLineChar = c => c === '\n' || c === '\r';
2337    const isNewline = (text, idx) => idx < text.length && idx >= 0 ? isNewLineChar(text[idx]) : false;
2338    const normalize$4 = (text, tabSpaces = 4, isStartOfContent = true, isEndOfContent = true) => {
2339      const tabSpace = repeat(' ', tabSpaces);
2340      const normalizedText = text.replace(/\t/g, tabSpace);
2341      const result = foldl(normalizedText, (acc, c) => {
2342        if (isCollapsibleWhitespace$1(c) || c === nbsp) {
2343          if (acc.pcIsSpace || acc.str === '' && isStartOfContent || acc.str.length === normalizedText.length - 1 && isEndOfContent || isNewline(normalizedText, acc.str.length + 1)) {
2344            return {
2345              pcIsSpace: false,
2346              str: acc.str + nbsp
2347            };
2348          } else {
2349            return {
2350              pcIsSpace: true,
2351              str: acc.str + ' '
2352            };
2353          }
2354        } else {
2355          return {
2356            pcIsSpace: isNewLineChar(c),
2357            str: acc.str + c
2358          };
2359        }
2360      }, {
2361        pcIsSpace: false,
2362        str: ''
2363      });
2364      return result.str;
2365    };
2366
2367    const hasWhitespacePreserveParent = (node, rootNode) => {
2368      const rootElement = SugarElement.fromDom(rootNode);
2369      const startNode = SugarElement.fromDom(node);
2370      return ancestor$2(startNode, 'pre,code', curry(eq, rootElement));
2371    };
2372    const isWhitespace$1 = (node, rootNode) => {
2373      return isText$a(node) && isWhitespaceText(node.data) && !hasWhitespacePreserveParent(node, rootNode);
2374    };
2375    const isNamedAnchor = node => {
2376      return isElement$6(node) && node.nodeName === 'A' && !node.hasAttribute('href') && (node.hasAttribute('name') || node.hasAttribute('id'));
2377    };
2378    const isContent$1 = (node, rootNode) => {
2379      return isCaretCandidate$3(node) && !isWhitespace$1(node, rootNode) || isNamedAnchor(node) || isBookmark(node);
2380    };
2381    const isBookmark = hasAttribute('data-mce-bookmark');
2382    const isBogus$1 = hasAttribute('data-mce-bogus');
2383    const isBogusAll = hasAttributeValue('data-mce-bogus', 'all');
2384    const isEmptyNode = (targetNode, skipBogus) => {
2385      let brCount = 0;
2386      if (isContent$1(targetNode, targetNode)) {
2387        return false;
2388      } else {
2389        let node = targetNode.firstChild;
2390        if (!node) {
2391          return true;
2392        }
2393        const walker = new DomTreeWalker(node, targetNode);
2394        do {
2395          if (skipBogus) {
2396            if (isBogusAll(node)) {
2397              node = walker.next(true);
2398              continue;
2399            }
2400            if (isBogus$1(node)) {
2401              node = walker.next();
2402              continue;
2403            }
2404          }
2405          if (isBr$6(node)) {
2406            brCount++;
2407            node = walker.next();
2408            continue;
2409          }
2410          if (isContent$1(node, targetNode)) {
2411            return false;
2412          }
2413          node = walker.next();
2414        } while (node);
2415        return brCount <= 1;
2416      }
2417    };
2418    const isEmpty$2 = (elm, skipBogus = true) => isEmptyNode(elm.dom, skipBogus);
2419
2420    const transparentBlockAttr = 'data-mce-block';
2421    const elementNames = map => filter$5(keys(map), key => !/[A-Z]/.test(key));
2422    const makeSelectorFromSchemaMap = map => elementNames(map).join(',');
2423    const updateTransparent = (blocksSelector, transparent) => {
2424      if (isNonNullable(transparent.querySelector(blocksSelector))) {
2425        transparent.setAttribute(transparentBlockAttr, 'true');
2426        if (transparent.getAttribute('data-mce-selected') === 'inline-boundary') {
2427          transparent.removeAttribute('data-mce-selected');
2428        }
2429        return true;
2430      } else {
2431        transparent.removeAttribute(transparentBlockAttr);
2432        return false;
2433      }
2434    };
2435    const updateBlockStateOnChildren = (schema, scope) => {
2436      const transparentSelector = makeSelectorFromSchemaMap(schema.getTransparentElements());
2437      const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
2438      return filter$5(scope.querySelectorAll(transparentSelector), transparent => updateTransparent(blocksSelector, transparent));
2439    };
2440    const trimEdge = (el, leftSide) => {
2441      var _a;
2442      const childPropertyName = leftSide ? 'lastChild' : 'firstChild';
2443      for (let child = el[childPropertyName]; child; child = child[childPropertyName]) {
2444        if (isEmpty$2(SugarElement.fromDom(child))) {
2445          (_a = child.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(child);
2446          return;
2447        }
2448      }
2449    };
2450    const split$2 = (parentElm, splitElm) => {
2451      const range = document.createRange();
2452      const parentNode = parentElm.parentNode;
2453      if (parentNode) {
2454        range.setStartBefore(parentElm);
2455        range.setEndBefore(splitElm);
2456        const beforeFragment = range.extractContents();
2457        trimEdge(beforeFragment, true);
2458        range.setStartAfter(splitElm);
2459        range.setEndAfter(parentElm);
2460        const afterFragment = range.extractContents();
2461        trimEdge(afterFragment, false);
2462        if (!isEmpty$2(SugarElement.fromDom(beforeFragment))) {
2463          parentNode.insertBefore(beforeFragment, parentElm);
2464        }
2465        if (!isEmpty$2(SugarElement.fromDom(splitElm))) {
2466          parentNode.insertBefore(splitElm, parentElm);
2467        }
2468        if (!isEmpty$2(SugarElement.fromDom(afterFragment))) {
2469          parentNode.insertBefore(afterFragment, parentElm);
2470        }
2471        parentNode.removeChild(parentElm);
2472      }
2473    };
2474    const splitInvalidChildren = (schema, scope, transparentBlocks) => {
2475      const blocksElements = schema.getBlockElements();
2476      const rootNode = SugarElement.fromDom(scope);
2477      const isBlock = el => name(el) in blocksElements;
2478      const isRoot = el => eq(el, rootNode);
2479      each$e(fromDom$1(transparentBlocks), transparentBlock => {
2480        ancestor$4(transparentBlock, isBlock, isRoot).each(parentBlock => {
2481          const invalidChildren = children(transparentBlock, el => isBlock(el) && !schema.isValidChild(name(parentBlock), name(el)));
2482          if (invalidChildren.length > 0) {
2483            const stateScope = parentElement(parentBlock);
2484            each$e(invalidChildren, child => {
2485              ancestor$4(child, isBlock, isRoot).each(parentBlock => {
2486                split$2(parentBlock.dom, child.dom);
2487              });
2488            });
2489            stateScope.each(scope => updateBlockStateOnChildren(schema, scope.dom));
2490          }
2491        });
2492      });
2493    };
2494    const unwrapInvalidChildren = (schema, scope, transparentBlocks) => {
2495      each$e([
2496        ...transparentBlocks,
2497        ...isTransparentBlock(schema, scope) ? [scope] : []
2498      ], block => each$e(descendants(SugarElement.fromDom(block), block.nodeName.toLowerCase()), elm => {
2499        if (isTransparentInline(schema, elm.dom)) {
2500          unwrap(elm);
2501        }
2502      }));
2503    };
2504    const updateChildren = (schema, scope) => {
2505      const transparentBlocks = updateBlockStateOnChildren(schema, scope);
2506      splitInvalidChildren(schema, scope, transparentBlocks);
2507      unwrapInvalidChildren(schema, scope, transparentBlocks);
2508    };
2509    const updateElement = (schema, target) => {
2510      if (isTransparentElement(schema, target)) {
2511        const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
2512        updateTransparent(blocksSelector, target);
2513      }
2514    };
2515    const updateCaret = (schema, root, caretParent) => {
2516      const isRoot = el => eq(el, SugarElement.fromDom(root));
2517      const parents = parents$1(SugarElement.fromDom(caretParent), isRoot);
2518      get$b(parents, parents.length - 2).filter(isElement$7).fold(() => updateChildren(schema, root), scope => updateChildren(schema, scope.dom));
2519    };
2520    const hasBlockAttr = el => el.hasAttribute(transparentBlockAttr);
2521    const isTransparentElementName = (schema, name) => has$2(schema.getTransparentElements(), name);
2522    const isTransparentElement = (schema, node) => isElement$6(node) && isTransparentElementName(schema, node.nodeName);
2523    const isTransparentBlock = (schema, node) => isTransparentElement(schema, node) && hasBlockAttr(node);
2524    const isTransparentInline = (schema, node) => isTransparentElement(schema, node) && !hasBlockAttr(node);
2525    const isTransparentAstBlock = (schema, node) => node.type === 1 && isTransparentElementName(schema, node.name) && isString(node.attr(transparentBlockAttr));
2526
2527    const browser$1 = detect$2().browser;
2528    const firstElement = nodes => find$2(nodes, isElement$7);
2529    const getTableCaptionDeltaY = elm => {
2530      if (browser$1.isFirefox() && name(elm) === 'table') {
2531        return firstElement(children$1(elm)).filter(elm => {
2532          return name(elm) === 'caption';
2533        }).bind(caption => {
2534          return firstElement(nextSiblings(caption)).map(body => {
2535            const bodyTop = body.dom.offsetTop;
2536            const captionTop = caption.dom.offsetTop;
2537            const captionHeight = caption.dom.offsetHeight;
2538            return bodyTop <= captionTop ? -captionHeight : 0;
2539          });
2540        }).getOr(0);
2541      } else {
2542        return 0;
2543      }
2544    };
2545    const hasChild = (elm, child) => elm.children && contains$2(elm.children, child);
2546    const getPos = (body, elm, rootElm) => {
2547      let x = 0, y = 0;
2548      const doc = body.ownerDocument;
2549      rootElm = rootElm ? rootElm : body;
2550      if (elm) {
2551        if (rootElm === body && elm.getBoundingClientRect && get$7(SugarElement.fromDom(body), 'position') === 'static') {
2552          const pos = elm.getBoundingClientRect();
2553          x = pos.left + (doc.documentElement.scrollLeft || body.scrollLeft) - doc.documentElement.clientLeft;
2554          y = pos.top + (doc.documentElement.scrollTop || body.scrollTop) - doc.documentElement.clientTop;
2555          return {
2556            x,
2557            y
2558          };
2559        }
2560        let offsetParent = elm;
2561        while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
2562          const castOffsetParent = offsetParent;
2563          x += castOffsetParent.offsetLeft || 0;
2564          y += castOffsetParent.offsetTop || 0;
2565          offsetParent = castOffsetParent.offsetParent;
2566        }
2567        offsetParent = elm.parentNode;
2568        while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
2569          x -= offsetParent.scrollLeft || 0;
2570          y -= offsetParent.scrollTop || 0;
2571          offsetParent = offsetParent.parentNode;
2572        }
2573        y += getTableCaptionDeltaY(SugarElement.fromDom(elm));
2574      }
2575      return {
2576        x,
2577        y
2578      };
2579    };
2580
2581    const StyleSheetLoader = (documentOrShadowRoot, settings = {}) => {
2582      let idCount = 0;
2583      const loadedStates = {};
2584      const edos = SugarElement.fromDom(documentOrShadowRoot);
2585      const doc = documentOrOwner(edos);
2586      const _setReferrerPolicy = referrerPolicy => {
2587        settings.referrerPolicy = referrerPolicy;
2588      };
2589      const _setContentCssCors = contentCssCors => {
2590        settings.contentCssCors = contentCssCors;
2591      };
2592      const addStyle = element => {
2593        append$1(getStyleContainer(edos), element);
2594      };
2595      const removeStyle = id => {
2596        const styleContainer = getStyleContainer(edos);
2597        descendant(styleContainer, '#' + id).each(remove$5);
2598      };
2599      const getOrCreateState = url => get$a(loadedStates, url).getOrThunk(() => ({
2600        id: 'mce-u' + idCount++,
2601        passed: [],
2602        failed: [],
2603        count: 0
2604      }));
2605      const load = url => new Promise((success, failure) => {
2606        let link;
2607        const urlWithSuffix = Tools._addCacheSuffix(url);
2608        const state = getOrCreateState(urlWithSuffix);
2609        loadedStates[urlWithSuffix] = state;
2610        state.count++;
2611        const resolve = (callbacks, status) => {
2612          each$e(callbacks, call);
2613          state.status = status;
2614          state.passed = [];
2615          state.failed = [];
2616          if (link) {
2617            link.onload = null;
2618            link.onerror = null;
2619            link = null;
2620          }
2621        };
2622        const passed = () => resolve(state.passed, 2);
2623        const failed = () => resolve(state.failed, 3);
2624        if (success) {
2625          state.passed.push(success);
2626        }
2627        if (failure) {
2628          state.failed.push(failure);
2629        }
2630        if (state.status === 1) {
2631          return;
2632        }
2633        if (state.status === 2) {
2634          passed();
2635          return;
2636        }
2637        if (state.status === 3) {
2638          failed();
2639          return;
2640        }
2641        state.status = 1;
2642        const linkElem = SugarElement.fromTag('link', doc.dom);
2643        setAll$1(linkElem, {
2644          rel: 'stylesheet',
2645          type: 'text/css',
2646          id: state.id
2647        });
2648        if (settings.contentCssCors) {
2649          set$3(linkElem, 'crossOrigin', 'anonymous');
2650        }
2651        if (settings.referrerPolicy) {
2652          set$3(linkElem, 'referrerpolicy', settings.referrerPolicy);
2653        }
2654        link = linkElem.dom;
2655        link.onload = passed;
2656        link.onerror = failed;
2657        addStyle(linkElem);
2658        set$3(linkElem, 'href', urlWithSuffix);
2659      });
2660      const loadAll = urls => {
2661        const loadedUrls = Promise.allSettled(map$3(urls, url => load(url).then(constant(url))));
2662        return loadedUrls.then(results => {
2663          const parts = partition$2(results, r => r.status === 'fulfilled');
2664          if (parts.fail.length > 0) {
2665            return Promise.reject(map$3(parts.fail, result => result.reason));
2666          } else {
2667            return map$3(parts.pass, result => result.value);
2668          }
2669        });
2670      };
2671      const unload = url => {
2672        const urlWithSuffix = Tools._addCacheSuffix(url);
2673        get$a(loadedStates, urlWithSuffix).each(state => {
2674          const count = --state.count;
2675          if (count === 0) {
2676            delete loadedStates[urlWithSuffix];
2677            removeStyle(state.id);
2678          }
2679        });
2680      };
2681      const unloadAll = urls => {
2682        each$e(urls, url => {
2683          unload(url);
2684        });
2685      };
2686      return {
2687        load,
2688        loadAll,
2689        unload,
2690        unloadAll,
2691        _setReferrerPolicy,
2692        _setContentCssCors
2693      };
2694    };
2695
2696    const create$d = () => {
2697      const map = new WeakMap();
2698      const forElement = (referenceElement, settings) => {
2699        const root = getRootNode(referenceElement);
2700        const rootDom = root.dom;
2701        return Optional.from(map.get(rootDom)).getOrThunk(() => {
2702          const sl = StyleSheetLoader(rootDom, settings);
2703          map.set(rootDom, sl);
2704          return sl;
2705        });
2706      };
2707      return { forElement };
2708    };
2709    const instance = create$d();
2710
2711    const isSpan = node => node.nodeName.toLowerCase() === 'span';
2712    const isInlineContent = (node, root) => isNonNullable(node) && (isContent$1(node, root) || isInline$1(SugarElement.fromDom(node)));
2713    const surroundedByInlineContent = (node, root) => {
2714      const prev = new DomTreeWalker(node, root).prev(false);
2715      const next = new DomTreeWalker(node, root).next(false);
2716      const prevIsInline = isUndefined(prev) || isInlineContent(prev, root);
2717      const nextIsInline = isUndefined(next) || isInlineContent(next, root);
2718      return prevIsInline && nextIsInline;
2719    };
2720    const isBookmarkNode$2 = node => isSpan(node) && node.getAttribute('data-mce-type') === 'bookmark';
2721    const isKeepTextNode = (node, root) => isText$a(node) && node.data.length > 0 && surroundedByInlineContent(node, root);
2722    const isKeepElement = node => isElement$6(node) ? node.childNodes.length > 0 : false;
2723    const isDocument = node => isDocumentFragment(node) || isDocument$1(node);
2724    const trimNode = (dom, node, root) => {
2725      var _a;
2726      const rootNode = root || node;
2727      if (isElement$6(node) && isBookmarkNode$2(node)) {
2728        return node;
2729      }
2730      const children = node.childNodes;
2731      for (let i = children.length - 1; i >= 0; i--) {
2732        trimNode(dom, children[i], rootNode);
2733      }
2734      if (isElement$6(node)) {
2735        const currentChildren = node.childNodes;
2736        if (currentChildren.length === 1 && isBookmarkNode$2(currentChildren[0])) {
2737          (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(currentChildren[0], node);
2738        }
2739      }
2740      if (!isDocument(node) && !isContent$1(node, rootNode) && !isKeepElement(node) && !isKeepTextNode(node, rootNode)) {
2741        dom.remove(node);
2742      }
2743      return node;
2744    };
2745
2746    const makeMap$3 = Tools.makeMap;
2747    const attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
2748    const textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
2749    const rawCharsRegExp = /[<>&\"\']/g;
2750    const entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi;
2751    const asciiMap = {
2752      128: '\u20AC',
2753      130: '\u201A',
2754      131: '\u0192',
2755      132: '\u201E',
2756      133: '\u2026',
2757      134: '\u2020',
2758      135: '\u2021',
2759      136: '\u02c6',
2760      137: '\u2030',
2761      138: '\u0160',
2762      139: '\u2039',
2763      140: '\u0152',
2764      142: '\u017d',
2765      145: '\u2018',
2766      146: '\u2019',
2767      147: '\u201C',
2768      148: '\u201D',
2769      149: '\u2022',
2770      150: '\u2013',
2771      151: '\u2014',
2772      152: '\u02DC',
2773      153: '\u2122',
2774      154: '\u0161',
2775      155: '\u203A',
2776      156: '\u0153',
2777      158: '\u017e',
2778      159: '\u0178'
2779    };
2780    const baseEntities = {
2781      '"': '&quot;',
2782      '\'': '&#39;',
2783      '<': '&lt;',
2784      '>': '&gt;',
2785      '&': '&amp;',
2786      '`': '&#96;'
2787    };
2788    const reverseEntities = {
2789      '&lt;': '<',
2790      '&gt;': '>',
2791      '&amp;': '&',
2792      '&quot;': '"',
2793      '&apos;': `'`
2794    };
2795    const nativeDecode = text => {
2796      const elm = SugarElement.fromTag('div').dom;
2797      elm.innerHTML = text;
2798      return elm.textContent || elm.innerText || text;
2799    };
2800    const buildEntitiesLookup = (items, radix) => {
2801      const lookup = {};
2802      if (items) {
2803        const itemList = items.split(',');
2804        radix = radix || 10;
2805        for (let i = 0; i < itemList.length; i += 2) {
2806          const chr = String.fromCharCode(parseInt(itemList[i], radix));
2807          if (!baseEntities[chr]) {
2808            const entity = '&' + itemList[i + 1] + ';';
2809            lookup[chr] = entity;
2810            lookup[entity] = chr;
2811          }
2812        }
2813        return lookup;
2814      } else {
2815        return undefined;
2816      }
2817    };
2818    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);
2819    const encodeRaw = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
2820      return baseEntities[chr] || chr;
2821    });
2822    const encodeAllRaw = text => ('' + text).replace(rawCharsRegExp, chr => {
2823      return baseEntities[chr] || chr;
2824    });
2825    const encodeNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
2826      if (chr.length > 1) {
2827        return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
2828      }
2829      return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
2830    });
2831    const encodeNamed = (text, attr, entities) => {
2832      const resolveEntities = entities || namedEntities;
2833      return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
2834        return baseEntities[chr] || resolveEntities[chr] || chr;
2835      });
2836    };
2837    const getEncodeFunc = (name, entities) => {
2838      const entitiesMap = buildEntitiesLookup(entities) || namedEntities;
2839      const encodeNamedAndNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
2840        if (baseEntities[chr] !== undefined) {
2841          return baseEntities[chr];
2842        }
2843        if (entitiesMap[chr] !== undefined) {
2844          return entitiesMap[chr];
2845        }
2846        if (chr.length > 1) {
2847          return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
2848        }
2849        return '&#' + chr.charCodeAt(0) + ';';
2850      });
2851      const encodeCustomNamed = (text, attr) => {
2852        return encodeNamed(text, attr, entitiesMap);
2853      };
2854      const nameMap = makeMap$3(name.replace(/\+/g, ','));
2855      if (nameMap.named && nameMap.numeric) {
2856        return encodeNamedAndNumeric;
2857      }
2858      if (nameMap.named) {
2859        if (entities) {
2860          return encodeCustomNamed;
2861        }
2862        return encodeNamed;
2863      }
2864      if (nameMap.numeric) {
2865        return encodeNumeric;
2866      }
2867      return encodeRaw;
2868    };
2869    const decode = text => text.replace(entityRegExp, (all, numeric) => {
2870      if (numeric) {
2871        if (numeric.charAt(0).toLowerCase() === 'x') {
2872          numeric = parseInt(numeric.substr(1), 16);
2873        } else {
2874          numeric = parseInt(numeric, 10);
2875        }
2876        if (numeric > 65535) {
2877          numeric -= 65536;
2878          return String.fromCharCode(55296 + (numeric >> 10), 56320 + (numeric & 1023));
2879        }
2880        return asciiMap[numeric] || String.fromCharCode(numeric);
2881      }
2882      return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
2883    });
2884    const Entities = {
2885      encodeRaw,
2886      encodeAllRaw,
2887      encodeNumeric,
2888      encodeNamed,
2889      getEncodeFunc,
2890      decode
2891    };
2892
2893    const lookupCache = {};
2894    const mapCache = {};
2895    const dummyObj = {};
2896    const makeMap$2 = Tools.makeMap, each$b = Tools.each, extend$2 = Tools.extend, explode$2 = Tools.explode, inArray = Tools.inArray;
2897    const split$1 = (items, delim) => {
2898      items = Tools.trim(items);
2899      return items ? items.split(delim || ' ') : [];
2900    };
2901    const createMap = (defaultValue, extendWith = {}) => {
2902      const value = makeMap$2(defaultValue, ' ', makeMap$2(defaultValue.toUpperCase(), ' '));
2903      return extend$2(value, extendWith);
2904    };
2905    const getTextRootBlockElements = schema => createMap('td th li dt dd figcaption caption details summary', schema.getTextBlockElements());
2906    const compileSchema = type => {
2907      const schema = {};
2908      let globalAttributes, blockContent;
2909      let phrasingContent, flowContent;
2910      const add = (name, attributes = '', children = '') => {
2911        const childNames = split$1(children);
2912        const names = split$1(name);
2913        let ni = names.length;
2914        while (ni--) {
2915          const attributesOrder = split$1([
2916            globalAttributes,
2917            attributes
2918          ].join(' '));
2919          schema[names[ni]] = {
2920            attributes: mapToObject(attributesOrder, () => ({})),
2921            attributesOrder,
2922            children: mapToObject(childNames, constant(dummyObj))
2923          };
2924        }
2925      };
2926      const addAttrs = (name, attributes) => {
2927        const names = split$1(name);
2928        const attrs = split$1(attributes);
2929        let ni = names.length;
2930        while (ni--) {
2931          const schemaItem = schema[names[ni]];
2932          for (let i = 0, l = attrs.length; i < l; i++) {
2933            schemaItem.attributes[attrs[i]] = {};
2934            schemaItem.attributesOrder.push(attrs[i]);
2935          }
2936        }
2937      };
2938      if (lookupCache[type]) {
2939        return lookupCache[type];
2940      }
2941      globalAttributes = 'id accesskey class dir lang style tabindex title role';
2942      blockContent = 'address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul';
2943      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';
2944      if (type !== 'html4') {
2945        const transparentContent = 'a ins del canvas map';
2946        globalAttributes += ' contenteditable contextmenu draggable dropzone ' + 'hidden spellcheck translate';
2947        blockContent += ' article aside details dialog figure main header footer hgroup section nav ' + transparentContent;
2948        phrasingContent += ' audio canvas command datalist mark meter output picture ' + 'progress time wbr video ruby bdi keygen';
2949      }
2950      if (type !== 'html5-strict') {
2951        globalAttributes += ' xml:lang';
2952        const html4PhrasingContent = 'acronym applet basefont big font strike tt';
2953        phrasingContent = [
2954          phrasingContent,
2955          html4PhrasingContent
2956        ].join(' ');
2957        each$b(split$1(html4PhrasingContent), name => {
2958          add(name, '', phrasingContent);
2959        });
2960        const html4BlockContent = 'center dir isindex noframes';
2961        blockContent = [
2962          blockContent,
2963          html4BlockContent
2964        ].join(' ');
2965        flowContent = [
2966          blockContent,
2967          phrasingContent
2968        ].join(' ');
2969        each$b(split$1(html4BlockContent), name => {
2970          add(name, '', flowContent);
2971        });
2972      }
2973      flowContent = flowContent || [
2974        blockContent,
2975        phrasingContent
2976      ].join(' ');
2977      add('html', 'manifest', 'head body');
2978      add('head', '', 'base command link meta noscript script style title');
2979      add('title hr noscript br');
2980      add('base', 'href target');
2981      add('link', 'href rel media hreflang type sizes hreflang');
2982      add('meta', 'name http-equiv content charset');
2983      add('style', 'media type scoped');
2984      add('script', 'src async defer type charset');
2985      add('body', 'onafterprint onbeforeprint onbeforeunload onblur onerror onfocus ' + 'onhashchange onload onmessage onoffline ononline onpagehide onpageshow ' + 'onpopstate onresize onscroll onstorage onunload', flowContent);
2986      add('dd div', '', flowContent);
2987      add('address dt caption', '', type === 'html4' ? phrasingContent : flowContent);
2988      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);
2989      add('blockquote', 'cite', flowContent);
2990      add('ol', 'reversed start type', 'li');
2991      add('ul', '', 'li');
2992      add('li', 'value', flowContent);
2993      add('dl', '', 'dt dd');
2994      add('a', 'href target rel media hreflang type', type === 'html4' ? phrasingContent : flowContent);
2995      add('q', 'cite', phrasingContent);
2996      add('ins del', 'cite datetime', flowContent);
2997      add('img', 'src sizes srcset alt usemap ismap width height');
2998      add('iframe', 'src name width height', flowContent);
2999      add('embed', 'src type width height');
3000      add('object', 'data type typemustmatch name usemap form width height', [
3001        flowContent,
3002        'param'
3003      ].join(' '));
3004      add('param', 'name value');
3005      add('map', 'name', [
3006        flowContent,
3007        'area'
3008      ].join(' '));
3009      add('area', 'alt coords shape href target rel media hreflang type');
3010      add('table', 'border', 'caption colgroup thead tfoot tbody tr' + (type === 'html4' ? ' col' : ''));
3011      add('colgroup', 'span', 'col');
3012      add('col', 'span');
3013      add('tbody thead tfoot', '', 'tr');
3014      add('tr', '', 'td th');
3015      add('td', 'colspan rowspan headers', flowContent);
3016      add('th', 'colspan rowspan headers scope abbr', flowContent);
3017      add('form', 'accept-charset action autocomplete enctype method name novalidate target', flowContent);
3018      add('fieldset', 'disabled form name', [
3019        flowContent,
3020        'legend'
3021      ].join(' '));
3022      add('label', 'form for', phrasingContent);
3023      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');
3024      add('button', 'disabled form formaction formenctype formmethod formnovalidate formtarget name type value', type === 'html4' ? flowContent : phrasingContent);
3025      add('select', 'disabled form multiple name required size', 'option optgroup');
3026      add('optgroup', 'disabled label', 'option');
3027      add('option', 'disabled label selected value');
3028      add('textarea', 'cols dirname disabled form maxlength name readonly required rows wrap');
3029      add('menu', 'type label', [
3030        flowContent,
3031        'li'
3032      ].join(' '));
3033      add('noscript', '', flowContent);
3034      if (type !== 'html4') {
3035        add('wbr');
3036        add('ruby', '', [
3037          phrasingContent,
3038          'rt rp'
3039        ].join(' '));
3040        add('figcaption', '', flowContent);
3041        add('mark rt rp summary bdi', '', phrasingContent);
3042        add('canvas', 'width height', flowContent);
3043        add('video', 'src crossorigin poster preload autoplay mediagroup loop ' + 'muted controls width height buffered', [
3044          flowContent,
3045          'track source'
3046        ].join(' '));
3047        add('audio', 'src crossorigin preload autoplay mediagroup loop muted controls ' + 'buffered volume', [
3048          flowContent,
3049          'track source'
3050        ].join(' '));
3051        add('picture', '', 'img source');
3052        add('source', 'src srcset type media sizes');
3053        add('track', 'kind src srclang label default');
3054        add('datalist', '', [
3055          phrasingContent,
3056          'option'
3057        ].join(' '));
3058        add('article section nav aside main header footer', '', flowContent);
3059        add('hgroup', '', 'h1 h2 h3 h4 h5 h6');
3060        add('figure', '', [
3061          flowContent,
3062          'figcaption'
3063        ].join(' '));
3064        add('time', 'datetime', phrasingContent);
3065        add('dialog', 'open', flowContent);
3066        add('command', 'type label icon disabled checked radiogroup command');
3067        add('output', 'for form name', phrasingContent);
3068        add('progress', 'value max', phrasingContent);
3069        add('meter', 'value min max low high optimum', phrasingContent);
3070        add('details', 'open', [
3071          flowContent,
3072          'summary'
3073        ].join(' '));
3074        add('keygen', 'autofocus challenge disabled form keytype name');
3075      }
3076      if (type !== 'html5-strict') {
3077        addAttrs('script', 'language xml:space');
3078        addAttrs('style', 'xml:space');
3079        addAttrs('object', 'declare classid code codebase codetype archive standby align border hspace vspace');
3080        addAttrs('embed', 'align name hspace vspace');
3081        addAttrs('param', 'valuetype type');
3082        addAttrs('a', 'charset name rev shape coords');
3083        addAttrs('br', 'clear');
3084        addAttrs('applet', 'codebase archive code object alt name width height align hspace vspace');
3085        addAttrs('img', 'name longdesc align border hspace vspace');
3086        addAttrs('iframe', 'longdesc frameborder marginwidth marginheight scrolling align');
3087        addAttrs('font basefont', 'size color face');
3088        addAttrs('input', 'usemap align');
3089        addAttrs('select');
3090        addAttrs('textarea');
3091        addAttrs('h1 h2 h3 h4 h5 h6 div p legend caption', 'align');
3092        addAttrs('ul', 'type compact');
3093        addAttrs('li', 'type');
3094        addAttrs('ol dl menu dir', 'compact');
3095        addAttrs('pre', 'width xml:space');
3096        addAttrs('hr', 'align noshade size width');
3097        addAttrs('isindex', 'prompt');
3098        addAttrs('table', 'summary width frame rules cellspacing cellpadding align bgcolor');
3099        addAttrs('col', 'width align char charoff valign');
3100        addAttrs('colgroup', 'width align char charoff valign');
3101        addAttrs('thead', 'align char charoff valign');
3102        addAttrs('tr', 'align char charoff valign bgcolor');
3103        addAttrs('th', 'axis align char charoff valign nowrap bgcolor width height');
3104        addAttrs('form', 'accept');
3105        addAttrs('td', 'abbr axis scope align char charoff valign nowrap bgcolor width height');
3106        addAttrs('tfoot', 'align char charoff valign');
3107        addAttrs('tbody', 'align char charoff valign');
3108        addAttrs('area', 'nohref');
3109        addAttrs('body', 'background bgcolor text link vlink alink');
3110      }
3111      if (type !== 'html4') {
3112        addAttrs('input button select textarea', 'autofocus');
3113        addAttrs('input textarea', 'placeholder');
3114        addAttrs('a', 'download');
3115        addAttrs('link script img', 'crossorigin');
3116        addAttrs('img', 'loading');
3117        addAttrs('iframe', 'sandbox seamless allow allowfullscreen loading');
3118      }
3119      if (type !== 'html4') {
3120        each$e([
3121          schema.video,
3122          schema.audio
3123        ], item => {
3124          delete item.children.audio;
3125          delete item.children.video;
3126        });
3127      }
3128      each$b(split$1('a form meter progress dfn'), name => {
3129        if (schema[name]) {
3130          delete schema[name].children[name];
3131        }
3132      });
3133      delete schema.caption.children.table;
3134      delete schema.script;
3135      lookupCache[type] = schema;
3136      return schema;
3137    };
3138    const compileElementMap = (value, mode) => {
3139      if (value) {
3140        const styles = {};
3141        if (isString(value)) {
3142          value = { '*': value };
3143        }
3144        each$b(value, (value, key) => {
3145          styles[key] = styles[key.toUpperCase()] = mode === 'map' ? makeMap$2(value, /[, ]/) : explode$2(value, /[, ]/);
3146        });
3147        return styles;
3148      } else {
3149        return undefined;
3150      }
3151    };
3152    const Schema = (settings = {}) => {
3153      var _a;
3154      const elements = {};
3155      const children = {};
3156      let patternElements = [];
3157      const customElementsMap = {};
3158      const specialElements = {};
3159      const createLookupTable = (option, defaultValue, extendWith) => {
3160        const value = settings[option];
3161        if (!value) {
3162          let newValue = mapCache[option];
3163          if (!newValue) {
3164            newValue = createMap(defaultValue, extendWith);
3165            mapCache[option] = newValue;
3166          }
3167          return newValue;
3168        } else {
3169          return makeMap$2(value, /[, ]/, makeMap$2(value.toUpperCase(), /[, ]/));
3170        }
3171      };
3172      const schemaType = (_a = settings.schema) !== null && _a !== void 0 ? _a : 'html5';
3173      const schemaItems = compileSchema(schemaType);
3174      if (settings.verify_html === false) {
3175        settings.valid_elements = '*[*]';
3176      }
3177      const validStyles = compileElementMap(settings.valid_styles);
3178      const invalidStyles = compileElementMap(settings.invalid_styles, 'map');
3179      const validClasses = compileElementMap(settings.valid_classes, 'map');
3180      const whitespaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea video audio iframe object code');
3181      const selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
3182      const voidElementsMap = createLookupTable('void_elements', 'area base basefont br col frame hr img input isindex link ' + 'meta param embed source wbr track');
3183      const boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' + 'noshade nowrap readonly selected autoplay loop controls allowfullscreen');
3184      const nonEmptyOrMoveCaretBeforeOnEnter = 'td th iframe video audio object script code';
3185      const nonEmptyElementsMap = createLookupTable('non_empty_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' pre', voidElementsMap);
3186      const moveCaretBeforeOnEnterElementsMap = createLookupTable('move_caret_before_on_enter_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' table', voidElementsMap);
3187      const textBlockElementsMap = createLookupTable('text_block_elements', 'h1 h2 h3 h4 h5 h6 p div address pre form ' + 'blockquote center dir fieldset header footer article section hgroup aside main nav figure');
3188      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', textBlockElementsMap);
3189      const textInlineElementsMap = createLookupTable('text_inline_elements', 'span strong b em i font s strike u var cite ' + 'dfn code mark q sup sub samp');
3190      const transparentElementsMap = createLookupTable('transparent_elements', 'a ins del canvas map');
3191      each$b('script noscript iframe noframes noembed title style textarea xmp plaintext'.split(' '), name => {
3192        specialElements[name] = new RegExp('</' + name + '[^>]*>', 'gi');
3193      });
3194      const patternToRegExp = str => new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
3195      const addValidElements = validElements => {
3196        const elementRuleRegExp = /^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)])?$/;
3197        const attrRuleRegExp = /^([!\-])?(\w+[\\:]:\w+|[^=~<]+)?(?:([=~<])(.*))?$/;
3198        const hasPatternsRegExp = /[*?+]/;
3199        if (validElements) {
3200          const validElementsArr = split$1(validElements, ',');
3201          let globalAttributes;
3202          let globalAttributesOrder;
3203          if (elements['@']) {
3204            globalAttributes = elements['@'].attributes;
3205            globalAttributesOrder = elements['@'].attributesOrder;
3206          }
3207          for (let ei = 0, el = validElementsArr.length; ei < el; ei++) {
3208            let matches = elementRuleRegExp.exec(validElementsArr[ei]);
3209            if (matches) {
3210              const prefix = matches[1];
3211              const elementName = matches[2];
3212              const outputName = matches[3];
3213              const attrData = matches[5];
3214              const attributes = {};
3215              const attributesOrder = [];
3216              const element = {
3217                attributes,
3218                attributesOrder
3219              };
3220              if (prefix === '#') {
3221                element.paddEmpty = true;
3222              }
3223              if (prefix === '-') {
3224                element.removeEmpty = true;
3225              }
3226              if (matches[4] === '!') {
3227                element.removeEmptyAttrs = true;
3228              }
3229              if (globalAttributes) {
3230                each$d(globalAttributes, (value, key) => {
3231                  attributes[key] = value;
3232                });
3233                if (globalAttributesOrder) {
3234                  attributesOrder.push(...globalAttributesOrder);
3235                }
3236              }
3237              if (attrData) {
3238                const attrDatas = split$1(attrData, '|');
3239                for (let ai = 0, al = attrDatas.length; ai < al; ai++) {
3240                  matches = attrRuleRegExp.exec(attrDatas[ai]);
3241                  if (matches) {
3242                    const attr = {};
3243                    const attrType = matches[1];
3244                    const attrName = matches[2].replace(/[\\:]:/g, ':');
3245                    const attrPrefix = matches[3];
3246                    const value = matches[4];
3247                    if (attrType === '!') {
3248                      element.attributesRequired = element.attributesRequired || [];
3249                      element.attributesRequired.push(attrName);
3250                      attr.required = true;
3251                    }
3252                    if (attrType === '-') {
3253                      delete attributes[attrName];
3254                      attributesOrder.splice(inArray(attributesOrder, attrName), 1);
3255                      continue;
3256                    }
3257                    if (attrPrefix) {
3258                      if (attrPrefix === '=') {
3259                        element.attributesDefault = element.attributesDefault || [];
3260                        element.attributesDefault.push({
3261                          name: attrName,
3262                          value
3263                        });
3264                        attr.defaultValue = value;
3265                      }
3266                      if (attrPrefix === '~') {
3267                        element.attributesForced = element.attributesForced || [];
3268                        element.attributesForced.push({
3269                          name: attrName,
3270                          value
3271                        });
3272                        attr.forcedValue = value;
3273                      }
3274                      if (attrPrefix === '<') {
3275                        attr.validValues = makeMap$2(value, '?');
3276                      }
3277                    }
3278                    if (hasPatternsRegExp.test(attrName)) {
3279                      const attrPattern = attr;
3280                      element.attributePatterns = element.attributePatterns || [];
3281                      attrPattern.pattern = patternToRegExp(attrName);
3282                      element.attributePatterns.push(attrPattern);
3283                    } else {
3284                      if (!attributes[attrName]) {
3285                        attributesOrder.push(attrName);
3286                      }
3287                      attributes[attrName] = attr;
3288                    }
3289                  }
3290                }
3291              }
3292              if (!globalAttributes && elementName === '@') {
3293                globalAttributes = attributes;
3294                globalAttributesOrder = attributesOrder;
3295              }
3296              if (outputName) {
3297                element.outputName = elementName;
3298                elements[outputName] = element;
3299              }
3300              if (hasPatternsRegExp.test(elementName)) {
3301                const patternElement = element;
3302                patternElement.pattern = patternToRegExp(elementName);
3303                patternElements.push(patternElement);
3304              } else {
3305                elements[elementName] = element;
3306              }
3307            }
3308          }
3309        }
3310      };
3311      const setValidElements = validElements => {
3312        patternElements = [];
3313        each$e(keys(elements), name => {
3314          delete elements[name];
3315        });
3316        addValidElements(validElements);
3317        each$b(schemaItems, (element, name) => {
3318          children[name] = element.children;
3319        });
3320      };
3321      const addCustomElements = customElements => {
3322        const customElementRegExp = /^(~)?(.+)$/;
3323        if (customElements) {
3324          delete mapCache.text_block_elements;
3325          delete mapCache.block_elements;
3326          each$b(split$1(customElements, ','), rule => {
3327            const matches = customElementRegExp.exec(rule);
3328            if (matches) {
3329              const inline = matches[1] === '~';
3330              const cloneName = inline ? 'span' : 'div';
3331              const name = matches[2];
3332              children[name] = children[cloneName];
3333              customElementsMap[name] = cloneName;
3334              nonEmptyElementsMap[name.toUpperCase()] = {};
3335              nonEmptyElementsMap[name] = {};
3336              if (!inline) {
3337                blockElementsMap[name.toUpperCase()] = {};
3338                blockElementsMap[name] = {};
3339              }
3340              if (!elements[name]) {
3341                let customRule = elements[cloneName];
3342                customRule = extend$2({}, customRule);
3343                delete customRule.removeEmptyAttrs;
3344                delete customRule.removeEmpty;
3345                elements[name] = customRule;
3346              }
3347              each$b(children, (element, elmName) => {
3348                if (element[cloneName]) {
3349                  children[elmName] = element = extend$2({}, children[elmName]);
3350                  element[name] = element[cloneName];
3351                }
3352              });
3353            }
3354          });
3355        }
3356      };
3357      const addValidChildren = validChildren => {
3358        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]+)\[([^\]]+)]$/;
3359        delete lookupCache[schemaType];
3360        if (validChildren) {
3361          each$b(split$1(validChildren, ','), rule => {
3362            const matches = childRuleRegExp.exec(rule);
3363            if (matches) {
3364              const prefix = matches[1];
3365              let parent;
3366              if (prefix) {
3367                parent = children[matches[2]];
3368              } else {
3369                parent = children[matches[2]] = { '#comment': {} };
3370              }
3371              parent = children[matches[2]];
3372              each$b(split$1(matches[3], '|'), child => {
3373                if (prefix === '-') {
3374                  delete parent[child];
3375                } else {
3376                  parent[child] = {};
3377                }
3378              });
3379            }
3380          });
3381        }
3382      };
3383      const getElementRule = name => {
3384        const element = elements[name];
3385        if (element) {
3386          return element;
3387        }
3388        let i = patternElements.length;
3389        while (i--) {
3390          const patternElement = patternElements[i];
3391          if (patternElement.pattern.test(name)) {
3392            return patternElement;
3393          }
3394        }
3395        return undefined;
3396      };
3397      if (!settings.valid_elements) {
3398        each$b(schemaItems, (element, name) => {
3399          elements[name] = {
3400            attributes: element.attributes,
3401            attributesOrder: element.attributesOrder
3402          };
3403          children[name] = element.children;
3404        });
3405        each$b(split$1('strong/b em/i'), item => {
3406          const items = split$1(item, '/');
3407          elements[items[1]].outputName = items[0];
3408        });
3409        each$b(textInlineElementsMap, (_val, name) => {
3410          if (elements[name]) {
3411            if (settings.padd_empty_block_inline_children) {
3412              elements[name].paddInEmptyBlock = true;
3413            }
3414            elements[name].removeEmpty = true;
3415          }
3416        });
3417        each$b(split$1('ol ul blockquote a table tbody'), name => {
3418          if (elements[name]) {
3419            elements[name].removeEmpty = true;
3420          }
3421        });
3422        each$b(split$1('p h1 h2 h3 h4 h5 h6 th td pre div address caption li summary'), name => {
3423          if (elements[name]) {
3424            elements[name].paddEmpty = true;
3425          }
3426        });
3427        each$b(split$1('span'), name => {
3428          elements[name].removeEmptyAttrs = true;
3429        });
3430      } else {
3431        setValidElements(settings.valid_elements);
3432      }
3433      addCustomElements(settings.custom_elements);
3434      addValidChildren(settings.valid_children);
3435      addValidElements(settings.extended_valid_elements);
3436      addValidChildren('+ol[ul|ol],+ul[ul|ol]');
3437      each$b({
3438        dd: 'dl',
3439        dt: 'dl',
3440        li: 'ul ol',
3441        td: 'tr',
3442        th: 'tr',
3443        tr: 'tbody thead tfoot',
3444        tbody: 'table',
3445        thead: 'table',
3446        tfoot: 'table',
3447        legend: 'fieldset',
3448        area: 'map',
3449        param: 'video audio object'
3450      }, (parents, item) => {
3451        if (elements[item]) {
3452          elements[item].parentsRequired = split$1(parents);
3453        }
3454      });
3455      if (settings.invalid_elements) {
3456        each$b(explode$2(settings.invalid_elements), item => {
3457          if (elements[item]) {
3458            delete elements[item];
3459          }
3460        });
3461      }
3462      if (!getElementRule('span')) {
3463        addValidElements('span[!data-mce-type|*]');
3464      }
3465      const getValidStyles = constant(validStyles);
3466      const getInvalidStyles = constant(invalidStyles);
3467      const getValidClasses = constant(validClasses);
3468      const getBoolAttrs = constant(boolAttrMap);
3469      const getBlockElements = constant(blockElementsMap);
3470      const getTextBlockElements = constant(textBlockElementsMap);
3471      const getTextInlineElements = constant(textInlineElementsMap);
3472      const getVoidElements = constant(Object.seal(voidElementsMap));
3473      const getSelfClosingElements = constant(selfClosingElementsMap);
3474      const getNonEmptyElements = constant(nonEmptyElementsMap);
3475      const getMoveCaretBeforeOnEnterElements = constant(moveCaretBeforeOnEnterElementsMap);
3476      const getWhitespaceElements = constant(whitespaceElementsMap);
3477      const getTransparentElements = constant(transparentElementsMap);
3478      const getSpecialElements = constant(Object.seal(specialElements));
3479      const isValidChild = (name, child) => {
3480        const parent = children[name.toLowerCase()];
3481        return !!(parent && parent[child.toLowerCase()]);
3482      };
3483      const isValid = (name, attr) => {
3484        const rule = getElementRule(name);
3485        if (rule) {
3486          if (attr) {
3487            if (rule.attributes[attr]) {
3488              return true;
3489            }
3490            const attrPatterns = rule.attributePatterns;
3491            if (attrPatterns) {
3492              let i = attrPatterns.length;
3493              while (i--) {
3494                if (attrPatterns[i].pattern.test(attr)) {
3495                  return true;
3496                }
3497              }
3498            }
3499          } else {
3500            return true;
3501          }
3502        }
3503        return false;
3504      };
3505      const getCustomElements = constant(customElementsMap);
3506      return {
3507        type: schemaType,
3508        children,
3509        elements,
3510        getValidStyles,
3511        getValidClasses,
3512        getBlockElements,
3513        getInvalidStyles,
3514        getVoidElements,
3515        getTextBlockElements,
3516        getTextInlineElements,
3517        getBoolAttrs,
3518        getElementRule,
3519        getSelfClosingElements,
3520        getNonEmptyElements,
3521        getMoveCaretBeforeOnEnterElements,
3522        getWhitespaceElements,
3523        getTransparentElements,
3524        getSpecialElements,
3525        isValidChild,
3526        isValid,
3527        getCustomElements,
3528        addValidElements,
3529        setValidElements,
3530        addCustomElements,
3531        addValidChildren
3532      };
3533    };
3534
3535    const Styles = (settings = {}, schema) => {
3536      const urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi;
3537      const styleRegExp = /\s*([^:]+):\s*([^;]+);?/g;
3538      const trimRightRegExp = /\s+$/;
3539      const encodingLookup = {};
3540      let validStyles;
3541      let invalidStyles;
3542      const invisibleChar = zeroWidth;
3543      if (schema) {
3544        validStyles = schema.getValidStyles();
3545        invalidStyles = schema.getInvalidStyles();
3546      }
3547      const encodingItems = (`\\" \\' \\; \\: ; : ` + invisibleChar).split(' ');
3548      for (let i = 0; i < encodingItems.length; i++) {
3549        encodingLookup[encodingItems[i]] = invisibleChar + i;
3550        encodingLookup[invisibleChar + i] = encodingItems[i];
3551      }
3552      const self = {
3553        parse: css => {
3554          const styles = {};
3555          let isEncoded = false;
3556          const urlConverter = settings.url_converter;
3557          const urlConverterScope = settings.url_converter_scope || self;
3558          const compress = (prefix, suffix, noJoin) => {
3559            const top = styles[prefix + '-top' + suffix];
3560            if (!top) {
3561              return;
3562            }
3563            const right = styles[prefix + '-right' + suffix];
3564            if (!right) {
3565              return;
3566            }
3567            const bottom = styles[prefix + '-bottom' + suffix];
3568            if (!bottom) {
3569              return;
3570            }
3571            const left = styles[prefix + '-left' + suffix];
3572            if (!left) {
3573              return;
3574            }
3575            const box = [
3576              top,
3577              right,
3578              bottom,
3579              left
3580            ];
3581            let i = box.length - 1;
3582            while (i--) {
3583              if (box[i] !== box[i + 1]) {
3584                break;
3585              }
3586            }
3587            if (i > -1 && noJoin) {
3588              return;
3589            }
3590            styles[prefix + suffix] = i === -1 ? box[0] : box.join(' ');
3591            delete styles[prefix + '-top' + suffix];
3592            delete styles[prefix + '-right' + suffix];
3593            delete styles[prefix + '-bottom' + suffix];
3594            delete styles[prefix + '-left' + suffix];
3595          };
3596          const canCompress = key => {
3597            const value = styles[key];
3598            if (!value) {
3599              return;
3600            }
3601            const values = value.split(' ');
3602            let i = values.length;
3603            while (i--) {
3604              if (values[i] !== values[0]) {
3605                return false;
3606              }
3607            }
3608            styles[key] = values[0];
3609            return true;
3610          };
3611          const compress2 = (target, a, b, c) => {
3612            if (!canCompress(a)) {
3613              return;
3614            }
3615            if (!canCompress(b)) {
3616              return;
3617            }
3618            if (!canCompress(c)) {
3619              return;
3620            }
3621            styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
3622            delete styles[a];
3623            delete styles[b];
3624            delete styles[c];
3625          };
3626          const encode = str => {
3627            isEncoded = true;
3628            return encodingLookup[str];
3629          };
3630          const decode = (str, keepSlashes) => {
3631            if (isEncoded) {
3632              str = str.replace(/\uFEFF[0-9]/g, str => {
3633                return encodingLookup[str];
3634              });
3635            }
3636            if (!keepSlashes) {
3637              str = str.replace(/\\([\'\";:])/g, '$1');
3638            }
3639            return str;
3640          };
3641          const decodeSingleHexSequence = escSeq => {
3642            return String.fromCharCode(parseInt(escSeq.slice(1), 16));
3643          };
3644          const decodeHexSequences = value => {
3645            return value.replace(/\\[0-9a-f]+/gi, decodeSingleHexSequence);
3646          };
3647          const processUrl = (match, url, url2, url3, str, str2) => {
3648            str = str || str2;
3649            if (str) {
3650              str = decode(str);
3651              return `'` + str.replace(/\'/g, `\\'`) + `'`;
3652            }
3653            url = decode(url || url2 || url3 || '');
3654            if (!settings.allow_script_urls) {
3655              const scriptUrl = url.replace(/[\s\r\n]+/g, '');
3656              if (/(java|vb)script:/i.test(scriptUrl)) {
3657                return '';
3658              }
3659              if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
3660                return '';
3661              }
3662            }
3663            if (urlConverter) {
3664              url = urlConverter.call(urlConverterScope, url, 'style');
3665            }
3666            return `url('` + url.replace(/\'/g, `\\'`) + `')`;
3667          };
3668          if (css) {
3669            css = css.replace(/[\u0000-\u001F]/g, '');
3670            css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, str => {
3671              return str.replace(/[;:]/g, encode);
3672            });
3673            let matches;
3674            while (matches = styleRegExp.exec(css)) {
3675              styleRegExp.lastIndex = matches.index + matches[0].length;
3676              let name = matches[1].replace(trimRightRegExp, '').toLowerCase();
3677              let value = matches[2].replace(trimRightRegExp, '');
3678              if (name && value) {
3679                name = decodeHexSequences(name);
3680                value = decodeHexSequences(value);
3681                if (name.indexOf(invisibleChar) !== -1 || name.indexOf('"') !== -1) {
3682                  continue;
3683                }
3684                if (!settings.allow_script_urls && (name === 'behavior' || /expression\s*\(|\/\*|\*\//.test(value))) {
3685                  continue;
3686                }
3687                if (name === 'font-weight' && value === '700') {
3688                  value = 'bold';
3689                } else if (name === 'color' || name === 'background-color') {
3690                  value = value.toLowerCase();
3691                }
3692                value = value.replace(urlOrStrRegExp, processUrl);
3693                styles[name] = isEncoded ? decode(value, true) : value;
3694              }
3695            }
3696            compress('border', '', true);
3697            compress('border', '-width');
3698            compress('border', '-color');
3699            compress('border', '-style');
3700            compress('padding', '');
3701            compress('margin', '');
3702            compress2('border', 'border-width', 'border-style', 'border-color');
3703            if (styles.border === 'medium none') {
3704              delete styles.border;
3705            }
3706            if (styles['border-image'] === 'none') {
3707              delete styles['border-image'];
3708            }
3709          }
3710          return styles;
3711        },
3712        serialize: (styles, elementName) => {
3713          let css = '';
3714          const serializeStyles = (elemName, validStyleList) => {
3715            const styleList = validStyleList[elemName];
3716            if (styleList) {
3717              for (let i = 0, l = styleList.length; i < l; i++) {
3718                const name = styleList[i];
3719                const value = styles[name];
3720                if (value) {
3721                  css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
3722                }
3723              }
3724            }
3725          };
3726          const isValid = (name, elemName) => {
3727            if (!invalidStyles || !elemName) {
3728              return true;
3729            }
3730            let styleMap = invalidStyles['*'];
3731            if (styleMap && styleMap[name]) {
3732              return false;
3733            }
3734            styleMap = invalidStyles[elemName];
3735            return !(styleMap && styleMap[name]);
3736          };
3737          if (elementName && validStyles) {
3738            serializeStyles('*', validStyles);
3739            serializeStyles(elementName, validStyles);
3740          } else {
3741            each$d(styles, (value, name) => {
3742              if (value && isValid(name, elementName)) {
3743                css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
3744              }
3745            });
3746          }
3747          return css;
3748        }
3749      };
3750      return self;
3751    };
3752
3753    const deprecated = {
3754      keyLocation: true,
3755      layerX: true,
3756      layerY: true,
3757      returnValue: true,
3758      webkitMovementX: true,
3759      webkitMovementY: true,
3760      keyIdentifier: true,
3761      mozPressure: true
3762    };
3763    const isNativeEvent = event => event instanceof Event || isFunction(event.initEvent);
3764    const hasIsDefaultPrevented = event => event.isDefaultPrevented === always || event.isDefaultPrevented === never;
3765    const needsNormalizing = event => isNullable(event.preventDefault) || isNativeEvent(event);
3766    const clone$3 = (originalEvent, data) => {
3767      const event = data !== null && data !== void 0 ? data : {};
3768      for (const name in originalEvent) {
3769        if (!has$2(deprecated, name)) {
3770          event[name] = originalEvent[name];
3771        }
3772      }
3773      if (isNonNullable(originalEvent.composedPath)) {
3774        event.composedPath = () => originalEvent.composedPath();
3775      }
3776      return event;
3777    };
3778    const normalize$3 = (type, originalEvent, fallbackTarget, data) => {
3779      var _a;
3780      const event = clone$3(originalEvent, data);
3781      event.type = type;
3782      if (isNullable(event.target)) {
3783        event.target = (_a = event.srcElement) !== null && _a !== void 0 ? _a : fallbackTarget;
3784      }
3785      if (needsNormalizing(originalEvent)) {
3786        event.preventDefault = () => {
3787          event.defaultPrevented = true;
3788          event.isDefaultPrevented = always;
3789          if (isFunction(originalEvent.preventDefault)) {
3790            originalEvent.preventDefault();
3791          }
3792        };
3793        event.stopPropagation = () => {
3794          event.cancelBubble = true;
3795          event.isPropagationStopped = always;
3796          if (isFunction(originalEvent.stopPropagation)) {
3797            originalEvent.stopPropagation();
3798          }
3799        };
3800        event.stopImmediatePropagation = () => {
3801          event.isImmediatePropagationStopped = always;
3802          event.stopPropagation();
3803        };
3804        if (!hasIsDefaultPrevented(event)) {
3805          event.isDefaultPrevented = event.defaultPrevented === true ? always : never;
3806          event.isPropagationStopped = event.cancelBubble === true ? always : never;
3807          event.isImmediatePropagationStopped = never;
3808        }
3809      }
3810      return event;
3811    };
3812
3813    const eventExpandoPrefix = 'mce-data-';
3814    const mouseEventRe = /^(?:mouse|contextmenu)|click/;
3815    const addEvent = (target, name, callback, capture) => {
3816      target.addEventListener(name, callback, capture || false);
3817    };
3818    const removeEvent = (target, name, callback, capture) => {
3819      target.removeEventListener(name, callback, capture || false);
3820    };
3821    const isMouseEvent = event => isNonNullable(event) && mouseEventRe.test(event.type);
3822    const fix = (originalEvent, data) => {
3823      const event = normalize$3(originalEvent.type, originalEvent, document, data);
3824      if (isMouseEvent(originalEvent) && isUndefined(originalEvent.pageX) && !isUndefined(originalEvent.clientX)) {
3825        const eventDoc = event.target.ownerDocument || document;
3826        const doc = eventDoc.documentElement;
3827        const body = eventDoc.body;
3828        const mouseEvent = event;
3829        mouseEvent.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
3830        mouseEvent.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
3831      }
3832      return event;
3833    };
3834    const bindOnReady = (win, callback, eventUtils) => {
3835      const doc = win.document, event = { type: 'ready' };
3836      if (eventUtils.domLoaded) {
3837        callback(event);
3838        return;
3839      }
3840      const isDocReady = () => {
3841        return doc.readyState === 'complete' || doc.readyState === 'interactive' && doc.body;
3842      };
3843      const readyHandler = () => {
3844        removeEvent(win, 'DOMContentLoaded', readyHandler);
3845        removeEvent(win, 'load', readyHandler);
3846        if (!eventUtils.domLoaded) {
3847          eventUtils.domLoaded = true;
3848          callback(event);
3849        }
3850        win = null;
3851      };
3852      if (isDocReady()) {
3853        readyHandler();
3854      } else {
3855        addEvent(win, 'DOMContentLoaded', readyHandler);
3856      }
3857      if (!eventUtils.domLoaded) {
3858        addEvent(win, 'load', readyHandler);
3859      }
3860    };
3861    class EventUtils {
3862      constructor() {
3863        this.domLoaded = false;
3864        this.events = {};
3865        this.count = 1;
3866        this.expando = eventExpandoPrefix + (+new Date()).toString(32);
3867        this.hasFocusIn = 'onfocusin' in document.documentElement;
3868        this.count = 1;
3869      }
3870      bind(target, names, callback, scope) {
3871        const self = this;
3872        let callbackList;
3873        const win = window;
3874        const defaultNativeHandler = evt => {
3875          self.executeHandlers(fix(evt || win.event), id);
3876        };
3877        if (!target || isText$a(target) || isComment(target)) {
3878          return callback;
3879        }
3880        let id;
3881        if (!target[self.expando]) {
3882          id = self.count++;
3883          target[self.expando] = id;
3884          self.events[id] = {};
3885        } else {
3886          id = target[self.expando];
3887        }
3888        scope = scope || target;
3889        const namesList = names.split(' ');
3890        let i = namesList.length;
3891        while (i--) {
3892          let name = namesList[i];
3893          let nativeHandler = defaultNativeHandler;
3894          let capture = false;
3895          let fakeName = false;
3896          if (name === 'DOMContentLoaded') {
3897            name = 'ready';
3898          }
3899          if (self.domLoaded && name === 'ready' && target.readyState === 'complete') {
3900            callback.call(scope, fix({ type: name }));
3901            continue;
3902          }
3903          if (!self.hasFocusIn && (name === 'focusin' || name === 'focusout')) {
3904            capture = true;
3905            fakeName = name === 'focusin' ? 'focus' : 'blur';
3906            nativeHandler = evt => {
3907              const event = fix(evt || win.event);
3908              event.type = event.type === 'focus' ? 'focusin' : 'focusout';
3909              self.executeHandlers(event, id);
3910            };
3911          }
3912          callbackList = self.events[id][name];
3913          if (!callbackList) {
3914            self.events[id][name] = callbackList = [{
3915                func: callback,
3916                scope
3917              }];
3918            callbackList.fakeName = fakeName;
3919            callbackList.capture = capture;
3920            callbackList.nativeHandler = nativeHandler;
3921            if (name === 'ready') {
3922              bindOnReady(target, nativeHandler, self);
3923            } else {
3924              addEvent(target, fakeName || name, nativeHandler, capture);
3925            }
3926          } else {
3927            if (name === 'ready' && self.domLoaded) {
3928              callback(fix({ type: name }));
3929            } else {
3930              callbackList.push({
3931                func: callback,
3932                scope
3933              });
3934            }
3935          }
3936        }
3937        target = callbackList = null;
3938        return callback;
3939      }
3940      unbind(target, names, callback) {
3941        if (!target || isText$a(target) || isComment(target)) {
3942          return this;
3943        }
3944        const id = target[this.expando];
3945        if (id) {
3946          let eventMap = this.events[id];
3947          if (names) {
3948            const namesList = names.split(' ');
3949            let i = namesList.length;
3950            while (i--) {
3951              const name = namesList[i];
3952              const callbackList = eventMap[name];
3953              if (callbackList) {
3954                if (callback) {
3955                  let ci = callbackList.length;
3956                  while (ci--) {
3957                    if (callbackList[ci].func === callback) {
3958                      const nativeHandler = callbackList.nativeHandler;
3959                      const fakeName = callbackList.fakeName, capture = callbackList.capture;
3960                      const newCallbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
3961                      newCallbackList.nativeHandler = nativeHandler;
3962                      newCallbackList.fakeName = fakeName;
3963                      newCallbackList.capture = capture;
3964                      eventMap[name] = newCallbackList;
3965                    }
3966                  }
3967                }
3968                if (!callback || callbackList.length === 0) {
3969                  delete eventMap[name];
3970                  removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
3971                }
3972              }
3973            }
3974          } else {
3975            each$d(eventMap, (callbackList, name) => {
3976              removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
3977            });
3978            eventMap = {};
3979          }
3980          for (const name in eventMap) {
3981            if (has$2(eventMap, name)) {
3982              return this;
3983            }
3984          }
3985          delete this.events[id];
3986          try {
3987            delete target[this.expando];
3988          } catch (ex) {
3989            target[this.expando] = null;
3990          }
3991        }
3992        return this;
3993      }
3994      fire(target, name, args) {
3995        return this.dispatch(target, name, args);
3996      }
3997      dispatch(target, name, args) {
3998        if (!target || isText$a(target) || isComment(target)) {
3999          return this;
4000        }
4001        const event = fix({
4002          type: name,
4003          target
4004        }, args);
4005        do {
4006          const id = target[this.expando];
4007          if (id) {
4008            this.executeHandlers(event, id);
4009          }
4010          target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow;
4011        } while (target && !event.isPropagationStopped());
4012        return this;
4013      }
4014      clean(target) {
4015        if (!target || isText$a(target) || isComment(target)) {
4016          return this;
4017        }
4018        if (target[this.expando]) {
4019          this.unbind(target);
4020        }
4021        if (!target.getElementsByTagName) {
4022          target = target.document;
4023        }
4024        if (target && target.getElementsByTagName) {
4025          this.unbind(target);
4026          const children = target.getElementsByTagName('*');
4027          let i = children.length;
4028          while (i--) {
4029            target = children[i];
4030            if (target[this.expando]) {
4031              this.unbind(target);
4032            }
4033          }
4034        }
4035        return this;
4036      }
4037      destroy() {
4038        this.events = {};
4039      }
4040      cancel(e) {
4041        if (e) {
4042          e.preventDefault();
4043          e.stopImmediatePropagation();
4044        }
4045        return false;
4046      }
4047      executeHandlers(evt, id) {
4048        const container = this.events[id];
4049        const callbackList = container && container[evt.type];
4050        if (callbackList) {
4051          for (let i = 0, l = callbackList.length; i < l; i++) {
4052            const callback = callbackList[i];
4053            if (callback && callback.func.call(callback.scope, evt) === false) {
4054              evt.preventDefault();
4055            }
4056            if (evt.isImmediatePropagationStopped()) {
4057              return;
4058            }
4059          }
4060        }
4061      }
4062    }
4063    EventUtils.Event = new EventUtils();
4064
4065    const each$a = Tools.each;
4066    const grep = Tools.grep;
4067    const internalStyleName = 'data-mce-style';
4068    const numericalCssMap = Tools.makeMap('fill-opacity font-weight line-height opacity orphans widows z-index zoom', ' ');
4069    const legacySetAttribute = (elm, name, value) => {
4070      if (isNullable(value) || value === '') {
4071        remove$a(elm, name);
4072      } else {
4073        set$3(elm, name, value);
4074      }
4075    };
4076    const camelCaseToHyphens = name => name.replace(/[A-Z]/g, v => '-' + v.toLowerCase());
4077    const findNodeIndex = (node, normalized) => {
4078      let idx = 0;
4079      if (node) {
4080        for (let lastNodeType = node.nodeType, tempNode = node.previousSibling; tempNode; tempNode = tempNode.previousSibling) {
4081          const nodeType = tempNode.nodeType;
4082          if (normalized && isText$a(tempNode)) {
4083            if (nodeType === lastNodeType || !tempNode.data.length) {
4084              continue;
4085            }
4086          }
4087          idx++;
4088          lastNodeType = nodeType;
4089        }
4090      }
4091      return idx;
4092    };
4093    const updateInternalStyleAttr = (styles, elm) => {
4094      const rawValue = get$9(elm, 'style');
4095      const value = styles.serialize(styles.parse(rawValue), name(elm));
4096      legacySetAttribute(elm, internalStyleName, value);
4097    };
4098    const convertStyleToString = (cssValue, cssName) => {
4099      if (isNumber(cssValue)) {
4100        return has$2(numericalCssMap, cssName) ? cssValue + '' : cssValue + 'px';
4101      } else {
4102        return cssValue;
4103      }
4104    };
4105    const applyStyle$1 = ($elm, cssName, cssValue) => {
4106      const normalizedName = camelCaseToHyphens(cssName);
4107      if (isNullable(cssValue) || cssValue === '') {
4108        remove$6($elm, normalizedName);
4109      } else {
4110        set$2($elm, normalizedName, convertStyleToString(cssValue, normalizedName));
4111      }
4112    };
4113    const setupAttrHooks = (styles, settings, getContext) => {
4114      const keepValues = settings.keep_values;
4115      const keepUrlHook = {
4116        set: (elm, value, name) => {
4117          const sugarElm = SugarElement.fromDom(elm);
4118          if (isFunction(settings.url_converter) && isNonNullable(value)) {
4119            value = settings.url_converter.call(settings.url_converter_scope || getContext(), String(value), name, elm);
4120          }
4121          const internalName = 'data-mce-' + name;
4122          legacySetAttribute(sugarElm, internalName, value);
4123          legacySetAttribute(sugarElm, name, value);
4124        },
4125        get: (elm, name) => {
4126          const sugarElm = SugarElement.fromDom(elm);
4127          return get$9(sugarElm, 'data-mce-' + name) || get$9(sugarElm, name);
4128        }
4129      };
4130      const attrHooks = {
4131        style: {
4132          set: (elm, value) => {
4133            const sugarElm = SugarElement.fromDom(elm);
4134            if (keepValues) {
4135              legacySetAttribute(sugarElm, internalStyleName, value);
4136            }
4137            remove$a(sugarElm, 'style');
4138            if (isString(value)) {
4139              setAll(sugarElm, styles.parse(value));
4140            }
4141          },
4142          get: elm => {
4143            const sugarElm = SugarElement.fromDom(elm);
4144            const value = get$9(sugarElm, internalStyleName) || get$9(sugarElm, 'style');
4145            return styles.serialize(styles.parse(value), name(sugarElm));
4146          }
4147        }
4148      };
4149      if (keepValues) {
4150        attrHooks.href = attrHooks.src = keepUrlHook;
4151      }
4152      return attrHooks;
4153    };
4154    const DOMUtils = (doc, settings = {}) => {
4155      const addedStyles = {};
4156      const win = window;
4157      const files = {};
4158      let counter = 0;
4159      const stdMode = true;
4160      const boxModel = true;
4161      const styleSheetLoader = instance.forElement(SugarElement.fromDom(doc), {
4162        contentCssCors: settings.contentCssCors,
4163        referrerPolicy: settings.referrerPolicy
4164      });
4165      const boundEvents = [];
4166      const schema = settings.schema ? settings.schema : Schema({});
4167      const styles = Styles({
4168        url_converter: settings.url_converter,
4169        url_converter_scope: settings.url_converter_scope
4170      }, settings.schema);
4171      const events = settings.ownEvents ? new EventUtils() : EventUtils.Event;
4172      const blockElementsMap = schema.getBlockElements();
4173      const isBlock = node => {
4174        if (isString(node)) {
4175          return has$2(blockElementsMap, node);
4176        } else {
4177          return isElement$6(node) && (has$2(blockElementsMap, node.nodeName) || isTransparentBlock(schema, node));
4178        }
4179      };
4180      const get = elm => elm && doc && isString(elm) ? doc.getElementById(elm) : elm;
4181      const _get = elm => {
4182        const value = get(elm);
4183        return isNonNullable(value) ? SugarElement.fromDom(value) : null;
4184      };
4185      const getAttrib = (elm, name, defaultVal = '') => {
4186        let value;
4187        const $elm = _get(elm);
4188        if (isNonNullable($elm) && isElement$7($elm)) {
4189          const hook = attrHooks[name];
4190          if (hook && hook.get) {
4191            value = hook.get($elm.dom, name);
4192          } else {
4193            value = get$9($elm, name);
4194          }
4195        }
4196        return isNonNullable(value) ? value : defaultVal;
4197      };
4198      const getAttribs = elm => {
4199        const node = get(elm);
4200        return isNullable(node) ? [] : node.attributes;
4201      };
4202      const setAttrib = (elm, name, value) => {
4203        run(elm, e => {
4204          if (isElement$6(e)) {
4205            const $elm = SugarElement.fromDom(e);
4206            const val = value === '' ? null : value;
4207            const originalValue = get$9($elm, name);
4208            const hook = attrHooks[name];
4209            if (hook && hook.set) {
4210              hook.set($elm.dom, val, name);
4211            } else {
4212              legacySetAttribute($elm, name, val);
4213            }
4214            if (originalValue !== val && settings.onSetAttrib) {
4215              settings.onSetAttrib({
4216                attrElm: $elm.dom,
4217                attrName: name,
4218                attrValue: val
4219              });
4220            }
4221          }
4222        });
4223      };
4224      const clone = (node, deep) => {
4225        return node.cloneNode(deep);
4226      };
4227      const getRoot = () => settings.root_element || doc.body;
4228      const getViewPort = argWin => {
4229        const vp = getBounds(argWin);
4230        return {
4231          x: vp.x,
4232          y: vp.y,
4233          w: vp.width,
4234          h: vp.height
4235        };
4236      };
4237      const getPos$1 = (elm, rootElm) => getPos(doc.body, get(elm), rootElm);
4238      const setStyle = (elm, name, value) => {
4239        run(elm, e => {
4240          const $elm = SugarElement.fromDom(e);
4241          applyStyle$1($elm, name, value);
4242          if (settings.update_styles) {
4243            updateInternalStyleAttr(styles, $elm);
4244          }
4245        });
4246      };
4247      const setStyles = (elm, stylesArg) => {
4248        run(elm, e => {
4249          const $elm = SugarElement.fromDom(e);
4250          each$d(stylesArg, (v, n) => {
4251            applyStyle$1($elm, n, v);
4252          });
4253          if (settings.update_styles) {
4254            updateInternalStyleAttr(styles, $elm);
4255          }
4256        });
4257      };
4258      const getStyle = (elm, name, computed) => {
4259        const $elm = get(elm);
4260        if (isNullable($elm) || !isElement$6($elm)) {
4261          return undefined;
4262        }
4263        if (computed) {
4264          return get$7(SugarElement.fromDom($elm), camelCaseToHyphens(name));
4265        } else {
4266          name = name.replace(/-(\D)/g, (a, b) => b.toUpperCase());
4267          if (name === 'float') {
4268            name = 'cssFloat';
4269          }
4270          return $elm.style ? $elm.style[name] : undefined;
4271        }
4272      };
4273      const getSize = elm => {
4274        const $elm = get(elm);
4275        if (!$elm) {
4276          return {
4277            w: 0,
4278            h: 0
4279          };
4280        }
4281        let w = getStyle($elm, 'width');
4282        let h = getStyle($elm, 'height');
4283        if (!w || w.indexOf('px') === -1) {
4284          w = '0';
4285        }
4286        if (!h || h.indexOf('px') === -1) {
4287          h = '0';
4288        }
4289        return {
4290          w: parseInt(w, 10) || $elm.offsetWidth || $elm.clientWidth,
4291          h: parseInt(h, 10) || $elm.offsetHeight || $elm.clientHeight
4292        };
4293      };
4294      const getRect = elm => {
4295        const $elm = get(elm);
4296        const pos = getPos$1($elm);
4297        const size = getSize($elm);
4298        return {
4299          x: pos.x,
4300          y: pos.y,
4301          w: size.w,
4302          h: size.h
4303        };
4304      };
4305      const is = (elm, selector) => {
4306        if (!elm) {
4307          return false;
4308        }
4309        const elms = isArray$1(elm) ? elm : [elm];
4310        return exists(elms, e => {
4311          return is$1(SugarElement.fromDom(e), selector);
4312        });
4313      };
4314      const getParents = (elm, selector, root, collect) => {
4315        const result = [];
4316        let node = get(elm);
4317        collect = collect === undefined;
4318        const resolvedRoot = root || (getRoot().nodeName !== 'BODY' ? getRoot().parentNode : null);
4319        if (isString(selector)) {
4320          if (selector === '*') {
4321            selector = isElement$6;
4322          } else {
4323            const selectorVal = selector;
4324            selector = node => is(node, selectorVal);
4325          }
4326        }
4327        while (node) {
4328          if (node === resolvedRoot || isNullable(node.nodeType) || isDocument$1(node) || isDocumentFragment(node)) {
4329            break;
4330          }
4331          if (!selector || selector(node)) {
4332            if (collect) {
4333              result.push(node);
4334            } else {
4335              return [node];
4336            }
4337          }
4338          node = node.parentNode;
4339        }
4340        return collect ? result : null;
4341      };
4342      const getParent = (node, selector, root) => {
4343        const parents = getParents(node, selector, root, false);
4344        return parents && parents.length > 0 ? parents[0] : null;
4345      };
4346      const _findSib = (node, selector, name) => {
4347        let func = selector;
4348        if (node) {
4349          if (isString(selector)) {
4350            func = node => {
4351              return is(node, selector);
4352            };
4353          }
4354          for (let tempNode = node[name]; tempNode; tempNode = tempNode[name]) {
4355            if (isFunction(func) && func(tempNode)) {
4356              return tempNode;
4357            }
4358          }
4359        }
4360        return null;
4361      };
4362      const getNext = (node, selector) => _findSib(node, selector, 'nextSibling');
4363      const getPrev = (node, selector) => _findSib(node, selector, 'previousSibling');
4364      const isParentNode = node => isFunction(node.querySelectorAll);
4365      const select = (selector, scope) => {
4366        var _a, _b;
4367        const elm = (_b = (_a = get(scope)) !== null && _a !== void 0 ? _a : settings.root_element) !== null && _b !== void 0 ? _b : doc;
4368        return isParentNode(elm) ? from(elm.querySelectorAll(selector)) : [];
4369      };
4370      const run = function (elm, func, scope) {
4371        const context = scope !== null && scope !== void 0 ? scope : this;
4372        if (isArray$1(elm)) {
4373          const result = [];
4374          each$a(elm, (e, i) => {
4375            const node = get(e);
4376            if (node) {
4377              result.push(func.call(context, node, i));
4378            }
4379          });
4380          return result;
4381        } else {
4382          const node = get(elm);
4383          return !node ? false : func.call(context, node);
4384        }
4385      };
4386      const setAttribs = (elm, attrs) => {
4387        run(elm, $elm => {
4388          each$d(attrs, (value, name) => {
4389            setAttrib($elm, name, value);
4390          });
4391        });
4392      };
4393      const setHTML = (elm, html) => {
4394        run(elm, e => {
4395          const $elm = SugarElement.fromDom(e);
4396          set$1($elm, html);
4397        });
4398      };
4399      const add = (parentElm, name, attrs, html, create) => run(parentElm, parentElm => {
4400        const newElm = isString(name) ? doc.createElement(name) : name;
4401        if (isNonNullable(attrs)) {
4402          setAttribs(newElm, attrs);
4403        }
4404        if (html) {
4405          if (!isString(html) && html.nodeType) {
4406            newElm.appendChild(html);
4407          } else if (isString(html)) {
4408            setHTML(newElm, html);
4409          }
4410        }
4411        return !create ? parentElm.appendChild(newElm) : newElm;
4412      });
4413      const create = (name, attrs, html) => add(doc.createElement(name), name, attrs, html, true);
4414      const decode = Entities.decode;
4415      const encode = Entities.encodeAllRaw;
4416      const createHTML = (name, attrs, html = '') => {
4417        let outHtml = '<' + name;
4418        for (const key in attrs) {
4419          if (hasNonNullableKey(attrs, key)) {
4420            outHtml += ' ' + key + '="' + encode(attrs[key]) + '"';
4421          }
4422        }
4423        if (isEmpty$3(html) && has$2(schema.getVoidElements(), name)) {
4424          return outHtml + ' />';
4425        } else {
4426          return outHtml + '>' + html + '</' + name + '>';
4427        }
4428      };
4429      const createFragment = html => {
4430        const container = doc.createElement('div');
4431        const frag = doc.createDocumentFragment();
4432        frag.appendChild(container);
4433        if (html) {
4434          container.innerHTML = html;
4435        }
4436        let node;
4437        while (node = container.firstChild) {
4438          frag.appendChild(node);
4439        }
4440        frag.removeChild(container);
4441        return frag;
4442      };
4443      const remove = (node, keepChildren) => {
4444        return run(node, n => {
4445          const $node = SugarElement.fromDom(n);
4446          if (keepChildren) {
4447            each$e(children$1($node), child => {
4448              if (isText$b(child) && child.dom.length === 0) {
4449                remove$5(child);
4450              } else {
4451                before$3($node, child);
4452              }
4453            });
4454          }
4455          remove$5($node);
4456          return $node.dom;
4457        });
4458      };
4459      const removeAllAttribs = e => run(e, e => {
4460        const attrs = e.attributes;
4461        for (let i = attrs.length - 1; i >= 0; i--) {
4462          e.removeAttributeNode(attrs.item(i));
4463        }
4464      });
4465      const parseStyle = cssText => styles.parse(cssText);
4466      const serializeStyle = (stylesArg, name) => styles.serialize(stylesArg, name);
4467      const addStyle = cssText => {
4468        if (self !== DOMUtils.DOM && doc === document) {
4469          if (addedStyles[cssText]) {
4470            return;
4471          }
4472          addedStyles[cssText] = true;
4473        }
4474        let styleElm = doc.getElementById('mceDefaultStyles');
4475        if (!styleElm) {
4476          styleElm = doc.createElement('style');
4477          styleElm.id = 'mceDefaultStyles';
4478          styleElm.type = 'text/css';
4479          const head = doc.head;
4480          if (head.firstChild) {
4481            head.insertBefore(styleElm, head.firstChild);
4482          } else {
4483            head.appendChild(styleElm);
4484          }
4485        }
4486        if (styleElm.styleSheet) {
4487          styleElm.styleSheet.cssText += cssText;
4488        } else {
4489          styleElm.appendChild(doc.createTextNode(cssText));
4490        }
4491      };
4492      const loadCSS = urls => {
4493        if (!urls) {
4494          urls = '';
4495        }
4496        each$e(urls.split(','), url => {
4497          files[url] = true;
4498          styleSheetLoader.load(url).catch(noop);
4499        });
4500      };
4501      const toggleClass = (elm, cls, state) => {
4502        run(elm, e => {
4503          if (isElement$6(e)) {
4504            const $elm = SugarElement.fromDom(e);
4505            const classes = cls.split(' ');
4506            each$e(classes, c => {
4507              if (isNonNullable(state)) {
4508                const fn = state ? add$2 : remove$7;
4509                fn($elm, c);
4510              } else {
4511                toggle$1($elm, c);
4512              }
4513            });
4514          }
4515        });
4516      };
4517      const addClass = (elm, cls) => {
4518        toggleClass(elm, cls, true);
4519      };
4520      const removeClass = (elm, cls) => {
4521        toggleClass(elm, cls, false);
4522      };
4523      const hasClass = (elm, cls) => {
4524        const $elm = _get(elm);
4525        const classes = cls.split(' ');
4526        return isNonNullable($elm) && forall(classes, c => has($elm, c));
4527      };
4528      const show = elm => {
4529        run(elm, e => remove$6(SugarElement.fromDom(e), 'display'));
4530      };
4531      const hide = elm => {
4532        run(elm, e => set$2(SugarElement.fromDom(e), 'display', 'none'));
4533      };
4534      const isHidden = elm => {
4535        const $elm = _get(elm);
4536        return isNonNullable($elm) && is$2(getRaw($elm, 'display'), 'none');
4537      };
4538      const uniqueId = prefix => (!prefix ? 'mce_' : prefix) + counter++;
4539      const getOuterHTML = elm => {
4540        const $elm = _get(elm);
4541        if (isNonNullable($elm)) {
4542          return isElement$6($elm.dom) ? $elm.dom.outerHTML : getOuter($elm);
4543        } else {
4544          return '';
4545        }
4546      };
4547      const setOuterHTML = (elm, html) => {
4548        run(elm, $elm => {
4549          if (isElement$6($elm)) {
4550            $elm.outerHTML = html;
4551          }
4552        });
4553      };
4554      const insertAfter = (node, reference) => {
4555        const referenceNode = get(reference);
4556        return run(node, node => {
4557          const parent = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.parentNode;
4558          const nextSibling = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.nextSibling;
4559          if (parent) {
4560            if (nextSibling) {
4561              parent.insertBefore(node, nextSibling);
4562            } else {
4563              parent.appendChild(node);
4564            }
4565          }
4566          return node;
4567        });
4568      };
4569      const replace = (newElm, oldElm, keepChildren) => run(oldElm, elm => {
4570        var _a;
4571        const replacee = isArray$1(oldElm) ? newElm.cloneNode(true) : newElm;
4572        if (keepChildren) {
4573          each$a(grep(elm.childNodes), node => {
4574            replacee.appendChild(node);
4575          });
4576        }
4577        (_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(replacee, elm);
4578        return elm;
4579      });
4580      const rename = (elm, name) => {
4581        if (elm.nodeName !== name.toUpperCase()) {
4582          const newElm = create(name);
4583          each$a(getAttribs(elm), attrNode => {
4584            setAttrib(newElm, attrNode.nodeName, getAttrib(elm, attrNode.nodeName));
4585          });
4586          replace(newElm, elm, true);
4587          return newElm;
4588        } else {
4589          return elm;
4590        }
4591      };
4592      const findCommonAncestor = (a, b) => {
4593        let ps = a;
4594        while (ps) {
4595          let pe = b;
4596          while (pe && ps !== pe) {
4597            pe = pe.parentNode;
4598          }
4599          if (ps === pe) {
4600            break;
4601          }
4602          ps = ps.parentNode;
4603        }
4604        if (!ps && a.ownerDocument) {
4605          return a.ownerDocument.documentElement;
4606        } else {
4607          return ps;
4608        }
4609      };
4610      const isNonEmptyElement = node => {
4611        if (isElement$6(node)) {
4612          const isNamedAnchor = node.nodeName.toLowerCase() === 'a' && !getAttrib(node, 'href') && getAttrib(node, 'id');
4613          if (getAttrib(node, 'name') || getAttrib(node, 'data-mce-bookmark') || isNamedAnchor) {
4614            return true;
4615          }
4616        }
4617        return false;
4618      };
4619      const isEmpty = (node, elements, options) => {
4620        let brCount = 0;
4621        if (isNonEmptyElement(node)) {
4622          return false;
4623        }
4624        const firstChild = node.firstChild;
4625        if (firstChild) {
4626          const walker = new DomTreeWalker(firstChild, node);
4627          const whitespaceElements = schema ? schema.getWhitespaceElements() : {};
4628          const nonEmptyElements = elements || (schema ? schema.getNonEmptyElements() : null);
4629          let tempNode = firstChild;
4630          do {
4631            if (isElement$6(tempNode)) {
4632              const bogusVal = tempNode.getAttribute('data-mce-bogus');
4633              if (bogusVal) {
4634                tempNode = walker.next(bogusVal === 'all');
4635                continue;
4636              }
4637              const name = tempNode.nodeName.toLowerCase();
4638              if (nonEmptyElements && nonEmptyElements[name]) {
4639                if (name === 'br') {
4640                  brCount++;
4641                  tempNode = walker.next();
4642                  continue;
4643                }
4644                return false;
4645              }
4646              if (isNonEmptyElement(tempNode)) {
4647                return false;
4648              }
4649            }
4650            if (isComment(tempNode)) {
4651              return false;
4652            }
4653            if (isText$a(tempNode) && !isWhitespaceText(tempNode.data) && (!(options === null || options === void 0 ? void 0 : options.includeZwsp) || !isZwsp(tempNode.data))) {
4654              return false;
4655            }
4656            if (isText$a(tempNode) && tempNode.parentNode && whitespaceElements[tempNode.parentNode.nodeName] && isWhitespaceText(tempNode.data)) {
4657              return false;
4658            }
4659            tempNode = walker.next();
4660          } while (tempNode);
4661        }
4662        return brCount <= 1;
4663      };
4664      const createRng = () => doc.createRange();
4665      const split = (parentElm, splitElm, replacementElm) => {
4666        let range = createRng();
4667        let beforeFragment;
4668        let afterFragment;
4669        if (parentElm && splitElm && parentElm.parentNode && splitElm.parentNode) {
4670          const parentNode = parentElm.parentNode;
4671          range.setStart(parentNode, findNodeIndex(parentElm));
4672          range.setEnd(splitElm.parentNode, findNodeIndex(splitElm));
4673          beforeFragment = range.extractContents();
4674          range = createRng();
4675          range.setStart(splitElm.parentNode, findNodeIndex(splitElm) + 1);
4676          range.setEnd(parentNode, findNodeIndex(parentElm) + 1);
4677          afterFragment = range.extractContents();
4678          parentNode.insertBefore(trimNode(self, beforeFragment), parentElm);
4679          if (replacementElm) {
4680            parentNode.insertBefore(replacementElm, parentElm);
4681          } else {
4682            parentNode.insertBefore(splitElm, parentElm);
4683          }
4684          parentNode.insertBefore(trimNode(self, afterFragment), parentElm);
4685          remove(parentElm);
4686          return replacementElm || splitElm;
4687        } else {
4688          return undefined;
4689        }
4690      };
4691      const bind = (target, name, func, scope) => {
4692        if (isArray$1(target)) {
4693          let i = target.length;
4694          const rv = [];
4695          while (i--) {
4696            rv[i] = bind(target[i], name, func, scope);
4697          }
4698          return rv;
4699        } else {
4700          if (settings.collect && (target === doc || target === win)) {
4701            boundEvents.push([
4702              target,
4703              name,
4704              func,
4705              scope
4706            ]);
4707          }
4708          return events.bind(target, name, func, scope || self);
4709        }
4710      };
4711      const unbind = (target, name, func) => {
4712        if (isArray$1(target)) {
4713          let i = target.length;
4714          const rv = [];
4715          while (i--) {
4716            rv[i] = unbind(target[i], name, func);
4717          }
4718          return rv;
4719        } else {
4720          if (boundEvents.length > 0 && (target === doc || target === win)) {
4721            let i = boundEvents.length;
4722            while (i--) {
4723              const [boundTarget, boundName, boundFunc] = boundEvents[i];
4724              if (target === boundTarget && (!name || name === boundName) && (!func || func === boundFunc)) {
4725                events.unbind(boundTarget, boundName, boundFunc);
4726              }
4727            }
4728          }
4729          return events.unbind(target, name, func);
4730        }
4731      };
4732      const dispatch = (target, name, evt) => events.dispatch(target, name, evt);
4733      const fire = (target, name, evt) => events.dispatch(target, name, evt);
4734      const getContentEditable = node => {
4735        if (node && isElement$6(node)) {
4736          const contentEditable = node.getAttribute('data-mce-contenteditable');
4737          if (contentEditable && contentEditable !== 'inherit') {
4738            return contentEditable;
4739          }
4740          return node.contentEditable !== 'inherit' ? node.contentEditable : null;
4741        } else {
4742          return null;
4743        }
4744      };
4745      const getContentEditableParent = node => {
4746        const root = getRoot();
4747        let state = null;
4748        for (let tempNode = node; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
4749          state = getContentEditable(tempNode);
4750          if (state !== null) {
4751            break;
4752          }
4753        }
4754        return state;
4755      };
4756      const isEditable = node => {
4757        if (isNonNullable(node)) {
4758          const scope = isElement$6(node) ? node : node.parentElement;
4759          return isNonNullable(scope) && isEditable$3(SugarElement.fromDom(scope));
4760        } else {
4761          return false;
4762        }
4763      };
4764      const destroy = () => {
4765        if (boundEvents.length > 0) {
4766          let i = boundEvents.length;
4767          while (i--) {
4768            const [boundTarget, boundName, boundFunc] = boundEvents[i];
4769            events.unbind(boundTarget, boundName, boundFunc);
4770          }
4771        }
4772        each$d(files, (_, url) => {
4773          styleSheetLoader.unload(url);
4774          delete files[url];
4775        });
4776      };
4777      const isChildOf = (node, parent) => {
4778        return node === parent || parent.contains(node);
4779      };
4780      const dumpRng = r => 'startContainer: ' + r.startContainer.nodeName + ', startOffset: ' + r.startOffset + ', endContainer: ' + r.endContainer.nodeName + ', endOffset: ' + r.endOffset;
4781      const self = {
4782        doc,
4783        settings,
4784        win,
4785        files,
4786        stdMode,
4787        boxModel,
4788        styleSheetLoader,
4789        boundEvents,
4790        styles,
4791        schema,
4792        events,
4793        isBlock: isBlock,
4794        root: null,
4795        clone,
4796        getRoot,
4797        getViewPort,
4798        getRect,
4799        getSize,
4800        getParent,
4801        getParents: getParents,
4802        get,
4803        getNext,
4804        getPrev,
4805        select,
4806        is,
4807        add,
4808        create,
4809        createHTML,
4810        createFragment,
4811        remove,
4812        setStyle,
4813        getStyle: getStyle,
4814        setStyles,
4815        removeAllAttribs,
4816        setAttrib,
4817        setAttribs,
4818        getAttrib,
4819        getPos: getPos$1,
4820        parseStyle,
4821        serializeStyle,
4822        addStyle,
4823        loadCSS,
4824        addClass,
4825        removeClass,
4826        hasClass,
4827        toggleClass,
4828        show,
4829        hide,
4830        isHidden,
4831        uniqueId,
4832        setHTML,
4833        getOuterHTML,
4834        setOuterHTML,
4835        decode,
4836        encode,
4837        insertAfter,
4838        replace,
4839        rename,
4840        findCommonAncestor,
4841        run,
4842        getAttribs,
4843        isEmpty,
4844        createRng,
4845        nodeIndex: findNodeIndex,
4846        split,
4847        bind: bind,
4848        unbind: unbind,
4849        fire,
4850        dispatch,
4851        getContentEditable,
4852        getContentEditableParent,
4853        isEditable,
4854        destroy,
4855        isChildOf,
4856        dumpRng
4857      };
4858      const attrHooks = setupAttrHooks(styles, settings, constant(self));
4859      return self;
4860    };
4861    DOMUtils.DOM = DOMUtils(document);
4862    DOMUtils.nodeIndex = findNodeIndex;
4863
4864    const DOM$b = DOMUtils.DOM;
4865    const QUEUED = 0;
4866    const LOADING = 1;
4867    const LOADED = 2;
4868    const FAILED = 3;
4869    class ScriptLoader {
4870      constructor(settings = {}) {
4871        this.states = {};
4872        this.queue = [];
4873        this.scriptLoadedCallbacks = {};
4874        this.queueLoadedCallbacks = [];
4875        this.loading = false;
4876        this.settings = settings;
4877      }
4878      _setReferrerPolicy(referrerPolicy) {
4879        this.settings.referrerPolicy = referrerPolicy;
4880      }
4881      loadScript(url) {
4882        return new Promise((resolve, reject) => {
4883          const dom = DOM$b;
4884          let elm;
4885          const cleanup = () => {
4886            dom.remove(id);
4887            if (elm) {
4888              elm.onerror = elm.onload = elm = null;
4889            }
4890          };
4891          const done = () => {
4892            cleanup();
4893            resolve();
4894          };
4895          const error = () => {
4896            cleanup();
4897            reject('Failed to load script: ' + url);
4898          };
4899          const id = dom.uniqueId();
4900          elm = document.createElement('script');
4901          elm.id = id;
4902          elm.type = 'text/javascript';
4903          elm.src = Tools._addCacheSuffix(url);
4904          if (this.settings.referrerPolicy) {
4905            dom.setAttrib(elm, 'referrerpolicy', this.settings.referrerPolicy);
4906          }
4907          elm.onload = done;
4908          elm.onerror = error;
4909          (document.getElementsByTagName('head')[0] || document.body).appendChild(elm);
4910        });
4911      }
4912      isDone(url) {
4913        return this.states[url] === LOADED;
4914      }
4915      markDone(url) {
4916        this.states[url] = LOADED;
4917      }
4918      add(url) {
4919        const self = this;
4920        self.queue.push(url);
4921        const state = self.states[url];
4922        if (state === undefined) {
4923          self.states[url] = QUEUED;
4924        }
4925        return new Promise((resolve, reject) => {
4926          if (!self.scriptLoadedCallbacks[url]) {
4927            self.scriptLoadedCallbacks[url] = [];
4928          }
4929          self.scriptLoadedCallbacks[url].push({
4930            resolve,
4931            reject
4932          });
4933        });
4934      }
4935      load(url) {
4936        return this.add(url);
4937      }
4938      remove(url) {
4939        delete this.states[url];
4940        delete this.scriptLoadedCallbacks[url];
4941      }
4942      loadQueue() {
4943        const queue = this.queue;
4944        this.queue = [];
4945        return this.loadScripts(queue);
4946      }
4947      loadScripts(scripts) {
4948        const self = this;
4949        const execCallbacks = (name, url) => {
4950          get$a(self.scriptLoadedCallbacks, url).each(callbacks => {
4951            each$e(callbacks, callback => callback[name](url));
4952          });
4953          delete self.scriptLoadedCallbacks[url];
4954        };
4955        const processResults = results => {
4956          const failures = filter$5(results, result => result.status === 'rejected');
4957          if (failures.length > 0) {
4958            return Promise.reject(bind$3(failures, ({reason}) => isArray$1(reason) ? reason : [reason]));
4959          } else {
4960            return Promise.resolve();
4961          }
4962        };
4963        const load = urls => Promise.allSettled(map$3(urls, url => {
4964          if (self.states[url] === LOADED) {
4965            execCallbacks('resolve', url);
4966            return Promise.resolve();
4967          } else if (self.states[url] === FAILED) {
4968            execCallbacks('reject', url);
4969            return Promise.reject(url);
4970          } else {
4971            self.states[url] = LOADING;
4972            return self.loadScript(url).then(() => {
4973              self.states[url] = LOADED;
4974              execCallbacks('resolve', url);
4975              const queue = self.queue;
4976              if (queue.length > 0) {
4977                self.queue = [];
4978                return load(queue).then(processResults);
4979              } else {
4980                return Promise.resolve();
4981              }
4982            }, () => {
4983              self.states[url] = FAILED;
4984              execCallbacks('reject', url);
4985              return Promise.reject(url);
4986            });
4987          }
4988        }));
4989        const processQueue = urls => {
4990          self.loading = true;
4991          return load(urls).then(results => {
4992            self.loading = false;
4993            const nextQueuedItem = self.queueLoadedCallbacks.shift();
4994            Optional.from(nextQueuedItem).each(call);
4995            return processResults(results);
4996          });
4997        };
4998        const uniqueScripts = stringArray(scripts);
4999        if (self.loading) {
5000          return new Promise((resolve, reject) => {
5001            self.queueLoadedCallbacks.push(() => {
5002              processQueue(uniqueScripts).then(resolve, reject);
5003            });
5004          });
5005        } else {
5006          return processQueue(uniqueScripts);
5007        }
5008      }
5009    }
5010    ScriptLoader.ScriptLoader = new ScriptLoader();
5011
5012    const Cell = initial => {
5013      let value = initial;
5014      const get = () => {
5015        return value;
5016      };
5017      const set = v => {
5018        value = v;
5019      };
5020      return {
5021        get,
5022        set
5023      };
5024    };
5025
5026    const isRaw = str => isObject(str) && has$2(str, 'raw');
5027    const isTokenised = str => isArray$1(str) && str.length > 1;
5028    const data = {};
5029    const currentCode = Cell('en');
5030    const getLanguageData = () => get$a(data, currentCode.get());
5031    const getData$1 = () => map$2(data, value => ({ ...value }));
5032    const setCode = newCode => {
5033      if (newCode) {
5034        currentCode.set(newCode);
5035      }
5036    };
5037    const getCode = () => currentCode.get();
5038    const add$1 = (code, items) => {
5039      let langData = data[code];
5040      if (!langData) {
5041        data[code] = langData = {};
5042      }
5043      each$d(items, (translation, name) => {
5044        langData[name.toLowerCase()] = translation;
5045      });
5046    };
5047    const translate = text => {
5048      const langData = getLanguageData().getOr({});
5049      const toString = obj => {
5050        if (isFunction(obj)) {
5051          return Object.prototype.toString.call(obj);
5052        }
5053        return !isEmpty(obj) ? '' + obj : '';
5054      };
5055      const isEmpty = text => text === '' || text === null || text === undefined;
5056      const getLangData = text => {
5057        const textstr = toString(text);
5058        return get$a(langData, textstr.toLowerCase()).map(toString).getOr(textstr);
5059      };
5060      const removeContext = str => str.replace(/{context:\w+}$/, '');
5061      if (isEmpty(text)) {
5062        return '';
5063      }
5064      if (isRaw(text)) {
5065        return toString(text.raw);
5066      }
5067      if (isTokenised(text)) {
5068        const values = text.slice(1);
5069        const substitued = getLangData(text[0]).replace(/\{([0-9]+)\}/g, ($1, $2) => has$2(values, $2) ? toString(values[$2]) : $1);
5070        return removeContext(substitued);
5071      }
5072      return removeContext(getLangData(text));
5073    };
5074    const isRtl$1 = () => getLanguageData().bind(items => get$a(items, '_dir')).exists(dir => dir === 'rtl');
5075    const hasCode = code => has$2(data, code);
5076    const I18n = {
5077      getData: getData$1,
5078      setCode,
5079      getCode,
5080      add: add$1,
5081      translate,
5082      isRtl: isRtl$1,
5083      hasCode
5084    };
5085
5086    const AddOnManager = () => {
5087      const items = [];
5088      const urls = {};
5089      const lookup = {};
5090      const _listeners = [];
5091      const runListeners = (name, state) => {
5092        const matchedListeners = filter$5(_listeners, listener => listener.name === name && listener.state === state);
5093        each$e(matchedListeners, listener => listener.resolve());
5094      };
5095      const isLoaded = name => has$2(urls, name);
5096      const isAdded = name => has$2(lookup, name);
5097      const get = name => {
5098        if (lookup[name]) {
5099          return lookup[name].instance;
5100        }
5101        return undefined;
5102      };
5103      const loadLanguagePack = (name, languages) => {
5104        const language = I18n.getCode();
5105        const wrappedLanguages = ',' + (languages || '') + ',';
5106        if (!language || languages && wrappedLanguages.indexOf(',' + language + ',') === -1) {
5107          return;
5108        }
5109        ScriptLoader.ScriptLoader.add(urls[name] + '/langs/' + language + '.js');
5110      };
5111      const requireLangPack = (name, languages) => {
5112        if (AddOnManager.languageLoad !== false) {
5113          if (isLoaded(name)) {
5114            loadLanguagePack(name, languages);
5115          } else {
5116            waitFor(name, 'loaded').then(() => loadLanguagePack(name, languages));
5117          }
5118        }
5119      };
5120      const add = (id, addOn) => {
5121        items.push(addOn);
5122        lookup[id] = { instance: addOn };
5123        runListeners(id, 'added');
5124        return addOn;
5125      };
5126      const remove = name => {
5127        delete urls[name];
5128        delete lookup[name];
5129      };
5130      const createUrl = (baseUrl, dep) => {
5131        if (isString(dep)) {
5132          return isString(baseUrl) ? {
5133            prefix: '',
5134            resource: dep,
5135            suffix: ''
5136          } : {
5137            prefix: baseUrl.prefix,
5138            resource: dep,
5139            suffix: baseUrl.suffix
5140          };
5141        } else {
5142          return dep;
5143        }
5144      };
5145      const load = (name, addOnUrl) => {
5146        if (urls[name]) {
5147          return Promise.resolve();
5148        }
5149        let urlString = isString(addOnUrl) ? addOnUrl : addOnUrl.prefix + addOnUrl.resource + addOnUrl.suffix;
5150        if (urlString.indexOf('/') !== 0 && urlString.indexOf('://') === -1) {
5151          urlString = AddOnManager.baseURL + '/' + urlString;
5152        }
5153        urls[name] = urlString.substring(0, urlString.lastIndexOf('/'));
5154        const done = () => {
5155          runListeners(name, 'loaded');
5156          return Promise.resolve();
5157        };
5158        if (lookup[name]) {
5159          return done();
5160        } else {
5161          return ScriptLoader.ScriptLoader.add(urlString).then(done);
5162        }
5163      };
5164      const waitFor = (name, state = 'added') => {
5165        if (state === 'added' && isAdded(name)) {
5166          return Promise.resolve();
5167        } else if (state === 'loaded' && isLoaded(name)) {
5168          return Promise.resolve();
5169        } else {
5170          return new Promise(resolve => {
5171            _listeners.push({
5172              name,
5173              state,
5174              resolve
5175            });
5176          });
5177        }
5178      };
5179      return {
5180        items,
5181        urls,
5182        lookup,
5183        get,
5184        requireLangPack,
5185        add,
5186        remove,
5187        createUrl,
5188        load,
5189        waitFor
5190      };
5191    };
5192    AddOnManager.languageLoad = true;
5193    AddOnManager.baseURL = '';
5194    AddOnManager.PluginManager = AddOnManager();
5195    AddOnManager.ThemeManager = AddOnManager();
5196    AddOnManager.ModelManager = AddOnManager();
5197
5198    const singleton = doRevoke => {
5199      const subject = Cell(Optional.none());
5200      const revoke = () => subject.get().each(doRevoke);
5201      const clear = () => {
5202        revoke();
5203        subject.set(Optional.none());
5204      };
5205      const isSet = () => subject.get().isSome();
5206      const get = () => subject.get();
5207      const set = s => {
5208        revoke();
5209        subject.set(Optional.some(s));
5210      };
5211      return {
5212        clear,
5213        isSet,
5214        get,
5215        set
5216      };
5217    };
5218    const repeatable = delay => {
5219      const intervalId = Cell(Optional.none());
5220      const revoke = () => intervalId.get().each(id => clearInterval(id));
5221      const clear = () => {
5222        revoke();
5223        intervalId.set(Optional.none());
5224      };
5225      const isSet = () => intervalId.get().isSome();
5226      const get = () => intervalId.get();
5227      const set = functionToRepeat => {
5228        revoke();
5229        intervalId.set(Optional.some(setInterval(functionToRepeat, delay)));
5230      };
5231      return {
5232        clear,
5233        isSet,
5234        get,
5235        set
5236      };
5237    };
5238    const value$2 = () => {
5239      const subject = singleton(noop);
5240      const on = f => subject.get().each(f);
5241      return {
5242        ...subject,
5243        on
5244      };
5245    };
5246
5247    const first$1 = (fn, rate) => {
5248      let timer = null;
5249      const cancel = () => {
5250        if (!isNull(timer)) {
5251          clearTimeout(timer);
5252          timer = null;
5253        }
5254      };
5255      const throttle = (...args) => {
5256        if (isNull(timer)) {
5257          timer = setTimeout(() => {
5258            timer = null;
5259            fn.apply(null, args);
5260          }, rate);
5261        }
5262      };
5263      return {
5264        cancel,
5265        throttle
5266      };
5267    };
5268    const last$1 = (fn, rate) => {
5269      let timer = null;
5270      const cancel = () => {
5271        if (!isNull(timer)) {
5272          clearTimeout(timer);
5273          timer = null;
5274        }
5275      };
5276      const throttle = (...args) => {
5277        cancel();
5278        timer = setTimeout(() => {
5279          timer = null;
5280          fn.apply(null, args);
5281        }, rate);
5282      };
5283      return {
5284        cancel,
5285        throttle
5286      };
5287    };
5288
5289    const annotation = constant('mce-annotation');
5290    const dataAnnotation = constant('data-mce-annotation');
5291    const dataAnnotationId = constant('data-mce-annotation-uid');
5292    const dataAnnotationActive = constant('data-mce-annotation-active');
5293    const dataAnnotationClasses = constant('data-mce-annotation-classes');
5294    const dataAnnotationAttributes = constant('data-mce-annotation-attrs');
5295
5296    const isRoot$1 = root => node => eq(node, root);
5297    const identify = (editor, annotationName) => {
5298      const rng = editor.selection.getRng();
5299      const start = SugarElement.fromDom(rng.startContainer);
5300      const root = SugarElement.fromDom(editor.getBody());
5301      const selector = annotationName.fold(() => '.' + annotation(), an => `[${ dataAnnotation() }="${ an }"]`);
5302      const newStart = child$1(start, rng.startOffset).getOr(start);
5303      const closest = closest$3(newStart, selector, isRoot$1(root));
5304      return closest.bind(c => getOpt(c, `${ dataAnnotationId() }`).bind(uid => getOpt(c, `${ dataAnnotation() }`).map(name => {
5305        const elements = findMarkers(editor, uid);
5306        return {
5307          uid,
5308          name,
5309          elements
5310        };
5311      })));
5312    };
5313    const isAnnotation = elem => isElement$7(elem) && has(elem, annotation());
5314    const isBogusElement = (elem, root) => has$1(elem, 'data-mce-bogus') || ancestor$2(elem, '[data-mce-bogus="all"]', isRoot$1(root));
5315    const findMarkers = (editor, uid) => {
5316      const body = SugarElement.fromDom(editor.getBody());
5317      const descendants$1 = descendants(body, `[${ dataAnnotationId() }="${ uid }"]`);
5318      return filter$5(descendants$1, descendant => !isBogusElement(descendant, body));
5319    };
5320    const findAll = (editor, name) => {
5321      const body = SugarElement.fromDom(editor.getBody());
5322      const markers = descendants(body, `[${ dataAnnotation() }="${ name }"]`);
5323      const directory = {};
5324      each$e(markers, m => {
5325        if (!isBogusElement(m, body)) {
5326          const uid = get$9(m, dataAnnotationId());
5327          const nodesAlready = get$a(directory, uid).getOr([]);
5328          directory[uid] = nodesAlready.concat([m]);
5329        }
5330      });
5331      return directory;
5332    };
5333
5334    const setup$x = (editor, registry) => {
5335      const changeCallbacks = Cell({});
5336      const initData = () => ({
5337        listeners: [],
5338        previous: value$2()
5339      });
5340      const withCallbacks = (name, f) => {
5341        updateCallbacks(name, data => {
5342          f(data);
5343          return data;
5344        });
5345      };
5346      const updateCallbacks = (name, f) => {
5347        const callbackMap = changeCallbacks.get();
5348        const data = get$a(callbackMap, name).getOrThunk(initData);
5349        const outputData = f(data);
5350        callbackMap[name] = outputData;
5351        changeCallbacks.set(callbackMap);
5352      };
5353      const fireCallbacks = (name, uid, elements) => {
5354        withCallbacks(name, data => {
5355          each$e(data.listeners, f => f(true, name, {
5356            uid,
5357            nodes: map$3(elements, elem => elem.dom)
5358          }));
5359        });
5360      };
5361      const fireNoAnnotation = name => {
5362        withCallbacks(name, data => {
5363          each$e(data.listeners, f => f(false, name));
5364        });
5365      };
5366      const toggleActiveAttr = (uid, state) => {
5367        each$e(findMarkers(editor, uid), elem => {
5368          if (state) {
5369            set$3(elem, dataAnnotationActive(), 'true');
5370          } else {
5371            remove$a(elem, dataAnnotationActive());
5372          }
5373        });
5374      };
5375      const onNodeChange = last$1(() => {
5376        const annotations = sort(registry.getNames());
5377        each$e(annotations, name => {
5378          updateCallbacks(name, data => {
5379            const prev = data.previous.get();
5380            identify(editor, Optional.some(name)).fold(() => {
5381              prev.each(uid => {
5382                fireNoAnnotation(name);
5383                data.previous.clear();
5384                toggleActiveAttr(uid, false);
5385              });
5386            }, ({uid, name, elements}) => {
5387              if (!is$2(prev, uid)) {
5388                prev.each(uid => toggleActiveAttr(uid, false));
5389                fireCallbacks(name, uid, elements);
5390                data.previous.set(uid);
5391                toggleActiveAttr(uid, true);
5392              }
5393            });
5394            return {
5395              previous: data.previous,
5396              listeners: data.listeners
5397            };
5398          });
5399        });
5400      }, 30);
5401      editor.on('remove', () => {
5402        onNodeChange.cancel();
5403      });
5404      editor.on('NodeChange', () => {
5405        onNodeChange.throttle();
5406      });
5407      const addListener = (name, f) => {
5408        updateCallbacks(name, data => ({
5409          previous: data.previous,
5410          listeners: data.listeners.concat([f])
5411        }));
5412      };
5413      return { addListener };
5414    };
5415
5416    const setup$w = (editor, registry) => {
5417      const dataAnnotation$1 = dataAnnotation();
5418      const identifyParserNode = node => Optional.from(node.attr(dataAnnotation$1)).bind(registry.lookup);
5419      const removeDirectAnnotation = node => {
5420        var _a, _b;
5421        node.attr(dataAnnotationId(), null);
5422        node.attr(dataAnnotation(), null);
5423        node.attr(dataAnnotationActive(), null);
5424        const customAttrNames = Optional.from(node.attr(dataAnnotationAttributes())).map(names => names.split(',')).getOr([]);
5425        const customClasses = Optional.from(node.attr(dataAnnotationClasses())).map(names => names.split(',')).getOr([]);
5426        each$e(customAttrNames, name => node.attr(name, null));
5427        const classList = (_b = (_a = node.attr('class')) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : [];
5428        const newClassList = difference(classList, [annotation()].concat(customClasses));
5429        node.attr('class', newClassList.length > 0 ? newClassList.join(' ') : null);
5430        node.attr(dataAnnotationClasses(), null);
5431        node.attr(dataAnnotationAttributes(), null);
5432      };
5433      editor.serializer.addTempAttr(dataAnnotationActive());
5434      editor.serializer.addAttributeFilter(dataAnnotation$1, nodes => {
5435        for (const node of nodes) {
5436          identifyParserNode(node).each(settings => {
5437            if (settings.persistent === false) {
5438              if (node.name === 'span') {
5439                node.unwrap();
5440              } else {
5441                removeDirectAnnotation(node);
5442              }
5443            }
5444          });
5445        }
5446      });
5447    };
5448
5449    const create$c = () => {
5450      const annotations = {};
5451      const register = (name, settings) => {
5452        annotations[name] = {
5453          name,
5454          settings
5455        };
5456      };
5457      const lookup = name => get$a(annotations, name).map(a => a.settings);
5458      const getNames = () => keys(annotations);
5459      return {
5460        register,
5461        lookup,
5462        getNames
5463      };
5464    };
5465
5466    let unique = 0;
5467    const generate$1 = prefix => {
5468      const date = new Date();
5469      const time = date.getTime();
5470      const random = Math.floor(Math.random() * 1000000000);
5471      unique++;
5472      return prefix + '_' + random + unique + String(time);
5473    };
5474
5475    const add = (element, classes) => {
5476      each$e(classes, x => {
5477        add$2(element, x);
5478      });
5479    };
5480    const remove$4 = (element, classes) => {
5481      each$e(classes, x => {
5482        remove$7(element, x);
5483      });
5484    };
5485
5486    const clone$2 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
5487    const shallow$1 = original => clone$2(original, false);
5488    const deep$1 = original => clone$2(original, true);
5489    const shallowAs = (original, tag) => {
5490      const nu = SugarElement.fromTag(tag);
5491      const attributes = clone$4(original);
5492      setAll$1(nu, attributes);
5493      return nu;
5494    };
5495    const mutate = (original, tag) => {
5496      const nu = shallowAs(original, tag);
5497      after$4(original, nu);
5498      const children = children$1(original);
5499      append(nu, children);
5500      remove$5(original);
5501      return nu;
5502    };
5503
5504    const TextWalker = (startNode, rootNode, isBoundary = never) => {
5505      const walker = new DomTreeWalker(startNode, rootNode);
5506      const walk = direction => {
5507        let next;
5508        do {
5509          next = walker[direction]();
5510        } while (next && !isText$a(next) && !isBoundary(next));
5511        return Optional.from(next).filter(isText$a);
5512      };
5513      return {
5514        current: () => Optional.from(walker.current()).filter(isText$a),
5515        next: () => walk('next'),
5516        prev: () => walk('prev'),
5517        prev2: () => walk('prev2')
5518      };
5519    };
5520
5521    const TextSeeker = (dom, isBoundary) => {
5522      const isBlockBoundary = isBoundary ? isBoundary : node => dom.isBlock(node) || isBr$6(node) || isContentEditableFalse$b(node);
5523      const walk = (node, offset, walker, process) => {
5524        if (isText$a(node)) {
5525          const newOffset = process(node, offset, node.data);
5526          if (newOffset !== -1) {
5527            return Optional.some({
5528              container: node,
5529              offset: newOffset
5530            });
5531          }
5532        }
5533        return walker().bind(next => walk(next.container, next.offset, walker, process));
5534      };
5535      const backwards = (node, offset, process, root) => {
5536        const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
5537        return walk(node, offset, () => walker.prev().map(prev => ({
5538          container: prev,
5539          offset: prev.length
5540        })), process).getOrNull();
5541      };
5542      const forwards = (node, offset, process, root) => {
5543        const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
5544        return walk(node, offset, () => walker.next().map(next => ({
5545          container: next,
5546          offset: 0
5547        })), process).getOrNull();
5548      };
5549      return {
5550        backwards,
5551        forwards
5552      };
5553    };
5554
5555    const round$2 = Math.round;
5556    const clone$1 = rect => {
5557      if (!rect) {
5558        return {
5559          left: 0,
5560          top: 0,
5561          bottom: 0,
5562          right: 0,
5563          width: 0,
5564          height: 0
5565        };
5566      }
5567      return {
5568        left: round$2(rect.left),
5569        top: round$2(rect.top),
5570        bottom: round$2(rect.bottom),
5571        right: round$2(rect.right),
5572        width: round$2(rect.width),
5573        height: round$2(rect.height)
5574      };
5575    };
5576    const collapse = (rect, toStart) => {
5577      rect = clone$1(rect);
5578      if (toStart) {
5579        rect.right = rect.left;
5580      } else {
5581        rect.left = rect.left + rect.width;
5582        rect.right = rect.left;
5583      }
5584      rect.width = 0;
5585      return rect;
5586    };
5587    const isEqual = (rect1, rect2) => rect1.left === rect2.left && rect1.top === rect2.top && rect1.bottom === rect2.bottom && rect1.right === rect2.right;
5588    const isValidOverflow = (overflowY, rect1, rect2) => overflowY >= 0 && overflowY <= Math.min(rect1.height, rect2.height) / 2;
5589    const isAbove$1 = (rect1, rect2) => {
5590      const halfHeight = Math.min(rect2.height / 2, rect1.height / 2);
5591      if (rect1.bottom - halfHeight < rect2.top) {
5592        return true;
5593      }
5594      if (rect1.top > rect2.bottom) {
5595        return false;
5596      }
5597      return isValidOverflow(rect2.top - rect1.bottom, rect1, rect2);
5598    };
5599    const isBelow$1 = (rect1, rect2) => {
5600      if (rect1.top > rect2.bottom) {
5601        return true;
5602      }
5603      if (rect1.bottom < rect2.top) {
5604        return false;
5605      }
5606      return isValidOverflow(rect2.bottom - rect1.top, rect1, rect2);
5607    };
5608    const containsXY = (rect, clientX, clientY) => clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
5609    const boundingClientRectFromRects = rects => {
5610      return foldl(rects, (acc, rect) => {
5611        return acc.fold(() => Optional.some(rect), prevRect => {
5612          const left = Math.min(rect.left, prevRect.left);
5613          const top = Math.min(rect.top, prevRect.top);
5614          const right = Math.max(rect.right, prevRect.right);
5615          const bottom = Math.max(rect.bottom, prevRect.bottom);
5616          return Optional.some({
5617            top,
5618            right,
5619            bottom,
5620            left,
5621            width: right - left,
5622            height: bottom - top
5623          });
5624        });
5625      }, Optional.none());
5626    };
5627    const distanceToRectEdgeFromXY = (rect, x, y) => {
5628      const cx = Math.max(Math.min(x, rect.left + rect.width), rect.left);
5629      const cy = Math.max(Math.min(y, rect.top + rect.height), rect.top);
5630      return Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
5631    };
5632    const overlapY = (r1, r2) => Math.max(0, Math.min(r1.bottom, r2.bottom) - Math.max(r1.top, r2.top));
5633
5634    const clamp$2 = (value, min, max) => Math.min(Math.max(value, min), max);
5635
5636    const getSelectedNode = range => {
5637      const startContainer = range.startContainer, startOffset = range.startOffset;
5638      if (startContainer === range.endContainer && startContainer.hasChildNodes() && range.endOffset === startOffset + 1) {
5639        return startContainer.childNodes[startOffset];
5640      }
5641      return null;
5642    };
5643    const getNode$1 = (container, offset) => {
5644      if (isElement$6(container) && container.hasChildNodes()) {
5645        const childNodes = container.childNodes;
5646        const safeOffset = clamp$2(offset, 0, childNodes.length - 1);
5647        return childNodes[safeOffset];
5648      } else {
5649        return container;
5650      }
5651    };
5652    const getNodeUnsafe = (container, offset) => {
5653      if (offset < 0 && isElement$6(container) && container.hasChildNodes()) {
5654        return undefined;
5655      } else {
5656        return getNode$1(container, offset);
5657      }
5658    };
5659
5660    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]');
5661    const isExtendingChar = ch => isString(ch) && ch.charCodeAt(0) >= 768 && extendingChars.test(ch);
5662
5663    const or = (...args) => {
5664      return x => {
5665        for (let i = 0; i < args.length; i++) {
5666          if (args[i](x)) {
5667            return true;
5668          }
5669        }
5670        return false;
5671      };
5672    };
5673    const and = (...args) => {
5674      return x => {
5675        for (let i = 0; i < args.length; i++) {
5676          if (!args[i](x)) {
5677            return false;
5678          }
5679        }
5680        return true;
5681      };
5682    };
5683
5684    const isElement$4 = isElement$6;
5685    const isCaretCandidate$2 = isCaretCandidate$3;
5686    const isBlock$1 = matchStyleValues('display', 'block table');
5687    const isFloated = matchStyleValues('float', 'left right');
5688    const isValidElementCaretCandidate = and(isElement$4, isCaretCandidate$2, not(isFloated));
5689    const isNotPre = not(matchStyleValues('white-space', 'pre pre-line pre-wrap'));
5690    const isText$7 = isText$a;
5691    const isBr$3 = isBr$6;
5692    const nodeIndex$1 = DOMUtils.nodeIndex;
5693    const resolveIndex$1 = getNodeUnsafe;
5694    const createRange$1 = doc => doc ? doc.createRange() : DOMUtils.DOM.createRng();
5695    const isWhiteSpace$1 = chr => isString(chr) && /[\r\n\t ]/.test(chr);
5696    const isRange = rng => !!rng.setStart && !!rng.setEnd;
5697    const isHiddenWhiteSpaceRange = range => {
5698      const container = range.startContainer;
5699      const offset = range.startOffset;
5700      if (isWhiteSpace$1(range.toString()) && isNotPre(container.parentNode) && isText$a(container)) {
5701        const text = container.data;
5702        if (isWhiteSpace$1(text[offset - 1]) || isWhiteSpace$1(text[offset + 1])) {
5703          return true;
5704        }
5705      }
5706      return false;
5707    };
5708    const getBrClientRect = brNode => {
5709      const doc = brNode.ownerDocument;
5710      const rng = createRange$1(doc);
5711      const nbsp$1 = doc.createTextNode(nbsp);
5712      const parentNode = brNode.parentNode;
5713      parentNode.insertBefore(nbsp$1, brNode);
5714      rng.setStart(nbsp$1, 0);
5715      rng.setEnd(nbsp$1, 1);
5716      const clientRect = clone$1(rng.getBoundingClientRect());
5717      parentNode.removeChild(nbsp$1);
5718      return clientRect;
5719    };
5720    const getBoundingClientRectWebKitText = rng => {
5721      const sc = rng.startContainer;
5722      const ec = rng.endContainer;
5723      const so = rng.startOffset;
5724      const eo = rng.endOffset;
5725      if (sc === ec && isText$a(ec) && so === 0 && eo === 1) {
5726        const newRng = rng.cloneRange();
5727        newRng.setEndAfter(ec);
5728        return getBoundingClientRect$1(newRng);
5729      } else {
5730        return null;
5731      }
5732    };
5733    const isZeroRect = r => r.left === 0 && r.right === 0 && r.top === 0 && r.bottom === 0;
5734    const getBoundingClientRect$1 = item => {
5735      var _a;
5736      let clientRect;
5737      const clientRects = item.getClientRects();
5738      if (clientRects.length > 0) {
5739        clientRect = clone$1(clientRects[0]);
5740      } else {
5741        clientRect = clone$1(item.getBoundingClientRect());
5742      }
5743      if (!isRange(item) && isBr$3(item) && isZeroRect(clientRect)) {
5744        return getBrClientRect(item);
5745      }
5746      if (isZeroRect(clientRect) && isRange(item)) {
5747        return (_a = getBoundingClientRectWebKitText(item)) !== null && _a !== void 0 ? _a : clientRect;
5748      }
5749      return clientRect;
5750    };
5751    const collapseAndInflateWidth = (clientRect, toStart) => {
5752      const newClientRect = collapse(clientRect, toStart);
5753      newClientRect.width = 1;
5754      newClientRect.right = newClientRect.left + 1;
5755      return newClientRect;
5756    };
5757    const getCaretPositionClientRects = caretPosition => {
5758      const clientRects = [];
5759      const addUniqueAndValidRect = clientRect => {
5760        if (clientRect.height === 0) {
5761          return;
5762        }
5763        if (clientRects.length > 0) {
5764          if (isEqual(clientRect, clientRects[clientRects.length - 1])) {
5765            return;
5766          }
5767        }
5768        clientRects.push(clientRect);
5769      };
5770      const addCharacterOffset = (container, offset) => {
5771        const range = createRange$1(container.ownerDocument);
5772        if (offset < container.data.length) {
5773          if (isExtendingChar(container.data[offset])) {
5774            return;
5775          }
5776          if (isExtendingChar(container.data[offset - 1])) {
5777            range.setStart(container, offset);
5778            range.setEnd(container, offset + 1);
5779            if (!isHiddenWhiteSpaceRange(range)) {
5780              addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
5781              return;
5782            }
5783          }
5784        }
5785        if (offset > 0) {
5786          range.setStart(container, offset - 1);
5787          range.setEnd(container, offset);
5788          if (!isHiddenWhiteSpaceRange(range)) {
5789            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
5790          }
5791        }
5792        if (offset < container.data.length) {
5793          range.setStart(container, offset);
5794          range.setEnd(container, offset + 1);
5795          if (!isHiddenWhiteSpaceRange(range)) {
5796            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), true));
5797          }
5798        }
5799      };
5800      const container = caretPosition.container();
5801      const offset = caretPosition.offset();
5802      if (isText$7(container)) {
5803        addCharacterOffset(container, offset);
5804        return clientRects;
5805      }
5806      if (isElement$4(container)) {
5807        if (caretPosition.isAtEnd()) {
5808          const node = resolveIndex$1(container, offset);
5809          if (isText$7(node)) {
5810            addCharacterOffset(node, node.data.length);
5811          }
5812          if (isValidElementCaretCandidate(node) && !isBr$3(node)) {
5813            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
5814          }
5815        } else {
5816          const node = resolveIndex$1(container, offset);
5817          if (isText$7(node)) {
5818            addCharacterOffset(node, 0);
5819          }
5820          if (isValidElementCaretCandidate(node) && caretPosition.isAtEnd()) {
5821            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
5822            return clientRects;
5823          }
5824          const beforeNode = resolveIndex$1(caretPosition.container(), caretPosition.offset() - 1);
5825          if (isValidElementCaretCandidate(beforeNode) && !isBr$3(beforeNode)) {
5826            if (isBlock$1(beforeNode) || isBlock$1(node) || !isValidElementCaretCandidate(node)) {
5827              addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(beforeNode), false));
5828            }
5829          }
5830          if (isValidElementCaretCandidate(node)) {
5831            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), true));
5832          }
5833        }
5834      }
5835      return clientRects;
5836    };
5837    const CaretPosition = (container, offset, clientRects) => {
5838      const isAtStart = () => {
5839        if (isText$7(container)) {
5840          return offset === 0;
5841        }
5842        return offset === 0;
5843      };
5844      const isAtEnd = () => {
5845        if (isText$7(container)) {
5846          return offset >= container.data.length;
5847        }
5848        return offset >= container.childNodes.length;
5849      };
5850      const toRange = () => {
5851        const range = createRange$1(container.ownerDocument);
5852        range.setStart(container, offset);
5853        range.setEnd(container, offset);
5854        return range;
5855      };
5856      const getClientRects = () => {
5857        if (!clientRects) {
5858          clientRects = getCaretPositionClientRects(CaretPosition(container, offset));
5859        }
5860        return clientRects;
5861      };
5862      const isVisible = () => getClientRects().length > 0;
5863      const isEqual = caretPosition => caretPosition && container === caretPosition.container() && offset === caretPosition.offset();
5864      const getNode = before => resolveIndex$1(container, before ? offset - 1 : offset);
5865      return {
5866        container: constant(container),
5867        offset: constant(offset),
5868        toRange,
5869        getClientRects,
5870        isVisible,
5871        isAtStart,
5872        isAtEnd,
5873        isEqual,
5874        getNode
5875      };
5876    };
5877    CaretPosition.fromRangeStart = range => CaretPosition(range.startContainer, range.startOffset);
5878    CaretPosition.fromRangeEnd = range => CaretPosition(range.endContainer, range.endOffset);
5879    CaretPosition.after = node => CaretPosition(node.parentNode, nodeIndex$1(node) + 1);
5880    CaretPosition.before = node => CaretPosition(node.parentNode, nodeIndex$1(node));
5881    CaretPosition.isAbove = (pos1, pos2) => lift2(head(pos2.getClientRects()), last$3(pos1.getClientRects()), isAbove$1).getOr(false);
5882    CaretPosition.isBelow = (pos1, pos2) => lift2(last$3(pos2.getClientRects()), head(pos1.getClientRects()), isBelow$1).getOr(false);
5883    CaretPosition.isAtStart = pos => pos ? pos.isAtStart() : false;
5884    CaretPosition.isAtEnd = pos => pos ? pos.isAtEnd() : false;
5885    CaretPosition.isTextPosition = pos => pos ? isText$a(pos.container()) : false;
5886    CaretPosition.isElementPosition = pos => !CaretPosition.isTextPosition(pos);
5887
5888    const trimEmptyTextNode$1 = (dom, node) => {
5889      if (isText$a(node) && node.data.length === 0) {
5890        dom.remove(node);
5891      }
5892    };
5893    const insertNode = (dom, rng, node) => {
5894      rng.insertNode(node);
5895      trimEmptyTextNode$1(dom, node.previousSibling);
5896      trimEmptyTextNode$1(dom, node.nextSibling);
5897    };
5898    const insertFragment = (dom, rng, frag) => {
5899      const firstChild = Optional.from(frag.firstChild);
5900      const lastChild = Optional.from(frag.lastChild);
5901      rng.insertNode(frag);
5902      firstChild.each(child => trimEmptyTextNode$1(dom, child.previousSibling));
5903      lastChild.each(child => trimEmptyTextNode$1(dom, child.nextSibling));
5904    };
5905    const rangeInsertNode = (dom, rng, node) => {
5906      if (isDocumentFragment(node)) {
5907        insertFragment(dom, rng, node);
5908      } else {
5909        insertNode(dom, rng, node);
5910      }
5911    };
5912
5913    const isText$6 = isText$a;
5914    const isBogus = isBogus$2;
5915    const nodeIndex = DOMUtils.nodeIndex;
5916    const normalizedParent = node => {
5917      const parentNode = node.parentNode;
5918      if (isBogus(parentNode)) {
5919        return normalizedParent(parentNode);
5920      }
5921      return parentNode;
5922    };
5923    const getChildNodes = node => {
5924      if (!node) {
5925        return [];
5926      }
5927      return reduce(node.childNodes, (result, node) => {
5928        if (isBogus(node) && node.nodeName !== 'BR') {
5929          result = result.concat(getChildNodes(node));
5930        } else {
5931          result.push(node);
5932        }
5933        return result;
5934      }, []);
5935    };
5936    const normalizedTextOffset = (node, offset) => {
5937      let tempNode = node;
5938      while (tempNode = tempNode.previousSibling) {
5939        if (!isText$6(tempNode)) {
5940          break;
5941        }
5942        offset += tempNode.data.length;
5943      }
5944      return offset;
5945    };
5946    const equal = a => b => a === b;
5947    const normalizedNodeIndex = node => {
5948      let nodes, index;
5949      nodes = getChildNodes(normalizedParent(node));
5950      index = findIndex$1(nodes, equal(node), node);
5951      nodes = nodes.slice(0, index + 1);
5952      const numTextFragments = reduce(nodes, (result, node, i) => {
5953        if (isText$6(node) && isText$6(nodes[i - 1])) {
5954          result++;
5955        }
5956        return result;
5957      }, 0);
5958      nodes = filter$3(nodes, matchNodeNames([node.nodeName]));
5959      index = findIndex$1(nodes, equal(node), node);
5960      return index - numTextFragments;
5961    };
5962    const createPathItem = node => {
5963      const name = isText$6(node) ? 'text()' : node.nodeName.toLowerCase();
5964      return name + '[' + normalizedNodeIndex(node) + ']';
5965    };
5966    const parentsUntil$1 = (root, node, predicate) => {
5967      const parents = [];
5968      for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
5969        if (predicate && predicate(tempNode)) {
5970          break;
5971        }
5972        parents.push(tempNode);
5973      }
5974      return parents;
5975    };
5976    const create$b = (root, caretPosition) => {
5977      let path = [];
5978      let container = caretPosition.container();
5979      let offset = caretPosition.offset();
5980      let outputOffset;
5981      if (isText$6(container)) {
5982        outputOffset = normalizedTextOffset(container, offset);
5983      } else {
5984        const childNodes = container.childNodes;
5985        if (offset >= childNodes.length) {
5986          outputOffset = 'after';
5987          offset = childNodes.length - 1;
5988        } else {
5989          outputOffset = 'before';
5990        }
5991        container = childNodes[offset];
5992      }
5993      path.push(createPathItem(container));
5994      let parents = parentsUntil$1(root, container);
5995      parents = filter$3(parents, not(isBogus$2));
5996      path = path.concat(map$1(parents, node => {
5997        return createPathItem(node);
5998      }));
5999      return path.reverse().join('/') + ',' + outputOffset;
6000    };
6001    const resolvePathItem = (node, name, index) => {
6002      let nodes = getChildNodes(node);
6003      nodes = filter$3(nodes, (node, index) => {
6004        return !isText$6(node) || !isText$6(nodes[index - 1]);
6005      });
6006      nodes = filter$3(nodes, matchNodeNames([name]));
6007      return nodes[index];
6008    };
6009    const findTextPosition = (container, offset) => {
6010      let node = container;
6011      let targetOffset = 0;
6012      while (isText$6(node)) {
6013        const dataLen = node.data.length;
6014        if (offset >= targetOffset && offset <= targetOffset + dataLen) {
6015          container = node;
6016          offset = offset - targetOffset;
6017          break;
6018        }
6019        if (!isText$6(node.nextSibling)) {
6020          container = node;
6021          offset = dataLen;
6022          break;
6023        }
6024        targetOffset += dataLen;
6025        node = node.nextSibling;
6026      }
6027      if (isText$6(container) && offset > container.data.length) {
6028        offset = container.data.length;
6029      }
6030      return CaretPosition(container, offset);
6031    };
6032    const resolve$1 = (root, path) => {
6033      if (!path) {
6034        return null;
6035      }
6036      const parts = path.split(',');
6037      const paths = parts[0].split('/');
6038      const offset = parts.length > 1 ? parts[1] : 'before';
6039      const container = reduce(paths, (result, value) => {
6040        const match = /([\w\-\(\)]+)\[([0-9]+)\]/.exec(value);
6041        if (!match) {
6042          return null;
6043        }
6044        if (match[1] === 'text()') {
6045          match[1] = '#text';
6046        }
6047        return resolvePathItem(result, match[1], parseInt(match[2], 10));
6048      }, root);
6049      if (!container) {
6050        return null;
6051      }
6052      if (!isText$6(container) && container.parentNode) {
6053        let nodeOffset;
6054        if (offset === 'after') {
6055          nodeOffset = nodeIndex(container) + 1;
6056        } else {
6057          nodeOffset = nodeIndex(container);
6058        }
6059        return CaretPosition(container.parentNode, nodeOffset);
6060      }
6061      return findTextPosition(container, parseInt(offset, 10));
6062    };
6063
6064    const isContentEditableFalse$9 = isContentEditableFalse$b;
6065    const getNormalizedTextOffset$1 = (trim, container, offset) => {
6066      let trimmedOffset = trim(container.data.slice(0, offset)).length;
6067      for (let node = container.previousSibling; node && isText$a(node); node = node.previousSibling) {
6068        trimmedOffset += trim(node.data).length;
6069      }
6070      return trimmedOffset;
6071    };
6072    const getPoint = (dom, trim, normalized, rng, start) => {
6073      const container = start ? rng.startContainer : rng.endContainer;
6074      let offset = start ? rng.startOffset : rng.endOffset;
6075      const point = [];
6076      const root = dom.getRoot();
6077      if (isText$a(container)) {
6078        point.push(normalized ? getNormalizedTextOffset$1(trim, container, offset) : offset);
6079      } else {
6080        let after = 0;
6081        const childNodes = container.childNodes;
6082        if (offset >= childNodes.length && childNodes.length) {
6083          after = 1;
6084          offset = Math.max(0, childNodes.length - 1);
6085        }
6086        point.push(dom.nodeIndex(childNodes[offset], normalized) + after);
6087      }
6088      for (let node = container; node && node !== root; node = node.parentNode) {
6089        point.push(dom.nodeIndex(node, normalized));
6090      }
6091      return point;
6092    };
6093    const getLocation = (trim, selection, normalized, rng) => {
6094      const dom = selection.dom;
6095      const start = getPoint(dom, trim, normalized, rng, true);
6096      const forward = selection.isForward();
6097      const fakeCaret = isRangeInCaretContainerBlock(rng) ? { isFakeCaret: true } : {};
6098      if (!selection.isCollapsed()) {
6099        const end = getPoint(dom, trim, normalized, rng, false);
6100        return {
6101          start,
6102          end,
6103          forward,
6104          ...fakeCaret
6105        };
6106      } else {
6107        return {
6108          start,
6109          forward,
6110          ...fakeCaret
6111        };
6112      }
6113    };
6114    const findIndex = (dom, name, element) => {
6115      let count = 0;
6116      Tools.each(dom.select(name), node => {
6117        if (node.getAttribute('data-mce-bogus') === 'all') {
6118          return;
6119        } else if (node === element) {
6120          return false;
6121        } else {
6122          count++;
6123          return;
6124        }
6125      });
6126      return count;
6127    };
6128    const moveEndPoint$1 = (rng, start) => {
6129      let container = start ? rng.startContainer : rng.endContainer;
6130      let offset = start ? rng.startOffset : rng.endOffset;
6131      if (isElement$6(container) && container.nodeName === 'TR') {
6132        const childNodes = container.childNodes;
6133        container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)];
6134        if (container) {
6135          offset = start ? 0 : container.childNodes.length;
6136          if (start) {
6137            rng.setStart(container, offset);
6138          } else {
6139            rng.setEnd(container, offset);
6140          }
6141        }
6142      }
6143    };
6144    const normalizeTableCellSelection = rng => {
6145      moveEndPoint$1(rng, true);
6146      moveEndPoint$1(rng, false);
6147      return rng;
6148    };
6149    const findSibling = (node, offset) => {
6150      if (isElement$6(node)) {
6151        node = getNode$1(node, offset);
6152        if (isContentEditableFalse$9(node)) {
6153          return node;
6154        }
6155      }
6156      if (isCaretContainer$2(node)) {
6157        if (isText$a(node) && isCaretContainerBlock$1(node)) {
6158          node = node.parentNode;
6159        }
6160        let sibling = node.previousSibling;
6161        if (isContentEditableFalse$9(sibling)) {
6162          return sibling;
6163        }
6164        sibling = node.nextSibling;
6165        if (isContentEditableFalse$9(sibling)) {
6166          return sibling;
6167        }
6168      }
6169      return undefined;
6170    };
6171    const findAdjacentContentEditableFalseElm = rng => {
6172      return findSibling(rng.startContainer, rng.startOffset) || findSibling(rng.endContainer, rng.endOffset);
6173    };
6174    const getOffsetBookmark = (trim, normalized, selection) => {
6175      const element = selection.getNode();
6176      const rng = selection.getRng();
6177      if (element.nodeName === 'IMG' || isContentEditableFalse$9(element)) {
6178        const name = element.nodeName;
6179        return {
6180          name,
6181          index: findIndex(selection.dom, name, element)
6182        };
6183      }
6184      const sibling = findAdjacentContentEditableFalseElm(rng);
6185      if (sibling) {
6186        const name = sibling.tagName;
6187        return {
6188          name,
6189          index: findIndex(selection.dom, name, sibling)
6190        };
6191      }
6192      return getLocation(trim, selection, normalized, rng);
6193    };
6194    const getCaretBookmark = selection => {
6195      const rng = selection.getRng();
6196      return {
6197        start: create$b(selection.dom.getRoot(), CaretPosition.fromRangeStart(rng)),
6198        end: create$b(selection.dom.getRoot(), CaretPosition.fromRangeEnd(rng)),
6199        forward: selection.isForward()
6200      };
6201    };
6202    const getRangeBookmark = selection => {
6203      return {
6204        rng: selection.getRng(),
6205        forward: selection.isForward()
6206      };
6207    };
6208    const createBookmarkSpan = (dom, id, filled) => {
6209      const args = {
6210        'data-mce-type': 'bookmark',
6211        id,
6212        'style': 'overflow:hidden;line-height:0px'
6213      };
6214      return filled ? dom.create('span', args, '&#xFEFF;') : dom.create('span', args);
6215    };
6216    const getPersistentBookmark = (selection, filled) => {
6217      const dom = selection.dom;
6218      let rng = selection.getRng();
6219      const id = dom.uniqueId();
6220      const collapsed = selection.isCollapsed();
6221      const element = selection.getNode();
6222      const name = element.nodeName;
6223      const forward = selection.isForward();
6224      if (name === 'IMG') {
6225        return {
6226          name,
6227          index: findIndex(dom, name, element)
6228        };
6229      }
6230      const rng2 = normalizeTableCellSelection(rng.cloneRange());
6231      if (!collapsed) {
6232        rng2.collapse(false);
6233        const endBookmarkNode = createBookmarkSpan(dom, id + '_end', filled);
6234        rangeInsertNode(dom, rng2, endBookmarkNode);
6235      }
6236      rng = normalizeTableCellSelection(rng);
6237      rng.collapse(true);
6238      const startBookmarkNode = createBookmarkSpan(dom, id + '_start', filled);
6239      rangeInsertNode(dom, rng, startBookmarkNode);
6240      selection.moveToBookmark({
6241        id,
6242        keep: true,
6243        forward
6244      });
6245      return {
6246        id,
6247        forward
6248      };
6249    };
6250    const getBookmark$2 = (selection, type, normalized = false) => {
6251      if (type === 2) {
6252        return getOffsetBookmark(trim$1, normalized, selection);
6253      } else if (type === 3) {
6254        return getCaretBookmark(selection);
6255      } else if (type) {
6256        return getRangeBookmark(selection);
6257      } else {
6258        return getPersistentBookmark(selection, false);
6259      }
6260    };
6261    const getUndoBookmark = curry(getOffsetBookmark, identity, true);
6262
6263    const value$1 = value => {
6264      const applyHelper = fn => fn(value);
6265      const constHelper = constant(value);
6266      const outputHelper = () => output;
6267      const output = {
6268        tag: true,
6269        inner: value,
6270        fold: (_onError, onValue) => onValue(value),
6271        isValue: always,
6272        isError: never,
6273        map: mapper => Result.value(mapper(value)),
6274        mapError: outputHelper,
6275        bind: applyHelper,
6276        exists: applyHelper,
6277        forall: applyHelper,
6278        getOr: constHelper,
6279        or: outputHelper,
6280        getOrThunk: constHelper,
6281        orThunk: outputHelper,
6282        getOrDie: constHelper,
6283        each: fn => {
6284          fn(value);
6285        },
6286        toOptional: () => Optional.some(value)
6287      };
6288      return output;
6289    };
6290    const error = error => {
6291      const outputHelper = () => output;
6292      const output = {
6293        tag: false,
6294        inner: error,
6295        fold: (onError, _onValue) => onError(error),
6296        isValue: never,
6297        isError: always,
6298        map: outputHelper,
6299        mapError: mapper => Result.error(mapper(error)),
6300        bind: outputHelper,
6301        exists: never,
6302        forall: always,
6303        getOr: identity,
6304        or: identity,
6305        getOrThunk: apply$1,
6306        orThunk: apply$1,
6307        getOrDie: die(String(error)),
6308        each: noop,
6309        toOptional: Optional.none
6310      };
6311      return output;
6312    };
6313    const fromOption = (optional, err) => optional.fold(() => error(err), value$1);
6314    const Result = {
6315      value: value$1,
6316      error,
6317      fromOption
6318    };
6319
6320    const generate = cases => {
6321      if (!isArray$1(cases)) {
6322        throw new Error('cases must be an array');
6323      }
6324      if (cases.length === 0) {
6325        throw new Error('there must be at least one case');
6326      }
6327      const constructors = [];
6328      const adt = {};
6329      each$e(cases, (acase, count) => {
6330        const keys$1 = keys(acase);
6331        if (keys$1.length !== 1) {
6332          throw new Error('one and only one name per case');
6333        }
6334        const key = keys$1[0];
6335        const value = acase[key];
6336        if (adt[key] !== undefined) {
6337          throw new Error('duplicate key detected:' + key);
6338        } else if (key === 'cata') {
6339          throw new Error('cannot have a case named cata (sorry)');
6340        } else if (!isArray$1(value)) {
6341          throw new Error('case arguments must be an array');
6342        }
6343        constructors.push(key);
6344        adt[key] = (...args) => {
6345          const argLength = args.length;
6346          if (argLength !== value.length) {
6347            throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
6348          }
6349          const match = branches => {
6350            const branchKeys = keys(branches);
6351            if (constructors.length !== branchKeys.length) {
6352              throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
6353            }
6354            const allReqd = forall(constructors, reqKey => {
6355              return contains$2(branchKeys, reqKey);
6356            });
6357            if (!allReqd) {
6358              throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
6359            }
6360            return branches[key].apply(null, args);
6361          };
6362          return {
6363            fold: (...foldArgs) => {
6364              if (foldArgs.length !== cases.length) {
6365                throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
6366              }
6367              const target = foldArgs[count];
6368              return target.apply(null, args);
6369            },
6370            match,
6371            log: label => {
6372              console.log(label, {
6373                constructors,
6374                constructor: key,
6375                params: args
6376              });
6377            }
6378          };
6379        };
6380      });
6381      return adt;
6382    };
6383    const Adt = { generate };
6384
6385    Adt.generate([
6386      {
6387        bothErrors: [
6388          'error1',
6389          'error2'
6390        ]
6391      },
6392      {
6393        firstError: [
6394          'error1',
6395          'value2'
6396        ]
6397      },
6398      {
6399        secondError: [
6400          'value1',
6401          'error2'
6402        ]
6403      },
6404      {
6405        bothValues: [
6406          'value1',
6407          'value2'
6408        ]
6409      }
6410    ]);
6411    const partition$1 = results => {
6412      const errors = [];
6413      const values = [];
6414      each$e(results, result => {
6415        result.fold(err => {
6416          errors.push(err);
6417        }, value => {
6418          values.push(value);
6419        });
6420      });
6421      return {
6422        errors,
6423        values
6424      };
6425    };
6426
6427    const isInlinePattern = pattern => pattern.type === 'inline-command' || pattern.type === 'inline-format';
6428    const isBlockPattern = pattern => pattern.type === 'block-command' || pattern.type === 'block-format';
6429    const normalizePattern = pattern => {
6430      const err = message => Result.error({
6431        message,
6432        pattern
6433      });
6434      const formatOrCmd = (name, onFormat, onCommand) => {
6435        if (pattern.format !== undefined) {
6436          let formats;
6437          if (isArray$1(pattern.format)) {
6438            if (!forall(pattern.format, isString)) {
6439              return err(name + ' pattern has non-string items in the `format` array');
6440            }
6441            formats = pattern.format;
6442          } else if (isString(pattern.format)) {
6443            formats = [pattern.format];
6444          } else {
6445            return err(name + ' pattern has non-string `format` parameter');
6446          }
6447          return Result.value(onFormat(formats));
6448        } else if (pattern.cmd !== undefined) {
6449          if (!isString(pattern.cmd)) {
6450            return err(name + ' pattern has non-string `cmd` parameter');
6451          }
6452          return Result.value(onCommand(pattern.cmd, pattern.value));
6453        } else {
6454          return err(name + ' pattern is missing both `format` and `cmd` parameters');
6455        }
6456      };
6457      if (!isObject(pattern)) {
6458        return err('Raw pattern is not an object');
6459      }
6460      if (!isString(pattern.start)) {
6461        return err('Raw pattern is missing `start` parameter');
6462      }
6463      if (pattern.end !== undefined) {
6464        if (!isString(pattern.end)) {
6465          return err('Inline pattern has non-string `end` parameter');
6466        }
6467        if (pattern.start.length === 0 && pattern.end.length === 0) {
6468          return err('Inline pattern has empty `start` and `end` parameters');
6469        }
6470        let start = pattern.start;
6471        let end = pattern.end;
6472        if (end.length === 0) {
6473          end = start;
6474          start = '';
6475        }
6476        return formatOrCmd('Inline', format => ({
6477          type: 'inline-format',
6478          start,
6479          end,
6480          format
6481        }), (cmd, value) => ({
6482          type: 'inline-command',
6483          start,
6484          end,
6485          cmd,
6486          value
6487        }));
6488      } else if (pattern.replacement !== undefined) {
6489        if (!isString(pattern.replacement)) {
6490          return err('Replacement pattern has non-string `replacement` parameter');
6491        }
6492        if (pattern.start.length === 0) {
6493          return err('Replacement pattern has empty `start` parameter');
6494        }
6495        return Result.value({
6496          type: 'inline-command',
6497          start: '',
6498          end: pattern.start,
6499          cmd: 'mceInsertContent',
6500          value: pattern.replacement
6501        });
6502      } else {
6503        if (pattern.start.length === 0) {
6504          return err('Block pattern has empty `start` parameter');
6505        }
6506        return formatOrCmd('Block', formats => ({
6507          type: 'block-format',
6508          start: pattern.start,
6509          format: formats[0]
6510        }), (command, commandValue) => ({
6511          type: 'block-command',
6512          start: pattern.start,
6513          cmd: command,
6514          value: commandValue
6515        }));
6516      }
6517    };
6518    const getBlockPatterns = patterns => filter$5(patterns, isBlockPattern);
6519    const getInlinePatterns = patterns => filter$5(patterns, isInlinePattern);
6520    const createPatternSet = (patterns, dynamicPatternsLookup) => ({
6521      inlinePatterns: getInlinePatterns(patterns),
6522      blockPatterns: getBlockPatterns(patterns),
6523      dynamicPatternsLookup
6524    });
6525    const fromRawPatterns = patterns => {
6526      const normalized = partition$1(map$3(patterns, normalizePattern));
6527      each$e(normalized.errors, err => console.error(err.message, err.pattern));
6528      return normalized.values;
6529    };
6530    const fromRawPatternsLookup = lookupFn => {
6531      return ctx => {
6532        const rawPatterns = lookupFn(ctx);
6533        return fromRawPatterns(rawPatterns);
6534      };
6535    };
6536
6537    const deviceDetection$1 = detect$2().deviceType;
6538    const isTouch = deviceDetection$1.isTouch();
6539    const DOM$a = DOMUtils.DOM;
6540    const getHash = value => {
6541      const items = value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(',');
6542      return foldl(items, (output, item) => {
6543        const arr = item.split('=');
6544        const key = arr[0];
6545        const val = arr.length > 1 ? arr[1] : key;
6546        output[trim$3(key)] = trim$3(val);
6547        return output;
6548      }, {});
6549    };
6550    const isRegExp = x => is$4(x, RegExp);
6551    const option = name => editor => editor.options.get(name);
6552    const stringOrObjectProcessor = value => isString(value) || isObject(value);
6553    const bodyOptionProcessor = (editor, defaultValue = '') => value => {
6554      const valid = isString(value);
6555      if (valid) {
6556        if (value.indexOf('=') !== -1) {
6557          const bodyObj = getHash(value);
6558          return {
6559            value: get$a(bodyObj, editor.id).getOr(defaultValue),
6560            valid
6561          };
6562        } else {
6563          return {
6564            value,
6565            valid
6566          };
6567        }
6568      } else {
6569        return {
6570          valid: false,
6571          message: 'Must be a string.'
6572        };
6573      }
6574    };
6575    const register$7 = editor => {
6576      const registerOption = editor.options.register;
6577      registerOption('id', {
6578        processor: 'string',
6579        default: editor.id
6580      });
6581      registerOption('selector', { processor: 'string' });
6582      registerOption('target', { processor: 'object' });
6583      registerOption('suffix', { processor: 'string' });
6584      registerOption('cache_suffix', { processor: 'string' });
6585      registerOption('base_url', { processor: 'string' });
6586      registerOption('referrer_policy', {
6587        processor: 'string',
6588        default: ''
6589      });
6590      registerOption('language_load', {
6591        processor: 'boolean',
6592        default: true
6593      });
6594      registerOption('inline', {
6595        processor: 'boolean',
6596        default: false
6597      });
6598      registerOption('iframe_attrs', {
6599        processor: 'object',
6600        default: {}
6601      });
6602      registerOption('doctype', {
6603        processor: 'string',
6604        default: '<!DOCTYPE html>'
6605      });
6606      registerOption('document_base_url', {
6607        processor: 'string',
6608        default: editor.documentBaseUrl
6609      });
6610      registerOption('body_id', {
6611        processor: bodyOptionProcessor(editor, 'tinymce'),
6612        default: 'tinymce'
6613      });
6614      registerOption('body_class', {
6615        processor: bodyOptionProcessor(editor),
6616        default: ''
6617      });
6618      registerOption('content_security_policy', {
6619        processor: 'string',
6620        default: ''
6621      });
6622      registerOption('br_in_pre', {
6623        processor: 'boolean',
6624        default: true
6625      });
6626      registerOption('forced_root_block', {
6627        processor: value => {
6628          const valid = isString(value) && isNotEmpty(value);
6629          if (valid) {
6630            return {
6631              value,
6632              valid
6633            };
6634          } else {
6635            return {
6636              valid: false,
6637              message: 'Must be a non-empty string.'
6638            };
6639          }
6640        },
6641        default: 'p'
6642      });
6643      registerOption('forced_root_block_attrs', {
6644        processor: 'object',
6645        default: {}
6646      });
6647      registerOption('newline_behavior', {
6648        processor: value => {
6649          const valid = contains$2([
6650            'block',
6651            'linebreak',
6652            'invert',
6653            'default'
6654          ], value);
6655          return valid ? {
6656            value,
6657            valid
6658          } : {
6659            valid: false,
6660            message: 'Must be one of: block, linebreak, invert or default.'
6661          };
6662        },
6663        default: 'default'
6664      });
6665      registerOption('br_newline_selector', {
6666        processor: 'string',
6667        default: '.mce-toc h2,figcaption,caption'
6668      });
6669      registerOption('no_newline_selector', {
6670        processor: 'string',
6671        default: ''
6672      });
6673      registerOption('keep_styles', {
6674        processor: 'boolean',
6675        default: true
6676      });
6677      registerOption('end_container_on_empty_block', {
6678        processor: value => {
6679          if (isBoolean(value)) {
6680            return {
6681              valid: true,
6682              value
6683            };
6684          } else if (isString(value)) {
6685            return {
6686              valid: true,
6687              value
6688            };
6689          } else {
6690            return {
6691              valid: false,
6692              message: 'Must be boolean or a string'
6693            };
6694          }
6695        },
6696        default: 'blockquote'
6697      });
6698      registerOption('font_size_style_values', {
6699        processor: 'string',
6700        default: 'xx-small,x-small,small,medium,large,x-large,xx-large'
6701      });
6702      registerOption('font_size_legacy_values', {
6703        processor: 'string',
6704        default: 'xx-small,small,medium,large,x-large,xx-large,300%'
6705      });
6706      registerOption('font_size_classes', {
6707        processor: 'string',
6708        default: ''
6709      });
6710      registerOption('automatic_uploads', {
6711        processor: 'boolean',
6712        default: true
6713      });
6714      registerOption('images_reuse_filename', {
6715        processor: 'boolean',
6716        default: false
6717      });
6718      registerOption('images_replace_blob_uris', {
6719        processor: 'boolean',
6720        default: true
6721      });
6722      registerOption('icons', {
6723        processor: 'string',
6724        default: ''
6725      });
6726      registerOption('icons_url', {
6727        processor: 'string',
6728        default: ''
6729      });
6730      registerOption('images_upload_url', {
6731        processor: 'string',
6732        default: ''
6733      });
6734      registerOption('images_upload_base_path', {
6735        processor: 'string',
6736        default: ''
6737      });
6738      registerOption('images_upload_credentials', {
6739        processor: 'boolean',
6740        default: false
6741      });
6742      registerOption('images_upload_handler', { processor: 'function' });
6743      registerOption('language', {
6744        processor: 'string',
6745        default: 'en'
6746      });
6747      registerOption('language_url', {
6748        processor: 'string',
6749        default: ''
6750      });
6751      registerOption('entity_encoding', {
6752        processor: 'string',
6753        default: 'named'
6754      });
6755      registerOption('indent', {
6756        processor: 'boolean',
6757        default: true
6758      });
6759      registerOption('indent_before', {
6760        processor: 'string',
6761        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'
6762      });
6763      registerOption('indent_after', {
6764        processor: 'string',
6765        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'
6766      });
6767      registerOption('indent_use_margin', {
6768        processor: 'boolean',
6769        default: false
6770      });
6771      registerOption('indentation', {
6772        processor: 'string',
6773        default: '40px'
6774      });
6775      registerOption('content_css', {
6776        processor: value => {
6777          const valid = value === false || isString(value) || isArrayOf(value, isString);
6778          if (valid) {
6779            if (isString(value)) {
6780              return {
6781                value: map$3(value.split(','), trim$3),
6782                valid
6783              };
6784            } else if (isArray$1(value)) {
6785              return {
6786                value,
6787                valid
6788              };
6789            } else if (value === false) {
6790              return {
6791                value: [],
6792                valid
6793              };
6794            } else {
6795              return {
6796                value,
6797                valid
6798              };
6799            }
6800          } else {
6801            return {
6802              valid: false,
6803              message: 'Must be false, a string or an array of strings.'
6804            };
6805          }
6806        },
6807        default: isInline(editor) ? [] : ['default']
6808      });
6809      registerOption('content_style', { processor: 'string' });
6810      registerOption('content_css_cors', {
6811        processor: 'boolean',
6812        default: false
6813      });
6814      registerOption('font_css', {
6815        processor: value => {
6816          const valid = isString(value) || isArrayOf(value, isString);
6817          if (valid) {
6818            const newValue = isArray$1(value) ? value : map$3(value.split(','), trim$3);
6819            return {
6820              value: newValue,
6821              valid
6822            };
6823          } else {
6824            return {
6825              valid: false,
6826              message: 'Must be a string or an array of strings.'
6827            };
6828          }
6829        },
6830        default: []
6831      });
6832      registerOption('inline_boundaries', {
6833        processor: 'boolean',
6834        default: true
6835      });
6836      registerOption('inline_boundaries_selector', {
6837        processor: 'string',
6838        default: 'a[href],code,span.mce-annotation'
6839      });
6840      registerOption('object_resizing', {
6841        processor: value => {
6842          const valid = isBoolean(value) || isString(value);
6843          if (valid) {
6844            if (value === false || deviceDetection$1.isiPhone() || deviceDetection$1.isiPad()) {
6845              return {
6846                value: '',
6847                valid
6848              };
6849            } else {
6850              return {
6851                value: value === true ? 'table,img,figure.image,div,video,iframe' : value,
6852                valid
6853              };
6854            }
6855          } else {
6856            return {
6857              valid: false,
6858              message: 'Must be boolean or a string'
6859            };
6860          }
6861        },
6862        default: !isTouch
6863      });
6864      registerOption('resize_img_proportional', {
6865        processor: 'boolean',
6866        default: true
6867      });
6868      registerOption('event_root', { processor: 'object' });
6869      registerOption('service_message', { processor: 'string' });
6870      registerOption('theme', {
6871        processor: value => value === false || isString(value) || isFunction(value),
6872        default: 'silver'
6873      });
6874      registerOption('theme_url', { processor: 'string' });
6875      registerOption('formats', { processor: 'object' });
6876      registerOption('format_empty_lines', {
6877        processor: 'boolean',
6878        default: false
6879      });
6880      registerOption('format_noneditable_selector', {
6881        processor: 'string',
6882        default: ''
6883      });
6884      registerOption('preview_styles', {
6885        processor: value => {
6886          const valid = value === false || isString(value);
6887          if (valid) {
6888            return {
6889              value: value === false ? '' : value,
6890              valid
6891            };
6892          } else {
6893            return {
6894              valid: false,
6895              message: 'Must be false or a string'
6896            };
6897          }
6898        },
6899        default: 'font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow'
6900      });
6901      registerOption('custom_ui_selector', {
6902        processor: 'string',
6903        default: ''
6904      });
6905      registerOption('hidden_input', {
6906        processor: 'boolean',
6907        default: true
6908      });
6909      registerOption('submit_patch', {
6910        processor: 'boolean',
6911        default: true
6912      });
6913      registerOption('encoding', { processor: 'string' });
6914      registerOption('add_form_submit_trigger', {
6915        processor: 'boolean',
6916        default: true
6917      });
6918      registerOption('add_unload_trigger', {
6919        processor: 'boolean',
6920        default: true
6921      });
6922      registerOption('custom_undo_redo_levels', {
6923        processor: 'number',
6924        default: 0
6925      });
6926      registerOption('disable_nodechange', {
6927        processor: 'boolean',
6928        default: false
6929      });
6930      registerOption('readonly', {
6931        processor: 'boolean',
6932        default: false
6933      });
6934      registerOption('editable_root', {
6935        processor: 'boolean',
6936        default: true
6937      });
6938      registerOption('plugins', {
6939        processor: 'string[]',
6940        default: []
6941      });
6942      registerOption('external_plugins', { processor: 'object' });
6943      registerOption('forced_plugins', { processor: 'string[]' });
6944      registerOption('model', {
6945        processor: 'string',
6946        default: editor.hasPlugin('rtc') ? 'plugin' : 'dom'
6947      });
6948      registerOption('model_url', { processor: 'string' });
6949      registerOption('block_unsupported_drop', {
6950        processor: 'boolean',
6951        default: true
6952      });
6953      registerOption('visual', {
6954        processor: 'boolean',
6955        default: true
6956      });
6957      registerOption('visual_table_class', {
6958        processor: 'string',
6959        default: 'mce-item-table'
6960      });
6961      registerOption('visual_anchor_class', {
6962        processor: 'string',
6963        default: 'mce-item-anchor'
6964      });
6965      registerOption('iframe_aria_text', {
6966        processor: 'string',
6967        default: 'Rich Text Area. Press ALT-0 for help.'
6968      });
6969      registerOption('setup', { processor: 'function' });
6970      registerOption('init_instance_callback', { processor: 'function' });
6971      registerOption('url_converter', {
6972        processor: 'function',
6973        default: editor.convertURL
6974      });
6975      registerOption('url_converter_scope', {
6976        processor: 'object',
6977        default: editor
6978      });
6979      registerOption('urlconverter_callback', { processor: 'function' });
6980      registerOption('allow_conditional_comments', {
6981        processor: 'boolean',
6982        default: false
6983      });
6984      registerOption('allow_html_data_urls', {
6985        processor: 'boolean',
6986        default: false
6987      });
6988      registerOption('allow_svg_data_urls', { processor: 'boolean' });
6989      registerOption('allow_html_in_named_anchor', {
6990        processor: 'boolean',
6991        default: false
6992      });
6993      registerOption('allow_script_urls', {
6994        processor: 'boolean',
6995        default: false
6996      });
6997      registerOption('allow_unsafe_link_target', {
6998        processor: 'boolean',
6999        default: false
7000      });
7001      registerOption('convert_fonts_to_spans', {
7002        processor: 'boolean',
7003        default: true,
7004        deprecated: true
7005      });
7006      registerOption('fix_list_elements', {
7007        processor: 'boolean',
7008        default: false
7009      });
7010      registerOption('preserve_cdata', {
7011        processor: 'boolean',
7012        default: false
7013      });
7014      registerOption('remove_trailing_brs', {
7015        processor: 'boolean',
7016        default: true
7017      });
7018      registerOption('
7018pad_empty_with_br', {
7019        processor: 'boolean',
7020        default: fals
vendor: 209,358 bytes, lines 7020-12343
7020e
7021      });
7022      registerOption('inline_styles', {
7023        processor: 'boolean',
7024        default: true,
7025        deprecated: true
7026      });
7027      registerOption('element_format', {
7028        processor: 'string',
7029        default: 'html'
7030      });
7031      registerOption('entities', { processor: 'string' });
7032      registerOption('schema', {
7033        processor: 'string',
7034        default: 'html5'
7035      });
7036      registerOption('convert_urls', {
7037        processor: 'boolean',
7038        default: true
7039      });
7040      registerOption('relative_urls', {
7041        processor: 'boolean',
7042        default: true
7043      });
7044      registerOption('remove_script_host', {
7045        processor: 'boolean',
7046        default: true
7047      });
7048      registerOption('custom_elements', { processor: 'string' });
7049      registerOption('extended_valid_elements', { processor: 'string' });
7050      registerOption('invalid_elements', { processor: 'string' });
7051      registerOption('invalid_styles', { processor: stringOrObjectProcessor });
7052      registerOption('valid_children', { processor: 'string' });
7053      registerOption('valid_classes', { processor: stringOrObjectProcessor });
7054      registerOption('valid_elements', { processor: 'string' });
7055      registerOption('valid_styles', { processor: stringOrObjectProcessor });
7056      registerOption('verify_html', {
7057        processor: 'boolean',
7058        default: true
7059      });
7060      registerOption('auto_focus', { processor: value => isString(value) || value === true });
7061      registerOption('browser_spellcheck', {
7062        processor: 'boolean',
7063        default: false
7064      });
7065      registerOption('protect', { processor: 'array' });
7066      registerOption('images_file_types', {
7067        processor: 'string',
7068        default: 'jpeg,jpg,jpe,jfi,jif,jfif,png,gif,bmp,webp'
7069      });
7070      registerOption('deprecation_warnings', {
7071        processor: 'boolean',
7072        default: true
7073      });
7074      registerOption('a11y_advanced_options', {
7075        processor: 'boolean',
7076        default: false
7077      });
7078      registerOption('api_key', { processor: 'string' });
7079      registerOption('paste_block_drop', {
7080        processor: 'boolean',
7081        default: false
7082      });
7083      registerOption('paste_data_images', {
7084        processor: 'boolean',
7085        default: true
7086      });
7087      registerOption('paste_preprocess', { processor: 'function' });
7088      registerOption('paste_postprocess', { processor: 'function' });
7089      registerOption('paste_webkit_styles', {
7090        processor: 'string',
7091        default: 'none'
7092      });
7093      registerOption('paste_remove_styles_if_webkit', {
7094        processor: 'boolean',
7095        default: true
7096      });
7097      registerOption('paste_merge_formats', {
7098        processor: 'boolean',
7099        default: true
7100      });
7101      registerOption('smart_paste', {
7102        processor: 'boolean',
7103        default: true
7104      });
7105      registerOption('paste_as_text', {
7106        processor: 'boolean',
7107        default: false
7108      });
7109      registerOption('paste_tab_spaces', {
7110        processor: 'number',
7111        default: 4
7112      });
7113      registerOption('text_patterns', {
7114        processor: value => {
7115          if (isArrayOf(value, isObject) || value === false) {
7116            const patterns = value === false ? [] : value;
7117            return {
7118              value: fromRawPatterns(patterns),
7119              valid: true
7120            };
7121          } else {
7122            return {
7123              valid: false,
7124              message: 'Must be an array of objects or false.'
7125            };
7126          }
7127        },
7128        default: [
7129          {
7130            start: '*',
7131            end: '*',
7132            format: 'italic'
7133          },
7134          {
7135            start: '**',
7136            end: '**',
7137            format: 'bold'
7138          },
7139          {
7140            start: '#',
7141            format: 'h1'
7142          },
7143          {
7144            start: '##',
7145            format: 'h2'
7146          },
7147          {
7148            start: '###',
7149            format: 'h3'
7150          },
7151          {
7152            start: '####',
7153            format: 'h4'
7154          },
7155          {
7156            start: '#####',
7157            format: 'h5'
7158          },
7159          {
7160            start: '######',
7161            format: 'h6'
7162          },
7163          {
7164            start: '1. ',
7165            cmd: 'InsertOrderedList'
7166          },
7167          {
7168            start: '* ',
7169            cmd: 'InsertUnorderedList'
7170          },
7171          {
7172            start: '- ',
7173            cmd: 'InsertUnorderedList'
7174          }
7175        ]
7176      });
7177      registerOption('text_patterns_lookup', {
7178        processor: value => {
7179          if (isFunction(value)) {
7180            return {
7181              value: fromRawPatternsLookup(value),
7182              valid: true
7183            };
7184          } else {
7185            return {
7186              valid: false,
7187              message: 'Must be a single function'
7188            };
7189          }
7190        },
7191        default: _ctx => []
7192      });
7193      registerOption('noneditable_class', {
7194        processor: 'string',
7195        default: 'mceNonEditable'
7196      });
7197      registerOption('editable_class', {
7198        processor: 'string',
7199        default: 'mceEditable'
7200      });
7201      registerOption('noneditable_regexp', {
7202        processor: value => {
7203          if (isArrayOf(value, isRegExp)) {
7204            return {
7205              value,
7206              valid: true
7207            };
7208          } else if (isRegExp(value)) {
7209            return {
7210              value: [value],
7211              valid: true
7212            };
7213          } else {
7214            return {
7215              valid: false,
7216              message: 'Must be a RegExp or an array of RegExp.'
7217            };
7218          }
7219        },
7220        default: []
7221      });
7222      registerOption('table_tab_navigation', {
7223        processor: 'boolean',
7224        default: true
7225      });
7226      registerOption('highlight_on_focus', {
7227        processor: 'boolean',
7228        default: false
7229      });
7230      registerOption('xss_sanitization', {
7231        processor: 'boolean',
7232        default: true
7233      });
7234      registerOption('details_initial_state', {
7235        processor: value => {
7236          const valid = contains$2([
7237            'inherited',
7238            'collapsed',
7239            'expanded'
7240          ], value);
7241          return valid ? {
7242            value,
7243            valid
7244          } : {
7245            valid: false,
7246            message: 'Must be one of: inherited, collapsed, or expanded.'
7247          };
7248        },
7249        default: 'inherited'
7250      });
7251      registerOption('details_serialized_state', {
7252        processor: value => {
7253          const valid = contains$2([
7254            'inherited',
7255            'collapsed',
7256            'expanded'
7257          ], value);
7258          return valid ? {
7259            value,
7260            valid
7261          } : {
7262            valid: false,
7263            message: 'Must be one of: inherited, collapsed, or expanded.'
7264          };
7265        },
7266        default: 'inherited'
7267      });
7268      registerOption('init_content_sync', {
7269        processor: 'boolean',
7270        default: false
7271      });
7272      registerOption('newdocument_content', {
7273        processor: 'string',
7274        default: ''
7275      });
7276      editor.on('ScriptsLoaded', () => {
7277        registerOption('directionality', {
7278          processor: 'string',
7279          default: I18n.isRtl() ? 'rtl' : undefined
7280        });
7281        registerOption('placeholder', {
7282          processor: 'string',
7283          default: DOM$a.getAttrib(editor.getElement(), 'placeholder')
7284        });
7285      });
7286    };
7287    const getIframeAttrs = option('iframe_attrs');
7288    const getDocType = option('doctype');
7289    const getDocumentBaseUrl = option('document_base_url');
7290    const getBodyId = option('body_id');
7291    const getBodyClass = option('body_class');
7292    const getContentSecurityPolicy = option('content_security_policy');
7293    const shouldPutBrInPre$1 = option('br_in_pre');
7294    const getForcedRootBlock = option('forced_root_block');
7295    const getForcedRootBlockAttrs = option('forced_root_block_attrs');
7296    const getNewlineBehavior = option('newline_behavior');
7297    const getBrNewLineSelector = option('br_newline_selector');
7298    const getNoNewLineSelector = option('no_newline_selector');
7299    const shouldKeepStyles = option('keep_styles');
7300    const shouldEndContainerOnEmptyBlock = option('end_container_on_empty_block');
7301    const isAutomaticUploadsEnabled = option('automatic_uploads');
7302    const shouldReuseFileName = option('images_reuse_filename');
7303    const shouldReplaceBlobUris = option('images_replace_blob_uris');
7304    const getIconPackName = option('icons');
7305    const getIconsUrl = option('icons_url');
7306    const getImageUploadUrl = option('images_upload_url');
7307    const getImageUploadBasePath = option('images_upload_base_path');
7308    const getImagesUploadCredentials = option('images_upload_credentials');
7309    const getImagesUploadHandler = option('images_upload_handler');
7310    const shouldUseContentCssCors = option('content_css_cors');
7311    const getReferrerPolicy = option('referrer_policy');
7312    const getLanguageCode = option('language');
7313    const getLanguageUrl = option('language_url');
7314    const shouldIndentUseMargin = option('indent_use_margin');
7315    const getIndentation = option('indentation');
7316    const getContentCss = option('content_css');
7317    const getContentStyle = option('content_style');
7318    const getFontCss = option('font_css');
7319    const getDirectionality = option('directionality');
7320    const getInlineBoundarySelector = option('inline_boundaries_selector');
7321    const getObjectResizing = option('object_resizing');
7322    const getResizeImgProportional = option('resize_img_proportional');
7323    const getPlaceholder = option('placeholder');
7324    const getEventRoot = option('event_root');
7325    const getServiceMessage = option('service_message');
7326    const getTheme = option('theme');
7327    const getThemeUrl = option('theme_url');
7328    const getModel = option('model');
7329    const getModelUrl = option('model_url');
7330    const isInlineBoundariesEnabled = option('inline_boundaries');
7331    const getFormats = option('formats');
7332    const getPreviewStyles = option('preview_styles');
7333    const canFormatEmptyLines = option('format_empty_lines');
7334    const getFormatNoneditableSelector = option('format_noneditable_selector');
7335    const getCustomUiSelector = option('custom_ui_selector');
7336    const isInline = option('inline');
7337    const hasHiddenInput = option('hidden_input');
7338    const shouldPatchSubmit = option('submit_patch');
7339    const shouldAddFormSubmitTrigger = option('add_form_submit_trigger');
7340    const shouldAddUnloadTrigger = option('add_unload_trigger');
7341    const getCustomUndoRedoLevels = option('custom_undo_redo_levels');
7342    const shouldDisableNodeChange = option('disable_nodechange');
7343    const isReadOnly$1 = option('readonly');
7344    const hasEditableRoot$1 = option('editable_root');
7345    const hasContentCssCors = option('content_css_cors');
7346    const getPlugins = option('plugins');
7347    const getExternalPlugins$1 = option('external_plugins');
7348    const shouldBlockUnsupportedDrop = option('block_unsupported_drop');
7349    const isVisualAidsEnabled = option('visual');
7350    const getVisualAidsTableClass = option('visual_table_class');
7351    const getVisualAidsAnchorClass = option('visual_anchor_class');
7352    const getIframeAriaText = option('iframe_aria_text');
7353    const getSetupCallback = option('setup');
7354    const getInitInstanceCallback = option('init_instance_callback');
7355    const getUrlConverterCallback = option('urlconverter_callback');
7356    const getAutoFocus = option('auto_focus');
7357    const shouldBrowserSpellcheck = option('browser_spellcheck');
7358    const getProtect = option('protect');
7359    const shouldPasteBlockDrop = option('paste_block_drop');
7360    const shouldPasteDataImages = option('paste_data_images');
7361    const getPastePreProcess = option('paste_preprocess');
7362    const getPastePostProcess = option('paste_postprocess');
7363    const getNewDocumentContent = option('newdocument_content');
7364    const getPasteWebkitStyles = option('paste_webkit_styles');
7365    const shouldPasteRemoveWebKitStyles = option('paste_remove_styles_if_webkit');
7366    const shouldPasteMergeFormats = option('paste_merge_formats');
7367    const isSmartPasteEnabled = option('smart_paste');
7368    const isPasteAsTextEnabled = option('paste_as_text');
7369    const getPasteTabSpaces = option('paste_tab_spaces');
7370    const shouldAllowHtmlDataUrls = option('allow_html_data_urls');
7371    const getTextPatterns = option('text_patterns');
7372    const getTextPatternsLookup = option('text_patterns_lookup');
7373    const getNonEditableClass = option('noneditable_class');
7374    const getEditableClass = option('editable_class');
7375    const getNonEditableRegExps = option('noneditable_regexp');
7376    const shouldPreserveCData = option('preserve_cdata');
7377    const shouldHighlightOnFocus = option('highlight_on_focus');
7378    const shouldSanitizeXss = option('xss_sanitization');
7379    const shouldUseDocumentWrite = option('init_content_sync');
7380    const hasTextPatternsLookup = editor => editor.options.isSet('text_patterns_lookup');
7381    const getFontStyleValues = editor => Tools.explode(editor.options.get('font_size_style_values'));
7382    const getFontSizeClasses = editor => Tools.explode(editor.options.get('font_size_classes'));
7383    const isEncodingXml = editor => editor.options.get('encoding') === 'xml';
7384    const getAllowedImageFileTypes = editor => Tools.explode(editor.options.get('images_file_types'));
7385    const hasTableTabNavigation = option('table_tab_navigation');
7386    const getDetailsInitialState = option('details_initial_state');
7387    const getDetailsSerializedState = option('details_serialized_state');
7388
7389    const isElement$3 = isElement$6;
7390    const isText$5 = isText$a;
7391    const removeNode$1 = node => {
7392      const parentNode = node.parentNode;
7393      if (parentNode) {
7394        parentNode.removeChild(node);
7395      }
7396    };
7397    const trimCount = text => {
7398      const trimmedText = trim$1(text);
7399      return {
7400        count: text.length - trimmedText.length,
7401        text: trimmedText
7402      };
7403    };
7404    const deleteZwspChars = caretContainer => {
7405      let idx;
7406      while ((idx = caretContainer.data.lastIndexOf(ZWSP$1)) !== -1) {
7407        caretContainer.deleteData(idx, 1);
7408      }
7409    };
7410    const removeUnchanged = (caretContainer, pos) => {
7411      remove$3(caretContainer);
7412      return pos;
7413    };
7414    const removeTextAndReposition = (caretContainer, pos) => {
7415      const before = trimCount(caretContainer.data.substr(0, pos.offset()));
7416      const after = trimCount(caretContainer.data.substr(pos.offset()));
7417      const text = before.text + after.text;
7418      if (text.length > 0) {
7419        deleteZwspChars(caretContainer);
7420        return CaretPosition(caretContainer, pos.offset() - before.count);
7421      } else {
7422        return pos;
7423      }
7424    };
7425    const removeElementAndReposition = (caretContainer, pos) => {
7426      const parentNode = pos.container();
7427      const newPosition = indexOf$1(from(parentNode.childNodes), caretContainer).map(index => {
7428        return index < pos.offset() ? CaretPosition(parentNode, pos.offset() - 1) : pos;
7429      }).getOr(pos);
7430      remove$3(caretContainer);
7431      return newPosition;
7432    };
7433    const removeTextCaretContainer = (caretContainer, pos) => isText$5(caretContainer) && pos.container() === caretContainer ? removeTextAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
7434    const removeElementCaretContainer = (caretContainer, pos) => pos.container() === caretContainer.parentNode ? removeElementAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
7435    const removeAndReposition = (container, pos) => CaretPosition.isTextPosition(pos) ? removeTextCaretContainer(container, pos) : removeElementCaretContainer(container, pos);
7436    const remove$3 = caretContainerNode => {
7437      if (isElement$3(caretContainerNode) && isCaretContainer$2(caretContainerNode)) {
7438        if (hasContent(caretContainerNode)) {
7439          caretContainerNode.removeAttribute('data-mce-caret');
7440        } else {
7441          removeNode$1(caretContainerNode);
7442        }
7443      }
7444      if (isText$5(caretContainerNode)) {
7445        deleteZwspChars(caretContainerNode);
7446        if (caretContainerNode.data.length === 0) {
7447          removeNode$1(caretContainerNode);
7448        }
7449      }
7450    };
7451
7452    const isContentEditableFalse$8 = isContentEditableFalse$b;
7453    const isMedia$1 = isMedia$2;
7454    const isTableCell$1 = isTableCell$3;
7455    const inlineFakeCaretSelector = '*[contentEditable=false],video,audio,embed,object';
7456    const getAbsoluteClientRect = (root, element, before) => {
7457      const clientRect = collapse(element.getBoundingClientRect(), before);
7458      let scrollX;
7459      let scrollY;
7460      if (root.tagName === 'BODY') {
7461        const docElm = root.ownerDocument.documentElement;
7462        scrollX = root.scrollLeft || docElm.scrollLeft;
7463        scrollY = root.scrollTop || docElm.scrollTop;
7464      } else {
7465        const rootRect = root.getBoundingClientRect();
7466        scrollX = root.scrollLeft - rootRect.left;
7467        scrollY = root.scrollTop - rootRect.top;
7468      }
7469      clientRect.left += scrollX;
7470      clientRect.right += scrollX;
7471      clientRect.top += scrollY;
7472      clientRect.bottom += scrollY;
7473      clientRect.width = 1;
7474      let margin = element.offsetWidth - element.clientWidth;
7475      if (margin > 0) {
7476        if (before) {
7477          margin *= -1;
7478        }
7479        clientRect.left += margin;
7480        clientRect.right += margin;
7481      }
7482      return clientRect;
7483    };
7484    const trimInlineCaretContainers = root => {
7485      var _a, _b;
7486      const fakeCaretTargetNodes = descendants(SugarElement.fromDom(root), inlineFakeCaretSelector);
7487      for (let i = 0; i < fakeCaretTargetNodes.length; i++) {
7488        const node = fakeCaretTargetNodes[i].dom;
7489        let sibling = node.previousSibling;
7490        if (endsWithCaretContainer$1(sibling)) {
7491          const data = sibling.data;
7492          if (data.length === 1) {
7493            (_a = sibling.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(sibling);
7494          } else {
7495            sibling.deleteData(data.length - 1, 1);
7496          }
7497        }
7498        sibling = node.nextSibling;
7499        if (startsWithCaretContainer$1(sibling)) {
7500          const data = sibling.data;
7501          if (data.length === 1) {
7502            (_b = sibling.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(sibling);
7503          } else {
7504            sibling.deleteData(0, 1);
7505          }
7506        }
7507      }
7508    };
7509    const FakeCaret = (editor, root, isBlock, hasFocus) => {
7510      const lastVisualCaret = value$2();
7511      let cursorInterval;
7512      let caretContainerNode;
7513      const caretBlock = getForcedRootBlock(editor);
7514      const dom = editor.dom;
7515      const show = (before, element) => {
7516        let rng;
7517        hide();
7518        if (isTableCell$1(element)) {
7519          return null;
7520        }
7521        if (isBlock(element)) {
7522          const caretContainer = insertBlock(caretBlock, element, before);
7523          const clientRect = getAbsoluteClientRect(root, element, before);
7524          dom.setStyle(caretContainer, 'top', clientRect.top);
7525          caretContainerNode = caretContainer;
7526          const caret = dom.create('div', {
7527            'class': 'mce-visual-caret',
7528            'data-mce-bogus': 'all'
7529          });
7530          dom.setStyles(caret, { ...clientRect });
7531          dom.add(root, caret);
7532          lastVisualCaret.set({
7533            caret,
7534            element,
7535            before
7536          });
7537          if (before) {
7538            dom.addClass(caret, 'mce-visual-caret-before');
7539          }
7540          startBlink();
7541          rng = element.ownerDocument.createRange();
7542          rng.setStart(caretContainer, 0);
7543          rng.setEnd(caretContainer, 0);
7544        } else {
7545          caretContainerNode = insertInline$1(element, before);
7546          rng = element.ownerDocument.createRange();
7547          if (isInlineFakeCaretTarget(caretContainerNode.nextSibling)) {
7548            rng.setStart(caretContainerNode, 0);
7549            rng.setEnd(caretContainerNode, 0);
7550          } else {
7551            rng.setStart(caretContainerNode, 1);
7552            rng.setEnd(caretContainerNode, 1);
7553          }
7554          return rng;
7555        }
7556        return rng;
7557      };
7558      const hide = () => {
7559        trimInlineCaretContainers(root);
7560        if (caretContainerNode) {
7561          remove$3(caretContainerNode);
7562          caretContainerNode = null;
7563        }
7564        lastVisualCaret.on(caretState => {
7565          dom.remove(caretState.caret);
7566          lastVisualCaret.clear();
7567        });
7568        if (cursorInterval) {
7569          clearInterval(cursorInterval);
7570          cursorInterval = undefined;
7571        }
7572      };
7573      const startBlink = () => {
7574        cursorInterval = setInterval(() => {
7575          lastVisualCaret.on(caretState => {
7576            if (hasFocus()) {
7577              dom.toggleClass(caretState.caret, 'mce-visual-caret-hidden');
7578            } else {
7579              dom.addClass(caretState.caret, 'mce-visual-caret-hidden');
7580            }
7581          });
7582        }, 500);
7583      };
7584      const reposition = () => {
7585        lastVisualCaret.on(caretState => {
7586          const clientRect = getAbsoluteClientRect(root, caretState.element, caretState.before);
7587          dom.setStyles(caretState.caret, { ...clientRect });
7588        });
7589      };
7590      const destroy = () => clearInterval(cursorInterval);
7591      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;' + '}';
7592      return {
7593        show,
7594        hide,
7595        getCss,
7596        reposition,
7597        destroy
7598      };
7599    };
7600    const isFakeCaretTableBrowser = () => Env.browser.isFirefox();
7601    const isInlineFakeCaretTarget = node => isContentEditableFalse$8(node) || isMedia$1(node);
7602    const isFakeCaretTarget = node => {
7603      const isTarget = isInlineFakeCaretTarget(node) || isTable$2(node) && isFakeCaretTableBrowser();
7604      return isTarget && parentElement(SugarElement.fromDom(node)).exists(isEditable$3);
7605    };
7606
7607    const isContentEditableTrue$1 = isContentEditableTrue$3;
7608    const isContentEditableFalse$7 = isContentEditableFalse$b;
7609    const isMedia = isMedia$2;
7610    const isBlockLike = matchStyleValues('display', 'block table table-cell table-caption list-item');
7611    const isCaretContainer = isCaretContainer$2;
7612    const isCaretContainerBlock = isCaretContainerBlock$1;
7613    const isElement$2 = isElement$6;
7614    const isText$4 = isText$a;
7615    const isCaretCandidate$1 = isCaretCandidate$3;
7616    const isForwards = direction => direction > 0;
7617    const isBackwards = direction => direction < 0;
7618    const skipCaretContainers = (walk, shallow) => {
7619      let node;
7620      while (node = walk(shallow)) {
7621        if (!isCaretContainerBlock(node)) {
7622          return node;
7623        }
7624      }
7625      return null;
7626    };
7627    const findNode = (node, direction, predicateFn, rootNode, shallow) => {
7628      const walker = new DomTreeWalker(node, rootNode);
7629      const isCefOrCaretContainer = isContentEditableFalse$7(node) || isCaretContainerBlock(node);
7630      let tempNode;
7631      if (isBackwards(direction)) {
7632        if (isCefOrCaretContainer) {
7633          tempNode = skipCaretContainers(walker.prev.bind(walker), true);
7634          if (predicateFn(tempNode)) {
7635            return tempNode;
7636          }
7637        }
7638        while (tempNode = skipCaretContainers(walker.prev.bind(walker), shallow)) {
7639          if (predicateFn(tempNode)) {
7640            return tempNode;
7641          }
7642        }
7643      }
7644      if (isForwards(direction)) {
7645        if (isCefOrCaretContainer) {
7646          tempNode = skipCaretContainers(walker.next.bind(walker), true);
7647          if (predicateFn(tempNode)) {
7648            return tempNode;
7649          }
7650        }
7651        while (tempNode = skipCaretContainers(walker.next.bind(walker), shallow)) {
7652          if (predicateFn(tempNode)) {
7653            return tempNode;
7654          }
7655        }
7656      }
7657      return null;
7658    };
7659    const getEditingHost = (node, rootNode) => {
7660      const isCETrue = node => isContentEditableTrue$1(node.dom);
7661      const isRoot = node => node.dom === rootNode;
7662      return ancestor$4(SugarElement.fromDom(node), isCETrue, isRoot).map(elm => elm.dom).getOr(rootNode);
7663    };
7664    const getParentBlock$3 = (node, rootNode) => {
7665      while (node && node !== rootNode) {
7666        if (isBlockLike(node)) {
7667          return node;
7668        }
7669        node = node.parentNode;
7670      }
7671      return null;
7672    };
7673    const isInSameBlock = (caretPosition1, caretPosition2, rootNode) => getParentBlock$3(caretPosition1.container(), rootNode) === getParentBlock$3(caretPosition2.container(), rootNode);
7674    const getChildNodeAtRelativeOffset = (relativeOffset, caretPosition) => {
7675      if (!caretPosition) {
7676        return Optional.none();
7677      }
7678      const container = caretPosition.container();
7679      const offset = caretPosition.offset();
7680      if (!isElement$2(container)) {
7681        return Optional.none();
7682      }
7683      return Optional.from(container.childNodes[offset + relativeOffset]);
7684    };
7685    const beforeAfter = (before, node) => {
7686      var _a;
7687      const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
7688      const range = doc.createRange();
7689      if (before) {
7690        range.setStartBefore(node);
7691        range.setEndBefore(node);
7692      } else {
7693        range.setStartAfter(node);
7694        range.setEndAfter(node);
7695      }
7696      return range;
7697    };
7698    const isNodesInSameBlock = (root, node1, node2) => getParentBlock$3(node1, root) === getParentBlock$3(node2, root);
7699    const lean = (left, root, node) => {
7700      const siblingName = left ? 'previousSibling' : 'nextSibling';
7701      let tempNode = node;
7702      while (tempNode && tempNode !== root) {
7703        let sibling = tempNode[siblingName];
7704        if (sibling && isCaretContainer(sibling)) {
7705          sibling = sibling[siblingName];
7706        }
7707        if (isContentEditableFalse$7(sibling) || isMedia(sibling)) {
7708          if (isNodesInSameBlock(root, sibling, tempNode)) {
7709            return sibling;
7710          }
7711          break;
7712        }
7713        if (isCaretCandidate$1(sibling)) {
7714          break;
7715        }
7716        tempNode = tempNode.parentNode;
7717      }
7718      return null;
7719    };
7720    const before$2 = curry(beforeAfter, true);
7721    const after$2 = curry(beforeAfter, false);
7722    const normalizeRange = (direction, root, range) => {
7723      let node;
7724      const leanLeft = curry(lean, true, root);
7725      const leanRight = curry(lean, false, root);
7726      const container = range.startContainer;
7727      const offset = range.startOffset;
7728      if (isCaretContainerBlock$1(container)) {
7729        const block = isText$4(container) ? container.parentNode : container;
7730        const location = block.getAttribute('data-mce-caret');
7731        if (location === 'before') {
7732          node = block.nextSibling;
7733          if (isFakeCaretTarget(node)) {
7734            return before$2(node);
7735          }
7736        }
7737        if (location === 'after') {
7738          node = block.previousSibling;
7739          if (isFakeCaretTarget(node)) {
7740            return after$2(node);
7741          }
7742        }
7743      }
7744      if (!range.collapsed) {
7745        return range;
7746      }
7747      if (isText$a(container)) {
7748        if (isCaretContainer(container)) {
7749          if (direction === 1) {
7750            node = leanRight(container);
7751            if (node) {
7752              return before$2(node);
7753            }
7754            node = leanLeft(container);
7755            if (node) {
7756              return after$2(node);
7757            }
7758          }
7759          if (direction === -1) {
7760            node = leanLeft(container);
7761            if (node) {
7762              return after$2(node);
7763            }
7764            node = leanRight(container);
7765            if (node) {
7766              return before$2(node);
7767            }
7768          }
7769          return range;
7770        }
7771        if (endsWithCaretContainer$1(container) && offset >= container.data.length - 1) {
7772          if (direction === 1) {
7773            node = leanRight(container);
7774            if (node) {
7775              return before$2(node);
7776            }
7777          }
7778          return range;
7779        }
7780        if (startsWithCaretContainer$1(container) && offset <= 1) {
7781          if (direction === -1) {
7782            node = leanLeft(container);
7783            if (node) {
7784              return after$2(node);
7785            }
7786          }
7787          return range;
7788        }
7789        if (offset === container.data.length) {
7790          node = leanRight(container);
7791          if (node) {
7792            return before$2(node);
7793          }
7794          return range;
7795        }
7796        if (offset === 0) {
7797          node = leanLeft(container);
7798          if (node) {
7799            return after$2(node);
7800          }
7801          return range;
7802        }
7803      }
7804      return range;
7805    };
7806    const getRelativeCefElm = (forward, caretPosition) => getChildNodeAtRelativeOffset(forward ? 0 : -1, caretPosition).filter(isContentEditableFalse$7);
7807    const getNormalizedRangeEndPoint = (direction, root, range) => {
7808      const normalizedRange = normalizeRange(direction, root, range);
7809      return direction === -1 ? CaretPosition.fromRangeStart(normalizedRange) : CaretPosition.fromRangeEnd(normalizedRange);
7810    };
7811    const getElementFromPosition = pos => Optional.from(pos.getNode()).map(SugarElement.fromDom);
7812    const getElementFromPrevPosition = pos => Optional.from(pos.getNode(true)).map(SugarElement.fromDom);
7813    const getVisualCaretPosition = (walkFn, caretPosition) => {
7814      let pos = caretPosition;
7815      while (pos = walkFn(pos)) {
7816        if (pos.isVisible()) {
7817          return pos;
7818        }
7819      }
7820      return pos;
7821    };
7822    const isMoveInsideSameBlock = (from, to) => {
7823      const inSameBlock = isInSameBlock(from, to);
7824      if (!inSameBlock && isBr$6(from.getNode())) {
7825        return true;
7826      }
7827      return inSameBlock;
7828    };
7829
7830    var HDirection;
7831    (function (HDirection) {
7832      HDirection[HDirection['Backwards'] = -1] = 'Backwards';
7833      HDirection[HDirection['Forwards'] = 1] = 'Forwards';
7834    }(HDirection || (HDirection = {})));
7835    const isContentEditableFalse$6 = isContentEditableFalse$b;
7836    const isText$3 = isText$a;
7837    const isElement$1 = isElement$6;
7838    const isBr$2 = isBr$6;
7839    const isCaretCandidate = isCaretCandidate$3;
7840    const isAtomic = isAtomic$1;
7841    const isEditableCaretCandidate = isEditableCaretCandidate$1;
7842    const getParents$3 = (node, root) => {
7843      const parents = [];
7844      let tempNode = node;
7845      while (tempNode && tempNode !== root) {
7846        parents.push(tempNode);
7847        tempNode = tempNode.parentNode;
7848      }
7849      return parents;
7850    };
7851    const nodeAtIndex = (container, offset) => {
7852      if (container.hasChildNodes() && offset < container.childNodes.length) {
7853        return container.childNodes[offset];
7854      }
7855      return null;
7856    };
7857    const getCaretCandidatePosition = (direction, node) => {
7858      if (isForwards(direction)) {
7859        if (isCaretCandidate(node.previousSibling) && !isText$3(node.previousSibling)) {
7860          return CaretPosition.before(node);
7861        }
7862        if (isText$3(node)) {
7863          return CaretPosition(node, 0);
7864        }
7865      }
7866      if (isBackwards(direction)) {
7867        if (isCaretCandidate(node.nextSibling) && !isText$3(node.nextSibling)) {
7868          return CaretPosition.after(node);
7869        }
7870        if (isText$3(node)) {
7871          return CaretPosition(node, node.data.length);
7872        }
7873      }
7874      if (isBackwards(direction)) {
7875        if (isBr$2(node)) {
7876          return CaretPosition.before(node);
7877        }
7878        return CaretPosition.after(node);
7879      }
7880      return CaretPosition.before(node);
7881    };
7882    const moveForwardFromBr = (root, nextNode) => {
7883      const nextSibling = nextNode.nextSibling;
7884      if (nextSibling && isCaretCandidate(nextSibling)) {
7885        if (isText$3(nextSibling)) {
7886          return CaretPosition(nextSibling, 0);
7887        } else {
7888          return CaretPosition.before(nextSibling);
7889        }
7890      } else {
7891        return findCaretPosition$1(HDirection.Forwards, CaretPosition.after(nextNode), root);
7892      }
7893    };
7894    const findCaretPosition$1 = (direction, startPos, root) => {
7895      let node;
7896      let nextNode;
7897      let innerNode;
7898      let caretPosition;
7899      if (!isElement$1(root) || !startPos) {
7900        return null;
7901      }
7902      if (startPos.isEqual(CaretPosition.after(root)) && root.lastChild) {
7903        caretPosition = CaretPosition.after(root.lastChild);
7904        if (isBackwards(direction) && isCaretCandidate(root.lastChild) && isElement$1(root.lastChild)) {
7905          return isBr$2(root.lastChild) ? CaretPosition.before(root.lastChild) : caretPosition;
7906        }
7907      } else {
7908        caretPosition = startPos;
7909      }
7910      const container = caretPosition.container();
7911      let offset = caretPosition.offset();
7912      if (isText$3(container)) {
7913        if (isBackwards(direction) && offset > 0) {
7914          return CaretPosition(container, --offset);
7915        }
7916        if (isForwards(direction) && offset < container.length) {
7917          return CaretPosition(container, ++offset);
7918        }
7919        node = container;
7920      } else {
7921        if (isBackwards(direction) && offset > 0) {
7922          nextNode = nodeAtIndex(container, offset - 1);
7923          if (isCaretCandidate(nextNode)) {
7924            if (!isAtomic(nextNode)) {
7925              innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
7926              if (innerNode) {
7927                if (isText$3(innerNode)) {
7928                  return CaretPosition(innerNode, innerNode.data.length);
7929                }
7930                return CaretPosition.after(innerNode);
7931              }
7932            }
7933            if (isText$3(nextNode)) {
7934              return CaretPosition(nextNode, nextNode.data.length);
7935            }
7936            return CaretPosition.before(nextNode);
7937          }
7938        }
7939        if (isForwards(direction) && offset < container.childNodes.length) {
7940          nextNode = nodeAtIndex(container, offset);
7941          if (isCaretCandidate(nextNode)) {
7942            if (isBr$2(nextNode)) {
7943              return moveForwardFromBr(root, nextNode);
7944            }
7945            if (!isAtomic(nextNode)) {
7946              innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
7947              if (innerNode) {
7948                if (isText$3(innerNode)) {
7949                  return CaretPosition(innerNode, 0);
7950                }
7951                return CaretPosition.before(innerNode);
7952              }
7953            }
7954            if (isText$3(nextNode)) {
7955              return CaretPosition(nextNode, 0);
7956            }
7957            return CaretPosition.after(nextNode);
7958          }
7959        }
7960        node = nextNode ? nextNode : caretPosition.getNode();
7961      }
7962      if (node && (isForwards(direction) && caretPosition.isAtEnd() || isBackwards(direction) && caretPosition.isAtStart())) {
7963        node = findNode(node, direction, always, root, true);
7964        if (isEditableCaretCandidate(node, root)) {
7965          return getCaretCandidatePosition(direction, node);
7966        }
7967      }
7968      nextNode = node ? findNode(node, direction, isEditableCaretCandidate, root) : node;
7969      const rootContentEditableFalseElm = last$2(filter$5(getParents$3(container, root), isContentEditableFalse$6));
7970      if (rootContentEditableFalseElm && (!nextNode || !rootContentEditableFalseElm.contains(nextNode))) {
7971        if (isForwards(direction)) {
7972          caretPosition = CaretPosition.after(rootContentEditableFalseElm);
7973        } else {
7974          caretPosition = CaretPosition.before(rootContentEditableFalseElm);
7975        }
7976        return caretPosition;
7977      }
7978      if (nextNode) {
7979        return getCaretCandidatePosition(direction, nextNode);
7980      }
7981      return null;
7982    };
7983    const CaretWalker = root => ({
7984      next: caretPosition => {
7985        return findCaretPosition$1(HDirection.Forwards, caretPosition, root);
7986      },
7987      prev: caretPosition => {
7988        return findCaretPosition$1(HDirection.Backwards, caretPosition, root);
7989      }
7990    });
7991
7992    const walkToPositionIn = (forward, root, start) => {
7993      const position = forward ? CaretPosition.before(start) : CaretPosition.after(start);
7994      return fromPosition(forward, root, position);
7995    };
7996    const afterElement = node => isBr$6(node) ? CaretPosition.before(node) : CaretPosition.after(node);
7997    const isBeforeOrStart = position => {
7998      if (CaretPosition.isTextPosition(position)) {
7999        return position.offset() === 0;
8000      } else {
8001        return isCaretCandidate$3(position.getNode());
8002      }
8003    };
8004    const isAfterOrEnd = position => {
8005      if (CaretPosition.isTextPosition(position)) {
8006        const container = position.container();
8007        return position.offset() === container.data.length;
8008      } else {
8009        return isCaretCandidate$3(position.getNode(true));
8010      }
8011    };
8012    const isBeforeAfterSameElement = (from, to) => !CaretPosition.isTextPosition(from) && !CaretPosition.isTextPosition(to) && from.getNode() === to.getNode(true);
8013    const isAtBr = position => !CaretPosition.isTextPosition(position) && isBr$6(position.getNode());
8014    const shouldSkipPosition = (forward, from, to) => {
8015      if (forward) {
8016        return !isBeforeAfterSameElement(from, to) && !isAtBr(from) && isAfterOrEnd(from) && isBeforeOrStart(to);
8017      } else {
8018        return !isBeforeAfterSameElement(to, from) && isBeforeOrStart(from) && isAfterOrEnd(to);
8019      }
8020    };
8021    const fromPosition = (forward, root, pos) => {
8022      const walker = CaretWalker(root);
8023      return Optional.from(forward ? walker.next(pos) : walker.prev(pos));
8024    };
8025    const navigate = (forward, root, from) => fromPosition(forward, root, from).bind(to => {
8026      if (isInSameBlock(from, to, root) && shouldSkipPosition(forward, from, to)) {
8027        return fromPosition(forward, root, to);
8028      } else {
8029        return Optional.some(to);
8030      }
8031    });
8032    const navigateIgnore = (forward, root, from, ignoreFilter) => navigate(forward, root, from).bind(pos => ignoreFilter(pos) ? navigateIgnore(forward, root, pos, ignoreFilter) : Optional.some(pos));
8033    const positionIn = (forward, element) => {
8034      const startNode = forward ? element.firstChild : element.lastChild;
8035      if (isText$a(startNode)) {
8036        return Optional.some(CaretPosition(startNode, forward ? 0 : startNode.data.length));
8037      } else if (startNode) {
8038        if (isCaretCandidate$3(startNode)) {
8039          return Optional.some(forward ? CaretPosition.before(startNode) : afterElement(startNode));
8040        } else {
8041          return walkToPositionIn(forward, element, startNode);
8042        }
8043      } else {
8044        return Optional.none();
8045      }
8046    };
8047    const nextPosition = curry(fromPosition, true);
8048    const prevPosition = curry(fromPosition, false);
8049    const firstPositionIn = curry(positionIn, true);
8050    const lastPositionIn = curry(positionIn, false);
8051
8052    const CARET_ID = '_mce_caret';
8053    const isCaretNode = node => isElement$6(node) && node.id === CARET_ID;
8054    const getParentCaretContainer = (body, node) => {
8055      let currentNode = node;
8056      while (currentNode && currentNode !== body) {
8057        if (isCaretNode(currentNode)) {
8058          return currentNode;
8059        }
8060        currentNode = currentNode.parentNode;
8061      }
8062      return null;
8063    };
8064
8065    const isStringPathBookmark = bookmark => isString(bookmark.start);
8066    const isRangeBookmark = bookmark => has$2(bookmark, 'rng');
8067    const isIdBookmark = bookmark => has$2(bookmark, 'id');
8068    const isIndexBookmark = bookmark => has$2(bookmark, 'name');
8069    const isPathBookmark = bookmark => Tools.isArray(bookmark.start);
8070
8071    const isForwardBookmark = bookmark => !isIndexBookmark(bookmark) && isBoolean(bookmark.forward) ? bookmark.forward : true;
8072    const addBogus = (dom, node) => {
8073      if (isElement$6(node) && dom.isBlock(node) && !node.innerHTML) {
8074        node.innerHTML = '<br data-mce-bogus="1" />';
8075      }
8076      return node;
8077    };
8078    const resolveCaretPositionBookmark = (dom, bookmark) => {
8079      const startPos = Optional.from(resolve$1(dom.getRoot(), bookmark.start));
8080      const endPos = Optional.from(resolve$1(dom.getRoot(), bookmark.end));
8081      return lift2(startPos, endPos, (start, end) => {
8082        const range = dom.createRng();
8083        range.setStart(start.container(), start.offset());
8084        range.setEnd(end.container(), end.offset());
8085        return {
8086          range,
8087          forward: isForwardBookmark(bookmark)
8088        };
8089      });
8090    };
8091    const insertZwsp = (node, rng) => {
8092      var _a;
8093      const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
8094      const textNode = doc.createTextNode(ZWSP$1);
8095      node.appendChild(textNode);
8096      rng.setStart(textNode, 0);
8097      rng.setEnd(textNode, 0);
8098    };
8099    const isEmpty$1 = node => !node.hasChildNodes();
8100    const tryFindRangePosition = (node, rng) => lastPositionIn(node).fold(never, pos => {
8101      rng.setStart(pos.container(), pos.offset());
8102      rng.setEnd(pos.container(), pos.offset());
8103      return true;
8104    });
8105    const padEmptyCaretContainer = (root, node, rng) => {
8106      if (isEmpty$1(node) && getParentCaretContainer(root, node)) {
8107        insertZwsp(node, rng);
8108        return true;
8109      } else {
8110        return false;
8111      }
8112    };
8113    const setEndPoint = (dom, start, bookmark, rng) => {
8114      const point = bookmark[start ? 'start' : 'end'];
8115      const root = dom.getRoot();
8116      if (point) {
8117        let node = root;
8118        let offset = point[0];
8119        for (let i = point.length - 1; node && i >= 1; i--) {
8120          const children = node.childNodes;
8121          if (padEmptyCaretContainer(root, node, rng)) {
8122            return true;
8123          }
8124          if (point[i] > children.length - 1) {
8125            if (padEmptyCaretContainer(root, node, rng)) {
8126              return true;
8127            }
8128            return tryFindRangePosition(node, rng);
8129          }
8130          node = children[point[i]];
8131        }
8132        if (isText$a(node)) {
8133          offset = Math.min(point[0], node.data.length);
8134        }
8135        if (isElement$6(node)) {
8136          offset = Math.min(point[0], node.childNodes.length);
8137        }
8138        if (start) {
8139          rng.setStart(node, offset);
8140        } else {
8141          rng.setEnd(node, offset);
8142        }
8143      }
8144      return true;
8145    };
8146    const isValidTextNode = node => isText$a(node) && node.data.length > 0;
8147    const restoreEndPoint = (dom, suffix, bookmark) => {
8148      const marker = dom.get(bookmark.id + '_' + suffix);
8149      const markerParent = marker === null || marker === void 0 ? void 0 : marker.parentNode;
8150      const keep = bookmark.keep;
8151      if (marker && markerParent) {
8152        let container;
8153        let offset;
8154        if (suffix === 'start') {
8155          if (!keep) {
8156            container = markerParent;
8157            offset = dom.nodeIndex(marker);
8158          } else {
8159            if (marker.hasChildNodes()) {
8160              container = marker.firstChild;
8161              offset = 1;
8162            } else if (isValidTextNode(marker.nextSibling)) {
8163              container = marker.nextSibling;
8164              offset = 0;
8165            } else if (isValidTextNode(marker.previousSibling)) {
8166              container = marker.previousSibling;
8167              offset = marker.previousSibling.data.length;
8168            } else {
8169              container = markerParent;
8170              offset = dom.nodeIndex(marker) + 1;
8171            }
8172          }
8173        } else {
8174          if (!keep) {
8175            container = markerParent;
8176            offset = dom.nodeIndex(marker);
8177          } else {
8178            if (marker.hasChildNodes()) {
8179              container = marker.firstChild;
8180              offset = 1;
8181            } else if (isValidTextNode(marker.previousSibling)) {
8182              container = marker.previousSibling;
8183              offset = marker.previousSibling.data.length;
8184            } else {
8185              container = markerParent;
8186              offset = dom.nodeIndex(marker);
8187            }
8188          }
8189        }
8190        if (!keep) {
8191          const prev = marker.previousSibling;
8192          const next = marker.nextSibling;
8193          Tools.each(Tools.grep(marker.childNodes), node => {
8194            if (isText$a(node)) {
8195              node.data = node.data.replace(/\uFEFF/g, '');
8196            }
8197          });
8198          let otherMarker;
8199          while (otherMarker = dom.get(bookmark.id + '_' + suffix)) {
8200            dom.remove(otherMarker, true);
8201          }
8202          if (isText$a(next) && isText$a(prev) && !Env.browser.isOpera()) {
8203            const idx = prev.data.length;
8204            prev.appendData(next.data);
8205            dom.remove(next);
8206            container = prev;
8207            offset = idx;
8208          }
8209        }
8210        return Optional.some(CaretPosition(container, offset));
8211      } else {
8212        return Optional.none();
8213      }
8214    };
8215    const resolvePaths = (dom, bookmark) => {
8216      const range = dom.createRng();
8217      if (setEndPoint(dom, true, bookmark, range) && setEndPoint(dom, false, bookmark, range)) {
8218        return Optional.some({
8219          range,
8220          forward: isForwardBookmark(bookmark)
8221        });
8222      } else {
8223        return Optional.none();
8224      }
8225    };
8226    const resolveId = (dom, bookmark) => {
8227      const startPos = restoreEndPoint(dom, 'start', bookmark);
8228      const endPos = restoreEndPoint(dom, 'end', bookmark);
8229      return lift2(startPos, endPos.or(startPos), (spos, epos) => {
8230        const range = dom.createRng();
8231        range.setStart(addBogus(dom, spos.container()), spos.offset());
8232        range.setEnd(addBogus(dom, epos.container()), epos.offset());
8233        return {
8234          range,
8235          forward: isForwardBookmark(bookmark)
8236        };
8237      });
8238    };
8239    const resolveIndex = (dom, bookmark) => Optional.from(dom.select(bookmark.name)[bookmark.index]).map(elm => {
8240      const range = dom.createRng();
8241      range.selectNode(elm);
8242      return {
8243        range,
8244        forward: true
8245      };
8246    });
8247    const resolve = (selection, bookmark) => {
8248      const dom = selection.dom;
8249      if (bookmark) {
8250        if (isPathBookmark(bookmark)) {
8251          return resolvePaths(dom, bookmark);
8252        } else if (isStringPathBookmark(bookmark)) {
8253          return resolveCaretPositionBookmark(dom, bookmark);
8254        } else if (isIdBookmark(bookmark)) {
8255          return resolveId(dom, bookmark);
8256        } else if (isIndexBookmark(bookmark)) {
8257          return resolveIndex(dom, bookmark);
8258        } else if (isRangeBookmark(bookmark)) {
8259          return Optional.some({
8260            range: bookmark.rng,
8261            forward: isForwardBookmark(bookmark)
8262          });
8263        }
8264      }
8265      return Optional.none();
8266    };
8267
8268    const getBookmark$1 = (selection, type, normalized) => {
8269      return getBookmark$2(selection, type, normalized);
8270    };
8271    const moveToBookmark = (selection, bookmark) => {
8272      resolve(selection, bookmark).each(({range, forward}) => {
8273        selection.setRng(range, forward);
8274      });
8275    };
8276    const isBookmarkNode$1 = node => {
8277      return isElement$6(node) && node.tagName === 'SPAN' && node.getAttribute('data-mce-type') === 'bookmark';
8278    };
8279
8280    const is = expected => actual => expected === actual;
8281    const isNbsp = is(nbsp);
8282    const isWhiteSpace = chr => chr !== '' && ' \f\n\r\t\x0B'.indexOf(chr) !== -1;
8283    const isContent = chr => !isWhiteSpace(chr) && !isNbsp(chr) && !isZwsp$2(chr);
8284
8285    const hexColour = value => ({ value: normalizeHex(value) });
8286    const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();
8287    const toHex = component => {
8288      const hex = component.toString(16);
8289      return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
8290    };
8291    const fromRgba = rgbaColour => {
8292      const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
8293      return hexColour(value);
8294    };
8295
8296    const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/i;
8297    const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?(?:\.\d+)?)\s*\)\s*$/i;
8298    const rgbaColour = (red, green, blue, alpha) => ({
8299      red,
8300      green,
8301      blue,
8302      alpha
8303    });
8304    const fromStringValues = (red, green, blue, alpha) => {
8305      const r = parseInt(red, 10);
8306      const g = parseInt(green, 10);
8307      const b = parseInt(blue, 10);
8308      const a = parseFloat(alpha);
8309      return rgbaColour(r, g, b, a);
8310    };
8311    const fromString = rgbaString => {
8312      if (rgbaString === 'transparent') {
8313        return Optional.some(rgbaColour(0, 0, 0, 0));
8314      }
8315      const rgbMatch = rgbRegex.exec(rgbaString);
8316      if (rgbMatch !== null) {
8317        return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
8318      }
8319      const rgbaMatch = rgbaRegex.exec(rgbaString);
8320      if (rgbaMatch !== null) {
8321        return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
8322      }
8323      return Optional.none();
8324    };
8325
8326    const rgbaToHexString = color => fromString(color).map(fromRgba).map(h => '#' + h.value).getOr(color);
8327
8328    const getRanges$1 = selection => {
8329      const ranges = [];
8330      if (selection) {
8331        for (let i = 0; i < selection.rangeCount; i++) {
8332          ranges.push(selection.getRangeAt(i));
8333        }
8334      }
8335      return ranges;
8336    };
8337    const getSelectedNodes = ranges => {
8338      return bind$3(ranges, range => {
8339        const node = getSelectedNode(range);
8340        return node ? [SugarElement.fromDom(node)] : [];
8341      });
8342    };
8343    const hasMultipleRanges = selection => {
8344      return getRanges$1(selection).length > 1;
8345    };
8346
8347    const getCellsFromRanges = ranges => filter$5(getSelectedNodes(ranges), isTableCell$2);
8348    const getCellsFromElement = elm => descendants(elm, 'td[data-mce-selected],th[data-mce-selected]');
8349    const getCellsFromElementOrRanges = (ranges, element) => {
8350      const selectedCells = getCellsFromElement(element);
8351      return selectedCells.length > 0 ? selectedCells : getCellsFromRanges(ranges);
8352    };
8353    const getCellsFromEditor = editor => getCellsFromElementOrRanges(getRanges$1(editor.selection.getSel()), SugarElement.fromDom(editor.getBody()));
8354    const getClosestTable = (cell, isRoot) => ancestor$3(cell, 'table', isRoot);
8355
8356    const getStartNode = rng => {
8357      const sc = rng.startContainer, so = rng.startOffset;
8358      if (isText$a(sc)) {
8359        return so === 0 ? Optional.some(SugarElement.fromDom(sc)) : Optional.none();
8360      } else {
8361        return Optional.from(sc.childNodes[so]).map(SugarElement.fromDom);
8362      }
8363    };
8364    const getEndNode = rng => {
8365      const ec = rng.endContainer, eo = rng.endOffset;
8366      if (isText$a(ec)) {
8367        return eo === ec.data.length ? Optional.some(SugarElement.fromDom(ec)) : Optional.none();
8368      } else {
8369        return Optional.from(ec.childNodes[eo - 1]).map(SugarElement.fromDom);
8370      }
8371    };
8372    const getFirstChildren = node => {
8373      return firstChild(node).fold(constant([node]), child => {
8374        return [node].concat(getFirstChildren(child));
8375      });
8376    };
8377    const getLastChildren = node => {
8378      return lastChild(node).fold(constant([node]), child => {
8379        if (name(child) === 'br') {
8380          return prevSibling(child).map(sibling => {
8381            return [node].concat(getLastChildren(sibling));
8382          }).getOr([]);
8383        } else {
8384          return [node].concat(getLastChildren(child));
8385        }
8386      });
8387    };
8388    const hasAllContentsSelected = (elm, rng) => {
8389      return lift2(getStartNode(rng), getEndNode(rng), (startNode, endNode) => {
8390        const start = find$2(getFirstChildren(elm), curry(eq, startNode));
8391        const end = find$2(getLastChildren(elm), curry(eq, endNode));
8392        return start.isSome() && end.isSome();
8393      }).getOr(false);
8394    };
8395    const moveEndPoint = (dom, rng, node, start) => {
8396      const root = node;
8397      const walker = new DomTreeWalker(node, root);
8398      const moveCaretBeforeOnEnterElementsMap = filter$4(dom.schema.getMoveCaretBeforeOnEnterElements(), (_, name) => !contains$2([
8399        'td',
8400        'th',
8401        'table'
8402      ], name.toLowerCase()));
8403      let currentNode = node;
8404      do {
8405        if (isText$a(currentNode) && Tools.trim(currentNode.data).length !== 0) {
8406          if (start) {
8407            rng.setStart(currentNode, 0);
8408          } else {
8409            rng.setEnd(currentNode, currentNode.data.length);
8410          }
8411          return;
8412        }
8413        if (moveCaretBeforeOnEnterElementsMap[currentNode.nodeName]) {
8414          if (start) {
8415            rng.setStartBefore(currentNode);
8416          } else {
8417            if (currentNode.nodeName === 'BR') {
8418              rng.setEndBefore(currentNode);
8419            } else {
8420              rng.setEndAfter(currentNode);
8421            }
8422          }
8423          return;
8424        }
8425      } while (currentNode = start ? walker.next() : walker.prev());
8426      if (root.nodeName === 'BODY') {
8427        if (start) {
8428          rng.setStart(root, 0);
8429        } else {
8430          rng.setEnd(root, root.childNodes.length);
8431        }
8432      }
8433    };
8434    const hasAnyRanges = editor => {
8435      const sel = editor.selection.getSel();
8436      return isNonNullable(sel) && sel.rangeCount > 0;
8437    };
8438    const runOnRanges = (editor, executor) => {
8439      const fakeSelectionNodes = getCellsFromEditor(editor);
8440      if (fakeSelectionNodes.length > 0) {
8441        each$e(fakeSelectionNodes, elem => {
8442          const node = elem.dom;
8443          const fakeNodeRng = editor.dom.createRng();
8444          fakeNodeRng.setStartBefore(node);
8445          fakeNodeRng.setEndAfter(node);
8446          executor(fakeNodeRng, true);
8447        });
8448      } else {
8449        executor(editor.selection.getRng(), false);
8450      }
8451    };
8452    const preserve = (selection, fillBookmark, executor) => {
8453      const bookmark = getPersistentBookmark(selection, fillBookmark);
8454      executor(bookmark);
8455      selection.moveToBookmark(bookmark);
8456    };
8457
8458    const isNode = node => isNumber(node === null || node === void 0 ? void 0 : node.nodeType);
8459    const isElementNode$1 = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$2(node);
8460    const isElementDirectlySelected = (dom, node) => {
8461      if (isElementNode$1(node) && !/^(TD|TH)$/.test(node.nodeName)) {
8462        const selectedAttr = dom.getAttrib(node, 'data-mce-selected');
8463        const value = parseInt(selectedAttr, 10);
8464        return !isNaN(value) && value > 0;
8465      } else {
8466        return false;
8467      }
8468    };
8469    const isEditable$2 = elm => elm.isContentEditable === true;
8470    const preserveSelection = (editor, action, shouldMoveStart) => {
8471      const {selection, dom} = editor;
8472      const selectedNodeBeforeAction = selection.getNode();
8473      const isSelectedBeforeNodeNoneditable = isContentEditableFalse$b(selectedNodeBeforeAction);
8474      preserve(selection, true, () => {
8475        action();
8476      });
8477      const isBeforeNodeStillNoneditable = isSelectedBeforeNodeNoneditable && isContentEditableFalse$b(selectedNodeBeforeAction);
8478      if (isBeforeNodeStillNoneditable && dom.isChildOf(selectedNodeBeforeAction, editor.getBody())) {
8479        editor.selection.select(selectedNodeBeforeAction);
8480      } else if (shouldMoveStart(selection.getStart())) {
8481        moveStartToNearestText(dom, selection);
8482      }
8483    };
8484    const moveStartToNearestText = (dom, selection) => {
8485      var _a, _b;
8486      const rng = selection.getRng();
8487      const {startContainer, startOffset} = rng;
8488      const selectedNode = selection.getNode();
8489      if (isElementDirectlySelected(dom, selectedNode)) {
8490        return;
8491      }
8492      if (isElement$6(startContainer)) {
8493        const nodes = startContainer.childNodes;
8494        const root = dom.getRoot();
8495        let walker;
8496        if (startOffset < nodes.length) {
8497          const startNode = nodes[startOffset];
8498          walker = new DomTreeWalker(startNode, (_a = dom.getParent(startNode, dom.isBlock)) !== null && _a !== void 0 ? _a : root);
8499        } else {
8500          const startNode = nodes[nodes.length - 1];
8501          walker = new DomTreeWalker(startNode, (_b = dom.getParent(startNode, dom.isBlock)) !== null && _b !== void 0 ? _b : root);
8502          walker.next(true);
8503        }
8504        for (let node = walker.current(); node; node = walker.next()) {
8505          if (dom.getContentEditable(node) === 'false') {
8506            return;
8507          } else if (isText$a(node) && !isWhiteSpaceNode$1(node)) {
8508            rng.setStart(node, 0);
8509            selection.setRng(rng);
8510            return;
8511          }
8512        }
8513      }
8514    };
8515    const getNonWhiteSpaceSibling = (node, next, inc) => {
8516      if (node) {
8517        const nextName = next ? 'nextSibling' : 'previousSibling';
8518        for (node = inc ? node : node[nextName]; node; node = node[nextName]) {
8519          if (isElement$6(node) || !isWhiteSpaceNode$1(node)) {
8520            return node;
8521          }
8522        }
8523      }
8524      return undefined;
8525    };
8526    const isTextBlock$1 = (schema, node) => !!schema.getTextBlockElements()[node.nodeName.toLowerCase()] || isTransparentBlock(schema, node);
8527    const isValid = (ed, parent, child) => {
8528      return ed.schema.isValidChild(parent, child);
8529    };
8530    const isWhiteSpaceNode$1 = (node, allowSpaces = false) => {
8531      if (isNonNullable(node) && isText$a(node)) {
8532        const data = allowSpaces ? node.data.replace(/ /g, '\xA0') : node.data;
8533        return isWhitespaceText(data);
8534      } else {
8535        return false;
8536      }
8537    };
8538    const isEmptyTextNode$1 = node => {
8539      return isNonNullable(node) && isText$a(node) && node.length === 0;
8540    };
8541    const isWrapNoneditableTarget = (editor, node) => {
8542      const baseDataSelector = '[data-mce-cef-wrappable]';
8543      const formatNoneditableSelector = getFormatNoneditableSelector(editor);
8544      const selector = isEmpty$3(formatNoneditableSelector) ? baseDataSelector : `${ baseDataSelector },${ formatNoneditableSelector }`;
8545      return is$1(SugarElement.fromDom(node), selector);
8546    };
8547    const isWrappableNoneditable = (editor, node) => {
8548      const dom = editor.dom;
8549      return isElementNode$1(node) && dom.getContentEditable(node) === 'false' && isWrapNoneditableTarget(editor, node) && dom.select('[contenteditable="true"]', node).length === 0;
8550    };
8551    const replaceVars = (value, vars) => {
8552      if (isFunction(value)) {
8553        return value(vars);
8554      } else if (isNonNullable(vars)) {
8555        value = value.replace(/%(\w+)/g, (str, name) => {
8556          return vars[name] || str;
8557        });
8558      }
8559      return value;
8560    };
8561    const isEq$5 = (str1, str2) => {
8562      str1 = str1 || '';
8563      str2 = str2 || '';
8564      str1 = '' + (str1.nodeName || str1);
8565      str2 = '' + (str2.nodeName || str2);
8566      return str1.toLowerCase() === str2.toLowerCase();
8567    };
8568    const normalizeStyleValue = (value, name) => {
8569      if (isNullable(value)) {
8570        return null;
8571      } else {
8572        let strValue = String(value);
8573        if (name === 'color' || name === 'backgroundColor') {
8574          strValue = rgbaToHexString(strValue);
8575        }
8576        if (name === 'fontWeight' && value === 700) {
8577          strValue = 'bold';
8578        }
8579        if (name === 'fontFamily') {
8580          strValue = strValue.replace(/[\'\"]/g, '').replace(/,\s+/g, ',');
8581        }
8582        return strValue;
8583      }
8584    };
8585    const getStyle = (dom, node, name) => {
8586      const style = dom.getStyle(node, name);
8587      return normalizeStyleValue(style, name);
8588    };
8589    const getTextDecoration = (dom, node) => {
8590      let decoration;
8591      dom.getParent(node, n => {
8592        if (isElement$6(n)) {
8593          decoration = dom.getStyle(n, 'text-decoration');
8594          return !!decoration && decoration !== 'none';
8595        } else {
8596          return false;
8597        }
8598      });
8599      return decoration;
8600    };
8601    const getParents$2 = (dom, node, selector) => {
8602      return dom.getParents(node, selector, dom.getRoot());
8603    };
8604    const isFormatPredicate = (editor, formatName, predicate) => {
8605      const formats = editor.formatter.get(formatName);
8606      return isNonNullable(formats) && exists(formats, predicate);
8607    };
8608    const isVariableFormatName = (editor, formatName) => {
8609      const hasVariableValues = format => {
8610        const isVariableValue = val => isFunction(val) || val.length > 1 && val.charAt(0) === '%';
8611        return exists([
8612          'styles',
8613          'attributes'
8614        ], key => get$a(format, key).exists(field => {
8615          const fieldValues = isArray$1(field) ? field : values(field);
8616          return exists(fieldValues, isVariableValue);
8617        }));
8618      };
8619      return isFormatPredicate(editor, formatName, hasVariableValues);
8620    };
8621    const areSimilarFormats = (editor, formatName, otherFormatName) => {
8622      const validKeys = [
8623        'inline',
8624        'block',
8625        'selector',
8626        'attributes',
8627        'styles',
8628        'classes'
8629      ];
8630      const filterObj = format => filter$4(format, (_, key) => exists(validKeys, validKey => validKey === key));
8631      return isFormatPredicate(editor, formatName, fmt1 => {
8632        const filteredFmt1 = filterObj(fmt1);
8633        return isFormatPredicate(editor, otherFormatName, fmt2 => {
8634          const filteredFmt2 = filterObj(fmt2);
8635          return equal$1(filteredFmt1, filteredFmt2);
8636        });
8637      });
8638    };
8639    const isBlockFormat = format => hasNonNullableKey(format, 'block');
8640    const isWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper === true;
8641    const isNonWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper !== true;
8642    const isSelectorFormat = format => hasNonNullableKey(format, 'selector');
8643    const isInlineFormat = format => hasNonNullableKey(format, 'inline');
8644    const isMixedFormat = format => isSelectorFormat(format) && isInlineFormat(format) && is$2(get$a(format, 'mixed'), true);
8645    const shouldExpandToSelector = format => isSelectorFormat(format) && format.expand !== false && !isInlineFormat(format);
8646
8647    const isBookmarkNode = isBookmarkNode$1;
8648    const getParents$1 = getParents$2;
8649    const isWhiteSpaceNode = isWhiteSpaceNode$1;
8650    const isTextBlock = isTextBlock$1;
8651    const isBogusBr = node => {
8652      return isBr$6(node) && node.getAttribute('data-mce-bogus') && !node.nextSibling;
8653    };
8654    const findParentContentEditable = (dom, node) => {
8655      let parent = node;
8656      while (parent) {
8657        if (isElement$6(parent) && dom.getContentEditable(parent)) {
8658          return dom.getContentEditable(parent) === 'false' ? parent : node;
8659        }
8660        parent = parent.parentNode;
8661      }
8662      return node;
8663    };
8664    const walkText = (start, node, offset, predicate) => {
8665      const str = node.data;
8666      if (start) {
8667        for (let i = offset; i > 0; i--) {
8668          if (predicate(str.charAt(i - 1))) {
8669            return i;
8670          }
8671        }
8672      } else {
8673        for (let i = offset; i < str.length; i++) {
8674          if (predicate(str.charAt(i))) {
8675            return i;
8676          }
8677        }
8678      }
8679      return -1;
8680    };
8681    const findSpace = (start, node, offset) => walkText(start, node, offset, c => isNbsp(c) || isWhiteSpace(c));
8682    const findContent = (start, node, offset) => walkText(start, node, offset, isContent);
8683    const findWordEndPoint = (dom, body, container, offset, start, includeTrailingSpaces) => {
8684      let lastTextNode;
8685      const rootNode = dom.getParent(container, dom.isBlock) || body;
8686      const walk = (container, offset, pred) => {
8687        const textSeeker = TextSeeker(dom);
8688        const walker = start ? textSeeker.backwards : textSeeker.forwards;
8689        return Optional.from(walker(container, offset, (text, textOffset) => {
8690          if (isBookmarkNode(text.parentNode)) {
8691            return -1;
8692          } else {
8693            lastTextNode = text;
8694            return pred(start, text, textOffset);
8695          }
8696        }, rootNode));
8697      };
8698      const spaceResult = walk(container, offset, findSpace);
8699      return spaceResult.bind(result => includeTrailingSpaces ? walk(result.container, result.offset + (start ? -1 : 0), findContent) : Optional.some(result)).orThunk(() => lastTextNode ? Optional.some({
8700        container: lastTextNode,
8701        offset: start ? 0 : lastTextNode.length
8702      }) : Optional.none());
8703    };
8704    const findSelectorEndPoint = (dom, formatList, rng, container, siblingName) => {
8705      const sibling = container[siblingName];
8706      if (isText$a(container) && isEmpty$3(container.data) && sibling) {
8707        container = sibling;
8708      }
8709      const parents = getParents$1(dom, container);
8710      for (let i = 0; i < parents.length; i++) {
8711        for (let y = 0; y < formatList.length; y++) {
8712          const curFormat = formatList[y];
8713          if (isNonNullable(curFormat.collapsed) && curFormat.collapsed !== rng.collapsed) {
8714            continue;
8715          }
8716          if (isSelectorFormat(curFormat) && dom.is(parents[i], curFormat.selector)) {
8717            return parents[i];
8718          }
8719        }
8720      }
8721      return container;
8722    };
8723    const findBlockEndPoint = (dom, formatList, container, siblingName) => {
8724      var _a;
8725      let node = container;
8726      const root = dom.getRoot();
8727      const format = formatList[0];
8728      if (isBlockFormat(format)) {
8729        node = format.wrapper ? null : dom.getParent(container, format.block, root);
8730      }
8731      if (!node) {
8732        const scopeRoot = (_a = dom.getParent(container, 'LI,TD,TH')) !== null && _a !== void 0 ? _a : root;
8733        node = dom.getParent(isText$a(container) ? container.parentNode : container, node => node !== root && isTextBlock(dom.schema, node), scopeRoot);
8734      }
8735      if (node && isBlockFormat(format) && format.wrapper) {
8736        node = getParents$1(dom, node, 'ul,ol').reverse()[0] || node;
8737      }
8738      if (!node) {
8739        node = container;
8740        while (node && node[siblingName] && !dom.isBlock(node[siblingName])) {
8741          node = node[siblingName];
8742          if (isEq$5(node, 'br')) {
8743            break;
8744          }
8745        }
8746      }
8747      return node || container;
8748    };
8749    const isAtBlockBoundary$1 = (dom, root, container, siblingName) => {
8750      const parent = container.parentNode;
8751      if (isNonNullable(container[siblingName])) {
8752        return false;
8753      } else if (parent === root || isNullable(parent) || dom.isBlock(parent)) {
8754        return true;
8755      } else {
8756        return isAtBlockBoundary$1(dom, root, parent, siblingName);
8757      }
8758    };
8759    const findParentContainer = (dom, formatList, container, offset, start) => {
8760      let parent = container;
8761      const siblingName = start ? 'previousSibling' : 'nextSibling';
8762      const root = dom.getRoot();
8763      if (isText$a(container) && !isWhiteSpaceNode(container)) {
8764        if (start ? offset > 0 : offset < container.data.length) {
8765          return container;
8766        }
8767      }
8768      while (parent) {
8769        if (!formatList[0].block_expand && dom.isBlock(parent)) {
8770          return parent;
8771        }
8772        for (let sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
8773          const allowSpaces = isText$a(sibling) && !isAtBlockBoundary$1(dom, root, sibling, siblingName);
8774          if (!isBookmarkNode(sibling) && !isBogusBr(sibling) && !isWhiteSpaceNode(sibling, allowSpaces)) {
8775            return parent;
8776          }
8777        }
8778        if (parent === root || parent.parentNode === root) {
8779          container = parent;
8780          break;
8781        }
8782        parent = parent.parentNode;
8783      }
8784      return container;
8785    };
8786    const isSelfOrParentBookmark = container => isBookmarkNode(container.parentNode) || isBookmarkNode(container);
8787    const expandRng = (dom, rng, formatList, includeTrailingSpace = false) => {
8788      let {startContainer, startOffset, endContainer, endOffset} = rng;
8789      const format = formatList[0];
8790      if (isElement$6(startContainer) && startContainer.hasChildNodes()) {
8791        startContainer = getNode$1(startContainer, startOffset);
8792        if (isText$a(startContainer)) {
8793          startOffset = 0;
8794        }
8795      }
8796      if (isElement$6(endContainer) && endContainer.hasChildNodes()) {
8797        endContainer = getNode$1(endContainer, rng.collapsed ? endOffset : endOffset - 1);
8798        if (isText$a(endContainer)) {
8799          endOffset = endContainer.data.length;
8800        }
8801      }
8802      startContainer = findParentContentEditable(dom, startContainer);
8803      endContainer = findParentContentEditable(dom, endContainer);
8804      if (isSelfOrParentBookmark(startContainer)) {
8805        startContainer = isBookmarkNode(startContainer) ? startContainer : startContainer.parentNode;
8806        if (rng.collapsed) {
8807          startContainer = startContainer.previousSibling || startContainer;
8808        } else {
8809          startContainer = startContainer.nextSibling || startContainer;
8810        }
8811        if (isText$a(startContainer)) {
8812          startOffset = rng.collapsed ? startContainer.length : 0;
8813        }
8814      }
8815      if (isSelfOrParentBookmark(endContainer)) {
8816        endContainer = isBookmarkNode(endContainer) ? endContainer : endContainer.parentNode;
8817        if (rng.collapsed) {
8818          endContainer = endContainer.nextSibling || endContainer;
8819        } else {
8820          endContainer = endContainer.previousSibling || endContainer;
8821        }
8822        if (isText$a(endContainer)) {
8823          endOffset = rng.collapsed ? 0 : endContainer.length;
8824        }
8825      }
8826      if (rng.collapsed) {
8827        const startPoint = findWordEndPoint(dom, dom.getRoot(), startContainer, startOffset, true, includeTrailingSpace);
8828        startPoint.each(({container, offset}) => {
8829          startContainer = container;
8830          startOffset = offset;
8831        });
8832        const endPoint = findWordEndPoint(dom, dom.getRoot(), endContainer, endOffset, false, includeTrailingSpace);
8833        endPoint.each(({container, offset}) => {
8834          endContainer = container;
8835          endOffset = offset;
8836        });
8837      }
8838      if (isInlineFormat(format) || format.block_expand) {
8839        if (!isInlineFormat(format) || (!isText$a(startContainer) || startOffset === 0)) {
8840          startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true);
8841        }
8842        if (!isInlineFormat(format) || (!isText$a(endContainer) || endOffset === endContainer.data.length)) {
8843          endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false);
8844        }
8845      }
8846      if (shouldExpandToSelector(format)) {
8847        startContainer = findSelectorEndPoint(dom, formatList, rng, startContainer, 'previousSibling');
8848        endContainer = findSelectorEndPoint(dom, formatList, rng, endContainer, 'nextSibling');
8849      }
8850      if (isBlockFormat(format) || isSelectorFormat(format)) {
8851        startContainer = findBlockEndPoint(dom, formatList, startContainer, 'previousSibling');
8852        endContainer = findBlockEndPoint(dom, formatList, endContainer, 'nextSibling');
8853        if (isBlockFormat(format)) {
8854          if (!dom.isBlock(startContainer)) {
8855            startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true);
8856          }
8857          if (!dom.isBlock(endContainer)) {
8858            endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false);
8859          }
8860        }
8861      }
8862      if (isElement$6(startContainer) && startContainer.parentNode) {
8863        startOffset = dom.nodeIndex(startContainer);
8864        startContainer = startContainer.parentNode;
8865      }
8866      if (isElement$6(endContainer) && endContainer.parentNode) {
8867        endOffset = dom.nodeIndex(endContainer) + 1;
8868        endContainer = endContainer.parentNode;
8869      }
8870      return {
8871        startContainer,
8872        startOffset,
8873        endContainer,
8874        endOffset
8875      };
8876    };
8877
8878    const walk$3 = (dom, rng, callback) => {
8879      var _a;
8880      const startOffset = rng.startOffset;
8881      const startContainer = getNode$1(rng.startContainer, startOffset);
8882      const endOffset = rng.endOffset;
8883      const endContainer = getNode$1(rng.endContainer, endOffset - 1);
8884      const exclude = nodes => {
8885        const firstNode = nodes[0];
8886        if (isText$a(firstNode) && firstNode === startContainer && startOffset >= firstNode.data.length) {
8887          nodes.splice(0, 1);
8888        }
8889        const lastNode = nodes[nodes.length - 1];
8890        if (endOffset === 0 && nodes.length > 0 && lastNode === endContainer && isText$a(lastNode)) {
8891          nodes.splice(nodes.length - 1, 1);
8892        }
8893        return nodes;
8894      };
8895      const collectSiblings = (node, name, endNode) => {
8896        const siblings = [];
8897        for (; node && node !== endNode; node = node[name]) {
8898          siblings.push(node);
8899        }
8900        return siblings;
8901      };
8902      const findEndPoint = (node, root) => dom.getParent(node, node => node.parentNode === root, root);
8903      const walkBoundary = (startNode, endNode, next) => {
8904        const siblingName = next ? 'nextSibling' : 'previousSibling';
8905        for (let node = startNode, parent = node.parentNode; node && node !== endNode; node = parent) {
8906          parent = node.parentNode;
8907          const siblings = collectSiblings(node === startNode ? node : node[siblingName], siblingName);
8908          if (siblings.length) {
8909            if (!next) {
8910              siblings.reverse();
8911            }
8912            callback(exclude(siblings));
8913          }
8914        }
8915      };
8916      if (startContainer === endContainer) {
8917        return callback(exclude([startContainer]));
8918      }
8919      const ancestor = (_a = dom.findCommonAncestor(startContainer, endContainer)) !== null && _a !== void 0 ? _a : dom.getRoot();
8920      if (dom.isChildOf(startContainer, endContainer)) {
8921        return walkBoundary(startContainer, ancestor, true);
8922      }
8923      if (dom.isChildOf(endContainer, startContainer)) {
8924        return walkBoundary(endContainer, ancestor);
8925      }
8926      const startPoint = findEndPoint(startContainer, ancestor) || startContainer;
8927      const endPoint = findEndPoint(endContainer, ancestor) || endContainer;
8928      walkBoundary(startContainer, startPoint, true);
8929      const siblings = collectSiblings(startPoint === startContainer ? startPoint : startPoint.nextSibling, 'nextSibling', endPoint === endContainer ? endPoint.nextSibling : endPoint);
8930      if (siblings.length) {
8931        callback(exclude(siblings));
8932      }
8933      walkBoundary(endContainer, endPoint);
8934    };
8935
8936    const validBlocks = [
8937      'pre[class*=language-][contenteditable="false"]',
8938      'figure.image',
8939      'div[data-ephox-embed-iri]',
8940      'div.tiny-pageembed',
8941      'div.mce-toc',
8942      'div[data-mce-toc]'
8943    ];
8944    const isZeroWidth = elem => isText$b(elem) && get$3(elem) === ZWSP$1;
8945    const context = (editor, elem, wrapName, nodeName) => parent(elem).fold(() => 'skipping', parent => {
8946      if (nodeName === 'br' || isZeroWidth(elem)) {
8947        return 'valid';
8948      } else if (isAnnotation(elem)) {
8949        return 'existing';
8950      } else if (isCaretNode(elem.dom)) {
8951        return 'caret';
8952      } else if (exists(validBlocks, selector => is$1(elem, selector))) {
8953        return 'valid-block';
8954      } else if (!isValid(editor, wrapName, nodeName) || !isValid(editor, name(parent), wrapName)) {
8955        return 'invalid-child';
8956      } else {
8957        return 'valid';
8958      }
8959    });
8960
8961    const applyWordGrab = (editor, rng) => {
8962      const r = expandRng(editor.dom, rng, [{ inline: 'span' }]);
8963      rng.setStart(r.startContainer, r.startOffset);
8964      rng.setEnd(r.endContainer, r.endOffset);
8965      editor.selection.setRng(rng);
8966    };
8967    const applyAnnotation = (elem, masterUId, data, annotationName, decorate, directAnnotation) => {
8968      const {uid = masterUId, ...otherData} = data;
8969      add$2(elem, annotation());
8970      set$3(elem, `${ dataAnnotationId() }`, uid);
8971      set$3(elem, `${ dataAnnotation() }`, annotationName);
8972      const {attributes = {}, classes = []} = decorate(uid, otherData);
8973      setAll$1(elem, attributes);
8974      add(elem, classes);
8975      if (directAnnotation) {
8976        if (classes.length > 0) {
8977          set$3(elem, `${ dataAnnotationClasses() }`, classes.join(','));
8978        }
8979        const attributeNames = keys(attributes);
8980        if (attributeNames.length > 0) {
8981          set$3(elem, `${ dataAnnotationAttributes() }`, attributeNames.join(','));
8982        }
8983      }
8984    };
8985    const removeDirectAnnotation = elem => {
8986      remove$7(elem, annotation());
8987      remove$a(elem, `${ dataAnnotationId() }`);
8988      remove$a(elem, `${ dataAnnotation() }`);
8989      remove$a(elem, `${ dataAnnotationActive() }`);
8990      const customAttrNames = getOpt(elem, `${ dataAnnotationAttributes() }`).map(names => names.split(',')).getOr([]);
8991      const customClasses = getOpt(elem, `${ dataAnnotationClasses() }`).map(names => names.split(',')).getOr([]);
8992      each$e(customAttrNames, name => remove$a(elem, name));
8993      remove$4(elem, customClasses);
8994      remove$a(elem, `${ dataAnnotationClasses() }`);
8995      remove$a(elem, `${ dataAnnotationAttributes() }`);
8996    };
8997    const makeAnnotation = (eDoc, uid, data, annotationName, decorate) => {
8998      const master = SugarElement.fromTag('span', eDoc);
8999      applyAnnotation(master, uid, data, annotationName, decorate, false);
9000      return master;
9001    };
9002    const annotate = (editor, rng, uid, annotationName, decorate, data) => {
9003      const newWrappers = [];
9004      const master = makeAnnotation(editor.getDoc(), uid, data, annotationName, decorate);
9005      const wrapper = value$2();
9006      const finishWrapper = () => {
9007        wrapper.clear();
9008      };
9009      const getOrOpenWrapper = () => wrapper.get().getOrThunk(() => {
9010        const nu = shallow$1(master);
9011        newWrappers.push(nu);
9012        wrapper.set(nu);
9013        return nu;
9014      });
9015      const processElements = elems => {
9016        each$e(elems, processElement);
9017      };
9018      const processElement = elem => {
9019        const ctx = context(editor, elem, 'span', name(elem));
9020        switch (ctx) {
9021        case 'invalid-child': {
9022            finishWrapper();
9023            const children = children$1(elem);
9024            processElements(children);
9025            finishWrapper();
9026            break;
9027          }
9028        case 'valid-block': {
9029            finishWrapper();
9030            applyAnnotation(elem, uid, data, annotationName, decorate, true);
9031            break;
9032          }
9033        case 'valid': {
9034            const w = getOrOpenWrapper();
9035            wrap$2(elem, w);
9036            break;
9037          }
9038        }
9039      };
9040      const processNodes = nodes => {
9041        const elems = map$3(nodes, SugarElement.fromDom);
9042        processElements(elems);
9043      };
9044      walk$3(editor.dom, rng, nodes => {
9045        finishWrapper();
9046        processNodes(nodes);
9047      });
9048      return newWrappers;
9049    };
9050    const annotateWithBookmark = (editor, name, settings, data) => {
9051      editor.undoManager.transact(() => {
9052        const selection = editor.selection;
9053        const initialRng = selection.getRng();
9054        const hasFakeSelection = getCellsFromEditor(editor).length > 0;
9055        const masterUid = generate$1('mce-annotation');
9056        if (initialRng.collapsed && !hasFakeSelection) {
9057          applyWordGrab(editor, initialRng);
9058        }
9059        if (selection.getRng().collapsed && !hasFakeSelection) {
9060          const wrapper = makeAnnotation(editor.getDoc(), masterUid, data, name, settings.decorate);
9061          set$1(wrapper, nbsp);
9062          selection.getRng().insertNode(wrapper.dom);
9063          selection.select(wrapper.dom);
9064        } else {
9065          preserve(selection, false, () => {
9066            runOnRanges(editor, selectionRng => {
9067              annotate(editor, selectionRng, masterUid, name, settings.decorate, data);
9068            });
9069          });
9070        }
9071      });
9072    };
9073
9074    const Annotator = editor => {
9075      const registry = create$c();
9076      setup$w(editor, registry);
9077      const changes = setup$x(editor, registry);
9078      const isSpan = isTag('span');
9079      const removeAnnotations = elements => {
9080        each$e(elements, element => {
9081          if (isSpan(element)) {
9082            unwrap(element);
9083          } else {
9084            removeDirectAnnotation(element);
9085          }
9086        });
9087      };
9088      return {
9089        register: (name, settings) => {
9090          registry.register(name, settings);
9091        },
9092        annotate: (name, data) => {
9093          registry.lookup(name).each(settings => {
9094            annotateWithBookmark(editor, name, settings, data);
9095          });
9096        },
9097        annotationChanged: (name, callback) => {
9098          changes.addListener(name, callback);
9099        },
9100        remove: name => {
9101          identify(editor, Optional.some(name)).each(({elements}) => {
9102            const bookmark = editor.selection.getBookmark();
9103            removeAnnotations(elements);
9104            editor.selection.moveToBookmark(bookmark);
9105          });
9106        },
9107        removeAll: name => {
9108          const bookmark = editor.selection.getBookmark();
9109          each$d(findAll(editor, name), (elements, _) => {
9110            removeAnnotations(elements);
9111          });
9112          editor.selection.moveToBookmark(bookmark);
9113        },
9114        getAll: name => {
9115          const directory = findAll(editor, name);
9116          return map$2(directory, elems => map$3(elems, elem => elem.dom));
9117        }
9118      };
9119    };
9120
9121    const BookmarkManager = selection => {
9122      return {
9123        getBookmark: curry(getBookmark$1, selection),
9124        moveToBookmark: curry(moveToBookmark, selection)
9125      };
9126    };
9127    BookmarkManager.isBookmarkNode = isBookmarkNode$1;
9128
9129    const isXYWithinRange = (clientX, clientY, range) => {
9130      if (range.collapsed) {
9131        return false;
9132      } else {
9133        return exists(range.getClientRects(), rect => containsXY(rect, clientX, clientY));
9134      }
9135    };
9136
9137    const firePreProcess = (editor, args) => editor.dispatch('PreProcess', args);
9138    const firePostProcess = (editor, args) => editor.dispatch('PostProcess', args);
9139    const fireRemove = editor => {
9140      editor.dispatch('remove');
9141    };
9142    const fireDetach = editor => {
9143      editor.dispatch('detach');
9144    };
9145    const fireSwitchMode = (editor, mode) => {
9146      editor.dispatch('SwitchMode', { mode });
9147    };
9148    const fireObjectResizeStart = (editor, target, width, height, origin) => {
9149      editor.dispatch('ObjectResizeStart', {
9150        target,
9151        width,
9152        height,
9153        origin
9154      });
9155    };
9156    const fireObjectResized = (editor, target, width, height, origin) => {
9157      editor.dispatch('ObjectResized', {
9158        target,
9159        width,
9160        height,
9161        origin
9162      });
9163    };
9164    const firePreInit = editor => {
9165      editor.dispatch('PreInit');
9166    };
9167    const firePostRender = editor => {
9168      editor.dispatch('PostRender');
9169    };
9170    const fireInit = editor => {
9171      editor.dispatch('Init');
9172    };
9173    const firePlaceholderToggle = (editor, state) => {
9174      editor.dispatch('PlaceholderToggle', { state });
9175    };
9176    const fireError = (editor, errorType, error) => {
9177      editor.dispatch(errorType, error);
9178    };
9179    const fireFormatApply = (editor, format, node, vars) => {
9180      editor.dispatch('FormatApply', {
9181        format,
9182        node,
9183        vars
9184      });
9185    };
9186    const fireFormatRemove = (editor, format, node, vars) => {
9187      editor.dispatch('FormatRemove', {
9188        format,
9189        node,
9190        vars
9191      });
9192    };
9193    const fireBeforeSetContent = (editor, args) => editor.dispatch('BeforeSetContent', args);
9194    const fireSetContent = (editor, args) => editor.dispatch('SetContent', args);
9195    const fireBeforeGetContent = (editor, args) => editor.dispatch('BeforeGetContent', args);
9196    const fireGetContent = (editor, args) => editor.dispatch('GetContent', args);
9197    const fireAutocompleterStart = (editor, args) => {
9198      editor.dispatch('AutocompleterStart', args);
9199    };
9200    const fireAutocompleterUpdate = (editor, args) => {
9201      editor.dispatch('AutocompleterUpdate', args);
9202    };
9203    const fireAutocompleterEnd = editor => {
9204      editor.dispatch('AutocompleterEnd');
9205    };
9206    const firePastePreProcess = (editor, html, internal) => editor.dispatch('PastePreProcess', {
9207      content: html,
9208      internal
9209    });
9210    const firePastePostProcess = (editor, node, internal) => editor.dispatch('PastePostProcess', {
9211      node,
9212      internal
9213    });
9214    const firePastePlainTextToggle = (editor, state) => editor.dispatch('PastePlainTextToggle', { state });
9215    const fireEditableRootStateChange = (editor, state) => editor.dispatch('EditableRootStateChange', { state });
9216
9217    const VK = {
9218      BACKSPACE: 8,
9219      DELETE: 46,
9220      DOWN: 40,
9221      ENTER: 13,
9222      ESC: 27,
9223      LEFT: 37,
9224      RIGHT: 39,
9225      SPACEBAR: 32,
9226      TAB: 9,
9227      UP: 38,
9228      PAGE_UP: 33,
9229      PAGE_DOWN: 34,
9230      END: 35,
9231      HOME: 36,
9232      modifierPressed: e => {
9233        return e.shiftKey || e.ctrlKey || e.altKey || VK.metaKeyPressed(e);
9234      },
9235      metaKeyPressed: e => {
9236        return Env.os.isMacOS() || Env.os.isiOS() ? e.metaKey : e.ctrlKey && !e.altKey;
9237      }
9238    };
9239
9240    const elementSelectionAttr = 'data-mce-selected';
9241    const controlElmSelector = 'table,img,figure.image,hr,video,span.mce-preview-object,details';
9242    const abs = Math.abs;
9243    const round$1 = Math.round;
9244    const resizeHandles = {
9245      nw: [
9246        0,
9247        0,
9248        -1,
9249        -1
9250      ],
9251      ne: [
9252        1,
9253        0,
9254        1,
9255        -1
9256      ],
9257      se: [
9258        1,
9259        1,
9260        1,
9261        1
9262      ],
9263      sw: [
9264        0,
9265        1,
9266        -1,
9267        1
9268      ]
9269    };
9270    const isTouchEvent = evt => evt.type === 'longpress' || evt.type.indexOf('touch') === 0;
9271    const ControlSelection = (selection, editor) => {
9272      const dom = editor.dom;
9273      const editableDoc = editor.getDoc();
9274      const rootDocument = document;
9275      const rootElement = editor.getBody();
9276      let selectedElm, selectedElmGhost, resizeHelper, selectedHandle, resizeBackdrop;
9277      let startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted;
9278      let width;
9279      let height;
9280      let startScrollWidth;
9281      let startScrollHeight;
9282      const isImage = elm => isNonNullable(elm) && (isImg(elm) || dom.is(elm, 'figure.image'));
9283      const isMedia = elm => isMedia$2(elm) || dom.hasClass(elm, 'mce-preview-object');
9284      const isEventOnImageOutsideRange = (evt, range) => {
9285        if (isTouchEvent(evt)) {
9286          const touch = evt.touches[0];
9287          return isImage(evt.target) && !isXYWithinRange(touch.clientX, touch.clientY, range);
9288        } else {
9289          return isImage(evt.target) && !isXYWithinRange(evt.clientX, evt.clientY, range);
9290        }
9291      };
9292      const contextMenuSelectImage = evt => {
9293        const target = evt.target;
9294        if (isEventOnImageOutsideRange(evt, editor.selection.getRng()) && !evt.isDefaultPrevented()) {
9295          editor.selection.select(target);
9296        }
9297      };
9298      const getResizeTargets = elm => {
9299        if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
9300          return [
9301            elm,
9302            elm.firstElementChild
9303          ];
9304        } else if (dom.is(elm, 'figure.image')) {
9305          return [elm.querySelector('img')];
9306        } else {
9307          return [elm];
9308        }
9309      };
9310      const isResizable = elm => {
9311        const selector = getObjectResizing(editor);
9312        if (!selector) {
9313          return false;
9314        }
9315        if (elm.getAttribute('data-mce-resize') === 'false') {
9316          return false;
9317        }
9318        if (elm === editor.getBody()) {
9319          return false;
9320        }
9321        if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
9322          return is$1(SugarElement.fromDom(elm.firstElementChild), selector);
9323        } else {
9324          return is$1(SugarElement.fromDom(elm), selector);
9325        }
9326      };
9327      const createGhostElement = elm => {
9328        if (isMedia(elm)) {
9329          return dom.create('img', { src: Env.transparentSrc });
9330        } else {
9331          return elm.cloneNode(true);
9332        }
9333      };
9334      const setSizeProp = (element, name, value) => {
9335        if (isNonNullable(value)) {
9336          const targets = getResizeTargets(element);
9337          each$e(targets, target => {
9338            if (target.style[name] || !editor.schema.isValid(target.nodeName.toLowerCase(), name)) {
9339              dom.setStyle(target, name, value);
9340            } else {
9341              dom.setAttrib(target, name, '' + value);
9342            }
9343          });
9344        }
9345      };
9346      const setGhostElmSize = (ghostElm, width, height) => {
9347        setSizeProp(ghostElm, 'width', width);
9348        setSizeProp(ghostElm, 'height', height);
9349      };
9350      const resizeGhostElement = e => {
9351        let deltaX, deltaY, proportional;
9352        let resizeHelperX, resizeHelperY;
9353        deltaX = e.screenX - startX;
9354        deltaY = e.screenY - startY;
9355        width = deltaX * selectedHandle[2] + startW;
9356        height = deltaY * selectedHandle[3] + startH;
9357        width = width < 5 ? 5 : width;
9358        height = height < 5 ? 5 : height;
9359        if ((isImage(selectedElm) || isMedia(selectedElm)) && getResizeImgProportional(editor) !== false) {
9360          proportional = !VK.modifierPressed(e);
9361        } else {
9362          proportional = VK.modifierPressed(e);
9363        }
9364        if (proportional) {
9365          if (abs(deltaX) > abs(deltaY)) {
9366            height = round$1(width * ratio);
9367            width = round$1(height / ratio);
9368          } else {
9369            width = round$1(height / ratio);
9370            height = round$1(width * ratio);
9371          }
9372        }
9373        setGhostElmSize(selectedElmGhost, width, height);
9374        resizeHelperX = selectedHandle.startPos.x + deltaX;
9375        resizeHelperY = selectedHandle.startPos.y + deltaY;
9376        resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0;
9377        resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0;
9378        dom.setStyles(resizeHelper, {
9379          left: resizeHelperX,
9380          top: resizeHelperY,
9381          display: 'block'
9382        });
9383        resizeHelper.innerHTML = width + ' &times; ' + height;
9384        if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) {
9385          dom.setStyle(selectedElmGhost, 'left', selectedElmX + (startW - width));
9386        }
9387        if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) {
9388          dom.setStyle(selectedElmGhost, 'top', selectedElmY + (startH - height));
9389        }
9390        deltaX = rootElement.scrollWidth - startScrollWidth;
9391        deltaY = rootElement.scrollHeight - startScrollHeight;
9392        if (deltaX + deltaY !== 0) {
9393          dom.setStyles(resizeHelper, {
9394            left: resizeHelperX - deltaX,
9395            top: resizeHelperY - deltaY
9396          });
9397        }
9398        if (!resizeStarted) {
9399          fireObjectResizeStart(editor, selectedElm, startW, startH, 'corner-' + selectedHandle.name);
9400          resizeStarted = true;
9401        }
9402      };
9403      const endGhostResize = () => {
9404        const wasResizeStarted = resizeStarted;
9405        resizeStarted = false;
9406        if (wasResizeStarted) {
9407          setSizeProp(selectedElm, 'width', width);
9408          setSizeProp(selectedElm, 'height', height);
9409        }
9410        dom.unbind(editableDoc, 'mousemove', resizeGhostElement);
9411        dom.unbind(editableDoc, 'mouseup', endGhostResize);
9412        if (rootDocument !== editableDoc) {
9413          dom.unbind(rootDocument, 'mousemove', resizeGhostElement);
9414          dom.unbind(rootDocument, 'mouseup', endGhostResize);
9415        }
9416        dom.remove(selectedElmGhost);
9417        dom.remove(resizeHelper);
9418        dom.remove(resizeBackdrop);
9419        showResizeRect(selectedElm);
9420        if (wasResizeStarted) {
9421          fireObjectResized(editor, selectedElm, width, height, 'corner-' + selectedHandle.name);
9422          dom.setAttrib(selectedElm, 'style', dom.getAttrib(selectedElm, 'style'));
9423        }
9424        editor.nodeChanged();
9425      };
9426      const showResizeRect = targetElm => {
9427        unbindResizeHandleEvents();
9428        const position = dom.getPos(targetElm, rootElement);
9429        const selectedElmX = position.x;
9430        const selectedElmY = position.y;
9431        const rect = targetElm.getBoundingClientRect();
9432        const targetWidth = rect.width || rect.right - rect.left;
9433        const targetHeight = rect.height || rect.bottom - rect.top;
9434        if (selectedElm !== targetElm) {
9435          hideResizeRect();
9436          selectedElm = targetElm;
9437          width = height = 0;
9438        }
9439        const e = editor.dispatch('ObjectSelected', { target: targetElm });
9440        if (isResizable(targetElm) && !e.isDefaultPrevented()) {
9441          each$d(resizeHandles, (handle, name) => {
9442            const startDrag = e => {
9443              const target = getResizeTargets(selectedElm)[0];
9444              startX = e.screenX;
9445              startY = e.screenY;
9446              startW = target.clientWidth;
9447              startH = target.clientHeight;
9448              ratio = startH / startW;
9449              selectedHandle = handle;
9450              selectedHandle.name = name;
9451              selectedHandle.startPos = {
9452                x: targetWidth * handle[0] + selectedElmX,
9453                y: targetHeight * handle[1] + selectedElmY
9454              };
9455              startScrollWidth = rootElement.scrollWidth;
9456              startScrollHeight = rootElement.scrollHeight;
9457              resizeBackdrop = dom.add(rootElement, 'div', {
9458                'class': 'mce-resize-backdrop',
9459                'data-mce-bogus': 'all'
9460              });
9461              dom.setStyles(resizeBackdrop, {
9462                position: 'fixed',
9463                left: '0',
9464                top: '0',
9465                width: '100%',
9466                height: '100%'
9467              });
9468              selectedElmGhost = createGhostElement(selectedElm);
9469              dom.addClass(selectedElmGhost, 'mce-clonedresizable');
9470              dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all');
9471              selectedElmGhost.contentEditable = 'false';
9472              dom.setStyles(selectedElmGhost, {
9473                left: selectedElmX,
9474                top: selectedElmY,
9475                margin: 0
9476              });
9477              setGhostElmSize(selectedElmGhost, targetWidth, targetHeight);
9478              selectedElmGhost.removeAttribute(elementSelectionAttr);
9479              rootElement.appendChild(selectedElmGhost);
9480              dom.bind(editableDoc, 'mousemove', resizeGhostElement);
9481              dom.bind(editableDoc, 'mouseup', endGhostResize);
9482              if (rootDocument !== editableDoc) {
9483                dom.bind(rootDocument, 'mousemove', resizeGhostElement);
9484                dom.bind(rootDocument, 'mouseup', endGhostResize);
9485              }
9486              resizeHelper = dom.add(rootElement, 'div', {
9487                'class': 'mce-resize-helper',
9488                'data-mce-bogus': 'all'
9489              }, startW + ' &times; ' + startH);
9490            };
9491            let handleElm = dom.get('mceResizeHandle' + name);
9492            if (handleElm) {
9493              dom.remove(handleElm);
9494            }
9495            handleElm = dom.add(rootElement, 'div', {
9496              'id': 'mceResizeHandle' + name,
9497              'data-mce-bogus': 'all',
9498              'class': 'mce-resizehandle',
9499              'unselectable': true,
9500              'style': 'cursor:' + name + '-resize; margin:0; padding:0'
9501            });
9502            dom.bind(handleElm, 'mousedown', e => {
9503              e.stopImmediatePropagation();
9504              e.preventDefault();
9505              startDrag(e);
9506            });
9507            handle.elm = handleElm;
9508            dom.setStyles(handleElm, {
9509              left: targetWidth * handle[0] + selectedElmX - handleElm.offsetWidth / 2,
9510              top: targetHeight * handle[1] + selectedElmY - handleElm.offsetHeight / 2
9511            });
9512          });
9513        } else {
9514          hideResizeRect(false);
9515        }
9516      };
9517      const throttledShowResizeRect = first$1(showResizeRect, 0);
9518      const hideResizeRect = (removeSelected = true) => {
9519        throttledShowResizeRect.cancel();
9520        unbindResizeHandleEvents();
9521        if (selectedElm && removeSelected) {
9522          selectedElm.removeAttribute(elementSelectionAttr);
9523        }
9524        each$d(resizeHandles, (value, name) => {
9525          const handleElm = dom.get('mceResizeHandle' + name);
9526          if (handleElm) {
9527            dom.unbind(handleElm);
9528            dom.remove(handleElm);
9529          }
9530        });
9531      };
9532      const isChildOrEqual = (node, parent) => dom.isChildOf(node, parent);
9533      const updateResizeRect = e => {
9534        if (resizeStarted || editor.removed || editor.composing) {
9535          return;
9536        }
9537        const targetElm = e.type === 'mousedown' ? e.target : selection.getNode();
9538        const controlElm = closest$3(SugarElement.fromDom(targetElm), controlElmSelector).map(e => e.dom).filter(e => dom.isEditable(e.parentElement)).getOrUndefined();
9539        const selectedValue = isNonNullable(controlElm) ? dom.getAttrib(controlElm, elementSelectionAttr, '1') : '1';
9540        each$e(dom.select(`img[${ elementSelectionAttr }],hr[${ elementSelectionAttr }]`), img => {
9541          img.removeAttribute(elementSelectionAttr);
9542        });
9543        if (isNonNullable(controlElm) && isChildOrEqual(controlElm, rootElement) && editor.hasFocus()) {
9544          disableGeckoResize();
9545          const startElm = selection.getStart(true);
9546          if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) {
9547            dom.setAttrib(controlElm, elementSelectionAttr, selectedValue);
9548            throttledShowResizeRect.throttle(controlElm);
9549            return;
9550          }
9551        }
9552        hideResizeRect();
9553      };
9554      const unbindResizeHandleEvents = () => {
9555        each$d(resizeHandles, handle => {
9556          if (handle.elm) {
9557            dom.unbind(handle.elm);
9558            delete handle.elm;
9559          }
9560        });
9561      };
9562      const disableGeckoResize = () => {
9563        try {
9564          editor.getDoc().execCommand('enableObjectResizing', false, 'false');
9565        } catch (ex) {
9566        }
9567      };
9568      editor.on('init', () => {
9569        disableGeckoResize();
9570        editor.on('NodeChange ResizeEditor ResizeWindow ResizeContent drop', updateResizeRect);
9571        editor.on('keyup compositionend', e => {
9572          if (selectedElm && selectedElm.nodeName === 'TABLE') {
9573            updateResizeRect(e);
9574          }
9575        });
9576        editor.on('hide blur', hideResizeRect);
9577        editor.on('contextmenu longpress', contextMenuSelectImage, true);
9578      });
9579      editor.on('remove', unbindResizeHandleEvents);
9580      const destroy = () => {
9581        throttledShowResizeRect.cancel();
9582        selectedElm = selectedElmGhost = resizeBackdrop = null;
9583      };
9584      return {
9585        isResizable,
9586        showResizeRect,
9587        hideResizeRect,
9588        updateResizeRect,
9589        destroy
9590      };
9591    };
9592
9593    const setStart = (rng, situ) => {
9594      situ.fold(e => {
9595        rng.setStartBefore(e.dom);
9596      }, (e, o) => {
9597        rng.setStart(e.dom, o);
9598      }, e => {
9599        rng.setStartAfter(e.dom);
9600      });
9601    };
9602    const setFinish = (rng, situ) => {
9603      situ.fold(e => {
9604        rng.setEndBefore(e.dom);
9605      }, (e, o) => {
9606        rng.setEnd(e.dom, o);
9607      }, e => {
9608        rng.setEndAfter(e.dom);
9609      });
9610    };
9611    const relativeToNative = (win, startSitu, finishSitu) => {
9612      const range = win.document.createRange();
9613      setStart(range, startSitu);
9614      setFinish(range, finishSitu);
9615      return range;
9616    };
9617    const exactToNative = (win, start, soffset, finish, foffset) => {
9618      const rng = win.document.createRange();
9619      rng.setStart(start.dom, soffset);
9620      rng.setEnd(finish.dom, foffset);
9621      return rng;
9622    };
9623
9624    const adt$3 = Adt.generate([
9625      {
9626        ltr: [
9627          'start',
9628          'soffset',
9629          'finish',
9630          'foffset'
9631        ]
9632      },
9633      {
9634        rtl: [
9635          'start',
9636          'soffset',
9637          'finish',
9638          'foffset'
9639        ]
9640      }
9641    ]);
9642    const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset);
9643    const getRanges = (win, selection) => selection.match({
9644      domRange: rng => {
9645        return {
9646          ltr: constant(rng),
9647          rtl: Optional.none
9648        };
9649      },
9650      relative: (startSitu, finishSitu) => {
9651        return {
9652          ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
9653          rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
9654        };
9655      },
9656      exact: (start, soffset, finish, foffset) => {
9657        return {
9658          ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)),
9659          rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset)))
9660        };
9661      }
9662    });
9663    const doDiagnose = (win, ranges) => {
9664      const rng = ranges.ltr();
9665      if (rng.collapsed) {
9666        const reversed = ranges.rtl().filter(rev => rev.collapsed === false);
9667        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));
9668      } else {
9669        return fromRange(win, adt$3.ltr, rng);
9670      }
9671    };
9672    const diagnose = (win, selection) => {
9673      const ranges = getRanges(win, selection);
9674      return doDiagnose(win, ranges);
9675    };
9676    adt$3.ltr;
9677    adt$3.rtl;
9678
9679    const create$a = (start, soffset, finish, foffset) => ({
9680      start,
9681      soffset,
9682      finish,
9683      foffset
9684    });
9685    const SimRange = { create: create$a };
9686
9687    const caretPositionFromPoint = (doc, x, y) => {
9688      var _a, _b;
9689      return Optional.from((_b = (_a = doc.dom).caretPositionFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y)).bind(pos => {
9690        if (pos.offsetNode === null) {
9691          return Optional.none();
9692        }
9693        const r = doc.dom.createRange();
9694        r.setStart(pos.offsetNode, pos.offset);
9695        r.collapse();
9696        return Optional.some(r);
9697      });
9698    };
9699    const caretRangeFromPoint = (doc, x, y) => {
9700      var _a, _b;
9701      return Optional.from((_b = (_a = doc.dom).caretRangeFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y));
9702    };
9703    const availableSearch = (() => {
9704      if (document.caretPositionFromPoint) {
9705        return caretPositionFromPoint;
9706      } else if (document.caretRangeFromPoint) {
9707        return caretRangeFromPoint;
9708      } else {
9709        return Optional.none;
9710      }
9711    })();
9712    const fromPoint$1 = (win, x, y) => {
9713      const doc = SugarElement.fromDom(win.document);
9714      return availableSearch(doc, x, y).map(rng => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
9715    };
9716
9717    const adt$2 = Adt.generate([
9718      { before: ['element'] },
9719      {
9720        on: [
9721          'element',
9722          'offset'
9723        ]
9724      },
9725      { after: ['element'] }
9726    ]);
9727    const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
9728    const getStart$2 = situ => situ.fold(identity, identity, identity);
9729    const before$1 = adt$2.before;
9730    const on = adt$2.on;
9731    const after$1 = adt$2.after;
9732    const Situ = {
9733      before: before$1,
9734      on,
9735      after: after$1,
9736      cata,
9737      getStart: getStart$2
9738    };
9739
9740    const adt$1 = Adt.generate([
9741      { domRange: ['rng'] },
9742      {
9743        relative: [
9744          'startSitu',
9745          'finishSitu'
9746        ]
9747      },
9748      {
9749        exact: [
9750          'start',
9751          'soffset',
9752          'finish',
9753          'foffset'
9754        ]
9755      }
9756    ]);
9757    const exactFromRange = simRange => adt$1.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
9758    const getStart$1 = selection => selection.match({
9759      domRange: rng => SugarElement.fromDom(rng.startContainer),
9760      relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
9761      exact: (start, _soffset, _finish, _foffset) => start
9762    });
9763    const domRange = adt$1.domRange;
9764    const relative = adt$1.relative;
9765    const exact = adt$1.exact;
9766    const getWin = selection => {
9767      const start = getStart$1(selection);
9768      return defaultView(start);
9769    };
9770    const range = SimRange.create;
9771    const SimSelection = {
9772      domRange,
9773      relative,
9774      exact,
9775      exactFromRange,
9776      getWin,
9777      range
9778    };
9779
9780    const beforeSpecial = (element, offset) => {
9781      const name$1 = name(element);
9782      if ('input' === name$1) {
9783        return Situ.after(element);
9784      } else if (!contains$2([
9785          'br',
9786          'img'
9787        ], name$1)) {
9788        return Situ.on(element, offset);
9789      } else {
9790        return offset === 0 ? Situ.before(element) : Situ.after(element);
9791      }
9792    };
9793    const preprocessRelative = (startSitu, finishSitu) => {
9794      const start = startSitu.fold(Situ.before, beforeSpecial, Situ.after);
9795      const finish = finishSitu.fold(Situ.before, beforeSpecial, Situ.after);
9796      return SimSelection.relative(start, finish);
9797    };
9798    const preprocessExact = (start, soffset, finish, foffset) => {
9799      const startSitu = beforeSpecial(start, soffset);
9800      const finishSitu = beforeSpecial(finish, foffset);
9801      return SimSelection.relative(startSitu, finishSitu);
9802    };
9803    const preprocess = selection => selection.match({
9804      domRange: rng => {
9805        const start = SugarElement.fromDom(rng.startContainer);
9806        const finish = SugarElement.fromDom(rng.endContainer);
9807        return preprocessExact(start, rng.startOffset, finish, rng.endOffset);
9808      },
9809      relative: preprocessRelative,
9810      exact: preprocessExact
9811    });
9812
9813    const fromElements = (elements, scope) => {
9814      const doc = scope || document;
9815      const fragment = doc.createDocumentFragment();
9816      each$e(elements, element => {
9817        fragment.appendChild(element.dom);
9818      });
9819      return SugarElement.fromDom(fragment);
9820    };
9821
9822    const toNative = selection => {
9823      const win = SimSelection.getWin(selection).dom;
9824      const getDomRange = (start, soffset, finish, foffset) => exactToNative(win, start, soffset, finish, foffset);
9825      const filtered = preprocess(selection);
9826      return diagnose(win, filtered).match({
9827        ltr: getDomRange,
9828        rtl: getDomRange
9829      });
9830    };
9831    const getAtPoint = (win, x, y) => fromPoint$1(win, x, y);
9832
9833    const fromPoint = (clientX, clientY, doc) => {
9834      const win = defaultView(SugarElement.fromDom(doc));
9835      return getAtPoint(win.dom, clientX, clientY).map(simRange => {
9836        const rng = doc.createRange();
9837        rng.setStart(simRange.start.dom, simRange.soffset);
9838        rng.setEnd(simRange.finish.dom, simRange.foffset);
9839        return rng;
9840      }).getOrUndefined();
9841    };
9842
9843    const isEq$4 = (rng1, rng2) => {
9844      return isNonNullable(rng1) && isNonNullable(rng2) && (rng1.startContainer === rng2.startContainer && rng1.startOffset === rng2.startOffset) && (rng1.endContainer === rng2.endContainer && rng1.endOffset === rng2.endOffset);
9845    };
9846
9847    const findParent = (node, rootNode, predicate) => {
9848      let currentNode = node;
9849      while (currentNode && currentNode !== rootNode) {
9850        if (predicate(currentNode)) {
9851          return currentNode;
9852        }
9853        currentNode = currentNode.parentNode;
9854      }
9855      return null;
9856    };
9857    const hasParent$1 = (node, rootNode, predicate) => findParent(node, rootNode, predicate) !== null;
9858    const hasParentWithName = (node, rootNode, name) => hasParent$1(node, rootNode, node => node.nodeName === name);
9859    const isCeFalseCaretContainer = (node, rootNode) => isCaretContainer$2(node) && !hasParent$1(node, rootNode, isCaretNode);
9860    const hasBrBeforeAfter = (dom, node, left) => {
9861      const parentNode = node.parentNode;
9862      if (parentNode) {
9863        const walker = new DomTreeWalker(node, dom.getParent(parentNode, dom.isBlock) || dom.getRoot());
9864        let currentNode;
9865        while (currentNode = walker[left ? 'prev' : 'next']()) {
9866          if (isBr$6(currentNode)) {
9867            return true;
9868          }
9869        }
9870      }
9871      return false;
9872    };
9873    const isPrevNode = (node, name) => {
9874      var _a;
9875      return ((_a = node.previousSibling) === null || _a === void 0 ? void 0 : _a.nodeName) === name;
9876    };
9877    const hasContentEditableFalseParent = (root, node) => {
9878      let currentNode = node;
9879      while (currentNode && currentNode !== root) {
9880        if (isContentEditableFalse$b(currentNode)) {
9881          return true;
9882        }
9883        currentNode = currentNode.parentNode;
9884      }
9885      return false;
9886    };
9887    const findTextNodeRelative = (dom, isAfterNode, collapsed, left, startNode) => {
9888      const body = dom.getRoot();
9889      const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
9890      const parentNode = startNode.parentNode;
9891      let lastInlineElement;
9892      let node;
9893      if (!parentNode) {
9894        return Optional.none();
9895      }
9896      const parentBlockContainer = dom.getParent(parentNode, dom.isBlock) || body;
9897      if (left && isBr$6(startNode) && isAfterNode && dom.isEmpty(parentBlockContainer)) {
9898        return Optional.some(CaretPosition(parentNode, dom.nodeIndex(startNode)));
9899      }
9900      const walker = new DomTreeWalker(startNode, parentBlockContainer);
9901      while (node = walker[left ? 'prev' : 'next']()) {
9902        if (dom.getContentEditableParent(node) === 'false' || isCeFalseCaretContainer(node, body)) {
9903          return Optional.none();
9904        }
9905        if (isText$a(node) && node.data.length > 0) {
9906          if (!hasParentWithName(node, body, 'A')) {
9907            return Optional.some(CaretPosition(node, left ? node.data.length : 0));
9908          }
9909          return Optional.none();
9910        }
9911        if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
9912          return Optional.none();
9913        }
9914        lastInlineElement = node;
9915      }
9916      if (isComment(lastInlineElement)) {
9917        return Optional.none();
9918      }
9919      if (collapsed && lastInlineElement) {
9920        return Optional.some(CaretPosition(lastInlineElement, 0));
9921      }
9922      return Optional.none();
9923    };
9924    const normalizeEndPoint = (dom, collapsed, start, rng) => {
9925      const body = dom.getRoot();
9926      let node;
9927      let normalized = false;
9928      let container = start ? rng.startContainer : rng.endContainer;
9929      let offset = start ? rng.startOffset : rng.endOffset;
9930      const isAfterNode = isElement$6(container) && offset === container.childNodes.length;
9931      const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
9932      let directionLeft = start;
9933      if (isCaretContainer$2(container)) {
9934        return Optional.none();
9935      }
9936      if (isElement$6(container) && offset > container.childNodes.length - 1) {
9937        directionLeft = false;
9938      }
9939      if (isDocument$1(container)) {
9940        container = body;
9941        offset = 0;
9942      }
9943      if (container === body) {
9944        if (directionLeft) {
9945          node = container.childNodes[offset > 0 ? offset - 1 : 0];
9946          if (node) {
9947            if (isCaretContainer$2(node)) {
9948              return Optional.none();
9949            }
9950            if (nonEmptyElementsMap[node.nodeName] || isTable$2(node)) {
9951              return Optional.none();
9952            }
9953          }
9954        }
9955        if (container.hasChildNodes()) {
9956          offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
9957          container = container.childNodes[offset];
9958          offset = isText$a(container) && isAfterNode ? container.data.length : 0;
9959          if (!collapsed && container === body.lastChild && isTable$2(container)) {
9960            return Optional.none();
9961          }
9962          if (hasContentEditableFalseParent(body, container) || isCaretContainer$2(container)) {
9963            return Optional.none();
9964          }
9965          if (container.hasChildNodes() && !isTable$2(container)) {
9966            node = container;
9967            const walker = new DomTreeWalker(container, body);
9968            do {
9969              if (isContentEditableFalse$b(node) || isCaretContainer$2(node)) {
9970                normalized = false;
9971                break;
9972              }
9973              if (isText$a(node) && node.data.length > 0) {
9974                offset = directionLeft ? 0 : node.data.length;
9975                container = node;
9976                normalized = true;
9977                break;
9978              }
9979              if (nonEmptyElementsMap[node.nodeName.toLowerCase()] && !isTableCellOrCaption(node)) {
9980                offset = dom.nodeIndex(node);
9981                container = node.parentNode;
9982                if (!directionLeft) {
9983                  offset++;
9984                }
9985                normalized = true;
9986                break;
9987              }
9988            } while (node = directionLeft ? walker.next() : walker.prev());
9989          }
9990        }
9991      }
9992      if (collapsed) {
9993        if (isText$a(container) && offset === 0) {
9994          findTextNodeRelative(dom, isAfterNode, collapsed, true, container).each(pos => {
9995            container = pos.container();
9996            offset = pos.offset();
9997            normalized = true;
9998          });
9999        }
10000        if (isElement$6(container)) {
10001          node = container.childNodes[offset];
10002          if (!node) {
10003            node = container.childNodes[offset - 1];
10004          }
10005          if (node && isBr$6(node) && !isPrevNode(node, 'A') && !hasBrBeforeAfter(dom, node, false) && !hasBrBeforeAfter(dom, node, true)) {
10006            findTextNodeRelative(dom, isAfterNode, collapsed, true, node).each(pos => {
10007              container = pos.container();
10008              offset = pos.offset();
10009              normalized = true;
10010            });
10011          }
10012        }
10013      }
10014      if (directionLeft && !collapsed && isText$a(container) && offset === container.data.length) {
10015        findTextNodeRelative(dom, isAfterNode, collapsed, false, container).each(pos => {
10016          container = pos.container();
10017          offset = pos.offset();
10018          normalized = true;
10019        });
10020      }
10021      return normalized && container ? Optional.some(CaretPosition(container, offset)) : Optional.none();
10022    };
10023    const normalize$2 = (dom, rng) => {
10024      const collapsed = rng.collapsed, normRng = rng.cloneRange();
10025      const startPos = CaretPosition.fromRangeStart(rng);
10026      normalizeEndPoint(dom, collapsed, true, normRng).each(pos => {
10027        if (!collapsed || !CaretPosition.isAbove(startPos, pos)) {
10028          normRng.setStart(pos.container(), pos.offset());
10029        }
10030      });
10031      if (!collapsed) {
10032        normalizeEndPoint(dom, collapsed, false, normRng).each(pos => {
10033          normRng.setEnd(pos.container(), pos.offset());
10034        });
10035      }
10036      if (collapsed) {
10037        normRng.collapse(true);
10038      }
10039      return isEq$4(rng, normRng) ? Optional.none() : Optional.some(normRng);
10040    };
10041
10042    const splitText = (node, offset) => {
10043      return node.splitText(offset);
10044    };
10045    const split = rng => {
10046      let startContainer = rng.startContainer, startOffset = rng.startOffset, endContainer = rng.endContainer, endOffset = rng.endOffset;
10047      if (startContainer === endContainer && isText$a(startContainer)) {
10048        if (startOffset > 0 && startOffset < startContainer.data.length) {
10049          endContainer = splitText(startContainer, startOffset);
10050          startContainer = endContainer.previousSibling;
10051          if (endOffset > startOffset) {
10052            endOffset = endOffset - startOffset;
10053            const newContainer = splitText(endContainer, endOffset).previousSibling;
10054            startContainer = endContainer = newContainer;
10055            endOffset = newContainer.data.length;
10056            startOffset = 0;
10057          } else {
10058            endOffset = 0;
10059          }
10060        }
10061      } else {
10062        if (isText$a(startContainer) && startOffset > 0 && startOffset < startContainer.data.length) {
10063          startContainer = splitText(startContainer, startOffset);
10064          startOffset = 0;
10065        }
10066        if (isText$a(endContainer) && endOffset > 0 && endOffset < endContainer.data.length) {
10067          const newContainer = splitText(endContainer, endOffset).previousSibling;
10068          endContainer = newContainer;
10069          endOffset = newContainer.data.length;
10070        }
10071      }
10072      return {
10073        startContainer,
10074        startOffset,
10075        endContainer,
10076        endOffset
10077      };
10078    };
10079
10080    const RangeUtils = dom => {
10081      const walk = (rng, callback) => {
10082        return walk$3(dom, rng, callback);
10083      };
10084      const split$1 = split;
10085      const normalize = rng => {
10086        return normalize$2(dom, rng).fold(never, normalizedRng => {
10087          rng.setStart(normalizedRng.startContainer, normalizedRng.startOffset);
10088          rng.setEnd(normalizedRng.endContainer, normalizedRng.endOffset);
10089          return true;
10090        });
10091      };
10092      const expand = (rng, options = { type: 'word' }) => {
10093        if (options.type === 'word') {
10094          const rangeLike = expandRng(dom, rng, [{ inline: 'span' }]);
10095          const newRange = dom.createRng();
10096          newRange.setStart(rangeLike.startContainer, rangeLike.startOffset);
10097          newRange.setEnd(rangeLike.endContainer, rangeLike.endOffset);
10098          return newRange;
10099        }
10100        return rng;
10101      };
10102      return {
10103        walk,
10104        split: split$1,
10105        expand,
10106        normalize
10107      };
10108    };
10109    RangeUtils.compareRanges = isEq$4;
10110    RangeUtils.getCaretRangeFromPoint = fromPoint;
10111    RangeUtils.getSelectedNode = getSelectedNode;
10112    RangeUtils.getNode = getNode$1;
10113
10114    const Dimension = (name, getOffset) => {
10115      const set = (element, h) => {
10116        if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
10117          throw new Error(name + '.set accepts only positive integer values. Value was ' + h);
10118        }
10119        const dom = element.dom;
10120        if (isSupported(dom)) {
10121          dom.style[name] = h + 'px';
10122        }
10123      };
10124      const get = element => {
10125        const r = getOffset(element);
10126        if (r <= 0 || r === null) {
10127          const css = get$7(element, name);
10128          return parseFloat(css) || 0;
10129        }
10130        return r;
10131      };
10132      const getOuter = get;
10133      const aggregate = (element, properties) => foldl(properties, (acc, property) => {
10134        const val = get$7(element, property);
10135        const value = val === undefined ? 0 : parseInt(val, 10);
10136        return isNaN(value) ? acc : acc + value;
10137      }, 0);
10138      const max = (element, value, properties) => {
10139        const cumulativeInclusions = aggregate(element, properties);
10140        const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0;
10141        return absoluteMax;
10142      };
10143      return {
10144        set,
10145        get,
10146        getOuter,
10147        aggregate,
10148        max
10149      };
10150    };
10151
10152    const api = Dimension('height', element => {
10153      const dom = element.dom;
10154      return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
10155    });
10156    const get$2 = element => api.get(element);
10157
10158    const getDocument = () => SugarElement.fromDom(document);
10159
10160    const walkUp = (navigation, doc) => {
10161      const frame = navigation.view(doc);
10162      return frame.fold(constant([]), f => {
10163        const parent = navigation.owner(f);
10164        const rest = walkUp(navigation, parent);
10165        return [f].concat(rest);
10166      });
10167    };
10168    const pathTo = (element, navigation) => {
10169      const d = navigation.owner(element);
10170      return walkUp(navigation, d);
10171    };
10172
10173    const view = doc => {
10174      var _a;
10175      const element = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement);
10176      return element.map(SugarElement.fromDom);
10177    };
10178    const owner = element => documentOrOwner(element);
10179
10180    var Navigation = /*#__PURE__*/Object.freeze({
10181        __proto__: null,
10182        view: view,
10183        owner: owner
10184    });
10185
10186    const find = element => {
10187      const doc = getDocument();
10188      const scroll = get$5(doc);
10189      const frames = pathTo(element, Navigation);
10190      const offset = viewport(element);
10191      const r = foldr(frames, (b, a) => {
10192        const loc = viewport(a);
10193        return {
10194          left: b.left + loc.left,
10195          top: b.top + loc.top
10196        };
10197      }, {
10198        left: 0,
10199        top: 0
10200      });
10201      return SugarPosition(r.left + offset.left + scroll.left, r.top + offset.top + scroll.top);
10202    };
10203
10204    const excludeFromDescend = element => name(element) === 'textarea';
10205    const fireScrollIntoViewEvent = (editor, data) => {
10206      const scrollEvent = editor.dispatch('ScrollIntoView', data);
10207      return scrollEvent.isDefaultPrevented();
10208    };
10209    const fireAfterScrollIntoViewEvent = (editor, data) => {
10210      editor.dispatch('AfterScrollIntoView', data);
10211    };
10212    const descend = (element, offset) => {
10213      const children = children$1(element);
10214      if (children.length === 0 || excludeFromDescend(element)) {
10215        return {
10216          element,
10217          offset
10218        };
10219      } else if (offset < children.length && !excludeFromDescend(children[offset])) {
10220        return {
10221          element: children[offset],
10222          offset: 0
10223        };
10224      } else {
10225        const last = children[children.length - 1];
10226        if (excludeFromDescend(last)) {
10227          return {
10228            element,
10229            offset
10230          };
10231        } else {
10232          if (name(last) === 'img') {
10233            return {
10234              element: last,
10235              offset: 1
10236            };
10237          } else if (isText$b(last)) {
10238            return {
10239              element: last,
10240              offset: get$3(last).length
10241            };
10242          } else {
10243            return {
10244              element: last,
10245              offset: children$1(last).length
10246            };
10247          }
10248        }
10249      }
10250    };
10251    const markerInfo = (element, cleanupFun) => {
10252      const pos = absolute(element);
10253      const height = get$2(element);
10254      return {
10255        element,
10256        bottom: pos.top + height,
10257        height,
10258        pos,
10259        cleanup: cleanupFun
10260      };
10261    };
10262    const createMarker$1 = (element, offset) => {
10263      const startPoint = descend(element, offset);
10264      const span = SugarElement.fromHtml('<span data-mce-bogus="all" style="display: inline-block;">' + ZWSP$1 + '</span>');
10265      before$3(startPoint.element, span);
10266      return markerInfo(span, () => remove$5(span));
10267    };
10268    const elementMarker = element => markerInfo(SugarElement.fromDom(element), noop);
10269    const withMarker = (editor, f, rng, alignToTop) => {
10270      preserveWith(editor, (_s, _e) => applyWithMarker(editor, f, rng, alignToTop), rng);
10271    };
10272    const withScrollEvents = (editor, doc, f, marker, alignToTop) => {
10273      const data = {
10274        elm: marker.element.dom,
10275        alignToTop
10276      };
10277      if (fireScrollIntoViewEvent(editor, data)) {
10278        return;
10279      }
10280      const scrollTop = get$5(doc).top;
10281      f(doc, scrollTop, marker, alignToTop);
10282      fireAfterScrollIntoViewEvent(editor, data);
10283    };
10284    const applyWithMarker = (editor, f, rng, alignToTop) => {
10285      const body = SugarElement.fromDom(editor.getBody());
10286      const doc = SugarElement.fromDom(editor.getDoc());
10287      reflow(body);
10288      const marker = createMarker$1(SugarElement.fromDom(rng.startContainer), rng.startOffset);
10289      withScrollEvents(editor, doc, f, marker, alignToTop);
10290      marker.cleanup();
10291    };
10292    const withElement = (editor, element, f, alignToTop) => {
10293      const doc = SugarElement.fromDom(editor.getDoc());
10294      withScrollEvents(editor, doc, f, elementMarker(element), alignToTop);
10295    };
10296    const preserveWith = (editor, f, rng) => {
10297      const startElement = rng.startContainer;
10298      const startOffset = rng.startOffset;
10299      const endElement = rng.endContainer;
10300      const endOffset = rng.endOffset;
10301      f(SugarElement.fromDom(startElement), SugarElement.fromDom(endElement));
10302      const newRng = editor.dom.createRng();
10303      newRng.setStart(startElement, startOffset);
10304      newRng.setEnd(endElement, endOffset);
10305      editor.selection.setRng(rng);
10306    };
10307    const scrollToMarker = (marker, alignToTop) => marker.element.dom.scrollIntoView({ block: alignToTop ? 'start' : 'end' });
10308    const intoWindowIfNeeded = (scrollTop, viewHeight, marker, alignToTop) => {
10309      const viewportBottom = viewHeight + scrollTop;
10310      const markerTop = marker.pos.top;
10311      const markerBottom = marker.bottom;
10312      const largerThanViewport = markerBottom - markerTop >= viewHeight;
10313      if (markerTop < scrollTop) {
10314        scrollToMarker(marker, alignToTop !== false);
10315      } else if (markerTop > viewportBottom) {
10316        const align = largerThanViewport ? alignToTop !== false : alignToTop === true;
10317        scrollToMarker(marker, align);
10318      } else if (markerBottom > viewportBottom && !largerThanViewport) {
10319        scrollToMarker(marker, alignToTop === true);
10320      }
10321    };
10322    const intoWindow = (doc, scrollTop, marker, alignToTop) => {
10323      const viewHeight = defaultView(doc).dom.innerHeight;
10324      intoWindowIfNeeded(scrollTop, viewHeight, marker, alignToTop);
10325    };
10326    const intoFrame = (doc, scrollTop, marker, alignToTop) => {
10327      const frameViewHeight = defaultView(doc).dom.innerHeight;
10328      intoWindowIfNeeded(scrollTop, frameViewHeight, marker, alignToTop);
10329      const op = find(marker.element);
10330      const viewportBounds = getBounds(window);
10331      if (op.top < viewportBounds.y) {
10332        intoView(marker.element, alignToTop !== false);
10333      } else if (op.top > viewportBounds.bottom) {
10334        intoView(marker.element, alignToTop === true);
10335      }
10336    };
10337    const rangeIntoWindow = (editor, rng, alignToTop) => withMarker(editor, intoWindow, rng, alignToTop);
10338    const elementIntoWindow = (editor, element, alignToTop) => withElement(editor, element, intoWindow, alignToTop);
10339    const rangeIntoFrame = (editor, rng, alignToTop) => withMarker(editor, intoFrame, rng, alignToTop);
10340    const elementIntoFrame = (editor, element, alignToTop) => withElement(editor, element, intoFrame, alignToTop);
10341    const scrollElementIntoView = (editor, element, alignToTop) => {
10342      const scroller = editor.inline ? elementIntoWindow : elementIntoFrame;
10343      scroller(editor, element, alignToTop);
10344    };
10345    const scrollRangeIntoView = (editor, rng, alignToTop) => {
10346      const scroller = editor.inline ? rangeIntoWindow : rangeIntoFrame;
10347      scroller(editor, rng, alignToTop);
10348    };
10349
10350    const focus$1 = element => element.dom.focus();
10351    const hasFocus$1 = element => {
10352      const root = getRootNode(element).dom;
10353      return element.dom === root.activeElement;
10354    };
10355    const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
10356    const search = element => active$1(getRootNode(element)).filter(e => element.dom.contains(e.dom));
10357
10358    const clamp$1 = (offset, element) => {
10359      const max = isText$b(element) ? get$3(element).length : children$1(element).length + 1;
10360      if (offset > max) {
10361        return max;
10362      } else if (offset < 0) {
10363        return 0;
10364      }
10365      return offset;
10366    };
10367    const normalizeRng = rng => SimSelection.range(rng.start, clamp$1(rng.soffset, rng.start), rng.finish, clamp$1(rng.foffset, rng.finish));
10368    const isOrContains = (root, elm) => !isRestrictedNode(elm.dom) && (contains(root, elm) || eq(root, elm));
10369    const isRngInRoot = root => rng => isOrContains(root, rng.start) && isOrContains(root, rng.finish);
10370    const shouldStore = editor => editor.inline || Env.browser.isFirefox();
10371    const nativeRangeToSelectionRange = r => SimSelection.range(SugarElement.fromDom(r.startContainer), r.startOffset, SugarElement.fromDom(r.endContainer), r.endOffset);
10372    const readRange = win => {
10373      const selection = win.getSelection();
10374      const rng = !selection || selection.rangeCount === 0 ? Optional.none() : Optional.from(selection.getRangeAt(0));
10375      return rng.map(nativeRangeToSelectionRange);
10376    };
10377    const getBookmark = root => {
10378      const win = defaultView(root);
10379      return readRange(win.dom).filter(isRngInRoot(root));
10380    };
10381    const validate = (root, bookmark) => Optional.from(bookmark).filter(isRngInRoot(root)).map(normalizeRng);
10382    const bookmarkToNativeRng = bookmark => {
10383      const rng = document.createRange();
10384      try {
10385        rng.setStart(bookmark.start.dom, bookmark.soffset);
10386        rng.setEnd(bookmark.finish.dom, bookmark.foffset);
10387        return Optional.some(rng);
10388      } catch (_) {
10389        return Optional.none();
10390      }
10391    };
10392    const store = editor => {
10393      const newBookmark = shouldStore(editor) ? getBookmark(SugarElement.fromDom(editor.getBody())) : Optional.none();
10394      editor.bookmark = newBookmark.isSome() ? newBookmark : editor.bookmark;
10395    };
10396    const getRng = editor => {
10397      const bookmark = editor.bookmark ? editor.bookmark : Optional.none();
10398      return bookmark.bind(x => validate(SugarElement.fromDom(editor.getBody()), x)).bind(bookmarkToNativeRng);
10399    };
10400    const restore = editor => {
10401      getRng(editor).each(rng => editor.selection.setRng(rng));
10402    };
10403
10404    const isEditorUIElement$1 = elm => {
10405      const className = elm.className.toString();
10406      return className.indexOf('tox-') !== -1 || className.indexOf('mce-') !== -1;
10407    };
10408    const FocusManager = { isEditorUIElement: isEditorUIElement$1 };
10409
10410    const wrappedSetTimeout = (callback, time) => {
10411      if (!isNumber(time)) {
10412        time = 0;
10413      }
10414      return setTimeout(callback, time);
10415    };
10416    const wrappedSetInterval = (callback, time) => {
10417      if (!isNumber(time)) {
10418        time = 0;
10419      }
10420      return setInterval(callback, time);
10421    };
10422    const Delay = {
10423      setEditorTimeout: (editor, callback, time) => {
10424        return wrappedSetTimeout(() => {
10425          if (!editor.removed) {
10426            callback();
10427          }
10428        }, time);
10429      },
10430      setEditorInterval: (editor, callback, time) => {
10431        const timer = wrappedSetInterval(() => {
10432          if (!editor.removed) {
10433            callback();
10434          } else {
10435            clearInterval(timer);
10436          }
10437        }, time);
10438        return timer;
10439      }
10440    };
10441
10442    const isManualNodeChange = e => {
10443      return e.type === 'nodechange' && e.selectionChange;
10444    };
10445    const registerPageMouseUp = (editor, throttledStore) => {
10446      const mouseUpPage = () => {
10447        throttledStore.throttle();
10448      };
10449      DOMUtils.DOM.bind(document, 'mouseup', mouseUpPage);
10450      editor.on('remove', () => {
10451        DOMUtils.DOM.unbind(document, 'mouseup', mouseUpPage);
10452      });
10453    };
10454    const registerMouseUp = (editor, throttledStore) => {
10455      editor.on('mouseup touchend', _e => {
10456        throttledStore.throttle();
10457      });
10458    };
10459    const registerEditorEvents = (editor, throttledStore) => {
10460      registerMouseUp(editor, throttledStore);
10461      editor.on('keyup NodeChange AfterSetSelectionRange', e => {
10462        if (!isManualNodeChange(e)) {
10463          store(editor);
10464        }
10465      });
10466    };
10467    const register$6 = editor => {
10468      const throttledStore = first$1(() => {
10469        store(editor);
10470      }, 0);
10471      editor.on('init', () => {
10472        if (editor.inline) {
10473          registerPageMouseUp(editor, throttledStore);
10474        }
10475        registerEditorEvents(editor, throttledStore);
10476      });
10477      editor.on('remove', () => {
10478        throttledStore.cancel();
10479      });
10480    };
10481
10482    let documentFocusInHandler;
10483    const DOM$9 = DOMUtils.DOM;
10484    const isEditorUIElement = elm => {
10485      return isElement$6(elm) && FocusManager.isEditorUIElement(elm);
10486    };
10487    const isEditorContentAreaElement = elm => {
10488      const classList = elm.classList;
10489      if (classList !== undefined) {
10490        return classList.contains('tox-edit-area') || classList.contains('tox-edit-area__iframe') || classList.contains('mce-content-body');
10491      } else {
10492        return false;
10493      }
10494    };
10495    const isUIElement = (editor, elm) => {
10496      const customSelector = getCustomUiSelector(editor);
10497      const parent = DOM$9.getParent(elm, elm => {
10498        return isEditorUIElement(elm) || (customSelector ? editor.dom.is(elm, customSelector) : false);
10499      });
10500      return parent !== null;
10501    };
10502    const getActiveElement = editor => {
10503      try {
10504        const root = getRootNode(SugarElement.fromDom(editor.getElement()));
10505        return active$1(root).fold(() => document.body, x => x.dom);
10506      } catch (ex) {
10507        return document.body;
10508      }
10509    };
10510    const registerEvents$1 = (editorManager, e) => {
10511      const editor = e.editor;
10512      register$6(editor);
10513      const toggleContentAreaOnFocus = (editor, fn) => {
10514        if (shouldHighlightOnFocus(editor) && editor.inline !== true) {
10515          const contentArea = SugarElement.fromDom(editor.getContainer());
10516          fn(contentArea, 'tox-edit-focus');
10517        }
10518      };
10519      editor.on('focusin', () => {
10520        const focusedEditor = editorManager.focusedEditor;
10521        if (isEditorContentAreaElement(getActiveElement(editor))) {
10522          toggleContentAreaOnFocus(editor, add$2);
10523        }
10524        if (focusedEditor !== editor) {
10525          if (focusedEditor) {
10526            focusedEditor.dispatch('blur', { focusedEditor: editor });
10527          }
10528          editorManager.setActive(editor);
10529          editorManager.focusedEditor = editor;
10530          editor.dispatch('focus', { blurredEditor: focusedEditor });
10531          editor.focus(true);
10532        }
10533      });
10534      editor.on('focusout', () => {
10535        Delay.setEditorTimeout(editor, () => {
10536          const focusedEditor = editorManager.focusedEditor;
10537          if (!isEditorContentAreaElement(getActiveElement(editor)) || focusedEditor !== editor) {
10538            toggleContentAreaOnFocus(editor, remove$7);
10539          }
10540          if (!isUIElement(editor, getActiveElement(editor)) && focusedEditor === editor) {
10541            editor.dispatch('blur', { focusedEditor: null });
10542            editorManager.focusedEditor = null;
10543          }
10544        });
10545      });
10546      if (!documentFocusInHandler) {
10547        documentFocusInHandler = e => {
10548          const activeEditor = editorManager.activeEditor;
10549          if (activeEditor) {
10550            getOriginalEventTarget(e).each(target => {
10551              const elem = target;
10552              if (elem.ownerDocument === document) {
10553                if (elem !== document.body && !isUIElement(activeEditor, elem) && editorManager.focusedEditor === activeEditor) {
10554                  activeEditor.dispatch('blur', { focusedEditor: null });
10555                  editorManager.focusedEditor = null;
10556                }
10557              }
10558            });
10559          }
10560        };
10561        DOM$9.bind(document, 'focusin', documentFocusInHandler);
10562      }
10563    };
10564    const unregisterDocumentEvents = (editorManager, e) => {
10565      if (editorManager.focusedEditor === e.editor) {
10566        editorManager.focusedEditor = null;
10567      }
10568      if (!editorManager.activeEditor && documentFocusInHandler) {
10569        DOM$9.unbind(document, 'focusin', documentFocusInHandler);
10570        documentFocusInHandler = null;
10571      }
10572    };
10573    const setup$v = editorManager => {
10574      editorManager.on('AddEditor', curry(registerEvents$1, editorManager));
10575      editorManager.on('RemoveEditor', curry(unregisterDocumentEvents, editorManager));
10576    };
10577
10578    const getContentEditableHost = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'true');
10579    const getCollapsedNode = rng => rng.collapsed ? Optional.from(getNode$1(rng.startContainer, rng.startOffset)).map(SugarElement.fromDom) : Optional.none();
10580    const getFocusInElement = (root, rng) => getCollapsedNode(rng).bind(node => {
10581      if (isTableSection(node)) {
10582        return Optional.some(node);
10583      } else if (!contains(root, node)) {
10584        return Optional.some(root);
10585      } else {
10586        return Optional.none();
10587      }
10588    });
10589    const normalizeSelection = (editor, rng) => {
10590      getFocusInElement(SugarElement.fromDom(editor.getBody()), rng).bind(elm => {
10591        return firstPositionIn(elm.dom);
10592      }).fold(() => {
10593        editor.selection.normalize();
10594      }, caretPos => editor.selection.setRng(caretPos.toRange()));
10595    };
10596    const focusBody = body => {
10597      if (body.setActive) {
10598        try {
10599          body.setActive();
10600        } catch (ex) {
10601          body.focus();
10602        }
10603      } else {
10604        body.focus();
10605      }
10606    };
10607    const hasElementFocus = elm => hasFocus$1(elm) || search(elm).isSome();
10608    const hasIframeFocus = editor => isNonNullable(editor.iframeElement) && hasFocus$1(SugarElement.fromDom(editor.iframeElement));
10609    const hasInlineFocus = editor => {
10610      const rawBody = editor.getBody();
10611      return rawBody && hasElementFocus(SugarElement.fromDom(rawBody));
10612    };
10613    const hasUiFocus = editor => {
10614      const dos = getRootNode(SugarElement.fromDom(editor.getElement()));
10615      return active$1(dos).filter(elem => !isEditorContentAreaElement(elem.dom) && isUIElement(editor, elem.dom)).isSome();
10616    };
10617    const hasFocus = editor => editor.inline ? hasInlineFocus(editor) : hasIframeFocus(editor);
10618    const hasEditorOrUiFocus = editor => hasFocus(editor) || hasUiFocus(editor);
10619    const focusEditor = editor => {
10620      const selection = editor.selection;
10621      const body = editor.getBody();
10622      let rng = selection.getRng();
10623      editor.quirks.refreshContentEditable();
10624      if (isNonNullable(editor.bookmark) && !hasFocus(editor)) {
10625        getRng(editor).each(bookmarkRng => {
10626          editor.selection.setRng(bookmarkRng);
10627          rng = bookmarkRng;
10628        });
10629      }
10630      const contentEditableHost = getContentEditableHost(editor, selection.getNode());
10631      if (contentEditableHost && editor.dom.isChildOf(contentEditableHost, body)) {
10632        focusBody(contentEditableHost);
10633        normalizeSelection(editor, rng);
10634        activateEditor(editor);
10635        return;
10636      }
10637      if (!editor.inline) {
10638        if (!Env.browser.isOpera()) {
10639          focusBody(body);
10640        }
10641        editor.getWin().focus();
10642      }
10643      if (Env.browser.isFirefox() || editor.inline) {
10644        focusBody(body);
10645        normalizeSelection(editor, rng);
10646      }
10647      activateEditor(editor);
10648    };
10649    const activateEditor = editor => editor.editorManager.setActive(editor);
10650    const focus = (editor, skipFocus) => {
10651      if (editor.removed) {
10652        return;
10653      }
10654      if (skipFocus) {
10655        activateEditor(editor);
10656      } else {
10657        focusEditor(editor);
10658      }
10659    };
10660
10661    const getEndpointElement = (root, rng, start, real, resolve) => {
10662      const container = start ? rng.startContainer : rng.endContainer;
10663      const offset = start ? rng.startOffset : rng.endOffset;
10664      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);
10665    };
10666    const getStart = (root, rng, real = false) => getEndpointElement(root, rng, true, real, (elm, offset) => Math.min(childNodesCount(elm), offset));
10667    const getEnd$1 = (root, rng, real = false) => getEndpointElement(root, rng, false, real, (elm, offset) => offset > 0 ? offset - 1 : offset);
10668    const skipEmptyTextNodes = (node, forwards) => {
10669      const orig = node;
10670      while (node && isText$a(node) && node.length === 0) {
10671        node = forwards ? node.nextSibling : node.previousSibling;
10672      }
10673      return node || orig;
10674    };
10675    const getNode = (root, rng) => {
10676      if (!rng) {
10677        return root;
10678      }
10679      let startContainer = rng.startContainer;
10680      let endContainer = rng.endContainer;
10681      const startOffset = rng.startOffset;
10682      const endOffset = rng.endOffset;
10683      let node = rng.commonAncestorContainer;
10684      if (!rng.collapsed) {
10685        if (startContainer === endContainer) {
10686          if (endOffset - startOffset < 2) {
10687            if (startContainer.hasChildNodes()) {
10688              node = startContainer.childNodes[startOffset];
10689            }
10690          }
10691        }
10692        if (isText$a(startContainer) && isText$a(endContainer)) {
10693          if (startContainer.length === startOffset) {
10694            startContainer = skipEmptyTextNodes(startContainer.nextSibling, true);
10695          } else {
10696            startContainer = startContainer.parentNode;
10697          }
10698          if (endOffset === 0) {
10699            endContainer = skipEmptyTextNodes(endContainer.previousSibling, false);
10700          } else {
10701            endContainer = endContainer.parentNode;
10702          }
10703          if (startContainer && startContainer === endContainer) {
10704            node = startContainer;
10705          }
10706        }
10707      }
10708      const elm = isText$a(node) ? node.parentNode : node;
10709      return isElement$6(elm) ? elm : root;
10710    };
10711    const getSelectedBlocks = (dom, rng, startElm, endElm) => {
10712      const selectedBlocks = [];
10713      const root = dom.getRoot();
10714      const start = dom.getParent(startElm || getStart(root, rng, rng.collapsed), dom.isBlock);
10715      const end = dom.getParent(endElm || getEnd$1(root, rng, rng.collapsed), dom.isBlock);
10716      if (start && start !== root) {
10717        selectedBlocks.push(start);
10718      }
10719      if (start && end && start !== end) {
10720        let node;
10721        const walker = new DomTreeWalker(start, root);
10722        while ((node = walker.next()) && node !== end) {
10723          if (dom.isBlock(node)) {
10724            selectedBlocks.push(node);
10725          }
10726        }
10727      }
10728      if (end && start !== end && end !== root) {
10729        selectedBlocks.push(end);
10730      }
10731      return selectedBlocks;
10732    };
10733    const select = (dom, node, content) => Optional.from(node).bind(node => Optional.from(node.parentNode).map(parent => {
10734      const idx = dom.nodeIndex(node);
10735      const rng = dom.createRng();
10736      rng.setStart(parent, idx);
10737      rng.setEnd(parent, idx + 1);
10738      if (content) {
10739        moveEndPoint(dom, rng, node, true);
10740        moveEndPoint(dom, rng, node, false);
10741      }
10742      return rng;
10743    }));
10744
10745    const processRanges = (editor, ranges) => map$3(ranges, range => {
10746      const evt = editor.dispatch('GetSelectionRange', { range });
10747      return evt.range !== range ? evt.range : range;
10748    });
10749
10750    const getEnd = element => name(element) === 'img' ? 1 : getOption(element).fold(() => children$1(element).length, v => v.length);
10751    const isTextNodeWithCursorPosition = el => getOption(el).filter(text => text.trim().length !== 0 || text.indexOf(nbsp) > -1).isSome();
10752    const isContentEditableFalse$5 = elem => isHTMLElement(elem) && get$9(elem, 'contenteditable') === 'false';
10753    const elementsWithCursorPosition = [
10754      'img',
10755      'br'
10756    ];
10757    const isCursorPosition = elem => {
10758      const hasCursorPosition = isTextNodeWithCursorPosition(elem);
10759      return hasCursorPosition || contains$2(elementsWithCursorPosition, name(elem)) || isContentEditableFalse$5(elem);
10760    };
10761
10762    const first = element => descendant$1(element, isCursorPosition);
10763    const last = element => descendantRtl(element, isCursorPosition);
10764    const descendantRtl = (scope, predicate) => {
10765      const descend = element => {
10766        const children = children$1(element);
10767        for (let i = children.length - 1; i >= 0; i--) {
10768          const child = children[i];
10769          if (predicate(child)) {
10770            return Optional.some(child);
10771          }
10772          const res = descend(child);
10773          if (res.isSome()) {
10774            return res;
10775          }
10776        }
10777        return Optional.none();
10778      };
10779      return descend(scope);
10780    };
10781
10782    const autocompleteSelector = '[data-mce-autocompleter]';
10783    const create$9 = (editor, range) => {
10784      if (findIn(SugarElement.fromDom(editor.getBody())).isNone()) {
10785        const wrapper = SugarElement.fromHtml('<span data-mce-autocompleter="1" data-mce-bogus="1"></span>', editor.getDoc());
10786        append$1(wrapper, SugarElement.fromDom(range.extractContents()));
10787        range.insertNode(wrapper.dom);
10788        parent(wrapper).each(elm => elm.dom.normalize());
10789        last(wrapper).map(last => {
10790          editor.selection.setCursorLocation(last.dom, getEnd(last));
10791        });
10792      }
10793    };
10794    const detect$1 = elm => closest$3(elm, autocompleteSelector);
10795    const findIn = elm => descendant(elm, autocompleteSelector);
10796    const remove$2 = (editor, elm) => findIn(elm).each(wrapper => {
10797      const bookmark = editor.selection.getBookmark();
10798      unwrap(wrapper);
10799      editor.selection.moveToBookmark(bookmark);
10800    });
10801
10802    const typeLookup = {
10803      '#text': 3,
10804      '#comment': 8,
10805      '#cdata': 4,
10806      '#pi': 7,
10807      '#doctype': 10,
10808      '#document-fragment': 11
10809    };
10810    const walk$2 = (node, root, prev) => {
10811      const startName = prev ? 'lastChild' : 'firstChild';
10812      const siblingName = prev ? 'prev' : 'next';
10813      if (node[startName]) {
10814        return node[startName];
10815      }
10816      if (node !== root) {
10817        let sibling = node[siblingName];
10818        if (sibling) {
10819          return sibling;
10820        }
10821        for (let parent = node.parent; parent && parent !== root; parent = parent.parent) {
10822          sibling = parent[siblingName];
10823          if (sibling) {
10824            return sibling;
10825          }
10826        }
10827      }
10828      return undefined;
10829    };
10830    const isEmptyTextNode = node => {
10831      var _a;
10832      const text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
10833      if (!isWhitespaceText(text)) {
10834        return false;
10835      }
10836      const parentNode = node.parent;
10837      if (parentNode && (parentNode.name !== 'span' || parentNode.attr('style')) && /^[ ]+$/.test(text)) {
10838        return false;
10839      }
10840      return true;
10841    };
10842    const isNonEmptyElement = node => {
10843      const isNamedAnchor = node.name === 'a' && !node.attr('href') && node.attr('id');
10844      return node.attr('name') || node.attr('id') && !node.firstChild || node.attr('data-mce-bookmark') || isNamedAnchor;
10845    };
10846    class AstNode {
10847      static create(name, attrs) {
10848        const node = new AstNode(name, typeLookup[name] || 1);
10849        if (attrs) {
10850          each$d(attrs, (value, attrName) => {
10851            node.attr(attrName, value);
10852          });
10853        }
10854        return node;
10855      }
10856      constructor(name, type) {
10857        this.name = name;
10858        this.type = type;
10859        if (type === 1) {
10860          this.attributes = [];
10861          this.attributes.map = {};
10862        }
10863      }
10864      replace(node) {
10865        const self = this;
10866        if (node.parent) {
10867          node.remove();
10868        }
10869        self.insert(node, self);
10870        self.remove();
10871        return self;
10872      }
10873      attr(name, value) {
10874        const self = this;
10875        if (!isString(name)) {
10876          if (isNonNullable(name)) {
10877            each$d(name, (value, key) => {
10878              self.attr(key, value);
10879            });
10880          }
10881          return self;
10882        }
10883        const attrs = self.attributes;
10884        if (attrs) {
10885          if (value !== undefined) {
10886            if (value === null) {
10887              if (name in attrs.map) {
10888                delete attrs.map[name];
10889                let i = attrs.length;
10890                while (i--) {
10891                  if (attrs[i].name === name) {
10892                    attrs.splice(i, 1);
10893                    return self;
10894                  }
10895                }
10896              }
10897              return self;
10898            }
10899            if (name in attrs.map) {
10900              let i = attrs.length;
10901              while (i--) {
10902                if (attrs[i].name === name) {
10903                  attrs[i].value = value;
10904                  break;
10905                }
10906              }
10907            } else {
10908              attrs.push({
10909                name,
10910                value
10911              });
10912            }
10913            attrs.map[name] = value;
10914            return self;
10915          }
10916          return attrs.map[name];
10917        }
10918        return undefined;
10919      }
10920      clone() {
10921        const self = this;
10922        const clone = new AstNode(self.name, self.type);
10923        const selfAttrs = self.attributes;
10924        if (selfAttrs) {
10925          const cloneAttrs = [];
10926          cloneAttrs.map = {};
10927          for (let i = 0, l = selfAttrs.length; i < l; i++) {
10928            const selfAttr = selfAttrs[i];
10929            if (selfAttr.name !== 'id') {
10930              cloneAttrs[cloneAttrs.length] = {
10931                name: selfAttr.name,
10932                value: selfAttr.value
10933              };
10934              cloneAttrs.map[selfAttr.name] = selfAttr.value;
10935            }
10936          }
10937          clone.attributes = cloneAttrs;
10938        }
10939        clone.value = self.value;
10940        return clone;
10941      }
10942      wrap(wrapper) {
10943        const self = this;
10944        if (self.parent) {
10945          self.parent.insert(wrapper, self);
10946          wrapper.append(self);
10947        }
10948        return self;
10949      }
10950      unwrap() {
10951        const self = this;
10952        for (let node = self.firstChild; node;) {
10953          const next = node.next;
10954          self.insert(node, self, true);
10955          node = next;
10956        }
10957        self.remove();
10958      }
10959      remove() {
10960        const self = this, parent = self.parent, next = self.next, prev = self.prev;
10961        if (parent) {
10962          if (parent.firstChild === self) {
10963            parent.firstChild = next;
10964            if (next) {
10965              next.prev = null;
10966            }
10967          } else if (prev) {
10968            prev.next = next;
10969          }
10970          if (parent.lastChild === self) {
10971            parent.lastChild = prev;
10972            if (prev) {
10973              prev.next = null;
10974            }
10975          } else if (next) {
10976            next.prev = prev;
10977          }
10978          self.parent = self.next = self.prev = null;
10979        }
10980        return self;
10981      }
10982      append(node) {
10983        const self = this;
10984        if (node.parent) {
10985          node.remove();
10986        }
10987        const last = self.lastChild;
10988        if (last) {
10989          last.next = node;
10990          node.prev = last;
10991          self.lastChild = node;
10992        } else {
10993          self.lastChild = self.firstChild = node;
10994        }
10995        node.parent = self;
10996        return node;
10997      }
10998      insert(node, refNode, before) {
10999        if (node.parent) {
11000          node.remove();
11001        }
11002        const parent = refNode.parent || this;
11003        if (before) {
11004          if (refNode === parent.firstChild) {
11005            parent.firstChild = node;
11006          } else if (refNode.prev) {
11007            refNode.prev.next = node;
11008          }
11009          node.prev = refNode.prev;
11010          node.next = refNode;
11011          refNode.prev = node;
11012        } else {
11013          if (refNode === parent.lastChild) {
11014            parent.lastChild = node;
11015          } else if (refNode.next) {
11016            refNode.next.prev = node;
11017          }
11018          node.next = refNode.next;
11019          node.prev = refNode;
11020          refNode.next = node;
11021        }
11022        node.parent = parent;
11023        return node;
11024      }
11025      getAll(name) {
11026        const self = this;
11027        const collection = [];
11028        for (let node = self.firstChild; node; node = walk$2(node, self)) {
11029          if (node.name === name) {
11030            collection.push(node);
11031          }
11032        }
11033        return collection;
11034      }
11035      children() {
11036        const self = this;
11037        const collection = [];
11038        for (let node = self.firstChild; node; node = node.next) {
11039          collection.push(node);
11040        }
11041        return collection;
11042      }
11043      empty() {
11044        const self = this;
11045        if (self.firstChild) {
11046          const nodes = [];
11047          for (let node = self.firstChild; node; node = walk$2(node, self)) {
11048            nodes.push(node);
11049          }
11050          let i = nodes.length;
11051          while (i--) {
11052            const node = nodes[i];
11053            node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
11054          }
11055        }
11056        self.firstChild = self.lastChild = null;
11057        return self;
11058      }
11059      isEmpty(elements, whitespace = {}, predicate) {
11060        var _a;
11061        const self = this;
11062        let node = self.firstChild;
11063        if (isNonEmptyElement(self)) {
11064          return false;
11065        }
11066        if (node) {
11067          do {
11068            if (node.type === 1) {
11069              if (node.attr('data-mce-bogus')) {
11070                continue;
11071              }
11072              if (elements[node.name]) {
11073                return false;
11074              }
11075              if (isNonEmptyElement(node)) {
11076                return false;
11077              }
11078            }
11079            if (node.type === 8) {
11080              return false;
11081            }
11082            if (node.type === 3 && !isEmptyTextNode(node)) {
11083              return false;
11084            }
11085            if (node.type === 3 && node.parent && whitespace[node.parent.name] && isWhitespaceText((_a = node.value) !== null && _a !== void 0 ? _a : '')) {
11086              return false;
11087            }
11088            if (predicate && predicate(node)) {
11089              return false;
11090            }
11091          } while (node = walk$2(node, self));
11092        }
11093        return true;
11094      }
11095      walk(prev) {
11096        return walk$2(this, null, prev);
11097      }
11098    }
11099
11100    const isConditionalComment = (html, startIndex) => /^\s*\[if [\w\W]+\]>.*<!\[endif\](--!?)?>/.test(html.substr(startIndex));
11101    const findCommentEndIndex = (html, isBogus, startIndex = 0) => {
11102      const lcHtml = html.toLowerCase();
11103      if (lcHtml.indexOf('[if ', startIndex) !== -1 && isConditionalComment(lcHtml, startIndex)) {
11104        const endIfIndex = lcHtml.indexOf('[endif]', startIndex);
11105        return lcHtml.indexOf('>', endIfIndex);
11106      } else {
11107        if (isBogus) {
11108          const endIndex = lcHtml.indexOf('>', startIndex);
11109          return endIndex !== -1 ? endIndex : lcHtml.length;
11110        } else {
11111          const endCommentRegexp = /--!?>/g;
11112          endCommentRegexp.lastIndex = startIndex;
11113          const match = endCommentRegexp.exec(html);
11114          return match ? match.index + match[0].length : lcHtml.length;
11115        }
11116      }
11117    };
11118    const findMatchingEndTagIndex = (schema, html, startIndex) => {
11119      const startTagRegExp = /<([!?\/])?([A-Za-z0-9\-_:.]+)/g;
11120      const endTagRegExp = /(?:\s(?:[^'">]+(?:"[^"]*"|'[^']*'))*[^"'>]*(?:"[^">]*|'[^'>]*)?|\s*|\/)>/g;
11121      const voidElements = schema.getVoidElements();
11122      let count = 1, index = startIndex;
11123      while (count !== 0) {
11124        startTagRegExp.lastIndex = index;
11125        while (true) {
11126          const startMatch = startTagRegExp.exec(html);
11127          if (startMatch === null) {
11128            return index;
11129          } else if (startMatch[1] === '!') {
11130            if (startsWith(startMatch[2], '--')) {
11131              index = findCommentEndIndex(html, false, startMatch.index + '!--'.length);
11132            } else {
11133              index = findCommentEndIndex(html, true, startMatch.index + 1);
11134            }
11135            break;
11136          } else {
11137            endTagRegExp.lastIndex = startTagRegExp.lastIndex;
11138            const endMatch = endTagRegExp.exec(html);
11139            if (isNull(endMatch) || endMatch.index !== startTagRegExp.lastIndex) {
11140              continue;
11141            }
11142            if (startMatch[1] === '/') {
11143              count -= 1;
11144            } else if (!has$2(voidElements, startMatch[2])) {
11145              count += 1;
11146            }
11147            index = startTagRegExp.lastIndex + endMatch[0].length;
11148            break;
11149          }
11150        }
11151      }
11152      return index;
11153    };
11154    const trimHtml$1 = (tempAttrs, html) => {
11155      const trimContentRegExp = new RegExp(['\\s?(' + tempAttrs.join('|') + ')="[^"]+"'].join('|'), 'gi');
11156      return html.replace(trimContentRegExp, '');
11157    };
11158    const trimInternal = (serializer, html) => {
11159      const bogusAllRegExp = /<(\w+) [^>]*data-mce-bogus="all"[^>]*>/g;
11160      const schema = serializer.schema;
11161      let content = trimHtml$1(serializer.getTempAttrs(), html);
11162      const voidElements = schema.getVoidElements();
11163      let matches;
11164      while (matches = bogusAllRegExp.exec(content)) {
11165        const index = bogusAllRegExp.lastIndex;
11166        const matchLength = matches[0].length;
11167        let endTagIndex;
11168        if (voidElements[matches[1]]) {
11169          endTagIndex = index;
11170        } else {
11171          endTagIndex = findMatchingEndTagIndex(schema, content, index);
11172        }
11173        content = content.substring(0, index - matchLength) + content.substring(endTagIndex);
11174        bogusAllRegExp.lastIndex = index - matchLength;
11175      }
11176      return trim$1(content);
11177    };
11178    const trimExternal = trimInternal;
11179
11180    const cleanupBogusElements = parent => {
11181      const bogusElements = descendants(parent, '[data-mce-bogus]');
11182      each$e(bogusElements, elem => {
11183        const bogusValue = get$9(elem, 'data-mce-bogus');
11184        if (bogusValue === 'all') {
11185          remove$5(elem);
11186        } else if (isBr$5(elem)) {
11187          before$3(elem, SugarElement.fromText(zeroWidth));
11188          remove$5(elem);
11189        } else {
11190          unwrap(elem);
11191        }
11192      });
11193    };
11194    const cleanupInputNames = parent => {
11195      const inputs = descendants(parent, 'input');
11196      each$e(inputs, input => {
11197        remove$a(input, 'name');
11198      });
11199    };
11200
11201    const trimEmptyContents = (editor, html) => {
11202      const blockName = getForcedRootBlock(editor);
11203      const emptyRegExp = new RegExp(`^(<${ blockName }[^>]*>(&nbsp;|&#160;|\\s|\u00a0|<br \\/>|)<\\/${ blockName }>[\r\n]*|<br \\/>[\r\n]*)$`);
11204      return html.replace(emptyRegExp, '');
11205    };
11206    const getPlainTextContent = (editor, body) => {
11207      const doc = editor.getDoc();
11208      const dos = getRootNode(SugarElement.fromDom(editor.getBody()));
11209      const offscreenDiv = SugarElement.fromTag('div', doc);
11210      set$3(offscreenDiv, 'data-mce-bogus', 'all');
11211      setAll(offscreenDiv, {
11212        position: 'fixed',
11213        left: '-9999999px',
11214        top: '0'
11215      });
11216      set$1(offscreenDiv, body.innerHTML);
11217      cleanupBogusElements(offscreenDiv);
11218      cleanupInputNames(offscreenDiv);
11219      const root = getContentContainer(dos);
11220      append$1(root, offscreenDiv);
11221      const content = trim$1(offscreenDiv.dom.innerText);
11222      remove$5(offscreenDiv);
11223      return content;
11224    };
11225    const getContentFromBody = (editor, args, body) => {
11226      let content;
11227      if (args.format === 'raw') {
11228        content = Tools.trim(trimExternal(editor.serializer, body.innerHTML));
11229      } else if (args.format === 'text') {
11230        content = getPlainTextContent(editor, body);
11231      } else if (args.format === 'tree') {
11232        content = editor.serializer.serialize(body, args);
11233      } else {
11234        content = trimEmptyContents(editor, editor.serializer.serialize(body, args));
11235      }
11236      const shouldTrim = args.format !== 'text' && !isWsPreserveElement(SugarElement.fromDom(body));
11237      return shouldTrim && isString(content) ? Tools.trim(content) : content;
11238    };
11239    const getContentInternal = (editor, args) => Optional.from(editor.getBody()).fold(constant(args.format === 'tree' ? new AstNode('body', 11) : ''), body => getContentFromBody(editor, args, body));
11240
11241    const makeMap$1 = Tools.makeMap;
11242    const Writer = settings => {
11243      const html = [];
11244      settings = settings || {};
11245      const indent = settings.indent;
11246      const indentBefore = makeMap$1(settings.indent_before || '');
11247      const indentAfter = makeMap$1(settings.indent_after || '');
11248      const encode = Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
11249      const htmlOutput = settings.element_format !== 'xhtml';
11250      return {
11251        start: (name, attrs, empty) => {
11252          if (indent && indentBefore[name] && html.length > 0) {
11253            const value = html[html.length - 1];
11254            if (value.length > 0 && value !== '\n') {
11255              html.push('\n');
11256            }
11257          }
11258          html.push('<', name);
11259          if (attrs) {
11260            for (let i = 0, l = attrs.length; i < l; i++) {
11261              const attr = attrs[i];
11262              html.push(' ', attr.name, '="', encode(attr.value, true), '"');
11263            }
11264          }
11265          if (!empty || htmlOutput) {
11266            html[html.length] = '>';
11267          } else {
11268            html[html.length] = ' />';
11269          }
11270          if (empty && indent && indentAfter[name] && html.length > 0) {
11271            const value = html[html.length - 1];
11272            if (value.length > 0 && value !== '\n') {
11273              html.push('\n');
11274            }
11275          }
11276        },
11277        end: name => {
11278          let value;
11279          html.push('</', name, '>');
11280          if (indent && indentAfter[name] && html.length > 0) {
11281            value = html[html.length - 1];
11282            if (value.length > 0 && value !== '\n') {
11283              html.push('\n');
11284            }
11285          }
11286        },
11287        text: (text, raw) => {
11288          if (text.length > 0) {
11289            html[html.length] = raw ? text : encode(text);
11290          }
11291        },
11292        cdata: text => {
11293          html.push('<![CDATA[', text, ']]>');
11294        },
11295        comment: text => {
11296          html.push('<!--', text, '-->');
11297        },
11298        pi: (name, text) => {
11299          if (text) {
11300            html.push('<?', name, ' ', encode(text), '?>');
11301          } else {
11302            html.push('<?', name, '?>');
11303          }
11304          if (indent) {
11305            html.push('\n');
11306          }
11307        },
11308        doctype: text => {
11309          html.push('<!DOCTYPE', text, '>', indent ? '\n' : '');
11310        },
11311        reset: () => {
11312          html.length = 0;
11313        },
11314        getContent: () => {
11315          return html.join('').replace(/\n$/, '');
11316        }
11317      };
11318    };
11319
11320    const HtmlSerializer = (settings = {}, schema = Schema()) => {
11321      const writer = Writer(settings);
11322      settings.validate = 'validate' in settings ? settings.validate : true;
11323      const serialize = node => {
11324        const validate = settings.validate;
11325        const handlers = {
11326          3: node => {
11327            var _a;
11328            writer.text((_a = node.value) !== null && _a !== void 0 ? _a : '', node.raw);
11329          },
11330          8: node => {
11331            var _a;
11332            writer.comment((_a = node.value) !== null && _a !== void 0 ? _a : '');
11333          },
11334          7: node => {
11335            writer.pi(node.name, node.value);
11336          },
11337          10: node => {
11338            var _a;
11339            writer.doctype((_a = node.value) !== null && _a !== void 0 ? _a : '');
11340          },
11341          4: node => {
11342            var _a;
11343            writer.cdata((_a = node.value) !== null && _a !== void 0 ? _a : '');
11344          },
11345          11: node => {
11346            let tempNode = node;
11347            if (tempNode = tempNode.firstChild) {
11348              do {
11349                walk(tempNode);
11350              } while (tempNode = tempNode.next);
11351            }
11352          }
11353        };
11354        writer.reset();
11355        const walk = node => {
11356          var _a;
11357          const handler = handlers[node.type];
11358          if (!handler) {
11359            const name = node.name;
11360            const isEmpty = name in schema.getVoidElements();
11361            let attrs = node.attributes;
11362            if (validate && attrs && attrs.length > 1) {
11363              const sortedAttrs = [];
11364              sortedAttrs.map = {};
11365              const elementRule = schema.getElementRule(node.name);
11366              if (elementRule) {
11367                for (let i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
11368                  const attrName = elementRule.attributesOrder[i];
11369                  if (attrName in attrs.map) {
11370                    const attrValue = attrs.map[attrName];
11371                    sortedAttrs.map[attrName] = attrValue;
11372                    sortedAttrs.push({
11373                      name: attrName,
11374                      value: attrValue
11375                    });
11376                  }
11377                }
11378                for (let i = 0, l = attrs.length; i < l; i++) {
11379                  const attrName = attrs[i].name;
11380                  if (!(attrName in sortedAttrs.map)) {
11381                    const attrValue = attrs.map[attrName];
11382                    sortedAttrs.map[attrName] = attrValue;
11383                    sortedAttrs.push({
11384                      name: attrName,
11385                      value: attrValue
11386                    });
11387                  }
11388                }
11389                attrs = sortedAttrs;
11390              }
11391            }
11392            writer.start(name, attrs, isEmpty);
11393            if (!isEmpty) {
11394              let child = node.firstChild;
11395              if (child) {
11396                if ((name === 'pre' || name === 'textarea') && child.type === 3 && ((_a = child.value) === null || _a === void 0 ? void 0 : _a[0]) === '\n') {
11397                  writer.text('\n', true);
11398                }
11399                do {
11400                  walk(child);
11401                } while (child = child.next);
11402              }
11403              writer.end(name);
11404            }
11405          } else {
11406            handler(node);
11407          }
11408        };
11409        if (node.type === 1 && !settings.inner) {
11410          walk(node);
11411        } else if (node.type === 3) {
11412          handlers[3](node);
11413        } else {
11414          handlers[11](node);
11415        }
11416        return writer.getContent();
11417      };
11418      return { serialize };
11419    };
11420
11421    const nonInheritableStyles = new Set();
11422    (() => {
11423      const nonInheritableStylesArr = [
11424        'margin',
11425        'margin-left',
11426        'margin-right',
11427        'margin-top',
11428        'margin-bottom',
11429        'padding',
11430        'padding-left',
11431        'padding-right',
11432        'padding-top',
11433        'padding-bottom',
11434        'border',
11435        'border-width',
11436        'border-style',
11437        'border-color',
11438        'background',
11439        'background-attachment',
11440        'background-clip',
11441        'background-color',
11442        'background-image',
11443        'background-origin',
11444        'background-position',
11445        'background-repeat',
11446        'background-size',
11447        'float',
11448        'position',
11449        'left',
11450        'right',
11451        'top',
11452        'bottom',
11453        'z-index',
11454        'display',
11455        'transform',
11456        'width',
11457        'max-width',
11458        'min-width',
11459        'height',
11460        'max-height',
11461        'min-height',
11462        'overflow',
11463        'overflow-x',
11464        'overflow-y',
11465        'text-overflow',
11466        'vertical-align',
11467        'transition',
11468        'transition-delay',
11469        'transition-duration',
11470        'transition-property',
11471        'transition-timing-function'
11472      ];
11473      each$e(nonInheritableStylesArr, style => {
11474        nonInheritableStyles.add(style);
11475      });
11476    })();
11477    const shorthandStyleProps = [
11478      'font',
11479      'text-decoration',
11480      'text-emphasis'
11481    ];
11482    const getStyleProps = (dom, node) => keys(dom.parseStyle(dom.getAttrib(node, 'style')));
11483    const isNonInheritableStyle = style => nonInheritableStyles.has(style);
11484    const hasInheritableStyles = (dom, node) => forall(getStyleProps(dom, node), style => !isNonInheritableStyle(style));
11485    const getLonghandStyleProps = styles => filter$5(styles, style => exists(shorthandStyleProps, prop => startsWith(style, prop)));
11486    const hasStyleConflict = (dom, node, parentNode) => {
11487      const nodeStyleProps = getStyleProps(dom, node);
11488      const parentNodeStyleProps = getStyleProps(dom, parentNode);
11489      const valueMismatch = prop => {
11490        var _a, _b;
11491        const nodeValue = (_a = dom.getStyle(node, prop)) !== null && _a !== void 0 ? _a : '';
11492        const parentValue = (_b = dom.getStyle(parentNode, prop)) !== null && _b !== void 0 ? _b : '';
11493        return isNotEmpty(nodeValue) && isNotEmpty(parentValue) && nodeValue !== parentValue;
11494      };
11495      return exists(nodeStyleProps, nodeStyleProp => {
11496        const propExists = props => exists(props, prop => prop === nodeStyleProp);
11497        if (!propExists(parentNodeStyleProps) && propExists(shorthandStyleProps)) {
11498          const longhandProps = getLonghandStyleProps(parentNodeStyleProps);
11499          return exists(longhandProps, valueMismatch);
11500        } else {
11501          return valueMismatch(nodeStyleProp);
11502        }
11503      });
11504    };
11505
11506    const isChar = (forward, predicate, pos) => Optional.from(pos.container()).filter(isText$a).exists(text => {
11507      const delta = forward ? 0 : -1;
11508      return predicate(text.data.charAt(pos.offset() + delta));
11509    });
11510    const isBeforeSpace = curry(isChar, true, isWhiteSpace);
11511    const isAfterSpace = curry(isChar, false, isWhiteSpace);
11512    const isEmptyText = pos => {
11513      const container = pos.container();
11514      return isText$a(container) && (container.data.length === 0 || isZwsp$1(container.data) && BookmarkManager.isBookmarkNode(container.parentNode));
11515    };
11516    const matchesElementPosition = (before, predicate) => pos => getChildNodeAtRelativeOffset(before ? 0 : -1, pos).filter(predicate).isSome();
11517    const isImageBlock = node => isImg(node) && get$7(SugarElement.fromDom(node), 'display') === 'block';
11518    const isCefNode = node => isContentEditableFalse$b(node) && !isBogusAll$1(node);
11519    const isBeforeImageBlock = matchesElementPosition(true, isImageBlock);
11520    const isAfterImageBlock = matchesElementPosition(false, isImageBlock);
11521    const isBeforeMedia = matchesElementPosition(true, isMedia$2);
11522    const isAfterMedia = matchesElementPosition(false, isMedia$2);
11523    const isBeforeTable = matchesElementPosition(true, isTable$2);
11524    const isAfterTable = matchesElementPosition(false, isTable$2);
11525    const isBeforeContentEditableFalse = matchesElementPosition(true, isCefNode);
11526    const isAfterContentEditableFalse = matchesElementPosition(false, isCefNode);
11527
11528    const dropLast = xs => xs.slice(0, -1);
11529    const parentsUntil = (start, root, predicate) => {
11530      if (contains(root, start)) {
11531        return dropLast(parents$1(start, elm => {
11532          return predicate(elm) || eq(elm, root);
11533        }));
11534      } else {
11535        return [];
11536      }
11537    };
11538    const parents = (start, root) => parentsUntil(start, root, never);
11539    const parentsAndSelf = (start, root) => [start].concat(parents(start, root));
11540
11541    const navigateIgnoreEmptyTextNodes = (forward, root, from) => navigateIgnore(forward, root, from, isEmptyText);
11542    const getClosestBlock$1 = (root, pos) => find$2(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$2);
11543    const isAtBeforeAfterBlockBoundary = (forward, root, pos) => navigateIgnoreEmptyTextNodes(forward, root.dom, pos).forall(newPos => getClosestBlock$1(root, pos).fold(() => !isInSameBlock(newPos, pos, root.dom), fromBlock => !isInSameBlock(newPos, pos, root.dom) && contains(fromBlock, SugarElement.fromDom(newPos.container()))));
11544    const isAtBlockBoundary = (forward, root, pos) => getClosestBlock$1(root, pos).fold(() => navigateIgnoreEmptyTextNodes(forward, root.dom, pos).forall(newPos => !isInSameBlock(newPos, pos, root.dom)), parent => navigateIgnoreEmptyTextNodes(forward, parent.dom, pos).isNone());
11545    const isAtStartOfBlock = curry(isAtBlockBoundary, false);
11546    const isAtEndOfBlock = curry(isAtBlockBoundary, true);
11547    const isBeforeBlock = curry(isAtBeforeAfterBlockBoundary, false);
11548    const isAfterBlock = curry(isAtBeforeAfterBlockBoundary, true);
11549
11550    const isBr$1 = pos => getElementFromPosition(pos).exists(isBr$5);
11551    const findBr = (forward, root, pos) => {
11552      const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$2);
11553      const scope = head(parentBlocks).getOr(root);
11554      return fromPosition(forward, scope.dom, pos).filter(isBr$1);
11555    };
11556    const isBeforeBr$1 = (root, pos) => getElementFromPosition(pos).exists(isBr$5) || findBr(true, root, pos).isSome();
11557    const isAfterBr = (root, pos) => getElementFromPrevPosition(pos).exists(isBr$5) || findBr(false, root, pos).isSome();
11558    const findPreviousBr = curry(findBr, false);
11559    const findNextBr = curry(findBr, true);
11560
11561    const isInMiddleOfText = pos => CaretPosition.isTextPosition(pos) && !pos.isAtStart() && !pos.isAtEnd();
11562    const getClosestBlock = (root, pos) => {
11563      const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$2);
11564      return head(parentBlocks).getOr(root);
11565    };
11566    const hasSpaceBefore = (root, pos) => {
11567      if (isInMiddleOfText(pos)) {
11568        return isAfterSpace(pos);
11569      } else {
11570        return isAfterSpace(pos) || prevPosition(getClosestBlock(root, pos).dom, pos).exists(isAfterSpace);
11571      }
11572    };
11573    const hasSpaceAfter = (root, pos) => {
11574      if (isInMiddleOfText(pos)) {
11575        return isBeforeSpace(pos);
11576      } else {
11577        return isBeforeSpace(pos) || nextPosition(getClosestBlock(root, pos).dom, pos).exists(isBeforeSpace);
11578      }
11579    };
11580    const isPreValue = value => contains$2([
11581      'pre',
11582      'pre-wrap'
11583    ], value);
11584    const isInPre = pos => getElementFromPosition(pos).bind(elm => closest$4(elm, isElement$7)).exists(elm => isPreValue(get$7(elm, 'white-space')));
11585    const isAtBeginningOfBody = (root, pos) => prevPosition(root.dom, pos).isNone();
11586    const isAtEndOfBody = (root, pos) => nextPosition(root.dom, pos).isNone();
11587    const isAtLineBoundary = (root, pos) => isAtBeginningOfBody(root, pos) || isAtEndOfBody(root, pos) || isAtStartOfBlock(root, pos) || isAtEndOfBlock(root, pos) || isAfterBr(root, pos) || isBeforeBr$1(root, pos);
11588    const isCefBlock = node => isNonNullable(node) && isContentEditableFalse$b(node) && isBlockLike(node);
11589    const isSiblingCefBlock = (root, direction) => container => {
11590      return isCefBlock(new DomTreeWalker(container, root)[direction]());
11591    };
11592    const isBeforeCefBlock = (root, pos) => {
11593      const nextPos = nextPosition(root.dom, pos).getOr(pos);
11594      const isNextCefBlock = isSiblingCefBlock(root.dom, 'next');
11595      return pos.isAtEnd() && (isNextCefBlock(pos.container()) || isNextCefBlock(nextPos.container()));
11596    };
11597    const isAfterCefBlock = (root, pos) => {
11598      const prevPos = prevPosition(root.dom, pos).getOr(pos);
11599      const isPrevCefBlock = isSiblingCefBlock(root.dom, 'prev');
11600      return pos.isAtStart() && (isPrevCefBlock(pos.container()) || isPrevCefBlock(prevPos.container()));
11601    };
11602    const needsToHaveNbsp = (root, pos) => {
11603      if (isInPre(pos)) {
11604        return false;
11605      } else {
11606        return isAtLineBoundary(root, pos) || hasSpaceBefore(root, pos) || hasSpaceAfter(root, pos);
11607      }
11608    };
11609    const needsToBeNbspLeft = (root, pos) => {
11610      if (isInPre(pos)) {
11611        return false;
11612      } else {
11613        return isAtStartOfBlock(root, pos) || isBeforeBlock(root, pos) || isAfterBr(root, pos) || hasSpaceBefore(root, pos) || isAfterCefBlock(root, pos);
11614      }
11615    };
11616    const leanRight = pos => {
11617      const container = pos.container();
11618      const offset = pos.offset();
11619      if (isText$a(container) && offset < container.data.length) {
11620        return CaretPosition(container, offset + 1);
11621      } else {
11622        return pos;
11623      }
11624    };
11625    const needsToBeNbspRight = (root, pos) => {
11626      if (isInPre(pos)) {
11627        return false;
11628      } else {
11629        return isAtEndOfBlock(root, pos) || isAfterBlock(root, pos) || isBeforeBr$1(root, pos) || hasSpaceAfter(root, pos) || isBeforeCefBlock(root, pos);
11630      }
11631    };
11632    const needsToBeNbsp = (root, pos) => needsToBeNbspLeft(root, pos) || needsToBeNbspRight(root, leanRight(pos));
11633    const isNbspAt = (text, offset) => isNbsp(text.charAt(offset));
11634    const isWhiteSpaceAt = (text, offset) => isWhiteSpace(text.charAt(offset));
11635    const hasNbsp = pos => {
11636      const container = pos.container();
11637      return isText$a(container) && contains$1(container.data, nbsp);
11638    };
11639    const normalizeNbspMiddle = text => {
11640      const chars = text.split('');
11641      return map$3(chars, (chr, i) => {
11642        if (isNbsp(chr) && i > 0 && i < chars.length - 1 && isContent(chars[i - 1]) && isContent(chars[i + 1])) {
11643          return ' ';
11644        } else {
11645          return chr;
11646        }
11647      }).join('');
11648    };
11649    const normalizeNbspAtStart = (root, node, makeNbsp) => {
11650      const text = node.data;
11651      const firstPos = CaretPosition(node, 0);
11652      if (!makeNbsp && isNbspAt(text, 0) && !needsToBeNbsp(root, firstPos)) {
11653        node.data = ' ' + text.slice(1);
11654        return true;
11655      } else if (makeNbsp && isWhiteSpaceAt(text, 0) && needsToBeNbspLeft(root, firstPos)) {
11656        node.data = nbsp + text.slice(1);
11657        return true;
11658      } else {
11659        return false;
11660      }
11661    };
11662    const normalizeNbspInMiddleOfTextNode = node => {
11663      const text = node.data;
11664      const newText = normalizeNbspMiddle(text);
11665      if (newText !== text) {
11666        node.data = newText;
11667        return true;
11668      } else {
11669        return false;
11670      }
11671    };
11672    const normalizeNbspAtEnd = (root, node, makeNbsp) => {
11673      const text = node.data;
11674      const lastPos = CaretPosition(node, text.length - 1);
11675      if (!makeNbsp && isNbspAt(text, text.length - 1) && !needsToBeNbsp(root, lastPos)) {
11676        node.data = text.slice(0, -1) + ' ';
11677        return true;
11678      } else if (makeNbsp && isWhiteSpaceAt(text, text.length - 1) && needsToBeNbspRight(root, lastPos)) {
11679        node.data = text.slice(0, -1) + nbsp;
11680        return true;
11681      } else {
11682        return false;
11683      }
11684    };
11685    const normalizeNbsps = (root, pos) => {
11686      const container = pos.container();
11687      if (!isText$a(container)) {
11688        return Optional.none();
11689      }
11690      if (hasNbsp(pos)) {
11691        const normalized = normalizeNbspAtStart(root, container, false) || normalizeNbspInMiddleOfTextNode(container) || normalizeNbspAtEnd(root, container, false);
11692        return someIf(normalized, pos);
11693      } else if (needsToBeNbsp(root, pos)) {
11694        const normalized = normalizeNbspAtStart(root, container, true) || normalizeNbspAtEnd(root, container, true);
11695        return someIf(normalized, pos);
11696      } else {
11697        return Optional.none();
11698      }
11699    };
11700    const normalizeNbspsInEditor = editor => {
11701      const root = SugarElement.fromDom(editor.getBody());
11702      if (editor.selection.isCollapsed()) {
11703        normalizeNbsps(root, CaretPosition.fromRangeStart(editor.selection.getRng())).each(pos => {
11704          editor.selection.setRng(pos.toRange());
11705        });
11706      }
11707    };
11708
11709    const normalize$1 = (node, offset, count) => {
11710      if (count === 0) {
11711        return;
11712      }
11713      const elm = SugarElement.fromDom(node);
11714      const root = ancestor$4(elm, isBlock$2).getOr(elm);
11715      const whitespace = node.data.slice(offset, offset + count);
11716      const isEndOfContent = offset + count >= node.data.length && needsToBeNbspRight(root, CaretPosition(node, node.data.length));
11717      const isStartOfContent = offset === 0 && needsToBeNbspLeft(root, CaretPosition(node, 0));
11718      node.replaceData(offset, count, normalize$4(whitespace, 4, isStartOfContent, isEndOfContent));
11719    };
11720    const normalizeWhitespaceAfter = (node, offset) => {
11721      const content = node.data.slice(offset);
11722      const whitespaceCount = content.length - lTrim(content).length;
11723      normalize$1(node, offset, whitespaceCount);
11724    };
11725    const normalizeWhitespaceBefore = (node, offset) => {
11726      const content = node.data.slice(0, offset);
11727      const whitespaceCount = content.length - rTrim(content).length;
11728      normalize$1(node, offset - whitespaceCount, whitespaceCount);
11729    };
11730    const mergeTextNodes = (prevNode, nextNode, normalizeWhitespace, mergeToPrev = true) => {
11731      const whitespaceOffset = rTrim(prevNode.data).length;
11732      const newNode = mergeToPrev ? prevNode : nextNode;
11733      const removeNode = mergeToPrev ? nextNode : prevNode;
11734      if (mergeToPrev) {
11735        newNode.appendData(removeNode.data);
11736      } else {
11737        newNode.insertData(0, removeNode.data);
11738      }
11739      remove$5(SugarElement.fromDom(removeNode));
11740      if (normalizeWhitespace) {
11741        normalizeWhitespaceAfter(newNode, whitespaceOffset);
11742      }
11743      return newNode;
11744    };
11745
11746    const needsReposition = (pos, elm) => {
11747      const container = pos.container();
11748      const offset = pos.offset();
11749      return !CaretPosition.isTextPosition(pos) && container === elm.parentNode && offset > CaretPosition.before(elm).offset();
11750    };
11751    const reposition = (elm, pos) => needsReposition(pos, elm) ? CaretPosition(pos.container(), pos.offset() - 1) : pos;
11752    const beforeOrStartOf = node => isText$a(node) ? CaretPosition(node, 0) : CaretPosition.before(node);
11753    const afterOrEndOf = node => isText$a(node) ? CaretPosition(node, node.data.length) : CaretPosition.after(node);
11754    const getPreviousSiblingCaretPosition = elm => {
11755      if (isCaretCandidate$3(elm.previousSibling)) {
11756        return Optional.some(afterOrEndOf(elm.previousSibling));
11757      } else {
11758        return elm.previousSibling ? lastPositionIn(elm.previousSibling) : Optional.none();
11759      }
11760    };
11761    const getNextSiblingCaretPosition = elm => {
11762      if (isCaretCandidate$3(elm.nextSibling)) {
11763        return Optional.some(beforeOrStartOf(elm.nextSibling));
11764      } else {
11765        return elm.nextSibling ? firstPositionIn(elm.nextSibling) : Optional.none();
11766      }
11767    };
11768    const findCaretPositionBackwardsFromElm = (rootElement, elm) => {
11769      return Optional.from(elm.previousSibling ? elm.previousSibling : elm.parentNode).bind(node => prevPosition(rootElement, CaretPosition.before(node))).orThunk(() => nextPosition(rootElement, CaretPosition.after(elm)));
11770    };
11771    const findCaretPositionForwardsFromElm = (rootElement, elm) => nextPosition(rootElement, CaretPosition.after(elm)).orThunk(() => prevPosition(rootElement, CaretPosition.before(elm)));
11772    const findCaretPositionBackwards = (rootElement, elm) => getPreviousSiblingCaretPosition(elm).orThunk(() => getNextSiblingCaretPosition(elm)).orThunk(() => findCaretPositionBackwardsFromElm(rootElement, elm));
11773    const findCaretPositionForward = (rootElement, elm) => getNextSiblingCaretPosition(elm).orThunk(() => getPreviousSiblingCaretPosition(elm)).orThunk(() => findCaretPositionForwardsFromElm(rootElement, elm));
11774    const findCaretPosition = (forward, rootElement, elm) => forward ? findCaretPositionForward(rootElement, elm) : findCaretPositionBackwards(rootElement, elm);
11775    const findCaretPosOutsideElmAfterDelete = (forward, rootElement, elm) => findCaretPosition(forward, rootElement, elm).map(curry(reposition, elm));
11776    const setSelection$1 = (editor, forward, pos) => {
11777      pos.fold(() => {
11778        editor.focus();
11779      }, pos => {
11780        editor.selection.setRng(pos.toRange(), forward);
11781      });
11782    };
11783    const eqRawNode = rawNode => elm => elm.dom === rawNode;
11784    const isBlock = (editor, elm) => elm && has$2(editor.schema.getBlockElements(), name(elm));
11785    const paddEmptyBlock = elm => {
11786      if (isEmpty$2(elm)) {
11787        const br = SugarElement.fromHtml('<br data-mce-bogus="1">');
11788        empty(elm);
11789        append$1(elm, br);
11790        return Optional.some(CaretPosition.before(br.dom));
11791      } else {
11792        return Optional.none();
11793      }
11794    };
11795    const deleteNormalized = (elm, afterDeletePosOpt, normalizeWhitespace) => {
11796      const prevTextOpt = prevSibling(elm).filter(isText$b);
11797      const nextTextOpt = nextSibling(elm).filter(isText$b);
11798      remove$5(elm);
11799      return lift3(prevTextOpt, nextTextOpt, afterDeletePosOpt, (prev, next, pos) => {
11800        const prevNode = prev.dom, nextNode = next.dom;
11801        const offset = prevNode.data.length;
11802        mergeTextNodes(prevNode, nextNode, normalizeWhitespace);
11803        return pos.container() === nextNode ? CaretPosition(prevNode, offset) : pos;
11804      }).orThunk(() => {
11805        if (normalizeWhitespace) {
11806          prevTextOpt.each(elm => normalizeWhitespaceBefore(elm.dom, elm.dom.length));
11807          nextTextOpt.each(elm => normalizeWhitespaceAfter(elm.dom, 0));
11808        }
11809        return afterDeletePosOpt;
11810      });
11811    };
11812    const isInlineElement = (editor, element) => has$2(editor.schema.getTextInlineElements(), name(element));
11813    const deleteElement$2 = (editor, forward, elm, moveCaret = true) => {
11814      const afterDeletePos = findCaretPosOutsideElmAfterDelete(forward, editor.getBody(), elm.dom);
11815      const parentBlock = ancestor$4(elm, curry(isBlock, editor), eqRawNode(editor.getBody()));
11816      const normalizedAfterDeletePos = deleteNormalized(elm, afterDeletePos, isInlineElement(editor, elm));
11817      if (editor.dom.isEmpty(editor.getBody())) {
11818        editor.setContent('');
11819        editor.selection.setCursorLocation();
11820      } else {
11821        parentBlock.bind(paddEmptyBlock).fold(() => {
11822          if (moveCaret) {
11823            setSelection$1(editor, forward, normalizedAfterDeletePos);
11824          }
11825        }, paddPos => {
11826          if (moveCaret) {
11827            setSelection$1(editor, forward, Optional.some(paddPos));
11828          }
11829        });
11830      }
11831    };
11832
11833    const strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/;
11834    const hasStrongRtl = text => strongRtl.test(text);
11835
11836    const isInlineTarget = (editor, elm) => is$1(SugarElement.fromDom(elm), getInlineBoundarySelector(editor)) && !isTransparentBlock(editor.schema, elm) && editor.dom.isEditable(elm);
11837    const isRtl = element => {
11838      var _a;
11839      return DOMUtils.DOM.getStyle(element, 'direction', true) === 'rtl' || hasStrongRtl((_a = element.textContent) !== null && _a !== void 0 ? _a : '');
11840    };
11841    const findInlineParents = (isInlineTarget, rootNode, pos) => filter$5(DOMUtils.DOM.getParents(pos.container(), '*', rootNode), isInlineTarget);
11842    const findRootInline = (isInlineTarget, rootNode, pos) => {
11843      const parents = findInlineParents(isInlineTarget, rootNode, pos);
11844      return Optional.from(parents[parents.length - 1]);
11845    };
11846    const hasSameParentBlock = (rootNode, node1, node2) => {
11847      const block1 = getParentBlock$3(node1, rootNode);
11848      const block2 = getParentBlock$3(node2, rootNode);
11849      return isNonNullable(block1) && block1 === block2;
11850    };
11851    const isAtZwsp = pos => isBeforeInline(pos) || isAfterInline(pos);
11852    const normalizePosition = (forward, pos) => {
11853      const container = pos.container(), offset = pos.offset();
11854      if (forward) {
11855        if (isCaretContainerInline(container)) {
11856          if (isText$a(container.nextSibling)) {
11857            return CaretPosition(container.nextSibling, 0);
11858          } else {
11859            return CaretPosition.after(container);
11860          }
11861        } else {
11862          return isBeforeInline(pos) ? CaretPosition(container, offset + 1) : pos;
11863        }
11864      } else {
11865        if (isCaretContainerInline(container)) {
11866          if (isText$a(container.previousSibling)) {
11867            return CaretPosition(container.previousSibling, container.previousSibling.data.length);
11868          } else {
11869            return CaretPosition.before(container);
11870          }
11871        } else {
11872          return isAfterInline(pos) ? CaretPosition(container, offset - 1) : pos;
11873        }
11874      }
11875    };
11876    const normalizeForwards = curry(normalizePosition, true);
11877    const normalizeBackwards = curry(normalizePosition, false);
11878
11879    const execCommandIgnoreInputEvents = (editor, command) => {
11880      const inputBlocker = e => e.stopImmediatePropagation();
11881      editor.on('beforeinput input', inputBlocker, true);
11882      editor.getDoc().execCommand(command);
11883      editor.off('beforeinput input', inputBlocker);
11884    };
11885    const execEditorDeleteCommand = editor => {
11886      editor.execCommand('delete');
11887    };
11888    const execNativeDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'Delete');
11889    const execNativeForwardDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'ForwardDelete');
11890    const isBeforeRoot = rootNode => elm => is$2(parent(elm), rootNode, eq);
11891    const isTextBlockOrListItem = element => isTextBlock$2(element) || isListItem$1(element);
11892    const getParentBlock$2 = (rootNode, elm) => {
11893      if (contains(rootNode, elm)) {
11894        return closest$4(elm, isTextBlockOrListItem, isBeforeRoot(rootNode));
11895      } else {
11896        return Optional.none();
11897      }
11898    };
11899    const paddEmptyBody = (editor, moveSelection = true) => {
11900      if (editor.dom.isEmpty(editor.getBody())) {
11901        editor.setContent('', { no_selection: !moveSelection });
11902      }
11903    };
11904    const willDeleteLastPositionInElement = (forward, fromPos, elm) => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
11905      const normalizedFirstPos = normalizePosition(true, firstPos);
11906      const normalizedLastPos = normalizePosition(false, lastPos);
11907      const normalizedFromPos = normalizePosition(false, fromPos);
11908      if (forward) {
11909        return nextPosition(elm, normalizedFromPos).exists(nextPos => nextPos.isEqual(normalizedLastPos) && fromPos.isEqual(normalizedFirstPos));
11910      } else {
11911        return prevPosition(elm, normalizedFromPos).exists(prevPos => prevPos.isEqual(normalizedFirstPos) && fromPos.isEqual(normalizedLastPos));
11912      }
11913    }).getOr(true);
11914    const freefallRtl = root => {
11915      const child = isComment$1(root) ? prevSibling(root) : lastChild(root);
11916      return child.bind(freefallRtl).orThunk(() => Optional.some(root));
11917    };
11918    const deleteRangeContents = (editor, rng, root, moveSelection = true) => {
11919      var _a;
11920      rng.deleteContents();
11921      const lastNode = freefallRtl(root).getOr(root);
11922      const lastBlock = SugarElement.fromDom((_a = editor.dom.getParent(lastNode.dom, editor.dom.isBlock)) !== null && _a !== void 0 ? _a : root.dom);
11923      if (lastBlock.dom === editor.getBody()) {
11924        paddEmptyBody(editor, moveSelection);
11925      } else if (isEmpty$2(lastBlock)) {
11926        fillWithPaddingBr(lastBlock);
11927        if (moveSelection) {
11928          editor.selection.setCursorLocation(lastBlock.dom, 0);
11929        }
11930      }
11931      if (!eq(root, lastBlock)) {
11932        const additionalCleanupNodes = is$2(parent(lastBlock), root) ? [] : siblings(lastBlock);
11933        each$e(additionalCleanupNodes.concat(children$1(root)), node => {
11934          if (!eq(node, lastBlock) && !contains(node, lastBlock) && isEmpty$2(node)) {
11935            remove$5(node);
11936          }
11937        });
11938      }
11939    };
11940
11941    const isRootFromElement = root => cur => eq(root, cur);
11942    const getTableCells = table => descendants(table, 'td,th');
11943    const getTableDetailsFromRange = (rng, isRoot) => {
11944      const getTable = node => getClosestTable(SugarElement.fromDom(node), isRoot);
11945      const startTable = getTable(rng.startContainer);
11946      const endTable = getTable(rng.endContainer);
11947      const isStartInTable = startTable.isSome();
11948      const isEndInTable = endTable.isSome();
11949      const isSameTable = lift2(startTable, endTable, eq).getOr(false);
11950      const isMultiTable = !isSameTable && isStartInTable && isEndInTable;
11951      return {
11952        startTable,
11953        endTable,
11954        isStartInTable,
11955        isEndInTable,
11956        isSameTable,
11957        isMultiTable
11958      };
11959    };
11960
11961    const tableCellRng = (start, end) => ({
11962      start,
11963      end
11964    });
11965    const tableSelection = (rng, table, cells) => ({
11966      rng,
11967      table,
11968      cells
11969    });
11970    const deleteAction = Adt.generate([
11971      {
11972        singleCellTable: [
11973          'rng',
11974          'cell'
11975        ]
11976      },
11977      { fullTable: ['table'] },
11978      {
11979        partialTable: [
11980          'cells',
11981          'outsideDetails'
11982        ]
11983      },
11984      {
11985        multiTable: [
11986          'startTableCells',
11987          'endTableCells',
11988          'betweenRng'
11989        ]
11990      }
11991    ]);
11992    const getClosestCell$1 = (container, isRoot) => closest$3(SugarElement.fromDom(container), 'td,th', isRoot);
11993    const isExpandedCellRng = cellRng => !eq(cellRng.start, cellRng.end);
11994    const getTableFromCellRng = (cellRng, isRoot) => getClosestTable(cellRng.start, isRoot).bind(startParentTable => getClosestTable(cellRng.end, isRoot).bind(endParentTable => someIf(eq(startParentTable, endParentTable), startParentTable)));
11995    const isSingleCellTable = (cellRng, isRoot) => !isExpandedCellRng(cellRng) && getTableFromCellRng(cellRng, isRoot).exists(table => {
11996      const rows = table.dom.rows;
11997      return rows.length === 1 && rows[0].cells.length === 1;
11998    });
11999    const getCellRng = (rng, isRoot) => {
12000      const startCell = getClosestCell$1(rng.startContainer, isRoot);
12001      const endCell = getClosestCell$1(rng.endContainer, isRoot);
12002      return lift2(startCell, endCell, tableCellRng);
12003    };
12004    const getCellRangeFromStartTable = isRoot => startCell => getClosestTable(startCell, isRoot).bind(table => last$3(getTableCells(table)).map(endCell => tableCellRng(startCell, endCell)));
12005    const getCellRangeFromEndTable = isRoot => endCell => getClosestTable(endCell, isRoot).bind(table => head(getTableCells(table)).map(startCell => tableCellRng(startCell, endCell)));
12006    const getTableSelectionFromCellRng = isRoot => cellRng => getTableFromCellRng(cellRng, isRoot).map(table => tableSelection(cellRng, table, getTableCells(table)));
12007    const getTableSelections = (cellRng, selectionDetails, rng, isRoot) => {
12008      if (rng.collapsed || !cellRng.forall(isExpandedCellRng)) {
12009        return Optional.none();
12010      } else if (selectionDetails.isSameTable) {
12011        const sameTableSelection = cellRng.bind(getTableSelectionFromCellRng(isRoot));
12012        return Optional.some({
12013          start: sameTableSelection,
12014          end: sameTableSelection
12015        });
12016      } else {
12017        const startCell = getClosestCell$1(rng.startContainer, isRoot);
12018        const endCell = getClosestCell$1(rng.endContainer, isRoot);
12019        const startTableSelection = startCell.bind(getCellRangeFromStartTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
12020        const endTableSelection = endCell.bind(getCellRangeFromEndTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
12021        return Optional.some({
12022          start: startTableSelection,
12023          end: endTableSelection
12024        });
12025      }
12026    };
12027    const getCellIndex = (cells, cell) => findIndex$2(cells, x => eq(x, cell));
12028    const getSelectedCells = tableSelection => lift2(getCellIndex(tableSelection.cells, tableSelection.rng.start), getCellIndex(tableSelection.cells, tableSelection.rng.end), (startIndex, endIndex) => tableSelection.cells.slice(startIndex, endIndex + 1));
12029    const isSingleCellTableContentSelected = (optCellRng, rng, isRoot) => optCellRng.exists(cellRng => isSingleCellTable(cellRng, isRoot) && hasAllContentsSelected(cellRng.start, rng));
12030    const unselectCells = (rng, selectionDetails) => {
12031      const {startTable, endTable} = selectionDetails;
12032      const otherContentRng = rng.cloneRange();
12033      startTable.each(table => otherContentRng.setStartAfter(table.dom));
12034      endTable.each(table => otherContentRng.setEndBefore(table.dom));
12035      return otherContentRng;
12036    };
12037    const handleSingleTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => start.or(end)).bind(tableSelection => {
12038      const {isSameTable} = selectionDetails;
12039      const selectedCells = getSelectedCells(tableSelection).getOr([]);
12040      if (isSameTable && tableSelection.cells.length === selectedCells.length) {
12041        return Optional.some(deleteAction.fullTable(tableSelection.table));
12042      } else if (selectedCells.length > 0) {
12043        if (isSameTable) {
12044          return Optional.some(deleteAction.partialTable(selectedCells, Optional.none()));
12045        } else {
12046          const otherContentRng = unselectCells(rng, selectionDetails);
12047          return Optional.some(deleteAction.partialTable(selectedCells, Optional.some({
12048            ...selectionDetails,
12049            rng: otherContentRng
12050          })));
12051        }
12052      } else {
12053        return Optional.none();
12054      }
12055    });
12056    const handleMultiTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => {
12057      const startTableSelectedCells = start.bind(getSelectedCells).getOr([]);
12058      const endTableSelectedCells = end.bind(getSelectedCells).getOr([]);
12059      if (startTableSelectedCells.length > 0 && endTableSelectedCells.length > 0) {
12060        const otherContentRng = unselectCells(rng, selectionDetails);
12061        return Optional.some(deleteAction.multiTable(startTableSelectedCells, endTableSelectedCells, otherContentRng));
12062      } else {
12063        return Optional.none();
12064      }
12065    });
12066    const getActionFromRange = (root, rng) => {
12067      const isRoot = isRootFromElement(root);
12068      const optCellRng = getCellRng(rng, isRoot);
12069      const selectionDetails = getTableDetailsFromRange(rng, isRoot);
12070      if (isSingleCellTableContentSelected(optCellRng, rng, isRoot)) {
12071        return optCellRng.map(cellRng => deleteAction.singleCellTable(rng, cellRng.start));
12072      } else if (selectionDetails.isMultiTable) {
12073        return handleMultiTable(optCellRng, selectionDetails, rng, isRoot);
12074      } else {
12075        return handleSingleTable(optCellRng, selectionDetails, rng, isRoot);
12076      }
12077    };
12078
12079    const cleanCells = cells => each$e(cells, cell => {
12080      remove$a(cell, 'contenteditable');
12081      fillWithPaddingBr(cell);
12082    });
12083    const getOutsideBlock = (editor, container) => Optional.from(editor.dom.getParent(container, editor.dom.isBlock)).map(SugarElement.fromDom);
12084    const handleEmptyBlock = (editor, startInTable, emptyBlock) => {
12085      emptyBlock.each(block => {
12086        if (startInTable) {
12087          remove$5(block);
12088        } else {
12089          fillWithPaddingBr(block);
12090          editor.selection.setCursorLocation(block.dom, 0);
12091        }
12092      });
12093    };
12094    const deleteContentInsideCell = (editor, cell, rng, isFirstCellInSelection) => {
12095      const insideTableRng = rng.cloneRange();
12096      if (isFirstCellInSelection) {
12097        insideTableRng.setStart(rng.startContainer, rng.startOffset);
12098        insideTableRng.setEndAfter(cell.dom.lastChild);
12099      } else {
12100        insideTableRng.setStartBefore(cell.dom.firstChild);
12101        insideTableRng.setEnd(rng.endContainer, rng.endOffset);
12102      }
12103      deleteCellContents(editor, insideTableRng, cell, false).each(action => action());
12104    };
12105    const collapseAndRestoreCellSelection = editor => {
12106      const selectedCells = getCellsFromEditor(editor);
12107      const selectedNode = SugarElement.fromDom(editor.selection.getNode());
12108      if (isTableCell$3(selectedNode.dom) && isEmpty$2(selectedNode)) {
12109        editor.selection.setCursorLocation(selectedNode.dom, 0);
12110      } else {
12111        editor.selection.collapse(true);
12112      }
12113      if (selectedCells.length > 1 && exists(selectedCells, cell => eq(cell, selectedNode))) {
12114        set$3(selectedNode, 'data-mce-selected', '1');
12115      }
12116    };
12117    const emptySingleTableCells = (editor, cells, outsideDetails) => Optional.some(() => {
12118      const editorRng = editor.selection.getRng();
12119      const cellsToClean = outsideDetails.bind(({rng, isStartInTable}) => {
12120        const outsideBlock = getOutsideBlock(editor, isStartInTable ? rng.endContainer : rng.startContainer);
12121        rng.deleteContents();
12122        handleEmptyBlock(editor, isStartInTable, outsideBlock.filter(isEmpty$2));
12123        const endPointCell = isStartInTable ? cells[0] : cells[cells.length - 1];
12124        deleteContentInsideCell(editor, endPointCell, editorRng, isStartInTable);
12125        if (!isEmpty$2(endPointCell)) {
12126          return Optional.some(isStartInTable ? cells.slice(1) : cells.slice(0, -1));
12127        } else {
12128          return Optional.none();
12129        }
12130      }).getOr(cells);
12131      cleanCells(cellsToClean);
12132      collapseAndRestoreCellSelection(editor);
12133    });
12134    const emptyMultiTableCells = (editor, startTableCells, endTableCells, betweenRng) => Optional.some(() => {
12135      const rng = editor.selection.getRng();
12136      const startCell = startTableCells[0];
12137      const endCell = endTableCells[endTableCells.length - 1];
12138      deleteContentInsideCell(editor, startCell, rng, true);
12139      deleteContentInsideCell(editor, endCell, rng, false);
12140      const startTableCellsToClean = isEmpty$2(startCell) ? startTableCells : startTableCells.slice(1);
12141      const endTableCellsToClean = isEmpty$2(endCell) ? endTableCells : endTableCells.slice(0, -1);
12142      cleanCells(startTableCellsToClean.concat(endTableCellsToClean));
12143      betweenRng.deleteContents();
12144      collapseAndRestoreCellSelection(editor);
12145    });
12146    const deleteCellContents = (editor, rng, cell, moveSelection = true) => Optional.some(() => {
12147      deleteRangeContents(editor, rng, cell, moveSelection);
12148    });
12149    const deleteTableElement = (editor, table) => Optional.some(() => deleteElement$2(editor, false, table));
12150    const deleteCellRange = (editor, rootElm, rng) => getActionFromRange(rootElm, rng).bind(action => action.fold(curry(deleteCellContents, editor), curry(deleteTableElement, editor), curry(emptySingleTableCells, editor), curry(emptyMultiTableCells, editor)));
12151    const deleteCaptionRange = (editor, caption) => emptyElement(editor, caption);
12152    const deleteTableRange = (editor, rootElm, rng, startElm) => getParentCaption(rootElm, startElm).fold(() => deleteCellRange(editor, rootElm, rng), caption => deleteCaptionRange(editor, caption));
12153    const deleteRange$3 = (editor, startElm, selectedCells) => {
12154      const rootNode = SugarElement.fromDom(editor.getBody());
12155      const rng = editor.selection.getRng();
12156      return selectedCells.length !== 0 ? emptySingleTableCells(editor, selectedCells, Optional.none()) : deleteTableRange(editor, rootNode, rng, startElm);
12157    };
12158    const getParentCell = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTableCell$2);
12159    const getParentCaption = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTag('caption'));
12160    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)));
12161    const emptyElement = (editor, elm) => Optional.some(() => {
12162      fillWithPaddingBr(elm);
12163      editor.selection.setCursorLocation(elm.dom, 0);
12164    });
12165    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);
12166    const emptyCaretCaption = (editor, elm) => emptyElement(editor, elm);
12167    const validateCaretCaption = (rootElm, fromCaption, to) => getParentCaption(rootElm, SugarElement.fromDom(to.getNode())).fold(() => Optional.some(noop), toCaption => someIf(!eq(toCaption, fromCaption), noop));
12168    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));
12169    const deleteCaretCells = (editor, forward, rootElm, startElm) => {
12170      const from = CaretPosition.fromRangeStart(editor.selection.getRng());
12171      return getParentCell(rootElm, startElm).bind(fromCell => isEmpty$2(fromCell) ? emptyElement(editor, fromCell) : deleteBetweenCells(editor, rootElm, forward, fromCell, from));
12172    };
12173    const deleteCaretCaption = (editor, forward, rootElm, fromCaption) => {
12174      const from = CaretPosition.fromRangeStart(editor.selection.getRng());
12175      return isEmpty$2(fromCaption) ? emptyElement(editor, fromCaption) : deleteCaretInsideCaption(editor, rootElm, forward, fromCaption, from);
12176    };
12177    const isNearTable = (forward, pos) => forward ? isBeforeTable(pos) : isAfterTable(pos);
12178    const isBeforeOrAfterTable = (editor, forward) => {
12179      const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
12180      return isNearTable(forward, fromPos) || fromPosition(forward, editor.getBody(), fromPos).exists(pos => isNearTable(forward, pos));
12181    };
12182    const deleteCaret$3 = (editor, forward, startElm) => {
12183      const rootElm = SugarElement.fromDom(editor.getBody());
12184      return getParentCaption(rootElm, startElm).fold(() => deleteCaretCells(editor, forward, rootElm, startElm).orThunk(() => someIf(isBeforeOrAfterTable(editor, forward), noop)), fromCaption => deleteCaretCaption(editor, forward, rootElm, fromCaption));
12185    };
12186    const backspaceDelete$9 = (editor, forward) => {
12187      const startElm = SugarElement.fromDom(editor.selection.getStart(true));
12188      const cells = getCellsFromEditor(editor);
12189      return editor.selection.isCollapsed() && cells.length === 0 ? deleteCaret$3(editor, forward, startElm) : deleteRange$3(editor, startElm, cells);
12190    };
12191
12192    const getContentEditableRoot$1 = (root, node) => {
12193      let tempNode = node;
12194      while (tempNode && tempNode !== root) {
12195        if (isContentEditableTrue$3(tempNode) || isContentEditableFalse$b(tempNode)) {
12196          return tempNode;
12197        }
12198        tempNode = tempNode.parentNode;
12199      }
12200      return null;
12201    };
12202
12203    const internalAttributesPrefixes = [
12204      'data-ephox-',
12205      'data-mce-',
12206      'data-alloy-',
12207      'data-snooker-',
12208      '_'
12209    ];
12210    const each$9 = Tools.each;
12211    const ElementUtils = editor => {
12212      const dom = editor.dom;
12213      const internalAttributes = new Set(editor.serializer.getTempAttrs());
12214      const compare = (node1, node2) => {
12215        if (node1.nodeName !== node2.nodeName || node1.nodeType !== node2.nodeType) {
12216          return false;
12217        }
12218        const getAttribs = node => {
12219          const attribs = {};
12220          each$9(dom.getAttribs(node), attr => {
12221            const name = attr.nodeName.toLowerCase();
12222            if (name !== 'style' && !isAttributeInternal(name)) {
12223              attribs[name] = dom.getAttrib(node, name);
12224            }
12225          });
12226          return attribs;
12227        };
12228        const compareObjects = (obj1, obj2) => {
12229          for (const name in obj1) {
12230            if (has$2(obj1, name)) {
12231              const value = obj2[name];
12232              if (isUndefined(value)) {
12233                return false;
12234              }
12235              if (obj1[name] !== value) {
12236                return false;
12237              }
12238              delete obj2[name];
12239            }
12240          }
12241          for (const name in obj2) {
12242            if (has$2(obj2, name)) {
12243              return false;
12244            }
12245          }
12246          return true;
12247        };
12248        if (isElement$6(node1) && isElement$6(node2)) {
12249          if (!compareObjects(getAttribs(node1), getAttribs(node2))) {
12250            return false;
12251          }
12252          if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style')))) {
12253            return false;
12254          }
12255        }
12256        return !isBookmarkNode$1(node1) && !isBookmarkNode$1(node2);
12257      };
12258      const isAttributeInternal = attributeName => exists(internalAttributesPrefixes, value => startsWith(attributeName, value)) || internalAttributes.has(attributeName);
12259      return {
12260        compare,
12261        isAttributeInternal
12262      };
12263    };
12264
12265    const traverse = (root, fn) => {
12266      let node = root;
12267      while (node = node.walk()) {
12268        fn(node);
12269      }
12270    };
12271    const matchNode$1 = (nodeFilters, attributeFilters, node, matches) => {
12272      const name = node.name;
12273      for (let ni = 0, nl = nodeFilters.length; ni < nl; ni++) {
12274        const filter = nodeFilters[ni];
12275        if (filter.name === name) {
12276          const match = matches.nodes[name];
12277          if (match) {
12278            match.nodes.push(node);
12279          } else {
12280            matches.nodes[name] = {
12281              filter,
12282              nodes: [node]
12283            };
12284          }
12285        }
12286      }
12287      if (node.attributes) {
12288        for (let ai = 0, al = attributeFilters.length; ai < al; ai++) {
12289          const filter = attributeFilters[ai];
12290          const attrName = filter.name;
12291          if (attrName in node.attributes.map) {
12292            const match = matches.attributes[attrName];
12293            if (match) {
12294              match.nodes.push(node);
12295            } else {
12296              matches.attributes[attrName] = {
12297                filter,
12298                nodes: [node]
12299              };
12300            }
12301          }
12302        }
12303      }
12304    };
12305    const findMatchingNodes = (nodeFilters, attributeFilters, node) => {
12306      const matches = {
12307        nodes: {},
12308        attributes: {}
12309      };
12310      if (node.firstChild) {
12311        traverse(node, childNode => {
12312          matchNode$1(nodeFilters, attributeFilters, childNode, matches);
12313        });
12314      }
12315      return matches;
12316    };
12317    const runFilters = (matches, args) => {
12318      const run = (matchRecord, filteringAttributes) => {
12319        each$d(matchRecord, match => {
12320          const nodes = from(match.nodes);
12321          each$e(match.filter.callbacks, callback => {
12322            for (let i = nodes.length - 1; i >= 0; i--) {
12323              const node = nodes[i];
12324              const valueMatches = filteringAttributes ? node.attr(match.filter.name) !== undefined : node.name === match.filter.name;
12325              if (!valueMatches || isNullable(node.parent)) {
12326                nodes.splice(i, 1);
12327              }
12328            }
12329            if (nodes.length > 0) {
12330              callback(nodes, match.filter.name, args);
12331            }
12332          });
12333        });
12334      };
12335      run(matches.nodes, false);
12336      run(matches.attributes, true);
12337    };
12338    const filter$2 = (nodeFilters, attributeFilters, node, args = {}) => {
12339      const matches = findMatchingNodes(nodeFilters, attributeFilters, node);
12340      runFilters(matches, args);
12341    };
12342
12343    const paddEmptyNode = (
12343settings, args, isBlock, node) => {
12344      const brPreferred = settings.pad_empty_with_br || args.insert;
12345      if (brPreferred && isBlock(node)) {
12346        const astNode = new AstNode('br', 1);
12347        if (args.insert) {
12348          astNode.attr('data-mce-bogus', '1');
12349        }
vendor: 90,906 bytes, lines 12349-14605
12349
12350        node.empty().append(astNode);
12351      } else {
12352        node.empty().append(new AstNode('#text', 3)).value = nbsp;
12353      }
12354    };
12355    const isPaddedWithNbsp = node => {
12356      var _a;
12357      return hasOnlyChild(node, '#text') && ((_a = node === null || node === void 0 ? void 0 : node.firstChild) === null || _a === void 0 ? void 0 : _a.value) === nbsp;
12358    };
12359    const hasOnlyChild = (node, name) => {
12360      const firstChild = node === null || node === void 0 ? void 0 : node.firstChild;
12361      return isNonNullable(firstChild) && firstChild === node.lastChild && firstChild.name === name;
12362    };
12363    const isPadded = (schema, node) => {
12364      const rule = schema.getElementRule(node.name);
12365      return (rule === null || rule === void 0 ? void 0 : rule.paddEmpty) === true;
12366    };
12367    const isEmpty = (schema, nonEmptyElements, whitespaceElements, node) => node.isEmpty(nonEmptyElements, whitespaceElements, node => isPadded(schema, node));
12368    const isLineBreakNode = (node, isBlock) => isNonNullable(node) && (isBlock(node) || node.name === 'br');
12369    const findClosestEditingHost = scope => {
12370      let editableNode;
12371      for (let node = scope; node; node = node.parent) {
12372        const contentEditable = node.attr('contenteditable');
12373        if (contentEditable === 'false') {
12374          break;
12375        } else if (contentEditable === 'true') {
12376          editableNode = node;
12377        }
12378      }
12379      return Optional.from(editableNode);
12380    };
12381
12382    const removeOrUnwrapInvalidNode = (node, schema, originalNodeParent = node.parent) => {
12383      if (schema.getSpecialElements()[node.name]) {
12384        node.empty().remove();
12385      } else {
12386        const children = node.children();
12387        for (const childNode of children) {
12388          if (originalNodeParent && !schema.isValidChild(originalNodeParent.name, childNode.name)) {
12389            removeOrUnwrapInvalidNode(childNode, schema, originalNodeParent);
12390          }
12391        }
12392        node.unwrap();
12393      }
12394    };
12395    const cleanInvalidNodes = (nodes, schema, rootNode, onCreate = noop) => {
12396      const textBlockElements = schema.getTextBlockElements();
12397      const nonEmptyElements = schema.getNonEmptyElements();
12398      const whitespaceElements = schema.getWhitespaceElements();
12399      const nonSplittableElements = Tools.makeMap('tr,td,th,tbody,thead,tfoot,table');
12400      const fixed = new Set();
12401      const isSplittableElement = node => node !== rootNode && !nonSplittableElements[node.name];
12402      for (let ni = 0; ni < nodes.length; ni++) {
12403        const node = nodes[ni];
12404        let parent;
12405        let newParent;
12406        let tempNode;
12407        if (!node.parent || fixed.has(node)) {
12408          continue;
12409        }
12410        if (textBlockElements[node.name] && node.parent.name === 'li') {
12411          let sibling = node.next;
12412          while (sibling) {
12413            if (textBlockElements[sibling.name]) {
12414              sibling.name = 'li';
12415              fixed.add(sibling);
12416              node.parent.insert(sibling, node.parent);
12417            } else {
12418              break;
12419            }
12420            sibling = sibling.next;
12421          }
12422          node.unwrap();
12423          continue;
12424        }
12425        const parents = [node];
12426        for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && isSplittableElement(parent); parent = parent.parent) {
12427          parents.push(parent);
12428        }
12429        if (parent && parents.length > 1) {
12430          if (schema.isValidChild(parent.name, node.name)) {
12431            parents.reverse();
12432            newParent = parents[0].clone();
12433            onCreate(newParent);
12434            let currentNode = newParent;
12435            for (let i = 0; i < parents.length - 1; i++) {
12436              if (schema.isValidChild(currentNode.name, parents[i].name) && i > 0) {
12437                tempNode = parents[i].clone();
12438                onCreate(tempNode);
12439                currentNode.append(tempNode);
12440              } else {
12441                tempNode = currentNode;
12442              }
12443              for (let childNode = parents[i].firstChild; childNode && childNode !== parents[i + 1];) {
12444                const nextNode = childNode.next;
12445                tempNode.append(childNode);
12446                childNode = nextNode;
12447              }
12448              currentNode = tempNode;
12449            }
12450            if (!isEmpty(schema, nonEmptyElements, whitespaceElements, newParent)) {
12451              parent.insert(newParent, parents[0], true);
12452              parent.insert(node, newParent);
12453            } else {
12454              parent.insert(node, parents[0], true);
12455            }
12456            parent = parents[0];
12457            if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent) || hasOnlyChild(parent, 'br')) {
12458              parent.empty().remove();
12459            }
12460          } else {
12461            removeOrUnwrapInvalidNode(node, schema);
12462          }
12463        } else if (node.parent) {
12464          if (node.name === 'li') {
12465            let sibling = node.prev;
12466            if (sibling && (sibling.name === 'ul' || sibling.name === 'ol')) {
12467              sibling.append(node);
12468              continue;
12469            }
12470            sibling = node.next;
12471            if (sibling && (sibling.name === 'ul' || sibling.name === 'ol') && sibling.firstChild) {
12472              sibling.insert(node, sibling.firstChild, true);
12473              continue;
12474            }
12475            const wrapper = new AstNode('ul', 1);
12476            onCreate(wrapper);
12477            node.wrap(wrapper);
12478            continue;
12479          }
12480          if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) {
12481            const wrapper = new AstNode('div', 1);
12482            onCreate(wrapper);
12483            node.wrap(wrapper);
12484          } else {
12485            removeOrUnwrapInvalidNode(node, schema);
12486          }
12487        }
12488      }
12489    };
12490    const hasClosest = (node, parentName) => {
12491      let tempNode = node;
12492      while (tempNode) {
12493        if (tempNode.name === parentName) {
12494          return true;
12495        }
12496        tempNode = tempNode.parent;
12497      }
12498      return false;
12499    };
12500    const isInvalid = (schema, node, parent = node.parent) => {
12501      if (parent && schema.children[node.name] && !schema.isValidChild(parent.name, node.name)) {
12502        return true;
12503      } else if (parent && node.name === 'a' && hasClosest(parent, 'a')) {
12504        return true;
12505      } else {
12506        return false;
12507      }
12508    };
12509
12510    const createRange = (sc, so, ec, eo) => {
12511      const rng = document.createRange();
12512      rng.setStart(sc, so);
12513      rng.setEnd(ec, eo);
12514      return rng;
12515    };
12516    const normalizeBlockSelectionRange = rng => {
12517      const startPos = CaretPosition.fromRangeStart(rng);
12518      const endPos = CaretPosition.fromRangeEnd(rng);
12519      const rootNode = rng.commonAncestorContainer;
12520      return fromPosition(false, rootNode, endPos).map(newEndPos => {
12521        if (!isInSameBlock(startPos, endPos, rootNode) && isInSameBlock(startPos, newEndPos, rootNode)) {
12522          return createRange(startPos.container(), startPos.offset(), newEndPos.container(), newEndPos.offset());
12523        } else {
12524          return rng;
12525        }
12526      }).getOr(rng);
12527    };
12528    const normalize = rng => rng.collapsed ? rng : normalizeBlockSelectionRange(rng);
12529
12530    const hasOnlyOneChild$1 = node => {
12531      return isNonNullable(node.firstChild) && node.firstChild === node.lastChild;
12532    };
12533    const isPaddingNode = node => {
12534      return node.name === 'br' || node.value === nbsp;
12535    };
12536    const isPaddedEmptyBlock = (schema, node) => {
12537      const blockElements = schema.getBlockElements();
12538      return blockElements[node.name] && hasOnlyOneChild$1(node) && isPaddingNode(node.firstChild);
12539    };
12540    const isEmptyFragmentElement = (schema, node) => {
12541      const nonEmptyElements = schema.getNonEmptyElements();
12542      return isNonNullable(node) && (node.isEmpty(nonEmptyElements) || isPaddedEmptyBlock(schema, node));
12543    };
12544    const isListFragment = (schema, fragment) => {
12545      let firstChild = fragment.firstChild;
12546      let lastChild = fragment.lastChild;
12547      if (firstChild && firstChild.name === 'meta') {
12548        firstChild = firstChild.next;
12549      }
12550      if (lastChild && lastChild.attr('id') === 'mce_marker') {
12551        lastChild = lastChild.prev;
12552      }
12553      if (isEmptyFragmentElement(schema, lastChild)) {
12554        lastChild = lastChild === null || lastChild === void 0 ? void 0 : lastChild.prev;
12555      }
12556      if (!firstChild || firstChild !== lastChild) {
12557        return false;
12558      }
12559      return firstChild.name === 'ul' || firstChild.name === 'ol';
12560    };
12561    const cleanupDomFragment = domFragment => {
12562      var _a, _b;
12563      const firstChild = domFragment.firstChild;
12564      const lastChild = domFragment.lastChild;
12565      if (firstChild && firstChild.nodeName === 'META') {
12566        (_a = firstChild.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(firstChild);
12567      }
12568      if (lastChild && lastChild.id === 'mce_marker') {
12569        (_b = lastChild.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(lastChild);
12570      }
12571      return domFragment;
12572    };
12573    const toDomFragment = (dom, serializer, fragment) => {
12574      const html = serializer.serialize(fragment);
12575      const domFragment = dom.createFragment(html);
12576      return cleanupDomFragment(domFragment);
12577    };
12578    const listItems = elm => {
12579      var _a;
12580      return filter$5((_a = elm === null || elm === void 0 ? void 0 : elm.childNodes) !== null && _a !== void 0 ? _a : [], child => {
12581        return child.nodeName === 'LI';
12582      });
12583    };
12584    const isPadding = node => {
12585      return node.data === nbsp || isBr$6(node);
12586    };
12587    const isListItemPadded = node => {
12588      return isNonNullable(node === null || node === void 0 ? void 0 : node.firstChild) && node.firstChild === node.lastChild && isPadding(node.firstChild);
12589    };
12590    const isEmptyOrPadded = elm => {
12591      return !elm.firstChild || isListItemPadded(elm);
12592    };
12593    const trimListItems = elms => {
12594      return elms.length > 0 && isEmptyOrPadded(elms[elms.length - 1]) ? elms.slice(0, -1) : elms;
12595    };
12596    const getParentLi = (dom, node) => {
12597      const parentBlock = dom.getParent(node, dom.isBlock);
12598      return parentBlock && parentBlock.nodeName === 'LI' ? parentBlock : null;
12599    };
12600    const isParentBlockLi = (dom, node) => {
12601      return !!getParentLi(dom, node);
12602    };
12603    const getSplit = (parentNode, rng) => {
12604      const beforeRng = rng.cloneRange();
12605      const afterRng = rng.cloneRange();
12606      beforeRng.setStartBefore(parentNode);
12607      afterRng.setEndAfter(parentNode);
12608      return [
12609        beforeRng.cloneContents(),
12610        afterRng.cloneContents()
12611      ];
12612    };
12613    const findFirstIn = (node, rootNode) => {
12614      const caretPos = CaretPosition.before(node);
12615      const caretWalker = CaretWalker(rootNode);
12616      const newCaretPos = caretWalker.next(caretPos);
12617      return newCaretPos ? newCaretPos.toRange() : null;
12618    };
12619    const findLastOf = (node, rootNode) => {
12620      const caretPos = CaretPosition.after(node);
12621      const caretWalker = CaretWalker(rootNode);
12622      const newCaretPos = caretWalker.prev(caretPos);
12623      return newCaretPos ? newCaretPos.toRange() : null;
12624    };
12625    const insertMiddle = (target, elms, rootNode, rng) => {
12626      const parts = getSplit(target, rng);
12627      const parentElm = target.parentNode;
12628      if (parentElm) {
12629        parentElm.insertBefore(parts[0], target);
12630        Tools.each(elms, li => {
12631          parentElm.insertBefore(li, target);
12632        });
12633        parentElm.insertBefore(parts[1], target);
12634        parentElm.removeChild(target);
12635      }
12636      return findLastOf(elms[elms.length - 1], rootNode);
12637    };
12638    const insertBefore$1 = (target, elms, rootNode) => {
12639      const parentElm = target.parentNode;
12640      if (parentElm) {
12641        Tools.each(elms, elm => {
12642          parentElm.insertBefore(elm, target);
12643        });
12644      }
12645      return findFirstIn(target, rootNode);
12646    };
12647    const insertAfter$1 = (target, elms, rootNode, dom) => {
12648      dom.insertAfter(elms.reverse(), target);
12649      return findLastOf(elms[0], rootNode);
12650    };
12651    const insertAtCaret$1 = (serializer, dom, rng, fragment) => {
12652      const domFragment = toDomFragment(dom, serializer, fragment);
12653      const liTarget = getParentLi(dom, rng.startContainer);
12654      const liElms = trimListItems(listItems(domFragment.firstChild));
12655      const BEGINNING = 1, END = 2;
12656      const rootNode = dom.getRoot();
12657      const isAt = location => {
12658        const caretPos = CaretPosition.fromRangeStart(rng);
12659        const caretWalker = CaretWalker(dom.getRoot());
12660        const newPos = location === BEGINNING ? caretWalker.prev(caretPos) : caretWalker.next(caretPos);
12661        const newPosNode = newPos === null || newPos === void 0 ? void 0 : newPos.getNode();
12662        return newPosNode ? getParentLi(dom, newPosNode) !== liTarget : true;
12663      };
12664      if (!liTarget) {
12665        return null;
12666      } else if (isAt(BEGINNING)) {
12667        return insertBefore$1(liTarget, liElms, rootNode);
12668      } else if (isAt(END)) {
12669        return insertAfter$1(liTarget, liElms, rootNode, dom);
12670      } else {
12671        return insertMiddle(liTarget, liElms, rootNode, rng);
12672      }
12673    };
12674
12675    const mergeableWrappedElements = ['pre'];
12676    const shouldPasteContentOnly = (dom, fragment, parentNode, root) => {
12677      var _a;
12678      const firstNode = fragment.firstChild;
12679      const lastNode = fragment.lastChild;
12680      const last = lastNode.attr('data-mce-type') === 'bookmark' ? lastNode.prev : lastNode;
12681      const isPastingSingleElement = firstNode === last;
12682      const isWrappedElement = contains$2(mergeableWrappedElements, firstNode.name);
12683      if (isPastingSingleElement && isWrappedElement) {
12684        const isContentEditable = firstNode.attr('contenteditable') !== 'false';
12685        const isPastingInTheSameBlockTag = ((_a = dom.getParent(parentNode, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName.toLowerCase()) === firstNode.name;
12686        const isPastingInContentEditable = Optional.from(getContentEditableRoot$1(root, parentNode)).forall(isContentEditableTrue$3);
12687        return isContentEditable && isPastingInTheSameBlockTag && isPastingInContentEditable;
12688      } else {
12689        return false;
12690      }
12691    };
12692    const isTableCell = isTableCell$3;
12693    const isTableCellContentSelected = (dom, rng, cell) => {
12694      if (isNonNullable(cell)) {
12695        const endCell = dom.getParent(rng.endContainer, isTableCell);
12696        return cell === endCell && hasAllContentsSelected(SugarElement.fromDom(cell), rng);
12697      } else {
12698        return false;
12699      }
12700    };
12701    const validInsertion = (editor, value, parentNode) => {
12702      var _a;
12703      if (parentNode.getAttribute('data-mce-bogus') === 'all') {
12704        (_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(editor.dom.createFragment(value), parentNode);
12705      } else {
12706        const node = parentNode.firstChild;
12707        const node2 = parentNode.lastChild;
12708        if (!node || node === node2 && node.nodeName === 'BR') {
12709          editor.dom.setHTML(parentNode, value);
12710        } else {
12711          editor.selection.setContent(value, { no_events: true });
12712        }
12713      }
12714    };
12715    const trimBrsFromTableCell = (dom, elm) => {
12716      Optional.from(dom.getParent(elm, 'td,th')).map(SugarElement.fromDom).each(trimBlockTrailingBr);
12717    };
12718    const reduceInlineTextElements = (editor, merge) => {
12719      const textInlineElements = editor.schema.getTextInlineElements();
12720      const dom = editor.dom;
12721      if (merge) {
12722        const root = editor.getBody();
12723        const elementUtils = ElementUtils(editor);
12724        Tools.each(dom.select('*[data-mce-fragment]'), node => {
12725          const isInline = isNonNullable(textInlineElements[node.nodeName.toLowerCase()]);
12726          if (isInline && hasInheritableStyles(dom, node)) {
12727            for (let parentNode = node.parentElement; isNonNullable(parentNode) && parentNode !== root; parentNode = parentNode.parentElement) {
12728              const styleConflict = hasStyleConflict(dom, node, parentNode);
12729              if (styleConflict) {
12730                break;
12731              }
12732              if (elementUtils.compare(parentNode, node)) {
12733                dom.remove(node, true);
12734                break;
12735              }
12736            }
12737          }
12738        });
12739      }
12740    };
12741    const markFragmentElements = fragment => {
12742      let node = fragment;
12743      while (node = node.walk()) {
12744        if (node.type === 1) {
12745          node.attr('data-mce-fragment', '1');
12746        }
12747      }
12748    };
12749    const unmarkFragmentElements = elm => {
12750      Tools.each(elm.getElementsByTagName('*'), elm => {
12751        elm.removeAttribute('data-mce-fragment');
12752      });
12753    };
12754    const isPartOfFragment = node => {
12755      return !!node.getAttribute('data-mce-fragment');
12756    };
12757    const canHaveChildren = (editor, node) => {
12758      return isNonNullable(node) && !editor.schema.getVoidElements()[node.nodeName];
12759    };
12760    const moveSelectionToMarker = (editor, marker) => {
12761      var _a, _b, _c;
12762      let nextRng;
12763      const dom = editor.dom;
12764      const selection = editor.selection;
12765      if (!marker) {
12766        return;
12767      }
12768      selection.scrollIntoView(marker);
12769      const parentEditableElm = getContentEditableRoot$1(editor.getBody(), marker);
12770      if (parentEditableElm && dom.getContentEditable(parentEditableElm) === 'false') {
12771        dom.remove(marker);
12772        selection.select(parentEditableElm);
12773        return;
12774      }
12775      let rng = dom.createRng();
12776      const node = marker.previousSibling;
12777      if (isText$a(node)) {
12778        rng.setStart(node, (_b = (_a = node.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
12779        const node2 = marker.nextSibling;
12780        if (isText$a(node2)) {
12781          node.appendData(node2.data);
12782          (_c = node2.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(node2);
12783        }
12784      } else {
12785        rng.setStartBefore(marker);
12786        rng.setEndBefore(marker);
12787      }
12788      const findNextCaretRng = rng => {
12789        let caretPos = CaretPosition.fromRangeStart(rng);
12790        const caretWalker = CaretWalker(editor.getBody());
12791        caretPos = caretWalker.next(caretPos);
12792        return caretPos === null || caretPos === void 0 ? void 0 : caretPos.toRange();
12793      };
12794      const parentBlock = dom.getParent(marker, dom.isBlock);
12795      dom.remove(marker);
12796      if (parentBlock && dom.isEmpty(parentBlock)) {
12797        empty(SugarElement.fromDom(parentBlock));
12798        rng.setStart(parentBlock, 0);
12799        rng.setEnd(parentBlock, 0);
12800        if (!isTableCell(parentBlock) && !isPartOfFragment(parentBlock) && (nextRng = findNextCaretRng(rng))) {
12801          rng = nextRng;
12802          dom.remove(parentBlock);
12803        } else {
12804          dom.add(parentBlock, dom.create('br', { 'data-mce-bogus': '1' }));
12805        }
12806      }
12807      selection.setRng(rng);
12808    };
12809    const deleteSelectedContent = editor => {
12810      const dom = editor.dom;
12811      const rng = normalize(editor.selection.getRng());
12812      editor.selection.setRng(rng);
12813      const startCell = dom.getParent(rng.startContainer, isTableCell);
12814      if (isTableCellContentSelected(dom, rng, startCell)) {
12815        deleteCellContents(editor, rng, SugarElement.fromDom(startCell));
12816      } else if (rng.startContainer === rng.endContainer && rng.endOffset - rng.startOffset === 1 && isText$a(rng.startContainer.childNodes[rng.startOffset])) {
12817        rng.deleteContents();
12818      } else {
12819        editor.getDoc().execCommand('Delete', false);
12820      }
12821    };
12822    const findMarkerNode = scope => {
12823      for (let markerNode = scope; markerNode; markerNode = markerNode.walk()) {
12824        if (markerNode.attr('id') === 'mce_marker') {
12825          return Optional.some(markerNode);
12826        }
12827      }
12828      return Optional.none();
12829    };
12830    const preventSplittingSummary = editor => {
12831      each$e(from(editor.getBody().querySelectorAll('details')), accordion => {
12832        const summaries = filter$5(from(accordion.children), node => node.nodeName === 'SUMMARY');
12833        if (summaries.length > 1) {
12834          each$e(summaries.slice(1), summary => {
12835            const element = SugarElement.fromDom(summary);
12836            remove$7(element, 'mce-accordion-summary');
12837            mutate(element, 'p');
12838          });
12839        }
12840      });
12841    };
12842    const insertHtmlAtCaret = (editor, value, details) => {
12843      var _a, _b;
12844      const selection = editor.selection;
12845      const dom = editor.dom;
12846      const parser = editor.parser;
12847      const merge = details.merge;
12848      const serializer = HtmlSerializer({ validate: true }, editor.schema);
12849      const bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;</span>';
12850      if (value.indexOf('{$caret}') === -1) {
12851        value += '{$caret}';
12852      }
12853      value = value.replace(/\{\$caret\}/, bookmarkHtml);
12854      let rng = selection.getRng();
12855      const caretElement = rng.startContainer;
12856      const body = editor.getBody();
12857      if (caretElement === body && selection.isCollapsed()) {
12858        if (dom.isBlock(body.firstChild) && canHaveChildren(editor, body.firstChild) && dom.isEmpty(body.firstChild)) {
12859          rng = dom.createRng();
12860          rng.setStart(body.firstChild, 0);
12861          rng.setEnd(body.firstChild, 0);
12862          selection.setRng(rng);
12863        }
12864      }
12865      if (!selection.isCollapsed()) {
12866        deleteSelectedContent(editor);
12867      }
12868      const parentNode = selection.getNode();
12869      const parserArgs = {
12870        context: parentNode.nodeName.toLowerCase(),
12871        data: details.data,
12872        insert: true
12873      };
12874      const fragment = parser.parse(value, parserArgs);
12875      if (details.paste === true && isListFragment(editor.schema, fragment) && isParentBlockLi(dom, parentNode)) {
12876        rng = insertAtCaret$1(serializer, dom, selection.getRng(), fragment);
12877        if (rng) {
12878          selection.setRng(rng);
12879        }
12880        return value;
12881      }
12882      if (details.paste === true && shouldPasteContentOnly(dom, fragment, parentNode, editor.getBody())) {
12883        (_a = fragment.firstChild) === null || _a === void 0 ? void 0 : _a.unwrap();
12884      }
12885      markFragmentElements(fragment);
12886      let node = fragment.lastChild;
12887      if (node && node.attr('id') === 'mce_marker') {
12888        const marker = node;
12889        for (node = node.prev; node; node = node.walk(true)) {
12890          if (node.type === 3 || !dom.isBlock(node.name)) {
12891            if (node.parent && editor.schema.isValidChild(node.parent.name, 'span')) {
12892              node.parent.insert(marker, node, node.name === 'br');
12893            }
12894            break;
12895          }
12896        }
12897      }
12898      editor._selectionOverrides.showBlockCaretContainer(parentNode);
12899      if (!parserArgs.invalid) {
12900        value = serializer.serialize(fragment);
12901        validInsertion(editor, value, parentNode);
12902      } else {
12903        editor.selection.setContent(bookmarkHtml);
12904        let parentNode = selection.getNode();
12905        let tempNode;
12906        const rootNode = editor.getBody();
12907        if (isDocument$1(parentNode)) {
12908          parentNode = tempNode = rootNode;
12909        } else {
12910          tempNode = parentNode;
12911        }
12912        while (tempNode && tempNode !== rootNode) {
12913          parentNode = tempNode;
12914          tempNode = tempNode.parentNode;
12915        }
12916        value = parentNode === rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode);
12917        const root = parser.parse(value);
12918        const markerNode = findMarkerNode(root);
12919        const editingHost = markerNode.bind(findClosestEditingHost).getOr(root);
12920        markerNode.each(marker => marker.replace(fragment));
12921        const toExtract = fragment.children();
12922        const parent = (_b = fragment.parent) !== null && _b !== void 0 ? _b : root;
12923        fragment.unwrap();
12924        const invalidChildren = filter$5(toExtract, node => isInvalid(editor.schema, node, parent));
12925        cleanInvalidNodes(invalidChildren, editor.schema, editingHost);
12926        filter$2(parser.getNodeFilters(), parser.getAttributeFilters(), root);
12927        value = serializer.serialize(root);
12928        if (parentNode === rootNode) {
12929          dom.setHTML(rootNode, value);
12930        } else {
12931          dom.setOuterHTML(parentNode, value);
12932        }
12933      }
12934      reduceInlineTextElements(editor, merge);
12935      moveSelectionToMarker(editor, dom.get('mce_marker'));
12936      unmarkFragmentElements(editor.getBody());
12937      trimBrsFromTableCell(dom, selection.getStart());
12938      preventSplittingSummary(editor);
12939      updateCaret(editor.schema, editor.getBody(), selection.getStart());
12940      return value;
12941    };
12942
12943    const isTreeNode = content => content instanceof AstNode;
12944
12945    const moveSelection = editor => {
12946      if (hasFocus(editor)) {
12947        firstPositionIn(editor.getBody()).each(pos => {
12948          const node = pos.getNode();
12949          const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
12950          editor.selection.setRng(caretPos.toRange());
12951        });
12952      }
12953    };
12954    const setEditorHtml = (editor, html, noSelection) => {
12955      editor.dom.setHTML(editor.getBody(), html);
12956      if (noSelection !== true) {
12957        moveSelection(editor);
12958      }
12959    };
12960    const setContentString = (editor, body, content, args) => {
12961      if (content.length === 0 || /^\s+$/.test(content)) {
12962        const padd = '<br data-mce-bogus="1">';
12963        if (body.nodeName === 'TABLE') {
12964          content = '<tr><td>' + padd + '</td></tr>';
12965        } else if (/^(UL|OL)$/.test(body.nodeName)) {
12966          content = '<li>' + padd + '</li>';
12967        }
12968        const forcedRootBlockName = getForcedRootBlock(editor);
12969        if (editor.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
12970          content = padd;
12971          content = editor.dom.createHTML(forcedRootBlockName, getForcedRootBlockAttrs(editor), content);
12972        } else if (!content) {
12973          content = padd;
12974        }
12975        setEditorHtml(editor, content, args.no_selection);
12976        return {
12977          content,
12978          html: content
12979        };
12980      } else {
12981        if (args.format !== 'raw') {
12982          content = HtmlSerializer({ validate: false }, editor.schema).serialize(editor.parser.parse(content, {
12983            isRootContent: true,
12984            insert: true
12985          }));
12986        }
12987        const trimmedHtml = isWsPreserveElement(SugarElement.fromDom(body)) ? content : Tools.trim(content);
12988        setEditorHtml(editor, trimmedHtml, args.no_selection);
12989        return {
12990          content: trimmedHtml,
12991          html: trimmedHtml
12992        };
12993      }
12994    };
12995    const setContentTree = (editor, body, content, args) => {
12996      filter$2(editor.parser.getNodeFilters(), editor.parser.getAttributeFilters(), content);
12997      const html = HtmlSerializer({ validate: false }, editor.schema).serialize(content);
12998      const trimmedHtml = isWsPreserveElement(SugarElement.fromDom(body)) ? html : Tools.trim(html);
12999      setEditorHtml(editor, trimmedHtml, args.no_selection);
13000      return {
13001        content,
13002        html: trimmedHtml
13003      };
13004    };
13005    const setContentInternal = (editor, content, args) => {
13006      return Optional.from(editor.getBody()).map(body => {
13007        if (isTreeNode(content)) {
13008          return setContentTree(editor, body, content, args);
13009        } else {
13010          return setContentString(editor, body, content, args);
13011        }
13012      }).getOr({
13013        content,
13014        html: isTreeNode(args.content) ? '' : args.content
13015      });
13016    };
13017
13018    const ancestor$1 = (scope, predicate, isRoot) => ancestor$4(scope, predicate, isRoot).isSome();
13019    const sibling = (scope, predicate) => sibling$1(scope, predicate).isSome();
13020
13021    const ensureIsRoot = isRoot => isFunction(isRoot) ? isRoot : never;
13022    const ancestor = (scope, transform, isRoot) => {
13023      let element = scope.dom;
13024      const stop = ensureIsRoot(isRoot);
13025      while (element.parentNode) {
13026        element = element.parentNode;
13027        const el = SugarElement.fromDom(element);
13028        const transformed = transform(el);
13029        if (transformed.isSome()) {
13030          return transformed;
13031        } else if (stop(el)) {
13032          break;
13033        }
13034      }
13035      return Optional.none();
13036    };
13037    const closest$1 = (scope, transform, isRoot) => {
13038      const current = transform(scope);
13039      const stop = ensureIsRoot(isRoot);
13040      return current.orThunk(() => stop(scope) ? Optional.none() : ancestor(scope, transform, stop));
13041    };
13042
13043    const isEq$3 = isEq$5;
13044    const matchesUnInheritedFormatSelector = (ed, node, name) => {
13045      const formatList = ed.formatter.get(name);
13046      if (formatList) {
13047        for (let i = 0; i < formatList.length; i++) {
13048          const format = formatList[i];
13049          if (isSelectorFormat(format) && format.inherit === false && ed.dom.is(node, format.selector)) {
13050            return true;
13051          }
13052        }
13053      }
13054      return false;
13055    };
13056    const matchParents = (editor, node, name, vars, similar) => {
13057      const root = editor.dom.getRoot();
13058      if (node === root) {
13059        return false;
13060      }
13061      const matchedNode = editor.dom.getParent(node, elm => {
13062        if (matchesUnInheritedFormatSelector(editor, elm, name)) {
13063          return true;
13064        }
13065        return elm.parentNode === root || !!matchNode(editor, elm, name, vars, true);
13066      });
13067      return !!matchNode(editor, matchedNode, name, vars, similar);
13068    };
13069    const matchName = (dom, node, format) => {
13070      if (isInlineFormat(format) && isEq$3(node, format.inline)) {
13071        return true;
13072      }
13073      if (isBlockFormat(format) && isEq$3(node, format.block)) {
13074        return true;
13075      }
13076      if (isSelectorFormat(format)) {
13077        return isElement$6(node) && dom.is(node, format.selector);
13078      }
13079      return false;
13080    };
13081    const matchItems = (dom, node, format, itemName, similar, vars) => {
13082      const items = format[itemName];
13083      const matchAttributes = itemName === 'attributes';
13084      if (isFunction(format.onmatch)) {
13085        return format.onmatch(node, format, itemName);
13086      }
13087      if (items) {
13088        if (!isArrayLike(items)) {
13089          for (const key in items) {
13090            if (has$2(items, key)) {
13091              const value = matchAttributes ? dom.getAttrib(node, key) : getStyle(dom, node, key);
13092              const expectedValue = replaceVars(items[key], vars);
13093              const isEmptyValue = isNullable(value) || isEmpty$3(value);
13094              if (isEmptyValue && isNullable(expectedValue)) {
13095                continue;
13096              }
13097              if (similar && isEmptyValue && !format.exact) {
13098                return false;
13099              }
13100              if ((!similar || format.exact) && !isEq$3(value, normalizeStyleValue(expectedValue, key))) {
13101                return false;
13102              }
13103            }
13104          }
13105        } else {
13106          for (let i = 0; i < items.length; i++) {
13107            if (matchAttributes ? dom.getAttrib(node, items[i]) : getStyle(dom, node, items[i])) {
13108              return true;
13109            }
13110          }
13111        }
13112      }
13113      return true;
13114    };
13115    const matchNode = (ed, node, name, vars, similar) => {
13116      const formatList = ed.formatter.get(name);
13117      const dom = ed.dom;
13118      if (formatList && isElement$6(node)) {
13119        for (let i = 0; i < formatList.length; i++) {
13120          const format = formatList[i];
13121          if (matchName(ed.dom, node, format) && matchItems(dom, node, format, 'attributes', similar, vars) && matchItems(dom, node, format, 'styles', similar, vars)) {
13122            const classes = format.classes;
13123            if (classes) {
13124              for (let x = 0; x < classes.length; x++) {
13125                if (!ed.dom.hasClass(node, replaceVars(classes[x], vars))) {
13126                  return;
13127                }
13128              }
13129            }
13130            return format;
13131          }
13132        }
13133      }
13134      return undefined;
13135    };
13136    const match$2 = (editor, name, vars, node, similar) => {
13137      if (node) {
13138        return matchParents(editor, node, name, vars, similar);
13139      }
13140      node = editor.selection.getNode();
13141      if (matchParents(editor, node, name, vars, similar)) {
13142        return true;
13143      }
13144      const startNode = editor.selection.getStart();
13145      if (startNode !== node) {
13146        if (matchParents(editor, startNode, name, vars, similar)) {
13147          return true;
13148        }
13149      }
13150      return false;
13151    };
13152    const matchAll = (editor, names, vars) => {
13153      const matchedFormatNames = [];
13154      const checkedMap = {};
13155      const startElement = editor.selection.getStart();
13156      editor.dom.getParent(startElement, node => {
13157        for (let i = 0; i < names.length; i++) {
13158          const name = names[i];
13159          if (!checkedMap[name] && matchNode(editor, node, name, vars)) {
13160            checkedMap[name] = true;
13161            matchedFormatNames.push(name);
13162          }
13163        }
13164      }, editor.dom.getRoot());
13165      return matchedFormatNames;
13166    };
13167    const closest = (editor, names) => {
13168      const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
13169      const match = (elm, name) => matchNode(editor, elm.dom, name) ? Optional.some(name) : Optional.none();
13170      return Optional.from(editor.selection.getStart(true)).bind(rawElm => closest$1(SugarElement.fromDom(rawElm), elm => findMap(names, name => match(elm, name)), isRoot)).getOrNull();
13171    };
13172    const canApply = (editor, name) => {
13173      const formatList = editor.formatter.get(name);
13174      const dom = editor.dom;
13175      if (formatList && editor.selection.isEditable()) {
13176        const startNode = editor.selection.getStart();
13177        const parents = getParents$2(dom, startNode);
13178        for (let x = formatList.length - 1; x >= 0; x--) {
13179          const format = formatList[x];
13180          if (!isSelectorFormat(format)) {
13181            return true;
13182          }
13183          for (let i = parents.length - 1; i >= 0; i--) {
13184            if (dom.is(parents[i], format.selector)) {
13185              return true;
13186            }
13187          }
13188        }
13189      }
13190      return false;
13191    };
13192    const matchAllOnNode = (editor, node, formatNames) => foldl(formatNames, (acc, name) => {
13193      const matchSimilar = isVariableFormatName(editor, name);
13194      if (editor.formatter.matchNode(node, name, {}, matchSimilar)) {
13195        return acc.concat([name]);
13196      } else {
13197        return acc;
13198      }
13199    }, []);
13200
13201    const ZWSP = ZWSP$1;
13202    const importNode = (ownerDocument, node) => {
13203      return ownerDocument.importNode(node, true);
13204    };
13205    const getEmptyCaretContainers = node => {
13206      const nodes = [];
13207      let tempNode = node;
13208      while (tempNode) {
13209        if (isText$a(tempNode) && tempNode.data !== ZWSP || tempNode.childNodes.length > 1) {
13210          return [];
13211        }
13212        if (isElement$6(tempNode)) {
13213          nodes.push(tempNode);
13214        }
13215        tempNode = tempNode.firstChild;
13216      }
13217      return nodes;
13218    };
13219    const isCaretContainerEmpty = node => {
13220      return getEmptyCaretContainers(node).length > 0;
13221    };
13222    const findFirstTextNode = node => {
13223      if (node) {
13224        const walker = new DomTreeWalker(node, node);
13225        for (let tempNode = walker.current(); tempNode; tempNode = walker.next()) {
13226          if (isText$a(tempNode)) {
13227            return tempNode;
13228          }
13229        }
13230      }
13231      return null;
13232    };
13233    const createCaretContainer = fill => {
13234      const caretContainer = SugarElement.fromTag('span');
13235      setAll$1(caretContainer, {
13236        'id': CARET_ID,
13237        'data-mce-bogus': '1',
13238        'data-mce-type': 'format-caret'
13239      });
13240      if (fill) {
13241        append$1(caretContainer, SugarElement.fromText(ZWSP));
13242      }
13243      return caretContainer;
13244    };
13245    const trimZwspFromCaretContainer = caretContainerNode => {
13246      const textNode = findFirstTextNode(caretContainerNode);
13247      if (textNode && textNode.data.charAt(0) === ZWSP) {
13248        textNode.deleteData(0, 1);
13249      }
13250      return textNode;
13251    };
13252    const removeCaretContainerNode = (editor, node, moveCaret = true) => {
13253      const dom = editor.dom, selection = editor.selection;
13254      if (isCaretContainerEmpty(node)) {
13255        deleteElement$2(editor, false, SugarElement.fromDom(node), moveCaret);
13256      } else {
13257        const rng = selection.getRng();
13258        const block = dom.getParent(node, dom.isBlock);
13259        const startContainer = rng.startContainer;
13260        const startOffset = rng.startOffset;
13261        const endContainer = rng.endContainer;
13262        const endOffset = rng.endOffset;
13263        const textNode = trimZwspFromCaretContainer(node);
13264        dom.remove(node, true);
13265        if (startContainer === textNode && startOffset > 0) {
13266          rng.setStart(textNode, startOffset - 1);
13267        }
13268        if (endContainer === textNode && endOffset > 0) {
13269          rng.setEnd(textNode, endOffset - 1);
13270        }
13271        if (block && dom.isEmpty(block)) {
13272          fillWithPaddingBr(SugarElement.fromDom(block));
13273        }
13274        selection.setRng(rng);
13275      }
13276    };
13277    const removeCaretContainer = (editor, node, moveCaret = true) => {
13278      const dom = editor.dom, selection = editor.selection;
13279      if (!node) {
13280        node = getParentCaretContainer(editor.getBody(), selection.getStart());
13281        if (!node) {
13282          while (node = dom.get(CARET_ID)) {
13283            removeCaretContainerNode(editor, node, moveCaret);
13284          }
13285        }
13286      } else {
13287        removeCaretContainerNode(editor, node, moveCaret);
13288      }
13289    };
13290    const insertCaretContainerNode = (editor, caretContainer, formatNode) => {
13291      var _a, _b;
13292      const dom = editor.dom;
13293      const block = dom.getParent(formatNode, curry(isTextBlock$1, editor.schema));
13294      if (block && dom.isEmpty(block)) {
13295        (_a = formatNode.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(caretContainer, formatNode);
13296      } else {
13297        removeTrailingBr(SugarElement.fromDom(formatNode));
13298        if (dom.isEmpty(formatNode)) {
13299          (_b = formatNode.parentNode) === null || _b === void 0 ? void 0 : _b.replaceChild(caretContainer, formatNode);
13300        } else {
13301          dom.insertAfter(caretContainer, formatNode);
13302        }
13303      }
13304    };
13305    const appendNode = (parentNode, node) => {
13306      parentNode.appendChild(node);
13307      return node;
13308    };
13309    const insertFormatNodesIntoCaretContainer = (formatNodes, caretContainer) => {
13310      var _a;
13311      const innerMostFormatNode = foldr(formatNodes, (parentNode, formatNode) => {
13312        return appendNode(parentNode, formatNode.cloneNode(false));
13313      }, caretContainer);
13314      const doc = (_a = innerMostFormatNode.ownerDocument) !== null && _a !== void 0 ? _a : document;
13315      return appendNode(innerMostFormatNode, doc.createTextNode(ZWSP));
13316    };
13317    const cleanFormatNode = (editor, caretContainer, formatNode, name, vars, similar) => {
13318      const formatter = editor.formatter;
13319      const dom = editor.dom;
13320      const validFormats = filter$5(keys(formatter.get()), formatName => formatName !== name && !contains$1(formatName, 'removeformat'));
13321      const matchedFormats = matchAllOnNode(editor, formatNode, validFormats);
13322      const uniqueFormats = filter$5(matchedFormats, fmtName => !areSimilarFormats(editor, fmtName, name));
13323      if (uniqueFormats.length > 0) {
13324        const clonedFormatNode = formatNode.cloneNode(false);
13325        dom.add(caretContainer, clonedFormatNode);
13326        formatter.remove(name, vars, clonedFormatNode, similar);
13327        dom.remove(clonedFormatNode);
13328        return Optional.some(clonedFormatNode);
13329      } else {
13330        return Optional.none();
13331      }
13332    };
13333    const applyCaretFormat = (editor, name, vars) => {
13334      let caretContainer;
13335      const selection = editor.selection;
13336      const formatList = editor.formatter.get(name);
13337      if (!formatList) {
13338        return;
13339      }
13340      const selectionRng = selection.getRng();
13341      let offset = selectionRng.startOffset;
13342      const container = selectionRng.startContainer;
13343      const text = container.nodeValue;
13344      caretContainer = getParentCaretContainer(editor.getBody(), selection.getStart());
13345      const wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
13346      if (text && offset > 0 && offset < text.length && wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) {
13347        const bookmark = selection.getBookmark();
13348        selectionRng.collapse(true);
13349        let rng = expandRng(editor.dom, selectionRng, formatList);
13350        rng = split(rng);
13351        editor.formatter.apply(name, vars, rng);
13352        selection.moveToBookmark(bookmark);
13353      } else {
13354        let textNode = caretContainer ? findFirstTextNode(caretContainer) : null;
13355        if (!caretContainer || (textNode === null || textNode === void 0 ? void 0 : textNode.data) !== ZWSP) {
13356          caretContainer = importNode(editor.getDoc(), createCaretContainer(true).dom);
13357          textNode = caretContainer.firstChild;
13358          selectionRng.insertNode(caretContainer);
13359          offset = 1;
13360          editor.formatter.apply(name, vars, caretContainer);
13361        } else {
13362          editor.formatter.apply(name, vars, caretContainer);
13363        }
13364        selection.setCursorLocation(textNode, offset);
13365      }
13366    };
13367    const removeCaretFormat = (editor, name, vars, similar) => {
13368      const dom = editor.dom;
13369      const selection = editor.selection;
13370      let hasContentAfter = false;
13371      const formatList = editor.formatter.get(name);
13372      if (!formatList) {
13373        return;
13374      }
13375      const rng = selection.getRng();
13376      const container = rng.startContainer;
13377      const offset = rng.startOffset;
13378      let node = container;
13379      if (isText$a(container)) {
13380        if (offset !== container.data.length) {
13381          hasContentAfter = true;
13382        }
13383        node = node.parentNode;
13384      }
13385      const parents = [];
13386      let formatNode;
13387      while (node) {
13388        if (matchNode(editor, node, name, vars, similar)) {
13389          formatNode = node;
13390          break;
13391        }
13392        if (node.nextSibling) {
13393          hasContentAfter = true;
13394        }
13395        parents.push(node);
13396        node = node.parentNode;
13397      }
13398      if (!formatNode) {
13399        return;
13400      }
13401      if (hasContentAfter) {
13402        const bookmark = selection.getBookmark();
13403        rng.collapse(true);
13404        let expandedRng = expandRng(dom, rng, formatList, true);
13405        expandedRng = split(expandedRng);
13406        editor.formatter.remove(name, vars, expandedRng, similar);
13407        selection.moveToBookmark(bookmark);
13408      } else {
13409        const caretContainer = getParentCaretContainer(editor.getBody(), formatNode);
13410        const newCaretContainer = createCaretContainer(false).dom;
13411        insertCaretContainerNode(editor, newCaretContainer, caretContainer !== null && caretContainer !== void 0 ? caretContainer : formatNode);
13412        const cleanedFormatNode = cleanFormatNode(editor, newCaretContainer, formatNode, name, vars, similar);
13413        const caretTextNode = insertFormatNodesIntoCaretContainer(parents.concat(cleanedFormatNode.toArray()), newCaretContainer);
13414        if (caretContainer) {
13415          removeCaretContainerNode(editor, caretContainer, false);
13416        }
13417        selection.setCursorLocation(caretTextNode, 1);
13418        if (dom.isEmpty(formatNode)) {
13419          dom.remove(formatNode);
13420        }
13421      }
13422    };
13423    const disableCaretContainer = (editor, keyCode, moveCaret) => {
13424      const selection = editor.selection, body = editor.getBody();
13425      removeCaretContainer(editor, null, moveCaret);
13426      if ((keyCode === 8 || keyCode === 46) && selection.isCollapsed() && selection.getStart().innerHTML === ZWSP) {
13427        removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()));
13428      }
13429      if (keyCode === 37 || keyCode === 39) {
13430        removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()));
13431      }
13432    };
13433    const endsWithNbsp = element => isText$a(element) && endsWith(element.data, nbsp);
13434    const setup$u = editor => {
13435      editor.on('mouseup keydown', e => {
13436        disableCaretContainer(editor, e.keyCode, endsWithNbsp(editor.selection.getRng().endContainer));
13437      });
13438    };
13439    const createCaretFormat = formatNodes => {
13440      const caretContainer = createCaretContainer(false);
13441      const innerMost = insertFormatNodesIntoCaretContainer(formatNodes, caretContainer.dom);
13442      return {
13443        caretContainer,
13444        caretPosition: CaretPosition(innerMost, 0)
13445      };
13446    };
13447    const replaceWithCaretFormat = (targetNode, formatNodes) => {
13448      const {caretContainer, caretPosition} = createCaretFormat(formatNodes);
13449      before$3(SugarElement.fromDom(targetNode), caretContainer);
13450      remove$5(SugarElement.fromDom(targetNode));
13451      return caretPosition;
13452    };
13453    const createCaretFormatAtStart$1 = (rng, formatNodes) => {
13454      const {caretContainer, caretPosition} = createCaretFormat(formatNodes);
13455      rng.insertNode(caretContainer.dom);
13456      return caretPosition;
13457    };
13458    const isFormatElement = (editor, element) => {
13459      const inlineElements = editor.schema.getTextInlineElements();
13460      return has$2(inlineElements, name(element)) && !isCaretNode(element.dom) && !isBogus$2(element.dom);
13461    };
13462    const isEmptyCaretFormatElement = element => {
13463      return isCaretNode(element.dom) && isCaretContainerEmpty(element.dom);
13464    };
13465
13466    const postProcessHooks = {};
13467    const isPre = matchNodeNames(['pre']);
13468    const addPostProcessHook = (name, hook) => {
13469      const hooks = postProcessHooks[name];
13470      if (!hooks) {
13471        postProcessHooks[name] = [];
13472      }
13473      postProcessHooks[name].push(hook);
13474    };
13475    const postProcess$1 = (name, editor) => {
13476      if (has$2(postProcessHooks, name)) {
13477        each$e(postProcessHooks[name], hook => {
13478          hook(editor);
13479        });
13480      }
13481    };
13482    addPostProcessHook('pre', editor => {
13483      const rng = editor.selection.getRng();
13484      const hasPreSibling = blocks => pre => {
13485        const prev = pre.previousSibling;
13486        return isPre(prev) && contains$2(blocks, prev);
13487      };
13488      const joinPre = (pre1, pre2) => {
13489        const sPre2 = SugarElement.fromDom(pre2);
13490        const doc = documentOrOwner(sPre2).dom;
13491        remove$5(sPre2);
13492        append(SugarElement.fromDom(pre1), [
13493          SugarElement.fromTag('br', doc),
13494          SugarElement.fromTag('br', doc),
13495          ...children$1(sPre2)
13496        ]);
13497      };
13498      if (!rng.collapsed) {
13499        const blocks = editor.selection.getSelectedBlocks();
13500        const preBlocks = filter$5(filter$5(blocks, isPre), hasPreSibling(blocks));
13501        each$e(preBlocks, pre => {
13502          joinPre(pre.previousSibling, pre);
13503        });
13504      }
13505    });
13506
13507    const listItemStyles = [
13508      'fontWeight',
13509      'fontStyle',
13510      'color',
13511      'fontSize',
13512      'fontFamily'
13513    ];
13514    const hasListStyles = fmt => isObject(fmt.styles) && exists(keys(fmt.styles), name => contains$2(listItemStyles, name));
13515    const findExpandedListItemFormat = formats => find$2(formats, fmt => isInlineFormat(fmt) && fmt.inline === 'span' && hasListStyles(fmt));
13516    const getExpandedListItemFormat = (formatter, format) => {
13517      const formatList = formatter.get(format);
13518      return isArray$1(formatList) ? findExpandedListItemFormat(formatList) : Optional.none();
13519    };
13520    const isRngStartAtStartOfElement = (rng, elm) => prevPosition(elm, CaretPosition.fromRangeStart(rng)).isNone();
13521    const isRngEndAtEndOfElement = (rng, elm) => {
13522      return nextPosition(elm, CaretPosition.fromRangeEnd(rng)).exists(pos => !isBr$6(pos.getNode()) || nextPosition(elm, pos).isSome()) === false;
13523    };
13524    const isEditableListItem = dom => elm => isListItem$2(elm) && dom.isEditable(elm);
13525    const getFullySelectedBlocks = selection => {
13526      const blocks = selection.getSelectedBlocks();
13527      const rng = selection.getRng();
13528      if (selection.isCollapsed()) {
13529        return [];
13530      }
13531      if (blocks.length === 1) {
13532        return isRngStartAtStartOfElement(rng, blocks[0]) && isRngEndAtEndOfElement(rng, blocks[0]) ? blocks : [];
13533      } else {
13534        const first = head(blocks).filter(elm => isRngStartAtStartOfElement(rng, elm)).toArray();
13535        const last = last$3(blocks).filter(elm => isRngEndAtEndOfElement(rng, elm)).toArray();
13536        const middle = blocks.slice(1, -1);
13537        return first.concat(middle).concat(last);
13538      }
13539    };
13540    const getFullySelectedListItems = selection => filter$5(getFullySelectedBlocks(selection), isEditableListItem(selection.dom));
13541    const getPartiallySelectedListItems = selection => filter$5(selection.getSelectedBlocks(), isEditableListItem(selection.dom));
13542
13543    const each$8 = Tools.each;
13544    const isElementNode = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$2(node);
13545    const findElementSibling = (node, siblingName) => {
13546      for (let sibling = node; sibling; sibling = sibling[siblingName]) {
13547        if (isText$a(sibling) && isNotEmpty(sibling.data)) {
13548          return node;
13549        }
13550        if (isElement$6(sibling) && !isBookmarkNode$1(sibling)) {
13551          return sibling;
13552        }
13553      }
13554      return node;
13555    };
13556    const mergeSiblingsNodes = (editor, prev, next) => {
13557      const elementUtils = ElementUtils(editor);
13558      const isPrevEditable = isElement$6(prev) && isEditable$2(prev);
13559      const isNextEditable = isElement$6(next) && isEditable$2(next);
13560      if (isPrevEditable && isNextEditable) {
13561        const prevSibling = findElementSibling(prev, 'previousSibling');
13562        const nextSibling = findElementSibling(next, 'nextSibling');
13563        if (elementUtils.compare(prevSibling, nextSibling)) {
13564          for (let sibling = prevSibling.nextSibling; sibling && sibling !== nextSibling;) {
13565            const tmpSibling = sibling;
13566            sibling = sibling.nextSibling;
13567            prevSibling.appendChild(tmpSibling);
13568          }
13569          editor.dom.remove(nextSibling);
13570          Tools.each(Tools.grep(nextSibling.childNodes), node => {
13571            prevSibling.appendChild(node);
13572          });
13573          return prevSibling;
13574        }
13575      }
13576      return next;
13577    };
13578    const mergeSiblings = (editor, format, vars, node) => {
13579      var _a;
13580      if (node && format.merge_siblings !== false) {
13581        const newNode = (_a = mergeSiblingsNodes(editor, getNonWhiteSpaceSibling(node), node)) !== null && _a !== void 0 ? _a : node;
13582        mergeSiblingsNodes(editor, newNode, getNonWhiteSpaceSibling(newNode, true));
13583      }
13584    };
13585    const clearChildStyles = (dom, format, node) => {
13586      if (format.clear_child_styles) {
13587        const selector = format.links ? '*:not(a)' : '*';
13588        each$8(dom.select(selector, node), childNode => {
13589          if (isElementNode(childNode) && isEditable$2(childNode)) {
13590            each$8(format.styles, (_value, name) => {
13591              dom.setStyle(childNode, name, '');
13592            });
13593          }
13594        });
13595      }
13596    };
13597    const processChildElements = (node, filter, process) => {
13598      each$8(node.childNodes, node => {
13599        if (isElementNode(node)) {
13600          if (filter(node)) {
13601            process(node);
13602          }
13603          if (node.hasChildNodes()) {
13604            processChildElements(node, filter, process);
13605          }
13606        }
13607      });
13608    };
13609    const unwrapEmptySpan = (dom, node) => {
13610      if (node.nodeName === 'SPAN' && dom.getAttribs(node).length === 0) {
13611        dom.remove(node, true);
13612      }
13613    };
13614    const hasStyle = (dom, name) => node => !!(node && getStyle(dom, node, name));
13615    const applyStyle = (dom, name, value) => node => {
13616      dom.setStyle(node, name, value);
13617      if (node.getAttribute('style') === '') {
13618        node.removeAttribute('style');
13619      }
13620      unwrapEmptySpan(dom, node);
13621    };
13622
13623    const removeResult = Adt.generate([
13624      { keep: [] },
13625      { rename: ['name'] },
13626      { removed: [] }
13627    ]);
13628    const MCE_ATTR_RE = /^(src|href|style)$/;
13629    const each$7 = Tools.each;
13630    const isEq$2 = isEq$5;
13631    const isTableCellOrRow = node => /^(TR|TH|TD)$/.test(node.nodeName);
13632    const isChildOfInlineParent = (dom, node, parent) => dom.isChildOf(node, parent) && node !== parent && !dom.isBlock(parent);
13633    const getContainer = (ed, rng, start) => {
13634      let container = rng[start ? 'startContainer' : 'endContainer'];
13635      let offset = rng[start ? 'startOffset' : 'endOffset'];
13636      if (isElement$6(container)) {
13637        const lastIdx = container.childNodes.length - 1;
13638        if (!start && offset) {
13639          offset--;
13640        }
13641        container = container.childNodes[offset > lastIdx ? lastIdx : offset];
13642      }
13643      if (isText$a(container) && start && offset >= container.data.length) {
13644        container = new DomTreeWalker(container, ed.getBody()).next() || container;
13645      }
13646      if (isText$a(container) && !start && offset === 0) {
13647        container = new DomTreeWalker(container, ed.getBody()).prev() || container;
13648      }
13649      return container;
13650    };
13651    const normalizeTableSelection = (node, start) => {
13652      const prop = start ? 'firstChild' : 'lastChild';
13653      const childNode = node[prop];
13654      if (isTableCellOrRow(node) && childNode) {
13655        if (node.nodeName === 'TR') {
13656          return childNode[prop] || childNode;
13657        } else {
13658          return childNode;
13659        }
13660      }
13661      return node;
13662    };
13663    const wrap$1 = (dom, node, name, attrs) => {
13664      var _a;
13665      const wrapper = dom.create(name, attrs);
13666      (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(wrapper, node);
13667      wrapper.appendChild(node);
13668      return wrapper;
13669    };
13670    const wrapWithSiblings = (dom, node, next, name, attrs) => {
13671      const start = SugarElement.fromDom(node);
13672      const wrapper = SugarElement.fromDom(dom.create(name, attrs));
13673      const siblings = next ? nextSiblings(start) : prevSiblings(start);
13674      append(wrapper, siblings);
13675      if (next) {
13676        before$3(start, wrapper);
13677        prepend(wrapper, start);
13678      } else {
13679        after$4(start, wrapper);
13680        append$1(wrapper, start);
13681      }
13682      return wrapper.dom;
13683    };
13684    const isColorFormatAndAnchor = (node, format) => format.links && node.nodeName === 'A';
13685    const removeNode = (ed, node, format) => {
13686      const parentNode = node.parentNode;
13687      let rootBlockElm;
13688      const dom = ed.dom;
13689      const forcedRootBlock = getForcedRootBlock(ed);
13690      if (isBlockFormat(format)) {
13691        if (parentNode === dom.getRoot()) {
13692          if (!format.list_block || !isEq$2(node, format.list_block)) {
13693            each$e(from(node.childNodes), node => {
13694              if (isValid(ed, forcedRootBlock, node.nodeName.toLowerCase())) {
13695                if (!rootBlockElm) {
13696                  rootBlockElm = wrap$1(dom, node, forcedRootBlock);
13697                  dom.setAttribs(rootBlockElm, getForcedRootBlockAttrs(ed));
13698                } else {
13699                  rootBlockElm.appendChild(node);
13700                }
13701              } else {
13702                rootBlockElm = null;
13703              }
13704            });
13705          }
13706        }
13707      }
13708      if (isMixedFormat(format) && !isEq$2(format.inline, node)) {
13709        return;
13710      }
13711      dom.remove(node, true);
13712    };
13713    const processFormatAttrOrStyle = (name, value, vars) => {
13714      if (isNumber(name)) {
13715        return {
13716          name: value,
13717          value: null
13718        };
13719      } else {
13720        return {
13721          name,
13722          value: replaceVars(value, vars)
13723        };
13724      }
13725    };
13726    const removeEmptyStyleAttributeIfNeeded = (dom, elm) => {
13727      if (dom.getAttrib(elm, 'style') === '') {
13728        elm.removeAttribute('style');
13729        elm.removeAttribute('data-mce-style');
13730      }
13731    };
13732    const removeStyles = (dom, elm, format, vars, compareNode) => {
13733      let stylesModified = false;
13734      each$7(format.styles, (value, name) => {
13735        const {
13736          name: styleName,
13737          value: styleValue
13738        } = processFormatAttrOrStyle(name, value, vars);
13739        const normalizedStyleValue = normalizeStyleValue(styleValue, styleName);
13740        if (format.remove_similar || isNull(styleValue) || !isElement$6(compareNode) || isEq$2(getStyle(dom, compareNode, styleName), normalizedStyleValue)) {
13741          dom.setStyle(elm, styleName, '');
13742        }
13743        stylesModified = true;
13744      });
13745      if (stylesModified) {
13746        removeEmptyStyleAttributeIfNeeded(dom, elm);
13747      }
13748    };
13749    const removeListStyleFormats = (editor, name, vars) => {
13750      if (name === 'removeformat') {
13751        each$e(getPartiallySelectedListItems(editor.selection), li => {
13752          each$e(listItemStyles, name => editor.dom.setStyle(li, name, ''));
13753          removeEmptyStyleAttributeIfNeeded(editor.dom, li);
13754        });
13755      } else {
13756        getExpandedListItemFormat(editor.formatter, name).each(liFmt => {
13757          each$e(getPartiallySelectedListItems(editor.selection), li => removeStyles(editor.dom, li, liFmt, vars, null));
13758        });
13759      }
13760    };
13761    const removeNodeFormatInternal = (ed, format, vars, node, compareNode) => {
13762      const dom = ed.dom;
13763      const elementUtils = ElementUtils(ed);
13764      const schema = ed.schema;
13765      if (isInlineFormat(format) && isTransparentElementName(schema, format.inline) && isTransparentBlock(schema, node) && node.parentElement === ed.getBody()) {
13766        removeNode(ed, node, format);
13767        return removeResult.removed();
13768      }
13769      if (!format.ceFalseOverride && node && dom.getContentEditableParent(node) === 'false') {
13770        return removeResult.keep();
13771      }
13772      if (node && !matchName(dom, node, format) && !isColorFormatAndAnchor(node, format)) {
13773        return removeResult.keep();
13774      }
13775      const elm = node;
13776      const preserveAttributes = format.preserve_attributes;
13777      if (isInlineFormat(format) && format.remove === 'all' && isArray$1(preserveAttributes)) {
13778        const attrsToPreserve = filter$5(dom.getAttribs(elm), attr => contains$2(preserveAttributes, attr.name.toLowerCase()));
13779        dom.removeAllAttribs(elm);
13780        each$e(attrsToPreserve, attr => dom.setAttrib(elm, attr.name, attr.value));
13781        if (attrsToPreserve.length > 0) {
13782          return removeResult.rename('span');
13783        }
13784      }
13785      if (format.remove !== 'all') {
13786        removeStyles(dom, elm, format, vars, compareNode);
13787        each$7(format.attributes, (value, name) => {
13788          const {
13789            name: attrName,
13790            value: attrValue
13791          } = processFormatAttrOrStyle(name, value, vars);
13792          if (format.remove_similar || isNull(attrValue) || !isElement$6(compareNode) || isEq$2(dom.getAttrib(compareNode, attrName), attrValue)) {
13793            if (attrName === 'class') {
13794              const currentValue = dom.getAttrib(elm, attrName);
13795              if (currentValue) {
13796                let valueOut = '';
13797                each$e(currentValue.split(/\s+/), cls => {
13798                  if (/mce\-\w+/.test(cls)) {
13799                    valueOut += (valueOut ? ' ' : '') + cls;
13800                  }
13801                });
13802                if (valueOut) {
13803                  dom.setAttrib(elm, attrName, valueOut);
13804                  return;
13805                }
13806              }
13807            }
13808            if (MCE_ATTR_RE.test(attrName)) {
13809              elm.removeAttribute('data-mce-' + attrName);
13810            }
13811            if (attrName === 'style' && matchNodeNames(['li'])(elm) && dom.getStyle(elm, 'list-style-type') === 'none') {
13812              elm.removeAttribute(attrName);
13813              dom.setStyle(elm, 'list-style-type', 'none');
13814              return;
13815            }
13816            if (attrName === 'class') {
13817              elm.removeAttribute('className');
13818            }
13819            elm.removeAttribute(attrName);
13820          }
13821        });
13822        each$7(format.classes, value => {
13823          value = replaceVars(value, vars);
13824          if (!isElement$6(compareNode) || dom.hasClass(compareNode, value)) {
13825            dom.removeClass(elm, value);
13826          }
13827        });
13828        const attrs = dom.getAttribs(elm);
13829        for (let i = 0; i < attrs.length; i++) {
13830          const attrName = attrs[i].nodeName;
13831          if (!elementUtils.isAttributeInternal(attrName)) {
13832            return removeResult.keep();
13833          }
13834        }
13835      }
13836      if (format.remove !== 'none') {
13837        removeNode(ed, elm, format);
13838        return removeResult.removed();
13839      }
13840      return removeResult.keep();
13841    };
13842    const findFormatRoot = (editor, container, name, vars, similar) => {
13843      let formatRoot;
13844      if (container.parentNode) {
13845        each$e(getParents$2(editor.dom, container.parentNode).reverse(), parent => {
13846          if (!formatRoot && isElement$6(parent) && parent.id !== '_start' && parent.id !== '_end') {
13847            const format = matchNode(editor, parent, name, vars, similar);
13848            if (format && format.split !== false) {
13849              formatRoot = parent;
13850            }
13851          }
13852        });
13853      }
13854      return formatRoot;
13855    };
13856    const removeNodeFormatFromClone = (editor, format, vars, clone) => removeNodeFormatInternal(editor, format, vars, clone, clone).fold(constant(clone), newName => {
13857      const fragment = editor.dom.createFragment();
13858      fragment.appendChild(clone);
13859      return editor.dom.rename(clone, newName);
13860    }, constant(null));
13861    const wrapAndSplit = (editor, formatList, formatRoot, container, target, split, format, vars) => {
13862      var _a, _b;
13863      let lastClone;
13864      let firstClone;
13865      const dom = editor.dom;
13866      if (formatRoot) {
13867        const formatRootParent = formatRoot.parentNode;
13868        for (let parent = container.parentNode; parent && parent !== formatRootParent; parent = parent.parentNode) {
13869          let clone = dom.clone(parent, false);
13870          for (let i = 0; i < formatList.length; i++) {
13871            clone = removeNodeFormatFromClone(editor, formatList[i], vars, clone);
13872            if (clone === null) {
13873              break;
13874            }
13875          }
13876          if (clone) {
13877            if (lastClone) {
13878              clone.appendChild(lastClone);
13879            }
13880            if (!firstClone) {
13881              firstClone = clone;
13882            }
13883            lastClone = clone;
13884          }
13885        }
13886        if (split && (!format.mixed || !dom.isBlock(formatRoot))) {
13887          container = (_a = dom.split(formatRoot, container)) !== null && _a !== void 0 ? _a : container;
13888        }
13889        if (lastClone && firstClone) {
13890          (_b = target.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(lastClone, target);
13891          firstClone.appendChild(target);
13892          if (isInlineFormat(format)) {
13893            mergeSiblings(editor, format, vars, lastClone);
13894          }
13895        }
13896      }
13897      return container;
13898    };
13899    const removeFormatInternal = (ed, name, vars, node, similar) => {
13900      const formatList = ed.formatter.get(name);
13901      const format = formatList[0];
13902      const dom = ed.dom;
13903      const selection = ed.selection;
13904      const splitToFormatRoot = container => {
13905        const formatRoot = findFormatRoot(ed, container, name, vars, similar);
13906        return wrapAndSplit(ed, formatList, formatRoot, container, container, true, format, vars);
13907      };
13908      const isRemoveBookmarkNode = node => isBookmarkNode$1(node) && isElement$6(node) && (node.id === '_start' || node.id === '_end');
13909      const removeFormatOnNode = node => exists(formatList, fmt => removeNodeFormat(ed, fmt, vars, node, node));
13910      const process = node => {
13911        const children = from(node.childNodes);
13912        const removed = removeFormatOnNode(node);
13913        const currentNodeMatches = removed || exists(formatList, f => matchName(dom, node, f));
13914        const parentNode = node.parentNode;
13915        if (!currentNodeMatches && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
13916          removeFormatOnNode(parentNode);
13917        }
13918        if (format.deep) {
13919          if (children.length) {
13920            for (let i = 0; i < children.length; i++) {
13921              process(children[i]);
13922            }
13923          }
13924        }
13925        const textDecorations = [
13926          'underline',
13927          'line-through',
13928          'overline'
13929        ];
13930        each$e(textDecorations, decoration => {
13931          if (isElement$6(node) && ed.dom.getStyle(node, 'text-decoration') === decoration && node.parentNode && getTextDecoration(dom, node.parentNode) === decoration) {
13932            removeNodeFormat(ed, {
13933              deep: false,
13934              exact: true,
13935              inline: 'span',
13936              styles: { textDecoration: decoration }
13937            }, undefined, node);
13938          }
13939        });
13940      };
13941      const unwrap = start => {
13942        const node = dom.get(start ? '_start' : '_end');
13943        if (node) {
13944          let out = node[start ? 'firstChild' : 'lastChild'];
13945          if (isRemoveBookmarkNode(out)) {
13946            out = out[start ? 'firstChild' : 'lastChild'];
13947          }
13948          if (isText$a(out) && out.data.length === 0) {
13949            out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling;
13950          }
13951          dom.remove(node, true);
13952          return out;
13953        } else {
13954          return null;
13955        }
13956      };
13957      const removeRngStyle = rng => {
13958        let startContainer;
13959        let endContainer;
13960        let expandedRng = expandRng(dom, rng, formatList, rng.collapsed);
13961        if (format.split) {
13962          expandedRng = split(expandedRng);
13963          startContainer = getContainer(ed, expandedRng, true);
13964          endContainer = getContainer(ed, expandedRng);
13965          if (startContainer !== endContainer) {
13966            startContainer = normalizeTableSelection(startContainer, true);
13967            endContainer = normalizeTableSelection(endContainer, false);
13968            if (isChildOfInlineParent(dom, startContainer, endContainer)) {
13969              const marker = Optional.from(startContainer.firstChild).getOr(startContainer);
13970              splitToFormatRoot(wrapWithSiblings(dom, marker, true, 'span', {
13971                'id': '_start',
13972                'data-mce-type': 'bookmark'
13973              }));
13974              unwrap(true);
13975              return;
13976            }
13977            if (isChildOfInlineParent(dom, endContainer, startContainer)) {
13978              const marker = Optional.from(endContainer.lastChild).getOr(endContainer);
13979              splitToFormatRoot(wrapWithSiblings(dom, marker, false, 'span', {
13980                'id': '_end',
13981                'data-mce-type': 'bookmark'
13982              }));
13983              unwrap(false);
13984              return;
13985            }
13986            startContainer = wrap$1(dom, startContainer, 'span', {
13987              'id': '_start',
13988              'data-mce-type': 'bookmark'
13989            });
13990            endContainer = wrap$1(dom, endContainer, 'span', {
13991              'id': '_end',
13992              'data-mce-type': 'bookmark'
13993            });
13994            const newRng = dom.createRng();
13995            newRng.setStartAfter(startContainer);
13996            newRng.setEndBefore(endContainer);
13997            walk$3(dom, newRng, nodes => {
13998              each$e(nodes, n => {
13999                if (!isBookmarkNode$1(n) && !isBookmarkNode$1(n.parentNode)) {
14000                  splitToFormatRoot(n);
14001                }
14002              });
14003            });
14004            splitToFormatRoot(startContainer);
14005            splitToFormatRoot(endContainer);
14006            startContainer = unwrap(true);
14007            endContainer = unwrap();
14008          } else {
14009            startContainer = endContainer = splitToFormatRoot(startContainer);
14010          }
14011          expandedRng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
14012          expandedRng.startOffset = dom.nodeIndex(startContainer);
14013          expandedRng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
14014          expandedRng.endOffset = dom.nodeIndex(endContainer) + 1;
14015        }
14016        walk$3(dom, expandedRng, nodes => {
14017          each$e(nodes, process);
14018        });
14019      };
14020      if (node) {
14021        if (isNode(node)) {
14022          const rng = dom.createRng();
14023          rng.setStartBefore(node);
14024          rng.setEndAfter(node);
14025          removeRngStyle(rng);
14026        } else {
14027          removeRngStyle(node);
14028        }
14029        fireFormatRemove(ed, name, node, vars);
14030        return;
14031      }
14032      if (!selection.isCollapsed() || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
14033        preserveSelection(ed, () => runOnRanges(ed, removeRngStyle), startNode => isInlineFormat(format) && match$2(ed, name, vars, startNode));
14034        ed.nodeChanged();
14035      } else {
14036        removeCaretFormat(ed, name, vars, similar);
14037      }
14038      removeListStyleFormats(ed, name, vars);
14039      fireFormatRemove(ed, name, node, vars);
14040    };
14041    const removeFormat$1 = (ed, name, vars, node, similar) => {
14042      if (node || ed.selection.isEditable()) {
14043        removeFormatInternal(ed, name, vars, node, similar);
14044      }
14045    };
14046    const removeNodeFormat = (editor, format, vars, node, compareNode) => {
14047      return removeNodeFormatInternal(editor, format, vars, node, compareNode).fold(never, newName => {
14048        editor.dom.rename(node, newName);
14049        return true;
14050      }, always);
14051    };
14052
14053    const each$6 = Tools.each;
14054    const mergeTextDecorationsAndColor = (dom, format, vars, node) => {
14055      const processTextDecorationsAndColor = n => {
14056        if (isElement$6(n) && isElement$6(n.parentNode) && isEditable$2(n)) {
14057          const parentTextDecoration = getTextDecoration(dom, n.parentNode);
14058          if (dom.getStyle(n, 'color') && parentTextDecoration) {
14059            dom.setStyle(n, 'text-decoration', parentTextDecoration);
14060          } else if (dom.getStyle(n, 'text-decoration') === parentTextDecoration) {
14061            dom.setStyle(n, 'text-decoration', null);
14062          }
14063        }
14064      };
14065      if (format.styles && (format.styles.color || format.styles.textDecoration)) {
14066        Tools.walk(node, processTextDecorationsAndColor, 'childNodes');
14067        processTextDecorationsAndColor(node);
14068      }
14069    };
14070    const mergeBackgroundColorAndFontSize = (dom, format, vars, node) => {
14071      if (format.styles && format.styles.backgroundColor) {
14072        const hasFontSize = hasStyle(dom, 'fontSize');
14073        processChildElements(node, elm => hasFontSize(elm) && isEditable$2(elm), applyStyle(dom, 'backgroundColor', replaceVars(format.styles.backgroundColor, vars)));
14074      }
14075    };
14076    const mergeSubSup = (dom, format, vars, node) => {
14077      if (isInlineFormat(format) && (format.inline === 'sub' || format.inline === 'sup')) {
14078        const hasFontSize = hasStyle(dom, 'fontSize');
14079        processChildElements(node, elm => hasFontSize(elm) && isEditable$2(elm), applyStyle(dom, 'fontSize', ''));
14080        const inverseTagDescendants = filter$5(dom.select(format.inline === 'sup' ? 'sub' : 'sup', node), isEditable$2);
14081        dom.remove(inverseTagDescendants, true);
14082      }
14083    };
14084    const mergeWithChildren = (editor, formatList, vars, node) => {
14085      each$6(formatList, format => {
14086        if (isInlineFormat(format)) {
14087          each$6(editor.dom.select(format.inline, node), child => {
14088            if (isElementNode(child)) {
14089              removeNodeFormat(editor, format, vars, child, format.exact ? child : null);
14090            }
14091          });
14092        }
14093        clearChildStyles(editor.dom, format, node);
14094      });
14095    };
14096    const mergeWithParents = (editor, format, name, vars, node) => {
14097      const parentNode = node.parentNode;
14098      if (matchNode(editor, parentNode, name, vars)) {
14099        if (removeNodeFormat(editor, format, vars, node)) {
14100          return;
14101        }
14102      }
14103      if (format.merge_with_parents && parentNode) {
14104        editor.dom.getParent(parentNode, parent => {
14105          if (matchNode(editor, parent, name, vars)) {
14106            removeNodeFormat(editor, format, vars, node);
14107            return true;
14108          } else {
14109            return false;
14110          }
14111        });
14112      }
14113    };
14114
14115    const each$5 = Tools.each;
14116    const canFormatBR = (editor, format, node, parentName) => {
14117      if (canFormatEmptyLines(editor) && isInlineFormat(format) && node.parentNode) {
14118        const validBRParentElements = getTextRootBlockElements(editor.schema);
14119        const hasCaretNodeSibling = sibling(SugarElement.fromDom(node), sibling => isCaretNode(sibling.dom));
14120        return hasNonNullableKey(validBRParentElements, parentName) && isEmpty$2(SugarElement.fromDom(node.parentNode), false) && !hasCaretNodeSibling;
14121      } else {
14122        return false;
14123      }
14124    };
14125    const applyStyles = (dom, elm, format, vars) => {
14126      each$5(format.styles, (value, name) => {
14127        dom.setStyle(elm, name, replaceVars(value, vars));
14128      });
14129      if (format.styles) {
14130        const styleVal = dom.getAttrib(elm, 'style');
14131        if (styleVal) {
14132          dom.setAttrib(elm, 'data-mce-style', styleVal);
14133        }
14134      }
14135    };
14136    const applyFormatAction = (ed, name, vars, node) => {
14137      const formatList = ed.formatter.get(name);
14138      const format = formatList[0];
14139      const isCollapsed = !node && ed.selection.isCollapsed();
14140      const dom = ed.dom;
14141      const selection = ed.selection;
14142      const setElementFormat = (elm, fmt = format) => {
14143        if (isFunction(fmt.onformat)) {
14144          fmt.onformat(elm, fmt, vars, node);
14145        }
14146        applyStyles(dom, elm, fmt, vars);
14147        each$5(fmt.attributes, (value, name) => {
14148          dom.setAttrib(elm, name, replaceVars(value, vars));
14149        });
14150        each$5(fmt.classes, value => {
14151          const newValue = replaceVars(value, vars);
14152          if (!dom.hasClass(elm, newValue)) {
14153            dom.addClass(elm, newValue);
14154          }
14155        });
14156      };
14157      const applyNodeStyle = (formatList, node) => {
14158        let found = false;
14159        each$5(formatList, format => {
14160          if (!isSelectorFormat(format)) {
14161            return false;
14162          }
14163          if (dom.getContentEditable(node) === 'false' && !format.ceFalseOverride) {
14164            return true;
14165          }
14166          if (isNonNullable(format.collapsed) && format.collapsed !== isCollapsed) {
14167            return true;
14168          }
14169          if (dom.is(node, format.selector) && !isCaretNode(node)) {
14170            setElementFormat(node, format);
14171            found = true;
14172            return false;
14173          }
14174          return true;
14175        });
14176        return found;
14177      };
14178      const createWrapElement = wrapName => {
14179        if (isString(wrapName)) {
14180          const wrapElm = dom.create(wrapName);
14181          setElementFormat(wrapElm);
14182          return wrapElm;
14183        } else {
14184          return null;
14185        }
14186      };
14187      const applyRngStyle = (dom, rng, nodeSpecific) => {
14188        const newWrappers = [];
14189        let contentEditable = true;
14190        const wrapName = format.inline || format.block;
14191        const wrapElm = createWrapElement(wrapName);
14192        const isMatchingWrappingBlock = node => isWrappingBlockFormat(format) && matchNode(ed, node, name, vars);
14193        const canRenameBlock = (node, parentName, isEditableDescendant) => {
14194          const isValidBlockFormatForNode = isNonWrappingBlockFormat(format) && isTextBlock$1(ed.schema, node) && isValid(ed, parentName, wrapName);
14195          return isEditableDescendant && isValidBlockFormatForNode;
14196        };
14197        const canWrapNode = (node, parentName, isEditableDescendant, isWrappableNoneditableElm) => {
14198          const nodeName = node.nodeName.toLowerCase();
14199          const isValidWrapNode = isValid(ed, wrapName, nodeName) && isValid(ed, parentName, wrapName);
14200          const isZwsp = !nodeSpecific && isText$a(node) && isZwsp$1(node.data);
14201          const isCaret = isCaretNode(node);
14202          const isCorrectFormatForNode = !isInlineFormat(format) || !dom.isBlock(node);
14203          return (isEditableDescendant || isWrappableNoneditableElm) && isValidWrapNode && !isZwsp && !isCaret && isCorrectFormatForNode;
14204        };
14205        walk$3(dom, rng, nodes => {
14206          let currentWrapElm;
14207          const process = node => {
14208            let hasContentEditableState = false;
14209            let lastContentEditable = contentEditable;
14210            let isWrappableNoneditableElm = false;
14211            const parentNode = node.parentNode;
14212            const parentName = parentNode.nodeName.toLowerCase();
14213            const contentEditableValue = dom.getContentEditable(node);
14214            if (isNonNullable(contentEditableValue)) {
14215              lastContentEditable = contentEditable;
14216              contentEditable = contentEditableValue === 'true';
14217              hasContentEditableState = true;
14218              isWrappableNoneditableElm = isWrappableNoneditable(ed, node);
14219            }
14220            const isEditableDescendant = contentEditable && !hasContentEditableState;
14221            if (isBr$6(node) && !canFormatBR(ed, format, node, parentName)) {
14222              currentWrapElm = null;
14223              if (isBlockFormat(format)) {
14224                dom.remove(node);
14225              }
14226              return;
14227            }
14228            if (isMatchingWrappingBlock(node)) {
14229              currentWrapElm = null;
14230              return;
14231            }
14232            if (canRenameBlock(node, parentName, isEditableDescendant)) {
14233              const elm = dom.rename(node, wrapName);
14234              setElementFormat(elm);
14235              newWrappers.push(elm);
14236              currentWrapElm = null;
14237              return;
14238            }
14239            if (isSelectorFormat(format)) {
14240              let found = applyNodeStyle(formatList, node);
14241              if (!found && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
14242                found = applyNodeStyle(formatList, parentNode);
14243              }
14244              if (!isInlineFormat(format) || found) {
14245                currentWrapElm = null;
14246                return;
14247              }
14248            }
14249            if (isNonNullable(wrapElm) && canWrapNode(node, parentName, isEditableDescendant, isWrappableNoneditableElm)) {
14250              if (!currentWrapElm) {
14251                currentWrapElm = dom.clone(wrapElm, false);
14252                parentNode.insertBefore(currentWrapElm, node);
14253                newWrappers.push(currentWrapElm);
14254              }
14255              if (isWrappableNoneditableElm && hasContentEditableState) {
14256                contentEditable = lastContentEditable;
14257              }
14258              currentWrapElm.appendChild(node);
14259            } else {
14260              currentWrapElm = null;
14261              each$e(from(node.childNodes), process);
14262              if (hasContentEditableState) {
14263                contentEditable = lastContentEditable;
14264              }
14265              currentWrapElm = null;
14266            }
14267          };
14268          each$e(nodes, process);
14269        });
14270        if (format.links === true) {
14271          each$e(newWrappers, node => {
14272            const process = node => {
14273              if (node.nodeName === 'A') {
14274                setElementFormat(node, format);
14275              }
14276              each$e(from(node.childNodes), process);
14277            };
14278            process(node);
14279          });
14280        }
14281        each$e(newWrappers, node => {
14282          const getChildCount = node => {
14283            let count = 0;
14284            each$e(node.childNodes, node => {
14285              if (!isEmptyTextNode$1(node) && !isBookmarkNode$1(node)) {
14286                count++;
14287              }
14288            });
14289            return count;
14290          };
14291          const mergeStyles = node => {
14292            const childElement = find$2(node.childNodes, isElementNode$1).filter(child => dom.getContentEditable(child) !== 'false' && matchName(dom, child, format));
14293            return childElement.map(child => {
14294              const clone = dom.clone(child, false);
14295              setElementFormat(clone);
14296              dom.replace(clone, node, true);
14297              dom.remove(child, true);
14298              return clone;
14299            }).getOr(node);
14300          };
14301          const childCount = getChildCount(node);
14302          if ((newWrappers.length > 1 || !dom.isBlock(node)) && childCount === 0) {
14303            dom.remove(node, true);
14304            return;
14305          }
14306          if (isInlineFormat(format) || isBlockFormat(format) && format.wrapper) {
14307            if (!format.exact && childCount === 1) {
14308              node = mergeStyles(node);
14309            }
14310            mergeWithChildren(ed, formatList, vars, node);
14311            mergeWithParents(ed, format, name, vars, node);
14312            mergeBackgroundColorAndFontSize(dom, format, vars, node);
14313            mergeTextDecorationsAndColor(dom, format, vars, node);
14314            mergeSubSup(dom, format, vars, node);
14315            mergeSiblings(ed, format, vars, node);
14316          }
14317        });
14318      };
14319      const targetNode = isNode(node) ? node : selection.getNode();
14320      if (dom.getContentEditable(targetNode) === 'false' && !isWrappableNoneditable(ed, targetNode)) {
14321        node = targetNode;
14322        applyNodeStyle(formatList, node);
14323        fireFormatApply(ed, name, node, vars);
14324        return;
14325      }
14326      if (format) {
14327        if (node) {
14328          if (isNode(node)) {
14329            if (!applyNodeStyle(formatList, node)) {
14330              const rng = dom.createRng();
14331              rng.setStartBefore(node);
14332              rng.setEndAfter(node);
14333              applyRngStyle(dom, expandRng(dom, rng, formatList), true);
14334            }
14335          } else {
14336            applyRngStyle(dom, node, true);
14337          }
14338        } else {
14339          if (!isCollapsed || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
14340            selection.setRng(normalize(selection.getRng()));
14341            preserveSelection(ed, () => {
14342              runOnRanges(ed, (selectionRng, fake) => {
14343                const expandedRng = fake ? selectionRng : expandRng(dom, selectionRng, formatList);
14344                applyRngStyle(dom, expandedRng, false);
14345              });
14346            }, always);
14347            ed.nodeChanged();
14348          } else {
14349            applyCaretFormat(ed, name, vars);
14350          }
14351          getExpandedListItemFormat(ed.formatter, name).each(liFmt => {
14352            each$e(getFullySelectedListItems(ed.selection), li => applyStyles(dom, li, liFmt, vars));
14353          });
14354        }
14355        postProcess$1(name, ed);
14356      }
14357      fireFormatApply(ed, name, node, vars);
14358    };
14359    const applyFormat$1 = (editor, name, vars, node) => {
14360      if (node || editor.selection.isEditable()) {
14361        applyFormatAction(editor, name, vars, node);
14362      }
14363    };
14364
14365    const hasVars = value => has$2(value, 'vars');
14366    const setup$t = (registeredFormatListeners, editor) => {
14367      registeredFormatListeners.set({});
14368      editor.on('NodeChange', e => {
14369        updateAndFireChangeCallbacks(editor, e.element, registeredFormatListeners.get());
14370      });
14371      editor.on('FormatApply FormatRemove', e => {
14372        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));
14373        updateAndFireChangeCallbacks(editor, element, registeredFormatListeners.get());
14374      });
14375    };
14376    const fallbackElement = editor => editor.selection.getStart();
14377    const matchingNode = (editor, parents, format, similar, vars) => {
14378      const isMatchingNode = node => {
14379        const matchingFormat = editor.formatter.matchNode(node, format, vars !== null && vars !== void 0 ? vars : {}, similar);
14380        return !isUndefined(matchingFormat);
14381      };
14382      const isUnableToMatch = node => {
14383        if (matchesUnInheritedFormatSelector(editor, node, format)) {
14384          return true;
14385        } else {
14386          if (!similar) {
14387            return isNonNullable(editor.formatter.matchNode(node, format, vars, true));
14388          } else {
14389            return false;
14390          }
14391        }
14392      };
14393      return findUntil$1(parents, isMatchingNode, isUnableToMatch);
14394    };
14395    const getParents = (editor, elm) => {
14396      const element = elm !== null && elm !== void 0 ? elm : fallbackElement(editor);
14397      return filter$5(getParents$2(editor.dom, element), node => isElement$6(node) && !isBogus$2(node));
14398    };
14399    const updateAndFireChangeCallbacks = (editor, elm, registeredCallbacks) => {
14400      const parents = getParents(editor, elm);
14401      each$d(registeredCallbacks, (data, format) => {
14402        const runIfChanged = spec => {
14403          const match = matchingNode(editor, parents, format, spec.similar, hasVars(spec) ? spec.vars : undefined);
14404          const isSet = match.isSome();
14405          if (spec.state.get() !== isSet) {
14406            spec.state.set(isSet);
14407            const node = match.getOr(elm);
14408            if (hasVars(spec)) {
14409              spec.callback(isSet, {
14410                node,
14411                format,
14412                parents
14413              });
14414            } else {
14415              each$e(spec.callbacks, callback => callback(isSet, {
14416                node,
14417                format,
14418                parents
14419              }));
14420            }
14421          }
14422        };
14423        each$e([
14424          data.withSimilar,
14425          data.withoutSimilar
14426        ], runIfChanged);
14427        each$e(data.withVars, runIfChanged);
14428      });
14429    };
14430    const addListeners = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
14431      const formatChangeItems = registeredFormatListeners.get();
14432      each$e(formats.split(','), format => {
14433        const group = get$a(formatChangeItems, format).getOrThunk(() => {
14434          const base = {
14435            withSimilar: {
14436              state: Cell(false),
14437              similar: true,
14438              callbacks: []
14439            },
14440            withoutSimilar: {
14441              state: Cell(false),
14442              similar: false,
14443              callbacks: []
14444            },
14445            withVars: []
14446          };
14447          formatChangeItems[format] = base;
14448          return base;
14449        });
14450        const getCurrent = () => {
14451          const parents = getParents(editor);
14452          return matchingNode(editor, parents, format, similar, vars).isSome();
14453        };
14454        if (isUndefined(vars)) {
14455          const toAppendTo = similar ? group.withSimilar : group.withoutSimilar;
14456          toAppendTo.callbacks.push(callback);
14457          if (toAppendTo.callbacks.length === 1) {
14458            toAppendTo.state.set(getCurrent());
14459          }
14460        } else {
14461          group.withVars.push({
14462            state: Cell(getCurrent()),
14463            similar,
14464            vars,
14465            callback
14466          });
14467        }
14468      });
14469      registeredFormatListeners.set(formatChangeItems);
14470    };
14471    const removeListeners = (registeredFormatListeners, formats, callback) => {
14472      const formatChangeItems = registeredFormatListeners.get();
14473      each$e(formats.split(','), format => get$a(formatChangeItems, format).each(group => {
14474        formatChangeItems[format] = {
14475          withSimilar: {
14476            ...group.withSimilar,
14477            callbacks: filter$5(group.withSimilar.callbacks, cb => cb !== callback)
14478          },
14479          withoutSimilar: {
14480            ...group.withoutSimilar,
14481            callbacks: filter$5(group.withoutSimilar.callbacks, cb => cb !== callback)
14482          },
14483          withVars: filter$5(group.withVars, item => item.callback !== callback)
14484        };
14485      }));
14486      registeredFormatListeners.set(formatChangeItems);
14487    };
14488    const formatChangedInternal = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
14489      addListeners(editor, registeredFormatListeners, formats, callback, similar, vars);
14490      return { unbind: () => removeListeners(registeredFormatListeners, formats, callback) };
14491    };
14492
14493    const toggle = (editor, name, vars, node) => {
14494      const fmt = editor.formatter.get(name);
14495      if (fmt) {
14496        if (match$2(editor, name, vars, node) && (!('toggle' in fmt[0]) || fmt[0].toggle)) {
14497          removeFormat$1(editor, name, vars, node);
14498        } else {
14499          applyFormat$1(editor, name, vars, node);
14500        }
14501      }
14502    };
14503
14504    const explode$1 = Tools.explode;
14505    const create$8 = () => {
14506      const filters = {};
14507      const addFilter = (name, callback) => {
14508        each$e(explode$1(name), name => {
14509          if (!has$2(filters, name)) {
14510            filters[name] = {
14511              name,
14512              callbacks: []
14513            };
14514          }
14515          filters[name].callbacks.push(callback);
14516        });
14517      };
14518      const getFilters = () => values(filters);
14519      const removeFilter = (name, callback) => {
14520        each$e(explode$1(name), name => {
14521          if (has$2(filters, name)) {
14522            if (isNonNullable(callback)) {
14523              const filter = filters[name];
14524              const newCallbacks = filter$5(filter.callbacks, c => c !== callback);
14525              if (newCallbacks.length > 0) {
14526                filter.callbacks = newCallbacks;
14527              } else {
14528                delete filters[name];
14529              }
14530            } else {
14531              delete filters[name];
14532            }
14533          }
14534        });
14535      };
14536      return {
14537        addFilter,
14538        getFilters,
14539        removeFilter
14540      };
14541    };
14542
14543    const removeAttrs = (node, names) => {
14544      each$e(names, name => {
14545        node.attr(name, null);
14546      });
14547    };
14548    const addFontToSpansFilter = (domParser, styles, fontSizes) => {
14549      domParser.addNodeFilter('font', nodes => {
14550        each$e(nodes, node => {
14551          const props = styles.parse(node.attr('style'));
14552          const color = node.attr('color');
14553          const face = node.attr('face');
14554          const size = node.attr('size');
14555          if (color) {
14556            props.color = color;
14557          }
14558          if (face) {
14559            props['font-family'] = face;
14560          }
14561          if (size) {
14562            toInt(size).each(num => {
14563              props['font-size'] = fontSizes[num - 1];
14564            });
14565          }
14566          node.name = 'span';
14567          node.attr('style', styles.serialize(props));
14568          removeAttrs(node, [
14569            'color',
14570            'face',
14571            'size'
14572          ]);
14573        });
14574      });
14575    };
14576    const addStrikeFilter = (domParser, schema, styles) => {
14577      domParser.addNodeFilter('strike', nodes => {
14578        const convertToSTag = schema.type !== 'html4';
14579        each$e(nodes, node => {
14580          if (convertToSTag) {
14581            node.name = 's';
14582          } else {
14583            const props = styles.parse(node.attr('style'));
14584            props['text-decoration'] = 'line-through';
14585            node.name = 'span';
14586            node.attr('style', styles.serialize(props));
14587          }
14588        });
14589      });
14590    };
14591    const addFilters = (domParser, settings, schema) => {
14592      var _a;
14593      const styles = Styles();
14594      if (settings.convert_fonts_to_spans) {
14595        addFontToSpansFilter(domParser, styles, Tools.explode((_a = settings.font_size_legacy_values) !== null && _a !== void 0 ? _a : ''));
14596      }
14597      addStrikeFilter(domParser, schema, styles);
14598    };
14599    const register$5 = (domParser, settings, schema) => {
14600      if (settings.inline_styles) {
14601        addFilters(domParser, settings, schema);
14602      }
14603    };
14604
14605    const addNodeFilter = (
vendor: 1,416 bytes, lines 14605-14635
14605settings, htmlParser, schema) => {
14606      htmlParser.addNodeFilter('br', (nodes, _, args) => {
14607        const blockElements = Tools.extend({}, schema.getBlockElements());
14608        const nonEmptyElements = schema.getNonEmptyElements();
14609        const whitespaceElements = schema.getWhitespaceElements();
14610        blockElements.body = 1;
14611        const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node);
14612        for (let i = 0, l = nodes.length; i < l; i++) {
14613          let node = nodes[i];
14614          let parent = node.parent;
14615          if (parent && isBlock(parent) && node === parent.lastChild) {
14616            let prev = node.prev;
14617            while (prev) {
14618              const prevName = prev.name;
14619              if (prevName !== 'span' || prev.attr('data-mce-type') !== 'bookmark') {
14620                if (prevName === 'br') {
14621                  node = null;
14622                }
14623                break;
14624              }
14625              prev = prev.prev;
14626            }
14627            if (node) {
14628              node.remove();
14629              if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent)) {
14630                const elementRule = schema.getElementRule(parent.name);
14631                if (elementRule) {
14632                  if (elementRule.removeEmpty) {
14633                    parent.remove();
14634                  } else if (elementRule.paddEmpty) {
14635                    paddEmptyNode(settings, 
vendor: 5,755 bytes, lines 14635-14790
14635args, isBlock, parent);
14636                  }
14637                }
14638              }
14639            }
14640          } else {
14641            let lastParent = node;
14642            while (parent && parent.firstChild === lastParent && parent.lastChild === lastParent) {
14643              lastParent = parent;
14644              if (blockElements[parent.name]) {
14645                break;
14646              }
14647              parent = parent.parent;
14648            }
14649            if (lastParent === parent) {
14650              const textNode = new AstNode('#text', 3);
14651              textNode.value = nbsp;
14652              node.replace(textNode);
14653            }
14654          }
14655        }
14656      });
14657    };
14658
14659    const blobUriToBlob = url => fetch(url).then(res => res.ok ? res.blob() : Promise.reject()).catch(() => Promise.reject({
14660      message: `Cannot convert ${ url } to Blob. Resource might not exist or is inaccessible.`,
14661      uriType: 'blob'
14662    }));
14663    const extractBase64Data = data => {
14664      const matches = /([a-z0-9+\/=\s]+)/i.exec(data);
14665      return matches ? matches[1] : '';
14666    };
14667    const parseDataUri = uri => {
14668      const [type, ...rest] = uri.split(',');
14669      const data = rest.join(',');
14670      const matches = /data:([^/]+\/[^;]+)(;.+)?/.exec(type);
14671      if (matches) {
14672        const base64Encoded = matches[2] === ';base64';
14673        const extractedData = base64Encoded ? extractBase64Data(data) : decodeURIComponent(data);
14674        return Optional.some({
14675          type: matches[1],
14676          data: extractedData,
14677          base64Encoded
14678        });
14679      } else {
14680        return Optional.none();
14681      }
14682    };
14683    const buildBlob = (type, data, base64Encoded = true) => {
14684      let str = data;
14685      if (base64Encoded) {
14686        try {
14687          str = atob(data);
14688        } catch (e) {
14689          return Optional.none();
14690        }
14691      }
14692      const arr = new Uint8Array(str.length);
14693      for (let i = 0; i < arr.length; i++) {
14694        arr[i] = str.charCodeAt(i);
14695      }
14696      return Optional.some(new Blob([arr], { type }));
14697    };
14698    const dataUriToBlob = uri => {
14699      return new Promise((resolve, reject) => {
14700        parseDataUri(uri).bind(({type, data, base64Encoded}) => buildBlob(type, data, base64Encoded)).fold(() => reject('Invalid data URI'), resolve);
14701      });
14702    };
14703    const uriToBlob = url => {
14704      if (startsWith(url, 'blob:')) {
14705        return blobUriToBlob(url);
14706      } else if (startsWith(url, 'data:')) {
14707        return dataUriToBlob(url);
14708      } else {
14709        return Promise.reject('Unknown URI format');
14710      }
14711    };
14712    const blobToDataUri = blob => {
14713      return new Promise((resolve, reject) => {
14714        const reader = new FileReader();
14715        reader.onloadend = () => {
14716          resolve(reader.result);
14717        };
14718        reader.onerror = () => {
14719          var _a;
14720          reject((_a = reader.error) === null || _a === void 0 ? void 0 : _a.message);
14721        };
14722        reader.readAsDataURL(blob);
14723      });
14724    };
14725
14726    let count$1 = 0;
14727    const uniqueId$1 = prefix => {
14728      return (prefix || 'blobid') + count$1++;
14729    };
14730    const processDataUri = (dataUri, base64Only, generateBlobInfo) => {
14731      return parseDataUri(dataUri).bind(({data, type, base64Encoded}) => {
14732        if (base64Only && !base64Encoded) {
14733          return Optional.none();
14734        } else {
14735          const base64 = base64Encoded ? data : btoa(data);
14736          return generateBlobInfo(base64, type);
14737        }
14738      });
14739    };
14740    const createBlobInfo$1 = (blobCache, blob, base64) => {
14741      const blobInfo = blobCache.create(uniqueId$1(), blob, base64);
14742      blobCache.add(blobInfo);
14743      return blobInfo;
14744    };
14745    const dataUriToBlobInfo = (blobCache, dataUri, base64Only = false) => {
14746      return processDataUri(dataUri, base64Only, (base64, type) => Optional.from(blobCache.getByData(base64, type)).orThunk(() => buildBlob(type, base64).map(blob => createBlobInfo$1(blobCache, blob, base64))));
14747    };
14748    const imageToBlobInfo = (blobCache, imageSrc) => {
14749      const invalidDataUri = () => Promise.reject('Invalid data URI');
14750      if (startsWith(imageSrc, 'blob:')) {
14751        const blobInfo = blobCache.getByUri(imageSrc);
14752        if (isNonNullable(blobInfo)) {
14753          return Promise.resolve(blobInfo);
14754        } else {
14755          return uriToBlob(imageSrc).then(blob => {
14756            return blobToDataUri(blob).then(dataUri => {
14757              return processDataUri(dataUri, false, base64 => {
14758                return Optional.some(createBlobInfo$1(blobCache, blob, base64));
14759              }).getOrThunk(invalidDataUri);
14760            });
14761          });
14762        }
14763      } else if (startsWith(imageSrc, 'data:')) {
14764        return dataUriToBlobInfo(blobCache, imageSrc).fold(invalidDataUri, blobInfo => Promise.resolve(blobInfo));
14765      } else {
14766        return Promise.reject('Unknown image data format');
14767      }
14768    };
14769
14770    const isBogusImage = img => isNonNullable(img.attr('data-mce-bogus'));
14771    const isInternalImageSource = img => img.attr('src') === Env.transparentSrc || isNonNullable(img.attr('data-mce-placeholder'));
14772    const registerBase64ImageFilter = (parser, settings) => {
14773      const {blob_cache: blobCache} = settings;
14774      if (blobCache) {
14775        const processImage = img => {
14776          const inputSrc = img.attr('src');
14777          if (isInternalImageSource(img) || isBogusImage(img) || isNullable(inputSrc)) {
14778            return;
14779          }
14780          dataUriToBlobInfo(blobCache, inputSrc, true).each(blobInfo => {
14781            img.attr('src', blobInfo.blobUri());
14782          });
14783        };
14784        parser.addAttributeFilter('src', nodes => each$e(nodes, processImage));
14785      }
14786    };
14787    const register$4 = (parser, settings) => {
14788      const schema = parser.schema;
14789      if (settings.remove_trailing_brs) {
14790        addNodeFilter(
14790settings, 
vendor: 14,444 bytes, lines 14790-15353
14790parser, schema);
14791      }
14792      parser.addAttributeFilter('href', nodes => {
14793        let i = nodes.length;
14794        const appendRel = rel => {
14795          const parts = rel.split(' ').filter(p => p.length > 0);
14796          return parts.concat(['noopener']).sort().join(' ');
14797        };
14798        const addNoOpener = rel => {
14799          const newRel = rel ? Tools.trim(rel) : '';
14800          if (!/\b(noopener)\b/g.test(newRel)) {
14801            return appendRel(newRel);
14802          } else {
14803            return newRel;
14804          }
14805        };
14806        if (!settings.allow_unsafe_link_target) {
14807          while (i--) {
14808            const node = nodes[i];
14809            if (node.name === 'a' && node.attr('target') === '_blank') {
14810              node.attr('rel', addNoOpener(node.attr('rel')));
14811            }
14812          }
14813        }
14814      });
14815      if (!settings.allow_html_in_named_anchor) {
14816        parser.addAttributeFilter('id,name', nodes => {
14817          let i = nodes.length, sibling, prevSibling, parent, node;
14818          while (i--) {
14819            node = nodes[i];
14820            if (node.name === 'a' && node.firstChild && !node.attr('href')) {
14821              parent = node.parent;
14822              sibling = node.lastChild;
14823              while (sibling && parent) {
14824                prevSibling = sibling.prev;
14825                parent.insert(sibling, node);
14826                sibling = prevSibling;
14827              }
14828            }
14829          }
14830        });
14831      }
14832      if (settings.fix_list_elements) {
14833        parser.addNodeFilter('ul,ol', nodes => {
14834          let i = nodes.length, node, parentNode;
14835          while (i--) {
14836            node = nodes[i];
14837            parentNode = node.parent;
14838            if (parentNode && (parentNode.name === 'ul' || parentNode.name === 'ol')) {
14839              if (node.prev && node.prev.name === 'li') {
14840                node.prev.append(node);
14841              } else {
14842                const li = new AstNode('li', 1);
14843                li.attr('style', 'list-style-type: none');
14844                node.wrap(li);
14845              }
14846            }
14847          }
14848        });
14849      }
14850      const validClasses = schema.getValidClasses();
14851      if (settings.validate && validClasses) {
14852        parser.addAttributeFilter('class', nodes => {
14853          var _a;
14854          let i = nodes.length;
14855          while (i--) {
14856            const node = nodes[i];
14857            const clazz = (_a = node.attr('class')) !== null && _a !== void 0 ? _a : '';
14858            const classList = Tools.explode(clazz, ' ');
14859            let classValue = '';
14860            for (let ci = 0; ci < classList.length; ci++) {
14861              const className = classList[ci];
14862              let valid = false;
14863              let validClassesMap = validClasses['*'];
14864              if (validClassesMap && validClassesMap[className]) {
14865                valid = true;
14866              }
14867              validClassesMap = validClasses[node.name];
14868              if (!valid && validClassesMap && validClassesMap[className]) {
14869                valid = true;
14870              }
14871              if (valid) {
14872                if (classValue) {
14873                  classValue += ' ';
14874                }
14875                classValue += className;
14876              }
14877            }
14878            if (!classValue.length) {
14879              classValue = null;
14880            }
14881            node.attr('class', classValue);
14882          }
14883        });
14884      }
14885      registerBase64ImageFilter(parser, settings);
14886    };
14887
14888    function _typeof(obj) {
14889      '@babel/helpers - typeof';
14890      return _typeof = 'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator ? function (obj) {
14891        return typeof obj;
14892      } : function (obj) {
14893        return obj && 'function' == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? 'symbol' : typeof obj;
14894      }, _typeof(obj);
14895    }
14896    function _setPrototypeOf(o, p) {
14897      _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
14898        o.__proto__ = p;
14899        return o;
14900      };
14901      return _setPrototypeOf(o, p);
14902    }
14903    function _isNativeReflectConstruct() {
14904      if (typeof Reflect === 'undefined' || !Reflect.construct)
14905        return false;
14906      if (Reflect.construct.sham)
14907        return false;
14908      if (typeof Proxy === 'function')
14909        return true;
14910      try {
14911        Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {
14912        }));
14913        return true;
14914      } catch (e) {
14915        return false;
14916      }
14917    }
14918    function _construct(Parent, args, Class) {
14919      if (_isNativeReflectConstruct()) {
14920        _construct = Reflect.construct;
14921      } else {
14922        _construct = function _construct(Parent, args, Class) {
14923          var a = [null];
14924          a.push.apply(a, args);
14925          var Constructor = Function.bind.apply(Parent, a);
14926          var instance = new Constructor();
14927          if (Class)
14928            _setPrototypeOf(instance, Class.prototype);
14929          return instance;
14930        };
14931      }
14932      return _construct.apply(null, arguments);
14933    }
14934    function _toConsumableArray(arr) {
14935      return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
14936    }
14937    function _arrayWithoutHoles(arr) {
14938      if (Array.isArray(arr))
14939        return _arrayLikeToArray(arr);
14940    }
14941    function _iterableToArray(iter) {
14942      if (typeof Symbol !== 'undefined' && iter[Symbol.iterator] != null || iter['@@iterator'] != null)
14943        return Array.from(iter);
14944    }
14945    function _unsupportedIterableToArray(o, minLen) {
14946      if (!o)
14947        return;
14948      if (typeof o === 'string')
14949        return _arrayLikeToArray(o, minLen);
14950      var n = Object.prototype.toString.call(o).slice(8, -1);
14951      if (n === 'Object' && o.constructor)
14952        n = o.constructor.name;
14953      if (n === 'Map' || n === 'Set')
14954        return Array.from(o);
14955      if (n === 'Arguments' || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
14956        return _arrayLikeToArray(o, minLen);
14957    }
14958    function _arrayLikeToArray(arr, len) {
14959      if (len == null || len > arr.length)
14960        len = arr.length;
14961      for (var i = 0, arr2 = new Array(len); i < len; i++)
14962        arr2[i] = arr[i];
14963      return arr2;
14964    }
14965    function _nonIterableSpread() {
14966      throw new TypeError('Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.');
14967    }
14968    var hasOwnProperty = Object.hasOwnProperty, setPrototypeOf = Object.setPrototypeOf, isFrozen = Object.isFrozen, getPrototypeOf = Object.getPrototypeOf, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
14969    var freeze = Object.freeze, seal = Object.seal, create$7 = Object.create;
14970    var _ref = typeof Reflect !== 'undefined' && Reflect, apply = _ref.apply, construct = _ref.construct;
14971    if (!apply) {
14972      apply = function apply(fun, thisValue, args) {
14973        return fun.apply(thisValue, args);
14974      };
14975    }
14976    if (!freeze) {
14977      freeze = function freeze(x) {
14978        return x;
14979      };
14980    }
14981    if (!seal) {
14982      seal = function seal(x) {
14983        return x;
14984      };
14985    }
14986    if (!construct) {
14987      construct = function construct(Func, args) {
14988        return _construct(Func, _toConsumableArray(args));
14989      };
14990    }
14991    var arrayForEach = unapply(Array.prototype.forEach);
14992    var arrayPop = unapply(Array.prototype.pop);
14993    var arrayPush = unapply(Array.prototype.push);
14994    var stringToLowerCase = unapply(String.prototype.toLowerCase);
14995    var stringMatch = unapply(String.prototype.match);
14996    var stringReplace = unapply(String.prototype.replace);
14997    var stringIndexOf = unapply(String.prototype.indexOf);
14998    var stringTrim = unapply(String.prototype.trim);
14999    var regExpTest = unapply(RegExp.prototype.test);
15000    var typeErrorCreate = unconstruct(TypeError);
15001    function unapply(func) {
15002      return function (thisArg) {
15003        for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
15004          args[_key - 1] = arguments[_key];
15005        }
15006        return apply(func, thisArg, args);
15007      };
15008    }
15009    function unconstruct(func) {
15010      return function () {
15011        for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
15012          args[_key2] = arguments[_key2];
15013        }
15014        return construct(func, args);
15015      };
15016    }
15017    function addToSet(set, array) {
15018      if (setPrototypeOf) {
15019        setPrototypeOf(set, null);
15020      }
15021      var l = array.length;
15022      while (l--) {
15023        var element = array[l];
15024        if (typeof element === 'string') {
15025          var lcElement = stringToLowerCase(element);
15026          if (lcElement !== element) {
15027            if (!isFrozen(array)) {
15028              array[l] = lcElement;
15029            }
15030            element = lcElement;
15031          }
15032        }
15033        set[element] = true;
15034      }
15035      return set;
15036    }
15037    function clone(object) {
15038      var newObject = create$7(null);
15039      var property;
15040      for (property in object) {
15041        if (apply(hasOwnProperty, object, [property])) {
15042          newObject[property] = object[property];
15043        }
15044      }
15045      return newObject;
15046    }
15047    function lookupGetter(object, prop) {
15048      while (object !== null) {
15049        var desc = getOwnPropertyDescriptor(object, prop);
15050        if (desc) {
15051          if (desc.get) {
15052            return unapply(desc.get);
15053          }
15054          if (typeof desc.value === 'function') {
15055            return unapply(desc.value);
15056          }
15057        }
15058        object = getPrototypeOf(object);
15059      }
15060      function fallbackValue(element) {
15061        console.warn('fallback value for', element);
15062        return null;
15063      }
15064      return fallbackValue;
15065    }
15066    var html$1 = freeze([
15067      'a',
15068      'abbr',
15069      'acronym',
15070      'address',
15071      'area',
15072      'article',
15073      'aside',
15074      'audio',
15075      'b',
15076      'bdi',
15077      'bdo',
15078      'big',
15079      'blink',
15080      'blockquote',
15081      'body',
15082      'br',
15083      'button',
15084      'canvas',
15085      'caption',
15086      'center',
15087      'cite',
15088      'code',
15089      'col',
15090      'colgroup',
15091      'content',
15092      'data',
15093      'datalist',
15094      'dd',
15095      'decorator',
15096      'del',
15097      'details',
15098      'dfn',
15099      'dialog',
15100      'dir',
15101      'div',
15102      'dl',
15103      'dt',
15104      'element',
15105      'em',
15106      'fieldset',
15107      'figcaption',
15108      'figure',
15109      'font',
15110      'footer',
15111      'form',
15112      'h1',
15113      'h2',
15114      'h3',
15115      'h4',
15116      'h5',
15117      'h6',
15118      'head',
15119      'header',
15120      'hgroup',
15121      'hr',
15122      'html',
15123      'i',
15124      'img',
15125      'input',
15126      'ins',
15127      'kbd',
15128      'label',
15129      'legend',
15130      'li',
15131      'main',
15132      'map',
15133      'mark',
15134      'marquee',
15135      'menu',
15136      'menuitem',
15137      'meter',
15138      'nav',
15139      'nobr',
15140      'ol',
15141      'optgroup',
15142      'option',
15143      'output',
15144      'p',
15145      'picture',
15146      'pre',
15147      'progress',
15148      'q',
15149      'rp',
15150      'rt',
15151      'ruby',
15152      's',
15153      'samp',
15154      'section',
15155      'select',
15156      'shadow',
15157      'small',
15158      'source',
15159      'spacer',
15160      'span',
15161      'strike',
15162      'strong',
15163      'style',
15164      'sub',
15165      'summary',
15166      'sup',
15167      'table',
15168      'tbody',
15169      'td',
15170      'template',
15171      'textarea',
15172      'tfoot',
15173      'th',
15174      'thead',
15175      'time',
15176      'tr',
15177      'track',
15178      'tt',
15179      'u',
15180      'ul',
15181      'var',
15182      'video',
15183      'wbr'
15184    ]);
15185    var svg$1 = freeze([
15186      'svg',
15187      'a',
15188      'altglyph',
15189      'altglyphdef',
15190      'altglyphitem',
15191      'animatecolor',
15192      'animatemotion',
15193      'animatetransform',
15194      'circle',
15195      'clippath',
15196      'defs',
15197      'desc',
15198      'ellipse',
15199      'filter',
15200      'font',
15201      'g',
15202      'glyph',
15203      'glyphref',
15204      'hkern',
15205      'image',
15206      'line',
15207      'lineargradient',
15208      'marker',
15209      'mask',
15210      'metadata',
15211      'mpath',
15212      'path',
15213      'pattern',
15214      'polygon',
15215      'polyline',
15216      'radialgradient',
15217      'rect',
15218      'stop',
15219      'style',
15220      'switch',
15221      'symbol',
15222      'text',
15223      'textpath',
15224      'title',
15225      'tref',
15226      'tspan',
15227      'view',
15228      'vkern'
15229    ]);
15230    var svgFilters = freeze([
15231      'feBlend',
15232      'feColorMatrix',
15233      'feComponentTransfer',
15234      'feComposite',
15235      'feConvolveMatrix',
15236      'feDiffuseLighting',
15237      'feDisplacementMap',
15238      'feDistantLight',
15239      'feFlood',
15240      'feFuncA',
15241      'feFuncB',
15242      'feFuncG',
15243      'feFuncR',
15244      'feGaussianBlur',
15245      'feImage',
15246      'feMerge',
15247      'feMergeNode',
15248      'feMorphology',
15249      'feOffset',
15250      'fePointLight',
15251      'feSpecularLighting',
15252      'feSpotLight',
15253      'feTile',
15254      'feTurbulence'
15255    ]);
15256    var svgDisallowed = freeze([
15257      'animate',
15258      'color-profile',
15259      'cursor',
15260      'discard',
15261      'fedropshadow',
15262      'font-face',
15263      'font-face-format',
15264      'font-face-name',
15265      'font-face-src',
15266      'font-face-uri',
15267      'foreignobject',
15268      'hatch',
15269      'hatchpath',
15270      'mesh',
15271      'meshgradient',
15272      'meshpatch',
15273      'meshrow',
15274      'missing-glyph',
15275      'script',
15276      'set',
15277      'solidcolor',
15278      'unknown',
15279      'use'
15280    ]);
15281    var mathMl$1 = freeze([
15282      'math',
15283      'menclose',
15284      'merror',
15285      'mfenced',
15286      'mfrac',
15287      'mglyph',
15288      'mi',
15289      'mlabeledtr',
15290      'mmultiscripts',
15291      'mn',
15292      'mo',
15293      'mover',
15294      'mpadded',
15295      'mphantom',
15296      'mroot',
15297      'mrow',
15298      'ms',
15299      'mspace',
15300      'msqrt',
15301      'mstyle',
15302      'msub',
15303      'msup',
15304      'msubsup',
15305      'mtable',
15306      'mtd',
15307      'mtext',
15308      'mtr',
15309      'munder',
15310      'munderover'
15311    ]);
15312    var mathMlDisallowed = freeze([
15313      'maction',
15314      'maligngroup',
15315      'malignmark',
15316      'mlongdiv',
15317      'mscarries',
15318      'mscarry',
15319      'msgroup',
15320      'mstack',
15321      'msline',
15322      'msrow',
15323      'semantics',
15324      'annotation',
15325      'annotation-xml',
15326      'mprescripts',
15327      'none'
15328    ]);
15329    var text = freeze(['#text']);
15330    var html = freeze([
15331      'accept',
15332      'action',
15333      'align',
15334      'alt',
15335      'autocapitalize',
15336      'autocomplete',
15337      'autopictureinpicture',
15338      'autoplay',
15339      'background',
15340      'bgcolor',
15341      'border',
15342      'capture',
15343      'cellpadding',
15344      'cellspacing',
15345      'checked',
15346      'cite',
15347      'class',
15348      'clear',
15349      'color',
15350      'cols',
15351      'colspan',
15352      'controls',
15353      'controlslist',
vendor: 35,063 bytes, lines 15354-16373
15354      'coords',
15355      'crossorigin',
15356      'datetime',
15357      'decoding',
15358      'default',
15359      'dir',
15360      'disabled',
15361      'disablepictureinpicture',
15362      'disableremoteplayback',
15363      'download',
15364      'draggable',
15365      'enctype',
15366      'enterkeyhint',
15367      'face',
15368      'for',
15369      'headers',
15370      'height',
15371      'hidden',
15372      'high',
15373      'href',
15374      'hreflang',
15375      'id',
15376      'inputmode',
15377      'integrity',
15378      'ismap',
15379      'kind',
15380      'label',
15381      'lang',
15382      'list',
15383      'loading',
15384      'loop',
15385      'low',
15386      'max',
15387      'maxlength',
15388      'media',
15389      'method',
15390      'min',
15391      'minlength',
15392      'multiple',
15393      'muted',
15394      'name',
15395      'nonce',
15396      'noshade',
15397      'novalidate',
15398      'nowrap',
15399      'open',
15400      'optimum',
15401      'pattern',
15402      'placeholder',
15403      'playsinline',
15404      'poster',
15405      'preload',
15406      'pubdate',
15407      'radiogroup',
15408      'readonly',
15409      'rel',
15410      'required',
15411      'rev',
15412      'reversed',
15413      'role',
15414      'rows',
15415      'rowspan',
15416      'spellcheck',
15417      'scope',
15418      'selected',
15419      'shape',
15420      'size',
15421      'sizes',
15422      'span',
15423      'srclang',
15424      'start',
15425      'src',
15426      'srcset',
15427      'step',
15428      'style',
15429      'summary',
15430      'tabindex',
15431      'title',
15432      'translate',
15433      'type',
15434      'usemap',
15435      'valign',
15436      'value',
15437      'width',
15438      'xmlns',
15439      'slot'
15440    ]);
15441    var svg = freeze([
15442      'accent-height',
15443      'accumulate',
15444      'additive',
15445      'alignment-baseline',
15446      'ascent',
15447      'attributename',
15448      'attributetype',
15449      'azimuth',
15450      'basefrequency',
15451      'baseline-shift',
15452      'begin',
15453      'bias',
15454      'by',
15455      'class',
15456      'clip',
15457      'clippathunits',
15458      'clip-path',
15459      'clip-rule',
15460      'color',
15461      'color-interpolation',
15462      'color-interpolation-filters',
15463      'color-profile',
15464      'color-rendering',
15465      'cx',
15466      'cy',
15467      'd',
15468      'dx',
15469      'dy',
15470      'diffuseconstant',
15471      'direction',
15472      'display',
15473      'divisor',
15474      'dur',
15475      'edgemode',
15476      'elevation',
15477      'end',
15478      'fill',
15479      'fill-opacity',
15480      'fill-rule',
15481      'filter',
15482      'filterunits',
15483      'flood-color',
15484      'flood-opacity',
15485      'font-family',
15486      'font-size',
15487      'font-size-adjust',
15488      'font-stretch',
15489      'font-style',
15490      'font-variant',
15491      'font-weight',
15492      'fx',
15493      'fy',
15494      'g1',
15495      'g2',
15496      'glyph-name',
15497      'glyphref',
15498      'gradientunits',
15499      'gradienttransform',
15500      'height',
15501      'href',
15502      'id',
15503      'image-rendering',
15504      'in',
15505      'in2',
15506      'k',
15507      'k1',
15508      'k2',
15509      'k3',
15510      'k4',
15511      'kerning',
15512      'keypoints',
15513      'keysplines',
15514      'keytimes',
15515      'lang',
15516      'lengthadjust',
15517      'letter-spacing',
15518      'kernelmatrix',
15519      'kernelunitlength',
15520      'lighting-color',
15521      'local',
15522      'marker-end',
15523      'marker-mid',
15524      'marker-start',
15525      'markerheight',
15526      'markerunits',
15527      'markerwidth',
15528      'maskcontentunits',
15529      'maskunits',
15530      'max',
15531      'mask',
15532      'media',
15533      'method',
15534      'mode',
15535      'min',
15536      'name',
15537      'numoctaves',
15538      'offset',
15539      'operator',
15540      'opacity',
15541      'order',
15542      'orient',
15543      'orientation',
15544      'origin',
15545      'overflow',
15546      'paint-order',
15547      'path',
15548      'pathlength',
15549      'patterncontentunits',
15550      'patterntransform',
15551      'patternunits',
15552      'points',
15553      'preservealpha',
15554      'preserveaspectratio',
15555      'primitiveunits',
15556      'r',
15557      'rx',
15558      'ry',
15559      'radius',
15560      'refx',
15561      'refy',
15562      'repeatcount',
15563      'repeatdur',
15564      'restart',
15565      'result',
15566      'rotate',
15567      'scale',
15568      'seed',
15569      'shape-rendering',
15570      'specularconstant',
15571      'specularexponent',
15572      'spreadmethod',
15573      'startoffset',
15574      'stddeviation',
15575      'stitchtiles',
15576      'stop-color',
15577      'stop-opacity',
15578      'stroke-dasharray',
15579      'stroke-dashoffset',
15580      'stroke-linecap',
15581      'stroke-linejoin',
15582      'stroke-miterlimit',
15583      'stroke-opacity',
15584      'stroke',
15585      'stroke-width',
15586      'style',
15587      'surfacescale',
15588      'systemlanguage',
15589      'tabindex',
15590      'targetx',
15591      'targety',
15592      'transform',
15593      'transform-origin',
15594      'text-anchor',
15595      'text-decoration',
15596      'text-rendering',
15597      'textlength',
15598      'type',
15599      'u1',
15600      'u2',
15601      'unicode',
15602      'values',
15603      'viewbox',
15604      'visibility',
15605      'version',
15606      'vert-adv-y',
15607      'vert-origin-x',
15608      'vert-origin-y',
15609      'width',
15610      'word-spacing',
15611      'wrap',
15612      'writing-mode',
15613      'xchannelselector',
15614      'ychannelselector',
15615      'x',
15616      'x1',
15617      'x2',
15618      'xmlns',
15619      'y',
15620      'y1',
15621      'y2',
15622      'z',
15623      'zoomandpan'
15624    ]);
15625    var mathMl = freeze([
15626      'accent',
15627      'accentunder',
15628      'align',
15629      'bevelled',
15630      'close',
15631      'columnsalign',
15632      'columnlines',
15633      'columnspan',
15634      'denomalign',
15635      'depth',
15636      'dir',
15637      'display',
15638      'displaystyle',
15639      'encoding',
15640      'fence',
15641      'frame',
15642      'height',
15643      'href',
15644      'id',
15645      'largeop',
15646      'length',
15647      'linethickness',
15648      'lspace',
15649      'lquote',
15650      'mathbackground',
15651      'mathcolor',
15652      'mathsize',
15653      'mathvariant',
15654      'maxsize',
15655      'minsize',
15656      'movablelimits',
15657      'notation',
15658      'numalign',
15659      'open',
15660      'rowalign',
15661      'rowlines',
15662      'rowspacing',
15663      'rowspan',
15664      'rspace',
15665      'rquote',
15666      'scriptlevel',
15667      'scriptminsize',
15668      'scriptsizemultiplier',
15669      'selection',
15670      'separator',
15671      'separators',
15672      'stretchy',
15673      'subscriptshift',
15674      'supscriptshift',
15675      'symmetric',
15676      'voffset',
15677      'width',
15678      'xmlns'
15679    ]);
15680    var xml = freeze([
15681      'xlink:href',
15682      'xml:id',
15683      'xlink:title',
15684      'xml:space',
15685      'xmlns:xlink'
15686    ]);
15687    var MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm);
15688    var ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
15689    var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/);
15690    var ARIA_ATTR = seal(/^aria-[\-\w]+$/);
15691    var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i);
15692    var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
15693    var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g);
15694    var DOCTYPE_NAME = seal(/^html$/i);
15695    var getGlobal = function getGlobal() {
15696      return typeof window === 'undefined' ? null : window;
15697    };
15698    var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {
15699      if (_typeof(trustedTypes) !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
15700        return null;
15701      }
15702      var suffix = null;
15703      var ATTR_NAME = 'data-tt-policy-suffix';
15704      if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {
15705        suffix = document.currentScript.getAttribute(ATTR_NAME);
15706      }
15707      var policyName = 'dompurify' + (suffix ? '#' + suffix : '');
15708      try {
15709        return trustedTypes.createPolicy(policyName, {
15710          createHTML: function createHTML(html) {
15711            return html;
15712          }
15713        });
15714      } catch (_) {
15715        console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
15716        return null;
15717      }
15718    };
15719    function createDOMPurify() {
15720      var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
15721      var DOMPurify = function DOMPurify(root) {
15722        return createDOMPurify(root);
15723      };
15724      DOMPurify.version = '2.3.8';
15725      DOMPurify.removed = [];
15726      if (!window || !window.document || window.document.nodeType !== 9) {
15727        DOMPurify.isSupported = false;
15728        return DOMPurify;
15729      }
15730      var originalDocument = window.document;
15731      var document = window.document;
15732      var DocumentFragment = window.DocumentFragment, HTMLTemplateElement = window.HTMLTemplateElement, Node = window.Node, Element = window.Element, NodeFilter = window.NodeFilter, _window$NamedNodeMap = window.NamedNodeMap, NamedNodeMap = _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap, HTMLFormElement = window.HTMLFormElement, DOMParser = window.DOMParser, trustedTypes = window.trustedTypes;
15733      var ElementPrototype = Element.prototype;
15734      var cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
15735      var getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
15736      var getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
15737      var getParentNode = lookupGetter(ElementPrototype, 'parentNode');
15738      if (typeof HTMLTemplateElement === 'function') {
15739        var template = document.createElement('template');
15740        if (template.content && template.content.ownerDocument) {
15741          document = template.content.ownerDocument;
15742        }
15743      }
15744      var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
15745      var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
15746      var _document = document, implementation = _document.implementation, createNodeIterator = _document.createNodeIterator, createDocumentFragment = _document.createDocumentFragment, getElementsByTagName = _document.getElementsByTagName;
15747      var importNode = originalDocument.importNode;
15748      var documentMode = {};
15749      try {
15750        documentMode = clone(document).documentMode ? document.documentMode : {};
15751      } catch (_) {
15752      }
15753      var hooks = {};
15754      DOMPurify.isSupported = typeof getParentNode === 'function' && implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
15755      var MUSTACHE_EXPR$1 = MUSTACHE_EXPR, ERB_EXPR$1 = ERB_EXPR, DATA_ATTR$1 = DATA_ATTR, ARIA_ATTR$1 = ARIA_ATTR, IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, ATTR_WHITESPACE$1 = ATTR_WHITESPACE;
15756      var IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
15757      var ALLOWED_TAGS = null;
15758      var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(html$1), _toConsumableArray(svg$1), _toConsumableArray(svgFilters), _toConsumableArray(mathMl$1), _toConsumableArray(text)));
15759      var ALLOWED_ATTR = null;
15760      var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray(html), _toConsumableArray(svg), _toConsumableArray(mathMl), _toConsumableArray(xml)));
15761      var CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
15762        tagNameCheck: {
15763          writable: true,
15764          configurable: false,
15765          enumerable: true,
15766          value: null
15767        },
15768        attributeNameCheck: {
15769          writable: true,
15770          configurable: false,
15771          enumerable: true,
15772          value: null
15773        },
15774        allowCustomizedBuiltInElements: {
15775          writable: true,
15776          configurable: false,
15777          enumerable: true,
15778          value: false
15779        }
15780      }));
15781      var FORBID_TAGS = null;
15782      var FORBID_ATTR = null;
15783      var ALLOW_ARIA_ATTR = true;
15784      var ALLOW_DATA_ATTR = true;
15785      var ALLOW_UNKNOWN_PROTOCOLS = false;
15786      var SAFE_FOR_TEMPLATES = false;
15787      var WHOLE_DOCUMENT = false;
15788      var SET_CONFIG = false;
15789      var FORCE_BODY = false;
15790      var RETURN_DOM = false;
15791      var RETURN_DOM_FRAGMENT = false;
15792      var RETURN_TRUSTED_TYPE = false;
15793      var SANITIZE_DOM = true;
15794      var KEEP_CONTENT = true;
15795      var IN_PLACE = false;
15796      var USE_PROFILES = {};
15797      var FORBID_CONTENTS = null;
15798      var DEFAULT_FORBID_CONTENTS = addToSet({}, [
15799        'annotation-xml',
15800        'audio',
15801        'colgroup',
15802        'desc',
15803        'foreignobject',
15804        'head',
15805        'iframe',
15806        'math',
15807        'mi',
15808        'mn',
15809        'mo',
15810        'ms',
15811        'mtext',
15812        'noembed',
15813        'noframes',
15814        'noscript',
15815        'plaintext',
15816        'script',
15817        'style',
15818        'svg',
15819        'template',
15820        'thead',
15821        'title',
15822        'video',
15823        'xmp'
15824      ]);
15825      var DATA_URI_TAGS = null;
15826      var DEFAULT_DATA_URI_TAGS = addToSet({}, [
15827        'audio',
15828        'video',
15829        'img',
15830        'source',
15831        'image',
15832        'track'
15833      ]);
15834      var URI_SAFE_ATTRIBUTES = null;
15835      var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [
15836        'alt',
15837        'class',
15838        'for',
15839        'id',
15840        'label',
15841        'name',
15842        'pattern',
15843        'placeholder',
15844        'role',
15845        'summary',
15846        'title',
15847        'value',
15848        'style',
15849        'xmlns'
15850      ]);
15851      var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
15852      var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
15853      var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
15854      var NAMESPACE = HTML_NAMESPACE;
15855      var IS_EMPTY_INPUT = false;
15856      var PARSER_MEDIA_TYPE;
15857      var SUPPORTED_PARSER_MEDIA_TYPES = [
15858        'application/xhtml+xml',
15859        'text/html'
15860      ];
15861      var DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
15862      var transformCaseFunc;
15863      var CONFIG = null;
15864      var formElement = document.createElement('form');
15865      var isRegexOrFunction = function isRegexOrFunction(testValue) {
15866        return testValue instanceof RegExp || testValue instanceof Function;
15867      };
15868      var _parseConfig = function _parseConfig(cfg) {
15869        if (CONFIG && CONFIG === cfg) {
15870          return;
15871        }
15872        if (!cfg || _typeof(cfg) !== 'object') {
15873          cfg = {};
15874        }
15875        cfg = clone(cfg);
15876        ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS;
15877        ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
15878        URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
15879        DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;
15880        FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS) : DEFAULT_FORBID_CONTENTS;
15881        FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
15882        FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
15883        USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
15884        ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false;
15885        ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false;
15886        ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false;
15887        SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false;
15888        WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false;
15889        RETURN_DOM = cfg.RETURN_DOM || false;
15890        RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false;
15891        RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false;
15892        FORCE_BODY = cfg.FORCE_BODY || false;
15893        SANITIZE_DOM = cfg.SANITIZE_DOM !== false;
15894        KEEP_CONTENT = cfg.KEEP_CONTENT !== false;
15895        IN_PLACE = cfg.IN_PLACE || false;
15896        IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$1;
15897        NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
15898        if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
15899          CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
15900        }
15901        if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
15902          CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
15903        }
15904        if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
15905          CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
15906        }
15907        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;
15908        transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? function (x) {
15909          return x;
15910        } : stringToLowerCase;
15911        if (SAFE_FOR_TEMPLATES) {
15912          ALLOW_DATA_ATTR = false;
15913        }
15914        if (RETURN_DOM_FRAGMENT) {
15915          RETURN_DOM = true;
15916        }
15917        if (USE_PROFILES) {
15918          ALLOWED_TAGS = addToSet({}, _toConsumableArray(text));
15919          ALLOWED_ATTR = [];
15920          if (USE_PROFILES.html === true) {
15921            addToSet(ALLOWED_TAGS, html$1);
15922            addToSet(ALLOWED_ATTR, html);
15923          }
15924          if (USE_PROFILES.svg === true) {
15925            addToSet(ALLOWED_TAGS, svg$1);
15926            addToSet(ALLOWED_ATTR, svg);
15927            addToSet(ALLOWED_ATTR, xml);
15928          }
15929          if (USE_PROFILES.svgFilters === true) {
15930            addToSet(ALLOWED_TAGS, svgFilters);
15931            addToSet(ALLOWED_ATTR, svg);
15932            addToSet(ALLOWED_ATTR, xml);
15933          }
15934          if (USE_PROFILES.mathMl === true) {
15935            addToSet(ALLOWED_TAGS, mathMl$1);
15936            addToSet(ALLOWED_ATTR, mathMl);
15937            addToSet(ALLOWED_ATTR, xml);
15938          }
15939        }
15940        if (cfg.ADD_TAGS) {
15941          if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
15942            ALLOWED_TAGS = clone(ALLOWED_TAGS);
15943          }
15944          addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
15945        }
15946        if (cfg.ADD_ATTR) {
15947          if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
15948            ALLOWED_ATTR = clone(ALLOWED_ATTR);
15949          }
15950          addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
15951        }
15952        if (cfg.ADD_URI_SAFE_ATTR) {
15953          addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
15954        }
15955        if (cfg.FORBID_CONTENTS) {
15956          if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
15957            FORBID_CONTENTS = clone(FORBID_CONTENTS);
15958          }
15959          addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
15960        }
15961        if (KEEP_CONTENT) {
15962          ALLOWED_TAGS['#text'] = true;
15963        }
15964        if (WHOLE_DOCUMENT) {
15965          addToSet(ALLOWED_TAGS, [
15966            'html',
15967            'head',
15968            'body'
15969          ]);
15970        }
15971        if (ALLOWED_TAGS.table) {
15972          addToSet(ALLOWED_TAGS, ['tbody']);
15973          delete FORBID_TAGS.tbody;
15974        }
15975        if (freeze) {
15976          freeze(cfg);
15977        }
15978        CONFIG = cfg;
15979      };
15980      var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [
15981        'mi',
15982        'mo',
15983        'mn',
15984        'ms',
15985        'mtext'
15986      ]);
15987      var HTML_INTEGRATION_POINTS = addToSet({}, [
15988        'foreignobject',
15989        'desc',
15990        'title',
15991        'annotation-xml'
15992      ]);
15993      var COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [
15994        'title',
15995        'style',
15996        'font',
15997        'a',
15998        'script'
15999      ]);
16000      var ALL_SVG_TAGS = addToSet({}, svg$1);
16001      addToSet(ALL_SVG_TAGS, svgFilters);
16002      addToSet(ALL_SVG_TAGS, svgDisallowed);
16003      var ALL_MATHML_TAGS = addToSet({}, mathMl$1);
16004      addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
16005      var _checkValidNamespace = function _checkValidNamespace(element) {
16006        var parent = getParentNode(element);
16007        if (!parent || !parent.tagName) {
16008          parent = {
16009            namespaceURI: HTML_NAMESPACE,
16010            tagName: 'template'
16011          };
16012        }
16013        var tagName = stringToLowerCase(element.tagName);
16014        var parentTagName = stringToLowerCase(parent.tagName);
16015        if (element.namespaceURI === SVG_NAMESPACE) {
16016          if (parent.namespaceURI === HTML_NAMESPACE) {
16017            return tagName === 'svg';
16018          }
16019          if (parent.namespaceURI === MATHML_NAMESPACE) {
16020            return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
16021          }
16022          return Boolean(ALL_SVG_TAGS[tagName]);
16023        }
16024        if (element.namespaceURI === MATHML_NAMESPACE) {
16025          if (parent.namespaceURI === HTML_NAMESPACE) {
16026            return tagName === 'math';
16027          }
16028          if (parent.namespaceURI === SVG_NAMESPACE) {
16029            return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
16030          }
16031          return Boolean(ALL_MATHML_TAGS[tagName]);
16032        }
16033        if (element.namespaceURI === HTML_NAMESPACE) {
16034          if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
16035            return false;
16036          }
16037          if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
16038            return false;
16039          }
16040          return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
16041        }
16042        return false;
16043      };
16044      var _forceRemove = function _forceRemove(node) {
16045        arrayPush(DOMPurify.removed, { element: node });
16046        try {
16047          node.parentNode.removeChild(node);
16048        } catch (_) {
16049          try {
16050            node.outerHTML = emptyHTML;
16051          } catch (_) {
16052            node.remove();
16053          }
16054        }
16055      };
16056      var _removeAttribute = function _removeAttribute(name, node) {
16057        try {
16058          arrayPush(DOMPurify.removed, {
16059            attribute: node.getAttributeNode(name),
16060            from: node
16061          });
16062        } catch (_) {
16063          arrayPush(DOMPurify.removed, {
16064            attribute: null,
16065            from: node
16066          });
16067        }
16068        node.removeAttribute(name);
16069        if (name === 'is' && !ALLOWED_ATTR[name]) {
16070          if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
16071            try {
16072              _forceRemove(node);
16073            } catch (_) {
16074            }
16075          } else {
16076            try {
16077              node.setAttribute(name, '');
16078            } catch (_) {
16079            }
16080          }
16081        }
16082      };
16083      var _initDocument = function _initDocument(dirty) {
16084        var doc;
16085        var leadingWhitespace;
16086        if (FORCE_BODY) {
16087          dirty = '<remove></remove>' + dirty;
16088        } else {
16089          var matches = stringMatch(dirty, /^[\r\n\t ]+/);
16090          leadingWhitespace = matches && matches[0];
16091        }
16092        if (PARSER_MEDIA_TYPE === 'application/xhtml+xml') {
16093          dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
16094        }
16095        var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
16096        if (NAMESPACE === HTML_NAMESPACE) {
16097          try {
16098            doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
16099          } catch (_) {
16100          }
16101        }
16102        if (!doc || !doc.documentElement) {
16103          doc = implementation.createDocument(NAMESPACE, 'template', null);
16104          try {
16105            doc.documentElement.innerHTML = IS_EMPTY_INPUT ? '' : dirtyPayload;
16106          } catch (_) {
16107          }
16108        }
16109        var body = doc.body || doc.documentElement;
16110        if (dirty && leadingWhitespace) {
16111          body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
16112        }
16113        if (NAMESPACE === HTML_NAMESPACE) {
16114          return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
16115        }
16116        return WHOLE_DOCUMENT ? doc.documentElement : body;
16117      };
16118      var _createIterator = function _createIterator(root) {
16119        return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
16120      };
16121      var _isClobbered = function _isClobbered(elm) {
16122        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');
16123      };
16124      var _isNode = function _isNode(object) {
16125        return _typeof(Node) === 'object' ? object instanceof Node : object && _typeof(object) === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
16126      };
16127      var _executeHook = function _executeHook(entryPoint, currentNode, data) {
16128        if (!hooks[entryPoint]) {
16129          return;
16130        }
16131        arrayForEach(hooks[entryPoint], function (hook) {
16132          hook.call(DOMPurify, currentNode, data, CONFIG);
16133        });
16134      };
16135      var _sanitizeElements = function _sanitizeElements(currentNode) {
16136        var content;
16137        _executeHook('beforeSanitizeElements', currentNode, null);
16138        if (_isClobbered(currentNode)) {
16139          _forceRemove(currentNode);
16140          return true;
16141        }
16142        if (regExpTest(/[\u0080-\uFFFF]/, currentNode.nodeName)) {
16143          _forceRemove(currentNode);
16144          return true;
16145        }
16146        var tagName = transformCaseFunc(currentNode.nodeName);
16147        _executeHook('uponSanitizeElement', currentNode, {
16148          tagName: tagName,
16149          allowedTags: ALLOWED_TAGS
16150        });
16151        if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
16152          _forceRemove(currentNode);
16153          return true;
16154        }
16155        if (tagName === 'select' && regExpTest(/<template/i, currentNode.innerHTML)) {
16156          _forceRemove(currentNode);
16157          return true;
16158        }
16159        if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
16160          if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
16161            if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName))
16162              return false;
16163            if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName))
16164              return false;
16165          }
16166          if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
16167            var parentNode = getParentNode(currentNode) || currentNode.parentNode;
16168            var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
16169            if (childNodes && parentNode) {
16170              var childCount = childNodes.length;
16171              for (var i = childCount - 1; i >= 0; --i) {
16172                parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
16173              }
16174            }
16175          }
16176          _forceRemove(currentNode);
16177          return true;
16178        }
16179        if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
16180          _forceRemove(currentNode);
16181          return true;
16182        }
16183        if ((tagName === 'noscript' || tagName === 'noembed') && regExpTest(/<\/no(script|embed)/i, currentNode.innerHTML)) {
16184          _forceRemove(currentNode);
16185          return true;
16186        }
16187        if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
16188          content = currentNode.textContent;
16189          content = stringReplace(content, MUSTACHE_EXPR$1, ' ');
16190          content = stringReplace(content, ERB_EXPR$1, ' ');
16191          if (currentNode.textContent !== content) {
16192            arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
16193            currentNode.textContent = content;
16194          }
16195        }
16196        _executeHook('afterSanitizeElements', currentNode, null);
16197        return false;
16198      };
16199      var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
16200        if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
16201          return false;
16202        }
16203        if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$1, lcName));
16204        else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName));
16205        else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
16206          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)));
16207          else {
16208            return false;
16209          }
16210        } else if (URI_SAFE_ATTRIBUTES[lcName]);
16211        else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, '')));
16212        else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]);
16213        else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, '')));
16214        else if (!value);
16215        else {
16216          return false;
16217        }
16218        return true;
16219      };
16220      var _basicCustomElementTest = function _basicCustomElementTest(tagName) {
16221        return tagName.indexOf('-') > 0;
16222      };
16223      var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
16224        var attr;
16225        var value;
16226        var lcName;
16227        var l;
16228        _executeHook('beforeSanitizeAttributes', currentNode, null);
16229        var attributes = currentNode.attributes;
16230        if (!attributes) {
16231          return;
16232        }
16233        var hookEvent = {
16234          attrName: '',
16235          attrValue: '',
16236          keepAttr: true,
16237          allowedAttributes: ALLOWED_ATTR
16238        };
16239        l = attributes.length;
16240        while (l--) {
16241          attr = attributes[l];
16242          var _attr = attr, name = _attr.name, namespaceURI = _attr.namespaceURI;
16243          value = name === 'value' ? attr.value : stringTrim(attr.value);
16244          lcName = transformCaseFunc(name);
16245          var initValue = value;
16246          hookEvent.attrName = lcName;
16247          hookEvent.attrValue = value;
16248          hookEvent.keepAttr = true;
16249          hookEvent.forceKeepAttr = undefined;
16250          _executeHook('uponSanitizeAttribute', currentNode, hookEvent);
16251          value = hookEvent.attrValue;
16252          if (hookEvent.forceKeepAttr) {
16253            continue;
16254          }
16255          if (!hookEvent.keepAttr) {
16256            _removeAttribute(name, currentNode);
16257            continue;
16258          }
16259          if (regExpTest(/\/>/i, value)) {
16260            _removeAttribute(name, currentNode);
16261            continue;
16262          }
16263          if (SAFE_FOR_TEMPLATES) {
16264            value = stringReplace(value, MUSTACHE_EXPR$1, ' ');
16265            value = stringReplace(value, ERB_EXPR$1, ' ');
16266          }
16267          var lcTag = transformCaseFunc(currentNode.nodeName);
16268          if (!_isValidAttribute(lcTag, lcName, value)) {
16269            _removeAttribute(name, currentNode);
16270            continue;
16271          }
16272          if (value !== initValue) {
16273            try {
16274              if (namespaceURI) {
16275                currentNode.setAttributeNS(namespaceURI, name, value);
16276              } else {
16277                currentNode.setAttribute(name, value);
16278              }
16279            } catch (_) {
16280              _removeAttribute(name, currentNode);
16281            }
16282          }
16283        }
16284        _executeHook('afterSanitizeAttributes', currentNode, null);
16285      };
16286      var _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
16287        var shadowNode;
16288        var shadowIterator = _createIterator(fragment);
16289        _executeHook('beforeSanitizeShadowDOM', fragment, null);
16290        while (shadowNode = shadowIterator.nextNode()) {
16291          _executeHook('uponSanitizeShadowNode', shadowNode, null);
16292          if (_sanitizeElements(shadowNode)) {
16293            continue;
16294          }
16295          if (shadowNode.content instanceof DocumentFragment) {
16296            _sanitizeShadowDOM(shadowNode.content);
16297          }
16298          _sanitizeAttributes(shadowNode);
16299        }
16300        _executeHook('afterSanitizeShadowDOM', fragment, null);
16301      };
16302      DOMPurify.sanitize = function (dirty, cfg) {
16303        var body;
16304        var importedNode;
16305        var currentNode;
16306        var oldNode;
16307        var returnNode;
16308        IS_EMPTY_INPUT = !dirty;
16309        if (IS_EMPTY_INPUT) {
16310          dirty = '<!-->';
16311        }
16312        if (typeof dirty !== 'string' && !_isNode(dirty)) {
16313          if (typeof dirty.toString !== 'function') {
16314            throw typeErrorCreate('toString is not a function');
16315          } else {
16316            dirty = dirty.toString();
16317            if (typeof dirty !== 'string') {
16318              throw typeErrorCreate('dirty is not a string, aborting');
16319            }
16320          }
16321        }
16322        if (!DOMPurify.isSupported) {
16323          if (_typeof(window.toStaticHTML) === 'object' || typeof window.toStaticHTML === 'function') {
16324            if (typeof dirty === 'string') {
16325              return window.toStaticHTML(dirty);
16326            }
16327            if (_isNode(dirty)) {
16328              return window.toStaticHTML(dirty.outerHTML);
16329            }
16330          }
16331          return dirty;
16332        }
16333        if (!SET_CONFIG) {
16334          _parseConfig(cfg);
16335        }
16336        DOMPurify.removed = [];
16337        if (typeof dirty === 'string') {
16338          IN_PLACE = false;
16339        }
16340        if (IN_PLACE) {
16341          if (dirty.nodeName) {
16342            var tagName = transformCaseFunc(dirty.nodeName);
16343            if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
16344              throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
16345            }
16346          }
16347        } else if (dirty instanceof Node) {
16348          body = _initDocument('<!---->');
16349          importedNode = body.ownerDocument.importNode(dirty, true);
16350          if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
16351            body = importedNode;
16352          } else if (importedNode.nodeName === 'HTML') {
16353            body = importedNode;
16354          } else {
16355            body.appendChild(importedNode);
16356          }
16357        } else {
16358          if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf('<') === -1) {
16359            return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
16360          }
16361          body = _initDocument(dirty);
16362          if (!body) {
16363            return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
16364          }
16365        }
16366        if (body && FORCE_BODY) {
16367          _forceRemove(body.firstChild);
16368        }
16369        var nodeIterator = _createIterator(IN_PLACE ? dirty : body);
16370        while (currentNode = nodeIterator.nextNode()) {
16371          if (currentNode.nodeType === 3 && currentNode === oldNode) {
16372            continue;
16373          }
vendor: 22,996 bytes, lines 16374-17002
16374          if (_sanitizeElements(currentNode)) {
16375            continue;
16376          }
16377          if (currentNode.content instanceof DocumentFragment) {
16378            _sanitizeShadowDOM(currentNode.content);
16379          }
16380          _sanitizeAttributes(currentNode);
16381          oldNode = currentNode;
16382        }
16383        oldNode = null;
16384        if (IN_PLACE) {
16385          return dirty;
16386        }
16387        if (RETURN_DOM) {
16388          if (RETURN_DOM_FRAGMENT) {
16389            returnNode = createDocumentFragment.call(body.ownerDocument);
16390            while (body.firstChild) {
16391              returnNode.appendChild(body.firstChild);
16392            }
16393          } else {
16394            returnNode = body;
16395          }
16396          if (ALLOWED_ATTR.shadowroot) {
16397            returnNode = importNode.call(originalDocument, returnNode, true);
16398          }
16399          return returnNode;
16400        }
16401        var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
16402        if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
16403          serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
16404        }
16405        if (SAFE_FOR_TEMPLATES) {
16406          serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$1, ' ');
16407          serializedHTML = stringReplace(serializedHTML, ERB_EXPR$1, ' ');
16408        }
16409        return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
16410      };
16411      DOMPurify.setConfig = function (cfg) {
16412        _parseConfig(cfg);
16413        SET_CONFIG = true;
16414      };
16415      DOMPurify.clearConfig = function () {
16416        CONFIG = null;
16417        SET_CONFIG = false;
16418      };
16419      DOMPurify.isValidAttribute = function (tag, attr, value) {
16420        if (!CONFIG) {
16421          _parseConfig({});
16422        }
16423        var lcTag = transformCaseFunc(tag);
16424        var lcName = transformCaseFunc(attr);
16425        return _isValidAttribute(lcTag, lcName, value);
16426      };
16427      DOMPurify.addHook = function (entryPoint, hookFunction) {
16428        if (typeof hookFunction !== 'function') {
16429          return;
16430        }
16431        hooks[entryPoint] = hooks[entryPoint] || [];
16432        arrayPush(hooks[entryPoint], hookFunction);
16433      };
16434      DOMPurify.removeHook = function (entryPoint) {
16435        if (hooks[entryPoint]) {
16436          return arrayPop(hooks[entryPoint]);
16437        }
16438      };
16439      DOMPurify.removeHooks = function (entryPoint) {
16440        if (hooks[entryPoint]) {
16441          hooks[entryPoint] = [];
16442        }
16443      };
16444      DOMPurify.removeAllHooks = function () {
16445        hooks = {};
16446      };
16447      return DOMPurify;
16448    }
16449    var purify = createDOMPurify();
16450
16451    const each$4 = Tools.each, trim = Tools.trim;
16452    const queryParts = [
16453      'source',
16454      'protocol',
16455      'authority',
16456      'userInfo',
16457      'user',
16458      'password',
16459      'host',
16460      'port',
16461      'relative',
16462      'path',
16463      'directory',
16464      'file',
16465      'query',
16466      'anchor'
16467    ];
16468    const DEFAULT_PORTS = {
16469      ftp: 21,
16470      http: 80,
16471      https: 443,
16472      mailto: 25
16473    };
16474    const safeSvgDataUrlElements = [
16475      'img',
16476      'video'
16477    ];
16478    const blockSvgDataUris = (allowSvgDataUrls, tagName) => {
16479      if (isNonNullable(allowSvgDataUrls)) {
16480        return !allowSvgDataUrls;
16481      } else {
16482        return isNonNullable(tagName) ? !contains$2(safeSvgDataUrlElements, tagName) : true;
16483      }
16484    };
16485    const decodeUri = encodedUri => {
16486      try {
16487        return decodeURIComponent(encodedUri);
16488      } catch (ex) {
16489        return unescape(encodedUri);
16490      }
16491    };
16492    const isInvalidUri = (settings, uri, tagName) => {
16493      const decodedUri = decodeUri(uri).replace(/\s/g, '');
16494      if (settings.allow_script_urls) {
16495        return false;
16496      } else if (/((java|vb)script|mhtml):/i.test(decodedUri)) {
16497        return true;
16498      } else if (settings.allow_html_data_urls) {
16499        return false;
16500      } else if (/^data:image\//i.test(decodedUri)) {
16501        return blockSvgDataUris(settings.allow_svg_data_urls, tagName) && /^data:image\/svg\+xml/i.test(decodedUri);
16502      } else {
16503        return /^data:/i.test(decodedUri);
16504      }
16505    };
16506    class URI {
16507      static parseDataUri(uri) {
16508        let type;
16509        const uriComponents = decodeURIComponent(uri).split(',');
16510        const matches = /data:([^;]+)/.exec(uriComponents[0]);
16511        if (matches) {
16512          type = matches[1];
16513        }
16514        return {
16515          type,
16516          data: uriComponents[1]
16517        };
16518      }
16519      static isDomSafe(uri, context, options = {}) {
16520        if (options.allow_script_urls) {
16521          return true;
16522        } else {
16523          const decodedUri = Entities.decode(uri).replace(/[\s\u0000-\u001F]+/g, '');
16524          return !isInvalidUri(options, decodedUri, context);
16525        }
16526      }
16527      static getDocumentBaseUrl(loc) {
16528        var _a;
16529        let baseUrl;
16530        if (loc.protocol.indexOf('http') !== 0 && loc.protocol !== 'file:') {
16531          baseUrl = (_a = loc.href) !== null && _a !== void 0 ? _a : '';
16532        } else {
16533          baseUrl = loc.protocol + '//' + loc.host + loc.pathname;
16534        }
16535        if (/^[^:]+:\/\/\/?[^\/]+\//.test(baseUrl)) {
16536          baseUrl = baseUrl.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
16537          if (!/[\/\\]$/.test(baseUrl)) {
16538            baseUrl += '/';
16539          }
16540        }
16541        return baseUrl;
16542      }
16543      constructor(url, settings = {}) {
16544        this.path = '';
16545        this.directory = '';
16546        url = trim(url);
16547        this.settings = settings;
16548        const baseUri = settings.base_uri;
16549        const self = this;
16550        if (/^([\w\-]+):([^\/]{2})/i.test(url) || /^\s*#/.test(url)) {
16551          self.source = url;
16552          return;
16553        }
16554        const isProtocolRelative = url.indexOf('//') === 0;
16555        if (url.indexOf('/') === 0 && !isProtocolRelative) {
16556          url = (baseUri ? baseUri.protocol || 'http' : 'http') + '://mce_host' + url;
16557        }
16558        if (!/^[\w\-]*:?\/\//.test(url)) {
16559          const baseUrl = baseUri ? baseUri.path : new URI(document.location.href).directory;
16560          if ((baseUri === null || baseUri === void 0 ? void 0 : baseUri.protocol) === '') {
16561            url = '//mce_host' + self.toAbsPath(baseUrl, url);
16562          } else {
16563            const match = /([^#?]*)([#?]?.*)/.exec(url);
16564            if (match) {
16565              url = (baseUri && baseUri.protocol || 'http') + '://mce_host' + self.toAbsPath(baseUrl, match[1]) + match[2];
16566            }
16567          }
16568        }
16569        url = url.replace(/@@/g, '(mce_at)');
16570        const urlMatch = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?(\[[a-zA-Z0-9:.%]+\]|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url);
16571        if (urlMatch) {
16572          each$4(queryParts, (v, i) => {
16573            let part = urlMatch[i];
16574            if (part) {
16575              part = part.replace(/\(mce_at\)/g, '@@');
16576            }
16577            self[v] = part;
16578          });
16579        }
16580        if (baseUri) {
16581          if (!self.protocol) {
16582            self.protocol = baseUri.protocol;
16583          }
16584          if (!self.userInfo) {
16585            self.userInfo = baseUri.userInfo;
16586          }
16587          if (!self.port && self.host === 'mce_host') {
16588            self.port = baseUri.port;
16589          }
16590          if (!self.host || self.host === 'mce_host') {
16591            self.host = baseUri.host;
16592          }
16593          self.source = '';
16594        }
16595        if (isProtocolRelative) {
16596          self.protocol = '';
16597        }
16598      }
16599      setPath(path) {
16600        const pathMatch = /^(.*?)\/?(\w+)?$/.exec(path);
16601        if (pathMatch) {
16602          this.path = pathMatch[0];
16603          this.directory = pathMatch[1];
16604          this.file = pathMatch[2];
16605        }
16606        this.source = '';
16607        this.getURI();
16608      }
16609      toRelative(uri) {
16610        if (uri === './') {
16611          return uri;
16612        }
16613        const relativeUri = new URI(uri, { base_uri: this });
16614        if (relativeUri.host !== 'mce_host' && this.host !== relativeUri.host && relativeUri.host || this.port !== relativeUri.port || this.protocol !== relativeUri.protocol && relativeUri.protocol !== '') {
16615          return relativeUri.getURI();
16616        }
16617        const tu = this.getURI(), uu = relativeUri.getURI();
16618        if (tu === uu || tu.charAt(tu.length - 1) === '/' && tu.substr(0, tu.length - 1) === uu) {
16619          return tu;
16620        }
16621        let output = this.toRelPath(this.path, relativeUri.path);
16622        if (relativeUri.query) {
16623          output += '?' + relativeUri.query;
16624        }
16625        if (relativeUri.anchor) {
16626          output += '#' + relativeUri.anchor;
16627        }
16628        return output;
16629      }
16630      toAbsolute(uri, noHost) {
16631        const absoluteUri = new URI(uri, { base_uri: this });
16632        return absoluteUri.getURI(noHost && this.isSameOrigin(absoluteUri));
16633      }
16634      isSameOrigin(uri) {
16635        if (this.host == uri.host && this.protocol == uri.protocol) {
16636          if (this.port == uri.port) {
16637            return true;
16638          }
16639          const defaultPort = this.protocol ? DEFAULT_PORTS[this.protocol] : null;
16640          if (defaultPort && (this.port || defaultPort) == (uri.port || defaultPort)) {
16641            return true;
16642          }
16643        }
16644        return false;
16645      }
16646      toRelPath(base, path) {
16647        let breakPoint = 0, out = '', i, l;
16648        const normalizedBase = base.substring(0, base.lastIndexOf('/')).split('/');
16649        const items = path.split('/');
16650        if (normalizedBase.length >= items.length) {
16651          for (i = 0, l = normalizedBase.length; i < l; i++) {
16652            if (i >= items.length || normalizedBase[i] !== items[i]) {
16653              breakPoint = i + 1;
16654              break;
16655            }
16656          }
16657        }
16658        if (normalizedBase.length < items.length) {
16659          for (i = 0, l = items.length; i < l; i++) {
16660            if (i >= normalizedBase.length || normalizedBase[i] !== items[i]) {
16661              breakPoint = i + 1;
16662              break;
16663            }
16664          }
16665        }
16666        if (breakPoint === 1) {
16667          return path;
16668        }
16669        for (i = 0, l = normalizedBase.length - (breakPoint - 1); i < l; i++) {
16670          out += '../';
16671        }
16672        for (i = breakPoint - 1, l = items.length; i < l; i++) {
16673          if (i !== breakPoint - 1) {
16674            out += '/' + items[i];
16675          } else {
16676            out += items[i];
16677          }
16678        }
16679        return out;
16680      }
16681      toAbsPath(base, path) {
16682        let nb = 0;
16683        const tr = /\/$/.test(path) ? '/' : '';
16684        const normalizedBase = base.split('/');
16685        const normalizedPath = path.split('/');
16686        const baseParts = [];
16687        each$4(normalizedBase, k => {
16688          if (k) {
16689            baseParts.push(k);
16690          }
16691        });
16692        const pathParts = [];
16693        for (let i = normalizedPath.length - 1; i >= 0; i--) {
16694          if (normalizedPath[i].length === 0 || normalizedPath[i] === '.') {
16695            continue;
16696          }
16697          if (normalizedPath[i] === '..') {
16698            nb++;
16699            continue;
16700          }
16701          if (nb > 0) {
16702            nb--;
16703            continue;
16704          }
16705          pathParts.push(normalizedPath[i]);
16706        }
16707        const i = baseParts.length - nb;
16708        let outPath;
16709        if (i <= 0) {
16710          outPath = reverse(pathParts).join('/');
16711        } else {
16712          outPath = baseParts.slice(0, i).join('/') + '/' + reverse(pathParts).join('/');
16713        }
16714        if (outPath.indexOf('/') !== 0) {
16715          outPath = '/' + outPath;
16716        }
16717        if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) {
16718          outPath += tr;
16719        }
16720        return outPath;
16721      }
16722      getURI(noProtoHost = false) {
16723        let s;
16724        if (!this.source || noProtoHost) {
16725          s = '';
16726          if (!noProtoHost) {
16727            if (this.protocol) {
16728              s += this.protocol + '://';
16729            } else {
16730              s += '//';
16731            }
16732            if (this.userInfo) {
16733              s += this.userInfo + '@';
16734            }
16735            if (this.host) {
16736              s += this.host;
16737            }
16738            if (this.port) {
16739              s += ':' + this.port;
16740            }
16741          }
16742          if (this.path) {
16743            s += this.path;
16744          }
16745          if (this.query) {
16746            s += '?' + this.query;
16747          }
16748          if (this.anchor) {
16749            s += '#' + this.anchor;
16750          }
16751          this.source = s;
16752        }
16753        return this.source;
16754      }
16755    }
16756
16757    const filteredUrlAttrs = Tools.makeMap('src,href,data,background,action,formaction,poster,xlink:href');
16758    const internalElementAttr = 'data-mce-type';
16759    let uid = 0;
16760    const processNode = (node, settings, schema, evt) => {
16761      var _a, _b, _c, _d;
16762      const validate = settings.validate;
16763      const specialElements = schema.getSpecialElements();
16764      if (node.nodeType === COMMENT && !settings.allow_conditional_comments && /^\[if/i.test((_a = node.nodeValue) !== null && _a !== void 0 ? _a : '')) {
16765        node.nodeValue = ' ' + node.nodeValue;
16766      }
16767      const lcTagName = (_b = evt === null || evt === void 0 ? void 0 : evt.tagName) !== null && _b !== void 0 ? _b : node.nodeName.toLowerCase();
16768      if (node.nodeType !== ELEMENT || lcTagName === 'body') {
16769        return;
16770      }
16771      const element = SugarElement.fromDom(node);
16772      const isInternalElement = has$1(element, internalElementAttr);
16773      const bogus = get$9(element, 'data-mce-bogus');
16774      if (!isInternalElement && isString(bogus)) {
16775        if (bogus === 'all') {
16776          remove$5(element);
16777        } else {
16778          unwrap(element);
16779        }
16780        return;
16781      }
16782      const rule = schema.getElementRule(lcTagName);
16783      if (validate && !rule) {
16784        if (has$2(specialElements, lcTagName)) {
16785          remove$5(element);
16786        } else {
16787          unwrap(element);
16788        }
16789        return;
16790      } else {
16791        if (isNonNullable(evt)) {
16792          evt.allowedTags[lcTagName] = true;
16793        }
16794      }
16795      if (validate && rule && !isInternalElement) {
16796        each$e((_c = rule.attributesForced) !== null && _c !== void 0 ? _c : [], attr => {
16797          set$3(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
16798        });
16799        each$e((_d = rule.attributesDefault) !== null && _d !== void 0 ? _d : [], attr => {
16800          if (!has$1(element, attr.name)) {
16801            set$3(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
16802          }
16803        });
16804        if (rule.attributesRequired && !exists(rule.attributesRequired, attr => has$1(element, attr))) {
16805          unwrap(element);
16806          return;
16807        }
16808        if (rule.removeEmptyAttrs && hasNone(element)) {
16809          unwrap(element);
16810          return;
16811        }
16812        if (rule.outputName && rule.outputName !== lcTagName) {
16813          mutate(element, rule.outputName);
16814        }
16815      }
16816    };
16817    const shouldKeepAttribute = (settings, schema, tagName, attrName, attrValue) => !(attrName in filteredUrlAttrs && isInvalidUri(settings, attrValue, tagName)) && (!settings.validate || schema.isValid(tagName, attrName) || startsWith(attrName, 'data-') || startsWith(attrName, 'aria-'));
16818    const isRequiredAttributeOfInternalElement = (ele, attrName) => ele.hasAttribute(internalElementAttr) && (attrName === 'id' || attrName === 'class' || attrName === 'style');
16819    const isBooleanAttribute = (attrName, schema) => attrName in schema.getBoolAttrs();
16820    const filterAttributes = (ele, settings, schema) => {
16821      const {attributes} = ele;
16822      for (let i = attributes.length - 1; i >= 0; i--) {
16823        const attr = attributes[i];
16824        const attrName = attr.name;
16825        const attrValue = attr.value;
16826        if (!shouldKeepAttribute(settings, schema, ele.tagName.toLowerCase(), attrName, attrValue) && !isRequiredAttributeOfInternalElement(ele, attrName)) {
16827          ele.removeAttribute(attrName);
16828        } else if (isBooleanAttribute(attrName, schema)) {
16829          ele.setAttribute(attrName, attrName);
16830        }
16831      }
16832    };
16833    const setupPurify = (settings, schema) => {
16834      const purify$1 = purify();
16835      purify$1.addHook('uponSanitizeElement', (ele, evt) => {
16836        processNode(ele, settings, schema, evt);
16837      });
16838      purify$1.addHook('uponSanitizeAttribute', (ele, evt) => {
16839        const tagName = ele.tagName.toLowerCase();
16840        const {attrName, attrValue} = evt;
16841        evt.keepAttr = shouldKeepAttribute(settings, schema, tagName, attrName, attrValue);
16842        if (evt.keepAttr) {
16843          evt.allowedAttributes[attrName] = true;
16844          if (isBooleanAttribute(attrName, schema)) {
16845            evt.attrValue = attrName;
16846          }
16847          if (settings.allow_svg_data_urls && startsWith(attrValue, 'data:image/svg+xml')) {
16848            evt.forceKeepAttr = true;
16849          }
16850        } else if (isRequiredAttributeOfInternalElement(ele, attrName)) {
16851          evt.forceKeepAttr = true;
16852        }
16853      });
16854      return purify$1;
16855    };
16856    const getPurifyConfig = (settings, mimeType) => {
16857      const basePurifyConfig = {
16858        IN_PLACE: true,
16859        ALLOW_UNKNOWN_PROTOCOLS: true,
16860        ALLOWED_TAGS: [
16861          '#comment',
16862          '#cdata-section',
16863          'body'
16864        ],
16865        ALLOWED_ATTR: []
16866      };
16867      const config = { ...basePurifyConfig };
16868      config.PARSER_MEDIA_TYPE = mimeType;
16869      if (settings.allow_script_urls) {
16870        config.ALLOWED_URI_REGEXP = /.*/;
16871      } else if (settings.allow_html_data_urls) {
16872        config.ALLOWED_URI_REGEXP = /^(?!(\w+script|mhtml):)/i;
16873      }
16874      return config;
16875    };
16876    const getSanitizer = (settings, schema) => {
16877      if (settings.sanitize) {
16878        const purify = setupPurify(settings, schema);
16879        return (body, mimeType) => {
16880          purify.sanitize(body, getPurifyConfig(settings, mimeType));
16881          purify.removed = [];
16882        };
16883      } else {
16884        return (body, _) => {
16885          const nodeIterator = document.createNodeIterator(body, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT);
16886          let node;
16887          while (node = nodeIterator.nextNode()) {
16888            processNode(node, settings, schema);
16889            if (isElement$6(node)) {
16890              filterAttributes(node, settings, schema);
16891            }
16892          }
16893        };
16894      }
16895    };
16896
16897    const makeMap = Tools.makeMap, extend$1 = Tools.extend;
16898    const transferChildren = (parent, nativeParent, specialElements) => {
16899      const parentName = parent.name;
16900      const isSpecial = parentName in specialElements && parentName !== 'title' && parentName !== 'textarea';
16901      const childNodes = nativeParent.childNodes;
16902      for (let ni = 0, nl = childNodes.length; ni < nl; ni++) {
16903        const nativeChild = childNodes[ni];
16904        const child = new AstNode(nativeChild.nodeName.toLowerCase(), nativeChild.nodeType);
16905        if (isElement$6(nativeChild)) {
16906          const attributes = nativeChild.attributes;
16907          for (let ai = 0, al = attributes.length; ai < al; ai++) {
16908            const attr = attributes[ai];
16909            child.attr(attr.name, attr.value);
16910          }
16911        } else if (isText$a(nativeChild)) {
16912          child.value = nativeChild.data;
16913          if (isSpecial) {
16914            child.raw = true;
16915          }
16916        } else if (isComment(nativeChild) || isCData(nativeChild) || isPi(nativeChild)) {
16917          child.value = nativeChild.data;
16918        }
16919        transferChildren(child, nativeChild, specialElements);
16920        parent.append(child);
16921      }
16922    };
16923    const walkTree = (root, preprocessors, postprocessors) => {
16924      const traverseOrder = [];
16925      for (let node = root, lastNode = node; node; lastNode = node, node = node.walk()) {
16926        const tempNode = node;
16927        each$e(preprocessors, preprocess => preprocess(tempNode));
16928        if (isNullable(tempNode.parent) && tempNode !== root) {
16929          node = lastNode;
16930        } else {
16931          traverseOrder.push(tempNode);
16932        }
16933      }
16934      for (let i = traverseOrder.length - 1; i >= 0; i--) {
16935        const node = traverseOrder[i];
16936        each$e(postprocessors, postprocess => postprocess(node));
16937      }
16938    };
16939    const whitespaceCleaner = (root, schema, settings, args) => {
16940      const validate = settings.validate;
16941      const nonEmptyElements = schema.getNonEmptyElements();
16942      const whitespaceElements = schema.getWhitespaceElements();
16943      const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
16944      const textRootBlockElements = getTextRootBlockElements(schema);
16945      const allWhiteSpaceRegExp = /[ \t\r\n]+/g;
16946      const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
16947      const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
16948      const hasWhitespaceParent = node => {
16949        let tempNode = node.parent;
16950        while (isNonNullable(tempNode)) {
16951          if (tempNode.name in whitespaceElements) {
16952            return true;
16953          } else {
16954            tempNode = tempNode.parent;
16955          }
16956        }
16957        return false;
16958      };
16959      const isTextRootBlockEmpty = node => {
16960        let tempNode = node;
16961        while (isNonNullable(tempNode)) {
16962          if (tempNode.name in textRootBlockElements) {
16963            return isEmpty(schema, nonEmptyElements, whitespaceElements, tempNode);
16964          } else {
16965            tempNode = tempNode.parent;
16966          }
16967        }
16968        return false;
16969      };
16970      const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node);
16971      const isAtEdgeOfBlock = (node, start) => {
16972        const neighbour = start ? node.prev : node.next;
16973        if (isNonNullable(neighbour) || isNullable(node.parent)) {
16974          return false;
16975        }
16976        return isBlock(node.parent) && (node.parent !== root || args.isRootContent === true);
16977      };
16978      const preprocess = node => {
16979        var _a;
16980        if (node.type === 3) {
16981          if (!hasWhitespaceParent(node)) {
16982            let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
16983            text = text.replace(allWhiteSpaceRegExp, ' ');
16984            if (isLineBreakNode(node.prev, isBlock) || isAtEdgeOfBlock(node, true)) {
16985              text = text.replace(startWhiteSpaceRegExp, '');
16986            }
16987            if (text.length === 0) {
16988              node.remove();
16989            } else {
16990              node.value = text;
16991            }
16992          }
16993        }
16994      };
16995      const postprocess = node => {
16996        var _a;
16997        if (node.type === 1) {
16998          const elementRule = schema.getElementRule(node.name);
16999          if (validate && elementRule) {
17000            const isNodeEmpty = isEmpty(schema, nonEmptyElements, whitespaceElements, node);
17001            if (elementRule.paddInEmptyBlock && isNodeEmpty && isTextRootBlockEmpty(node)) {
17002              paddEmptyNode(
17002settings, args, isBlock, node);
17003            } else if (elementRule.removeEmpty && isNodeEmpty) {
17004              if (isBlock(node)) {
17005                node.remove();
17006              } else {
17007                node.unwrap();
17008              }
17009            } else if (elementRule.paddEmpty && (isNodeEmpty || isPaddedWithNbsp(node))) {
17010              paddEmptyNode(settings, 
vendor: 65,570 bytes, lines 17010-18685
17010args, isBlock, node);
17011            }
17012          }
17013        } else if (node.type === 3) {
17014          if (!hasWhitespaceParent(node)) {
17015            let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
17016            if (node.next && isBlock(node.next) || isAtEdgeOfBlock(node, false)) {
17017              text = text.replace(endWhiteSpaceRegExp, '');
17018            }
17019            if (text.length === 0) {
17020              node.remove();
17021            } else {
17022              node.value = text;
17023            }
17024          }
17025        }
17026      };
17027      return [
17028        preprocess,
17029        postprocess
17030      ];
17031    };
17032    const getRootBlockName = (settings, args) => {
17033      var _a;
17034      const name = (_a = args.forced_root_block) !== null && _a !== void 0 ? _a : settings.forced_root_block;
17035      if (name === false) {
17036        return '';
17037      } else if (name === true) {
17038        return 'p';
17039      } else {
17040        return name;
17041      }
17042    };
17043    const DomParser = (settings = {}, schema = Schema()) => {
17044      const nodeFilterRegistry = create$8();
17045      const attributeFilterRegistry = create$8();
17046      const defaultedSettings = {
17047        validate: true,
17048        root_name: 'body',
17049        sanitize: true,
17050        ...settings
17051      };
17052      const parser = new DOMParser();
17053      const sanitize = getSanitizer(defaultedSettings, schema);
17054      const parseAndSanitizeWithContext = (html, rootName, format = 'html') => {
17055        const mimeType = format === 'xhtml' ? 'application/xhtml+xml' : 'text/html';
17056        const isSpecialRoot = has$2(schema.getSpecialElements(), rootName.toLowerCase());
17057        const content = isSpecialRoot ? `<${ rootName }>${ html }</${ rootName }>` : html;
17058        const wrappedHtml = format === 'xhtml' ? `<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>${ content }</body></html>` : `<body>${ content }</body>`;
17059        const body = parser.parseFromString(wrappedHtml, mimeType).body;
17060        sanitize(body, mimeType);
17061        return isSpecialRoot ? body.firstChild : body;
17062      };
17063      const addNodeFilter = nodeFilterRegistry.addFilter;
17064      const getNodeFilters = nodeFilterRegistry.getFilters;
17065      const removeNodeFilter = nodeFilterRegistry.removeFilter;
17066      const addAttributeFilter = attributeFilterRegistry.addFilter;
17067      const getAttributeFilters = attributeFilterRegistry.getFilters;
17068      const removeAttributeFilter = attributeFilterRegistry.removeFilter;
17069      const findInvalidChildren = (node, invalidChildren) => {
17070        if (isInvalid(schema, node)) {
17071          invalidChildren.push(node);
17072        }
17073      };
17074      const isWrappableNode = (blockElements, node) => {
17075        const isInternalElement = isString(node.attr(internalElementAttr));
17076        const isInlineElement = node.type === 1 && (!has$2(blockElements, node.name) && !isTransparentAstBlock(schema, node));
17077        return node.type === 3 || isInlineElement && !isInternalElement;
17078      };
17079      const addRootBlocks = (rootNode, rootBlockName) => {
17080        const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
17081        const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
17082        const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
17083        let node = rootNode.firstChild, rootBlockNode = null;
17084        const trim = rootBlock => {
17085          var _a, _b;
17086          if (rootBlock) {
17087            node = rootBlock.firstChild;
17088            if (node && node.type === 3) {
17089              node.value = (_a = node.value) === null || _a === void 0 ? void 0 : _a.replace(startWhiteSpaceRegExp, '');
17090            }
17091            node = rootBlock.lastChild;
17092            if (node && node.type === 3) {
17093              node.value = (_b = node.value) === null || _b === void 0 ? void 0 : _b.replace(endWhiteSpaceRegExp, '');
17094            }
17095          }
17096        };
17097        if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) {
17098          return;
17099        }
17100        while (node) {
17101          const next = node.next;
17102          if (isWrappableNode(blockElements, node)) {
17103            if (!rootBlockNode) {
17104              rootBlockNode = new AstNode(rootBlockName, 1);
17105              rootBlockNode.attr(defaultedSettings.forced_root_block_attrs);
17106              rootNode.insert(rootBlockNode, node);
17107              rootBlockNode.append(node);
17108            } else {
17109              rootBlockNode.append(node);
17110            }
17111          } else {
17112            trim(rootBlockNode);
17113            rootBlockNode = null;
17114          }
17115          node = next;
17116        }
17117        trim(rootBlockNode);
17118      };
17119      const parse = (html, args = {}) => {
17120        var _a;
17121        const validate = defaultedSettings.validate;
17122        const rootName = (_a = args.context) !== null && _a !== void 0 ? _a : defaultedSettings.root_name;
17123        const element = parseAndSanitizeWithContext(html, rootName, args.format);
17124        updateChildren(schema, element);
17125        const rootNode = new AstNode(rootName, 11);
17126        transferChildren(rootNode, element, schema.getSpecialElements());
17127        element.innerHTML = '';
17128        const [whitespacePre, whitespacePost] = whitespaceCleaner(rootNode, schema, defaultedSettings, args);
17129        const invalidChildren = [];
17130        const invalidFinder = validate ? node => findInvalidChildren(node, invalidChildren) : noop;
17131        const matches = {
17132          nodes: {},
17133          attributes: {}
17134        };
17135        const matchFinder = node => matchNode$1(getNodeFilters(), getAttributeFilters(), node, matches);
17136        walkTree(rootNode, [
17137          whitespacePre,
17138          matchFinder
17139        ], [
17140          whitespacePost,
17141          invalidFinder
17142        ]);
17143        invalidChildren.reverse();
17144        if (validate && invalidChildren.length > 0) {
17145          if (args.context) {
17146            const {
17147              pass: topLevelChildren,
17148              fail: otherChildren
17149            } = partition$2(invalidChildren, child => child.parent === rootNode);
17150            cleanInvalidNodes(otherChildren, schema, rootNode, matchFinder);
17151            args.invalid = topLevelChildren.length > 0;
17152          } else {
17153            cleanInvalidNodes(invalidChildren, schema, rootNode, matchFinder);
17154          }
17155        }
17156        const rootBlockName = getRootBlockName(defaultedSettings, args);
17157        if (rootBlockName && (rootNode.name === 'body' || args.isRootContent)) {
17158          addRootBlocks(rootNode, rootBlockName);
17159        }
17160        if (!args.invalid) {
17161          runFilters(matches, args);
17162        }
17163        return rootNode;
17164      };
17165      const exports = {
17166        schema,
17167        addAttributeFilter,
17168        getAttributeFilters,
17169        removeAttributeFilter,
17170        addNodeFilter,
17171        getNodeFilters,
17172        removeNodeFilter,
17173        parse
17174      };
17175      register$4(exports, defaultedSettings);
17176      register$5(exports, defaultedSettings, schema);
17177      return exports;
17178    };
17179
17180    const serializeContent = content => isTreeNode(content) ? HtmlSerializer({ validate: false }).serialize(content) : content;
17181    const withSerializedContent = (content, fireEvent, sanitize) => {
17182      const serializedContent = serializeContent(content);
17183      const eventArgs = fireEvent(serializedContent);
17184      if (eventArgs.isDefaultPrevented()) {
17185        return eventArgs;
17186      } else if (isTreeNode(content)) {
17187        if (eventArgs.content !== serializedContent) {
17188          const rootNode = DomParser({
17189            validate: false,
17190            forced_root_block: false,
17191            sanitize
17192          }).parse(eventArgs.content, { context: content.name });
17193          return {
17194            ...eventArgs,
17195            content: rootNode
17196          };
17197        } else {
17198          return {
17199            ...eventArgs,
17200            content
17201          };
17202        }
17203      } else {
17204        return eventArgs;
17205      }
17206    };
17207    const preProcessGetContent = (editor, args) => {
17208      if (args.no_events) {
17209        return Result.value(args);
17210      } else {
17211        const eventArgs = fireBeforeGetContent(editor, args);
17212        if (eventArgs.isDefaultPrevented()) {
17213          return Result.error(fireGetContent(editor, {
17214            content: '',
17215            ...eventArgs
17216          }).content);
17217        } else {
17218          return Result.value(eventArgs);
17219        }
17220      }
17221    };
17222    const postProcessGetContent = (editor, content, args) => {
17223      if (args.no_events) {
17224        return content;
17225      } else {
17226        const processedEventArgs = withSerializedContent(content, content => fireGetContent(editor, {
17227          ...args,
17228          content
17229        }), shouldSanitizeXss(editor));
17230        return processedEventArgs.content;
17231      }
17232    };
17233    const preProcessSetContent = (editor, args) => {
17234      if (args.no_events) {
17235        return Result.value(args);
17236      } else {
17237        const processedEventArgs = withSerializedContent(args.content, content => fireBeforeSetContent(editor, {
17238          ...args,
17239          content
17240        }), shouldSanitizeXss(editor));
17241        if (processedEventArgs.isDefaultPrevented()) {
17242          fireSetContent(editor, processedEventArgs);
17243          return Result.error(undefined);
17244        } else {
17245          return Result.value(processedEventArgs);
17246        }
17247      }
17248    };
17249    const postProcessSetContent = (editor, content, args) => {
17250      if (!args.no_events) {
17251        fireSetContent(editor, {
17252          ...args,
17253          content
17254        });
17255      }
17256    };
17257
17258    const tableModel = (element, width, rows) => ({
17259      element,
17260      width,
17261      rows
17262    });
17263    const tableRow = (element, cells) => ({
17264      element,
17265      cells
17266    });
17267    const cellPosition = (x, y) => ({
17268      x,
17269      y
17270    });
17271    const getSpan = (td, key) => {
17272      return getOpt(td, key).bind(toInt).getOr(1);
17273    };
17274    const fillout = (table, x, y, tr, td) => {
17275      const rowspan = getSpan(td, 'rowspan');
17276      const colspan = getSpan(td, 'colspan');
17277      const rows = table.rows;
17278      for (let y2 = y; y2 < y + rowspan; y2++) {
17279        if (!rows[y2]) {
17280          rows[y2] = tableRow(deep$1(tr), []);
17281        }
17282        for (let x2 = x; x2 < x + colspan; x2++) {
17283          const cells = rows[y2].cells;
17284          cells[x2] = y2 === y && x2 === x ? td : shallow$1(td);
17285        }
17286      }
17287    };
17288    const cellExists = (table, x, y) => {
17289      const rows = table.rows;
17290      const cells = rows[y] ? rows[y].cells : [];
17291      return !!cells[x];
17292    };
17293    const skipCellsX = (table, x, y) => {
17294      while (cellExists(table, x, y)) {
17295        x++;
17296      }
17297      return x;
17298    };
17299    const getWidth = rows => {
17300      return foldl(rows, (acc, row) => {
17301        return row.cells.length > acc ? row.cells.length : acc;
17302      }, 0);
17303    };
17304    const findElementPos = (table, element) => {
17305      const rows = table.rows;
17306      for (let y = 0; y < rows.length; y++) {
17307        const cells = rows[y].cells;
17308        for (let x = 0; x < cells.length; x++) {
17309          if (eq(cells[x], element)) {
17310            return Optional.some(cellPosition(x, y));
17311          }
17312        }
17313      }
17314      return Optional.none();
17315    };
17316    const extractRows = (table, sx, sy, ex, ey) => {
17317      const newRows = [];
17318      const rows = table.rows;
17319      for (let y = sy; y <= ey; y++) {
17320        const cells = rows[y].cells;
17321        const slice = sx < ex ? cells.slice(sx, ex + 1) : cells.slice(ex, sx + 1);
17322        newRows.push(tableRow(rows[y].element, slice));
17323      }
17324      return newRows;
17325    };
17326    const subTable = (table, startPos, endPos) => {
17327      const sx = startPos.x, sy = startPos.y;
17328      const ex = endPos.x, ey = endPos.y;
17329      const newRows = sy < ey ? extractRows(table, sx, sy, ex, ey) : extractRows(table, sx, ey, ex, sy);
17330      return tableModel(table.element, getWidth(newRows), newRows);
17331    };
17332    const createDomTable = (table, rows) => {
17333      const tableElement = shallow$1(table.element);
17334      const tableBody = SugarElement.fromTag('tbody');
17335      append(tableBody, rows);
17336      append$1(tableElement, tableBody);
17337      return tableElement;
17338    };
17339    const modelRowsToDomRows = table => {
17340      return map$3(table.rows, row => {
17341        const cells = map$3(row.cells, cell => {
17342          const td = deep$1(cell);
17343          remove$a(td, 'colspan');
17344          remove$a(td, 'rowspan');
17345          return td;
17346        });
17347        const tr = shallow$1(row.element);
17348        append(tr, cells);
17349        return tr;
17350      });
17351    };
17352    const fromDom = tableElm => {
17353      const table = tableModel(shallow$1(tableElm), 0, []);
17354      each$e(descendants(tableElm, 'tr'), (tr, y) => {
17355        each$e(descendants(tr, 'td,th'), (td, x) => {
17356          fillout(table, skipCellsX(table, x, y), y, tr, td);
17357        });
17358      });
17359      return tableModel(table.element, getWidth(table.rows), table.rows);
17360    };
17361    const toDom = table => {
17362      return createDomTable(table, modelRowsToDomRows(table));
17363    };
17364    const subsection = (table, startElement, endElement) => {
17365      return findElementPos(table, startElement).bind(startPos => {
17366        return findElementPos(table, endElement).map(endPos => {
17367          return subTable(table, startPos, endPos);
17368        });
17369      });
17370    };
17371
17372    const findParentListContainer = parents => find$2(parents, elm => name(elm) === 'ul' || name(elm) === 'ol');
17373    const getFullySelectedListWrappers = (parents, rng) => find$2(parents, elm => name(elm) === 'li' && hasAllContentsSelected(elm, rng)).fold(constant([]), _li => findParentListContainer(parents).map(listCont => {
17374      const listElm = SugarElement.fromTag(name(listCont));
17375      const listStyles = filter$4(getAllRaw(listCont), (_style, name) => startsWith(name, 'list-style'));
17376      setAll(listElm, listStyles);
17377      return [
17378        SugarElement.fromTag('li'),
17379        listElm
17380      ];
17381    }).getOr([]));
17382    const wrap = (innerElm, elms) => {
17383      const wrapped = foldl(elms, (acc, elm) => {
17384        append$1(elm, acc);
17385        return elm;
17386      }, innerElm);
17387      return elms.length > 0 ? fromElements([wrapped]) : wrapped;
17388    };
17389    const directListWrappers = commonAnchorContainer => {
17390      if (isListItem$1(commonAnchorContainer)) {
17391        return parent(commonAnchorContainer).filter(isList).fold(constant([]), listElm => [
17392          commonAnchorContainer,
17393          listElm
17394        ]);
17395      } else {
17396        return isList(commonAnchorContainer) ? [commonAnchorContainer] : [];
17397      }
17398    };
17399    const getWrapElements = (rootNode, rng) => {
17400      const commonAnchorContainer = SugarElement.fromDom(rng.commonAncestorContainer);
17401      const parents = parentsAndSelf(commonAnchorContainer, rootNode);
17402      const wrapElements = filter$5(parents, isWrapElement);
17403      const listWrappers = getFullySelectedListWrappers(parents, rng);
17404      const allWrappers = wrapElements.concat(listWrappers.length ? listWrappers : directListWrappers(commonAnchorContainer));
17405      return map$3(allWrappers, shallow$1);
17406    };
17407    const emptyFragment = () => fromElements([]);
17408    const getFragmentFromRange = (rootNode, rng) => wrap(SugarElement.fromDom(rng.cloneContents()), getWrapElements(rootNode, rng));
17409    const getParentTable = (rootElm, cell) => ancestor$3(cell, 'table', curry(eq, rootElm));
17410    const getTableFragment = (rootNode, selectedTableCells) => getParentTable(rootNode, selectedTableCells[0]).bind(tableElm => {
17411      const firstCell = selectedTableCells[0];
17412      const lastCell = selectedTableCells[selectedTableCells.length - 1];
17413      const fullTableModel = fromDom(tableElm);
17414      return subsection(fullTableModel, firstCell, lastCell).map(sectionedTableModel => fromElements([toDom(sectionedTableModel)]));
17415    }).getOrThunk(emptyFragment);
17416    const getSelectionFragment = (rootNode, ranges) => ranges.length > 0 && ranges[0].collapsed ? emptyFragment() : getFragmentFromRange(rootNode, ranges[0]);
17417    const read$3 = (rootNode, ranges) => {
17418      const selectedCells = getCellsFromElementOrRanges(ranges, rootNode);
17419      return selectedCells.length > 0 ? getTableFragment(rootNode, selectedCells) : getSelectionFragment(rootNode, ranges);
17420    };
17421
17422    const isCollapsibleWhitespace = (text, index) => index >= 0 && index < text.length && isWhiteSpace(text.charAt(index));
17423    const getInnerText = bin => {
17424      return trim$1(bin.innerText);
17425    };
17426    const getContextNodeName = parentBlockOpt => parentBlockOpt.map(block => block.nodeName).getOr('div').toLowerCase();
17427    const getTextContent = editor => Optional.from(editor.selection.getRng()).map(rng => {
17428      var _a;
17429      const parentBlockOpt = Optional.from(editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock));
17430      const body = editor.getBody();
17431      const contextNodeName = getContextNodeName(parentBlockOpt);
17432      const rangeContentClone = SugarElement.fromDom(rng.cloneContents());
17433      cleanupBogusElements(rangeContentClone);
17434      cleanupInputNames(rangeContentClone);
17435      const bin = editor.dom.add(body, contextNodeName, {
17436        'data-mce-bogus': 'all',
17437        'style': 'overflow: hidden; opacity: 0;'
17438      }, rangeContentClone.dom);
17439      const text = getInnerText(bin);
17440      const nonRenderedText = trim$1((_a = bin.textContent) !== null && _a !== void 0 ? _a : '');
17441      editor.dom.remove(bin);
17442      if (isCollapsibleWhitespace(nonRenderedText, 0) || isCollapsibleWhitespace(nonRenderedText, nonRenderedText.length - 1)) {
17443        const parentBlock = parentBlockOpt.getOr(body);
17444        const parentBlockText = getInnerText(parentBlock);
17445        const textIndex = parentBlockText.indexOf(text);
17446        if (textIndex === -1) {
17447          return text;
17448        } else {
17449          const hasProceedingSpace = isCollapsibleWhitespace(parentBlockText, textIndex - 1);
17450          const hasTrailingSpace = isCollapsibleWhitespace(parentBlockText, textIndex + text.length);
17451          return (hasProceedingSpace ? ' ' : '') + text + (hasTrailingSpace ? ' ' : '');
17452        }
17453      } else {
17454        return text;
17455      }
17456    }).getOr('');
17457    const getSerializedContent = (editor, args) => {
17458      const rng = editor.selection.getRng(), tmpElm = editor.dom.create('body');
17459      const sel = editor.selection.getSel();
17460      const ranges = processRanges(editor, getRanges$1(sel));
17461      const fragment = args.contextual ? read$3(SugarElement.fromDom(editor.getBody()), ranges).dom : rng.cloneContents();
17462      if (fragment) {
17463        tmpElm.appendChild(fragment);
17464      }
17465      return editor.selection.serializer.serialize(tmpElm, args);
17466    };
17467    const extractSelectedContent = (editor, args) => {
17468      if (args.format === 'text') {
17469        return getTextContent(editor);
17470      } else {
17471        const content = getSerializedContent(editor, args);
17472        if (args.format === 'tree') {
17473          return content;
17474        } else {
17475          return editor.selection.isCollapsed() ? '' : content;
17476        }
17477      }
17478    };
17479    const setupArgs$3 = (args, format) => ({
17480      ...args,
17481      format,
17482      get: true,
17483      selection: true,
17484      getInner: true
17485    });
17486    const getSelectedContentInternal = (editor, format, args = {}) => {
17487      const defaultedArgs = setupArgs$3(args, format);
17488      return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
17489        const content = extractSelectedContent(editor, updatedArgs);
17490        return postProcessGetContent(editor, content, updatedArgs);
17491      });
17492    };
17493
17494    const KEEP = 0, INSERT = 1, DELETE = 2;
17495    const diff = (left, right) => {
17496      const size = left.length + right.length + 2;
17497      const vDown = new Array(size);
17498      const vUp = new Array(size);
17499      const snake = (start, end, diag) => {
17500        return {
17501          start,
17502          end,
17503          diag
17504        };
17505      };
17506      const buildScript = (start1, end1, start2, end2, script) => {
17507        const middle = getMiddleSnake(start1, end1, start2, end2);
17508        if (middle === null || middle.start === end1 && middle.diag === end1 - end2 || middle.end === start1 && middle.diag === start1 - start2) {
17509          let i = start1;
17510          let j = start2;
17511          while (i < end1 || j < end2) {
17512            if (i < end1 && j < end2 && left[i] === right[j]) {
17513              script.push([
17514                KEEP,
17515                left[i]
17516              ]);
17517              ++i;
17518              ++j;
17519            } else {
17520              if (end1 - start1 > end2 - start2) {
17521                script.push([
17522                  DELETE,
17523                  left[i]
17524                ]);
17525                ++i;
17526              } else {
17527                script.push([
17528                  INSERT,
17529                  right[j]
17530                ]);
17531                ++j;
17532              }
17533            }
17534          }
17535        } else {
17536          buildScript(start1, middle.start, start2, middle.start - middle.diag, script);
17537          for (let i2 = middle.start; i2 < middle.end; ++i2) {
17538            script.push([
17539              KEEP,
17540              left[i2]
17541            ]);
17542          }
17543          buildScript(middle.end, end1, middle.end - middle.diag, end2, script);
17544        }
17545      };
17546      const buildSnake = (start, diag, end1, end2) => {
17547        let end = start;
17548        while (end - diag < end2 && end < end1 && left[end] === right[end - diag]) {
17549          ++end;
17550        }
17551        return snake(start, end, diag);
17552      };
17553      const getMiddleSnake = (start1, end1, start2, end2) => {
17554        const m = end1 - start1;
17555        const n = end2 - start2;
17556        if (m === 0 || n === 0) {
17557          return null;
17558        }
17559        const delta = m - n;
17560        const sum = n + m;
17561        const offset = (sum % 2 === 0 ? sum : sum + 1) / 2;
17562        vDown[1 + offset] = start1;
17563        vUp[1 + offset] = end1 + 1;
17564        let d, k, i, x, y;
17565        for (d = 0; d <= offset; ++d) {
17566          for (k = -d; k <= d; k += 2) {
17567            i = k + offset;
17568            if (k === -d || k !== d && vDown[i - 1] < vDown[i + 1]) {
17569              vDown[i] = vDown[i + 1];
17570            } else {
17571              vDown[i] = vDown[i - 1] + 1;
17572            }
17573            x = vDown[i];
17574            y = x - start1 + start2 - k;
17575            while (x < end1 && y < end2 && left[x] === right[y]) {
17576              vDown[i] = ++x;
17577              ++y;
17578            }
17579            if (delta % 2 !== 0 && delta - d <= k && k <= delta + d) {
17580              if (vUp[i - delta] <= vDown[i]) {
17581                return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
17582              }
17583            }
17584          }
17585          for (k = delta - d; k <= delta + d; k += 2) {
17586            i = k + offset - delta;
17587            if (k === delta - d || k !== delta + d && vUp[i + 1] <= vUp[i - 1]) {
17588              vUp[i] = vUp[i + 1] - 1;
17589            } else {
17590              vUp[i] = vUp[i - 1];
17591            }
17592            x = vUp[i] - 1;
17593            y = x - start1 + start2 - k;
17594            while (x >= start1 && y >= start2 && left[x] === right[y]) {
17595              vUp[i] = x--;
17596              y--;
17597            }
17598            if (delta % 2 === 0 && -d <= k && k <= d) {
17599              if (vUp[i] <= vDown[i + delta]) {
17600                return buildSnake(vUp[i], k + start1 - start2, end1, end2);
17601              }
17602            }
17603          }
17604        }
17605        return null;
17606      };
17607      const script = [];
17608      buildScript(0, left.length, 0, right.length, script);
17609      return script;
17610    };
17611
17612    const getOuterHtml = elm => {
17613      if (isElement$6(elm)) {
17614        return elm.outerHTML;
17615      } else if (isText$a(elm)) {
17616        return Entities.encodeRaw(elm.data, false);
17617      } else if (isComment(elm)) {
17618        return '<!--' + elm.data + '-->';
17619      }
17620      return '';
17621    };
17622    const createFragment = html => {
17623      let node;
17624      const container = document.createElement('div');
17625      const frag = document.createDocumentFragment();
17626      if (html) {
17627        container.innerHTML = html;
17628      }
17629      while (node = container.firstChild) {
17630        frag.appendChild(node);
17631      }
17632      return frag;
17633    };
17634    const insertAt = (elm, html, index) => {
17635      const fragment = createFragment(html);
17636      if (elm.hasChildNodes() && index < elm.childNodes.length) {
17637        const target = elm.childNodes[index];
17638        elm.insertBefore(fragment, target);
17639      } else {
17640        elm.appendChild(fragment);
17641      }
17642    };
17643    const removeAt = (elm, index) => {
17644      if (elm.hasChildNodes() && index < elm.childNodes.length) {
17645        const target = elm.childNodes[index];
17646        elm.removeChild(target);
17647      }
17648    };
17649    const applyDiff = (diff, elm) => {
17650      let index = 0;
17651      each$e(diff, action => {
17652        if (action[0] === KEEP) {
17653          index++;
17654        } else if (action[0] === INSERT) {
17655          insertAt(elm, action[1], index);
17656          index++;
17657        } else if (action[0] === DELETE) {
17658          removeAt(elm, index);
17659        }
17660      });
17661    };
17662    const read$2 = elm => {
17663      return filter$5(map$3(from(elm.childNodes), getOuterHtml), item => {
17664        return item.length > 0;
17665      });
17666    };
17667    const write = (fragments, elm) => {
17668      const currentFragments = map$3(from(elm.childNodes), getOuterHtml);
17669      applyDiff(diff(currentFragments, fragments), elm);
17670      return elm;
17671    };
17672
17673    const lazyTempDocument = cached(() => document.implementation.createHTMLDocument('undo'));
17674    const hasIframes = html => {
17675      return html.indexOf('</iframe>') !== -1;
17676    };
17677    const createFragmentedLevel = fragments => {
17678      return {
17679        type: 'fragmented',
17680        fragments,
17681        content: '',
17682        bookmark: null,
17683        beforeBookmark: null
17684      };
17685    };
17686    const createCompleteLevel = content => {
17687      return {
17688        type: 'complete',
17689        fragments: null,
17690        content,
17691        bookmark: null,
17692        beforeBookmark: null
17693      };
17694    };
17695    const createFromEditor = editor => {
17696      const fragments = read$2(editor.getBody());
17697      const trimmedFragments = bind$3(fragments, html => {
17698        const trimmed = trimInternal(editor.serializer, html);
17699        return trimmed.length > 0 ? [trimmed] : [];
17700      });
17701      const content = trimmedFragments.join('');
17702      return hasIframes(content) ? createFragmentedLevel(trimmedFragments) : createCompleteLevel(content);
17703    };
17704    const applyToEditor = (editor, level, before) => {
17705      const bookmark = before ? level.beforeBookmark : level.bookmark;
17706      if (level.type === 'fragmented') {
17707        write(level.fragments, editor.getBody());
17708      } else {
17709        editor.setContent(level.content, {
17710          format: 'raw',
17711          no_selection: isNonNullable(bookmark) && isPathBookmark(bookmark) ? !bookmark.isFakeCaret : true
17712        });
17713      }
17714      if (bookmark) {
17715        editor.selection.moveToBookmark(bookmark);
17716        editor.selection.scrollIntoView();
17717      }
17718    };
17719    const getLevelContent = level => {
17720      return level.type === 'fragmented' ? level.fragments.join('') : level.content;
17721    };
17722    const getCleanLevelContent = level => {
17723      const elm = SugarElement.fromTag('body', lazyTempDocument());
17724      set$1(elm, getLevelContent(level));
17725      each$e(descendants(elm, '*[data-mce-bogus]'), unwrap);
17726      return get$6(elm);
17727    };
17728    const hasEqualContent = (level1, level2) => getLevelContent(level1) === getLevelContent(level2);
17729    const hasEqualCleanedContent = (level1, level2) => getCleanLevelContent(level1) === getCleanLevelContent(level2);
17730    const isEq$1 = (level1, level2) => {
17731      if (!level1 || !level2) {
17732        return false;
17733      } else if (hasEqualContent(level1, level2)) {
17734        return true;
17735      } else {
17736        return hasEqualCleanedContent(level1, level2);
17737      }
17738    };
17739
17740    const isUnlocked = locks => locks.get() === 0;
17741
17742    const setTyping = (undoManager, typing, locks) => {
17743      if (isUnlocked(locks)) {
17744        undoManager.typing = typing;
17745      }
17746    };
17747    const endTyping = (undoManager, locks) => {
17748      if (undoManager.typing) {
17749        setTyping(undoManager, false, locks);
17750        undoManager.add();
17751      }
17752    };
17753    const endTypingLevelIgnoreLocks = undoManager => {
17754      if (undoManager.typing) {
17755        undoManager.typing = false;
17756        undoManager.add();
17757      }
17758    };
17759
17760    const beforeChange$1 = (editor, locks, beforeBookmark) => {
17761      if (isUnlocked(locks)) {
17762        beforeBookmark.set(getUndoBookmark(editor.selection));
17763      }
17764    };
17765    const addUndoLevel$1 = (editor, undoManager, index, locks, beforeBookmark, level, event) => {
17766      const currentLevel = createFromEditor(editor);
17767      const newLevel = Tools.extend(level || {}, currentLevel);
17768      if (!isUnlocked(locks) || editor.removed) {
17769        return null;
17770      }
17771      const lastLevel = undoManager.data[index.get()];
17772      if (editor.dispatch('BeforeAddUndo', {
17773          level: newLevel,
17774          lastLevel,
17775          originalEvent: event
17776        }).isDefaultPrevented()) {
17777        return null;
17778      }
17779      if (lastLevel && isEq$1(lastLevel, newLevel)) {
17780        return null;
17781      }
17782      if (undoManager.data[index.get()]) {
17783        beforeBookmark.get().each(bm => {
17784          undoManager.data[index.get()].beforeBookmark = bm;
17785        });
17786      }
17787      const customUndoRedoLevels = getCustomUndoRedoLevels(editor);
17788      if (customUndoRedoLevels) {
17789        if (undoManager.data.length > customUndoRedoLevels) {
17790          for (let i = 0; i < undoManager.data.length - 1; i++) {
17791            undoManager.data[i] = undoManager.data[i + 1];
17792          }
17793          undoManager.data.length--;
17794          index.set(undoManager.data.length);
17795        }
17796      }
17797      newLevel.bookmark = getUndoBookmark(editor.selection);
17798      if (index.get() < undoManager.data.length - 1) {
17799        undoManager.data.length = index.get() + 1;
17800      }
17801      undoManager.data.push(newLevel);
17802      index.set(undoManager.data.length - 1);
17803      const args = {
17804        level: newLevel,
17805        lastLevel,
17806        originalEvent: event
17807      };
17808      if (index.get() > 0) {
17809        editor.setDirty(true);
17810        editor.dispatch('AddUndo', args);
17811        editor.dispatch('change', args);
17812      } else {
17813        editor.dispatch('AddUndo', args);
17814      }
17815      return newLevel;
17816    };
17817    const clear$1 = (editor, undoManager, index) => {
17818      undoManager.data = [];
17819      index.set(0);
17820      undoManager.typing = false;
17821      editor.dispatch('ClearUndos');
17822    };
17823    const extra$1 = (editor, undoManager, index, callback1, callback2) => {
17824      if (undoManager.transact(callback1)) {
17825        const bookmark = undoManager.data[index.get()].bookmark;
17826        const lastLevel = undoManager.data[index.get() - 1];
17827        applyToEditor(editor, lastLevel, true);
17828        if (undoManager.transact(callback2)) {
17829          undoManager.data[index.get() - 1].beforeBookmark = bookmark;
17830        }
17831      }
17832    };
17833    const redo$1 = (editor, index, data) => {
17834      let level;
17835      if (index.get() < data.length - 1) {
17836        index.set(index.get() + 1);
17837        level = data[index.get()];
17838        applyToEditor(editor, level, false);
17839        editor.setDirty(true);
17840        editor.dispatch('Redo', { level });
17841      }
17842      return level;
17843    };
17844    const undo$1 = (editor, undoManager, locks, index) => {
17845      let level;
17846      if (undoManager.typing) {
17847        undoManager.add();
17848        undoManager.typing = false;
17849        setTyping(undoManager, false, locks);
17850      }
17851      if (index.get() > 0) {
17852        index.set(index.get() - 1);
17853        level = undoManager.data[index.get()];
17854        applyToEditor(editor, level, true);
17855        editor.setDirty(true);
17856        editor.dispatch('Undo', { level });
17857      }
17858      return level;
17859    };
17860    const reset$1 = undoManager => {
17861      undoManager.clear();
17862      undoManager.add();
17863    };
17864    const hasUndo$1 = (editor, undoManager, index) => index.get() > 0 || undoManager.typing && undoManager.data[0] && !isEq$1(createFromEditor(editor), undoManager.data[0]);
17865    const hasRedo$1 = (undoManager, index) => index.get() < undoManager.data.length - 1 && !undoManager.typing;
17866    const transact$1 = (undoManager, locks, callback) => {
17867      endTyping(undoManager, locks);
17868      undoManager.beforeChange();
17869      undoManager.ignore(callback);
17870      return undoManager.add();
17871    };
17872    const ignore$1 = (locks, callback) => {
17873      try {
17874        locks.set(locks.get() + 1);
17875        callback();
17876      } finally {
17877        locks.set(locks.get() - 1);
17878      }
17879    };
17880
17881    const addVisualInternal = (editor, elm) => {
17882      const dom = editor.dom;
17883      const scope = isNonNullable(elm) ? elm : editor.getBody();
17884      each$e(dom.select('table,a', scope), matchedElm => {
17885        switch (matchedElm.nodeName) {
17886        case 'TABLE':
17887          const cls = getVisualAidsTableClass(editor);
17888          const value = dom.getAttrib(matchedElm, 'border');
17889          if ((!value || value === '0') && editor.hasVisual) {
17890            dom.addClass(matchedElm, cls);
17891          } else {
17892            dom.removeClass(matchedElm, cls);
17893          }
17894          break;
17895        case 'A':
17896          if (!dom.getAttrib(matchedElm, 'href')) {
17897            const value = dom.getAttrib(matchedElm, 'name') || matchedElm.id;
17898            const cls = getVisualAidsAnchorClass(editor);
17899            if (value && editor.hasVisual) {
17900              dom.addClass(matchedElm, cls);
17901            } else {
17902              dom.removeClass(matchedElm, cls);
17903            }
17904          }
17905          break;
17906        }
17907      });
17908      editor.dispatch('VisualAid', {
17909        element: elm,
17910        hasVisual: editor.hasVisual
17911      });
17912    };
17913
17914    const makePlainAdaptor = editor => ({
17915      init: { bindEvents: noop },
17916      undoManager: {
17917        beforeChange: (locks, beforeBookmark) => beforeChange$1(editor, locks, beforeBookmark),
17918        add: (undoManager, index, locks, beforeBookmark, level, event) => addUndoLevel$1(editor, undoManager, index, locks, beforeBookmark, level, event),
17919        undo: (undoManager, locks, index) => undo$1(editor, undoManager, locks, index),
17920        redo: (index, data) => redo$1(editor, index, data),
17921        clear: (undoManager, index) => clear$1(editor, undoManager, index),
17922        reset: undoManager => reset$1(undoManager),
17923        hasUndo: (undoManager, index) => hasUndo$1(editor, undoManager, index),
17924        hasRedo: (undoManager, index) => hasRedo$1(undoManager, index),
17925        transact: (undoManager, locks, callback) => transact$1(undoManager, locks, callback),
17926        ignore: (locks, callback) => ignore$1(locks, callback),
17927        extra: (undoManager, index, callback1, callback2) => extra$1(editor, undoManager, index, callback1, callback2)
17928      },
17929      formatter: {
17930        match: (name, vars, node, similar) => match$2(editor, name, vars, node, similar),
17931        matchAll: (names, vars) => matchAll(editor, names, vars),
17932        matchNode: (node, name, vars, similar) => matchNode(editor, node, name, vars, similar),
17933        canApply: name => canApply(editor, name),
17934        closest: names => closest(editor, names),
17935        apply: (name, vars, node) => applyFormat$1(editor, name, vars, node),
17936        remove: (name, vars, node, similar) => removeFormat$1(editor, name, vars, node, similar),
17937        toggle: (name, vars, node) => toggle(editor, name, vars, node),
17938        formatChanged: (registeredFormatListeners, formats, callback, similar, vars) => formatChangedInternal(editor, registeredFormatListeners, formats, callback, similar, vars)
17939      },
17940      editor: {
17941        getContent: args => getContentInternal(editor, args),
17942        setContent: (content, args) => setContentInternal(editor, content, args),
17943        insertContent: (value, details) => insertHtmlAtCaret(editor, value, details),
17944        addVisual: elm => addVisualInternal(editor, elm)
17945      },
17946      selection: { getContent: (format, args) => getSelectedContentInternal(editor, format, args) },
17947      autocompleter: {
17948        addDecoration: range => create$9(editor, range),
17949        removeDecoration: () => remove$2(editor, SugarElement.fromDom(editor.getBody()))
17950      },
17951      raw: { getModel: () => Optional.none() }
17952    });
17953    const makeRtcAdaptor = rtcEditor => {
17954      const defaultVars = vars => isObject(vars) ? vars : {};
17955      const {init, undoManager, formatter, editor, selection, autocompleter, raw} = rtcEditor;
17956      return {
17957        init: { bindEvents: init.bindEvents },
17958        undoManager: {
17959          beforeChange: undoManager.beforeChange,
17960          add: undoManager.add,
17961          undo: undoManager.undo,
17962          redo: undoManager.redo,
17963          clear: undoManager.clear,
17964          reset: undoManager.reset,
17965          hasUndo: undoManager.hasUndo,
17966          hasRedo: undoManager.hasRedo,
17967          transact: (_undoManager, _locks, fn) => undoManager.transact(fn),
17968          ignore: (_locks, callback) => undoManager.ignore(callback),
17969          extra: (_undoManager, _index, callback1, callback2) => undoManager.extra(callback1, callback2)
17970        },
17971        formatter: {
17972          match: (name, vars, _node, similar) => formatter.match(name, defaultVars(vars), similar),
17973          matchAll: formatter.matchAll,
17974          matchNode: formatter.matchNode,
17975          canApply: name => formatter.canApply(name),
17976          closest: names => formatter.closest(names),
17977          apply: (name, vars, _node) => formatter.apply(name, defaultVars(vars)),
17978          remove: (name, vars, _node, _similar) => formatter.remove(name, defaultVars(vars)),
17979          toggle: (name, vars, _node) => formatter.toggle(name, defaultVars(vars)),
17980          formatChanged: (_rfl, formats, callback, similar, vars) => formatter.formatChanged(formats, callback, similar, vars)
17981        },
17982        editor: {
17983          getContent: args => editor.getContent(args),
17984          setContent: (content, args) => {
17985            return {
17986              content: editor.setContent(content, args),
17987              html: ''
17988            };
17989          },
17990          insertContent: (content, _details) => {
17991            editor.insertContent(content);
17992            return '';
17993          },
17994          addVisual: editor.addVisual
17995        },
17996        selection: { getContent: (_format, args) => selection.getContent(args) },
17997        autocompleter: {
17998          addDecoration: autocompleter.addDecoration,
17999          removeDecoration: autocompleter.removeDecoration
18000        },
18001        raw: { getModel: () => Optional.some(raw.getRawModel()) }
18002      };
18003    };
18004    const makeNoopAdaptor = () => {
18005      const nul = constant(null);
18006      const empty = constant('');
18007      return {
18008        init: { bindEvents: noop },
18009        undoManager: {
18010          beforeChange: noop,
18011          add: nul,
18012          undo: nul,
18013          redo: nul,
18014          clear: noop,
18015          reset: noop,
18016          hasUndo: never,
18017          hasRedo: never,
18018          transact: nul,
18019          ignore: noop,
18020          extra: noop
18021        },
18022        formatter: {
18023          match: never,
18024          matchAll: constant([]),
18025          matchNode: constant(undefined),
18026          canApply: never,
18027          closest: empty,
18028          apply: noop,
18029          remove: noop,
18030          toggle: noop,
18031          formatChanged: constant({ unbind: noop })
18032        },
18033        editor: {
18034          getContent: empty,
18035          setContent: constant({
18036            content: '',
18037            html: ''
18038          }),
18039          insertContent: constant(''),
18040          addVisual: noop
18041        },
18042        selection: { getContent: empty },
18043        autocompleter: {
18044          addDecoration: noop,
18045          removeDecoration: noop
18046        },
18047        raw: { getModel: constant(Optional.none()) }
18048      };
18049    };
18050    const isRtc = editor => has$2(editor.plugins, 'rtc');
18051    const getRtcSetup = editor => get$a(editor.plugins, 'rtc').bind(rtcPlugin => Optional.from(rtcPlugin.setup));
18052    const setup$s = editor => {
18053      const editorCast = editor;
18054      return getRtcSetup(editor).fold(() => {
18055        editorCast.rtcInstance = makePlainAdaptor(editor);
18056        return Optional.none();
18057      }, setup => {
18058        editorCast.rtcInstance = makeNoopAdaptor();
18059        return Optional.some(() => setup().then(rtcEditor => {
18060          editorCast.rtcInstance = makeRtcAdaptor(rtcEditor);
18061          return rtcEditor.rtc.isRemote;
18062        }));
18063      });
18064    };
18065    const getRtcInstanceWithFallback = editor => editor.rtcInstance ? editor.rtcInstance : makePlainAdaptor(editor);
18066    const getRtcInstanceWithError = editor => {
18067      const rtcInstance = editor.rtcInstance;
18068      if (!rtcInstance) {
18069        throw new Error('Failed to get RTC instance not yet initialized.');
18070      } else {
18071        return rtcInstance;
18072      }
18073    };
18074    const beforeChange = (editor, locks, beforeBookmark) => {
18075      getRtcInstanceWithError(editor).undoManager.beforeChange(locks, beforeBookmark);
18076    };
18077    const addUndoLevel = (editor, undoManager, index, locks, beforeBookmark, level, event) => getRtcInstanceWithError(editor).undoManager.add(undoManager, index, locks, beforeBookmark, level, event);
18078    const undo = (editor, undoManager, locks, index) => getRtcInstanceWithError(editor).undoManager.undo(undoManager, locks, index);
18079    const redo = (editor, index, data) => getRtcInstanceWithError(editor).undoManager.redo(index, data);
18080    const clear = (editor, undoManager, index) => {
18081      getRtcInstanceWithError(editor).undoManager.clear(undoManager, index);
18082    };
18083    const reset = (editor, undoManager) => {
18084      getRtcInstanceWithError(editor).undoManager.reset(undoManager);
18085    };
18086    const hasUndo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasUndo(undoManager, index);
18087    const hasRedo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasRedo(undoManager, index);
18088    const transact = (editor, undoManager, locks, callback) => getRtcInstanceWithError(editor).undoManager.transact(undoManager, locks, callback);
18089    const ignore = (editor, locks, callback) => {
18090      getRtcInstanceWithError(editor).undoManager.ignore(locks, callback);
18091    };
18092    const extra = (editor, undoManager, index, callback1, callback2) => {
18093      getRtcInstanceWithError(editor).undoManager.extra(undoManager, index, callback1, callback2);
18094    };
18095    const matchFormat = (editor, name, vars, node, similar) => getRtcInstanceWithError(editor).formatter.match(name, vars, node, similar);
18096    const matchAllFormats = (editor, names, vars) => getRtcInstanceWithError(editor).formatter.matchAll(names, vars);
18097    const matchNodeFormat = (editor, node, name, vars, similar) => getRtcInstanceWithError(editor).formatter.matchNode(node, name, vars, similar);
18098    const canApplyFormat = (editor, name) => getRtcInstanceWithError(editor).formatter.canApply(name);
18099    const closestFormat = (editor, names) => getRtcInstanceWithError(editor).formatter.closest(names);
18100    const applyFormat = (editor, name, vars, node) => {
18101      getRtcInstanceWithError(editor).formatter.apply(name, vars, node);
18102    };
18103    const removeFormat = (editor, name, vars, node, similar) => {
18104      getRtcInstanceWithError(editor).formatter.remove(name, vars, node, similar);
18105    };
18106    const toggleFormat = (editor, name, vars, node) => {
18107      getRtcInstanceWithError(editor).formatter.toggle(name, vars, node);
18108    };
18109    const formatChanged = (editor, registeredFormatListeners, formats, callback, similar, vars) => getRtcInstanceWithError(editor).formatter.formatChanged(registeredFormatListeners, formats, callback, similar, vars);
18110    const getContent$2 = (editor, args) => getRtcInstanceWithFallback(editor).editor.getContent(args);
18111    const setContent$2 = (editor, content, args) => getRtcInstanceWithFallback(editor).editor.setContent(content, args);
18112    const insertContent$1 = (editor, value, details) => getRtcInstanceWithFallback(editor).editor.insertContent(value, details);
18113    const getSelectedContent = (editor, format, args) => getRtcInstanceWithError(editor).selection.getContent(format, args);
18114    const addVisual$1 = (editor, elm) => getRtcInstanceWithError(editor).editor.addVisual(elm);
18115    const bindEvents = editor => getRtcInstanceWithError(editor).init.bindEvents();
18116    const addAutocompleterDecoration = (editor, range) => getRtcInstanceWithError(editor).autocompleter.addDecoration(range);
18117    const removeAutocompleterDecoration = editor => getRtcInstanceWithError(editor).autocompleter.removeDecoration();
18118
18119    const getContent$1 = (editor, args = {}) => {
18120      const format = args.format ? args.format : 'html';
18121      return getSelectedContent(editor, format, args);
18122    };
18123
18124    const removeEmpty = text => {
18125      if (text.dom.length === 0) {
18126        remove$5(text);
18127        return Optional.none();
18128      } else {
18129        return Optional.some(text);
18130      }
18131    };
18132    const walkPastBookmark = (node, start) => node.filter(elm => BookmarkManager.isBookmarkNode(elm.dom)).bind(start ? nextSibling : prevSibling);
18133    const merge$1 = (outer, inner, rng, start) => {
18134      const outerElm = outer.dom;
18135      const innerElm = inner.dom;
18136      const oldLength = start ? outerElm.length : innerElm.length;
18137      if (start) {
18138        mergeTextNodes(outerElm, innerElm, false, !start);
18139        rng.setStart(innerElm, oldLength);
18140      } else {
18141        mergeTextNodes(innerElm, outerElm, false, !start);
18142        rng.setEnd(innerElm, oldLength);
18143      }
18144    };
18145    const normalizeTextIfRequired = (inner, start) => {
18146      parent(inner).each(root => {
18147        const text = inner.dom;
18148        if (start && needsToBeNbspLeft(root, CaretPosition(text, 0))) {
18149          normalizeWhitespaceAfter(text, 0);
18150        } else if (!start && needsToBeNbspRight(root, CaretPosition(text, text.length))) {
18151          normalizeWhitespaceBefore(text, text.length);
18152        }
18153      });
18154    };
18155    const mergeAndNormalizeText = (outerNode, innerNode, rng, start) => {
18156      outerNode.bind(outer => {
18157        const normalizer = start ? normalizeWhitespaceBefore : normalizeWhitespaceAfter;
18158        normalizer(outer.dom, start ? outer.dom.length : 0);
18159        return innerNode.filter(isText$b).map(inner => merge$1(outer, inner, rng, start));
18160      }).orThunk(() => {
18161        const innerTextNode = walkPastBookmark(innerNode, start).or(innerNode).filter(isText$b);
18162        return innerTextNode.map(inner => normalizeTextIfRequired(inner, start));
18163      });
18164    };
18165    const rngSetContent = (rng, fragment) => {
18166      const firstChild = Optional.from(fragment.firstChild).map(SugarElement.fromDom);
18167      const lastChild = Optional.from(fragment.lastChild).map(SugarElement.fromDom);
18168      rng.deleteContents();
18169      rng.insertNode(fragment);
18170      const prevText = firstChild.bind(prevSibling).filter(isText$b).bind(removeEmpty);
18171      const nextText = lastChild.bind(nextSibling).filter(isText$b).bind(removeEmpty);
18172      mergeAndNormalizeText(prevText, firstChild, rng, true);
18173      mergeAndNormalizeText(nextText, lastChild, rng, false);
18174      rng.collapse(false);
18175    };
18176    const setupArgs$2 = (args, content) => ({
18177      format: 'html',
18178      ...args,
18179      set: true,
18180      selection: true,
18181      content
18182    });
18183    const cleanContent = (editor, args) => {
18184      if (args.format !== 'raw') {
18185        const rng = editor.selection.getRng();
18186        const contextBlock = editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock);
18187        const contextArgs = contextBlock ? { context: contextBlock.nodeName.toLowerCase() } : {};
18188        const node = editor.parser.parse(args.content, {
18189          forced_root_block: false,
18190          ...contextArgs,
18191          ...args
18192        });
18193        return HtmlSerializer({ validate: false }, editor.schema).serialize(node);
18194      } else {
18195        return args.content;
18196      }
18197    };
18198    const setContent$1 = (editor, content, args = {}) => {
18199      const defaultedArgs = setupArgs$2(args, content);
18200      preProcessSetContent(editor, defaultedArgs).each(updatedArgs => {
18201        const cleanedContent = cleanContent(editor, updatedArgs);
18202        const rng = editor.selection.getRng();
18203        rngSetContent(rng, rng.createContextualFragment(cleanedContent));
18204        editor.selection.setRng(rng);
18205        scrollRangeIntoView(editor, rng);
18206        postProcessSetContent(editor, cleanedContent, updatedArgs);
18207      });
18208    };
18209
18210    const deleteFromCallbackMap = (callbackMap, selector, callback) => {
18211      if (has$2(callbackMap, selector)) {
18212        const newCallbacks = filter$5(callbackMap[selector], cb => cb !== callback);
18213        if (newCallbacks.length === 0) {
18214          delete callbackMap[selector];
18215        } else {
18216          callbackMap[selector] = newCallbacks;
18217        }
18218      }
18219    };
18220    var SelectorChanged = (dom, editor) => {
18221      let selectorChangedData;
18222      let currentSelectors;
18223      const findMatchingNode = (selector, nodes) => find$2(nodes, node => dom.is(node, selector));
18224      const getParents = elem => dom.getParents(elem, undefined, dom.getRoot());
18225      const setup = () => {
18226        selectorChangedData = {};
18227        currentSelectors = {};
18228        editor.on('NodeChange', e => {
18229          const node = e.element;
18230          const parents = getParents(node);
18231          const matchedSelectors = {};
18232          each$d(selectorChangedData, (callbacks, selector) => {
18233            findMatchingNode(selector, parents).each(node => {
18234              if (!currentSelectors[selector]) {
18235                each$e(callbacks, callback => {
18236                  callback(true, {
18237                    node,
18238                    selector,
18239                    parents
18240                  });
18241                });
18242                currentSelectors[selector] = callbacks;
18243              }
18244              matchedSelectors[selector] = callbacks;
18245            });
18246          });
18247          each$d(currentSelectors, (callbacks, selector) => {
18248            if (!matchedSelectors[selector]) {
18249              delete currentSelectors[selector];
18250              each$e(callbacks, callback => {
18251                callback(false, {
18252                  node,
18253                  selector,
18254                  parents
18255                });
18256              });
18257            }
18258          });
18259        });
18260      };
18261      return {
18262        selectorChangedWithUnbind: (selector, callback) => {
18263          if (!selectorChangedData) {
18264            setup();
18265          }
18266          if (!selectorChangedData[selector]) {
18267            selectorChangedData[selector] = [];
18268          }
18269          selectorChangedData[selector].push(callback);
18270          findMatchingNode(selector, getParents(editor.selection.getStart())).each(() => {
18271            currentSelectors[selector] = selectorChangedData[selector];
18272          });
18273          return {
18274            unbind: () => {
18275              deleteFromCallbackMap(selectorChangedData, selector, callback);
18276              deleteFromCallbackMap(currentSelectors, selector, callback);
18277            }
18278          };
18279        }
18280      };
18281    };
18282
18283    const isAttachedToDom = node => {
18284      return !!(node && node.ownerDocument) && contains(SugarElement.fromDom(node.ownerDocument), SugarElement.fromDom(node));
18285    };
18286    const isValidRange = rng => {
18287      if (!rng) {
18288        return false;
18289      } else {
18290        return isAttachedToDom(rng.startContainer) && isAttachedToDom(rng.endContainer);
18291      }
18292    };
18293    const EditorSelection = (dom, win, serializer, editor) => {
18294      let selectedRange;
18295      let explicitRange;
18296      const {selectorChangedWithUnbind} = SelectorChanged(dom, editor);
18297      const setCursorLocation = (node, offset) => {
18298        const rng = dom.createRng();
18299        if (isNonNullable(node) && isNonNullable(offset)) {
18300          rng.setStart(node, offset);
18301          rng.setEnd(node, offset);
18302          setRng(rng);
18303          collapse(false);
18304        } else {
18305          moveEndPoint(dom, rng, editor.getBody(), true);
18306          setRng(rng);
18307        }
18308      };
18309      const getContent = args => getContent$1(editor, args);
18310      const setContent = (content, args) => setContent$1(editor, content, args);
18311      const getStart$1 = real => getStart(editor.getBody(), getRng$1(), real);
18312      const getEnd = real => getEnd$1(editor.getBody(), getRng$1(), real);
18313      const getBookmark = (type, normalized) => bookmarkManager.getBookmark(type, normalized);
18314      const moveToBookmark = bookmark => bookmarkManager.moveToBookmark(bookmark);
18315      const select$1 = (node, content) => {
18316        select(dom, node, content).each(setRng);
18317        return node;
18318      };
18319      const isCollapsed = () => {
18320        const rng = getRng$1(), sel = getSel();
18321        if (!rng || rng.item) {
18322          return false;
18323        }
18324        if (rng.compareEndPoints) {
18325          return rng.compareEndPoints('StartToEnd', rng) === 0;
18326        }
18327        return !sel || rng.collapsed;
18328      };
18329      const isEditable = () => {
18330        const rng = getRng$1();
18331        const fakeSelectedElements = editor.getBody().querySelectorAll('[data-mce-selected="1"]');
18332        if (fakeSelectedElements.length > 0) {
18333          return forall(fakeSelectedElements, el => dom.isEditable(el.parentElement));
18334        } else if (rng.startContainer === rng.endContainer) {
18335          return dom.isEditable(rng.startContainer);
18336        } else {
18337          return dom.isEditable(rng.startContainer) && dom.isEditable(rng.endContainer);
18338        }
18339      };
18340      const collapse = toStart => {
18341        const rng = getRng$1();
18342        rng.collapse(!!toStart);
18343        setRng(rng);
18344      };
18345      const getSel = () => win.getSelection ? win.getSelection() : win.document.selection;
18346      const getRng$1 = () => {
18347        let rng;
18348        const tryCompareBoundaryPoints = (how, sourceRange, destinationRange) => {
18349          try {
18350            return sourceRange.compareBoundaryPoints(how, destinationRange);
18351          } catch (ex) {
18352            return -1;
18353          }
18354        };
18355        const doc = win.document;
18356        if (isNonNullable(editor.bookmark) && !hasFocus(editor)) {
18357          const bookmark = getRng(editor);
18358          if (bookmark.isSome()) {
18359            return bookmark.map(r => processRanges(editor, [r])[0]).getOr(doc.createRange());
18360          }
18361        }
18362        try {
18363          const selection = getSel();
18364          if (selection && !isRestrictedNode(selection.anchorNode)) {
18365            if (selection.rangeCount > 0) {
18366              rng = selection.getRangeAt(0);
18367            } else {
18368              rng = doc.createRange();
18369            }
18370            rng = processRanges(editor, [rng])[0];
18371          }
18372        } catch (ex) {
18373        }
18374        if (!rng) {
18375          rng = doc.createRange();
18376        }
18377        if (isDocument$1(rng.startContainer) && rng.collapsed) {
18378          const elm = dom.getRoot();
18379          rng.setStart(elm, 0);
18380          rng.setEnd(elm, 0);
18381        }
18382        if (selectedRange && explicitRange) {
18383          if (tryCompareBoundaryPoints(rng.START_TO_START, rng, selectedRange) === 0 && tryCompareBoundaryPoints(rng.END_TO_END, rng, selectedRange) === 0) {
18384            rng = explicitRange;
18385          } else {
18386            selectedRange = null;
18387            explicitRange = null;
18388          }
18389        }
18390        return rng;
18391      };
18392      const setRng = (rng, forward) => {
18393        if (!isValidRange(rng)) {
18394          return;
18395        }
18396        const sel = getSel();
18397        const evt = editor.dispatch('SetSelectionRange', {
18398          range: rng,
18399          forward
18400        });
18401        rng = evt.range;
18402        if (sel) {
18403          explicitRange = rng;
18404          try {
18405            sel.removeAllRanges();
18406            sel.addRange(rng);
18407          } catch (ex) {
18408          }
18409          if (forward === false && sel.extend) {
18410            sel.collapse(rng.endContainer, rng.endOffset);
18411            sel.extend(rng.startContainer, rng.startOffset);
18412          }
18413          selectedRange = sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
18414        }
18415        if (!rng.collapsed && rng.startContainer === rng.endContainer && (sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent)) {
18416          if (rng.endOffset - rng.startOffset < 2) {
18417            if (rng.startContainer.hasChildNodes()) {
18418              const node = rng.startContainer.childNodes[rng.startOffset];
18419              if (node && node.nodeName === 'IMG') {
18420                sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset);
18421                if (sel.anchorNode !== rng.startContainer || sel.focusNode !== rng.endContainer) {
18422                  sel.setBaseAndExtent(node, 0, node, 1);
18423                }
18424              }
18425            }
18426          }
18427        }
18428        editor.dispatch('AfterSetSelectionRange', {
18429          range: rng,
18430          forward
18431        });
18432      };
18433      const setNode = elm => {
18434        setContent(dom.getOuterHTML(elm));
18435        return elm;
18436      };
18437      const getNode$1 = () => getNode(editor.getBody(), getRng$1());
18438      const getSelectedBlocks$1 = (startElm, endElm) => getSelectedBlocks(dom, getRng$1(), startElm, endElm);
18439      const isForward = () => {
18440        const sel = getSel();
18441        const anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
18442        const focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
18443        if (!sel || !anchorNode || !focusNode || isRestrictedNode(anchorNode) || isRestrictedNode(focusNode)) {
18444          return true;
18445        }
18446        const anchorRange = dom.createRng();
18447        const focusRange = dom.createRng();
18448        try {
18449          anchorRange.setStart(anchorNode, sel.anchorOffset);
18450          anchorRange.collapse(true);
18451          focusRange.setStart(focusNode, sel.focusOffset);
18452          focusRange.collapse(true);
18453        } catch (e) {
18454          return true;
18455        }
18456        return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
18457      };
18458      const normalize = () => {
18459        const rng = getRng$1();
18460        const sel = getSel();
18461        if (!hasMultipleRanges(sel) && hasAnyRanges(editor)) {
18462          const normRng = normalize$2(dom, rng);
18463          normRng.each(normRng => {
18464            setRng(normRng, isForward());
18465          });
18466          return normRng.getOr(rng);
18467        }
18468        return rng;
18469      };
18470      const selectorChanged = (selector, callback) => {
18471        selectorChangedWithUnbind(selector, callback);
18472        return exports;
18473      };
18474      const getScrollContainer = () => {
18475        let scrollContainer;
18476        let node = dom.getRoot();
18477        while (node && node.nodeName !== 'BODY') {
18478          if (node.scrollHeight > node.clientHeight) {
18479            scrollContainer = node;
18480            break;
18481          }
18482          node = node.parentNode;
18483        }
18484        return scrollContainer;
18485      };
18486      const scrollIntoView = (elm, alignToTop) => {
18487        if (isNonNullable(elm)) {
18488          scrollElementIntoView(editor, elm, alignToTop);
18489        } else {
18490          scrollRangeIntoView(editor, getRng$1(), alignToTop);
18491        }
18492      };
18493      const placeCaretAt = (clientX, clientY) => setRng(fromPoint(clientX, clientY, editor.getDoc()));
18494      const getBoundingClientRect = () => {
18495        const rng = getRng$1();
18496        return rng.collapsed ? CaretPosition.fromRangeStart(rng).getClientRects()[0] : rng.getBoundingClientRect();
18497      };
18498      const destroy = () => {
18499        win = selectedRange = explicitRange = null;
18500        controlSelection.destroy();
18501      };
18502      const expand = (options = { type: 'word' }) => setRng(RangeUtils(dom).expand(getRng$1(), options));
18503      const exports = {
18504        dom,
18505        win,
18506        serializer,
18507        editor,
18508        expand,
18509        collapse,
18510        setCursorLocation,
18511        getContent,
18512        setContent,
18513        getBookmark,
18514        moveToBookmark,
18515        select: select$1,
18516        isCollapsed,
18517        isEditable,
18518        isForward,
18519        setNode,
18520        getNode: getNode$1,
18521        getSel,
18522        setRng,
18523        getRng: getRng$1,
18524        getStart: getStart$1,
18525        getEnd,
18526        getSelectedBlocks: getSelectedBlocks$1,
18527        normalize,
18528        selectorChanged,
18529        selectorChangedWithUnbind,
18530        getScrollContainer,
18531        scrollIntoView,
18532        placeCaretAt,
18533        getBoundingClientRect,
18534        destroy
18535      };
18536      const bookmarkManager = BookmarkManager(exports);
18537      const controlSelection = ControlSelection(exports, editor);
18538      exports.bookmarkManager = bookmarkManager;
18539      exports.controlSelection = controlSelection;
18540      return exports;
18541    };
18542
18543    const register$3 = (htmlParser, settings, dom) => {
18544      htmlParser.addAttributeFilter('data-mce-tabindex', (nodes, name) => {
18545        let i = nodes.length;
18546        while (i--) {
18547          const node = nodes[i];
18548          node.attr('tabindex', node.attr('data-mce-tabindex'));
18549          node.attr(name, null);
18550        }
18551      });
18552      htmlParser.addAttributeFilter('src,href,style', (nodes, name) => {
18553        const internalName = 'data-mce-' + name;
18554        const urlConverter = settings.url_converter;
18555        const urlConverterScope = settings.url_converter_scope;
18556        let i = nodes.length;
18557        while (i--) {
18558          const node = nodes[i];
18559          let value = node.attr(internalName);
18560          if (value !== undefined) {
18561            node.attr(name, value.length > 0 ? value : null);
18562            node.attr(internalName, null);
18563          } else {
18564            value = node.attr(name);
18565            if (name === 'style') {
18566              value = dom.serializeStyle(dom.parseStyle(value), node.name);
18567            } else if (urlConverter) {
18568              value = urlConverter.call(urlConverterScope, value, name, node.name);
18569            }
18570            node.attr(name, value.length > 0 ? value : null);
18571          }
18572        }
18573      });
18574      htmlParser.addAttributeFilter('class', nodes => {
18575        let i = nodes.length;
18576        while (i--) {
18577          const node = nodes[i];
18578          let value = node.attr('class');
18579          if (value) {
18580            value = value.replace(/(?:^|\s)mce-item-\w+(?!\S)/g, '');
18581            node.attr('class', value.length > 0 ? value : null);
18582          }
18583        }
18584      });
18585      htmlParser.addAttributeFilter('data-mce-type', (nodes, name, args) => {
18586        let i = nodes.length;
18587        while (i--) {
18588          const node = nodes[i];
18589          if (node.attr('data-mce-type') === 'bookmark' && !args.cleanup) {
18590            const hasChildren = Optional.from(node.firstChild).exists(firstChild => {
18591              var _a;
18592              return !isZwsp$1((_a = firstChild.value) !== null && _a !== void 0 ? _a : '');
18593            });
18594            if (hasChildren) {
18595              node.unwrap();
18596            } else {
18597              node.remove();
18598            }
18599          }
18600        }
18601      });
18602      htmlParser.addNodeFilter('noscript', nodes => {
18603        var _a;
18604        let i = nodes.length;
18605        while (i--) {
18606          const node = nodes[i].firstChild;
18607          if (node) {
18608            node.value = Entities.decode((_a = node.value) !== null && _a !== void 0 ? _a : '');
18609          }
18610        }
18611      });
18612      htmlParser.addNodeFilter('script,style', (nodes, name) => {
18613        var _a;
18614        const trim = value => {
18615          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, '');
18616        };
18617        let i = nodes.length;
18618        while (i--) {
18619          const node = nodes[i];
18620          const firstChild = node.firstChild;
18621          const value = (_a = firstChild === null || firstChild === void 0 ? void 0 : firstChild.value) !== null && _a !== void 0 ? _a : '';
18622          if (name === 'script') {
18623            const type = node.attr('type');
18624            if (type) {
18625              node.attr('type', type === 'mce-no/type' ? null : type.replace(/^mce\-/, ''));
18626            }
18627            if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
18628              firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
18629            }
18630          } else {
18631            if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
18632              firstChild.value = '<!--\n' + trim(value) + '\n-->';
18633            }
18634          }
18635        }
18636      });
18637      htmlParser.addNodeFilter('#comment', nodes => {
18638        let i = nodes.length;
18639        while (i--) {
18640          const node = nodes[i];
18641          const value = node.value;
18642          if (settings.preserve_cdata && (value === null || value === void 0 ? void 0 : value.indexOf('[CDATA[')) === 0) {
18643            node.name = '#cdata';
18644            node.type = 4;
18645            node.value = dom.decode(value.replace(/^\[CDATA\[|\]\]$/g, ''));
18646          } else if ((value === null || value === void 0 ? void 0 : value.indexOf('mce:protected ')) === 0) {
18647            node.name = '#text';
18648            node.type = 3;
18649            node.raw = true;
18650            node.value = unescape(value).substr(14);
18651          }
18652        }
18653      });
18654      htmlParser.addNodeFilter('xml:namespace,input', (nodes, name) => {
18655        let i = nodes.length;
18656        while (i--) {
18657          const node = nodes[i];
18658          if (node.type === 7) {
18659            node.remove();
18660          } else if (node.type === 1) {
18661            if (name === 'input' && !node.attr('type')) {
18662              node.attr('type', 'text');
18663            }
18664          }
18665        }
18666      });
18667      htmlParser.addAttributeFilter('data-mce-type', nodes => {
18668        each$e(nodes, node => {
18669          if (node.attr('data-mce-type') === 'format-caret') {
18670            if (node.isEmpty(htmlParser.schema.getNonEmptyElements())) {
18671              node.remove();
18672            } else {
18673              node.unwrap();
18674            }
18675          }
18676        });
18677      });
18678      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) => {
18679        let i = nodes.length;
18680        while (i--) {
18681          nodes[i].attr(name, null);
18682        }
18683      });
18684      if (settings.remove_trailing_brs) {
18685        addNodeFilter(
vendor: 2,413 bytes, lines 18685-18761
18685settings, htmlParser, htmlParser.schema);
18686      }
18687    };
18688    const trimTrailingBr = rootNode => {
18689      const isBr = node => {
18690        return (node === null || node === void 0 ? void 0 : node.name) === 'br';
18691      };
18692      const brNode1 = rootNode.lastChild;
18693      if (isBr(brNode1)) {
18694        const brNode2 = brNode1.prev;
18695        if (isBr(brNode2)) {
18696          brNode1.remove();
18697          brNode2.remove();
18698        }
18699      }
18700    };
18701
18702    const preProcess$1 = (editor, node, args) => {
18703      let oldDoc;
18704      const dom = editor.dom;
18705      let clonedNode = node.cloneNode(true);
18706      const impl = document.implementation;
18707      if (impl.createHTMLDocument) {
18708        const doc = impl.createHTMLDocument('');
18709        Tools.each(clonedNode.nodeName === 'BODY' ? clonedNode.childNodes : [clonedNode], node => {
18710          doc.body.appendChild(doc.importNode(node, true));
18711        });
18712        if (clonedNode.nodeName !== 'BODY') {
18713          clonedNode = doc.body.firstChild;
18714        } else {
18715          clonedNode = doc.body;
18716        }
18717        oldDoc = dom.doc;
18718        dom.doc = doc;
18719      }
18720      firePreProcess(editor, {
18721        ...args,
18722        node: clonedNode
18723      });
18724      if (oldDoc) {
18725        dom.doc = oldDoc;
18726      }
18727      return clonedNode;
18728    };
18729    const shouldFireEvent = (editor, args) => {
18730      return isNonNullable(editor) && editor.hasEventListeners('PreProcess') && !args.no_events;
18731    };
18732    const process$1 = (editor, node, args) => {
18733      return shouldFireEvent(editor, args) ? preProcess$1(editor, node, args) : node;
18734    };
18735
18736    const addTempAttr = (htmlParser, tempAttrs, name) => {
18737      if (Tools.inArray(tempAttrs, name) === -1) {
18738        htmlParser.addAttributeFilter(name, (nodes, name) => {
18739          let i = nodes.length;
18740          while (i--) {
18741            nodes[i].attr(name, null);
18742          }
18743        });
18744        tempAttrs.push(name);
18745      }
18746    };
18747    const postProcess = (editor, args, content) => {
18748      if (!args.no_events && editor) {
18749        const outArgs = firePostProcess(editor, {
18750          ...args,
18751          content
18752        });
18753        return outArgs.content;
18754      } else {
18755        return content;
18756      }
18757    };
18758    const getHtmlFromNode = (dom, node, args) => {
18759      const html = trim$1(args.getInner ? node.innerHTML : dom.getOuterHTML(node));
18760      return args.selection || isWsPreserveElement(SugarElement.fromDom(node)) ? html : Tools.trim(html);
18761    };
18762    const parseHtml = (htmlParser, html, args) => {
18763      const parserArgs = args.selection ? {
18764        forced_root_block: false,
18765        ...args
18766      } : args;
18767      const rootNode = htmlParser.parse(html, parserArgs);
18768      trimTrailingBr(rootNode);
18769      return rootNode;
18770    };
18771    const serializeNode = (settings, schema, node) => {
18772      const htmlSerializer = HtmlSerializer(settings, schema);
18773      return htmlSerializer.serialize(node);
18774    };
18775    const toHtml = (editor, settings, schema, rootNode, args) => {
18776      const content = serializeNode(settings, schema, rootNode);
18777      return postProcess(editor, args, content);
18778    };
18779    const DomSerializerImpl = (settings, editor) => {
18780      const tempAttrs = ['data-mce-selected'];
18781      const defaultedSettings = {
18782        entity_encoding: 'named',
18783        remove_trailing_brs: true,
18784        pad_empty_with_br: fals
vendor: 365,104 bytes, lines 18784-28055
18784e,
18785        ...settings
18786      };
18787      const dom = editor && editor.dom ? editor.dom : DOMUtils.DOM;
18788      const schema = editor && editor.schema ? editor.schema : Schema(defaultedSettings);
18789      const htmlParser = DomParser(defaultedSettings, schema);
18790      register$3(htmlParser, defaultedSettings, dom);
18791      const serialize = (node, parserArgs = {}) => {
18792        const args = {
18793          format: 'html',
18794          ...parserArgs
18795        };
18796        const targetNode = process$1(editor, node, args);
18797        const html = getHtmlFromNode(dom, targetNode, args);
18798        const rootNode = parseHtml(htmlParser, html, args);
18799        return args.format === 'tree' ? rootNode : toHtml(editor, defaultedSettings, schema, rootNode, args);
18800      };
18801      return {
18802        schema,
18803        addNodeFilter: htmlParser.addNodeFilter,
18804        addAttributeFilter: htmlParser.addAttributeFilter,
18805        serialize: serialize,
18806        addRules: schema.addValidElements,
18807        setRules: schema.setValidElements,
18808        addTempAttr: curry(addTempAttr, htmlParser, tempAttrs),
18809        getTempAttrs: constant(tempAttrs),
18810        getNodeFilters: htmlParser.getNodeFilters,
18811        getAttributeFilters: htmlParser.getAttributeFilters,
18812        removeNodeFilter: htmlParser.removeNodeFilter,
18813        removeAttributeFilter: htmlParser.removeAttributeFilter
18814      };
18815    };
18816
18817    const DomSerializer = (settings, editor) => {
18818      const domSerializer = DomSerializerImpl(settings, editor);
18819      return {
18820        schema: domSerializer.schema,
18821        addNodeFilter: domSerializer.addNodeFilter,
18822        addAttributeFilter: domSerializer.addAttributeFilter,
18823        serialize: domSerializer.serialize,
18824        addRules: domSerializer.addRules,
18825        setRules: domSerializer.setRules,
18826        addTempAttr: domSerializer.addTempAttr,
18827        getTempAttrs: domSerializer.getTempAttrs,
18828        getNodeFilters: domSerializer.getNodeFilters,
18829        getAttributeFilters: domSerializer.getAttributeFilters,
18830        removeNodeFilter: domSerializer.removeNodeFilter,
18831        removeAttributeFilter: domSerializer.removeAttributeFilter
18832      };
18833    };
18834
18835    const defaultFormat$1 = 'html';
18836    const setupArgs$1 = (args, format) => ({
18837      ...args,
18838      format,
18839      get: true,
18840      getInner: true
18841    });
18842    const getContent = (editor, args = {}) => {
18843      const format = args.format ? args.format : defaultFormat$1;
18844      const defaultedArgs = setupArgs$1(args, format);
18845      return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
18846        const content = getContent$2(editor, updatedArgs);
18847        return postProcessGetContent(editor, content, updatedArgs);
18848      });
18849    };
18850
18851    const defaultFormat = 'html';
18852    const setupArgs = (args, content) => ({
18853      format: defaultFormat,
18854      ...args,
18855      set: true,
18856      content
18857    });
18858    const setContent = (editor, content, args = {}) => {
18859      const defaultedArgs = setupArgs(args, content);
18860      return preProcessSetContent(editor, defaultedArgs).map(updatedArgs => {
18861        const result = setContent$2(editor, updatedArgs.content, updatedArgs);
18862        postProcessSetContent(editor, result.html, updatedArgs);
18863        return result.content;
18864      }).getOr(content);
18865    };
18866
18867    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').split(',');
18868    const deprecatedOptions = '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(',');
18869    const removedPlugins = 'bbcode,colorpicker,contextmenu,fullpage,legacyoutput,spellchecker,textcolor'.split(',');
18870    const deprecatedPlugins = [
18871      {
18872        name: 'template',
18873        replacedWith: 'Advanced Template'
18874      },
18875      { name: 'rtc' }
18876    ];
18877    const getMatchingOptions = (options, searchingFor) => {
18878      const settingNames = filter$5(searchingFor, setting => has$2(options, setting));
18879      return sort(settingNames);
18880    };
18881    const getRemovedOptions = options => {
18882      const settingNames = getMatchingOptions(options, removedOptions);
18883      const forcedRootBlock = options.forced_root_block;
18884      if (forcedRootBlock === false || forcedRootBlock === '') {
18885        settingNames.push('forced_root_block (false only)');
18886      }
18887      return sort(settingNames);
18888    };
18889    const getDeprecatedOptions = options => getMatchingOptions(options, deprecatedOptions);
18890    const getMatchingPlugins = (options, searchingFor) => {
18891      const plugins = Tools.makeMap(options.plugins, ' ');
18892      const hasPlugin = plugin => has$2(plugins, plugin);
18893      const pluginNames = filter$5(searchingFor, hasPlugin);
18894      return sort(pluginNames);
18895    };
18896    const getRemovedPlugins = options => getMatchingPlugins(options, removedPlugins);
18897    const getDeprecatedPlugins = options => getMatchingPlugins(options, deprecatedPlugins.map(entry => entry.name));
18898    const logRemovedWarnings = (rawOptions, normalizedOptions) => {
18899      const removedOptions = getRemovedOptions(rawOptions);
18900      const removedPlugins = getRemovedPlugins(normalizedOptions);
18901      const hasRemovedPlugins = removedPlugins.length > 0;
18902      const hasRemovedOptions = removedOptions.length > 0;
18903      const isLegacyMobileTheme = normalizedOptions.theme === 'mobile';
18904      if (hasRemovedPlugins || hasRemovedOptions || isLegacyMobileTheme) {
18905        const listJoiner = '\n- ';
18906        const themesMessage = isLegacyMobileTheme ? `\n\nThemes:${ listJoiner }mobile` : '';
18907        const pluginsMessage = hasRemovedPlugins ? `\n\nPlugins:${ listJoiner }${ removedPlugins.join(listJoiner) }` : '';
18908        const optionsMessage = hasRemovedOptions ? `\n\nOptions:${ listJoiner }${ removedOptions.join(listJoiner) }` : '';
18909        console.warn('The following deprecated features are currently enabled and have been removed in TinyMCE 6.0. These features will no longer work and should be removed from the TinyMCE configuration. ' + 'See https://www.tiny.cloud/docs/tinymce/6/migration-from-5x/ for more information.' + themesMessage + pluginsMessage + optionsMessage);
18910      }
18911    };
18912    const getPluginDescription = name => find$2(deprecatedPlugins, entry => entry.name === name).fold(() => name, entry => {
18913      if (entry.replacedWith) {
18914        return `${ name }, replaced by ${ entry.replacedWith }`;
18915      } else {
18916        return name;
18917      }
18918    });
18919    const logDeprecatedWarnings = (rawOptions, normalizedOptions) => {
18920      const deprecatedOptions = getDeprecatedOptions(rawOptions);
18921      const deprecatedPlugins = getDeprecatedPlugins(normalizedOptions);
18922      const hasDeprecatedPlugins = deprecatedPlugins.length > 0;
18923      const hasDeprecatedOptions = deprecatedOptions.length > 0;
18924      if (hasDeprecatedPlugins || hasDeprecatedOptions) {
18925        const listJoiner = '\n- ';
18926        const pluginsMessage = hasDeprecatedPlugins ? `\n\nPlugins:${ listJoiner }${ deprecatedPlugins.map(getPluginDescription).join(listJoiner) }` : '';
18927        const optionsMessage = hasDeprecatedOptions ? `\n\nOptions:${ listJoiner }${ deprecatedOptions.join(listJoiner) }` : '';
18928        console.warn('The following deprecated features are currently enabled but will be removed soon.' + pluginsMessage + optionsMessage);
18929      }
18930    };
18931    const logWarnings = (rawOptions, normalizedOptions) => {
18932      logRemovedWarnings(rawOptions, normalizedOptions);
18933      logDeprecatedWarnings(rawOptions, normalizedOptions);
18934    };
18935
18936    const DOM$8 = DOMUtils.DOM;
18937    const restoreOriginalStyles = editor => {
18938      DOM$8.setStyle(editor.id, 'display', editor.orgDisplay);
18939    };
18940    const safeDestroy = x => Optional.from(x).each(x => x.destroy());
18941    const clearDomReferences = editor => {
18942      const ed = editor;
18943      ed.contentAreaContainer = ed.formElement = ed.container = ed.editorContainer = null;
18944      ed.bodyElement = ed.contentDocument = ed.contentWindow = null;
18945      ed.iframeElement = ed.targetElm = null;
18946      const selection = editor.selection;
18947      if (selection) {
18948        const dom = selection.dom;
18949        ed.selection = selection.win = selection.dom = dom.doc = null;
18950      }
18951    };
18952    const restoreForm = editor => {
18953      const form = editor.formElement;
18954      if (form) {
18955        if (form._mceOldSubmit) {
18956          form.submit = form._mceOldSubmit;
18957          delete form._mceOldSubmit;
18958        }
18959        DOM$8.unbind(form, 'submit reset', editor.formEventDelegate);
18960      }
18961    };
18962    const remove$1 = editor => {
18963      if (!editor.removed) {
18964        const {_selectionOverrides, editorUpload} = editor;
18965        const body = editor.getBody();
18966        const element = editor.getElement();
18967        if (body) {
18968          editor.save({ is_removing: true });
18969        }
18970        editor.removed = true;
18971        editor.unbindAllNativeEvents();
18972        if (editor.hasHiddenInput && isNonNullable(element === null || element === void 0 ? void 0 : element.nextSibling)) {
18973          DOM$8.remove(element.nextSibling);
18974        }
18975        fireRemove(editor);
18976        editor.editorManager.remove(editor);
18977        if (!editor.inline && body) {
18978          restoreOriginalStyles(editor);
18979        }
18980        fireDetach(editor);
18981        DOM$8.remove(editor.getContainer());
18982        safeDestroy(_selectionOverrides);
18983        safeDestroy(editorUpload);
18984        editor.destroy();
18985      }
18986    };
18987    const destroy = (editor, automatic) => {
18988      const {selection, dom} = editor;
18989      if (editor.destroyed) {
18990        return;
18991      }
18992      if (!automatic && !editor.removed) {
18993        editor.remove();
18994        return;
18995      }
18996      if (!automatic) {
18997        editor.editorManager.off('beforeunload', editor._beforeUnload);
18998        if (editor.theme && editor.theme.destroy) {
18999          editor.theme.destroy();
19000        }
19001        safeDestroy(selection);
19002        safeDestroy(dom);
19003      }
19004      restoreForm(editor);
19005      clearDomReferences(editor);
19006      editor.destroyed = true;
19007    };
19008
19009    const CreateIconManager = () => {
19010      const lookup = {};
19011      const add = (id, iconPack) => {
19012        lookup[id] = iconPack;
19013      };
19014      const get = id => {
19015        if (lookup[id]) {
19016          return lookup[id];
19017        } else {
19018          return { icons: {} };
19019        }
19020      };
19021      const has = id => has$2(lookup, id);
19022      return {
19023        add,
19024        get,
19025        has
19026      };
19027    };
19028    const IconManager = CreateIconManager();
19029
19030    const ModelManager = AddOnManager.ModelManager;
19031
19032    const getProp = (propName, elm) => {
19033      const rawElm = elm.dom;
19034      return rawElm[propName];
19035    };
19036    const getComputedSizeProp = (propName, elm) => parseInt(get$7(elm, propName), 10);
19037    const getClientWidth = curry(getProp, 'clientWidth');
19038    const getClientHeight = curry(getProp, 'clientHeight');
19039    const getMarginTop = curry(getComputedSizeProp, 'margin-top');
19040    const getMarginLeft = curry(getComputedSizeProp, 'margin-left');
19041    const getBoundingClientRect = elm => elm.dom.getBoundingClientRect();
19042    const isInsideElementContentArea = (bodyElm, clientX, clientY) => {
19043      const clientWidth = getClientWidth(bodyElm);
19044      const clientHeight = getClientHeight(bodyElm);
19045      return clientX >= 0 && clientY >= 0 && clientX <= clientWidth && clientY <= clientHeight;
19046    };
19047    const transpose = (inline, elm, clientX, clientY) => {
19048      const clientRect = getBoundingClientRect(elm);
19049      const deltaX = inline ? clientRect.left + elm.dom.clientLeft + getMarginLeft(elm) : 0;
19050      const deltaY = inline ? clientRect.top + elm.dom.clientTop + getMarginTop(elm) : 0;
19051      const x = clientX - deltaX;
19052      const y = clientY - deltaY;
19053      return {
19054        x,
19055        y
19056      };
19057    };
19058    const isXYInContentArea = (editor, clientX, clientY) => {
19059      const bodyElm = SugarElement.fromDom(editor.getBody());
19060      const targetElm = editor.inline ? bodyElm : documentElement(bodyElm);
19061      const transposedPoint = transpose(editor.inline, targetElm, clientX, clientY);
19062      return isInsideElementContentArea(targetElm, transposedPoint.x, transposedPoint.y);
19063    };
19064    const fromDomSafe = node => Optional.from(node).map(SugarElement.fromDom);
19065    const isEditorAttachedToDom = editor => {
19066      const rawContainer = editor.inline ? editor.getBody() : editor.getContentAreaContainer();
19067      return fromDomSafe(rawContainer).map(inBody).getOr(false);
19068    };
19069
19070    var NotificationManagerImpl = () => {
19071      const unimplemented = () => {
19072        throw new Error('Theme did not provide a NotificationManager implementation.');
19073      };
19074      return {
19075        open: unimplemented,
19076        close: unimplemented,
19077        getArgs: unimplemented
19078      };
19079    };
19080
19081    const NotificationManager = editor => {
19082      const notifications = [];
19083      const getImplementation = () => {
19084        const theme = editor.theme;
19085        return theme && theme.getNotificationManagerImpl ? theme.getNotificationManagerImpl() : NotificationManagerImpl();
19086      };
19087      const getTopNotification = () => {
19088        return Optional.from(notifications[0]);
19089      };
19090      const isEqual = (a, b) => {
19091        return a.type === b.type && a.text === b.text && !a.progressBar && !a.timeout && !b.progressBar && !b.timeout;
19092      };
19093      const reposition = () => {
19094        each$e(notifications, notification => {
19095          notification.reposition();
19096        });
19097      };
19098      const addNotification = notification => {
19099        notifications.push(notification);
19100      };
19101      const closeNotification = notification => {
19102        findIndex$2(notifications, otherNotification => {
19103          return otherNotification === notification;
19104        }).each(index => {
19105          notifications.splice(index, 1);
19106        });
19107      };
19108      const open = (spec, fireEvent = true) => {
19109        if (editor.removed || !isEditorAttachedToDom(editor)) {
19110          return {};
19111        }
19112        if (fireEvent) {
19113          editor.dispatch('BeforeOpenNotification', { notification: spec });
19114        }
19115        return find$2(notifications, notification => {
19116          return isEqual(getImplementation().getArgs(notification), spec);
19117        }).getOrThunk(() => {
19118          editor.editorManager.setActive(editor);
19119          const notification = getImplementation().open(spec, () => {
19120            closeNotification(notification);
19121            reposition();
19122            getTopNotification().fold(() => editor.focus(), top => focus$1(SugarElement.fromDom(top.getEl())));
19123          });
19124          addNotification(notification);
19125          reposition();
19126          editor.dispatch('OpenNotification', { notification: { ...notification } });
19127          return notification;
19128        });
19129      };
19130      const close = () => {
19131        getTopNotification().each(notification => {
19132          getImplementation().close(notification);
19133          closeNotification(notification);
19134          reposition();
19135        });
19136      };
19137      const getNotifications = constant(notifications);
19138      const registerEvents = editor => {
19139        editor.on('SkinLoaded', () => {
19140          const serviceMessage = getServiceMessage(editor);
19141          if (serviceMessage) {
19142            open({
19143              text: serviceMessage,
19144              type: 'warning',
19145              timeout: 0
19146            }, false);
19147          }
19148          reposition();
19149        });
19150        editor.on('show ResizeEditor ResizeWindow NodeChange', () => {
19151          requestAnimationFrame(reposition);
19152        });
19153        editor.on('remove', () => {
19154          each$e(notifications.slice(), notification => {
19155            getImplementation().close(notification);
19156          });
19157        });
19158      };
19159      registerEvents(editor);
19160      return {
19161        open,
19162        close,
19163        getNotifications
19164      };
19165    };
19166
19167    const PluginManager = AddOnManager.PluginManager;
19168
19169    const ThemeManager = AddOnManager.ThemeManager;
19170
19171    var WindowManagerImpl = () => {
19172      const unimplemented = () => {
19173        throw new Error('Theme did not provide a WindowManager implementation.');
19174      };
19175      return {
19176        open: unimplemented,
19177        openUrl: unimplemented,
19178        alert: unimplemented,
19179        confirm: unimplemented,
19180        close: unimplemented
19181      };
19182    };
19183
19184    const WindowManager = editor => {
19185      let dialogs = [];
19186      const getImplementation = () => {
19187        const theme = editor.theme;
19188        return theme && theme.getWindowManagerImpl ? theme.getWindowManagerImpl() : WindowManagerImpl();
19189      };
19190      const funcBind = (scope, f) => {
19191        return (...args) => {
19192          return f ? f.apply(scope, args) : undefined;
19193        };
19194      };
19195      const fireOpenEvent = dialog => {
19196        editor.dispatch('OpenWindow', { dialog });
19197      };
19198      const fireCloseEvent = dialog => {
19199        editor.dispatch('CloseWindow', { dialog });
19200      };
19201      const addDialog = dialog => {
19202        dialogs.push(dialog);
19203        fireOpenEvent(dialog);
19204      };
19205      const closeDialog = dialog => {
19206        fireCloseEvent(dialog);
19207        dialogs = filter$5(dialogs, otherDialog => {
19208          return otherDialog !== dialog;
19209        });
19210        if (dialogs.length === 0) {
19211          editor.focus();
19212        }
19213      };
19214      const getTopDialog = () => {
19215        return Optional.from(dialogs[dialogs.length - 1]);
19216      };
19217      const storeSelectionAndOpenDialog = openDialog => {
19218        editor.editorManager.setActive(editor);
19219        store(editor);
19220        editor.ui.show();
19221        const dialog = openDialog();
19222        addDialog(dialog);
19223        return dialog;
19224      };
19225      const open = (args, params) => {
19226        return storeSelectionAndOpenDialog(() => getImplementation().open(args, params, closeDialog));
19227      };
19228      const openUrl = args => {
19229        return storeSelectionAndOpenDialog(() => getImplementation().openUrl(args, closeDialog));
19230      };
19231      const alert = (message, callback, scope) => {
19232        const windowManagerImpl = getImplementation();
19233        windowManagerImpl.alert(message, funcBind(scope ? scope : windowManagerImpl, callback));
19234      };
19235      const confirm = (message, callback, scope) => {
19236        const windowManagerImpl = getImplementation();
19237        windowManagerImpl.confirm(message, funcBind(scope ? scope : windowManagerImpl, callback));
19238      };
19239      const close = () => {
19240        getTopDialog().each(dialog => {
19241          getImplementation().close(dialog);
19242          closeDialog(dialog);
19243        });
19244      };
19245      editor.on('remove', () => {
19246        each$e(dialogs, dialog => {
19247          getImplementation().close(dialog);
19248        });
19249      });
19250      return {
19251        open,
19252        openUrl,
19253        alert,
19254        confirm,
19255        close
19256      };
19257    };
19258
19259    const displayNotification = (editor, message) => {
19260      editor.notificationManager.open({
19261        type: 'error',
19262        text: message
19263      });
19264    };
19265    const displayError = (editor, message) => {
19266      if (editor._skinLoaded) {
19267        displayNotification(editor, message);
19268      } else {
19269        editor.on('SkinLoaded', () => {
19270          displayNotification(editor, message);
19271        });
19272      }
19273    };
19274    const uploadError = (editor, message) => {
19275      displayError(editor, I18n.translate([
19276        'Failed to upload image: {0}',
19277        message
19278      ]));
19279    };
19280    const logError = (editor, errorType, msg) => {
19281      fireError(editor, errorType, { message: msg });
19282      console.error(msg);
19283    };
19284    const createLoadError = (type, url, name) => name ? `Failed to load ${ type }: ${ name } from url ${ url }` : `Failed to load ${ type } url: ${ url }`;
19285    const pluginLoadError = (editor, url, name) => {
19286      logError(editor, 'PluginLoadError', createLoadError('plugin', url, name));
19287    };
19288    const iconsLoadError = (editor, url, name) => {
19289      logError(editor, 'IconsLoadError', createLoadError('icons', url, name));
19290    };
19291    const languageLoadError = (editor, url, name) => {
19292      logError(editor, 'LanguageLoadError', createLoadError('language', url, name));
19293    };
19294    const themeLoadError = (editor, url, name) => {
19295      logError(editor, 'ThemeLoadError', createLoadError('theme', url, name));
19296    };
19297    const modelLoadError = (editor, url, name) => {
19298      logError(editor, 'ModelLoadError', createLoadError('model', url, name));
19299    };
19300    const pluginInitError = (editor, name, err) => {
19301      const message = I18n.translate([
19302        'Failed to initialize plugin: {0}',
19303        name
19304      ]);
19305      fireError(editor, 'PluginLoadError', { message });
19306      initError(message, err);
19307      displayError(editor, message);
19308    };
19309    const initError = (message, ...x) => {
19310      const console = window.console;
19311      if (console) {
19312        if (console.error) {
19313          console.error(message, ...x);
19314        } else {
19315          console.log(message, ...x);
19316        }
19317      }
19318    };
19319
19320    const isContentCssSkinName = url => /^[a-z0-9\-]+$/i.test(url);
19321    const getContentCssUrls = editor => {
19322      return transformToUrls(editor, getContentCss(editor));
19323    };
19324    const getFontCssUrls = editor => {
19325      return transformToUrls(editor, getFontCss(editor));
19326    };
19327    const transformToUrls = (editor, cssLinks) => {
19328      const skinUrl = editor.editorManager.baseURL + '/skins/content';
19329      const suffix = editor.editorManager.suffix;
19330      const contentCssFile = `content${ suffix }.css`;
19331      return map$3(cssLinks, url => {
19332        if (isContentCssSkinName(url) && !editor.inline) {
19333          return `${ skinUrl }/${ url }/${ contentCssFile }`;
19334        } else {
19335          return editor.documentBaseURI.toAbsolute(url);
19336        }
19337      });
19338    };
19339    const appendContentCssFromSettings = editor => {
19340      editor.contentCSS = editor.contentCSS.concat(getContentCssUrls(editor), getFontCssUrls(editor));
19341    };
19342
19343    const getAllImages = elm => {
19344      return elm ? from(elm.getElementsByTagName('img')) : [];
19345    };
19346    const ImageScanner = (uploadStatus, blobCache) => {
19347      const cachedPromises = {};
19348      const findAll = (elm, predicate = always) => {
19349        const images = filter$5(getAllImages(elm), img => {
19350          const src = img.src;
19351          if (img.hasAttribute('data-mce-bogus')) {
19352            return false;
19353          }
19354          if (img.hasAttribute('data-mce-placeholder')) {
19355            return false;
19356          }
19357          if (!src || src === Env.transparentSrc) {
19358            return false;
19359          }
19360          if (startsWith(src, 'blob:')) {
19361            return !uploadStatus.isUploaded(src) && predicate(img);
19362          }
19363          if (startsWith(src, 'data:')) {
19364            return predicate(img);
19365          }
19366          return false;
19367        });
19368        const promises = map$3(images, img => {
19369          const imageSrc = img.src;
19370          if (has$2(cachedPromises, imageSrc)) {
19371            return cachedPromises[imageSrc].then(imageInfo => {
19372              if (isString(imageInfo)) {
19373                return imageInfo;
19374              } else {
19375                return {
19376                  image: img,
19377                  blobInfo: imageInfo.blobInfo
19378                };
19379              }
19380            });
19381          } else {
19382            const newPromise = imageToBlobInfo(blobCache, imageSrc).then(blobInfo => {
19383              delete cachedPromises[imageSrc];
19384              return {
19385                image: img,
19386                blobInfo
19387              };
19388            }).catch(error => {
19389              delete cachedPromises[imageSrc];
19390              return error;
19391            });
19392            cachedPromises[imageSrc] = newPromise;
19393            return newPromise;
19394          }
19395        });
19396        return Promise.all(promises);
19397      };
19398      return { findAll };
19399    };
19400
19401    const UploadStatus = () => {
19402      const PENDING = 1, UPLOADED = 2;
19403      let blobUriStatuses = {};
19404      const createStatus = (status, resultUri) => {
19405        return {
19406          status,
19407          resultUri
19408        };
19409      };
19410      const hasBlobUri = blobUri => {
19411        return blobUri in blobUriStatuses;
19412      };
19413      const getResultUri = blobUri => {
19414        const result = blobUriStatuses[blobUri];
19415        return result ? result.resultUri : null;
19416      };
19417      const isPending = blobUri => {
19418        return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === PENDING : false;
19419      };
19420      const isUploaded = blobUri => {
19421        return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === UPLOADED : false;
19422      };
19423      const markPending = blobUri => {
19424        blobUriStatuses[blobUri] = createStatus(PENDING, null);
19425      };
19426      const markUploaded = (blobUri, resultUri) => {
19427        blobUriStatuses[blobUri] = createStatus(UPLOADED, resultUri);
19428      };
19429      const removeFailed = blobUri => {
19430        delete blobUriStatuses[blobUri];
19431      };
19432      const destroy = () => {
19433        blobUriStatuses = {};
19434      };
19435      return {
19436        hasBlobUri,
19437        getResultUri,
19438        isPending,
19439        isUploaded,
19440        markPending,
19441        markUploaded,
19442        removeFailed,
19443        destroy
19444      };
19445    };
19446
19447    let count = 0;
19448    const seed = () => {
19449      const rnd = () => {
19450        return Math.round(Math.random() * 4294967295).toString(36);
19451      };
19452      const now = new Date().getTime();
19453      return 's' + now.toString(36) + rnd() + rnd() + rnd();
19454    };
19455    const uuid = prefix => {
19456      return prefix + count++ + seed();
19457    };
19458
19459    const BlobCache = () => {
19460      let cache = [];
19461      const mimeToExt = mime => {
19462        const mimes = {
19463          'image/jpeg': 'jpg',
19464          'image/jpg': 'jpg',
19465          'image/gif': 'gif',
19466          'image/png': 'png',
19467          'image/apng': 'apng',
19468          'image/avif': 'avif',
19469          'image/svg+xml': 'svg',
19470          'image/webp': 'webp',
19471          'image/bmp': 'bmp',
19472          'image/tiff': 'tiff'
19473        };
19474        return mimes[mime.toLowerCase()] || 'dat';
19475      };
19476      const create = (o, blob, base64, name, filename) => {
19477        if (isString(o)) {
19478          const id = o;
19479          return toBlobInfo({
19480            id,
19481            name,
19482            filename,
19483            blob: blob,
19484            base64: base64
19485          });
19486        } else if (isObject(o)) {
19487          return toBlobInfo(o);
19488        } else {
19489          throw new Error('Unknown input type');
19490        }
19491      };
19492      const toBlobInfo = o => {
19493        if (!o.blob || !o.base64) {
19494          throw new Error('blob and base64 representations of the image are required for BlobInfo to be created');
19495        }
19496        const id = o.id || uuid('blobid');
19497        const name = o.name || id;
19498        const blob = o.blob;
19499        return {
19500          id: constant(id),
19501          name: constant(name),
19502          filename: constant(o.filename || name + '.' + mimeToExt(blob.type)),
19503          blob: constant(blob),
19504          base64: constant(o.base64),
19505          blobUri: constant(o.blobUri || URL.createObjectURL(blob)),
19506          uri: constant(o.uri)
19507        };
19508      };
19509      const add = blobInfo => {
19510        if (!get(blobInfo.id())) {
19511          cache.push(blobInfo);
19512        }
19513      };
19514      const findFirst = predicate => find$2(cache, predicate).getOrUndefined();
19515      const get = id => findFirst(cachedBlobInfo => cachedBlobInfo.id() === id);
19516      const getByUri = blobUri => findFirst(blobInfo => blobInfo.blobUri() === blobUri);
19517      const getByData = (base64, type) => findFirst(blobInfo => blobInfo.base64() === base64 && blobInfo.blob().type === type);
19518      const removeByUri = blobUri => {
19519        cache = filter$5(cache, blobInfo => {
19520          if (blobInfo.blobUri() === blobUri) {
19521            URL.revokeObjectURL(blobInfo.blobUri());
19522            return false;
19523          }
19524          return true;
19525        });
19526      };
19527      const destroy = () => {
19528        each$e(cache, cachedBlobInfo => {
19529          URL.revokeObjectURL(cachedBlobInfo.blobUri());
19530        });
19531        cache = [];
19532      };
19533      return {
19534        create,
19535        add,
19536        get,
19537        getByUri,
19538        getByData,
19539        findFirst,
19540        removeByUri,
19541        destroy
19542      };
19543    };
19544
19545    const Uploader = (uploadStatus, settings) => {
19546      const pendingPromises = {};
19547      const pathJoin = (path1, path2) => {
19548        if (path1) {
19549          return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, '');
19550        }
19551        return path2;
19552      };
19553      const defaultHandler = (blobInfo, progress) => new Promise((success, failure) => {
19554        const xhr = new XMLHttpRequest();
19555        xhr.open('POST', settings.url);
19556        xhr.withCredentials = settings.credentials;
19557        xhr.upload.onprogress = e => {
19558          progress(e.loaded / e.total * 100);
19559        };
19560        xhr.onerror = () => {
19561          failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
19562        };
19563        xhr.onload = () => {
19564          if (xhr.status < 200 || xhr.status >= 300) {
19565            failure('HTTP Error: ' + xhr.status);
19566            return;
19567          }
19568          const json = JSON.parse(xhr.responseText);
19569          if (!json || !isString(json.location)) {
19570            failure('Invalid JSON: ' + xhr.responseText);
19571            return;
19572          }
19573          success(pathJoin(settings.basePath, json.location));
19574        };
19575        const formData = new FormData();
19576        formData.append('file', blobInfo.blob(), blobInfo.filename());
19577        xhr.send(formData);
19578      });
19579      const uploadHandler = isFunction(settings.handler) ? settings.handler : defaultHandler;
19580      const noUpload = () => new Promise(resolve => {
19581        resolve([]);
19582      });
19583      const handlerSuccess = (blobInfo, url) => ({
19584        url,
19585        blobInfo,
19586        status: true
19587      });
19588      const handlerFailure = (blobInfo, error) => ({
19589        url: '',
19590        blobInfo,
19591        status: false,
19592        error
19593      });
19594      const resolvePending = (blobUri, result) => {
19595        Tools.each(pendingPromises[blobUri], resolve => {
19596          resolve(result);
19597        });
19598        delete pendingPromises[blobUri];
19599      };
19600      const uploadBlobInfo = (blobInfo, handler, openNotification) => {
19601        uploadStatus.markPending(blobInfo.blobUri());
19602        return new Promise(resolve => {
19603          let notification;
19604          let progress;
19605          try {
19606            const closeNotification = () => {
19607              if (notification) {
19608                notification.close();
19609                progress = noop;
19610              }
19611            };
19612            const success = url => {
19613              closeNotification();
19614              uploadStatus.markUploaded(blobInfo.blobUri(), url);
19615              resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url));
19616              resolve(handlerSuccess(blobInfo, url));
19617            };
19618            const failure = error => {
19619              closeNotification();
19620              uploadStatus.removeFailed(blobInfo.blobUri());
19621              resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, error));
19622              resolve(handlerFailure(blobInfo, error));
19623            };
19624            progress = percent => {
19625              if (percent < 0 || percent > 100) {
19626                return;
19627              }
19628              Optional.from(notification).orThunk(() => Optional.from(openNotification).map(apply$1)).each(n => {
19629                notification = n;
19630                n.progressBar.value(percent);
19631              });
19632            };
19633            handler(blobInfo, progress).then(success, err => {
19634              failure(isString(err) ? { message: err } : err);
19635            });
19636          } catch (ex) {
19637            resolve(handlerFailure(blobInfo, ex));
19638          }
19639        });
19640      };
19641      const isDefaultHandler = handler => handler === defaultHandler;
19642      const pendingUploadBlobInfo = blobInfo => {
19643        const blobUri = blobInfo.blobUri();
19644        return new Promise(resolve => {
19645          pendingPromises[blobUri] = pendingPromises[blobUri] || [];
19646          pendingPromises[blobUri].push(resolve);
19647        });
19648      };
19649      const uploadBlobs = (blobInfos, openNotification) => {
19650        blobInfos = Tools.grep(blobInfos, blobInfo => !uploadStatus.isUploaded(blobInfo.blobUri()));
19651        return Promise.all(Tools.map(blobInfos, blobInfo => uploadStatus.isPending(blobInfo.blobUri()) ? pendingUploadBlobInfo(blobInfo) : uploadBlobInfo(blobInfo, uploadHandler, openNotification)));
19652      };
19653      const upload = (blobInfos, openNotification) => !settings.url && isDefaultHandler(uploadHandler) ? noUpload() : uploadBlobs(blobInfos, openNotification);
19654      return { upload };
19655    };
19656
19657    const openNotification = editor => () => editor.notificationManager.open({
19658      text: editor.translate('Image uploading...'),
19659      type: 'info',
19660      timeout: -1,
19661      progressBar: true
19662    });
19663    const createUploader = (editor, uploadStatus) => Uploader(uploadStatus, {
19664      url: getImageUploadUrl(editor),
19665      basePath: getImageUploadBasePath(editor),
19666      credentials: getImagesUploadCredentials(editor),
19667      handler: getImagesUploadHandler(editor)
19668    });
19669    const ImageUploader = editor => {
19670      const uploadStatus = UploadStatus();
19671      const uploader = createUploader(editor, uploadStatus);
19672      return { upload: (blobInfos, showNotification = true) => uploader.upload(blobInfos, showNotification ? openNotification(editor) : undefined) };
19673    };
19674
19675    const isEmptyForPadding = (editor, element) => editor.dom.isEmpty(element.dom) && isNonNullable(editor.schema.getTextBlockElements()[name(element)]);
19676    const addPaddingToEmpty = editor => element => {
19677      if (isEmptyForPadding(editor, element)) {
19678        append$1(element, SugarElement.fromHtml('<br data-mce-bogus="1" />'));
19679      }
19680    };
19681    const EditorUpload = editor => {
19682      const blobCache = BlobCache();
19683      let uploader, imageScanner;
19684      const uploadStatus = UploadStatus();
19685      const urlFilters = [];
19686      const aliveGuard = callback => {
19687        return result => {
19688          if (editor.selection) {
19689            return callback(result);
19690          }
19691          return [];
19692        };
19693      };
19694      const cacheInvalidator = url => url + (url.indexOf('?') === -1 ? '?' : '&') + new Date().getTime();
19695      const replaceString = (content, search, replace) => {
19696        let index = 0;
19697        do {
19698          index = content.indexOf(search, index);
19699          if (index !== -1) {
19700            content = content.substring(0, index) + replace + content.substr(index + search.length);
19701            index += replace.length - search.length + 1;
19702          }
19703        } while (index !== -1);
19704        return content;
19705      };
19706      const replaceImageUrl = (content, targetUrl, replacementUrl) => {
19707        const replacementString = `src="${ replacementUrl }"${ replacementUrl === Env.transparentSrc ? ' data-mce-placeholder="1"' : '' }`;
19708        content = replaceString(content, `src="${ targetUrl }"`, replacementString);
19709        content = replaceString(content, 'data-mce-src="' + targetUrl + '"', 'data-mce-src="' + replacementUrl + '"');
19710        return content;
19711      };
19712      const replaceUrlInUndoStack = (targetUrl, replacementUrl) => {
19713        each$e(editor.undoManager.data, level => {
19714          if (level.type === 'fragmented') {
19715            level.fragments = map$3(level.fragments, fragment => replaceImageUrl(fragment, targetUrl, replacementUrl));
19716          } else {
19717            level.content = replaceImageUrl(level.content, targetUrl, replacementUrl);
19718          }
19719        });
19720      };
19721      const replaceImageUriInView = (image, resultUri) => {
19722        const src = editor.convertURL(resultUri, 'src');
19723        replaceUrlInUndoStack(image.src, resultUri);
19724        setAll$1(SugarElement.fromDom(image), {
19725          'src': shouldReuseFileName(editor) ? cacheInvalidator(resultUri) : resultUri,
19726          'data-mce-src': src
19727        });
19728      };
19729      const uploadImages = () => {
19730        if (!uploader) {
19731          uploader = createUploader(editor, uploadStatus);
19732        }
19733        return scanForImages().then(aliveGuard(imageInfos => {
19734          const blobInfos = map$3(imageInfos, imageInfo => imageInfo.blobInfo);
19735          return uploader.upload(blobInfos, openNotification(editor)).then(aliveGuard(result => {
19736            const imagesToRemove = [];
19737            let shouldDispatchChange = false;
19738            const filteredResult = map$3(result, (uploadInfo, index) => {
19739              const {blobInfo, image} = imageInfos[index];
19740              let removed = false;
19741              if (uploadInfo.status && shouldReplaceBlobUris(editor)) {
19742                if (uploadInfo.url && !contains$1(image.src, uploadInfo.url)) {
19743                  shouldDispatchChange = true;
19744                }
19745                blobCache.removeByUri(image.src);
19746                if (isRtc(editor)) ; else {
19747                  replaceImageUriInView(image, uploadInfo.url);
19748                }
19749              } else if (uploadInfo.error) {
19750                if (uploadInfo.error.remove) {
19751                  replaceUrlInUndoStack(image.src, Env.transparentSrc);
19752                  imagesToRemove.push(image);
19753                  removed = true;
19754                }
19755                uploadError(editor, uploadInfo.error.message);
19756              }
19757              return {
19758                element: image,
19759                status: uploadInfo.status,
19760                uploadUri: uploadInfo.url,
19761                blobInfo,
19762                removed
19763              };
19764            });
19765            if (imagesToRemove.length > 0 && !isRtc(editor)) {
19766              editor.undoManager.transact(() => {
19767                each$e(fromDom$1(imagesToRemove), sugarElement => {
19768                  const parentOpt = parent(sugarElement);
19769                  remove$5(sugarElement);
19770                  parentOpt.each(addPaddingToEmpty(editor));
19771                  blobCache.removeByUri(sugarElement.dom.src);
19772                });
19773              });
19774            } else if (shouldDispatchChange) {
19775              editor.undoManager.dispatchChange();
19776            }
19777            return filteredResult;
19778          }));
19779        }));
19780      };
19781      const uploadImagesAuto = () => isAutomaticUploadsEnabled(editor) ? uploadImages() : Promise.resolve([]);
19782      const isValidDataUriImage = imgElm => forall(urlFilters, filter => filter(imgElm));
19783      const addFilter = filter => {
19784        urlFilters.push(filter);
19785      };
19786      const scanForImages = () => {
19787        if (!imageScanner) {
19788          imageScanner = ImageScanner(uploadStatus, blobCache);
19789        }
19790        return imageScanner.findAll(editor.getBody(), isValidDataUriImage).then(aliveGuard(result => {
19791          const filteredResult = filter$5(result, resultItem => {
19792            if (isString(resultItem)) {
19793              displayError(editor, resultItem);
19794              return false;
19795            } else if (resultItem.uriType === 'blob') {
19796              return false;
19797            } else {
19798              return true;
19799            }
19800          });
19801          if (isRtc(editor)) ; else {
19802            each$e(filteredResult, resultItem => {
19803              replaceUrlInUndoStack(resultItem.image.src, resultItem.blobInfo.blobUri());
19804              resultItem.image.src = resultItem.blobInfo.blobUri();
19805              resultItem.image.removeAttribute('data-mce-src');
19806            });
19807          }
19808          return filteredResult;
19809        }));
19810      };
19811      const destroy = () => {
19812        blobCache.destroy();
19813        uploadStatus.destroy();
19814        imageScanner = uploader = null;
19815      };
19816      const replaceBlobUris = content => {
19817        return content.replace(/src="(blob:[^"]+)"/g, (match, blobUri) => {
19818          const resultUri = uploadStatus.getResultUri(blobUri);
19819          if (resultUri) {
19820            return 'src="' + resultUri + '"';
19821          }
19822          let blobInfo = blobCache.getByUri(blobUri);
19823          if (!blobInfo) {
19824            blobInfo = foldl(editor.editorManager.get(), (result, editor) => {
19825              return result || editor.editorUpload && editor.editorUpload.blobCache.getByUri(blobUri);
19826            }, undefined);
19827          }
19828          if (blobInfo) {
19829            const blob = blobInfo.blob();
19830            return 'src="data:' + blob.type + ';base64,' + blobInfo.base64() + '"';
19831          }
19832          return match;
19833        });
19834      };
19835      editor.on('SetContent', () => {
19836        if (isAutomaticUploadsEnabled(editor)) {
19837          uploadImagesAuto();
19838        } else {
19839          scanForImages();
19840        }
19841      });
19842      editor.on('RawSaveContent', e => {
19843        e.content = replaceBlobUris(e.content);
19844      });
19845      editor.on('GetContent', e => {
19846        if (e.source_view || e.format === 'raw' || e.format === 'tree') {
19847          return;
19848        }
19849        e.content = replaceBlobUris(e.content);
19850      });
19851      editor.on('PostRender', () => {
19852        editor.parser.addNodeFilter('img', images => {
19853          each$e(images, img => {
19854            const src = img.attr('src');
19855            if (!src || blobCache.getByUri(src)) {
19856              return;
19857            }
19858            const resultUri = uploadStatus.getResultUri(src);
19859            if (resultUri) {
19860              img.attr('src', resultUri);
19861            }
19862          });
19863        });
19864      });
19865      return {
19866        blobCache,
19867        addFilter,
19868        uploadImages,
19869        uploadImagesAuto,
19870        scanForImages,
19871        destroy
19872      };
19873    };
19874
19875    const get$1 = editor => {
19876      const dom = editor.dom;
19877      const schemaType = editor.schema.type;
19878      const formats = {
19879        valigntop: [{
19880            selector: 'td,th',
19881            styles: { verticalAlign: 'top' }
19882          }],
19883        valignmiddle: [{
19884            selector: 'td,th',
19885            styles: { verticalAlign: 'middle' }
19886          }],
19887        valignbottom: [{
19888            selector: 'td,th',
19889            styles: { verticalAlign: 'bottom' }
19890          }],
19891        alignleft: [
19892          {
19893            selector: 'figure.image',
19894            collapsed: false,
19895            classes: 'align-left',
19896            ceFalseOverride: true,
19897            preview: 'font-family font-size'
19898          },
19899          {
19900            selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
19901            styles: { textAlign: 'left' },
19902            inherit: false,
19903            preview: false
19904          },
19905          {
19906            selector: 'img,audio,video',
19907            collapsed: false,
19908            styles: { float: 'left' },
19909            preview: 'font-family font-size'
19910          },
19911          {
19912            selector: 'table',
19913            collapsed: false,
19914            styles: {
19915              marginLeft: '0px',
19916              marginRight: 'auto'
19917            },
19918            onformat: table => {
19919              dom.setStyle(table, 'float', null);
19920            },
19921            preview: 'font-family font-size'
19922          },
19923          {
19924            selector: '.mce-preview-object,[data-ephox-embed-iri]',
19925            ceFalseOverride: true,
19926            styles: { float: 'left' }
19927          }
19928        ],
19929        aligncenter: [
19930          {
19931            selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
19932            styles: { textAlign: 'center' },
19933            inherit: false,
19934            preview: 'font-family font-size'
19935          },
19936          {
19937            selector: 'figure.image',
19938            collapsed: false,
19939            classes: 'align-center',
19940            ceFalseOverride: true,
19941            preview: 'font-family font-size'
19942          },
19943          {
19944            selector: 'img,audio,video',
19945            collapsed: false,
19946            styles: {
19947              display: 'block',
19948              marginLeft: 'auto',
19949              marginRight: 'auto'
19950            },
19951            preview: false
19952          },
19953          {
19954            selector: 'table',
19955            collapsed: false,
19956            styles: {
19957              marginLeft: 'auto',
19958              marginRight: 'auto'
19959            },
19960            preview: 'font-family font-size'
19961          },
19962          {
19963            selector: '.mce-preview-object',
19964            ceFalseOverride: true,
19965            styles: {
19966              display: 'table',
19967              marginLeft: 'auto',
19968              marginRight: 'auto'
19969            },
19970            preview: false
19971          },
19972          {
19973            selector: '[data-ephox-embed-iri]',
19974            ceFalseOverride: true,
19975            styles: {
19976              marginLeft: 'auto',
19977              marginRight: 'auto'
19978            },
19979            preview: false
19980          }
19981        ],
19982        alignright: [
19983          {
19984            selector: 'figure.image',
19985            collapsed: false,
19986            classes: 'align-right',
19987            ceFalseOverride: true,
19988            preview: 'font-family font-size'
19989          },
19990          {
19991            selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
19992            styles: { textAlign: 'right' },
19993            inherit: false,
19994            preview: 'font-family font-size'
19995          },
19996          {
19997            selector: 'img,audio,video',
19998            collapsed: false,
19999            styles: { float: 'right' },
20000            preview: 'font-family font-size'
20001          },
20002          {
20003            selector: 'table',
20004            collapsed: false,
20005            styles: {
20006              marginRight: '0px',
20007              marginLeft: 'auto'
20008            },
20009            onformat: table => {
20010              dom.setStyle(table, 'float', null);
20011            },
20012            preview: 'font-family font-size'
20013          },
20014          {
20015            selector: '.mce-preview-object,[data-ephox-embed-iri]',
20016            ceFalseOverride: true,
20017            styles: { float: 'right' },
20018            preview: false
20019          }
20020        ],
20021        alignjustify: [{
20022            selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
20023            styles: { textAlign: 'justify' },
20024            inherit: false,
20025            preview: 'font-family font-size'
20026          }],
20027        bold: [
20028          {
20029            inline: 'strong',
20030            remove: 'all',
20031            preserve_attributes: [
20032              'class',
20033              'style'
20034            ]
20035          },
20036          {
20037            inline: 'span',
20038            styles: { fontWeight: 'bold' }
20039          },
20040          {
20041            inline: 'b',
20042            remove: 'all',
20043            preserve_attributes: [
20044              'class',
20045              'style'
20046            ]
20047          }
20048        ],
20049        italic: [
20050          {
20051            inline: 'em',
20052            remove: 'all',
20053            preserve_attributes: [
20054              'class',
20055              'style'
20056            ]
20057          },
20058          {
20059            inline: 'span',
20060            styles: { fontStyle: 'italic' }
20061          },
20062          {
20063            inline: 'i',
20064            remove: 'all',
20065            preserve_attributes: [
20066              'class',
20067              'style'
20068            ]
20069          }
20070        ],
20071        underline: [
20072          {
20073            inline: 'span',
20074            styles: { textDecoration: 'underline' },
20075            exact: true
20076          },
20077          {
20078            inline: 'u',
20079            remove: 'all',
20080            preserve_attributes: [
20081              'class',
20082              'style'
20083            ]
20084          }
20085        ],
20086        strikethrough: (() => {
20087          const span = {
20088            inline: 'span',
20089            styles: { textDecoration: 'line-through' },
20090            exact: true
20091          };
20092          const strike = {
20093            inline: 'strike',
20094            remove: 'all',
20095            preserve_attributes: [
20096              'class',
20097              'style'
20098            ]
20099          };
20100          const s = {
20101            inline: 's',
20102            remove: 'all',
20103            preserve_attributes: [
20104              'class',
20105              'style'
20106            ]
20107          };
20108          return schemaType !== 'html4' ? [
20109            s,
20110            span,
20111            strike
20112          ] : [
20113            span,
20114            s,
20115            strike
20116          ];
20117        })(),
20118        forecolor: {
20119          inline: 'span',
20120          styles: { color: '%value' },
20121          links: true,
20122          remove_similar: true,
20123          clear_child_styles: true
20124        },
20125        hilitecolor: {
20126          inline: 'span',
20127          styles: { backgroundColor: '%value' },
20128          links: true,
20129          remove_similar: true,
20130          clear_child_styles: true
20131        },
20132        fontname: {
20133          inline: 'span',
20134          toggle: false,
20135          styles: { fontFamily: '%value' },
20136          clear_child_styles: true
20137        },
20138        fontsize: {
20139          inline: 'span',
20140          toggle: false,
20141          styles: { fontSize: '%value' },
20142          clear_child_styles: true
20143        },
20144        lineheight: {
20145          selector: 'h1,h2,h3,h4,h5,h6,p,li,td,th,div',
20146          styles: { lineHeight: '%value' }
20147        },
20148        fontsize_class: {
20149          inline: 'span',
20150          attributes: { class: '%value' }
20151        },
20152        blockquote: {
20153          block: 'blockquote',
20154          wrapper: true,
20155          remove: 'all'
20156        },
20157        subscript: { inline: 'sub' },
20158        superscript: { inline: 'sup' },
20159        code: { inline: 'code' },
20160        link: {
20161          inline: 'a',
20162          selector: 'a',
20163          remove: 'all',
20164          split: true,
20165          deep: true,
20166          onmatch: (node, _fmt, _itemName) => {
20167            return isElement$6(node) && node.hasAttribute('href');
20168          },
20169          onformat: (elm, _fmt, vars) => {
20170            Tools.each(vars, (value, key) => {
20171              dom.setAttrib(elm, key, value);
20172            });
20173          }
20174        },
20175        lang: {
20176          inline: 'span',
20177          clear_child_styles: true,
20178          remove_similar: true,
20179          attributes: {
20180            'lang': '%value',
20181            'data-mce-lang': vars => {
20182              var _a;
20183              return (_a = vars === null || vars === void 0 ? void 0 : vars.customValue) !== null && _a !== void 0 ? _a : null;
20184            }
20185          }
20186        },
20187        removeformat: [
20188          {
20189            selector: 'b,strong,em,i,font,u,strike,s,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins,small',
20190            remove: 'all',
20191            split: true,
20192            expand: false,
20193            block_expand: true,
20194            deep: true
20195          },
20196          {
20197            selector: 'span',
20198            attributes: [
20199              'style',
20200              'class'
20201            ],
20202            remove: 'empty',
20203            split: true,
20204            expand: false,
20205            deep: true
20206          },
20207          {
20208            selector: '*',
20209            attributes: [
20210              'style',
20211              'class'
20212            ],
20213            split: false,
20214            expand: false,
20215            deep: true
20216          }
20217        ]
20218      };
20219      Tools.each('p h1 h2 h3 h4 h5 h6 div address pre dt dd samp'.split(/\s/), name => {
20220        formats[name] = {
20221          block: name,
20222          remove: 'all'
20223        };
20224      });
20225      return formats;
20226    };
20227
20228    const genericBase = {
20229      remove_similar: true,
20230      inherit: false
20231    };
20232    const cellBase = {
20233      selector: 'td,th',
20234      ...genericBase
20235    };
20236    const cellFormats = {
20237      tablecellbackgroundcolor: {
20238        styles: { backgroundColor: '%value' },
20239        ...cellBase
20240      },
20241      tablecellverticalalign: {
20242        styles: { 'vertical-align': '%value' },
20243        ...cellBase
20244      },
20245      tablecellbordercolor: {
20246        styles: { borderColor: '%value' },
20247        ...cellBase
20248      },
20249      tablecellclass: {
20250        classes: ['%value'],
20251        ...cellBase
20252      },
20253      tableclass: {
20254        selector: 'table',
20255        classes: ['%value'],
20256        ...genericBase
20257      },
20258      tablecellborderstyle: {
20259        styles: { borderStyle: '%value' },
20260        ...cellBase
20261      },
20262      tablecellborderwidth: {
20263        styles: { borderWidth: '%value' },
20264        ...cellBase
20265      }
20266    };
20267    const get = constant(cellFormats);
20268
20269    const FormatRegistry = editor => {
20270      const formats = {};
20271      const get$2 = name => isNonNullable(name) ? formats[name] : formats;
20272      const has = name => has$2(formats, name);
20273      const register = (name, format) => {
20274        if (name) {
20275          if (!isString(name)) {
20276            each$d(name, (format, name) => {
20277              register(name, format);
20278            });
20279          } else {
20280            if (!isArray$1(format)) {
20281              format = [format];
20282            }
20283            each$e(format, format => {
20284              if (isUndefined(format.deep)) {
20285                format.deep = !isSelectorFormat(format);
20286              }
20287              if (isUndefined(format.split)) {
20288                format.split = !isSelectorFormat(format) || isInlineFormat(format);
20289              }
20290              if (isUndefined(format.remove) && isSelectorFormat(format) && !isInlineFormat(format)) {
20291                format.remove = 'none';
20292              }
20293              if (isSelectorFormat(format) && isInlineFormat(format)) {
20294                format.mixed = true;
20295                format.block_expand = true;
20296              }
20297              if (isString(format.classes)) {
20298                format.classes = format.classes.split(/\s+/);
20299              }
20300            });
20301            formats[name] = format;
20302          }
20303        }
20304      };
20305      const unregister = name => {
20306        if (name && formats[name]) {
20307          delete formats[name];
20308        }
20309        return formats;
20310      };
20311      register(get$1(editor));
20312      register(get());
20313      register(getFormats(editor));
20314      return {
20315        get: get$2,
20316        has,
20317        register,
20318        unregister
20319      };
20320    };
20321
20322    const each$3 = Tools.each;
20323    const dom = DOMUtils.DOM;
20324    const isPreviewItem = item => isNonNullable(item) && isObject(item);
20325    const parsedSelectorToHtml = (ancestry, editor) => {
20326      const schema = editor && editor.schema || Schema({});
20327      const decorate = (elm, item) => {
20328        if (item.classes.length > 0) {
20329          dom.addClass(elm, item.classes.join(' '));
20330        }
20331        dom.setAttribs(elm, item.attrs);
20332      };
20333      const createElement = sItem => {
20334        const item = isString(sItem) ? {
20335          name: sItem,
20336          classes: [],
20337          attrs: {}
20338        } : sItem;
20339        const elm = dom.create(item.name);
20340        decorate(elm, item);
20341        return elm;
20342      };
20343      const getRequiredParent = (elm, candidate) => {
20344        const elmRule = schema.getElementRule(elm.nodeName.toLowerCase());
20345        const parentsRequired = elmRule === null || elmRule === void 0 ? void 0 : elmRule.parentsRequired;
20346        if (parentsRequired && parentsRequired.length) {
20347          return candidate && contains$2(parentsRequired, candidate) ? candidate : parentsRequired[0];
20348        } else {
20349          return false;
20350        }
20351      };
20352      const wrapInHtml = (elm, ancestors, siblings) => {
20353        let parentCandidate;
20354        const ancestor = ancestors[0];
20355        const ancestorName = isPreviewItem(ancestor) ? ancestor.name : undefined;
20356        const parentRequired = getRequiredParent(elm, ancestorName);
20357        if (parentRequired) {
20358          if (ancestorName === parentRequired) {
20359            parentCandidate = ancestor;
20360            ancestors = ancestors.slice(1);
20361          } else {
20362            parentCandidate = parentRequired;
20363          }
20364        } else if (ancestor) {
20365          parentCandidate = ancestor;
20366          ancestors = ancestors.slice(1);
20367        } else if (!siblings) {
20368          return elm;
20369        }
20370        const parent = parentCandidate ? createElement(parentCandidate) : dom.create('div');
20371        parent.appendChild(elm);
20372        if (siblings) {
20373          Tools.each(siblings, sibling => {
20374            const siblingElm = createElement(sibling);
20375            parent.insertBefore(siblingElm, elm);
20376          });
20377        }
20378        const parentSiblings = isPreviewItem(parentCandidate) ? parentCandidate.siblings : undefined;
20379        return wrapInHtml(parent, ancestors, parentSiblings);
20380      };
20381      const fragment = dom.create('div');
20382      if (ancestry.length > 0) {
20383        const item = ancestry[0];
20384        const elm = createElement(item);
20385        const siblings = isPreviewItem(item) ? item.siblings : undefined;
20386        fragment.appendChild(wrapInHtml(elm, ancestry.slice(1), siblings));
20387      }
20388      return fragment;
20389    };
20390    const parseSelectorItem = item => {
20391      item = Tools.trim(item);
20392      let tagName = 'div';
20393      const obj = {
20394        name: tagName,
20395        classes: [],
20396        attrs: {},
20397        selector: item
20398      };
20399      if (item !== '*') {
20400        tagName = item.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g, ($0, $1, $2, $3, $4) => {
20401          switch ($1) {
20402          case '#':
20403            obj.attrs.id = $2;
20404            break;
20405          case '.':
20406            obj.classes.push($2);
20407            break;
20408          case ':':
20409            if (Tools.inArray('checked disabled enabled read-only required'.split(' '), $2) !== -1) {
20410              obj.attrs[$2] = $2;
20411            }
20412            break;
20413          }
20414          if ($3 === '[') {
20415            const m = $4.match(/([\w\-]+)(?:\=\"([^\"]+))?/);
20416            if (m) {
20417              obj.attrs[m[1]] = m[2];
20418            }
20419          }
20420          return '';
20421        });
20422      }
20423      obj.name = tagName || 'div';
20424      return obj;
20425    };
20426    const parseSelector = selector => {
20427      if (!isString(selector)) {
20428        return [];
20429      }
20430      selector = selector.split(/\s*,\s*/)[0];
20431      selector = selector.replace(/\s*(~\+|~|\+|>)\s*/g, '$1');
20432      return Tools.map(selector.split(/(?:>|\s+(?![^\[\]]+\]))/), item => {
20433        const siblings = Tools.map(item.split(/(?:~\+|~|\+)/), parseSelectorItem);
20434        const obj = siblings.pop();
20435        if (siblings.length) {
20436          obj.siblings = siblings;
20437        }
20438        return obj;
20439      }).reverse();
20440    };
20441    const getCssText = (editor, format) => {
20442      let previewCss = '';
20443      let previewStyles = getPreviewStyles(editor);
20444      if (previewStyles === '') {
20445        return '';
20446      }
20447      const removeVars = val => {
20448        return isString(val) ? val.replace(/%(\w+)/g, '') : '';
20449      };
20450      const getComputedStyle = (name, elm) => {
20451        return dom.getStyle(elm !== null && elm !== void 0 ? elm : editor.getBody(), name, true);
20452      };
20453      if (isString(format)) {
20454        const formats = editor.formatter.get(format);
20455        if (!formats) {
20456          return '';
20457        }
20458        format = formats[0];
20459      }
20460      if ('preview' in format) {
20461        const preview = format.preview;
20462        if (preview === false) {
20463          return '';
20464        } else {
20465          previewStyles = preview || previewStyles;
20466        }
20467      }
20468      let name = format.block || format.inline || 'span';
20469      let previewFrag;
20470      const items = parseSelector(format.selector);
20471      if (items.length > 0) {
20472        if (!items[0].name) {
20473          items[0].name = name;
20474        }
20475        name = format.selector;
20476        previewFrag = parsedSelectorToHtml(items, editor);
20477      } else {
20478        previewFrag = parsedSelectorToHtml([name], editor);
20479      }
20480      const previewElm = dom.select(name, previewFrag)[0] || previewFrag.firstChild;
20481      each$3(format.styles, (value, name) => {
20482        const newValue = removeVars(value);
20483        if (newValue) {
20484          dom.setStyle(previewElm, name, newValue);
20485        }
20486      });
20487      each$3(format.attributes, (value, name) => {
20488        const newValue = removeVars(value);
20489        if (newValue) {
20490          dom.setAttrib(previewElm, name, newValue);
20491        }
20492      });
20493      each$3(format.classes, value => {
20494        const newValue = removeVars(value);
20495        if (!dom.hasClass(previewElm, newValue)) {
20496          dom.addClass(previewElm, newValue);
20497        }
20498      });
20499      editor.dispatch('PreviewFormats');
20500      dom.setStyles(previewFrag, {
20501        position: 'absolute',
20502        left: -65535
20503      });
20504      editor.getBody().appendChild(previewFrag);
20505      const rawParentFontSize = getComputedStyle('fontSize');
20506      const parentFontSize = /px$/.test(rawParentFontSize) ? parseInt(rawParentFontSize, 10) : 0;
20507      each$3(previewStyles.split(' '), name => {
20508        let value = getComputedStyle(name, previewElm);
20509        if (name === 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
20510          value = getComputedStyle(name);
20511          if (rgbaToHexString(value).toLowerCase() === '#ffffff') {
20512            return;
20513          }
20514        }
20515        if (name === 'color') {
20516          if (rgbaToHexString(value).toLowerCase() === '#000000') {
20517            return;
20518          }
20519        }
20520        if (name === 'font-size') {
20521          if (/em|%$/.test(value)) {
20522            if (parentFontSize === 0) {
20523              return;
20524            }
20525            const numValue = parseFloat(value) / (/%$/.test(value) ? 100 : 1);
20526            value = numValue * parentFontSize + 'px';
20527          }
20528        }
20529        if (name === 'border' && value) {
20530          previewCss += 'padding:0 2px;';
20531        }
20532        previewCss += name + ':' + value + ';';
20533      });
20534      editor.dispatch('AfterPreviewFormats');
20535      dom.remove(previewFrag);
20536      return previewCss;
20537    };
20538
20539    const setup$r = editor => {
20540      editor.addShortcut('meta+b', '', 'Bold');
20541      editor.addShortcut('meta+i', '', 'Italic');
20542      editor.addShortcut('meta+u', '', 'Underline');
20543      for (let i = 1; i <= 6; i++) {
20544        editor.addShortcut('access+' + i, '', [
20545          'FormatBlock',
20546          false,
20547          'h' + i
20548        ]);
20549      }
20550      editor.addShortcut('access+7', '', [
20551        'FormatBlock',
20552        false,
20553        'p'
20554      ]);
20555      editor.addShortcut('access+8', '', [
20556        'FormatBlock',
20557        false,
20558        'div'
20559      ]);
20560      editor.addShortcut('access+9', '', [
20561        'FormatBlock',
20562        false,
20563        'address'
20564      ]);
20565    };
20566
20567    const Formatter = editor => {
20568      const formats = FormatRegistry(editor);
20569      const formatChangeState = Cell({});
20570      setup$r(editor);
20571      setup$u(editor);
20572      if (!isRtc(editor)) {
20573        setup$t(formatChangeState, editor);
20574      }
20575      return {
20576        get: formats.get,
20577        has: formats.has,
20578        register: formats.register,
20579        unregister: formats.unregister,
20580        apply: (name, vars, node) => {
20581          applyFormat(editor, name, vars, node);
20582        },
20583        remove: (name, vars, node, similar) => {
20584          removeFormat(editor, name, vars, node, similar);
20585        },
20586        toggle: (name, vars, node) => {
20587          toggleFormat(editor, name, vars, node);
20588        },
20589        match: (name, vars, node, similar) => matchFormat(editor, name, vars, node, similar),
20590        closest: names => closestFormat(editor, names),
20591        matchAll: (names, vars) => matchAllFormats(editor, names, vars),
20592        matchNode: (node, name, vars, similar) => matchNodeFormat(editor, node, name, vars, similar),
20593        canApply: name => canApplyFormat(editor, name),
20594        formatChanged: (formats, callback, similar, vars) => formatChanged(editor, formatChangeState, formats, callback, similar, vars),
20595        getCssText: curry(getCssText, editor)
20596      };
20597    };
20598
20599    const shouldIgnoreCommand = cmd => {
20600      switch (cmd.toLowerCase()) {
20601      case 'undo':
20602      case 'redo':
20603      case 'mcefocus':
20604        return true;
20605      default:
20606        return false;
20607      }
20608    };
20609    const registerEvents = (editor, undoManager, locks) => {
20610      const isFirstTypedCharacter = Cell(false);
20611      const addNonTypingUndoLevel = e => {
20612        setTyping(undoManager, false, locks);
20613        undoManager.add({}, e);
20614      };
20615      editor.on('init', () => {
20616        undoManager.add();
20617      });
20618      editor.on('BeforeExecCommand', e => {
20619        const cmd = e.command;
20620        if (!shouldIgnoreCommand(cmd)) {
20621          endTyping(undoManager, locks);
20622          undoManager.beforeChange();
20623        }
20624      });
20625      editor.on('ExecCommand', e => {
20626        const cmd = e.command;
20627        if (!shouldIgnoreCommand(cmd)) {
20628          addNonTypingUndoLevel(e);
20629        }
20630      });
20631      editor.on('ObjectResizeStart cut', () => {
20632        undoManager.beforeChange();
20633      });
20634      editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
20635      editor.on('dragend', addNonTypingUndoLevel);
20636      editor.on('keyup', e => {
20637        const keyCode = e.keyCode;
20638        if (e.isDefaultPrevented()) {
20639          return;
20640        }
20641        const isMeta = Env.os.isMacOS() && e.key === 'Meta';
20642        if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45 || e.ctrlKey || isMeta) {
20643          addNonTypingUndoLevel();
20644          editor.nodeChanged();
20645        }
20646        if (keyCode === 46 || keyCode === 8) {
20647          editor.nodeChanged();
20648        }
20649        if (isFirstTypedCharacter.get() && undoManager.typing && !isEq$1(createFromEditor(editor), undoManager.data[0])) {
20650          if (!editor.isDirty()) {
20651            editor.setDirty(true);
20652          }
20653          editor.dispatch('TypingUndo');
20654          isFirstTypedCharacter.set(false);
20655          editor.nodeChanged();
20656        }
20657      });
20658      editor.on('keydown', e => {
20659        const keyCode = e.keyCode;
20660        if (e.isDefaultPrevented()) {
20661          return;
20662        }
20663        if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45) {
20664          if (undoManager.typing) {
20665            addNonTypingUndoLevel(e);
20666          }
20667          return;
20668        }
20669        const modKey = e.ctrlKey && !e.altKey || e.metaKey;
20670        if ((keyCode < 16 || keyCode > 20) && keyCode !== 224 && keyCode !== 91 && !undoManager.typing && !modKey) {
20671          undoManager.beforeChange();
20672          setTyping(undoManager, true, locks);
20673          undoManager.add({}, e);
20674          isFirstTypedCharacter.set(true);
20675          return;
20676        }
20677        const hasOnlyMetaOrCtrlModifier = Env.os.isMacOS() ? e.metaKey : e.ctrlKey && !e.altKey;
20678        if (hasOnlyMetaOrCtrlModifier) {
20679          undoManager.beforeChange();
20680        }
20681      });
20682      editor.on('mousedown', e => {
20683        if (undoManager.typing) {
20684          addNonTypingUndoLevel(e);
20685        }
20686      });
20687      const isInsertReplacementText = event => event.inputType === 'insertReplacementText';
20688      const isInsertTextDataNull = event => event.inputType === 'insertText' && event.data === null;
20689      const isInsertFromPasteOrDrop = event => event.inputType === 'insertFromPaste' || event.inputType === 'insertFromDrop';
20690      editor.on('input', e => {
20691        if (e.inputType && (isInsertReplacementText(e) || isInsertTextDataNull(e) || isInsertFromPasteOrDrop(e))) {
20692          addNonTypingUndoLevel(e);
20693        }
20694      });
20695      editor.on('AddUndo Undo Redo ClearUndos', e => {
20696        if (!e.isDefaultPrevented()) {
20697          editor.nodeChanged();
20698        }
20699      });
20700    };
20701    const addKeyboardShortcuts = editor => {
20702      editor.addShortcut('meta+z', '', 'Undo');
20703      editor.addShortcut('meta+y,meta+shift+z', '', 'Redo');
20704    };
20705
20706    const UndoManager = editor => {
20707      const beforeBookmark = value$2();
20708      const locks = Cell(0);
20709      const index = Cell(0);
20710      const undoManager = {
20711        data: [],
20712        typing: false,
20713        beforeChange: () => {
20714          beforeChange(editor, locks, beforeBookmark);
20715        },
20716        add: (level, event) => {
20717          return addUndoLevel(editor, undoManager, index, locks, beforeBookmark, level, event);
20718        },
20719        dispatchChange: () => {
20720          editor.setDirty(true);
20721          const level = createFromEditor(editor);
20722          level.bookmark = getUndoBookmark(editor.selection);
20723          editor.dispatch('change', {
20724            level,
20725            lastLevel: get$b(undoManager.data, index.get()).getOrUndefined()
20726          });
20727        },
20728        undo: () => {
20729          return undo(editor, undoManager, locks, index);
20730        },
20731        redo: () => {
20732          return redo(editor, index, undoManager.data);
20733        },
20734        clear: () => {
20735          clear(editor, undoManager, index);
20736        },
20737        reset: () => {
20738          reset(editor, undoManager);
20739        },
20740        hasUndo: () => {
20741          return hasUndo(editor, undoManager, index);
20742        },
20743        hasRedo: () => {
20744          return hasRedo(editor, undoManager, index);
20745        },
20746        transact: callback => {
20747          return transact(editor, undoManager, locks, callback);
20748        },
20749        ignore: callback => {
20750          ignore(editor, locks, callback);
20751        },
20752        extra: (callback1, callback2) => {
20753          extra(editor, undoManager, index, callback1, callback2);
20754        }
20755      };
20756      if (!isRtc(editor)) {
20757        registerEvents(editor, undoManager, locks);
20758      }
20759      addKeyboardShortcuts(editor);
20760      return undoManager;
20761    };
20762
20763    const nonTypingKeycodes = [
20764      9,
20765      27,
20766      VK.HOME,
20767      VK.END,
20768      19,
20769      20,
20770      44,
20771      144,
20772      145,
20773      33,
20774      34,
20775      45,
20776      16,
20777      17,
20778      18,
20779      91,
20780      92,
20781      93,
20782      VK.DOWN,
20783      VK.UP,
20784      VK.LEFT,
20785      VK.RIGHT
20786    ].concat(Env.browser.isFirefox() ? [224] : []);
20787    const placeholderAttr = 'data-mce-placeholder';
20788    const isKeyboardEvent = e => e.type === 'keydown' || e.type === 'keyup';
20789    const isDeleteEvent = e => {
20790      const keyCode = e.keyCode;
20791      return keyCode === VK.BACKSPACE || keyCode === VK.DELETE;
20792    };
20793    const isNonTypingKeyboardEvent = e => {
20794      if (isKeyboardEvent(e)) {
20795        const keyCode = e.keyCode;
20796        return !isDeleteEvent(e) && (VK.metaKeyPressed(e) || e.altKey || keyCode >= 112 && keyCode <= 123 || contains$2(nonTypingKeycodes, keyCode));
20797      } else {
20798        return false;
20799      }
20800    };
20801    const isTypingKeyboardEvent = e => isKeyboardEvent(e) && !(isDeleteEvent(e) || e.type === 'keyup' && e.keyCode === 229);
20802    const isVisuallyEmpty = (dom, rootElm, forcedRootBlock) => {
20803      if (isEmpty$2(SugarElement.fromDom(rootElm), false)) {
20804        const firstElement = rootElm.firstElementChild;
20805        if (!firstElement) {
20806          return true;
20807        } else if (dom.getStyle(rootElm.firstElementChild, 'padding-left') || dom.getStyle(rootElm.firstElementChild, 'padding-right')) {
20808          return false;
20809        } else {
20810          return forcedRootBlock === firstElement.nodeName.toLowerCase();
20811        }
20812      } else {
20813        return false;
20814      }
20815    };
20816    const setup$q = editor => {
20817      var _a;
20818      const dom = editor.dom;
20819      const rootBlock = getForcedRootBlock(editor);
20820      const placeholder = (_a = getPlaceholder(editor)) !== null && _a !== void 0 ? _a : '';
20821      const updatePlaceholder = (e, initial) => {
20822        if (isNonTypingKeyboardEvent(e)) {
20823          return;
20824        }
20825        const body = editor.getBody();
20826        const showPlaceholder = isTypingKeyboardEvent(e) ? false : isVisuallyEmpty(dom, body, rootBlock);
20827        const isPlaceholderShown = dom.getAttrib(body, placeholderAttr) !== '';
20828        if (isPlaceholderShown !== showPlaceholder || initial) {
20829          dom.setAttrib(body, placeholderAttr, showPlaceholder ? placeholder : null);
20830          dom.setAttrib(body, 'aria-placeholder', showPlaceholder ? placeholder : null);
20831          firePlaceholderToggle(editor, showPlaceholder);
20832          editor.on(showPlaceholder ? 'keydown' : 'keyup', updatePlaceholder);
20833          editor.off(showPlaceholder ? 'keyup' : 'keydown', updatePlaceholder);
20834        }
20835      };
20836      if (isNotEmpty(placeholder)) {
20837        editor.on('init', e => {
20838          updatePlaceholder(e, true);
20839          editor.on('change SetContent ExecCommand', updatePlaceholder);
20840          editor.on('paste', e => Delay.setEditorTimeout(editor, () => updatePlaceholder(e)));
20841        });
20842      }
20843    };
20844
20845    const blockPosition = (block, position) => ({
20846      block,
20847      position
20848    });
20849    const blockBoundary = (from, to) => ({
20850      from,
20851      to
20852    });
20853    const getBlockPosition = (rootNode, pos) => {
20854      const rootElm = SugarElement.fromDom(rootNode);
20855      const containerElm = SugarElement.fromDom(pos.container());
20856      return getParentBlock$2(rootElm, containerElm).map(block => blockPosition(block, pos));
20857    };
20858    const isDifferentBlocks = blockBoundary => !eq(blockBoundary.from.block, blockBoundary.to.block);
20859    const getClosestHost = (root, scope) => {
20860      const isRoot = node => eq(node, root);
20861      const isHost = node => isTableCell$2(node) || isContentEditableTrue$3(node.dom);
20862      return closest$4(scope, isHost, isRoot).filter(isElement$7).getOr(root);
20863    };
20864    const hasSameHost = (rootNode, blockBoundary) => {
20865      const root = SugarElement.fromDom(rootNode);
20866      return eq(getClosestHost(root, blockBoundary.from.block), getClosestHost(root, blockBoundary.to.block));
20867    };
20868    const isEditable$1 = blockBoundary => isContentEditableFalse$b(blockBoundary.from.block.dom) === false && isContentEditableFalse$b(blockBoundary.to.block.dom) === false;
20869    const hasValidBlocks = blockBoundary => {
20870      const isValidBlock = block => isTextBlock$2(block) || hasBlockAttr(block.dom);
20871      return isValidBlock(blockBoundary.from.block) && isValidBlock(blockBoundary.to.block);
20872    };
20873    const skipLastBr = (rootNode, forward, blockPosition) => {
20874      if (isBr$6(blockPosition.position.getNode()) && !isEmpty$2(blockPosition.block)) {
20875        return positionIn(false, blockPosition.block.dom).bind(lastPositionInBlock => {
20876          if (lastPositionInBlock.isEqual(blockPosition.position)) {
20877            return fromPosition(forward, rootNode, lastPositionInBlock).bind(to => getBlockPosition(rootNode, to));
20878          } else {
20879            return Optional.some(blockPosition);
20880          }
20881        }).getOr(blockPosition);
20882      } else {
20883        return blockPosition;
20884      }
20885    };
20886    const readFromRange = (rootNode, forward, rng) => {
20887      const fromBlockPos = getBlockPosition(rootNode, CaretPosition.fromRangeStart(rng));
20888      const toBlockPos = fromBlockPos.bind(blockPos => fromPosition(forward, rootNode, blockPos.position).bind(to => getBlockPosition(rootNode, to).map(blockPos => skipLastBr(rootNode, forward, blockPos))));
20889      return lift2(fromBlockPos, toBlockPos, blockBoundary).filter(blockBoundary => isDifferentBlocks(blockBoundary) && hasSameHost(rootNode, blockBoundary) && isEditable$1(blockBoundary) && hasValidBlocks(blockBoundary));
20890    };
20891    const read$1 = (rootNode, forward, rng) => rng.collapsed ? readFromRange(rootNode, forward, rng) : Optional.none();
20892
20893    const getChildrenUntilBlockBoundary = block => {
20894      const children = children$1(block);
20895      return findIndex$2(children, isBlock$2).fold(constant(children), index => children.slice(0, index));
20896    };
20897    const extractChildren = block => {
20898      const children = getChildrenUntilBlockBoundary(block);
20899      each$e(children, remove$5);
20900      return children;
20901    };
20902    const removeEmptyRoot = (rootNode, block) => {
20903      const parents = parentsAndSelf(block, rootNode);
20904      return find$2(parents.reverse(), element => isEmpty$2(element)).each(remove$5);
20905    };
20906    const isEmptyBefore = el => filter$5(prevSiblings(el), el => !isEmpty$2(el)).length === 0;
20907    const nestedBlockMerge = (rootNode, fromBlock, toBlock, insertionPoint) => {
20908      if (isEmpty$2(toBlock)) {
20909        fillWithPaddingBr(toBlock);
20910        return firstPositionIn(toBlock.dom);
20911      }
20912      if (isEmptyBefore(insertionPoint) && isEmpty$2(fromBlock)) {
20913        before$3(insertionPoint, SugarElement.fromTag('br'));
20914      }
20915      const position = prevPosition(toBlock.dom, CaretPosition.before(insertionPoint.dom));
20916      each$e(extractChildren(fromBlock), child => {
20917        before$3(insertionPoint, child);
20918      });
20919      removeEmptyRoot(rootNode, fromBlock);
20920      return position;
20921    };
20922    const sidelongBlockMerge = (rootNode, fromBlock, toBlock) => {
20923      if (isEmpty$2(toBlock)) {
20924        if (isEmpty$2(fromBlock)) {
20925          const getInlineToBlockDescendants = el => {
20926            const helper = (node, elements) => firstChild(node).fold(() => elements, child => isInline$1(child) ? helper(child, elements.concat(shallow$1(child))) : elements);
20927            return helper(el, []);
20928          };
20929          const newFromBlockDescendants = foldr(getInlineToBlockDescendants(toBlock), (element, descendant) => {
20930            wrap$2(element, descendant);
20931            return descendant;
20932          }, createPaddingBr());
20933          empty(fromBlock);
20934          append$1(fromBlock, newFromBlockDescendants);
20935        }
20936        remove$5(toBlock);
20937        return firstPositionIn(fromBlock.dom);
20938      }
20939      const position = lastPositionIn(toBlock.dom);
20940      each$e(extractChildren(fromBlock), child => {
20941        append$1(toBlock, child);
20942      });
20943      removeEmptyRoot(rootNode, fromBlock);
20944      return position;
20945    };
20946    const findInsertionPoint = (toBlock, block) => {
20947      const parentsAndSelf$1 = parentsAndSelf(block, toBlock);
20948      return Optional.from(parentsAndSelf$1[parentsAndSelf$1.length - 1]);
20949    };
20950    const getInsertionPoint = (fromBlock, toBlock) => contains(toBlock, fromBlock) ? findInsertionPoint(toBlock, fromBlock) : Optional.none();
20951    const trimBr = (first, block) => {
20952      positionIn(first, block.dom).bind(position => Optional.from(position.getNode())).map(SugarElement.fromDom).filter(isBr$5).each(remove$5);
20953    };
20954    const mergeBlockInto = (rootNode, fromBlock, toBlock) => {
20955      trimBr(true, fromBlock);
20956      trimBr(false, toBlock);
20957      return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock), curry(nestedBlockMerge, rootNode, fromBlock, toBlock));
20958    };
20959    const mergeBlocks = (rootNode, forward, block1, block2) => forward ? mergeBlockInto(rootNode, block2, block1) : mergeBlockInto(rootNode, block1, block2);
20960
20961    const backspaceDelete$8 = (editor, forward) => {
20962      const rootNode = SugarElement.fromDom(editor.getBody());
20963      const position = read$1(rootNode.dom, forward, editor.selection.getRng()).map(blockBoundary => () => {
20964        mergeBlocks(rootNode, forward, blockBoundary.from.block, blockBoundary.to.block).each(pos => {
20965          editor.selection.setRng(pos.toRange());
20966        });
20967      });
20968      return position;
20969    };
20970
20971    const deleteRangeMergeBlocks = (rootNode, selection) => {
20972      const rng = selection.getRng();
20973      return lift2(getParentBlock$2(rootNode, SugarElement.fromDom(rng.startContainer)), getParentBlock$2(rootNode, SugarElement.fromDom(rng.endContainer)), (block1, block2) => {
20974        if (!eq(block1, block2)) {
20975          return Optional.some(() => {
20976            rng.deleteContents();
20977            mergeBlocks(rootNode, true, block1, block2).each(pos => {
20978              selection.setRng(pos.toRange());
20979            });
20980          });
20981        } else {
20982          return Optional.none();
20983        }
20984      }).getOr(Optional.none());
20985    };
20986    const isRawNodeInTable = (root, rawNode) => {
20987      const node = SugarElement.fromDom(rawNode);
20988      const isRoot = curry(eq, root);
20989      return ancestor$4(node, isTableCell$2, isRoot).isSome();
20990    };
20991    const isSelectionInTable = (root, rng) => isRawNodeInTable(root, rng.startContainer) || isRawNodeInTable(root, rng.endContainer);
20992    const isEverythingSelected = (root, rng) => {
20993      const noPrevious = prevPosition(root.dom, CaretPosition.fromRangeStart(rng)).isNone();
20994      const noNext = nextPosition(root.dom, CaretPosition.fromRangeEnd(rng)).isNone();
20995      return !isSelectionInTable(root, rng) && noPrevious && noNext;
20996    };
20997    const emptyEditor = editor => {
20998      return Optional.some(() => {
20999        editor.setContent('');
21000        editor.selection.setCursorLocation();
21001      });
21002    };
21003    const deleteRange$2 = editor => {
21004      const rootNode = SugarElement.fromDom(editor.getBody());
21005      const rng = editor.selection.getRng();
21006      return isEverythingSelected(rootNode, rng) ? emptyEditor(editor) : deleteRangeMergeBlocks(rootNode, editor.selection);
21007    };
21008    const backspaceDelete$7 = (editor, _forward) => editor.selection.isCollapsed() ? Optional.none() : deleteRange$2(editor);
21009
21010    const showCaret = (direction, editor, node, before, scrollIntoView) => Optional.from(editor._selectionOverrides.showCaret(direction, node, before, scrollIntoView));
21011    const getNodeRange = node => {
21012      const rng = node.ownerDocument.createRange();
21013      rng.selectNode(node);
21014      return rng;
21015    };
21016    const selectNode = (editor, node) => {
21017      const e = editor.dispatch('BeforeObjectSelected', { target: node });
21018      if (e.isDefaultPrevented()) {
21019        return Optional.none();
21020      }
21021      return Optional.some(getNodeRange(node));
21022    };
21023    const renderCaretAtRange = (editor, range, scrollIntoView) => {
21024      const normalizedRange = normalizeRange(1, editor.getBody(), range);
21025      const caretPosition = CaretPosition.fromRangeStart(normalizedRange);
21026      const caretPositionNode = caretPosition.getNode();
21027      if (isInlineFakeCaretTarget(caretPositionNode)) {
21028        return showCaret(1, editor, caretPositionNode, !caretPosition.isAtEnd(), false);
21029      }
21030      const caretPositionBeforeNode = caretPosition.getNode(true);
21031      if (isInlineFakeCaretTarget(caretPositionBeforeNode)) {
21032        return showCaret(1, editor, caretPositionBeforeNode, false, false);
21033      }
21034      const ceRoot = getContentEditableRoot$1(editor.dom.getRoot(), caretPosition.getNode());
21035      if (isInlineFakeCaretTarget(ceRoot)) {
21036        return showCaret(1, editor, ceRoot, false, scrollIntoView);
21037      }
21038      return Optional.none();
21039    };
21040    const renderRangeCaret = (editor, range, scrollIntoView) => range.collapsed ? renderCaretAtRange(editor, range, scrollIntoView).getOr(range) : range;
21041
21042    const isBeforeBoundary = pos => isBeforeContentEditableFalse(pos) || isBeforeMedia(pos);
21043    const isAfterBoundary = pos => isAfterContentEditableFalse(pos) || isAfterMedia(pos);
21044    const trimEmptyTextNode = (dom, node) => {
21045      if (isText$a(node) && node.data.length === 0) {
21046        dom.remove(node);
21047      }
21048    };
21049    const deleteContentAndShowCaret = (editor, range, node, direction, forward, peekCaretPosition) => {
21050      showCaret(direction, editor, peekCaretPosition.getNode(!forward), forward, true).each(caretRange => {
21051        if (range.collapsed) {
21052          const deleteRange = range.cloneRange();
21053          if (forward) {
21054            deleteRange.setEnd(caretRange.startContainer, caretRange.startOffset);
21055          } else {
21056            deleteRange.setStart(caretRange.endContainer, caretRange.endOffset);
21057          }
21058          deleteRange.deleteContents();
21059        } else {
21060          range.deleteContents();
21061        }
21062        editor.selection.setRng(caretRange);
21063      });
21064      trimEmptyTextNode(editor.dom, node);
21065    };
21066    const deleteBoundaryText = (editor, forward) => {
21067      const range = editor.selection.getRng();
21068      if (!isText$a(range.commonAncestorContainer)) {
21069        return Optional.none();
21070      }
21071      const direction = forward ? HDirection.Forwards : HDirection.Backwards;
21072      const caretWalker = CaretWalker(editor.getBody());
21073      const getNextPosFn = curry(getVisualCaretPosition, forward ? caretWalker.next : caretWalker.prev);
21074      const isBeforeFn = forward ? isBeforeBoundary : isAfterBoundary;
21075      const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
21076      const nextCaretPosition = getNextPosFn(caretPosition);
21077      const normalizedNextCaretPosition = nextCaretPosition ? normalizePosition(forward, nextCaretPosition) : nextCaretPosition;
21078      if (!normalizedNextCaretPosition || !isMoveInsideSameBlock(caretPosition, normalizedNextCaretPosition)) {
21079        return Optional.none();
21080      } else if (isBeforeFn(normalizedNextCaretPosition)) {
21081        return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, normalizedNextCaretPosition));
21082      }
21083      const peekCaretPosition = getNextPosFn(normalizedNextCaretPosition);
21084      if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
21085        if (isMoveInsideSameBlock(normalizedNextCaretPosition, peekCaretPosition)) {
21086          return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, peekCaretPosition));
21087        }
21088      }
21089      return Optional.none();
21090    };
21091    const backspaceDelete$6 = (editor, forward) => deleteBoundaryText(editor, forward);
21092
21093    const getEdgeCefPosition = (editor, atStart) => {
21094      const root = editor.getBody();
21095      return atStart ? firstPositionIn(root).filter(isBeforeContentEditableFalse) : lastPositionIn(root).filter(isAfterContentEditableFalse);
21096    };
21097    const isCefAtEdgeSelected = editor => {
21098      const rng = editor.selection.getRng();
21099      return !rng.collapsed && (getEdgeCefPosition(editor, true).exists(pos => pos.isEqual(CaretPosition.fromRangeStart(rng))) || getEdgeCefPosition(editor, false).exists(pos => pos.isEqual(CaretPosition.fromRangeEnd(rng))));
21100    };
21101
21102    const isCompoundElement = node => isNonNullable(node) && (isTableCell$2(SugarElement.fromDom(node)) || isListItem$1(SugarElement.fromDom(node)));
21103    const DeleteAction = Adt.generate([
21104      { remove: ['element'] },
21105      { moveToElement: ['element'] },
21106      { moveToPosition: ['position'] }
21107    ]);
21108    const isAtContentEditableBlockCaret = (forward, from) => {
21109      const elm = from.getNode(!forward);
21110      const caretLocation = forward ? 'after' : 'before';
21111      return isElement$6(elm) && elm.getAttribute('data-mce-caret') === caretLocation;
21112    };
21113    const isDeleteFromCefDifferentBlocks = (root, forward, from, to) => {
21114      const inSameBlock = elm => isInline$1(SugarElement.fromDom(elm)) && !isInSameBlock(from, to, root);
21115      return getRelativeCefElm(!forward, from).fold(() => getRelativeCefElm(forward, to).fold(never, inSameBlock), inSameBlock);
21116    };
21117    const deleteEmptyBlockOrMoveToCef = (root, forward, from, to) => {
21118      const toCefElm = to.getNode(!forward);
21119      return getParentBlock$2(SugarElement.fromDom(root), SugarElement.fromDom(from.getNode())).map(blockElm => isEmpty$2(blockElm) ? DeleteAction.remove(blockElm.dom) : DeleteAction.moveToElement(toCefElm)).orThunk(() => Optional.some(DeleteAction.moveToElement(toCefElm)));
21120    };
21121    const findCefPosition = (root, forward, from) => fromPosition(forward, root, from).bind(to => {
21122      if (isCompoundElement(to.getNode())) {
21123        return Optional.none();
21124      } else if (isDeleteFromCefDifferentBlocks(root, forward, from, to)) {
21125        return Optional.none();
21126      } else if (forward && isContentEditableFalse$b(to.getNode())) {
21127        return deleteEmptyBlockOrMoveToCef(root, forward, from, to);
21128      } else if (!forward && isContentEditableFalse$b(to.getNode(true))) {
21129        return deleteEmptyBlockOrMoveToCef(root, forward, from, to);
21130      } else if (forward && isAfterContentEditableFalse(from)) {
21131        return Optional.some(DeleteAction.moveToPosition(to));
21132      } else if (!forward && isBeforeContentEditableFalse(from)) {
21133        return Optional.some(DeleteAction.moveToPosition(to));
21134      } else {
21135        return Optional.none();
21136      }
21137    });
21138    const getContentEditableBlockAction = (forward, elm) => {
21139      if (isNullable(elm)) {
21140        return Optional.none();
21141      } else if (forward && isContentEditableFalse$b(elm.nextSibling)) {
21142        return Optional.some(DeleteAction.moveToElement(elm.nextSibling));
21143      } else if (!forward && isContentEditableFalse$b(elm.previousSibling)) {
21144        return Optional.some(DeleteAction.moveToElement(elm.previousSibling));
21145      } else {
21146        return Optional.none();
21147      }
21148    };
21149    const skipMoveToActionFromInlineCefToContent = (root, from, deleteAction) => deleteAction.fold(elm => Optional.some(DeleteAction.remove(elm)), elm => Optional.some(DeleteAction.moveToElement(elm)), to => {
21150      if (isInSameBlock(from, to, root)) {
21151        return Optional.none();
21152      } else {
21153        return Optional.some(DeleteAction.moveToPosition(to));
21154      }
21155    });
21156    const getContentEditableAction = (root, forward, from) => {
21157      if (isAtContentEditableBlockCaret(forward, from)) {
21158        return getContentEditableBlockAction(forward, from.getNode(!forward)).orThunk(() => findCefPosition(root, forward, from));
21159      } else {
21160        return findCefPosition(root, forward, from).bind(deleteAction => skipMoveToActionFromInlineCefToContent(root, from, deleteAction));
21161      }
21162    };
21163    const read = (root, forward, rng) => {
21164      const normalizedRange = normalizeRange(forward ? 1 : -1, root, rng);
21165      const from = CaretPosition.fromRangeStart(normalizedRange);
21166      const rootElement = SugarElement.fromDom(root);
21167      if (!forward && isAfterContentEditableFalse(from)) {
21168        return Optional.some(DeleteAction.remove(from.getNode(true)));
21169      } else if (forward && isBeforeContentEditableFalse(from)) {
21170        return Optional.some(DeleteAction.remove(from.getNode()));
21171      } else if (!forward && isBeforeContentEditableFalse(from) && isAfterBr(rootElement, from)) {
21172        return findPreviousBr(rootElement, from).map(br => DeleteAction.remove(br.getNode()));
21173      } else if (forward && isAfterContentEditableFalse(from) && isBeforeBr$1(rootElement, from)) {
21174        return findNextBr(rootElement, from).map(br => DeleteAction.remove(br.getNode()));
21175      } else {
21176        return getContentEditableAction(root, forward, from);
21177      }
21178    };
21179
21180    const deleteElement$1 = (editor, forward) => element => {
21181      editor._selectionOverrides.hideFakeCaret();
21182      deleteElement$2(editor, forward, SugarElement.fromDom(element));
21183      return true;
21184    };
21185    const moveToElement = (editor, forward) => element => {
21186      const pos = forward ? CaretPosition.before(element) : CaretPosition.after(element);
21187      editor.selection.setRng(pos.toRange());
21188      return true;
21189    };
21190    const moveToPosition = editor => pos => {
21191      editor.selection.setRng(pos.toRange());
21192      return true;
21193    };
21194    const getAncestorCe = (editor, node) => Optional.from(getContentEditableRoot$1(editor.getBody(), node));
21195    const backspaceDeleteCaret = (editor, forward) => {
21196      const selectedNode = editor.selection.getNode();
21197      return getAncestorCe(editor, selectedNode).filter(isContentEditableFalse$b).fold(() => read(editor.getBody(), forward, editor.selection.getRng()).map(deleteAction => () => deleteAction.fold(deleteElement$1(editor, forward), moveToElement(editor, forward), moveToPosition(editor))), () => Optional.some(noop));
21198    };
21199    const deleteOffscreenSelection = rootElement => {
21200      each$e(descendants(rootElement, '.mce-offscreen-selection'), remove$5);
21201    };
21202    const backspaceDeleteRange = (editor, forward) => {
21203      const selectedNode = editor.selection.getNode();
21204      if (isContentEditableFalse$b(selectedNode) && !isTableCell$3(selectedNode)) {
21205        const hasCefAncestor = getAncestorCe(editor, selectedNode.parentNode).filter(isContentEditableFalse$b);
21206        return hasCefAncestor.fold(() => Optional.some(() => {
21207          deleteOffscreenSelection(SugarElement.fromDom(editor.getBody()));
21208          deleteElement$2(editor, forward, SugarElement.fromDom(editor.selection.getNode()));
21209          paddEmptyBody(editor);
21210        }), () => Optional.some(noop));
21211      }
21212      if (isCefAtEdgeSelected(editor)) {
21213        return Optional.some(() => {
21214          deleteRangeContents(editor, editor.selection.getRng(), SugarElement.fromDom(editor.getBody()));
21215        });
21216      }
21217      return Optional.none();
21218    };
21219    const paddEmptyElement = editor => {
21220      const dom = editor.dom, selection = editor.selection;
21221      const ceRoot = getContentEditableRoot$1(editor.getBody(), selection.getNode());
21222      if (isContentEditableTrue$3(ceRoot) && dom.isBlock(ceRoot) && dom.isEmpty(ceRoot)) {
21223        const br = dom.create('br', { 'data-mce-bogus': '1' });
21224        dom.setHTML(ceRoot, '');
21225        ceRoot.appendChild(br);
21226        selection.setRng(CaretPosition.before(br).toRange());
21227      }
21228      return true;
21229    };
21230    const backspaceDelete$5 = (editor, forward) => {
21231      if (editor.selection.isCollapsed()) {
21232        return backspaceDeleteCaret(editor, forward);
21233      } else {
21234        return backspaceDeleteRange(editor, forward);
21235      }
21236    };
21237
21238    const deleteCaret$2 = (editor, forward) => {
21239      const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
21240      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));
21241    };
21242    const backspaceDelete$4 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$2(editor, forward) : Optional.none();
21243
21244    const isText$2 = isText$a;
21245    const startsWithCaretContainer = node => isText$2(node) && node.data[0] === ZWSP$1;
21246    const endsWithCaretContainer = node => isText$2(node) && node.data[node.data.length - 1] === ZWSP$1;
21247    const createZwsp = node => {
21248      var _a;
21249      const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
21250      return doc.createTextNode(ZWSP$1);
21251    };
21252    const insertBefore = node => {
21253      var _a;
21254      if (isText$2(node.previousSibling)) {
21255        if (endsWithCaretContainer(node.previousSibling)) {
21256          return node.previousSibling;
21257        } else {
21258          node.previousSibling.appendData(ZWSP$1);
21259          return node.previousSibling;
21260        }
21261      } else if (isText$2(node)) {
21262        if (startsWithCaretContainer(node)) {
21263          return node;
21264        } else {
21265          node.insertData(0, ZWSP$1);
21266          return node;
21267        }
21268      } else {
21269        const newNode = createZwsp(node);
21270        (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node);
21271        return newNode;
21272      }
21273    };
21274    const insertAfter = node => {
21275      var _a, _b;
21276      if (isText$2(node.nextSibling)) {
21277        if (startsWithCaretContainer(node.nextSibling)) {
21278          return node.nextSibling;
21279        } else {
21280          node.nextSibling.insertData(0, ZWSP$1);
21281          return node.nextSibling;
21282        }
21283      } else if (isText$2(node)) {
21284        if (endsWithCaretContainer(node)) {
21285          return node;
21286        } else {
21287          node.appendData(ZWSP$1);
21288          return node;
21289        }
21290      } else {
21291        const newNode = createZwsp(node);
21292        if (node.nextSibling) {
21293          (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node.nextSibling);
21294        } else {
21295          (_b = node.parentNode) === null || _b === void 0 ? void 0 : _b.appendChild(newNode);
21296        }
21297        return newNode;
21298      }
21299    };
21300    const insertInline = (before, node) => before ? insertBefore(node) : insertAfter(node);
21301    const insertInlineBefore = curry(insertInline, true);
21302    const insertInlineAfter = curry(insertInline, false);
21303
21304    const insertInlinePos = (pos, before) => {
21305      if (isText$a(pos.container())) {
21306        return insertInline(before, pos.container());
21307      } else {
21308        return insertInline(before, pos.getNode());
21309      }
21310    };
21311    const isPosCaretContainer = (pos, caret) => {
21312      const caretNode = caret.get();
21313      return caretNode && pos.container() === caretNode && isCaretContainerInline(caretNode);
21314    };
21315    const renderCaret = (caret, location) => location.fold(element => {
21316      remove$3(caret.get());
21317      const text = insertInlineBefore(element);
21318      caret.set(text);
21319      return Optional.some(CaretPosition(text, text.length - 1));
21320    }, element => firstPositionIn(element).map(pos => {
21321      if (!isPosCaretContainer(pos, caret)) {
21322        remove$3(caret.get());
21323        const text = insertInlinePos(pos, true);
21324        caret.set(text);
21325        return CaretPosition(text, 1);
21326      } else {
21327        const node = caret.get();
21328        return CaretPosition(node, 1);
21329      }
21330    }), element => lastPositionIn(element).map(pos => {
21331      if (!isPosCaretContainer(pos, caret)) {
21332        remove$3(caret.get());
21333        const text = insertInlinePos(pos, false);
21334        caret.set(text);
21335        return CaretPosition(text, text.length - 1);
21336      } else {
21337        const node = caret.get();
21338        return CaretPosition(node, node.length - 1);
21339      }
21340    }), element => {
21341      remove$3(caret.get());
21342      const text = insertInlineAfter(element);
21343      caret.set(text);
21344      return Optional.some(CaretPosition(text, 1));
21345    });
21346
21347    const evaluateUntil = (fns, args) => {
21348      for (let i = 0; i < fns.length; i++) {
21349        const result = fns[i].apply(null, args);
21350        if (result.isSome()) {
21351          return result;
21352        }
21353      }
21354      return Optional.none();
21355    };
21356
21357    const Location = Adt.generate([
21358      { before: ['element'] },
21359      { start: ['element'] },
21360      { end: ['element'] },
21361      { after: ['element'] }
21362    ]);
21363    const rescope$1 = (rootNode, node) => {
21364      const parentBlock = getParentBlock$3(node, rootNode);
21365      return parentBlock ? parentBlock : rootNode;
21366    };
21367    const before = (isInlineTarget, rootNode, pos) => {
21368      const nPos = normalizeForwards(pos);
21369      const scope = rescope$1(rootNode, nPos.container());
21370      return findRootInline(isInlineTarget, scope, nPos).fold(() => nextPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.before(inline)), Optional.none);
21371    };
21372    const isNotInsideFormatCaretContainer = (rootNode, elm) => getParentCaretContainer(rootNode, elm) === null;
21373    const findInsideRootInline = (isInlineTarget, rootNode, pos) => findRootInline(isInlineTarget, rootNode, pos).filter(curry(isNotInsideFormatCaretContainer, rootNode));
21374    const start$1 = (isInlineTarget, rootNode, pos) => {
21375      const nPos = normalizeBackwards(pos);
21376      return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
21377        const prevPos = prevPosition(inline, nPos);
21378        return prevPos.isNone() ? Optional.some(Location.start(inline)) : Optional.none();
21379      });
21380    };
21381    const end = (isInlineTarget, rootNode, pos) => {
21382      const nPos = normalizeForwards(pos);
21383      return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
21384        const nextPos = nextPosition(inline, nPos);
21385        return nextPos.isNone() ? Optional.some(Location.end(inline)) : Optional.none();
21386      });
21387    };
21388    const after = (isInlineTarget, rootNode, pos) => {
21389      const nPos = normalizeBackwards(pos);
21390      const scope = rescope$1(rootNode, nPos.container());
21391      return findRootInline(isInlineTarget, scope, nPos).fold(() => prevPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.after(inline)), Optional.none);
21392    };
21393    const isValidLocation = location => !isRtl(getElement(location));
21394    const readLocation = (isInlineTarget, rootNode, pos) => {
21395      const location = evaluateUntil([
21396        before,
21397        start$1,
21398        end,
21399        after
21400      ], [
21401        isInlineTarget,
21402        rootNode,
21403        pos
21404      ]);
21405      return location.filter(isValidLocation);
21406    };
21407    const getElement = location => location.fold(identity, identity, identity, identity);
21408    const getName = location => location.fold(constant('before'), constant('start'), constant('end'), constant('after'));
21409    const outside = location => location.fold(Location.before, Location.before, Location.after, Location.after);
21410    const inside = location => location.fold(Location.start, Location.start, Location.end, Location.end);
21411    const isEq = (location1, location2) => getName(location1) === getName(location2) && getElement(location1) === getElement(location2);
21412    const betweenInlines = (forward, isInlineTarget, rootNode, from, to, location) => lift2(findRootInline(isInlineTarget, rootNode, from), findRootInline(isInlineTarget, rootNode, to), (fromInline, toInline) => {
21413      if (fromInline !== toInline && hasSameParentBlock(rootNode, fromInline, toInline)) {
21414        return Location.after(forward ? fromInline : toInline);
21415      } else {
21416        return location;
21417      }
21418    }).getOr(location);
21419    const skipNoMovement = (fromLocation, toLocation) => fromLocation.fold(always, fromLocation => !isEq(fromLocation, toLocation));
21420    const findLocationTraverse = (forward, isInlineTarget, rootNode, fromLocation, pos) => {
21421      const from = normalizePosition(forward, pos);
21422      const to = fromPosition(forward, rootNode, from).map(curry(normalizePosition, forward));
21423      const location = to.fold(() => fromLocation.map(outside), to => readLocation(isInlineTarget, rootNode, to).map(curry(betweenInlines, forward, isInlineTarget, rootNode, from, to)).filter(curry(skipNoMovement, fromLocation)));
21424      return location.filter(isValidLocation);
21425    };
21426    const findLocationSimple = (forward, location) => {
21427      if (forward) {
21428        return location.fold(compose(Optional.some, Location.start), Optional.none, compose(Optional.some, Location.after), Optional.none);
21429      } else {
21430        return location.fold(Optional.none, compose(Optional.some, Location.before), Optional.none, compose(Optional.some, Location.end));
21431      }
21432    };
21433    const findLocation$1 = (forward, isInlineTarget, rootNode, pos) => {
21434      const from = normalizePosition(forward, pos);
21435      const fromLocation = readLocation(isInlineTarget, rootNode, from);
21436      return readLocation(isInlineTarget, rootNode, from).bind(curry(findLocationSimple, forward)).orThunk(() => findLocationTraverse(forward, isInlineTarget, rootNode, fromLocation, pos));
21437    };
21438
21439    const hasSelectionModifyApi = editor => {
21440      return isFunction(editor.selection.getSel().modify);
21441    };
21442    const moveRel = (forward, selection, pos) => {
21443      const delta = forward ? 1 : -1;
21444      selection.setRng(CaretPosition(pos.container(), pos.offset() + delta).toRange());
21445      selection.getSel().modify('move', forward ? 'forward' : 'backward', 'word');
21446      return true;
21447    };
21448    const moveByWord = (forward, editor) => {
21449      const rng = editor.selection.getRng();
21450      const pos = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
21451      if (!hasSelectionModifyApi(editor)) {
21452        return false;
21453      } else if (forward && isBeforeInline(pos)) {
21454        return moveRel(true, editor.selection, pos);
21455      } else if (!forward && isAfterInline(pos)) {
21456        return moveRel(false, editor.selection, pos);
21457      } else {
21458        return false;
21459      }
21460    };
21461
21462    var BreakType;
21463    (function (BreakType) {
21464      BreakType[BreakType['Br'] = 0] = 'Br';
21465      BreakType[BreakType['Block'] = 1] = 'Block';
21466      BreakType[BreakType['Wrap'] = 2] = 'Wrap';
21467      BreakType[BreakType['Eol'] = 3] = 'Eol';
21468    }(BreakType || (BreakType = {})));
21469    const flip = (direction, positions) => direction === HDirection.Backwards ? reverse(positions) : positions;
21470    const walk$1 = (direction, caretWalker, pos) => direction === HDirection.Forwards ? caretWalker.next(pos) : caretWalker.prev(pos);
21471    const getBreakType = (scope, direction, currentPos, nextPos) => {
21472      if (isBr$6(nextPos.getNode(direction === HDirection.Forwards))) {
21473        return BreakType.Br;
21474      } else if (isInSameBlock(currentPos, nextPos) === false) {
21475        return BreakType.Block;
21476      } else {
21477        return BreakType.Wrap;
21478      }
21479    };
21480    const getPositionsUntil = (predicate, direction, scope, start) => {
21481      const caretWalker = CaretWalker(scope);
21482      let currentPos = start;
21483      const positions = [];
21484      while (currentPos) {
21485        const nextPos = walk$1(direction, caretWalker, currentPos);
21486        if (!nextPos) {
21487          break;
21488        }
21489        if (isBr$6(nextPos.getNode(false))) {
21490          if (direction === HDirection.Forwards) {
21491            return {
21492              positions: flip(direction, positions).concat([nextPos]),
21493              breakType: BreakType.Br,
21494              breakAt: Optional.some(nextPos)
21495            };
21496          } else {
21497            return {
21498              positions: flip(direction, positions),
21499              breakType: BreakType.Br,
21500              breakAt: Optional.some(nextPos)
21501            };
21502          }
21503        }
21504        if (!nextPos.isVisible()) {
21505          currentPos = nextPos;
21506          continue;
21507        }
21508        if (predicate(currentPos, nextPos)) {
21509          const breakType = getBreakType(scope, direction, currentPos, nextPos);
21510          return {
21511            positions: flip(direction, positions),
21512            breakType,
21513            breakAt: Optional.some(nextPos)
21514          };
21515        }
21516        positions.push(nextPos);
21517        currentPos = nextPos;
21518      }
21519      return {
21520        positions: flip(direction, positions),
21521        breakType: BreakType.Eol,
21522        breakAt: Optional.none()
21523      };
21524    };
21525    const getAdjacentLinePositions = (direction, getPositionsUntilBreak, scope, start) => getPositionsUntilBreak(scope, start).breakAt.map(pos => {
21526      const positions = getPositionsUntilBreak(scope, pos).positions;
21527      return direction === HDirection.Backwards ? positions.concat(pos) : [pos].concat(positions);
21528    }).getOr([]);
21529    const findClosestHorizontalPositionFromPoint = (positions, x) => foldl(positions, (acc, newPos) => acc.fold(() => Optional.some(newPos), lastPos => lift2(head(lastPos.getClientRects()), head(newPos.getClientRects()), (lastRect, newRect) => {
21530      const lastDist = Math.abs(x - lastRect.left);
21531      const newDist = Math.abs(x - newRect.left);
21532      return newDist <= lastDist ? newPos : lastPos;
21533    }).or(acc)), Optional.none());
21534    const findClosestHorizontalPosition = (positions, pos) => head(pos.getClientRects()).bind(targetRect => findClosestHorizontalPositionFromPoint(positions, targetRect.left));
21535    const getPositionsUntilPreviousLine = curry(getPositionsUntil, CaretPosition.isAbove, -1);
21536    const getPositionsUntilNextLine = curry(getPositionsUntil, CaretPosition.isBelow, 1);
21537    const getPositionsAbove = curry(getAdjacentLinePositions, -1, getPositionsUntilPreviousLine);
21538    const getPositionsBelow = curry(getAdjacentLinePositions, 1, getPositionsUntilNextLine);
21539    const isAtFirstLine = (scope, pos) => getPositionsUntilPreviousLine(scope, pos).breakAt.isNone();
21540    const isAtLastLine = (scope, pos) => getPositionsUntilNextLine(scope, pos).breakAt.isNone();
21541    const getFirstLinePositions = scope => firstPositionIn(scope).map(pos => [pos].concat(getPositionsUntilNextLine(scope, pos).positions)).getOr([]);
21542    const getLastLinePositions = scope => lastPositionIn(scope).map(pos => getPositionsUntilPreviousLine(scope, pos).positions.concat(pos)).getOr([]);
21543    const getClosestPositionAbove = (scope, pos) => findClosestHorizontalPosition(getPositionsAbove(scope, pos), pos);
21544    const getClosestPositionBelow = (scope, pos) => findClosestHorizontalPosition(getPositionsBelow(scope, pos), pos);
21545
21546    const isContentEditableFalse$4 = isContentEditableFalse$b;
21547    const distanceToRectLeft$1 = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
21548    const distanceToRectRight$1 = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
21549    const isNodeClientRect = rect => hasNonNullableKey(rect, 'node');
21550    const findClosestClientRect = (clientRects, clientX) => reduce(clientRects, (oldClientRect, clientRect) => {
21551      const oldDistance = Math.min(distanceToRectLeft$1(oldClientRect, clientX), distanceToRectRight$1(oldClientRect, clientX));
21552      const newDistance = Math.min(distanceToRectLeft$1(clientRect, clientX), distanceToRectRight$1(clientRect, clientX));
21553      if (newDistance === oldDistance && isNodeClientRect(clientRect) && isContentEditableFalse$4(clientRect.node)) {
21554        return clientRect;
21555      }
21556      if (newDistance < oldDistance) {
21557        return clientRect;
21558      }
21559      return oldClientRect;
21560    });
21561
21562    const getNodeClientRects = node => {
21563      const toArrayWithNode = clientRects => {
21564        return map$3(clientRects, rect => {
21565          const clientRect = clone$1(rect);
21566          clientRect.node = node;
21567          return clientRect;
21568        });
21569      };
21570      if (isElement$6(node)) {
21571        return toArrayWithNode(node.getClientRects());
21572      } else if (isText$a(node)) {
21573        const rng = node.ownerDocument.createRange();
21574        rng.setStart(node, 0);
21575        rng.setEnd(node, node.data.length);
21576        return toArrayWithNode(rng.getClientRects());
21577      } else {
21578        return [];
21579      }
21580    };
21581    const getClientRects = nodes => bind$3(nodes, getNodeClientRects);
21582
21583    var VDirection;
21584    (function (VDirection) {
21585      VDirection[VDirection['Up'] = -1] = 'Up';
21586      VDirection[VDirection['Down'] = 1] = 'Down';
21587    }(VDirection || (VDirection = {})));
21588    const findUntil = (direction, root, predicateFn, node) => {
21589      let currentNode = node;
21590      while (currentNode = findNode(currentNode, direction, isEditableCaretCandidate$1, root)) {
21591        if (predicateFn(currentNode)) {
21592          return;
21593        }
21594      }
21595    };
21596    const walkUntil = (direction, isAboveFn, isBeflowFn, root, predicateFn, caretPosition) => {
21597      let line = 0;
21598      const result = [];
21599      const add = node => {
21600        let clientRects = getClientRects([node]);
21601        if (direction === -1) {
21602          clientRects = clientRects.reverse();
21603        }
21604        for (let i = 0; i < clientRects.length; i++) {
21605          const clientRect = clientRects[i];
21606          if (isBeflowFn(clientRect, targetClientRect)) {
21607            continue;
21608          }
21609          if (result.length > 0 && isAboveFn(clientRect, last$2(result))) {
21610            line++;
21611          }
21612          clientRect.line = line;
21613          if (predicateFn(clientRect)) {
21614            return true;
21615          }
21616          result.push(clientRect);
21617        }
21618        return false;
21619      };
21620      const targetClientRect = last$2(caretPosition.getClientRects());
21621      if (!targetClientRect) {
21622        return result;
21623      }
21624      const node = caretPosition.getNode();
21625      if (node) {
21626        add(node);
21627        findUntil(direction, root, add, node);
21628      }
21629      return result;
21630    };
21631    const aboveLineNumber = (lineNumber, clientRect) => clientRect.line > lineNumber;
21632    const isLineNumber = (lineNumber, clientRect) => clientRect.line === lineNumber;
21633    const upUntil = curry(walkUntil, VDirection.Up, isAbove$1, isBelow$1);
21634    const downUntil = curry(walkUntil, VDirection.Down, isBelow$1, isAbove$1);
21635    const getLastClientRect = caretPosition => {
21636      return last$2(caretPosition.getClientRects());
21637    };
21638    const positionsUntil = (direction, root, predicateFn, node) => {
21639      const caretWalker = CaretWalker(root);
21640      let walkFn;
21641      let isBelowFn;
21642      let isAboveFn;
21643      let caretPosition;
21644      const result = [];
21645      let line = 0;
21646      if (direction === 1) {
21647        walkFn = caretWalker.next;
21648        isBelowFn = isBelow$1;
21649        isAboveFn = isAbove$1;
21650        caretPosition = CaretPosition.after(node);
21651      } else {
21652        walkFn = caretWalker.prev;
21653        isBelowFn = isAbove$1;
21654        isAboveFn = isBelow$1;
21655        caretPosition = CaretPosition.before(node);
21656      }
21657      const targetClientRect = getLastClientRect(caretPosition);
21658      do {
21659        if (!caretPosition.isVisible()) {
21660          continue;
21661        }
21662        const rect = getLastClientRect(caretPosition);
21663        if (isAboveFn(rect, targetClientRect)) {
21664          continue;
21665        }
21666        if (result.length > 0 && isBelowFn(rect, last$2(result))) {
21667          line++;
21668        }
21669        const clientRect = clone$1(rect);
21670        clientRect.position = caretPosition;
21671        clientRect.line = line;
21672        if (predicateFn(clientRect)) {
21673          return result;
21674        }
21675        result.push(clientRect);
21676      } while (caretPosition = walkFn(caretPosition));
21677      return result;
21678    };
21679    const isAboveLine = lineNumber => clientRect => aboveLineNumber(lineNumber, clientRect);
21680    const isLine = lineNumber => clientRect => isLineNumber(lineNumber, clientRect);
21681
21682    const moveToRange = (editor, rng) => {
21683      editor.selection.setRng(rng);
21684      scrollRangeIntoView(editor, editor.selection.getRng());
21685    };
21686    const renderRangeCaretOpt = (editor, range, scrollIntoView) => Optional.some(renderRangeCaret(editor, range, scrollIntoView));
21687    const moveHorizontally = (editor, direction, range, isBefore, isAfter, isElement) => {
21688      const forwards = direction === HDirection.Forwards;
21689      const caretWalker = CaretWalker(editor.getBody());
21690      const getNextPosFn = curry(getVisualCaretPosition, forwards ? caretWalker.next : caretWalker.prev);
21691      const isBeforeFn = forwards ? isBefore : isAfter;
21692      if (!range.collapsed) {
21693        const node = getSelectedNode(range);
21694        if (isElement(node)) {
21695          return showCaret(direction, editor, node, direction === HDirection.Backwards, false);
21696        } else if (isCefAtEdgeSelected(editor)) {
21697          const newRange = range.cloneRange();
21698          newRange.collapse(direction === HDirection.Backwards);
21699          return Optional.from(newRange);
21700        }
21701      }
21702      const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
21703      if (isBeforeFn(caretPosition)) {
21704        return selectNode(editor, caretPosition.getNode(!forwards));
21705      }
21706      let nextCaretPosition = getNextPosFn(caretPosition);
21707      const rangeIsInContainerBlock = isRangeInCaretContainerBlock(range);
21708      if (!nextCaretPosition) {
21709        return rangeIsInContainerBlock ? Optional.some(range) : Optional.none();
21710      } else {
21711        nextCaretPosition = normalizePosition(forwards, nextCaretPosition);
21712      }
21713      if (isBeforeFn(nextCaretPosition)) {
21714        return showCaret(direction, editor, nextCaretPosition.getNode(!forwards), forwards, false);
21715      }
21716      const peekCaretPosition = getNextPosFn(nextCaretPosition);
21717      if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
21718        if (isMoveInsideSameBlock(nextCaretPosition, peekCaretPosition)) {
21719          return showCaret(direction, editor, peekCaretPosition.getNode(!forwards), forwards, false);
21720        }
21721      }
21722      if (rangeIsInContainerBlock) {
21723        return renderRangeCaretOpt(editor, nextCaretPosition.toRange(), false);
21724      }
21725      return Optional.none();
21726    };
21727    const moveVertically = (editor, direction, range, isBefore, isAfter, isElement) => {
21728      const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
21729      const caretClientRect = last$2(caretPosition.getClientRects());
21730      const forwards = direction === VDirection.Down;
21731      const root = editor.getBody();
21732      if (!caretClientRect) {
21733        return Optional.none();
21734      }
21735      if (isCefAtEdgeSelected(editor)) {
21736        const caretPosition = forwards ? CaretPosition.fromRangeEnd(range) : CaretPosition.fromRangeStart(range);
21737        const getClosestFn = !forwards ? getClosestPositionAbove : getClosestPositionBelow;
21738        return getClosestFn(root, caretPosition).orThunk(() => Optional.from(caretPosition)).map(pos => pos.toRange());
21739      }
21740      const walkerFn = forwards ? downUntil : upUntil;
21741      const linePositions = walkerFn(root, isAboveLine(1), caretPosition);
21742      const nextLinePositions = filter$5(linePositions, isLine(1));
21743      const clientX = caretClientRect.left;
21744      const nextLineRect = findClosestClientRect(nextLinePositions, clientX);
21745      if (nextLineRect && isElement(nextLineRect.node)) {
21746        const dist1 = Math.abs(clientX - nextLineRect.left);
21747        const dist2 = Math.abs(clientX - nextLineRect.right);
21748        return showCaret(direction, editor, nextLineRect.node, dist1 < dist2, false);
21749      }
21750      let currentNode;
21751      if (isBefore(caretPosition)) {
21752        currentNode = caretPosition.getNode();
21753      } else if (isAfter(caretPosition)) {
21754        currentNode = caretPosition.getNode(true);
21755      } else {
21756        currentNode = getSelectedNode(range);
21757      }
21758      if (currentNode) {
21759        const caretPositions = positionsUntil(direction, root, isAboveLine(1), currentNode);
21760        let closestNextLineRect = findClosestClientRect(filter$5(caretPositions, isLine(1)), clientX);
21761        if (closestNextLineRect) {
21762          return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
21763        }
21764        closestNextLineRect = last$2(filter$5(caretPositions, isLine(0)));
21765        if (closestNextLineRect) {
21766          return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
21767        }
21768      }
21769      if (nextLinePositions.length === 0) {
21770        return getLineEndPoint(editor, forwards).filter(forwards ? isAfter : isBefore).map(pos => renderRangeCaret(editor, pos.toRange(), false));
21771      }
21772      return Optional.none();
21773    };
21774    const getLineEndPoint = (editor, forward) => {
21775      const rng = editor.selection.getRng();
21776      const from = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
21777      const host = getEditingHost(from.container(), editor.getBody());
21778      if (forward) {
21779        const lineInfo = getPositionsUntilNextLine(host, from);
21780        return last$3(lineInfo.positions);
21781      } else {
21782        const lineInfo = getPositionsUntilPreviousLine(host, from);
21783        return head(lineInfo.positions);
21784      }
21785    };
21786    const moveToLineEndPoint$3 = (editor, forward, isElementPosition) => getLineEndPoint(editor, forward).filter(isElementPosition).exists(pos => {
21787      editor.selection.setRng(pos.toRange());
21788      return true;
21789    });
21790
21791    const setCaretPosition = (editor, pos) => {
21792      const rng = editor.dom.createRng();
21793      rng.setStart(pos.container(), pos.offset());
21794      rng.setEnd(pos.container(), pos.offset());
21795      editor.selection.setRng(rng);
21796    };
21797    const setSelected = (state, elm) => {
21798      if (state) {
21799        elm.setAttribute('data-mce-selected', 'inline-boundary');
21800      } else {
21801        elm.removeAttribute('data-mce-selected');
21802      }
21803    };
21804    const renderCaretLocation = (editor, caret, location) => renderCaret(caret, location).map(pos => {
21805      setCaretPosition(editor, pos);
21806      return location;
21807    });
21808    const getPositionFromRange = (range, root, forward) => {
21809      const start = CaretPosition.fromRangeStart(range);
21810      if (range.collapsed) {
21811        return start;
21812      } else {
21813        const end = CaretPosition.fromRangeEnd(range);
21814        return forward ? prevPosition(root, end).getOr(end) : nextPosition(root, start).getOr(start);
21815      }
21816    };
21817    const findLocation = (editor, caret, forward) => {
21818      const rootNode = editor.getBody();
21819      const from = getPositionFromRange(editor.selection.getRng(), rootNode, forward);
21820      const isInlineTarget$1 = curry(isInlineTarget, editor);
21821      const location = findLocation$1(forward, isInlineTarget$1, rootNode, from);
21822      return location.bind(location => renderCaretLocation(editor, caret, location));
21823    };
21824    const toggleInlines = (isInlineTarget, dom, elms) => {
21825      const inlineBoundaries = map$3(descendants(SugarElement.fromDom(dom.getRoot()), '*[data-mce-selected="inline-boundary"]'), e => e.dom);
21826      const selectedInlines = filter$5(inlineBoundaries, isInlineTarget);
21827      const targetInlines = filter$5(elms, isInlineTarget);
21828      each$e(difference(selectedInlines, targetInlines), curry(setSelected, false));
21829      each$e(difference(targetInlines, selectedInlines), curry(setSelected, true));
21830    };
21831    const safeRemoveCaretContainer = (editor, caret) => {
21832      const caretValue = caret.get();
21833      if (editor.selection.isCollapsed() && !editor.composing && caretValue) {
21834        const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
21835        if (CaretPosition.isTextPosition(pos) && !isAtZwsp(pos)) {
21836          setCaretPosition(editor, removeAndReposition(caretValue, pos));
21837          caret.set(null);
21838        }
21839      }
21840    };
21841    const renderInsideInlineCaret = (isInlineTarget, editor, caret, elms) => {
21842      if (editor.selection.isCollapsed()) {
21843        const inlines = filter$5(elms, isInlineTarget);
21844        each$e(inlines, _inline => {
21845          const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
21846          readLocation(isInlineTarget, editor.getBody(), pos).bind(location => renderCaretLocation(editor, caret, location));
21847        });
21848      }
21849    };
21850    const move$2 = (editor, caret, forward) => isInlineBoundariesEnabled(editor) ? findLocation(editor, caret, forward).isSome() : false;
21851    const moveWord = (forward, editor, _caret) => isInlineBoundariesEnabled(editor) ? moveByWord(forward, editor) : false;
21852    const setupSelectedState = editor => {
21853      const caret = Cell(null);
21854      const isInlineTarget$1 = curry(isInlineTarget, editor);
21855      editor.on('NodeChange', e => {
21856        if (isInlineBoundariesEnabled(editor)) {
21857          toggleInlines(isInlineTarget$1, editor.dom, e.parents);
21858          safeRemoveCaretContainer(editor, caret);
21859          renderInsideInlineCaret(isInlineTarget$1, editor, caret, e.parents);
21860        }
21861      });
21862      return caret;
21863    };
21864    const moveNextWord = curry(moveWord, true);
21865    const movePrevWord = curry(moveWord, false);
21866    const moveToLineEndPoint$2 = (editor, forward, caret) => {
21867      if (isInlineBoundariesEnabled(editor)) {
21868        const linePoint = getLineEndPoint(editor, forward).getOrThunk(() => {
21869          const rng = editor.selection.getRng();
21870          return forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
21871        });
21872        return readLocation(curry(isInlineTarget, editor), editor.getBody(), linePoint).exists(loc => {
21873          const outsideLoc = outside(loc);
21874          return renderCaret(caret, outsideLoc).exists(pos => {
21875            setCaretPosition(editor, pos);
21876            return true;
21877          });
21878        });
21879      } else {
21880        return false;
21881      }
21882    };
21883
21884    const rangeFromPositions = (from, to) => {
21885      const range = document.createRange();
21886      range.setStart(from.container(), from.offset());
21887      range.setEnd(to.container(), to.offset());
21888      return range;
21889    };
21890    const hasOnlyTwoOrLessPositionsLeft = elm => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
21891      const normalizedFirstPos = normalizePosition(true, firstPos);
21892      const normalizedLastPos = normalizePosition(false, lastPos);
21893      return nextPosition(elm, normalizedFirstPos).forall(pos => pos.isEqual(normalizedLastPos));
21894    }).getOr(true);
21895    const setCaretLocation = (editor, caret) => location => renderCaret(caret, location).map(pos => () => setCaretPosition(editor, pos));
21896    const deleteFromTo = (editor, caret, from, to) => {
21897      const rootNode = editor.getBody();
21898      const isInlineTarget$1 = curry(isInlineTarget, editor);
21899      editor.undoManager.ignore(() => {
21900        editor.selection.setRng(rangeFromPositions(from, to));
21901        execNativeDeleteCommand(editor);
21902        readLocation(isInlineTarget$1, rootNode, CaretPosition.fromRangeStart(editor.selection.getRng())).map(inside).bind(setCaretLocation(editor, caret)).each(call);
21903      });
21904      editor.nodeChanged();
21905    };
21906    const rescope = (rootNode, node) => {
21907      const parentBlock = getParentBlock$3(node, rootNode);
21908      return parentBlock ? parentBlock : rootNode;
21909    };
21910    const backspaceDeleteCollapsed = (editor, caret, forward, from) => {
21911      const rootNode = rescope(editor.getBody(), from.container());
21912      const isInlineTarget$1 = curry(isInlineTarget, editor);
21913      const fromLocation = readLocation(isInlineTarget$1, rootNode, from);
21914      const location = fromLocation.bind(location => {
21915        if (forward) {
21916          return location.fold(constant(Optional.some(inside(location))), Optional.none, constant(Optional.some(outside(location))), Optional.none);
21917        } else {
21918          return location.fold(Optional.none, constant(Optional.some(outside(location))), Optional.none, constant(Optional.some(inside(location))));
21919        }
21920      });
21921      return location.map(setCaretLocation(editor, caret)).getOrThunk(() => {
21922        const toPosition = navigate(forward, rootNode, from);
21923        const toLocation = toPosition.bind(pos => readLocation(isInlineTarget$1, rootNode, pos));
21924        return lift2(fromLocation, toLocation, () => findRootInline(isInlineTarget$1, rootNode, from).bind(elm => {
21925          if (hasOnlyTwoOrLessPositionsLeft(elm)) {
21926            return Optional.some(() => {
21927              deleteElement$2(editor, forward, SugarElement.fromDom(elm));
21928            });
21929          } else {
21930            return Optional.none();
21931          }
21932        })).getOrThunk(() => toLocation.bind(() => toPosition.map(to => {
21933          return () => {
21934            if (forward) {
21935              deleteFromTo(editor, caret, from, to);
21936            } else {
21937              deleteFromTo(editor, caret, to, from);
21938            }
21939          };
21940        })));
21941      });
21942    };
21943    const backspaceDelete$3 = (editor, caret, forward) => {
21944      if (editor.selection.isCollapsed() && isInlineBoundariesEnabled(editor)) {
21945        const from = CaretPosition.fromRangeStart(editor.selection.getRng());
21946        return backspaceDeleteCollapsed(editor, caret, forward, from);
21947      }
21948      return Optional.none();
21949    };
21950
21951    const hasMultipleChildren = elm => childNodesCount(elm) > 1;
21952    const getParentsUntil = (editor, pred) => {
21953      const rootElm = SugarElement.fromDom(editor.getBody());
21954      const startElm = SugarElement.fromDom(editor.selection.getStart());
21955      const parents = parentsAndSelf(startElm, rootElm);
21956      return findIndex$2(parents, pred).fold(constant(parents), index => parents.slice(0, index));
21957    };
21958    const hasOnlyOneChild = elm => childNodesCount(elm) === 1;
21959    const getParentInlinesUntilMultichildInline = editor => getParentsUntil(editor, elm => isBlock$2(elm) || hasMultipleChildren(elm));
21960    const getParentInlines = editor => getParentsUntil(editor, isBlock$2);
21961    const getFormatNodes = (editor, parentInlines) => {
21962      const isFormatElement$1 = curry(isFormatElement, editor);
21963      return bind$3(parentInlines, elm => isFormatElement$1(elm) ? [elm.dom] : []);
21964    };
21965    const getFormatNodesAtStart = editor => {
21966      const parentInlines = getParentInlines(editor);
21967      return getFormatNodes(editor, parentInlines);
21968    };
21969    const deleteLastPosition = (forward, editor, target, parentInlines) => {
21970      const formatNodes = getFormatNodes(editor, parentInlines);
21971      if (formatNodes.length === 0) {
21972        deleteElement$2(editor, forward, target);
21973      } else {
21974        const pos = replaceWithCaretFormat(target.dom, formatNodes);
21975        editor.selection.setRng(pos.toRange());
21976      }
21977    };
21978    const deleteCaret$1 = (editor, forward) => {
21979      const parentInlines = filter$5(getParentInlinesUntilMultichildInline(editor), hasOnlyOneChild);
21980      return last$3(parentInlines).bind(target => {
21981        const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
21982        if (willDeleteLastPositionInElement(forward, fromPos, target.dom) && !isEmptyCaretFormatElement(target)) {
21983          return Optional.some(() => deleteLastPosition(forward, editor, target, parentInlines));
21984        } else {
21985          return Optional.none();
21986        }
21987      });
21988    };
21989    const isBrInEmptyElement = (editor, elm) => {
21990      const parentElm = elm.parentElement;
21991      return isBr$6(elm) && !isNull(parentElm) && editor.dom.isEmpty(parentElm);
21992    };
21993    const isEmptyCaret = elm => isEmptyCaretFormatElement(SugarElement.fromDom(elm));
21994    const createCaretFormatAtStart = (editor, formatNodes) => {
21995      const startElm = editor.selection.getStart();
21996      const pos = isBrInEmptyElement(editor, startElm) || isEmptyCaret(startElm) ? replaceWithCaretFormat(startElm, formatNodes) : createCaretFormatAtStart$1(editor.selection.getRng(), formatNodes);
21997      editor.selection.setRng(pos.toRange());
21998    };
21999    const updateCaretFormat = (editor, updateFormats) => {
22000      const missingFormats = difference(updateFormats, getFormatNodesAtStart(editor));
22001      if (missingFormats.length > 0) {
22002        createCaretFormatAtStart(editor, missingFormats);
22003      }
22004    };
22005    const rangeStartsAtTextContainer = rng => isText$a(rng.startContainer);
22006    const rangeStartsAtStartOfTextContainer = rng => rng.startOffset === 0 && rangeStartsAtTextContainer(rng);
22007    const rangeStartParentIsFormatElement = (editor, rng) => {
22008      const startParent = rng.startContainer.parentElement;
22009      return !isNull(startParent) && isFormatElement(editor, SugarElement.fromDom(startParent));
22010    };
22011    const rangeStartAndEndHaveSameParent = rng => {
22012      const startParent = rng.startContainer.parentNode;
22013      const endParent = rng.endContainer.parentNode;
22014      return !isNull(startParent) && !isNull(endParent) && startParent.isEqualNode(endParent);
22015    };
22016    const rangeEndsAtEndOfEndContainer = rng => {
22017      const endContainer = rng.endContainer;
22018      return rng.endOffset === (isText$a(endContainer) ? endContainer.length : endContainer.childNodes.length);
22019    };
22020    const rangeEndsAtEndOfStartContainer = rng => rangeStartAndEndHaveSameParent(rng) && rangeEndsAtEndOfEndContainer(rng);
22021    const rangeEndsAfterEndOfStartContainer = rng => !rng.endContainer.isEqualNode(rng.commonAncestorContainer);
22022    const rangeEndsAtOrAfterEndOfStartContainer = rng => rangeEndsAtEndOfStartContainer(rng) || rangeEndsAfterEndOfStartContainer(rng);
22023    const requiresDeleteRangeOverride = editor => {
22024      const rng = editor.selection.getRng();
22025      return rangeStartsAtStartOfTextContainer(rng) && rangeStartParentIsFormatElement(editor, rng) && rangeEndsAtOrAfterEndOfStartContainer(rng);
22026    };
22027    const deleteRange$1 = editor => {
22028      if (requiresDeleteRangeOverride(editor)) {
22029        const formatNodes = getFormatNodesAtStart(editor);
22030        return Optional.some(() => {
22031          execNativeDeleteCommand(editor);
22032          updateCaretFormat(editor, formatNodes);
22033        });
22034      } else {
22035        return Optional.none();
22036      }
22037    };
22038    const backspaceDelete$2 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$1(editor, forward) : deleteRange$1(editor);
22039    const hasAncestorInlineCaret = elm => ancestor$1(elm, node => isCaretNode(node.dom), isBlock$2);
22040    const hasAncestorInlineCaretAtStart = editor => hasAncestorInlineCaret(SugarElement.fromDom(editor.selection.getStart()));
22041    const requiresRefreshCaretOverride = editor => {
22042      const rng = editor.selection.getRng();
22043      return rng.collapsed && (rangeStartsAtTextContainer(rng) || editor.dom.isEmpty(rng.startContainer)) && !hasAncestorInlineCaretAtStart(editor);
22044    };
22045    const refreshCaret = editor => {
22046      if (requiresRefreshCaretOverride(editor)) {
22047        createCaretFormatAtStart(editor, []);
22048      }
22049      return true;
22050    };
22051
22052    const deleteElement = (editor, forward, element) => {
22053      if (isNonNullable(element)) {
22054        return Optional.some(() => {
22055          editor._selectionOverrides.hideFakeCaret();
22056          deleteElement$2(editor, forward, SugarElement.fromDom(element));
22057        });
22058      } else {
22059        return Optional.none();
22060      }
22061    };
22062    const deleteCaret = (editor, forward) => {
22063      const isNearMedia = forward ? isBeforeMedia : isAfterMedia;
22064      const direction = forward ? HDirection.Forwards : HDirection.Backwards;
22065      const fromPos = getNormalizedRangeEndPoint(direction, editor.getBody(), editor.selection.getRng());
22066      if (isNearMedia(fromPos)) {
22067        return deleteElement(editor, forward, fromPos.getNode(!forward));
22068      } else {
22069        return Optional.from(normalizePosition(forward, fromPos)).filter(pos => isNearMedia(pos) && isMoveInsideSameBlock(fromPos, pos)).bind(pos => deleteElement(editor, forward, pos.getNode(!forward)));
22070      }
22071    };
22072    const deleteRange = (editor, forward) => {
22073      const selectedNode = editor.selection.getNode();
22074      return isMedia$2(selectedNode) ? deleteElement(editor, forward, selectedNode) : Optional.none();
22075    };
22076    const backspaceDelete$1 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret(editor, forward) : deleteRange(editor, forward);
22077
22078    const isEditable = target => closest$4(target, elm => isContentEditableTrue$3(elm.dom) || isContentEditableFalse$b(elm.dom)).exists(elm => isContentEditableTrue$3(elm.dom));
22079    const parseIndentValue = value => toInt(value !== null && value !== void 0 ? value : '').getOr(0);
22080    const getIndentStyleName = (useMargin, element) => {
22081      const indentStyleName = useMargin || isTable$1(element) ? 'margin' : 'padding';
22082      const suffix = get$7(element, 'direction') === 'rtl' ? '-right' : '-left';
22083      return indentStyleName + suffix;
22084    };
22085    const indentElement = (dom, command, useMargin, value, unit, element) => {
22086      const indentStyleName = getIndentStyleName(useMargin, SugarElement.fromDom(element));
22087      const parsedValue = parseIndentValue(dom.getStyle(element, indentStyleName));
22088      if (command === 'outdent') {
22089        const styleValue = Math.max(0, parsedValue - value);
22090        dom.setStyle(element, indentStyleName, styleValue ? styleValue + unit : '');
22091      } else {
22092        const styleValue = parsedValue + value + unit;
22093        dom.setStyle(element, indentStyleName, styleValue);
22094      }
22095    };
22096    const validateBlocks = (editor, blocks) => forall(blocks, block => {
22097      const indentStyleName = getIndentStyleName(shouldIndentUseMargin(editor), block);
22098      const intentValue = getRaw(block, indentStyleName).map(parseIndentValue).getOr(0);
22099      const contentEditable = editor.dom.getContentEditable(block.dom);
22100      return contentEditable !== 'false' && intentValue > 0;
22101    });
22102    const canOutdent = editor => {
22103      const blocks = getBlocksToIndent(editor);
22104      return !editor.mode.isReadOnly() && (blocks.length > 1 || validateBlocks(editor, blocks));
22105    };
22106    const isListComponent = el => isList(el) || isListItem$1(el);
22107    const parentIsListComponent = el => parent(el).exists(isListComponent);
22108    const getBlocksToIndent = editor => filter$5(fromDom$1(editor.selection.getSelectedBlocks()), el => !isListComponent(el) && !parentIsListComponent(el) && isEditable(el));
22109    const handle = (editor, command) => {
22110      var _a, _b;
22111      const {dom} = editor;
22112      const indentation = getIndentation(editor);
22113      const indentUnit = (_b = (_a = /[a-z%]+$/i.exec(indentation)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 'px';
22114      const indentValue = parseIndentValue(indentation);
22115      const useMargin = shouldIndentUseMargin(editor);
22116      each$e(getBlocksToIndent(editor), block => {
22117        indentElement(dom, command, useMargin, indentValue, indentUnit, block.dom);
22118      });
22119    };
22120    const indent = editor => handle(editor, 'indent');
22121    const outdent = editor => handle(editor, 'outdent');
22122
22123    const backspaceDelete = editor => {
22124      if (editor.selection.isCollapsed() && canOutdent(editor)) {
22125        const dom = editor.dom;
22126        const rng = editor.selection.getRng();
22127        const pos = CaretPosition.fromRangeStart(rng);
22128        const block = dom.getParent(rng.startContainer, dom.isBlock);
22129        if (block !== null && isAtStartOfBlock(SugarElement.fromDom(block), pos)) {
22130          return Optional.some(() => outdent(editor));
22131        }
22132      }
22133      return Optional.none();
22134    };
22135
22136    const findAction = (editor, caret, forward) => findMap([
22137      backspaceDelete,
22138      backspaceDelete$5,
22139      backspaceDelete$6,
22140      (editor, forward) => backspaceDelete$3(editor, caret, forward),
22141      backspaceDelete$8,
22142      backspaceDelete$9,
22143      backspaceDelete$4,
22144      backspaceDelete$1,
22145      backspaceDelete$7,
22146      backspaceDelete$2
22147    ], item => item(editor, forward)).filter(_ => editor.selection.isEditable());
22148    const deleteCommand = (editor, caret) => {
22149      const result = findAction(editor, caret, false);
22150      result.fold(() => {
22151        execNativeDeleteCommand(editor);
22152        paddEmptyBody(editor);
22153      }, call);
22154    };
22155    const forwardDeleteCommand = (editor, caret) => {
22156      const result = findAction(editor, caret, true);
22157      result.fold(() => execNativeForwardDeleteCommand(editor), call);
22158    };
22159    const setup$p = (editor, caret) => {
22160      editor.addCommand('delete', () => {
22161        deleteCommand(editor, caret);
22162      });
22163      editor.addCommand('forwardDelete', () => {
22164        forwardDeleteCommand(editor, caret);
22165      });
22166    };
22167
22168    const SIGNIFICANT_MOVE = 5;
22169    const LONGPRESS_DELAY = 400;
22170    const getTouch = event => {
22171      if (event.touches === undefined || event.touches.length !== 1) {
22172        return Optional.none();
22173      }
22174      return Optional.some(event.touches[0]);
22175    };
22176    const isFarEnough = (touch, data) => {
22177      const distX = Math.abs(touch.clientX - data.x);
22178      const distY = Math.abs(touch.clientY - data.y);
22179      return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
22180    };
22181    const setup$o = editor => {
22182      const startData = value$2();
22183      const longpressFired = Cell(false);
22184      const debounceLongpress = last$1(e => {
22185        editor.dispatch('longpress', {
22186          ...e,
22187          type: 'longpress'
22188        });
22189        longpressFired.set(true);
22190      }, LONGPRESS_DELAY);
22191      editor.on('touchstart', e => {
22192        getTouch(e).each(touch => {
22193          debounceLongpress.cancel();
22194          const data = {
22195            x: touch.clientX,
22196            y: touch.clientY,
22197            target: e.target
22198          };
22199          debounceLongpress.throttle(e);
22200          longpressFired.set(false);
22201          startData.set(data);
22202        });
22203      }, true);
22204      editor.on('touchmove', e => {
22205        debounceLongpress.cancel();
22206        getTouch(e).each(touch => {
22207          startData.on(data => {
22208            if (isFarEnough(touch, data)) {
22209              startData.clear();
22210              longpressFired.set(false);
22211              editor.dispatch('longpresscancel');
22212            }
22213          });
22214        });
22215      }, true);
22216      editor.on('touchend touchcancel', e => {
22217        debounceLongpress.cancel();
22218        if (e.type === 'touchcancel') {
22219          return;
22220        }
22221        startData.get().filter(data => data.target.isEqualNode(e.target)).each(() => {
22222          if (longpressFired.get()) {
22223            e.preventDefault();
22224          } else {
22225            editor.dispatch('tap', {
22226              ...e,
22227              type: 'tap'
22228            });
22229          }
22230        });
22231      }, true);
22232    };
22233
22234    const isBlockElement = (blockElements, node) => has$2(blockElements, node.nodeName);
22235    const isValidTarget = (schema, node) => {
22236      if (isText$a(node)) {
22237        return true;
22238      } else if (isElement$6(node)) {
22239        return !isBlockElement(schema.getBlockElements(), node) && !isBookmarkNode$1(node) && !isTransparentBlock(schema, node);
22240      } else {
22241        return false;
22242      }
22243    };
22244    const hasBlockParent = (blockElements, root, node) => {
22245      return exists(parents(SugarElement.fromDom(node), SugarElement.fromDom(root)), elm => {
22246        return isBlockElement(blockElements, elm.dom);
22247      });
22248    };
22249    const shouldRemoveTextNode = (blockElements, node) => {
22250      if (isText$a(node)) {
22251        if (node.data.length === 0) {
22252          return true;
22253        } else if (/^\s+$/.test(node.data) && (!node.nextSibling || isBlockElement(blockElements, node.nextSibling))) {
22254          return true;
22255        }
22256      }
22257      return false;
22258    };
22259    const createRootBlock = editor => editor.dom.create(getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
22260    const addRootBlocks = editor => {
22261      const dom = editor.dom, selection = editor.selection;
22262      const schema = editor.schema;
22263      const blockElements = schema.getBlockElements();
22264      const startNode = selection.getStart();
22265      const rootNode = editor.getBody();
22266      let rootBlockNode;
22267      let tempNode;
22268      let wrapped = false;
22269      const forcedRootBlock = getForcedRootBlock(editor);
22270      if (!startNode || !isElement$6(startNode)) {
22271        return;
22272      }
22273      const rootNodeName = rootNode.nodeName.toLowerCase();
22274      if (!schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase()) || hasBlockParent(blockElements, rootNode, startNode)) {
22275        return;
22276      }
22277      const rng = selection.getRng();
22278      const {startContainer, startOffset, endContainer, endOffset} = rng;
22279      const restoreSelection = hasFocus(editor);
22280      let node = rootNode.firstChild;
22281      while (node) {
22282        if (isElement$6(node)) {
22283          updateElement(schema, node);
22284        }
22285        if (isValidTarget(schema, node)) {
22286          if (shouldRemoveTextNode(blockElements, node)) {
22287            tempNode = node;
22288            node = node.nextSibling;
22289            dom.remove(tempNode);
22290            continue;
22291          }
22292          if (!rootBlockNode) {
22293            rootBlockNode = createRootBlock(editor);
22294            rootNode.insertBefore(rootBlockNode, node);
22295            wrapped = true;
22296          }
22297          tempNode = node;
22298          node = node.nextSibling;
22299          rootBlockNode.appendChild(tempNode);
22300        } else {
22301          rootBlockNode = null;
22302          node = node.nextSibling;
22303        }
22304      }
22305      if (wrapped && restoreSelection) {
22306        rng.setStart(startContainer, startOffset);
22307        rng.setEnd(endContainer, endOffset);
22308        selection.setRng(rng);
22309        editor.nodeChanged();
22310      }
22311    };
22312    const insertEmptyLine = (editor, root, insertBlock) => {
22313      const block = SugarElement.fromDom(createRootBlock(editor));
22314      const br = createPaddingBr();
22315      append$1(block, br);
22316      insertBlock(root, block);
22317      const rng = document.createRange();
22318      rng.setStartBefore(br.dom);
22319      rng.setEndBefore(br.dom);
22320      return rng;
22321    };
22322    const setup$n = editor => {
22323      editor.on('NodeChange', curry(addRootBlocks, editor));
22324    };
22325
22326    const hasClass = checkClassName => node => (' ' + node.attr('class') + ' ').indexOf(checkClassName) !== -1;
22327    const replaceMatchWithSpan = (editor, content, cls) => {
22328      return function (match) {
22329        const args = arguments, index = args[args.length - 2];
22330        const prevChar = index > 0 ? content.charAt(index - 1) : '';
22331        if (prevChar === '"') {
22332          return match;
22333        }
22334        if (prevChar === '>') {
22335          const findStartTagIndex = content.lastIndexOf('<', index);
22336          if (findStartTagIndex !== -1) {
22337            const tagHtml = content.substring(findStartTagIndex, index);
22338            if (tagHtml.indexOf('contenteditable="false"') !== -1) {
22339              return match;
22340            }
22341          }
22342        }
22343        return '<span class="' + cls + '" data-mce-content="' + editor.dom.encode(args[0]) + '">' + editor.dom.encode(typeof args[1] === 'string' ? args[1] : args[0]) + '</span>';
22344      };
22345    };
22346    const convertRegExpsToNonEditable = (editor, nonEditableRegExps, e) => {
22347      let i = nonEditableRegExps.length, content = e.content;
22348      if (e.format === 'raw') {
22349        return;
22350      }
22351      while (i--) {
22352        content = content.replace(nonEditableRegExps[i], replaceMatchWithSpan(editor, content, getNonEditableClass(editor)));
22353      }
22354      e.content = content;
22355    };
22356    const setup$m = editor => {
22357      const contentEditableAttrName = 'contenteditable';
22358      const editClass = ' ' + Tools.trim(getEditableClass(editor)) + ' ';
22359      const nonEditClass = ' ' + Tools.trim(getNonEditableClass(editor)) + ' ';
22360      const hasEditClass = hasClass(editClass);
22361      const hasNonEditClass = hasClass(nonEditClass);
22362      const nonEditableRegExps = getNonEditableRegExps(editor);
22363      if (nonEditableRegExps.length > 0) {
22364        editor.on('BeforeSetContent', e => {
22365          convertRegExpsToNonEditable(editor, nonEditableRegExps, e);
22366        });
22367      }
22368      editor.parser.addAttributeFilter('class', nodes => {
22369        let i = nodes.length;
22370        while (i--) {
22371          const node = nodes[i];
22372          if (hasEditClass(node)) {
22373            node.attr(contentEditableAttrName, 'true');
22374          } else if (hasNonEditClass(node)) {
22375            node.attr(contentEditableAttrName, 'false');
22376          }
22377        }
22378      });
22379      editor.serializer.addAttributeFilter(contentEditableAttrName, nodes => {
22380        let i = nodes.length;
22381        while (i--) {
22382          const node = nodes[i];
22383          if (!hasEditClass(node) && !hasNonEditClass(node)) {
22384            continue;
22385          }
22386          if (nonEditableRegExps.length > 0 && node.attr('data-mce-content')) {
22387            node.name = '#text';
22388            node.type = 3;
22389            node.raw = true;
22390            node.value = node.attr('data-mce-content');
22391          } else {
22392            node.attr(contentEditableAttrName, null);
22393          }
22394        }
22395      });
22396    };
22397
22398    const findBlockCaretContainer = editor => descendant(SugarElement.fromDom(editor.getBody()), '*[data-mce-caret]').map(elm => elm.dom).getOrNull();
22399    const showBlockCaretContainer = (editor, blockCaretContainer) => {
22400      if (blockCaretContainer.hasAttribute('data-mce-caret')) {
22401        showCaretContainerBlock(blockCaretContainer);
22402        editor.selection.setRng(editor.selection.getRng());
22403        editor.selection.scrollIntoView(blockCaretContainer);
22404      }
22405    };
22406    const handleBlockContainer = (editor, e) => {
22407      const blockCaretContainer = findBlockCaretContainer(editor);
22408      if (!blockCaretContainer) {
22409        return;
22410      }
22411      if (e.type === 'compositionstart') {
22412        e.preventDefault();
22413        e.stopPropagation();
22414        showBlockCaretContainer(editor, blockCaretContainer);
22415        return;
22416      }
22417      if (hasContent(blockCaretContainer)) {
22418        showBlockCaretContainer(editor, blockCaretContainer);
22419        editor.undoManager.add();
22420      }
22421    };
22422    const setup$l = editor => {
22423      editor.on('keyup compositionstart', curry(handleBlockContainer, editor));
22424    };
22425
22426    const isContentEditableFalse$3 = isContentEditableFalse$b;
22427    const moveToCeFalseHorizontally = (direction, editor, range) => moveHorizontally(editor, direction, range, isBeforeContentEditableFalse, isAfterContentEditableFalse, isContentEditableFalse$3);
22428    const moveToCeFalseVertically = (direction, editor, range) => {
22429      const isBefore = caretPosition => isBeforeContentEditableFalse(caretPosition) || isBeforeTable(caretPosition);
22430      const isAfter = caretPosition => isAfterContentEditableFalse(caretPosition) || isAfterTable(caretPosition);
22431      return moveVertically(editor, direction, range, isBefore, isAfter, isContentEditableFalse$3);
22432    };
22433    const createTextBlock = editor => {
22434      const textBlock = editor.dom.create(getForcedRootBlock(editor));
22435      textBlock.innerHTML = '<br data-mce-bogus="1">';
22436      return textBlock;
22437    };
22438    const exitPreBlock = (editor, direction, range) => {
22439      const caretWalker = CaretWalker(editor.getBody());
22440      const getVisualCaretPosition$1 = curry(getVisualCaretPosition, direction === 1 ? caretWalker.next : caretWalker.prev);
22441      if (range.collapsed) {
22442        const pre = editor.dom.getParent(range.startContainer, 'PRE');
22443        if (!pre) {
22444          return;
22445        }
22446        const caretPos = getVisualCaretPosition$1(CaretPosition.fromRangeStart(range));
22447        if (!caretPos) {
22448          const newBlock = SugarElement.fromDom(createTextBlock(editor));
22449          if (direction === 1) {
22450            after$4(SugarElement.fromDom(pre), newBlock);
22451          } else {
22452            before$3(SugarElement.fromDom(pre), newBlock);
22453          }
22454          editor.selection.select(newBlock.dom, true);
22455          editor.selection.collapse();
22456        }
22457      }
22458    };
22459    const getHorizontalRange = (editor, forward) => {
22460      const direction = forward ? HDirection.Forwards : HDirection.Backwards;
22461      const range = editor.selection.getRng();
22462      return moveToCeFalseHorizontally(direction, editor, range).orThunk(() => {
22463        exitPreBlock(editor, direction, range);
22464        return Optional.none();
22465      });
22466    };
22467    const getVerticalRange = (editor, down) => {
22468      const direction = down ? 1 : -1;
22469      const range = editor.selection.getRng();
22470      return moveToCeFalseVertically(direction, editor, range).orThunk(() => {
22471        exitPreBlock(editor, direction, range);
22472        return Optional.none();
22473      });
22474    };
22475    const flipDirection = (selection, forward) => {
22476      const elm = forward ? selection.getEnd(true) : selection.getStart(true);
22477      return isRtl(elm) ? !forward : forward;
22478    };
22479    const moveH$2 = (editor, forward) => getHorizontalRange(editor, flipDirection(editor.selection, forward)).exists(newRange => {
22480      moveToRange(editor, newRange);
22481      return true;
22482    });
22483    const moveV$3 = (editor, down) => getVerticalRange(editor, down).exists(newRange => {
22484      moveToRange(editor, newRange);
22485      return true;
22486    });
22487    const moveToLineEndPoint$1 = (editor, forward) => {
22488      const isCefPosition = forward ? isAfterContentEditableFalse : isBeforeContentEditableFalse;
22489      return moveToLineEndPoint$3(editor, forward, isCefPosition);
22490    };
22491    const selectToEndPoint = (editor, forward) => getEdgeCefPosition(editor, !forward).map(pos => {
22492      const rng = pos.toRange();
22493      const curRng = editor.selection.getRng();
22494      if (forward) {
22495        rng.setStart(curRng.startContainer, curRng.startOffset);
22496      } else {
22497        rng.setEnd(curRng.endContainer, curRng.endOffset);
22498      }
22499      return rng;
22500    }).exists(rng => {
22501      moveToRange(editor, rng);
22502      return true;
22503    });
22504
22505    const isTarget = node => contains$2(['figcaption'], name(node));
22506    const getClosestTargetBlock = (pos, root) => {
22507      const isRoot = curry(eq, root);
22508      return closest$4(SugarElement.fromDom(pos.container()), isBlock$2, isRoot).filter(isTarget);
22509    };
22510    const isAtFirstOrLastLine = (root, forward, pos) => forward ? isAtLastLine(root.dom, pos) : isAtFirstLine(root.dom, pos);
22511    const moveCaretToNewEmptyLine = (editor, forward) => {
22512      const root = SugarElement.fromDom(editor.getBody());
22513      const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
22514      return getClosestTargetBlock(pos, root).exists(() => {
22515        if (isAtFirstOrLastLine(root, forward, pos)) {
22516          const insertFn = forward ? append$1 : prepend;
22517          const rng = insertEmptyLine(editor, root, insertFn);
22518          editor.selection.setRng(rng);
22519          return true;
22520        } else {
22521          return false;
22522        }
22523      });
22524    };
22525    const moveV$2 = (editor, forward) => {
22526      if (editor.selection.isCollapsed()) {
22527        return moveCaretToNewEmptyLine(editor, forward);
22528      } else {
22529        return false;
22530      }
22531    };
22532
22533    const baseKeyPattern = {
22534      shiftKey: false,
22535      altKey: false,
22536      ctrlKey: false,
22537      metaKey: false,
22538      keyCode: 0
22539    };
22540    const defaultPatterns = patterns => map$3(patterns, pattern => ({
22541      ...baseKeyPattern,
22542      ...pattern
22543    }));
22544    const defaultDelayedPatterns = patterns => map$3(patterns, pattern => ({
22545      ...baseKeyPattern,
22546      ...pattern
22547    }));
22548    const matchesEvent = (pattern, evt) => evt.keyCode === pattern.keyCode && evt.shiftKey === pattern.shiftKey && evt.altKey === pattern.altKey && evt.ctrlKey === pattern.ctrlKey && evt.metaKey === pattern.metaKey;
22549    const match$1 = (patterns, evt) => bind$3(defaultPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
22550    const matchDelayed = (patterns, evt) => bind$3(defaultDelayedPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
22551    const action = (f, ...x) => () => f.apply(null, x);
22552    const execute = (patterns, evt) => find$2(match$1(patterns, evt), pattern => pattern.action());
22553    const executeWithDelayedAction = (patterns, evt) => findMap(matchDelayed(patterns, evt), pattern => pattern.action());
22554
22555    const moveH$1 = (editor, forward) => {
22556      const direction = forward ? HDirection.Forwards : HDirection.Backwards;
22557      const range = editor.selection.getRng();
22558      return moveHorizontally(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
22559        moveToRange(editor, newRange);
22560        return true;
22561      });
22562    };
22563    const moveV$1 = (editor, down) => {
22564      const direction = down ? 1 : -1;
22565      const range = editor.selection.getRng();
22566      return moveVertically(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
22567        moveToRange(editor, newRange);
22568        return true;
22569      });
22570    };
22571    const moveToLineEndPoint = (editor, forward) => {
22572      const isNearMedia = forward ? isAfterMedia : isBeforeMedia;
22573      return moveToLineEndPoint$3(editor, forward, isNearMedia);
22574    };
22575
22576    const adt = Adt.generate([
22577      { none: ['current'] },
22578      { first: ['current'] },
22579      {
22580        middle: [
22581          'current',
22582          'target'
22583        ]
22584      },
22585      { last: ['current'] }
22586    ]);
22587    const none = current => adt.none(current);
22588    const CellLocation = {
22589      ...adt,
22590      none
22591    };
22592
22593    const firstLayer = (scope, selector) => {
22594      return filterFirstLayer(scope, selector, always);
22595    };
22596    const filterFirstLayer = (scope, selector, predicate) => {
22597      return bind$3(children$1(scope), x => {
22598        if (is$1(x, selector)) {
22599          return predicate(x) ? [x] : [];
22600        } else {
22601          return filterFirstLayer(x, selector, predicate);
22602        }
22603      });
22604    };
22605
22606    const lookup$1 = (tags, element, isRoot = never) => {
22607      if (isRoot(element)) {
22608        return Optional.none();
22609      }
22610      if (contains$2(tags, name(element))) {
22611        return Optional.some(element);
22612      }
22613      const isRootOrUpperTable = elm => is$1(elm, 'table') || isRoot(elm);
22614      return ancestor$3(element, tags.join(','), isRootOrUpperTable);
22615    };
22616    const cell = (element, isRoot) => lookup$1([
22617      'td',
22618      'th'
22619    ], element, isRoot);
22620    const cells = ancestor => firstLayer(ancestor, 'th,td');
22621    const table = (element, isRoot) => closest$3(element, 'table', isRoot);
22622
22623    const walk = (all, current, index, direction, isEligible = always) => {
22624      const forwards = direction === 1;
22625      if (!forwards && index <= 0) {
22626        return CellLocation.first(all[0]);
22627      } else if (forwards && index >= all.length - 1) {
22628        return CellLocation.last(all[all.length - 1]);
22629      } else {
22630        const newIndex = index + direction;
22631        const elem = all[newIndex];
22632        return isEligible(elem) ? CellLocation.middle(current, elem) : walk(all, current, newIndex, direction, isEligible);
22633      }
22634    };
22635    const detect = (current, isRoot) => {
22636      return table(current, isRoot).bind(table => {
22637        const all = cells(table);
22638        const index = findIndex$2(all, x => eq(current, x));
22639        return index.map(index => ({
22640          index,
22641          all
22642        }));
22643      });
22644    };
22645    const next = (current, isEligible, isRoot) => {
22646      const detection = detect(current, isRoot);
22647      return detection.fold(() => {
22648        return CellLocation.none(current);
22649      }, info => {
22650        return walk(info.all, current, info.index, 1, isEligible);
22651      });
22652    };
22653    const prev = (current, isEligible, isRoot) => {
22654      const detection = detect(current, isRoot);
22655      return detection.fold(() => {
22656        return CellLocation.none();
22657      }, info => {
22658        return walk(info.all, current, info.index, -1, isEligible);
22659      });
22660    };
22661
22662    const deflate = (rect, delta) => ({
22663      left: rect.left - delta,
22664      top: rect.top - delta,
22665      right: rect.right + delta * 2,
22666      bottom: rect.bottom + delta * 2,
22667      width: rect.width + delta,
22668      height: rect.height + delta
22669    });
22670    const getCorners = (getYAxisValue, tds) => bind$3(tds, td => {
22671      const rect = deflate(clone$1(td.getBoundingClientRect()), -1);
22672      return [
22673        {
22674          x: rect.left,
22675          y: getYAxisValue(rect),
22676          cell: td
22677        },
22678        {
22679          x: rect.right,
22680          y: getYAxisValue(rect),
22681          cell: td
22682        }
22683      ];
22684    });
22685    const findClosestCorner = (corners, x, y) => foldl(corners, (acc, newCorner) => acc.fold(() => Optional.some(newCorner), oldCorner => {
22686      const oldDist = Math.sqrt(Math.abs(oldCorner.x - x) + Math.abs(oldCorner.y - y));
22687      const newDist = Math.sqrt(Math.abs(newCorner.x - x) + Math.abs(newCorner.y - y));
22688      return Optional.some(newDist < oldDist ? newCorner : oldCorner);
22689    }), Optional.none());
22690    const getClosestCell = (getYAxisValue, isTargetCorner, table, x, y) => {
22691      const cells = descendants(SugarElement.fromDom(table), 'td,th,caption').map(e => e.dom);
22692      const corners = filter$5(getCorners(getYAxisValue, cells), corner => isTargetCorner(corner, y));
22693      return findClosestCorner(corners, x, y).map(corner => corner.cell);
22694    };
22695    const getBottomValue = rect => rect.bottom;
22696    const getTopValue = rect => rect.top;
22697    const isAbove = (corner, y) => corner.y < y;
22698    const isBelow = (corner, y) => corner.y > y;
22699    const getClosestCellAbove = curry(getClosestCell, getBottomValue, isAbove);
22700    const getClosestCellBelow = curry(getClosestCell, getTopValue, isBelow);
22701    const findClosestPositionInAboveCell = (table, pos) => head(pos.getClientRects()).bind(rect => getClosestCellAbove(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getLastLinePositions(cell), pos));
22702    const findClosestPositionInBelowCell = (table, pos) => last$3(pos.getClientRects()).bind(rect => getClosestCellBelow(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getFirstLinePositions(cell), pos));
22703
22704    const hasNextBreak = (getPositionsUntil, scope, lineInfo) => lineInfo.breakAt.exists(breakPos => getPositionsUntil(scope, breakPos).breakAt.isSome());
22705    const startsWithWrapBreak = lineInfo => lineInfo.breakType === BreakType.Wrap && lineInfo.positions.length === 0;
22706    const startsWithBrBreak = lineInfo => lineInfo.breakType === BreakType.Br && lineInfo.positions.length === 1;
22707    const isAtTableCellLine = (getPositionsUntil, scope, pos) => {
22708      const lineInfo = getPositionsUntil(scope, pos);
22709      if (startsWithWrapBreak(lineInfo) || !isBr$6(pos.getNode()) && startsWithBrBreak(lineInfo)) {
22710        return !hasNextBreak(getPositionsUntil, scope, lineInfo);
22711      } else {
22712        return lineInfo.breakAt.isNone();
22713      }
22714    };
22715    const isAtFirstTableCellLine = curry(isAtTableCellLine, getPositionsUntilPreviousLine);
22716    const isAtLastTableCellLine = curry(isAtTableCellLine, getPositionsUntilNextLine);
22717    const isCaretAtStartOrEndOfTable = (forward, rng, table) => {
22718      const caretPos = CaretPosition.fromRangeStart(rng);
22719      return positionIn(!forward, table).exists(pos => pos.isEqual(caretPos));
22720    };
22721    const navigateHorizontally = (editor, forward, table, _td) => {
22722      const rng = editor.selection.getRng();
22723      const direction = forward ? 1 : -1;
22724      if (isFakeCaretTableBrowser() && isCaretAtStartOrEndOfTable(forward, rng, table)) {
22725        showCaret(direction, editor, table, !forward, false).each(newRng => {
22726          moveToRange(editor, newRng);
22727        });
22728        return true;
22729      }
22730      return false;
22731    };
22732    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));
22733    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));
22734    const getTable = (previous, pos) => {
22735      const node = pos.getNode(previous);
22736      return isTable$2(node) ? Optional.some(node) : Optional.none();
22737    };
22738    const renderBlock = (down, editor, table) => {
22739      editor.undoManager.transact(() => {
22740        const insertFn = down ? after$4 : before$3;
22741        const rng = insertEmptyLine(editor, SugarElement.fromDom(table), insertFn);
22742        moveToRange(editor, rng);
22743      });
22744    };
22745    const moveCaret = (editor, down, pos) => {
22746      const table = down ? getTable(true, pos) : getTable(false, pos);
22747      const last = down === false;
22748      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)));
22749    };
22750    const navigateVertically = (editor, down, table, td) => {
22751      const rng = editor.selection.getRng();
22752      const pos = CaretPosition.fromRangeStart(rng);
22753      const root = editor.getBody();
22754      if (!down && isAtFirstTableCellLine(td, pos)) {
22755        const newPos = getClosestAbovePosition(root, table, pos);
22756        moveCaret(editor, down, newPos);
22757        return true;
22758      } else if (down && isAtLastTableCellLine(td, pos)) {
22759        const newPos = getClosestBelowPosition(root, table, pos);
22760        moveCaret(editor, down, newPos);
22761        return true;
22762      } else {
22763        return false;
22764      }
22765    };
22766    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);
22767    const moveH = (editor, forward) => move$1(editor, forward, navigateHorizontally);
22768    const moveV = (editor, forward) => move$1(editor, forward, navigateVertically);
22769    const getCellFirstCursorPosition = cell => {
22770      const selection = SimSelection.exact(cell, 0, cell, 0);
22771      return toNative(selection);
22772    };
22773    const tabGo = (editor, isRoot, cell) => {
22774      return cell.fold(Optional.none, Optional.none, (_current, next) => {
22775        return first(next).map(cell => {
22776          return getCellFirstCursorPosition(cell);
22777        });
22778      }, current => {
22779        editor.execCommand('mceTableInsertRowAfter');
22780        return tabForward(editor, isRoot, current);
22781      });
22782    };
22783    const tabForward = (editor, isRoot, cell) => tabGo(editor, isRoot, next(cell, isEditable$3));
22784    const tabBackward = (editor, isRoot, cell) => tabGo(editor, isRoot, prev(cell, isEditable$3));
22785    const handleTab = (editor, forward) => {
22786      const rootElements = [
22787        'table',
22788        'li',
22789        'dl'
22790      ];
22791      const body = SugarElement.fromDom(editor.getBody());
22792      const isRoot = element => {
22793        const name$1 = name(element);
22794        return eq(element, body) || contains$2(rootElements, name$1);
22795      };
22796      const rng = editor.selection.getRng();
22797      const container = SugarElement.fromDom(!forward ? rng.startContainer : rng.endContainer);
22798      return cell(container, isRoot).map(cell => {
22799        table(cell, isRoot).each(table => {
22800          editor.model.table.clearSelectedCells(table.dom);
22801        });
22802        editor.selection.collapse(!forward);
22803        const navigation = !forward ? tabBackward : tabForward;
22804        const rng = navigation(editor, isRoot, cell);
22805        rng.each(range => {
22806          editor.selection.setRng(range);
22807        });
22808        return true;
22809      }).getOr(false);
22810    };
22811
22812    const executeKeydownOverride$4 = (editor, caret, evt) => {
22813      const isMac = Env.os.isMacOS() || Env.os.isiOS();
22814      execute([
22815        {
22816          keyCode: VK.RIGHT,
22817          action: action(moveH$2, editor, true)
22818        },
22819        {
22820          keyCode: VK.LEFT,
22821          action: action(moveH$2, editor, false)
22822        },
22823        {
22824          keyCode: VK.UP,
22825          action: action(moveV$3, editor, false)
22826        },
22827        {
22828          keyCode: VK.DOWN,
22829          action: action(moveV$3, editor, true)
22830        },
22831        ...isMac ? [
22832          {
22833            keyCode: VK.UP,
22834            action: action(selectToEndPoint, editor, false),
22835            metaKey: true,
22836            shiftKey: true
22837          },
22838          {
22839            keyCode: VK.DOWN,
22840            action: action(selectToEndPoint, editor, true),
22841            metaKey: true,
22842            shiftKey: true
22843          }
22844        ] : [],
22845        {
22846          keyCode: VK.RIGHT,
22847          action: action(moveH, editor, true)
22848        },
22849        {
22850          keyCode: VK.LEFT,
22851          action: action(moveH, editor, false)
22852        },
22853        {
22854          keyCode: VK.UP,
22855          action: action(moveV, editor, false)
22856        },
22857        {
22858          keyCode: VK.DOWN,
22859          action: action(moveV, editor, true)
22860        },
22861        {
22862          keyCode: VK.RIGHT,
22863          action: action(moveH$1, editor, true)
22864        },
22865        {
22866          keyCode: VK.LEFT,
22867          action: action(moveH$1, editor, false)
22868        },
22869        {
22870          keyCode: VK.UP,
22871          action: action(moveV$1, editor, false)
22872        },
22873        {
22874          keyCode: VK.DOWN,
22875          action: action(moveV$1, editor, true)
22876        },
22877        {
22878          keyCode: VK.RIGHT,
22879          action: action(move$2, editor, caret, true)
22880        },
22881        {
22882          keyCode: VK.LEFT,
22883          action: action(move$2, editor, caret, false)
22884        },
22885        {
22886          keyCode: VK.RIGHT,
22887          ctrlKey: !isMac,
22888          altKey: isMac,
22889          action: action(moveNextWord, editor, caret)
22890        },
22891        {
22892          keyCode: VK.LEFT,
22893          ctrlKey: !isMac,
22894          altKey: isMac,
22895          action: action(movePrevWord, editor, caret)
22896        },
22897        {
22898          keyCode: VK.UP,
22899          action: action(moveV$2, editor, false)
22900        },
22901        {
22902          keyCode: VK.DOWN,
22903          action: action(moveV$2, editor, true)
22904        }
22905      ], evt).each(_ => {
22906        evt.preventDefault();
22907      });
22908    };
22909    const setup$k = (editor, caret) => {
22910      editor.on('keydown', evt => {
22911        if (!evt.isDefaultPrevented()) {
22912          executeKeydownOverride$4(editor, caret, evt);
22913        }
22914      });
22915    };
22916
22917    const point = (container, offset) => ({
22918      container,
22919      offset
22920    });
22921
22922    const DOM$7 = DOMUtils.DOM;
22923    const alwaysNext = startNode => node => startNode === node ? -1 : 0;
22924    const isBoundary = dom => node => dom.isBlock(node) || contains$2([
22925      'BR',
22926      'IMG',
22927      'HR',
22928      'INPUT'
22929    ], node.nodeName) || dom.getContentEditable(node) === 'false';
22930    const textBefore = (node, offset, rootNode) => {
22931      if (isText$a(node) && offset >= 0) {
22932        return Optional.some(point(node, offset));
22933      } else {
22934        const textSeeker = TextSeeker(DOM$7);
22935        return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, prev.container.data.length));
22936      }
22937    };
22938    const textAfter = (node, offset, rootNode) => {
22939      if (isText$a(node) && offset >= node.length) {
22940        return Optional.some(point(node, offset));
22941      } else {
22942        const textSeeker = TextSeeker(DOM$7);
22943        return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, 0));
22944      }
22945    };
22946    const scanLeft = (node, offset, rootNode) => {
22947      if (!isText$a(node)) {
22948        return Optional.none();
22949      }
22950      const text = node.data;
22951      if (offset >= 0 && offset <= text.length) {
22952        return Optional.some(point(node, offset));
22953      } else {
22954        const textSeeker = TextSeeker(DOM$7);
22955        return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).bind(prev => {
22956          const prevText = prev.container.data;
22957          return scanLeft(prev.container, offset + prevText.length, rootNode);
22958        });
22959      }
22960    };
22961    const scanRight = (node, offset, rootNode) => {
22962      if (!isText$a(node)) {
22963        return Optional.none();
22964      }
22965      const text = node.data;
22966      if (offset <= text.length) {
22967        return Optional.some(point(node, offset));
22968      } else {
22969        const textSeeker = TextSeeker(DOM$7);
22970        return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).bind(next => scanRight(next.container, offset - text.length, rootNode));
22971      }
22972    };
22973    const repeatLeft = (dom, node, offset, process, rootNode) => {
22974      const search = TextSeeker(dom, isBoundary(dom));
22975      return Optional.from(search.backwards(node, offset, process, rootNode));
22976    };
22977
22978    const isValidTextRange = rng => rng.collapsed && isText$a(rng.startContainer);
22979    const getText = rng => trim$1(rng.toString().replace(/\u00A0/g, ' '));
22980    const isWhitespace = chr => chr !== '' && ' \xA0\f\n\r\t\x0B'.indexOf(chr) !== -1;
22981
22982    const stripTrigger = (text, trigger) => text.substring(trigger.length);
22983    const findTrigger = (text, index, trigger) => {
22984      let i;
22985      const firstChar = trigger.charAt(0);
22986      for (i = index - 1; i >= 0; i--) {
22987        const char = text.charAt(i);
22988        if (isWhitespace(char)) {
22989          return Optional.none();
22990        }
22991        if (firstChar === char && contains$1(text, trigger, i, index)) {
22992          break;
22993        }
22994      }
22995      return Optional.some(i);
22996    };
22997    const findStart = (dom, initRange, trigger, minChars = 0) => {
22998      if (!isValidTextRange(initRange)) {
22999        return Optional.none();
23000      }
23001      const buffer = {
23002        text: '',
23003        offset: 0
23004      };
23005      const findTriggerIndex = (element, offset, text) => {
23006        buffer.text = text + buffer.text;
23007        buffer.offset += offset;
23008        return findTrigger(buffer.text, buffer.offset, trigger).getOr(offset);
23009      };
23010      const root = dom.getParent(initRange.startContainer, dom.isBlock) || dom.getRoot();
23011      return repeatLeft(dom, initRange.startContainer, initRange.startOffset, findTriggerIndex, root).bind(spot => {
23012        const range = initRange.cloneRange();
23013        range.setStart(spot.container, spot.offset);
23014        range.setEnd(initRange.endContainer, initRange.endOffset);
23015        if (range.collapsed) {
23016          return Optional.none();
23017        }
23018        const text = getText(range);
23019        const triggerIndex = text.lastIndexOf(trigger);
23020        if (triggerIndex !== 0 || stripTrigger(text, trigger).length < minChars) {
23021          return Optional.none();
23022        } else {
23023          return Optional.some({
23024            text: stripTrigger(text, trigger),
23025            range,
23026            trigger
23027          });
23028        }
23029      });
23030    };
23031    const getContext = (dom, initRange, trigger, minChars = 0) => detect$1(SugarElement.fromDom(initRange.startContainer)).fold(() => findStart(dom, initRange, trigger, minChars), elm => {
23032      const range = dom.createRng();
23033      range.selectNode(elm.dom);
23034      const text = getText(range);
23035      return Optional.some({
23036        range,
23037        text: stripTrigger(text, trigger),
23038        trigger
23039      });
23040    });
23041
23042    const isText$1 = node => node.nodeType === TEXT;
23043    const isElement = node => node.nodeType === ELEMENT;
23044    const toLast = node => {
23045      if (isText$1(node)) {
23046        return point(node, node.data.length);
23047      } else {
23048        const children = node.childNodes;
23049        return children.length > 0 ? toLast(children[children.length - 1]) : point(node, children.length);
23050      }
23051    };
23052    const toLeaf = (node, offset) => {
23053      const children = node.childNodes;
23054      if (children.length > 0 && offset < children.length) {
23055        return toLeaf(children[offset], 0);
23056      } else if (children.length > 0 && isElement(node) && children.length === offset) {
23057        return toLast(children[children.length - 1]);
23058      } else {
23059        return point(node, offset);
23060      }
23061    };
23062
23063    const isPreviousCharContent = (dom, leaf) => {
23064      var _a;
23065      const root = (_a = dom.getParent(leaf.container, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot();
23066      return repeatLeft(dom, leaf.container, leaf.offset, (_element, offset) => offset === 0 ? -1 : offset, root).filter(spot => {
23067        const char = spot.container.data.charAt(spot.offset - 1);
23068        return !isWhitespace(char);
23069      }).isSome();
23070    };
23071    const isStartOfWord = dom => rng => {
23072      const leaf = toLeaf(rng.startContainer, rng.startOffset);
23073      return !isPreviousCharContent(dom, leaf);
23074    };
23075    const getTriggerContext = (dom, initRange, database) => findMap(database.triggers, trigger => getContext(dom, initRange, trigger));
23076    const lookup = (editor, getDatabase) => {
23077      const database = getDatabase();
23078      const rng = editor.selection.getRng();
23079      return getTriggerContext(editor.dom, rng, database).bind(context => lookupWithContext(editor, getDatabase, context));
23080    };
23081    const lookupWithContext = (editor, getDatabase, context, fetchOptions = {}) => {
23082      var _a;
23083      const database = getDatabase();
23084      const rng = editor.selection.getRng();
23085      const startText = (_a = rng.startContainer.nodeValue) !== null && _a !== void 0 ? _a : '';
23086      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));
23087      if (autocompleters.length === 0) {
23088        return Optional.none();
23089      }
23090      const lookupData = Promise.all(map$3(autocompleters, ac => {
23091        const fetchResult = ac.fetch(context.text, ac.maxResults, fetchOptions);
23092        return fetchResult.then(results => ({
23093          matchText: context.text,
23094          items: results,
23095          columns: ac.columns,
23096          onAction: ac.onAction,
23097          highlightOn: ac.highlightOn
23098        }));
23099      }));
23100      return Optional.some({
23101        lookupData,
23102        context
23103      });
23104    };
23105
23106    var SimpleResultType;
23107    (function (SimpleResultType) {
23108      SimpleResultType[SimpleResultType['Error'] = 0] = 'Error';
23109      SimpleResultType[SimpleResultType['Value'] = 1] = 'Value';
23110    }(SimpleResultType || (SimpleResultType = {})));
23111    const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
23112    const partition = results => {
23113      const values = [];
23114      const errors = [];
23115      each$e(results, obj => {
23116        fold$1(obj, err => errors.push(err), val => values.push(val));
23117      });
23118      return {
23119        values,
23120        errors
23121      };
23122    };
23123    const mapError = (res, f) => {
23124      if (res.stype === SimpleResultType.Error) {
23125        return {
23126          stype: SimpleResultType.Error,
23127          serror: f(res.serror)
23128        };
23129      } else {
23130        return res;
23131      }
23132    };
23133    const map = (res, f) => {
23134      if (res.stype === SimpleResultType.Value) {
23135        return {
23136          stype: SimpleResultType.Value,
23137          svalue: f(res.svalue)
23138        };
23139      } else {
23140        return res;
23141      }
23142    };
23143    const bind$1 = (res, f) => {
23144      if (res.stype === SimpleResultType.Value) {
23145        return f(res.svalue);
23146      } else {
23147        return res;
23148      }
23149    };
23150    const bindError = (res, f) => {
23151      if (res.stype === SimpleResultType.Error) {
23152        return f(res.serror);
23153      } else {
23154        return res;
23155      }
23156    };
23157    const svalue = v => ({
23158      stype: SimpleResultType.Value,
23159      svalue: v
23160    });
23161    const serror = e => ({
23162      stype: SimpleResultType.Error,
23163      serror: e
23164    });
23165    const toResult = res => fold$1(res, Result.error, Result.value);
23166    const fromResult = res => res.fold(serror, svalue);
23167    const SimpleResult = {
23168      fromResult,
23169      toResult,
23170      svalue,
23171      partition,
23172      serror,
23173      bind: bind$1,
23174      bindError,
23175      map,
23176      mapError,
23177      fold: fold$1
23178    };
23179
23180    const formatObj = input => {
23181      return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
23182    };
23183    const formatErrors = errors => {
23184      const es = errors.length > 10 ? errors.slice(0, 10).concat([{
23185          path: [],
23186          getErrorInfo: constant('... (only showing first ten failures)')
23187        }]) : errors;
23188      return map$3(es, e => {
23189        return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
23190      });
23191    };
23192
23193    const nu = (path, getErrorInfo) => {
23194      return SimpleResult.serror([{
23195          path,
23196          getErrorInfo
23197        }]);
23198    };
23199    const missingRequired = (path, key, obj) => nu(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
23200    const missingKey = (path, key) => nu(path, () => 'Choice schema did not contain choice key: "' + key + '"');
23201    const missingBranch = (path, branches, branch) => nu(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
23202    const custom = (path, err) => nu(path, constant(err));
23203
23204    const chooseFrom = (path, input, branches, ch) => {
23205      const fields = get$a(branches, ch);
23206      return fields.fold(() => missingBranch(path, branches, ch), vp => vp.extract(path.concat(['branch: ' + ch]), input));
23207    };
23208    const choose$1 = (key, branches) => {
23209      const extract = (path, input) => {
23210        const choice = get$a(input, key);
23211        return choice.fold(() => missingKey(path, key), chosen => chooseFrom(path, input, branches, chosen));
23212      };
23213      const toString = () => 'chooseOn(' + key + '). Possible values: ' + keys(branches);
23214      return {
23215        extract,
23216        toString
23217      };
23218    };
23219
23220    const shallow = (old, nu) => {
23221      return nu;
23222    };
23223    const deep = (old, nu) => {
23224      const bothObjects = isPlainObject(old) && isPlainObject(nu);
23225      return bothObjects ? deepMerge(old, nu) : nu;
23226    };
23227    const baseMerge = merger => {
23228      return (...objects) => {
23229        if (objects.length === 0) {
23230          throw new Error(`Can't merge zero objects`);
23231        }
23232        const ret = {};
23233        for (let j = 0; j < objects.length; j++) {
23234          const curObject = objects[j];
23235          for (const key in curObject) {
23236            if (has$2(curObject, key)) {
23237              ret[key] = merger(ret[key], curObject[key]);
23238            }
23239          }
23240        }
23241        return ret;
23242      };
23243    };
23244    const deepMerge = baseMerge(deep);
23245    const merge = baseMerge(shallow);
23246
23247    const required = () => ({
23248      tag: 'required',
23249      process: {}
23250    });
23251    const defaultedThunk = fallbackThunk => ({
23252      tag: 'defaultedThunk',
23253      process: fallbackThunk
23254    });
23255    const defaulted$1 = fallback => defaultedThunk(constant(fallback));
23256    const asOption = () => ({
23257      tag: 'option',
23258      process: {}
23259    });
23260
23261    const mergeValues = (values, base) => values.length > 0 ? SimpleResult.svalue(deepMerge(base, merge.apply(undefined, values))) : SimpleResult.svalue(base);
23262    const mergeErrors = errors => compose(SimpleResult.serror, flatten)(errors);
23263    const consolidateObj = (objects, base) => {
23264      const partition = SimpleResult.partition(objects);
23265      return partition.errors.length > 0 ? mergeErrors(partition.errors) : mergeValues(partition.values, base);
23266    };
23267    const consolidateArr = objects => {
23268      const partitions = SimpleResult.partition(objects);
23269      return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : SimpleResult.svalue(partitions.values);
23270    };
23271    const ResultCombine = {
23272      consolidateObj,
23273      consolidateArr
23274    };
23275
23276    const field$1 = (key, newKey, presence, prop) => ({
23277      tag: 'field',
23278      key,
23279      newKey,
23280      presence,
23281      prop
23282    });
23283    const customField$1 = (newKey, instantiator) => ({
23284      tag: 'custom',
23285      newKey,
23286      instantiator
23287    });
23288    const fold = (value, ifField, ifCustom) => {
23289      switch (value.tag) {
23290      case 'field':
23291        return ifField(value.key, value.newKey, value.presence, value.prop);
23292      case 'custom':
23293        return ifCustom(value.newKey, value.instantiator);
23294      }
23295    };
23296
23297    const value = validator => {
23298      const extract = (path, val) => {
23299        return SimpleResult.bindError(validator(val), err => custom(path, err));
23300      };
23301      const toString = constant('val');
23302      return {
23303        extract,
23304        toString
23305      };
23306    };
23307    const anyValue$1 = value(SimpleResult.svalue);
23308
23309    const requiredAccess = (path, obj, key, bundle) => get$a(obj, key).fold(() => missingRequired(path, key, obj), bundle);
23310    const fallbackAccess = (obj, key, fallback, bundle) => {
23311      const v = get$a(obj, key).getOrThunk(() => fallback(obj));
23312      return bundle(v);
23313    };
23314    const optionAccess = (obj, key, bundle) => bundle(get$a(obj, key));
23315    const optionDefaultedAccess = (obj, key, fallback, bundle) => {
23316      const opt = get$a(obj, key).map(val => val === true ? fallback(obj) : val);
23317      return bundle(opt);
23318    };
23319    const extractField = (field, path, obj, key, prop) => {
23320      const bundle = av => prop.extract(path.concat([key]), av);
23321      const bundleAsOption = optValue => optValue.fold(() => SimpleResult.svalue(Optional.none()), ov => {
23322        const result = prop.extract(path.concat([key]), ov);
23323        return SimpleResult.map(result, Optional.some);
23324      });
23325      switch (field.tag) {
23326      case 'required':
23327        return requiredAccess(path, obj, key, bundle);
23328      case 'defaultedThunk':
23329        return fallbackAccess(obj, key, field.process, bundle);
23330      case 'option':
23331        return optionAccess(obj, key, bundleAsOption);
23332      case 'defaultedOptionThunk':
23333        return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
23334      case 'mergeWithThunk': {
23335          return fallbackAccess(obj, key, constant({}), v => {
23336            const result = deepMerge(field.process(obj), v);
23337            return bundle(result);
23338          });
23339        }
23340      }
23341    };
23342    const extractFields = (path, obj, fields) => {
23343      const success = {};
23344      const errors = [];
23345      for (const field of fields) {
23346        fold(field, (key, newKey, presence, prop) => {
23347          const result = extractField(presence, path, obj, key, prop);
23348          SimpleResult.fold(result, err => {
23349            errors.push(...err);
23350          }, res => {
23351            success[newKey] = res;
23352          });
23353        }, (newKey, instantiator) => {
23354          success[newKey] = instantiator(obj);
23355        });
23356      }
23357      return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
23358    };
23359    const objOf = values => {
23360      const extract = (path, o) => extractFields(path, o, values);
23361      const toString = () => {
23362        const fieldStrings = map$3(values, value => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
23363        return 'obj{\n' + fieldStrings.join('\n') + '}';
23364      };
23365      return {
23366        extract,
23367        toString
23368      };
23369    };
23370    const arrOf = prop => {
23371      const extract = (path, array) => {
23372        const results = map$3(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
23373        return ResultCombine.consolidateArr(results);
23374      };
23375      const toString = () => 'array(' + prop.toString() + ')';
23376      return {
23377        extract,
23378        toString
23379      };
23380    };
23381
23382    const valueOf = validator => value(v => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
23383    const extractValue = (label, prop, obj) => {
23384      const res = prop.extract([label], obj);
23385      return SimpleResult.mapError(res, errs => ({
23386        input: obj,
23387        errors: errs
23388      }));
23389    };
23390    const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
23391    const formatError = errInfo => {
23392      return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input);
23393    };
23394    const choose = (key, branches) => choose$1(key, map$2(branches, objOf));
23395
23396    const anyValue = constant(anyValue$1);
23397    const typedValue = (validator, expectedType) => value(a => {
23398      const actualType = typeof a;
23399      return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${ expectedType } but got: ${ actualType }`);
23400    });
23401    const number = typedValue(isNumber, 'number');
23402    const string = typedValue(isString, 'string');
23403    const boolean = typedValue(isBoolean, 'boolean');
23404    const functionProcessor = typedValue(isFunction, 'function');
23405
23406    const field = field$1;
23407    const customField = customField$1;
23408    const validateEnum = values => valueOf(value => contains$2(values, value) ? Result.value(value) : Result.error(`Unsupported value: "${ value }", choose one of "${ values.join(', ') }".`));
23409    const requiredOf = (key, schema) => field(key, key, required(), schema);
23410    const requiredString = key => requiredOf(key, string);
23411    const requiredFunction = key => requiredOf(key, functionProcessor);
23412    const requiredArrayOf = (key, schema) => field(key, key, required(), arrOf(schema));
23413    const optionOf = (key, schema) => field(key, key, asOption(), schema);
23414    const optionString = key => optionOf(key, string);
23415    const optionFunction = key => optionOf(key, functionProcessor);
23416    const defaulted = (key, fallback) => field(key, key, defaulted$1(fallback), anyValue());
23417    const defaultedOf = (key, fallback, schema) => field(key, key, defaulted$1(fallback), schema);
23418    const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
23419    const defaultedString = (key, fallback) => defaultedOf(key, fallback, string);
23420    const defaultedStringEnum = (key, fallback, values) => defaultedOf(key, fallback, validateEnum(values));
23421    const defaultedBoolean = (key, fallback) => defaultedOf(key, fallback, boolean);
23422    const defaultedFunction = (key, fallback) => defaultedOf(key, fallback, functionProcessor);
23423    const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
23424
23425    const type = requiredString('type');
23426    const fetch$1 = requiredFunction('fetch');
23427    const onAction = requiredFunction('onAction');
23428    const onSetup = defaultedFunction('onSetup', () => noop);
23429    const optionalText = optionString('text');
23430    const optionalIcon = optionString('icon');
23431    const optionalTooltip = optionString('tooltip');
23432    const optionalLabel = optionString('label');
23433    const active = defaultedBoolean('active', false);
23434    const enabled = defaultedBoolean('enabled', true);
23435    const primary = defaultedBoolean('primary', false);
23436    const defaultedColumns = num => defaulted('columns', num);
23437    const defaultedType = type => defaultedString('type', type);
23438
23439    const autocompleterSchema = objOf([
23440      type,
23441      requiredString('trigger'),
23442      defaultedNumber('minChars', 1),
23443      defaultedColumns(1),
23444      defaultedNumber('maxResults', 10),
23445      optionFunction('matches'),
23446      fetch$1,
23447      onAction,
23448      defaultedArrayOf('highlightOn', [], string)
23449    ]);
23450    const createAutocompleter = spec => asRaw('Autocompleter', autocompleterSchema, {
23451      trigger: spec.ch,
23452      ...spec
23453    });
23454
23455    const baseToolbarButtonFields = [
23456      enabled,
23457      optionalTooltip,
23458      optionalIcon,
23459      optionalText,
23460      onSetup
23461    ];
23462
23463    const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
23464
23465    const contextBarFields = [
23466      defaultedFunction('predicate', never),
23467      defaultedStringEnum('scope', 'node', [
23468        'node',
23469        'editor'
23470      ]),
23471      defaultedStringEnum('position', 'selection', [
23472        'node',
23473        'selection',
23474        'line'
23475      ])
23476    ];
23477
23478    const contextButtonFields = baseToolbarButtonFields.concat([
23479      defaultedType('contextformbutton'),
23480      primary,
23481      onAction,
23482      customField('original', identity)
23483    ]);
23484    const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
23485      defaultedType('contextformbutton'),
23486      primary,
23487      onAction,
23488      customField('original', identity)
23489    ]);
23490    const launchButtonFields = baseToolbarButtonFields.concat([defaultedType('contextformbutton')]);
23491    const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType('contextformtogglebutton')]);
23492    const toggleOrNormal = choose('type', {
23493      contextformbutton: contextButtonFields,
23494      contextformtogglebutton: contextToggleButtonFields
23495    });
23496    objOf([
23497      defaultedType('contextform'),
23498      defaultedFunction('initValue', constant('')),
23499      optionalLabel,
23500      requiredArrayOf('commands', toggleOrNormal),
23501      optionOf('launch', choose('type', {
23502        contextformbutton: launchButtonFields,
23503        contextformtogglebutton: launchToggleButtonFields
23504      }))
23505    ].concat(contextBarFields));
23506
23507    const register$2 = editor => {
23508      const popups = editor.ui.registry.getAll().popups;
23509      const dataset = map$2(popups, popup => createAutocompleter(popup).fold(err => {
23510        throw new Error(formatError(err));
23511      }, identity));
23512      const triggers = stringArray(mapToArray(dataset, v => v.trigger));
23513      const datasetValues = values(dataset);
23514      const lookupByTrigger = trigger => filter$5(datasetValues, dv => dv.trigger === trigger);
23515      return {
23516        dataset,
23517        triggers,
23518        lookupByTrigger
23519      };
23520    };
23521
23522    const setupEditorInput = (editor, api) => {
23523      const update = last$1(api.load, 50);
23524      editor.on('keypress compositionend', e => {
23525        if (e.which === 27) {
23526          return;
23527        }
23528        update.throttle();
23529      });
23530      editor.on('keydown', e => {
23531        const keyCode = e.which;
23532        if (keyCode === 8) {
23533          update.throttle();
23534        } else if (keyCode === 27) {
23535          api.cancelIfNecessary();
23536        }
23537      });
23538      editor.on('remove', update.cancel);
23539    };
23540    const setup$j = editor => {
23541      const activeAutocompleter = value$2();
23542      const uiActive = Cell(false);
23543      const isActive = activeAutocompleter.isSet;
23544      const cancelIfNecessary = () => {
23545        if (isActive()) {
23546          removeAutocompleterDecoration(editor);
23547          fireAutocompleterEnd(editor);
23548          uiActive.set(false);
23549          activeAutocompleter.clear();
23550        }
23551      };
23552      const commenceIfNecessary = context => {
23553        if (!isActive()) {
23554          addAutocompleterDecoration(editor, context.range);
23555          activeAutocompleter.set({
23556            trigger: context.trigger,
23557            matchLength: context.text.length
23558          });
23559        }
23560      };
23561      const getAutocompleters = cached(() => register$2(editor));
23562      const doLookup = fetchOptions => activeAutocompleter.get().map(ac => getContext(editor.dom, editor.selection.getRng(), ac.trigger).bind(newContext => lookupWithContext(editor, getAutocompleters, newContext, fetchOptions))).getOrThunk(() => lookup(editor, getAutocompleters));
23563      const load = fetchOptions => {
23564        doLookup(fetchOptions).fold(cancelIfNecessary, lookupInfo => {
23565          commenceIfNecessary(lookupInfo.context);
23566          lookupInfo.lookupData.then(lookupData => {
23567            activeAutocompleter.get().map(ac => {
23568              const context = lookupInfo.context;
23569              if (ac.trigger === context.trigger) {
23570                if (context.text.length - ac.matchLength >= 10) {
23571                  cancelIfNecessary();
23572                } else {
23573                  activeAutocompleter.set({
23574                    ...ac,
23575                    matchLength: context.text.length
23576                  });
23577                  if (uiActive.get()) {
23578                    fireAutocompleterUpdate(editor, { lookupData });
23579                  } else {
23580                    uiActive.set(true);
23581                    fireAutocompleterStart(editor, { lookupData });
23582                  }
23583                }
23584              }
23585            });
23586          });
23587        });
23588      };
23589      editor.addCommand('mceAutocompleterReload', (_ui, value) => {
23590        const fetchOptions = isObject(value) ? value.fetchOptions : {};
23591        load(fetchOptions);
23592      });
23593      editor.addCommand('mceAutocompleterClose', cancelIfNecessary);
23594      setupEditorInput(editor, {
23595        cancelIfNecessary,
23596        load
23597      });
23598    };
23599
23600    const createAndFireInputEvent = eventType => (editor, inputType, specifics = {}) => {
23601      const target = editor.getBody();
23602      const overrides = {
23603        bubbles: true,
23604        composed: true,
23605        data: null,
23606        isComposing: false,
23607        detail: 0,
23608        view: null,
23609        target,
23610        currentTarget: target,
23611        eventPhase: Event.AT_TARGET,
23612        originalTarget: target,
23613        explicitOriginalTarget: target,
23614        isTrusted: false,
23615        srcElement: target,
23616        cancelable: false,
23617        preventDefault: noop,
23618        inputType
23619      };
23620      const input = clone$3(new InputEvent(eventType));
23621      return editor.dispatch(eventType, {
23622        ...input,
23623        ...overrides,
23624        ...specifics
23625      });
23626    };
23627    const fireInputEvent = createAndFireInputEvent('input');
23628    const fireBeforeInputEvent = createAndFireInputEvent('beforeinput');
23629
23630    const executeKeydownOverride$3 = (editor, caret, evt) => {
23631      const inputType = evt.keyCode === VK.BACKSPACE ? 'deleteContentBackward' : 'deleteContentForward';
23632      executeWithDelayedAction([
23633        {
23634          keyCode: VK.BACKSPACE,
23635          action: action(backspaceDelete, editor)
23636        },
23637        {
23638          keyCode: VK.BACKSPACE,
23639          action: action(backspaceDelete$5, editor, false)
23640        },
23641        {
23642          keyCode: VK.DELETE,
23643          action: action(backspaceDelete$5, editor, true)
23644        },
23645        {
23646          keyCode: VK.BACKSPACE,
23647          action: action(backspaceDelete$6, editor, false)
23648        },
23649        {
23650          keyCode: VK.DELETE,
23651          action: action(backspaceDelete$6, editor, true)
23652        },
23653        {
23654          keyCode: VK.BACKSPACE,
23655          action: action(backspaceDelete$3, editor, caret, false)
23656        },
23657        {
23658          keyCode: VK.DELETE,
23659          action: action(backspaceDelete$3, editor, caret, true)
23660        },
23661        {
23662          keyCode: VK.BACKSPACE,
23663          action: action(backspaceDelete$9, editor, false)
23664        },
23665        {
23666          keyCode: VK.DELETE,
23667          action: action(backspaceDelete$9, editor, true)
23668        },
23669        {
23670          keyCode: VK.BACKSPACE,
23671          action: action(backspaceDelete$4, editor, false)
23672        },
23673        {
23674          keyCode: VK.DELETE,
23675          action: action(backspaceDelete$4, editor, true)
23676        },
23677        {
23678          keyCode: VK.BACKSPACE,
23679          action: action(backspaceDelete$1, editor, false)
23680        },
23681        {
23682          keyCode: VK.DELETE,
23683          action: action(backspaceDelete$1, editor, true)
23684        },
23685        {
23686          keyCode: VK.BACKSPACE,
23687          action: action(backspaceDelete$7, editor, false)
23688        },
23689        {
23690          keyCode: VK.DELETE,
23691          action: action(backspaceDelete$7, editor, true)
23692        },
23693        {
23694          keyCode: VK.BACKSPACE,
23695          action: action(backspaceDelete$8, editor, false)
23696        },
23697        {
23698          keyCode: VK.DELETE,
23699          action: action(backspaceDelete$8, editor, true)
23700        },
23701        {
23702          keyCode: VK.BACKSPACE,
23703          action: action(backspaceDelete$2, editor, false)
23704        },
23705        {
23706          keyCode: VK.DELETE,
23707          action: action(backspaceDelete$2, editor, true)
23708        }
23709      ], evt).filter(_ => editor.selection.isEditable()).each(applyAction => {
23710        evt.preventDefault();
23711        const beforeInput = fireBeforeInputEvent(editor, inputType);
23712        if (!beforeInput.isDefaultPrevented()) {
23713          applyAction();
23714          fireInputEvent(editor, inputType);
23715        }
23716      });
23717    };
23718    const executeKeyupOverride = (editor, evt, isBackspaceKeydown) => {
23719      const platform = detect$2();
23720      const os = platform.os;
23721      const browser = platform.browser;
23722      const multiDeleteKeyPatterns = os.isMacOS() ? [
23723        {
23724          keyCode: VK.BACKSPACE,
23725          altKey: true,
23726          action: action(refreshCaret, editor)
23727        },
23728        {
23729          keyCode: VK.DELETE,
23730          altKey: true,
23731          action: action(refreshCaret, editor)
23732        }
23733      ] : [
23734        {
23735          keyCode: VK.BACKSPACE,
23736          ctrlKey: true,
23737          action: action(refreshCaret, editor)
23738        },
23739        {
23740          keyCode: VK.DELETE,
23741          ctrlKey: true,
23742          action: action(refreshCaret, editor)
23743        }
23744      ];
23745      if (os.isMacOS() && isBackspaceKeydown) {
23746        multiDeleteKeyPatterns.push({
23747          keyCode: browser.isFirefox() ? 224 : 91,
23748          action: action(refreshCaret, editor)
23749        });
23750      }
23751      execute([
23752        {
23753          keyCode: VK.BACKSPACE,
23754          action: action(paddEmptyElement, editor)
23755        },
23756        {
23757          keyCode: VK.DELETE,
23758          action: action(paddEmptyElement, editor)
23759        },
23760        ...multiDeleteKeyPatterns
23761      ], evt);
23762    };
23763    const setup$i = (editor, caret) => {
23764      let isBackspaceKeydown = false;
23765      editor.on('keydown', evt => {
23766        isBackspaceKeydown = evt.keyCode === VK.BACKSPACE;
23767        if (!evt.isDefaultPrevented()) {
23768          executeKeydownOverride$3(editor, caret, evt);
23769        }
23770      });
23771      editor.on('keyup', evt => {
23772        if (!evt.isDefaultPrevented()) {
23773          executeKeyupOverride(editor, evt, isBackspaceKeydown);
23774        }
23775        isBackspaceKeydown = false;
23776      });
23777    };
23778
23779    const firstNonWhiteSpaceNodeSibling = node => {
23780      while (node) {
23781        if (isElement$6(node) || isText$a(node) && node.data && /[\r\n\s]/.test(node.data)) {
23782          return node;
23783        }
23784        node = node.nextSibling;
23785      }
23786      return null;
23787    };
23788    const moveToCaretPosition = (editor, root) => {
23789      const dom = editor.dom;
23790      const moveCaretBeforeOnEnterElementsMap = editor.schema.getMoveCaretBeforeOnEnterElements();
23791      if (!root) {
23792        return;
23793      }
23794      if (/^(LI|DT|DD)$/.test(root.nodeName)) {
23795        const firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild);
23796        if (firstChild && /^(UL|OL|DL)$/.test(firstChild.nodeName)) {
23797          root.insertBefore(dom.doc.createTextNode(nbsp), root.firstChild);
23798        }
23799      }
23800      const rng = dom.createRng();
23801      root.normalize();
23802      if (root.hasChildNodes()) {
23803        const walker = new DomTreeWalker(root, root);
23804        let lastNode = root;
23805        let node;
23806        while (node = walker.current()) {
23807          if (isText$a(node)) {
23808            rng.setStart(node, 0);
23809            rng.setEnd(node, 0);
23810            break;
23811          }
23812          if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
23813            rng.setStartBefore(node);
23814            rng.setEndBefore(node);
23815            break;
23816          }
23817          lastNode = node;
23818          node = walker.next();
23819        }
23820        if (!node) {
23821          rng.setStart(lastNode, 0);
23822          rng.setEnd(lastNode, 0);
23823        }
23824      } else {
23825        if (isBr$6(root)) {
23826          if (root.nextSibling && dom.isBlock(root.nextSibling)) {
23827            rng.setStartBefore(root);
23828            rng.setEndBefore(root);
23829          } else {
23830            rng.setStartAfter(root);
23831            rng.setEndAfter(root);
23832          }
23833        } else {
23834          rng.setStart(root, 0);
23835          rng.setEnd(root, 0);
23836        }
23837      }
23838      editor.selection.setRng(rng);
23839      scrollRangeIntoView(editor, rng);
23840    };
23841    const getEditableRoot = (dom, node) => {
23842      const root = dom.getRoot();
23843      let editableRoot;
23844      let parent = node;
23845      while (parent !== root && parent && dom.getContentEditable(parent) !== 'false') {
23846        if (dom.getContentEditable(parent) === 'true') {
23847          editableRoot = parent;
23848        }
23849        parent = parent.parentNode;
23850      }
23851      return parent !== root ? editableRoot : root;
23852    };
23853    const getParentBlock$1 = editor => {
23854      return Optional.from(editor.dom.getParent(editor.selection.getStart(true), editor.dom.isBlock));
23855    };
23856    const getParentBlockName = editor => {
23857      return getParentBlock$1(editor).fold(constant(''), parentBlock => {
23858        return parentBlock.nodeName.toUpperCase();
23859      });
23860    };
23861    const isListItemParentBlock = editor => {
23862      return getParentBlock$1(editor).filter(elm => {
23863        return isListItem$1(SugarElement.fromDom(elm));
23864      }).isSome();
23865    };
23866
23867    const getDetailsRoot = (editor, element) => editor.dom.getParent(element, isDetails);
23868    const isAtDetailsEdge = (root, element, isTextBlock) => {
23869      let node = element;
23870      while (node && node !== root && isNull(node.nextSibling)) {
23871        const parent = node.parentElement;
23872        if (!parent || !isTextBlock(parent)) {
23873          return isDetails(parent);
23874        }
23875        node = parent;
23876      }
23877      return false;
23878    };
23879    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()));
23880    const insertNewLine = (editor, createNewBlock, parentBlock) => {
23881      var _a, _b, _c;
23882      const newBlock = createNewBlock(getForcedRootBlock(editor));
23883      const root = getDetailsRoot(editor, parentBlock);
23884      if (!root) {
23885        return;
23886      }
23887      editor.dom.insertAfter(newBlock, root);
23888      moveToCaretPosition(editor, newBlock);
23889      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) {
23890        editor.dom.remove(parentBlock);
23891      }
23892    };
23893
23894    const hasFirstChild = (elm, name) => {
23895      return elm.firstChild && elm.firstChild.nodeName === name;
23896    };
23897    const isFirstChild = elm => {
23898      var _a;
23899      return ((_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === elm;
23900    };
23901    const hasParent = (elm, parentName) => {
23902      const parentNode = elm === null || elm === void 0 ? void 0 : elm.parentNode;
23903      return isNonNullable(parentNode) && parentNode.nodeName === parentName;
23904    };
23905    const isListBlock = elm => {
23906      return isNonNullable(elm) && /^(OL|UL|LI)$/.test(elm.nodeName);
23907    };
23908    const isListItem = elm => {
23909      return isNonNullable(elm) && /^(LI|DT|DD)$/.test(elm.nodeName);
23910    };
23911    const isNestedList = elm => {
23912      return isListBlock(elm) && isListBlock(elm.parentNode);
23913    };
23914    const getContainerBlock = containerBlock => {
23915      const containerBlockParent = containerBlock.parentNode;
23916      return isListItem(containerBlockParent) ? containerBlockParent : containerBlock;
23917    };
23918    const isFirstOrLastLi = (containerBlock, parentBlock, first) => {
23919      let node = containerBlock[first ? 'firstChild' : 'lastChild'];
23920      while (node) {
23921        if (isElement$6(node)) {
23922          break;
23923        }
23924        node = node[first ? 'nextSibling' : 'previousSibling'];
23925      }
23926      return node === parentBlock;
23927    };
23928    const insert$3 = (editor, createNewBlock, containerBlock, parentBlock, newBlockName) => {
23929      const dom = editor.dom;
23930      const rng = editor.selection.getRng();
23931      const containerParent = containerBlock.parentNode;
23932      if (containerBlock === editor.getBody() || !containerParent) {
23933        return;
23934      }
23935      if (isNestedList(containerBlock)) {
23936        newBlockName = 'LI';
23937      }
23938      let newBlock = createNewBlock(newBlockName);
23939      if (isFirstOrLastLi(containerBlock, parentBlock, true) && isFirstOrLastLi(containerBlock, parentBlock, false)) {
23940        if (hasParent(containerBlock, 'LI')) {
23941          const containerBlockParent = getContainerBlock(containerBlock);
23942          dom.insertAfter(newBlock, containerBlockParent);
23943          if (isFirstChild(containerBlock)) {
23944            dom.remove(containerBlockParent);
23945          } else {
23946            dom.remove(containerBlock);
23947          }
23948        } else {
23949          dom.replace(newBlock, containerBlock);
23950        }
23951      } else if (isFirstOrLastLi(containerBlock, parentBlock, true)) {
23952        if (hasParent(containerBlock, 'LI')) {
23953          dom.insertAfter(newBlock, getContainerBlock(containerBlock));
23954          newBlock.appendChild(dom.doc.createTextNode(' '));
23955          newBlock.appendChild(containerBlock);
23956        } else {
23957          containerParent.insertBefore(newBlock, containerBlock);
23958        }
23959        dom.remove(parentBlock);
23960      } else if (isFirstOrLastLi(containerBlock, parentBlock, false)) {
23961        dom.insertAfter(newBlock, getContainerBlock(containerBlock));
23962        dom.remove(parentBlock);
23963      } else {
23964        containerBlock = getContainerBlock(containerBlock);
23965        const tmpRng = rng.cloneRange();
23966        tmpRng.setStartAfter(parentBlock);
23967        tmpRng.setEndAfter(containerBlock);
23968        const fragment = tmpRng.extractContents();
23969        if (newBlockName === 'LI' && hasFirstChild(fragment, 'LI')) {
23970          newBlock = fragment.firstChild;
23971          dom.insertAfter(fragment, containerBlock);
23972        } else {
23973          dom.insertAfter(fragment, containerBlock);
23974          dom.insertAfter(newBlock, containerBlock);
23975        }
23976        dom.remove(parentBlock);
23977      }
23978      moveToCaretPosition(editor, newBlock);
23979    };
23980
23981    const trimZwsp = fragment => {
23982      each$e(descendants$1(SugarElement.fromDom(fragment), isText$b), text => {
23983        const rawNode = text.dom;
23984        rawNode.nodeValue = trim$1(rawNode.data);
23985      });
23986    };
23987    const isWithinNonEditableList = (editor, node) => {
23988      const parentList = editor.dom.getParent(node, 'ol,ul,dl');
23989      return parentList !== null && editor.dom.getContentEditableParent(parentList) === 'false';
23990    };
23991    const isEmptyAnchor = (dom, elm) => {
23992      return elm && elm.nodeName === 'A' && dom.isEmpty(elm);
23993    };
23994    const emptyBlock = elm => {
23995      elm.innerHTML = '<br data-mce-bogus="1">';
23996    };
23997    const containerAndSiblingName = (container, nodeName) => {
23998      return container.nodeName === nodeName || container.previousSibling && container.previousSibling.nodeName === nodeName;
23999    };
24000    const canSplitBlock = (dom, node) => {
24001      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';
24002    };
24003    const trimInlineElementsOnLeftSideOfBlock = (dom, nonEmptyElementsMap, block) => {
24004      var _a;
24005      const firstChilds = [];
24006      if (!block) {
24007        return;
24008      }
24009      let currentNode = block;
24010      while (currentNode = currentNode.firstChild) {
24011        if (dom.isBlock(currentNode)) {
24012          return;
24013        }
24014        if (isElement$6(currentNode) && !nonEmptyElementsMap[currentNode.nodeName.toLowerCase()]) {
24015          firstChilds.push(currentNode);
24016        }
24017      }
24018      let i = firstChilds.length;
24019      while (i--) {
24020        currentNode = firstChilds[i];
24021        if (!currentNode.hasChildNodes() || currentNode.firstChild === currentNode.lastChild && ((_a = currentNode.firstChild) === null || _a === void 0 ? void 0 : _a.nodeValue) === '') {
24022          dom.remove(currentNode);
24023        } else {
24024          if (isEmptyAnchor(dom, currentNode)) {
24025            dom.remove(currentNode);
24026          }
24027        }
24028      }
24029    };
24030    const normalizeZwspOffset = (start, container, offset) => {
24031      if (!isText$a(container)) {
24032        return offset;
24033      } else if (start) {
24034        return offset === 1 && container.data.charAt(offset - 1) === ZWSP$1 ? 0 : offset;
24035      } else {
24036        return offset === container.data.length - 1 && container.data.charAt(offset) === ZWSP$1 ? container.data.length : offset;
24037      }
24038    };
24039    const includeZwspInRange = rng => {
24040      const newRng = rng.cloneRange();
24041      newRng.setStart(rng.startContainer, normalizeZwspOffset(true, rng.startContainer, rng.startOffset));
24042      newRng.setEnd(rng.endContainer, normalizeZwspOffset(false, rng.endContainer, rng.endOffset));
24043      return newRng;
24044    };
24045    const trimLeadingLineBreaks = node => {
24046      let currentNode = node;
24047      do {
24048        if (isText$a(currentNode)) {
24049          currentNode.data = currentNode.data.replace(/^[\r\n]+/, '');
24050        }
24051        currentNode = currentNode.firstChild;
24052      } while (currentNode);
24053    };
24054    const applyAttributes = (editor, node, forcedRootBlockAttrs) => {
24055      const dom = editor.dom;
24056      Optional.from(forcedRootBlockAttrs.style).map(dom.parseStyle).each(attrStyles => {
24057        const currentStyles = getAllRaw(SugarElement.fromDom(node));
24058        const newStyles = {
24059          ...currentStyles,
24060          ...attrStyles
24061        };
24062        dom.setStyles(node, newStyles);
24063      });
24064      const attrClassesOpt = Optional.from(forcedRootBlockAttrs.class).map(attrClasses => attrClasses.split(/\s+/));
24065      const currentClassesOpt = Optional.from(node.className).map(currentClasses => filter$5(currentClasses.split(/\s+/), clazz => clazz !== ''));
24066      lift2(attrClassesOpt, currentClassesOpt, (attrClasses, currentClasses) => {
24067        const filteredClasses = filter$5(currentClasses, clazz => !contains$2(attrClasses, clazz));
24068        const newClasses = [
24069          ...attrClasses,
24070          ...filteredClasses
24071        ];
24072        dom.setAttrib(node, 'class', newClasses.join(' '));
24073      });
24074      const appliedAttrs = [
24075        'style',
24076        'class'
24077      ];
24078      const remainingAttrs = filter$4(forcedRootBlockAttrs, (_, attrs) => !contains$2(appliedAttrs, attrs));
24079      dom.setAttribs(node, remainingAttrs);
24080    };
24081    const setForcedBlockAttrs = (editor, node) => {
24082      const forcedRootBlockName = getForcedRootBlock(editor);
24083      if (forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) {
24084        const forcedRootBlockAttrs = getForcedRootBlockAttrs(editor);
24085        applyAttributes(editor, node, forcedRootBlockAttrs);
24086      }
24087    };
24088    const wrapSelfAndSiblingsInDefaultBlock = (editor, newBlockName, rng, container, offset) => {
24089      var _a, _b;
24090      const dom = editor.dom;
24091      const editableRoot = (_a = getEditableRoot(dom, container)) !== null && _a !== void 0 ? _a : dom.getRoot();
24092      let parentBlock = dom.getParent(container, dom.isBlock);
24093      if (!parentBlock || !canSplitBlock(dom, parentBlock)) {
24094        parentBlock = parentBlock || editableRoot;
24095        if (!parentBlock.hasChildNodes()) {
24096          const newBlock = dom.create(newBlockName);
24097          setForcedBlockAttrs(editor, newBlock);
24098          parentBlock.appendChild(newBlock);
24099          rng.setStart(newBlock, 0);
24100          rng.setEnd(newBlock, 0);
24101          return newBlock;
24102        }
24103        let node = container;
24104        while (node && node.parentNode !== parentBlock) {
24105          node = node.parentNode;
24106        }
24107        let startNode;
24108        while (node && !dom.isBlock(node)) {
24109          startNode = node;
24110          node = node.previousSibling;
24111        }
24112        const startNodeName = (_b = startNode === null || startNode === void 0 ? void 0 : startNode.parentElement) === null || _b === void 0 ? void 0 : _b.nodeName;
24113        if (startNode && startNodeName && editor.schema.isValidChild(startNodeName, newBlockName.toLowerCase())) {
24114          const startNodeParent = startNode.parentNode;
24115          const newBlock = dom.create(newBlockName);
24116          setForcedBlockAttrs(editor, newBlock);
24117          startNodeParent.insertBefore(newBlock, startNode);
24118          node = startNode;
24119          while (node && !dom.isBlock(node)) {
24120            const next = node.nextSibling;
24121            newBlock.appendChild(node);
24122            node = next;
24123          }
24124          rng.setStart(container, offset);
24125          rng.setEnd(container, offset);
24126        }
24127      }
24128      return container;
24129    };
24130    const addBrToBlockIfNeeded = (dom, block) => {
24131      block.normalize();
24132      const lastChild = block.lastChild;
24133      if (!lastChild || isElement$6(lastChild) && /^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true))) {
24134        dom.add(block, 'br');
24135      }
24136    };
24137    const shouldEndContainer = (editor, container) => {
24138      const optionValue = shouldEndContainerOnEmptyBlock(editor);
24139      if (isNullable(container)) {
24140        return false;
24141      } else if (isString(optionValue)) {
24142        return contains$2(Tools.explode(optionValue), container.nodeName.toLowerCase());
24143      } else {
24144        return optionValue;
24145      }
24146    };
24147    const insert$2 = (editor, evt) => {
24148      let container;
24149      let offset;
24150      let parentBlockName;
24151      let containerBlock;
24152      let isAfterLastNodeInContainer = false;
24153      const dom = editor.dom;
24154      const schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
24155      const rng = editor.selection.getRng();
24156      const newBlockName = getForcedRootBlock(editor);
24157      const isInRoot = rng.collapsed && rng.startContainer === editor.dom.getRoot();
24158      const start = SugarElement.fromDom(rng.startContainer);
24159      const child = child$1(start, rng.startOffset);
24160      const isCef = child.exists(element => isHTMLElement(element) && !isEditable$3(element));
24161      const inRootAndLastOrCef = isInRoot && isCef;
24162      const createNewBlock = name => {
24163        let node = container;
24164        const textInlineElements = schema.getTextInlineElements();
24165        let block;
24166        if (name || parentBlockName === 'TABLE' || parentBlockName === 'HR') {
24167          block = dom.create(name || newBlockName);
24168        } else {
24169          block = parentBlock.cloneNode(false);
24170        }
24171        let caretNode = block;
24172        if (shouldKeepStyles(editor) === false) {
24173          dom.setAttrib(block, 'style', null);
24174          dom.setAttrib(block, 'class', null);
24175        } else {
24176          do {
24177            if (textInlineElements[node.nodeName]) {
24178              if (isCaretNode(node) || isBookmarkNode$1(node)) {
24179                continue;
24180              }
24181              const clonedNode = node.cloneNode(false);
24182              dom.setAttrib(clonedNode, 'id', '');
24183              if (block.hasChildNodes()) {
24184                clonedNode.appendChild(block.firstChild);
24185                block.appendChild(clonedNode);
24186              } else {
24187                caretNode = clonedNode;
24188                block.appendChild(clonedNode);
24189              }
24190            }
24191          } while ((node = node.parentNode) && node !== editableRoot);
24192        }
24193        setForcedBlockAttrs(editor, block);
24194        emptyBlock(caretNode);
24195        return block;
24196      };
24197      const isCaretAtStartOrEndOfBlock = start => {
24198        const normalizedOffset = normalizeZwspOffset(start, container, offset);
24199        if (isText$a(container) && (start ? normalizedOffset > 0 : normalizedOffset < container.data.length)) {
24200          return false;
24201        }
24202        if (container.parentNode === parentBlock && isAfterLastNodeInContainer && !start) {
24203          return true;
24204        }
24205        if (start && isElement$6(container) && container === parentBlock.firstChild) {
24206          return true;
24207        }
24208        if (containerAndSiblingName(container, 'TABLE') || containerAndSiblingName(container, 'HR')) {
24209          return isAfterLastNodeInContainer && !start || !isAfterLastNodeInContainer && start;
24210        }
24211        const walker = new DomTreeWalker(container, parentBlock);
24212        if (isText$a(container)) {
24213          if (start && normalizedOffset === 0) {
24214            walker.prev();
24215          } else if (!start && normalizedOffset === container.data.length) {
24216            walker.next();
24217          }
24218        }
24219        let node;
24220        while (node = walker.current()) {
24221          if (isElement$6(node)) {
24222            if (!node.getAttribute('data-mce-bogus')) {
24223              const name = node.nodeName.toLowerCase();
24224              if (nonEmptyElementsMap[name] && name !== 'br') {
24225                return false;
24226              }
24227            }
24228          } else if (isText$a(node) && !isWhitespaceText(node.data)) {
24229            return false;
24230          }
24231          if (start) {
24232            walker.prev();
24233          } else {
24234            walker.next();
24235          }
24236        }
24237        return true;
24238      };
24239      const insertNewBlockAfter = () => {
24240        let block;
24241        if (/^(H[1-6]|PRE|FIGURE)$/.test(parentBlockName) && containerBlockName !== 'HGROUP') {
24242          block = createNewBlock(newBlockName);
24243        } else {
24244          block = createNewBlock();
24245        }
24246        if (shouldEndContainer(editor, containerBlock) && canSplitBlock(dom, containerBlock) && dom.isEmpty(parentBlock, undefined, { includeZwsp: true })) {
24247          block = dom.split(containerBlock, parentBlock);
24248        } else {
24249          dom.insertAfter(block, parentBlock);
24250        }
24251        moveToCaretPosition(editor, block);
24252        return block;
24253      };
24254      normalize$2(dom, rng).each(normRng => {
24255        rng.setStart(normRng.startContainer, normRng.startOffset);
24256        rng.setEnd(normRng.endContainer, normRng.endOffset);
24257      });
24258      container = rng.startContainer;
24259      offset = rng.startOffset;
24260      const shiftKey = !!(evt && evt.shiftKey);
24261      const ctrlKey = !!(evt && evt.ctrlKey);
24262      if (isElement$6(container) && container.hasChildNodes() && !inRootAndLastOrCef) {
24263        isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
24264        container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
24265        if (isAfterLastNodeInContainer && isText$a(container)) {
24266          offset = container.data.length;
24267        } else {
24268          offset = 0;
24269        }
24270      }
24271      const editableRoot = getEditableRoot(dom, container);
24272      if (!editableRoot || isWithinNonEditableList(editor, container)) {
24273        return;
24274      }
24275      if (!shiftKey) {
24276        container = wrapSelfAndSiblingsInDefaultBlock(editor, newBlockName, rng, container, offset);
24277      }
24278      let parentBlock = dom.getParent(container, dom.isBlock) || dom.getRoot();
24279      containerBlock = isNonNullable(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.parentNode) ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
24280      parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
24281      const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
24282      if (containerBlockName === 'LI' && !ctrlKey) {
24283        const liBlock = containerBlock;
24284        parentBlock = liBlock;
24285        containerBlock = liBlock.parentNode;
24286        parentBlockName = containerBlockName;
24287      }
24288      if (isElement$6(containerBlock) && isLastEmptyBlockInDetails(editor, shiftKey, parentBlock)) {
24289        return insertNewLine(editor, createNewBlock, parentBlock);
24290      }
24291      if (/^(LI|DT|DD)$/.test(parentBlockName) && isElement$6(containerBlock)) {
24292        if (dom.isEmpty(parentBlock)) {
24293          insert$3(editor, createNewBlock, containerBlock, parentBlock, newBlockName);
24294          return;
24295        }
24296      }
24297      if (!inRootAndLastOrCef && (parentBlock === editor.getBody() || !canSplitBlock(dom, parentBlock))) {
24298        return;
24299      }
24300      const parentBlockParent = parentBlock.parentNode;
24301      let newBlock;
24302      if (inRootAndLastOrCef) {
24303        newBlock = createNewBlock(newBlockName);
24304        child.fold(() => {
24305          append$1(start, SugarElement.fromDom(newBlock));
24306        }, child => {
24307          before$3(child, SugarElement.fromDom(newBlock));
24308        });
24309        editor.selection.setCursorLocation(newBlock, 0);
24310      } else if (isCaretContainerBlock$1(parentBlock)) {
24311        newBlock = showCaretContainerBlock(parentBlock);
24312        if (dom.isEmpty(parentBlock)) {
24313          emptyBlock(parentBlock);
24314        }
24315        setForcedBlockAttrs(editor, newBlock);
24316        moveToCaretPosition(editor, newBlock);
24317      } else if (isCaretAtStartOrEndOfBlock(false)) {
24318        newBlock = insertNewBlockAfter();
24319      } else if (isCaretAtStartOrEndOfBlock(true) && parentBlockParent) {
24320        newBlock = parentBlockParent.insertBefore(createNewBlock(), parentBlock);
24321        const isNearChildren = hasChildNodes(SugarElement.fromDom(rng.startContainer)) && rng.collapsed;
24322        moveToCaretPosition(editor, containerAndSiblingName(parentBlock, 'HR') || isNearChildren ? newBlock : parentBlock);
24323      } else {
24324        const tmpRng = includeZwspInRange(rng).cloneRange();
24325        tmpRng.setEndAfter(parentBlock);
24326        const fragment = tmpRng.extractContents();
24327        trimZwsp(fragment);
24328        trimLeadingLineBreaks(fragment);
24329        newBlock = fragment.firstChild;
24330        dom.insertAfter(fragment, parentBlock);
24331        trimInlineElementsOnLeftSideOfBlock(dom, nonEmptyElementsMap, newBlock);
24332        addBrToBlockIfNeeded(dom, parentBlock);
24333        if (dom.isEmpty(parentBlock)) {
24334          emptyBlock(parentBlock);
24335        }
24336        newBlock.normalize();
24337        if (dom.isEmpty(newBlock)) {
24338          dom.remove(newBlock);
24339          insertNewBlockAfter();
24340        } else {
24341          setForcedBlockAttrs(editor, newBlock);
24342          moveToCaretPosition(editor, newBlock);
24343        }
24344      }
24345      dom.setAttrib(newBlock, 'id', '');
24346      editor.dispatch('NewBlock', { newBlock });
24347    };
24348    const fakeEventName$1 = 'insertParagraph';
24349    const blockbreak = {
24350      insert: insert$2,
24351      fakeEventName: fakeEventName$1
24352    };
24353
24354    const hasRightSideContent = (schema, container, parentBlock) => {
24355      const walker = new DomTreeWalker(container, parentBlock);
24356      let node;
24357      const nonEmptyElementsMap = schema.getNonEmptyElements();
24358      while (node = walker.next()) {
24359        if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || isText$a(node) && node.length > 0) {
24360          return true;
24361        }
24362      }
24363      return false;
24364    };
24365    const moveSelectionToBr = (editor, brElm, extraBr) => {
24366      const rng = editor.dom.createRng();
24367      if (!extraBr) {
24368        rng.setStartAfter(brElm);
24369        rng.setEndAfter(brElm);
24370      } else {
24371        rng.setStartBefore(brElm);
24372        rng.setEndBefore(brElm);
24373      }
24374      editor.selection.setRng(rng);
24375      scrollRangeIntoView(editor, rng);
24376    };
24377    const insertBrAtCaret = (editor, evt) => {
24378      const selection = editor.selection;
24379      const dom = editor.dom;
24380      const rng = selection.getRng();
24381      let brElm;
24382      let extraBr = false;
24383      normalize$2(dom, rng).each(normRng => {
24384        rng.setStart(normRng.startContainer, normRng.startOffset);
24385        rng.setEnd(normRng.endContainer, normRng.endOffset);
24386      });
24387      let offset = rng.startOffset;
24388      let container = rng.startContainer;
24389      if (isElement$6(container) && container.hasChildNodes()) {
24390        const isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
24391        container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
24392        if (isAfterLastNodeInContainer && isText$a(container)) {
24393          offset = container.data.length;
24394        } else {
24395          offset = 0;
24396        }
24397      }
24398      let parentBlock = dom.getParent(container, dom.isBlock);
24399      const containerBlock = parentBlock && parentBlock.parentNode ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
24400      const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
24401      const isControlKey = !!(evt && evt.ctrlKey);
24402      if (containerBlockName === 'LI' && !isControlKey) {
24403        parentBlock = containerBlock;
24404      }
24405      if (isText$a(container) && offset >= container.data.length) {
24406        if (!hasRightSideContent(editor.schema, container, parentBlock || dom.getRoot())) {
24407          brElm = dom.create('br');
24408          rng.insertNode(brElm);
24409          rng.setStartAfter(brElm);
24410          rng.setEndAfter(brElm);
24411          extraBr = true;
24412        }
24413      }
24414      brElm = dom.create('br');
24415      rangeInsertNode(dom, rng, brElm);
24416      moveSelectionToBr(editor, brElm, extraBr);
24417      editor.undoManager.add();
24418    };
24419    const insertBrBefore = (editor, inline) => {
24420      const br = SugarElement.fromTag('br');
24421      before$3(SugarElement.fromDom(inline), br);
24422      editor.undoManager.add();
24423    };
24424    const insertBrAfter = (editor, inline) => {
24425      if (!hasBrAfter(editor.getBody(), inline)) {
24426        after$4(SugarElement.fromDom(inline), SugarElement.fromTag('br'));
24427      }
24428      const br = SugarElement.fromTag('br');
24429      after$4(SugarElement.fromDom(inline), br);
24430      moveSelectionToBr(editor, br.dom, false);
24431      editor.undoManager.add();
24432    };
24433    const isBeforeBr = pos => {
24434      return isBr$6(pos.getNode());
24435    };
24436    const hasBrAfter = (rootNode, startNode) => {
24437      if (isBeforeBr(CaretPosition.after(startNode))) {
24438        return true;
24439      } else {
24440        return nextPosition(rootNode, CaretPosition.after(startNode)).map(pos => {
24441          return isBr$6(pos.getNode());
24442        }).getOr(false);
24443      }
24444    };
24445    const isAnchorLink = elm => {
24446      return elm && elm.nodeName === 'A' && 'href' in elm;
24447    };
24448    const isInsideAnchor = location => {
24449      return location.fold(never, isAnchorLink, isAnchorLink, never);
24450    };
24451    const readInlineAnchorLocation = editor => {
24452      const isInlineTarget$1 = curry(isInlineTarget, editor);
24453      const position = CaretPosition.fromRangeStart(editor.selection.getRng());
24454      return readLocation(isInlineTarget$1, editor.getBody(), position).filter(isInsideAnchor);
24455    };
24456    const insertBrOutsideAnchor = (editor, location) => {
24457      location.fold(noop, curry(insertBrBefore, editor), curry(insertBrAfter, editor), noop);
24458    };
24459    const insert$1 = (editor, evt) => {
24460      const anchorLocation = readInlineAnchorLocation(editor);
24461      if (anchorLocation.isSome()) {
24462        anchorLocation.each(curry(insertBrOutsideAnchor, editor));
24463      } else {
24464        insertBrAtCaret(editor, evt);
24465      }
24466    };
24467    const fakeEventName = 'insertLineBreak';
24468    const linebreak = {
24469      insert: insert$1,
24470      fakeEventName
24471    };
24472
24473    const matchesSelector = (editor, selector) => {
24474      return getParentBlock$1(editor).filter(parentBlock => {
24475        return selector.length > 0 && is$1(SugarElement.fromDom(parentBlock), selector);
24476      }).isSome();
24477    };
24478    const shouldInsertBr = editor => {
24479      return matchesSelector(editor, getBrNewLineSelector(editor));
24480    };
24481    const shouldBlockNewLine$1 = editor => {
24482      return matchesSelector(editor, getNoNewLineSelector(editor));
24483    };
24484
24485    const newLineAction = Adt.generate([
24486      { br: [] },
24487      { block: [] },
24488      { none: [] }
24489    ]);
24490    const shouldBlockNewLine = (editor, _shiftKey) => {
24491      return shouldBlockNewLine$1(editor);
24492    };
24493    const inListBlock = requiredState => {
24494      return (editor, _shiftKey) => {
24495        return isListItemParentBlock(editor) === requiredState;
24496      };
24497    };
24498    const inBlock = (blockName, requiredState) => (editor, _shiftKey) => {
24499      const state = getParentBlockName(editor) === blockName.toUpperCase();
24500      return state === requiredState;
24501    };
24502    const inCefBlock = editor => {
24503      const editableRoot = getEditableRoot(editor.dom, editor.selection.getStart());
24504      return isNullable(editableRoot);
24505    };
24506    const inPreBlock = requiredState => inBlock('pre', requiredState);
24507    const inSummaryBlock = () => inBlock('summary', true);
24508    const shouldPutBrInPre = requiredState => {
24509      return (editor, _shiftKey) => {
24510        return shouldPutBrInPre$1(editor) === requiredState;
24511      };
24512    };
24513    const inBrContext = (editor, _shiftKey) => {
24514      return shouldInsertBr(editor);
24515    };
24516    const hasShiftKey = (_editor, shiftKey) => {
24517      return shiftKey;
24518    };
24519    const canInsertIntoEditableRoot = editor => {
24520      const forcedRootBlock = getForcedRootBlock(editor);
24521      const rootEditable = getEditableRoot(editor.dom, editor.selection.getStart());
24522      return isNonNullable(rootEditable) && editor.schema.isValidChild(rootEditable.nodeName, forcedRootBlock);
24523    };
24524    const isInRootWithEmptyOrCEF = editor => {
24525      const rng = editor.selection.getRng();
24526      const isInRoot = rng.collapsed && rng.startContainer === editor.dom.getRoot();
24527      const start = SugarElement.fromDom(rng.startContainer);
24528      const child = child$1(start, rng.startOffset);
24529      const isCefOpt = child.map(element => isHTMLElement(element) && !isEditable$3(element));
24530      return isInRoot && isCefOpt.getOr(true);
24531    };
24532    const match = (predicates, action) => {
24533      return (editor, shiftKey) => {
24534        const isMatch = foldl(predicates, (res, p) => {
24535          return res && p(editor, shiftKey);
24536        }, true);
24537        return isMatch ? Optional.some(action) : Optional.none();
24538      };
24539    };
24540    const getAction = (editor, evt) => {
24541      return evaluateUntil([
24542        match([shouldBlockNewLine], newLineAction.none()),
24543        match([
24544          inPreBlock(true),
24545          inCefBlock
24546        ], newLineAction.none()),
24547        match([inSummaryBlock()], newLineAction.br()),
24548        match([
24549          inPreBlock(true),
24550          shouldPutBrInPre(false),
24551          hasShiftKey
24552        ], newLineAction.br()),
24553        match([
24554          inPreBlock(true),
24555          shouldPutBrInPre(false)
24556        ], newLineAction.block()),
24557        match([
24558          inPreBlock(true),
24559          shouldPutBrInPre(true),
24560          hasShiftKey
24561        ], newLineAction.block()),
24562        match([
24563          inPreBlock(true),
24564          shouldPutBrInPre(true)
24565        ], newLineAction.br()),
24566        match([
24567          inListBlock(true),
24568          hasShiftKey
24569        ], newLineAction.br()),
24570        match([inListBlock(true)], newLineAction.block()),
24571        match([inBrContext], newLineAction.br()),
24572        match([hasShiftKey], newLineAction.br()),
24573        match([canInsertIntoEditableRoot], newLineAction.block()),
24574        match([isInRootWithEmptyOrCEF], newLineAction.block())
24575      ], [
24576        editor,
24577        !!(evt && evt.shiftKey)
24578      ]).getOr(newLineAction.none());
24579    };
24580
24581    const insertBreak = (breakType, editor, evt) => {
24582      if (!editor.selection.isCollapsed()) {
24583        execEditorDeleteCommand(editor);
24584      }
24585      if (isNonNullable(evt)) {
24586        const event = fireBeforeInputEvent(editor, breakType.fakeEventName);
24587        if (event.isDefaultPrevented()) {
24588          return;
24589        }
24590      }
24591      breakType.insert(editor, evt);
24592      if (isNonNullable(evt)) {
24593        fireInputEvent(editor, breakType.fakeEventName);
24594      }
24595    };
24596    const insert = (editor, evt) => {
24597      const br = () => insertBreak(linebreak, editor, evt);
24598      const block = () => insertBreak(blockbreak, editor, evt);
24599      const logicalAction = getAction(editor, evt);
24600      switch (getNewlineBehavior(editor)) {
24601      case 'linebreak':
24602        logicalAction.fold(br, br, noop);
24603        break;
24604      case 'block':
24605        logicalAction.fold(block, block, noop);
24606        break;
24607      case 'invert':
24608        logicalAction.fold(block, br, noop);
24609        break;
24610      default:
24611        logicalAction.fold(br, block, noop);
24612        break;
24613      }
24614    };
24615
24616    const platform$2 = detect$2();
24617    const isIOSSafari = platform$2.os.isiOS() && platform$2.browser.isSafari();
24618    const handleEnterKeyEvent = (editor, event) => {
24619      if (event.isDefaultPrevented()) {
24620        return;
24621      }
24622      event.preventDefault();
24623      endTypingLevelIgnoreLocks(editor.undoManager);
24624      editor.undoManager.transact(() => {
24625        insert(editor, event);
24626      });
24627    };
24628    const isCaretAfterKoreanCharacter = rng => {
24629      if (!rng.collapsed) {
24630        return false;
24631      }
24632      const startContainer = rng.startContainer;
24633      if (isText$a(startContainer)) {
24634        const koreanCharRegex = /^[\uAC00-\uD7AF\u1100-\u11FF\u3130-\u318F\uA960-\uA97F\uD7B0-\uD7FF]$/;
24635        const char = startContainer.data.charAt(rng.startOffset - 1);
24636        return koreanCharRegex.test(char);
24637      } else {
24638        return false;
24639      }
24640    };
24641    const setup$h = editor => {
24642      let iOSSafariKeydownBookmark = Optional.none();
24643      const iOSSafariKeydownOverride = editor => {
24644        iOSSafariKeydownBookmark = Optional.some(editor.selection.getBookmark());
24645        editor.undoManager.add();
24646      };
24647      const iOSSafariKeyupOverride = (editor, event) => {
24648        editor.undoManager.undo();
24649        iOSSafariKeydownBookmark.fold(noop, b => editor.selection.moveToBookmark(b));
24650        handleEnterKeyEvent(editor, event);
24651        iOSSafariKeydownBookmark = Optional.none();
24652      };
24653      editor.on('keydown', event => {
24654        if (event.keyCode === VK.ENTER) {
24655          if (isIOSSafari && isCaretAfterKoreanCharacter(editor.selection.getRng())) {
24656            iOSSafariKeydownOverride(editor);
24657          } else {
24658            handleEnterKeyEvent(editor, event);
24659          }
24660        }
24661      });
24662      editor.on('keyup', event => {
24663        if (event.keyCode === VK.ENTER) {
24664          iOSSafariKeydownBookmark.each(() => iOSSafariKeyupOverride(editor, event));
24665        }
24666      });
24667    };
24668
24669    const executeKeydownOverride$2 = (editor, caret, evt) => {
24670      const isMac = Env.os.isMacOS() || Env.os.isiOS();
24671      execute([
24672        {
24673          keyCode: VK.END,
24674          action: action(moveToLineEndPoint$1, editor, true)
24675        },
24676        {
24677          keyCode: VK.HOME,
24678          action: action(moveToLineEndPoint$1, editor, false)
24679        },
24680        ...!isMac ? [
24681          {
24682            keyCode: VK.HOME,
24683            action: action(selectToEndPoint, editor, false),
24684            ctrlKey: true,
24685            shiftKey: true
24686          },
24687          {
24688            keyCode: VK.END,
24689            action: action(selectToEndPoint, editor, true),
24690            ctrlKey: true,
24691            shiftKey: true
24692          }
24693        ] : [],
24694        {
24695          keyCode: VK.END,
24696          action: action(moveToLineEndPoint, editor, true)
24697        },
24698        {
24699          keyCode: VK.HOME,
24700          action: action(moveToLineEndPoint, editor, false)
24701        },
24702        {
24703          keyCode: VK.END,
24704          action: action(moveToLineEndPoint$2, editor, true, caret)
24705        },
24706        {
24707          keyCode: VK.HOME,
24708          action: action(moveToLineEndPoint$2, editor, false, caret)
24709        }
24710      ], evt).each(_ => {
24711        evt.preventDefault();
24712      });
24713    };
24714    const setup$g = (editor, caret) => {
24715      editor.on('keydown', evt => {
24716        if (!evt.isDefaultPrevented()) {
24717          executeKeydownOverride$2(editor, caret, evt);
24718        }
24719      });
24720    };
24721
24722    const setup$f = editor => {
24723      editor.on('input', e => {
24724        if (!e.isComposing) {
24725          normalizeNbspsInEditor(editor);
24726        }
24727      });
24728    };
24729
24730    const platform$1 = detect$2();
24731    const executeKeyupAction = (editor, caret, evt) => {
24732      execute([
24733        {
24734          keyCode: VK.PAGE_UP,
24735          action: action(moveToLineEndPoint$2, editor, false, caret)
24736        },
24737        {
24738          keyCode: VK.PAGE_DOWN,
24739          action: action(moveToLineEndPoint$2, editor, true, caret)
24740        }
24741      ], evt);
24742    };
24743    const stopImmediatePropagation = e => e.stopImmediatePropagation();
24744    const isPageUpDown = evt => evt.keyCode === VK.PAGE_UP || evt.keyCode === VK.PAGE_DOWN;
24745    const setNodeChangeBlocker = (blocked, editor, block) => {
24746      if (block && !blocked.get()) {
24747        editor.on('NodeChange', stopImmediatePropagation, true);
24748      } else if (!block && blocked.get()) {
24749        editor.off('NodeChange', stopImmediatePropagation);
24750      }
24751      blocked.set(block);
24752    };
24753    const setup$e = (editor, caret) => {
24754      if (platform$1.os.isMacOS()) {
24755        return;
24756      }
24757      const blocked = Cell(false);
24758      editor.on('keydown', evt => {
24759        if (isPageUpDown(evt)) {
24760          setNodeChangeBlocker(blocked, editor, true);
24761        }
24762      });
24763      editor.on('keyup', evt => {
24764        if (!evt.isDefaultPrevented()) {
24765          executeKeyupAction(editor, caret, evt);
24766        }
24767        if (isPageUpDown(evt) && blocked.get()) {
24768          setNodeChangeBlocker(blocked, editor, false);
24769          editor.nodeChanged();
24770        }
24771      });
24772    };
24773
24774    const insertTextAtPosition = (text, pos) => {
24775      const container = pos.container();
24776      const offset = pos.offset();
24777      if (isText$a(container)) {
24778        container.insertData(offset, text);
24779        return Optional.some(CaretPosition(container, offset + text.length));
24780      } else {
24781        return getElementFromPosition(pos).map(elm => {
24782          const textNode = SugarElement.fromText(text);
24783          if (pos.isAtEnd()) {
24784            after$4(elm, textNode);
24785          } else {
24786            before$3(elm, textNode);
24787          }
24788          return CaretPosition(textNode.dom, text.length);
24789        });
24790      }
24791    };
24792    const insertNbspAtPosition = curry(insertTextAtPosition, nbsp);
24793    const insertSpaceAtPosition = curry(insertTextAtPosition, ' ');
24794
24795    const insertSpaceOrNbspAtPosition = (root, pos) => needsToHaveNbsp(root, pos) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
24796    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)));
24797    const insertInlineBoundarySpaceOrNbsp = (root, pos) => checkPos => needsToHaveNbsp(root, checkPos) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
24798    const setSelection = editor => pos => {
24799      editor.selection.setRng(pos.toRange());
24800      editor.nodeChanged();
24801    };
24802    const isInsideSummary = (domUtils, node) => domUtils.isEditable(domUtils.getParent(node, 'summary'));
24803    const insertSpaceOrNbspAtSelection = editor => {
24804      const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
24805      const root = SugarElement.fromDom(editor.getBody());
24806      if (editor.selection.isCollapsed()) {
24807        const isInlineTarget$1 = curry(isInlineTarget, editor);
24808        const caretPosition = CaretPosition.fromRangeStart(editor.selection.getRng());
24809        return readLocation(isInlineTarget$1, editor.getBody(), caretPosition).bind(locationToCaretPosition(root)).map(checkPos => () => insertInlineBoundarySpaceOrNbsp(root, pos)(checkPos).each(setSelection(editor)));
24810      } else {
24811        return Optional.none();
24812      }
24813    };
24814    const insertSpaceInSummaryAtSelectionOnFirefox = editor => {
24815      const insertSpaceThunk = () => {
24816        const root = SugarElement.fromDom(editor.getBody());
24817        if (!editor.selection.isCollapsed()) {
24818          editor.getDoc().execCommand('Delete');
24819        }
24820        const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
24821        insertSpaceOrNbspAtPosition(root, pos).each(setSelection(editor));
24822      };
24823      return someIf(Env.browser.isFirefox() && editor.selection.isEditable() && isInsideSummary(editor.dom, editor.selection.getRng().startContainer), insertSpaceThunk);
24824    };
24825
24826    const executeKeydownOverride$1 = (editor, evt) => {
24827      executeWithDelayedAction([
24828        {
24829          keyCode: VK.SPACEBAR,
24830          action: action(insertSpaceOrNbspAtSelection, editor)
24831        },
24832        {
24833          keyCode: VK.SPACEBAR,
24834          action: action(insertSpaceInSummaryAtSelectionOnFirefox, editor)
24835        }
24836      ], evt).each(applyAction => {
24837        evt.preventDefault();
24838        const event = fireBeforeInputEvent(editor, 'insertText', { data: ' ' });
24839        if (!event.isDefaultPrevented()) {
24840          applyAction();
24841          fireInputEvent(editor, 'insertText', { data: ' ' });
24842        }
24843      });
24844    };
24845    const setup$d = editor => {
24846      editor.on('keydown', evt => {
24847        if (!evt.isDefaultPrevented()) {
24848          executeKeydownOverride$1(editor, evt);
24849        }
24850      });
24851    };
24852
24853    const tableTabNavigation = editor => {
24854      if (hasTableTabNavigation(editor)) {
24855        return [
24856          {
24857            keyCode: VK.TAB,
24858            action: action(handleTab, editor, true)
24859          },
24860          {
24861            keyCode: VK.TAB,
24862            shiftKey: true,
24863            action: action(handleTab, editor, false)
24864          }
24865        ];
24866      } else {
24867        return [];
24868      }
24869    };
24870    const executeKeydownOverride = (editor, evt) => {
24871      execute([...tableTabNavigation(editor)], evt).each(_ => {
24872        evt.preventDefault();
24873      });
24874    };
24875    const setup$c = editor => {
24876      editor.on('keydown', evt => {
24877        if (!evt.isDefaultPrevented()) {
24878          executeKeydownOverride(editor, evt);
24879        }
24880      });
24881    };
24882
24883    const setup$b = editor => {
24884      editor.addShortcut('Meta+P', '', 'mcePrint');
24885      setup$j(editor);
24886      if (isRtc(editor)) {
24887        return Cell(null);
24888      } else {
24889        const caret = setupSelectedState(editor);
24890        setup$l(editor);
24891        setup$k(editor, caret);
24892        setup$i(editor, caret);
24893        setup$h(editor);
24894        setup$d(editor);
24895        setup$f(editor);
24896        setup$c(editor);
24897        setup$g(editor, caret);
24898        setup$e(editor, caret);
24899        return caret;
24900      }
24901    };
24902
24903    class NodeChange {
24904      constructor(editor) {
24905        this.lastPath = [];
24906        this.editor = editor;
24907        let lastRng;
24908        const self = this;
24909        if (!('onselectionchange' in editor.getDoc())) {
24910          editor.on('NodeChange click mouseup keyup focus', e => {
24911            const nativeRng = editor.selection.getRng();
24912            const fakeRng = {
24913              startContainer: nativeRng.startContainer,
24914              startOffset: nativeRng.startOffset,
24915              endContainer: nativeRng.endContainer,
24916              endOffset: nativeRng.endOffset
24917            };
24918            if (e.type === 'nodechange' || !isEq$4(fakeRng, lastRng)) {
24919              editor.dispatch('SelectionChange');
24920            }
24921            lastRng = fakeRng;
24922          });
24923        }
24924        editor.on('contextmenu', () => {
24925          editor.dispatch('SelectionChange');
24926        });
24927        editor.on('SelectionChange', () => {
24928          const startElm = editor.selection.getStart(true);
24929          if (!startElm) {
24930            return;
24931          }
24932          if (hasAnyRanges(editor) && !self.isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
24933            editor.nodeChanged({ selectionChange: true });
24934          }
24935        });
24936        editor.on('mouseup', e => {
24937          if (!e.isDefaultPrevented() && hasAnyRanges(editor)) {
24938            if (editor.selection.getNode().nodeName === 'IMG') {
24939              Delay.setEditorTimeout(editor, () => {
24940                editor.nodeChanged();
24941              });
24942            } else {
24943              editor.nodeChanged();
24944            }
24945          }
24946        });
24947      }
24948      nodeChanged(args = {}) {
24949        const selection = this.editor.selection;
24950        let node;
24951        if (this.editor.initialized && selection && !shouldDisableNodeChange(this.editor) && !this.editor.mode.isReadOnly()) {
24952          const root = this.editor.getBody();
24953          node = selection.getStart(true) || root;
24954          if (node.ownerDocument !== this.editor.getDoc() || !this.editor.dom.isChildOf(node, root)) {
24955            node = root;
24956          }
24957          const parents = [];
24958          this.editor.dom.getParent(node, node => {
24959            if (node === root) {
24960              return true;
24961            } else {
24962              parents.push(node);
24963              return false;
24964            }
24965          });
24966          this.editor.dispatch('NodeChange', {
24967            ...args,
24968            element: node,
24969            parents
24970          });
24971        }
24972      }
24973      isSameElementPath(startElm) {
24974        let i;
24975        const editor = this.editor;
24976        const currentPath = reverse(editor.dom.getParents(startElm, always, editor.getBody()));
24977        if (currentPath.length === this.lastPath.length) {
24978          for (i = currentPath.length; i >= 0; i--) {
24979            if (currentPath[i] !== this.lastPath[i]) {
24980              break;
24981            }
24982          }
24983          if (i === -1) {
24984            this.lastPath = currentPath;
24985            return true;
24986          }
24987        }
24988        this.lastPath = currentPath;
24989        return false;
24990      }
24991    }
24992
24993    const imageId = generate$1('image');
24994    const getDragImage = transfer => {
24995      const dt = transfer;
24996      return Optional.from(dt[imageId]);
24997    };
24998    const setDragImage = (transfer, imageData) => {
24999      const dt = transfer;
25000      dt[imageId] = imageData;
25001    };
25002
25003    const eventId = generate$1('event');
25004    const getEvent = transfer => {
25005      const dt = transfer;
25006      return Optional.from(dt[eventId]);
25007    };
25008    const mkSetEventFn = type => transfer => {
25009      const dt = transfer;
25010      dt[eventId] = type;
25011    };
25012    const setEvent = (transfer, type) => mkSetEventFn(type)(transfer);
25013    const setDragstartEvent = mkSetEventFn(0);
25014    const setDropEvent = mkSetEventFn(2);
25015    const setDragendEvent = mkSetEventFn(1);
25016    const checkEvent = expectedType => transfer => {
25017      const dt = transfer;
25018      return Optional.from(dt[eventId]).exists(type => type === expectedType);
25019    };
25020    const isInDragStartEvent = checkEvent(0);
25021
25022    const createEmptyFileList = () => Object.freeze({
25023      length: 0,
25024      item: _ => null
25025    });
25026
25027    const modeId = generate$1('mode');
25028    const getMode = transfer => {
25029      const dt = transfer;
25030      return Optional.from(dt[modeId]);
25031    };
25032    const mkSetModeFn = mode => transfer => {
25033      const dt = transfer;
25034      dt[modeId] = mode;
25035    };
25036    const setMode$1 = (transfer, mode) => mkSetModeFn(mode)(transfer);
25037    const setReadWriteMode = mkSetModeFn(0);
25038    const setReadOnlyMode = mkSetModeFn(2);
25039    const setProtectedMode = mkSetModeFn(1);
25040    const checkMode = expectedMode => transfer => {
25041      const dt = transfer;
25042      return Optional.from(dt[modeId]).exists(mode => mode === expectedMode);
25043    };
25044    const isInReadWriteMode = checkMode(0);
25045    const isInProtectedMode = checkMode(1);
25046
25047    const normalizeItems = (dataTransfer, itemsImpl) => ({
25048      ...itemsImpl,
25049      get length() {
25050        return itemsImpl.length;
25051      },
25052      add: (data, type) => {
25053        if (isInReadWriteMode(dataTransfer)) {
25054          if (isString(data)) {
25055            if (!isUndefined(type)) {
25056              return itemsImpl.add(data, type);
25057            }
25058          } else {
25059            return itemsImpl.add(data);
25060          }
25061        }
25062        return null;
25063      },
25064      remove: idx => {
25065        if (isInReadWriteMode(dataTransfer)) {
25066          itemsImpl.remove(idx);
25067        }
25068      },
25069      clear: () => {
25070        if (isInReadWriteMode(dataTransfer)) {
25071          itemsImpl.clear();
25072        }
25073      }
25074    });
25075
25076    const validDropEffects = [
25077      'none',
25078      'copy',
25079      'link',
25080      'move'
25081    ];
25082    const validEffectAlloweds = [
25083      'none',
25084      'copy',
25085      'copyLink',
25086      'copyMove',
25087      'link',
25088      'linkMove',
25089      'move',
25090      'all',
25091      'uninitialized'
25092    ];
25093    const createDataTransfer = () => {
25094      const dataTransferImpl = new window.DataTransfer();
25095      let dropEffect = 'move';
25096      let effectAllowed = 'all';
25097      const dataTransfer = {
25098        get dropEffect() {
25099          return dropEffect;
25100        },
25101        set dropEffect(effect) {
25102          if (contains$2(validDropEffects, effect)) {
25103            dropEffect = effect;
25104          }
25105        },
25106        get effectAllowed() {
25107          return effectAllowed;
25108        },
25109        set effectAllowed(allowed) {
25110          if (isInDragStartEvent(dataTransfer) && contains$2(validEffectAlloweds, allowed)) {
25111            effectAllowed = allowed;
25112          }
25113        },
25114        get items() {
25115          return normalizeItems(dataTransfer, dataTransferImpl.items);
25116        },
25117        get files() {
25118          if (isInProtectedMode(dataTransfer)) {
25119            return createEmptyFileList();
25120          } else {
25121            return dataTransferImpl.files;
25122          }
25123        },
25124        get types() {
25125          return dataTransferImpl.types;
25126        },
25127        setDragImage: (image, x, y) => {
25128          if (isInReadWriteMode(dataTransfer)) {
25129            setDragImage(dataTransfer, {
25130              image,
25131              x,
25132              y
25133            });
25134            dataTransferImpl.setDragImage(image, x, y);
25135          }
25136        },
25137        getData: format => {
25138          if (isInProtectedMode(dataTransfer)) {
25139            return '';
25140          } else {
25141            return dataTransferImpl.getData(format);
25142          }
25143        },
25144        setData: (format, data) => {
25145          if (isInReadWriteMode(dataTransfer)) {
25146            dataTransferImpl.setData(format, data);
25147          }
25148        },
25149        clearData: format => {
25150          if (isInReadWriteMode(dataTransfer)) {
25151            dataTransferImpl.clearData(format);
25152          }
25153        }
25154      };
25155      setReadWriteMode(dataTransfer);
25156      return dataTransfer;
25157    };
25158    const cloneDataTransfer = original => {
25159      const clone = createDataTransfer();
25160      const originalMode = getMode(original);
25161      setReadOnlyMode(original);
25162      setDragstartEvent(clone);
25163      clone.dropEffect = original.dropEffect;
25164      clone.effectAllowed = original.effectAllowed;
25165      getDragImage(original).each(imageData => clone.setDragImage(imageData.image, imageData.x, imageData.y));
25166      each$e(original.types, type => {
25167        if (type !== 'Files') {
25168          clone.setData(type, original.getData(type));
25169        }
25170      });
25171      each$e(original.files, file => clone.items.add(file));
25172      getEvent(original).each(type => {
25173        setEvent(clone, type);
25174      });
25175      originalMode.each(mode => {
25176        setMode$1(original, mode);
25177        setMode$1(clone, mode);
25178      });
25179      return clone;
25180    };
25181
25182    const getHtmlData = dataTransfer => {
25183      const html = dataTransfer.getData('text/html');
25184      return html === '' ? Optional.none() : Optional.some(html);
25185    };
25186    const setHtmlData = (dataTransfer, html) => dataTransfer.setData('text/html', html);
25187
25188    const internalMimeType = 'x-tinymce/html';
25189    const internalHtmlMime = constant(internalMimeType);
25190    const internalMark = '<!-- ' + internalMimeType + ' -->';
25191    const mark = html => internalMark + html;
25192    const unmark = html => html.replace(internalMark, '');
25193    const isMarked = html => html.indexOf(internalMark) !== -1;
25194
25195    const isPlainText = text => {
25196      return !/<(?:\/?(?!(?:div|p|br|span)>)\w+|(?:(?!(?:span style="white-space:\s?pre;?">)|br\s?\/>))\w+\s[^>]+)>/i.test(text);
25197    };
25198    const openContainer = (rootTag, rootAttrs) => {
25199      let tag = '<' + rootTag;
25200      const attrs = mapToArray(rootAttrs, (value, key) => key + '="' + Entities.encodeAllRaw(value) + '"');
25201      if (attrs.length) {
25202        tag += ' ' + attrs.join(' ');
25203      }
25204      return tag + '>';
25205    };
25206    const toBlockElements = (text, rootTag, rootAttrs) => {
25207      const blocks = text.split(/\n\n/);
25208      const tagOpen = openContainer(rootTag, rootAttrs);
25209      const tagClose = '</' + rootTag + '>';
25210      const paragraphs = map$3(blocks, p => {
25211        return p.split(/\n/).join('<br />');
25212      });
25213      const stitch = p => {
25214        return tagOpen + p + tagClose;
25215      };
25216      return paragraphs.length === 1 ? paragraphs[0] : map$3(paragraphs, stitch).join('');
25217    };
25218
25219    const pasteBinDefaultContent = '%MCEPASTEBIN%';
25220    const create$6 = (editor, lastRngCell) => {
25221      const {dom, selection} = editor;
25222      const body = editor.getBody();
25223      lastRngCell.set(selection.getRng());
25224      const pasteBinElm = dom.add(editor.getBody(), 'div', {
25225        'id': 'mcepastebin',
25226        'class': 'mce-pastebin',
25227        'contentEditable': true,
25228        'data-mce-bogus': 'all',
25229        'style': 'position: fixed; top: 50%; width: 10px; height: 10px; overflow: hidden; opacity: 0'
25230      }, pasteBinDefaultContent);
25231      if (Env.browser.isFirefox()) {
25232        dom.setStyle(pasteBinElm, 'left', dom.getStyle(body, 'direction', true) === 'rtl' ? 65535 : -65535);
25233      }
25234      dom.bind(pasteBinElm, 'beforedeactivate focusin focusout', e => {
25235        e.stopPropagation();
25236      });
25237      pasteBinElm.focus();
25238      selection.select(pasteBinElm, true);
25239    };
25240    const remove = (editor, lastRngCell) => {
25241      const dom = editor.dom;
25242      if (getEl(editor)) {
25243        let pasteBinClone;
25244        const lastRng = lastRngCell.get();
25245        while (pasteBinClone = getEl(editor)) {
25246          dom.remove(pasteBinClone);
25247          dom.unbind(pasteBinClone);
25248        }
25249        if (lastRng) {
25250          editor.selection.setRng(lastRng);
25251        }
25252      }
25253      lastRngCell.set(null);
25254    };
25255    const getEl = editor => editor.dom.get('mcepastebin');
25256    const isPasteBin = elm => isNonNullable(elm) && elm.id === 'mcepastebin';
25257    const getHtml = editor => {
25258      const dom = editor.dom;
25259      const copyAndRemove = (toElm, fromElm) => {
25260        toElm.appendChild(fromElm);
25261        dom.remove(fromElm, true);
25262      };
25263      const [pasteBinElm, ...pasteBinClones] = filter$5(editor.getBody().childNodes, isPasteBin);
25264      each$e(pasteBinClones, pasteBinClone => {
25265        copyAndRemove(pasteBinElm, pasteBinClone);
25266      });
25267      const dirtyWrappers = dom.select('div[id=mcepastebin]', pasteBinElm);
25268      for (let i = dirtyWrappers.length - 1; i >= 0; i--) {
25269        const cleanWrapper = dom.create('div');
25270        pasteBinElm.insertBefore(cleanWrapper, dirtyWrappers[i]);
25271        copyAndRemove(cleanWrapper, dirtyWrappers[i]);
25272      }
25273      return pasteBinElm ? pasteBinElm.innerHTML : '';
25274    };
25275    const isDefaultPasteBinContent = content => content === pasteBinDefaultContent;
25276    const PasteBin = editor => {
25277      const lastRng = Cell(null);
25278      return {
25279        create: () => create$6(editor, lastRng),
25280        remove: () => remove(editor, lastRng),
25281        getEl: () => getEl(editor),
25282        getHtml: () => getHtml(editor),
25283        getLastRng: lastRng.get
25284      };
25285    };
25286
25287    const filter$1 = (content, items) => {
25288      Tools.each(items, v => {
25289        if (is$4(v, RegExp)) {
25290          content = content.replace(v, '');
25291        } else {
25292          content = content.replace(v[0], v[1]);
25293        }
25294      });
25295      return content;
25296    };
25297    const innerText = html => {
25298      const schema = Schema();
25299      const domParser = DomParser({}, schema);
25300      let text = '';
25301      const voidElements = schema.getVoidElements();
25302      const ignoreElements = Tools.makeMap('script noscript style textarea video audio iframe object', ' ');
25303      const blockElements = schema.getBlockElements();
25304      const walk = node => {
25305        const name = node.name, currentNode = node;
25306        if (name === 'br') {
25307          text += '\n';
25308          return;
25309        }
25310        if (name === 'wbr') {
25311          return;
25312        }
25313        if (voidElements[name]) {
25314          text += ' ';
25315        }
25316        if (ignoreElements[name]) {
25317          text += ' ';
25318          return;
25319        }
25320        if (node.type === 3) {
25321          text += node.value;
25322        }
25323        if (!(node.name in schema.getVoidElements())) {
25324          let currentNode = node.firstChild;
25325          if (currentNode) {
25326            do {
25327              walk(currentNode);
25328            } while (currentNode = currentNode.next);
25329          }
25330        }
25331        if (blockElements[name] && currentNode.next) {
25332          text += '\n';
25333          if (name === 'p') {
25334            text += '\n';
25335          }
25336        }
25337      };
25338      html = filter$1(html, [/<!\[[^\]]+\]>/g]);
25339      walk(domParser.parse(html));
25340      return text;
25341    };
25342    const trimHtml = html => {
25343      const trimSpaces = (all, s1, s2) => {
25344        if (!s1 && !s2) {
25345          return ' ';
25346        }
25347        return nbsp;
25348      };
25349      html = filter$1(html, [
25350        /^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/ig,
25351        /<!--StartFragment-->|<!--EndFragment-->/g,
25352        [
25353          /( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g,
25354          trimSpaces
25355        ],
25356        /<br class="Apple-interchange-newline">/g,
25357        /<br>$/i
25358      ]);
25359      return html;
25360    };
25361    const createIdGenerator = prefix => {
25362      let count = 0;
25363      return () => {
25364        return prefix + count++;
25365      };
25366    };
25367    const getImageMimeType = ext => {
25368      const lowerExt = ext.toLowerCase();
25369      const mimeOverrides = {
25370        jpg: 'jpeg',
25371        jpe: 'jpeg',
25372        jfi: 'jpeg',
25373        jif: 'jpeg',
25374        jfif: 'jpeg',
25375        pjpeg: 'jpeg',
25376        pjp: 'jpeg',
25377        svg: 'svg+xml'
25378      };
25379      return Tools.hasOwn(mimeOverrides, lowerExt) ? 'image/' + mimeOverrides[lowerExt] : 'image/' + lowerExt;
25380    };
25381
25382    const preProcess = (editor, html) => {
25383      const parser = DomParser({ sanitize: shouldSanitizeXss(editor) }, editor.schema);
25384      parser.addNodeFilter('meta', nodes => {
25385        Tools.each(nodes, node => {
25386          node.remove();
25387        });
25388      });
25389      const fragment = parser.parse(html, {
25390        forced_root_block: false,
25391        isRootContent: true
25392      });
25393      return HtmlSerializer({ validate: true }, editor.schema).serialize(fragment);
25394    };
25395    const processResult = (content, cancelled) => ({
25396      content,
25397      cancelled
25398    });
25399    const postProcessFilter = (editor, html, internal) => {
25400      const tempBody = editor.dom.create('div', { style: 'display:none' }, html);
25401      const postProcessArgs = firePastePostProcess(editor, tempBody, internal);
25402      return processResult(postProcessArgs.node.innerHTML, postProcessArgs.isDefaultPrevented());
25403    };
25404    const filterContent = (editor, content, internal) => {
25405      const preProcessArgs = firePastePreProcess(editor, content, internal);
25406      const filteredContent = preProcess(editor, preProcessArgs.content);
25407      if (editor.hasEventListeners('PastePostProcess') && !preProcessArgs.isDefaultPrevented()) {
25408        return postProcessFilter(editor, filteredContent, internal);
25409      } else {
25410        return processResult(filteredContent, preProcessArgs.isDefaultPrevented());
25411      }
25412    };
25413    const process = (editor, html, internal) => {
25414      return filterContent(editor, html, internal);
25415    };
25416
25417    const pasteHtml$1 = (editor, html) => {
25418      editor.insertContent(html, {
25419        merge: shouldPasteMergeFormats(editor),
25420        paste: true
25421      });
25422      return true;
25423    };
25424    const isAbsoluteUrl = url => /^https?:\/\/[\w\-\/+=.,!;:&%@^~(){}?#]+$/i.test(url);
25425    const isImageUrl = (editor, url) => {
25426      return isAbsoluteUrl(url) && exists(getAllowedImageFileTypes(editor), type => endsWith(url.toLowerCase(), `.${ type.toLowerCase() }`));
25427    };
25428    const createImage = (editor, url, pasteHtmlFn) => {
25429      editor.undoManager.extra(() => {
25430        pasteHtmlFn(editor, url);
25431      }, () => {
25432        editor.insertContent('<img src="' + url + '">');
25433      });
25434      return true;
25435    };
25436    const createLink = (editor, url, pasteHtmlFn) => {
25437      editor.undoManager.extra(() => {
25438        pasteHtmlFn(editor, url);
25439      }, () => {
25440        editor.execCommand('mceInsertLink', false, url);
25441      });
25442      return true;
25443    };
25444    const linkSelection = (editor, html, pasteHtmlFn) => !editor.selection.isCollapsed() && isAbsoluteUrl(html) ? createLink(editor, html, pasteHtmlFn) : false;
25445    const insertImage = (editor, html, pasteHtmlFn) => isImageUrl(editor, html) ? createImage(editor, html, pasteHtmlFn) : false;
25446    const smartInsertContent = (editor, html) => {
25447      Tools.each([
25448        linkSelection,
25449        insertImage,
25450        pasteHtml$1
25451      ], action => {
25452        return !action(editor, html, pasteHtml$1);
25453      });
25454    };
25455    const insertContent = (editor, html, pasteAsText) => {
25456      if (pasteAsText || !isSmartPasteEnabled(editor)) {
25457        pasteHtml$1(editor, html);
25458      } else {
25459        smartInsertContent(editor, html);
25460      }
25461    };
25462
25463    const uniqueId = createIdGenerator('mceclip');
25464    const createPasteDataTransfer = html => {
25465      const dataTransfer = createDataTransfer();
25466      setHtmlData(dataTransfer, html);
25467      setReadOnlyMode(dataTransfer);
25468      return dataTransfer;
25469    };
25470    const doPaste = (editor, content, internal, pasteAsText, shouldSimulateInputEvent) => {
25471      const res = process(editor, content, internal);
25472      if (!res.cancelled) {
25473        const content = res.content;
25474        const doPasteAction = () => insertContent(editor, content, pasteAsText);
25475        if (shouldSimulateInputEvent) {
25476          const args = fireBeforeInputEvent(editor, 'insertFromPaste', { dataTransfer: createPasteDataTransfer(content) });
25477          if (!args.isDefaultPrevented()) {
25478            doPasteAction();
25479            fireInputEvent(editor, 'insertFromPaste');
25480          }
25481        } else {
25482          doPasteAction();
25483        }
25484      }
25485    };
25486    const pasteHtml = (editor, html, internalFlag, shouldSimulateInputEvent) => {
25487      const internal = internalFlag ? internalFlag : isMarked(html);
25488      doPaste(editor, unmark(html), internal, false, shouldSimulateInputEvent);
25489    };
25490    const pasteText = (editor, text, shouldSimulateInputEvent) => {
25491      const encodedText = editor.dom.encode(text).replace(/\r\n/g, '\n');
25492      const normalizedText = normalize$4(encodedText, getPasteTabSpaces(editor));
25493      const html = toBlockElements(normalizedText, getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
25494      doPaste(editor, html, false, true, shouldSimulateInputEvent);
25495    };
25496    const getDataTransferItems = dataTransfer => {
25497      const items = {};
25498      if (dataTransfer && dataTransfer.types) {
25499        for (let i = 0; i < dataTransfer.types.length; i++) {
25500          const contentType = dataTransfer.types[i];
25501          try {
25502            items[contentType] = dataTransfer.getData(contentType);
25503          } catch (ex) {
25504            items[contentType] = '';
25505          }
25506        }
25507      }
25508      return items;
25509    };
25510    const hasContentType = (clipboardContent, mimeType) => mimeType in clipboardContent && clipboardContent[mimeType].length > 0;
25511    const hasHtmlOrText = content => hasContentType(content, 'text/html') || hasContentType(content, 'text/plain');
25512    const extractFilename = (editor, str) => {
25513      const m = str.match(/([\s\S]+?)(?:\.[a-z0-9.]+)$/i);
25514      return isNonNullable(m) ? editor.dom.encode(m[1]) : undefined;
25515    };
25516    const createBlobInfo = (editor, blobCache, file, base64) => {
25517      const id = uniqueId();
25518      const useFileName = shouldReuseFileName(editor) && isNonNullable(file.name);
25519      const name = useFileName ? extractFilename(editor, file.name) : id;
25520      const filename = useFileName ? file.name : undefined;
25521      const blobInfo = blobCache.create(id, file, base64, name, filename);
25522      blobCache.add(blobInfo);
25523      return blobInfo;
25524    };
25525    const pasteImage = (editor, imageItem) => {
25526      parseDataUri(imageItem.uri).each(({data, type, base64Encoded}) => {
25527        const base64 = base64Encoded ? data : btoa(data);
25528        const file = imageItem.file;
25529        const blobCache = editor.editorUpload.blobCache;
25530        const existingBlobInfo = blobCache.getByData(base64, type);
25531        const blobInfo = existingBlobInfo !== null && existingBlobInfo !== void 0 ? existingBlobInfo : createBlobInfo(editor, blobCache, file, base64);
25532        pasteHtml(editor, `<img src="${ blobInfo.blobUri() }">`, false, true);
25533      });
25534    };
25535    const isClipboardEvent = event => event.type === 'paste';
25536    const readFilesAsDataUris = items => Promise.all(map$3(items, file => {
25537      return blobToDataUri(file).then(uri => ({
25538        file,
25539        uri
25540      }));
25541    }));
25542    const isImage = editor => {
25543      const allowedExtensions = getAllowedImageFileTypes(editor);
25544      return file => startsWith(file.type, 'image/') && exists(allowedExtensions, extension => {
25545        return getImageMimeType(extension) === file.type;
25546      });
25547    };
25548    const getImagesFromDataTransfer = (editor, dataTransfer) => {
25549      const items = dataTransfer.items ? bind$3(from(dataTransfer.items), item => {
25550        return item.kind === 'file' ? [item.getAsFile()] : [];
25551      }) : [];
25552      const files = dataTransfer.files ? from(dataTransfer.files) : [];
25553      return filter$5(items.length > 0 ? items : files, isImage(editor));
25554    };
25555    const pasteImageData = (editor, e, rng) => {
25556      const dataTransfer = isClipboardEvent(e) ? e.clipboardData : e.dataTransfer;
25557      if (shouldPasteDataImages(editor) && dataTransfer) {
25558        const images = getImagesFromDataTransfer(editor, dataTransfer);
25559        if (images.length > 0) {
25560          e.preventDefault();
25561          readFilesAsDataUris(images).then(fileResults => {
25562            if (rng) {
25563              editor.selection.setRng(rng);
25564            }
25565            each$e(fileResults, result => {
25566              pasteImage(editor, result);
25567            });
25568          });
25569          return true;
25570        }
25571      }
25572      return false;
25573    };
25574    const isBrokenAndroidClipboardEvent = e => {
25575      var _a, _b;
25576      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;
25577    };
25578    const isKeyboardPasteEvent = e => VK.metaKeyPressed(e) && e.keyCode === 86 || e.shiftKey && e.keyCode === 45;
25579    const insertClipboardContent = (editor, clipboardContent, html, plainTextMode, shouldSimulateInputEvent) => {
25580      let content = trimHtml(html);
25581      const isInternal = hasContentType(clipboardContent, internalHtmlMime()) || isMarked(html);
25582      const isPlainTextHtml = !isInternal && isPlainText(content);
25583      const isAbsoluteUrl$1 = isAbsoluteUrl(content);
25584      if (isDefaultPasteBinContent(content) || !content.length || isPlainTextHtml && !isAbsoluteUrl$1) {
25585        plainTextMode = true;
25586      }
25587      if (plainTextMode || isAbsoluteUrl$1) {
25588        if (hasContentType(clipboardContent, 'text/plain') && isPlainTextHtml) {
25589          content = clipboardContent['text/plain'];
25590        } else {
25591          content = innerText(content);
25592        }
25593      }
25594      if (isDefaultPasteBinContent(content)) {
25595        return;
25596      }
25597      if (plainTextMode) {
25598        pasteText(editor, content, shouldSimulateInputEvent);
25599      } else {
25600        pasteHtml(editor, content, isInternal, shouldSimulateInputEvent);
25601      }
25602    };
25603    const registerEventHandlers = (editor, pasteBin, pasteFormat) => {
25604      let keyboardPastePlainTextState;
25605      const getLastRng = () => pasteBin.getLastRng() || editor.selection.getRng();
25606      editor.on('keydown', e => {
25607        if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
25608          keyboardPastePlainTextState = e.shiftKey && e.keyCode === 86;
25609        }
25610      });
25611      editor.on('paste', e => {
25612        if (e.isDefaultPrevented() || isBrokenAndroidClipboardEvent(e)) {
25613          return;
25614        }
25615        const plainTextMode = pasteFormat.get() === 'text' || keyboardPastePlainTextState;
25616        keyboardPastePlainTextState = false;
25617        const clipboardContent = getDataTransferItems(e.clipboardData);
25618        if (!hasHtmlOrText(clipboardContent) && pasteImageData(editor, e, getLastRng())) {
25619          return;
25620        }
25621        if (hasContentType(clipboardContent, 'text/html')) {
25622          e.preventDefault();
25623          insertClipboardContent(editor, clipboardContent, clipboardContent['text/html'], plainTextMode, true);
25624        } else if (hasContentType(clipboardContent, 'text/plain') && hasContentType(clipboardContent, 'text/uri-list')) {
25625          e.preventDefault();
25626          insertClipboardContent(editor, clipboardContent, clipboardContent['text/plain'], plainTextMode, true);
25627        } else {
25628          pasteBin.create();
25629          Delay.setEditorTimeout(editor, () => {
25630            const html = pasteBin.getHtml();
25631            pasteBin.remove();
25632            insertClipboardContent(editor, clipboardContent, html, plainTextMode, false);
25633          }, 0);
25634        }
25635      });
25636    };
25637    const registerDataImageFilter = editor => {
25638      const isWebKitFakeUrl = src => startsWith(src, 'webkit-fake-url');
25639      const isDataUri = src => startsWith(src, 'data:');
25640      const isPasteInsert = args => {
25641        var _a;
25642        return ((_a = args.data) === null || _a === void 0 ? void 0 : _a.paste) === true;
25643      };
25644      editor.parser.addNodeFilter('img', (nodes, name, args) => {
25645        if (!shouldPasteDataImages(editor) && isPasteInsert(args)) {
25646          for (const node of nodes) {
25647            const src = node.attr('src');
25648            if (isString(src) && !node.attr('data-mce-object') && src !== Env.transparentSrc) {
25649              if (isWebKitFakeUrl(src)) {
25650                node.remove();
25651              } else if (!shouldAllowHtmlDataUrls(editor) && isDataUri(src)) {
25652                node.remove();
25653              }
25654            }
25655          }
25656        }
25657      });
25658    };
25659    const registerEventsAndFilters = (editor, pasteBin, pasteFormat) => {
25660      registerEventHandlers(editor, pasteBin, pasteFormat);
25661      registerDataImageFilter(editor);
25662    };
25663
25664    const togglePlainTextPaste = (editor, pasteFormat) => {
25665      if (pasteFormat.get() === 'text') {
25666        pasteFormat.set('html');
25667        firePastePlainTextToggle(editor, false);
25668      } else {
25669        pasteFormat.set('text');
25670        firePastePlainTextToggle(editor, true);
25671      }
25672      editor.focus();
25673    };
25674    const register$1 = (editor, pasteFormat) => {
25675      editor.addCommand('mceTogglePlainTextPaste', () => {
25676        togglePlainTextPaste(editor, pasteFormat);
25677      });
25678      editor.addCommand('mceInsertClipboardContent', (ui, value) => {
25679        if (value.html) {
25680          pasteHtml(editor, value.html, value.internal, false);
25681        }
25682        if (value.text) {
25683          pasteText(editor, value.text, false);
25684        }
25685      });
25686    };
25687
25688    const setHtml5Clipboard = (clipboardData, html, text) => {
25689      if (clipboardData) {
25690        try {
25691          clipboardData.clearData();
25692          clipboardData.setData('text/html', html);
25693          clipboardData.setData('text/plain', text);
25694          clipboardData.setData(internalHtmlMime(), html);
25695          return true;
25696        } catch (e) {
25697          return false;
25698        }
25699      } else {
25700        return false;
25701      }
25702    };
25703    const setClipboardData = (evt, data, fallback, done) => {
25704      if (setHtml5Clipboard(evt.clipboardData, data.html, data.text)) {
25705        evt.preventDefault();
25706        done();
25707      } else {
25708        fallback(data.html, done);
25709      }
25710    };
25711    const fallback = editor => (html, done) => {
25712      const {dom, selection} = editor;
25713      const outer = dom.create('div', {
25714        'contenteditable': 'false',
25715        'data-mce-bogus': 'all'
25716      });
25717      const inner = dom.create('div', { contenteditable: 'true' }, html);
25718      dom.setStyles(outer, {
25719        position: 'fixed',
25720        top: '0',
25721        left: '-3000px',
25722        width: '1000px',
25723        overflow: 'hidden'
25724      });
25725      outer.appendChild(inner);
25726      dom.add(editor.getBody(), outer);
25727      const range = selection.getRng();
25728      inner.focus();
25729      const offscreenRange = dom.createRng();
25730      offscreenRange.selectNodeContents(inner);
25731      selection.setRng(offscreenRange);
25732      Delay.setEditorTimeout(editor, () => {
25733        selection.setRng(range);
25734        dom.remove(outer);
25735        done();
25736      }, 0);
25737    };
25738    const getData = editor => ({
25739      html: mark(editor.selection.getContent({ contextual: true })),
25740      text: editor.selection.getContent({ format: 'text' })
25741    });
25742    const isTableSelection = editor => !!editor.dom.getParent(editor.selection.getStart(), 'td[data-mce-selected],th[data-mce-selected]', editor.getBody());
25743    const hasSelectedContent = editor => !editor.selection.isCollapsed() || isTableSelection(editor);
25744    const cut = editor => evt => {
25745      if (!evt.isDefaultPrevented() && hasSelectedContent(editor)) {
25746        setClipboardData(evt, getData(editor), fallback(editor), () => {
25747          if (Env.browser.isChromium() || Env.browser.isFirefox()) {
25748            const rng = editor.selection.getRng();
25749            Delay.setEditorTimeout(editor, () => {
25750              editor.selection.setRng(rng);
25751              editor.execCommand('Delete');
25752            }, 0);
25753          } else {
25754            editor.execCommand('Delete');
25755          }
25756        });
25757      }
25758    };
25759    const copy = editor => evt => {
25760      if (!evt.isDefaultPrevented() && hasSelectedContent(editor)) {
25761        setClipboardData(evt, getData(editor), fallback(editor), noop);
25762      }
25763    };
25764    const register = editor => {
25765      editor.on('cut', cut(editor));
25766      editor.on('copy', copy(editor));
25767    };
25768
25769    const getCaretRangeFromEvent = (editor, e) => {
25770      var _a, _b;
25771      return RangeUtils.getCaretRangeFromPoint((_a = e.clientX) !== null && _a !== void 0 ? _a : 0, (_b = e.clientY) !== null && _b !== void 0 ? _b : 0, editor.getDoc());
25772    };
25773    const isPlainTextFileUrl = content => {
25774      const plainTextContent = content['text/plain'];
25775      return plainTextContent ? plainTextContent.indexOf('file://') === 0 : false;
25776    };
25777    const setFocusedRange = (editor, rng) => {
25778      editor.focus();
25779      if (rng) {
25780        editor.selection.setRng(rng);
25781      }
25782    };
25783    const hasImage = dataTransfer => exists(dataTransfer.files, file => /^image\//.test(file.type));
25784    const isTransparentBlockDrop = (dom, schema, target, dropContent) => {
25785      const parentTransparent = dom.getParent(target, node => isTransparentBlock(schema, node));
25786      if (parentTransparent && has$2(dropContent, 'text/html')) {
25787        const fragment = new DOMParser().parseFromString(dropContent['text/html'], 'text/html').body;
25788        return !isNull(fragment.querySelector(parentTransparent.nodeName.toLowerCase()));
25789      } else {
25790        return false;
25791      }
25792    };
25793    const setup$a = (editor, draggingInternallyState) => {
25794      if (shouldPasteBlockDrop(editor)) {
25795        editor.on('dragend dragover draggesture dragdrop drop drag', e => {
25796          e.preventDefault();
25797          e.stopPropagation();
25798        });
25799      }
25800      if (!shouldPasteDataImages(editor)) {
25801        editor.on('drop', e => {
25802          const dataTransfer = e.dataTransfer;
25803          if (dataTransfer && hasImage(dataTransfer)) {
25804            e.preventDefault();
25805          }
25806        });
25807      }
25808      editor.on('drop', e => {
25809        if (e.isDefaultPrevented()) {
25810          return;
25811        }
25812        const rng = getCaretRangeFromEvent(editor, e);
25813        if (isNullable(rng)) {
25814          return;
25815        }
25816        const dropContent = getDataTransferItems(e.dataTransfer);
25817        const internal = hasContentType(dropContent, internalHtmlMime());
25818        if ((!hasHtmlOrText(dropContent) || isPlainTextFileUrl(dropContent)) && pasteImageData(editor, e, rng)) {
25819          return;
25820        }
25821        const internalContent = dropContent[internalHtmlMime()];
25822        const content = internalContent || dropContent['text/html'] || dropContent['text/plain'];
25823        const transparentElementDrop = isTransparentBlockDrop(editor.dom, editor.schema, rng.startContainer, dropContent);
25824        if (draggingInternallyState.get() && !transparentElementDrop) {
25825          return;
25826        }
25827        if (content) {
25828          e.preventDefault();
25829          Delay.setEditorTimeout(editor, () => {
25830            editor.undoManager.transact(() => {
25831              if (internalContent) {
25832                editor.execCommand('Delete');
25833              }
25834              setFocusedRange(editor, rng);
25835              const trimmedContent = trimHtml(content);
25836              if (dropContent['text/html']) {
25837                pasteHtml(editor, trimmedContent, internal, true);
25838              } else {
25839                pasteText(editor, trimmedContent, true);
25840              }
25841            });
25842          });
25843        }
25844      });
25845      editor.on('dragstart', _e => {
25846        draggingInternallyState.set(true);
25847      });
25848      editor.on('dragover dragend', e => {
25849        if (shouldPasteDataImages(editor) && !draggingInternallyState.get()) {
25850          e.preventDefault();
25851          setFocusedRange(editor, getCaretRangeFromEvent(editor, e));
25852        }
25853        if (e.type === 'dragend') {
25854          draggingInternallyState.set(false);
25855        }
25856      });
25857    };
25858
25859    const setup$9 = editor => {
25860      const processEvent = f => e => {
25861        f(editor, e);
25862      };
25863      const preProcess = getPastePreProcess(editor);
25864      if (isFunction(preProcess)) {
25865        editor.on('PastePreProcess', processEvent(preProcess));
25866      }
25867      const postProcess = getPastePostProcess(editor);
25868      if (isFunction(postProcess)) {
25869        editor.on('PastePostProcess', processEvent(postProcess));
25870      }
25871    };
25872
25873    const addPreProcessFilter = (editor, filterFunc) => {
25874      editor.on('PastePreProcess', e => {
25875        e.content = filterFunc(editor, e.content, e.internal);
25876      });
25877    };
25878    const rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi;
25879    const rgbToHex = value => Tools.trim(value).replace(rgbRegExp, rgbaToHexString).toLowerCase();
25880    const removeWebKitStyles = (editor, content, internal) => {
25881      const webKitStylesOption = getPasteWebkitStyles(editor);
25882      if (internal || webKitStylesOption === 'all' || !shouldPasteRemoveWebKitStyles(editor)) {
25883        return content;
25884      }
25885      const webKitStyles = webKitStylesOption ? webKitStylesOption.split(/[, ]/) : [];
25886      if (webKitStyles && webKitStylesOption !== 'none') {
25887        const dom = editor.dom, node = editor.selection.getNode();
25888        content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, (all, before, value, after) => {
25889          const inputStyles = dom.parseStyle(dom.decode(value));
25890          const outputStyles = {};
25891          for (let i = 0; i < webKitStyles.length; i++) {
25892            const inputValue = inputStyles[webKitStyles[i]];
25893            let compareInput = inputValue;
25894            let currentValue = dom.getStyle(node, webKitStyles[i], true);
25895            if (/color/.test(webKitStyles[i])) {
25896              compareInput = rgbToHex(compareInput);
25897              currentValue = rgbToHex(currentValue);
25898            }
25899            if (currentValue !== compareInput) {
25900              outputStyles[webKitStyles[i]] = inputValue;
25901            }
25902          }
25903          const outputStyle = dom.serializeStyle(outputStyles, 'span');
25904          if (outputStyle) {
25905            return before + ' style="' + outputStyle + '"' + after;
25906          }
25907          return before + after;
25908        });
25909      } else {
25910        content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, '$1$3');
25911      }
25912      content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, (all, before, value, after) => {
25913        return before + ' style="' + value + '"' + after;
25914      });
25915      return content;
25916    };
25917    const setup$8 = editor => {
25918      if (Env.browser.isChromium() || Env.browser.isSafari()) {
25919        addPreProcessFilter(editor, removeWebKitStyles);
25920      }
25921    };
25922
25923    const setup$7 = editor => {
25924      const draggingInternallyState = Cell(false);
25925      const pasteFormat = Cell(isPasteAsTextEnabled(editor) ? 'text' : 'html');
25926      const pasteBin = PasteBin(editor);
25927      setup$8(editor);
25928      register$1(editor, pasteFormat);
25929      setup$9(editor);
25930      editor.on('PreInit', () => {
25931        register(editor);
25932        setup$a(editor, draggingInternallyState);
25933        registerEventsAndFilters(editor, pasteBin, pasteFormat);
25934      });
25935    };
25936
25937    const preventSummaryToggle = editor => {
25938      editor.on('click', e => {
25939        if (editor.dom.getParent(e.target, 'details')) {
25940          e.preventDefault();
25941        }
25942      });
25943    };
25944    const filterDetails = editor => {
25945      editor.parser.addNodeFilter('details', elms => {
25946        const initialStateOption = getDetailsInitialState(editor);
25947        each$e(elms, details => {
25948          if (initialStateOption === 'expanded') {
25949            details.attr('open', 'open');
25950          } else if (initialStateOption === 'collapsed') {
25951            details.attr('open', null);
25952          }
25953        });
25954      });
25955      editor.serializer.addNodeFilter('details', elms => {
25956        const serializedStateOption = getDetailsSerializedState(editor);
25957        each$e(elms, details => {
25958          if (serializedStateOption === 'expanded') {
25959            details.attr('open', 'open');
25960          } else if (serializedStateOption === 'collapsed') {
25961            details.attr('open', null);
25962          }
25963        });
25964      });
25965    };
25966    const emptyNodeContents = node => fillWithPaddingBr(SugarElement.fromDom(node));
25967    const setCaretToPosition = (editor, position) => {
25968      const node = position.getNode();
25969      if (!isUndefined(node)) {
25970        editor.selection.setCursorLocation(node, position.offset());
25971      }
25972    };
25973    const isEntireNodeSelected = (rng, node) => {
25974      var _a;
25975      return rng.startOffset === 0 && rng.endOffset === ((_a = node.textContent) === null || _a === void 0 ? void 0 : _a.length);
25976    };
25977    const platform = detect$2();
25978    const browser = platform.browser;
25979    const os = platform.os;
25980    const isSafari = browser.isSafari();
25981    const isMacOSOriOS = os.isMacOS() || os.isiOS();
25982    const isCaretInTheBeginningOf = (caretPos, element) => firstPositionIn(element).exists(pos => pos.isEqual(caretPos));
25983    const isCaretInTheEndOf = (caretPos, element) => {
25984      return lastPositionIn(element).exists(pos => {
25985        if (isBr$6(pos.getNode())) {
25986          return prevPosition(element, pos).exists(pos2 => pos2.isEqual(caretPos)) || pos.isEqual(caretPos);
25987        } else {
25988          return pos.isEqual(caretPos);
25989        }
25990      });
25991    };
25992    const getDetailsElements = (dom, rng) => {
25993      const startDetails = Optional.from(dom.getParent(rng.startContainer, 'details'));
25994      const endDetails = Optional.from(dom.getParent(rng.endContainer, 'details'));
25995      if (startDetails.isSome() || endDetails.isSome()) {
25996        const startSummary = startDetails.bind(details => Optional.from(dom.select('summary', details)[0]));
25997        return Optional.some({
25998          startSummary,
25999          startDetails,
26000          endDetails
26001        });
26002      } else {
26003        return Optional.none();
26004      }
26005    };
26006    const isPartialDelete = (rng, detailsElements) => {
26007      const containsStart = element => element.contains(rng.startContainer);
26008      const containsEnd = element => element.contains(rng.endContainer);
26009      const startInSummary = detailsElements.startSummary.exists(containsStart);
26010      const endInSummary = detailsElements.startSummary.exists(containsEnd);
26011      const isPartiallySelectedDetailsElements = detailsElements.startDetails.forall(startDetails => detailsElements.endDetails.forall(endDetails => startDetails !== endDetails));
26012      const isInPartiallySelectedSummary = (startInSummary || endInSummary) && !(startInSummary && endInSummary);
26013      return isInPartiallySelectedSummary || isPartiallySelectedDetailsElements;
26014    };
26015    const isCaretAtStartOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheBeginningOf(caretPos, summary));
26016    const isCaretAtEndOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheEndOf(caretPos, summary));
26017    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()))));
26018    const isCaretInLastPositionInBody = (root, caretPos, detailsElements) => detailsElements.startDetails.exists(details => nextPosition(root, caretPos).forall(pos => !details.contains(pos.container())));
26019    const isInDetailsElement = (dom, pos) => isNonNullable(dom.getParent(pos.container(), 'details'));
26020    const moveCaretToDetailsPos = (editor, pos) => {
26021      const details = editor.dom.getParent(pos.container(), 'details');
26022      if (details && !details.open) {
26023        const summary = editor.dom.select('summary', details)[0];
26024        if (summary) {
26025          lastPositionIn(summary).each(pos => setCaretToPosition(editor, pos));
26026        }
26027      } else {
26028        setCaretToPosition(editor, pos);
26029      }
26030    };
26031    const preventDeleteIntoDetails = (editor, forward) => {
26032      const {dom, selection} = editor;
26033      const root = editor.getBody();
26034      if (editor.selection.isCollapsed()) {
26035        const caretPos = CaretPosition.fromRangeStart(selection.getRng());
26036        const parentBlock = dom.getParent(caretPos.container(), dom.isBlock);
26037        if (parentBlock && dom.isEmpty(parentBlock)) {
26038          if (isNull(parentBlock.nextSibling)) {
26039            const pos = prevPosition(root, caretPos).filter(pos => isInDetailsElement(dom, pos));
26040            if (pos.isSome()) {
26041              pos.each(pos => {
26042                if (!forward) {
26043                  moveCaretToDetailsPos(editor, pos);
26044                }
26045              });
26046              return true;
26047            }
26048          } else if (isNull(parentBlock.previousSibling)) {
26049            const pos = nextPosition(root, caretPos).filter(pos => isInDetailsElement(dom, pos));
26050            if (pos) {
26051              return true;
26052            }
26053          }
26054        }
26055        return navigate(forward, root, caretPos).fold(never, pos => {
26056          if (isInDetailsElement(dom, pos)) {
26057            if (parentBlock && dom.isEmpty(parentBlock)) {
26058              editor.dom.remove(parentBlock);
26059            }
26060            if (!forward) {
26061              moveCaretToDetailsPos(editor, pos);
26062            }
26063            return true;
26064          } else {
26065            return false;
26066          }
26067        });
26068      } else {
26069        return false;
26070      }
26071    };
26072    const preventDeleteSummaryAction = (editor, detailElements, e) => {
26073      const selection = editor.selection;
26074      const node = selection.getNode();
26075      const rng = selection.getRng();
26076      const isBackspace = e.keyCode === VK.BACKSPACE;
26077      const isDelete = e.keyCode === VK.DELETE;
26078      const isCollapsed = editor.selection.isCollapsed();
26079      const caretPos = CaretPosition.fromRangeStart(rng);
26080      const root = editor.getBody();
26081      if (!isCollapsed && isPartialDelete(rng, detailElements)) {
26082        return true;
26083      } else if (isCollapsed && isBackspace && isCaretAtStartOfSummary(caretPos, detailElements)) {
26084        return true;
26085      } else if (isCollapsed && isDelete && isCaretAtEndOfSummary(caretPos, detailElements)) {
26086        return true;
26087      } else if (isCollapsed && isBackspace && isCaretInFirstPositionInBody(caretPos, detailElements)) {
26088        return true;
26089      } else if (isCollapsed && isDelete && isCaretInLastPositionInBody(root, caretPos, detailElements)) {
26090        return true;
26091      } else if (isSafari && isSummary(node)) {
26092        if (!isCollapsed && isEntireNodeSelected(rng, node) || willDeleteLastPositionInElement(isDelete, caretPos, node)) {
26093          emptyNodeContents(node);
26094        } else {
26095          editor.undoManager.transact(() => {
26096            const sel = selection.getSel();
26097            let {anchorNode, anchorOffset, focusNode, focusOffset} = sel !== null && sel !== void 0 ? sel : {};
26098            const applySelection = () => {
26099              if (isNonNullable(anchorNode) && isNonNullable(anchorOffset) && isNonNullable(focusNode) && isNonNullable(focusOffset)) {
26100                sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
26101              }
26102            };
26103            const updateSelection = () => {
26104              anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
26105              anchorOffset = sel === null || sel === void 0 ? void 0 : sel.anchorOffset;
26106              focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
26107              focusOffset = sel === null || sel === void 0 ? void 0 : sel.focusOffset;
26108            };
26109            const appendAllChildNodes = (from, to) => {
26110              each$e(from.childNodes, child => {
26111                if (isNode(child)) {
26112                  to.appendChild(child);
26113                }
26114              });
26115            };
26116            const container = editor.dom.create('span', { 'data-mce-bogus': 'all' });
26117            appendAllChildNodes(node, container);
26118            node.appendChild(container);
26119            applySelection();
26120            if (isCollapsed && (isMacOSOriOS && (e.altKey || isBackspace && e.metaKey) || !isMacOSOriOS && e.ctrlKey)) {
26121              sel === null || sel === void 0 ? void 0 : sel.modify('extend', isBackspace ? 'left' : 'right', e.metaKey ? 'line' : 'word');
26122            }
26123            if (!selection.isCollapsed() && isEntireNodeSelected(selection.getRng(), container)) {
26124              emptyNodeContents(node);
26125            } else {
26126              editor.execCommand(isBackspace ? 'Delete' : 'ForwardDelete');
26127              updateSelection();
26128              appendAllChildNodes(container, node);
26129              applySelection();
26130            }
26131            editor.dom.remove(container);
26132          });
26133        }
26134        return true;
26135      }
26136      return false;
26137    };
26138    const preventDeletingSummary = editor => {
26139      editor.on('keydown', e => {
26140        if (e.keyCode === VK.BACKSPACE || e.keyCode === VK.DELETE) {
26141          getDetailsElements(editor.dom, editor.selection.getRng()).fold(() => {
26142            if (preventDeleteIntoDetails(editor, e.keyCode === VK.DELETE)) {
26143              e.preventDefault();
26144            }
26145          }, detailsElements => {
26146            if (preventDeleteSummaryAction(editor, detailsElements, e)) {
26147              e.preventDefault();
26148            }
26149          });
26150        }
26151      });
26152    };
26153    const setup$6 = editor => {
26154      preventSummaryToggle(editor);
26155      filterDetails(editor);
26156      preventDeletingSummary(editor);
26157    };
26158
26159    const isBr = isBr$6;
26160    const isText = isText$a;
26161    const isContentEditableFalse$2 = elm => isContentEditableFalse$b(elm.dom);
26162    const isContentEditableTrue = elm => isContentEditableTrue$3(elm.dom);
26163    const isRoot = rootNode => elm => eq(SugarElement.fromDom(rootNode), elm);
26164    const getClosestScope = (node, rootNode) => closest$4(SugarElement.fromDom(node), elm => isContentEditableTrue(elm) || isBlock$2(elm), isRoot(rootNode)).getOr(SugarElement.fromDom(rootNode)).dom;
26165    const getClosestCef = (node, rootNode) => closest$4(SugarElement.fromDom(node), isContentEditableFalse$2, isRoot(rootNode));
26166    const findEdgeCaretCandidate = (startNode, scope, forward) => {
26167      const walker = new DomTreeWalker(startNode, scope);
26168      const next = forward ? walker.next.bind(walker) : walker.prev.bind(walker);
26169      let result = startNode;
26170      for (let current = forward ? startNode : next(); current && !isBr(current); current = next()) {
26171        if (isCaretCandidate$3(current)) {
26172          result = current;
26173        }
26174      }
26175      return result;
26176    };
26177    const findClosestBlockRange = (startRng, rootNode) => {
26178      const startPos = CaretPosition.fromRangeStart(startRng);
26179      const clickNode = startPos.getNode();
26180      const scope = getClosestScope(clickNode, rootNode);
26181      const startNode = findEdgeCaretCandidate(clickNode, scope, false);
26182      const endNode = findEdgeCaretCandidate(clickNode, scope, true);
26183      const rng = document.createRange();
26184      getClosestCef(startNode, scope).fold(() => {
26185        if (isText(startNode)) {
26186          rng.setStart(startNode, 0);
26187        } else {
26188          rng.setStartBefore(startNode);
26189        }
26190      }, cef => rng.setStartBefore(cef.dom));
26191      getClosestCef(endNode, scope).fold(() => {
26192        if (isText(endNode)) {
26193          rng.setEnd(endNode, endNode.data.length);
26194        } else {
26195          rng.setEndAfter(endNode);
26196        }
26197      }, cef => rng.setEndAfter(cef.dom));
26198      return rng;
26199    };
26200    const onTripleClickSelect = editor => {
26201      const rng = findClosestBlockRange(editor.selection.getRng(), editor.getBody());
26202      editor.selection.setRng(normalize(rng));
26203    };
26204    const setup$5 = editor => {
26205      editor.on('mousedown', e => {
26206        if (e.detail >= 3) {
26207          e.preventDefault();
26208          onTripleClickSelect(editor);
26209        }
26210      });
26211    };
26212
26213    var FakeCaretPosition;
26214    (function (FakeCaretPosition) {
26215      FakeCaretPosition['Before'] = 'before';
26216      FakeCaretPosition['After'] = 'after';
26217    }(FakeCaretPosition || (FakeCaretPosition = {})));
26218    const distanceToRectLeft = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
26219    const distanceToRectRight = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
26220    const isInsideY = (clientY, clientRect) => clientY >= clientRect.top && clientY <= clientRect.bottom;
26221    const collidesY = (r1, r2) => r1.top < r2.bottom && r1.bottom > r2.top;
26222    const isOverlapping = (r1, r2) => {
26223      const overlap = overlapY(r1, r2) / Math.min(r1.height, r2.height);
26224      return collidesY(r1, r2) && overlap > 0.5;
26225    };
26226    const splitRectsPerAxis = (rects, y) => {
26227      const intersectingRects = filter$5(rects, rect => isInsideY(y, rect));
26228      return boundingClientRectFromRects(intersectingRects).fold(() => [
26229        [],
26230        rects
26231      ], boundingRect => {
26232        const {
26233          pass: horizontal,
26234          fail: vertical
26235        } = partition$2(rects, rect => isOverlapping(rect, boundingRect));
26236        return [
26237          horizontal,
26238          vertical
26239        ];
26240      });
26241    };
26242    const clientInfo = (rect, clientX) => {
26243      return {
26244        node: rect.node,
26245        position: distanceToRectLeft(rect, clientX) < distanceToRectRight(rect, clientX) ? FakeCaretPosition.Before : FakeCaretPosition.After
26246      };
26247    };
26248    const horizontalDistance = (rect, x, _y) => x > rect.left && x < rect.right ? 0 : Math.min(Math.abs(rect.left - x), Math.abs(rect.right - x));
26249    const closestChildCaretCandidateNodeRect = (children, clientX, clientY) => {
26250      const caretCandidateRect = rect => {
26251        if (isCaretCandidate$3(rect.node)) {
26252          return Optional.some(rect);
26253        } else if (isElement$6(rect.node)) {
26254          return closestChildCaretCandidateNodeRect(from(rect.node.childNodes), clientX, clientY);
26255        } else {
26256          return Optional.none();
26257        }
26258      };
26259      const getClosestTextNode = (rects, distance) => {
26260        if (rects.length >= 2) {
26261          const r1 = caretCandidateRect(rects[0]).getOr(rects[0]);
26262          const r2 = caretCandidateRect(rects[1]).getOr(rects[1]);
26263          const deltaDistance = Math.abs(distance(r1, clientX, clientY) - distance(r2, clientX, clientY));
26264          if (deltaDistance < 2) {
26265            if (isText$a(r1.node)) {
26266              return Optional.some(r1);
26267            } else if (isText$a(r2.node)) {
26268              return Optional.some(r2);
26269            }
26270          }
26271        }
26272        return Optional.none();
26273      };
26274      const findClosestCaretCandidateNodeRect = (rects, distance) => {
26275        const sortedRects = sort(rects, (r1, r2) => distance(r1, clientX, clientY) - distance(r2, clientX, clientY));
26276        return getClosestTextNode(sortedRects, distance).orThunk(() => findMap(sortedRects, caretCandidateRect));
26277      };
26278      const [horizontalRects, verticalRects] = splitRectsPerAxis(getClientRects(children), clientY);
26279      const {
26280        pass: above,
26281        fail: below
26282      } = partition$2(verticalRects, rect => rect.top < clientY);
26283      return findClosestCaretCandidateNodeRect(horizontalRects, horizontalDistance).orThunk(() => findClosestCaretCandidateNodeRect(below, distanceToRectEdgeFromXY)).orThunk(() => findClosestCaretCandidateNodeRect(above, distanceToRectEdgeFromXY));
26284    };
26285    const traverseUp = (rootElm, scope, clientX, clientY) => {
26286      const helper = (scope, prevScope) => {
26287        const isDragGhostContainer = node => isElement$6(node) && node.classList.contains('mce-drag-container');
26288        const childNodesWithoutGhost = filter$5(scope.dom.childNodes, not(isDragGhostContainer));
26289        return prevScope.fold(() => closestChildCaretCandidateNodeRect(childNodesWithoutGhost, clientX, clientY), prevScope => {
26290          const uncheckedChildren = filter$5(childNodesWithoutGhost, node => node !== prevScope.dom);
26291          return closestChildCaretCandidateNodeRect(uncheckedChildren, clientX, clientY);
26292        }).orThunk(() => {
26293          const parent = eq(scope, rootElm) ? Optional.none() : parentElement(scope);
26294          return parent.bind(newScope => helper(newScope, Optional.some(scope)));
26295        });
26296      };
26297      return helper(scope, Optional.none());
26298    };
26299    const closestCaretCandidateNodeRect = (root, clientX, clientY) => {
26300      const rootElm = SugarElement.fromDom(root);
26301      const ownerDoc = documentOrOwner(rootElm);
26302      const elementAtPoint = SugarElement.fromPoint(ownerDoc, clientX, clientY).filter(elm => contains(rootElm, elm));
26303      const element = elementAtPoint.getOr(rootElm);
26304      return traverseUp(rootElm, element, clientX, clientY);
26305    };
26306    const closestFakeCaretCandidate = (root, clientX, clientY) => closestCaretCandidateNodeRect(root, clientX, clientY).filter(rect => isFakeCaretTarget(rect.node)).map(rect => clientInfo(rect, clientX));
26307
26308    const getAbsolutePosition = elm => {
26309      var _a, _b;
26310      const clientRect = elm.getBoundingClientRect();
26311      const doc = elm.ownerDocument;
26312      const docElem = doc.documentElement;
26313      const win = doc.defaultView;
26314      return {
26315        top: clientRect.top + ((_a = win === null || win === void 0 ? void 0 : win.scrollY) !== null && _a !== void 0 ? _a : 0) - docElem.clientTop,
26316        left: clientRect.left + ((_b = win === null || win === void 0 ? void 0 : win.scrollX) !== null && _b !== void 0 ? _b : 0) - docElem.clientLeft
26317      };
26318    };
26319    const getBodyPosition = editor => editor.inline ? getAbsolutePosition(editor.getBody()) : {
26320      left: 0,
26321      top: 0
26322    };
26323    const getScrollPosition = editor => {
26324      const body = editor.getBody();
26325      return editor.inline ? {
26326        left: body.scrollLeft,
26327        top: body.scrollTop
26328      } : {
26329        left: 0,
26330        top: 0
26331      };
26332    };
26333    const getBodyScroll = editor => {
26334      const body = editor.getBody(), docElm = editor.getDoc().documentElement;
26335      const inlineScroll = {
26336        left: body.scrollLeft,
26337        top: body.scrollTop
26338      };
26339      const iframeScroll = {
26340        left: body.scrollLeft || docElm.scrollLeft,
26341        top: body.scrollTop || docElm.scrollTop
26342      };
26343      return editor.inline ? inlineScroll : iframeScroll;
26344    };
26345    const getMousePosition = (editor, event) => {
26346      if (event.target.ownerDocument !== editor.getDoc()) {
26347        const iframePosition = getAbsolutePosition(editor.getContentAreaContainer());
26348        const scrollPosition = getBodyScroll(editor);
26349        return {
26350          left: event.pageX - iframePosition.left + scrollPosition.left,
26351          top: event.pageY - iframePosition.top + scrollPosition.top
26352        };
26353      }
26354      return {
26355        left: event.pageX,
26356        top: event.pageY
26357      };
26358    };
26359    const calculatePosition = (bodyPosition, scrollPosition, mousePosition) => ({
26360      pageX: mousePosition.left - bodyPosition.left + scrollPosition.left,
26361      pageY: mousePosition.top - bodyPosition.top + scrollPosition.top
26362    });
26363    const calc = (editor, event) => calculatePosition(getBodyPosition(editor), getScrollPosition(editor), getMousePosition(editor, event));
26364
26365    const getTargetProps = target => ({
26366      target,
26367      srcElement: target
26368    });
26369    const makeDndEventFromMouseEvent = (type, mouseEvent, target, dataTransfer) => ({
26370      ...mouseEvent,
26371      dataTransfer,
26372      type,
26373      ...getTargetProps(target)
26374    });
26375    const makeDndEvent = (type, target, dataTransfer) => {
26376      const fail = die('Function not supported on simulated event.');
26377      const event = {
26378        bubbles: true,
26379        cancelBubble: false,
26380        cancelable: true,
26381        composed: false,
26382        currentTarget: null,
26383        defaultPrevented: false,
26384        eventPhase: 0,
26385        isTrusted: true,
26386        returnValue: false,
26387        timeStamp: 0,
26388        type,
26389        composedPath: fail,
26390        initEvent: fail,
26391        preventDefault: noop,
26392        stopImmediatePropagation: noop,
26393        stopPropagation: noop,
26394        AT_TARGET: window.Event.AT_TARGET,
26395        BUBBLING_PHASE: window.Event.BUBBLING_PHASE,
26396        CAPTURING_PHASE: window.Event.CAPTURING_PHASE,
26397        NONE: window.Event.NONE,
26398        altKey: false,
26399        button: 0,
26400        buttons: 0,
26401        clientX: 0,
26402        clientY: 0,
26403        ctrlKey: false,
26404        metaKey: false,
26405        movementX: 0,
26406        movementY: 0,
26407        offsetX: 0,
26408        offsetY: 0,
26409        pageX: 0,
26410        pageY: 0,
26411        relatedTarget: null,
26412        screenX: 0,
26413        screenY: 0,
26414        shiftKey: false,
26415        x: 0,
26416        y: 0,
26417        detail: 0,
26418        view: null,
26419        which: 0,
26420        initUIEvent: fail,
26421        initMouseEvent: fail,
26422        getModifierState: fail,
26423        dataTransfer,
26424        ...getTargetProps(target)
26425      };
26426      return event;
26427    };
26428    const makeDataTransferCopyForDragEvent = (dataTransfer, eventType) => {
26429      const copy = cloneDataTransfer(dataTransfer);
26430      if (eventType === 'dragstart') {
26431        setDragstartEvent(copy);
26432        setReadWriteMode(copy);
26433      } else if (eventType === 'drop') {
26434        setDropEvent(copy);
26435        setReadOnlyMode(copy);
26436      } else {
26437        setDragendEvent(copy);
26438        setProtectedMode(copy);
26439      }
26440      return copy;
26441    };
26442    const makeDragEvent = (type, target, dataTransfer, mouseEvent) => {
26443      const dataTransferForDispatch = makeDataTransferCopyForDragEvent(dataTransfer, type);
26444      return isUndefined(mouseEvent) ? makeDndEvent(type, target, dataTransferForDispatch) : makeDndEventFromMouseEvent(type, mouseEvent, target, dataTransferForDispatch);
26445    };
26446
26447    const scrollPixelsPerInterval = 32;
26448    const scrollIntervalValue = 100;
26449    const mouseRangeToTriggerScrollInsideEditor = 8;
26450    const mouseRangeToTriggerScrollOutsideEditor = 16;
26451    const isContentEditableFalse$1 = isContentEditableFalse$b;
26452    const isContentEditable = or(isContentEditableFalse$1, isContentEditableTrue$3);
26453    const isDraggable = (dom, rootElm, elm) => isContentEditableFalse$1(elm) && elm !== rootElm && dom.isEditable(elm.parentElement);
26454    const isValidDropTarget = (editor, targetElement, dragElement) => {
26455      if (isNullable(targetElement)) {
26456        return false;
26457      } else if (targetElement === dragElement || editor.dom.isChildOf(targetElement, dragElement)) {
26458        return false;
26459      } else {
26460        return editor.dom.isEditable(targetElement);
26461      }
26462    };
26463    const createGhost = (editor, elm, width, height) => {
26464      const dom = editor.dom;
26465      const clonedElm = elm.cloneNode(true);
26466      dom.setStyles(clonedElm, {
26467        width,
26468        height
26469      });
26470      dom.setAttrib(clonedElm, 'data-mce-selected', null);
26471      const ghostElm = dom.create('div', {
26472        'class': 'mce-drag-container',
26473        'data-mce-bogus': 'all',
26474        'unselectable': 'on',
26475        'contenteditable': 'false'
26476      });
26477      dom.setStyles(ghostElm, {
26478        position: 'absolute',
26479        opacity: 0.5,
26480        overflow: 'hidden',
26481        border: 0,
26482        padding: 0,
26483        margin: 0,
26484        width,
26485        height
26486      });
26487      dom.setStyles(clonedElm, {
26488        margin: 0,
26489        boxSizing: 'border-box'
26490      });
26491      ghostElm.appendChild(clonedElm);
26492      return ghostElm;
26493    };
26494    const appendGhostToBody = (ghostElm, bodyElm) => {
26495      if (ghostElm.parentNode !== bodyElm) {
26496        bodyElm.appendChild(ghostElm);
26497      }
26498    };
26499    const scrollEditor = (direction, amount) => win => () => {
26500      const current = direction === 'left' ? win.scrollX : win.scrollY;
26501      win.scroll({
26502        [direction]: current + amount,
26503        behavior: 'smooth'
26504      });
26505    };
26506    const scrollLeft = scrollEditor('left', -scrollPixelsPerInterval);
26507    const scrollRight = scrollEditor('left', scrollPixelsPerInterval);
26508    const scrollUp = scrollEditor('top', -scrollPixelsPerInterval);
26509    const scrollDown = scrollEditor('top', scrollPixelsPerInterval);
26510    const moveGhost = (ghostElm, position, width, height, maxX, maxY, mouseY, mouseX, contentAreaContainer, win, state, mouseEventOriginatedFromWithinTheEditor) => {
26511      let overflowX = 0, overflowY = 0;
26512      ghostElm.style.left = position.pageX + 'px';
26513      ghostElm.style.top = position.pageY + 'px';
26514      if (position.pageX + width > maxX) {
26515        overflowX = position.pageX + width - maxX;
26516      }
26517      if (position.pageY + height > maxY) {
26518        overflowY = position.pageY + height - maxY;
26519      }
26520      ghostElm.style.width = width - overflowX + 'px';
26521      ghostElm.style.height = height - overflowY + 'px';
26522      const clientHeight = contentAreaContainer.clientHeight;
26523      const clientWidth = contentAreaContainer.clientWidth;
26524      const outerMouseY = mouseY + contentAreaContainer.getBoundingClientRect().top;
26525      const outerMouseX = mouseX + contentAreaContainer.getBoundingClientRect().left;
26526      state.on(state => {
26527        state.intervalId.clear();
26528        if (state.dragging && mouseEventOriginatedFromWithinTheEditor) {
26529          if (mouseY + mouseRangeToTriggerScrollInsideEditor >= clientHeight) {
26530            state.intervalId.set(scrollDown(win));
26531          } else if (mouseY - mouseRangeToTriggerScrollInsideEditor <= 0) {
26532            state.intervalId.set(scrollUp(win));
26533          } else if (mouseX + mouseRangeToTriggerScrollInsideEditor >= clientWidth) {
26534            state.intervalId.set(scrollRight(win));
26535          } else if (mouseX - mouseRangeToTriggerScrollInsideEditor <= 0) {
26536            state.intervalId.set(scrollLeft(win));
26537          } else if (outerMouseY + mouseRangeToTriggerScrollOutsideEditor >= window.innerHeight) {
26538            state.intervalId.set(scrollDown(window));
26539          } else if (outerMouseY - mouseRangeToTriggerScrollOutsideEditor <= 0) {
26540            state.intervalId.set(scrollUp(window));
26541          } else if (outerMouseX + mouseRangeToTriggerScrollOutsideEditor >= window.innerWidth) {
26542            state.intervalId.set(scrollRight(window));
26543          } else if (outerMouseX - mouseRangeToTriggerScrollOutsideEditor <= 0) {
26544            state.intervalId.set(scrollLeft(window));
26545          }
26546        }
26547      });
26548    };
26549    const removeElement = elm => {
26550      if (elm && elm.parentNode) {
26551        elm.parentNode.removeChild(elm);
26552      }
26553    };
26554    const removeElementWithPadding = (dom, elm) => {
26555      const parentBlock = dom.getParent(elm.parentNode, dom.isBlock);
26556      removeElement(elm);
26557      if (parentBlock && parentBlock !== dom.getRoot() && dom.isEmpty(parentBlock)) {
26558        fillWithPaddingBr(SugarElement.fromDom(parentBlock));
26559      }
26560    };
26561    const isLeftMouseButtonPressed = e => e.button === 0;
26562    const applyRelPos = (state, position) => ({
26563      pageX: position.pageX - state.relX,
26564      pageY: position.pageY + 5
26565    });
26566    const start = (state, editor) => e => {
26567      if (isLeftMouseButtonPressed(e)) {
26568        const ceElm = find$2(editor.dom.getParents(e.target), isContentEditable).getOr(null);
26569        if (isNonNullable(ceElm) && isDraggable(editor.dom, editor.getBody(), ceElm)) {
26570          const elmPos = editor.dom.getPos(ceElm);
26571          const bodyElm = editor.getBody();
26572          const docElm = editor.getDoc().documentElement;
26573          state.set({
26574            element: ceElm,
26575            dataTransfer: createDataTransfer(),
26576            dragging: false,
26577            screenX: e.screenX,
26578            screenY: e.screenY,
26579            maxX: (editor.inline ? bodyElm.scrollWidth : docElm.offsetWidth) - 2,
26580            maxY: (editor.inline ? bodyElm.scrollHeight : docElm.offsetHeight) - 2,
26581            relX: e.pageX - elmPos.x,
26582            relY: e.pageY - elmPos.y,
26583            width: ceElm.offsetWidth,
26584            height: ceElm.offsetHeight,
26585            ghost: createGhost(editor, ceElm, ceElm.offsetWidth, ceElm.offsetHeight),
26586            intervalId: repeatable(scrollIntervalValue)
26587          });
26588        }
26589      }
26590    };
26591    const placeCaretAt = (editor, clientX, clientY) => {
26592      editor._selectionOverrides.hideFakeCaret();
26593      closestFakeCaretCandidate(editor.getBody(), clientX, clientY).fold(() => editor.selection.placeCaretAt(clientX, clientY), caretInfo => {
26594        const range = editor._selectionOverrides.showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
26595        if (range) {
26596          editor.selection.setRng(range);
26597        } else {
26598          editor.selection.placeCaretAt(clientX, clientY);
26599        }
26600      });
26601    };
26602    const dispatchDragEvent = (editor, type, target, dataTransfer, mouseEvent) => {
26603      if (type === 'dragstart') {
26604        setHtmlData(dataTransfer, editor.dom.getOuterHTML(target));
26605      }
26606      const event = makeDragEvent(type, target, dataTransfer, mouseEvent);
26607      const args = editor.dispatch(type, event);
26608      return args;
26609    };
26610    const move = (state, editor) => {
26611      const throttledPlaceCaretAt = first$1((clientX, clientY) => placeCaretAt(editor, clientX, clientY), 0);
26612      editor.on('remove', throttledPlaceCaretAt.cancel);
26613      const state_ = state;
26614      return e => state.on(state => {
26615        const movement = Math.max(Math.abs(e.screenX - state.screenX), Math.abs(e.screenY - state.screenY));
26616        if (!state.dragging && movement > 10) {
26617          const args = dispatchDragEvent(editor, 'dragstart', state.element, state.dataTransfer, e);
26618          if (isNonNullable(args.dataTransfer)) {
26619            state.dataTransfer = args.dataTransfer;
26620          }
26621          if (args.isDefaultPrevented()) {
26622            return;
26623          }
26624          state.dragging = true;
26625          editor.focus();
26626        }
26627        if (state.dragging) {
26628          const mouseEventOriginatedFromWithinTheEditor = e.currentTarget === editor.getDoc().documentElement;
26629          const targetPos = applyRelPos(state, calc(editor, e));
26630          appendGhostToBody(state.ghost, editor.getBody());
26631          moveGhost(state.ghost, targetPos, state.width, state.height, state.maxX, state.maxY, e.clientY, e.clientX, editor.getContentAreaContainer(), editor.getWin(), state_, mouseEventOriginatedFromWithinTheEditor);
26632          throttledPlaceCaretAt.throttle(e.clientX, e.clientY);
26633        }
26634      });
26635    };
26636    const getRawTarget = selection => {
26637      const sel = selection.getSel();
26638      if (isNonNullable(sel)) {
26639        const rng = sel.getRangeAt(0);
26640        const startContainer = rng.startContainer;
26641        return isText$a(startContainer) ? startContainer.parentNode : startContainer;
26642      } else {
26643        return null;
26644      }
26645    };
26646    const drop = (state, editor) => e => {
26647      state.on(state => {
26648        var _a;
26649        state.intervalId.clear();
26650        if (state.dragging) {
26651          if (isValidDropTarget(editor, getRawTarget(editor.selection), state.element)) {
26652            const dropTarget = (_a = editor.getDoc().elementFromPoint(e.clientX, e.clientY)) !== null && _a !== void 0 ? _a : editor.getBody();
26653            const args = dispatchDragEvent(editor, 'drop', dropTarget, state.dataTransfer, e);
26654            if (!args.isDefaultPrevented()) {
26655              editor.undoManager.transact(() => {
26656                removeElementWithPadding(editor.dom, state.element);
26657                getHtmlData(state.dataTransfer).each(content => editor.insertContent(content));
26658                editor._selectionOverrides.hideFakeCaret();
26659              });
26660            }
26661          }
26662          dispatchDragEvent(editor, 'dragend', editor.getBody(), state.dataTransfer, e);
26663        }
26664      });
26665      removeDragState(state);
26666    };
26667    const stopDragging = (state, editor, e) => {
26668      state.on(state => {
26669        state.intervalId.clear();
26670        if (state.dragging) {
26671          e.fold(() => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer), mouseEvent => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer, mouseEvent));
26672        }
26673      });
26674      removeDragState(state);
26675    };
26676    const stop = (state, editor) => e => stopDragging(state, editor, Optional.some(e));
26677    const removeDragState = state => {
26678      state.on(state => {
26679        state.intervalId.clear();
26680        removeElement(state.ghost);
26681      });
26682      state.clear();
26683    };
26684    const bindFakeDragEvents = editor => {
26685      const state = value$2();
26686      const pageDom = DOMUtils.DOM;
26687      const rootDocument = document;
26688      const dragStartHandler = start(state, editor);
26689      const dragHandler = move(state, editor);
26690      const dropHandler = drop(state, editor);
26691      const dragEndHandler = stop(state, editor);
26692      editor.on('mousedown', dragStartHandler);
26693      editor.on('mousemove', dragHandler);
26694      editor.on('mouseup', dropHandler);
26695      pageDom.bind(rootDocument, 'mousemove', dragHandler);
26696      pageDom.bind(rootDocument, 'mouseup', dragEndHandler);
26697      editor.on('remove', () => {
26698        pageDom.unbind(rootDocument, 'mousemove', dragHandler);
26699        pageDom.unbind(rootDocument, 'mouseup', dragEndHandler);
26700      });
26701      editor.on('keydown', e => {
26702        if (e.keyCode === VK.ESC) {
26703          stopDragging(state, editor, Optional.none());
26704        }
26705      });
26706    };
26707    const blockUnsupportedFileDrop = editor => {
26708      const preventFileDrop = e => {
26709        if (!e.isDefaultPrevented()) {
26710          const dataTransfer = e.dataTransfer;
26711          if (dataTransfer && (contains$2(dataTransfer.types, 'Files') || dataTransfer.files.length > 0)) {
26712            e.preventDefault();
26713            if (e.type === 'drop') {
26714              displayError(editor, 'Dropped file type is not supported');
26715            }
26716          }
26717        }
26718      };
26719      const preventFileDropIfUIElement = e => {
26720        if (isUIElement(editor, e.target)) {
26721          preventFileDrop(e);
26722        }
26723      };
26724      const setup = () => {
26725        const pageDom = DOMUtils.DOM;
26726        const dom = editor.dom;
26727        const doc = document;
26728        const editorRoot = editor.inline ? editor.getBody() : editor.getDoc();
26729        const eventNames = [
26730          'drop',
26731          'dragover'
26732        ];
26733        each$e(eventNames, name => {
26734          pageDom.bind(doc, name, preventFileDropIfUIElement);
26735          dom.bind(editorRoot, name, preventFileDrop);
26736        });
26737        editor.on('remove', () => {
26738          each$e(eventNames, name => {
26739            pageDom.unbind(doc, name, preventFileDropIfUIElement);
26740            dom.unbind(editorRoot, name, preventFileDrop);
26741          });
26742        });
26743      };
26744      editor.on('init', () => {
26745        Delay.setEditorTimeout(editor, setup, 0);
26746      });
26747    };
26748    const init$2 = editor => {
26749      bindFakeDragEvents(editor);
26750      if (shouldBlockUnsupportedDrop(editor)) {
26751        blockUnsupportedFileDrop(editor);
26752      }
26753    };
26754
26755    const setup$4 = editor => {
26756      const renderFocusCaret = first$1(() => {
26757        if (!editor.removed && editor.getBody().contains(document.activeElement)) {
26758          const rng = editor.selection.getRng();
26759          if (rng.collapsed) {
26760            const caretRange = renderRangeCaret(editor, rng, false);
26761            editor.selection.setRng(caretRange);
26762          }
26763        }
26764      }, 0);
26765      editor.on('focus', () => {
26766        renderFocusCaret.throttle();
26767      });
26768      editor.on('blur', () => {
26769        renderFocusCaret.cancel();
26770      });
26771    };
26772
26773    const setup$3 = editor => {
26774      editor.on('init', () => {
26775        editor.on('focusin', e => {
26776          const target = e.target;
26777          if (isMedia$2(target)) {
26778            const ceRoot = getContentEditableRoot$1(editor.getBody(), target);
26779            const node = isContentEditableFalse$b(ceRoot) ? ceRoot : target;
26780            if (editor.selection.getNode() !== node) {
26781              selectNode(editor, node).each(rng => editor.selection.setRng(rng));
26782            }
26783          }
26784        });
26785      });
26786    };
26787
26788    const isContentEditableFalse = isContentEditableFalse$b;
26789    const getContentEditableRoot = (editor, node) => getContentEditableRoot$1(editor.getBody(), node);
26790    const SelectionOverrides = editor => {
26791      const selection = editor.selection, dom = editor.dom;
26792      const rootNode = editor.getBody();
26793      const fakeCaret = FakeCaret(editor, rootNode, dom.isBlock, () => hasFocus(editor));
26794      const realSelectionId = 'sel-' + dom.uniqueId();
26795      const elementSelectionAttr = 'data-mce-selected';
26796      let selectedElement;
26797      const isFakeSelectionElement = node => isNonNullable(node) && dom.hasClass(node, 'mce-offscreen-selection');
26798      const isFakeSelectionTargetElement = node => node !== rootNode && (isContentEditableFalse(node) || isMedia$2(node)) && dom.isChildOf(node, rootNode) && dom.isEditable(node.parentNode);
26799      const setRange = range => {
26800        if (range) {
26801          selection.setRng(range);
26802        }
26803      };
26804      const showCaret = (direction, node, before, scrollIntoView = true) => {
26805        const e = editor.dispatch('ShowCaret', {
26806          target: node,
26807          direction,
26808          before
26809        });
26810        if (e.isDefaultPrevented()) {
26811          return null;
26812        }
26813        if (scrollIntoView) {
26814          selection.scrollIntoView(node, direction === -1);
26815        }
26816        return fakeCaret.show(before, node);
26817      };
26818      const showBlockCaretContainer = blockCaretContainer => {
26819        if (blockCaretContainer.hasAttribute('data-mce-caret')) {
26820          showCaretContainerBlock(blockCaretContainer);
26821          selection.scrollIntoView(blockCaretContainer);
26822        }
26823      };
26824      const registerEvents = () => {
26825        editor.on('click', e => {
26826          if (!dom.isEditable(e.target)) {
26827            e.preventDefault();
26828            editor.focus();
26829          }
26830        });
26831        editor.on('blur NewBlock', removeElementSelection);
26832        editor.on('ResizeWindow FullscreenStateChanged', fakeCaret.reposition);
26833        editor.on('tap', e => {
26834          const targetElm = e.target;
26835          const contentEditableRoot = getContentEditableRoot(editor, targetElm);
26836          if (isContentEditableFalse(contentEditableRoot)) {
26837            e.preventDefault();
26838            selectNode(editor, contentEditableRoot).each(setElementSelection);
26839          } else if (isFakeSelectionTargetElement(targetElm)) {
26840            selectNode(editor, targetElm).each(setElementSelection);
26841          }
26842        }, true);
26843        editor.on('mousedown', e => {
26844          const targetElm = e.target;
26845          if (targetElm !== rootNode && targetElm.nodeName !== 'HTML' && !dom.isChildOf(targetElm, rootNode)) {
26846            return;
26847          }
26848          if (!isXYInContentArea(editor, e.clientX, e.clientY)) {
26849            return;
26850          }
26851          removeElementSelection();
26852          hideFakeCaret();
26853          const closestContentEditable = getContentEditableRoot(editor, targetElm);
26854          if (isContentEditableFalse(closestContentEditable)) {
26855            e.preventDefault();
26856            selectNode(editor, closestContentEditable).each(setElementSelection);
26857          } else {
26858            closestFakeCaretCandidate(rootNode, e.clientX, e.clientY).each(caretInfo => {
26859              e.preventDefault();
26860              const range = showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
26861              setRange(range);
26862              if (isElement$6(closestContentEditable)) {
26863                closestContentEditable.focus();
26864              } else {
26865                editor.getBody().focus();
26866              }
26867            });
26868          }
26869        });
26870        editor.on('keypress', e => {
26871          if (VK.modifierPressed(e)) {
26872            return;
26873          }
26874          if (isContentEditableFalse(selection.getNode())) {
26875            e.preventDefault();
26876          }
26877        });
26878        editor.on('GetSelectionRange', e => {
26879          let rng = e.range;
26880          if (selectedElement) {
26881            if (!selectedElement.parentNode) {
26882              selectedElement = null;
26883              return;
26884            }
26885            rng = rng.cloneRange();
26886            rng.selectNode(selectedElement);
26887            e.range = rng;
26888          }
26889        });
26890        editor.on('SetSelectionRange', e => {
26891          e.range = normalizeVoidElementSelection(e.range);
26892          const rng = setElementSelection(e.range, e.forward);
26893          if (rng) {
26894            e.range = rng;
26895          }
26896        });
26897        const isPasteBin = node => isElement$6(node) && node.id === 'mcepastebin';
26898        editor.on('AfterSetSelectionRange', e => {
26899          const rng = e.range;
26900          const parent = rng.startContainer.parentElement;
26901          if (!isRangeInCaretContainer(rng) && !isPasteBin(parent)) {
26902            hideFakeCaret();
26903          }
26904          if (!isFakeSelectionElement(parent)) {
26905            removeElementSelection();
26906          }
26907        });
26908        init$2(editor);
26909        setup$4(editor);
26910        setup$3(editor);
26911      };
26912      const isWithinCaretContainer = node => isCaretContainer$2(node) || startsWithCaretContainer$1(node) || endsWithCaretContainer$1(node);
26913      const isRangeInCaretContainer = rng => isWithinCaretContainer(rng.startContainer) || isWithinCaretContainer(rng.endContainer);
26914      const normalizeVoidElementSelection = rng => {
26915        const voidElements = editor.schema.getVoidElements();
26916        const newRng = dom.createRng();
26917        const startContainer = rng.startContainer;
26918        const startOffset = rng.startOffset;
26919        const endContainer = rng.endContainer;
26920        const endOffset = rng.endOffset;
26921        if (has$2(voidElements, startContainer.nodeName.toLowerCase())) {
26922          if (startOffset === 0) {
26923            newRng.setStartBefore(startContainer);
26924          } else {
26925            newRng.setStartAfter(startContainer);
26926          }
26927        } else {
26928          newRng.setStart(startContainer, startOffset);
26929        }
26930        if (has$2(voidElements, endContainer.nodeName.toLowerCase())) {
26931          if (endOffset === 0) {
26932            newRng.setEndBefore(endContainer);
26933          } else {
26934            newRng.setEndAfter(endContainer);
26935          }
26936        } else {
26937          newRng.setEnd(endContainer, endOffset);
26938        }
26939        return newRng;
26940      };
26941      const setupOffscreenSelection = (node, targetClone) => {
26942        const body = SugarElement.fromDom(editor.getBody());
26943        const doc = editor.getDoc();
26944        const realSelectionContainer = descendant(body, '#' + realSelectionId).getOrThunk(() => {
26945          const newContainer = SugarElement.fromHtml('<div data-mce-bogus="all" class="mce-offscreen-selection"></div>', doc);
26946          set$3(newContainer, 'id', realSelectionId);
26947          append$1(body, newContainer);
26948          return newContainer;
26949        });
26950        const newRange = dom.createRng();
26951        empty(realSelectionContainer);
26952        append(realSelectionContainer, [
26953          SugarElement.fromText(nbsp, doc),
26954          SugarElement.fromDom(targetClone),
26955          SugarElement.fromText(nbsp, doc)
26956        ]);
26957        newRange.setStart(realSelectionContainer.dom.firstChild, 1);
26958        newRange.setEnd(realSelectionContainer.dom.lastChild, 0);
26959        setAll(realSelectionContainer, { top: dom.getPos(node, editor.getBody()).y + 'px' });
26960        focus$1(realSelectionContainer);
26961        const sel = selection.getSel();
26962        if (sel) {
26963          sel.removeAllRanges();
26964          sel.addRange(newRange);
26965        }
26966        return newRange;
26967      };
26968      const selectElement = elm => {
26969        const targetClone = elm.cloneNode(true);
26970        const e = editor.dispatch('ObjectSelected', {
26971          target: elm,
26972          targetClone
26973        });
26974        if (e.isDefaultPrevented()) {
26975          return null;
26976        }
26977        const range = setupOffscreenSelection(elm, e.targetClone);
26978        const nodeElm = SugarElement.fromDom(elm);
26979        each$e(descendants(SugarElement.fromDom(editor.getBody()), `*[${ elementSelectionAttr }]`), elm => {
26980          if (!eq(nodeElm, elm)) {
26981            remove$a(elm, elementSelectionAttr);
26982          }
26983        });
26984        if (!dom.getAttrib(elm, elementSelectionAttr)) {
26985          elm.setAttribute(elementSelectionAttr, '1');
26986        }
26987        selectedElement = elm;
26988        hideFakeCaret();
26989        return range;
26990      };
26991      const setElementSelection = (range, forward) => {
26992        if (!range) {
26993          return null;
26994        }
26995        if (range.collapsed) {
26996          if (!isRangeInCaretContainer(range)) {
26997            const dir = forward ? 1 : -1;
26998            const caretPosition = getNormalizedRangeEndPoint(dir, rootNode, range);
26999            const beforeNode = caretPosition.getNode(!forward);
27000            if (isNonNullable(beforeNode)) {
27001              if (isFakeCaretTarget(beforeNode)) {
27002                return showCaret(dir, beforeNode, forward ? !caretPosition.isAtEnd() : false, false);
27003              }
27004              if (isCaretContainerInline(beforeNode) && isContentEditableFalse$b(beforeNode.nextSibling)) {
27005                const rng = dom.createRng();
27006                rng.setStart(beforeNode, 0);
27007                rng.setEnd(beforeNode, 0);
27008                return rng;
27009              }
27010            }
27011            const afterNode = caretPosition.getNode(forward);
27012            if (isNonNullable(afterNode)) {
27013              if (isFakeCaretTarget(afterNode)) {
27014                return showCaret(dir, afterNode, forward ? false : !caretPosition.isAtEnd(), false);
27015              }
27016              if (isCaretContainerInline(afterNode) && isContentEditableFalse$b(afterNode.previousSibling)) {
27017                const rng = dom.createRng();
27018                rng.setStart(afterNode, 1);
27019                rng.setEnd(afterNode, 1);
27020                return rng;
27021              }
27022            }
27023          }
27024          return null;
27025        }
27026        let startContainer = range.startContainer;
27027        let startOffset = range.startOffset;
27028        const endOffset = range.endOffset;
27029        if (isText$a(startContainer) && startOffset === 0 && isContentEditableFalse(startContainer.parentNode)) {
27030          startContainer = startContainer.parentNode;
27031          startOffset = dom.nodeIndex(startContainer);
27032          startContainer = startContainer.parentNode;
27033        }
27034        if (!isElement$6(startContainer)) {
27035          return null;
27036        }
27037        if (endOffset === startOffset + 1 && startContainer === range.endContainer) {
27038          const node = startContainer.childNodes[startOffset];
27039          if (isFakeSelectionTargetElement(node)) {
27040            return selectElement(node);
27041          }
27042        }
27043        return null;
27044      };
27045      const removeElementSelection = () => {
27046        if (selectedElement) {
27047          selectedElement.removeAttribute(elementSelectionAttr);
27048        }
27049        descendant(SugarElement.fromDom(editor.getBody()), '#' + realSelectionId).each(remove$5);
27050        selectedElement = null;
27051      };
27052      const destroy = () => {
27053        fakeCaret.destroy();
27054        selectedElement = null;
27055      };
27056      const hideFakeCaret = () => {
27057        fakeCaret.hide();
27058      };
27059      if (!isRtc(editor)) {
27060        registerEvents();
27061      }
27062      return {
27063        showCaret,
27064        showBlockCaretContainer,
27065        hideFakeCaret,
27066        destroy
27067      };
27068    };
27069
27070    const getNormalizedTextOffset = (container, offset) => {
27071      let normalizedOffset = offset;
27072      for (let node = container.previousSibling; isText$a(node); node = node.previousSibling) {
27073        normalizedOffset += node.data.length;
27074      }
27075      return normalizedOffset;
27076    };
27077    const generatePath = (dom, root, node, offset, normalized) => {
27078      if (isText$a(node) && (offset < 0 || offset > node.data.length)) {
27079        return [];
27080      }
27081      const p = normalized && isText$a(node) ? [getNormalizedTextOffset(node, offset)] : [offset];
27082      let current = node;
27083      while (current !== root && current.parentNode) {
27084        p.push(dom.nodeIndex(current, normalized));
27085        current = current.parentNode;
27086      }
27087      return current === root ? p.reverse() : [];
27088    };
27089    const generatePathRange = (dom, root, startNode, startOffset, endNode, endOffset, normalized = false) => {
27090      const start = generatePath(dom, root, startNode, startOffset, normalized);
27091      const end = generatePath(dom, root, endNode, endOffset, normalized);
27092      return {
27093        start,
27094        end
27095      };
27096    };
27097    const resolvePath = (root, path) => {
27098      const nodePath = path.slice();
27099      const offset = nodePath.pop();
27100      if (!isNumber(offset)) {
27101        return Optional.none();
27102      } else {
27103        const resolvedNode = foldl(nodePath, (optNode, index) => optNode.bind(node => Optional.from(node.childNodes[index])), Optional.some(root));
27104        return resolvedNode.bind(node => {
27105          if (isText$a(node) && (offset < 0 || offset > node.data.length)) {
27106            return Optional.none();
27107          } else {
27108            return Optional.some({
27109              node,
27110              offset
27111            });
27112          }
27113        });
27114      }
27115    };
27116    const resolvePathRange = (root, range) => resolvePath(root, range.start).bind(({
27117      node: startNode,
27118      offset: startOffset
27119    }) => resolvePath(root, range.end).map(({
27120      node: endNode,
27121      offset: endOffset
27122    }) => {
27123      const rng = document.createRange();
27124      rng.setStart(startNode, startOffset);
27125      rng.setEnd(endNode, endOffset);
27126      return rng;
27127    }));
27128    const generatePathRangeFromRange = (dom, root, range, normalized = false) => generatePathRange(dom, root, range.startContainer, range.startOffset, range.endContainer, range.endOffset, normalized);
27129
27130    const cleanEmptyNodes = (dom, node, isRoot) => {
27131      if (node && dom.isEmpty(node) && !isRoot(node)) {
27132        const parent = node.parentNode;
27133        dom.remove(node);
27134        cleanEmptyNodes(dom, parent, isRoot);
27135      }
27136    };
27137    const deleteRng = (dom, rng, isRoot, clean = true) => {
27138      const startParent = rng.startContainer.parentNode;
27139      const endParent = rng.endContainer.parentNode;
27140      rng.deleteContents();
27141      if (clean && !isRoot(rng.startContainer)) {
27142        if (isText$a(rng.startContainer) && rng.startContainer.data.length === 0) {
27143          dom.remove(rng.startContainer);
27144        }
27145        if (isText$a(rng.endContainer) && rng.endContainer.data.length === 0) {
27146          dom.remove(rng.endContainer);
27147        }
27148        cleanEmptyNodes(dom, startParent, isRoot);
27149        if (startParent !== endParent) {
27150          cleanEmptyNodes(dom, endParent, isRoot);
27151        }
27152      }
27153    };
27154    const getParentBlock = (editor, rng) => Optional.from(editor.dom.getParent(rng.startContainer, editor.dom.isBlock));
27155    const resolveFromDynamicPatterns = (patternSet, block, beforeText) => {
27156      const dynamicPatterns = patternSet.dynamicPatternsLookup({
27157        text: beforeText,
27158        block
27159      });
27160      return {
27161        ...patternSet,
27162        blockPatterns: getBlockPatterns(dynamicPatterns).concat(patternSet.blockPatterns),
27163        inlinePatterns: getInlinePatterns(dynamicPatterns).concat(patternSet.inlinePatterns)
27164      };
27165    };
27166    const getBeforeText = (dom, block, node, offset) => {
27167      const rng = dom.createRng();
27168      rng.setStart(block, 0);
27169      rng.setEnd(node, offset);
27170      return rng.toString();
27171    };
27172
27173    const startsWithSingleSpace = s => /^\s[^\s]/.test(s);
27174    const stripPattern = (dom, block, pattern) => {
27175      const firstTextNode = textAfter(block, 0, block);
27176      firstTextNode.each(spot => {
27177        const node = spot.container;
27178        scanRight(node, pattern.start.length, block).each(end => {
27179          const rng = dom.createRng();
27180          rng.setStart(node, 0);
27181          rng.setEnd(end.container, end.offset);
27182          deleteRng(dom, rng, e => e === block);
27183        });
27184        const text = SugarElement.fromDom(node);
27185        const textContent = get$3(text);
27186        if (startsWithSingleSpace(textContent)) {
27187          set(text, textContent.slice(1));
27188        }
27189      });
27190    };
27191    const applyPattern$1 = (editor, match) => {
27192      const dom = editor.dom;
27193      const pattern = match.pattern;
27194      const rng = resolvePathRange(dom.getRoot(), match.range).getOrDie('Unable to resolve path range');
27195      const isBlockFormatName = (name, formatter) => {
27196        const formatSet = formatter.get(name);
27197        return isArray$1(formatSet) && head(formatSet).exists(format => has$2(format, 'block'));
27198      };
27199      getParentBlock(editor, rng).each(block => {
27200        if (pattern.type === 'block-format') {
27201          if (isBlockFormatName(pattern.format, editor.formatter)) {
27202            editor.undoManager.transact(() => {
27203              stripPattern(editor.dom, block, pattern);
27204              editor.formatter.apply(pattern.format);
27205            });
27206          }
27207        } else if (pattern.type === 'block-command') {
27208          editor.undoManager.transact(() => {
27209            stripPattern(editor.dom, block, pattern);
27210            editor.execCommand(pattern.cmd, false, pattern.value);
27211          });
27212        }
27213      });
27214      return true;
27215    };
27216    const sortPatterns$1 = patterns => sort(patterns, (a, b) => b.start.length - a.start.length);
27217    const findPattern$1 = (patterns, text) => {
27218      const sortedPatterns = sortPatterns$1(patterns);
27219      const nuText = text.replace(nbsp, ' ');
27220      return find$2(sortedPatterns, pattern => text.indexOf(pattern.start) === 0 || nuText.indexOf(pattern.start) === 0);
27221    };
27222    const findPatterns$1 = (editor, block, patternSet, normalizedMatches) => {
27223      var _a;
27224      const dom = editor.dom;
27225      const forcedRootBlock = getForcedRootBlock(editor);
27226      if (!dom.is(block, forcedRootBlock)) {
27227        return [];
27228      }
27229      const blockText = (_a = block.textContent) !== null && _a !== void 0 ? _a : '';
27230      return findPattern$1(patternSet.blockPatterns, blockText).map(pattern => {
27231        if (Tools.trim(blockText).length === pattern.start.length) {
27232          return [];
27233        }
27234        return [{
27235            pattern,
27236            range: generatePathRange(dom, dom.getRoot(), block, 0, block, 0, normalizedMatches)
27237          }];
27238      }).getOr([]);
27239    };
27240    const applyMatches$1 = (editor, matches) => {
27241      if (matches.length === 0) {
27242        return;
27243      }
27244      const bookmark = editor.selection.getBookmark();
27245      each$e(matches, match => applyPattern$1(editor, match));
27246      editor.selection.moveToBookmark(bookmark);
27247    };
27248
27249    const newMarker = (dom, id) => dom.create('span', {
27250      'data-mce-type': 'bookmark',
27251      id
27252    });
27253    const rangeFromMarker = (dom, marker) => {
27254      const rng = dom.createRng();
27255      rng.setStartAfter(marker.start);
27256      rng.setEndBefore(marker.end);
27257      return rng;
27258    };
27259    const createMarker = (dom, markerPrefix, pathRange) => {
27260      const rng = resolvePathRange(dom.getRoot(), pathRange).getOrDie('Unable to resolve path range');
27261      const startNode = rng.startContainer;
27262      const endNode = rng.endContainer;
27263      const textEnd = rng.endOffset === 0 ? endNode : endNode.splitText(rng.endOffset);
27264      const textStart = rng.startOffset === 0 ? startNode : startNode.splitText(rng.startOffset);
27265      const startParentNode = textStart.parentNode;
27266      const endParentNode = textEnd.parentNode;
27267      return {
27268        prefix: markerPrefix,
27269        end: endParentNode.insertBefore(newMarker(dom, markerPrefix + '-end'), textEnd),
27270        start: startParentNode.insertBefore(newMarker(dom, markerPrefix + '-start'), textStart)
27271      };
27272    };
27273    const removeMarker = (dom, marker, isRoot) => {
27274      cleanEmptyNodes(dom, dom.get(marker.prefix + '-end'), isRoot);
27275      cleanEmptyNodes(dom, dom.get(marker.prefix + '-start'), isRoot);
27276    };
27277
27278    const isReplacementPattern = pattern => pattern.start.length === 0;
27279    const matchesPattern = patternContent => (element, offset) => {
27280      const text = element.data;
27281      const searchText = text.substring(0, offset);
27282      const startEndIndex = searchText.lastIndexOf(patternContent.charAt(patternContent.length - 1));
27283      const startIndex = searchText.lastIndexOf(patternContent);
27284      if (startIndex !== -1) {
27285        return startIndex + patternContent.length;
27286      } else if (startEndIndex !== -1) {
27287        return startEndIndex + 1;
27288      } else {
27289        return -1;
27290      }
27291    };
27292    const findPatternStartFromSpot = (dom, pattern, block, spot) => {
27293      const startPattern = pattern.start;
27294      const startSpot = repeatLeft(dom, spot.container, spot.offset, matchesPattern(startPattern), block);
27295      return startSpot.bind(spot => {
27296        var _a, _b;
27297        const startPatternIndex = (_b = (_a = block.textContent) === null || _a === void 0 ? void 0 : _a.indexOf(startPattern)) !== null && _b !== void 0 ? _b : -1;
27298        const isCompleteMatch = startPatternIndex !== -1 && spot.offset >= startPatternIndex + startPattern.length;
27299        if (isCompleteMatch) {
27300          const rng = dom.createRng();
27301          rng.setStart(spot.container, spot.offset - startPattern.length);
27302          rng.setEnd(spot.container, spot.offset);
27303          return Optional.some(rng);
27304        } else {
27305          const offset = spot.offset - startPattern.length;
27306          return scanLeft(spot.container, offset, block).map(nextSpot => {
27307            const rng = dom.createRng();
27308            rng.setStart(nextSpot.container, nextSpot.offset);
27309            rng.setEnd(spot.container, spot.offset);
27310            return rng;
27311          }).filter(rng => rng.toString() === startPattern).orThunk(() => findPatternStartFromSpot(dom, pattern, block, point(spot.container, 0)));
27312        }
27313      });
27314    };
27315    const findPatternStart = (dom, pattern, node, offset, block, requireGap = false) => {
27316      if (pattern.start.length === 0 && !requireGap) {
27317        const rng = dom.createRng();
27318        rng.setStart(node, offset);
27319        rng.setEnd(node, offset);
27320        return Optional.some(rng);
27321      }
27322      return textBefore(node, offset, block).bind(spot => {
27323        const start = findPatternStartFromSpot(dom, pattern, block, spot);
27324        return start.bind(startRange => {
27325          var _a;
27326          if (requireGap) {
27327            if (startRange.endContainer === spot.container && startRange.endOffset === spot.offset) {
27328              return Optional.none();
27329            } else if (spot.offset === 0 && ((_a = startRange.endContainer.textContent) === null || _a === void 0 ? void 0 : _a.length) === startRange.endOffset) {
27330              return Optional.none();
27331            }
27332          }
27333          return Optional.some(startRange);
27334        });
27335      });
27336    };
27337    const findPattern = (editor, block, details, normalizedMatches) => {
27338      const dom = editor.dom;
27339      const root = dom.getRoot();
27340      const pattern = details.pattern;
27341      const endNode = details.position.container;
27342      const endOffset = details.position.offset;
27343      return scanLeft(endNode, endOffset - details.pattern.end.length, block).bind(spot => {
27344        const endPathRng = generatePathRange(dom, root, spot.container, spot.offset, endNode, endOffset, normalizedMatches);
27345        if (isReplacementPattern(pattern)) {
27346          return Optional.some({
27347            matches: [{
27348                pattern,
27349                startRng: endPathRng,
27350                endRng: endPathRng
27351              }],
27352            position: spot
27353          });
27354        } else {
27355          const resultsOpt = findPatternsRec(editor, details.remainingPatterns, spot.container, spot.offset, block, normalizedMatches);
27356          const results = resultsOpt.getOr({
27357            matches: [],
27358            position: spot
27359          });
27360          const pos = results.position;
27361          const start = findPatternStart(dom, pattern, pos.container, pos.offset, block, resultsOpt.isNone());
27362          return start.map(startRng => {
27363            const startPathRng = generatePathRangeFromRange(dom, root, startRng, normalizedMatches);
27364            return {
27365              matches: results.matches.concat([{
27366                  pattern,
27367                  startRng: startPathRng,
27368                  endRng: endPathRng
27369                }]),
27370              position: point(startRng.startContainer, startRng.startOffset)
27371            };
27372          });
27373        }
27374      });
27375    };
27376    const findPatternsRec = (editor, patterns, node, offset, block, normalizedMatches) => {
27377      const dom = editor.dom;
27378      return textBefore(node, offset, dom.getRoot()).bind(endSpot => {
27379        const text = getBeforeText(dom, block, node, offset);
27380        for (let i = 0; i < patterns.length; i++) {
27381          const pattern = patterns[i];
27382          if (!endsWith(text, pattern.end)) {
27383            continue;
27384          }
27385          const patternsWithoutCurrent = patterns.slice();
27386          patternsWithoutCurrent.splice(i, 1);
27387          const result = findPattern(editor, block, {
27388            pattern,
27389            remainingPatterns: patternsWithoutCurrent,
27390            position: endSpot
27391          }, normalizedMatches);
27392          if (result.isNone() && offset > 0) {
27393            return findPatternsRec(editor, patterns, node, offset - 1, block, normalizedMatches);
27394          }
27395          if (result.isSome()) {
27396            return result;
27397          }
27398        }
27399        return Optional.none();
27400      });
27401    };
27402    const applyPattern = (editor, pattern, patternRange) => {
27403      editor.selection.setRng(patternRange);
27404      if (pattern.type === 'inline-format') {
27405        each$e(pattern.format, format => {
27406          editor.formatter.apply(format);
27407        });
27408      } else {
27409        editor.execCommand(pattern.cmd, false, pattern.value);
27410      }
27411    };
27412    const applyReplacementPattern = (editor, pattern, marker, isRoot) => {
27413      const markerRange = rangeFromMarker(editor.dom, marker);
27414      deleteRng(editor.dom, markerRange, isRoot);
27415      applyPattern(editor, pattern, markerRange);
27416    };
27417    const applyPatternWithContent = (editor, pattern, startMarker, endMarker, isRoot) => {
27418      const dom = editor.dom;
27419      const markerEndRange = rangeFromMarker(dom, endMarker);
27420      const markerStartRange = rangeFromMarker(dom, startMarker);
27421      deleteRng(dom, markerStartRange, isRoot);
27422      deleteRng(dom, markerEndRange, isRoot);
27423      const patternMarker = {
27424        prefix: startMarker.prefix,
27425        start: startMarker.end,
27426        end: endMarker.start
27427      };
27428      const patternRange = rangeFromMarker(dom, patternMarker);
27429      applyPattern(editor, pattern, patternRange);
27430    };
27431    const addMarkers = (dom, matches) => {
27432      const markerPrefix = generate$1('mce_textpattern');
27433      const matchesWithEnds = foldr(matches, (acc, match) => {
27434        const endMarker = createMarker(dom, markerPrefix + `_end${ acc.length }`, match.endRng);
27435        return acc.concat([{
27436            ...match,
27437            endMarker
27438          }]);
27439      }, []);
27440      return foldr(matchesWithEnds, (acc, match) => {
27441        const idx = matchesWithEnds.length - acc.length - 1;
27442        const startMarker = isReplacementPattern(match.pattern) ? match.endMarker : createMarker(dom, markerPrefix + `_start${ idx }`, match.startRng);
27443        return acc.concat([{
27444            ...match,
27445            startMarker
27446          }]);
27447      }, []);
27448    };
27449    const sortPatterns = patterns => sort(patterns, (a, b) => b.end.length - a.end.length);
27450    const getBestMatches = (matches, matchesWithSortedPatterns) => {
27451      const hasSameMatches = forall(matches, match => exists(matchesWithSortedPatterns, sortedMatch => match.pattern.start === sortedMatch.pattern.start && match.pattern.end === sortedMatch.pattern.end));
27452      if (matches.length === matchesWithSortedPatterns.length) {
27453        if (hasSameMatches) {
27454          return matches;
27455        } else {
27456          return matchesWithSortedPatterns;
27457        }
27458      }
27459      return matches.length > matchesWithSortedPatterns.length ? matches : matchesWithSortedPatterns;
27460    };
27461    const findPatterns = (editor, block, node, offset, patternSet, normalizedMatches) => {
27462      const matches = findPatternsRec(editor, patternSet.inlinePatterns, node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
27463      const matchesWithSortedPatterns = findPatternsRec(editor, sortPatterns(patternSet.inlinePatterns), node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
27464      return getBestMatches(matches, matchesWithSortedPatterns);
27465    };
27466    const applyMatches = (editor, matches) => {
27467      if (matches.length === 0) {
27468        return;
27469      }
27470      const dom = editor.dom;
27471      const bookmark = editor.selection.getBookmark();
27472      const matchesWithMarkers = addMarkers(dom, matches);
27473      each$e(matchesWithMarkers, match => {
27474        const block = dom.getParent(match.startMarker.start, dom.isBlock);
27475        const isRoot = node => node === block;
27476        if (isReplacementPattern(match.pattern)) {
27477          applyReplacementPattern(editor, match.pattern, match.endMarker, isRoot);
27478        } else {
27479          applyPatternWithContent(editor, match.pattern, match.startMarker, match.endMarker, isRoot);
27480        }
27481        removeMarker(dom, match.endMarker, isRoot);
27482        removeMarker(dom, match.startMarker, isRoot);
27483      });
27484      editor.selection.moveToBookmark(bookmark);
27485    };
27486
27487    const handleEnter = (editor, patternSet) => {
27488      const rng = editor.selection.getRng();
27489      return getParentBlock(editor, rng).map(block => {
27490        var _a;
27491        const offset = Math.max(0, rng.startOffset);
27492        const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, (_a = block.textContent) !== null && _a !== void 0 ? _a : '');
27493        const inlineMatches = findPatterns(editor, block, rng.startContainer, offset, dynamicPatternSet, true);
27494        const blockMatches = findPatterns$1(editor, block, dynamicPatternSet, true);
27495        if (blockMatches.length > 0 || inlineMatches.length > 0) {
27496          editor.undoManager.add();
27497          editor.undoManager.extra(() => {
27498            editor.execCommand('mceInsertNewLine');
27499          }, () => {
27500            editor.insertContent(zeroWidth);
27501            applyMatches(editor, inlineMatches);
27502            applyMatches$1(editor, blockMatches);
27503            const range = editor.selection.getRng();
27504            const spot = textBefore(range.startContainer, range.startOffset, editor.dom.getRoot());
27505            editor.execCommand('mceInsertNewLine');
27506            spot.each(s => {
27507              const node = s.container;
27508              if (node.data.charAt(s.offset - 1) === zeroWidth) {
27509                node.deleteData(s.offset - 1, 1);
27510                cleanEmptyNodes(editor.dom, node.parentNode, e => e === editor.dom.getRoot());
27511              }
27512            });
27513          });
27514          return true;
27515        }
27516        return false;
27517      }).getOr(false);
27518    };
27519    const handleInlineKey = (editor, patternSet) => {
27520      const rng = editor.selection.getRng();
27521      getParentBlock(editor, rng).map(block => {
27522        const offset = Math.max(0, rng.startOffset - 1);
27523        const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset);
27524        const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText);
27525        const inlineMatches = findPatterns(editor, block, rng.startContainer, offset, dynamicPatternSet, false);
27526        if (inlineMatches.length > 0) {
27527          editor.undoManager.transact(() => {
27528            applyMatches(editor, inlineMatches);
27529          });
27530        }
27531      });
27532    };
27533    const checkKeyEvent = (codes, event, predicate) => {
27534      for (let i = 0; i < codes.length; i++) {
27535        if (predicate(codes[i], event)) {
27536          return true;
27537        }
27538      }
27539      return false;
27540    };
27541    const checkKeyCode = (codes, event) => checkKeyEvent(codes, event, (code, event) => {
27542      return code === event.keyCode && !VK.modifierPressed(event);
27543    });
27544    const checkCharCode = (chars, event) => checkKeyEvent(chars, event, (chr, event) => {
27545      return chr.charCodeAt(0) === event.charCode;
27546    });
27547
27548    const setup$2 = editor => {
27549      const charCodes = [
27550        ',',
27551        '.',
27552        ';',
27553        ':',
27554        '!',
27555        '?'
27556      ];
27557      const keyCodes = [32];
27558      const getPatternSet = () => createPatternSet(getTextPatterns(editor), getTextPatternsLookup(editor));
27559      const hasDynamicPatterns = () => hasTextPatternsLookup(editor);
27560      editor.on('keydown', e => {
27561        if (e.keyCode === 13 && !VK.modifierPressed(e) && editor.selection.isCollapsed()) {
27562          const patternSet = getPatternSet();
27563          const hasPatterns = patternSet.inlinePatterns.length > 0 || patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
27564          if (hasPatterns && handleEnter(editor, patternSet)) {
27565            e.preventDefault();
27566          }
27567        }
27568      }, true);
27569      const handleInlineTrigger = () => {
27570        if (editor.selection.isCollapsed()) {
27571          const patternSet = getPatternSet();
27572          const hasPatterns = patternSet.inlinePatterns.length > 0 || hasDynamicPatterns();
27573          if (hasPatterns) {
27574            handleInlineKey(editor, patternSet);
27575          }
27576        }
27577      };
27578      editor.on('keyup', e => {
27579        if (checkKeyCode(keyCodes, e)) {
27580          handleInlineTrigger();
27581        }
27582      });
27583      editor.on('keypress', e => {
27584        if (checkCharCode(charCodes, e)) {
27585          Delay.setEditorTimeout(editor, handleInlineTrigger);
27586        }
27587      });
27588    };
27589
27590    const setup$1 = editor => {
27591      setup$2(editor);
27592    };
27593
27594    const Quirks = editor => {
27595      const each = Tools.each;
27596      const BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, parser = editor.parser;
27597      const browser = Env.browser;
27598      const isGecko = browser.isFirefox();
27599      const isWebKit = browser.isChromium() || browser.isSafari();
27600      const isiOS = Env.deviceType.isiPhone() || Env.deviceType.isiPad();
27601      const isMac = Env.os.isMacOS() || Env.os.isiOS();
27602      const setEditorCommandState = (cmd, state) => {
27603        try {
27604          editor.getDoc().execCommand(cmd, false, String(state));
27605        } catch (ex) {
27606        }
27607      };
27608      const isDefaultPrevented = e => {
27609        return e.isDefaultPrevented();
27610      };
27611      const emptyEditorWhenDeleting = () => {
27612        const serializeRng = rng => {
27613          const body = dom.create('body');
27614          const contents = rng.cloneContents();
27615          body.appendChild(contents);
27616          return selection.serializer.serialize(body, { format: 'html' });
27617        };
27618        const allContentsSelected = rng => {
27619          const selection = serializeRng(rng);
27620          const allRng = dom.createRng();
27621          allRng.selectNode(editor.getBody());
27622          const allSelection = serializeRng(allRng);
27623          return selection === allSelection;
27624        };
27625        editor.on('keydown', e => {
27626          const keyCode = e.keyCode;
27627          if (!isDefaultPrevented(e) && (keyCode === DELETE || keyCode === BACKSPACE) && editor.selection.isEditable()) {
27628            const isCollapsed = editor.selection.isCollapsed();
27629            const body = editor.getBody();
27630            if (isCollapsed && !dom.isEmpty(body)) {
27631              return;
27632            }
27633            if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) {
27634              return;
27635            }
27636            e.preventDefault();
27637            editor.setContent('');
27638            if (body.firstChild && dom.isBlock(body.firstChild)) {
27639              editor.selection.setCursorLocation(body.firstChild, 0);
27640            } else {
27641              editor.selection.setCursorLocation(body, 0);
27642            }
27643            editor.nodeChanged();
27644          }
27645        });
27646      };
27647      const selectAll = () => {
27648        editor.shortcuts.add('meta+a', null, 'SelectAll');
27649      };
27650      const documentElementEditingFocus = () => {
27651        if (!editor.inline) {
27652          dom.bind(editor.getDoc(), 'mousedown mouseup', e => {
27653            let rng;
27654            if (e.target === editor.getDoc().documentElement) {
27655              rng = selection.getRng();
27656              editor.getBody().focus();
27657              if (e.type === 'mousedown') {
27658                if (isCaretContainer$2(rng.startContainer)) {
27659                  return;
27660                }
27661                selection.placeCaretAt(e.clientX, e.clientY);
27662              } else {
27663                selection.setRng(rng);
27664              }
27665            }
27666          });
27667        }
27668      };
27669      const removeHrOnBackspace = () => {
27670        editor.on('keydown', e => {
27671          if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
27672            if (!editor.getBody().getElementsByTagName('hr').length) {
27673              return;
27674            }
27675            if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
27676              const node = selection.getNode();
27677              const previousSibling = node.previousSibling;
27678              if (node.nodeName === 'HR') {
27679                dom.remove(node);
27680                e.preventDefault();
27681                return;
27682              }
27683              if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'hr') {
27684                dom.remove(previousSibling);
27685                e.preventDefault();
27686              }
27687            }
27688          }
27689        });
27690      };
27691      const focusBody = () => {
27692        if (!Range.prototype.getClientRects) {
27693          editor.on('mousedown', e => {
27694            if (!isDefaultPrevented(e) && e.target.nodeName === 'HTML') {
27695              const body = editor.getBody();
27696              body.blur();
27697              Delay.setEditorTimeout(editor, () => {
27698                body.focus();
27699              });
27700            }
27701          });
27702        }
27703      };
27704      const selectControlElements = () => {
27705        const visualAidsAnchorClass = getVisualAidsAnchorClass(editor);
27706        editor.on('click', e => {
27707          const target = e.target;
27708          if (/^(IMG|HR)$/.test(target.nodeName) && dom.isEditable(target.parentNode)) {
27709            e.preventDefault();
27710            editor.selection.select(target);
27711            editor.nodeChanged();
27712          }
27713          if (target.nodeName === 'A' && dom.hasClass(target, visualAidsAnchorClass) && target.childNodes.length === 0 && dom.isEditable(target.parentNode)) {
27714            e.preventDefault();
27715            selection.select(target);
27716          }
27717        });
27718      };
27719      const removeStylesWhenDeletingAcrossBlockElements = () => {
27720        const getAttributeApplyFunction = () => {
27721          const template = dom.getAttribs(selection.getStart().cloneNode(false));
27722          return () => {
27723            const target = selection.getStart();
27724            if (target !== editor.getBody()) {
27725              dom.setAttrib(target, 'style', null);
27726              each(template, attr => {
27727                target.setAttributeNode(attr.cloneNode(true));
27728              });
27729            }
27730          };
27731        };
27732        const isSelectionAcrossElements = () => {
27733          return !selection.isCollapsed() && dom.getParent(selection.getStart(), dom.isBlock) !== dom.getParent(selection.getEnd(), dom.isBlock);
27734        };
27735        editor.on('keypress', e => {
27736          let applyAttributes;
27737          if (!isDefaultPrevented(e) && (e.keyCode === 8 || e.keyCode === 46) && isSelectionAcrossElements()) {
27738            applyAttributes = getAttributeApplyFunction();
27739            editor.getDoc().execCommand('delete', false);
27740            applyAttributes();
27741            e.preventDefault();
27742            return false;
27743          } else {
27744            return true;
27745          }
27746        });
27747        dom.bind(editor.getDoc(), 'cut', e => {
27748          if (!isDefaultPrevented(e) && isSelectionAcrossElements()) {
27749            const applyAttributes = getAttributeApplyFunction();
27750            Delay.setEditorTimeout(editor, () => {
27751              applyAttributes();
27752            });
27753          }
27754        });
27755      };
27756      const disableBackspaceIntoATable = () => {
27757        editor.on('keydown', e => {
27758          if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
27759            if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
27760              const previousSibling = selection.getNode().previousSibling;
27761              if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'table') {
27762                e.preventDefault();
27763                return false;
27764              }
27765            }
27766          }
27767          return true;
27768        });
27769      };
27770      const removeBlockQuoteOnBackSpace = () => {
27771        editor.on('keydown', e => {
27772          if (isDefaultPrevented(e) || e.keyCode !== VK.BACKSPACE) {
27773            return;
27774          }
27775          let rng = selection.getRng();
27776          const container = rng.startContainer;
27777          const offset = rng.startOffset;
27778          const root = dom.getRoot();
27779          let parent = container;
27780          if (!rng.collapsed || offset !== 0) {
27781            return;
27782          }
27783          while (parent.parentNode && parent.parentNode.firstChild === parent && parent.parentNode !== root) {
27784            parent = parent.parentNode;
27785          }
27786          if (parent.nodeName === 'BLOCKQUOTE') {
27787            editor.formatter.toggle('blockquote', undefined, parent);
27788            rng = dom.createRng();
27789            rng.setStart(container, 0);
27790            rng.setEnd(container, 0);
27791            selection.setRng(rng);
27792          }
27793        });
27794      };
27795      const setGeckoEditingOptions = () => {
27796        const setOpts = () => {
27797          setEditorCommandState('StyleWithCSS', false);
27798          setEditorCommandState('enableInlineTableEditing', false);
27799          if (!getObjectResizing(editor)) {
27800            setEditorCommandState('enableObjectResizing', false);
27801          }
27802        };
27803        if (!isReadOnly$1(editor)) {
27804          editor.on('BeforeExecCommand mousedown', setOpts);
27805        }
27806      };
27807      const addBrAfterLastLinks = () => {
27808        const fixLinks = () => {
27809          each(dom.select('a:not([data-mce-block])'), node => {
27810            var _a;
27811            let parentNode = node.parentNode;
27812            const root = dom.getRoot();
27813            if ((parentNode === null || parentNode === void 0 ? void 0 : parentNode.lastChild) === node) {
27814              while (parentNode && !dom.isBlock(parentNode)) {
27815                if (((_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.lastChild) !== parentNode || parentNode === root) {
27816                  return;
27817                }
27818                parentNode = parentNode.parentNode;
27819              }
27820              dom.add(parentNode, 'br', { 'data-mce-bogus': 1 });
27821            }
27822          });
27823        };
27824        editor.on('SetContent ExecCommand', e => {
27825          if (e.type === 'setcontent' || e.command === 'mceInsertLink') {
27826            fixLinks();
27827          }
27828        });
27829      };
27830      const setDefaultBlockType = () => {
27831        editor.on('init', () => {
27832          setEditorCommandState('DefaultParagraphSeparator', getForcedRootBlock(editor));
27833        });
27834      };
27835      const isAllContentSelected = editor => {
27836        const body = editor.getBody();
27837        const rng = editor.selection.getRng();
27838        return rng.startContainer === rng.endContainer && rng.startContainer === body && rng.startOffset === 0 && rng.endOffset === body.childNodes.length;
27839      };
27840      const normalizeSelection = () => {
27841        editor.on('keyup focusin mouseup', e => {
27842          if (!VK.modifierPressed(e) && !isAllContentSelected(editor)) {
27843            selection.normalize();
27844          }
27845        }, true);
27846      };
27847      const showBrokenImageIcon = () => {
27848        editor.contentStyles.push('img:-moz-broken {' + '-moz-force-broken-image-icon:1;' + 'min-width:24px;' + 'min-height:24px' + '}');
27849      };
27850      const restoreFocusOnKeyDown = () => {
27851        if (!editor.inline) {
27852          editor.on('keydown', () => {
27853            if (document.activeElement === document.body) {
27854              editor.getWin().focus();
27855            }
27856          });
27857        }
27858      };
27859      const bodyHeight = () => {
27860        if (!editor.inline) {
27861          editor.contentStyles.push('body {min-height: 150px}');
27862          editor.on('click', e => {
27863            let rng;
27864            if (e.target.nodeName === 'HTML') {
27865              rng = editor.selection.getRng();
27866              editor.getBody().focus();
27867              editor.selection.setRng(rng);
27868              editor.selection.normalize();
27869              editor.nodeChanged();
27870            }
27871          });
27872        }
27873      };
27874      const blockCmdArrowNavigation = () => {
27875        if (isMac) {
27876          editor.on('keydown', e => {
27877            if (VK.metaKeyPressed(e) && !e.shiftKey && (e.keyCode === 37 || e.keyCode === 39)) {
27878              e.preventDefault();
27879              const selection = editor.selection.getSel();
27880              selection.modify('move', e.keyCode === 37 ? 'backward' : 'forward', 'lineboundary');
27881            }
27882          });
27883        }
27884      };
27885      const tapLinksAndImages = () => {
27886        editor.on('click', e => {
27887          let elm = e.target;
27888          do {
27889            if (elm.tagName === 'A') {
27890              e.preventDefault();
27891              return;
27892            }
27893          } while (elm = elm.parentNode);
27894        });
27895        editor.contentStyles.push('.mce-content-body {-webkit-touch-callout: none}');
27896      };
27897      const blockFormSubmitInsideEditor = () => {
27898        editor.on('init', () => {
27899          editor.dom.bind(editor.getBody(), 'submit', e => {
27900            e.preventDefault();
27901          });
27902        });
27903      };
27904      const removeAppleInterchangeBrs = () => {
27905        parser.addNodeFilter('br', nodes => {
27906          let i = nodes.length;
27907          while (i--) {
27908            if (nodes[i].attr('class') === 'Apple-interchange-newline') {
27909              nodes[i].remove();
27910            }
27911          }
27912        });
27913      };
27914      const refreshContentEditable = noop;
27915      const isHidden = () => {
27916        if (!isGecko || editor.removed) {
27917          return false;
27918        }
27919        const sel = editor.selection.getSel();
27920        return !sel || !sel.rangeCount || sel.rangeCount === 0;
27921      };
27922      const setupRtc = () => {
27923        if (isWebKit) {
27924          documentElementEditingFocus();
27925          selectControlElements();
27926          blockFormSubmitInsideEditor();
27927          selectAll();
27928          if (isiOS) {
27929            restoreFocusOnKeyDown();
27930            bodyHeight();
27931            tapLinksAndImages();
27932          }
27933        }
27934        if (isGecko) {
27935          focusBody();
27936          setGeckoEditingOptions();
27937          showBrokenImageIcon();
27938          blockCmdArrowNavigation();
27939        }
27940      };
27941      const dropDragEndEvent = () => {
27942        editor.on('drop', event => {
27943          var _a;
27944          const data = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData('text/html');
27945          if (isString(data) && /^<img[^>]*>$/.test(data)) {
27946            editor.dispatch('dragend', new window.DragEvent('dragend', event));
27947          }
27948        });
27949      };
27950      const setup = () => {
27951        removeBlockQuoteOnBackSpace();
27952        emptyEditorWhenDeleting();
27953        if (!Env.windowsPhone) {
27954          normalizeSelection();
27955        }
27956        if (isWebKit) {
27957          documentElementEditingFocus();
27958          selectControlElements();
27959          setDefaultBlockType();
27960          blockFormSubmitInsideEditor();
27961          disableBackspaceIntoATable();
27962          removeAppleInterchangeBrs();
27963          if (isiOS) {
27964            restoreFocusOnKeyDown();
27965            bodyHeight();
27966            tapLinksAndImages();
27967          } else {
27968            selectAll();
27969          }
27970        }
27971        if (isGecko) {
27972          removeHrOnBackspace();
27973          focusBody();
27974          removeStylesWhenDeletingAcrossBlockElements();
27975          setGeckoEditingOptions();
27976          addBrAfterLastLinks();
27977          showBrokenImageIcon();
27978          blockCmdArrowNavigation();
27979          disableBackspaceIntoATable();
27980          dropDragEndEvent();
27981        }
27982      };
27983      if (isRtc(editor)) {
27984        setupRtc();
27985      } else {
27986        setup();
27987      }
27988      return {
27989        refreshContentEditable,
27990        isHidden
27991      };
27992    };
27993
27994    const DOM$6 = DOMUtils.DOM;
27995    const appendStyle = (editor, text) => {
27996      const body = SugarElement.fromDom(editor.getBody());
27997      const container = getStyleContainer(getRootNode(body));
27998      const style = SugarElement.fromTag('style');
27999      set$3(style, 'type', 'text/css');
28000      append$1(style, SugarElement.fromText(text));
28001      append$1(container, style);
28002      editor.on('remove', () => {
28003        remove$5(style);
28004      });
28005    };
28006    const getRootName = editor => editor.inline ? editor.getElement().nodeName.toLowerCase() : undefined;
28007    const removeUndefined = obj => filter$4(obj, v => isUndefined(v) === false);
28008    const mkParserSettings = editor => {
28009      const getOption = editor.options.get;
28010      const blobCache = editor.editorUpload.blobCache;
28011      return removeUndefined({
28012        allow_conditional_comments: getOption('allow_conditional_comments'),
28013        allow_html_data_urls: getOption('allow_html_data_urls'),
28014        allow_svg_data_urls: getOption('allow_svg_data_urls'),
28015        allow_html_in_named_anchor: getOption('allow_html_in_named_anchor'),
28016        allow_script_urls: getOption('allow_script_urls'),
28017        allow_unsafe_link_target: getOption('allow_unsafe_link_target'),
28018        convert_fonts_to_spans: getOption('convert_fonts_to_spans'),
28019        fix_list_elements: getOption('fix_list_elements'),
28020        font_size_legacy_values: getOption('font_size_legacy_values'),
28021        forced_root_block: getOption('forced_root_block'),
28022        forced_root_block_attrs: getOption('forced_root_block_attrs'),
28023        preserve_cdata: getOption('preserve_cdata'),
28024        inline_styles: getOption('inline_styles'),
28025        root_name: getRootName(editor),
28026        sanitize: getOption('xss_sanitization'),
28027        validate: true,
28028        blob_cache: blobCache,
28029        document: editor.getDoc()
28030      });
28031    };
28032    const mkSchemaSettings = editor => {
28033      const getOption = editor.options.get;
28034      return removeUndefined({
28035        custom_elements: getOption('custom_elements'),
28036        extended_valid_elements: getOption('extended_valid_elements'),
28037        invalid_elements: getOption('invalid_elements'),
28038        invalid_styles: getOption('invalid_styles'),
28039        schema: getOption('schema'),
28040        valid_children: getOption('valid_children'),
28041        valid_classes: getOption('valid_classes'),
28042        valid_elements: getOption('valid_elements'),
28043        valid_styles: getOption('valid_styles'),
28044        verify_html: getOption('verify_html'),
28045        padd_empty_block_inline_children: getOption('format_empty_lines')
28046      });
28047    };
28048    const mkSerializerSettings = editor => {
28049      const getOption = editor.options.get;
28050      return {
28051        ...mkParserSettings(editor),
28052        ...mkSchemaSettings(editor),
28053        ...removeUndefined({
28054          remove_trailing_brs: getOption('remove_trailing_brs'),
28055          
28055pad_empty_with_br: getOption('pad_empty_with_br
vendor: 93,003 bytes, lines 28055-30697
28055'),
28056          url_converter: getOption('url_converter'),
28057          url_converter_scope: getOption('url_converter_scope'),
28058          element_format: getOption('element_format'),
28059          entities: getOption('entities'),
28060          entity_encoding: getOption('entity_encoding'),
28061          indent: getOption('indent'),
28062          indent_after: getOption('indent_after'),
28063          indent_before: getOption('indent_before')
28064        })
28065      };
28066    };
28067    const createParser = editor => {
28068      const parser = DomParser(mkParserSettings(editor), editor.schema);
28069      parser.addAttributeFilter('src,href,style,tabindex', (nodes, name) => {
28070        const dom = editor.dom;
28071        const internalName = 'data-mce-' + name;
28072        let i = nodes.length;
28073        while (i--) {
28074          const node = nodes[i];
28075          let value = node.attr(name);
28076          if (value && !node.attr(internalName)) {
28077            if (value.indexOf('data:') === 0 || value.indexOf('blob:') === 0) {
28078              continue;
28079            }
28080            if (name === 'style') {
28081              value = dom.serializeStyle(dom.parseStyle(value), node.name);
28082              if (!value.length) {
28083                value = null;
28084              }
28085              node.attr(internalName, value);
28086              node.attr(name, value);
28087            } else if (name === 'tabindex') {
28088              node.attr(internalName, value);
28089              node.attr(name, null);
28090            } else {
28091              node.attr(internalName, editor.convertURL(value, name, node.name));
28092            }
28093          }
28094        }
28095      });
28096      parser.addNodeFilter('script', nodes => {
28097        let i = nodes.length;
28098        while (i--) {
28099          const node = nodes[i];
28100          const type = node.attr('type') || 'no/type';
28101          if (type.indexOf('mce-') !== 0) {
28102            node.attr('type', 'mce-' + type);
28103          }
28104        }
28105      });
28106      if (shouldPreserveCData(editor)) {
28107        parser.addNodeFilter('#cdata', nodes => {
28108          var _a;
28109          let i = nodes.length;
28110          while (i--) {
28111            const node = nodes[i];
28112            node.type = 8;
28113            node.name = '#comment';
28114            node.value = '[CDATA[' + editor.dom.encode((_a = node.value) !== null && _a !== void 0 ? _a : '') + ']]';
28115          }
28116        });
28117      }
28118      parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', nodes => {
28119        let i = nodes.length;
28120        const nonEmptyElements = editor.schema.getNonEmptyElements();
28121        while (i--) {
28122          const node = nodes[i];
28123          if (node.isEmpty(nonEmptyElements) && node.getAll('br').length === 0) {
28124            node.append(new AstNode('br', 1));
28125          }
28126        }
28127      });
28128      return parser;
28129    };
28130    const autoFocus = editor => {
28131      const autoFocus = getAutoFocus(editor);
28132      if (autoFocus) {
28133        Delay.setEditorTimeout(editor, () => {
28134          let focusEditor;
28135          if (autoFocus === true) {
28136            focusEditor = editor;
28137          } else {
28138            focusEditor = editor.editorManager.get(autoFocus);
28139          }
28140          if (focusEditor && !focusEditor.destroyed) {
28141            focusEditor.focus();
28142            focusEditor.selection.scrollIntoView();
28143          }
28144        }, 100);
28145      }
28146    };
28147    const moveSelectionToFirstCaretPosition = editor => {
28148      const root = editor.dom.getRoot();
28149      if (!editor.inline && (!hasAnyRanges(editor) || editor.selection.getStart(true) === root)) {
28150        firstPositionIn(root).each(pos => {
28151          const node = pos.getNode();
28152          const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
28153          editor.selection.setRng(caretPos.toRange());
28154        });
28155      }
28156    };
28157    const initEditor = editor => {
28158      editor.bindPendingEventDelegates();
28159      editor.initialized = true;
28160      fireInit(editor);
28161      editor.focus(true);
28162      moveSelectionToFirstCaretPosition(editor);
28163      editor.nodeChanged({ initial: true });
28164      const initInstanceCallback = getInitInstanceCallback(editor);
28165      if (isFunction(initInstanceCallback)) {
28166        initInstanceCallback.call(editor, editor);
28167      }
28168      autoFocus(editor);
28169    };
28170    const getStyleSheetLoader$1 = editor => editor.inline ? editor.ui.styleSheetLoader : editor.dom.styleSheetLoader;
28171    const makeStylesheetLoadingPromises = (editor, css, framedFonts) => {
28172      const promises = [getStyleSheetLoader$1(editor).loadAll(css)];
28173      if (editor.inline) {
28174        return promises;
28175      } else {
28176        return promises.concat([editor.ui.styleSheetLoader.loadAll(framedFonts)]);
28177      }
28178    };
28179    const loadContentCss = editor => {
28180      const styleSheetLoader = getStyleSheetLoader$1(editor);
28181      const fontCss = getFontCss(editor);
28182      const css = editor.contentCSS;
28183      const removeCss = () => {
28184        styleSheetLoader.unloadAll(css);
28185        if (!editor.inline) {
28186          editor.ui.styleSheetLoader.unloadAll(fontCss);
28187        }
28188      };
28189      const loaded = () => {
28190        if (editor.removed) {
28191          removeCss();
28192        } else {
28193          editor.on('remove', removeCss);
28194        }
28195      };
28196      if (editor.contentStyles.length > 0) {
28197        let contentCssText = '';
28198        Tools.each(editor.contentStyles, style => {
28199          contentCssText += style + '\r\n';
28200        });
28201        editor.dom.addStyle(contentCssText);
28202      }
28203      const allStylesheets = Promise.all(makeStylesheetLoadingPromises(editor, css, fontCss)).then(loaded).catch(loaded);
28204      const contentStyle = getContentStyle(editor);
28205      if (contentStyle) {
28206        appendStyle(editor, contentStyle);
28207      }
28208      return allStylesheets;
28209    };
28210    const preInit = editor => {
28211      const doc = editor.getDoc(), body = editor.getBody();
28212      firePreInit(editor);
28213      if (!shouldBrowserSpellcheck(editor)) {
28214        doc.body.spellcheck = false;
28215        DOM$6.setAttrib(body, 'spellcheck', 'false');
28216      }
28217      editor.quirks = Quirks(editor);
28218      firePostRender(editor);
28219      const directionality = getDirectionality(editor);
28220      if (directionality !== undefined) {
28221        body.dir = directionality;
28222      }
28223      const protect = getProtect(editor);
28224      if (protect) {
28225        editor.on('BeforeSetContent', e => {
28226          Tools.each(protect, pattern => {
28227            e.content = e.content.replace(pattern, str => {
28228              return '<!--mce:protected ' + escape(str) + '-->';
28229            });
28230          });
28231        });
28232      }
28233      editor.on('SetContent', () => {
28234        editor.addVisual(editor.getBody());
28235      });
28236      editor.on('compositionstart compositionend', e => {
28237        editor.composing = e.type === 'compositionstart';
28238      });
28239    };
28240    const loadInitialContent = editor => {
28241      if (!isRtc(editor)) {
28242        editor.load({
28243          initial: true,
28244          format: 'html'
28245        });
28246      }
28247      editor.startContent = editor.getContent({ format: 'raw' });
28248    };
28249    const initEditorWithInitialContent = editor => {
28250      if (editor.removed !== true) {
28251        loadInitialContent(editor);
28252        initEditor(editor);
28253      }
28254    };
28255    const contentBodyLoaded = editor => {
28256      const targetElm = editor.getElement();
28257      let doc = editor.getDoc();
28258      if (editor.inline) {
28259        DOM$6.addClass(targetElm, 'mce-content-body');
28260        editor.contentDocument = doc = document;
28261        editor.contentWindow = window;
28262        editor.bodyElement = targetElm;
28263        editor.contentAreaContainer = targetElm;
28264      }
28265      const body = editor.getBody();
28266      body.disabled = true;
28267      editor.readonly = isReadOnly$1(editor);
28268      editor._editableRoot = hasEditableRoot$1(editor);
28269      if (!editor.readonly && editor.hasEditableRoot()) {
28270        if (editor.inline && DOM$6.getStyle(body, 'position', true) === 'static') {
28271          body.style.position = 'relative';
28272        }
28273        body.contentEditable = 'true';
28274      }
28275      body.disabled = false;
28276      editor.editorUpload = EditorUpload(editor);
28277      editor.schema = Schema(mkSchemaSettings(editor));
28278      editor.dom = DOMUtils(doc, {
28279        keep_values: true,
28280        url_converter: editor.convertURL,
28281        url_converter_scope: editor,
28282        update_styles: true,
28283        root_element: editor.inline ? editor.getBody() : null,
28284        collect: editor.inline,
28285        schema: editor.schema,
28286        contentCssCors: shouldUseContentCssCors(editor),
28287        referrerPolicy: getReferrerPolicy(editor),
28288        onSetAttrib: e => {
28289          editor.dispatch('SetAttrib', e);
28290        }
28291      });
28292      editor.parser = createParser(editor);
28293      editor.serializer = DomSerializer(mkSerializerSettings(editor), editor);
28294      editor.selection = EditorSelection(editor.dom, editor.getWin(), editor.serializer, editor);
28295      editor.annotator = Annotator(editor);
28296      editor.formatter = Formatter(editor);
28297      editor.undoManager = UndoManager(editor);
28298      editor._nodeChangeDispatcher = new NodeChange(editor);
28299      editor._selectionOverrides = SelectionOverrides(editor);
28300      setup$o(editor);
28301      setup$6(editor);
28302      setup$m(editor);
28303      if (!isRtc(editor)) {
28304        setup$5(editor);
28305        setup$1(editor);
28306      }
28307      const caret = setup$b(editor);
28308      setup$p(editor, caret);
28309      setup$n(editor);
28310      setup$q(editor);
28311      setup$7(editor);
28312      const setupRtcThunk = setup$s(editor);
28313      preInit(editor);
28314      setupRtcThunk.fold(() => {
28315        loadContentCss(editor).then(() => initEditorWithInitialContent(editor));
28316      }, setupRtc => {
28317        editor.setProgressState(true);
28318        loadContentCss(editor).then(() => {
28319          setupRtc().then(_rtcMode => {
28320            editor.setProgressState(false);
28321            initEditorWithInitialContent(editor);
28322            bindEvents(editor);
28323          }, err => {
28324            editor.notificationManager.open({
28325              type: 'error',
28326              text: String(err)
28327            });
28328            initEditorWithInitialContent(editor);
28329            bindEvents(editor);
28330          });
28331        });
28332      });
28333    };
28334
28335    const filter = always;
28336    const bind = (element, event, handler) => bind$2(element, event, filter, handler);
28337
28338    const DOM$5 = DOMUtils.DOM;
28339    const createIframeElement = (id, title, customAttrs, tabindex) => {
28340      const iframe = SugarElement.fromTag('iframe');
28341      tabindex.each(t => set$3(iframe, 'tabindex', t));
28342      setAll$1(iframe, customAttrs);
28343      setAll$1(iframe, {
28344        id: id + '_ifr',
28345        frameBorder: '0',
28346        allowTransparency: 'true',
28347        title
28348      });
28349      add$2(iframe, 'tox-edit-area__iframe');
28350      return iframe;
28351    };
28352    const getIframeHtml = editor => {
28353      let iframeHTML = getDocType(editor) + '<html><head>';
28354      if (getDocumentBaseUrl(editor) !== editor.documentBaseUrl) {
28355        iframeHTML += '<base href="' + editor.documentBaseURI.getURI() + '" />';
28356      }
28357      iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
28358      const bodyId = getBodyId(editor);
28359      const bodyClass = getBodyClass(editor);
28360      const translatedAriaText = editor.translate(getIframeAriaText(editor));
28361      if (getContentSecurityPolicy(editor)) {
28362        iframeHTML += '<meta http-equiv="Content-Security-Policy" content="' + getContentSecurityPolicy(editor) + '" />';
28363      }
28364      iframeHTML += '</head>' + `<body id="${ bodyId }" class="mce-content-body ${ bodyClass }" data-id="${ editor.id }" aria-label="${ translatedAriaText }">` + '<br>' + '</body></html>';
28365      return iframeHTML;
28366    };
28367    const createIframe = (editor, boxInfo) => {
28368      const iframeTitle = editor.translate('Rich Text Area');
28369      const tabindex = getOpt(SugarElement.fromDom(editor.getElement()), 'tabindex').bind(toInt);
28370      const ifr = createIframeElement(editor.id, iframeTitle, getIframeAttrs(editor), tabindex).dom;
28371      ifr.onload = () => {
28372        ifr.onload = null;
28373        editor.dispatch('load');
28374      };
28375      editor.contentAreaContainer = boxInfo.iframeContainer;
28376      editor.iframeElement = ifr;
28377      editor.iframeHTML = getIframeHtml(editor);
28378      DOM$5.add(boxInfo.iframeContainer, ifr);
28379    };
28380    const setupIframeBody = editor => {
28381      const iframe = editor.iframeElement;
28382      const ready = () => {
28383        editor.contentDocument = iframe.contentDocument;
28384        contentBodyLoaded(editor);
28385      };
28386      if (shouldUseDocumentWrite(editor) || Env.browser.isFirefox()) {
28387        const doc = editor.getDoc();
28388        doc.open();
28389        doc.write(editor.iframeHTML);
28390        doc.close();
28391        ready();
28392      } else {
28393        const binder = bind(SugarElement.fromDom(iframe), 'load', () => {
28394          binder.unbind();
28395          ready();
28396        });
28397        iframe.srcdoc = editor.iframeHTML;
28398      }
28399    };
28400    const init$1 = (editor, boxInfo) => {
28401      createIframe(editor, boxInfo);
28402      if (boxInfo.editorContainer) {
28403        boxInfo.editorContainer.style.display = editor.orgDisplay;
28404        editor.hidden = DOM$5.isHidden(boxInfo.editorContainer);
28405      }
28406      editor.getElement().style.display = 'none';
28407      DOM$5.setAttrib(editor.id, 'aria-hidden', 'true');
28408      editor.getElement().style.visibility = editor.orgVisibility;
28409      setupIframeBody(editor);
28410    };
28411
28412    const DOM$4 = DOMUtils.DOM;
28413    const initPlugin = (editor, initializedPlugins, plugin) => {
28414      const Plugin = PluginManager.get(plugin);
28415      const pluginUrl = PluginManager.urls[plugin] || editor.documentBaseUrl.replace(/\/$/, '');
28416      plugin = Tools.trim(plugin);
28417      if (Plugin && Tools.inArray(initializedPlugins, plugin) === -1) {
28418        if (editor.plugins[plugin]) {
28419          return;
28420        }
28421        try {
28422          const pluginInstance = Plugin(editor, pluginUrl) || {};
28423          editor.plugins[plugin] = pluginInstance;
28424          if (isFunction(pluginInstance.init)) {
28425            pluginInstance.init(editor, pluginUrl);
28426            initializedPlugins.push(plugin);
28427          }
28428        } catch (e) {
28429          pluginInitError(editor, plugin, e);
28430        }
28431      }
28432    };
28433    const trimLegacyPrefix = name => {
28434      return name.replace(/^\-/, '');
28435    };
28436    const initPlugins = editor => {
28437      const initializedPlugins = [];
28438      each$e(getPlugins(editor), name => {
28439        initPlugin(editor, initializedPlugins, trimLegacyPrefix(name));
28440      });
28441    };
28442    const initIcons = editor => {
28443      const iconPackName = Tools.trim(getIconPackName(editor));
28444      const currentIcons = editor.ui.registry.getAll().icons;
28445      const loadIcons = {
28446        ...IconManager.get('default').icons,
28447        ...IconManager.get(iconPackName).icons
28448      };
28449      each$d(loadIcons, (svgData, icon) => {
28450        if (!has$2(currentIcons, icon)) {
28451          editor.ui.registry.addIcon(icon, svgData);
28452        }
28453      });
28454    };
28455    const initTheme = editor => {
28456      const theme = getTheme(editor);
28457      if (isString(theme)) {
28458        const Theme = ThemeManager.get(theme);
28459        editor.theme = Theme(editor, ThemeManager.urls[theme]) || {};
28460        if (isFunction(editor.theme.init)) {
28461          editor.theme.init(editor, ThemeManager.urls[theme] || editor.documentBaseUrl.replace(/\/$/, ''));
28462        }
28463      } else {
28464        editor.theme = {};
28465      }
28466    };
28467    const initModel = editor => {
28468      const model = getModel(editor);
28469      const Model = ModelManager.get(model);
28470      editor.model = Model(editor, ModelManager.urls[model]);
28471    };
28472    const renderFromLoadedTheme = editor => {
28473      const render = editor.theme.renderUI;
28474      return render ? render() : renderThemeFalse(editor);
28475    };
28476    const renderFromThemeFunc = editor => {
28477      const elm = editor.getElement();
28478      const theme = getTheme(editor);
28479      const info = theme(editor, elm);
28480      if (info.editorContainer.nodeType) {
28481        info.editorContainer.id = info.editorContainer.id || editor.id + '_parent';
28482      }
28483      if (info.iframeContainer && info.iframeContainer.nodeType) {
28484        info.iframeContainer.id = info.iframeContainer.id || editor.id + '_iframecontainer';
28485      }
28486      info.height = info.iframeHeight ? info.iframeHeight : elm.offsetHeight;
28487      return info;
28488    };
28489    const createThemeFalseResult = (element, iframe) => {
28490      return {
28491        editorContainer: element,
28492        iframeContainer: iframe,
28493        api: {}
28494      };
28495    };
28496    const renderThemeFalseIframe = targetElement => {
28497      const iframeContainer = DOM$4.create('div');
28498      DOM$4.insertAfter(iframeContainer, targetElement);
28499      return createThemeFalseResult(iframeContainer, iframeContainer);
28500    };
28501    const renderThemeFalse = editor => {
28502      const targetElement = editor.getElement();
28503      return editor.inline ? createThemeFalseResult(null) : renderThemeFalseIframe(targetElement);
28504    };
28505    const renderThemeUi = editor => {
28506      const elm = editor.getElement();
28507      editor.orgDisplay = elm.style.display;
28508      if (isString(getTheme(editor))) {
28509        return renderFromLoadedTheme(editor);
28510      } else if (isFunction(getTheme(editor))) {
28511        return renderFromThemeFunc(editor);
28512      } else {
28513        return renderThemeFalse(editor);
28514      }
28515    };
28516    const augmentEditorUiApi = (editor, api) => {
28517      const uiApiFacade = {
28518        show: Optional.from(api.show).getOr(noop),
28519        hide: Optional.from(api.hide).getOr(noop),
28520        isEnabled: Optional.from(api.isEnabled).getOr(always),
28521        setEnabled: state => {
28522          if (!editor.mode.isReadOnly()) {
28523            Optional.from(api.setEnabled).each(f => f(state));
28524          }
28525        }
28526      };
28527      editor.ui = {
28528        ...editor.ui,
28529        ...uiApiFacade
28530      };
28531    };
28532    const init = async editor => {
28533      editor.dispatch('ScriptsLoaded');
28534      initIcons(editor);
28535      initTheme(editor);
28536      initModel(editor);
28537      initPlugins(editor);
28538      const renderInfo = await renderThemeUi(editor);
28539      augmentEditorUiApi(editor, Optional.from(renderInfo.api).getOr({}));
28540      editor.editorContainer = renderInfo.editorContainer;
28541      appendContentCssFromSettings(editor);
28542      if (editor.inline) {
28543        contentBodyLoaded(editor);
28544      } else {
28545        init$1(editor, {
28546          editorContainer: renderInfo.editorContainer,
28547          iframeContainer: renderInfo.iframeContainer
28548        });
28549      }
28550    };
28551
28552    const DOM$3 = DOMUtils.DOM;
28553    const hasSkipLoadPrefix = name => name.charAt(0) === '-';
28554    const loadLanguage = (scriptLoader, editor) => {
28555      const languageCode = getLanguageCode(editor);
28556      const languageUrl = getLanguageUrl(editor);
28557      if (!I18n.hasCode(languageCode) && languageCode !== 'en') {
28558        const url = isNotEmpty(languageUrl) ? languageUrl : `${ editor.editorManager.baseURL }/langs/${ languageCode }.js`;
28559        scriptLoader.add(url).catch(() => {
28560          languageLoadError(editor, url, languageCode);
28561        });
28562      }
28563    };
28564    const loadTheme = (editor, suffix) => {
28565      const theme = getTheme(editor);
28566      if (isString(theme) && !hasSkipLoadPrefix(theme) && !has$2(ThemeManager.urls, theme)) {
28567        const themeUrl = getThemeUrl(editor);
28568        const url = themeUrl ? editor.documentBaseURI.toAbsolute(themeUrl) : `themes/${ theme }/theme${ suffix }.js`;
28569        ThemeManager.load(theme, url).catch(() => {
28570          themeLoadError(editor, url, theme);
28571        });
28572      }
28573    };
28574    const loadModel = (editor, suffix) => {
28575      const model = getModel(editor);
28576      if (model !== 'plugin' && !has$2(ModelManager.urls, model)) {
28577        const modelUrl = getModelUrl(editor);
28578        const url = isString(modelUrl) ? editor.documentBaseURI.toAbsolute(modelUrl) : `models/${ model }/model${ suffix }.js`;
28579        ModelManager.load(model, url).catch(() => {
28580          modelLoadError(editor, url, model);
28581        });
28582      }
28583    };
28584    const getIconsUrlMetaFromUrl = editor => Optional.from(getIconsUrl(editor)).filter(isNotEmpty).map(url => ({
28585      url,
28586      name: Optional.none()
28587    }));
28588    const getIconsUrlMetaFromName = (editor, name, suffix) => Optional.from(name).filter(name => isNotEmpty(name) && !IconManager.has(name)).map(name => ({
28589      url: `${ editor.editorManager.baseURL }/icons/${ name }/icons${ suffix }.js`,
28590      name: Optional.some(name)
28591    }));
28592    const loadIcons = (scriptLoader, editor, suffix) => {
28593      const defaultIconsUrl = getIconsUrlMetaFromName(editor, 'default', suffix);
28594      const customIconsUrl = getIconsUrlMetaFromUrl(editor).orThunk(() => getIconsUrlMetaFromName(editor, getIconPackName(editor), ''));
28595      each$e(cat([
28596        defaultIconsUrl,
28597        customIconsUrl
28598      ]), urlMeta => {
28599        scriptLoader.add(urlMeta.url).catch(() => {
28600          iconsLoadError(editor, urlMeta.url, urlMeta.name.getOrUndefined());
28601        });
28602      });
28603    };
28604    const loadPlugins = (editor, suffix) => {
28605      const loadPlugin = (name, url) => {
28606        PluginManager.load(name, url).catch(() => {
28607          pluginLoadError(editor, url, name);
28608        });
28609      };
28610      each$d(getExternalPlugins$1(editor), (url, name) => {
28611        loadPlugin(name, url);
28612        editor.options.set('plugins', getPlugins(editor).concat(name));
28613      });
28614      each$e(getPlugins(editor), plugin => {
28615        plugin = Tools.trim(plugin);
28616        if (plugin && !PluginManager.urls[plugin] && !hasSkipLoadPrefix(plugin)) {
28617          loadPlugin(plugin, `plugins/${ plugin }/plugin${ suffix }.js`);
28618        }
28619      });
28620    };
28621    const isThemeLoaded = editor => {
28622      const theme = getTheme(editor);
28623      return !isString(theme) || isNonNullable(ThemeManager.get(theme));
28624    };
28625    const isModelLoaded = editor => {
28626      const model = getModel(editor);
28627      return isNonNullable(ModelManager.get(model));
28628    };
28629    const loadScripts = (editor, suffix) => {
28630      const scriptLoader = ScriptLoader.ScriptLoader;
28631      const initEditor = () => {
28632        if (!editor.removed && isThemeLoaded(editor) && isModelLoaded(editor)) {
28633          init(editor);
28634        }
28635      };
28636      loadTheme(editor, suffix);
28637      loadModel(editor, suffix);
28638      loadLanguage(scriptLoader, editor);
28639      loadIcons(scriptLoader, editor, suffix);
28640      loadPlugins(editor, suffix);
28641      scriptLoader.loadQueue().then(initEditor, initEditor);
28642    };
28643    const getStyleSheetLoader = (element, editor) => instance.forElement(element, {
28644      contentCssCors: hasContentCssCors(editor),
28645      referrerPolicy: getReferrerPolicy(editor)
28646    });
28647    const render = editor => {
28648      const id = editor.id;
28649      I18n.setCode(getLanguageCode(editor));
28650      const readyHandler = () => {
28651        DOM$3.unbind(window, 'ready', readyHandler);
28652        editor.render();
28653      };
28654      if (!EventUtils.Event.domLoaded) {
28655        DOM$3.bind(window, 'ready', readyHandler);
28656        return;
28657      }
28658      if (!editor.getElement()) {
28659        return;
28660      }
28661      const element = SugarElement.fromDom(editor.getElement());
28662      const snapshot = clone$4(element);
28663      editor.on('remove', () => {
28664        eachr(element.dom.attributes, attr => remove$a(element, attr.name));
28665        setAll$1(element, snapshot);
28666      });
28667      editor.ui.styleSheetLoader = getStyleSheetLoader(element, editor);
28668      if (!isInline(editor)) {
28669        editor.orgVisibility = editor.getElement().style.visibility;
28670        editor.getElement().style.visibility = 'hidden';
28671      } else {
28672        editor.inline = true;
28673      }
28674      const form = editor.getElement().form || DOM$3.getParent(id, 'form');
28675      if (form) {
28676        editor.formElement = form;
28677        if (hasHiddenInput(editor) && !isTextareaOrInput(editor.getElement())) {
28678          DOM$3.insertAfter(DOM$3.create('input', {
28679            type: 'hidden',
28680            name: id
28681          }), id);
28682          editor.hasHiddenInput = true;
28683        }
28684        editor.formEventDelegate = e => {
28685          editor.dispatch(e.type, e);
28686        };
28687        DOM$3.bind(form, 'submit reset', editor.formEventDelegate);
28688        editor.on('reset', () => {
28689          editor.resetContent();
28690        });
28691        if (shouldPatchSubmit(editor) && !form.submit.nodeType && !form.submit.length && !form._mceOldSubmit) {
28692          form._mceOldSubmit = form.submit;
28693          form.submit = () => {
28694            editor.editorManager.triggerSave();
28695            editor.setDirty(false);
28696            return form._mceOldSubmit(form);
28697          };
28698        }
28699      }
28700      editor.windowManager = WindowManager(editor);
28701      editor.notificationManager = NotificationManager(editor);
28702      if (isEncodingXml(editor)) {
28703        editor.on('GetContent', e => {
28704          if (e.save) {
28705            e.content = DOM$3.encode(e.content);
28706          }
28707        });
28708      }
28709      if (shouldAddFormSubmitTrigger(editor)) {
28710        editor.on('submit', () => {
28711          if (editor.initialized) {
28712            editor.save();
28713          }
28714        });
28715      }
28716      if (shouldAddUnloadTrigger(editor)) {
28717        editor._beforeUnload = () => {
28718          if (editor.initialized && !editor.destroyed && !editor.isHidden()) {
28719            editor.save({
28720              format: 'raw',
28721              no_events: true,
28722              set_dirty: false
28723            });
28724          }
28725        };
28726        editor.editorManager.on('BeforeUnload', editor._beforeUnload);
28727      }
28728      editor.editorManager.add(editor);
28729      loadScripts(editor, editor.suffix);
28730    };
28731
28732    const setEditableRoot = (editor, state) => {
28733      if (editor._editableRoot !== state) {
28734        editor._editableRoot = state;
28735        if (!editor.readonly) {
28736          editor.getBody().contentEditable = String(editor.hasEditableRoot());
28737          editor.nodeChanged();
28738        }
28739        fireEditableRootStateChange(editor, state);
28740      }
28741    };
28742    const hasEditableRoot = editor => editor._editableRoot;
28743
28744    const sectionResult = (sections, settings) => ({
28745      sections: constant(sections),
28746      options: constant(settings)
28747    });
28748    const deviceDetection = detect$2().deviceType;
28749    const isPhone = deviceDetection.isPhone();
28750    const isTablet = deviceDetection.isTablet();
28751    const normalizePlugins = plugins => {
28752      if (isNullable(plugins)) {
28753        return [];
28754      } else {
28755        const pluginNames = isArray$1(plugins) ? plugins : plugins.split(/[ ,]/);
28756        const trimmedPlugins = map$3(pluginNames, trim$3);
28757        return filter$5(trimmedPlugins, isNotEmpty);
28758      }
28759    };
28760    const extractSections = (keys, options) => {
28761      const result = bifilter(options, (value, key) => {
28762        return contains$2(keys, key);
28763      });
28764      return sectionResult(result.t, result.f);
28765    };
28766    const getSection = (sectionResult, name, defaults = {}) => {
28767      const sections = sectionResult.sections();
28768      const sectionOptions = get$a(sections, name).getOr({});
28769      return Tools.extend({}, defaults, sectionOptions);
28770    };
28771    const hasSection = (sectionResult, name) => {
28772      return has$2(sectionResult.sections(), name);
28773    };
28774    const getSectionConfig = (sectionResult, name) => {
28775      return hasSection(sectionResult, name) ? sectionResult.sections()[name] : {};
28776    };
28777    const getMobileOverrideOptions = (mobileOptions, isPhone) => {
28778      const defaultMobileOptions = {
28779        table_grid: false,
28780        object_resizing: false,
28781        resize: false,
28782        toolbar_mode: get$a(mobileOptions, 'toolbar_mode').getOr('scrolling'),
28783        toolbar_sticky: false
28784      };
28785      const defaultPhoneOptions = { menubar: false };
28786      return {
28787        ...defaultMobileOptions,
28788        ...isPhone ? defaultPhoneOptions : {}
28789      };
28790    };
28791    const getExternalPlugins = (overrideOptions, options) => {
28792      var _a;
28793      const userDefinedExternalPlugins = (_a = options.external_plugins) !== null && _a !== void 0 ? _a : {};
28794      if (overrideOptions && overrideOptions.external_plugins) {
28795        return Tools.extend({}, overrideOptions.external_plugins, userDefinedExternalPlugins);
28796      } else {
28797        return userDefinedExternalPlugins;
28798      }
28799    };
28800    const combinePlugins = (forcedPlugins, plugins) => [
28801      ...normalizePlugins(forcedPlugins),
28802      ...normalizePlugins(plugins)
28803    ];
28804    const getPlatformPlugins = (isMobileDevice, sectionResult, desktopPlugins, mobilePlugins) => {
28805      if (isMobileDevice && hasSection(sectionResult, 'mobile')) {
28806        return mobilePlugins;
28807      } else {
28808        return desktopPlugins;
28809      }
28810    };
28811    const processPlugins = (isMobileDevice, sectionResult, defaultOverrideOptions, options) => {
28812      const forcedPlugins = normalizePlugins(defaultOverrideOptions.forced_plugins);
28813      const desktopPlugins = normalizePlugins(options.plugins);
28814      const mobileConfig = getSectionConfig(sectionResult, 'mobile');
28815      const mobilePlugins = mobileConfig.plugins ? normalizePlugins(mobileConfig.plugins) : desktopPlugins;
28816      const platformPlugins = getPlatformPlugins(isMobileDevice, sectionResult, desktopPlugins, mobilePlugins);
28817      const combinedPlugins = combinePlugins(forcedPlugins, platformPlugins);
28818      return Tools.extend(options, {
28819        forced_plugins: forcedPlugins,
28820        plugins: combinedPlugins
28821      });
28822    };
28823    const isOnMobile = (isMobileDevice, sectionResult) => {
28824      return isMobileDevice && hasSection(sectionResult, 'mobile');
28825    };
28826    const combineOptions = (isMobileDevice, isPhone, defaultOptions, defaultOverrideOptions, options) => {
28827      var _a;
28828      const deviceOverrideOptions = isMobileDevice ? { mobile: getMobileOverrideOptions((_a = options.mobile) !== null && _a !== void 0 ? _a : {}, isPhone) } : {};
28829      const sectionResult = extractSections(['mobile'], deepMerge(deviceOverrideOptions, options));
28830      const extendedOptions = Tools.extend(defaultOptions, defaultOverrideOptions, sectionResult.options(), isOnMobile(isMobileDevice, sectionResult) ? getSection(sectionResult, 'mobile') : {}, { external_plugins: getExternalPlugins(defaultOverrideOptions, sectionResult.options()) });
28831      return processPlugins(isMobileDevice, sectionResult, defaultOverrideOptions, extendedOptions);
28832    };
28833    const normalizeOptions = (defaultOverrideOptions, options) => combineOptions(isPhone || isTablet, isPhone, options, defaultOverrideOptions, options);
28834
28835    const addVisual = (editor, elm) => addVisual$1(editor, elm);
28836
28837    const registerExecCommands$3 = editor => {
28838      const toggleFormat = (name, value) => {
28839        editor.formatter.toggle(name, value);
28840        editor.nodeChanged();
28841      };
28842      const toggleAlign = align => () => {
28843        each$e('left,center,right,justify'.split(','), name => {
28844          if (align !== name) {
28845            editor.formatter.remove('align' + name);
28846          }
28847        });
28848        if (align !== 'none') {
28849          toggleFormat('align' + align);
28850        }
28851      };
28852      editor.editorCommands.addCommands({
28853        JustifyLeft: toggleAlign('left'),
28854        JustifyCenter: toggleAlign('center'),
28855        JustifyRight: toggleAlign('right'),
28856        JustifyFull: toggleAlign('justify'),
28857        JustifyNone: toggleAlign('none')
28858      });
28859    };
28860    const registerQueryStateCommands$1 = editor => {
28861      const alignStates = name => () => {
28862        const selection = editor.selection;
28863        const nodes = selection.isCollapsed() ? [editor.dom.getParent(selection.getNode(), editor.dom.isBlock)] : selection.getSelectedBlocks();
28864        return exists(nodes, node => isNonNullable(editor.formatter.matchNode(node, name)));
28865      };
28866      editor.editorCommands.addCommands({
28867        JustifyLeft: alignStates('alignleft'),
28868        JustifyCenter: alignStates('aligncenter'),
28869        JustifyRight: alignStates('alignright'),
28870        JustifyFull: alignStates('alignjustify')
28871      }, 'state');
28872    };
28873    const registerCommands$a = editor => {
28874      registerExecCommands$3(editor);
28875      registerQueryStateCommands$1(editor);
28876    };
28877
28878    const registerCommands$9 = editor => {
28879      editor.editorCommands.addCommands({
28880        'Cut,Copy,Paste': command => {
28881          const doc = editor.getDoc();
28882          let failed;
28883          try {
28884            doc.execCommand(command);
28885          } catch (ex) {
28886            failed = true;
28887          }
28888          if (command === 'paste' && !doc.queryCommandEnabled(command)) {
28889            failed = true;
28890          }
28891          if (failed || !doc.queryCommandSupported(command)) {
28892            let msg = editor.translate(`Your browser doesn't support direct access to the clipboard. ` + 'Please use the Ctrl+X/C/V keyboard shortcuts instead.');
28893            if (Env.os.isMacOS() || Env.os.isiOS()) {
28894              msg = msg.replace(/Ctrl\+/g, '\u2318+');
28895            }
28896            editor.notificationManager.open({
28897              text: msg,
28898              type: 'error'
28899            });
28900          }
28901        }
28902      });
28903    };
28904
28905    const trimOrPadLeftRight = (dom, rng, html) => {
28906      const root = SugarElement.fromDom(dom.getRoot());
28907      if (needsToBeNbspLeft(root, CaretPosition.fromRangeStart(rng))) {
28908        html = html.replace(/^ /, '&nbsp;');
28909      } else {
28910        html = html.replace(/^&nbsp;/, ' ');
28911      }
28912      if (needsToBeNbspRight(root, CaretPosition.fromRangeEnd(rng))) {
28913        html = html.replace(/(&nbsp;| )(<br( \/)>)?$/, '&nbsp;');
28914      } else {
28915        html = html.replace(/&nbsp;(<br( \/)?>)?$/, ' ');
28916      }
28917      return html;
28918    };
28919
28920    const processValue$1 = value => {
28921      if (typeof value !== 'string') {
28922        const details = Tools.extend({
28923          paste: value.paste,
28924          data: { paste: value.paste }
28925        }, value);
28926        return {
28927          content: value.content,
28928          details
28929        };
28930      }
28931      return {
28932        content: value,
28933        details: {}
28934      };
28935    };
28936    const trimOrPad = (editor, value) => {
28937      const selection = editor.selection;
28938      const dom = editor.dom;
28939      if (/^ | $/.test(value)) {
28940        return trimOrPadLeftRight(dom, selection.getRng(), value);
28941      } else {
28942        return value;
28943      }
28944    };
28945    const insertAtCaret = (editor, value) => {
28946      if (editor.selection.isEditable()) {
28947        const {content, details} = processValue$1(value);
28948        preProcessSetContent(editor, {
28949          ...details,
28950          content: trimOrPad(editor, content),
28951          format: 'html',
28952          set: false,
28953          selection: true
28954        }).each(args => {
28955          const insertedContent = insertContent$1(editor, args.content, details);
28956          postProcessSetContent(editor, insertedContent, args);
28957          editor.addVisual();
28958        });
28959      }
28960    };
28961
28962    const registerCommands$8 = editor => {
28963      editor.editorCommands.addCommands({
28964        mceCleanup: () => {
28965          const bm = editor.selection.getBookmark();
28966          editor.setContent(editor.getContent());
28967          editor.selection.moveToBookmark(bm);
28968        },
28969        insertImage: (_command, _ui, value) => {
28970          insertAtCaret(editor, editor.dom.createHTML('img', { src: value }));
28971        },
28972        insertHorizontalRule: () => {
28973          editor.execCommand('mceInsertContent', false, '<hr>');
28974        },
28975        insertText: (_command, _ui, value) => {
28976          insertAtCaret(editor, editor.dom.encode(value));
28977        },
28978        insertHTML: (_command, _ui, value) => {
28979          insertAtCaret(editor, value);
28980        },
28981        mceInsertContent: (_command, _ui, value) => {
28982          insertAtCaret(editor, value);
28983        },
28984        mceSetContent: (_command, _ui, value) => {
28985          editor.setContent(value);
28986        },
28987        mceReplaceContent: (_command, _ui, value) => {
28988          editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, editor.selection.getContent({ format: 'text' })));
28989        },
28990        mceNewDocument: () => {
28991          editor.setContent(getNewDocumentContent(editor));
28992        }
28993      });
28994    };
28995
28996    const legacyPropNames = {
28997      'font-size': 'size',
28998      'font-family': 'face'
28999    };
29000    const isFont = isTag('font');
29001    const getSpecifiedFontProp = (propName, rootElm, elm) => {
29002      const getProperty = elm => getRaw(elm, propName).orThunk(() => {
29003        if (isFont(elm)) {
29004          return get$a(legacyPropNames, propName).bind(legacyPropName => getOpt(elm, legacyPropName));
29005        } else {
29006          return Optional.none();
29007        }
29008      });
29009      const isRoot = elm => eq(SugarElement.fromDom(rootElm), elm);
29010      return closest$1(SugarElement.fromDom(elm), elm => getProperty(elm), isRoot);
29011    };
29012    const normalizeFontFamily = fontFamily => fontFamily.replace(/[\'\"\\]/g, '').replace(/,\s+/g, ',');
29013    const getComputedFontProp = (propName, elm) => Optional.from(DOMUtils.DOM.getStyle(elm, propName, true));
29014    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('');
29015    const getFontSize = getFontProp('font-size');
29016    const getFontFamily = compose(normalizeFontFamily, getFontProp('font-family'));
29017
29018    const findFirstCaretElement = editor => firstPositionIn(editor.getBody()).bind(caret => {
29019      const container = caret.container();
29020      return Optional.from(isText$a(container) ? container.parentNode : container);
29021    });
29022    const getCaretElement = editor => Optional.from(editor.selection.getRng()).bind(rng => {
29023      const root = editor.getBody();
29024      const atStartOfNode = rng.startContainer === root && rng.startOffset === 0;
29025      return atStartOfNode ? Optional.none() : Optional.from(editor.selection.getStart(true));
29026    });
29027    const bindRange = (editor, binder) => getCaretElement(editor).orThunk(curry(findFirstCaretElement, editor)).map(SugarElement.fromDom).filter(isElement$7).bind(binder);
29028    const mapRange = (editor, mapper) => bindRange(editor, compose1(Optional.some, mapper));
29029
29030    const fromFontSizeNumber = (editor, value) => {
29031      if (/^[0-9.]+$/.test(value)) {
29032        const fontSizeNumber = parseInt(value, 10);
29033        if (fontSizeNumber >= 1 && fontSizeNumber <= 7) {
29034          const fontSizes = getFontStyleValues(editor);
29035          const fontClasses = getFontSizeClasses(editor);
29036          if (fontClasses.length > 0) {
29037            return fontClasses[fontSizeNumber - 1] || value;
29038          } else {
29039            return fontSizes[fontSizeNumber - 1] || value;
29040          }
29041        } else {
29042          return value;
29043        }
29044      } else {
29045        return value;
29046      }
29047    };
29048    const normalizeFontNames = font => {
29049      const fonts = font.split(/\s*,\s*/);
29050      return map$3(fonts, font => {
29051        if (font.indexOf(' ') !== -1 && !(startsWith(font, '"') || startsWith(font, `'`))) {
29052          return `'${ font }'`;
29053        } else {
29054          return font;
29055        }
29056      }).join(',');
29057    };
29058    const fontNameAction = (editor, value) => {
29059      const font = fromFontSizeNumber(editor, value);
29060      editor.formatter.toggle('fontname', { value: normalizeFontNames(font) });
29061      editor.nodeChanged();
29062    };
29063    const fontNameQuery = editor => mapRange(editor, elm => getFontFamily(editor.getBody(), elm.dom)).getOr('');
29064    const fontSizeAction = (editor, value) => {
29065      editor.formatter.toggle('fontsize', { value: fromFontSizeNumber(editor, value) });
29066      editor.nodeChanged();
29067    };
29068    const fontSizeQuery = editor => mapRange(editor, elm => getFontSize(editor.getBody(), elm.dom)).getOr('');
29069
29070    const lineHeightQuery = editor => mapRange(editor, elm => {
29071      const root = SugarElement.fromDom(editor.getBody());
29072      const specifiedStyle = closest$1(elm, elm => getRaw(elm, 'line-height'), curry(eq, root));
29073      const computedStyle = () => {
29074        const lineHeight = parseFloat(get$7(elm, 'line-height'));
29075        const fontSize = parseFloat(get$7(elm, 'font-size'));
29076        return String(lineHeight / fontSize);
29077      };
29078      return specifiedStyle.getOrThunk(computedStyle);
29079    }).getOr('');
29080    const lineHeightAction = (editor, lineHeight) => {
29081      editor.formatter.toggle('lineheight', { value: String(lineHeight) });
29082      editor.nodeChanged();
29083    };
29084
29085    const registerExecCommands$2 = editor => {
29086      const toggleFormat = (name, value) => {
29087        editor.formatter.toggle(name, value);
29088        editor.nodeChanged();
29089      };
29090      editor.editorCommands.addCommands({
29091        'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => {
29092          toggleFormat(command);
29093        },
29094        'ForeColor,HiliteColor': (command, _ui, value) => {
29095          toggleFormat(command, { value });
29096        },
29097        'BackColor': (_command, _ui, value) => {
29098          toggleFormat('hilitecolor', { value });
29099        },
29100        'FontName': (_command, _ui, value) => {
29101          fontNameAction(editor, value);
29102        },
29103        'FontSize': (_command, _ui, value) => {
29104          fontSizeAction(editor, value);
29105        },
29106        'LineHeight': (_command, _ui, value) => {
29107          lineHeightAction(editor, value);
29108        },
29109        'Lang': (command, _ui, lang) => {
29110          var _a;
29111          toggleFormat(command, {
29112            value: lang.code,
29113            customValue: (_a = lang.customCode) !== null && _a !== void 0 ? _a : null
29114          });
29115        },
29116        'RemoveFormat': command => {
29117          editor.formatter.remove(command);
29118        },
29119        'mceBlockQuote': () => {
29120          toggleFormat('blockquote');
29121        },
29122        'FormatBlock': (_command, _ui, value) => {
29123          toggleFormat(isString(value) ? value : 'p');
29124        },
29125        'mceToggleFormat': (_command, _ui, value) => {
29126          toggleFormat(value);
29127        }
29128      });
29129    };
29130    const registerQueryValueCommands = editor => {
29131      const isFormatMatch = name => editor.formatter.match(name);
29132      editor.editorCommands.addCommands({
29133        'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => isFormatMatch(command),
29134        'mceBlockQuote': () => isFormatMatch('blockquote')
29135      }, 'state');
29136      editor.editorCommands.addQueryValueHandler('FontName', () => fontNameQuery(editor));
29137      editor.editorCommands.addQueryValueHandler('FontSize', () => fontSizeQuery(editor));
29138      editor.editorCommands.addQueryValueHandler('LineHeight', () => lineHeightQuery(editor));
29139    };
29140    const registerCommands$7 = editor => {
29141      registerExecCommands$2(editor);
29142      registerQueryValueCommands(editor);
29143    };
29144
29145    const registerCommands$6 = editor => {
29146      editor.editorCommands.addCommands({
29147        mceAddUndoLevel: () => {
29148          editor.undoManager.add();
29149        },
29150        mceEndUndoLevel: () => {
29151          editor.undoManager.add();
29152        },
29153        Undo: () => {
29154          editor.undoManager.undo();
29155        },
29156        Redo: () => {
29157          editor.undoManager.redo();
29158        }
29159      });
29160    };
29161
29162    const registerCommands$5 = editor => {
29163      editor.editorCommands.addCommands({
29164        Indent: () => {
29165          indent(editor);
29166        },
29167        Outdent: () => {
29168          outdent(editor);
29169        }
29170      });
29171      editor.editorCommands.addCommands({ Outdent: () => canOutdent(editor) }, 'state');
29172    };
29173
29174    const registerCommands$4 = editor => {
29175      const applyLinkToSelection = (_command, _ui, value) => {
29176        const linkDetails = isString(value) ? { href: value } : value;
29177        const anchor = editor.dom.getParent(editor.selection.getNode(), 'a');
29178        if (isObject(linkDetails) && isString(linkDetails.href)) {
29179          linkDetails.href = linkDetails.href.replace(/ /g, '%20');
29180          if (!anchor || !linkDetails.href) {
29181            editor.formatter.remove('link');
29182          }
29183          if (linkDetails.href) {
29184            editor.formatter.apply('link', linkDetails, anchor);
29185          }
29186        }
29187      };
29188      editor.editorCommands.addCommands({
29189        unlink: () => {
29190          if (editor.selection.isEditable()) {
29191            if (editor.selection.isCollapsed()) {
29192              const elm = editor.dom.getParent(editor.selection.getStart(), 'a');
29193              if (elm) {
29194                editor.dom.remove(elm, true);
29195              }
29196              return;
29197            }
29198            editor.formatter.remove('link');
29199          }
29200        },
29201        mceInsertLink: applyLinkToSelection,
29202        createLink: applyLinkToSelection
29203      });
29204    };
29205
29206    const registerExecCommands$1 = editor => {
29207      editor.editorCommands.addCommands({
29208        'InsertUnorderedList,InsertOrderedList': command => {
29209          editor.getDoc().execCommand(command);
29210          const listElm = editor.dom.getParent(editor.selection.getNode(), 'ol,ul');
29211          if (listElm) {
29212            const listParent = listElm.parentNode;
29213            if (listParent && /^(H[1-6]|P|ADDRESS|PRE)$/.test(listParent.nodeName)) {
29214              const bm = editor.selection.getBookmark();
29215              editor.dom.split(listParent, listElm);
29216              editor.selection.moveToBookmark(bm);
29217            }
29218          }
29219        }
29220      });
29221    };
29222    const registerQueryStateCommands = editor => {
29223      editor.editorCommands.addCommands({
29224        'InsertUnorderedList,InsertOrderedList': command => {
29225          const list = editor.dom.getParent(editor.selection.getNode(), 'ul,ol');
29226          return list && (command === 'insertunorderedlist' && list.tagName === 'UL' || command === 'insertorderedlist' && list.tagName === 'OL');
29227        }
29228      }, 'state');
29229    };
29230    const registerCommands$3 = editor => {
29231      registerExecCommands$1(editor);
29232      registerQueryStateCommands(editor);
29233    };
29234
29235    const registerCommands$2 = editor => {
29236      editor.editorCommands.addCommands({
29237        insertParagraph: () => {
29238          insertBreak(blockbreak, editor);
29239        },
29240        mceInsertNewLine: (_command, _ui, value) => {
29241          insert(editor, value);
29242        },
29243        InsertLineBreak: (_command, _ui, _value) => {
29244          insertBreak(linebreak, editor);
29245        }
29246      });
29247    };
29248
29249    const registerCommands$1 = editor => {
29250      editor.editorCommands.addCommands({
29251        mceSelectNodeDepth: (_command, _ui, value) => {
29252          let counter = 0;
29253          editor.dom.getParent(editor.selection.getNode(), node => {
29254            if (isElement$6(node) && counter++ === value) {
29255              editor.selection.select(node);
29256              return false;
29257            } else {
29258              return true;
29259            }
29260          }, editor.getBody());
29261        },
29262        mceSelectNode: (_command, _ui, value) => {
29263          editor.selection.select(value);
29264        },
29265        selectAll: () => {
29266          const editingHost = editor.dom.getParent(editor.selection.getStart(), isContentEditableTrue$3);
29267          if (editingHost) {
29268            const rng = editor.dom.createRng();
29269            rng.selectNodeContents(editingHost);
29270            editor.selection.setRng(rng);
29271          }
29272        }
29273      });
29274    };
29275
29276    const registerExecCommands = editor => {
29277      editor.editorCommands.addCommands({
29278        mceRemoveNode: (_command, _ui, value) => {
29279          const node = value !== null && value !== void 0 ? value : editor.selection.getNode();
29280          if (node !== editor.getBody()) {
29281            const bm = editor.selection.getBookmark();
29282            editor.dom.remove(node, true);
29283            editor.selection.moveToBookmark(bm);
29284          }
29285        },
29286        mcePrint: () => {
29287          editor.getWin().print();
29288        },
29289        mceFocus: (_command, _ui, value) => {
29290          focus(editor, value === true);
29291        },
29292        mceToggleVisualAid: () => {
29293          editor.hasVisual = !editor.hasVisual;
29294          editor.addVisual();
29295        }
29296      });
29297    };
29298    const registerCommands = editor => {
29299      registerCommands$a(editor);
29300      registerCommands$9(editor);
29301      registerCommands$6(editor);
29302      registerCommands$1(editor);
29303      registerCommands$8(editor);
29304      registerCommands$4(editor);
29305      registerCommands$5(editor);
29306      registerCommands$2(editor);
29307      registerCommands$3(editor);
29308      registerCommands$7(editor);
29309      registerExecCommands(editor);
29310    };
29311
29312    const selectionSafeCommands = ['toggleview'];
29313    const isSelectionSafeCommand = command => contains$2(selectionSafeCommands, command.toLowerCase());
29314    class EditorCommands {
29315      constructor(editor) {
29316        this.commands = {
29317          state: {},
29318          exec: {},
29319          value: {}
29320        };
29321        this.editor = editor;
29322      }
29323      execCommand(command, ui = false, value, args) {
29324        const editor = this.editor;
29325        const lowerCaseCommand = command.toLowerCase();
29326        const skipFocus = args === null || args === void 0 ? void 0 : args.skip_focus;
29327        if (editor.removed) {
29328          return false;
29329        }
29330        if (lowerCaseCommand !== 'mcefocus') {
29331          if (!/^(mceAddUndoLevel|mceEndUndoLevel)$/i.test(lowerCaseCommand) && !skipFocus) {
29332            editor.focus();
29333          } else {
29334            restore(editor);
29335          }
29336        }
29337        const eventArgs = editor.dispatch('BeforeExecCommand', {
29338          command,
29339          ui,
29340          value
29341        });
29342        if (eventArgs.isDefaultPrevented()) {
29343          return false;
29344        }
29345        const func = this.commands.exec[lowerCaseCommand];
29346        if (isFunction(func)) {
29347          func(lowerCaseCommand, ui, value);
29348          editor.dispatch('ExecCommand', {
29349            command,
29350            ui,
29351            value
29352          });
29353          return true;
29354        }
29355        return false;
29356      }
29357      queryCommandState(command) {
29358        if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
29359          return false;
29360        }
29361        const lowerCaseCommand = command.toLowerCase();
29362        const func = this.commands.state[lowerCaseCommand];
29363        if (isFunction(func)) {
29364          return func(lowerCaseCommand);
29365        }
29366        return false;
29367      }
29368      queryCommandValue(command) {
29369        if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
29370          return '';
29371        }
29372        const lowerCaseCommand = command.toLowerCase();
29373        const func = this.commands.value[lowerCaseCommand];
29374        if (isFunction(func)) {
29375          return func(lowerCaseCommand);
29376        }
29377        return '';
29378      }
29379      addCommands(commandList, type = 'exec') {
29380        const commands = this.commands;
29381        each$d(commandList, (callback, command) => {
29382          each$e(command.toLowerCase().split(','), command => {
29383            commands[type][command] = callback;
29384          });
29385        });
29386      }
29387      addCommand(command, callback, scope) {
29388        const lowerCaseCommand = command.toLowerCase();
29389        this.commands.exec[lowerCaseCommand] = (_command, ui, value) => callback.call(scope !== null && scope !== void 0 ? scope : this.editor, ui, value);
29390      }
29391      queryCommandSupported(command) {
29392        const lowerCaseCommand = command.toLowerCase();
29393        if (this.commands.exec[lowerCaseCommand]) {
29394          return true;
29395        } else {
29396          return false;
29397        }
29398      }
29399      addQueryStateHandler(command, callback, scope) {
29400        this.commands.state[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
29401      }
29402      addQueryValueHandler(command, callback, scope) {
29403        this.commands.value[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
29404      }
29405    }
29406
29407    const internalContentEditableAttr = 'data-mce-contenteditable';
29408    const toggleClass = (elm, cls, state) => {
29409      if (has(elm, cls) && !state) {
29410        remove$7(elm, cls);
29411      } else if (state) {
29412        add$2(elm, cls);
29413      }
29414    };
29415    const setEditorCommandState = (editor, cmd, state) => {
29416      try {
29417        editor.getDoc().execCommand(cmd, false, String(state));
29418      } catch (ex) {
29419      }
29420    };
29421    const setContentEditable = (elm, state) => {
29422      elm.dom.contentEditable = state ? 'true' : 'false';
29423    };
29424    const switchOffContentEditableTrue = elm => {
29425      each$e(descendants(elm, '*[contenteditable="true"]'), elm => {
29426        set$3(elm, internalContentEditableAttr, 'true');
29427        setContentEditable(elm, false);
29428      });
29429    };
29430    const switchOnContentEditableTrue = elm => {
29431      each$e(descendants(elm, `*[${ internalContentEditableAttr }="true"]`), elm => {
29432        remove$a(elm, internalContentEditableAttr);
29433        setContentEditable(elm, true);
29434      });
29435    };
29436    const removeFakeSelection = editor => {
29437      Optional.from(editor.selection.getNode()).each(elm => {
29438        elm.removeAttribute('data-mce-selected');
29439      });
29440    };
29441    const restoreFakeSelection = editor => {
29442      editor.selection.setRng(editor.selection.getRng());
29443    };
29444    const toggleReadOnly = (editor, state) => {
29445      const body = SugarElement.fromDom(editor.getBody());
29446      toggleClass(body, 'mce-content-readonly', state);
29447      if (state) {
29448        editor.selection.controlSelection.hideResizeRect();
29449        editor._selectionOverrides.hideFakeCaret();
29450        removeFakeSelection(editor);
29451        editor.readonly = true;
29452        setContentEditable(body, false);
29453        switchOffContentEditableTrue(body);
29454      } else {
29455        editor.readonly = false;
29456        if (editor.hasEditableRoot()) {
29457          setContentEditable(body, true);
29458        }
29459        switchOnContentEditableTrue(body);
29460        setEditorCommandState(editor, 'StyleWithCSS', false);
29461        setEditorCommandState(editor, 'enableInlineTableEditing', false);
29462        setEditorCommandState(editor, 'enableObjectResizing', false);
29463        if (hasEditorOrUiFocus(editor)) {
29464          editor.focus();
29465        }
29466        restoreFakeSelection(editor);
29467        editor.nodeChanged();
29468      }
29469    };
29470    const isReadOnly = editor => editor.readonly;
29471    const registerFilters = editor => {
29472      editor.parser.addAttributeFilter('contenteditable', nodes => {
29473        if (isReadOnly(editor)) {
29474          each$e(nodes, node => {
29475            node.attr(internalContentEditableAttr, node.attr('contenteditable'));
29476            node.attr('contenteditable', 'false');
29477          });
29478        }
29479      });
29480      editor.serializer.addAttributeFilter(internalContentEditableAttr, nodes => {
29481        if (isReadOnly(editor)) {
29482          each$e(nodes, node => {
29483            node.attr('contenteditable', node.attr(internalContentEditableAttr));
29484          });
29485        }
29486      });
29487      editor.serializer.addTempAttr(internalContentEditableAttr);
29488    };
29489    const registerReadOnlyContentFilters = editor => {
29490      if (editor.serializer) {
29491        registerFilters(editor);
29492      } else {
29493        editor.on('PreInit', () => {
29494          registerFilters(editor);
29495        });
29496      }
29497    };
29498    const isClickEvent = e => e.type === 'click';
29499    const allowedEvents = ['copy'];
29500    const isReadOnlyAllowedEvent = e => contains$2(allowedEvents, e.type);
29501    const getAnchorHrefOpt = (editor, elm) => {
29502      const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
29503      return closest$3(elm, 'a', isRoot).bind(a => getOpt(a, 'href'));
29504    };
29505    const processReadonlyEvents = (editor, e) => {
29506      if (isClickEvent(e) && !VK.metaKeyPressed(e)) {
29507        const elm = SugarElement.fromDom(e.target);
29508        getAnchorHrefOpt(editor, elm).each(href => {
29509          e.preventDefault();
29510          if (/^#/.test(href)) {
29511            const targetEl = editor.dom.select(`${ href },[name="${ removeLeading(href, '#') }"]`);
29512            if (targetEl.length) {
29513              editor.selection.scrollIntoView(targetEl[0], true);
29514            }
29515          } else {
29516            window.open(href, '_blank', 'rel=noopener noreferrer,menubar=yes,toolbar=yes,location=yes,status=yes,resizable=yes,scrollbars=yes');
29517          }
29518        });
29519      } else if (isReadOnlyAllowedEvent(e)) {
29520        editor.dispatch(e.type, e);
29521      }
29522    };
29523    const registerReadOnlySelectionBlockers = editor => {
29524      editor.on('ShowCaret', e => {
29525        if (isReadOnly(editor)) {
29526          e.preventDefault();
29527        }
29528      });
29529      editor.on('ObjectSelected', e => {
29530        if (isReadOnly(editor)) {
29531          e.preventDefault();
29532        }
29533      });
29534    };
29535
29536    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', ' ');
29537    class EventDispatcher {
29538      static isNative(name) {
29539        return !!nativeEvents[name.toLowerCase()];
29540      }
29541      constructor(settings) {
29542        this.bindings = {};
29543        this.settings = settings || {};
29544        this.scope = this.settings.scope || this;
29545        this.toggleEvent = this.settings.toggleEvent || never;
29546      }
29547      fire(name, args) {
29548        return this.dispatch(name, args);
29549      }
29550      dispatch(name, args) {
29551        const lcName = name.toLowerCase();
29552        const event = normalize$3(lcName, args !== null && args !== void 0 ? args : {}, this.scope);
29553        if (this.settings.beforeFire) {
29554          this.settings.beforeFire(event);
29555        }
29556        const handlers = this.bindings[lcName];
29557        if (handlers) {
29558          for (let i = 0, l = handlers.length; i < l; i++) {
29559            const callback = handlers[i];
29560            if (callback.removed) {
29561              continue;
29562            }
29563            if (callback.once) {
29564              this.off(lcName, callback.func);
29565            }
29566            if (event.isImmediatePropagationStopped()) {
29567              return event;
29568            }
29569            if (callback.func.call(this.scope, event) === false) {
29570              event.preventDefault();
29571              return event;
29572            }
29573          }
29574        }
29575        return event;
29576      }
29577      on(name, callback, prepend, extra) {
29578        if (callback === false) {
29579          callback = never;
29580        }
29581        if (callback) {
29582          const wrappedCallback = {
29583            func: callback,
29584            removed: false
29585          };
29586          if (extra) {
29587            Tools.extend(wrappedCallback, extra);
29588          }
29589          const names = name.toLowerCase().split(' ');
29590          let i = names.length;
29591          while (i--) {
29592            const currentName = names[i];
29593            let handlers = this.bindings[currentName];
29594            if (!handlers) {
29595              handlers = [];
29596              this.toggleEvent(currentName, true);
29597            }
29598            if (prepend) {
29599              handlers = [
29600                wrappedCallback,
29601                ...handlers
29602              ];
29603            } else {
29604              handlers = [
29605                ...handlers,
29606                wrappedCallback
29607              ];
29608            }
29609            this.bindings[currentName] = handlers;
29610          }
29611        }
29612        return this;
29613      }
29614      off(name, callback) {
29615        if (name) {
29616          const names = name.toLowerCase().split(' ');
29617          let i = names.length;
29618          while (i--) {
29619            const currentName = names[i];
29620            let handlers = this.bindings[currentName];
29621            if (!currentName) {
29622              each$d(this.bindings, (_value, bindingName) => {
29623                this.toggleEvent(bindingName, false);
29624                delete this.bindings[bindingName];
29625              });
29626              return this;
29627            }
29628            if (handlers) {
29629              if (!callback) {
29630                handlers.length = 0;
29631              } else {
29632                const filteredHandlers = partition$2(handlers, handler => handler.func === callback);
29633                handlers = filteredHandlers.fail;
29634                this.bindings[currentName] = handlers;
29635                each$e(filteredHandlers.pass, handler => {
29636                  handler.removed = true;
29637                });
29638              }
29639              if (!handlers.length) {
29640                this.toggleEvent(name, false);
29641                delete this.bindings[currentName];
29642              }
29643            }
29644          }
29645        } else {
29646          each$d(this.bindings, (_value, name) => {
29647            this.toggleEvent(name, false);
29648          });
29649          this.bindings = {};
29650        }
29651        return this;
29652      }
29653      once(name, callback, prepend) {
29654        return this.on(name, callback, prepend, { once: true });
29655      }
29656      has(name) {
29657        name = name.toLowerCase();
29658        const binding = this.bindings[name];
29659        return !(!binding || binding.length === 0);
29660      }
29661    }
29662
29663    const getEventDispatcher = obj => {
29664      if (!obj._eventDispatcher) {
29665        obj._eventDispatcher = new EventDispatcher({
29666          scope: obj,
29667          toggleEvent: (name, state) => {
29668            if (EventDispatcher.isNative(name) && obj.toggleNativeEvent) {
29669              obj.toggleNativeEvent(name, state);
29670            }
29671          }
29672        });
29673      }
29674      return obj._eventDispatcher;
29675    };
29676    const Observable = {
29677      fire(name, args, bubble) {
29678        return this.dispatch(name, args, bubble);
29679      },
29680      dispatch(name, args, bubble) {
29681        const self = this;
29682        if (self.removed && name !== 'remove' && name !== 'detach') {
29683          return normalize$3(name.toLowerCase(), args !== null && args !== void 0 ? args : {}, self);
29684        }
29685        const dispatcherArgs = getEventDispatcher(self).dispatch(name, args);
29686        if (bubble !== false && self.parent) {
29687          let parent = self.parent();
29688          while (parent && !dispatcherArgs.isPropagationStopped()) {
29689            parent.dispatch(name, dispatcherArgs, false);
29690            parent = parent.parent ? parent.parent() : undefined;
29691          }
29692        }
29693        return dispatcherArgs;
29694      },
29695      on(name, callback, prepend) {
29696        return getEventDispatcher(this).on(name, callback, prepend);
29697      },
29698      off(name, callback) {
29699        return getEventDispatcher(this).off(name, callback);
29700      },
29701      once(name, callback) {
29702        return getEventDispatcher(this).once(name, callback);
29703      },
29704      hasEventListeners(name) {
29705        return getEventDispatcher(this).has(name);
29706      }
29707    };
29708
29709    const DOM$2 = DOMUtils.DOM;
29710    let customEventRootDelegates;
29711    const getEventTarget = (editor, eventName) => {
29712      if (eventName === 'selectionchange') {
29713        return editor.getDoc();
29714      }
29715      if (!editor.inline && /^(?:mouse|touch|click|contextmenu|drop|dragover|dragend)/.test(eventName)) {
29716        return editor.getDoc().documentElement;
29717      }
29718      const eventRoot = getEventRoot(editor);
29719      if (eventRoot) {
29720        if (!editor.eventRoot) {
29721          editor.eventRoot = DOM$2.select(eventRoot)[0];
29722        }
29723        return editor.eventRoot;
29724      }
29725      return editor.getBody();
29726    };
29727    const isListening = editor => !editor.hidden && !isReadOnly(editor);
29728    const fireEvent = (editor, eventName, e) => {
29729      if (isListening(editor)) {
29730        editor.dispatch(eventName, e);
29731      } else if (isReadOnly(editor)) {
29732        processReadonlyEvents(editor, e);
29733      }
29734    };
29735    const bindEventDelegate = (editor, eventName) => {
29736      if (!editor.delegates) {
29737        editor.delegates = {};
29738      }
29739      if (editor.delegates[eventName] || editor.removed) {
29740        return;
29741      }
29742      const eventRootElm = getEventTarget(editor, eventName);
29743      if (getEventRoot(editor)) {
29744        if (!customEventRootDelegates) {
29745          customEventRootDelegates = {};
29746          editor.editorManager.on('removeEditor', () => {
29747            if (!editor.editorManager.activeEditor) {
29748              if (customEventRootDelegates) {
29749                each$d(customEventRootDelegates, (_value, name) => {
29750                  editor.dom.unbind(getEventTarget(editor, name));
29751                });
29752                customEventRootDelegates = null;
29753              }
29754            }
29755          });
29756        }
29757        if (customEventRootDelegates[eventName]) {
29758          return;
29759        }
29760        const delegate = e => {
29761          const target = e.target;
29762          const editors = editor.editorManager.get();
29763          let i = editors.length;
29764          while (i--) {
29765            const body = editors[i].getBody();
29766            if (body === target || DOM$2.isChildOf(target, body)) {
29767              fireEvent(editors[i], eventName, e);
29768            }
29769          }
29770        };
29771        customEventRootDelegates[eventName] = delegate;
29772        DOM$2.bind(eventRootElm, eventName, delegate);
29773      } else {
29774        const delegate = e => {
29775          fireEvent(editor, eventName, e);
29776        };
29777        DOM$2.bind(eventRootElm, eventName, delegate);
29778        editor.delegates[eventName] = delegate;
29779      }
29780    };
29781    const EditorObservable = {
29782      ...Observable,
29783      bindPendingEventDelegates() {
29784        const self = this;
29785        Tools.each(self._pendingNativeEvents, name => {
29786          bindEventDelegate(self, name);
29787        });
29788      },
29789      toggleNativeEvent(name, state) {
29790        const self = this;
29791        if (name === 'focus' || name === 'blur') {
29792          return;
29793        }
29794        if (self.removed) {
29795          return;
29796        }
29797        if (state) {
29798          if (self.initialized) {
29799            bindEventDelegate(self, name);
29800          } else {
29801            if (!self._pendingNativeEvents) {
29802              self._pendingNativeEvents = [name];
29803            } else {
29804              self._pendingNativeEvents.push(name);
29805            }
29806          }
29807        } else if (self.initialized && self.delegates) {
29808          self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]);
29809          delete self.delegates[name];
29810        }
29811      },
29812      unbindAllNativeEvents() {
29813        const self = this;
29814        const body = self.getBody();
29815        const dom = self.dom;
29816        if (self.delegates) {
29817          each$d(self.delegates, (value, name) => {
29818            self.dom.unbind(getEventTarget(self, name), name, value);
29819          });
29820          delete self.delegates;
29821        }
29822        if (!self.inline && body && dom) {
29823          body.onload = null;
29824          dom.unbind(self.getWin());
29825          dom.unbind(self.getDoc());
29826        }
29827        if (dom) {
29828          dom.unbind(body);
29829          dom.unbind(self.getContainer());
29830        }
29831      }
29832    };
29833
29834    const stringListProcessor = value => {
29835      if (isString(value)) {
29836        return {
29837          value: value.split(/[ ,]/),
29838          valid: true
29839        };
29840      } else if (isArrayOf(value, isString)) {
29841        return {
29842          value,
29843          valid: true
29844        };
29845      } else {
29846        return {
29847          valid: false,
29848          message: `The value must be a string[] or a comma/space separated string.`
29849        };
29850      }
29851    };
29852    const getBuiltInProcessor = type => {
29853      const validator = (() => {
29854        switch (type) {
29855        case 'array':
29856          return isArray$1;
29857        case 'boolean':
29858          return isBoolean;
29859        case 'function':
29860          return isFunction;
29861        case 'number':
29862          return isNumber;
29863        case 'object':
29864          return isObject;
29865        case 'string':
29866          return isString;
29867        case 'string[]':
29868          return stringListProcessor;
29869        case 'object[]':
29870          return val => isArrayOf(val, isObject);
29871        case 'regexp':
29872          return val => is$4(val, RegExp);
29873        default:
29874          return always;
29875        }
29876      })();
29877      return value => processValue(value, validator, `The value must be a ${ type }.`);
29878    };
29879    const isBuiltInSpec = spec => isString(spec.processor);
29880    const getErrorMessage = (message, result) => {
29881      const additionalText = isEmpty$3(result.message) ? '' : `. ${ result.message }`;
29882      return message + additionalText;
29883    };
29884    const isValidResult = result => result.valid;
29885    const processValue = (value, processor, message = '') => {
29886      const result = processor(value);
29887      if (isBoolean(result)) {
29888        return result ? {
29889          value: value,
29890          valid: true
29891        } : {
29892          valid: false,
29893          message
29894        };
29895      } else {
29896        return result;
29897      }
29898    };
29899    const processDefaultValue = (name, defaultValue, processor) => {
29900      if (!isUndefined(defaultValue)) {
29901        const result = processValue(defaultValue, processor);
29902        if (isValidResult(result)) {
29903          return result.value;
29904        } else {
29905          console.error(getErrorMessage(`Invalid default value passed for the "${ name }" option`, result));
29906        }
29907      }
29908      return undefined;
29909    };
29910    const create$5 = (editor, initialOptions) => {
29911      const registry = {};
29912      const values = {};
29913      const setValue = (name, value, processor) => {
29914        const result = processValue(value, processor);
29915        if (isValidResult(result)) {
29916          values[name] = result.value;
29917          return true;
29918        } else {
29919          console.warn(getErrorMessage(`Invalid value passed for the ${ name } option`, result));
29920          return false;
29921        }
29922      };
29923      const register = (name, spec) => {
29924        const processor = isBuiltInSpec(spec) ? getBuiltInProcessor(spec.processor) : spec.processor;
29925        const defaultValue = processDefaultValue(name, spec.default, processor);
29926        registry[name] = {
29927          ...spec,
29928          default: defaultValue,
29929          processor
29930        };
29931        const initValue = get$a(values, name).orThunk(() => get$a(initialOptions, name));
29932        initValue.each(value => setValue(name, value, processor));
29933      };
29934      const isRegistered = name => has$2(registry, name);
29935      const get = name => get$a(values, name).orThunk(() => get$a(registry, name).map(spec => spec.default)).getOrUndefined();
29936      const set = (name, value) => {
29937        if (!isRegistered(name)) {
29938          console.warn(`"${ name }" is not a registered option. Ensure the option has been registered before setting a value.`);
29939          return false;
29940        } else {
29941          const spec = registry[name];
29942          if (spec.immutable) {
29943            console.error(`"${ name }" is an immutable option and cannot be updated`);
29944            return false;
29945          } else {
29946            return setValue(name, value, spec.processor);
29947          }
29948        }
29949      };
29950      const unset = name => {
29951        const registered = isRegistered(name);
29952        if (registered) {
29953          delete values[name];
29954        }
29955        return registered;
29956      };
29957      const isSet = name => has$2(values, name);
29958      return {
29959        register,
29960        isRegistered,
29961        get,
29962        set,
29963        unset,
29964        isSet
29965      };
29966    };
29967
29968    const defaultModes = [
29969      'design',
29970      'readonly'
29971    ];
29972    const switchToMode = (editor, activeMode, availableModes, mode) => {
29973      const oldMode = availableModes[activeMode.get()];
29974      const newMode = availableModes[mode];
29975      try {
29976        newMode.activate();
29977      } catch (e) {
29978        console.error(`problem while activating editor mode ${ mode }:`, e);
29979        return;
29980      }
29981      oldMode.deactivate();
29982      if (oldMode.editorReadOnly !== newMode.editorReadOnly) {
29983        toggleReadOnly(editor, newMode.editorReadOnly);
29984      }
29985      activeMode.set(mode);
29986      fireSwitchMode(editor, mode);
29987    };
29988    const setMode = (editor, availableModes, activeMode, mode) => {
29989      if (mode === activeMode.get()) {
29990        return;
29991      } else if (!has$2(availableModes, mode)) {
29992        throw new Error(`Editor mode '${ mode }' is invalid`);
29993      }
29994      if (editor.initialized) {
29995        switchToMode(editor, activeMode, availableModes, mode);
29996      } else {
29997        editor.on('init', () => switchToMode(editor, activeMode, availableModes, mode));
29998      }
29999    };
30000    const registerMode = (availableModes, mode, api) => {
30001      if (contains$2(defaultModes, mode)) {
30002        throw new Error(`Cannot override default mode ${ mode }`);
30003      }
30004      return {
30005        ...availableModes,
30006        [mode]: {
30007          ...api,
30008          deactivate: () => {
30009            try {
30010              api.deactivate();
30011            } catch (e) {
30012              console.error(`problem while deactivating editor mode ${ mode }:`, e);
30013            }
30014          }
30015        }
30016      };
30017    };
30018
30019    const create$4 = editor => {
30020      const activeMode = Cell('design');
30021      const availableModes = Cell({
30022        design: {
30023          activate: noop,
30024          deactivate: noop,
30025          editorReadOnly: false
30026        },
30027        readonly: {
30028          activate: noop,
30029          deactivate: noop,
30030          editorReadOnly: true
30031        }
30032      });
30033      registerReadOnlyContentFilters(editor);
30034      registerReadOnlySelectionBlockers(editor);
30035      return {
30036        isReadOnly: () => isReadOnly(editor),
30037        set: mode => setMode(editor, availableModes.get(), activeMode, mode),
30038        get: () => activeMode.get(),
30039        register: (mode, api) => {
30040          availableModes.set(registerMode(availableModes.get(), mode, api));
30041        }
30042      };
30043    };
30044
30045    const each$2 = Tools.each, explode = Tools.explode;
30046    const keyCodeLookup = {
30047      f1: 112,
30048      f2: 113,
30049      f3: 114,
30050      f4: 115,
30051      f5: 116,
30052      f6: 117,
30053      f7: 118,
30054      f8: 119,
30055      f9: 120,
30056      f10: 121,
30057      f11: 122,
30058      f12: 123
30059    };
30060    const modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access');
30061    const isModifier = key => key in modifierNames;
30062    const parseShortcut = pattern => {
30063      const shortcut = {};
30064      const isMac = Env.os.isMacOS() || Env.os.isiOS();
30065      each$2(explode(pattern.toLowerCase(), '+'), value => {
30066        if (isModifier(value)) {
30067          shortcut[value] = true;
30068        } else {
30069          if (/^[0-9]{2,}$/.test(value)) {
30070            shortcut.keyCode = parseInt(value, 10);
30071          } else {
30072            shortcut.charCode = value.charCodeAt(0);
30073            shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
30074          }
30075        }
30076      });
30077      const id = [shortcut.keyCode];
30078      let key;
30079      for (key in modifierNames) {
30080        if (shortcut[key]) {
30081          id.push(key);
30082        } else {
30083          shortcut[key] = false;
30084        }
30085      }
30086      shortcut.id = id.join(',');
30087      if (shortcut.access) {
30088        shortcut.alt = true;
30089        if (isMac) {
30090          shortcut.ctrl = true;
30091        } else {
30092          shortcut.shift = true;
30093        }
30094      }
30095      if (shortcut.meta) {
30096        if (isMac) {
30097          shortcut.meta = true;
30098        } else {
30099          shortcut.ctrl = true;
30100          shortcut.meta = false;
30101        }
30102      }
30103      return shortcut;
30104    };
30105    class Shortcuts {
30106      constructor(editor) {
30107        this.shortcuts = {};
30108        this.pendingPatterns = [];
30109        this.editor = editor;
30110        const self = this;
30111        editor.on('keyup keypress keydown', e => {
30112          if ((self.hasModifier(e) || self.isFunctionKey(e)) && !e.isDefaultPrevented()) {
30113            each$2(self.shortcuts, shortcut => {
30114              if (self.matchShortcut(e, shortcut)) {
30115                self.pendingPatterns = shortcut.subpatterns.slice(0);
30116                if (e.type === 'keydown') {
30117                  self.executeShortcutAction(shortcut);
30118                }
30119              }
30120            });
30121            if (self.matchShortcut(e, self.pendingPatterns[0])) {
30122              if (self.pendingPatterns.length === 1) {
30123                if (e.type === 'keydown') {
30124                  self.executeShortcutAction(self.pendingPatterns[0]);
30125                }
30126              }
30127              self.pendingPatterns.shift();
30128            }
30129          }
30130        });
30131      }
30132      add(pattern, desc, cmdFunc, scope) {
30133        const self = this;
30134        const func = self.normalizeCommandFunc(cmdFunc);
30135        each$2(explode(Tools.trim(pattern)), pattern => {
30136          const shortcut = self.createShortcut(pattern, desc, func, scope);
30137          self.shortcuts[shortcut.id] = shortcut;
30138        });
30139        return true;
30140      }
30141      remove(pattern) {
30142        const shortcut = this.createShortcut(pattern);
30143        if (this.shortcuts[shortcut.id]) {
30144          delete this.shortcuts[shortcut.id];
30145          return true;
30146        }
30147        return false;
30148      }
30149      normalizeCommandFunc(cmdFunc) {
30150        const self = this;
30151        const cmd = cmdFunc;
30152        if (typeof cmd === 'string') {
30153          return () => {
30154            self.editor.execCommand(cmd, false, null);
30155          };
30156        } else if (Tools.isArray(cmd)) {
30157          return () => {
30158            self.editor.execCommand(cmd[0], cmd[1], cmd[2]);
30159          };
30160        } else {
30161          return cmd;
30162        }
30163      }
30164      createShortcut(pattern, desc, cmdFunc, scope) {
30165        const shortcuts = Tools.map(explode(pattern, '>'), parseShortcut);
30166        shortcuts[shortcuts.length - 1] = Tools.extend(shortcuts[shortcuts.length - 1], {
30167          func: cmdFunc,
30168          scope: scope || this.editor
30169        });
30170        return Tools.extend(shortcuts[0], {
30171          desc: this.editor.translate(desc),
30172          subpatterns: shortcuts.slice(1)
30173        });
30174      }
30175      hasModifier(e) {
30176        return e.altKey || e.ctrlKey || e.metaKey;
30177      }
30178      isFunctionKey(e) {
30179        return e.type === 'keydown' && e.keyCode >= 112 && e.keyCode <= 123;
30180      }
30181      matchShortcut(e, shortcut) {
30182        if (!shortcut) {
30183          return false;
30184        }
30185        if (shortcut.ctrl !== e.ctrlKey || shortcut.meta !== e.metaKey) {
30186          return false;
30187        }
30188        if (shortcut.alt !== e.altKey || shortcut.shift !== e.shiftKey) {
30189          return false;
30190        }
30191        if (e.keyCode === shortcut.keyCode || e.charCode && e.charCode === shortcut.charCode) {
30192          e.preventDefault();
30193          return true;
30194        }
30195        return false;
30196      }
30197      executeShortcutAction(shortcut) {
30198        return shortcut.func ? shortcut.func.call(shortcut.scope) : null;
30199      }
30200    }
30201
30202    const create$3 = () => {
30203      const buttons = {};
30204      const menuItems = {};
30205      const popups = {};
30206      const icons = {};
30207      const contextMenus = {};
30208      const contextToolbars = {};
30209      const sidebars = {};
30210      const views = {};
30211      const add = (collection, type) => (name, spec) => {
30212        collection[name.toLowerCase()] = {
30213          ...spec,
30214          type
30215        };
30216      };
30217      const addIcon = (name, svgData) => icons[name.toLowerCase()] = svgData;
30218      return {
30219        addButton: add(buttons, 'button'),
30220        addGroupToolbarButton: add(buttons, 'grouptoolbarbutton'),
30221        addToggleButton: add(buttons, 'togglebutton'),
30222        addMenuButton: add(buttons, 'menubutton'),
30223        addSplitButton: add(buttons, 'splitbutton'),
30224        addMenuItem: add(menuItems, 'menuitem'),
30225        addNestedMenuItem: add(menuItems, 'nestedmenuitem'),
30226        addToggleMenuItem: add(menuItems, 'togglemenuitem'),
30227        addAutocompleter: add(popups, 'autocompleter'),
30228        addContextMenu: add(contextMenus, 'contextmenu'),
30229        addContextToolbar: add(contextToolbars, 'contexttoolbar'),
30230        addContextForm: add(contextToolbars, 'contextform'),
30231        addSidebar: add(sidebars, 'sidebar'),
30232        addView: add(views, 'views'),
30233        addIcon,
30234        getAll: () => ({
30235          buttons,
30236          menuItems,
30237          icons,
30238          popups,
30239          contextMenus,
30240          contextToolbars,
30241          sidebars,
30242          views
30243        })
30244      };
30245    };
30246
30247    const registry = () => {
30248      const bridge = create$3();
30249      return {
30250        addAutocompleter: bridge.addAutocompleter,
30251        addButton: bridge.addButton,
30252        addContextForm: bridge.addContextForm,
30253        addContextMenu: bridge.addContextMenu,
30254        addContextToolbar: bridge.addContextToolbar,
30255        addIcon: bridge.addIcon,
30256        addMenuButton: bridge.addMenuButton,
30257        addMenuItem: bridge.addMenuItem,
30258        addNestedMenuItem: bridge.addNestedMenuItem,
30259        addSidebar: bridge.addSidebar,
30260        addSplitButton: bridge.addSplitButton,
30261        addToggleButton: bridge.addToggleButton,
30262        addGroupToolbarButton: bridge.addGroupToolbarButton,
30263        addToggleMenuItem: bridge.addToggleMenuItem,
30264        addView: bridge.addView,
30265        getAll: bridge.getAll
30266      };
30267    };
30268
30269    const DOM$1 = DOMUtils.DOM;
30270    const extend = Tools.extend, each$1 = Tools.each;
30271    class Editor {
30272      constructor(id, options, editorManager) {
30273        this.plugins = {};
30274        this.contentCSS = [];
30275        this.contentStyles = [];
30276        this.loadedCSS = {};
30277        this.isNotDirty = false;
30278        this.composing = false;
30279        this.destroyed = false;
30280        this.hasHiddenInput = false;
30281        this.iframeElement = null;
30282        this.initialized = false;
30283        this.readonly = false;
30284        this.removed = false;
30285        this.startContent = '';
30286        this._pendingNativeEvents = [];
30287        this._skinLoaded = false;
30288        this._editableRoot = true;
30289        this.editorManager = editorManager;
30290        this.documentBaseUrl = editorManager.documentBaseURL;
30291        extend(this, EditorObservable);
30292        const self = this;
30293        this.id = id;
30294        this.hidden = false;
30295        const normalizedOptions = normalizeOptions(editorManager.defaultOptions, options);
30296        this.options = create$5(self, normalizedOptions);
30297        register$7(self);
30298        const getOption = this.options.get;
30299        if (getOption('deprecation_warnings')) {
30300          logWarnings(options, normalizedOptions);
30301        }
30302        const suffix = getOption('suffix');
30303        if (suffix) {
30304          editorManager.suffix = suffix;
30305        }
30306        this.suffix = editorManager.suffix;
30307        const baseUrl = getOption('base_url');
30308        if (baseUrl) {
30309          editorManager._setBaseUrl(baseUrl);
30310        }
30311        this.baseUri = editorManager.baseURI;
30312        const referrerPolicy = getReferrerPolicy(self);
30313        if (referrerPolicy) {
30314          ScriptLoader.ScriptLoader._setReferrerPolicy(referrerPolicy);
30315          DOMUtils.DOM.styleSheetLoader._setReferrerPolicy(referrerPolicy);
30316        }
30317        const contentCssCors = hasContentCssCors(self);
30318        if (isNonNullable(contentCssCors)) {
30319          DOMUtils.DOM.styleSheetLoader._setContentCssCors(contentCssCors);
30320        }
30321        AddOnManager.languageLoad = getOption('language_load');
30322        AddOnManager.baseURL = editorManager.baseURL;
30323        this.setDirty(false);
30324        this.documentBaseURI = new URI(getDocumentBaseUrl(self), { base_uri: this.baseUri });
30325        this.baseURI = this.baseUri;
30326        this.inline = isInline(self);
30327        this.hasVisual = isVisualAidsEnabled(self);
30328        this.shortcuts = new Shortcuts(this);
30329        this.editorCommands = new EditorCommands(this);
30330        registerCommands(this);
30331        const cacheSuffix = getOption('cache_suffix');
30332        if (cacheSuffix) {
30333          Env.cacheSuffix = cacheSuffix.replace(/^[\?\&]+/, '');
30334        }
30335        this.ui = {
30336          registry: registry(),
30337          styleSheetLoader: undefined,
30338          show: noop,
30339          hide: noop,
30340          setEnabled: noop,
30341          isEnabled: always
30342        };
30343        this.mode = create$4(self);
30344        editorManager.dispatch('SetupEditor', { editor: this });
30345        const setupCallback = getSetupCallback(self);
30346        if (isFunction(setupCallback)) {
30347          setupCallback.call(self, self);
30348        }
30349      }
30350      render() {
30351        render(this);
30352      }
30353      focus(skipFocus) {
30354        this.execCommand('mceFocus', false, skipFocus);
30355      }
30356      hasFocus() {
30357        return hasFocus(this);
30358      }
30359      translate(text) {
30360        return I18n.translate(text);
30361      }
30362      getParam(name, defaultVal, type) {
30363        const options = this.options;
30364        if (!options.isRegistered(name)) {
30365          if (isNonNullable(type)) {
30366            options.register(name, {
30367              processor: type,
30368              default: defaultVal
30369            });
30370          } else {
30371            options.register(name, {
30372              processor: always,
30373              default: defaultVal
30374            });
30375          }
30376        }
30377        return !options.isSet(name) && !isUndefined(defaultVal) ? defaultVal : options.get(name);
30378      }
30379      hasPlugin(name, loaded) {
30380        const hasPlugin = contains$2(getPlugins(this), name);
30381        if (hasPlugin) {
30382          return loaded ? PluginManager.get(name) !== undefined : true;
30383        } else {
30384          return false;
30385        }
30386      }
30387      nodeChanged(args) {
30388        this._nodeChangeDispatcher.nodeChanged(args);
30389      }
30390      addCommand(name, callback, scope) {
30391        this.editorCommands.addCommand(name, callback, scope);
30392      }
30393      addQueryStateHandler(name, callback, scope) {
30394        this.editorCommands.addQueryStateHandler(name, callback, scope);
30395      }
30396      addQueryValueHandler(name, callback, scope) {
30397        this.editorCommands.addQueryValueHandler(name, callback, scope);
30398      }
30399      addShortcut(pattern, desc, cmdFunc, scope) {
30400        this.shortcuts.add(pattern, desc, cmdFunc, scope);
30401      }
30402      execCommand(cmd, ui, value, args) {
30403        return this.editorCommands.execCommand(cmd, ui, value, args);
30404      }
30405      queryCommandState(cmd) {
30406        return this.editorCommands.queryCommandState(cmd);
30407      }
30408      queryCommandValue(cmd) {
30409        return this.editorCommands.queryCommandValue(cmd);
30410      }
30411      queryCommandSupported(cmd) {
30412        return this.editorCommands.queryCommandSupported(cmd);
30413      }
30414      show() {
30415        const self = this;
30416        if (self.hidden) {
30417          self.hidden = false;
30418          if (self.inline) {
30419            self.getBody().contentEditable = 'true';
30420          } else {
30421            DOM$1.show(self.getContainer());
30422            DOM$1.hide(self.id);
30423          }
30424          self.load();
30425          self.dispatch('show');
30426        }
30427      }
30428      hide() {
30429        const self = this;
30430        if (!self.hidden) {
30431          self.save();
30432          if (self.inline) {
30433            self.getBody().contentEditable = 'false';
30434            if (self === self.editorManager.focusedEditor) {
30435              self.editorManager.focusedEditor = null;
30436            }
30437          } else {
30438            DOM$1.hide(self.getContainer());
30439            DOM$1.setStyle(self.id, 'display', self.orgDisplay);
30440          }
30441          self.hidden = true;
30442          self.dispatch('hide');
30443        }
30444      }
30445      isHidden() {
30446        return this.hidden;
30447      }
30448      setProgressState(state, time) {
30449        this.dispatch('ProgressState', {
30450          state,
30451          time
30452        });
30453      }
30454      load(args = {}) {
30455        const self = this;
30456        const elm = self.getElement();
30457        if (self.removed) {
30458          return '';
30459        }
30460        if (elm) {
30461          const loadArgs = {
30462            ...args,
30463            load: true
30464          };
30465          const value = isTextareaOrInput(elm) ? elm.value : elm.innerHTML;
30466          const html = self.setContent(value, loadArgs);
30467          if (!loadArgs.no_events) {
30468            self.dispatch('LoadContent', {
30469              ...loadArgs,
30470              element: elm
30471            });
30472          }
30473          return html;
30474        } else {
30475          return '';
30476        }
30477      }
30478      save(args = {}) {
30479        const self = this;
30480        let elm = self.getElement();
30481        if (!elm || !self.initialized || self.removed) {
30482          return '';
30483        }
30484        const getArgs = {
30485          ...args,
30486          save: true,
30487          element: elm
30488        };
30489        let html = self.getContent(getArgs);
30490        const saveArgs = {
30491          ...getArgs,
30492          content: html
30493        };
30494        if (!saveArgs.no_events) {
30495          self.dispatch('SaveContent', saveArgs);
30496        }
30497        if (saveArgs.format === 'raw') {
30498          self.dispatch('RawSaveContent', saveArgs);
30499        }
30500        html = saveArgs.content;
30501        if (!isTextareaOrInput(elm)) {
30502          if (args.is_removing || !self.inline) {
30503            elm.innerHTML = html;
30504          }
30505          const form = DOM$1.getParent(self.id, 'form');
30506          if (form) {
30507            each$1(form.elements, elm => {
30508              if (elm.name === self.id) {
30509                elm.value = html;
30510                return false;
30511              } else {
30512                return true;
30513              }
30514            });
30515          }
30516        } else {
30517          elm.value = html;
30518        }
30519        saveArgs.element = getArgs.element = elm = null;
30520        if (saveArgs.set_dirty !== false) {
30521          self.setDirty(false);
30522        }
30523        return html;
30524      }
30525      setContent(content, args) {
30526        return setContent(this, content, args);
30527      }
30528      getContent(args) {
30529        return getContent(this, args);
30530      }
30531      insertContent(content, args) {
30532        if (args) {
30533          content = extend({ content }, args);
30534        }
30535        this.execCommand('mceInsertContent', false, content);
30536      }
30537      resetContent(initialContent) {
30538        if (initialContent === undefined) {
30539          setContent(this, this.startContent, { format: 'raw' });
30540        } else {
30541          setContent(this, initialContent);
30542        }
30543        this.undoManager.reset();
30544        this.setDirty(false);
30545        this.nodeChanged();
30546      }
30547      isDirty() {
30548        return !this.isNotDirty;
30549      }
30550      setDirty(state) {
30551        const oldState = !this.isNotDirty;
30552        this.isNotDirty = !state;
30553        if (state && state !== oldState) {
30554          this.dispatch('dirty');
30555        }
30556      }
30557      getContainer() {
30558        const self = this;
30559        if (!self.container) {
30560          self.container = self.editorContainer || DOM$1.get(self.id + '_parent');
30561        }
30562        return self.container;
30563      }
30564      getContentAreaContainer() {
30565        return this.contentAreaContainer;
30566      }
30567      getElement() {
30568        if (!this.targetElm) {
30569          this.targetElm = DOM$1.get(this.id);
30570        }
30571        return this.targetElm;
30572      }
30573      getWin() {
30574        const self = this;
30575        if (!self.contentWindow) {
30576          const elm = self.iframeElement;
30577          if (elm) {
30578            self.contentWindow = elm.contentWindow;
30579          }
30580        }
30581        return self.contentWindow;
30582      }
30583      getDoc() {
30584        const self = this;
30585        if (!self.contentDocument) {
30586          const win = self.getWin();
30587          if (win) {
30588            self.contentDocument = win.document;
30589          }
30590        }
30591        return self.contentDocument;
30592      }
30593      getBody() {
30594        var _a, _b;
30595        const doc = this.getDoc();
30596        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;
30597      }
30598      convertURL(url, name, elm) {
30599        const self = this, getOption = self.options.get;
30600        const urlConverterCallback = getUrlConverterCallback(self);
30601        if (isFunction(urlConverterCallback)) {
30602          return urlConverterCallback.call(self, url, elm, true, name);
30603        }
30604        if (!getOption('convert_urls') || elm === 'link' || isObject(elm) && elm.nodeName === 'LINK' || url.indexOf('file:') === 0 || url.length === 0) {
30605          return url;
30606        }
30607        if (getOption('relative_urls')) {
30608          return self.documentBaseURI.toRelative(url);
30609        }
30610        url = self.documentBaseURI.toAbsolute(url, getOption('remove_script_host'));
30611        return url;
30612      }
30613      addVisual(elm) {
30614        addVisual(this, elm);
30615      }
30616      setEditableRoot(state) {
30617        setEditableRoot(this, state);
30618      }
30619      hasEditableRoot() {
30620        return hasEditableRoot(this);
30621      }
30622      remove() {
30623        remove$1(this);
30624      }
30625      destroy(automatic) {
30626        destroy(this, automatic);
30627      }
30628      uploadImages() {
30629        return this.editorUpload.uploadImages();
30630      }
30631      _scanForImages() {
30632        return this.editorUpload.scanForImages();
30633      }
30634    }
30635
30636    const DOM = DOMUtils.DOM;
30637    const each = Tools.each;
30638    let boundGlobalEvents = false;
30639    let beforeUnloadDelegate;
30640    let editors = [];
30641    const globalEventDelegate = e => {
30642      const type = e.type;
30643      each(EditorManager.get(), editor => {
30644        switch (type) {
30645        case 'scroll':
30646          editor.dispatch('ScrollWindow', e);
30647          break;
30648        case 'resize':
30649          editor.dispatch('ResizeWindow', e);
30650          break;
30651        }
30652      });
30653    };
30654    const toggleGlobalEvents = state => {
30655      if (state !== boundGlobalEvents) {
30656        const DOM = DOMUtils.DOM;
30657        if (state) {
30658          DOM.bind(window, 'resize', globalEventDelegate);
30659          DOM.bind(window, 'scroll', globalEventDelegate);
30660        } else {
30661          DOM.unbind(window, 'resize', globalEventDelegate);
30662          DOM.unbind(window, 'scroll', globalEventDelegate);
30663        }
30664        boundGlobalEvents = state;
30665      }
30666    };
30667    const removeEditorFromList = targetEditor => {
30668      const oldEditors = editors;
30669      editors = filter$5(editors, editor => {
30670        return targetEditor !== editor;
30671      });
30672      if (EditorManager.activeEditor === targetEditor) {
30673        EditorManager.activeEditor = editors.length > 0 ? editors[0] : null;
30674      }
30675      if (EditorManager.focusedEditor === targetEditor) {
30676        EditorManager.focusedEditor = null;
30677      }
30678      return oldEditors.length !== editors.length;
30679    };
30680    const purgeDestroyedEditor = editor => {
30681      if (editor && editor.initialized && !(editor.getContainer() || editor.getBody()).parentNode) {
30682        removeEditorFromList(editor);
30683        editor.unbindAllNativeEvents();
30684        editor.destroy(true);
30685        editor.removed = true;
30686      }
30687    };
30688    const isQuirksMode = document.compatMode !== 'CSS1Compat';
30689    const EditorManager = {
30690      ...Observable,
30691      baseURI: null,
30692      baseURL: null,
30693      defaultOptions: {},
30694      documentBaseURL: null,
30695      suffix: null,
30696      majorVersion: '6',
30697      minorVersion: '
306976.2',
30698      releaseDate: '2023-08-0
vendor: 18,365 bytes, lines 30698-31305
306989',
30699      i18n: I18n,
30700      activeEditor: null,
30701      focusedEditor: null,
30702      setup() {
30703        const self = this;
30704        let baseURL = '';
30705        let suffix = '';
30706        let documentBaseURL = URI.getDocumentBaseUrl(document.location);
30707        if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) {
30708          documentBaseURL = documentBaseURL.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
30709          if (!/[\/\\]$/.test(documentBaseURL)) {
30710            documentBaseURL += '/';
30711          }
30712        }
30713        const preInit = window.tinymce || window.tinyMCEPreInit;
30714        if (preInit) {
30715          baseURL = preInit.base || preInit.baseURL;
30716          suffix = preInit.suffix;
30717        } else {
30718          const scripts = document.getElementsByTagName('script');
30719          for (let i = 0; i < scripts.length; i++) {
30720            const src = scripts[i].src || '';
30721            if (src === '') {
30722              continue;
30723            }
30724            const srcScript = src.substring(src.lastIndexOf('/'));
30725            if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
30726              if (srcScript.indexOf('.min') !== -1) {
30727                suffix = '.min';
30728              }
30729              baseURL = src.substring(0, src.lastIndexOf('/'));
30730              break;
30731            }
30732          }
30733          if (!baseURL && document.currentScript) {
30734            const src = document.currentScript.src;
30735            if (src.indexOf('.min') !== -1) {
30736              suffix = '.min';
30737            }
30738            baseURL = src.substring(0, src.lastIndexOf('/'));
30739          }
30740        }
30741        self.baseURL = new URI(documentBaseURL).toAbsolute(baseURL);
30742        self.documentBaseURL = documentBaseURL;
30743        self.baseURI = new URI(self.baseURL);
30744        self.suffix = suffix;
30745        setup$v(self);
30746      },
30747      overrideDefaults(defaultOptions) {
30748        const baseUrl = defaultOptions.base_url;
30749        if (baseUrl) {
30750          this._setBaseUrl(baseUrl);
30751        }
30752        const suffix = defaultOptions.suffix;
30753        if (suffix) {
30754          this.suffix = suffix;
30755        }
30756        this.defaultOptions = defaultOptions;
30757        const pluginBaseUrls = defaultOptions.plugin_base_urls;
30758        if (pluginBaseUrls !== undefined) {
30759          each$d(pluginBaseUrls, (pluginBaseUrl, pluginName) => {
30760            AddOnManager.PluginManager.urls[pluginName] = pluginBaseUrl;
30761          });
30762        }
30763      },
30764      init(options) {
30765        const self = this;
30766        let result;
30767        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', ' ');
30768        const isInvalidInlineTarget = (options, elm) => options.inline && elm.tagName.toLowerCase() in invalidInlineTargets;
30769        const createId = elm => {
30770          let id = elm.id;
30771          if (!id) {
30772            id = get$a(elm, 'name').filter(name => !DOM.get(name)).getOrThunk(DOM.uniqueId);
30773            elm.setAttribute('id', id);
30774          }
30775          return id;
30776        };
30777        const execCallback = name => {
30778          const callback = options[name];
30779          if (!callback) {
30780            return;
30781          }
30782          return callback.apply(self, []);
30783        };
30784        const findTargets = options => {
30785          if (Env.browser.isIE() || Env.browser.isEdge()) {
30786            initError('TinyMCE does not support the browser you are using. For a list of supported' + ' browsers please see: https://www.tiny.cloud/docs/tinymce/6/support/#supportedwebbrowsers');
30787            return [];
30788          } else if (isQuirksMode) {
30789            initError('Failed to initialize the editor as the document is not in standards mode. ' + 'TinyMCE requires standards mode.');
30790            return [];
30791          } else if (isString(options.selector)) {
30792            return DOM.select(options.selector);
30793          } else if (isNonNullable(options.target)) {
30794            return [options.target];
30795          } else {
30796            return [];
30797          }
30798        };
30799        let provideResults = editors => {
30800          result = editors;
30801        };
30802        const initEditors = () => {
30803          let initCount = 0;
30804          const editors = [];
30805          let targets;
30806          const createEditor = (id, options, targetElm) => {
30807            const editor = new Editor(id, options, self);
30808            editors.push(editor);
30809            editor.on('init', () => {
30810              if (++initCount === targets.length) {
30811                provideResults(editors);
30812              }
30813            });
30814            editor.targetElm = editor.targetElm || targetElm;
30815            editor.render();
30816          };
30817          DOM.unbind(window, 'ready', initEditors);
30818          execCallback('onpageload');
30819          targets = unique$1(findTargets(options));
30820          Tools.each(targets, elm => {
30821            purgeDestroyedEditor(self.get(elm.id));
30822          });
30823          targets = Tools.grep(targets, elm => {
30824            return !self.get(elm.id);
30825          });
30826          if (targets.length === 0) {
30827            provideResults([]);
30828          } else {
30829            each(targets, elm => {
30830              if (isInvalidInlineTarget(options, elm)) {
30831                initError('Could not initialize inline editor on invalid inline target element', elm);
30832              } else {
30833                createEditor(createId(elm), options, elm);
30834              }
30835            });
30836          }
30837        };
30838        DOM.bind(window, 'ready', initEditors);
30839        return new Promise(resolve => {
30840          if (result) {
30841            resolve(result);
30842          } else {
30843            provideResults = editors => {
30844              resolve(editors);
30845            };
30846          }
30847        });
30848      },
30849      get(id) {
30850        if (arguments.length === 0) {
30851          return editors.slice(0);
30852        } else if (isString(id)) {
30853          return find$2(editors, editor => {
30854            return editor.id === id;
30855          }).getOr(null);
30856        } else if (isNumber(id)) {
30857          return editors[id] ? editors[id] : null;
30858        } else {
30859          return null;
30860        }
30861      },
30862      add(editor) {
30863        const self = this;
30864        const existingEditor = self.get(editor.id);
30865        if (existingEditor === editor) {
30866          return editor;
30867        }
30868        if (existingEditor === null) {
30869          editors.push(editor);
30870        }
30871        toggleGlobalEvents(true);
30872        self.activeEditor = editor;
30873        self.dispatch('AddEditor', { editor });
30874        if (!beforeUnloadDelegate) {
30875          beforeUnloadDelegate = e => {
30876            const event = self.dispatch('BeforeUnload');
30877            if (event.returnValue) {
30878              e.preventDefault();
30879              e.returnValue = event.returnValue;
30880              return event.returnValue;
30881            }
30882          };
30883          window.addEventListener('beforeunload', beforeUnloadDelegate);
30884        }
30885        return editor;
30886      },
30887      createEditor(id, options) {
30888        return this.add(new Editor(id, options, this));
30889      },
30890      remove(selector) {
30891        const self = this;
30892        let editor;
30893        if (!selector) {
30894          for (let i = editors.length - 1; i >= 0; i--) {
30895            self.remove(editors[i]);
30896          }
30897          return;
30898        }
30899        if (isString(selector)) {
30900          each(DOM.select(selector), elm => {
30901            editor = self.get(elm.id);
30902            if (editor) {
30903              self.remove(editor);
30904            }
30905          });
30906          return;
30907        }
30908        editor = selector;
30909        if (isNull(self.get(editor.id))) {
30910          return null;
30911        }
30912        if (removeEditorFromList(editor)) {
30913          self.dispatch('RemoveEditor', { editor });
30914        }
30915        if (editors.length === 0) {
30916          window.removeEventListener('beforeunload', beforeUnloadDelegate);
30917        }
30918        editor.remove();
30919        toggleGlobalEvents(editors.length > 0);
30920        return editor;
30921      },
30922      execCommand(cmd, ui, value) {
30923        var _a;
30924        const self = this;
30925        const editorId = isObject(value) ? (_a = value.id) !== null && _a !== void 0 ? _a : value.index : value;
30926        switch (cmd) {
30927        case 'mceAddEditor': {
30928            if (!self.get(editorId)) {
30929              const editorOptions = value.options;
30930              new Editor(editorId, editorOptions, self).render();
30931            }
30932            return true;
30933          }
30934        case 'mceRemoveEditor': {
30935            const editor = self.get(editorId);
30936            if (editor) {
30937              editor.remove();
30938            }
30939            return true;
30940          }
30941        case 'mceToggleEditor': {
30942            const editor = self.get(editorId);
30943            if (!editor) {
30944              self.execCommand('mceAddEditor', false, value);
30945              return true;
30946            }
30947            if (editor.isHidden()) {
30948              editor.show();
30949            } else {
30950              editor.hide();
30951            }
30952            return true;
30953          }
30954        }
30955        if (self.activeEditor) {
30956          return self.activeEditor.execCommand(cmd, ui, value);
30957        }
30958        return false;
30959      },
30960      triggerSave: () => {
30961        each(editors, editor => {
30962          editor.save();
30963        });
30964      },
30965      addI18n: (code, items) => {
30966        I18n.add(code, items);
30967      },
30968      translate: text => {
30969        return I18n.translate(text);
30970      },
30971      setActive(editor) {
30972        const activeEditor = this.activeEditor;
30973        if (this.activeEditor !== editor) {
30974          if (activeEditor) {
30975            activeEditor.dispatch('deactivate', { relatedTarget: editor });
30976          }
30977          editor.dispatch('activate', { relatedTarget: activeEditor });
30978        }
30979        this.activeEditor = editor;
30980      },
30981      _setBaseUrl(baseUrl) {
30982        this.baseURL = new URI(this.documentBaseURL).toAbsolute(baseUrl.replace(/\/+$/, ''));
30983        this.baseURI = new URI(this.baseURL);
30984      }
30985    };
30986    EditorManager.setup();
30987
30988    const setup = () => {
30989      const dataValue = value$2();
30990      const FakeClipboardItem = items => ({
30991        items,
30992        types: keys(items),
30993        getType: type => get$a(items, type).getOrUndefined()
30994      });
30995      const write = data => {
30996        dataValue.set(data);
30997      };
30998      const read = () => dataValue.get().getOrUndefined();
30999      const clear = dataValue.clear;
31000      return {
31001        FakeClipboardItem,
31002        write,
31003        read,
31004        clear
31005      };
31006    };
31007    const FakeClipboard = setup();
31008
31009    const min = Math.min, max = Math.max, round = Math.round;
31010    const relativePosition = (rect, targetRect, rel) => {
31011      let x = targetRect.x;
31012      let y = targetRect.y;
31013      const w = rect.w;
31014      const h = rect.h;
31015      const targetW = targetRect.w;
31016      const targetH = targetRect.h;
31017      const relChars = (rel || '').split('');
31018      if (relChars[0] === 'b') {
31019        y += targetH;
31020      }
31021      if (relChars[1] === 'r') {
31022        x += targetW;
31023      }
31024      if (relChars[0] === 'c') {
31025        y += round(targetH / 2);
31026      }
31027      if (relChars[1] === 'c') {
31028        x += round(targetW / 2);
31029      }
31030      if (relChars[3] === 'b') {
31031        y -= h;
31032      }
31033      if (relChars[4] === 'r') {
31034        x -= w;
31035      }
31036      if (relChars[3] === 'c') {
31037        y -= round(h / 2);
31038      }
31039      if (relChars[4] === 'c') {
31040        x -= round(w / 2);
31041      }
31042      return create$2(x, y, w, h);
31043    };
31044    const findBestRelativePosition = (rect, targetRect, constrainRect, rels) => {
31045      for (let i = 0; i < rels.length; i++) {
31046        const pos = relativePosition(rect, targetRect, rels[i]);
31047        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) {
31048          return rels[i];
31049        }
31050      }
31051      return null;
31052    };
31053    const inflate = (rect, w, h) => {
31054      return create$2(rect.x - w, rect.y - h, rect.w + w * 2, rect.h + h * 2);
31055    };
31056    const intersect = (rect, cropRect) => {
31057      const x1 = max(rect.x, cropRect.x);
31058      const y1 = max(rect.y, cropRect.y);
31059      const x2 = min(rect.x + rect.w, cropRect.x + cropRect.w);
31060      const y2 = min(rect.y + rect.h, cropRect.y + cropRect.h);
31061      if (x2 - x1 < 0 || y2 - y1 < 0) {
31062        return null;
31063      }
31064      return create$2(x1, y1, x2 - x1, y2 - y1);
31065    };
31066    const clamp = (rect, clampRect, fixedSize) => {
31067      let x1 = rect.x;
31068      let y1 = rect.y;
31069      let x2 = rect.x + rect.w;
31070      let y2 = rect.y + rect.h;
31071      const cx2 = clampRect.x + clampRect.w;
31072      const cy2 = clampRect.y + clampRect.h;
31073      const underflowX1 = max(0, clampRect.x - x1);
31074      const underflowY1 = max(0, clampRect.y - y1);
31075      const overflowX2 = max(0, x2 - cx2);
31076      const overflowY2 = max(0, y2 - cy2);
31077      x1 += underflowX1;
31078      y1 += underflowY1;
31079      if (fixedSize) {
31080        x2 += underflowX1;
31081        y2 += underflowY1;
31082        x1 -= overflowX2;
31083        y1 -= overflowY2;
31084      }
31085      x2 -= overflowX2;
31086      y2 -= overflowY2;
31087      return create$2(x1, y1, x2 - x1, y2 - y1);
31088    };
31089    const create$2 = (x, y, w, h) => {
31090      return {
31091        x,
31092        y,
31093        w,
31094        h
31095      };
31096    };
31097    const fromClientRect = clientRect => {
31098      return create$2(clientRect.left, clientRect.top, clientRect.width, clientRect.height);
31099    };
31100    const Rect = {
31101      inflate,
31102      relativePosition,
31103      findBestRelativePosition,
31104      intersect,
31105      clamp,
31106      create: create$2,
31107      fromClientRect
31108    };
31109
31110    const awaiter = (resolveCb, rejectCb, timeout = 1000) => {
31111      let done = false;
31112      let timer = null;
31113      const complete = completer => (...args) => {
31114        if (!done) {
31115          done = true;
31116          if (timer !== null) {
31117            clearTimeout(timer);
31118            timer = null;
31119          }
31120          completer.apply(null, args);
31121        }
31122      };
31123      const resolve = complete(resolveCb);
31124      const reject = complete(rejectCb);
31125      const start = (...args) => {
31126        if (!done && timer === null) {
31127          timer = setTimeout(() => reject.apply(null, args), timeout);
31128        }
31129      };
31130      return {
31131        start,
31132        resolve,
31133        reject
31134      };
31135    };
31136    const create$1 = () => {
31137      const tasks = {};
31138      const resultFns = {};
31139      const load = (id, url) => {
31140        const loadErrMsg = `Script at URL "${ url }" failed to load`;
31141        const runErrMsg = `Script at URL "${ url }" did not call \`tinymce.Resource.add('${ id }', data)\` within 1 second`;
31142        if (tasks[id] !== undefined) {
31143          return tasks[id];
31144        } else {
31145          const task = new Promise((resolve, reject) => {
31146            const waiter = awaiter(resolve, reject);
31147            resultFns[id] = waiter.resolve;
31148            ScriptLoader.ScriptLoader.loadScript(url).then(() => waiter.start(runErrMsg), () => waiter.reject(loadErrMsg));
31149          });
31150          tasks[id] = task;
31151          return task;
31152        }
31153      };
31154      const add = (id, data) => {
31155        if (resultFns[id] !== undefined) {
31156          resultFns[id](data);
31157          delete resultFns[id];
31158        }
31159        tasks[id] = Promise.resolve(data);
31160      };
31161      const unload = id => {
31162        delete tasks[id];
31163      };
31164      return {
31165        load,
31166        add,
31167        unload
31168      };
31169    };
31170    const Resource = create$1();
31171
31172    const create = () => (() => {
31173      let data = {};
31174      let keys = [];
31175      const storage = {
31176        getItem: key => {
31177          const item = data[key];
31178          return item ? item : null;
31179        },
31180        setItem: (key, value) => {
31181          keys.push(key);
31182          data[key] = String(value);
31183        },
31184        key: index => {
31185          return keys[index];
31186        },
31187        removeItem: key => {
31188          keys = keys.filter(k => k === key);
31189          delete data[key];
31190        },
31191        clear: () => {
31192          keys = [];
31193          data = {};
31194        },
31195        length: 0
31196      };
31197      Object.defineProperty(storage, 'length', {
31198        get: () => keys.length,
31199        configurable: false,
31200        enumerable: false
31201      });
31202      return storage;
31203    })();
31204
31205    let localStorage;
31206    try {
31207      const test = '__storage_test__';
31208      localStorage = window.localStorage;
31209      localStorage.setItem(test, test);
31210      localStorage.removeItem(test);
31211    } catch (e) {
31212      localStorage = create();
31213    }
31214    var LocalStorage = localStorage;
31215
31216    const publicApi = {
31217      geom: { Rect },
31218      util: {
31219        Delay,
31220        Tools,
31221        VK,
31222        URI,
31223        EventDispatcher,
31224        Observable,
31225        I18n,
31226        LocalStorage,
31227        ImageUploader
31228      },
31229      dom: {
31230        EventUtils,
31231        TreeWalker: DomTreeWalker,
31232        TextSeeker,
31233        DOMUtils,
31234        ScriptLoader,
31235        RangeUtils,
31236        Serializer: DomSerializer,
31237        StyleSheetLoader,
31238        ControlSelection,
31239        BookmarkManager,
31240        Selection: EditorSelection,
31241        Event: EventUtils.Event
31242      },
31243      html: {
31244        Styles,
31245        Entities,
31246        Node: AstNode,
31247        Schema,
31248        DomParser,
31249        Writer,
31250        Serializer: HtmlSerializer
31251      },
31252      Env,
31253      AddOnManager,
31254      Annotator,
31255      Formatter,
31256      UndoManager,
31257      EditorCommands,
31258      WindowManager,
31259      NotificationManager,
31260      EditorObservable,
31261      Shortcuts,
31262      Editor,
31263      FocusManager,
31264      EditorManager,
31265      DOM: DOMUtils.DOM,
31266      ScriptLoader: ScriptLoader.ScriptLoader,
31267      PluginManager,
31268      ThemeManager,
31269      ModelManager,
31270      IconManager,
31271      Resource,
31272      FakeClipboard,
31273      trim: Tools.trim,
31274      isArray: Tools.isArray,
31275      is: Tools.is,
31276      toArray: Tools.toArray,
31277      makeMap: Tools.makeMap,
31278      each: Tools.each,
31279      map: Tools.map,
31280      grep: Tools.grep,
31281      inArray: Tools.inArray,
31282      extend: Tools.extend,
31283      walk: Tools.walk,
31284      resolve: Tools.resolve,
31285      explode: Tools.explode,
31286      _addCacheSuffix: Tools._addCacheSuffix
31287    };
31288    const tinymce = Tools.extend(EditorManager, publicApi);
31289
31290    const exportToModuleLoaders = tinymce => {
31291      if (typeof module === 'object') {
31292        try {
31293          module.exports = tinymce;
31294        } catch (_) {
31295        }
31296      }
31297    };
31298    const exportToWindowGlobal = tinymce => {
31299      window.tinymce = tinymce;
31300      window.tinyMCE = tinymce;
31301    };
31302    exportToWindowGlobal(tinymce);
31303    exportToModuleLoaders(tinymce);
31304
31305})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.