Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/**
1441 ariadna 2
 * TinyMCE version 7.7.1 (2025-03-05)
1 efrain 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);
1441 ariadna 427
    const last$2 = xs => get$b(xs, xs.length - 1);
1 efrain 428
    const from = isFunction(Array.from) ? Array.from : x => nativeSlice.call(x);
429
    const findMap = (arr, f) => {
430
      for (let i = 0; i < arr.length; i++) {
431
        const r = f(arr[i], i);
432
        if (r.isSome()) {
433
          return r;
434
        }
435
      }
436
      return Optional.none();
437
    };
438
    const unique$1 = (xs, comparator) => {
439
      const r = [];
440
      const isDuplicated = isFunction(comparator) ? x => exists(r, i => comparator(i, x)) : x => contains$2(r, x);
441
      for (let i = 0, len = xs.length; i < len; i++) {
442
        const x = xs[i];
443
        if (!isDuplicated(x)) {
444
          r.push(x);
445
        }
446
      }
447
      return r;
448
    };
449
 
450
    const keys = Object.keys;
451
    const hasOwnProperty$1 = Object.hasOwnProperty;
452
    const each$d = (obj, f) => {
453
      const props = keys(obj);
454
      for (let k = 0, len = props.length; k < len; k++) {
455
        const i = props[k];
456
        const x = obj[i];
457
        f(x, i);
458
      }
459
    };
460
    const map$2 = (obj, f) => {
461
      return tupleMap(obj, (x, i) => ({
462
        k: i,
463
        v: f(x, i)
464
      }));
465
    };
466
    const tupleMap = (obj, f) => {
467
      const r = {};
468
      each$d(obj, (x, i) => {
469
        const tuple = f(x, i);
470
        r[tuple.k] = tuple.v;
471
      });
472
      return r;
473
    };
474
    const objAcc = r => (x, i) => {
475
      r[i] = x;
476
    };
477
    const internalFilter = (obj, pred, onTrue, onFalse) => {
478
      each$d(obj, (x, i) => {
479
        (pred(x, i) ? onTrue : onFalse)(x, i);
480
      });
481
    };
482
    const bifilter = (obj, pred) => {
483
      const t = {};
484
      const f = {};
485
      internalFilter(obj, pred, objAcc(t), objAcc(f));
486
      return {
487
        t,
488
        f
489
      };
490
    };
491
    const filter$4 = (obj, pred) => {
492
      const t = {};
493
      internalFilter(obj, pred, objAcc(t), noop);
494
      return t;
495
    };
496
    const mapToArray = (obj, f) => {
497
      const r = [];
498
      each$d(obj, (value, name) => {
499
        r.push(f(value, name));
500
      });
501
      return r;
502
    };
503
    const values = obj => {
504
      return mapToArray(obj, identity);
505
    };
506
    const get$a = (obj, key) => {
507
      return has$2(obj, key) ? Optional.from(obj[key]) : Optional.none();
508
    };
509
    const has$2 = (obj, key) => hasOwnProperty$1.call(obj, key);
510
    const hasNonNullableKey = (obj, key) => has$2(obj, key) && obj[key] !== undefined && obj[key] !== null;
511
    const equal$1 = (a1, a2, eq = eqAny) => eqRecord(eq).eq(a1, a2);
512
 
513
    const stringArray = a => {
514
      const all = {};
515
      each$e(a, key => {
516
        all[key] = {};
517
      });
518
      return keys(all);
519
    };
520
 
521
    const isArrayLike = o => o.length !== undefined;
522
    const isArray = Array.isArray;
523
    const toArray$1 = obj => {
524
      if (!isArray(obj)) {
525
        const array = [];
526
        for (let i = 0, l = obj.length; i < l; i++) {
527
          array[i] = obj[i];
528
        }
529
        return array;
530
      } else {
531
        return obj;
532
      }
533
    };
534
    const each$c = (o, cb, s) => {
535
      if (!o) {
536
        return false;
537
      }
538
      s = s || o;
539
      if (isArrayLike(o)) {
540
        for (let n = 0, l = o.length; n < l; n++) {
541
          if (cb.call(s, o[n], n, o) === false) {
542
            return false;
543
          }
544
        }
545
      } else {
546
        for (const n in o) {
547
          if (has$2(o, n)) {
548
            if (cb.call(s, o[n], n, o) === false) {
549
              return false;
550
            }
551
          }
552
        }
553
      }
554
      return true;
555
    };
556
    const map$1 = (array, callback) => {
557
      const out = [];
558
      each$c(array, (item, index) => {
559
        out.push(callback(item, index, array));
560
      });
561
      return out;
562
    };
563
    const filter$3 = (a, f) => {
564
      const o = [];
565
      each$c(a, (v, index) => {
566
        if (!f || f(v, index, a)) {
567
          o.push(v);
568
        }
569
      });
570
      return o;
571
    };
572
    const indexOf = (a, v) => {
573
      if (a) {
574
        for (let i = 0, l = a.length; i < l; i++) {
575
          if (a[i] === v) {
576
            return i;
577
          }
578
        }
579
      }
580
      return -1;
581
    };
582
    const reduce = (collection, iteratee, accumulator, thisArg) => {
583
      let acc = isUndefined(accumulator) ? collection[0] : accumulator;
584
      for (let i = 0; i < collection.length; i++) {
585
        acc = iteratee.call(thisArg, acc, collection[i], i);
586
      }
587
      return acc;
588
    };
589
    const findIndex$1 = (array, predicate, thisArg) => {
590
      for (let i = 0, l = array.length; i < l; i++) {
591
        if (predicate.call(thisArg, array[i], i, array)) {
592
          return i;
593
        }
594
      }
595
      return -1;
596
    };
1441 ariadna 597
    const last$1 = collection => collection[collection.length - 1];
1 efrain 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
    };
1441 ariadna 655
    const detect$4 = (versionRegexes, agent) => {
1 efrain 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,
1441 ariadna 673
      detect: detect$4,
1 efrain 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
 
1441 ariadna 690
    const detect$3 = (candidates, userAgent) => {
1 efrain 691
      const agent = String(userAgent).toLowerCase();
692
      return find$2(candidates, candidate => {
693
        return candidate.search(agent);
694
      });
695
    };
696
    const detectBrowser = (browsers, userAgent) => {
1441 ariadna 697
      return detect$3(browsers, userAgent).map(browser => {
1 efrain 698
        const version = Version.detect(browser.versionRegexes, userAgent);
699
        return {
700
          current: browser.name,
701
          version
702
        };
703
      });
704
    };
705
    const detectOs = (oses, userAgent) => {
1441 ariadna 706
      return detect$3(oses, userAgent).map(os => {
1 efrain 707
        const version = Version.detect(os.versionRegexes, userAgent);
708
        return {
709
          current: os.name,
710
          version
711
        };
712
      });
713
    };
714
 
715
    const removeFromStart = (str, numChars) => {
716
      return str.substring(numChars);
717
    };
718
 
719
    const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
720
    const removeLeading = (str, prefix) => {
721
      return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
722
    };
723
    const contains$1 = (str, substr, start = 0, end) => {
724
      const idx = str.indexOf(substr, start);
725
      if (idx !== -1) {
726
        return isUndefined(end) ? true : idx + substr.length <= end;
727
      } else {
728
        return false;
729
      }
730
    };
731
    const startsWith = (str, prefix) => {
732
      return checkRange(str, prefix, 0);
733
    };
734
    const endsWith = (str, suffix) => {
735
      return checkRange(str, suffix, str.length - suffix.length);
736
    };
737
    const blank = r => s => s.replace(r, '');
738
    const trim$4 = blank(/^\s+|\s+$/g);
739
    const lTrim = blank(/^\s+/g);
740
    const rTrim = blank(/\s+$/g);
741
    const isNotEmpty = s => s.length > 0;
742
    const isEmpty$3 = s => !isNotEmpty(s);
743
    const repeat = (s, count) => count <= 0 ? '' : new Array(count + 1).join(s);
744
    const toInt = (value, radix = 10) => {
745
      const num = parseInt(value, radix);
746
      return isNaN(num) ? Optional.none() : Optional.some(num);
747
    };
748
 
749
    const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
750
    const checkContains = target => {
751
      return uastring => {
752
        return contains$1(uastring, target);
753
      };
754
    };
755
    const browsers = [
756
      {
757
        name: 'Edge',
758
        versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
759
        search: uastring => {
760
          return contains$1(uastring, 'edge/') && contains$1(uastring, 'chrome') && contains$1(uastring, 'safari') && contains$1(uastring, 'applewebkit');
761
        }
762
      },
763
      {
764
        name: 'Chromium',
765
        brand: 'Chromium',
766
        versionRegexes: [
767
          /.*?chrome\/([0-9]+)\.([0-9]+).*/,
768
          normalVersionRegex
769
        ],
770
        search: uastring => {
771
          return contains$1(uastring, 'chrome') && !contains$1(uastring, 'chromeframe');
772
        }
773
      },
774
      {
775
        name: 'IE',
776
        versionRegexes: [
777
          /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
778
          /.*?rv:([0-9]+)\.([0-9]+).*/
779
        ],
780
        search: uastring => {
781
          return contains$1(uastring, 'msie') || contains$1(uastring, 'trident');
782
        }
783
      },
784
      {
785
        name: 'Opera',
786
        versionRegexes: [
787
          normalVersionRegex,
788
          /.*?opera\/([0-9]+)\.([0-9]+).*/
789
        ],
790
        search: checkContains('opera')
791
      },
792
      {
793
        name: 'Firefox',
794
        versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
795
        search: checkContains('firefox')
796
      },
797
      {
798
        name: 'Safari',
799
        versionRegexes: [
800
          normalVersionRegex,
801
          /.*?cpu os ([0-9]+)_([0-9]+).*/
802
        ],
803
        search: uastring => {
804
          return (contains$1(uastring, 'safari') || contains$1(uastring, 'mobile/')) && contains$1(uastring, 'applewebkit');
805
        }
806
      }
807
    ];
808
    const oses = [
809
      {
810
        name: 'Windows',
811
        search: checkContains('win'),
812
        versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
813
      },
814
      {
815
        name: 'iOS',
816
        search: uastring => {
817
          return contains$1(uastring, 'iphone') || contains$1(uastring, 'ipad');
818
        },
819
        versionRegexes: [
820
          /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
821
          /.*cpu os ([0-9]+)_([0-9]+).*/,
822
          /.*cpu iphone os ([0-9]+)_([0-9]+).*/
823
        ]
824
      },
825
      {
826
        name: 'Android',
827
        search: checkContains('android'),
828
        versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
829
      },
830
      {
831
        name: 'macOS',
832
        search: checkContains('mac os x'),
833
        versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
834
      },
835
      {
836
        name: 'Linux',
837
        search: checkContains('linux'),
838
        versionRegexes: []
839
      },
840
      {
841
        name: 'Solaris',
842
        search: checkContains('sunos'),
843
        versionRegexes: []
844
      },
845
      {
846
        name: 'FreeBSD',
847
        search: checkContains('freebsd'),
848
        versionRegexes: []
849
      },
850
      {
851
        name: 'ChromeOS',
852
        search: checkContains('cros'),
853
        versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
854
      }
855
    ];
856
    const PlatformInfo = {
857
      browsers: constant(browsers),
858
      oses: constant(oses)
859
    };
860
 
861
    const edge = 'Edge';
862
    const chromium = 'Chromium';
863
    const ie = 'IE';
864
    const opera = 'Opera';
865
    const firefox = 'Firefox';
866
    const safari = 'Safari';
867
    const unknown$1 = () => {
868
      return nu$2({
869
        current: undefined,
870
        version: Version.unknown()
871
      });
872
    };
873
    const nu$2 = info => {
874
      const current = info.current;
875
      const version = info.version;
876
      const isBrowser = name => () => current === name;
877
      return {
878
        current,
879
        version,
880
        isEdge: isBrowser(edge),
881
        isChromium: isBrowser(chromium),
882
        isIE: isBrowser(ie),
883
        isOpera: isBrowser(opera),
884
        isFirefox: isBrowser(firefox),
885
        isSafari: isBrowser(safari)
886
      };
887
    };
888
    const Browser = {
889
      unknown: unknown$1,
890
      nu: nu$2,
891
      edge: constant(edge),
892
      chromium: constant(chromium),
893
      ie: constant(ie),
894
      opera: constant(opera),
895
      firefox: constant(firefox),
896
      safari: constant(safari)
897
    };
898
 
899
    const windows = 'Windows';
900
    const ios = 'iOS';
901
    const android = 'Android';
902
    const linux = 'Linux';
903
    const macos = 'macOS';
904
    const solaris = 'Solaris';
905
    const freebsd = 'FreeBSD';
906
    const chromeos = 'ChromeOS';
907
    const unknown = () => {
908
      return nu$1({
909
        current: undefined,
910
        version: Version.unknown()
911
      });
912
    };
913
    const nu$1 = info => {
914
      const current = info.current;
915
      const version = info.version;
916
      const isOS = name => () => current === name;
917
      return {
918
        current,
919
        version,
920
        isWindows: isOS(windows),
921
        isiOS: isOS(ios),
922
        isAndroid: isOS(android),
923
        isMacOS: isOS(macos),
924
        isLinux: isOS(linux),
925
        isSolaris: isOS(solaris),
926
        isFreeBSD: isOS(freebsd),
927
        isChromeOS: isOS(chromeos)
928
      };
929
    };
930
    const OperatingSystem = {
931
      unknown,
932
      nu: nu$1,
933
      windows: constant(windows),
934
      ios: constant(ios),
935
      android: constant(android),
936
      linux: constant(linux),
937
      macos: constant(macos),
938
      solaris: constant(solaris),
939
      freebsd: constant(freebsd),
940
      chromeos: constant(chromeos)
941
    };
942
 
1441 ariadna 943
    const detect$2 = (userAgent, userAgentDataOpt, mediaMatch) => {
1 efrain 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
    };
1441 ariadna 955
    const PlatformDetection = { detect: detect$2 };
1 efrain 956
 
957
    const mediaMatch = query => window.matchMedia(query).matches;
1441 ariadna 958
    let platform$4 = cached(() => PlatformDetection.detect(window.navigator.userAgent, Optional.from(window.navigator.userAgentData), mediaMatch));
959
    const detect$1 = () => platform$4();
1 efrain 960
 
1441 ariadna 961
    const userAgent = window.navigator.userAgent;
962
    const platform$3 = detect$1();
1 efrain 963
    const browser$3 = platform$3.browser;
964
    const os$1 = platform$3.os;
965
    const deviceType = platform$3.deviceType;
966
    const windowsPhone = userAgent.indexOf('Windows Phone') !== -1;
967
    const Env = {
968
      transparentSrc: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
969
      documentMode: browser$3.isIE() ? document.documentMode || 7 : 10,
970
      cacheSuffix: null,
971
      container: null,
972
      canHaveCSP: !browser$3.isIE(),
973
      windowsPhone,
974
      browser: {
975
        current: browser$3.current,
976
        version: browser$3.version,
977
        isChromium: browser$3.isChromium,
978
        isEdge: browser$3.isEdge,
979
        isFirefox: browser$3.isFirefox,
980
        isIE: browser$3.isIE,
981
        isOpera: browser$3.isOpera,
982
        isSafari: browser$3.isSafari
983
      },
984
      os: {
985
        current: os$1.current,
986
        version: os$1.version,
987
        isAndroid: os$1.isAndroid,
988
        isChromeOS: os$1.isChromeOS,
989
        isFreeBSD: os$1.isFreeBSD,
990
        isiOS: os$1.isiOS,
991
        isLinux: os$1.isLinux,
992
        isMacOS: os$1.isMacOS,
993
        isSolaris: os$1.isSolaris,
994
        isWindows: os$1.isWindows
995
      },
996
      deviceType: {
997
        isDesktop: deviceType.isDesktop,
998
        isiPad: deviceType.isiPad,
999
        isiPhone: deviceType.isiPhone,
1000
        isPhone: deviceType.isPhone,
1001
        isTablet: deviceType.isTablet,
1002
        isTouch: deviceType.isTouch,
1003
        isWebView: deviceType.isWebView
1004
      }
1005
    };
1006
 
1007
    const whiteSpaceRegExp$1 = /^\s*|\s*$/g;
1008
    const trim$3 = str => {
1009
      return isNullable(str) ? '' : ('' + str).replace(whiteSpaceRegExp$1, '');
1010
    };
1011
    const is$3 = (obj, type) => {
1012
      if (!type) {
1013
        return obj !== undefined;
1014
      }
1015
      if (type === 'array' && isArray(obj)) {
1016
        return true;
1017
      }
1018
      return typeof obj === type;
1019
    };
1020
    const makeMap$4 = (items, delim, map = {}) => {
1021
      const resolvedItems = isString(items) ? items.split(delim || ',') : items || [];
1022
      let i = resolvedItems.length;
1023
      while (i--) {
1024
        map[resolvedItems[i]] = {};
1025
      }
1026
      return map;
1027
    };
1028
    const hasOwnProperty = has$2;
1029
    const extend$3 = (obj, ...exts) => {
1030
      for (let i = 0; i < exts.length; i++) {
1031
        const ext = exts[i];
1032
        for (const name in ext) {
1033
          if (has$2(ext, name)) {
1034
            const value = ext[name];
1035
            if (value !== undefined) {
1036
              obj[name] = value;
1037
            }
1038
          }
1039
        }
1040
      }
1041
      return obj;
1042
    };
1043
    const walk$4 = function (o, f, n, s) {
1044
      s = s || this;
1045
      if (o) {
1046
        if (n) {
1047
          o = o[n];
1048
        }
1049
        each$c(o, (o, i) => {
1050
          if (f.call(s, o, i, n) === false) {
1051
            return false;
1052
          } else {
1053
            walk$4(o, f, n, s);
1054
            return true;
1055
          }
1056
        });
1057
      }
1058
    };
1059
    const resolve$3 = (n, o = window) => {
1060
      const path = n.split('.');
1061
      for (let i = 0, l = path.length; i < l; i++) {
1062
        o = o[path[i]];
1063
        if (!o) {
1064
          break;
1065
        }
1066
      }
1067
      return o;
1068
    };
1069
    const explode$3 = (s, d) => {
1070
      if (isArray$1(s)) {
1071
        return s;
1072
      } else if (s === '') {
1073
        return [];
1074
      } else {
1075
        return map$1(s.split(d || ','), trim$3);
1076
      }
1077
    };
1078
    const _addCacheSuffix = url => {
1079
      const cacheSuffix = Env.cacheSuffix;
1080
      if (cacheSuffix) {
1081
        url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix;
1082
      }
1083
      return url;
1084
    };
1085
    const Tools = {
1086
      trim: trim$3,
1087
      isArray: isArray,
1088
      is: is$3,
1089
      toArray: toArray$1,
1090
      makeMap: makeMap$4,
1091
      each: each$c,
1092
      map: map$1,
1093
      grep: filter$3,
1094
      inArray: indexOf,
1095
      hasOwn: hasOwnProperty,
1096
      extend: extend$3,
1097
      walk: walk$4,
1098
      resolve: resolve$3,
1099
      explode: explode$3,
1100
      _addCacheSuffix
1101
    };
1102
 
1103
    const is$2 = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
1104
    const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
1105
    const cat = arr => {
1106
      const r = [];
1107
      const push = x => {
1108
        r.push(x);
1109
      };
1110
      for (let i = 0; i < arr.length; i++) {
1111
        arr[i].each(push);
1112
      }
1113
      return r;
1114
    };
1115
    const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
1116
    const lift3 = (oa, ob, oc, f) => oa.isSome() && ob.isSome() && oc.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Optional.none();
1117
    const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
1118
 
1119
    const Global = typeof window !== 'undefined' ? window : Function('return this;')();
1120
 
1121
    const path = (parts, scope) => {
1122
      let o = scope !== undefined && scope !== null ? scope : Global;
1123
      for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) {
1124
        o = o[parts[i]];
1125
      }
1126
      return o;
1127
    };
1128
    const resolve$2 = (p, scope) => {
1129
      const parts = p.split('.');
1130
      return path(parts, scope);
1131
    };
1132
 
1133
    const unsafe = (name, scope) => {
1134
      return resolve$2(name, scope);
1135
    };
1136
    const getOrDie = (name, scope) => {
1137
      const actual = unsafe(name, scope);
1138
      if (actual === undefined || actual === null) {
1139
        throw new Error(name + ' not available on this browser');
1140
      }
1141
      return actual;
1142
    };
1143
 
1144
    const getPrototypeOf$1 = Object.getPrototypeOf;
1145
    const sandHTMLElement = scope => {
1146
      return getOrDie('HTMLElement', scope);
1147
    };
1148
    const isPrototypeOf = x => {
1149
      const scope = resolve$2('ownerDocument.defaultView', x);
1150
      return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf$1(x).constructor.name));
1151
    };
1152
 
1153
    const COMMENT = 8;
1154
    const DOCUMENT = 9;
1155
    const DOCUMENT_FRAGMENT = 11;
1156
    const ELEMENT = 1;
1157
    const TEXT = 3;
1158
 
1159
    const name = element => {
1160
      const r = element.dom.nodeName;
1161
      return r.toLowerCase();
1162
    };
1163
    const type$1 = element => element.dom.nodeType;
1164
    const isType = t => element => type$1(element) === t;
1165
    const isComment$1 = element => type$1(element) === COMMENT || name(element) === '#comment';
1166
    const isHTMLElement$1 = element => isElement$7(element) && isPrototypeOf(element.dom);
1167
    const isElement$7 = isType(ELEMENT);
1441 ariadna 1168
    const isText$c = isType(TEXT);
1 efrain 1169
    const isDocument$2 = isType(DOCUMENT);
1170
    const isDocumentFragment$1 = isType(DOCUMENT_FRAGMENT);
1171
    const isTag = tag => e => isElement$7(e) && name(e) === tag;
1172
 
1173
    const rawSet = (dom, key, value) => {
1174
      if (isString(value) || isBoolean(value) || isNumber(value)) {
1175
        dom.setAttribute(key, value + '');
1176
      } else {
1177
        console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
1178
        throw new Error('Attribute value was not simple');
1179
      }
1180
    };
1441 ariadna 1181
    const set$4 = (element, key, value) => {
1 efrain 1182
      rawSet(element.dom, key, value);
1183
    };
1184
    const setAll$1 = (element, attrs) => {
1185
      const dom = element.dom;
1186
      each$d(attrs, (v, k) => {
1187
        rawSet(dom, k, v);
1188
      });
1189
    };
1190
    const get$9 = (element, key) => {
1191
      const v = element.dom.getAttribute(key);
1192
      return v === null ? undefined : v;
1193
    };
1194
    const getOpt = (element, key) => Optional.from(get$9(element, key));
1195
    const has$1 = (element, key) => {
1196
      const dom = element.dom;
1197
      return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
1198
    };
1441 ariadna 1199
    const remove$9 = (element, key) => {
1 efrain 1200
      element.dom.removeAttribute(key);
1201
    };
1202
    const hasNone = element => {
1203
      const attrs = element.dom.attributes;
1204
      return attrs === undefined || attrs === null || attrs.length === 0;
1205
    };
1206
    const clone$4 = element => foldl(element.dom.attributes, (acc, attr) => {
1207
      acc[attr.name] = attr.value;
1208
      return acc;
1209
    }, {});
1210
 
1211
    const read$4 = (element, attr) => {
1212
      const value = get$9(element, attr);
1213
      return value === undefined || value === '' ? [] : value.split(' ');
1214
    };
1215
    const add$4 = (element, attr, id) => {
1216
      const old = read$4(element, attr);
1217
      const nu = old.concat([id]);
1441 ariadna 1218
      set$4(element, attr, nu.join(' '));
1 efrain 1219
      return true;
1220
    };
1441 ariadna 1221
    const remove$8 = (element, attr, id) => {
1 efrain 1222
      const nu = filter$5(read$4(element, attr), v => v !== id);
1223
      if (nu.length > 0) {
1441 ariadna 1224
        set$4(element, attr, nu.join(' '));
1 efrain 1225
      } else {
1441 ariadna 1226
        remove$9(element, attr);
1 efrain 1227
      }
1228
      return false;
1229
    };
1230
 
1231
    const supports = element => element.dom.classList !== undefined;
1232
    const get$8 = element => read$4(element, 'class');
1233
    const add$3 = (element, clazz) => add$4(element, 'class', clazz);
1441 ariadna 1234
    const remove$7 = (element, clazz) => remove$8(element, 'class', clazz);
1 efrain 1235
    const toggle$2 = (element, clazz) => {
1236
      if (contains$2(get$8(element), clazz)) {
1441 ariadna 1237
        return remove$7(element, clazz);
1 efrain 1238
      } else {
1239
        return add$3(element, clazz);
1240
      }
1241
    };
1242
 
1243
    const add$2 = (element, clazz) => {
1244
      if (supports(element)) {
1245
        element.dom.classList.add(clazz);
1246
      } else {
1247
        add$3(element, clazz);
1248
      }
1249
    };
1250
    const cleanClass = element => {
1251
      const classList = supports(element) ? element.dom.classList : get$8(element);
1252
      if (classList.length === 0) {
1441 ariadna 1253
        remove$9(element, 'class');
1 efrain 1254
      }
1255
    };
1441 ariadna 1256
    const remove$6 = (element, clazz) => {
1 efrain 1257
      if (supports(element)) {
1258
        const classList = element.dom.classList;
1259
        classList.remove(clazz);
1260
      } else {
1441 ariadna 1261
        remove$7(element, clazz);
1 efrain 1262
      }
1263
      cleanClass(element);
1264
    };
1265
    const toggle$1 = (element, clazz) => {
1266
      const result = supports(element) ? element.dom.classList.toggle(clazz) : toggle$2(element, clazz);
1267
      cleanClass(element);
1268
      return result;
1269
    };
1270
    const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz);
1271
 
1272
    const fromHtml$1 = (html, scope) => {
1273
      const doc = scope || document;
1274
      const div = doc.createElement('div');
1275
      div.innerHTML = html;
1276
      if (!div.hasChildNodes() || div.childNodes.length > 1) {
1277
        const message = 'HTML does not have a single root node';
1278
        console.error(message, html);
1279
        throw new Error(message);
1280
      }
1281
      return fromDom$2(div.childNodes[0]);
1282
    };
1283
    const fromTag = (tag, scope) => {
1284
      const doc = scope || document;
1285
      const node = doc.createElement(tag);
1286
      return fromDom$2(node);
1287
    };
1288
    const fromText = (text, scope) => {
1289
      const doc = scope || document;
1290
      const node = doc.createTextNode(text);
1291
      return fromDom$2(node);
1292
    };
1293
    const fromDom$2 = node => {
1294
      if (node === null || node === undefined) {
1295
        throw new Error('Node cannot be null or undefined');
1296
      }
1297
      return { dom: node };
1298
    };
1299
    const fromPoint$2 = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$2);
1300
    const SugarElement = {
1301
      fromHtml: fromHtml$1,
1302
      fromTag,
1303
      fromText,
1304
      fromDom: fromDom$2,
1305
      fromPoint: fromPoint$2
1306
    };
1307
 
1308
    const toArray = (target, f) => {
1309
      const r = [];
1310
      const recurse = e => {
1311
        r.push(e);
1312
        return f(e);
1313
      };
1314
      let cur = f(target);
1315
      do {
1316
        cur = cur.bind(recurse);
1317
      } while (cur.isSome());
1318
      return r;
1319
    };
1320
 
1321
    const is$1 = (element, selector) => {
1322
      const dom = element.dom;
1323
      if (dom.nodeType !== ELEMENT) {
1324
        return false;
1325
      } else {
1326
        const elem = dom;
1327
        if (elem.matches !== undefined) {
1328
          return elem.matches(selector);
1329
        } else if (elem.msMatchesSelector !== undefined) {
1330
          return elem.msMatchesSelector(selector);
1331
        } else if (elem.webkitMatchesSelector !== undefined) {
1332
          return elem.webkitMatchesSelector(selector);
1333
        } else if (elem.mozMatchesSelector !== undefined) {
1334
          return elem.mozMatchesSelector(selector);
1335
        } else {
1336
          throw new Error('Browser lacks native selectors');
1337
        }
1338
      }
1339
    };
1340
    const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
1341
    const all = (selector, scope) => {
1342
      const base = scope === undefined ? document : scope.dom;
1343
      return bypassSelector(base) ? [] : map$3(base.querySelectorAll(selector), SugarElement.fromDom);
1344
    };
1345
    const one = (selector, scope) => {
1346
      const base = scope === undefined ? document : scope.dom;
1347
      return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
1348
    };
1349
 
1350
    const eq = (e1, e2) => e1.dom === e2.dom;
1351
    const contains = (e1, e2) => {
1352
      const d1 = e1.dom;
1353
      const d2 = e2.dom;
1354
      return d1 === d2 ? false : d1.contains(d2);
1355
    };
1356
 
1357
    const owner$1 = element => SugarElement.fromDom(element.dom.ownerDocument);
1358
    const documentOrOwner = dos => isDocument$2(dos) ? dos : owner$1(dos);
1359
    const documentElement = element => SugarElement.fromDom(documentOrOwner(element).dom.documentElement);
1360
    const defaultView = element => SugarElement.fromDom(documentOrOwner(element).dom.defaultView);
1361
    const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
1362
    const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
1363
    const parents$1 = (element, isRoot) => {
1364
      const stop = isFunction(isRoot) ? isRoot : never;
1365
      let dom = element.dom;
1366
      const ret = [];
1367
      while (dom.parentNode !== null && dom.parentNode !== undefined) {
1368
        const rawParent = dom.parentNode;
1369
        const p = SugarElement.fromDom(rawParent);
1370
        ret.push(p);
1371
        if (stop(p) === true) {
1372
          break;
1373
        } else {
1374
          dom = rawParent;
1375
        }
1376
      }
1377
      return ret;
1378
    };
1379
    const siblings = element => {
1380
      const filterSelf = elements => filter$5(elements, x => !eq(element, x));
1381
      return parent(element).map(children$1).map(filterSelf).getOr([]);
1382
    };
1383
    const prevSibling = element => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom);
1384
    const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
1385
    const prevSiblings = element => reverse(toArray(element, prevSibling));
1386
    const nextSiblings = element => toArray(element, nextSibling);
1387
    const children$1 = element => map$3(element.dom.childNodes, SugarElement.fromDom);
1388
    const child$1 = (element, index) => {
1389
      const cs = element.dom.childNodes;
1390
      return Optional.from(cs[index]).map(SugarElement.fromDom);
1391
    };
1392
    const firstChild = element => child$1(element, 0);
1393
    const lastChild = element => child$1(element, element.dom.childNodes.length - 1);
1394
    const childNodesCount = element => element.dom.childNodes.length;
1395
 
1396
    const getHead = doc => {
1397
      const b = doc.dom.head;
1398
      if (b === null || b === undefined) {
1399
        throw new Error('Head is not available yet');
1400
      }
1401
      return SugarElement.fromDom(b);
1402
    };
1403
 
1404
    const isShadowRoot = dos => isDocumentFragment$1(dos) && isNonNullable(dos.dom.host);
1441 ariadna 1405
    const getRootNode = e => SugarElement.fromDom(e.dom.getRootNode());
1 efrain 1406
    const getStyleContainer = dos => isShadowRoot(dos) ? dos : getHead(documentOrOwner(dos));
1407
    const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
1408
    const getShadowRoot = e => {
1409
      const r = getRootNode(e);
1410
      return isShadowRoot(r) ? Optional.some(r) : Optional.none();
1411
    };
1412
    const getShadowHost = e => SugarElement.fromDom(e.dom.host);
1413
    const getOriginalEventTarget = event => {
1441 ariadna 1414
      if (isNonNullable(event.target)) {
1 efrain 1415
        const el = SugarElement.fromDom(event.target);
1416
        if (isElement$7(el) && isOpenShadowHost(el)) {
1417
          if (event.composed && event.composedPath) {
1418
            const composedPath = event.composedPath();
1419
            if (composedPath) {
1420
              return head(composedPath);
1421
            }
1422
          }
1423
        }
1424
      }
1425
      return Optional.from(event.target);
1426
    };
1427
    const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot);
1428
 
1429
    const inBody = element => {
1441 ariadna 1430
      const dom = isText$c(element) ? element.dom.parentNode : element.dom;
1 efrain 1431
      if (dom === undefined || dom === null || dom.ownerDocument === null) {
1432
        return false;
1433
      }
1434
      const doc = dom.ownerDocument;
1435
      return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
1436
    };
1437
 
1438
    var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
1439
      if (is(scope, a)) {
1440
        return Optional.some(scope);
1441
      } else if (isFunction(isRoot) && isRoot(scope)) {
1442
        return Optional.none();
1443
      } else {
1444
        return ancestor(scope, a, isRoot);
1445
      }
1446
    };
1447
 
1448
    const ancestor$4 = (scope, predicate, isRoot) => {
1449
      let element = scope.dom;
1450
      const stop = isFunction(isRoot) ? isRoot : never;
1451
      while (element.parentNode) {
1452
        element = element.parentNode;
1453
        const el = SugarElement.fromDom(element);
1454
        if (predicate(el)) {
1455
          return Optional.some(el);
1456
        } else if (stop(el)) {
1457
          break;
1458
        }
1459
      }
1460
      return Optional.none();
1461
    };
1462
    const closest$4 = (scope, predicate, isRoot) => {
1463
      const is = (s, test) => test(s);
1464
      return ClosestOrAncestor(is, ancestor$4, scope, predicate, isRoot);
1465
    };
1466
    const sibling$1 = (scope, predicate) => {
1467
      const element = scope.dom;
1468
      if (!element.parentNode) {
1469
        return Optional.none();
1470
      }
1471
      return child(SugarElement.fromDom(element.parentNode), x => !eq(scope, x) && predicate(x));
1472
    };
1473
    const child = (scope, predicate) => {
1474
      const pred = node => predicate(SugarElement.fromDom(node));
1475
      const result = find$2(scope.dom.childNodes, pred);
1476
      return result.map(SugarElement.fromDom);
1477
    };
1478
    const descendant$2 = (scope, predicate) => {
1479
      const descend = node => {
1480
        for (let i = 0; i < node.childNodes.length; i++) {
1481
          const child = SugarElement.fromDom(node.childNodes[i]);
1482
          if (predicate(child)) {
1483
            return Optional.some(child);
1484
          }
1485
          const res = descend(node.childNodes[i]);
1486
          if (res.isSome()) {
1487
            return res;
1488
          }
1489
        }
1490
        return Optional.none();
1491
      };
1492
      return descend(scope.dom);
1493
    };
1494
 
1495
    const ancestor$3 = (scope, selector, isRoot) => ancestor$4(scope, e => is$1(e, selector), isRoot);
1496
    const descendant$1 = (scope, selector) => one(selector, scope);
1497
    const closest$3 = (scope, selector, isRoot) => {
1498
      const is = (element, selector) => is$1(element, selector);
1499
      return ClosestOrAncestor(is, ancestor$3, scope, selector, isRoot);
1500
    };
1501
 
1502
    const closest$2 = target => closest$3(target, '[contenteditable]');
1503
    const isEditable$2 = (element, assumeEditable = false) => {
1504
      if (inBody(element)) {
1505
        return element.dom.isContentEditable;
1506
      } else {
1507
        return closest$2(element).fold(constant(assumeEditable), editable => getRaw$1(editable) === 'true');
1508
      }
1509
    };
1510
    const getRaw$1 = element => element.dom.contentEditable;
1441 ariadna 1511
    const set$3 = (element, editable) => {
1512
      element.dom.contentEditable = editable ? 'true' : 'false';
1513
    };
1 efrain 1514
 
1515
    const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
1516
 
1517
    const internalSet = (dom, property, value) => {
1518
      if (!isString(value)) {
1519
        console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
1520
        throw new Error('CSS value must be a string: ' + value);
1521
      }
1522
      if (isSupported(dom)) {
1523
        dom.style.setProperty(property, value);
1524
      }
1525
    };
1526
    const internalRemove = (dom, property) => {
1527
      if (isSupported(dom)) {
1528
        dom.style.removeProperty(property);
1529
      }
1530
    };
1531
    const set$2 = (element, property, value) => {
1532
      const dom = element.dom;
1533
      internalSet(dom, property, value);
1534
    };
1535
    const setAll = (element, css) => {
1536
      const dom = element.dom;
1537
      each$d(css, (v, k) => {
1538
        internalSet(dom, k, v);
1539
      });
1540
    };
1541
    const get$7 = (element, property) => {
1542
      const dom = element.dom;
1543
      const styles = window.getComputedStyle(dom);
1544
      const r = styles.getPropertyValue(property);
1545
      return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
1546
    };
1547
    const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : '';
1548
    const getRaw = (element, property) => {
1549
      const dom = element.dom;
1550
      const raw = getUnsafeProperty(dom, property);
1551
      return Optional.from(raw).filter(r => r.length > 0);
1552
    };
1553
    const getAllRaw = element => {
1554
      const css = {};
1555
      const dom = element.dom;
1556
      if (isSupported(dom)) {
1557
        for (let i = 0; i < dom.style.length; i++) {
1558
          const ruleName = dom.style.item(i);
1559
          css[ruleName] = dom.style[ruleName];
1560
        }
1561
      }
1562
      return css;
1563
    };
1441 ariadna 1564
    const remove$5 = (element, property) => {
1 efrain 1565
      const dom = element.dom;
1566
      internalRemove(dom, property);
1567
      if (is$2(getOpt(element, 'style').map(trim$4), '')) {
1441 ariadna 1568
        remove$9(element, 'style');
1 efrain 1569
      }
1570
    };
1571
    const reflow = e => e.dom.offsetWidth;
1572
 
1573
    const before$3 = (marker, element) => {
1574
      const parent$1 = parent(marker);
1575
      parent$1.each(v => {
1576
        v.dom.insertBefore(element.dom, marker.dom);
1577
      });
1578
    };
1579
    const after$4 = (marker, element) => {
1580
      const sibling = nextSibling(marker);
1581
      sibling.fold(() => {
1582
        const parent$1 = parent(marker);
1583
        parent$1.each(v => {
1584
          append$1(v, element);
1585
        });
1586
      }, v => {
1587
        before$3(v, element);
1588
      });
1589
    };
1590
    const prepend = (parent, element) => {
1591
      const firstChild$1 = firstChild(parent);
1592
      firstChild$1.fold(() => {
1593
        append$1(parent, element);
1594
      }, v => {
1595
        parent.dom.insertBefore(element.dom, v.dom);
1596
      });
1597
    };
1598
    const append$1 = (parent, element) => {
1599
      parent.dom.appendChild(element.dom);
1600
    };
1601
    const wrap$2 = (element, wrapper) => {
1602
      before$3(element, wrapper);
1603
      append$1(wrapper, element);
1604
    };
1605
 
1606
    const after$3 = (marker, elements) => {
1607
      each$e(elements, (x, i) => {
1608
        const e = i === 0 ? marker : elements[i - 1];
1609
        after$4(e, x);
1610
      });
1611
    };
1612
    const append = (parent, elements) => {
1613
      each$e(elements, x => {
1614
        append$1(parent, x);
1615
      });
1616
    };
1617
 
1618
    const empty = element => {
1619
      element.dom.textContent = '';
1620
      each$e(children$1(element), rogue => {
1441 ariadna 1621
        remove$4(rogue);
1 efrain 1622
      });
1623
    };
1441 ariadna 1624
    const remove$4 = element => {
1 efrain 1625
      const dom = element.dom;
1626
      if (dom.parentNode !== null) {
1627
        dom.parentNode.removeChild(dom);
1628
      }
1629
    };
1630
    const unwrap = wrapper => {
1631
      const children = children$1(wrapper);
1632
      if (children.length > 0) {
1633
        after$3(wrapper, children);
1634
      }
1441 ariadna 1635
      remove$4(wrapper);
1 efrain 1636
    };
1637
 
1638
    const fromHtml = (html, scope) => {
1639
      const doc = scope || document;
1640
      const div = doc.createElement('div');
1641
      div.innerHTML = html;
1642
      return children$1(SugarElement.fromDom(div));
1643
    };
1644
    const fromDom$1 = nodes => map$3(nodes, SugarElement.fromDom);
1645
 
1646
    const get$6 = element => element.dom.innerHTML;
1647
    const set$1 = (element, content) => {
1648
      const owner = owner$1(element);
1649
      const docDom = owner.dom;
1650
      const fragment = SugarElement.fromDom(docDom.createDocumentFragment());
1651
      const contentElements = fromHtml(content, docDom);
1652
      append(fragment, contentElements);
1653
      empty(element);
1654
      append$1(element, fragment);
1655
    };
1656
    const getOuter = element => {
1657
      const container = SugarElement.fromTag('div');
1658
      const clone = SugarElement.fromDom(element.dom.cloneNode(true));
1659
      append$1(container, clone);
1660
      return get$6(container);
1661
    };
1662
 
1663
    const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({
1664
      target,
1665
      x,
1666
      y,
1667
      stop,
1668
      prevent,
1669
      kill,
1670
      raw
1671
    });
1672
    const fromRawEvent = rawEvent => {
1673
      const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
1674
      const stop = () => rawEvent.stopPropagation();
1675
      const prevent = () => rawEvent.preventDefault();
1676
      const kill = compose(prevent, stop);
1677
      return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent);
1678
    };
1679
    const handle$1 = (filter, handler) => rawEvent => {
1680
      if (filter(rawEvent)) {
1681
        handler(fromRawEvent(rawEvent));
1682
      }
1683
    };
1684
    const binder = (element, event, filter, handler, useCapture) => {
1685
      const wrapped = handle$1(filter, handler);
1686
      element.dom.addEventListener(event, wrapped, useCapture);
1687
      return { unbind: curry(unbind, element, event, wrapped, useCapture) };
1688
    };
1689
    const bind$2 = (element, event, filter, handler) => binder(element, event, filter, handler, false);
1690
    const unbind = (element, event, handler, useCapture) => {
1691
      element.dom.removeEventListener(event, handler, useCapture);
1692
    };
1693
 
1694
    const r = (left, top) => {
1695
      const translate = (x, y) => r(left + x, top + y);
1696
      return {
1697
        left,
1698
        top,
1699
        translate
1700
      };
1701
    };
1702
    const SugarPosition = r;
1703
 
1704
    const boxPosition = dom => {
1705
      const box = dom.getBoundingClientRect();
1706
      return SugarPosition(box.left, box.top);
1707
    };
1708
    const firstDefinedOrZero = (a, b) => {
1709
      if (a !== undefined) {
1710
        return a;
1711
      } else {
1712
        return b !== undefined ? b : 0;
1713
      }
1714
    };
1715
    const absolute = element => {
1716
      const doc = element.dom.ownerDocument;
1717
      const body = doc.body;
1718
      const win = doc.defaultView;
1719
      const html = doc.documentElement;
1720
      if (body === element.dom) {
1721
        return SugarPosition(body.offsetLeft, body.offsetTop);
1722
      }
1723
      const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html.scrollTop);
1724
      const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html.scrollLeft);
1725
      const clientTop = firstDefinedOrZero(html.clientTop, body.clientTop);
1726
      const clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft);
1727
      return viewport(element).translate(scrollLeft - clientLeft, scrollTop - clientTop);
1728
    };
1729
    const viewport = element => {
1730
      const dom = element.dom;
1731
      const doc = dom.ownerDocument;
1732
      const body = doc.body;
1733
      if (body === dom) {
1734
        return SugarPosition(body.offsetLeft, body.offsetTop);
1735
      }
1736
      if (!inBody(element)) {
1737
        return SugarPosition(0, 0);
1738
      }
1739
      return boxPosition(dom);
1740
    };
1741
 
1742
    const get$5 = _DOC => {
1743
      const doc = _DOC !== undefined ? _DOC.dom : document;
1744
      const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
1745
      const y = doc.body.scrollTop || doc.documentElement.scrollTop;
1746
      return SugarPosition(x, y);
1747
    };
1748
    const to = (x, y, _DOC) => {
1749
      const doc = _DOC !== undefined ? _DOC.dom : document;
1750
      const win = doc.defaultView;
1751
      if (win) {
1752
        win.scrollTo(x, y);
1753
      }
1754
    };
1755
    const intoView = (element, alignToTop) => {
1441 ariadna 1756
      const isSafari = detect$1().browser.isSafari();
1 efrain 1757
      if (isSafari && isFunction(element.dom.scrollIntoViewIfNeeded)) {
1758
        element.dom.scrollIntoViewIfNeeded(false);
1759
      } else {
1760
        element.dom.scrollIntoView(alignToTop);
1761
      }
1762
    };
1763
 
1764
    const get$4 = _win => {
1765
      const win = _win === undefined ? window : _win;
1441 ariadna 1766
      if (detect$1().browser.isFirefox()) {
1 efrain 1767
        return Optional.none();
1768
      } else {
1769
        return Optional.from(win.visualViewport);
1770
      }
1771
    };
1772
    const bounds = (x, y, width, height) => ({
1773
      x,
1774
      y,
1775
      width,
1776
      height,
1777
      right: x + width,
1778
      bottom: y + height
1779
    });
1780
    const getBounds = _win => {
1781
      const win = _win === undefined ? window : _win;
1782
      const doc = win.document;
1783
      const scroll = get$5(SugarElement.fromDom(doc));
1784
      return get$4(win).fold(() => {
1785
        const html = win.document.documentElement;
1786
        const width = html.clientWidth;
1787
        const height = html.clientHeight;
1788
        return bounds(scroll.left, scroll.top, width, height);
1789
      }, visualViewport => bounds(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
1790
    };
1791
 
1792
    const children = (scope, predicate) => filter$5(children$1(scope), predicate);
1793
    const descendants$1 = (scope, predicate) => {
1794
      let result = [];
1795
      each$e(children$1(scope), x => {
1796
        if (predicate(x)) {
1797
          result = result.concat([x]);
1798
        }
1799
        result = result.concat(descendants$1(x, predicate));
1800
      });
1801
      return result;
1802
    };
1803
 
1804
    const descendants = (scope, selector) => all(selector, scope);
1805
 
1441 ariadna 1806
    const ancestor$2 = (scope, predicate, isRoot) => ancestor$4(scope, predicate, isRoot).isSome();
1807
    const sibling = (scope, predicate) => sibling$1(scope, predicate).isSome();
1808
    const descendant = (scope, predicate) => descendant$2(scope, predicate).isSome();
1 efrain 1809
 
1810
    class DomTreeWalker {
1811
      constructor(startNode, rootNode) {
1812
        this.node = startNode;
1813
        this.rootNode = rootNode;
1814
        this.current = this.current.bind(this);
1815
        this.next = this.next.bind(this);
1816
        this.prev = this.prev.bind(this);
1817
        this.prev2 = this.prev2.bind(this);
1818
      }
1819
      current() {
1820
        return this.node;
1821
      }
1822
      next(shallow) {
1823
        this.node = this.findSibling(this.node, 'firstChild', 'nextSibling', shallow);
1824
        return this.node;
1825
      }
1826
      prev(shallow) {
1827
        this.node = this.findSibling(this.node, 'lastChild', 'previousSibling', shallow);
1828
        return this.node;
1829
      }
1830
      prev2(shallow) {
1831
        this.node = this.findPreviousNode(this.node, shallow);
1832
        return this.node;
1833
      }
1834
      findSibling(node, startName, siblingName, shallow) {
1835
        if (node) {
1836
          if (!shallow && node[startName]) {
1837
            return node[startName];
1838
          }
1839
          if (node !== this.rootNode) {
1840
            let sibling = node[siblingName];
1841
            if (sibling) {
1842
              return sibling;
1843
            }
1844
            for (let parent = node.parentNode; parent && parent !== this.rootNode; parent = parent.parentNode) {
1845
              sibling = parent[siblingName];
1846
              if (sibling) {
1847
                return sibling;
1848
              }
1849
            }
1850
          }
1851
        }
1852
        return undefined;
1853
      }
1854
      findPreviousNode(node, shallow) {
1855
        if (node) {
1856
          const sibling = node.previousSibling;
1857
          if (this.rootNode && sibling === this.rootNode) {
1858
            return;
1859
          }
1860
          if (sibling) {
1861
            if (!shallow) {
1862
              for (let child = sibling.lastChild; child; child = child.lastChild) {
1863
                if (!child.lastChild) {
1864
                  return child;
1865
                }
1866
              }
1867
            }
1868
            return sibling;
1869
          }
1870
          const parent = node.parentNode;
1871
          if (parent && parent !== this.rootNode) {
1872
            return parent;
1873
          }
1874
        }
1875
        return undefined;
1876
      }
1877
    }
1878
 
1441 ariadna 1879
    const zeroWidth = '\uFEFF';
1880
    const nbsp = '\xA0';
1881
    const isZwsp$2 = char => char === zeroWidth;
1882
    const removeZwsp = s => s.replace(/\uFEFF/g, '');
1883
 
1884
    const whiteSpaceRegExp = /^[ \t\r\n]*$/;
1885
    const isWhitespaceText = text => whiteSpaceRegExp.test(text);
1886
    const isZwsp$1 = text => {
1887
      for (const c of text) {
1888
        if (!isZwsp$2(c)) {
1889
          return false;
1890
        }
1891
      }
1892
      return true;
1893
    };
1894
    const isCollapsibleWhitespace$1 = c => ' \f\t\x0B'.indexOf(c) !== -1;
1895
    const isNewLineChar = c => c === '\n' || c === '\r';
1896
    const isNewline = (text, idx) => idx < text.length && idx >= 0 ? isNewLineChar(text[idx]) : false;
1897
    const normalize$4 = (text, tabSpaces = 4, isStartOfContent = true, isEndOfContent = true) => {
1898
      const tabSpace = repeat(' ', tabSpaces);
1899
      const normalizedText = text.replace(/\t/g, tabSpace);
1900
      const result = foldl(normalizedText, (acc, c) => {
1901
        if (isCollapsibleWhitespace$1(c) || c === nbsp) {
1902
          if (acc.pcIsSpace || acc.str === '' && isStartOfContent || acc.str.length === normalizedText.length - 1 && isEndOfContent || isNewline(normalizedText, acc.str.length + 1)) {
1903
            return {
1904
              pcIsSpace: false,
1905
              str: acc.str + nbsp
1906
            };
1907
          } else {
1908
            return {
1909
              pcIsSpace: true,
1910
              str: acc.str + ' '
1911
            };
1912
          }
1913
        } else {
1914
          return {
1915
            pcIsSpace: isNewLineChar(c),
1916
            str: acc.str + c
1917
          };
1918
        }
1919
      }, {
1920
        pcIsSpace: false,
1921
        str: ''
1922
      });
1923
      return result.str;
1924
    };
1925
 
1 efrain 1926
    const isNodeType = type => {
1927
      return node => {
1928
        return !!node && node.nodeType === type;
1929
      };
1930
    };
1931
    const isRestrictedNode = node => !!node && !Object.getPrototypeOf(node);
1932
    const isElement$6 = isNodeType(1);
1933
    const isHTMLElement = node => isElement$6(node) && isHTMLElement$1(SugarElement.fromDom(node));
1934
    const isSVGElement = node => isElement$6(node) && node.namespaceURI === 'http://www.w3.org/2000/svg';
1935
    const matchNodeName = name => {
1936
      const lowerCasedName = name.toLowerCase();
1937
      return node => isNonNullable(node) && node.nodeName.toLowerCase() === lowerCasedName;
1938
    };
1939
    const matchNodeNames = names => {
1940
      const lowerCasedNames = names.map(s => s.toLowerCase());
1941
      return node => {
1942
        if (node && node.nodeName) {
1943
          const nodeName = node.nodeName.toLowerCase();
1944
          return contains$2(lowerCasedNames, nodeName);
1945
        }
1946
        return false;
1947
      };
1948
    };
1949
    const matchStyleValues = (name, values) => {
1950
      const items = values.toLowerCase().split(' ');
1951
      return node => {
1952
        if (isElement$6(node)) {
1953
          const win = node.ownerDocument.defaultView;
1954
          if (win) {
1955
            for (let i = 0; i < items.length; i++) {
1956
              const computed = win.getComputedStyle(node, null);
1957
              const cssValue = computed ? computed.getPropertyValue(name) : null;
1958
              if (cssValue === items[i]) {
1959
                return true;
1960
              }
1961
            }
1962
          }
1963
        }
1964
        return false;
1965
      };
1966
    };
1967
    const hasAttribute = attrName => {
1968
      return node => {
1969
        return isElement$6(node) && node.hasAttribute(attrName);
1970
      };
1971
    };
1441 ariadna 1972
    const isBogus$1 = node => isElement$6(node) && node.hasAttribute('data-mce-bogus');
1973
    const isBogusAll = node => isElement$6(node) && node.getAttribute('data-mce-bogus') === 'all';
1 efrain 1974
    const isTable$2 = node => isElement$6(node) && node.tagName === 'TABLE';
1975
    const hasContentEditableState = value => {
1976
      return node => {
1977
        if (isHTMLElement(node)) {
1978
          if (node.contentEditable === value) {
1979
            return true;
1980
          }
1981
          if (node.getAttribute('data-mce-contenteditable') === value) {
1982
            return true;
1983
          }
1984
        }
1985
        return false;
1986
      };
1987
    };
1988
    const isTextareaOrInput = matchNodeNames([
1989
      'textarea',
1990
      'input'
1991
    ]);
1441 ariadna 1992
    const isText$b = isNodeType(3);
1 efrain 1993
    const isCData = isNodeType(4);
1994
    const isPi = isNodeType(7);
1995
    const isComment = isNodeType(8);
1996
    const isDocument$1 = isNodeType(9);
1997
    const isDocumentFragment = isNodeType(11);
1998
    const isBr$6 = matchNodeName('br');
1999
    const isImg = matchNodeName('img');
2000
    const isContentEditableTrue$3 = hasContentEditableState('true');
2001
    const isContentEditableFalse$b = hasContentEditableState('false');
1441 ariadna 2002
    const isEditingHost = node => isHTMLElement(node) && node.isContentEditable && isNonNullable(node.parentElement) && !node.parentElement.isContentEditable;
1 efrain 2003
    const isTableCell$3 = matchNodeNames([
2004
      'td',
2005
      'th'
2006
    ]);
2007
    const isTableCellOrCaption = matchNodeNames([
2008
      'td',
2009
      'th',
2010
      'caption'
2011
    ]);
2012
    const isMedia$2 = matchNodeNames([
2013
      'video',
2014
      'audio',
2015
      'object',
2016
      'embed'
2017
    ]);
2018
    const isListItem$2 = matchNodeName('li');
2019
    const isDetails = matchNodeName('details');
2020
    const isSummary$1 = matchNodeName('summary');
2021
 
1441 ariadna 2022
    const defaultOptionValues = {
2023
      skipBogus: true,
2024
      includeZwsp: false,
2025
      checkRootAsContent: false
1 efrain 2026
    };
1441 ariadna 2027
    const hasWhitespacePreserveParent = (node, rootNode, schema) => {
2028
      const rootElement = SugarElement.fromDom(rootNode);
2029
      const startNode = SugarElement.fromDom(node);
2030
      const whitespaceElements = schema.getWhitespaceElements();
2031
      const predicate = node => has$2(whitespaceElements, name(node));
2032
      return ancestor$2(startNode, predicate, curry(eq, rootElement));
1 efrain 2033
    };
1441 ariadna 2034
    const isNamedAnchor = node => {
2035
      return isElement$6(node) && node.nodeName === 'A' && !node.hasAttribute('href') && (node.hasAttribute('name') || node.hasAttribute('id'));
1 efrain 2036
    };
1441 ariadna 2037
    const isNonEmptyElement$1 = (node, schema) => {
2038
      return isElement$6(node) && has$2(schema.getNonEmptyElements(), node.nodeName);
1 efrain 2039
    };
1441 ariadna 2040
    const isBookmark = hasAttribute('data-mce-bookmark');
2041
    const hasNonEditableParent = node => parentElement(SugarElement.fromDom(node)).exists(parent => !isEditable$2(parent));
2042
    const isWhitespace$1 = (node, rootNode, schema) => isWhitespaceText(node.data) && !hasWhitespacePreserveParent(node, rootNode, schema);
2043
    const isText$a = (node, rootNode, schema, options) => isText$b(node) && !isWhitespace$1(node, rootNode, schema) && (!options.includeZwsp || !isZwsp$1(node.data));
2044
    const isContentNode = (schema, node, rootNode, options) => {
2045
      return isFunction(options.isContent) && options.isContent(node) || isNonEmptyElement$1(node, schema) || isBookmark(node) || isNamedAnchor(node) || isText$a(node, rootNode, schema, options) || isContentEditableFalse$b(node) || isContentEditableTrue$3(node) && hasNonEditableParent(node);
1 efrain 2046
    };
1441 ariadna 2047
    const isEmptyNode = (schema, targetNode, opts) => {
2048
      const options = {
2049
        ...defaultOptionValues,
2050
        ...opts
2051
      };
2052
      if (options.checkRootAsContent) {
2053
        if (isContentNode(schema, targetNode, targetNode, options)) {
2054
          return false;
1 efrain 2055
        }
2056
      }
1441 ariadna 2057
      let node = targetNode.firstChild;
2058
      let brCount = 0;
2059
      if (!node) {
2060
        return true;
1 efrain 2061
      }
1441 ariadna 2062
      const walker = new DomTreeWalker(node, targetNode);
2063
      do {
2064
        if (options.skipBogus && isElement$6(node)) {
2065
          const bogusValue = node.getAttribute('data-mce-bogus');
2066
          if (bogusValue) {
2067
            node = walker.next(bogusValue === 'all');
2068
            continue;
2069
          }
1 efrain 2070
        }
1441 ariadna 2071
        if (isComment(node)) {
2072
          node = walker.next(true);
2073
          continue;
1 efrain 2074
        }
1441 ariadna 2075
        if (isBr$6(node)) {
2076
          brCount++;
2077
          node = walker.next();
2078
          continue;
1 efrain 2079
        }
1441 ariadna 2080
        if (isContentNode(schema, node, targetNode, options)) {
1 efrain 2081
          return false;
2082
        }
1441 ariadna 2083
        node = walker.next();
2084
      } while (node);
2085
      return brCount <= 1;
1 efrain 2086
    };
1441 ariadna 2087
    const isEmpty$2 = (schema, elm, options) => {
2088
      return isEmptyNode(schema, elm.dom, {
2089
        checkRootAsContent: true,
2090
        ...options
1 efrain 2091
      });
2092
    };
1441 ariadna 2093
    const isContent$1 = (schema, node, options) => {
2094
      return isContentNode(schema, node, node, {
2095
        includeZwsp: defaultOptionValues.includeZwsp,
2096
        ...options
2097
      });
2098
    };
1 efrain 2099
 
1441 ariadna 2100
    const Cell = initial => {
2101
      let value = initial;
2102
      const get = () => {
2103
        return value;
2104
      };
2105
      const set = v => {
2106
        value = v;
2107
      };
2108
      return {
2109
        get,
2110
        set
2111
      };
1 efrain 2112
    };
1441 ariadna 2113
 
2114
    const singleton = doRevoke => {
2115
      const subject = Cell(Optional.none());
2116
      const revoke = () => subject.get().each(doRevoke);
2117
      const clear = () => {
2118
        revoke();
2119
        subject.set(Optional.none());
2120
      };
2121
      const isSet = () => subject.get().isSome();
2122
      const get = () => subject.get();
2123
      const set = s => {
2124
        revoke();
2125
        subject.set(Optional.some(s));
2126
      };
2127
      return {
2128
        clear,
2129
        isSet,
2130
        get,
2131
        set
2132
      };
1 efrain 2133
    };
1441 ariadna 2134
    const repeatable = delay => {
2135
      const intervalId = Cell(Optional.none());
2136
      const revoke = () => intervalId.get().each(id => clearInterval(id));
2137
      const clear = () => {
2138
        revoke();
2139
        intervalId.set(Optional.none());
2140
      };
2141
      const isSet = () => intervalId.get().isSome();
2142
      const get = () => intervalId.get();
2143
      const set = functionToRepeat => {
2144
        revoke();
2145
        intervalId.set(Optional.some(setInterval(functionToRepeat, delay)));
2146
      };
2147
      return {
2148
        clear,
2149
        isSet,
2150
        get,
2151
        set
2152
      };
1 efrain 2153
    };
1441 ariadna 2154
    const value$2 = () => {
2155
      const subject = singleton(noop);
2156
      const on = f => subject.get().each(f);
2157
      return {
2158
        ...subject,
2159
        on
2160
      };
1 efrain 2161
    };
1441 ariadna 2162
 
2163
    const nodeNameToNamespaceType = name => {
2164
      const lowerCaseName = name.toLowerCase();
2165
      if (lowerCaseName === 'svg') {
2166
        return 'svg';
2167
      } else if (lowerCaseName === 'math') {
2168
        return 'math';
1 efrain 2169
      } else {
1441 ariadna 2170
        return 'html';
1 efrain 2171
      }
2172
    };
1441 ariadna 2173
    const isNonHtmlElementRootName = name => nodeNameToNamespaceType(name) !== 'html';
1 efrain 2174
    const isNonHtmlElementRoot = node => isNonHtmlElementRootName(node.nodeName);
1441 ariadna 2175
    const toScopeType = node => nodeNameToNamespaceType(node.nodeName);
2176
    const namespaceElements = [
2177
      'svg',
2178
      'math'
2179
    ];
1 efrain 2180
    const createNamespaceTracker = () => {
1441 ariadna 2181
      const currentScope = value$2();
2182
      const current = () => currentScope.get().map(toScopeType).getOr('html');
1 efrain 2183
      const track = node => {
2184
        if (isNonHtmlElementRoot(node)) {
1441 ariadna 2185
          currentScope.set(node);
2186
        } else if (currentScope.get().exists(scopeNode => !scopeNode.contains(node))) {
2187
          currentScope.clear();
1 efrain 2188
        }
1441 ariadna 2189
        return current();
1 efrain 2190
      };
2191
      const reset = () => {
1441 ariadna 2192
        currentScope.clear();
1 efrain 2193
      };
2194
      return {
2195
        track,
2196
        current,
2197
        reset
2198
      };
2199
    };
2200
 
2201
    const transparentBlockAttr = 'data-mce-block';
2202
    const elementNames = map => filter$5(keys(map), key => !/[A-Z]/.test(key));
2203
    const makeSelectorFromSchemaMap = map => map$3(elementNames(map), name => {
1441 ariadna 2204
      const escapedName = CSS.escape(name);
2205
      return `${ escapedName }:` + map$3(namespaceElements, ns => `not(${ ns } ${ escapedName })`).join(':');
1 efrain 2206
    }).join(',');
2207
    const updateTransparent = (blocksSelector, transparent) => {
2208
      if (isNonNullable(transparent.querySelector(blocksSelector))) {
2209
        transparent.setAttribute(transparentBlockAttr, 'true');
2210
        if (transparent.getAttribute('data-mce-selected') === 'inline-boundary') {
2211
          transparent.removeAttribute('data-mce-selected');
2212
        }
2213
        return true;
2214
      } else {
2215
        transparent.removeAttribute(transparentBlockAttr);
2216
        return false;
2217
      }
2218
    };
2219
    const updateBlockStateOnChildren = (schema, scope) => {
2220
      const transparentSelector = makeSelectorFromSchemaMap(schema.getTransparentElements());
2221
      const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
2222
      return filter$5(scope.querySelectorAll(transparentSelector), transparent => updateTransparent(blocksSelector, transparent));
2223
    };
1441 ariadna 2224
    const trimEdge = (schema, el, leftSide) => {
1 efrain 2225
      var _a;
2226
      const childPropertyName = leftSide ? 'lastChild' : 'firstChild';
2227
      for (let child = el[childPropertyName]; child; child = child[childPropertyName]) {
1441 ariadna 2228
        if (isEmptyNode(schema, child, { checkRootAsContent: true })) {
1 efrain 2229
          (_a = child.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(child);
2230
          return;
2231
        }
2232
      }
2233
    };
1441 ariadna 2234
    const split$2 = (schema, parentElm, splitElm) => {
1 efrain 2235
      const range = document.createRange();
2236
      const parentNode = parentElm.parentNode;
2237
      if (parentNode) {
2238
        range.setStartBefore(parentElm);
2239
        range.setEndBefore(splitElm);
2240
        const beforeFragment = range.extractContents();
1441 ariadna 2241
        trimEdge(schema, beforeFragment, true);
1 efrain 2242
        range.setStartAfter(splitElm);
2243
        range.setEndAfter(parentElm);
2244
        const afterFragment = range.extractContents();
1441 ariadna 2245
        trimEdge(schema, afterFragment, false);
2246
        if (!isEmptyNode(schema, beforeFragment, { checkRootAsContent: true })) {
1 efrain 2247
          parentNode.insertBefore(beforeFragment, parentElm);
2248
        }
1441 ariadna 2249
        if (!isEmptyNode(schema, splitElm, { checkRootAsContent: true })) {
1 efrain 2250
          parentNode.insertBefore(splitElm, parentElm);
2251
        }
1441 ariadna 2252
        if (!isEmptyNode(schema, afterFragment, { checkRootAsContent: true })) {
1 efrain 2253
          parentNode.insertBefore(afterFragment, parentElm);
2254
        }
2255
        parentNode.removeChild(parentElm);
2256
      }
2257
    };
2258
    const splitInvalidChildren = (schema, scope, transparentBlocks) => {
2259
      const blocksElements = schema.getBlockElements();
2260
      const rootNode = SugarElement.fromDom(scope);
2261
      const isBlock = el => name(el) in blocksElements;
2262
      const isRoot = el => eq(el, rootNode);
2263
      each$e(fromDom$1(transparentBlocks), transparentBlock => {
2264
        ancestor$4(transparentBlock, isBlock, isRoot).each(parentBlock => {
2265
          const invalidChildren = children(transparentBlock, el => isBlock(el) && !schema.isValidChild(name(parentBlock), name(el)));
2266
          if (invalidChildren.length > 0) {
2267
            const stateScope = parentElement(parentBlock);
2268
            each$e(invalidChildren, child => {
2269
              ancestor$4(child, isBlock, isRoot).each(parentBlock => {
1441 ariadna 2270
                split$2(schema, parentBlock.dom, child.dom);
1 efrain 2271
              });
2272
            });
2273
            stateScope.each(scope => updateBlockStateOnChildren(schema, scope.dom));
2274
          }
2275
        });
2276
      });
2277
    };
2278
    const unwrapInvalidChildren = (schema, scope, transparentBlocks) => {
2279
      each$e([
2280
        ...transparentBlocks,
2281
        ...isTransparentBlock(schema, scope) ? [scope] : []
2282
      ], block => each$e(descendants(SugarElement.fromDom(block), block.nodeName.toLowerCase()), elm => {
2283
        if (isTransparentInline(schema, elm.dom)) {
2284
          unwrap(elm);
2285
        }
2286
      }));
2287
    };
2288
    const updateChildren = (schema, scope) => {
2289
      const transparentBlocks = updateBlockStateOnChildren(schema, scope);
2290
      splitInvalidChildren(schema, scope, transparentBlocks);
2291
      unwrapInvalidChildren(schema, scope, transparentBlocks);
2292
    };
2293
    const updateElement = (schema, target) => {
2294
      if (isTransparentElement(schema, target)) {
2295
        const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
2296
        updateTransparent(blocksSelector, target);
2297
      }
2298
    };
2299
    const updateCaret = (schema, root, caretParent) => {
2300
      const isRoot = el => eq(el, SugarElement.fromDom(root));
2301
      const parents = parents$1(SugarElement.fromDom(caretParent), isRoot);
2302
      get$b(parents, parents.length - 2).filter(isElement$7).fold(() => updateChildren(schema, root), scope => updateChildren(schema, scope.dom));
2303
    };
2304
    const hasBlockAttr = el => el.hasAttribute(transparentBlockAttr);
2305
    const isTransparentElementName = (schema, name) => has$2(schema.getTransparentElements(), name);
2306
    const isTransparentElement = (schema, node) => isElement$6(node) && isTransparentElementName(schema, node.nodeName);
2307
    const isTransparentBlock = (schema, node) => isTransparentElement(schema, node) && hasBlockAttr(node);
2308
    const isTransparentInline = (schema, node) => isTransparentElement(schema, node) && !hasBlockAttr(node);
2309
    const isTransparentAstBlock = (schema, node) => node.type === 1 && isTransparentElementName(schema, node.name) && isString(node.attr(transparentBlockAttr));
2310
 
1441 ariadna 2311
    const browser$2 = detect$1().browser;
1 efrain 2312
    const firstElement = nodes => find$2(nodes, isElement$7);
2313
    const getTableCaptionDeltaY = elm => {
2314
      if (browser$2.isFirefox() && name(elm) === 'table') {
2315
        return firstElement(children$1(elm)).filter(elm => {
2316
          return name(elm) === 'caption';
2317
        }).bind(caption => {
2318
          return firstElement(nextSiblings(caption)).map(body => {
2319
            const bodyTop = body.dom.offsetTop;
2320
            const captionTop = caption.dom.offsetTop;
2321
            const captionHeight = caption.dom.offsetHeight;
2322
            return bodyTop <= captionTop ? -captionHeight : 0;
2323
          });
2324
        }).getOr(0);
2325
      } else {
2326
        return 0;
2327
      }
2328
    };
2329
    const hasChild = (elm, child) => elm.children && contains$2(elm.children, child);
2330
    const getPos = (body, elm, rootElm) => {
2331
      let x = 0, y = 0;
2332
      const doc = body.ownerDocument;
2333
      rootElm = rootElm ? rootElm : body;
2334
      if (elm) {
2335
        if (rootElm === body && elm.getBoundingClientRect && get$7(SugarElement.fromDom(body), 'position') === 'static') {
2336
          const pos = elm.getBoundingClientRect();
2337
          x = pos.left + (doc.documentElement.scrollLeft || body.scrollLeft) - doc.documentElement.clientLeft;
2338
          y = pos.top + (doc.documentElement.scrollTop || body.scrollTop) - doc.documentElement.clientTop;
2339
          return {
2340
            x,
2341
            y
2342
          };
2343
        }
2344
        let offsetParent = elm;
2345
        while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
2346
          const castOffsetParent = offsetParent;
2347
          x += castOffsetParent.offsetLeft || 0;
2348
          y += castOffsetParent.offsetTop || 0;
2349
          offsetParent = castOffsetParent.offsetParent;
2350
        }
2351
        offsetParent = elm.parentNode;
2352
        while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
2353
          x -= offsetParent.scrollLeft || 0;
2354
          y -= offsetParent.scrollTop || 0;
2355
          offsetParent = offsetParent.parentNode;
2356
        }
2357
        y += getTableCaptionDeltaY(SugarElement.fromDom(elm));
2358
      }
2359
      return {
2360
        x,
2361
        y
2362
      };
2363
    };
2364
 
2365
    const StyleSheetLoader = (documentOrShadowRoot, settings = {}) => {
2366
      let idCount = 0;
2367
      const loadedStates = {};
2368
      const edos = SugarElement.fromDom(documentOrShadowRoot);
2369
      const doc = documentOrOwner(edos);
2370
      const _setReferrerPolicy = referrerPolicy => {
2371
        settings.referrerPolicy = referrerPolicy;
2372
      };
2373
      const _setContentCssCors = contentCssCors => {
2374
        settings.contentCssCors = contentCssCors;
2375
      };
2376
      const addStyle = element => {
2377
        append$1(getStyleContainer(edos), element);
2378
      };
2379
      const removeStyle = id => {
2380
        const styleContainer = getStyleContainer(edos);
1441 ariadna 2381
        descendant$1(styleContainer, '#' + id).each(remove$4);
1 efrain 2382
      };
2383
      const getOrCreateState = url => get$a(loadedStates, url).getOrThunk(() => ({
2384
        id: 'mce-u' + idCount++,
2385
        passed: [],
2386
        failed: [],
2387
        count: 0
2388
      }));
2389
      const load = url => new Promise((success, failure) => {
2390
        let link;
2391
        const urlWithSuffix = Tools._addCacheSuffix(url);
2392
        const state = getOrCreateState(urlWithSuffix);
2393
        loadedStates[urlWithSuffix] = state;
2394
        state.count++;
2395
        const resolve = (callbacks, status) => {
2396
          each$e(callbacks, call);
2397
          state.status = status;
2398
          state.passed = [];
2399
          state.failed = [];
2400
          if (link) {
2401
            link.onload = null;
2402
            link.onerror = null;
2403
            link = null;
2404
          }
2405
        };
2406
        const passed = () => resolve(state.passed, 2);
2407
        const failed = () => resolve(state.failed, 3);
2408
        if (success) {
2409
          state.passed.push(success);
2410
        }
2411
        if (failure) {
2412
          state.failed.push(failure);
2413
        }
2414
        if (state.status === 1) {
2415
          return;
2416
        }
2417
        if (state.status === 2) {
2418
          passed();
2419
          return;
2420
        }
2421
        if (state.status === 3) {
2422
          failed();
2423
          return;
2424
        }
2425
        state.status = 1;
2426
        const linkElem = SugarElement.fromTag('link', doc.dom);
2427
        setAll$1(linkElem, {
2428
          rel: 'stylesheet',
2429
          type: 'text/css',
2430
          id: state.id
2431
        });
2432
        if (settings.contentCssCors) {
1441 ariadna 2433
          set$4(linkElem, 'crossOrigin', 'anonymous');
1 efrain 2434
        }
2435
        if (settings.referrerPolicy) {
1441 ariadna 2436
          set$4(linkElem, 'referrerpolicy', settings.referrerPolicy);
1 efrain 2437
        }
2438
        link = linkElem.dom;
2439
        link.onload = passed;
2440
        link.onerror = failed;
2441
        addStyle(linkElem);
1441 ariadna 2442
        set$4(linkElem, 'href', urlWithSuffix);
1 efrain 2443
      });
2444
      const loadRawCss = (key, css) => {
2445
        const state = getOrCreateState(key);
2446
        loadedStates[key] = state;
2447
        state.count++;
2448
        const styleElem = SugarElement.fromTag('style', doc.dom);
2449
        setAll$1(styleElem, {
1441 ariadna 2450
          'rel': 'stylesheet',
2451
          'type': 'text/css',
2452
          'id': state.id,
2453
          'data-mce-key': key
1 efrain 2454
        });
2455
        styleElem.dom.innerHTML = css;
2456
        addStyle(styleElem);
2457
      };
2458
      const loadAll = urls => {
2459
        const loadedUrls = Promise.allSettled(map$3(urls, url => load(url).then(constant(url))));
2460
        return loadedUrls.then(results => {
2461
          const parts = partition$2(results, r => r.status === 'fulfilled');
2462
          if (parts.fail.length > 0) {
2463
            return Promise.reject(map$3(parts.fail, result => result.reason));
2464
          } else {
2465
            return map$3(parts.pass, result => result.value);
2466
          }
2467
        });
2468
      };
2469
      const unload = url => {
2470
        const urlWithSuffix = Tools._addCacheSuffix(url);
2471
        get$a(loadedStates, urlWithSuffix).each(state => {
2472
          const count = --state.count;
2473
          if (count === 0) {
2474
            delete loadedStates[urlWithSuffix];
2475
            removeStyle(state.id);
2476
          }
2477
        });
2478
      };
2479
      const unloadRawCss = key => {
2480
        get$a(loadedStates, key).each(state => {
2481
          const count = --state.count;
2482
          if (count === 0) {
2483
            delete loadedStates[key];
2484
            removeStyle(state.id);
2485
          }
2486
        });
2487
      };
2488
      const unloadAll = urls => {
2489
        each$e(urls, url => {
2490
          unload(url);
2491
        });
2492
      };
2493
      return {
2494
        load,
2495
        loadRawCss,
2496
        loadAll,
2497
        unload,
2498
        unloadRawCss,
2499
        unloadAll,
2500
        _setReferrerPolicy,
2501
        _setContentCssCors
2502
      };
2503
    };
2504
 
1441 ariadna 2505
    const create$c = () => {
1 efrain 2506
      const map = new WeakMap();
2507
      const forElement = (referenceElement, settings) => {
2508
        const root = getRootNode(referenceElement);
2509
        const rootDom = root.dom;
2510
        return Optional.from(map.get(rootDom)).getOrThunk(() => {
2511
          const sl = StyleSheetLoader(rootDom, settings);
2512
          map.set(rootDom, sl);
2513
          return sl;
2514
        });
2515
      };
2516
      return { forElement };
2517
    };
1441 ariadna 2518
    const instance = create$c();
1 efrain 2519
 
2520
    const isSpan = node => node.nodeName.toLowerCase() === 'span';
1441 ariadna 2521
    const isInlineContent = (node, schema) => isNonNullable(node) && (isContent$1(schema, node) || schema.isInline(node.nodeName.toLowerCase()));
1 efrain 2522
    const surroundedByInlineContent = (node, root, schema) => {
2523
      const prev = new DomTreeWalker(node, root).prev(false);
2524
      const next = new DomTreeWalker(node, root).next(false);
1441 ariadna 2525
      const prevIsInline = isUndefined(prev) || isInlineContent(prev, schema);
2526
      const nextIsInline = isUndefined(next) || isInlineContent(next, schema);
1 efrain 2527
      return prevIsInline && nextIsInline;
2528
    };
2529
    const isBookmarkNode$2 = node => isSpan(node) && node.getAttribute('data-mce-type') === 'bookmark';
1441 ariadna 2530
    const isKeepTextNode = (node, root, schema) => isText$b(node) && node.data.length > 0 && surroundedByInlineContent(node, root, schema);
1 efrain 2531
    const isKeepElement = node => isElement$6(node) ? node.childNodes.length > 0 : false;
2532
    const isDocument = node => isDocumentFragment(node) || isDocument$1(node);
2533
    const trimNode = (dom, node, schema, root) => {
2534
      var _a;
2535
      const rootNode = root || node;
2536
      if (isElement$6(node) && isBookmarkNode$2(node)) {
2537
        return node;
2538
      }
2539
      const children = node.childNodes;
2540
      for (let i = children.length - 1; i >= 0; i--) {
2541
        trimNode(dom, children[i], schema, rootNode);
2542
      }
2543
      if (isElement$6(node)) {
2544
        const currentChildren = node.childNodes;
2545
        if (currentChildren.length === 1 && isBookmarkNode$2(currentChildren[0])) {
2546
          (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(currentChildren[0], node);
2547
        }
2548
      }
1441 ariadna 2549
      if (!isDocument(node) && !isContent$1(schema, node) && !isKeepElement(node) && !isKeepTextNode(node, rootNode, schema)) {
1 efrain 2550
        dom.remove(node);
2551
      }
2552
      return node;
2553
    };
2554
 
2555
    const makeMap$3 = Tools.makeMap;
2556
    const attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
2557
    const textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
2558
    const rawCharsRegExp = /[<>&\"\']/g;
2559
    const entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi;
2560
    const asciiMap = {
2561
      128: '\u20AC',
2562
      130: '\u201A',
2563
      131: '\u0192',
2564
      132: '\u201E',
2565
      133: '\u2026',
2566
      134: '\u2020',
2567
      135: '\u2021',
2568
      136: '\u02c6',
2569
      137: '\u2030',
2570
      138: '\u0160',
2571
      139: '\u2039',
2572
      140: '\u0152',
2573
      142: '\u017d',
2574
      145: '\u2018',
2575
      146: '\u2019',
2576
      147: '\u201C',
2577
      148: '\u201D',
2578
      149: '\u2022',
2579
      150: '\u2013',
2580
      151: '\u2014',
2581
      152: '\u02DC',
2582
      153: '\u2122',
2583
      154: '\u0161',
2584
      155: '\u203A',
2585
      156: '\u0153',
2586
      158: '\u017e',
2587
      159: '\u0178'
2588
    };
2589
    const baseEntities = {
2590
      '"': '&quot;',
2591
      '\'': '&#39;',
2592
      '<': '&lt;',
2593
      '>': '&gt;',
2594
      '&': '&amp;',
2595
      '`': '&#96;'
2596
    };
2597
    const reverseEntities = {
2598
      '&lt;': '<',
2599
      '&gt;': '>',
2600
      '&amp;': '&',
2601
      '&quot;': '"',
2602
      '&apos;': `'`
2603
    };
2604
    const nativeDecode = text => {
2605
      const elm = SugarElement.fromTag('div').dom;
2606
      elm.innerHTML = text;
2607
      return elm.textContent || elm.innerText || text;
2608
    };
2609
    const buildEntitiesLookup = (items, radix) => {
2610
      const lookup = {};
2611
      if (items) {
2612
        const itemList = items.split(',');
2613
        radix = radix || 10;
2614
        for (let i = 0; i < itemList.length; i += 2) {
2615
          const chr = String.fromCharCode(parseInt(itemList[i], radix));
2616
          if (!baseEntities[chr]) {
2617
            const entity = '&' + itemList[i + 1] + ';';
2618
            lookup[chr] = entity;
2619
            lookup[entity] = chr;
2620
          }
2621
        }
2622
        return lookup;
2623
      } else {
2624
        return undefined;
2625
      }
2626
    };
2627
    const namedEntities = buildEntitiesLookup('50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' + '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' + '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' + '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' + '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' + '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' + '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' + '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' + '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' + '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' + 'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' + 'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' + 't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' + 'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' + 'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' + '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' + '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' + '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' + '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' + '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' + 'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' + 'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' + 'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' + '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' + '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', 32);
2628
    const encodeRaw = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
2629
      return baseEntities[chr] || chr;
2630
    });
2631
    const encodeAllRaw = text => ('' + text).replace(rawCharsRegExp, chr => {
2632
      return baseEntities[chr] || chr;
2633
    });
2634
    const encodeNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
2635
      if (chr.length > 1) {
2636
        return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
2637
      }
2638
      return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
2639
    });
2640
    const encodeNamed = (text, attr, entities) => {
2641
      const resolveEntities = entities || namedEntities;
2642
      return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
2643
        return baseEntities[chr] || resolveEntities[chr] || chr;
2644
      });
2645
    };
2646
    const getEncodeFunc = (name, entities) => {
2647
      const entitiesMap = buildEntitiesLookup(entities) || namedEntities;
2648
      const encodeNamedAndNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
2649
        if (baseEntities[chr] !== undefined) {
2650
          return baseEntities[chr];
2651
        }
2652
        if (entitiesMap[chr] !== undefined) {
2653
          return entitiesMap[chr];
2654
        }
2655
        if (chr.length > 1) {
2656
          return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
2657
        }
2658
        return '&#' + chr.charCodeAt(0) + ';';
2659
      });
2660
      const encodeCustomNamed = (text, attr) => {
2661
        return encodeNamed(text, attr, entitiesMap);
2662
      };
2663
      const nameMap = makeMap$3(name.replace(/\+/g, ','));
2664
      if (nameMap.named && nameMap.numeric) {
2665
        return encodeNamedAndNumeric;
2666
      }
2667
      if (nameMap.named) {
2668
        if (entities) {
2669
          return encodeCustomNamed;
2670
        }
2671
        return encodeNamed;
2672
      }
2673
      if (nameMap.numeric) {
2674
        return encodeNumeric;
2675
      }
2676
      return encodeRaw;
2677
    };
2678
    const decode = text => text.replace(entityRegExp, (all, numeric) => {
2679
      if (numeric) {
2680
        if (numeric.charAt(0).toLowerCase() === 'x') {
2681
          numeric = parseInt(numeric.substr(1), 16);
2682
        } else {
2683
          numeric = parseInt(numeric, 10);
2684
        }
2685
        if (numeric > 65535) {
2686
          numeric -= 65536;
2687
          return String.fromCharCode(55296 + (numeric >> 10), 56320 + (numeric & 1023));
2688
        }
2689
        return asciiMap[numeric] || String.fromCharCode(numeric);
2690
      }
2691
      return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
2692
    });
2693
    const Entities = {
2694
      encodeRaw,
2695
      encodeAllRaw,
2696
      encodeNumeric,
2697
      encodeNamed,
2698
      getEncodeFunc,
2699
      decode
2700
    };
2701
 
2702
    const split$1 = (items, delim) => {
2703
      items = Tools.trim(items);
2704
      return items ? items.split(delim || ' ') : [];
2705
    };
2706
    const patternToRegExp = str => new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
1441 ariadna 2707
    const isRegExp$1 = obj => isObject(obj) && obj.source && Object.prototype.toString.call(obj) === '[object RegExp]';
2708
    const deepCloneElementRule = obj => {
2709
      const helper = value => {
2710
        if (isArray$1(value)) {
2711
          return map$3(value, helper);
2712
        } else if (isRegExp$1(value)) {
2713
          return new RegExp(value.source, value.flags);
2714
        } else if (isObject(value)) {
2715
          return map$2(value, helper);
2716
        } else {
2717
          return value;
2718
        }
2719
      };
2720
      return helper(obj);
2721
    };
1 efrain 2722
 
2723
    const parseCustomElementsRules = value => {
2724
      const customElementRegExp = /^(~)?(.+)$/;
2725
      return bind$3(split$1(value, ','), rule => {
2726
        const matches = customElementRegExp.exec(rule);
2727
        if (matches) {
2728
          const inline = matches[1] === '~';
2729
          const cloneName = inline ? 'span' : 'div';
2730
          const name = matches[2];
2731
          return [{
2732
              cloneName,
2733
              name
2734
            }];
2735
        } else {
2736
          return [];
2737
        }
2738
      });
2739
    };
2740
 
1441 ariadna 2741
    const getGlobalAttributeSet = type => {
2742
      return Object.freeze([
2743
        'id',
2744
        'accesskey',
2745
        'class',
2746
        'dir',
2747
        'lang',
2748
        'style',
2749
        'tabindex',
2750
        'title',
2751
        'role',
2752
        ...type !== 'html4' ? [
2753
          'contenteditable',
2754
          'contextmenu',
2755
          'draggable',
2756
          'dropzone',
2757
          'hidden',
2758
          'spellcheck',
2759
          'translate',
2760
          'itemprop',
2761
          'itemscope',
2762
          'itemtype'
2763
        ] : [],
2764
        ...type !== 'html5-strict' ? ['xml:lang'] : []
2765
      ]);
2766
    };
2767
 
1 efrain 2768
    const getElementSetsAsStrings = type => {
1441 ariadna 2769
      let blockContent;
1 efrain 2770
      let phrasingContent;
2771
      blockContent = 'address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul';
2772
      phrasingContent = 'a abbr b bdo br button cite code del dfn em embed i iframe img input ins kbd ' + 'label map noscript object q s samp script select small span strong sub sup ' + 'textarea u var #text #comment';
2773
      if (type !== 'html4') {
2774
        const transparentContent = 'a ins del canvas map';
2775
        blockContent += ' article aside details dialog figure main header footer hgroup section nav ' + transparentContent;
1441 ariadna 2776
        phrasingContent += ' audio canvas command data datalist mark meter output picture ' + 'progress time wbr video ruby bdi keygen svg';
1 efrain 2777
      }
2778
      if (type !== 'html5-strict') {
2779
        const html4PhrasingContent = 'acronym applet basefont big font strike tt';
2780
        phrasingContent = [
2781
          phrasingContent,
2782
          html4PhrasingContent
2783
        ].join(' ');
2784
        const html4BlockContent = 'center dir isindex noframes';
2785
        blockContent = [
2786
          blockContent,
2787
          html4BlockContent
2788
        ].join(' ');
2789
      }
2790
      const flowContent = [
2791
        blockContent,
2792
        phrasingContent
2793
      ].join(' ');
2794
      return {
2795
        blockContent,
2796
        phrasingContent,
2797
        flowContent
2798
      };
2799
    };
1441 ariadna 2800
    const getElementSets = type => {
2801
      const {blockContent, phrasingContent, flowContent} = getElementSetsAsStrings(type);
2802
      const toArr = value => {
2803
        return Object.freeze(value.split(' '));
2804
      };
2805
      return Object.freeze({
2806
        blockContent: toArr(blockContent),
2807
        phrasingContent: toArr(phrasingContent),
2808
        flowContent: toArr(flowContent)
2809
      });
2810
    };
1 efrain 2811
 
1441 ariadna 2812
    const cachedSets = {
2813
      'html4': cached(() => getElementSets('html4')),
2814
      'html5': cached(() => getElementSets('html5')),
2815
      'html5-strict': cached(() => getElementSets('html5-strict'))
2816
    };
2817
    const getElementsPreset = (type, name) => {
2818
      const {blockContent, phrasingContent, flowContent} = cachedSets[type]();
2819
      if (name === 'blocks') {
2820
        return Optional.some(blockContent);
2821
      } else if (name === 'phrasing') {
2822
        return Optional.some(phrasingContent);
2823
      } else if (name === 'flow') {
2824
        return Optional.some(flowContent);
2825
      } else {
2826
        return Optional.none();
2827
      }
2828
    };
2829
 
1 efrain 2830
    const makeSchema = type => {
1441 ariadna 2831
      const globalAttributes = getGlobalAttributeSet(type);
2832
      const {phrasingContent, flowContent} = getElementSetsAsStrings(type);
1 efrain 2833
      const schema = {};
2834
      const addElement = (name, attributes, children) => {
2835
        schema[name] = {
2836
          attributes: mapToObject(attributes, constant({})),
2837
          attributesOrder: attributes,
2838
          children: mapToObject(children, constant({}))
2839
        };
2840
      };
2841
      const add = (name, attributes = '', children = '') => {
2842
        const childNames = split$1(children);
2843
        const names = split$1(name);
2844
        let ni = names.length;
1441 ariadna 2845
        const allAttributes = [
2846
          ...globalAttributes,
2847
          ...split$1(attributes)
2848
        ];
1 efrain 2849
        while (ni--) {
2850
          addElement(names[ni], allAttributes.slice(), childNames);
2851
        }
2852
      };
2853
      const addAttrs = (name, attributes) => {
2854
        const names = split$1(name);
2855
        const attrs = split$1(attributes);
2856
        let ni = names.length;
2857
        while (ni--) {
2858
          const schemaItem = schema[names[ni]];
2859
          for (let i = 0, l = attrs.length; i < l; i++) {
2860
            schemaItem.attributes[attrs[i]] = {};
2861
            schemaItem.attributesOrder.push(attrs[i]);
2862
          }
2863
        }
2864
      };
2865
      if (type !== 'html5-strict') {
2866
        const html4PhrasingContent = 'acronym applet basefont big font strike tt';
2867
        each$e(split$1(html4PhrasingContent), name => {
2868
          add(name, '', phrasingContent);
2869
        });
2870
        const html4BlockContent = 'center dir isindex noframes';
2871
        each$e(split$1(html4BlockContent), name => {
2872
          add(name, '', flowContent);
2873
        });
2874
      }
2875
      add('html', 'manifest', 'head body');
2876
      add('head', '', 'base command link meta noscript script style title');
2877
      add('title hr noscript br');
2878
      add('base', 'href target');
2879
      add('link', 'href rel media hreflang type sizes hreflang');
2880
      add('meta', 'name http-equiv content charset');
2881
      add('style', 'media type scoped');
2882
      add('script', 'src async defer type charset');
2883
      add('body', 'onafterprint onbeforeprint onbeforeunload onblur onerror onfocus ' + 'onhashchange onload onmessage onoffline ononline onpagehide onpageshow ' + 'onpopstate onresize onscroll onstorage onunload', flowContent);
2884
      add('dd div', '', flowContent);
2885
      add('address dt caption', '', type === 'html4' ? phrasingContent : flowContent);
2886
      add('h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn', '', phrasingContent);
2887
      add('blockquote', 'cite', flowContent);
2888
      add('ol', 'reversed start type', 'li');
2889
      add('ul', '', 'li');
2890
      add('li', 'value', flowContent);
2891
      add('dl', '', 'dt dd');
2892
      add('a', 'href target rel media hreflang type', type === 'html4' ? phrasingContent : flowContent);
2893
      add('q', 'cite', phrasingContent);
2894
      add('ins del', 'cite datetime', flowContent);
2895
      add('img', 'src sizes srcset alt usemap ismap width height');
2896
      add('iframe', 'src name width height', flowContent);
2897
      add('embed', 'src type width height');
2898
      add('object', 'data type typemustmatch name usemap form width height', [
2899
        flowContent,
2900
        'param'
2901
      ].join(' '));
2902
      add('param', 'name value');
2903
      add('map', 'name', [
2904
        flowContent,
2905
        'area'
2906
      ].join(' '));
2907
      add('area', 'alt coords shape href target rel media hreflang type');
2908
      add('table', 'border', 'caption colgroup thead tfoot tbody tr' + (type === 'html4' ? ' col' : ''));
2909
      add('colgroup', 'span', 'col');
2910
      add('col', 'span');
2911
      add('tbody thead tfoot', '', 'tr');
2912
      add('tr', '', 'td th');
2913
      add('td', 'colspan rowspan headers', flowContent);
2914
      add('th', 'colspan rowspan headers scope abbr', flowContent);
2915
      add('form', 'accept-charset action autocomplete enctype method name novalidate target', flowContent);
2916
      add('fieldset', 'disabled form name', [
2917
        flowContent,
2918
        'legend'
2919
      ].join(' '));
2920
      add('label', 'form for', phrasingContent);
2921
      add('input', 'accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate ' + 'formtarget height list max maxlength min multiple name pattern readonly required size src step type value width');
2922
      add('button', 'disabled form formaction formenctype formmethod formnovalidate formtarget name type value', type === 'html4' ? flowContent : phrasingContent);
2923
      add('select', 'disabled form multiple name required size', 'option optgroup');
2924
      add('optgroup', 'disabled label', 'option');
2925
      add('option', 'disabled label selected value');
2926
      add('textarea', 'cols dirname disabled form maxlength name readonly required rows wrap');
2927
      add('menu', 'type label', [
2928
        flowContent,
2929
        'li'
2930
      ].join(' '));
2931
      add('noscript', '', flowContent);
2932
      if (type !== 'html4') {
2933
        add('wbr');
2934
        add('ruby', '', [
2935
          phrasingContent,
2936
          'rt rp'
2937
        ].join(' '));
2938
        add('figcaption', '', flowContent);
2939
        add('mark rt rp bdi', '', phrasingContent);
2940
        add('summary', '', [
2941
          phrasingContent,
2942
          'h1 h2 h3 h4 h5 h6'
2943
        ].join(' '));
2944
        add('canvas', 'width height', flowContent);
1441 ariadna 2945
        add('data', 'value', phrasingContent);
1 efrain 2946
        add('video', 'src crossorigin poster preload autoplay mediagroup loop ' + 'muted controls width height buffered', [
2947
          flowContent,
2948
          'track source'
2949
        ].join(' '));
2950
        add('audio', 'src crossorigin preload autoplay mediagroup loop muted controls ' + 'buffered volume', [
2951
          flowContent,
2952
          'track source'
2953
        ].join(' '));
2954
        add('picture', '', 'img source');
2955
        add('source', 'src srcset type media sizes');
2956
        add('track', 'kind src srclang label default');
2957
        add('datalist', '', [
2958
          phrasingContent,
2959
          'option'
2960
        ].join(' '));
2961
        add('article section nav aside main header footer', '', flowContent);
2962
        add('hgroup', '', 'h1 h2 h3 h4 h5 h6');
2963
        add('figure', '', [
2964
          flowContent,
2965
          'figcaption'
2966
        ].join(' '));
2967
        add('time', 'datetime', phrasingContent);
2968
        add('dialog', 'open', flowContent);
2969
        add('command', 'type label icon disabled checked radiogroup command');
2970
        add('output', 'for form name', phrasingContent);
2971
        add('progress', 'value max', phrasingContent);
2972
        add('meter', 'value min max low high optimum', phrasingContent);
2973
        add('details', 'open', [
2974
          flowContent,
2975
          'summary'
2976
        ].join(' '));
2977
        add('keygen', 'autofocus challenge disabled form keytype name');
2978
        addElement('svg', 'id tabindex lang xml:space class style x y width height viewBox preserveAspectRatio zoomAndPan transform'.split(' '), []);
2979
      }
2980
      if (type !== 'html5-strict') {
2981
        addAttrs('script', 'language xml:space');
2982
        addAttrs('style', 'xml:space');
2983
        addAttrs('object', 'declare classid code codebase codetype archive standby align border hspace vspace');
2984
        addAttrs('embed', 'align name hspace vspace');
2985
        addAttrs('param', 'valuetype type');
2986
        addAttrs('a', 'charset name rev shape coords');
2987
        addAttrs('br', 'clear');
2988
        addAttrs('applet', 'codebase archive code object alt name width height align hspace vspace');
2989
        addAttrs('img', 'name longdesc align border hspace vspace');
2990
        addAttrs('iframe', 'longdesc frameborder marginwidth marginheight scrolling align');
2991
        addAttrs('font basefont', 'size color face');
2992
        addAttrs('input', 'usemap align');
2993
        addAttrs('select');
2994
        addAttrs('textarea');
2995
        addAttrs('h1 h2 h3 h4 h5 h6 div p legend caption', 'align');
2996
        addAttrs('ul', 'type compact');
2997
        addAttrs('li', 'type');
2998
        addAttrs('ol dl menu dir', 'compact');
2999
        addAttrs('pre', 'width xml:space');
3000
        addAttrs('hr', 'align noshade size width');
3001
        addAttrs('isindex', 'prompt');
3002
        addAttrs('table', 'summary width frame rules cellspacing cellpadding align bgcolor');
3003
        addAttrs('col', 'width align char charoff valign');
3004
        addAttrs('colgroup', 'width align char charoff valign');
3005
        addAttrs('thead', 'align char charoff valign');
3006
        addAttrs('tr', 'align char charoff valign bgcolor');
3007
        addAttrs('th', 'axis align char charoff valign nowrap bgcolor width height');
3008
        addAttrs('form', 'accept');
3009
        addAttrs('td', 'abbr axis scope align char charoff valign nowrap bgcolor width height');
3010
        addAttrs('tfoot', 'align char charoff valign');
3011
        addAttrs('tbody', 'align char charoff valign');
3012
        addAttrs('area', 'nohref');
3013
        addAttrs('body', 'background bgcolor text link vlink alink');
3014
      }
3015
      if (type !== 'html4') {
3016
        addAttrs('input button select textarea', 'autofocus');
3017
        addAttrs('input textarea', 'placeholder');
3018
        addAttrs('a', 'download');
3019
        addAttrs('link script img', 'crossorigin');
3020
        addAttrs('img', 'loading');
1441 ariadna 3021
        addAttrs('iframe', 'sandbox seamless allow allowfullscreen loading referrerpolicy');
1 efrain 3022
      }
3023
      if (type !== 'html4') {
3024
        each$e([
3025
          schema.video,
3026
          schema.audio
3027
        ], item => {
3028
          delete item.children.audio;
3029
          delete item.children.video;
3030
        });
3031
      }
3032
      each$e(split$1('a form meter progress dfn'), name => {
3033
        if (schema[name]) {
3034
          delete schema[name].children[name];
3035
        }
3036
      });
3037
      delete schema.caption.children.table;
3038
      delete schema.script;
3039
      return schema;
3040
    };
3041
 
3042
    const prefixToOperation = prefix => prefix === '-' ? 'remove' : 'add';
1441 ariadna 3043
    const parseValidChild = name => {
3044
      const validChildRegExp = /^(@?)([A-Za-z0-9_\-.\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]+)$/;
3045
      return Optional.from(validChildRegExp.exec(name)).map(matches => ({
3046
        preset: matches[1] === '@',
3047
        name: matches[2]
3048
      }));
3049
    };
1 efrain 3050
    const parseValidChildrenRules = value => {
3051
      const childRuleRegExp = /^([+\-]?)([A-Za-z0-9_\-.\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]+)\[([^\]]+)]$/;
3052
      return bind$3(split$1(value, ','), rule => {
3053
        const matches = childRuleRegExp.exec(rule);
3054
        if (matches) {
3055
          const prefix = matches[1];
3056
          const operation = prefix ? prefixToOperation(prefix) : 'replace';
3057
          const name = matches[2];
1441 ariadna 3058
          const validChildren = bind$3(split$1(matches[3], '|'), validChild => parseValidChild(validChild).toArray());
1 efrain 3059
          return [{
3060
              operation,
3061
              name,
3062
              validChildren
3063
            }];
3064
        } else {
3065
          return [];
3066
        }
3067
      });
3068
    };
3069
 
3070
    const parseValidElementsAttrDataIntoElement = (attrData, targetElement) => {
3071
      const attrRuleRegExp = /^([!\-])?(\w+[\\:]:\w+|[^=~<]+)?(?:([=~<])(.*))?$/;
3072
      const hasPatternsRegExp = /[*?+]/;
3073
      const {attributes, attributesOrder} = targetElement;
3074
      return each$e(split$1(attrData, '|'), rule => {
3075
        const matches = attrRuleRegExp.exec(rule);
3076
        if (matches) {
3077
          const attr = {};
3078
          const attrType = matches[1];
3079
          const attrName = matches[2].replace(/[\\:]:/g, ':');
3080
          const attrPrefix = matches[3];
3081
          const value = matches[4];
3082
          if (attrType === '!') {
3083
            targetElement.attributesRequired = targetElement.attributesRequired || [];
3084
            targetElement.attributesRequired.push(attrName);
3085
            attr.required = true;
3086
          }
3087
          if (attrType === '-') {
3088
            delete attributes[attrName];
3089
            attributesOrder.splice(Tools.inArray(attributesOrder, attrName), 1);
3090
            return;
3091
          }
3092
          if (attrPrefix) {
3093
            if (attrPrefix === '=') {
3094
              targetElement.attributesDefault = targetElement.attributesDefault || [];
3095
              targetElement.attributesDefault.push({
3096
                name: attrName,
3097
                value
3098
              });
3099
              attr.defaultValue = value;
3100
            } else if (attrPrefix === '~') {
3101
              targetElement.attributesForced = targetElement.attributesForced || [];
3102
              targetElement.attributesForced.push({
3103
                name: attrName,
3104
                value
3105
              });
3106
              attr.forcedValue = value;
3107
            } else if (attrPrefix === '<') {
3108
              attr.validValues = Tools.makeMap(value, '?');
3109
            }
3110
          }
3111
          if (hasPatternsRegExp.test(attrName)) {
3112
            const attrPattern = attr;
3113
            targetElement.attributePatterns = targetElement.attributePatterns || [];
3114
            attrPattern.pattern = patternToRegExp(attrName);
3115
            targetElement.attributePatterns.push(attrPattern);
3116
          } else {
3117
            if (!attributes[attrName]) {
3118
              attributesOrder.push(attrName);
3119
            }
3120
            attributes[attrName] = attr;
3121
          }
3122
        }
3123
      });
3124
    };
3125
    const cloneAttributesInto = (from, to) => {
3126
      each$d(from.attributes, (value, key) => {
3127
        to.attributes[key] = value;
3128
      });
3129
      to.attributesOrder.push(...from.attributesOrder);
3130
    };
3131
    const parseValidElementsRules = (globalElement, validElements) => {
3132
      const elementRuleRegExp = /^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)])?$/;
3133
      return bind$3(split$1(validElements, ','), rule => {
3134
        const matches = elementRuleRegExp.exec(rule);
3135
        if (matches) {
3136
          const prefix = matches[1];
3137
          const elementName = matches[2];
3138
          const outputName = matches[3];
3139
          const attrsPrefix = matches[4];
3140
          const attrData = matches[5];
3141
          const element = {
3142
            attributes: {},
3143
            attributesOrder: []
3144
          };
3145
          globalElement.each(el => cloneAttributesInto(el, element));
3146
          if (prefix === '#') {
3147
            element.paddEmpty = true;
3148
          } else if (prefix === '-') {
3149
            element.removeEmpty = true;
3150
          }
3151
          if (attrsPrefix === '!') {
3152
            element.removeEmptyAttrs = true;
3153
          }
3154
          if (attrData) {
3155
            parseValidElementsAttrDataIntoElement(attrData, element);
3156
          }
3157
          if (outputName) {
3158
            element.outputName = elementName;
3159
          }
3160
          if (elementName === '@') {
3161
            if (globalElement.isNone()) {
3162
              globalElement = Optional.some(element);
3163
            } else {
3164
              return [];
3165
            }
3166
          }
3167
          return [outputName ? {
3168
              name: elementName,
3169
              element,
3170
              aliasName: outputName
3171
            } : {
3172
              name: elementName,
3173
              element
3174
            }];
3175
        } else {
3176
          return [];
3177
        }
3178
      });
3179
    };
3180
 
3181
    const mapCache = {};
3182
    const makeMap$2 = Tools.makeMap, each$b = Tools.each, extend$2 = Tools.extend, explode$2 = Tools.explode;
3183
    const createMap = (defaultValue, extendWith = {}) => {
3184
      const value = makeMap$2(defaultValue, ' ', makeMap$2(defaultValue.toUpperCase(), ' '));
3185
      return extend$2(value, extendWith);
3186
    };
3187
    const getTextRootBlockElements = schema => createMap('td th li dt dd figcaption caption details summary', schema.getTextBlockElements());
3188
    const compileElementMap = (value, mode) => {
3189
      if (value) {
3190
        const styles = {};
3191
        if (isString(value)) {
3192
          value = { '*': value };
3193
        }
3194
        each$b(value, (value, key) => {
3195
          styles[key] = styles[key.toUpperCase()] = mode === 'map' ? makeMap$2(value, /[, ]/) : explode$2(value, /[, ]/);
3196
        });
3197
        return styles;
3198
      } else {
3199
        return undefined;
3200
      }
3201
    };
3202
    const Schema = (settings = {}) => {
3203
      var _a;
3204
      const elements = {};
3205
      const children = {};
3206
      let patternElements = [];
3207
      const customElementsMap = {};
3208
      const specialElements = {};
3209
      const createLookupTable = (option, defaultValue, extendWith) => {
3210
        const value = settings[option];
3211
        if (!value) {
3212
          let newValue = mapCache[option];
3213
          if (!newValue) {
3214
            newValue = createMap(defaultValue, extendWith);
3215
            mapCache[option] = newValue;
3216
          }
3217
          return newValue;
3218
        } else {
3219
          return makeMap$2(value, /[, ]/, makeMap$2(value.toUpperCase(), /[, ]/));
3220
        }
3221
      };
3222
      const schemaType = (_a = settings.schema) !== null && _a !== void 0 ? _a : 'html5';
3223
      const schemaItems = makeSchema(schemaType);
3224
      if (settings.verify_html === false) {
3225
        settings.valid_elements = '*[*]';
3226
      }
3227
      const validStyles = compileElementMap(settings.valid_styles);
3228
      const invalidStyles = compileElementMap(settings.invalid_styles, 'map');
3229
      const validClasses = compileElementMap(settings.valid_classes, 'map');
3230
      const whitespaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea video audio iframe object code');
3231
      const selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
3232
      const voidElementsMap = createLookupTable('void_elements', 'area base basefont br col frame hr img input isindex link ' + 'meta param embed source wbr track');
3233
      const boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' + 'noshade nowrap readonly selected autoplay loop controls allowfullscreen');
3234
      const nonEmptyOrMoveCaretBeforeOnEnter = 'td th iframe video audio object script code';
1441 ariadna 3235
      const nonEmptyElementsMap = createLookupTable('non_empty_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' pre svg textarea summary', voidElementsMap);
1 efrain 3236
      const moveCaretBeforeOnEnterElementsMap = createLookupTable('move_caret_before_on_enter_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' table', voidElementsMap);
3237
      const headings = 'h1 h2 h3 h4 h5 h6';
3238
      const textBlockElementsMap = createLookupTable('text_block_elements', headings + ' p div address pre form ' + 'blockquote center dir fieldset header footer article section hgroup aside main nav figure');
3239
      const blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' + 'th tr td li ol ul caption dl dt dd noscript menu isindex option ' + 'datalist select optgroup figcaption details summary html body multicol listing', textBlockElementsMap);
3240
      const textInlineElementsMap = createLookupTable('text_inline_elements', 'span strong b em i font s strike u var cite ' + 'dfn code mark q sup sub samp');
3241
      const transparentElementsMap = createLookupTable('transparent_elements', 'a ins del canvas map');
3242
      const wrapBlockElementsMap = createLookupTable('wrap_block_elements', 'pre ' + headings);
3243
      each$b('script noscript iframe noframes noembed title style textarea xmp plaintext'.split(' '), name => {
3244
        specialElements[name] = new RegExp('</' + name + '[^>]*>', 'gi');
3245
      });
3246
      const addValidElements = validElements => {
3247
        const globalElement = Optional.from(elements['@']);
3248
        const hasPatternsRegExp = /[*?+]/;
3249
        each$e(parseValidElementsRules(globalElement, validElements !== null && validElements !== void 0 ? validElements : ''), ({name, element, aliasName}) => {
3250
          if (aliasName) {
3251
            elements[aliasName] = element;
3252
          }
3253
          if (hasPatternsRegExp.test(name)) {
3254
            const patternElement = element;
3255
            patternElement.pattern = patternToRegExp(name);
3256
            patternElements.push(patternElement);
3257
          } else {
3258
            elements[name] = element;
3259
          }
3260
        });
3261
      };
3262
      const setValidElements = validElements => {
3263
        patternElements = [];
3264
        each$e(keys(elements), name => {
3265
          delete elements[name];
3266
        });
3267
        addValidElements(validElements);
3268
      };
1441 ariadna 3269
      const addCustomElement = (name, spec) => {
3270
        var _a, _b;
1 efrain 3271
        delete mapCache.text_block_elements;
3272
        delete mapCache.block_elements;
1441 ariadna 3273
        const inline = spec.extends ? !isBlock(spec.extends) : false;
3274
        const cloneName = spec.extends;
3275
        children[name] = cloneName ? children[cloneName] : {};
3276
        customElementsMap[name] = cloneName !== null && cloneName !== void 0 ? cloneName : name;
3277
        nonEmptyElementsMap[name.toUpperCase()] = {};
3278
        nonEmptyElementsMap[name] = {};
3279
        if (!inline) {
3280
          blockElementsMap[name.toUpperCase()] = {};
3281
          blockElementsMap[name] = {};
3282
        }
3283
        if (cloneName && !elements[name] && elements[cloneName]) {
3284
          const customRule = deepCloneElementRule(elements[cloneName]);
3285
          delete customRule.removeEmptyAttrs;
3286
          delete customRule.removeEmpty;
3287
          elements[name] = customRule;
3288
        } else {
3289
          elements[name] = {
3290
            attributesOrder: [],
3291
            attributes: {}
3292
          };
3293
        }
3294
        if (isArray$1(spec.attributes)) {
3295
          const processAttrName = name => {
3296
            customRule.attributesOrder.push(name);
3297
            customRule.attributes[name] = {};
3298
          };
3299
          const customRule = (_a = elements[name]) !== null && _a !== void 0 ? _a : {};
3300
          delete customRule.attributesDefault;
3301
          delete customRule.attributesForced;
3302
          delete customRule.attributePatterns;
3303
          delete customRule.attributesRequired;
3304
          customRule.attributesOrder = [];
3305
          customRule.attributes = {};
3306
          each$e(spec.attributes, attrName => {
3307
            const globalAttrs = getGlobalAttributeSet(schemaType);
3308
            parseValidChild(attrName).each(({preset, name}) => {
3309
              if (preset) {
3310
                if (name === 'global') {
3311
                  each$e(globalAttrs, processAttrName);
3312
                }
3313
              } else {
3314
                processAttrName(name);
3315
              }
3316
            });
3317
          });
3318
          elements[name] = customRule;
3319
        }
3320
        if (isBoolean(spec.padEmpty)) {
3321
          const customRule = (_b = elements[name]) !== null && _b !== void 0 ? _b : {};
3322
          customRule.paddEmpty = spec.padEmpty;
3323
          elements[name] = customRule;
3324
        }
3325
        if (isArray$1(spec.children)) {
3326
          const customElementChildren = {};
3327
          const processNodeName = name => {
3328
            customElementChildren[name] = {};
3329
          };
3330
          const processPreset = name => {
3331
            getElementsPreset(schemaType, name).each(names => {
3332
              each$e(names, processNodeName);
3333
            });
3334
          };
3335
          each$e(spec.children, child => {
3336
            parseValidChild(child).each(({preset, name}) => {
3337
              if (preset) {
3338
                processPreset(name);
3339
              } else {
3340
                processNodeName(name);
3341
              }
3342
            });
3343
          });
3344
          children[name] = customElementChildren;
3345
        }
3346
        if (cloneName) {
1 efrain 3347
          each$d(children, (element, elmName) => {
3348
            if (element[cloneName]) {
3349
              children[elmName] = element = extend$2({}, children[elmName]);
3350
              element[name] = element[cloneName];
3351
            }
3352
          });
1441 ariadna 3353
        }
3354
      };
3355
      const addCustomElementsFromString = customElements => {
3356
        each$e(parseCustomElementsRules(customElements !== null && customElements !== void 0 ? customElements : ''), ({name, cloneName}) => {
3357
          addCustomElement(name, { extends: cloneName });
1 efrain 3358
        });
3359
      };
1441 ariadna 3360
      const addCustomElements = customElements => {
3361
        if (isObject(customElements)) {
3362
          each$d(customElements, (spec, name) => addCustomElement(name, spec));
3363
        } else if (isString(customElements)) {
3364
          addCustomElementsFromString(customElements);
3365
        }
3366
      };
1 efrain 3367
      const addValidChildren = validChildren => {
3368
        each$e(parseValidChildrenRules(validChildren !== null && validChildren !== void 0 ? validChildren : ''), ({operation, name, validChildren}) => {
3369
          const parent = operation === 'replace' ? { '#comment': {} } : children[name];
1441 ariadna 3370
          const processNodeName = name => {
1 efrain 3371
            if (operation === 'remove') {
1441 ariadna 3372
              delete parent[name];
1 efrain 3373
            } else {
1441 ariadna 3374
              parent[name] = {};
1 efrain 3375
            }
1441 ariadna 3376
          };
3377
          const processPreset = name => {
3378
            getElementsPreset(schemaType, name).each(names => {
3379
              each$e(names, processNodeName);
3380
            });
3381
          };
3382
          each$e(validChildren, ({preset, name}) => {
3383
            if (preset) {
3384
              processPreset(name);
3385
            } else {
3386
              processNodeName(name);
3387
            }
1 efrain 3388
          });
3389
          children[name] = parent;
3390
        });
3391
      };
3392
      const getElementRule = name => {
3393
        const element = elements[name];
3394
        if (element) {
3395
          return element;
3396
        }
3397
        let i = patternElements.length;
3398
        while (i--) {
3399
          const patternElement = patternElements[i];
3400
          if (patternElement.pattern.test(name)) {
3401
            return patternElement;
3402
          }
3403
        }
3404
        return undefined;
3405
      };
1441 ariadna 3406
      const setup = () => {
3407
        if (!settings.valid_elements) {
3408
          each$b(schemaItems, (element, name) => {
3409
            elements[name] = {
3410
              attributes: element.attributes,
3411
              attributesOrder: element.attributesOrder
3412
            };
3413
            children[name] = element.children;
3414
          });
3415
          each$b(split$1('strong/b em/i'), item => {
3416
            const items = split$1(item, '/');
3417
            elements[items[1]].outputName = items[0];
3418
          });
3419
          each$b(textInlineElementsMap, (_val, name) => {
3420
            if (elements[name]) {
3421
              if (settings.padd_empty_block_inline_children) {
3422
                elements[name].paddInEmptyBlock = true;
3423
              }
3424
              elements[name].removeEmpty = true;
1 efrain 3425
            }
1441 ariadna 3426
          });
3427
          each$b(split$1('ol ul blockquote a table tbody'), name => {
3428
            if (elements[name]) {
3429
              elements[name].removeEmpty = true;
3430
            }
3431
          });
3432
          each$b(split$1('p h1 h2 h3 h4 h5 h6 th td pre div address caption li summary'), name => {
3433
            if (elements[name]) {
3434
              elements[name].paddEmpty = true;
3435
            }
3436
          });
3437
          each$b(split$1('span'), name => {
3438
            elements[name].removeEmptyAttrs = true;
3439
          });
3440
        } else {
3441
          setValidElements(settings.valid_elements);
3442
          each$b(schemaItems, (element, name) => {
3443
            children[name] = element.children;
3444
          });
1 efrain 3445
        }
1441 ariadna 3446
        delete elements.svg;
3447
        addCustomElements(settings.custom_elements);
3448
        addValidChildren(settings.valid_children);
3449
        addValidElements(settings.extended_valid_elements);
3450
        addValidChildren('+ol[ul|ol],+ul[ul|ol]');
3451
        each$b({
3452
          dd: 'dl',
3453
          dt: 'dl',
3454
          li: 'ul ol',
3455
          td: 'tr',
3456
          th: 'tr',
3457
          tr: 'tbody thead tfoot',
3458
          tbody: 'table',
3459
          thead: 'table',
3460
          tfoot: 'table',
3461
          legend: 'fieldset',
3462
          area: 'map',
3463
          param: 'video audio object'
3464
        }, (parents, item) => {
1 efrain 3465
          if (elements[item]) {
1441 ariadna 3466
            elements[item].parentsRequired = split$1(parents);
1 efrain 3467
          }
3468
        });
1441 ariadna 3469
        if (settings.invalid_elements) {
3470
          each$b(explode$2(settings.invalid_elements), item => {
3471
            if (elements[item]) {
3472
              delete elements[item];
3473
            }
3474
          });
3475
        }
3476
        if (!getElementRule('span')) {
3477
          addValidElements('span[!data-mce-type|*]');
3478
        }
3479
      };
1 efrain 3480
      const getValidStyles = constant(validStyles);
3481
      const getInvalidStyles = constant(invalidStyles);
3482
      const getValidClasses = constant(validClasses);
3483
      const getBoolAttrs = constant(boolAttrMap);
3484
      const getBlockElements = constant(blockElementsMap);
3485
      const getTextBlockElements = constant(textBlockElementsMap);
3486
      const getTextInlineElements = constant(textInlineElementsMap);
3487
      const getVoidElements = constant(Object.seal(voidElementsMap));
3488
      const getSelfClosingElements = constant(selfClosingElementsMap);
3489
      const getNonEmptyElements = constant(nonEmptyElementsMap);
3490
      const getMoveCaretBeforeOnEnterElements = constant(moveCaretBeforeOnEnterElementsMap);
3491
      const getWhitespaceElements = constant(whitespaceElementsMap);
3492
      const getTransparentElements = constant(transparentElementsMap);
3493
      const getWrapBlockElements = constant(wrapBlockElementsMap);
3494
      const getSpecialElements = constant(Object.seal(specialElements));
3495
      const isValidChild = (name, child) => {
3496
        const parent = children[name.toLowerCase()];
3497
        return !!(parent && parent[child.toLowerCase()]);
3498
      };
3499
      const isValid = (name, attr) => {
3500
        const rule = getElementRule(name);
3501
        if (rule) {
3502
          if (attr) {
3503
            if (rule.attributes[attr]) {
3504
              return true;
3505
            }
3506
            const attrPatterns = rule.attributePatterns;
3507
            if (attrPatterns) {
3508
              let i = attrPatterns.length;
3509
              while (i--) {
3510
                if (attrPatterns[i].pattern.test(attr)) {
3511
                  return true;
3512
                }
3513
              }
3514
            }
3515
          } else {
3516
            return true;
3517
          }
3518
        }
3519
        return false;
3520
      };
3521
      const isBlock = name => has$2(getBlockElements(), name);
3522
      const isInline = name => !startsWith(name, '#') && isValid(name) && !isBlock(name);
3523
      const isWrapper = name => has$2(getWrapBlockElements(), name) || isInline(name);
3524
      const getCustomElements = constant(customElementsMap);
1441 ariadna 3525
      setup();
1 efrain 3526
      return {
3527
        type: schemaType,
3528
        children,
3529
        elements,
3530
        getValidStyles,
3531
        getValidClasses,
3532
        getBlockElements,
3533
        getInvalidStyles,
3534
        getVoidElements,
3535
        getTextBlockElements,
3536
        getTextInlineElements,
3537
        getBoolAttrs,
3538
        getElementRule,
3539
        getSelfClosingElements,
3540
        getNonEmptyElements,
3541
        getMoveCaretBeforeOnEnterElements,
3542
        getWhitespaceElements,
3543
        getTransparentElements,
3544
        getSpecialElements,
3545
        isValidChild,
3546
        isValid,
3547
        isBlock,
3548
        isInline,
3549
        isWrapper,
3550
        getCustomElements,
3551
        addValidElements,
3552
        setValidElements,
3553
        addCustomElements,
3554
        addValidChildren
3555
      };
3556
    };
3557
 
3558
    const hexColour = value => ({ value: normalizeHex(value) });
3559
    const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();
3560
    const toHex = component => {
3561
      const hex = component.toString(16);
3562
      return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
3563
    };
3564
    const fromRgba = rgbaColour => {
3565
      const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
3566
      return hexColour(value);
3567
    };
3568
 
1441 ariadna 3569
    const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*\)\s*$/i;
3570
    const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*((?:\d?\.\d+|\d+)%?)\s*\)\s*$/i;
1 efrain 3571
    const rgbaColour = (red, green, blue, alpha) => ({
3572
      red,
3573
      green,
3574
      blue,
3575
      alpha
3576
    });
3577
    const fromStringValues = (red, green, blue, alpha) => {
3578
      const r = parseInt(red, 10);
3579
      const g = parseInt(green, 10);
3580
      const b = parseInt(blue, 10);
3581
      const a = parseFloat(alpha);
3582
      return rgbaColour(r, g, b, a);
3583
    };
1441 ariadna 3584
    const getColorFormat = colorString => {
3585
      if (rgbRegex.test(colorString)) {
3586
        return 'rgb';
3587
      } else if (rgbaRegex.test(colorString)) {
3588
        return 'rgba';
3589
      }
3590
      return 'other';
3591
    };
1 efrain 3592
    const fromString = rgbaString => {
3593
      const rgbMatch = rgbRegex.exec(rgbaString);
3594
      if (rgbMatch !== null) {
3595
        return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
3596
      }
3597
      const rgbaMatch = rgbaRegex.exec(rgbaString);
3598
      if (rgbaMatch !== null) {
3599
        return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
3600
      }
3601
      return Optional.none();
3602
    };
3603
    const toString = rgba => `rgba(${ rgba.red },${ rgba.green },${ rgba.blue },${ rgba.alpha })`;
3604
 
3605
    const rgbaToHexString = color => fromString(color).map(fromRgba).map(h => '#' + h.value).getOr(color);
3606
 
3607
    const Styles = (settings = {}, schema) => {
3608
      const urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi;
3609
      const styleRegExp = /\s*([^:]+):\s*([^;]+);?/g;
3610
      const trimRightRegExp = /\s+$/;
3611
      const encodingLookup = {};
3612
      let validStyles;
3613
      let invalidStyles;
3614
      const invisibleChar = zeroWidth;
3615
      if (schema) {
3616
        validStyles = schema.getValidStyles();
3617
        invalidStyles = schema.getInvalidStyles();
3618
      }
3619
      const encodingItems = (`\\" \\' \\; \\: ; : ` + invisibleChar).split(' ');
3620
      for (let i = 0; i < encodingItems.length; i++) {
3621
        encodingLookup[encodingItems[i]] = invisibleChar + i;
3622
        encodingLookup[invisibleChar + i] = encodingItems[i];
3623
      }
3624
      const self = {
3625
        parse: css => {
3626
          const styles = {};
3627
          let isEncoded = false;
3628
          const urlConverter = settings.url_converter;
3629
          const urlConverterScope = settings.url_converter_scope || self;
3630
          const compress = (prefix, suffix, noJoin) => {
3631
            const top = styles[prefix + '-top' + suffix];
3632
            if (!top) {
3633
              return;
3634
            }
3635
            const right = styles[prefix + '-right' + suffix];
3636
            if (!right) {
3637
              return;
3638
            }
3639
            const bottom = styles[prefix + '-bottom' + suffix];
3640
            if (!bottom) {
3641
              return;
3642
            }
3643
            const left = styles[prefix + '-left' + suffix];
3644
            if (!left) {
3645
              return;
3646
            }
3647
            const box = [
3648
              top,
3649
              right,
3650
              bottom,
3651
              left
3652
            ];
3653
            let i = box.length - 1;
3654
            while (i--) {
3655
              if (box[i] !== box[i + 1]) {
3656
                break;
3657
              }
3658
            }
3659
            if (i > -1 && noJoin) {
3660
              return;
3661
            }
3662
            styles[prefix + suffix] = i === -1 ? box[0] : box.join(' ');
3663
            delete styles[prefix + '-top' + suffix];
3664
            delete styles[prefix + '-right' + suffix];
3665
            delete styles[prefix + '-bottom' + suffix];
3666
            delete styles[prefix + '-left' + suffix];
3667
          };
3668
          const canCompress = key => {
3669
            const value = styles[key];
3670
            if (!value) {
3671
              return;
3672
            }
3673
            const values = value.indexOf(',') > -1 ? [value] : value.split(' ');
3674
            let i = values.length;
3675
            while (i--) {
3676
              if (values[i] !== values[0]) {
3677
                return false;
3678
              }
3679
            }
3680
            styles[key] = values[0];
3681
            return true;
3682
          };
3683
          const compress2 = (target, a, b, c) => {
3684
            if (!canCompress(a)) {
3685
              return;
3686
            }
3687
            if (!canCompress(b)) {
3688
              return;
3689
            }
3690
            if (!canCompress(c)) {
3691
              return;
3692
            }
3693
            styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
3694
            delete styles[a];
3695
            delete styles[b];
3696
            delete styles[c];
3697
          };
3698
          const encode = str => {
3699
            isEncoded = true;
3700
            return encodingLookup[str];
3701
          };
3702
          const decode = (str, keepSlashes) => {
3703
            if (isEncoded) {
3704
              str = str.replace(/\uFEFF[0-9]/g, str => {
3705
                return encodingLookup[str];
3706
              });
3707
            }
3708
            if (!keepSlashes) {
3709
              str = str.replace(/\\([\'\";:])/g, '$1');
3710
            }
3711
            return str;
3712
          };
3713
          const decodeSingleHexSequence = escSeq => {
3714
            return String.fromCharCode(parseInt(escSeq.slice(1), 16));
3715
          };
3716
          const decodeHexSequences = value => {
3717
            return value.replace(/\\[0-9a-f]+/gi, decodeSingleHexSequence);
3718
          };
3719
          const processUrl = (match, url, url2, url3, str, str2) => {
3720
            str = str || str2;
3721
            if (str) {
3722
              str = decode(str);
3723
              return `'` + str.replace(/\'/g, `\\'`) + `'`;
3724
            }
3725
            url = decode(url || url2 || url3 || '');
3726
            if (!settings.allow_script_urls) {
3727
              const scriptUrl = url.replace(/[\s\r\n]+/g, '');
3728
              if (/(java|vb)script:/i.test(scriptUrl)) {
3729
                return '';
3730
              }
3731
              if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
3732
                return '';
3733
              }
3734
            }
3735
            if (urlConverter) {
3736
              url = urlConverter.call(urlConverterScope, url, 'style');
3737
            }
3738
            return `url('` + url.replace(/\'/g, `\\'`) + `')`;
3739
          };
3740
          if (css) {
3741
            css = css.replace(/[\u0000-\u001F]/g, '');
3742
            css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, str => {
3743
              return str.replace(/[;:]/g, encode);
3744
            });
3745
            let matches;
3746
            while (matches = styleRegExp.exec(css)) {
3747
              styleRegExp.lastIndex = matches.index + matches[0].length;
3748
              let name = matches[1].replace(trimRightRegExp, '').toLowerCase();
3749
              let value = matches[2].replace(trimRightRegExp, '');
3750
              if (name && value) {
3751
                name = decodeHexSequences(name);
3752
                value = decodeHexSequences(value);
3753
                if (name.indexOf(invisibleChar) !== -1 || name.indexOf('"') !== -1) {
3754
                  continue;
3755
                }
3756
                if (!settings.allow_script_urls && (name === 'behavior' || /expression\s*\(|\/\*|\*\//.test(value))) {
3757
                  continue;
3758
                }
3759
                if (name === 'font-weight' && value === '700') {
3760
                  value = 'bold';
3761
                } else if (name === 'color' || name === 'background-color') {
3762
                  value = value.toLowerCase();
3763
                }
1441 ariadna 3764
                if (getColorFormat(value) === 'rgb') {
1 efrain 3765
                  fromString(value).each(rgba => {
1441 ariadna 3766
                    value = rgbaToHexString(toString(rgba)).toLowerCase();
1 efrain 3767
                  });
3768
                }
3769
                value = value.replace(urlOrStrRegExp, processUrl);
3770
                styles[name] = isEncoded ? decode(value, true) : value;
3771
              }
3772
            }
3773
            compress('border', '', true);
3774
            compress('border', '-width');
3775
            compress('border', '-color');
3776
            compress('border', '-style');
3777
            compress('padding', '');
3778
            compress('margin', '');
3779
            compress2('border', 'border-width', 'border-style', 'border-color');
3780
            if (styles.border === 'medium none') {
3781
              delete styles.border;
3782
            }
3783
            if (styles['border-image'] === 'none') {
3784
              delete styles['border-image'];
3785
            }
3786
          }
3787
          return styles;
3788
        },
3789
        serialize: (styles, elementName) => {
3790
          let css = '';
3791
          const serializeStyles = (elemName, validStyleList) => {
3792
            const styleList = validStyleList[elemName];
3793
            if (styleList) {
3794
              for (let i = 0, l = styleList.length; i < l; i++) {
3795
                const name = styleList[i];
3796
                const value = styles[name];
3797
                if (value) {
3798
                  css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
3799
                }
3800
              }
3801
            }
3802
          };
3803
          const isValid = (name, elemName) => {
3804
            if (!invalidStyles || !elemName) {
3805
              return true;
3806
            }
3807
            let styleMap = invalidStyles['*'];
3808
            if (styleMap && styleMap[name]) {
3809
              return false;
3810
            }
3811
            styleMap = invalidStyles[elemName];
3812
            return !(styleMap && styleMap[name]);
3813
          };
3814
          if (elementName && validStyles) {
3815
            serializeStyles('*', validStyles);
3816
            serializeStyles(elementName, validStyles);
3817
          } else {
3818
            each$d(styles, (value, name) => {
3819
              if (value && isValid(name, elementName)) {
3820
                css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
3821
              }
3822
            });
3823
          }
3824
          return css;
3825
        }
3826
      };
3827
      return self;
3828
    };
3829
 
3830
    const deprecated = {
3831
      keyLocation: true,
3832
      layerX: true,
3833
      layerY: true,
3834
      returnValue: true,
3835
      webkitMovementX: true,
3836
      webkitMovementY: true,
3837
      keyIdentifier: true,
3838
      mozPressure: true
3839
    };
3840
    const isNativeEvent = event => event instanceof Event || isFunction(event.initEvent);
3841
    const hasIsDefaultPrevented = event => event.isDefaultPrevented === always || event.isDefaultPrevented === never;
3842
    const needsNormalizing = event => isNullable(event.preventDefault) || isNativeEvent(event);
3843
    const clone$3 = (originalEvent, data) => {
3844
      const event = data !== null && data !== void 0 ? data : {};
3845
      for (const name in originalEvent) {
3846
        if (!has$2(deprecated, name)) {
3847
          event[name] = originalEvent[name];
3848
        }
3849
      }
3850
      if (isNonNullable(originalEvent.composedPath)) {
3851
        event.composedPath = () => originalEvent.composedPath();
3852
      }
3853
      if (isNonNullable(originalEvent.getModifierState)) {
3854
        event.getModifierState = keyArg => originalEvent.getModifierState(keyArg);
3855
      }
3856
      if (isNonNullable(originalEvent.getTargetRanges)) {
3857
        event.getTargetRanges = () => originalEvent.getTargetRanges();
3858
      }
3859
      return event;
3860
    };
3861
    const normalize$3 = (type, originalEvent, fallbackTarget, data) => {
3862
      var _a;
3863
      const event = clone$3(originalEvent, data);
3864
      event.type = type;
3865
      if (isNullable(event.target)) {
3866
        event.target = (_a = event.srcElement) !== null && _a !== void 0 ? _a : fallbackTarget;
3867
      }
3868
      if (needsNormalizing(originalEvent)) {
3869
        event.preventDefault = () => {
3870
          event.defaultPrevented = true;
3871
          event.isDefaultPrevented = always;
3872
          if (isFunction(originalEvent.preventDefault)) {
3873
            originalEvent.preventDefault();
3874
          }
3875
        };
3876
        event.stopPropagation = () => {
3877
          event.cancelBubble = true;
3878
          event.isPropagationStopped = always;
3879
          if (isFunction(originalEvent.stopPropagation)) {
3880
            originalEvent.stopPropagation();
3881
          }
3882
        };
3883
        event.stopImmediatePropagation = () => {
3884
          event.isImmediatePropagationStopped = always;
3885
          event.stopPropagation();
3886
        };
3887
        if (!hasIsDefaultPrevented(event)) {
3888
          event.isDefaultPrevented = event.defaultPrevented === true ? always : never;
3889
          event.isPropagationStopped = event.cancelBubble === true ? always : never;
3890
          event.isImmediatePropagationStopped = never;
3891
        }
3892
      }
3893
      return event;
3894
    };
3895
 
3896
    const eventExpandoPrefix = 'mce-data-';
3897
    const mouseEventRe = /^(?:mouse|contextmenu)|click/;
3898
    const addEvent = (target, name, callback, capture) => {
3899
      target.addEventListener(name, callback, capture || false);
3900
    };
3901
    const removeEvent = (target, name, callback, capture) => {
3902
      target.removeEventListener(name, callback, capture || false);
3903
    };
3904
    const isMouseEvent = event => isNonNullable(event) && mouseEventRe.test(event.type);
3905
    const fix = (originalEvent, data) => {
3906
      const event = normalize$3(originalEvent.type, originalEvent, document, data);
3907
      if (isMouseEvent(originalEvent) && isUndefined(originalEvent.pageX) && !isUndefined(originalEvent.clientX)) {
3908
        const eventDoc = event.target.ownerDocument || document;
3909
        const doc = eventDoc.documentElement;
3910
        const body = eventDoc.body;
3911
        const mouseEvent = event;
3912
        mouseEvent.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
3913
        mouseEvent.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
3914
      }
3915
      return event;
3916
    };
3917
    const bindOnReady = (win, callback, eventUtils) => {
3918
      const doc = win.document, event = { type: 'ready' };
3919
      if (eventUtils.domLoaded) {
3920
        callback(event);
3921
        return;
3922
      }
3923
      const isDocReady = () => {
3924
        return doc.readyState === 'complete' || doc.readyState === 'interactive' && doc.body;
3925
      };
3926
      const readyHandler = () => {
3927
        removeEvent(win, 'DOMContentLoaded', readyHandler);
3928
        removeEvent(win, 'load', readyHandler);
3929
        if (!eventUtils.domLoaded) {
3930
          eventUtils.domLoaded = true;
3931
          callback(event);
3932
        }
3933
        win = null;
3934
      };
3935
      if (isDocReady()) {
3936
        readyHandler();
3937
      } else {
3938
        addEvent(win, 'DOMContentLoaded', readyHandler);
3939
      }
3940
      if (!eventUtils.domLoaded) {
3941
        addEvent(win, 'load', readyHandler);
3942
      }
3943
    };
3944
    class EventUtils {
3945
      constructor() {
3946
        this.domLoaded = false;
3947
        this.events = {};
3948
        this.count = 1;
3949
        this.expando = eventExpandoPrefix + (+new Date()).toString(32);
3950
        this.hasFocusIn = 'onfocusin' in document.documentElement;
3951
        this.count = 1;
3952
      }
3953
      bind(target, names, callback, scope) {
3954
        const self = this;
3955
        let callbackList;
3956
        const win = window;
3957
        const defaultNativeHandler = evt => {
3958
          self.executeHandlers(fix(evt || win.event), id);
3959
        };
1441 ariadna 3960
        if (!target || isText$b(target) || isComment(target)) {
1 efrain 3961
          return callback;
3962
        }
3963
        let id;
3964
        if (!target[self.expando]) {
3965
          id = self.count++;
3966
          target[self.expando] = id;
3967
          self.events[id] = {};
3968
        } else {
3969
          id = target[self.expando];
3970
        }
3971
        scope = scope || target;
3972
        const namesList = names.split(' ');
3973
        let i = namesList.length;
3974
        while (i--) {
3975
          let name = namesList[i];
3976
          let nativeHandler = defaultNativeHandler;
3977
          let capture = false;
3978
          let fakeName = false;
3979
          if (name === 'DOMContentLoaded') {
3980
            name = 'ready';
3981
          }
3982
          if (self.domLoaded && name === 'ready' && target.readyState === 'complete') {
3983
            callback.call(scope, fix({ type: name }));
3984
            continue;
3985
          }
3986
          if (!self.hasFocusIn && (name === 'focusin' || name === 'focusout')) {
3987
            capture = true;
3988
            fakeName = name === 'focusin' ? 'focus' : 'blur';
3989
            nativeHandler = evt => {
3990
              const event = fix(evt || win.event);
3991
              event.type = event.type === 'focus' ? 'focusin' : 'focusout';
3992
              self.executeHandlers(event, id);
3993
            };
3994
          }
3995
          callbackList = self.events[id][name];
3996
          if (!callbackList) {
3997
            self.events[id][name] = callbackList = [{
3998
                func: callback,
3999
                scope
4000
              }];
4001
            callbackList.fakeName = fakeName;
4002
            callbackList.capture = capture;
4003
            callbackList.nativeHandler = nativeHandler;
4004
            if (name === 'ready') {
4005
              bindOnReady(target, nativeHandler, self);
4006
            } else {
4007
              addEvent(target, fakeName || name, nativeHandler, capture);
4008
            }
4009
          } else {
4010
            if (name === 'ready' && self.domLoaded) {
4011
              callback(fix({ type: name }));
4012
            } else {
4013
              callbackList.push({
4014
                func: callback,
4015
                scope
4016
              });
4017
            }
4018
          }
4019
        }
4020
        target = callbackList = null;
4021
        return callback;
4022
      }
4023
      unbind(target, names, callback) {
1441 ariadna 4024
        if (!target || isText$b(target) || isComment(target)) {
1 efrain 4025
          return this;
4026
        }
4027
        const id = target[this.expando];
4028
        if (id) {
4029
          let eventMap = this.events[id];
4030
          if (names) {
4031
            const namesList = names.split(' ');
4032
            let i = namesList.length;
4033
            while (i--) {
4034
              const name = namesList[i];
4035
              const callbackList = eventMap[name];
4036
              if (callbackList) {
4037
                if (callback) {
4038
                  let ci = callbackList.length;
4039
                  while (ci--) {
4040
                    if (callbackList[ci].func === callback) {
4041
                      const nativeHandler = callbackList.nativeHandler;
4042
                      const fakeName = callbackList.fakeName, capture = callbackList.capture;
4043
                      const newCallbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
4044
                      newCallbackList.nativeHandler = nativeHandler;
4045
                      newCallbackList.fakeName = fakeName;
4046
                      newCallbackList.capture = capture;
4047
                      eventMap[name] = newCallbackList;
4048
                    }
4049
                  }
4050
                }
4051
                if (!callback || callbackList.length === 0) {
4052
                  delete eventMap[name];
4053
                  removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
4054
                }
4055
              }
4056
            }
4057
          } else {
4058
            each$d(eventMap, (callbackList, name) => {
4059
              removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
4060
            });
4061
            eventMap = {};
4062
          }
4063
          for (const name in eventMap) {
4064
            if (has$2(eventMap, name)) {
4065
              return this;
4066
            }
4067
          }
4068
          delete this.events[id];
4069
          try {
4070
            delete target[this.expando];
1441 ariadna 4071
          } catch (_a) {
1 efrain 4072
            target[this.expando] = null;
4073
          }
4074
        }
4075
        return this;
4076
      }
4077
      fire(target, name, args) {
4078
        return this.dispatch(target, name, args);
4079
      }
4080
      dispatch(target, name, args) {
1441 ariadna 4081
        if (!target || isText$b(target) || isComment(target)) {
1 efrain 4082
          return this;
4083
        }
4084
        const event = fix({
4085
          type: name,
4086
          target
4087
        }, args);
4088
        do {
4089
          const id = target[this.expando];
4090
          if (id) {
4091
            this.executeHandlers(event, id);
4092
          }
4093
          target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow;
4094
        } while (target && !event.isPropagationStopped());
4095
        return this;
4096
      }
4097
      clean(target) {
1441 ariadna 4098
        if (!target || isText$b(target) || isComment(target)) {
1 efrain 4099
          return this;
4100
        }
4101
        if (target[this.expando]) {
4102
          this.unbind(target);
4103
        }
4104
        if (!target.getElementsByTagName) {
4105
          target = target.document;
4106
        }
4107
        if (target && target.getElementsByTagName) {
4108
          this.unbind(target);
4109
          const children = target.getElementsByTagName('*');
4110
          let i = children.length;
4111
          while (i--) {
4112
            target = children[i];
4113
            if (target[this.expando]) {
4114
              this.unbind(target);
4115
            }
4116
          }
4117
        }
4118
        return this;
4119
      }
4120
      destroy() {
4121
        this.events = {};
4122
      }
4123
      cancel(e) {
4124
        if (e) {
4125
          e.preventDefault();
4126
          e.stopImmediatePropagation();
4127
        }
4128
        return false;
4129
      }
4130
      executeHandlers(evt, id) {
4131
        const container = this.events[id];
4132
        const callbackList = container && container[evt.type];
4133
        if (callbackList) {
4134
          for (let i = 0, l = callbackList.length; i < l; i++) {
4135
            const callback = callbackList[i];
4136
            if (callback && callback.func.call(callback.scope, evt) === false) {
4137
              evt.preventDefault();
4138
            }
4139
            if (evt.isImmediatePropagationStopped()) {
4140
              return;
4141
            }
4142
          }
4143
        }
4144
      }
4145
    }
4146
    EventUtils.Event = new EventUtils();
4147
 
4148
    const each$a = Tools.each;
4149
    const grep = Tools.grep;
4150
    const internalStyleName = 'data-mce-style';
4151
    const numericalCssMap = Tools.makeMap('fill-opacity font-weight line-height opacity orphans widows z-index zoom', ' ');
4152
    const legacySetAttribute = (elm, name, value) => {
4153
      if (isNullable(value) || value === '') {
1441 ariadna 4154
        remove$9(elm, name);
1 efrain 4155
      } else {
1441 ariadna 4156
        set$4(elm, name, value);
1 efrain 4157
      }
4158
    };
4159
    const camelCaseToHyphens = name => name.replace(/[A-Z]/g, v => '-' + v.toLowerCase());
4160
    const findNodeIndex = (node, normalized) => {
4161
      let idx = 0;
4162
      if (node) {
4163
        for (let lastNodeType = node.nodeType, tempNode = node.previousSibling; tempNode; tempNode = tempNode.previousSibling) {
4164
          const nodeType = tempNode.nodeType;
1441 ariadna 4165
          if (normalized && isText$b(tempNode)) {
1 efrain 4166
            if (nodeType === lastNodeType || !tempNode.data.length) {
4167
              continue;
4168
            }
4169
          }
4170
          idx++;
4171
          lastNodeType = nodeType;
4172
        }
4173
      }
4174
      return idx;
4175
    };
4176
    const updateInternalStyleAttr = (styles, elm) => {
4177
      const rawValue = get$9(elm, 'style');
4178
      const value = styles.serialize(styles.parse(rawValue), name(elm));
4179
      legacySetAttribute(elm, internalStyleName, value);
4180
    };
4181
    const convertStyleToString = (cssValue, cssName) => {
4182
      if (isNumber(cssValue)) {
4183
        return has$2(numericalCssMap, cssName) ? cssValue + '' : cssValue + 'px';
4184
      } else {
4185
        return cssValue;
4186
      }
4187
    };
4188
    const applyStyle$1 = ($elm, cssName, cssValue) => {
4189
      const normalizedName = camelCaseToHyphens(cssName);
4190
      if (isNullable(cssValue) || cssValue === '') {
1441 ariadna 4191
        remove$5($elm, normalizedName);
1 efrain 4192
      } else {
4193
        set$2($elm, normalizedName, convertStyleToString(cssValue, normalizedName));
4194
      }
4195
    };
4196
    const setupAttrHooks = (styles, settings, getContext) => {
4197
      const keepValues = settings.keep_values;
4198
      const keepUrlHook = {
4199
        set: (elm, value, name) => {
4200
          const sugarElm = SugarElement.fromDom(elm);
4201
          if (isFunction(settings.url_converter) && isNonNullable(value)) {
4202
            value = settings.url_converter.call(settings.url_converter_scope || getContext(), String(value), name, elm);
4203
          }
4204
          const internalName = 'data-mce-' + name;
4205
          legacySetAttribute(sugarElm, internalName, value);
4206
          legacySetAttribute(sugarElm, name, value);
4207
        },
4208
        get: (elm, name) => {
4209
          const sugarElm = SugarElement.fromDom(elm);
4210
          return get$9(sugarElm, 'data-mce-' + name) || get$9(sugarElm, name);
4211
        }
4212
      };
4213
      const attrHooks = {
4214
        style: {
4215
          set: (elm, value) => {
4216
            const sugarElm = SugarElement.fromDom(elm);
4217
            if (keepValues) {
4218
              legacySetAttribute(sugarElm, internalStyleName, value);
4219
            }
1441 ariadna 4220
            remove$9(sugarElm, 'style');
1 efrain 4221
            if (isString(value)) {
4222
              setAll(sugarElm, styles.parse(value));
4223
            }
4224
          },
4225
          get: elm => {
4226
            const sugarElm = SugarElement.fromDom(elm);
4227
            const value = get$9(sugarElm, internalStyleName) || get$9(sugarElm, 'style');
4228
            return styles.serialize(styles.parse(value), name(sugarElm));
4229
          }
4230
        }
4231
      };
4232
      if (keepValues) {
4233
        attrHooks.href = attrHooks.src = keepUrlHook;
4234
      }
4235
      return attrHooks;
4236
    };
4237
    const DOMUtils = (doc, settings = {}) => {
4238
      const addedStyles = {};
4239
      const win = window;
4240
      const files = {};
4241
      let counter = 0;
4242
      const stdMode = true;
4243
      const boxModel = true;
4244
      const styleSheetLoader = instance.forElement(SugarElement.fromDom(doc), {
4245
        contentCssCors: settings.contentCssCors,
4246
        referrerPolicy: settings.referrerPolicy
4247
      });
4248
      const boundEvents = [];
4249
      const schema = settings.schema ? settings.schema : Schema({});
4250
      const styles = Styles({
4251
        url_converter: settings.url_converter,
1441 ariadna 4252
        url_converter_scope: settings.url_converter_scope
1 efrain 4253
      }, settings.schema);
4254
      const events = settings.ownEvents ? new EventUtils() : EventUtils.Event;
4255
      const blockElementsMap = schema.getBlockElements();
4256
      const isBlock = node => {
4257
        if (isString(node)) {
4258
          return has$2(blockElementsMap, node);
4259
        } else {
4260
          return isElement$6(node) && (has$2(blockElementsMap, node.nodeName) || isTransparentBlock(schema, node));
4261
        }
4262
      };
4263
      const get = elm => elm && doc && isString(elm) ? doc.getElementById(elm) : elm;
4264
      const _get = elm => {
4265
        const value = get(elm);
4266
        return isNonNullable(value) ? SugarElement.fromDom(value) : null;
4267
      };
4268
      const getAttrib = (elm, name, defaultVal = '') => {
4269
        let value;
4270
        const $elm = _get(elm);
4271
        if (isNonNullable($elm) && isElement$7($elm)) {
4272
          const hook = attrHooks[name];
4273
          if (hook && hook.get) {
4274
            value = hook.get($elm.dom, name);
4275
          } else {
4276
            value = get$9($elm, name);
4277
          }
4278
        }
4279
        return isNonNullable(value) ? value : defaultVal;
4280
      };
4281
      const getAttribs = elm => {
4282
        const node = get(elm);
4283
        return isNullable(node) ? [] : node.attributes;
4284
      };
4285
      const setAttrib = (elm, name, value) => {
4286
        run(elm, e => {
4287
          if (isElement$6(e)) {
4288
            const $elm = SugarElement.fromDom(e);
4289
            const val = value === '' ? null : value;
4290
            const originalValue = get$9($elm, name);
4291
            const hook = attrHooks[name];
4292
            if (hook && hook.set) {
4293
              hook.set($elm.dom, val, name);
4294
            } else {
4295
              legacySetAttribute($elm, name, val);
4296
            }
4297
            if (originalValue !== val && settings.onSetAttrib) {
4298
              settings.onSetAttrib({
4299
                attrElm: $elm.dom,
4300
                attrName: name,
4301
                attrValue: val
4302
              });
4303
            }
4304
          }
4305
        });
4306
      };
4307
      const clone = (node, deep) => {
4308
        return node.cloneNode(deep);
4309
      };
4310
      const getRoot = () => settings.root_element || doc.body;
4311
      const getViewPort = argWin => {
4312
        const vp = getBounds(argWin);
4313
        return {
4314
          x: vp.x,
4315
          y: vp.y,
4316
          w: vp.width,
4317
          h: vp.height
4318
        };
4319
      };
4320
      const getPos$1 = (elm, rootElm) => getPos(doc.body, get(elm), rootElm);
4321
      const setStyle = (elm, name, value) => {
4322
        run(elm, e => {
4323
          const $elm = SugarElement.fromDom(e);
4324
          applyStyle$1($elm, name, value);
4325
          if (settings.update_styles) {
4326
            updateInternalStyleAttr(styles, $elm);
4327
          }
4328
        });
4329
      };
4330
      const setStyles = (elm, stylesArg) => {
4331
        run(elm, e => {
4332
          const $elm = SugarElement.fromDom(e);
4333
          each$d(stylesArg, (v, n) => {
4334
            applyStyle$1($elm, n, v);
4335
          });
4336
          if (settings.update_styles) {
4337
            updateInternalStyleAttr(styles, $elm);
4338
          }
4339
        });
4340
      };
4341
      const getStyle = (elm, name, computed) => {
4342
        const $elm = get(elm);
4343
        if (isNullable($elm) || !isHTMLElement($elm) && !isSVGElement($elm)) {
4344
          return undefined;
4345
        }
4346
        if (computed) {
4347
          return get$7(SugarElement.fromDom($elm), camelCaseToHyphens(name));
4348
        } else {
4349
          name = name.replace(/-(\D)/g, (a, b) => b.toUpperCase());
4350
          if (name === 'float') {
4351
            name = 'cssFloat';
4352
          }
4353
          return $elm.style ? $elm.style[name] : undefined;
4354
        }
4355
      };
4356
      const getSize = elm => {
4357
        const $elm = get(elm);
4358
        if (!$elm) {
4359
          return {
4360
            w: 0,
4361
            h: 0
4362
          };
4363
        }
4364
        let w = getStyle($elm, 'width');
4365
        let h = getStyle($elm, 'height');
4366
        if (!w || w.indexOf('px') === -1) {
4367
          w = '0';
4368
        }
4369
        if (!h || h.indexOf('px') === -1) {
4370
          h = '0';
4371
        }
4372
        return {
4373
          w: parseInt(w, 10) || $elm.offsetWidth || $elm.clientWidth,
4374
          h: parseInt(h, 10) || $elm.offsetHeight || $elm.clientHeight
4375
        };
4376
      };
4377
      const getRect = elm => {
4378
        const $elm = get(elm);
4379
        const pos = getPos$1($elm);
4380
        const size = getSize($elm);
4381
        return {
4382
          x: pos.x,
4383
          y: pos.y,
4384
          w: size.w,
4385
          h: size.h
4386
        };
4387
      };
4388
      const is = (elm, selector) => {
4389
        if (!elm) {
4390
          return false;
4391
        }
4392
        const elms = isArray$1(elm) ? elm : [elm];
4393
        return exists(elms, e => {
4394
          return is$1(SugarElement.fromDom(e), selector);
4395
        });
4396
      };
4397
      const getParents = (elm, selector, root, collect) => {
4398
        const result = [];
4399
        let node = get(elm);
4400
        collect = collect === undefined;
4401
        const resolvedRoot = root || (getRoot().nodeName !== 'BODY' ? getRoot().parentNode : null);
4402
        if (isString(selector)) {
4403
          if (selector === '*') {
4404
            selector = isElement$6;
4405
          } else {
4406
            const selectorVal = selector;
4407
            selector = node => is(node, selectorVal);
4408
          }
4409
        }
4410
        while (node) {
4411
          if (node === resolvedRoot || isNullable(node.nodeType) || isDocument$1(node) || isDocumentFragment(node)) {
4412
            break;
4413
          }
4414
          if (!selector || selector(node)) {
4415
            if (collect) {
4416
              result.push(node);
4417
            } else {
4418
              return [node];
4419
            }
4420
          }
4421
          node = node.parentNode;
4422
        }
4423
        return collect ? result : null;
4424
      };
4425
      const getParent = (node, selector, root) => {
4426
        const parents = getParents(node, selector, root, false);
4427
        return parents && parents.length > 0 ? parents[0] : null;
4428
      };
4429
      const _findSib = (node, selector, name) => {
4430
        let func = selector;
4431
        if (node) {
4432
          if (isString(selector)) {
4433
            func = node => {
4434
              return is(node, selector);
4435
            };
4436
          }
4437
          for (let tempNode = node[name]; tempNode; tempNode = tempNode[name]) {
4438
            if (isFunction(func) && func(tempNode)) {
4439
              return tempNode;
4440
            }
4441
          }
4442
        }
4443
        return null;
4444
      };
4445
      const getNext = (node, selector) => _findSib(node, selector, 'nextSibling');
4446
      const getPrev = (node, selector) => _findSib(node, selector, 'previousSibling');
4447
      const isParentNode = node => isFunction(node.querySelectorAll);
4448
      const select = (selector, scope) => {
4449
        var _a, _b;
4450
        const elm = (_b = (_a = get(scope)) !== null && _a !== void 0 ? _a : settings.root_element) !== null && _b !== void 0 ? _b : doc;
4451
        return isParentNode(elm) ? from(elm.querySelectorAll(selector)) : [];
4452
      };
4453
      const run = function (elm, func, scope) {
4454
        const context = scope !== null && scope !== void 0 ? scope : this;
4455
        if (isArray$1(elm)) {
4456
          const result = [];
4457
          each$a(elm, (e, i) => {
4458
            const node = get(e);
4459
            if (node) {
4460
              result.push(func.call(context, node, i));
4461
            }
4462
          });
4463
          return result;
4464
        } else {
4465
          const node = get(elm);
4466
          return !node ? false : func.call(context, node);
4467
        }
4468
      };
4469
      const setAttribs = (elm, attrs) => {
4470
        run(elm, $elm => {
4471
          each$d(attrs, (value, name) => {
4472
            setAttrib($elm, name, value);
4473
          });
4474
        });
4475
      };
4476
      const setHTML = (elm, html) => {
4477
        run(elm, e => {
4478
          const $elm = SugarElement.fromDom(e);
4479
          set$1($elm, html);
4480
        });
4481
      };
4482
      const add = (parentElm, name, attrs, html, create) => run(parentElm, parentElm => {
4483
        const newElm = isString(name) ? doc.createElement(name) : name;
4484
        if (isNonNullable(attrs)) {
4485
          setAttribs(newElm, attrs);
4486
        }
4487
        if (html) {
4488
          if (!isString(html) && html.nodeType) {
4489
            newElm.appendChild(html);
4490
          } else if (isString(html)) {
4491
            setHTML(newElm, html);
4492
          }
4493
        }
4494
        return !create ? parentElm.appendChild(newElm) : newElm;
4495
      });
4496
      const create = (name, attrs, html) => add(doc.createElement(name), name, attrs, html, true);
4497
      const decode = Entities.decode;
4498
      const encode = Entities.encodeAllRaw;
4499
      const createHTML = (name, attrs, html = '') => {
4500
        let outHtml = '<' + name;
4501
        for (const key in attrs) {
4502
          if (hasNonNullableKey(attrs, key)) {
4503
            outHtml += ' ' + key + '="' + encode(attrs[key]) + '"';
4504
          }
4505
        }
4506
        if (isEmpty$3(html) && has$2(schema.getVoidElements(), name)) {
4507
          return outHtml + ' />';
4508
        } else {
4509
          return outHtml + '>' + html + '</' + name + '>';
4510
        }
4511
      };
4512
      const createFragment = html => {
4513
        const container = doc.createElement('div');
4514
        const frag = doc.createDocumentFragment();
4515
        frag.appendChild(container);
4516
        if (html) {
4517
          container.innerHTML = html;
4518
        }
4519
        let node;
4520
        while (node = container.firstChild) {
4521
          frag.appendChild(node);
4522
        }
4523
        frag.removeChild(container);
4524
        return frag;
4525
      };
4526
      const remove = (node, keepChildren) => {
4527
        return run(node, n => {
4528
          const $node = SugarElement.fromDom(n);
4529
          if (keepChildren) {
4530
            each$e(children$1($node), child => {
1441 ariadna 4531
              if (isText$c(child) && child.dom.length === 0) {
4532
                remove$4(child);
1 efrain 4533
              } else {
4534
                before$3($node, child);
4535
              }
4536
            });
4537
          }
1441 ariadna 4538
          remove$4($node);
1 efrain 4539
          return $node.dom;
4540
        });
4541
      };
4542
      const removeAllAttribs = e => run(e, e => {
4543
        const attrs = e.attributes;
4544
        for (let i = attrs.length - 1; i >= 0; i--) {
4545
          e.removeAttributeNode(attrs.item(i));
4546
        }
4547
      });
4548
      const parseStyle = cssText => styles.parse(cssText);
4549
      const serializeStyle = (stylesArg, name) => styles.serialize(stylesArg, name);
4550
      const addStyle = cssText => {
4551
        if (self !== DOMUtils.DOM && doc === document) {
4552
          if (addedStyles[cssText]) {
4553
            return;
4554
          }
4555
          addedStyles[cssText] = true;
4556
        }
4557
        let styleElm = doc.getElementById('mceDefaultStyles');
4558
        if (!styleElm) {
4559
          styleElm = doc.createElement('style');
4560
          styleElm.id = 'mceDefaultStyles';
4561
          styleElm.type = 'text/css';
4562
          const head = doc.head;
4563
          if (head.firstChild) {
4564
            head.insertBefore(styleElm, head.firstChild);
4565
          } else {
4566
            head.appendChild(styleElm);
4567
          }
4568
        }
4569
        if (styleElm.styleSheet) {
4570
          styleElm.styleSheet.cssText += cssText;
4571
        } else {
4572
          styleElm.appendChild(doc.createTextNode(cssText));
4573
        }
4574
      };
4575
      const loadCSS = urls => {
4576
        if (!urls) {
4577
          urls = '';
4578
        }
4579
        each$e(urls.split(','), url => {
4580
          files[url] = true;
4581
          styleSheetLoader.load(url).catch(noop);
4582
        });
4583
      };
4584
      const toggleClass = (elm, cls, state) => {
4585
        run(elm, e => {
4586
          if (isElement$6(e)) {
4587
            const $elm = SugarElement.fromDom(e);
4588
            const classes = cls.split(' ');
4589
            each$e(classes, c => {
4590
              if (isNonNullable(state)) {
1441 ariadna 4591
                const fn = state ? add$2 : remove$6;
1 efrain 4592
                fn($elm, c);
4593
              } else {
4594
                toggle$1($elm, c);
4595
              }
4596
            });
4597
          }
4598
        });
4599
      };
4600
      const addClass = (elm, cls) => {
4601
        toggleClass(elm, cls, true);
4602
      };
4603
      const removeClass = (elm, cls) => {
4604
        toggleClass(elm, cls, false);
4605
      };
4606
      const hasClass = (elm, cls) => {
4607
        const $elm = _get(elm);
4608
        const classes = cls.split(' ');
4609
        return isNonNullable($elm) && forall(classes, c => has($elm, c));
4610
      };
4611
      const show = elm => {
1441 ariadna 4612
        run(elm, e => remove$5(SugarElement.fromDom(e), 'display'));
1 efrain 4613
      };
4614
      const hide = elm => {
4615
        run(elm, e => set$2(SugarElement.fromDom(e), 'display', 'none'));
4616
      };
4617
      const isHidden = elm => {
4618
        const $elm = _get(elm);
4619
        return isNonNullable($elm) && is$2(getRaw($elm, 'display'), 'none');
4620
      };
4621
      const uniqueId = prefix => (!prefix ? 'mce_' : prefix) + counter++;
4622
      const getOuterHTML = elm => {
4623
        const $elm = _get(elm);
4624
        if (isNonNullable($elm)) {
4625
          return isElement$6($elm.dom) ? $elm.dom.outerHTML : getOuter($elm);
4626
        } else {
4627
          return '';
4628
        }
4629
      };
4630
      const setOuterHTML = (elm, html) => {
4631
        run(elm, $elm => {
4632
          if (isElement$6($elm)) {
4633
            $elm.outerHTML = html;
4634
          }
4635
        });
4636
      };
4637
      const insertAfter = (node, reference) => {
4638
        const referenceNode = get(reference);
4639
        return run(node, node => {
4640
          const parent = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.parentNode;
4641
          const nextSibling = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.nextSibling;
4642
          if (parent) {
4643
            if (nextSibling) {
4644
              parent.insertBefore(node, nextSibling);
4645
            } else {
4646
              parent.appendChild(node);
4647
            }
4648
          }
4649
          return node;
4650
        });
4651
      };
4652
      const replace = (newElm, oldElm, keepChildren) => run(oldElm, elm => {
4653
        var _a;
4654
        const replacee = isArray$1(oldElm) ? newElm.cloneNode(true) : newElm;
4655
        if (keepChildren) {
4656
          each$a(grep(elm.childNodes), node => {
4657
            replacee.appendChild(node);
4658
          });
4659
        }
4660
        (_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(replacee, elm);
4661
        return elm;
4662
      });
4663
      const rename = (elm, name) => {
4664
        if (elm.nodeName !== name.toUpperCase()) {
4665
          const newElm = create(name);
4666
          each$a(getAttribs(elm), attrNode => {
4667
            setAttrib(newElm, attrNode.nodeName, getAttrib(elm, attrNode.nodeName));
4668
          });
4669
          replace(newElm, elm, true);
4670
          return newElm;
4671
        } else {
4672
          return elm;
4673
        }
4674
      };
4675
      const findCommonAncestor = (a, b) => {
4676
        let ps = a;
4677
        while (ps) {
4678
          let pe = b;
4679
          while (pe && ps !== pe) {
4680
            pe = pe.parentNode;
4681
          }
4682
          if (ps === pe) {
4683
            break;
4684
          }
4685
          ps = ps.parentNode;
4686
        }
4687
        if (!ps && a.ownerDocument) {
4688
          return a.ownerDocument.documentElement;
4689
        } else {
4690
          return ps;
4691
        }
4692
      };
4693
      const isEmpty = (node, elements, options) => {
1441 ariadna 4694
        if (isPlainObject(elements)) {
4695
          const isContent = node => {
4696
            const name = node.nodeName.toLowerCase();
4697
            return Boolean(elements[name]);
4698
          };
4699
          return isEmptyNode(schema, node, {
4700
            ...options,
4701
            isContent
4702
          });
4703
        } else {
4704
          return isEmptyNode(schema, node, options);
1 efrain 4705
        }
4706
      };
4707
      const createRng = () => doc.createRange();
4708
      const split = (parentElm, splitElm, replacementElm) => {
4709
        let range = createRng();
4710
        let beforeFragment;
4711
        let afterFragment;
4712
        if (parentElm && splitElm && parentElm.parentNode && splitElm.parentNode) {
4713
          const parentNode = parentElm.parentNode;
4714
          range.setStart(parentNode, findNodeIndex(parentElm));
4715
          range.setEnd(splitElm.parentNode, findNodeIndex(splitElm));
4716
          beforeFragment = range.extractContents();
4717
          range = createRng();
4718
          range.setStart(splitElm.parentNode, findNodeIndex(splitElm) + 1);
4719
          range.setEnd(parentNode, findNodeIndex(parentElm) + 1);
4720
          afterFragment = range.extractContents();
4721
          parentNode.insertBefore(trimNode(self, beforeFragment, schema), parentElm);
4722
          if (replacementElm) {
4723
            parentNode.insertBefore(replacementElm, parentElm);
4724
          } else {
4725
            parentNode.insertBefore(splitElm, parentElm);
4726
          }
4727
          parentNode.insertBefore(trimNode(self, afterFragment, schema), parentElm);
4728
          remove(parentElm);
4729
          return replacementElm || splitElm;
4730
        } else {
4731
          return undefined;
4732
        }
4733
      };
4734
      const bind = (target, name, func, scope) => {
4735
        if (isArray$1(target)) {
4736
          let i = target.length;
4737
          const rv = [];
4738
          while (i--) {
4739
            rv[i] = bind(target[i], name, func, scope);
4740
          }
4741
          return rv;
4742
        } else {
4743
          if (settings.collect && (target === doc || target === win)) {
4744
            boundEvents.push([
4745
              target,
4746
              name,
4747
              func,
4748
              scope
4749
            ]);
4750
          }
4751
          return events.bind(target, name, func, scope || self);
4752
        }
4753
      };
4754
      const unbind = (target, name, func) => {
4755
        if (isArray$1(target)) {
4756
          let i = target.length;
4757
          const rv = [];
4758
          while (i--) {
4759
            rv[i] = unbind(target[i], name, func);
4760
          }
4761
          return rv;
4762
        } else {
4763
          if (boundEvents.length > 0 && (target === doc || target === win)) {
4764
            let i = boundEvents.length;
4765
            while (i--) {
4766
              const [boundTarget, boundName, boundFunc] = boundEvents[i];
4767
              if (target === boundTarget && (!name || name === boundName) && (!func || func === boundFunc)) {
4768
                events.unbind(boundTarget, boundName, boundFunc);
4769
              }
4770
            }
4771
          }
4772
          return events.unbind(target, name, func);
4773
        }
4774
      };
4775
      const dispatch = (target, name, evt) => events.dispatch(target, name, evt);
4776
      const fire = (target, name, evt) => events.dispatch(target, name, evt);
4777
      const getContentEditable = node => {
4778
        if (node && isHTMLElement(node)) {
4779
          const contentEditable = node.getAttribute('data-mce-contenteditable');
4780
          if (contentEditable && contentEditable !== 'inherit') {
4781
            return contentEditable;
4782
          }
4783
          return node.contentEditable !== 'inherit' ? node.contentEditable : null;
4784
        } else {
4785
          return null;
4786
        }
4787
      };
4788
      const getContentEditableParent = node => {
4789
        const root = getRoot();
4790
        let state = null;
4791
        for (let tempNode = node; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
4792
          state = getContentEditable(tempNode);
4793
          if (state !== null) {
4794
            break;
4795
          }
4796
        }
4797
        return state;
4798
      };
4799
      const isEditable = node => {
4800
        if (isNonNullable(node)) {
4801
          const scope = isElement$6(node) ? node : node.parentElement;
4802
          return isNonNullable(scope) && isHTMLElement(scope) && isEditable$2(SugarElement.fromDom(scope));
4803
        } else {
4804
          return false;
4805
        }
4806
      };
4807
      const destroy = () => {
4808
        if (boundEvents.length > 0) {
4809
          let i = boundEvents.length;
4810
          while (i--) {
4811
            const [boundTarget, boundName, boundFunc] = boundEvents[i];
4812
            events.unbind(boundTarget, boundName, boundFunc);
4813
          }
4814
        }
4815
        each$d(files, (_, url) => {
4816
          styleSheetLoader.unload(url);
4817
          delete files[url];
4818
        });
4819
      };
4820
      const isChildOf = (node, parent) => {
4821
        return node === parent || parent.contains(node);
4822
      };
4823
      const dumpRng = r => 'startContainer: ' + r.startContainer.nodeName + ', startOffset: ' + r.startOffset + ', endContainer: ' + r.endContainer.nodeName + ', endOffset: ' + r.endOffset;
4824
      const self = {
4825
        doc,
4826
        settings,
4827
        win,
4828
        files,
4829
        stdMode,
4830
        boxModel,
4831
        styleSheetLoader,
4832
        boundEvents,
4833
        styles,
4834
        schema,
4835
        events,
4836
        isBlock: isBlock,
4837
        root: null,
4838
        clone,
4839
        getRoot,
4840
        getViewPort,
4841
        getRect,
4842
        getSize,
4843
        getParent,
4844
        getParents: getParents,
4845
        get,
4846
        getNext,
4847
        getPrev,
4848
        select,
4849
        is,
4850
        add,
4851
        create,
4852
        createHTML,
4853
        createFragment,
4854
        remove,
4855
        setStyle,
4856
        getStyle: getStyle,
4857
        setStyles,
4858
        removeAllAttribs,
4859
        setAttrib,
4860
        setAttribs,
4861
        getAttrib,
4862
        getPos: getPos$1,
4863
        parseStyle,
4864
        serializeStyle,
4865
        addStyle,
4866
        loadCSS,
4867
        addClass,
4868
        removeClass,
4869
        hasClass,
4870
        toggleClass,
4871
        show,
4872
        hide,
4873
        isHidden,
4874
        uniqueId,
4875
        setHTML,
4876
        getOuterHTML,
4877
        setOuterHTML,
4878
        decode,
4879
        encode,
4880
        insertAfter,
4881
        replace,
4882
        rename,
4883
        findCommonAncestor,
4884
        run,
4885
        getAttribs,
4886
        isEmpty,
4887
        createRng,
4888
        nodeIndex: findNodeIndex,
4889
        split,
4890
        bind: bind,
4891
        unbind: unbind,
4892
        fire,
4893
        dispatch,
4894
        getContentEditable,
4895
        getContentEditableParent,
4896
        isEditable,
4897
        destroy,
4898
        isChildOf,
4899
        dumpRng
4900
      };
4901
      const attrHooks = setupAttrHooks(styles, settings, constant(self));
4902
      return self;
4903
    };
4904
    DOMUtils.DOM = DOMUtils(document);
4905
    DOMUtils.nodeIndex = findNodeIndex;
4906
 
4907
    const DOM$b = DOMUtils.DOM;
4908
    const QUEUED = 0;
4909
    const LOADING = 1;
4910
    const LOADED = 2;
4911
    const FAILED = 3;
4912
    class ScriptLoader {
4913
      constructor(settings = {}) {
4914
        this.states = {};
4915
        this.queue = [];
4916
        this.scriptLoadedCallbacks = {};
4917
        this.queueLoadedCallbacks = [];
4918
        this.loading = false;
4919
        this.settings = settings;
4920
      }
4921
      _setReferrerPolicy(referrerPolicy) {
4922
        this.settings.referrerPolicy = referrerPolicy;
4923
      }
4924
      loadScript(url) {
4925
        return new Promise((resolve, reject) => {
4926
          const dom = DOM$b;
4927
          let elm;
4928
          const cleanup = () => {
4929
            dom.remove(id);
4930
            if (elm) {
4931
              elm.onerror = elm.onload = elm = null;
4932
            }
4933
          };
4934
          const done = () => {
4935
            cleanup();
4936
            resolve();
4937
          };
4938
          const error = () => {
4939
            cleanup();
4940
            reject('Failed to load script: ' + url);
4941
          };
4942
          const id = dom.uniqueId();
4943
          elm = document.createElement('script');
4944
          elm.id = id;
4945
          elm.type = 'text/javascript';
4946
          elm.src = Tools._addCacheSuffix(url);
4947
          if (this.settings.referrerPolicy) {
4948
            dom.setAttrib(elm, 'referrerpolicy', this.settings.referrerPolicy);
4949
          }
4950
          elm.onload = done;
4951
          elm.onerror = error;
4952
          (document.getElementsByTagName('head')[0] || document.body).appendChild(elm);
4953
        });
4954
      }
4955
      isDone(url) {
4956
        return this.states[url] === LOADED;
4957
      }
4958
      markDone(url) {
4959
        this.states[url] = LOADED;
4960
      }
4961
      add(url) {
4962
        const self = this;
4963
        self.queue.push(url);
4964
        const state = self.states[url];
4965
        if (state === undefined) {
4966
          self.states[url] = QUEUED;
4967
        }
4968
        return new Promise((resolve, reject) => {
4969
          if (!self.scriptLoadedCallbacks[url]) {
4970
            self.scriptLoadedCallbacks[url] = [];
4971
          }
4972
          self.scriptLoadedCallbacks[url].push({
4973
            resolve,
4974
            reject
4975
          });
4976
        });
4977
      }
4978
      load(url) {
4979
        return this.add(url);
4980
      }
4981
      remove(url) {
4982
        delete this.states[url];
4983
        delete this.scriptLoadedCallbacks[url];
4984
      }
4985
      loadQueue() {
4986
        const queue = this.queue;
4987
        this.queue = [];
4988
        return this.loadScripts(queue);
4989
      }
4990
      loadScripts(scripts) {
4991
        const self = this;
4992
        const execCallbacks = (name, url) => {
4993
          get$a(self.scriptLoadedCallbacks, url).each(callbacks => {
4994
            each$e(callbacks, callback => callback[name](url));
4995
          });
4996
          delete self.scriptLoadedCallbacks[url];
4997
        };
4998
        const processResults = results => {
4999
          const failures = filter$5(results, result => result.status === 'rejected');
5000
          if (failures.length > 0) {
5001
            return Promise.reject(bind$3(failures, ({reason}) => isArray$1(reason) ? reason : [reason]));
5002
          } else {
5003
            return Promise.resolve();
5004
          }
5005
        };
5006
        const load = urls => Promise.allSettled(map$3(urls, url => {
5007
          if (self.states[url] === LOADED) {
5008
            execCallbacks('resolve', url);
5009
            return Promise.resolve();
5010
          } else if (self.states[url] === FAILED) {
5011
            execCallbacks('reject', url);
5012
            return Promise.reject(url);
5013
          } else {
5014
            self.states[url] = LOADING;
5015
            return self.loadScript(url).then(() => {
5016
              self.states[url] = LOADED;
5017
              execCallbacks('resolve', url);
5018
              const queue = self.queue;
5019
              if (queue.length > 0) {
5020
                self.queue = [];
5021
                return load(queue).then(processResults);
5022
              } else {
5023
                return Promise.resolve();
5024
              }
5025
            }, () => {
5026
              self.states[url] = FAILED;
5027
              execCallbacks('reject', url);
5028
              return Promise.reject(url);
5029
            });
5030
          }
5031
        }));
5032
        const processQueue = urls => {
5033
          self.loading = true;
5034
          return load(urls).then(results => {
5035
            self.loading = false;
5036
            const nextQueuedItem = self.queueLoadedCallbacks.shift();
5037
            Optional.from(nextQueuedItem).each(call);
5038
            return processResults(results);
5039
          });
5040
        };
5041
        const uniqueScripts = stringArray(scripts);
5042
        if (self.loading) {
5043
          return new Promise((resolve, reject) => {
5044
            self.queueLoadedCallbacks.push(() => {
5045
              processQueue(uniqueScripts).then(resolve, reject);
5046
            });
5047
          });
5048
        } else {
5049
          return processQueue(uniqueScripts);
5050
        }
5051
      }
5052
    }
5053
    ScriptLoader.ScriptLoader = new ScriptLoader();
5054
 
5055
    const isDuplicated = (items, item) => {
5056
      const firstIndex = items.indexOf(item);
5057
      return firstIndex !== -1 && items.indexOf(item, firstIndex + 1) > firstIndex;
5058
    };
5059
    const isRaw = str => isObject(str) && has$2(str, 'raw');
5060
    const isTokenised = str => isArray$1(str) && str.length > 1;
5061
    const data = {};
5062
    const currentCode = Cell('en');
5063
    const getLanguageData = () => get$a(data, currentCode.get());
5064
    const getData$1 = () => map$2(data, value => ({ ...value }));
5065
    const setCode = newCode => {
5066
      if (newCode) {
5067
        currentCode.set(newCode);
5068
      }
5069
    };
5070
    const getCode = () => currentCode.get();
5071
    const add$1 = (code, items) => {
5072
      let langData = data[code];
5073
      if (!langData) {
5074
        data[code] = langData = {};
5075
      }
5076
      const lcNames = map$3(keys(items), name => name.toLowerCase());
5077
      each$d(items, (translation, name) => {
5078
        const lcName = name.toLowerCase();
5079
        if (lcName !== name && isDuplicated(lcNames, lcName)) {
5080
          if (!has$2(items, lcName)) {
5081
            langData[lcName] = translation;
5082
          }
5083
          langData[name] = translation;
5084
        } else {
5085
          langData[lcName] = translation;
5086
        }
5087
      });
5088
    };
5089
    const translate = text => {
5090
      const langData = getLanguageData().getOr({});
5091
      const toString = obj => {
5092
        if (isFunction(obj)) {
5093
          return Object.prototype.toString.call(obj);
5094
        }
5095
        return !isEmpty(obj) ? '' + obj : '';
5096
      };
5097
      const isEmpty = text => text === '' || text === null || text === undefined;
5098
      const getLangData = text => {
5099
        const textStr = toString(text);
5100
        return has$2(langData, textStr) ? toString(langData[textStr]) : get$a(langData, textStr.toLowerCase()).map(toString).getOr(textStr);
5101
      };
5102
      const removeContext = str => str.replace(/{context:\w+}$/, '');
5103
      if (isEmpty(text)) {
5104
        return '';
5105
      }
5106
      if (isRaw(text)) {
5107
        return toString(text.raw);
5108
      }
5109
      if (isTokenised(text)) {
5110
        const values = text.slice(1);
5111
        const substitued = getLangData(text[0]).replace(/\{([0-9]+)\}/g, ($1, $2) => has$2(values, $2) ? toString(values[$2]) : $1);
5112
        return removeContext(substitued);
5113
      }
5114
      return removeContext(getLangData(text));
5115
    };
5116
    const isRtl$1 = () => getLanguageData().bind(items => get$a(items, '_dir')).exists(dir => dir === 'rtl');
5117
    const hasCode = code => has$2(data, code);
5118
    const I18n = {
5119
      getData: getData$1,
5120
      setCode,
5121
      getCode,
5122
      add: add$1,
5123
      translate,
5124
      isRtl: isRtl$1,
5125
      hasCode
5126
    };
5127
 
5128
    const AddOnManager = () => {
5129
      const items = [];
5130
      const urls = {};
5131
      const lookup = {};
5132
      const _listeners = [];
5133
      const runListeners = (name, state) => {
5134
        const matchedListeners = filter$5(_listeners, listener => listener.name === name && listener.state === state);
5135
        each$e(matchedListeners, listener => listener.resolve());
5136
      };
5137
      const isLoaded = name => has$2(urls, name);
5138
      const isAdded = name => has$2(lookup, name);
5139
      const get = name => {
5140
        if (lookup[name]) {
5141
          return lookup[name].instance;
5142
        }
5143
        return undefined;
5144
      };
5145
      const loadLanguagePack = (name, languages) => {
5146
        const language = I18n.getCode();
5147
        const wrappedLanguages = ',' + (languages || '') + ',';
5148
        if (!language || languages && wrappedLanguages.indexOf(',' + language + ',') === -1) {
5149
          return;
5150
        }
5151
        ScriptLoader.ScriptLoader.add(urls[name] + '/langs/' + language + '.js');
5152
      };
5153
      const requireLangPack = (name, languages) => {
5154
        if (AddOnManager.languageLoad !== false) {
5155
          if (isLoaded(name)) {
5156
            loadLanguagePack(name, languages);
5157
          } else {
5158
            waitFor(name, 'loaded').then(() => loadLanguagePack(name, languages));
5159
          }
5160
        }
5161
      };
5162
      const add = (id, addOn) => {
5163
        items.push(addOn);
5164
        lookup[id] = { instance: addOn };
5165
        runListeners(id, 'added');
5166
        return addOn;
5167
      };
5168
      const remove = name => {
5169
        delete urls[name];
5170
        delete lookup[name];
5171
      };
5172
      const createUrl = (baseUrl, dep) => {
5173
        if (isString(dep)) {
5174
          return isString(baseUrl) ? {
5175
            prefix: '',
5176
            resource: dep,
5177
            suffix: ''
5178
          } : {
5179
            prefix: baseUrl.prefix,
5180
            resource: dep,
5181
            suffix: baseUrl.suffix
5182
          };
5183
        } else {
5184
          return dep;
5185
        }
5186
      };
5187
      const load = (name, addOnUrl) => {
5188
        if (urls[name]) {
5189
          return Promise.resolve();
5190
        }
5191
        let urlString = isString(addOnUrl) ? addOnUrl : addOnUrl.prefix + addOnUrl.resource + addOnUrl.suffix;
5192
        if (urlString.indexOf('/') !== 0 && urlString.indexOf('://') === -1) {
5193
          urlString = AddOnManager.baseURL + '/' + urlString;
5194
        }
5195
        urls[name] = urlString.substring(0, urlString.lastIndexOf('/'));
5196
        const done = () => {
5197
          runListeners(name, 'loaded');
5198
          return Promise.resolve();
5199
        };
5200
        if (lookup[name]) {
5201
          return done();
5202
        } else {
5203
          return ScriptLoader.ScriptLoader.add(urlString).then(done);
5204
        }
5205
      };
5206
      const waitFor = (name, state = 'added') => {
5207
        if (state === 'added' && isAdded(name)) {
5208
          return Promise.resolve();
5209
        } else if (state === 'loaded' && isLoaded(name)) {
5210
          return Promise.resolve();
5211
        } else {
5212
          return new Promise(resolve => {
5213
            _listeners.push({
5214
              name,
5215
              state,
5216
              resolve
5217
            });
5218
          });
5219
        }
5220
      };
5221
      return {
5222
        items,
5223
        urls,
5224
        lookup,
5225
        get,
5226
        requireLangPack,
5227
        add,
5228
        remove,
5229
        createUrl,
5230
        load,
5231
        waitFor
5232
      };
5233
    };
5234
    AddOnManager.languageLoad = true;
5235
    AddOnManager.baseURL = '';
5236
    AddOnManager.PluginManager = AddOnManager();
5237
    AddOnManager.ThemeManager = AddOnManager();
5238
    AddOnManager.ModelManager = AddOnManager();
5239
 
5240
    const first$1 = (fn, rate) => {
5241
      let timer = null;
5242
      const cancel = () => {
5243
        if (!isNull(timer)) {
5244
          clearTimeout(timer);
5245
          timer = null;
5246
        }
5247
      };
5248
      const throttle = (...args) => {
5249
        if (isNull(timer)) {
5250
          timer = setTimeout(() => {
5251
            timer = null;
5252
            fn.apply(null, args);
5253
          }, rate);
5254
        }
5255
      };
5256
      return {
5257
        cancel,
5258
        throttle
5259
      };
5260
    };
1441 ariadna 5261
    const last = (fn, rate) => {
1 efrain 5262
      let timer = null;
5263
      const cancel = () => {
5264
        if (!isNull(timer)) {
5265
          clearTimeout(timer);
5266
          timer = null;
5267
        }
5268
      };
5269
      const throttle = (...args) => {
5270
        cancel();
5271
        timer = setTimeout(() => {
5272
          timer = null;
5273
          fn.apply(null, args);
5274
        }, rate);
5275
      };
5276
      return {
5277
        cancel,
5278
        throttle
5279
      };
5280
    };
5281
 
1441 ariadna 5282
    const ancestor$1 = (scope, selector, isRoot) => ancestor$3(scope, selector, isRoot).isSome();
5283
 
1 efrain 5284
    const annotation = constant('mce-annotation');
5285
    const dataAnnotation = constant('data-mce-annotation');
5286
    const dataAnnotationId = constant('data-mce-annotation-uid');
5287
    const dataAnnotationActive = constant('data-mce-annotation-active');
5288
    const dataAnnotationClasses = constant('data-mce-annotation-classes');
5289
    const dataAnnotationAttributes = constant('data-mce-annotation-attrs');
5290
 
5291
    const isRoot$1 = root => node => eq(node, root);
5292
    const identify = (editor, annotationName) => {
5293
      const rng = editor.selection.getRng();
5294
      const start = SugarElement.fromDom(rng.startContainer);
5295
      const root = SugarElement.fromDom(editor.getBody());
5296
      const selector = annotationName.fold(() => '.' + annotation(), an => `[${ dataAnnotation() }="${ an }"]`);
5297
      const newStart = child$1(start, rng.startOffset).getOr(start);
5298
      const closest = closest$3(newStart, selector, isRoot$1(root));
5299
      return closest.bind(c => getOpt(c, `${ dataAnnotationId() }`).bind(uid => getOpt(c, `${ dataAnnotation() }`).map(name => {
5300
        const elements = findMarkers(editor, uid);
5301
        return {
5302
          uid,
5303
          name,
5304
          elements
5305
        };
5306
      })));
5307
    };
5308
    const isAnnotation = elem => isElement$7(elem) && has(elem, annotation());
1441 ariadna 5309
    const isBogusElement = (elem, root) => has$1(elem, 'data-mce-bogus') || ancestor$1(elem, '[data-mce-bogus="all"]', isRoot$1(root));
1 efrain 5310
    const findMarkers = (editor, uid) => {
5311
      const body = SugarElement.fromDom(editor.getBody());
5312
      const descendants$1 = descendants(body, `[${ dataAnnotationId() }="${ uid }"]`);
5313
      return filter$5(descendants$1, descendant => !isBogusElement(descendant, body));
5314
    };
5315
    const findAll = (editor, name) => {
5316
      const body = SugarElement.fromDom(editor.getBody());
5317
      const markers = descendants(body, `[${ dataAnnotation() }="${ name }"]`);
5318
      const directory = {};
5319
      each$e(markers, m => {
5320
        if (!isBogusElement(m, body)) {
5321
          const uid = get$9(m, dataAnnotationId());
5322
          const nodesAlready = get$a(directory, uid).getOr([]);
5323
          directory[uid] = nodesAlready.concat([m]);
5324
        }
5325
      });
5326
      return directory;
5327
    };
5328
 
5329
    const setup$y = (editor, registry) => {
5330
      const changeCallbacks = Cell({});
5331
      const initData = () => ({
5332
        listeners: [],
5333
        previous: value$2()
5334
      });
5335
      const withCallbacks = (name, f) => {
5336
        updateCallbacks(name, data => {
5337
          f(data);
5338
          return data;
5339
        });
5340
      };
5341
      const updateCallbacks = (name, f) => {
5342
        const callbackMap = changeCallbacks.get();
5343
        const data = get$a(callbackMap, name).getOrThunk(initData);
5344
        const outputData = f(data);
5345
        callbackMap[name] = outputData;
5346
        changeCallbacks.set(callbackMap);
5347
      };
5348
      const fireCallbacks = (name, uid, elements) => {
5349
        withCallbacks(name, data => {
5350
          each$e(data.listeners, f => f(true, name, {
5351
            uid,
5352
            nodes: map$3(elements, elem => elem.dom)
5353
          }));
5354
        });
5355
      };
5356
      const fireNoAnnotation = name => {
5357
        withCallbacks(name, data => {
5358
          each$e(data.listeners, f => f(false, name));
5359
        });
5360
      };
5361
      const toggleActiveAttr = (uid, state) => {
5362
        each$e(findMarkers(editor, uid), elem => {
5363
          if (state) {
1441 ariadna 5364
            set$4(elem, dataAnnotationActive(), 'true');
1 efrain 5365
          } else {
1441 ariadna 5366
            remove$9(elem, dataAnnotationActive());
1 efrain 5367
          }
5368
        });
5369
      };
1441 ariadna 5370
      const onNodeChange = last(() => {
1 efrain 5371
        const annotations = sort(registry.getNames());
5372
        each$e(annotations, name => {
5373
          updateCallbacks(name, data => {
5374
            const prev = data.previous.get();
5375
            identify(editor, Optional.some(name)).fold(() => {
5376
              prev.each(uid => {
5377
                fireNoAnnotation(name);
5378
                data.previous.clear();
5379
                toggleActiveAttr(uid, false);
5380
              });
5381
            }, ({uid, name, elements}) => {
5382
              if (!is$2(prev, uid)) {
5383
                prev.each(uid => toggleActiveAttr(uid, false));
5384
                fireCallbacks(name, uid, elements);
5385
                data.previous.set(uid);
5386
                toggleActiveAttr(uid, true);
5387
              }
5388
            });
5389
            return {
5390
              previous: data.previous,
5391
              listeners: data.listeners
5392
            };
5393
          });
5394
        });
5395
      }, 30);
5396
      editor.on('remove', () => {
5397
        onNodeChange.cancel();
5398
      });
5399
      editor.on('NodeChange', () => {
5400
        onNodeChange.throttle();
5401
      });
5402
      const addListener = (name, f) => {
5403
        updateCallbacks(name, data => ({
5404
          previous: data.previous,
5405
          listeners: data.listeners.concat([f])
5406
        }));
5407
      };
5408
      return { addListener };
5409
    };
5410
 
5411
    const setup$x = (editor, registry) => {
5412
      const dataAnnotation$1 = dataAnnotation();
5413
      const identifyParserNode = node => Optional.from(node.attr(dataAnnotation$1)).bind(registry.lookup);
5414
      const removeDirectAnnotation = node => {
5415
        var _a, _b;
5416
        node.attr(dataAnnotationId(), null);
5417
        node.attr(dataAnnotation(), null);
5418
        node.attr(dataAnnotationActive(), null);
5419
        const customAttrNames = Optional.from(node.attr(dataAnnotationAttributes())).map(names => names.split(',')).getOr([]);
5420
        const customClasses = Optional.from(node.attr(dataAnnotationClasses())).map(names => names.split(',')).getOr([]);
5421
        each$e(customAttrNames, name => node.attr(name, null));
5422
        const classList = (_b = (_a = node.attr('class')) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : [];
5423
        const newClassList = difference(classList, [annotation()].concat(customClasses));
5424
        node.attr('class', newClassList.length > 0 ? newClassList.join(' ') : null);
5425
        node.attr(dataAnnotationClasses(), null);
5426
        node.attr(dataAnnotationAttributes(), null);
5427
      };
5428
      editor.serializer.addTempAttr(dataAnnotationActive());
5429
      editor.serializer.addAttributeFilter(dataAnnotation$1, nodes => {
5430
        for (const node of nodes) {
5431
          identifyParserNode(node).each(settings => {
5432
            if (settings.persistent === false) {
5433
              if (node.name === 'span') {
5434
                node.unwrap();
5435
              } else {
5436
                removeDirectAnnotation(node);
5437
              }
5438
            }
5439
          });
5440
        }
5441
      });
5442
    };
5443
 
1441 ariadna 5444
    const create$b = () => {
1 efrain 5445
      const annotations = {};
5446
      const register = (name, settings) => {
5447
        annotations[name] = {
5448
          name,
5449
          settings
5450
        };
5451
      };
5452
      const lookup = name => get$a(annotations, name).map(a => a.settings);
5453
      const getNames = () => keys(annotations);
5454
      return {
5455
        register,
5456
        lookup,
5457
        getNames
5458
      };
5459
    };
5460
 
1441 ariadna 5461
    const clamp$2 = (value, min, max) => Math.min(Math.max(value, min), max);
5462
    const random = () => window.crypto.getRandomValues(new Uint32Array(1))[0] / 4294967295;
5463
 
1 efrain 5464
    let unique = 0;
5465
    const generate$1 = prefix => {
5466
      const date = new Date();
5467
      const time = date.getTime();
1441 ariadna 5468
      const random$1 = Math.floor(random() * 1000000000);
1 efrain 5469
      unique++;
1441 ariadna 5470
      return prefix + '_' + random$1 + unique + String(time);
1 efrain 5471
    };
5472
 
5473
    const add = (element, classes) => {
5474
      each$e(classes, x => {
5475
        add$2(element, x);
5476
      });
5477
    };
1441 ariadna 5478
    const remove$3 = (element, classes) => {
1 efrain 5479
      each$e(classes, x => {
1441 ariadna 5480
        remove$6(element, x);
1 efrain 5481
      });
5482
    };
5483
 
5484
    const clone$2 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
5485
    const shallow$1 = original => clone$2(original, false);
5486
    const deep$1 = original => clone$2(original, true);
5487
    const shallowAs = (original, tag) => {
5488
      const nu = SugarElement.fromTag(tag);
5489
      const attributes = clone$4(original);
5490
      setAll$1(nu, attributes);
5491
      return nu;
5492
    };
5493
    const mutate = (original, tag) => {
5494
      const nu = shallowAs(original, tag);
5495
      after$4(original, nu);
5496
      const children = children$1(original);
5497
      append(nu, children);
1441 ariadna 5498
      remove$4(original);
1 efrain 5499
      return nu;
5500
    };
5501
 
5502
    const TextWalker = (startNode, rootNode, isBoundary = never) => {
5503
      const walker = new DomTreeWalker(startNode, rootNode);
5504
      const walk = direction => {
5505
        let next;
5506
        do {
5507
          next = walker[direction]();
1441 ariadna 5508
        } while (next && !isText$b(next) && !isBoundary(next));
5509
        return Optional.from(next).filter(isText$b);
1 efrain 5510
      };
5511
      return {
1441 ariadna 5512
        current: () => Optional.from(walker.current()).filter(isText$b),
1 efrain 5513
        next: () => walk('next'),
5514
        prev: () => walk('prev'),
5515
        prev2: () => walk('prev2')
5516
      };
5517
    };
5518
 
5519
    const TextSeeker = (dom, isBoundary) => {
5520
      const isBlockBoundary = isBoundary ? isBoundary : node => dom.isBlock(node) || isBr$6(node) || isContentEditableFalse$b(node);
5521
      const walk = (node, offset, walker, process) => {
1441 ariadna 5522
        if (isText$b(node)) {
1 efrain 5523
          const newOffset = process(node, offset, node.data);
5524
          if (newOffset !== -1) {
5525
            return Optional.some({
5526
              container: node,
5527
              offset: newOffset
5528
            });
5529
          }
5530
        }
5531
        return walker().bind(next => walk(next.container, next.offset, walker, process));
5532
      };
5533
      const backwards = (node, offset, process, root) => {
5534
        const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
5535
        return walk(node, offset, () => walker.prev().map(prev => ({
5536
          container: prev,
5537
          offset: prev.length
5538
        })), process).getOrNull();
5539
      };
5540
      const forwards = (node, offset, process, root) => {
5541
        const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
5542
        return walk(node, offset, () => walker.next().map(next => ({
5543
          container: next,
5544
          offset: 0
5545
        })), process).getOrNull();
5546
      };
5547
      return {
5548
        backwards,
5549
        forwards
5550
      };
5551
    };
5552
 
1441 ariadna 5553
    const NodeValue = (is, name) => {
5554
      const get = element => {
5555
        if (!is(element)) {
5556
          throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
5557
        }
5558
        return getOption(element).getOr('');
5559
      };
5560
      const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
5561
      const set = (element, value) => {
5562
        if (!is(element)) {
5563
          throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
5564
        }
5565
        element.dom.nodeValue = value;
5566
      };
5567
      return {
5568
        get,
5569
        getOption,
5570
        set
5571
      };
5572
    };
5573
 
5574
    const api$1 = NodeValue(isText$c, 'text');
5575
    const get$3 = element => api$1.get(element);
5576
    const getOption = element => api$1.getOption(element);
5577
    const set = (element, value) => api$1.set(element, value);
5578
 
5579
    const tableCells = [
5580
      'td',
5581
      'th'
5582
    ];
5583
    const tableSections = [
5584
      'thead',
5585
      'tbody',
5586
      'tfoot'
5587
    ];
5588
    const textBlocks = [
5589
      'h1',
5590
      'h2',
5591
      'h3',
5592
      'h4',
5593
      'h5',
5594
      'h6',
5595
      'p',
5596
      'div',
5597
      'address',
5598
      'pre',
5599
      'form',
5600
      'blockquote',
5601
      'center',
5602
      'dir',
5603
      'fieldset',
5604
      'header',
5605
      'footer',
5606
      'article',
5607
      'section',
5608
      'hgroup',
5609
      'aside',
5610
      'nav',
5611
      'figure'
5612
    ];
5613
    const listItems$1 = [
5614
      'li',
5615
      'dd',
5616
      'dt'
5617
    ];
5618
    const lists = [
5619
      'ul',
5620
      'ol',
5621
      'dl'
5622
    ];
5623
    const wsElements = [
5624
      'pre',
5625
      'script',
5626
      'textarea',
5627
      'style'
5628
    ];
5629
    const lazyLookup = items => {
5630
      let lookup;
5631
      return node => {
5632
        lookup = lookup ? lookup : mapToObject(items, always);
5633
        return has$2(lookup, name(node));
5634
      };
5635
    };
5636
    const isTable$1 = node => name(node) === 'table';
5637
    const isBr$5 = node => isElement$7(node) && name(node) === 'br';
5638
    const isTextBlock$2 = lazyLookup(textBlocks);
5639
    const isList = lazyLookup(lists);
5640
    const isListItem$1 = lazyLookup(listItems$1);
5641
    const isTableSection = lazyLookup(tableSections);
5642
    const isTableCell$2 = lazyLookup(tableCells);
5643
    const isWsPreserveElement = lazyLookup(wsElements);
5644
 
5645
    const getLastChildren$1 = elm => {
5646
      const children = [];
5647
      let rawNode = elm.dom;
5648
      while (rawNode) {
5649
        children.push(SugarElement.fromDom(rawNode));
5650
        rawNode = rawNode.lastChild;
5651
      }
5652
      return children;
5653
    };
5654
    const removeTrailingBr = elm => {
5655
      const allBrs = descendants(elm, 'br');
5656
      const brs = filter$5(getLastChildren$1(elm).slice(-1), isBr$5);
5657
      if (allBrs.length === brs.length) {
5658
        each$e(brs, remove$4);
5659
      }
5660
    };
5661
    const createPaddingBr = () => {
5662
      const br = SugarElement.fromTag('br');
5663
      set$4(br, 'data-mce-bogus', '1');
5664
      return br;
5665
    };
5666
    const fillWithPaddingBr = elm => {
5667
      empty(elm);
5668
      append$1(elm, createPaddingBr());
5669
    };
5670
    const trimBlockTrailingBr = (elm, schema) => {
5671
      lastChild(elm).each(lastChild => {
5672
        prevSibling(lastChild).each(lastChildPrevSibling => {
5673
          if (schema.isBlock(name(elm)) && isBr$5(lastChild) && schema.isBlock(name(lastChildPrevSibling))) {
5674
            remove$4(lastChild);
5675
          }
5676
        });
5677
      });
5678
    };
5679
 
5680
    const ZWSP$1 = zeroWidth;
5681
    const isZwsp = isZwsp$2;
5682
    const trim$2 = removeZwsp;
5683
    const insert$5 = editor => editor.insertContent(ZWSP$1, { preserve_zwsp: true });
5684
 
5685
    const isElement$5 = isElement$6;
5686
    const isText$9 = isText$b;
5687
    const isCaretContainerBlock$1 = node => {
5688
      if (isText$9(node)) {
5689
        node = node.parentNode;
5690
      }
5691
      return isElement$5(node) && node.hasAttribute('data-mce-caret');
5692
    };
5693
    const isCaretContainerInline = node => isText$9(node) && isZwsp(node.data);
5694
    const isCaretContainer$2 = node => isCaretContainerBlock$1(node) || isCaretContainerInline(node);
5695
    const hasContent = node => node.firstChild !== node.lastChild || !isBr$6(node.firstChild);
5696
    const insertInline$1 = (node, before) => {
5697
      var _a;
5698
      const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
5699
      const textNode = doc.createTextNode(ZWSP$1);
5700
      const parentNode = node.parentNode;
5701
      if (!before) {
5702
        const sibling = node.nextSibling;
5703
        if (isText$9(sibling)) {
5704
          if (isCaretContainer$2(sibling)) {
5705
            return sibling;
5706
          }
5707
          if (startsWithCaretContainer$1(sibling)) {
5708
            sibling.splitText(1);
5709
            return sibling;
5710
          }
5711
        }
5712
        if (node.nextSibling) {
5713
          parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node.nextSibling);
5714
        } else {
5715
          parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(textNode);
5716
        }
5717
      } else {
5718
        const sibling = node.previousSibling;
5719
        if (isText$9(sibling)) {
5720
          if (isCaretContainer$2(sibling)) {
5721
            return sibling;
5722
          }
5723
          if (endsWithCaretContainer$1(sibling)) {
5724
            return sibling.splitText(sibling.data.length - 1);
5725
          }
5726
        }
5727
        parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node);
5728
      }
5729
      return textNode;
5730
    };
5731
    const isBeforeInline = pos => {
5732
      const container = pos.container();
5733
      if (!isText$b(container)) {
5734
        return false;
5735
      }
5736
      return container.data.charAt(pos.offset()) === ZWSP$1 || pos.isAtStart() && isCaretContainerInline(container.previousSibling);
5737
    };
5738
    const isAfterInline = pos => {
5739
      const container = pos.container();
5740
      if (!isText$b(container)) {
5741
        return false;
5742
      }
5743
      return container.data.charAt(pos.offset() - 1) === ZWSP$1 || pos.isAtEnd() && isCaretContainerInline(container.nextSibling);
5744
    };
5745
    const insertBlock = (blockName, node, before) => {
5746
      var _a;
5747
      const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
5748
      const blockNode = doc.createElement(blockName);
5749
      blockNode.setAttribute('data-mce-caret', before ? 'before' : 'after');
5750
      blockNode.setAttribute('data-mce-bogus', 'all');
5751
      blockNode.appendChild(createPaddingBr().dom);
5752
      const parentNode = node.parentNode;
5753
      if (!before) {
5754
        if (node.nextSibling) {
5755
          parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node.nextSibling);
5756
        } else {
5757
          parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(blockNode);
5758
        }
5759
      } else {
5760
        parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node);
5761
      }
5762
      return blockNode;
5763
    };
5764
    const startsWithCaretContainer$1 = node => isText$9(node) && node.data[0] === ZWSP$1;
5765
    const endsWithCaretContainer$1 = node => isText$9(node) && node.data[node.data.length - 1] === ZWSP$1;
5766
    const trimBogusBr = elm => {
5767
      var _a;
5768
      const brs = elm.getElementsByTagName('br');
5769
      const lastBr = brs[brs.length - 1];
5770
      if (isBogus$1(lastBr)) {
5771
        (_a = lastBr.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(lastBr);
5772
      }
5773
    };
5774
    const showCaretContainerBlock = caretContainer => {
5775
      if (caretContainer && caretContainer.hasAttribute('data-mce-caret')) {
5776
        trimBogusBr(caretContainer);
5777
        caretContainer.removeAttribute('data-mce-caret');
5778
        caretContainer.removeAttribute('data-mce-bogus');
5779
        caretContainer.removeAttribute('style');
5780
        caretContainer.removeAttribute('data-mce-style');
5781
        caretContainer.removeAttribute('_moz_abspos');
5782
        return caretContainer;
5783
      }
5784
      return null;
5785
    };
5786
    const isRangeInCaretContainerBlock = range => isCaretContainerBlock$1(range.startContainer);
5787
 
1 efrain 5788
    const round$2 = Math.round;
5789
    const clone$1 = rect => {
5790
      if (!rect) {
5791
        return {
5792
          left: 0,
5793
          top: 0,
5794
          bottom: 0,
5795
          right: 0,
5796
          width: 0,
5797
          height: 0
5798
        };
5799
      }
5800
      return {
5801
        left: round$2(rect.left),
5802
        top: round$2(rect.top),
5803
        bottom: round$2(rect.bottom),
5804
        right: round$2(rect.right),
5805
        width: round$2(rect.width),
5806
        height: round$2(rect.height)
5807
      };
5808
    };
5809
    const collapse = (rect, toStart) => {
5810
      rect = clone$1(rect);
5811
      if (toStart) {
5812
        rect.right = rect.left;
5813
      } else {
5814
        rect.left = rect.left + rect.width;
5815
        rect.right = rect.left;
5816
      }
5817
      rect.width = 0;
5818
      return rect;
5819
    };
5820
    const isEqual = (rect1, rect2) => rect1.left === rect2.left && rect1.top === rect2.top && rect1.bottom === rect2.bottom && rect1.right === rect2.right;
5821
    const isValidOverflow = (overflowY, rect1, rect2) => overflowY >= 0 && overflowY <= Math.min(rect1.height, rect2.height) / 2;
5822
    const isAbove$1 = (rect1, rect2) => {
5823
      const halfHeight = Math.min(rect2.height / 2, rect1.height / 2);
5824
      if (rect1.bottom - halfHeight < rect2.top) {
5825
        return true;
5826
      }
5827
      if (rect1.top > rect2.bottom) {
5828
        return false;
5829
      }
5830
      return isValidOverflow(rect2.top - rect1.bottom, rect1, rect2);
5831
    };
5832
    const isBelow$1 = (rect1, rect2) => {
5833
      if (rect1.top > rect2.bottom) {
5834
        return true;
5835
      }
5836
      if (rect1.bottom < rect2.top) {
5837
        return false;
5838
      }
5839
      return isValidOverflow(rect2.bottom - rect1.top, rect1, rect2);
5840
    };
5841
    const containsXY = (rect, clientX, clientY) => clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
5842
    const boundingClientRectFromRects = rects => {
5843
      return foldl(rects, (acc, rect) => {
5844
        return acc.fold(() => Optional.some(rect), prevRect => {
5845
          const left = Math.min(rect.left, prevRect.left);
5846
          const top = Math.min(rect.top, prevRect.top);
5847
          const right = Math.max(rect.right, prevRect.right);
5848
          const bottom = Math.max(rect.bottom, prevRect.bottom);
5849
          return Optional.some({
5850
            top,
5851
            right,
5852
            bottom,
5853
            left,
5854
            width: right - left,
5855
            height: bottom - top
5856
          });
5857
        });
5858
      }, Optional.none());
5859
    };
5860
    const distanceToRectEdgeFromXY = (rect, x, y) => {
5861
      const cx = Math.max(Math.min(x, rect.left + rect.width), rect.left);
5862
      const cy = Math.max(Math.min(y, rect.top + rect.height), rect.top);
5863
      return Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
5864
    };
5865
    const overlapY = (r1, r2) => Math.max(0, Math.min(r1.bottom, r2.bottom) - Math.max(r1.top, r2.top));
5866
 
5867
    const getSelectedNode = range => {
5868
      const startContainer = range.startContainer, startOffset = range.startOffset;
5869
      if (startContainer === range.endContainer && startContainer.hasChildNodes() && range.endOffset === startOffset + 1) {
5870
        return startContainer.childNodes[startOffset];
5871
      }
5872
      return null;
5873
    };
5874
    const getNode$1 = (container, offset) => {
5875
      if (isElement$6(container) && container.hasChildNodes()) {
5876
        const childNodes = container.childNodes;
5877
        const safeOffset = clamp$2(offset, 0, childNodes.length - 1);
5878
        return childNodes[safeOffset];
5879
      } else {
5880
        return container;
5881
      }
5882
    };
5883
    const getNodeUnsafe = (container, offset) => {
5884
      if (offset < 0 && isElement$6(container) && container.hasChildNodes()) {
5885
        return undefined;
5886
      } else {
5887
        return getNode$1(container, offset);
5888
      }
5889
    };
5890
 
5891
    const extendingChars = new RegExp('[\u0300-\u036f\u0483-\u0487\u0488-\u0489\u0591-\u05bd\u05bf\u05c1-\u05c2\u05c4-\u05c5\u05c7\u0610-\u061a' + '\u064b-\u065f\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7-\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0' + '\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e3-\u0902\u093a\u093c' + '\u0941-\u0948\u094d\u0951-\u0957\u0962-\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2-\u09e3' + '\u0a01-\u0a02\u0a3c\u0a41-\u0a42\u0a47-\u0a48\u0a4b-\u0a4d\u0a51\u0a70-\u0a71\u0a75\u0a81-\u0a82\u0abc' + '\u0ac1-\u0ac5\u0ac7-\u0ac8\u0acd\u0ae2-\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57' + '\u0b62-\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c00\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55-\u0c56' + '\u0c62-\u0c63\u0c81\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc-\u0ccd\u0cd5-\u0cd6\u0ce2-\u0ce3\u0d01\u0d3e\u0d41-\u0d44' + '\u0d4d\u0d57\u0d62-\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9' + '\u0ebb-\u0ebc\u0ec8-\u0ecd\u0f18-\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86-\u0f87\u0f8d-\u0f97' + '\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039-\u103a\u103d-\u103e\u1058-\u1059\u105e-\u1060\u1071-\u1074' + '\u1082\u1085-\u1086\u108d\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752-\u1753\u1772-\u1773\u17b4-\u17b5' + '\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927-\u1928\u1932\u1939-\u193b\u1a17-\u1a18' + '\u1a1b\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1ab0-\u1abd\u1ABE\u1b00-\u1b03\u1b34' + '\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80-\u1b81\u1ba2-\u1ba5\u1ba8-\u1ba9\u1bab-\u1bad\u1be6\u1be8-\u1be9' + '\u1bed\u1bef-\u1bf1\u1c2c-\u1c33\u1c36-\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1cf4\u1cf8-\u1cf9' + '\u1dc0-\u1df5\u1dfc-\u1dff\u200c-\u200d\u20d0-\u20dc\u20DD-\u20E0\u20e1\u20E2-\u20E4\u20e5-\u20f0\u2cef-\u2cf1' + '\u2d7f\u2de0-\u2dff\u302a-\u302d\u302e-\u302f\u3099-\u309a\ua66f\uA670-\uA672\ua674-\ua67d\ua69e-\ua69f\ua6f0-\ua6f1' + '\ua802\ua806\ua80b\ua825-\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc' + '\ua9e5\uaa29-\uaa2e\uaa31-\uaa32\uaa35-\uaa36\uaa43\uaa4c\uaa7c\uaab0\uaab2-\uaab4\uaab7-\uaab8\uaabe-\uaabf\uaac1' + '\uaaec-\uaaed\uaaf6\uabe5\uabe8\uabed\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\uff9e-\uff9f]');
5892
    const isExtendingChar = ch => isString(ch) && ch.charCodeAt(0) >= 768 && extendingChars.test(ch);
5893
 
5894
    const or = (...args) => {
5895
      return x => {
5896
        for (let i = 0; i < args.length; i++) {
5897
          if (args[i](x)) {
5898
            return true;
5899
          }
5900
        }
5901
        return false;
5902
      };
5903
    };
5904
    const and = (...args) => {
5905
      return x => {
5906
        for (let i = 0; i < args.length; i++) {
5907
          if (!args[i](x)) {
5908
            return false;
5909
          }
5910
        }
5911
        return true;
5912
      };
5913
    };
5914
 
1441 ariadna 5915
    const isContentEditableTrue$2 = isContentEditableTrue$3;
5916
    const isContentEditableFalse$a = isContentEditableFalse$b;
5917
    const isBr$4 = isBr$6;
5918
    const isText$8 = isText$b;
5919
    const isInvalidTextElement = matchNodeNames([
5920
      'script',
5921
      'style',
5922
      'textarea'
5923
    ]);
5924
    const isAtomicInline = matchNodeNames([
5925
      'img',
5926
      'input',
5927
      'textarea',
5928
      'hr',
5929
      'iframe',
5930
      'video',
5931
      'audio',
5932
      'object',
5933
      'embed'
5934
    ]);
5935
    const isTable = matchNodeNames(['table']);
5936
    const isCaretContainer$1 = isCaretContainer$2;
5937
    const isCaretCandidate$3 = node => {
5938
      if (isCaretContainer$1(node)) {
5939
        return false;
5940
      }
5941
      if (isText$8(node)) {
5942
        return !isInvalidTextElement(node.parentNode);
5943
      }
5944
      return isAtomicInline(node) || isBr$4(node) || isTable(node) || isNonUiContentEditableFalse(node);
5945
    };
5946
    const isUnselectable = node => isElement$6(node) && node.getAttribute('unselectable') === 'true';
5947
    const isNonUiContentEditableFalse = node => !isUnselectable(node) && isContentEditableFalse$a(node);
5948
    const isInEditable = (node, root) => {
5949
      for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
5950
        if (isNonUiContentEditableFalse(tempNode)) {
5951
          return false;
5952
        }
5953
        if (isContentEditableTrue$2(tempNode)) {
5954
          return true;
5955
        }
5956
      }
5957
      return true;
5958
    };
5959
    const isAtomicContentEditableFalse = node => {
5960
      if (!isNonUiContentEditableFalse(node)) {
5961
        return false;
5962
      }
5963
      return !foldl(from(node.getElementsByTagName('*')), (result, elm) => {
5964
        return result || isContentEditableTrue$2(elm);
5965
      }, false);
5966
    };
5967
    const isAtomic$1 = node => isAtomicInline(node) || isAtomicContentEditableFalse(node);
5968
    const isEditableCaretCandidate$1 = (node, root) => isCaretCandidate$3(node) && isInEditable(node, root);
5969
 
1 efrain 5970
    const isElement$4 = isElement$6;
5971
    const isCaretCandidate$2 = isCaretCandidate$3;
5972
    const isBlock$2 = matchStyleValues('display', 'block table');
5973
    const isFloated = matchStyleValues('float', 'left right');
5974
    const isValidElementCaretCandidate = and(isElement$4, isCaretCandidate$2, not(isFloated));
5975
    const isNotPre = not(matchStyleValues('white-space', 'pre pre-line pre-wrap'));
1441 ariadna 5976
    const isText$7 = isText$b;
1 efrain 5977
    const isBr$3 = isBr$6;
5978
    const nodeIndex$1 = DOMUtils.nodeIndex;
5979
    const resolveIndex$1 = getNodeUnsafe;
5980
    const createRange$1 = doc => doc ? doc.createRange() : DOMUtils.DOM.createRng();
5981
    const isWhiteSpace$1 = chr => isString(chr) && /[\r\n\t ]/.test(chr);
5982
    const isRange = rng => !!rng.setStart && !!rng.setEnd;
5983
    const isHiddenWhiteSpaceRange = range => {
5984
      const container = range.startContainer;
5985
      const offset = range.startOffset;
1441 ariadna 5986
      if (isWhiteSpace$1(range.toString()) && isNotPre(container.parentNode) && isText$b(container)) {
1 efrain 5987
        const text = container.data;
5988
        if (isWhiteSpace$1(text[offset - 1]) || isWhiteSpace$1(text[offset + 1])) {
5989
          return true;
5990
        }
5991
      }
5992
      return false;
5993
    };
5994
    const getBrClientRect = brNode => {
5995
      const doc = brNode.ownerDocument;
5996
      const rng = createRange$1(doc);
5997
      const nbsp$1 = doc.createTextNode(nbsp);
5998
      const parentNode = brNode.parentNode;
5999
      parentNode.insertBefore(nbsp$1, brNode);
6000
      rng.setStart(nbsp$1, 0);
6001
      rng.setEnd(nbsp$1, 1);
6002
      const clientRect = clone$1(rng.getBoundingClientRect());
6003
      parentNode.removeChild(nbsp$1);
6004
      return clientRect;
6005
    };
6006
    const getBoundingClientRectWebKitText = rng => {
6007
      const sc = rng.startContainer;
6008
      const ec = rng.endContainer;
6009
      const so = rng.startOffset;
6010
      const eo = rng.endOffset;
1441 ariadna 6011
      if (sc === ec && isText$b(ec) && so === 0 && eo === 1) {
1 efrain 6012
        const newRng = rng.cloneRange();
6013
        newRng.setEndAfter(ec);
6014
        return getBoundingClientRect$1(newRng);
6015
      } else {
6016
        return null;
6017
      }
6018
    };
6019
    const isZeroRect = r => r.left === 0 && r.right === 0 && r.top === 0 && r.bottom === 0;
6020
    const getBoundingClientRect$1 = item => {
6021
      var _a;
6022
      let clientRect;
6023
      const clientRects = item.getClientRects();
6024
      if (clientRects.length > 0) {
6025
        clientRect = clone$1(clientRects[0]);
6026
      } else {
6027
        clientRect = clone$1(item.getBoundingClientRect());
6028
      }
6029
      if (!isRange(item) && isBr$3(item) && isZeroRect(clientRect)) {
6030
        return getBrClientRect(item);
6031
      }
6032
      if (isZeroRect(clientRect) && isRange(item)) {
6033
        return (_a = getBoundingClientRectWebKitText(item)) !== null && _a !== void 0 ? _a : clientRect;
6034
      }
6035
      return clientRect;
6036
    };
6037
    const collapseAndInflateWidth = (clientRect, toStart) => {
6038
      const newClientRect = collapse(clientRect, toStart);
6039
      newClientRect.width = 1;
6040
      newClientRect.right = newClientRect.left + 1;
6041
      return newClientRect;
6042
    };
6043
    const getCaretPositionClientRects = caretPosition => {
6044
      const clientRects = [];
6045
      const addUniqueAndValidRect = clientRect => {
6046
        if (clientRect.height === 0) {
6047
          return;
6048
        }
6049
        if (clientRects.length > 0) {
6050
          if (isEqual(clientRect, clientRects[clientRects.length - 1])) {
6051
            return;
6052
          }
6053
        }
6054
        clientRects.push(clientRect);
6055
      };
6056
      const addCharacterOffset = (container, offset) => {
6057
        const range = createRange$1(container.ownerDocument);
6058
        if (offset < container.data.length) {
6059
          if (isExtendingChar(container.data[offset])) {
6060
            return;
6061
          }
6062
          if (isExtendingChar(container.data[offset - 1])) {
6063
            range.setStart(container, offset);
6064
            range.setEnd(container, offset + 1);
6065
            if (!isHiddenWhiteSpaceRange(range)) {
6066
              addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
6067
              return;
6068
            }
6069
          }
6070
        }
6071
        if (offset > 0) {
6072
          range.setStart(container, offset - 1);
6073
          range.setEnd(container, offset);
6074
          if (!isHiddenWhiteSpaceRange(range)) {
6075
            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
6076
          }
6077
        }
6078
        if (offset < container.data.length) {
6079
          range.setStart(container, offset);
6080
          range.setEnd(container, offset + 1);
6081
          if (!isHiddenWhiteSpaceRange(range)) {
6082
            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), true));
6083
          }
6084
        }
6085
      };
6086
      const container = caretPosition.container();
6087
      const offset = caretPosition.offset();
6088
      if (isText$7(container)) {
6089
        addCharacterOffset(container, offset);
6090
        return clientRects;
6091
      }
6092
      if (isElement$4(container)) {
6093
        if (caretPosition.isAtEnd()) {
6094
          const node = resolveIndex$1(container, offset);
6095
          if (isText$7(node)) {
6096
            addCharacterOffset(node, node.data.length);
6097
          }
6098
          if (isValidElementCaretCandidate(node) && !isBr$3(node)) {
6099
            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
6100
          }
6101
        } else {
6102
          const node = resolveIndex$1(container, offset);
6103
          if (isText$7(node)) {
6104
            addCharacterOffset(node, 0);
6105
          }
6106
          if (isValidElementCaretCandidate(node) && caretPosition.isAtEnd()) {
6107
            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
6108
            return clientRects;
6109
          }
6110
          const beforeNode = resolveIndex$1(caretPosition.container(), caretPosition.offset() - 1);
6111
          if (isValidElementCaretCandidate(beforeNode) && !isBr$3(beforeNode)) {
6112
            if (isBlock$2(beforeNode) || isBlock$2(node) || !isValidElementCaretCandidate(node)) {
6113
              addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(beforeNode), false));
6114
            }
6115
          }
6116
          if (isValidElementCaretCandidate(node)) {
6117
            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), true));
6118
          }
6119
        }
6120
      }
6121
      return clientRects;
6122
    };
6123
    const CaretPosition = (container, offset, clientRects) => {
6124
      const isAtStart = () => {
6125
        if (isText$7(container)) {
6126
          return offset === 0;
6127
        }
6128
        return offset === 0;
6129
      };
6130
      const isAtEnd = () => {
6131
        if (isText$7(container)) {
6132
          return offset >= container.data.length;
6133
        }
6134
        return offset >= container.childNodes.length;
6135
      };
6136
      const toRange = () => {
6137
        const range = createRange$1(container.ownerDocument);
6138
        range.setStart(container, offset);
6139
        range.setEnd(container, offset);
6140
        return range;
6141
      };
6142
      const getClientRects = () => {
6143
        if (!clientRects) {
6144
          clientRects = getCaretPositionClientRects(CaretPosition(container, offset));
6145
        }
6146
        return clientRects;
6147
      };
6148
      const isVisible = () => getClientRects().length > 0;
6149
      const isEqual = caretPosition => caretPosition && container === caretPosition.container() && offset === caretPosition.offset();
6150
      const getNode = before => resolveIndex$1(container, before ? offset - 1 : offset);
6151
      return {
6152
        container: constant(container),
6153
        offset: constant(offset),
6154
        toRange,
6155
        getClientRects,
6156
        isVisible,
6157
        isAtStart,
6158
        isAtEnd,
6159
        isEqual,
6160
        getNode
6161
      };
6162
    };
6163
    CaretPosition.fromRangeStart = range => CaretPosition(range.startContainer, range.startOffset);
6164
    CaretPosition.fromRangeEnd = range => CaretPosition(range.endContainer, range.endOffset);
6165
    CaretPosition.after = node => CaretPosition(node.parentNode, nodeIndex$1(node) + 1);
6166
    CaretPosition.before = node => CaretPosition(node.parentNode, nodeIndex$1(node));
1441 ariadna 6167
    CaretPosition.isAbove = (pos1, pos2) => lift2(head(pos2.getClientRects()), last$2(pos1.getClientRects()), isAbove$1).getOr(false);
6168
    CaretPosition.isBelow = (pos1, pos2) => lift2(last$2(pos2.getClientRects()), head(pos1.getClientRects()), isBelow$1).getOr(false);
1 efrain 6169
    CaretPosition.isAtStart = pos => pos ? pos.isAtStart() : false;
6170
    CaretPosition.isAtEnd = pos => pos ? pos.isAtEnd() : false;
1441 ariadna 6171
    CaretPosition.isTextPosition = pos => pos ? isText$b(pos.container()) : false;
1 efrain 6172
    CaretPosition.isElementPosition = pos => !CaretPosition.isTextPosition(pos);
6173
 
6174
    const trimEmptyTextNode$1 = (dom, node) => {
1441 ariadna 6175
      if (isText$b(node) && node.data.length === 0) {
1 efrain 6176
        dom.remove(node);
6177
      }
6178
    };
6179
    const insertNode = (dom, rng, node) => {
6180
      rng.insertNode(node);
6181
      trimEmptyTextNode$1(dom, node.previousSibling);
6182
      trimEmptyTextNode$1(dom, node.nextSibling);
6183
    };
6184
    const insertFragment = (dom, rng, frag) => {
6185
      const firstChild = Optional.from(frag.firstChild);
6186
      const lastChild = Optional.from(frag.lastChild);
6187
      rng.insertNode(frag);
6188
      firstChild.each(child => trimEmptyTextNode$1(dom, child.previousSibling));
6189
      lastChild.each(child => trimEmptyTextNode$1(dom, child.nextSibling));
6190
    };
6191
    const rangeInsertNode = (dom, rng, node) => {
6192
      if (isDocumentFragment(node)) {
6193
        insertFragment(dom, rng, node);
6194
      } else {
6195
        insertNode(dom, rng, node);
6196
      }
6197
    };
6198
 
1441 ariadna 6199
    const isText$6 = isText$b;
6200
    const isBogus = isBogus$1;
1 efrain 6201
    const nodeIndex = DOMUtils.nodeIndex;
6202
    const normalizedParent = node => {
6203
      const parentNode = node.parentNode;
6204
      if (isBogus(parentNode)) {
6205
        return normalizedParent(parentNode);
6206
      }
6207
      return parentNode;
6208
    };
6209
    const getChildNodes = node => {
6210
      if (!node) {
6211
        return [];
6212
      }
6213
      return reduce(node.childNodes, (result, node) => {
6214
        if (isBogus(node) && node.nodeName !== 'BR') {
6215
          result = result.concat(getChildNodes(node));
6216
        } else {
6217
          result.push(node);
6218
        }
6219
        return result;
6220
      }, []);
6221
    };
6222
    const normalizedTextOffset = (node, offset) => {
6223
      let tempNode = node;
6224
      while (tempNode = tempNode.previousSibling) {
6225
        if (!isText$6(tempNode)) {
6226
          break;
6227
        }
6228
        offset += tempNode.data.length;
6229
      }
6230
      return offset;
6231
    };
6232
    const equal = a => b => a === b;
6233
    const normalizedNodeIndex = node => {
6234
      let nodes, index;
6235
      nodes = getChildNodes(normalizedParent(node));
6236
      index = findIndex$1(nodes, equal(node), node);
6237
      nodes = nodes.slice(0, index + 1);
6238
      const numTextFragments = reduce(nodes, (result, node, i) => {
6239
        if (isText$6(node) && isText$6(nodes[i - 1])) {
6240
          result++;
6241
        }
6242
        return result;
6243
      }, 0);
6244
      nodes = filter$3(nodes, matchNodeNames([node.nodeName]));
6245
      index = findIndex$1(nodes, equal(node), node);
6246
      return index - numTextFragments;
6247
    };
6248
    const createPathItem = node => {
6249
      const name = isText$6(node) ? 'text()' : node.nodeName.toLowerCase();
6250
      return name + '[' + normalizedNodeIndex(node) + ']';
6251
    };
6252
    const parentsUntil$1 = (root, node, predicate) => {
6253
      const parents = [];
6254
      for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
6255
        if (predicate && predicate(tempNode)) {
6256
          break;
6257
        }
6258
        parents.push(tempNode);
6259
      }
6260
      return parents;
6261
    };
1441 ariadna 6262
    const create$a = (root, caretPosition) => {
1 efrain 6263
      let path = [];
6264
      let container = caretPosition.container();
6265
      let offset = caretPosition.offset();
6266
      let outputOffset;
6267
      if (isText$6(container)) {
6268
        outputOffset = normalizedTextOffset(container, offset);
6269
      } else {
6270
        const childNodes = container.childNodes;
6271
        if (offset >= childNodes.length) {
6272
          outputOffset = 'after';
6273
          offset = childNodes.length - 1;
6274
        } else {
6275
          outputOffset = 'before';
6276
        }
6277
        container = childNodes[offset];
6278
      }
6279
      path.push(createPathItem(container));
6280
      let parents = parentsUntil$1(root, container);
1441 ariadna 6281
      parents = filter$3(parents, not(isBogus$1));
1 efrain 6282
      path = path.concat(map$1(parents, node => {
6283
        return createPathItem(node);
6284
      }));
6285
      return path.reverse().join('/') + ',' + outputOffset;
6286
    };
6287
    const resolvePathItem = (node, name, index) => {
6288
      let nodes = getChildNodes(node);
6289
      nodes = filter$3(nodes, (node, index) => {
6290
        return !isText$6(node) || !isText$6(nodes[index - 1]);
6291
      });
6292
      nodes = filter$3(nodes, matchNodeNames([name]));
6293
      return nodes[index];
6294
    };
6295
    const findTextPosition = (container, offset) => {
6296
      let node = container;
6297
      let targetOffset = 0;
6298
      while (isText$6(node)) {
6299
        const dataLen = node.data.length;
6300
        if (offset >= targetOffset && offset <= targetOffset + dataLen) {
6301
          container = node;
6302
          offset = offset - targetOffset;
6303
          break;
6304
        }
6305
        if (!isText$6(node.nextSibling)) {
6306
          container = node;
6307
          offset = dataLen;
6308
          break;
6309
        }
6310
        targetOffset += dataLen;
6311
        node = node.nextSibling;
6312
      }
6313
      if (isText$6(container) && offset > container.data.length) {
6314
        offset = container.data.length;
6315
      }
6316
      return CaretPosition(container, offset);
6317
    };
6318
    const resolve$1 = (root, path) => {
6319
      if (!path) {
6320
        return null;
6321
      }
6322
      const parts = path.split(',');
6323
      const paths = parts[0].split('/');
6324
      const offset = parts.length > 1 ? parts[1] : 'before';
6325
      const container = reduce(paths, (result, value) => {
6326
        const match = /([\w\-\(\)]+)\[([0-9]+)\]/.exec(value);
6327
        if (!match) {
6328
          return null;
6329
        }
6330
        if (match[1] === 'text()') {
6331
          match[1] = '#text';
6332
        }
6333
        return resolvePathItem(result, match[1], parseInt(match[2], 10));
6334
      }, root);
6335
      if (!container) {
6336
        return null;
6337
      }
6338
      if (!isText$6(container) && container.parentNode) {
6339
        let nodeOffset;
6340
        if (offset === 'after') {
6341
          nodeOffset = nodeIndex(container) + 1;
6342
        } else {
6343
          nodeOffset = nodeIndex(container);
6344
        }
6345
        return CaretPosition(container.parentNode, nodeOffset);
6346
      }
6347
      return findTextPosition(container, parseInt(offset, 10));
6348
    };
6349
 
6350
    const isContentEditableFalse$9 = isContentEditableFalse$b;
6351
    const getNormalizedTextOffset$1 = (trim, container, offset) => {
6352
      let trimmedOffset = trim(container.data.slice(0, offset)).length;
1441 ariadna 6353
      for (let node = container.previousSibling; node && isText$b(node); node = node.previousSibling) {
1 efrain 6354
        trimmedOffset += trim(node.data).length;
6355
      }
6356
      return trimmedOffset;
6357
    };
6358
    const getPoint = (dom, trim, normalized, rng, start) => {
6359
      const container = start ? rng.startContainer : rng.endContainer;
6360
      let offset = start ? rng.startOffset : rng.endOffset;
6361
      const point = [];
6362
      const root = dom.getRoot();
1441 ariadna 6363
      if (isText$b(container)) {
1 efrain 6364
        point.push(normalized ? getNormalizedTextOffset$1(trim, container, offset) : offset);
6365
      } else {
6366
        let after = 0;
6367
        const childNodes = container.childNodes;
6368
        if (offset >= childNodes.length && childNodes.length) {
6369
          after = 1;
6370
          offset = Math.max(0, childNodes.length - 1);
6371
        }
6372
        point.push(dom.nodeIndex(childNodes[offset], normalized) + after);
6373
      }
6374
      for (let node = container; node && node !== root; node = node.parentNode) {
6375
        point.push(dom.nodeIndex(node, normalized));
6376
      }
6377
      return point;
6378
    };
6379
    const getLocation = (trim, selection, normalized, rng) => {
6380
      const dom = selection.dom;
6381
      const start = getPoint(dom, trim, normalized, rng, true);
6382
      const forward = selection.isForward();
6383
      const fakeCaret = isRangeInCaretContainerBlock(rng) ? { isFakeCaret: true } : {};
6384
      if (!selection.isCollapsed()) {
6385
        const end = getPoint(dom, trim, normalized, rng, false);
6386
        return {
6387
          start,
6388
          end,
6389
          forward,
6390
          ...fakeCaret
6391
        };
6392
      } else {
6393
        return {
6394
          start,
6395
          forward,
6396
          ...fakeCaret
6397
        };
6398
      }
6399
    };
6400
    const findIndex = (dom, name, element) => {
6401
      let count = 0;
6402
      Tools.each(dom.select(name), node => {
6403
        if (node.getAttribute('data-mce-bogus') === 'all') {
6404
          return;
6405
        } else if (node === element) {
6406
          return false;
6407
        } else {
6408
          count++;
6409
          return;
6410
        }
6411
      });
6412
      return count;
6413
    };
6414
    const moveEndPoint$1 = (rng, start) => {
6415
      let container = start ? rng.startContainer : rng.endContainer;
6416
      let offset = start ? rng.startOffset : rng.endOffset;
6417
      if (isElement$6(container) && container.nodeName === 'TR') {
6418
        const childNodes = container.childNodes;
6419
        container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)];
6420
        if (container) {
6421
          offset = start ? 0 : container.childNodes.length;
6422
          if (start) {
6423
            rng.setStart(container, offset);
6424
          } else {
6425
            rng.setEnd(container, offset);
6426
          }
6427
        }
6428
      }
6429
    };
6430
    const normalizeTableCellSelection = rng => {
6431
      moveEndPoint$1(rng, true);
6432
      moveEndPoint$1(rng, false);
6433
      return rng;
6434
    };
6435
    const findSibling = (node, offset) => {
6436
      if (isElement$6(node)) {
6437
        node = getNode$1(node, offset);
6438
        if (isContentEditableFalse$9(node)) {
6439
          return node;
6440
        }
6441
      }
6442
      if (isCaretContainer$2(node)) {
1441 ariadna 6443
        if (isText$b(node) && isCaretContainerBlock$1(node)) {
1 efrain 6444
          node = node.parentNode;
6445
        }
6446
        let sibling = node.previousSibling;
6447
        if (isContentEditableFalse$9(sibling)) {
6448
          return sibling;
6449
        }
6450
        sibling = node.nextSibling;
6451
        if (isContentEditableFalse$9(sibling)) {
6452
          return sibling;
6453
        }
6454
      }
6455
      return undefined;
6456
    };
6457
    const findAdjacentContentEditableFalseElm = rng => {
6458
      return findSibling(rng.startContainer, rng.startOffset) || findSibling(rng.endContainer, rng.endOffset);
6459
    };
6460
    const getOffsetBookmark = (trim, normalized, selection) => {
6461
      const element = selection.getNode();
6462
      const rng = selection.getRng();
6463
      if (element.nodeName === 'IMG' || isContentEditableFalse$9(element)) {
6464
        const name = element.nodeName;
6465
        return {
6466
          name,
6467
          index: findIndex(selection.dom, name, element)
6468
        };
6469
      }
6470
      const sibling = findAdjacentContentEditableFalseElm(rng);
6471
      if (sibling) {
6472
        const name = sibling.tagName;
6473
        return {
6474
          name,
6475
          index: findIndex(selection.dom, name, sibling)
6476
        };
6477
      }
6478
      return getLocation(trim, selection, normalized, rng);
6479
    };
6480
    const getCaretBookmark = selection => {
6481
      const rng = selection.getRng();
6482
      return {
1441 ariadna 6483
        start: create$a(selection.dom.getRoot(), CaretPosition.fromRangeStart(rng)),
6484
        end: create$a(selection.dom.getRoot(), CaretPosition.fromRangeEnd(rng)),
1 efrain 6485
        forward: selection.isForward()
6486
      };
6487
    };
6488
    const getRangeBookmark = selection => {
6489
      return {
6490
        rng: selection.getRng(),
6491
        forward: selection.isForward()
6492
      };
6493
    };
6494
    const createBookmarkSpan = (dom, id, filled) => {
6495
      const args = {
6496
        'data-mce-type': 'bookmark',
6497
        id,
6498
        'style': 'overflow:hidden;line-height:0px'
6499
      };
6500
      return filled ? dom.create('span', args, '&#xFEFF;') : dom.create('span', args);
6501
    };
6502
    const getPersistentBookmark = (selection, filled) => {
6503
      const dom = selection.dom;
6504
      let rng = selection.getRng();
6505
      const id = dom.uniqueId();
6506
      const collapsed = selection.isCollapsed();
6507
      const element = selection.getNode();
6508
      const name = element.nodeName;
6509
      const forward = selection.isForward();
6510
      if (name === 'IMG') {
6511
        return {
6512
          name,
6513
          index: findIndex(dom, name, element)
6514
        };
6515
      }
6516
      const rng2 = normalizeTableCellSelection(rng.cloneRange());
6517
      if (!collapsed) {
6518
        rng2.collapse(false);
6519
        const endBookmarkNode = createBookmarkSpan(dom, id + '_end', filled);
6520
        rangeInsertNode(dom, rng2, endBookmarkNode);
6521
      }
6522
      rng = normalizeTableCellSelection(rng);
6523
      rng.collapse(true);
6524
      const startBookmarkNode = createBookmarkSpan(dom, id + '_start', filled);
6525
      rangeInsertNode(dom, rng, startBookmarkNode);
6526
      selection.moveToBookmark({
6527
        id,
6528
        keep: true,
6529
        forward
6530
      });
6531
      return {
6532
        id,
6533
        forward
6534
      };
6535
    };
1441 ariadna 6536
    const getBookmark$3 = (selection, type, normalized = false) => {
1 efrain 6537
      if (type === 2) {
6538
        return getOffsetBookmark(trim$2, normalized, selection);
6539
      } else if (type === 3) {
6540
        return getCaretBookmark(selection);
6541
      } else if (type) {
6542
        return getRangeBookmark(selection);
6543
      } else {
6544
        return getPersistentBookmark(selection, false);
6545
      }
6546
    };
6547
    const getUndoBookmark = curry(getOffsetBookmark, identity, true);
6548
 
6549
    const value$1 = value => {
6550
      const applyHelper = fn => fn(value);
6551
      const constHelper = constant(value);
6552
      const outputHelper = () => output;
6553
      const output = {
6554
        tag: true,
6555
        inner: value,
6556
        fold: (_onError, onValue) => onValue(value),
6557
        isValue: always,
6558
        isError: never,
6559
        map: mapper => Result.value(mapper(value)),
6560
        mapError: outputHelper,
6561
        bind: applyHelper,
6562
        exists: applyHelper,
6563
        forall: applyHelper,
6564
        getOr: constHelper,
6565
        or: outputHelper,
6566
        getOrThunk: constHelper,
6567
        orThunk: outputHelper,
6568
        getOrDie: constHelper,
6569
        each: fn => {
6570
          fn(value);
6571
        },
6572
        toOptional: () => Optional.some(value)
6573
      };
6574
      return output;
6575
    };
6576
    const error = error => {
6577
      const outputHelper = () => output;
6578
      const output = {
6579
        tag: false,
6580
        inner: error,
6581
        fold: (onError, _onValue) => onError(error),
6582
        isValue: never,
6583
        isError: always,
6584
        map: outputHelper,
6585
        mapError: mapper => Result.error(mapper(error)),
6586
        bind: outputHelper,
6587
        exists: never,
6588
        forall: always,
6589
        getOr: identity,
6590
        or: identity,
6591
        getOrThunk: apply$1,
6592
        orThunk: apply$1,
6593
        getOrDie: die(String(error)),
6594
        each: noop,
6595
        toOptional: Optional.none
6596
      };
6597
      return output;
6598
    };
6599
    const fromOption = (optional, err) => optional.fold(() => error(err), value$1);
6600
    const Result = {
6601
      value: value$1,
6602
      error,
6603
      fromOption
6604
    };
6605
 
6606
    const generate = cases => {
6607
      if (!isArray$1(cases)) {
6608
        throw new Error('cases must be an array');
6609
      }
6610
      if (cases.length === 0) {
6611
        throw new Error('there must be at least one case');
6612
      }
6613
      const constructors = [];
6614
      const adt = {};
6615
      each$e(cases, (acase, count) => {
6616
        const keys$1 = keys(acase);
6617
        if (keys$1.length !== 1) {
6618
          throw new Error('one and only one name per case');
6619
        }
6620
        const key = keys$1[0];
6621
        const value = acase[key];
6622
        if (adt[key] !== undefined) {
6623
          throw new Error('duplicate key detected:' + key);
6624
        } else if (key === 'cata') {
6625
          throw new Error('cannot have a case named cata (sorry)');
6626
        } else if (!isArray$1(value)) {
6627
          throw new Error('case arguments must be an array');
6628
        }
6629
        constructors.push(key);
6630
        adt[key] = (...args) => {
6631
          const argLength = args.length;
6632
          if (argLength !== value.length) {
6633
            throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
6634
          }
6635
          const match = branches => {
6636
            const branchKeys = keys(branches);
6637
            if (constructors.length !== branchKeys.length) {
6638
              throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
6639
            }
6640
            const allReqd = forall(constructors, reqKey => {
6641
              return contains$2(branchKeys, reqKey);
6642
            });
6643
            if (!allReqd) {
6644
              throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
6645
            }
6646
            return branches[key].apply(null, args);
6647
          };
6648
          return {
6649
            fold: (...foldArgs) => {
6650
              if (foldArgs.length !== cases.length) {
6651
                throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
6652
              }
6653
              const target = foldArgs[count];
6654
              return target.apply(null, args);
6655
            },
6656
            match,
6657
            log: label => {
6658
              console.log(label, {
6659
                constructors,
6660
                constructor: key,
6661
                params: args
6662
              });
6663
            }
6664
          };
6665
        };
6666
      });
6667
      return adt;
6668
    };
6669
    const Adt = { generate };
6670
 
6671
    Adt.generate([
6672
      {
6673
        bothErrors: [
6674
          'error1',
6675
          'error2'
6676
        ]
6677
      },
6678
      {
6679
        firstError: [
6680
          'error1',
6681
          'value2'
6682
        ]
6683
      },
6684
      {
6685
        secondError: [
6686
          'value1',
6687
          'error2'
6688
        ]
6689
      },
6690
      {
6691
        bothValues: [
6692
          'value1',
6693
          'value2'
6694
        ]
6695
      }
6696
    ]);
6697
    const partition$1 = results => {
6698
      const errors = [];
6699
      const values = [];
6700
      each$e(results, result => {
6701
        result.fold(err => {
6702
          errors.push(err);
6703
        }, value => {
6704
          values.push(value);
6705
        });
6706
      });
6707
      return {
6708
        errors,
6709
        values
6710
      };
6711
    };
6712
 
6713
    const isInlinePattern = pattern => pattern.type === 'inline-command' || pattern.type === 'inline-format';
6714
    const isBlockPattern = pattern => pattern.type === 'block-command' || pattern.type === 'block-format';
1441 ariadna 6715
    const hasBlockTrigger = (pattern, trigger) => (pattern.type === 'block-command' || pattern.type === 'block-format') && pattern.trigger === trigger;
1 efrain 6716
    const normalizePattern = pattern => {
1441 ariadna 6717
      var _a;
1 efrain 6718
      const err = message => Result.error({
6719
        message,
6720
        pattern
6721
      });
6722
      const formatOrCmd = (name, onFormat, onCommand) => {
6723
        if (pattern.format !== undefined) {
6724
          let formats;
6725
          if (isArray$1(pattern.format)) {
6726
            if (!forall(pattern.format, isString)) {
6727
              return err(name + ' pattern has non-string items in the `format` array');
6728
            }
6729
            formats = pattern.format;
6730
          } else if (isString(pattern.format)) {
6731
            formats = [pattern.format];
6732
          } else {
6733
            return err(name + ' pattern has non-string `format` parameter');
6734
          }
6735
          return Result.value(onFormat(formats));
6736
        } else if (pattern.cmd !== undefined) {
6737
          if (!isString(pattern.cmd)) {
6738
            return err(name + ' pattern has non-string `cmd` parameter');
6739
          }
6740
          return Result.value(onCommand(pattern.cmd, pattern.value));
6741
        } else {
6742
          return err(name + ' pattern is missing both `format` and `cmd` parameters');
6743
        }
6744
      };
6745
      if (!isObject(pattern)) {
6746
        return err('Raw pattern is not an object');
6747
      }
6748
      if (!isString(pattern.start)) {
6749
        return err('Raw pattern is missing `start` parameter');
6750
      }
6751
      if (pattern.end !== undefined) {
6752
        if (!isString(pattern.end)) {
6753
          return err('Inline pattern has non-string `end` parameter');
6754
        }
6755
        if (pattern.start.length === 0 && pattern.end.length === 0) {
6756
          return err('Inline pattern has empty `start` and `end` parameters');
6757
        }
6758
        let start = pattern.start;
6759
        let end = pattern.end;
6760
        if (end.length === 0) {
6761
          end = start;
6762
          start = '';
6763
        }
6764
        return formatOrCmd('Inline', format => ({
6765
          type: 'inline-format',
6766
          start,
6767
          end,
6768
          format
6769
        }), (cmd, value) => ({
6770
          type: 'inline-command',
6771
          start,
6772
          end,
6773
          cmd,
6774
          value
6775
        }));
6776
      } else if (pattern.replacement !== undefined) {
6777
        if (!isString(pattern.replacement)) {
6778
          return err('Replacement pattern has non-string `replacement` parameter');
6779
        }
6780
        if (pattern.start.length === 0) {
6781
          return err('Replacement pattern has empty `start` parameter');
6782
        }
6783
        return Result.value({
6784
          type: 'inline-command',
6785
          start: '',
6786
          end: pattern.start,
6787
          cmd: 'mceInsertContent',
6788
          value: pattern.replacement
6789
        });
6790
      } else {
1441 ariadna 6791
        const trigger = (_a = pattern.trigger) !== null && _a !== void 0 ? _a : 'space';
1 efrain 6792
        if (pattern.start.length === 0) {
6793
          return err('Block pattern has empty `start` parameter');
6794
        }
6795
        return formatOrCmd('Block', formats => ({
6796
          type: 'block-format',
6797
          start: pattern.start,
1441 ariadna 6798
          format: formats[0],
6799
          trigger
1 efrain 6800
        }), (command, commandValue) => ({
6801
          type: 'block-command',
6802
          start: pattern.start,
6803
          cmd: command,
1441 ariadna 6804
          value: commandValue,
6805
          trigger
1 efrain 6806
        }));
6807
      }
6808
    };
6809
    const getBlockPatterns = patterns => filter$5(patterns, isBlockPattern);
6810
    const getInlinePatterns = patterns => filter$5(patterns, isInlinePattern);
6811
    const createPatternSet = (patterns, dynamicPatternsLookup) => ({
6812
      inlinePatterns: getInlinePatterns(patterns),
6813
      blockPatterns: getBlockPatterns(patterns),
6814
      dynamicPatternsLookup
6815
    });
1441 ariadna 6816
    const filterByTrigger = (patterns, trigger) => {
6817
      return {
6818
        ...patterns,
6819
        blockPatterns: filter$5(patterns.blockPatterns, pattern => hasBlockTrigger(pattern, trigger))
6820
      };
6821
    };
1 efrain 6822
    const fromRawPatterns = patterns => {
6823
      const normalized = partition$1(map$3(patterns, normalizePattern));
6824
      each$e(normalized.errors, err => console.error(err.message, err.pattern));
6825
      return normalized.values;
6826
    };
6827
    const fromRawPatternsLookup = lookupFn => {
6828
      return ctx => {
6829
        const rawPatterns = lookupFn(ctx);
6830
        return fromRawPatterns(rawPatterns);
6831
      };
6832
    };
6833
 
1441 ariadna 6834
    const firePreProcess = (editor, args) => editor.dispatch('PreProcess', args);
6835
    const firePostProcess = (editor, args) => editor.dispatch('PostProcess', args);
6836
    const fireRemove = editor => {
6837
      editor.dispatch('remove');
6838
    };
6839
    const fireDetach = editor => {
6840
      editor.dispatch('detach');
6841
    };
6842
    const fireSwitchMode = (editor, mode) => {
6843
      editor.dispatch('SwitchMode', { mode });
6844
    };
6845
    const fireObjectResizeStart = (editor, target, width, height, origin) => {
6846
      editor.dispatch('ObjectResizeStart', {
6847
        target,
6848
        width,
6849
        height,
6850
        origin
6851
      });
6852
    };
6853
    const fireObjectResized = (editor, target, width, height, origin) => {
6854
      editor.dispatch('ObjectResized', {
6855
        target,
6856
        width,
6857
        height,
6858
        origin
6859
      });
6860
    };
6861
    const firePreInit = editor => {
6862
      editor.dispatch('PreInit');
6863
    };
6864
    const firePostRender = editor => {
6865
      editor.dispatch('PostRender');
6866
    };
6867
    const fireInit = editor => {
6868
      editor.dispatch('Init');
6869
    };
6870
    const firePlaceholderToggle = (editor, state) => {
6871
      editor.dispatch('PlaceholderToggle', { state });
6872
    };
6873
    const fireError = (editor, errorType, error) => {
6874
      editor.dispatch(errorType, error);
6875
    };
6876
    const fireFormatApply = (editor, format, node, vars) => {
6877
      editor.dispatch('FormatApply', {
6878
        format,
6879
        node,
6880
        vars
6881
      });
6882
    };
6883
    const fireFormatRemove = (editor, format, node, vars) => {
6884
      editor.dispatch('FormatRemove', {
6885
        format,
6886
        node,
6887
        vars
6888
      });
6889
    };
6890
    const fireBeforeSetContent = (editor, args) => editor.dispatch('BeforeSetContent', args);
6891
    const fireSetContent = (editor, args) => editor.dispatch('SetContent', args);
6892
    const fireBeforeGetContent = (editor, args) => editor.dispatch('BeforeGetContent', args);
6893
    const fireGetContent = (editor, args) => editor.dispatch('GetContent', args);
6894
    const fireAutocompleterStart = (editor, args) => {
6895
      editor.dispatch('AutocompleterStart', args);
6896
    };
6897
    const fireAutocompleterUpdate = (editor, args) => {
6898
      editor.dispatch('AutocompleterUpdate', args);
6899
    };
6900
    const fireAutocompleterUpdateActiveRange = (editor, args) => {
6901
      editor.dispatch('AutocompleterUpdateActiveRange', args);
6902
    };
6903
    const fireAutocompleterEnd = editor => {
6904
      editor.dispatch('AutocompleterEnd');
6905
    };
6906
    const firePastePreProcess = (editor, html, internal) => editor.dispatch('PastePreProcess', {
6907
      content: html,
6908
      internal
6909
    });
6910
    const firePastePostProcess = (editor, node, internal) => editor.dispatch('PastePostProcess', {
6911
      node,
6912
      internal
6913
    });
6914
    const firePastePlainTextToggle = (editor, state) => editor.dispatch('PastePlainTextToggle', { state });
6915
    const fireEditableRootStateChange = (editor, state) => editor.dispatch('EditableRootStateChange', { state });
6916
    const fireDisabledStateChange = (editor, state) => editor.dispatch('DisabledStateChange', { state });
6917
 
6918
    const deviceDetection$1 = detect$1().deviceType;
1 efrain 6919
    const isTouch = deviceDetection$1.isTouch();
6920
    const DOM$a = DOMUtils.DOM;
6921
    const getHash = value => {
6922
      const items = value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(',');
6923
      return foldl(items, (output, item) => {
6924
        const arr = item.split('=');
6925
        const key = arr[0];
6926
        const val = arr.length > 1 ? arr[1] : key;
6927
        output[trim$4(key)] = trim$4(val);
6928
        return output;
6929
      }, {});
6930
    };
6931
    const isRegExp = x => is$4(x, RegExp);
6932
    const option = name => editor => editor.options.get(name);
6933
    const stringOrObjectProcessor = value => isString(value) || isObject(value);
6934
    const bodyOptionProcessor = (editor, defaultValue = '') => value => {
6935
      const valid = isString(value);
6936
      if (valid) {
6937
        if (value.indexOf('=') !== -1) {
6938
          const bodyObj = getHash(value);
6939
          return {
6940
            value: get$a(bodyObj, editor.id).getOr(defaultValue),
6941
            valid
6942
          };
6943
        } else {
6944
          return {
6945
            value,
6946
            valid
6947
          };
6948
        }
6949
      } else {
6950
        return {
6951
          valid: false,
6952
          message: 'Must be a string.'
6953
        };
6954
      }
6955
    };
6956
    const register$7 = editor => {
6957
      const registerOption = editor.options.register;
6958
      registerOption('id', {
6959
        processor: 'string',
6960
        default: editor.id
6961
      });
6962
      registerOption('selector', { processor: 'string' });
6963
      registerOption('target', { processor: 'object' });
6964
      registerOption('suffix', { processor: 'string' });
6965
      registerOption('cache_suffix', { processor: 'string' });
6966
      registerOption('base_url', { processor: 'string' });
6967
      registerOption('referrer_policy', {
6968
        processor: 'string',
6969
        default: ''
6970
      });
6971
      registerOption('language_load', {
6972
        processor: 'boolean',
6973
        default: true
6974
      });
6975
      registerOption('inline', {
6976
        processor: 'boolean',
6977
        default: false
6978
      });
6979
      registerOption('iframe_attrs', {
6980
        processor: 'object',
6981
        default: {}
6982
      });
6983
      registerOption('doctype', {
6984
        processor: 'string',
6985
        default: '<!DOCTYPE html>'
6986
      });
6987
      registerOption('document_base_url', {
6988
        processor: 'string',
6989
        default: editor.documentBaseUrl
6990
      });
6991
      registerOption('body_id', {
6992
        processor: bodyOptionProcessor(editor, 'tinymce'),
6993
        default: 'tinymce'
6994
      });
6995
      registerOption('body_class', {
6996
        processor: bodyOptionProcessor(editor),
6997
        default: ''
6998
      });
6999
      registerOption('content_security_policy', {
7000
        processor: 'string',
7001
        default: ''
7002
      });
7003
      registerOption('br_in_pre', {
7004
        processor: 'boolean',
7005
        default: true
7006
      });
7007
      registerOption('forced_root_block', {
7008
        processor: value => {
7009
          const valid = isString(value) && isNotEmpty(value);
7010
          if (valid) {
7011
            return {
7012
              value,
7013
              valid
7014
            };
7015
          } else {
7016
            return {
7017
              valid: false,
7018
              message: 'Must be a non-empty string.'
7019
            };
7020
          }
7021
        },
7022
        default: 'p'
7023
      });
7024
      registerOption('forced_root_block_attrs', {
7025
        processor: 'object',
7026
        default: {}
7027
      });
7028
      registerOption('newline_behavior', {
7029
        processor: value => {
7030
          const valid = contains$2([
7031
            'block',
7032
            'linebreak',
7033
            'invert',
7034
            'default'
7035
          ], value);
7036
          return valid ? {
7037
            value,
7038
            valid
7039
          } : {
7040
            valid: false,
7041
            message: 'Must be one of: block, linebreak, invert or default.'
7042
          };
7043
        },
7044
        default: 'default'
7045
      });
7046
      registerOption('br_newline_selector', {
7047
        processor: 'string',
7048
        default: '.mce-toc h2,figcaption,caption'
7049
      });
7050
      registerOption('no_newline_selector', {
7051
        processor: 'string',
7052
        default: ''
7053
      });
7054
      registerOption('keep_styles', {
7055
        processor: 'boolean',
7056
        default: true
7057
      });
7058
      registerOption('end_container_on_empty_block', {
7059
        processor: value => {
7060
          if (isBoolean(value)) {
7061
            return {
7062
              valid: true,
7063
              value
7064
            };
7065
          } else if (isString(value)) {
7066
            return {
7067
              valid: true,
7068
              value
7069
            };
7070
          } else {
7071
            return {
7072
              valid: false,
7073
              message: 'Must be boolean or a string'
7074
            };
7075
          }
7076
        },
7077
        default: 'blockquote'
7078
      });
7079
      registerOption('font_size_style_values', {
7080
        processor: 'string',
7081
        default: 'xx-small,x-small,small,medium,large,x-large,xx-large'
7082
      });
7083
      registerOption('font_size_legacy_values', {
7084
        processor: 'string',
7085
        default: 'xx-small,small,medium,large,x-large,xx-large,300%'
7086
      });
7087
      registerOption('font_size_classes', {
7088
        processor: 'string',
7089
        default: ''
7090
      });
7091
      registerOption('automatic_uploads', {
7092
        processor: 'boolean',
7093
        default: true
7094
      });
7095
      registerOption('images_reuse_filename', {
7096
        processor: 'boolean',
7097
        default: false
7098
      });
7099
      registerOption('images_replace_blob_uris', {
7100
        processor: 'boolean',
7101
        default: true
7102
      });
7103
      registerOption('icons', {
7104
        processor: 'string',
7105
        default: ''
7106
      });
7107
      registerOption('icons_url', {
7108
        processor: 'string',
7109
        default: ''
7110
      });
7111
      registerOption('images_upload_url', {
7112
        processor: 'string',
7113
        default: ''
7114
      });
7115
      registerOption('images_upload_base_path', {
7116
        processor: 'string',
7117
        default: ''
7118
      });
7119
      registerOption('images_upload_credentials', {
7120
        processor: 'boolean',
7121
        default: false
7122
      });
7123
      registerOption('images_upload_handler', { processor: 'function' });
7124
      registerOption('language', {
7125
        processor: 'string',
7126
        default: 'en'
7127
      });
7128
      registerOption('language_url', {
7129
        processor: 'string',
7130
        default: ''
7131
      });
7132
      registerOption('entity_encoding', {
7133
        processor: 'string',
7134
        default: 'named'
7135
      });
7136
      registerOption('indent', {
7137
        processor: 'boolean',
7138
        default: true
7139
      });
7140
      registerOption('indent_before', {
7141
        processor: 'string',
7142
        default: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' + 'tfoot,tbody,tr,section,details,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist'
7143
      });
7144
      registerOption('indent_after', {
7145
        processor: 'string',
7146
        default: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' + 'tfoot,tbody,tr,section,details,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist'
7147
      });
7148
      registerOption('indent_use_margin', {
7149
        processor: 'boolean',
7150
        default: false
7151
      });
7152
      registerOption('indentation', {
7153
        processor: 'string',
7154
        default: '40px'
7155
      });
7156
      registerOption('content_css', {
7157
        processor: value => {
7158
          const valid = value === false || isString(value) || isArrayOf(value, isString);
7159
          if (valid) {
7160
            if (isString(value)) {
7161
              return {
7162
                value: map$3(value.split(','), trim$4),
7163
                valid
7164
              };
7165
            } else if (isArray$1(value)) {
7166
              return {
7167
                value,
7168
                valid
7169
              };
7170
            } else if (value === false) {
7171
              return {
7172
                value: [],
7173
                valid
7174
              };
7175
            } else {
7176
              return {
7177
                value,
7178
                valid
7179
              };
7180
            }
7181
          } else {
7182
            return {
7183
              valid: false,
7184
              message: 'Must be false, a string or an array of strings.'
7185
            };
7186
          }
7187
        },
7188
        default: isInline$1(editor) ? [] : ['default']
7189
      });
7190
      registerOption('content_style', { processor: 'string' });
7191
      registerOption('content_css_cors', {
7192
        processor: 'boolean',
7193
        default: false
7194
      });
7195
      registerOption('font_css', {
7196
        processor: value => {
7197
          const valid = isString(value) || isArrayOf(value, isString);
7198
          if (valid) {
7199
            const newValue = isArray$1(value) ? value : map$3(value.split(','), trim$4);
7200
            return {
7201
              value: newValue,
7202
              valid
7203
            };
7204
          } else {
7205
            return {
7206
              valid: false,
7207
              message: 'Must be a string or an array of strings.'
7208
            };
7209
          }
7210
        },
7211
        default: []
7212
      });
7213
      registerOption('inline_boundaries', {
7214
        processor: 'boolean',
7215
        default: true
7216
      });
7217
      registerOption('inline_boundaries_selector', {
7218
        processor: 'string',
7219
        default: 'a[href],code,span.mce-annotation'
7220
      });
7221
      registerOption('object_resizing', {
7222
        processor: value => {
7223
          const valid = isBoolean(value) || isString(value);
7224
          if (valid) {
7225
            if (value === false || deviceDetection$1.isiPhone() || deviceDetection$1.isiPad()) {
7226
              return {
7227
                value: '',
7228
                valid
7229
              };
7230
            } else {
7231
              return {
7232
                value: value === true ? 'table,img,figure.image,div,video,iframe' : value,
7233
                valid
7234
              };
7235
            }
7236
          } else {
7237
            return {
7238
              valid: false,
7239
              message: 'Must be boolean or a string'
7240
            };
7241
          }
7242
        },
7243
        default: !isTouch
7244
      });
7245
      registerOption('resize_img_proportional', {
7246
        processor: 'boolean',
7247
        default: true
7248
      });
1441 ariadna 7249
      registerOption('event_root', { processor: 'string' });
1 efrain 7250
      registerOption('service_message', { processor: 'string' });
7251
      registerOption('theme', {
7252
        processor: value => value === false || isString(value) || isFunction(value),
7253
        default: 'silver'
7254
      });
7255
      registerOption('theme_url', { processor: 'string' });
7256
      registerOption('formats', { processor: 'object' });
7257
      registerOption('format_empty_lines', {
7258
        processor: 'boolean',
7259
        default: false
7260
      });
7261
      registerOption('format_noneditable_selector', {
7262
        processor: 'string',
7263
        default: ''
7264
      });
7265
      registerOption('preview_styles', {
7266
        processor: value => {
7267
          const valid = value === false || isString(value);
7268
          if (valid) {
7269
            return {
7270
              value: value === false ? '' : value,
7271
              valid
7272
            };
7273
          } else {
7274
            return {
7275
              valid: false,
7276
              message: 'Must be false or a string'
7277
            };
7278
          }
7279
        },
7280
        default: 'font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow'
7281
      });
7282
      registerOption('custom_ui_selector', {
7283
        processor: 'string',
7284
        default: ''
7285
      });
7286
      registerOption('hidden_input', {
7287
        processor: 'boolean',
7288
        default: true
7289
      });
7290
      registerOption('submit_patch', {
7291
        processor: 'boolean',
7292
        default: true
7293
      });
7294
      registerOption('encoding', { processor: 'string' });
7295
      registerOption('add_form_submit_trigger', {
7296
        processor: 'boolean',
7297
        default: true
7298
      });
7299
      registerOption('add_unload_trigger', {
7300
        processor: 'boolean',
7301
        default: true
7302
      });
7303
      registerOption('custom_undo_redo_levels', {
7304
        processor: 'number',
7305
        default: 0
7306
      });
7307
      registerOption('disable_nodechange', {
7308
        processor: 'boolean',
7309
        default: false
7310
      });
1441 ariadna 7311
      registerOption('disabled', {
7312
        processor: value => {
7313
          if (isBoolean(value)) {
7314
            if (editor.initialized && isDisabled$1(editor) !== value) {
7315
              Promise.resolve().then(() => {
7316
                fireDisabledStateChange(editor, value);
7317
              });
7318
            }
7319
            return {
7320
              valid: true,
7321
              value
7322
            };
7323
          }
7324
          return {
7325
            valid: false,
7326
            message: 'The value must be a boolean.'
7327
          };
7328
        },
7329
        default: false
7330
      });
1 efrain 7331
      registerOption('readonly', {
7332
        processor: 'boolean',
7333
        default: false
7334
      });
7335
      registerOption('editable_root', {
7336
        processor: 'boolean',
7337
        default: true
7338
      });
7339
      registerOption('plugins', {
7340
        processor: 'string[]',
7341
        default: []
7342
      });
7343
      registerOption('external_plugins', { processor: 'object' });
7344
      registerOption('forced_plugins', { processor: 'string[]' });
7345
      registerOption('model', {
7346
        processor: 'string',
7347
        default: editor.hasPlugin('rtc') ? 'plugin' : 'dom'
7348
      });
7349
      registerOption('model_url', { processor: 'string' });
7350
      registerOption('block_unsupported_drop', {
7351
        processor: 'boolean',
7352
        default: true
7353
      });
7354
      registerOption('visual', {
7355
        processor: 'boolean',
7356
        default: true
7357
      });
7358
      registerOption('visual_table_class', {
7359
        processor: 'string',
7360
        default: 'mce-item-table'
7361
      });
7362
      registerOption('visual_anchor_class', {
7363
        processor: 'string',
7364
        default: 'mce-item-anchor'
7365
      });
7366
      registerOption('iframe_aria_text', {
7367
        processor: 'string',
1441 ariadna 7368
        default: 'Rich Text Area'.concat(editor.hasPlugin('help') ? '. Press ALT-0 for help.' : '')
1 efrain 7369
      });
7370
      registerOption('setup', { processor: 'function' });
7371
      registerOption('init_instance_callback', { processor: 'function' });
7372
      registerOption('url_converter', {
7373
        processor: 'function',
7374
        default: editor.convertURL
7375
      });
7376
      registerOption('url_converter_scope', {
7377
        processor: 'object',
7378
        default: editor
7379
      });
7380
      registerOption('urlconverter_callback', { processor: 'function' });
7381
      registerOption('allow_conditional_comments', {
7382
        processor: 'boolean',
7383
        default: false
7384
      });
7385
      registerOption('allow_html_data_urls', {
7386
        processor: 'boolean',
7387
        default: false
7388
      });
7389
      registerOption('allow_svg_data_urls', { processor: 'boolean' });
7390
      registerOption('allow_html_in_named_anchor', {
7391
        processor: 'boolean',
7392
        default: false
7393
      });
7394
      registerOption('allow_script_urls', {
7395
        processor: 'boolean',
7396
        default: false
7397
      });
7398
      registerOption('allow_unsafe_link_target', {
7399
        processor: 'boolean',
7400
        default: false
7401
      });
1441 ariadna 7402
      registerOption('allow_mathml_annotation_encodings', {
7403
        processor: value => {
7404
          const valid = isArrayOf(value, isString);
7405
          return valid ? {
7406
            value,
7407
            valid
7408
          } : {
7409
            valid: false,
7410
            message: 'Must be an array of strings.'
7411
          };
7412
        },
7413
        default: []
7414
      });
1 efrain 7415
      registerOption('convert_fonts_to_spans', {
7416
        processor: 'boolean',
7417
        default: true,
7418
        deprecated: true
7419
      });
7420
      registerOption('fix_list_elements', {
7421
        processor: 'boolean',
7422
        default: false
7423
      });
7424
      registerOption('preserve_cdata', {
7425
        processor: 'boolean',
7426
        default: false
7427
      });
7428
      registerOption('remove_trailing_brs', {
7429
        processor: 'boolean',
7430
        default: true
7431
      });
7432
      registerOption('pad_empty_with_br', {
7433
        processor: 'boolean',
7434
        default: false
7435
      });
7436
      registerOption('inline_styles', {
7437
        processor: 'boolean',
7438
        default: true,
7439
        deprecated: true
7440
      });
7441
      registerOption('element_format', {
7442
        processor: 'string',
7443
        default: 'html'
7444
      });
7445
      registerOption('entities', { processor: 'string' });
7446
      registerOption('schema', {
7447
        processor: 'string',
7448
        default: 'html5'
7449
      });
7450
      registerOption('convert_urls', {
7451
        processor: 'boolean',
7452
        default: true
7453
      });
7454
      registerOption('relative_urls', {
7455
        processor: 'boolean',
7456
        default: true
7457
      });
7458
      registerOption('remove_script_host', {
7459
        processor: 'boolean',
7460
        default: true
7461
      });
1441 ariadna 7462
      registerOption('custom_elements', { processor: stringOrObjectProcessor });
1 efrain 7463
      registerOption('extended_valid_elements', { processor: 'string' });
7464
      registerOption('invalid_elements', { processor: 'string' });
7465
      registerOption('invalid_styles', { processor: stringOrObjectProcessor });
7466
      registerOption('valid_children', { processor: 'string' });
7467
      registerOption('valid_classes', { processor: stringOrObjectProcessor });
7468
      registerOption('valid_elements', { processor: 'string' });
7469
      registerOption('valid_styles', { processor: stringOrObjectProcessor });
7470
      registerOption('verify_html', {
7471
        processor: 'boolean',
7472
        default: true
7473
      });
7474
      registerOption('auto_focus', { processor: value => isString(value) || value === true });
7475
      registerOption('browser_spellcheck', {
7476
        processor: 'boolean',
7477
        default: false
7478
      });
7479
      registerOption('protect', { processor: 'array' });
7480
      registerOption('images_file_types', {
7481
        processor: 'string',
7482
        default: 'jpeg,jpg,jpe,jfi,jif,jfif,png,gif,bmp,webp'
7483
      });
7484
      registerOption('deprecation_warnings', {
7485
        processor: 'boolean',
7486
        default: true
7487
      });
7488
      registerOption('a11y_advanced_options', {
7489
        processor: 'boolean',
7490
        default: false
7491
      });
7492
      registerOption('api_key', { processor: 'string' });
1441 ariadna 7493
      registerOption('license_key', { processor: 'string' });
1 efrain 7494
      registerOption('paste_block_drop', {
7495
        processor: 'boolean',
7496
        default: false
7497
      });
7498
      registerOption('paste_data_images', {
7499
        processor: 'boolean',
7500
        default: true
7501
      });
7502
      registerOption('paste_preprocess', { processor: 'function' });
7503
      registerOption('paste_postprocess', { processor: 'function' });
7504
      registerOption('paste_webkit_styles', {
7505
        processor: 'string',
7506
        default: 'none'
7507
      });
7508
      registerOption('paste_remove_styles_if_webkit', {
7509
        processor: 'boolean',
7510
        default: true
7511
      });
7512
      registerOption('paste_merge_formats', {
7513
        processor: 'boolean',
7514
        default: true
7515
      });
7516
      registerOption('smart_paste', {
7517
        processor: 'boolean',
7518
        default: true
7519
      });
7520
      registerOption('paste_as_text', {
7521
        processor: 'boolean',
7522
        default: false
7523
      });
7524
      registerOption('paste_tab_spaces', {
7525
        processor: 'number',
7526
        default: 4
7527
      });
7528
      registerOption('text_patterns', {
7529
        processor: value => {
7530
          if (isArrayOf(value, isObject) || value === false) {
7531
            const patterns = value === false ? [] : value;
7532
            return {
7533
              value: fromRawPatterns(patterns),
7534
              valid: true
7535
            };
7536
          } else {
7537
            return {
7538
              valid: false,
7539
              message: 'Must be an array of objects or false.'
7540
            };
7541
          }
7542
        },
7543
        default: [
7544
          {
7545
            start: '*',
7546
            end: '*',
7547
            format: 'italic'
7548
          },
7549
          {
7550
            start: '**',
7551
            end: '**',
7552
            format: 'bold'
7553
          },
7554
          {
7555
            start: '#',
1441 ariadna 7556
            format: 'h1',
7557
            trigger: 'space'
1 efrain 7558
          },
7559
          {
7560
            start: '##',
1441 ariadna 7561
            format: 'h2',
7562
            trigger: 'space'
1 efrain 7563
          },
7564
          {
7565
            start: '###',
1441 ariadna 7566
            format: 'h3',
7567
            trigger: 'space'
1 efrain 7568
          },
7569
          {
7570
            start: '####',
1441 ariadna 7571
            format: 'h4',
7572
            trigger: 'space'
1 efrain 7573
          },
7574
          {
7575
            start: '#####',
1441 ariadna 7576
            format: 'h5',
7577
            trigger: 'space'
1 efrain 7578
          },
7579
          {
7580
            start: '######',
1441 ariadna 7581
            format: 'h6',
7582
            trigger: 'space'
1 efrain 7583
          },
7584
          {
1441 ariadna 7585
            start: '1.',
7586
            cmd: 'InsertOrderedList',
7587
            trigger: 'space'
1 efrain 7588
          },
7589
          {
1441 ariadna 7590
            start: '*',
7591
            cmd: 'InsertUnorderedList',
7592
            trigger: 'space'
1 efrain 7593
          },
7594
          {
1441 ariadna 7595
            start: '-',
7596
            cmd: 'InsertUnorderedList',
7597
            trigger: 'space'
7598
          },
7599
          {
7600
            start: '>',
7601
            cmd: 'mceBlockQuote',
7602
            trigger: 'space'
7603
          },
7604
          {
7605
            start: '---',
7606
            cmd: 'InsertHorizontalRule',
7607
            trigger: 'space'
1 efrain 7608
          }
7609
        ]
7610
      });
7611
      registerOption('text_patterns_lookup', {
7612
        processor: value => {
7613
          if (isFunction(value)) {
7614
            return {
7615
              value: fromRawPatternsLookup(value),
7616
              valid: true
7617
            };
7618
          } else {
7619
            return {
7620
              valid: false,
7621
              message: 'Must be a single function'
7622
            };
7623
          }
7624
        },
7625
        default: _ctx => []
7626
      });
7627
      registerOption('noneditable_class', {
7628
        processor: 'string',
7629
        default: 'mceNonEditable'
7630
      });
7631
      registerOption('editable_class', {
7632
        processor: 'string',
7633
        default: 'mceEditable'
7634
      });
7635
      registerOption('noneditable_regexp', {
7636
        processor: value => {
7637
          if (isArrayOf(value, isRegExp)) {
7638
            return {
7639
              value,
7640
              valid: true
7641
            };
7642
          } else if (isRegExp(value)) {
7643
            return {
7644
              value: [value],
7645
              valid: true
7646
            };
7647
          } else {
7648
            return {
7649
              valid: false,
7650
              message: 'Must be a RegExp or an array of RegExp.'
7651
            };
7652
          }
7653
        },
7654
        default: []
7655
      });
7656
      registerOption('table_tab_navigation', {
7657
        processor: 'boolean',
7658
        default: true
7659
      });
7660
      registerOption('highlight_on_focus', {
7661
        processor: 'boolean',
1441 ariadna 7662
        default: true
1 efrain 7663
      });
7664
      registerOption('xss_sanitization', {
7665
        processor: 'boolean',
7666
        default: true
7667
      });
7668
      registerOption('details_initial_state', {
7669
        processor: value => {
7670
          const valid = contains$2([
7671
            'inherited',
7672
            'collapsed',
7673
            'expanded'
7674
          ], value);
7675
          return valid ? {
7676
            value,
7677
            valid
7678
          } : {
7679
            valid: false,
7680
            message: 'Must be one of: inherited, collapsed, or expanded.'
7681
          };
7682
        },
7683
        default: 'inherited'
7684
      });
7685
      registerOption('details_serialized_state', {
7686
        processor: value => {
7687
          const valid = contains$2([
7688
            'inherited',
7689
            'collapsed',
7690
            'expanded'
7691
          ], value);
7692
          return valid ? {
7693
            value,
7694
            valid
7695
          } : {
7696
            valid: false,
7697
            message: 'Must be one of: inherited, collapsed, or expanded.'
7698
          };
7699
        },
7700
        default: 'inherited'
7701
      });
7702
      registerOption('init_content_sync', {
7703
        processor: 'boolean',
7704
        default: false
7705
      });
7706
      registerOption('newdocument_content', {
7707
        processor: 'string',
7708
        default: ''
7709
      });
7710
      registerOption('sandbox_iframes', {
7711
        processor: 'boolean',
1441 ariadna 7712
        default: true
1 efrain 7713
      });
1441 ariadna 7714
      registerOption('sandbox_iframes_exclusions', {
7715
        processor: 'string[]',
7716
        default: [
7717
          'youtube.com',
7718
          'youtu.be',
7719
          'vimeo.com',
7720
          'player.vimeo.com',
7721
          'dailymotion.com',
7722
          'embed.music.apple.com',
7723
          'open.spotify.com',
7724
          'giphy.com',
7725
          'dai.ly',
7726
          'codepen.io'
7727
        ]
7728
      });
1 efrain 7729
      registerOption('convert_unsafe_embeds', {
7730
        processor: 'boolean',
1441 ariadna 7731
        default: true
1 efrain 7732
      });
7733
      editor.on('ScriptsLoaded', () => {
7734
        registerOption('directionality', {
7735
          processor: 'string',
7736
          default: I18n.isRtl() ? 'rtl' : undefined
7737
        });
7738
        registerOption('placeholder', {
7739
          processor: 'string',
7740
          default: DOM$a.getAttrib(editor.getElement(), 'placeholder')
7741
        });
7742
      });
7743
    };
7744
    const getIframeAttrs = option('iframe_attrs');
7745
    const getDocType = option('doctype');
7746
    const getDocumentBaseUrl = option('document_base_url');
7747
    const getBodyId = option('body_id');
7748
    const getBodyClass = option('body_class');
7749
    const getContentSecurityPolicy = option('content_security_policy');
7750
    const shouldPutBrInPre$1 = option('br_in_pre');
7751
    const getForcedRootBlock = option('forced_root_block');
7752
    const getForcedRootBlockAttrs = option('forced_root_block_attrs');
7753
    const getNewlineBehavior = option('newline_behavior');
7754
    const getBrNewLineSelector = option('br_newline_selector');
7755
    const getNoNewLineSelector = option('no_newline_selector');
7756
    const shouldKeepStyles = option('keep_styles');
7757
    const shouldEndContainerOnEmptyBlock = option('end_container_on_empty_block');
7758
    const isAutomaticUploadsEnabled = option('automatic_uploads');
7759
    const shouldReuseFileName = option('images_reuse_filename');
7760
    const shouldReplaceBlobUris = option('images_replace_blob_uris');
7761
    const getIconPackName = option('icons');
7762
    const getIconsUrl = option('icons_url');
7763
    const getImageUploadUrl = option('images_upload_url');
7764
    const getImageUploadBasePath = option('images_upload_base_path');
7765
    const getImagesUploadCredentials = option('images_upload_credentials');
7766
    const getImagesUploadHandler = option('images_upload_handler');
7767
    const shouldUseContentCssCors = option('content_css_cors');
7768
    const getReferrerPolicy = option('referrer_policy');
7769
    const getLanguageCode = option('language');
7770
    const getLanguageUrl = option('language_url');
7771
    const shouldIndentUseMargin = option('indent_use_margin');
7772
    const getIndentation = option('indentation');
7773
    const getContentCss = option('content_css');
7774
    const getContentStyle = option('content_style');
7775
    const getFontCss = option('font_css');
7776
    const getDirectionality = option('directionality');
7777
    const getInlineBoundarySelector = option('inline_boundaries_selector');
7778
    const getObjectResizing = option('object_resizing');
7779
    const getResizeImgProportional = option('resize_img_proportional');
7780
    const getPlaceholder = option('placeholder');
7781
    const getEventRoot = option('event_root');
7782
    const getServiceMessage = option('service_message');
7783
    const getTheme = option('theme');
7784
    const getThemeUrl = option('theme_url');
7785
    const getModel = option('model');
7786
    const getModelUrl = option('model_url');
7787
    const isInlineBoundariesEnabled = option('inline_boundaries');
7788
    const getFormats = option('formats');
7789
    const getPreviewStyles = option('preview_styles');
7790
    const canFormatEmptyLines = option('format_empty_lines');
7791
    const getFormatNoneditableSelector = option('format_noneditable_selector');
7792
    const getCustomUiSelector = option('custom_ui_selector');
7793
    const isInline$1 = option('inline');
7794
    const hasHiddenInput = option('hidden_input');
7795
    const shouldPatchSubmit = option('submit_patch');
7796
    const shouldAddFormSubmitTrigger = option('add_form_submit_trigger');
7797
    const shouldAddUnloadTrigger = option('add_unload_trigger');
7798
    const getCustomUndoRedoLevels = option('custom_undo_redo_levels');
7799
    const shouldDisableNodeChange = option('disable_nodechange');
7800
    const isReadOnly$1 = option('readonly');
7801
    const hasEditableRoot$1 = option('editable_root');
7802
    const hasContentCssCors = option('content_css_cors');
7803
    const getPlugins = option('plugins');
7804
    const getExternalPlugins$1 = option('external_plugins');
7805
    const shouldBlockUnsupportedDrop = option('block_unsupported_drop');
7806
    const isVisualAidsEnabled = option('visual');
7807
    const getVisualAidsTableClass = option('visual_table_class');
7808
    const getVisualAidsAnchorClass = option('visual_anchor_class');
7809
    const getIframeAriaText = option('iframe_aria_text');
7810
    const getSetupCallback = option('setup');
7811
    const getInitInstanceCallback = option('init_instance_callback');
7812
    const getUrlConverterCallback = option('urlconverter_callback');
7813
    const getAutoFocus = option('auto_focus');
7814
    const shouldBrowserSpellcheck = option('browser_spellcheck');
7815
    const getProtect = option('protect');
7816
    const shouldPasteBlockDrop = option('paste_block_drop');
7817
    const shouldPasteDataImages = option('paste_data_images');
7818
    const getPastePreProcess = option('paste_preprocess');
7819
    const getPastePostProcess = option('paste_postprocess');
7820
    const getNewDocumentContent = option('newdocument_content');
7821
    const getPasteWebkitStyles = option('paste_webkit_styles');
7822
    const shouldPasteRemoveWebKitStyles = option('paste_remove_styles_if_webkit');
7823
    const shouldPasteMergeFormats = option('paste_merge_formats');
7824
    const isSmartPasteEnabled = option('smart_paste');
7825
    const isPasteAsTextEnabled = option('paste_as_text');
7826
    const getPasteTabSpaces = option('paste_tab_spaces');
7827
    const shouldAllowHtmlDataUrls = option('allow_html_data_urls');
7828
    const getTextPatterns = option('text_patterns');
7829
    const getTextPatternsLookup = option('text_patterns_lookup');
7830
    const getNonEditableClass = option('noneditable_class');
7831
    const getEditableClass = option('editable_class');
7832
    const getNonEditableRegExps = option('noneditable_regexp');
7833
    const shouldPreserveCData = option('preserve_cdata');
7834
    const shouldHighlightOnFocus = option('highlight_on_focus');
7835
    const shouldSanitizeXss = option('xss_sanitization');
7836
    const shouldUseDocumentWrite = option('init_content_sync');
7837
    const hasTextPatternsLookup = editor => editor.options.isSet('text_patterns_lookup');
7838
    const getFontStyleValues = editor => Tools.explode(editor.options.get('font_size_style_values'));
7839
    const getFontSizeClasses = editor => Tools.explode(editor.options.get('font_size_classes'));
7840
    const isEncodingXml = editor => editor.options.get('encoding') === 'xml';
7841
    const getAllowedImageFileTypes = editor => Tools.explode(editor.options.get('images_file_types'));
7842
    const hasTableTabNavigation = option('table_tab_navigation');
7843
    const getDetailsInitialState = option('details_initial_state');
7844
    const getDetailsSerializedState = option('details_serialized_state');
7845
    const shouldSandboxIframes = option('sandbox_iframes');
1441 ariadna 7846
    const getSandboxIframesExclusions = editor => editor.options.get('sandbox_iframes_exclusions');
7847
    const shouldConvertUnsafeEmbeds = option('convert_unsafe_embeds');
7848
    const getLicenseKey = option('license_key');
7849
    const getApiKey = option('api_key');
7850
    const isDisabled$1 = option('disabled');
1 efrain 7851
 
7852
    const isElement$3 = isElement$6;
1441 ariadna 7853
    const isText$5 = isText$b;
1 efrain 7854
    const removeNode$1 = node => {
7855
      const parentNode = node.parentNode;
7856
      if (parentNode) {
7857
        parentNode.removeChild(node);
7858
      }
7859
    };
7860
    const trimCount = text => {
7861
      const trimmedText = trim$2(text);
7862
      return {
7863
        count: text.length - trimmedText.length,
7864
        text: trimmedText
7865
      };
7866
    };
7867
    const deleteZwspChars = caretContainer => {
7868
      let idx;
7869
      while ((idx = caretContainer.data.lastIndexOf(ZWSP$1)) !== -1) {
7870
        caretContainer.deleteData(idx, 1);
7871
      }
7872
    };
7873
    const removeUnchanged = (caretContainer, pos) => {
1441 ariadna 7874
      remove$2(caretContainer);
1 efrain 7875
      return pos;
7876
    };
7877
    const removeTextAndReposition = (caretContainer, pos) => {
7878
      const before = trimCount(caretContainer.data.substr(0, pos.offset()));
7879
      const after = trimCount(caretContainer.data.substr(pos.offset()));
7880
      const text = before.text + after.text;
7881
      if (text.length > 0) {
7882
        deleteZwspChars(caretContainer);
7883
        return CaretPosition(caretContainer, pos.offset() - before.count);
7884
      } else {
7885
        return pos;
7886
      }
7887
    };
7888
    const removeElementAndReposition = (caretContainer, pos) => {
7889
      const parentNode = pos.container();
7890
      const newPosition = indexOf$1(from(parentNode.childNodes), caretContainer).map(index => {
7891
        return index < pos.offset() ? CaretPosition(parentNode, pos.offset() - 1) : pos;
7892
      }).getOr(pos);
1441 ariadna 7893
      remove$2(caretContainer);
1 efrain 7894
      return newPosition;
7895
    };
7896
    const removeTextCaretContainer = (caretContainer, pos) => isText$5(caretContainer) && pos.container() === caretContainer ? removeTextAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
7897
    const removeElementCaretContainer = (caretContainer, pos) => pos.container() === caretContainer.parentNode ? removeElementAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
7898
    const removeAndReposition = (container, pos) => CaretPosition.isTextPosition(pos) ? removeTextCaretContainer(container, pos) : removeElementCaretContainer(container, pos);
1441 ariadna 7899
    const remove$2 = caretContainerNode => {
1 efrain 7900
      if (isElement$3(caretContainerNode) && isCaretContainer$2(caretContainerNode)) {
7901
        if (hasContent(caretContainerNode)) {
7902
          caretContainerNode.removeAttribute('data-mce-caret');
7903
        } else {
7904
          removeNode$1(caretContainerNode);
7905
        }
7906
      }
7907
      if (isText$5(caretContainerNode)) {
7908
        deleteZwspChars(caretContainerNode);
7909
        if (caretContainerNode.data.length === 0) {
7910
          removeNode$1(caretContainerNode);
7911
        }
7912
      }
7913
    };
7914
 
7915
    const isContentEditableFalse$8 = isContentEditableFalse$b;
7916
    const isMedia$1 = isMedia$2;
7917
    const isTableCell$1 = isTableCell$3;
7918
    const inlineFakeCaretSelector = '*[contentEditable=false],video,audio,embed,object';
7919
    const getAbsoluteClientRect = (root, element, before) => {
7920
      const clientRect = collapse(element.getBoundingClientRect(), before);
7921
      let scrollX;
7922
      let scrollY;
7923
      if (root.tagName === 'BODY') {
7924
        const docElm = root.ownerDocument.documentElement;
7925
        scrollX = root.scrollLeft || docElm.scrollLeft;
7926
        scrollY = root.scrollTop || docElm.scrollTop;
7927
      } else {
7928
        const rootRect = root.getBoundingClientRect();
7929
        scrollX = root.scrollLeft - rootRect.left;
7930
        scrollY = root.scrollTop - rootRect.top;
7931
      }
7932
      clientRect.left += scrollX;
7933
      clientRect.right += scrollX;
7934
      clientRect.top += scrollY;
7935
      clientRect.bottom += scrollY;
7936
      clientRect.width = 1;
7937
      let margin = element.offsetWidth - element.clientWidth;
7938
      if (margin > 0) {
7939
        if (before) {
7940
          margin *= -1;
7941
        }
7942
        clientRect.left += margin;
7943
        clientRect.right += margin;
7944
      }
7945
      return clientRect;
7946
    };
7947
    const trimInlineCaretContainers = root => {
7948
      var _a, _b;
7949
      const fakeCaretTargetNodes = descendants(SugarElement.fromDom(root), inlineFakeCaretSelector);
7950
      for (let i = 0; i < fakeCaretTargetNodes.length; i++) {
7951
        const node = fakeCaretTargetNodes[i].dom;
7952
        let sibling = node.previousSibling;
7953
        if (endsWithCaretContainer$1(sibling)) {
7954
          const data = sibling.data;
7955
          if (data.length === 1) {
7956
            (_a = sibling.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(sibling);
7957
          } else {
7958
            sibling.deleteData(data.length - 1, 1);
7959
          }
7960
        }
7961
        sibling = node.nextSibling;
7962
        if (startsWithCaretContainer$1(sibling)) {
7963
          const data = sibling.data;
7964
          if (data.length === 1) {
7965
            (_b = sibling.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(sibling);
7966
          } else {
7967
            sibling.deleteData(0, 1);
7968
          }
7969
        }
7970
      }
7971
    };
7972
    const FakeCaret = (editor, root, isBlock, hasFocus) => {
7973
      const lastVisualCaret = value$2();
7974
      let cursorInterval;
7975
      let caretContainerNode;
7976
      const caretBlock = getForcedRootBlock(editor);
7977
      const dom = editor.dom;
7978
      const show = (before, element) => {
7979
        let rng;
7980
        hide();
7981
        if (isTableCell$1(element)) {
7982
          return null;
7983
        }
7984
        if (isBlock(element)) {
7985
          const caretContainer = insertBlock(caretBlock, element, before);
7986
          const clientRect = getAbsoluteClientRect(root, element, before);
7987
          dom.setStyle(caretContainer, 'top', clientRect.top);
1441 ariadna 7988
          dom.setStyle(caretContainer, 'caret-color', 'transparent');
1 efrain 7989
          caretContainerNode = caretContainer;
7990
          const caret = dom.create('div', {
7991
            'class': 'mce-visual-caret',
7992
            'data-mce-bogus': 'all'
7993
          });
7994
          dom.setStyles(caret, { ...clientRect });
7995
          dom.add(root, caret);
7996
          lastVisualCaret.set({
7997
            caret,
7998
            element,
7999
            before
8000
          });
8001
          if (before) {
8002
            dom.addClass(caret, 'mce-visual-caret-before');
8003
          }
8004
          startBlink();
8005
          rng = element.ownerDocument.createRange();
8006
          rng.setStart(caretContainer, 0);
8007
          rng.setEnd(caretContainer, 0);
8008
        } else {
8009
          caretContainerNode = insertInline$1(element, before);
8010
          rng = element.ownerDocument.createRange();
8011
          if (isInlineFakeCaretTarget(caretContainerNode.nextSibling)) {
8012
            rng.setStart(caretContainerNode, 0);
8013
            rng.setEnd(caretContainerNode, 0);
8014
          } else {
8015
            rng.setStart(caretContainerNode, 1);
8016
            rng.setEnd(caretContainerNode, 1);
8017
          }
8018
          return rng;
8019
        }
8020
        return rng;
8021
      };
8022
      const hide = () => {
8023
        trimInlineCaretContainers(root);
8024
        if (caretContainerNode) {
1441 ariadna 8025
          remove$2(caretContainerNode);
1 efrain 8026
          caretContainerNode = null;
8027
        }
8028
        lastVisualCaret.on(caretState => {
8029
          dom.remove(caretState.caret);
8030
          lastVisualCaret.clear();
8031
        });
8032
        if (cursorInterval) {
8033
          clearInterval(cursorInterval);
8034
          cursorInterval = undefined;
8035
        }
8036
      };
8037
      const startBlink = () => {
8038
        cursorInterval = setInterval(() => {
8039
          lastVisualCaret.on(caretState => {
8040
            if (hasFocus()) {
8041
              dom.toggleClass(caretState.caret, 'mce-visual-caret-hidden');
8042
            } else {
8043
              dom.addClass(caretState.caret, 'mce-visual-caret-hidden');
8044
            }
8045
          });
8046
        }, 500);
8047
      };
8048
      const reposition = () => {
8049
        lastVisualCaret.on(caretState => {
8050
          const clientRect = getAbsoluteClientRect(root, caretState.element, caretState.before);
8051
          dom.setStyles(caretState.caret, { ...clientRect });
8052
        });
8053
      };
8054
      const destroy = () => clearInterval(cursorInterval);
8055
      const getCss = () => '.mce-visual-caret {' + 'position: absolute;' + 'background-color: black;' + 'background-color: currentcolor;' + '}' + '.mce-visual-caret-hidden {' + 'display: none;' + '}' + '*[data-mce-caret] {' + 'position: absolute;' + 'left: -1000px;' + 'right: auto;' + 'top: 0;' + 'margin: 0;' + 'padding: 0;' + '}';
8056
      return {
8057
        show,
8058
        hide,
8059
        getCss,
8060
        reposition,
8061
        destroy
8062
      };
8063
    };
8064
    const isFakeCaretTableBrowser = () => Env.browser.isFirefox();
8065
    const isInlineFakeCaretTarget = node => isContentEditableFalse$8(node) || isMedia$1(node);
8066
    const isFakeCaretTarget = node => {
8067
      const isTarget = isInlineFakeCaretTarget(node) || isTable$2(node) && isFakeCaretTableBrowser();
8068
      return isTarget && parentElement(SugarElement.fromDom(node)).exists(isEditable$2);
8069
    };
8070
 
8071
    const isContentEditableTrue$1 = isContentEditableTrue$3;
8072
    const isContentEditableFalse$7 = isContentEditableFalse$b;
8073
    const isMedia = isMedia$2;
1441 ariadna 8074
    const isBlockLike = matchStyleValues('display', 'block table table-cell table-row table-caption list-item');
1 efrain 8075
    const isCaretContainer = isCaretContainer$2;
8076
    const isCaretContainerBlock = isCaretContainerBlock$1;
8077
    const isElement$2 = isElement$6;
1441 ariadna 8078
    const isText$4 = isText$b;
1 efrain 8079
    const isCaretCandidate$1 = isCaretCandidate$3;
1441 ariadna 8080
    const isForwards = direction => direction === 1;
8081
    const isBackwards = direction => direction === -1;
1 efrain 8082
    const skipCaretContainers = (walk, shallow) => {
8083
      let node;
8084
      while (node = walk(shallow)) {
8085
        if (!isCaretContainerBlock(node)) {
8086
          return node;
8087
        }
8088
      }
8089
      return null;
8090
    };
8091
    const findNode = (node, direction, predicateFn, rootNode, shallow) => {
8092
      const walker = new DomTreeWalker(node, rootNode);
8093
      const isCefOrCaretContainer = isContentEditableFalse$7(node) || isCaretContainerBlock(node);
8094
      let tempNode;
8095
      if (isBackwards(direction)) {
8096
        if (isCefOrCaretContainer) {
8097
          tempNode = skipCaretContainers(walker.prev.bind(walker), true);
8098
          if (predicateFn(tempNode)) {
8099
            return tempNode;
8100
          }
8101
        }
8102
        while (tempNode = skipCaretContainers(walker.prev.bind(walker), shallow)) {
8103
          if (predicateFn(tempNode)) {
8104
            return tempNode;
8105
          }
8106
        }
8107
      }
8108
      if (isForwards(direction)) {
8109
        if (isCefOrCaretContainer) {
8110
          tempNode = skipCaretContainers(walker.next.bind(walker), true);
8111
          if (predicateFn(tempNode)) {
8112
            return tempNode;
8113
          }
8114
        }
8115
        while (tempNode = skipCaretContainers(walker.next.bind(walker), shallow)) {
8116
          if (predicateFn(tempNode)) {
8117
            return tempNode;
8118
          }
8119
        }
8120
      }
8121
      return null;
8122
    };
8123
    const getEditingHost = (node, rootNode) => {
8124
      const isCETrue = node => isContentEditableTrue$1(node.dom);
8125
      const isRoot = node => node.dom === rootNode;
8126
      return ancestor$4(SugarElement.fromDom(node), isCETrue, isRoot).map(elm => elm.dom).getOr(rootNode);
8127
    };
8128
    const getParentBlock$3 = (node, rootNode) => {
8129
      while (node && node !== rootNode) {
8130
        if (isBlockLike(node)) {
8131
          return node;
8132
        }
8133
        node = node.parentNode;
8134
      }
8135
      return null;
8136
    };
8137
    const isInSameBlock = (caretPosition1, caretPosition2, rootNode) => getParentBlock$3(caretPosition1.container(), rootNode) === getParentBlock$3(caretPosition2.container(), rootNode);
8138
    const getChildNodeAtRelativeOffset = (relativeOffset, caretPosition) => {
8139
      if (!caretPosition) {
8140
        return Optional.none();
8141
      }
8142
      const container = caretPosition.container();
8143
      const offset = caretPosition.offset();
8144
      if (!isElement$2(container)) {
8145
        return Optional.none();
8146
      }
8147
      return Optional.from(container.childNodes[offset + relativeOffset]);
8148
    };
8149
    const beforeAfter = (before, node) => {
8150
      var _a;
8151
      const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
8152
      const range = doc.createRange();
8153
      if (before) {
8154
        range.setStartBefore(node);
8155
        range.setEndBefore(node);
8156
      } else {
8157
        range.setStartAfter(node);
8158
        range.setEndAfter(node);
8159
      }
8160
      return range;
8161
    };
8162
    const isNodesInSameBlock = (root, node1, node2) => getParentBlock$3(node1, root) === getParentBlock$3(node2, root);
8163
    const lean = (left, root, node) => {
8164
      const siblingName = left ? 'previousSibling' : 'nextSibling';
8165
      let tempNode = node;
8166
      while (tempNode && tempNode !== root) {
8167
        let sibling = tempNode[siblingName];
8168
        if (sibling && isCaretContainer(sibling)) {
8169
          sibling = sibling[siblingName];
8170
        }
8171
        if (isContentEditableFalse$7(sibling) || isMedia(sibling)) {
8172
          if (isNodesInSameBlock(root, sibling, tempNode)) {
8173
            return sibling;
8174
          }
8175
          break;
8176
        }
8177
        if (isCaretCandidate$1(sibling)) {
8178
          break;
8179
        }
8180
        tempNode = tempNode.parentNode;
8181
      }
8182
      return null;
8183
    };
8184
    const before$2 = curry(beforeAfter, true);
8185
    const after$2 = curry(beforeAfter, false);
8186
    const normalizeRange = (direction, root, range) => {
8187
      let node;
8188
      const leanLeft = curry(lean, true, root);
8189
      const leanRight = curry(lean, false, root);
8190
      const container = range.startContainer;
8191
      const offset = range.startOffset;
8192
      if (isCaretContainerBlock$1(container)) {
8193
        const block = isText$4(container) ? container.parentNode : container;
8194
        const location = block.getAttribute('data-mce-caret');
8195
        if (location === 'before') {
8196
          node = block.nextSibling;
8197
          if (isFakeCaretTarget(node)) {
8198
            return before$2(node);
8199
          }
8200
        }
8201
        if (location === 'after') {
8202
          node = block.previousSibling;
8203
          if (isFakeCaretTarget(node)) {
8204
            return after$2(node);
8205
          }
8206
        }
8207
      }
8208
      if (!range.collapsed) {
8209
        return range;
8210
      }
1441 ariadna 8211
      if (isText$b(container)) {
1 efrain 8212
        if (isCaretContainer(container)) {
8213
          if (direction === 1) {
8214
            node = leanRight(container);
8215
            if (node) {
8216
              return before$2(node);
8217
            }
8218
            node = leanLeft(container);
8219
            if (node) {
8220
              return after$2(node);
8221
            }
8222
          }
8223
          if (direction === -1) {
8224
            node = leanLeft(container);
8225
            if (node) {
8226
              return after$2(node);
8227
            }
8228
            node = leanRight(container);
8229
            if (node) {
8230
              return before$2(node);
8231
            }
8232
          }
8233
          return range;
8234
        }
8235
        if (endsWithCaretContainer$1(container) && offset >= container.data.length - 1) {
8236
          if (direction === 1) {
8237
            node = leanRight(container);
8238
            if (node) {
8239
              return before$2(node);
8240
            }
8241
          }
8242
          return range;
8243
        }
8244
        if (startsWithCaretContainer$1(container) && offset <= 1) {
8245
          if (direction === -1) {
8246
            node = leanLeft(container);
8247
            if (node) {
8248
              return after$2(node);
8249
            }
8250
          }
8251
          return range;
8252
        }
8253
        if (offset === container.data.length) {
8254
          node = leanRight(container);
8255
          if (node) {
8256
            return before$2(node);
8257
          }
8258
          return range;
8259
        }
8260
        if (offset === 0) {
8261
          node = leanLeft(container);
8262
          if (node) {
8263
            return after$2(node);
8264
          }
8265
          return range;
8266
        }
8267
      }
8268
      return range;
8269
    };
8270
    const getRelativeCefElm = (forward, caretPosition) => getChildNodeAtRelativeOffset(forward ? 0 : -1, caretPosition).filter(isContentEditableFalse$7);
8271
    const getNormalizedRangeEndPoint = (direction, root, range) => {
8272
      const normalizedRange = normalizeRange(direction, root, range);
8273
      return direction === -1 ? CaretPosition.fromRangeStart(normalizedRange) : CaretPosition.fromRangeEnd(normalizedRange);
8274
    };
8275
    const getElementFromPosition = pos => Optional.from(pos.getNode()).map(SugarElement.fromDom);
8276
    const getElementFromPrevPosition = pos => Optional.from(pos.getNode(true)).map(SugarElement.fromDom);
8277
    const getVisualCaretPosition = (walkFn, caretPosition) => {
8278
      let pos = caretPosition;
8279
      while (pos = walkFn(pos)) {
8280
        if (pos.isVisible()) {
8281
          return pos;
8282
        }
8283
      }
8284
      return pos;
8285
    };
8286
    const isMoveInsideSameBlock = (from, to) => {
8287
      const inSameBlock = isInSameBlock(from, to);
8288
      if (!inSameBlock && isBr$6(from.getNode())) {
8289
        return true;
8290
      }
8291
      return inSameBlock;
8292
    };
8293
 
8294
    const isContentEditableFalse$6 = isContentEditableFalse$b;
1441 ariadna 8295
    const isText$3 = isText$b;
1 efrain 8296
    const isElement$1 = isElement$6;
8297
    const isBr$2 = isBr$6;
8298
    const isCaretCandidate = isCaretCandidate$3;
8299
    const isAtomic = isAtomic$1;
8300
    const isEditableCaretCandidate = isEditableCaretCandidate$1;
8301
    const getParents$3 = (node, root) => {
8302
      const parents = [];
8303
      let tempNode = node;
8304
      while (tempNode && tempNode !== root) {
8305
        parents.push(tempNode);
8306
        tempNode = tempNode.parentNode;
8307
      }
8308
      return parents;
8309
    };
8310
    const nodeAtIndex = (container, offset) => {
8311
      if (container.hasChildNodes() && offset < container.childNodes.length) {
8312
        return container.childNodes[offset];
8313
      }
8314
      return null;
8315
    };
8316
    const getCaretCandidatePosition = (direction, node) => {
8317
      if (isForwards(direction)) {
8318
        if (isCaretCandidate(node.previousSibling) && !isText$3(node.previousSibling)) {
8319
          return CaretPosition.before(node);
8320
        }
8321
        if (isText$3(node)) {
8322
          return CaretPosition(node, 0);
8323
        }
8324
      }
8325
      if (isBackwards(direction)) {
8326
        if (isCaretCandidate(node.nextSibling) && !isText$3(node.nextSibling)) {
8327
          return CaretPosition.after(node);
8328
        }
8329
        if (isText$3(node)) {
8330
          return CaretPosition(node, node.data.length);
8331
        }
8332
      }
8333
      if (isBackwards(direction)) {
8334
        if (isBr$2(node)) {
8335
          return CaretPosition.before(node);
8336
        }
8337
        return CaretPosition.after(node);
8338
      }
8339
      return CaretPosition.before(node);
8340
    };
8341
    const moveForwardFromBr = (root, nextNode) => {
8342
      const nextSibling = nextNode.nextSibling;
8343
      if (nextSibling && isCaretCandidate(nextSibling)) {
8344
        if (isText$3(nextSibling)) {
8345
          return CaretPosition(nextSibling, 0);
8346
        } else {
8347
          return CaretPosition.before(nextSibling);
8348
        }
8349
      } else {
1441 ariadna 8350
        return findCaretPosition$1(1, CaretPosition.after(nextNode), root);
1 efrain 8351
      }
8352
    };
8353
    const findCaretPosition$1 = (direction, startPos, root) => {
8354
      let node;
8355
      let nextNode;
8356
      let innerNode;
8357
      let caretPosition;
8358
      if (!isElement$1(root) || !startPos) {
8359
        return null;
8360
      }
8361
      if (startPos.isEqual(CaretPosition.after(root)) && root.lastChild) {
8362
        caretPosition = CaretPosition.after(root.lastChild);
8363
        if (isBackwards(direction) && isCaretCandidate(root.lastChild) && isElement$1(root.lastChild)) {
8364
          return isBr$2(root.lastChild) ? CaretPosition.before(root.lastChild) : caretPosition;
8365
        }
8366
      } else {
8367
        caretPosition = startPos;
8368
      }
8369
      const container = caretPosition.container();
8370
      let offset = caretPosition.offset();
8371
      if (isText$3(container)) {
8372
        if (isBackwards(direction) && offset > 0) {
8373
          return CaretPosition(container, --offset);
8374
        }
8375
        if (isForwards(direction) && offset < container.length) {
8376
          return CaretPosition(container, ++offset);
8377
        }
8378
        node = container;
8379
      } else {
8380
        if (isBackwards(direction) && offset > 0) {
8381
          nextNode = nodeAtIndex(container, offset - 1);
8382
          if (isCaretCandidate(nextNode)) {
8383
            if (!isAtomic(nextNode)) {
8384
              innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
8385
              if (innerNode) {
8386
                if (isText$3(innerNode)) {
8387
                  return CaretPosition(innerNode, innerNode.data.length);
8388
                }
8389
                return CaretPosition.after(innerNode);
8390
              }
8391
            }
8392
            if (isText$3(nextNode)) {
8393
              return CaretPosition(nextNode, nextNode.data.length);
8394
            }
8395
            return CaretPosition.before(nextNode);
8396
          }
8397
        }
8398
        if (isForwards(direction) && offset < container.childNodes.length) {
8399
          nextNode = nodeAtIndex(container, offset);
8400
          if (isCaretCandidate(nextNode)) {
8401
            if (isBr$2(nextNode)) {
8402
              return moveForwardFromBr(root, nextNode);
8403
            }
8404
            if (!isAtomic(nextNode)) {
8405
              innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
8406
              if (innerNode) {
8407
                if (isText$3(innerNode)) {
8408
                  return CaretPosition(innerNode, 0);
8409
                }
8410
                return CaretPosition.before(innerNode);
8411
              }
8412
            }
8413
            if (isText$3(nextNode)) {
8414
              return CaretPosition(nextNode, 0);
8415
            }
8416
            return CaretPosition.after(nextNode);
8417
          }
8418
        }
8419
        node = nextNode ? nextNode : caretPosition.getNode();
8420
      }
8421
      if (node && (isForwards(direction) && caretPosition.isAtEnd() || isBackwards(direction) && caretPosition.isAtStart())) {
8422
        node = findNode(node, direction, always, root, true);
8423
        if (isEditableCaretCandidate(node, root)) {
8424
          return getCaretCandidatePosition(direction, node);
8425
        }
8426
      }
8427
      nextNode = node ? findNode(node, direction, isEditableCaretCandidate, root) : node;
1441 ariadna 8428
      const rootContentEditableFalseElm = last$1(filter$5(getParents$3(container, root), isContentEditableFalse$6));
1 efrain 8429
      if (rootContentEditableFalseElm && (!nextNode || !rootContentEditableFalseElm.contains(nextNode))) {
8430
        if (isForwards(direction)) {
8431
          caretPosition = CaretPosition.after(rootContentEditableFalseElm);
8432
        } else {
8433
          caretPosition = CaretPosition.before(rootContentEditableFalseElm);
8434
        }
8435
        return caretPosition;
8436
      }
8437
      if (nextNode) {
8438
        return getCaretCandidatePosition(direction, nextNode);
8439
      }
8440
      return null;
8441
    };
8442
    const CaretWalker = root => ({
8443
      next: caretPosition => {
1441 ariadna 8444
        return findCaretPosition$1(1, caretPosition, root);
1 efrain 8445
      },
8446
      prev: caretPosition => {
1441 ariadna 8447
        return findCaretPosition$1(-1, caretPosition, root);
1 efrain 8448
      }
8449
    });
8450
 
8451
    const walkToPositionIn = (forward, root, start) => {
8452
      const position = forward ? CaretPosition.before(start) : CaretPosition.after(start);
8453
      return fromPosition(forward, root, position);
8454
    };
8455
    const afterElement = node => isBr$6(node) ? CaretPosition.before(node) : CaretPosition.after(node);
8456
    const isBeforeOrStart = position => {
8457
      if (CaretPosition.isTextPosition(position)) {
8458
        return position.offset() === 0;
8459
      } else {
8460
        return isCaretCandidate$3(position.getNode());
8461
      }
8462
    };
8463
    const isAfterOrEnd = position => {
8464
      if (CaretPosition.isTextPosition(position)) {
8465
        const container = position.container();
8466
        return position.offset() === container.data.length;
8467
      } else {
8468
        return isCaretCandidate$3(position.getNode(true));
8469
      }
8470
    };
8471
    const isBeforeAfterSameElement = (from, to) => !CaretPosition.isTextPosition(from) && !CaretPosition.isTextPosition(to) && from.getNode() === to.getNode(true);
8472
    const isAtBr = position => !CaretPosition.isTextPosition(position) && isBr$6(position.getNode());
8473
    const shouldSkipPosition = (forward, from, to) => {
8474
      if (forward) {
8475
        return !isBeforeAfterSameElement(from, to) && !isAtBr(from) && isAfterOrEnd(from) && isBeforeOrStart(to);
8476
      } else {
8477
        return !isBeforeAfterSameElement(to, from) && isBeforeOrStart(from) && isAfterOrEnd(to);
8478
      }
8479
    };
8480
    const fromPosition = (forward, root, pos) => {
8481
      const walker = CaretWalker(root);
8482
      return Optional.from(forward ? walker.next(pos) : walker.prev(pos));
8483
    };
8484
    const navigate = (forward, root, from) => fromPosition(forward, root, from).bind(to => {
8485
      if (isInSameBlock(from, to, root) && shouldSkipPosition(forward, from, to)) {
8486
        return fromPosition(forward, root, to);
8487
      } else {
8488
        return Optional.some(to);
8489
      }
8490
    });
8491
    const navigateIgnore = (forward, root, from, ignoreFilter) => navigate(forward, root, from).bind(pos => ignoreFilter(pos) ? navigateIgnore(forward, root, pos, ignoreFilter) : Optional.some(pos));
8492
    const positionIn = (forward, element) => {
8493
      const startNode = forward ? element.firstChild : element.lastChild;
1441 ariadna 8494
      if (isText$b(startNode)) {
1 efrain 8495
        return Optional.some(CaretPosition(startNode, forward ? 0 : startNode.data.length));
8496
      } else if (startNode) {
8497
        if (isCaretCandidate$3(startNode)) {
8498
          return Optional.some(forward ? CaretPosition.before(startNode) : afterElement(startNode));
8499
        } else {
8500
          return walkToPositionIn(forward, element, startNode);
8501
        }
8502
      } else {
8503
        return Optional.none();
8504
      }
8505
    };
8506
    const nextPosition = curry(fromPosition, true);
8507
    const prevPosition = curry(fromPosition, false);
8508
    const firstPositionIn = curry(positionIn, true);
8509
    const lastPositionIn = curry(positionIn, false);
8510
 
8511
    const CARET_ID = '_mce_caret';
8512
    const isCaretNode = node => isElement$6(node) && node.id === CARET_ID;
8513
    const getParentCaretContainer = (body, node) => {
8514
      let currentNode = node;
8515
      while (currentNode && currentNode !== body) {
8516
        if (isCaretNode(currentNode)) {
8517
          return currentNode;
8518
        }
8519
        currentNode = currentNode.parentNode;
8520
      }
8521
      return null;
8522
    };
8523
 
8524
    const isStringPathBookmark = bookmark => isString(bookmark.start);
8525
    const isRangeBookmark = bookmark => has$2(bookmark, 'rng');
8526
    const isIdBookmark = bookmark => has$2(bookmark, 'id');
8527
    const isIndexBookmark = bookmark => has$2(bookmark, 'name');
8528
    const isPathBookmark = bookmark => Tools.isArray(bookmark.start);
8529
 
8530
    const isForwardBookmark = bookmark => !isIndexBookmark(bookmark) && isBoolean(bookmark.forward) ? bookmark.forward : true;
8531
    const addBogus = (dom, node) => {
8532
      if (isElement$6(node) && dom.isBlock(node) && !node.innerHTML) {
8533
        node.innerHTML = '<br data-mce-bogus="1" />';
8534
      }
8535
      return node;
8536
    };
8537
    const resolveCaretPositionBookmark = (dom, bookmark) => {
8538
      const startPos = Optional.from(resolve$1(dom.getRoot(), bookmark.start));
8539
      const endPos = Optional.from(resolve$1(dom.getRoot(), bookmark.end));
8540
      return lift2(startPos, endPos, (start, end) => {
8541
        const range = dom.createRng();
8542
        range.setStart(start.container(), start.offset());
8543
        range.setEnd(end.container(), end.offset());
8544
        return {
8545
          range,
8546
          forward: isForwardBookmark(bookmark)
8547
        };
8548
      });
8549
    };
8550
    const insertZwsp = (node, rng) => {
8551
      var _a;
8552
      const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
8553
      const textNode = doc.createTextNode(ZWSP$1);
8554
      node.appendChild(textNode);
8555
      rng.setStart(textNode, 0);
8556
      rng.setEnd(textNode, 0);
8557
    };
8558
    const isEmpty$1 = node => !node.hasChildNodes();
8559
    const tryFindRangePosition = (node, rng) => lastPositionIn(node).fold(never, pos => {
8560
      rng.setStart(pos.container(), pos.offset());
8561
      rng.setEnd(pos.container(), pos.offset());
8562
      return true;
8563
    });
8564
    const padEmptyCaretContainer = (root, node, rng) => {
8565
      if (isEmpty$1(node) && getParentCaretContainer(root, node)) {
8566
        insertZwsp(node, rng);
8567
        return true;
8568
      } else {
8569
        return false;
8570
      }
8571
    };
8572
    const setEndPoint = (dom, start, bookmark, rng) => {
8573
      const point = bookmark[start ? 'start' : 'end'];
8574
      const root = dom.getRoot();
8575
      if (point) {
8576
        let node = root;
8577
        let offset = point[0];
8578
        for (let i = point.length - 1; node && i >= 1; i--) {
8579
          const children = node.childNodes;
8580
          if (padEmptyCaretContainer(root, node, rng)) {
8581
            return true;
8582
          }
8583
          if (point[i] > children.length - 1) {
8584
            if (padEmptyCaretContainer(root, node, rng)) {
8585
              return true;
8586
            }
8587
            return tryFindRangePosition(node, rng);
8588
          }
8589
          node = children[point[i]];
8590
        }
1441 ariadna 8591
        if (isText$b(node)) {
1 efrain 8592
          offset = Math.min(point[0], node.data.length);
8593
        }
8594
        if (isElement$6(node)) {
8595
          offset = Math.min(point[0], node.childNodes.length);
8596
        }
8597
        if (start) {
8598
          rng.setStart(node, offset);
8599
        } else {
8600
          rng.setEnd(node, offset);
8601
        }
8602
      }
8603
      return true;
8604
    };
1441 ariadna 8605
    const isValidTextNode = node => isText$b(node) && node.data.length > 0;
1 efrain 8606
    const restoreEndPoint = (dom, suffix, bookmark) => {
8607
      const marker = dom.get(bookmark.id + '_' + suffix);
8608
      const markerParent = marker === null || marker === void 0 ? void 0 : marker.parentNode;
8609
      const keep = bookmark.keep;
8610
      if (marker && markerParent) {
8611
        let container;
8612
        let offset;
8613
        if (suffix === 'start') {
8614
          if (!keep) {
8615
            container = markerParent;
8616
            offset = dom.nodeIndex(marker);
8617
          } else {
8618
            if (marker.hasChildNodes()) {
8619
              container = marker.firstChild;
8620
              offset = 1;
8621
            } else if (isValidTextNode(marker.nextSibling)) {
8622
              container = marker.nextSibling;
8623
              offset = 0;
8624
            } else if (isValidTextNode(marker.previousSibling)) {
8625
              container = marker.previousSibling;
8626
              offset = marker.previousSibling.data.length;
8627
            } else {
8628
              container = markerParent;
8629
              offset = dom.nodeIndex(marker) + 1;
8630
            }
8631
          }
8632
        } else {
8633
          if (!keep) {
8634
            container = markerParent;
8635
            offset = dom.nodeIndex(marker);
8636
          } else {
8637
            if (marker.hasChildNodes()) {
8638
              container = marker.firstChild;
8639
              offset = 1;
8640
            } else if (isValidTextNode(marker.previousSibling)) {
8641
              container = marker.previousSibling;
8642
              offset = marker.previousSibling.data.length;
8643
            } else {
8644
              container = markerParent;
8645
              offset = dom.nodeIndex(marker);
8646
            }
8647
          }
8648
        }
8649
        if (!keep) {
8650
          const prev = marker.previousSibling;
8651
          const next = marker.nextSibling;
8652
          Tools.each(Tools.grep(marker.childNodes), node => {
1441 ariadna 8653
            if (isText$b(node)) {
1 efrain 8654
              node.data = node.data.replace(/\uFEFF/g, '');
8655
            }
8656
          });
8657
          let otherMarker;
8658
          while (otherMarker = dom.get(bookmark.id + '_' + suffix)) {
8659
            dom.remove(otherMarker, true);
8660
          }
1441 ariadna 8661
          if (isText$b(next) && isText$b(prev) && !Env.browser.isOpera()) {
1 efrain 8662
            const idx = prev.data.length;
8663
            prev.appendData(next.data);
8664
            dom.remove(next);
8665
            container = prev;
8666
            offset = idx;
8667
          }
8668
        }
8669
        return Optional.some(CaretPosition(container, offset));
8670
      } else {
8671
        return Optional.none();
8672
      }
8673
    };
8674
    const resolvePaths = (dom, bookmark) => {
8675
      const range = dom.createRng();
8676
      if (setEndPoint(dom, true, bookmark, range) && setEndPoint(dom, false, bookmark, range)) {
8677
        return Optional.some({
8678
          range,
8679
          forward: isForwardBookmark(bookmark)
8680
        });
8681
      } else {
8682
        return Optional.none();
8683
      }
8684
    };
8685
    const resolveId = (dom, bookmark) => {
8686
      const startPos = restoreEndPoint(dom, 'start', bookmark);
8687
      const endPos = restoreEndPoint(dom, 'end', bookmark);
8688
      return lift2(startPos, endPos.or(startPos), (spos, epos) => {
8689
        const range = dom.createRng();
8690
        range.setStart(addBogus(dom, spos.container()), spos.offset());
8691
        range.setEnd(addBogus(dom, epos.container()), epos.offset());
8692
        return {
8693
          range,
8694
          forward: isForwardBookmark(bookmark)
8695
        };
8696
      });
8697
    };
8698
    const resolveIndex = (dom, bookmark) => Optional.from(dom.select(bookmark.name)[bookmark.index]).map(elm => {
8699
      const range = dom.createRng();
8700
      range.selectNode(elm);
8701
      return {
8702
        range,
8703
        forward: true
8704
      };
8705
    });
8706
    const resolve = (selection, bookmark) => {
8707
      const dom = selection.dom;
8708
      if (bookmark) {
8709
        if (isPathBookmark(bookmark)) {
8710
          return resolvePaths(dom, bookmark);
8711
        } else if (isStringPathBookmark(bookmark)) {
8712
          return resolveCaretPositionBookmark(dom, bookmark);
8713
        } else if (isIdBookmark(bookmark)) {
8714
          return resolveId(dom, bookmark);
8715
        } else if (isIndexBookmark(bookmark)) {
8716
          return resolveIndex(dom, bookmark);
8717
        } else if (isRangeBookmark(bookmark)) {
8718
          return Optional.some({
8719
            range: bookmark.rng,
8720
            forward: isForwardBookmark(bookmark)
8721
          });
8722
        }
8723
      }
8724
      return Optional.none();
8725
    };
8726
 
1441 ariadna 8727
    const getBookmark$2 = (selection, type, normalized) => {
8728
      return getBookmark$3(selection, type, normalized);
1 efrain 8729
    };
8730
    const moveToBookmark = (selection, bookmark) => {
8731
      resolve(selection, bookmark).each(({range, forward}) => {
8732
        selection.setRng(range, forward);
8733
      });
8734
    };
8735
    const isBookmarkNode$1 = node => {
8736
      return isElement$6(node) && node.tagName === 'SPAN' && node.getAttribute('data-mce-type') === 'bookmark';
8737
    };
8738
 
8739
    const is = expected => actual => expected === actual;
8740
    const isNbsp = is(nbsp);
8741
    const isWhiteSpace = chr => chr !== '' && ' \f\n\r\t\x0B'.indexOf(chr) !== -1;
8742
    const isContent = chr => !isWhiteSpace(chr) && !isNbsp(chr) && !isZwsp$2(chr);
8743
 
8744
    const getRanges$1 = selection => {
8745
      const ranges = [];
8746
      if (selection) {
8747
        for (let i = 0; i < selection.rangeCount; i++) {
8748
          ranges.push(selection.getRangeAt(i));
8749
        }
8750
      }
8751
      return ranges;
8752
    };
8753
    const getSelectedNodes = ranges => {
8754
      return bind$3(ranges, range => {
8755
        const node = getSelectedNode(range);
8756
        return node ? [SugarElement.fromDom(node)] : [];
8757
      });
8758
    };
8759
    const hasMultipleRanges = selection => {
8760
      return getRanges$1(selection).length > 1;
8761
    };
8762
 
8763
    const getCellsFromRanges = ranges => filter$5(getSelectedNodes(ranges), isTableCell$2);
8764
    const getCellsFromElement = elm => descendants(elm, 'td[data-mce-selected],th[data-mce-selected]');
8765
    const getCellsFromElementOrRanges = (ranges, element) => {
8766
      const selectedCells = getCellsFromElement(element);
8767
      return selectedCells.length > 0 ? selectedCells : getCellsFromRanges(ranges);
8768
    };
8769
    const getCellsFromEditor = editor => getCellsFromElementOrRanges(getRanges$1(editor.selection.getSel()), SugarElement.fromDom(editor.getBody()));
8770
    const getClosestTable = (cell, isRoot) => ancestor$3(cell, 'table', isRoot);
8771
 
8772
    const getStartNode = rng => {
8773
      const sc = rng.startContainer, so = rng.startOffset;
1441 ariadna 8774
      if (isText$b(sc)) {
1 efrain 8775
        return so === 0 ? Optional.some(SugarElement.fromDom(sc)) : Optional.none();
8776
      } else {
8777
        return Optional.from(sc.childNodes[so]).map(SugarElement.fromDom);
8778
      }
8779
    };
8780
    const getEndNode = rng => {
8781
      const ec = rng.endContainer, eo = rng.endOffset;
1441 ariadna 8782
      if (isText$b(ec)) {
1 efrain 8783
        return eo === ec.data.length ? Optional.some(SugarElement.fromDom(ec)) : Optional.none();
8784
      } else {
8785
        return Optional.from(ec.childNodes[eo - 1]).map(SugarElement.fromDom);
8786
      }
8787
    };
8788
    const getFirstChildren = node => {
8789
      return firstChild(node).fold(constant([node]), child => {
8790
        return [node].concat(getFirstChildren(child));
8791
      });
8792
    };
8793
    const getLastChildren = node => {
8794
      return lastChild(node).fold(constant([node]), child => {
8795
        if (name(child) === 'br') {
8796
          return prevSibling(child).map(sibling => {
8797
            return [node].concat(getLastChildren(sibling));
8798
          }).getOr([]);
8799
        } else {
8800
          return [node].concat(getLastChildren(child));
8801
        }
8802
      });
8803
    };
8804
    const hasAllContentsSelected = (elm, rng) => {
8805
      return lift2(getStartNode(rng), getEndNode(rng), (startNode, endNode) => {
8806
        const start = find$2(getFirstChildren(elm), curry(eq, startNode));
8807
        const end = find$2(getLastChildren(elm), curry(eq, endNode));
8808
        return start.isSome() && end.isSome();
8809
      }).getOr(false);
8810
    };
8811
    const moveEndPoint = (dom, rng, node, start) => {
8812
      const root = node;
8813
      const walker = new DomTreeWalker(node, root);
8814
      const moveCaretBeforeOnEnterElementsMap = filter$4(dom.schema.getMoveCaretBeforeOnEnterElements(), (_, name) => !contains$2([
8815
        'td',
8816
        'th',
8817
        'table'
8818
      ], name.toLowerCase()));
8819
      let currentNode = node;
8820
      do {
1441 ariadna 8821
        if (isText$b(currentNode) && Tools.trim(currentNode.data).length !== 0) {
1 efrain 8822
          if (start) {
8823
            rng.setStart(currentNode, 0);
8824
          } else {
8825
            rng.setEnd(currentNode, currentNode.data.length);
8826
          }
8827
          return;
8828
        }
8829
        if (moveCaretBeforeOnEnterElementsMap[currentNode.nodeName]) {
8830
          if (start) {
8831
            rng.setStartBefore(currentNode);
8832
          } else {
8833
            if (currentNode.nodeName === 'BR') {
8834
              rng.setEndBefore(currentNode);
8835
            } else {
8836
              rng.setEndAfter(currentNode);
8837
            }
8838
          }
8839
          return;
8840
        }
8841
      } while (currentNode = start ? walker.next() : walker.prev());
8842
      if (root.nodeName === 'BODY') {
8843
        if (start) {
8844
          rng.setStart(root, 0);
8845
        } else {
8846
          rng.setEnd(root, root.childNodes.length);
8847
        }
8848
      }
8849
    };
8850
    const hasAnyRanges = editor => {
8851
      const sel = editor.selection.getSel();
8852
      return isNonNullable(sel) && sel.rangeCount > 0;
8853
    };
8854
    const runOnRanges = (editor, executor) => {
8855
      const fakeSelectionNodes = getCellsFromEditor(editor);
8856
      if (fakeSelectionNodes.length > 0) {
8857
        each$e(fakeSelectionNodes, elem => {
8858
          const node = elem.dom;
8859
          const fakeNodeRng = editor.dom.createRng();
8860
          fakeNodeRng.setStartBefore(node);
8861
          fakeNodeRng.setEndAfter(node);
8862
          executor(fakeNodeRng, true);
8863
        });
8864
      } else {
8865
        executor(editor.selection.getRng(), false);
8866
      }
8867
    };
8868
    const preserve = (selection, fillBookmark, executor) => {
8869
      const bookmark = getPersistentBookmark(selection, fillBookmark);
8870
      executor(bookmark);
8871
      selection.moveToBookmark(bookmark);
8872
    };
8873
 
8874
    const isNode = node => isNumber(node === null || node === void 0 ? void 0 : node.nodeType);
1441 ariadna 8875
    const isElementNode$1 = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node);
1 efrain 8876
    const isElementDirectlySelected = (dom, node) => {
8877
      if (isElementNode$1(node) && !/^(TD|TH)$/.test(node.nodeName)) {
8878
        const selectedAttr = dom.getAttrib(node, 'data-mce-selected');
8879
        const value = parseInt(selectedAttr, 10);
8880
        return !isNaN(value) && value > 0;
8881
      } else {
8882
        return false;
8883
      }
8884
    };
8885
    const preserveSelection = (editor, action, shouldMoveStart) => {
8886
      const {selection, dom} = editor;
8887
      const selectedNodeBeforeAction = selection.getNode();
8888
      const isSelectedBeforeNodeNoneditable = isContentEditableFalse$b(selectedNodeBeforeAction);
8889
      preserve(selection, true, () => {
8890
        action();
8891
      });
8892
      const isBeforeNodeStillNoneditable = isSelectedBeforeNodeNoneditable && isContentEditableFalse$b(selectedNodeBeforeAction);
8893
      if (isBeforeNodeStillNoneditable && dom.isChildOf(selectedNodeBeforeAction, editor.getBody())) {
8894
        editor.selection.select(selectedNodeBeforeAction);
8895
      } else if (shouldMoveStart(selection.getStart())) {
8896
        moveStartToNearestText(dom, selection);
8897
      }
8898
    };
8899
    const moveStartToNearestText = (dom, selection) => {
8900
      var _a, _b;
8901
      const rng = selection.getRng();
8902
      const {startContainer, startOffset} = rng;
8903
      const selectedNode = selection.getNode();
8904
      if (isElementDirectlySelected(dom, selectedNode)) {
8905
        return;
8906
      }
8907
      if (isElement$6(startContainer)) {
8908
        const nodes = startContainer.childNodes;
8909
        const root = dom.getRoot();
8910
        let walker;
8911
        if (startOffset < nodes.length) {
8912
          const startNode = nodes[startOffset];
8913
          walker = new DomTreeWalker(startNode, (_a = dom.getParent(startNode, dom.isBlock)) !== null && _a !== void 0 ? _a : root);
8914
        } else {
8915
          const startNode = nodes[nodes.length - 1];
8916
          walker = new DomTreeWalker(startNode, (_b = dom.getParent(startNode, dom.isBlock)) !== null && _b !== void 0 ? _b : root);
8917
          walker.next(true);
8918
        }
8919
        for (let node = walker.current(); node; node = walker.next()) {
8920
          if (dom.getContentEditable(node) === 'false') {
8921
            return;
1441 ariadna 8922
          } else if (isText$b(node) && !isWhiteSpaceNode$1(node)) {
1 efrain 8923
            rng.setStart(node, 0);
8924
            selection.setRng(rng);
8925
            return;
8926
          }
8927
        }
8928
      }
8929
    };
8930
    const getNonWhiteSpaceSibling = (node, next, inc) => {
8931
      if (node) {
8932
        const nextName = next ? 'nextSibling' : 'previousSibling';
8933
        for (node = inc ? node : node[nextName]; node; node = node[nextName]) {
8934
          if (isElement$6(node) || !isWhiteSpaceNode$1(node)) {
8935
            return node;
8936
          }
8937
        }
8938
      }
8939
      return undefined;
8940
    };
8941
    const isTextBlock$1 = (schema, node) => !!schema.getTextBlockElements()[node.nodeName.toLowerCase()] || isTransparentBlock(schema, node);
8942
    const isValid = (ed, parent, child) => {
8943
      return ed.schema.isValidChild(parent, child);
8944
    };
8945
    const isWhiteSpaceNode$1 = (node, allowSpaces = false) => {
1441 ariadna 8946
      if (isNonNullable(node) && isText$b(node)) {
1 efrain 8947
        const data = allowSpaces ? node.data.replace(/ /g, '\xA0') : node.data;
8948
        return isWhitespaceText(data);
8949
      } else {
8950
        return false;
8951
      }
8952
    };
8953
    const isEmptyTextNode$1 = node => {
1441 ariadna 8954
      return isNonNullable(node) && isText$b(node) && node.length === 0;
1 efrain 8955
    };
8956
    const isWrapNoneditableTarget = (editor, node) => {
8957
      const baseDataSelector = '[data-mce-cef-wrappable]';
8958
      const formatNoneditableSelector = getFormatNoneditableSelector(editor);
8959
      const selector = isEmpty$3(formatNoneditableSelector) ? baseDataSelector : `${ baseDataSelector },${ formatNoneditableSelector }`;
8960
      return is$1(SugarElement.fromDom(node), selector);
8961
    };
8962
    const isWrappableNoneditable = (editor, node) => {
8963
      const dom = editor.dom;
8964
      return isElementNode$1(node) && dom.getContentEditable(node) === 'false' && isWrapNoneditableTarget(editor, node) && dom.select('[contenteditable="true"]', node).length === 0;
8965
    };
8966
    const replaceVars = (value, vars) => {
8967
      if (isFunction(value)) {
8968
        return value(vars);
8969
      } else if (isNonNullable(vars)) {
8970
        value = value.replace(/%(\w+)/g, (str, name) => {
8971
          return vars[name] || str;
8972
        });
8973
      }
8974
      return value;
8975
    };
8976
    const isEq$5 = (str1, str2) => {
8977
      str1 = str1 || '';
8978
      str2 = str2 || '';
8979
      str1 = '' + (str1.nodeName || str1);
8980
      str2 = '' + (str2.nodeName || str2);
8981
      return str1.toLowerCase() === str2.toLowerCase();
8982
    };
8983
    const normalizeStyleValue = (value, name) => {
8984
      if (isNullable(value)) {
8985
        return null;
8986
      } else {
8987
        let strValue = String(value);
8988
        if (name === 'color' || name === 'backgroundColor') {
8989
          strValue = rgbaToHexString(strValue);
8990
        }
8991
        if (name === 'fontWeight' && value === 700) {
8992
          strValue = 'bold';
8993
        }
8994
        if (name === 'fontFamily') {
8995
          strValue = strValue.replace(/[\'\"]/g, '').replace(/,\s+/g, ',');
8996
        }
8997
        return strValue;
8998
      }
8999
    };
9000
    const getStyle = (dom, node, name) => {
9001
      const style = dom.getStyle(node, name);
9002
      return normalizeStyleValue(style, name);
9003
    };
9004
    const getTextDecoration = (dom, node) => {
9005
      let decoration;
9006
      dom.getParent(node, n => {
9007
        if (isElement$6(n)) {
9008
          decoration = dom.getStyle(n, 'text-decoration');
9009
          return !!decoration && decoration !== 'none';
9010
        } else {
9011
          return false;
9012
        }
9013
      });
9014
      return decoration;
9015
    };
9016
    const getParents$2 = (dom, node, selector) => {
9017
      return dom.getParents(node, selector, dom.getRoot());
9018
    };
9019
    const isFormatPredicate = (editor, formatName, predicate) => {
9020
      const formats = editor.formatter.get(formatName);
9021
      return isNonNullable(formats) && exists(formats, predicate);
9022
    };
9023
    const isVariableFormatName = (editor, formatName) => {
9024
      const hasVariableValues = format => {
9025
        const isVariableValue = val => isFunction(val) || val.length > 1 && val.charAt(0) === '%';
9026
        return exists([
9027
          'styles',
9028
          'attributes'
9029
        ], key => get$a(format, key).exists(field => {
9030
          const fieldValues = isArray$1(field) ? field : values(field);
9031
          return exists(fieldValues, isVariableValue);
9032
        }));
9033
      };
9034
      return isFormatPredicate(editor, formatName, hasVariableValues);
9035
    };
9036
    const areSimilarFormats = (editor, formatName, otherFormatName) => {
9037
      const validKeys = [
9038
        'inline',
9039
        'block',
9040
        'selector',
9041
        'attributes',
9042
        'styles',
9043
        'classes'
9044
      ];
9045
      const filterObj = format => filter$4(format, (_, key) => exists(validKeys, validKey => validKey === key));
9046
      return isFormatPredicate(editor, formatName, fmt1 => {
9047
        const filteredFmt1 = filterObj(fmt1);
9048
        return isFormatPredicate(editor, otherFormatName, fmt2 => {
9049
          const filteredFmt2 = filterObj(fmt2);
9050
          return equal$1(filteredFmt1, filteredFmt2);
9051
        });
9052
      });
9053
    };
9054
    const isBlockFormat = format => hasNonNullableKey(format, 'block');
9055
    const isWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper === true;
9056
    const isNonWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper !== true;
9057
    const isSelectorFormat = format => hasNonNullableKey(format, 'selector');
9058
    const isInlineFormat = format => hasNonNullableKey(format, 'inline');
9059
    const isMixedFormat = format => isSelectorFormat(format) && isInlineFormat(format) && is$2(get$a(format, 'mixed'), true);
9060
    const shouldExpandToSelector = format => isSelectorFormat(format) && format.expand !== false && !isInlineFormat(format);
9061
    const getEmptyCaretContainers = node => {
9062
      const nodes = [];
9063
      let tempNode = node;
9064
      while (tempNode) {
1441 ariadna 9065
        if (isText$b(tempNode) && tempNode.data !== ZWSP$1 || tempNode.childNodes.length > 1) {
1 efrain 9066
          return [];
9067
        }
9068
        if (isElement$6(tempNode)) {
9069
          nodes.push(tempNode);
9070
        }
9071
        tempNode = tempNode.firstChild;
9072
      }
9073
      return nodes;
9074
    };
9075
    const isCaretContainerEmpty = node => {
9076
      return getEmptyCaretContainers(node).length > 0;
9077
    };
9078
    const isEmptyCaretFormatElement = element => {
9079
      return isCaretNode(element.dom) && isCaretContainerEmpty(element.dom);
9080
    };
9081
 
9082
    const isBookmarkNode = isBookmarkNode$1;
9083
    const getParents$1 = getParents$2;
9084
    const isWhiteSpaceNode = isWhiteSpaceNode$1;
9085
    const isTextBlock = isTextBlock$1;
9086
    const isBogusBr = node => {
9087
      return isBr$6(node) && node.getAttribute('data-mce-bogus') && !node.nextSibling;
9088
    };
9089
    const findParentContentEditable = (dom, node) => {
9090
      let parent = node;
9091
      while (parent) {
9092
        if (isElement$6(parent) && dom.getContentEditable(parent)) {
9093
          return dom.getContentEditable(parent) === 'false' ? parent : node;
9094
        }
9095
        parent = parent.parentNode;
9096
      }
9097
      return node;
9098
    };
9099
    const walkText = (start, node, offset, predicate) => {
9100
      const str = node.data;
9101
      if (start) {
9102
        for (let i = offset; i > 0; i--) {
9103
          if (predicate(str.charAt(i - 1))) {
9104
            return i;
9105
          }
9106
        }
9107
      } else {
9108
        for (let i = offset; i < str.length; i++) {
9109
          if (predicate(str.charAt(i))) {
9110
            return i;
9111
          }
9112
        }
9113
      }
9114
      return -1;
9115
    };
9116
    const findSpace = (start, node, offset) => walkText(start, node, offset, c => isNbsp(c) || isWhiteSpace(c));
9117
    const findContent = (start, node, offset) => walkText(start, node, offset, isContent);
9118
    const findWordEndPoint = (dom, body, container, offset, start, includeTrailingSpaces) => {
9119
      let lastTextNode;
1441 ariadna 9120
      const closestRoot = dom.getParent(container, node => isEditingHost(node) || dom.isBlock(node));
9121
      const rootNode = isNonNullable(closestRoot) ? closestRoot : body;
1 efrain 9122
      const walk = (container, offset, pred) => {
9123
        const textSeeker = TextSeeker(dom);
9124
        const walker = start ? textSeeker.backwards : textSeeker.forwards;
9125
        return Optional.from(walker(container, offset, (text, textOffset) => {
9126
          if (isBookmarkNode(text.parentNode)) {
9127
            return -1;
9128
          } else {
9129
            lastTextNode = text;
9130
            return pred(start, text, textOffset);
9131
          }
9132
        }, rootNode));
9133
      };
9134
      const spaceResult = walk(container, offset, findSpace);
9135
      return spaceResult.bind(result => includeTrailingSpaces ? walk(result.container, result.offset + (start ? -1 : 0), findContent) : Optional.some(result)).orThunk(() => lastTextNode ? Optional.some({
9136
        container: lastTextNode,
9137
        offset: start ? 0 : lastTextNode.length
9138
      }) : Optional.none());
9139
    };
9140
    const findSelectorEndPoint = (dom, formatList, rng, container, siblingName) => {
9141
      const sibling = container[siblingName];
1441 ariadna 9142
      if (isText$b(container) && isEmpty$3(container.data) && sibling) {
1 efrain 9143
        container = sibling;
9144
      }
9145
      const parents = getParents$1(dom, container);
9146
      for (let i = 0; i < parents.length; i++) {
9147
        for (let y = 0; y < formatList.length; y++) {
9148
          const curFormat = formatList[y];
9149
          if (isNonNullable(curFormat.collapsed) && curFormat.collapsed !== rng.collapsed) {
9150
            continue;
9151
          }
9152
          if (isSelectorFormat(curFormat) && dom.is(parents[i], curFormat.selector)) {
9153
            return parents[i];
9154
          }
9155
        }
9156
      }
9157
      return container;
9158
    };
9159
    const findBlockEndPoint = (dom, formatList, container, siblingName) => {
9160
      var _a;
9161
      let node = container;
9162
      const root = dom.getRoot();
9163
      const format = formatList[0];
9164
      if (isBlockFormat(format)) {
9165
        node = format.wrapper ? null : dom.getParent(container, format.block, root);
9166
      }
9167
      if (!node) {
9168
        const scopeRoot = (_a = dom.getParent(container, 'LI,TD,TH,SUMMARY')) !== null && _a !== void 0 ? _a : root;
1441 ariadna 9169
        node = dom.getParent(isText$b(container) ? container.parentNode : container, node => node !== root && isTextBlock(dom.schema, node), scopeRoot);
1 efrain 9170
      }
9171
      if (node && isBlockFormat(format) && format.wrapper) {
9172
        node = getParents$1(dom, node, 'ul,ol').reverse()[0] || node;
9173
      }
9174
      if (!node) {
9175
        node = container;
9176
        while (node && node[siblingName] && !dom.isBlock(node[siblingName])) {
9177
          node = node[siblingName];
9178
          if (isEq$5(node, 'br')) {
9179
            break;
9180
          }
9181
        }
9182
      }
9183
      return node || container;
9184
    };
9185
    const isAtBlockBoundary$1 = (dom, root, container, siblingName) => {
9186
      const parent = container.parentNode;
9187
      if (isNonNullable(container[siblingName])) {
9188
        return false;
9189
      } else if (parent === root || isNullable(parent) || dom.isBlock(parent)) {
9190
        return true;
9191
      } else {
9192
        return isAtBlockBoundary$1(dom, root, parent, siblingName);
9193
      }
9194
    };
1441 ariadna 9195
    const findParentContainer = (dom, formatList, container, offset, start, expandToBlock) => {
1 efrain 9196
      let parent = container;
9197
      const siblingName = start ? 'previousSibling' : 'nextSibling';
9198
      const root = dom.getRoot();
1441 ariadna 9199
      if (isText$b(container) && !isWhiteSpaceNode(container)) {
1 efrain 9200
        if (start ? offset > 0 : offset < container.data.length) {
9201
          return container;
9202
        }
9203
      }
9204
      while (parent) {
1441 ariadna 9205
        if (isEditingHost(parent)) {
9206
          return container;
9207
        }
1 efrain 9208
        if (!formatList[0].block_expand && dom.isBlock(parent)) {
1441 ariadna 9209
          return expandToBlock ? parent : container;
1 efrain 9210
        }
9211
        for (let sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
1441 ariadna 9212
          const allowSpaces = isText$b(sibling) && !isAtBlockBoundary$1(dom, root, sibling, siblingName);
1 efrain 9213
          if (!isBookmarkNode(sibling) && !isBogusBr(sibling) && !isWhiteSpaceNode(sibling, allowSpaces)) {
9214
            return parent;
9215
          }
9216
        }
9217
        if (parent === root || parent.parentNode === root) {
9218
          container = parent;
9219
          break;
9220
        }
9221
        parent = parent.parentNode;
9222
      }
9223
      return container;
9224
    };
9225
    const isSelfOrParentBookmark = container => isBookmarkNode(container.parentNode) || isBookmarkNode(container);
1441 ariadna 9226
    const expandRng = (dom, rng, formatList, expandOptions = {}) => {
9227
      const {includeTrailingSpace = false, expandToBlock = true} = expandOptions;
9228
      const editableHost = dom.getParent(rng.commonAncestorContainer, node => isEditingHost(node));
9229
      const root = isNonNullable(editableHost) ? editableHost : dom.getRoot();
1 efrain 9230
      let {startContainer, startOffset, endContainer, endOffset} = rng;
9231
      const format = formatList[0];
9232
      if (isElement$6(startContainer) && startContainer.hasChildNodes()) {
9233
        startContainer = getNode$1(startContainer, startOffset);
1441 ariadna 9234
        if (isText$b(startContainer)) {
1 efrain 9235
          startOffset = 0;
9236
        }
9237
      }
9238
      if (isElement$6(endContainer) && endContainer.hasChildNodes()) {
9239
        endContainer = getNode$1(endContainer, rng.collapsed ? endOffset : endOffset - 1);
1441 ariadna 9240
        if (isText$b(endContainer)) {
1 efrain 9241
          endOffset = endContainer.data.length;
9242
        }
9243
      }
9244
      startContainer = findParentContentEditable(dom, startContainer);
9245
      endContainer = findParentContentEditable(dom, endContainer);
9246
      if (isSelfOrParentBookmark(startContainer)) {
9247
        startContainer = isBookmarkNode(startContainer) ? startContainer : startContainer.parentNode;
9248
        if (rng.collapsed) {
9249
          startContainer = startContainer.previousSibling || startContainer;
9250
        } else {
9251
          startContainer = startContainer.nextSibling || startContainer;
9252
        }
1441 ariadna 9253
        if (isText$b(startContainer)) {
1 efrain 9254
          startOffset = rng.collapsed ? startContainer.length : 0;
9255
        }
9256
      }
9257
      if (isSelfOrParentBookmark(endContainer)) {
9258
        endContainer = isBookmarkNode(endContainer) ? endContainer : endContainer.parentNode;
9259
        if (rng.collapsed) {
9260
          endContainer = endContainer.nextSibling || endContainer;
9261
        } else {
9262
          endContainer = endContainer.previousSibling || endContainer;
9263
        }
1441 ariadna 9264
        if (isText$b(endContainer)) {
1 efrain 9265
          endOffset = rng.collapsed ? 0 : endContainer.length;
9266
        }
9267
      }
9268
      if (rng.collapsed) {
1441 ariadna 9269
        const startPoint = findWordEndPoint(dom, root, startContainer, startOffset, true, includeTrailingSpace);
1 efrain 9270
        startPoint.each(({container, offset}) => {
9271
          startContainer = container;
9272
          startOffset = offset;
9273
        });
1441 ariadna 9274
        const endPoint = findWordEndPoint(dom, root, endContainer, endOffset, false, includeTrailingSpace);
1 efrain 9275
        endPoint.each(({container, offset}) => {
9276
          endContainer = container;
9277
          endOffset = offset;
9278
        });
9279
      }
9280
      if (isInlineFormat(format) || format.block_expand) {
1441 ariadna 9281
        if (!isInlineFormat(format) || (!isText$b(startContainer) || startOffset === 0)) {
9282
          startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true, expandToBlock);
1 efrain 9283
        }
1441 ariadna 9284
        if (!isInlineFormat(format) || (!isText$b(endContainer) || endOffset === endContainer.data.length)) {
9285
          endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false, expandToBlock);
1 efrain 9286
        }
9287
      }
9288
      if (shouldExpandToSelector(format)) {
9289
        startContainer = findSelectorEndPoint(dom, formatList, rng, startContainer, 'previousSibling');
9290
        endContainer = findSelectorEndPoint(dom, formatList, rng, endContainer, 'nextSibling');
9291
      }
9292
      if (isBlockFormat(format) || isSelectorFormat(format)) {
9293
        startContainer = findBlockEndPoint(dom, formatList, startContainer, 'previousSibling');
9294
        endContainer = findBlockEndPoint(dom, formatList, endContainer, 'nextSibling');
9295
        if (isBlockFormat(format)) {
9296
          if (!dom.isBlock(startContainer)) {
1441 ariadna 9297
            startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true, expandToBlock);
9298
            if (isText$b(startContainer)) {
9299
              startOffset = 0;
9300
            }
1 efrain 9301
          }
9302
          if (!dom.isBlock(endContainer)) {
1441 ariadna 9303
            endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false, expandToBlock);
9304
            if (isText$b(endContainer)) {
9305
              endOffset = endContainer.data.length;
9306
            }
1 efrain 9307
          }
9308
        }
9309
      }
9310
      if (isElement$6(startContainer) && startContainer.parentNode) {
9311
        startOffset = dom.nodeIndex(startContainer);
9312
        startContainer = startContainer.parentNode;
9313
      }
9314
      if (isElement$6(endContainer) && endContainer.parentNode) {
9315
        endOffset = dom.nodeIndex(endContainer) + 1;
9316
        endContainer = endContainer.parentNode;
9317
      }
9318
      return {
9319
        startContainer,
9320
        startOffset,
9321
        endContainer,
9322
        endOffset
9323
      };
9324
    };
9325
 
9326
    const walk$3 = (dom, rng, callback) => {
9327
      var _a;
9328
      const startOffset = rng.startOffset;
9329
      const startContainer = getNode$1(rng.startContainer, startOffset);
9330
      const endOffset = rng.endOffset;
9331
      const endContainer = getNode$1(rng.endContainer, endOffset - 1);
9332
      const exclude = nodes => {
9333
        const firstNode = nodes[0];
1441 ariadna 9334
        if (isText$b(firstNode) && firstNode === startContainer && startOffset >= firstNode.data.length) {
1 efrain 9335
          nodes.splice(0, 1);
9336
        }
9337
        const lastNode = nodes[nodes.length - 1];
1441 ariadna 9338
        if (endOffset === 0 && nodes.length > 0 && lastNode === endContainer && isText$b(lastNode)) {
1 efrain 9339
          nodes.splice(nodes.length - 1, 1);
9340
        }
9341
        return nodes;
9342
      };
9343
      const collectSiblings = (node, name, endNode) => {
9344
        const siblings = [];
9345
        for (; node && node !== endNode; node = node[name]) {
9346
          siblings.push(node);
9347
        }
9348
        return siblings;
9349
      };
9350
      const findEndPoint = (node, root) => dom.getParent(node, node => node.parentNode === root, root);
9351
      const walkBoundary = (startNode, endNode, next) => {
9352
        const siblingName = next ? 'nextSibling' : 'previousSibling';
9353
        for (let node = startNode, parent = node.parentNode; node && node !== endNode; node = parent) {
9354
          parent = node.parentNode;
9355
          const siblings = collectSiblings(node === startNode ? node : node[siblingName], siblingName);
9356
          if (siblings.length) {
9357
            if (!next) {
9358
              siblings.reverse();
9359
            }
9360
            callback(exclude(siblings));
9361
          }
9362
        }
9363
      };
9364
      if (startContainer === endContainer) {
9365
        return callback(exclude([startContainer]));
9366
      }
9367
      const ancestor = (_a = dom.findCommonAncestor(startContainer, endContainer)) !== null && _a !== void 0 ? _a : dom.getRoot();
9368
      if (dom.isChildOf(startContainer, endContainer)) {
9369
        return walkBoundary(startContainer, ancestor, true);
9370
      }
9371
      if (dom.isChildOf(endContainer, startContainer)) {
9372
        return walkBoundary(endContainer, ancestor);
9373
      }
9374
      const startPoint = findEndPoint(startContainer, ancestor) || startContainer;
9375
      const endPoint = findEndPoint(endContainer, ancestor) || endContainer;
9376
      walkBoundary(startContainer, startPoint, true);
9377
      const siblings = collectSiblings(startPoint === startContainer ? startPoint : startPoint.nextSibling, 'nextSibling', endPoint === endContainer ? endPoint.nextSibling : endPoint);
9378
      if (siblings.length) {
9379
        callback(exclude(siblings));
9380
      }
9381
      walkBoundary(endContainer, endPoint);
9382
    };
9383
 
9384
    const validBlocks = [
9385
      'pre[class*=language-][contenteditable="false"]',
9386
      'figure.image',
9387
      'div[data-ephox-embed-iri]',
9388
      'div.tiny-pageembed',
9389
      'div.mce-toc',
9390
      'div[data-mce-toc]'
9391
    ];
1441 ariadna 9392
    const isZeroWidth = elem => isText$c(elem) && get$3(elem) === ZWSP$1;
1 efrain 9393
    const context = (editor, elem, wrapName, nodeName) => parent(elem).fold(() => 'skipping', parent => {
9394
      if (nodeName === 'br' || isZeroWidth(elem)) {
9395
        return 'valid';
9396
      } else if (isAnnotation(elem)) {
9397
        return 'existing';
9398
      } else if (isCaretNode(elem.dom)) {
9399
        return 'caret';
9400
      } else if (exists(validBlocks, selector => is$1(elem, selector))) {
9401
        return 'valid-block';
9402
      } else if (!isValid(editor, wrapName, nodeName) || !isValid(editor, name(parent), wrapName)) {
9403
        return 'invalid-child';
9404
      } else {
9405
        return 'valid';
9406
      }
9407
    });
9408
 
9409
    const applyWordGrab = (editor, rng) => {
9410
      const r = expandRng(editor.dom, rng, [{ inline: 'span' }]);
9411
      rng.setStart(r.startContainer, r.startOffset);
9412
      rng.setEnd(r.endContainer, r.endOffset);
9413
      editor.selection.setRng(rng);
9414
    };
9415
    const applyAnnotation = (elem, masterUId, data, annotationName, decorate, directAnnotation) => {
9416
      const {uid = masterUId, ...otherData} = data;
9417
      add$2(elem, annotation());
1441 ariadna 9418
      set$4(elem, `${ dataAnnotationId() }`, uid);
9419
      set$4(elem, `${ dataAnnotation() }`, annotationName);
1 efrain 9420
      const {attributes = {}, classes = []} = decorate(uid, otherData);
9421
      setAll$1(elem, attributes);
9422
      add(elem, classes);
9423
      if (directAnnotation) {
9424
        if (classes.length > 0) {
1441 ariadna 9425
          set$4(elem, `${ dataAnnotationClasses() }`, classes.join(','));
1 efrain 9426
        }
9427
        const attributeNames = keys(attributes);
9428
        if (attributeNames.length > 0) {
1441 ariadna 9429
          set$4(elem, `${ dataAnnotationAttributes() }`, attributeNames.join(','));
1 efrain 9430
        }
9431
      }
9432
    };
9433
    const removeDirectAnnotation = elem => {
1441 ariadna 9434
      remove$6(elem, annotation());
9435
      remove$9(elem, `${ dataAnnotationId() }`);
9436
      remove$9(elem, `${ dataAnnotation() }`);
9437
      remove$9(elem, `${ dataAnnotationActive() }`);
1 efrain 9438
      const customAttrNames = getOpt(elem, `${ dataAnnotationAttributes() }`).map(names => names.split(',')).getOr([]);
9439
      const customClasses = getOpt(elem, `${ dataAnnotationClasses() }`).map(names => names.split(',')).getOr([]);
1441 ariadna 9440
      each$e(customAttrNames, name => remove$9(elem, name));
9441
      remove$3(elem, customClasses);
9442
      remove$9(elem, `${ dataAnnotationClasses() }`);
9443
      remove$9(elem, `${ dataAnnotationAttributes() }`);
1 efrain 9444
    };
9445
    const makeAnnotation = (eDoc, uid, data, annotationName, decorate) => {
9446
      const master = SugarElement.fromTag('span', eDoc);
9447
      applyAnnotation(master, uid, data, annotationName, decorate, false);
9448
      return master;
9449
    };
9450
    const annotate = (editor, rng, uid, annotationName, decorate, data) => {
9451
      const newWrappers = [];
9452
      const master = makeAnnotation(editor.getDoc(), uid, data, annotationName, decorate);
9453
      const wrapper = value$2();
9454
      const finishWrapper = () => {
9455
        wrapper.clear();
9456
      };
9457
      const getOrOpenWrapper = () => wrapper.get().getOrThunk(() => {
9458
        const nu = shallow$1(master);
9459
        newWrappers.push(nu);
9460
        wrapper.set(nu);
9461
        return nu;
9462
      });
9463
      const processElements = elems => {
9464
        each$e(elems, processElement);
9465
      };
9466
      const processElement = elem => {
9467
        const ctx = context(editor, elem, 'span', name(elem));
9468
        switch (ctx) {
9469
        case 'invalid-child': {
9470
            finishWrapper();
9471
            const children = children$1(elem);
9472
            processElements(children);
9473
            finishWrapper();
9474
            break;
9475
          }
9476
        case 'valid-block': {
9477
            finishWrapper();
9478
            applyAnnotation(elem, uid, data, annotationName, decorate, true);
9479
            break;
9480
          }
9481
        case 'valid': {
9482
            const w = getOrOpenWrapper();
9483
            wrap$2(elem, w);
9484
            break;
9485
          }
9486
        }
9487
      };
9488
      const processNodes = nodes => {
9489
        const elems = map$3(nodes, SugarElement.fromDom);
9490
        processElements(elems);
9491
      };
9492
      walk$3(editor.dom, rng, nodes => {
9493
        finishWrapper();
9494
        processNodes(nodes);
9495
      });
9496
      return newWrappers;
9497
    };
9498
    const annotateWithBookmark = (editor, name, settings, data) => {
9499
      editor.undoManager.transact(() => {
9500
        const selection = editor.selection;
9501
        const initialRng = selection.getRng();
9502
        const hasFakeSelection = getCellsFromEditor(editor).length > 0;
9503
        const masterUid = generate$1('mce-annotation');
9504
        if (initialRng.collapsed && !hasFakeSelection) {
9505
          applyWordGrab(editor, initialRng);
9506
        }
9507
        if (selection.getRng().collapsed && !hasFakeSelection) {
9508
          const wrapper = makeAnnotation(editor.getDoc(), masterUid, data, name, settings.decorate);
9509
          set$1(wrapper, nbsp);
9510
          selection.getRng().insertNode(wrapper.dom);
9511
          selection.select(wrapper.dom);
9512
        } else {
9513
          preserve(selection, false, () => {
9514
            runOnRanges(editor, selectionRng => {
9515
              annotate(editor, selectionRng, masterUid, name, settings.decorate, data);
9516
            });
9517
          });
9518
        }
9519
      });
9520
    };
9521
 
9522
    const Annotator = editor => {
1441 ariadna 9523
      const registry = create$b();
1 efrain 9524
      setup$x(editor, registry);
9525
      const changes = setup$y(editor, registry);
9526
      const isSpan = isTag('span');
9527
      const removeAnnotations = elements => {
9528
        each$e(elements, element => {
9529
          if (isSpan(element)) {
9530
            unwrap(element);
9531
          } else {
9532
            removeDirectAnnotation(element);
9533
          }
9534
        });
9535
      };
9536
      return {
9537
        register: (name, settings) => {
9538
          registry.register(name, settings);
9539
        },
9540
        annotate: (name, data) => {
9541
          registry.lookup(name).each(settings => {
9542
            annotateWithBookmark(editor, name, settings, data);
9543
          });
9544
        },
9545
        annotationChanged: (name, callback) => {
9546
          changes.addListener(name, callback);
9547
        },
9548
        remove: name => {
9549
          identify(editor, Optional.some(name)).each(({elements}) => {
9550
            const bookmark = editor.selection.getBookmark();
9551
            removeAnnotations(elements);
9552
            editor.selection.moveToBookmark(bookmark);
9553
          });
9554
        },
9555
        removeAll: name => {
9556
          const bookmark = editor.selection.getBookmark();
9557
          each$d(findAll(editor, name), (elements, _) => {
9558
            removeAnnotations(elements);
9559
          });
9560
          editor.selection.moveToBookmark(bookmark);
9561
        },
9562
        getAll: name => {
9563
          const directory = findAll(editor, name);
9564
          return map$2(directory, elems => map$3(elems, elem => elem.dom));
9565
        }
9566
      };
9567
    };
9568
 
9569
    const BookmarkManager = selection => {
9570
      return {
1441 ariadna 9571
        getBookmark: curry(getBookmark$2, selection),
1 efrain 9572
        moveToBookmark: curry(moveToBookmark, selection)
9573
      };
9574
    };
9575
    BookmarkManager.isBookmarkNode = isBookmarkNode$1;
9576
 
9577
    const isXYWithinRange = (clientX, clientY, range) => {
9578
      if (range.collapsed) {
9579
        return false;
9580
      } else {
9581
        return exists(range.getClientRects(), rect => containsXY(rect, clientX, clientY));
9582
      }
9583
    };
9584
 
1441 ariadna 9585
    const getDocument = () => SugarElement.fromDom(document);
9586
 
9587
    const focus$1 = (element, preventScroll = false) => element.dom.focus({ preventScroll });
9588
    const hasFocus$1 = element => {
9589
      const root = getRootNode(element).dom;
9590
      return element.dom === root.activeElement;
1 efrain 9591
    };
1441 ariadna 9592
    const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
9593
    const search = element => active$1(getRootNode(element)).filter(e => element.dom.contains(e.dom));
9594
 
9595
    const create$9 = (start, soffset, finish, foffset) => ({
9596
      start,
9597
      soffset,
9598
      finish,
9599
      foffset
9600
    });
9601
    const SimRange = { create: create$9 };
9602
 
9603
    const adt$3 = Adt.generate([
9604
      { before: ['element'] },
9605
      {
9606
        on: [
9607
          'element',
9608
          'offset'
9609
        ]
9610
      },
9611
      { after: ['element'] }
9612
    ]);
9613
    const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
9614
    const getStart$2 = situ => situ.fold(identity, identity, identity);
9615
    const before$1 = adt$3.before;
9616
    const on = adt$3.on;
9617
    const after$1 = adt$3.after;
9618
    const Situ = {
9619
      before: before$1,
9620
      on,
9621
      after: after$1,
9622
      cata,
9623
      getStart: getStart$2
1 efrain 9624
    };
1441 ariadna 9625
 
9626
    const adt$2 = Adt.generate([
9627
      { domRange: ['rng'] },
9628
      {
9629
        relative: [
9630
          'startSitu',
9631
          'finishSitu'
9632
        ]
9633
      },
9634
      {
9635
        exact: [
9636
          'start',
9637
          'soffset',
9638
          'finish',
9639
          'foffset'
9640
        ]
9641
      }
9642
    ]);
9643
    const exactFromRange = simRange => adt$2.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
9644
    const getStart$1 = selection => selection.match({
9645
      domRange: rng => SugarElement.fromDom(rng.startContainer),
9646
      relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
9647
      exact: (start, _soffset, _finish, _foffset) => start
9648
    });
9649
    const domRange = adt$2.domRange;
9650
    const relative = adt$2.relative;
9651
    const exact = adt$2.exact;
9652
    const getWin = selection => {
9653
      const start = getStart$1(selection);
9654
      return defaultView(start);
1 efrain 9655
    };
1441 ariadna 9656
    const range = SimRange.create;
9657
    const SimSelection = {
9658
      domRange,
9659
      relative,
9660
      exact,
9661
      exactFromRange,
9662
      getWin,
9663
      range
9664
    };
9665
 
9666
    const clamp$1 = (offset, element) => {
9667
      const max = isText$c(element) ? get$3(element).length : children$1(element).length + 1;
9668
      if (offset > max) {
9669
        return max;
9670
      } else if (offset < 0) {
9671
        return 0;
9672
      }
9673
      return offset;
9674
    };
9675
    const normalizeRng = rng => SimSelection.range(rng.start, clamp$1(rng.soffset, rng.start), rng.finish, clamp$1(rng.foffset, rng.finish));
9676
    const isOrContains = (root, elm) => !isRestrictedNode(elm.dom) && (contains(root, elm) || eq(root, elm));
9677
    const isRngInRoot = root => rng => isOrContains(root, rng.start) && isOrContains(root, rng.finish);
9678
    const shouldStore = editor => editor.inline || Env.browser.isFirefox();
9679
    const nativeRangeToSelectionRange = r => SimSelection.range(SugarElement.fromDom(r.startContainer), r.startOffset, SugarElement.fromDom(r.endContainer), r.endOffset);
9680
    const readRange = win => {
9681
      const selection = win.getSelection();
9682
      const rng = !selection || selection.rangeCount === 0 ? Optional.none() : Optional.from(selection.getRangeAt(0));
9683
      return rng.map(nativeRangeToSelectionRange);
9684
    };
9685
    const getBookmark$1 = root => {
9686
      const win = defaultView(root);
9687
      return readRange(win.dom).filter(isRngInRoot(root));
9688
    };
9689
    const validate = (root, bookmark) => Optional.from(bookmark).filter(isRngInRoot(root)).map(normalizeRng);
9690
    const bookmarkToNativeRng = bookmark => {
9691
      const rng = document.createRange();
9692
      try {
9693
        rng.setStart(bookmark.start.dom, bookmark.soffset);
9694
        rng.setEnd(bookmark.finish.dom, bookmark.foffset);
9695
        return Optional.some(rng);
9696
      } catch (_a) {
9697
        return Optional.none();
9698
      }
9699
    };
9700
    const store = editor => {
9701
      const newBookmark = shouldStore(editor) ? getBookmark$1(SugarElement.fromDom(editor.getBody())) : Optional.none();
9702
      editor.bookmark = newBookmark.isSome() ? newBookmark : editor.bookmark;
9703
    };
9704
    const getRng = editor => {
9705
      const bookmark = editor.bookmark ? editor.bookmark : Optional.none();
9706
      return bookmark.bind(x => validate(SugarElement.fromDom(editor.getBody()), x)).bind(bookmarkToNativeRng);
9707
    };
9708
    const restore = editor => {
9709
      getRng(editor).each(rng => editor.selection.setRng(rng));
9710
    };
9711
 
9712
    const isEditorUIElement$1 = elm => {
9713
      const className = elm.className.toString();
9714
      return className.indexOf('tox-') !== -1 || className.indexOf('mce-') !== -1;
9715
    };
9716
    const FocusManager = { isEditorUIElement: isEditorUIElement$1 };
9717
 
9718
    const wrappedSetTimeout = (callback, time) => {
9719
      if (!isNumber(time)) {
9720
        time = 0;
9721
      }
9722
      return setTimeout(callback, time);
9723
    };
9724
    const wrappedSetInterval = (callback, time) => {
9725
      if (!isNumber(time)) {
9726
        time = 0;
9727
      }
9728
      return setInterval(callback, time);
9729
    };
9730
    const Delay = {
9731
      setEditorTimeout: (editor, callback, time) => {
9732
        return wrappedSetTimeout(() => {
9733
          if (!editor.removed) {
9734
            callback();
9735
          }
9736
        }, time);
9737
      },
9738
      setEditorInterval: (editor, callback, time) => {
9739
        const timer = wrappedSetInterval(() => {
9740
          if (!editor.removed) {
9741
            callback();
9742
          } else {
9743
            clearInterval(timer);
9744
          }
9745
        }, time);
9746
        return timer;
9747
      }
9748
    };
9749
 
9750
    const isManualNodeChange = e => {
9751
      return e.type === 'nodechange' && e.selectionChange;
9752
    };
9753
    const registerPageMouseUp = (editor, throttledStore) => {
9754
      const mouseUpPage = () => {
9755
        throttledStore.throttle();
9756
      };
9757
      DOMUtils.DOM.bind(document, 'mouseup', mouseUpPage);
9758
      editor.on('remove', () => {
9759
        DOMUtils.DOM.unbind(document, 'mouseup', mouseUpPage);
1 efrain 9760
      });
9761
    };
1441 ariadna 9762
    const registerMouseUp = (editor, throttledStore) => {
9763
      editor.on('mouseup touchend', _e => {
9764
        throttledStore.throttle();
1 efrain 9765
      });
9766
    };
1441 ariadna 9767
    const registerEditorEvents = (editor, throttledStore) => {
9768
      registerMouseUp(editor, throttledStore);
9769
      editor.on('keyup NodeChange AfterSetSelectionRange', e => {
9770
        if (!isManualNodeChange(e)) {
9771
          store(editor);
9772
        }
9773
      });
1 efrain 9774
    };
1441 ariadna 9775
    const register$6 = editor => {
9776
      const throttledStore = first$1(() => {
9777
        store(editor);
9778
      }, 0);
9779
      editor.on('init', () => {
9780
        if (editor.inline) {
9781
          registerPageMouseUp(editor, throttledStore);
9782
        }
9783
        registerEditorEvents(editor, throttledStore);
9784
      });
9785
      editor.on('remove', () => {
9786
        throttledStore.cancel();
9787
      });
1 efrain 9788
    };
1441 ariadna 9789
 
9790
    let documentFocusInHandler;
9791
    const DOM$9 = DOMUtils.DOM;
9792
    const isEditorUIElement = elm => {
9793
      return isElement$6(elm) && FocusManager.isEditorUIElement(elm);
1 efrain 9794
    };
1441 ariadna 9795
    const isEditorContentAreaElement = elm => {
9796
      const classList = elm.classList;
9797
      if (classList !== undefined) {
9798
        return classList.contains('tox-edit-area') || classList.contains('tox-edit-area__iframe') || classList.contains('mce-content-body');
9799
      } else {
9800
        return false;
9801
      }
1 efrain 9802
    };
1441 ariadna 9803
    const isUIElement = (editor, elm) => {
9804
      const customSelector = getCustomUiSelector(editor);
9805
      const parent = DOM$9.getParent(elm, elm => {
9806
        return isEditorUIElement(elm) || (customSelector ? editor.dom.is(elm, customSelector) : false);
1 efrain 9807
      });
1441 ariadna 9808
      return parent !== null;
1 efrain 9809
    };
1441 ariadna 9810
    const getActiveElement = editor => {
9811
      try {
9812
        const root = getRootNode(SugarElement.fromDom(editor.getElement()));
9813
        return active$1(root).fold(() => document.body, x => x.dom);
9814
      } catch (_a) {
9815
        return document.body;
9816
      }
9817
    };
9818
    const registerEvents$1 = (editorManager, e) => {
9819
      const editor = e.editor;
9820
      register$6(editor);
9821
      const toggleContentAreaOnFocus = (editor, fn) => {
9822
        if (shouldHighlightOnFocus(editor) && editor.inline !== true) {
9823
          const contentArea = SugarElement.fromDom(editor.getContainer());
9824
          fn(contentArea, 'tox-edit-focus');
9825
        }
9826
      };
9827
      editor.on('focusin', () => {
9828
        const focusedEditor = editorManager.focusedEditor;
9829
        if (isEditorContentAreaElement(getActiveElement(editor))) {
9830
          toggleContentAreaOnFocus(editor, add$2);
9831
        }
9832
        if (focusedEditor !== editor) {
9833
          if (focusedEditor) {
9834
            focusedEditor.dispatch('blur', { focusedEditor: editor });
9835
          }
9836
          editorManager.setActive(editor);
9837
          editorManager.focusedEditor = editor;
9838
          editor.dispatch('focus', { blurredEditor: focusedEditor });
9839
          editor.focus(true);
9840
        }
1 efrain 9841
      });
1441 ariadna 9842
      editor.on('focusout', () => {
9843
        Delay.setEditorTimeout(editor, () => {
9844
          const focusedEditor = editorManager.focusedEditor;
9845
          if (!isEditorContentAreaElement(getActiveElement(editor)) || focusedEditor !== editor) {
9846
            toggleContentAreaOnFocus(editor, remove$6);
9847
          }
9848
          if (!isUIElement(editor, getActiveElement(editor)) && focusedEditor === editor) {
9849
            editor.dispatch('blur', { focusedEditor: null });
9850
            editorManager.focusedEditor = null;
9851
          }
9852
        });
9853
      });
9854
      if (!documentFocusInHandler) {
9855
        documentFocusInHandler = e => {
9856
          const activeEditor = editorManager.activeEditor;
9857
          if (activeEditor) {
9858
            getOriginalEventTarget(e).each(target => {
9859
              const elem = target;
9860
              if (elem.ownerDocument === document) {
9861
                if (elem !== document.body && !isUIElement(activeEditor, elem) && editorManager.focusedEditor === activeEditor) {
9862
                  activeEditor.dispatch('blur', { focusedEditor: null });
9863
                  editorManager.focusedEditor = null;
9864
                }
9865
              }
9866
            });
9867
          }
9868
        };
9869
        DOM$9.bind(document, 'focusin', documentFocusInHandler);
9870
      }
1 efrain 9871
    };
1441 ariadna 9872
    const unregisterDocumentEvents = (editorManager, e) => {
9873
      if (editorManager.focusedEditor === e.editor) {
9874
        editorManager.focusedEditor = null;
9875
      }
9876
      if (!editorManager.activeEditor && documentFocusInHandler) {
9877
        DOM$9.unbind(document, 'focusin', documentFocusInHandler);
9878
        documentFocusInHandler = null;
9879
      }
1 efrain 9880
    };
1441 ariadna 9881
    const setup$w = editorManager => {
9882
      editorManager.on('AddEditor', curry(registerEvents$1, editorManager));
9883
      editorManager.on('RemoveEditor', curry(unregisterDocumentEvents, editorManager));
1 efrain 9884
    };
1441 ariadna 9885
 
9886
    const getContentEditableHost = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'true');
9887
    const hasContentEditableFalseParent$1 = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'false') !== null;
9888
    const getCollapsedNode = rng => rng.collapsed ? Optional.from(getNode$1(rng.startContainer, rng.startOffset)).map(SugarElement.fromDom) : Optional.none();
9889
    const getFocusInElement = (root, rng) => getCollapsedNode(rng).bind(node => {
9890
      if (isTableSection(node)) {
9891
        return Optional.some(node);
9892
      } else if (!contains(root, node)) {
9893
        return Optional.some(root);
9894
      } else {
9895
        return Optional.none();
9896
      }
9897
    });
9898
    const normalizeSelection = (editor, rng) => {
9899
      getFocusInElement(SugarElement.fromDom(editor.getBody()), rng).bind(elm => {
9900
        return firstPositionIn(elm.dom);
9901
      }).fold(() => {
9902
        editor.selection.normalize();
9903
      }, caretPos => editor.selection.setRng(caretPos.toRange()));
1 efrain 9904
    };
1441 ariadna 9905
    const focusBody = body => {
9906
      if (body.setActive) {
9907
        try {
9908
          body.setActive();
9909
        } catch (_a) {
9910
          body.focus();
9911
        }
9912
      } else {
9913
        body.focus();
9914
      }
9915
    };
9916
    const hasElementFocus = elm => hasFocus$1(elm) || search(elm).isSome();
9917
    const hasIframeFocus = editor => isNonNullable(editor.iframeElement) && hasFocus$1(SugarElement.fromDom(editor.iframeElement));
9918
    const hasInlineFocus = editor => {
9919
      const rawBody = editor.getBody();
9920
      return rawBody && hasElementFocus(SugarElement.fromDom(rawBody));
9921
    };
9922
    const hasUiFocus = editor => {
9923
      const dos = getRootNode(SugarElement.fromDom(editor.getElement()));
9924
      return active$1(dos).filter(elem => !isEditorContentAreaElement(elem.dom) && isUIElement(editor, elem.dom)).isSome();
9925
    };
9926
    const hasFocus = editor => editor.inline ? hasInlineFocus(editor) : hasIframeFocus(editor);
9927
    const hasEditorOrUiFocus = editor => hasFocus(editor) || hasUiFocus(editor);
9928
    const focusEditor = editor => {
9929
      const selection = editor.selection;
9930
      const body = editor.getBody();
9931
      let rng = selection.getRng();
9932
      editor.quirks.refreshContentEditable();
9933
      const restoreBookmark = editor => {
9934
        getRng(editor).each(bookmarkRng => {
9935
          editor.selection.setRng(bookmarkRng);
9936
          rng = bookmarkRng;
9937
        });
9938
      };
9939
      if (!hasFocus(editor) && editor.hasEditableRoot()) {
9940
        restoreBookmark(editor);
9941
      }
9942
      const contentEditableHost = getContentEditableHost(editor, selection.getNode());
9943
      if (contentEditableHost && editor.dom.isChildOf(contentEditableHost, body)) {
9944
        if (!hasContentEditableFalseParent$1(editor, contentEditableHost)) {
9945
          focusBody(body);
9946
        }
9947
        focusBody(contentEditableHost);
9948
        if (!editor.hasEditableRoot()) {
9949
          restoreBookmark(editor);
9950
        }
9951
        normalizeSelection(editor, rng);
9952
        activateEditor(editor);
9953
        return;
9954
      }
9955
      if (!editor.inline) {
9956
        if (!Env.browser.isOpera()) {
9957
          focusBody(body);
9958
        }
9959
        editor.getWin().focus();
9960
      }
9961
      if (Env.browser.isFirefox() || editor.inline) {
9962
        focusBody(body);
9963
        normalizeSelection(editor, rng);
9964
      }
9965
      activateEditor(editor);
9966
    };
9967
    const activateEditor = editor => editor.editorManager.setActive(editor);
9968
    const focus = (editor, skipFocus) => {
9969
      if (editor.removed) {
9970
        return;
9971
      }
9972
      if (skipFocus) {
9973
        activateEditor(editor);
9974
      } else {
9975
        focusEditor(editor);
9976
      }
9977
    };
1 efrain 9978
 
9979
    const VK = {
9980
      BACKSPACE: 8,
9981
      DELETE: 46,
9982
      DOWN: 40,
9983
      ENTER: 13,
9984
      ESC: 27,
9985
      LEFT: 37,
9986
      RIGHT: 39,
9987
      SPACEBAR: 32,
9988
      TAB: 9,
9989
      UP: 38,
9990
      PAGE_UP: 33,
9991
      PAGE_DOWN: 34,
9992
      END: 35,
9993
      HOME: 36,
9994
      modifierPressed: e => {
9995
        return e.shiftKey || e.ctrlKey || e.altKey || VK.metaKeyPressed(e);
9996
      },
9997
      metaKeyPressed: e => {
9998
        return Env.os.isMacOS() || Env.os.isiOS() ? e.metaKey : e.ctrlKey && !e.altKey;
9999
      }
10000
    };
10001
 
10002
    const elementSelectionAttr = 'data-mce-selected';
10003
    const controlElmSelector = 'table,img,figure.image,hr,video,span.mce-preview-object,details';
10004
    const abs = Math.abs;
10005
    const round$1 = Math.round;
10006
    const resizeHandles = {
10007
      nw: [
10008
        0,
10009
        0,
10010
        -1,
10011
        -1
10012
      ],
10013
      ne: [
10014
        1,
10015
        0,
10016
        1,
10017
        -1
10018
      ],
10019
      se: [
10020
        1,
10021
        1,
10022
        1,
10023
        1
10024
      ],
10025
      sw: [
10026
        0,
10027
        1,
10028
        -1,
10029
        1
10030
      ]
10031
    };
10032
    const isTouchEvent = evt => evt.type === 'longpress' || evt.type.indexOf('touch') === 0;
10033
    const ControlSelection = (selection, editor) => {
10034
      const dom = editor.dom;
10035
      const editableDoc = editor.getDoc();
10036
      const rootDocument = document;
10037
      const rootElement = editor.getBody();
10038
      let selectedElm, selectedElmGhost, resizeHelper, selectedHandle, resizeBackdrop;
1441 ariadna 10039
      let startX, startY, startW, startH, ratio, resizeStarted;
1 efrain 10040
      let width;
10041
      let height;
10042
      let startScrollWidth;
10043
      let startScrollHeight;
10044
      const isImage = elm => isNonNullable(elm) && (isImg(elm) || dom.is(elm, 'figure.image'));
10045
      const isMedia = elm => isMedia$2(elm) || dom.hasClass(elm, 'mce-preview-object');
10046
      const isEventOnImageOutsideRange = (evt, range) => {
10047
        if (isTouchEvent(evt)) {
10048
          const touch = evt.touches[0];
10049
          return isImage(evt.target) && !isXYWithinRange(touch.clientX, touch.clientY, range);
10050
        } else {
10051
          return isImage(evt.target) && !isXYWithinRange(evt.clientX, evt.clientY, range);
10052
        }
10053
      };
10054
      const contextMenuSelectImage = evt => {
10055
        const target = evt.target;
10056
        if (isEventOnImageOutsideRange(evt, editor.selection.getRng()) && !evt.isDefaultPrevented()) {
10057
          editor.selection.select(target);
10058
        }
10059
      };
10060
      const getResizeTargets = elm => {
10061
        if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
10062
          return [
10063
            elm,
10064
            elm.firstElementChild
10065
          ];
10066
        } else if (dom.is(elm, 'figure.image')) {
10067
          return [elm.querySelector('img')];
10068
        } else {
10069
          return [elm];
10070
        }
10071
      };
10072
      const isResizable = elm => {
10073
        const selector = getObjectResizing(editor);
1441 ariadna 10074
        if (!selector || editor.mode.isReadOnly()) {
1 efrain 10075
          return false;
10076
        }
10077
        if (elm.getAttribute('data-mce-resize') === 'false') {
10078
          return false;
10079
        }
10080
        if (elm === editor.getBody()) {
10081
          return false;
10082
        }
10083
        if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
10084
          return is$1(SugarElement.fromDom(elm.firstElementChild), selector);
10085
        } else {
10086
          return is$1(SugarElement.fromDom(elm), selector);
10087
        }
10088
      };
1441 ariadna 10089
      const createGhostElement = (dom, elm) => {
1 efrain 10090
        if (isMedia(elm)) {
10091
          return dom.create('img', { src: Env.transparentSrc });
1441 ariadna 10092
        } else if (isTable$2(elm)) {
10093
          const isNorth = startsWith(selectedHandle.name, 'n');
10094
          const rowSelect = isNorth ? head : last$2;
10095
          const tableElm = elm.cloneNode(true);
10096
          rowSelect(dom.select('tr', tableElm)).each(tr => {
10097
            const cells = dom.select('td,th', tr);
10098
            dom.setStyle(tr, 'height', null);
10099
            each$e(cells, cell => dom.setStyle(cell, 'height', null));
10100
          });
10101
          return tableElm;
1 efrain 10102
        } else {
10103
          return elm.cloneNode(true);
10104
        }
10105
      };
10106
      const setSizeProp = (element, name, value) => {
10107
        if (isNonNullable(value)) {
10108
          const targets = getResizeTargets(element);
10109
          each$e(targets, target => {
10110
            if (target.style[name] || !editor.schema.isValid(target.nodeName.toLowerCase(), name)) {
10111
              dom.setStyle(target, name, value);
10112
            } else {
10113
              dom.setAttrib(target, name, '' + value);
10114
            }
10115
          });
10116
        }
10117
      };
10118
      const setGhostElmSize = (ghostElm, width, height) => {
10119
        setSizeProp(ghostElm, 'width', width);
10120
        setSizeProp(ghostElm, 'height', height);
10121
      };
10122
      const resizeGhostElement = e => {
10123
        let deltaX, deltaY, proportional;
10124
        let resizeHelperX, resizeHelperY;
10125
        deltaX = e.screenX - startX;
10126
        deltaY = e.screenY - startY;
10127
        width = deltaX * selectedHandle[2] + startW;
10128
        height = deltaY * selectedHandle[3] + startH;
10129
        width = width < 5 ? 5 : width;
10130
        height = height < 5 ? 5 : height;
10131
        if ((isImage(selectedElm) || isMedia(selectedElm)) && getResizeImgProportional(editor) !== false) {
10132
          proportional = !VK.modifierPressed(e);
10133
        } else {
10134
          proportional = VK.modifierPressed(e);
10135
        }
10136
        if (proportional) {
10137
          if (abs(deltaX) > abs(deltaY)) {
10138
            height = round$1(width * ratio);
10139
            width = round$1(height / ratio);
10140
          } else {
10141
            width = round$1(height / ratio);
10142
            height = round$1(width * ratio);
10143
          }
10144
        }
10145
        setGhostElmSize(selectedElmGhost, width, height);
10146
        resizeHelperX = selectedHandle.startPos.x + deltaX;
10147
        resizeHelperY = selectedHandle.startPos.y + deltaY;
10148
        resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0;
10149
        resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0;
10150
        dom.setStyles(resizeHelper, {
10151
          left: resizeHelperX,
10152
          top: resizeHelperY,
10153
          display: 'block'
10154
        });
10155
        resizeHelper.innerHTML = width + ' &times; ' + height;
10156
        deltaX = rootElement.scrollWidth - startScrollWidth;
10157
        deltaY = rootElement.scrollHeight - startScrollHeight;
10158
        if (deltaX + deltaY !== 0) {
10159
          dom.setStyles(resizeHelper, {
10160
            left: resizeHelperX - deltaX,
10161
            top: resizeHelperY - deltaY
10162
          });
10163
        }
10164
        if (!resizeStarted) {
10165
          fireObjectResizeStart(editor, selectedElm, startW, startH, 'corner-' + selectedHandle.name);
10166
          resizeStarted = true;
10167
        }
10168
      };
10169
      const endGhostResize = () => {
10170
        const wasResizeStarted = resizeStarted;
10171
        resizeStarted = false;
10172
        if (wasResizeStarted) {
10173
          setSizeProp(selectedElm, 'width', width);
10174
          setSizeProp(selectedElm, 'height', height);
10175
        }
10176
        dom.unbind(editableDoc, 'mousemove', resizeGhostElement);
10177
        dom.unbind(editableDoc, 'mouseup', endGhostResize);
10178
        if (rootDocument !== editableDoc) {
10179
          dom.unbind(rootDocument, 'mousemove', resizeGhostElement);
10180
          dom.unbind(rootDocument, 'mouseup', endGhostResize);
10181
        }
10182
        dom.remove(selectedElmGhost);
10183
        dom.remove(resizeHelper);
10184
        dom.remove(resizeBackdrop);
10185
        showResizeRect(selectedElm);
10186
        if (wasResizeStarted) {
10187
          fireObjectResized(editor, selectedElm, width, height, 'corner-' + selectedHandle.name);
10188
          dom.setAttrib(selectedElm, 'style', dom.getAttrib(selectedElm, 'style'));
10189
        }
10190
        editor.nodeChanged();
10191
      };
10192
      const showResizeRect = targetElm => {
10193
        unbindResizeHandleEvents();
10194
        const position = dom.getPos(targetElm, rootElement);
10195
        const selectedElmX = position.x;
10196
        const selectedElmY = position.y;
10197
        const rect = targetElm.getBoundingClientRect();
10198
        const targetWidth = rect.width || rect.right - rect.left;
10199
        const targetHeight = rect.height || rect.bottom - rect.top;
10200
        if (selectedElm !== targetElm) {
10201
          hideResizeRect();
10202
          selectedElm = targetElm;
10203
          width = height = 0;
10204
        }
10205
        const e = editor.dispatch('ObjectSelected', { target: targetElm });
10206
        if (isResizable(targetElm) && !e.isDefaultPrevented()) {
10207
          each$d(resizeHandles, (handle, name) => {
10208
            const startDrag = e => {
10209
              const target = getResizeTargets(selectedElm)[0];
10210
              startX = e.screenX;
10211
              startY = e.screenY;
10212
              startW = target.clientWidth;
10213
              startH = target.clientHeight;
10214
              ratio = startH / startW;
10215
              selectedHandle = handle;
10216
              selectedHandle.name = name;
10217
              selectedHandle.startPos = {
10218
                x: targetWidth * handle[0] + selectedElmX,
10219
                y: targetHeight * handle[1] + selectedElmY
10220
              };
10221
              startScrollWidth = rootElement.scrollWidth;
10222
              startScrollHeight = rootElement.scrollHeight;
10223
              resizeBackdrop = dom.add(rootElement, 'div', {
10224
                'class': 'mce-resize-backdrop',
10225
                'data-mce-bogus': 'all'
10226
              });
10227
              dom.setStyles(resizeBackdrop, {
10228
                position: 'fixed',
10229
                left: '0',
10230
                top: '0',
10231
                width: '100%',
10232
                height: '100%'
10233
              });
1441 ariadna 10234
              selectedElmGhost = createGhostElement(dom, selectedElm);
1 efrain 10235
              dom.addClass(selectedElmGhost, 'mce-clonedresizable');
10236
              dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all');
10237
              selectedElmGhost.contentEditable = 'false';
10238
              dom.setStyles(selectedElmGhost, {
10239
                left: selectedElmX,
10240
                top: selectedElmY,
10241
                margin: 0
10242
              });
10243
              setGhostElmSize(selectedElmGhost, targetWidth, targetHeight);
10244
              selectedElmGhost.removeAttribute(elementSelectionAttr);
10245
              rootElement.appendChild(selectedElmGhost);
10246
              dom.bind(editableDoc, 'mousemove', resizeGhostElement);
10247
              dom.bind(editableDoc, 'mouseup', endGhostResize);
10248
              if (rootDocument !== editableDoc) {
10249
                dom.bind(rootDocument, 'mousemove', resizeGhostElement);
10250
                dom.bind(rootDocument, 'mouseup', endGhostResize);
10251
              }
10252
              resizeHelper = dom.add(rootElement, 'div', {
10253
                'class': 'mce-resize-helper',
10254
                'data-mce-bogus': 'all'
10255
              }, startW + ' &times; ' + startH);
10256
            };
10257
            let handleElm = dom.get('mceResizeHandle' + name);
10258
            if (handleElm) {
10259
              dom.remove(handleElm);
10260
            }
10261
            handleElm = dom.add(rootElement, 'div', {
10262
              'id': 'mceResizeHandle' + name,
10263
              'data-mce-bogus': 'all',
10264
              'class': 'mce-resizehandle',
10265
              'unselectable': true,
10266
              'style': 'cursor:' + name + '-resize; margin:0; padding:0'
10267
            });
10268
            dom.bind(handleElm, 'mousedown', e => {
10269
              e.stopImmediatePropagation();
10270
              e.preventDefault();
10271
              startDrag(e);
10272
            });
10273
            handle.elm = handleElm;
10274
            dom.setStyles(handleElm, {
10275
              left: targetWidth * handle[0] + selectedElmX - handleElm.offsetWidth / 2,
10276
              top: targetHeight * handle[1] + selectedElmY - handleElm.offsetHeight / 2
10277
            });
10278
          });
10279
        } else {
10280
          hideResizeRect(false);
10281
        }
10282
      };
10283
      const throttledShowResizeRect = first$1(showResizeRect, 0);
10284
      const hideResizeRect = (removeSelected = true) => {
10285
        throttledShowResizeRect.cancel();
10286
        unbindResizeHandleEvents();
10287
        if (selectedElm && removeSelected) {
10288
          selectedElm.removeAttribute(elementSelectionAttr);
10289
        }
10290
        each$d(resizeHandles, (value, name) => {
10291
          const handleElm = dom.get('mceResizeHandle' + name);
10292
          if (handleElm) {
10293
            dom.unbind(handleElm);
10294
            dom.remove(handleElm);
10295
          }
10296
        });
10297
      };
10298
      const isChildOrEqual = (node, parent) => dom.isChildOf(node, parent);
10299
      const updateResizeRect = e => {
10300
        if (resizeStarted || editor.removed || editor.composing) {
10301
          return;
10302
        }
10303
        const targetElm = e.type === 'mousedown' ? e.target : selection.getNode();
10304
        const controlElm = closest$3(SugarElement.fromDom(targetElm), controlElmSelector).map(e => e.dom).filter(e => dom.isEditable(e.parentElement) || e.nodeName === 'IMG' && dom.isEditable(e)).getOrUndefined();
10305
        const selectedValue = isNonNullable(controlElm) ? dom.getAttrib(controlElm, elementSelectionAttr, '1') : '1';
10306
        each$e(dom.select(`img[${ elementSelectionAttr }],hr[${ elementSelectionAttr }]`), img => {
10307
          img.removeAttribute(elementSelectionAttr);
10308
        });
1441 ariadna 10309
        if (isNonNullable(controlElm) && isChildOrEqual(controlElm, rootElement) && hasEditorOrUiFocus(editor)) {
1 efrain 10310
          disableGeckoResize();
10311
          const startElm = selection.getStart(true);
10312
          if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) {
10313
            dom.setAttrib(controlElm, elementSelectionAttr, selectedValue);
10314
            throttledShowResizeRect.throttle(controlElm);
10315
            return;
10316
          }
10317
        }
10318
        hideResizeRect();
10319
      };
10320
      const unbindResizeHandleEvents = () => {
10321
        each$d(resizeHandles, handle => {
10322
          if (handle.elm) {
10323
            dom.unbind(handle.elm);
10324
            delete handle.elm;
10325
          }
10326
        });
10327
      };
10328
      const disableGeckoResize = () => {
10329
        try {
10330
          editor.getDoc().execCommand('enableObjectResizing', false, 'false');
1441 ariadna 10331
        } catch (_a) {
1 efrain 10332
        }
10333
      };
10334
      editor.on('init', () => {
10335
        disableGeckoResize();
10336
        editor.on('NodeChange ResizeEditor ResizeWindow ResizeContent drop', updateResizeRect);
10337
        editor.on('keyup compositionend', e => {
10338
          if (selectedElm && selectedElm.nodeName === 'TABLE') {
10339
            updateResizeRect(e);
10340
          }
10341
        });
10342
        editor.on('hide blur', hideResizeRect);
10343
        editor.on('contextmenu longpress', contextMenuSelectImage, true);
10344
      });
10345
      editor.on('remove', unbindResizeHandleEvents);
10346
      const destroy = () => {
10347
        throttledShowResizeRect.cancel();
10348
        selectedElm = selectedElmGhost = resizeBackdrop = null;
10349
      };
10350
      return {
10351
        isResizable,
10352
        showResizeRect,
10353
        hideResizeRect,
10354
        updateResizeRect,
10355
        destroy
10356
      };
10357
    };
10358
 
10359
    const setStart = (rng, situ) => {
10360
      situ.fold(e => {
10361
        rng.setStartBefore(e.dom);
10362
      }, (e, o) => {
10363
        rng.setStart(e.dom, o);
10364
      }, e => {
10365
        rng.setStartAfter(e.dom);
10366
      });
10367
    };
10368
    const setFinish = (rng, situ) => {
10369
      situ.fold(e => {
10370
        rng.setEndBefore(e.dom);
10371
      }, (e, o) => {
10372
        rng.setEnd(e.dom, o);
10373
      }, e => {
10374
        rng.setEndAfter(e.dom);
10375
      });
10376
    };
10377
    const relativeToNative = (win, startSitu, finishSitu) => {
10378
      const range = win.document.createRange();
10379
      setStart(range, startSitu);
10380
      setFinish(range, finishSitu);
10381
      return range;
10382
    };
10383
    const exactToNative = (win, start, soffset, finish, foffset) => {
10384
      const rng = win.document.createRange();
10385
      rng.setStart(start.dom, soffset);
10386
      rng.setEnd(finish.dom, foffset);
10387
      return rng;
10388
    };
10389
 
1441 ariadna 10390
    const adt$1 = Adt.generate([
1 efrain 10391
      {
10392
        ltr: [
10393
          'start',
10394
          'soffset',
10395
          'finish',
10396
          'foffset'
10397
        ]
10398
      },
10399
      {
10400
        rtl: [
10401
          'start',
10402
          'soffset',
10403
          'finish',
10404
          'foffset'
10405
        ]
10406
      }
10407
    ]);
10408
    const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset);
10409
    const getRanges = (win, selection) => selection.match({
10410
      domRange: rng => {
10411
        return {
10412
          ltr: constant(rng),
10413
          rtl: Optional.none
10414
        };
10415
      },
10416
      relative: (startSitu, finishSitu) => {
10417
        return {
10418
          ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
10419
          rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
10420
        };
10421
      },
10422
      exact: (start, soffset, finish, foffset) => {
10423
        return {
10424
          ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)),
10425
          rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset)))
10426
        };
10427
      }
10428
    });
10429
    const doDiagnose = (win, ranges) => {
10430
      const rng = ranges.ltr();
10431
      if (rng.collapsed) {
10432
        const reversed = ranges.rtl().filter(rev => rev.collapsed === false);
1441 ariadna 10433
        return reversed.map(rev => adt$1.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$1.ltr, rng));
1 efrain 10434
      } else {
1441 ariadna 10435
        return fromRange(win, adt$1.ltr, rng);
1 efrain 10436
      }
10437
    };
10438
    const diagnose = (win, selection) => {
10439
      const ranges = getRanges(win, selection);
10440
      return doDiagnose(win, ranges);
10441
    };
1441 ariadna 10442
    adt$1.ltr;
10443
    adt$1.rtl;
1 efrain 10444
 
10445
    const caretPositionFromPoint = (doc, x, y) => {
1441 ariadna 10446
      var _a;
10447
      return Optional.from((_a = doc.caretPositionFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y)).bind(pos => {
1 efrain 10448
        if (pos.offsetNode === null) {
10449
          return Optional.none();
10450
        }
1441 ariadna 10451
        const r = doc.createRange();
1 efrain 10452
        r.setStart(pos.offsetNode, pos.offset);
10453
        r.collapse();
10454
        return Optional.some(r);
10455
      });
10456
    };
10457
    const caretRangeFromPoint = (doc, x, y) => {
1441 ariadna 10458
      var _a;
10459
      return Optional.from((_a = doc.caretRangeFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y));
1 efrain 10460
    };
1441 ariadna 10461
    const availableSearch = (doc, x, y) => {
10462
      if (doc.caretPositionFromPoint) {
10463
        return caretPositionFromPoint(doc, x, y);
10464
      } else if (doc.caretRangeFromPoint) {
10465
        return caretRangeFromPoint(doc, x, y);
1 efrain 10466
      } else {
1441 ariadna 10467
        return Optional.none();
1 efrain 10468
      }
1441 ariadna 10469
    };
1 efrain 10470
    const fromPoint$1 = (win, x, y) => {
1441 ariadna 10471
      const doc = win.document;
1 efrain 10472
      return availableSearch(doc, x, y).map(rng => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
10473
    };
10474
 
10475
    const beforeSpecial = (element, offset) => {
10476
      const name$1 = name(element);
10477
      if ('input' === name$1) {
10478
        return Situ.after(element);
10479
      } else if (!contains$2([
10480
          'br',
10481
          'img'
10482
        ], name$1)) {
10483
        return Situ.on(element, offset);
10484
      } else {
10485
        return offset === 0 ? Situ.before(element) : Situ.after(element);
10486
      }
10487
    };
10488
    const preprocessRelative = (startSitu, finishSitu) => {
10489
      const start = startSitu.fold(Situ.before, beforeSpecial, Situ.after);
10490
      const finish = finishSitu.fold(Situ.before, beforeSpecial, Situ.after);
10491
      return SimSelection.relative(start, finish);
10492
    };
10493
    const preprocessExact = (start, soffset, finish, foffset) => {
10494
      const startSitu = beforeSpecial(start, soffset);
10495
      const finishSitu = beforeSpecial(finish, foffset);
10496
      return SimSelection.relative(startSitu, finishSitu);
10497
    };
10498
    const preprocess = selection => selection.match({
10499
      domRange: rng => {
10500
        const start = SugarElement.fromDom(rng.startContainer);
10501
        const finish = SugarElement.fromDom(rng.endContainer);
10502
        return preprocessExact(start, rng.startOffset, finish, rng.endOffset);
10503
      },
10504
      relative: preprocessRelative,
10505
      exact: preprocessExact
10506
    });
10507
 
10508
    const fromElements = (elements, scope) => {
10509
      const doc = scope || document;
10510
      const fragment = doc.createDocumentFragment();
10511
      each$e(elements, element => {
10512
        fragment.appendChild(element.dom);
10513
      });
10514
      return SugarElement.fromDom(fragment);
10515
    };
10516
 
10517
    const toNative = selection => {
10518
      const win = SimSelection.getWin(selection).dom;
10519
      const getDomRange = (start, soffset, finish, foffset) => exactToNative(win, start, soffset, finish, foffset);
10520
      const filtered = preprocess(selection);
10521
      return diagnose(win, filtered).match({
10522
        ltr: getDomRange,
10523
        rtl: getDomRange
10524
      });
10525
    };
10526
    const getAtPoint = (win, x, y) => fromPoint$1(win, x, y);
10527
 
10528
    const fromPoint = (clientX, clientY, doc) => {
10529
      const win = defaultView(SugarElement.fromDom(doc));
10530
      return getAtPoint(win.dom, clientX, clientY).map(simRange => {
10531
        const rng = doc.createRange();
10532
        rng.setStart(simRange.start.dom, simRange.soffset);
10533
        rng.setEnd(simRange.finish.dom, simRange.foffset);
10534
        return rng;
10535
      }).getOrUndefined();
10536
    };
10537
 
10538
    const isEq$4 = (rng1, rng2) => {
10539
      return isNonNullable(rng1) && isNonNullable(rng2) && (rng1.startContainer === rng2.startContainer && rng1.startOffset === rng2.startOffset) && (rng1.endContainer === rng2.endContainer && rng1.endOffset === rng2.endOffset);
10540
    };
10541
 
10542
    const findParent = (node, rootNode, predicate) => {
10543
      let currentNode = node;
10544
      while (currentNode && currentNode !== rootNode) {
10545
        if (predicate(currentNode)) {
10546
          return currentNode;
10547
        }
10548
        currentNode = currentNode.parentNode;
10549
      }
10550
      return null;
10551
    };
10552
    const hasParent$1 = (node, rootNode, predicate) => findParent(node, rootNode, predicate) !== null;
10553
    const hasParentWithName = (node, rootNode, name) => hasParent$1(node, rootNode, node => node.nodeName === name);
10554
    const isCeFalseCaretContainer = (node, rootNode) => isCaretContainer$2(node) && !hasParent$1(node, rootNode, isCaretNode);
10555
    const hasBrBeforeAfter = (dom, node, left) => {
10556
      const parentNode = node.parentNode;
10557
      if (parentNode) {
10558
        const walker = new DomTreeWalker(node, dom.getParent(parentNode, dom.isBlock) || dom.getRoot());
10559
        let currentNode;
10560
        while (currentNode = walker[left ? 'prev' : 'next']()) {
10561
          if (isBr$6(currentNode)) {
10562
            return true;
10563
          }
10564
        }
10565
      }
10566
      return false;
10567
    };
10568
    const isPrevNode = (node, name) => {
10569
      var _a;
10570
      return ((_a = node.previousSibling) === null || _a === void 0 ? void 0 : _a.nodeName) === name;
10571
    };
10572
    const hasContentEditableFalseParent = (root, node) => {
10573
      let currentNode = node;
10574
      while (currentNode && currentNode !== root) {
10575
        if (isContentEditableFalse$b(currentNode)) {
10576
          return true;
10577
        }
10578
        currentNode = currentNode.parentNode;
10579
      }
10580
      return false;
10581
    };
10582
    const findTextNodeRelative = (dom, isAfterNode, collapsed, left, startNode) => {
10583
      const body = dom.getRoot();
10584
      const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
10585
      const parentNode = startNode.parentNode;
10586
      let lastInlineElement;
10587
      let node;
10588
      if (!parentNode) {
10589
        return Optional.none();
10590
      }
10591
      const parentBlockContainer = dom.getParent(parentNode, dom.isBlock) || body;
10592
      if (left && isBr$6(startNode) && isAfterNode && dom.isEmpty(parentBlockContainer)) {
10593
        return Optional.some(CaretPosition(parentNode, dom.nodeIndex(startNode)));
10594
      }
10595
      const walker = new DomTreeWalker(startNode, parentBlockContainer);
10596
      while (node = walker[left ? 'prev' : 'next']()) {
10597
        if (dom.getContentEditableParent(node) === 'false' || isCeFalseCaretContainer(node, body)) {
10598
          return Optional.none();
10599
        }
1441 ariadna 10600
        if (isText$b(node) && node.data.length > 0) {
1 efrain 10601
          if (!hasParentWithName(node, body, 'A')) {
10602
            return Optional.some(CaretPosition(node, left ? node.data.length : 0));
10603
          }
10604
          return Optional.none();
10605
        }
10606
        if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
10607
          return Optional.none();
10608
        }
10609
        lastInlineElement = node;
10610
      }
10611
      if (isComment(lastInlineElement)) {
10612
        return Optional.none();
10613
      }
10614
      if (collapsed && lastInlineElement) {
10615
        return Optional.some(CaretPosition(lastInlineElement, 0));
10616
      }
10617
      return Optional.none();
10618
    };
10619
    const normalizeEndPoint = (dom, collapsed, start, rng) => {
10620
      const body = dom.getRoot();
10621
      let node;
10622
      let normalized = false;
10623
      let container = start ? rng.startContainer : rng.endContainer;
10624
      let offset = start ? rng.startOffset : rng.endOffset;
10625
      const isAfterNode = isElement$6(container) && offset === container.childNodes.length;
10626
      const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
10627
      let directionLeft = start;
10628
      if (isCaretContainer$2(container)) {
10629
        return Optional.none();
10630
      }
10631
      if (isElement$6(container) && offset > container.childNodes.length - 1) {
10632
        directionLeft = false;
10633
      }
10634
      if (isDocument$1(container)) {
10635
        container = body;
10636
        offset = 0;
10637
      }
10638
      if (container === body) {
10639
        if (directionLeft) {
10640
          node = container.childNodes[offset > 0 ? offset - 1 : 0];
10641
          if (node) {
10642
            if (isCaretContainer$2(node)) {
10643
              return Optional.none();
10644
            }
10645
            if (nonEmptyElementsMap[node.nodeName] || isTable$2(node)) {
10646
              return Optional.none();
10647
            }
10648
          }
10649
        }
10650
        if (container.hasChildNodes()) {
10651
          offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
10652
          container = container.childNodes[offset];
1441 ariadna 10653
          offset = isText$b(container) && isAfterNode ? container.data.length : 0;
1 efrain 10654
          if (!collapsed && container === body.lastChild && isTable$2(container)) {
10655
            return Optional.none();
10656
          }
10657
          if (hasContentEditableFalseParent(body, container) || isCaretContainer$2(container)) {
10658
            return Optional.none();
10659
          }
10660
          if (isDetails(container)) {
10661
            return Optional.none();
10662
          }
10663
          if (container.hasChildNodes() && !isTable$2(container)) {
10664
            node = container;
10665
            const walker = new DomTreeWalker(container, body);
10666
            do {
10667
              if (isContentEditableFalse$b(node) || isCaretContainer$2(node)) {
10668
                normalized = false;
10669
                break;
10670
              }
1441 ariadna 10671
              if (isText$b(node) && node.data.length > 0) {
1 efrain 10672
                offset = directionLeft ? 0 : node.data.length;
10673
                container = node;
10674
                normalized = true;
10675
                break;
10676
              }
10677
              if (nonEmptyElementsMap[node.nodeName.toLowerCase()] && !isTableCellOrCaption(node)) {
10678
                offset = dom.nodeIndex(node);
10679
                container = node.parentNode;
10680
                if (!directionLeft) {
10681
                  offset++;
10682
                }
10683
                normalized = true;
10684
                break;
10685
              }
10686
            } while (node = directionLeft ? walker.next() : walker.prev());
10687
          }
10688
        }
10689
      }
10690
      if (collapsed) {
1441 ariadna 10691
        if (isText$b(container) && offset === 0) {
1 efrain 10692
          findTextNodeRelative(dom, isAfterNode, collapsed, true, container).each(pos => {
10693
            container = pos.container();
10694
            offset = pos.offset();
10695
            normalized = true;
10696
          });
10697
        }
10698
        if (isElement$6(container)) {
10699
          node = container.childNodes[offset];
10700
          if (!node) {
10701
            node = container.childNodes[offset - 1];
10702
          }
10703
          if (node && isBr$6(node) && !isPrevNode(node, 'A') && !hasBrBeforeAfter(dom, node, false) && !hasBrBeforeAfter(dom, node, true)) {
10704
            findTextNodeRelative(dom, isAfterNode, collapsed, true, node).each(pos => {
10705
              container = pos.container();
10706
              offset = pos.offset();
10707
              normalized = true;
10708
            });
10709
          }
10710
        }
10711
      }
1441 ariadna 10712
      if (directionLeft && !collapsed && isText$b(container) && offset === container.data.length) {
1 efrain 10713
        findTextNodeRelative(dom, isAfterNode, collapsed, false, container).each(pos => {
10714
          container = pos.container();
10715
          offset = pos.offset();
10716
          normalized = true;
10717
        });
10718
      }
10719
      return normalized && container ? Optional.some(CaretPosition(container, offset)) : Optional.none();
10720
    };
10721
    const normalize$2 = (dom, rng) => {
10722
      const collapsed = rng.collapsed, normRng = rng.cloneRange();
10723
      const startPos = CaretPosition.fromRangeStart(rng);
10724
      normalizeEndPoint(dom, collapsed, true, normRng).each(pos => {
10725
        if (!collapsed || !CaretPosition.isAbove(startPos, pos)) {
10726
          normRng.setStart(pos.container(), pos.offset());
10727
        }
10728
      });
10729
      if (!collapsed) {
10730
        normalizeEndPoint(dom, collapsed, false, normRng).each(pos => {
10731
          normRng.setEnd(pos.container(), pos.offset());
10732
        });
10733
      }
10734
      if (collapsed) {
10735
        normRng.collapse(true);
10736
      }
10737
      return isEq$4(rng, normRng) ? Optional.none() : Optional.some(normRng);
10738
    };
10739
 
10740
    const splitText = (node, offset) => {
10741
      return node.splitText(offset);
10742
    };
10743
    const split = rng => {
10744
      let startContainer = rng.startContainer, startOffset = rng.startOffset, endContainer = rng.endContainer, endOffset = rng.endOffset;
1441 ariadna 10745
      if (startContainer === endContainer && isText$b(startContainer)) {
1 efrain 10746
        if (startOffset > 0 && startOffset < startContainer.data.length) {
10747
          endContainer = splitText(startContainer, startOffset);
10748
          startContainer = endContainer.previousSibling;
10749
          if (endOffset > startOffset) {
10750
            endOffset = endOffset - startOffset;
10751
            const newContainer = splitText(endContainer, endOffset).previousSibling;
10752
            startContainer = endContainer = newContainer;
10753
            endOffset = newContainer.data.length;
10754
            startOffset = 0;
10755
          } else {
10756
            endOffset = 0;
10757
          }
10758
        }
10759
      } else {
1441 ariadna 10760
        if (isText$b(startContainer) && startOffset > 0 && startOffset < startContainer.data.length) {
1 efrain 10761
          startContainer = splitText(startContainer, startOffset);
10762
          startOffset = 0;
10763
        }
1441 ariadna 10764
        if (isText$b(endContainer) && endOffset > 0 && endOffset < endContainer.data.length) {
1 efrain 10765
          const newContainer = splitText(endContainer, endOffset).previousSibling;
10766
          endContainer = newContainer;
10767
          endOffset = newContainer.data.length;
10768
        }
10769
      }
10770
      return {
10771
        startContainer,
10772
        startOffset,
10773
        endContainer,
10774
        endOffset
10775
      };
10776
    };
10777
 
10778
    const RangeUtils = dom => {
10779
      const walk = (rng, callback) => {
10780
        return walk$3(dom, rng, callback);
10781
      };
10782
      const split$1 = split;
10783
      const normalize = rng => {
10784
        return normalize$2(dom, rng).fold(never, normalizedRng => {
10785
          rng.setStart(normalizedRng.startContainer, normalizedRng.startOffset);
10786
          rng.setEnd(normalizedRng.endContainer, normalizedRng.endOffset);
10787
          return true;
10788
        });
10789
      };
10790
      const expand = (rng, options = { type: 'word' }) => {
10791
        if (options.type === 'word') {
1441 ariadna 10792
          const rangeLike = expandRng(dom, rng, [{ inline: 'span' }], {
10793
            includeTrailingSpace: false,
10794
            expandToBlock: false
10795
          });
1 efrain 10796
          const newRange = dom.createRng();
10797
          newRange.setStart(rangeLike.startContainer, rangeLike.startOffset);
10798
          newRange.setEnd(rangeLike.endContainer, rangeLike.endOffset);
10799
          return newRange;
10800
        }
10801
        return rng;
10802
      };
10803
      return {
10804
        walk,
10805
        split: split$1,
10806
        expand,
10807
        normalize
10808
      };
10809
    };
10810
    RangeUtils.compareRanges = isEq$4;
10811
    RangeUtils.getCaretRangeFromPoint = fromPoint;
10812
    RangeUtils.getSelectedNode = getSelectedNode;
10813
    RangeUtils.getNode = getNode$1;
10814
 
10815
    const Dimension = (name, getOffset) => {
10816
      const set = (element, h) => {
10817
        if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
10818
          throw new Error(name + '.set accepts only positive integer values. Value was ' + h);
10819
        }
10820
        const dom = element.dom;
10821
        if (isSupported(dom)) {
10822
          dom.style[name] = h + 'px';
10823
        }
10824
      };
10825
      const get = element => {
10826
        const r = getOffset(element);
10827
        if (r <= 0 || r === null) {
10828
          const css = get$7(element, name);
10829
          return parseFloat(css) || 0;
10830
        }
10831
        return r;
10832
      };
10833
      const getOuter = get;
10834
      const aggregate = (element, properties) => foldl(properties, (acc, property) => {
10835
        const val = get$7(element, property);
10836
        const value = val === undefined ? 0 : parseInt(val, 10);
10837
        return isNaN(value) ? acc : acc + value;
10838
      }, 0);
10839
      const max = (element, value, properties) => {
10840
        const cumulativeInclusions = aggregate(element, properties);
10841
        const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0;
10842
        return absoluteMax;
10843
      };
10844
      return {
10845
        set,
10846
        get,
10847
        getOuter,
10848
        aggregate,
10849
        max
10850
      };
10851
    };
10852
 
10853
    const api = Dimension('height', element => {
10854
      const dom = element.dom;
10855
      return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
10856
    });
10857
    const get$2 = element => api.get(element);
10858
 
10859
    const walkUp = (navigation, doc) => {
10860
      const frame = navigation.view(doc);
10861
      return frame.fold(constant([]), f => {
10862
        const parent = navigation.owner(f);
10863
        const rest = walkUp(navigation, parent);
10864
        return [f].concat(rest);
10865
      });
10866
    };
10867
    const pathTo = (element, navigation) => {
10868
      const d = navigation.owner(element);
10869
      return walkUp(navigation, d);
10870
    };
10871
 
10872
    const view = doc => {
10873
      var _a;
10874
      const element = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement);
10875
      return element.map(SugarElement.fromDom);
10876
    };
10877
    const owner = element => documentOrOwner(element);
10878
 
10879
    var Navigation = /*#__PURE__*/Object.freeze({
10880
        __proto__: null,
10881
        view: view,
10882
        owner: owner
10883
    });
10884
 
10885
    const find = element => {
10886
      const doc = getDocument();
10887
      const scroll = get$5(doc);
10888
      const frames = pathTo(element, Navigation);
10889
      const offset = viewport(element);
10890
      const r = foldr(frames, (b, a) => {
10891
        const loc = viewport(a);
10892
        return {
10893
          left: b.left + loc.left,
10894
          top: b.top + loc.top
10895
        };
10896
      }, {
10897
        left: 0,
10898
        top: 0
10899
      });
10900
      return SugarPosition(r.left + offset.left + scroll.left, r.top + offset.top + scroll.top);
10901
    };
10902
 
10903
    const excludeFromDescend = element => name(element) === 'textarea';
10904
    const fireScrollIntoViewEvent = (editor, data) => {
10905
      const scrollEvent = editor.dispatch('ScrollIntoView', data);
10906
      return scrollEvent.isDefaultPrevented();
10907
    };
10908
    const fireAfterScrollIntoViewEvent = (editor, data) => {
10909
      editor.dispatch('AfterScrollIntoView', data);
10910
    };
10911
    const descend = (element, offset) => {
10912
      const children = children$1(element);
10913
      if (children.length === 0 || excludeFromDescend(element)) {
10914
        return {
10915
          element,
10916
          offset
10917
        };
10918
      } else if (offset < children.length && !excludeFromDescend(children[offset])) {
10919
        return {
10920
          element: children[offset],
10921
          offset: 0
10922
        };
10923
      } else {
10924
        const last = children[children.length - 1];
10925
        if (excludeFromDescend(last)) {
10926
          return {
10927
            element,
10928
            offset
10929
          };
10930
        } else {
10931
          if (name(last) === 'img') {
10932
            return {
10933
              element: last,
10934
              offset: 1
10935
            };
1441 ariadna 10936
          } else if (isText$c(last)) {
1 efrain 10937
            return {
10938
              element: last,
10939
              offset: get$3(last).length
10940
            };
10941
          } else {
10942
            return {
10943
              element: last,
10944
              offset: children$1(last).length
10945
            };
10946
          }
10947
        }
10948
      }
10949
    };
10950
    const markerInfo = (element, cleanupFun) => {
10951
      const pos = absolute(element);
10952
      const height = get$2(element);
10953
      return {
10954
        element,
10955
        bottom: pos.top + height,
10956
        height,
10957
        pos,
10958
        cleanup: cleanupFun
10959
      };
10960
    };
10961
    const createMarker$1 = (element, offset) => {
10962
      const startPoint = descend(element, offset);
10963
      const span = SugarElement.fromHtml('<span data-mce-bogus="all" style="display: inline-block;">' + ZWSP$1 + '</span>');
10964
      before$3(startPoint.element, span);
1441 ariadna 10965
      return markerInfo(span, () => remove$4(span));
1 efrain 10966
    };
10967
    const elementMarker = element => markerInfo(SugarElement.fromDom(element), noop);
10968
    const withMarker = (editor, f, rng, alignToTop) => {
10969
      preserveWith(editor, (_s, _e) => applyWithMarker(editor, f, rng, alignToTop), rng);
10970
    };
10971
    const withScrollEvents = (editor, doc, f, marker, alignToTop) => {
10972
      const data = {
10973
        elm: marker.element.dom,
10974
        alignToTop
10975
      };
10976
      if (fireScrollIntoViewEvent(editor, data)) {
10977
        return;
10978
      }
10979
      const scrollTop = get$5(doc).top;
10980
      f(editor, doc, scrollTop, marker, alignToTop);
10981
      fireAfterScrollIntoViewEvent(editor, data);
10982
    };
10983
    const applyWithMarker = (editor, f, rng, alignToTop) => {
10984
      const body = SugarElement.fromDom(editor.getBody());
10985
      const doc = SugarElement.fromDom(editor.getDoc());
10986
      reflow(body);
10987
      const marker = createMarker$1(SugarElement.fromDom(rng.startContainer), rng.startOffset);
10988
      withScrollEvents(editor, doc, f, marker, alignToTop);
10989
      marker.cleanup();
10990
    };
10991
    const withElement = (editor, element, f, alignToTop) => {
10992
      const doc = SugarElement.fromDom(editor.getDoc());
10993
      withScrollEvents(editor, doc, f, elementMarker(element), alignToTop);
10994
    };
10995
    const preserveWith = (editor, f, rng) => {
10996
      const startElement = rng.startContainer;
10997
      const startOffset = rng.startOffset;
10998
      const endElement = rng.endContainer;
10999
      const endOffset = rng.endOffset;
11000
      f(SugarElement.fromDom(startElement), SugarElement.fromDom(endElement));
11001
      const newRng = editor.dom.createRng();
11002
      newRng.setStart(startElement, startOffset);
11003
      newRng.setEnd(endElement, endOffset);
11004
      editor.selection.setRng(rng);
11005
    };
11006
    const scrollToMarker = (editor, marker, viewHeight, alignToTop, doc) => {
11007
      const pos = marker.pos;
11008
      if (alignToTop) {
11009
        to(pos.left, pos.top, doc);
11010
      } else {
11011
        const y = pos.top - viewHeight + marker.height;
11012
        to(-editor.getBody().getBoundingClientRect().left, y, doc);
11013
      }
11014
    };
11015
    const intoWindowIfNeeded = (editor, doc, scrollTop, viewHeight, marker, alignToTop) => {
11016
      const viewportBottom = viewHeight + scrollTop;
11017
      const markerTop = marker.pos.top;
11018
      const markerBottom = marker.bottom;
11019
      const largerThanViewport = markerBottom - markerTop >= viewHeight;
11020
      if (markerTop < scrollTop) {
11021
        scrollToMarker(editor, marker, viewHeight, alignToTop !== false, doc);
11022
      } else if (markerTop > viewportBottom) {
11023
        const align = largerThanViewport ? alignToTop !== false : alignToTop === true;
11024
        scrollToMarker(editor, marker, viewHeight, align, doc);
11025
      } else if (markerBottom > viewportBottom && !largerThanViewport) {
11026
        scrollToMarker(editor, marker, viewHeight, alignToTop === true, doc);
11027
      }
11028
    };
11029
    const intoWindow = (editor, doc, scrollTop, marker, alignToTop) => {
11030
      const viewHeight = defaultView(doc).dom.innerHeight;
11031
      intoWindowIfNeeded(editor, doc, scrollTop, viewHeight, marker, alignToTop);
11032
    };
11033
    const intoFrame = (editor, doc, scrollTop, marker, alignToTop) => {
11034
      const frameViewHeight = defaultView(doc).dom.innerHeight;
11035
      intoWindowIfNeeded(editor, doc, scrollTop, frameViewHeight, marker, alignToTop);
11036
      const op = find(marker.element);
11037
      const viewportBounds = getBounds(window);
11038
      if (op.top < viewportBounds.y) {
11039
        intoView(marker.element, alignToTop !== false);
11040
      } else if (op.top > viewportBounds.bottom) {
11041
        intoView(marker.element, alignToTop === true);
11042
      }
11043
    };
11044
    const rangeIntoWindow = (editor, rng, alignToTop) => withMarker(editor, intoWindow, rng, alignToTop);
11045
    const elementIntoWindow = (editor, element, alignToTop) => withElement(editor, element, intoWindow, alignToTop);
11046
    const rangeIntoFrame = (editor, rng, alignToTop) => withMarker(editor, intoFrame, rng, alignToTop);
11047
    const elementIntoFrame = (editor, element, alignToTop) => withElement(editor, element, intoFrame, alignToTop);
11048
    const scrollElementIntoView = (editor, element, alignToTop) => {
11049
      const scroller = editor.inline ? elementIntoWindow : elementIntoFrame;
11050
      scroller(editor, element, alignToTop);
11051
    };
11052
    const scrollRangeIntoView = (editor, rng, alignToTop) => {
11053
      const scroller = editor.inline ? rangeIntoWindow : rangeIntoFrame;
11054
      scroller(editor, rng, alignToTop);
11055
    };
11056
 
11057
    const isEditableRange = (dom, rng) => {
11058
      if (rng.collapsed) {
11059
        return dom.isEditable(rng.startContainer);
11060
      } else {
11061
        return dom.isEditable(rng.startContainer) && dom.isEditable(rng.endContainer);
11062
      }
11063
    };
11064
 
11065
    const getEndpointElement = (root, rng, start, real, resolve) => {
11066
      const container = start ? rng.startContainer : rng.endContainer;
11067
      const offset = start ? rng.startOffset : rng.endOffset;
11068
      return Optional.from(container).map(SugarElement.fromDom).map(elm => !real || !rng.collapsed ? child$1(elm, resolve(elm, offset)).getOr(elm) : elm).bind(elm => isElement$7(elm) ? Optional.some(elm) : parent(elm).filter(isElement$7)).map(elm => elm.dom).getOr(root);
11069
    };
11070
    const getStart = (root, rng, real = false) => getEndpointElement(root, rng, true, real, (elm, offset) => Math.min(childNodesCount(elm), offset));
1441 ariadna 11071
    const getEnd = (root, rng, real = false) => getEndpointElement(root, rng, false, real, (elm, offset) => offset > 0 ? offset - 1 : offset);
1 efrain 11072
    const skipEmptyTextNodes = (node, forwards) => {
11073
      const orig = node;
1441 ariadna 11074
      while (node && isText$b(node) && node.length === 0) {
1 efrain 11075
        node = forwards ? node.nextSibling : node.previousSibling;
11076
      }
11077
      return node || orig;
11078
    };
11079
    const getNode = (root, rng) => {
11080
      if (!rng) {
11081
        return root;
11082
      }
11083
      let startContainer = rng.startContainer;
11084
      let endContainer = rng.endContainer;
11085
      const startOffset = rng.startOffset;
11086
      const endOffset = rng.endOffset;
11087
      let node = rng.commonAncestorContainer;
11088
      if (!rng.collapsed) {
11089
        if (startContainer === endContainer) {
11090
          if (endOffset - startOffset < 2) {
11091
            if (startContainer.hasChildNodes()) {
11092
              node = startContainer.childNodes[startOffset];
11093
            }
11094
          }
11095
        }
1441 ariadna 11096
        if (isText$b(startContainer) && isText$b(endContainer)) {
1 efrain 11097
          if (startContainer.length === startOffset) {
11098
            startContainer = skipEmptyTextNodes(startContainer.nextSibling, true);
11099
          } else {
11100
            startContainer = startContainer.parentNode;
11101
          }
11102
          if (endOffset === 0) {
11103
            endContainer = skipEmptyTextNodes(endContainer.previousSibling, false);
11104
          } else {
11105
            endContainer = endContainer.parentNode;
11106
          }
11107
          if (startContainer && startContainer === endContainer) {
11108
            node = startContainer;
11109
          }
11110
        }
11111
      }
1441 ariadna 11112
      const elm = isText$b(node) ? node.parentNode : node;
1 efrain 11113
      return isHTMLElement(elm) ? elm : root;
11114
    };
11115
    const getSelectedBlocks = (dom, rng, startElm, endElm) => {
11116
      const selectedBlocks = [];
11117
      const root = dom.getRoot();
11118
      const start = dom.getParent(startElm || getStart(root, rng, rng.collapsed), dom.isBlock);
1441 ariadna 11119
      const end = dom.getParent(endElm || getEnd(root, rng, rng.collapsed), dom.isBlock);
1 efrain 11120
      if (start && start !== root) {
11121
        selectedBlocks.push(start);
11122
      }
11123
      if (start && end && start !== end) {
11124
        let node;
11125
        const walker = new DomTreeWalker(start, root);
11126
        while ((node = walker.next()) && node !== end) {
11127
          if (dom.isBlock(node)) {
11128
            selectedBlocks.push(node);
11129
          }
11130
        }
11131
      }
11132
      if (end && start !== end && end !== root) {
11133
        selectedBlocks.push(end);
11134
      }
11135
      return selectedBlocks;
11136
    };
11137
    const select = (dom, node, content) => Optional.from(node).bind(node => Optional.from(node.parentNode).map(parent => {
11138
      const idx = dom.nodeIndex(node);
11139
      const rng = dom.createRng();
11140
      rng.setStart(parent, idx);
11141
      rng.setEnd(parent, idx + 1);
11142
      if (content) {
11143
        moveEndPoint(dom, rng, node, true);
11144
        moveEndPoint(dom, rng, node, false);
11145
      }
11146
      return rng;
11147
    }));
11148
 
11149
    const processRanges = (editor, ranges) => map$3(ranges, range => {
11150
      const evt = editor.dispatch('GetSelectionRange', { range });
11151
      return evt.range !== range ? evt.range : range;
11152
    });
11153
 
11154
    const typeLookup = {
11155
      '#text': 3,
11156
      '#comment': 8,
11157
      '#cdata': 4,
11158
      '#pi': 7,
11159
      '#doctype': 10,
11160
      '#document-fragment': 11
11161
    };
11162
    const walk$2 = (node, root, prev) => {
11163
      const startName = prev ? 'lastChild' : 'firstChild';
11164
      const siblingName = prev ? 'prev' : 'next';
11165
      if (node[startName]) {
11166
        return node[startName];
11167
      }
11168
      if (node !== root) {
11169
        let sibling = node[siblingName];
11170
        if (sibling) {
11171
          return sibling;
11172
        }
11173
        for (let parent = node.parent; parent && parent !== root; parent = parent.parent) {
11174
          sibling = parent[siblingName];
11175
          if (sibling) {
11176
            return sibling;
11177
          }
11178
        }
11179
      }
11180
      return undefined;
11181
    };
11182
    const isEmptyTextNode = node => {
11183
      var _a;
11184
      const text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
11185
      if (!isWhitespaceText(text)) {
11186
        return false;
11187
      }
11188
      const parentNode = node.parent;
11189
      if (parentNode && (parentNode.name !== 'span' || parentNode.attr('style')) && /^[ ]+$/.test(text)) {
11190
        return false;
11191
      }
11192
      return true;
11193
    };
11194
    const isNonEmptyElement = node => {
11195
      const isNamedAnchor = node.name === 'a' && !node.attr('href') && node.attr('id');
11196
      return node.attr('name') || node.attr('id') && !node.firstChild || node.attr('data-mce-bookmark') || isNamedAnchor;
11197
    };
11198
    class AstNode {
11199
      static create(name, attrs) {
11200
        const node = new AstNode(name, typeLookup[name] || 1);
11201
        if (attrs) {
11202
          each$d(attrs, (value, attrName) => {
11203
            node.attr(attrName, value);
11204
          });
11205
        }
11206
        return node;
11207
      }
11208
      constructor(name, type) {
11209
        this.name = name;
11210
        this.type = type;
11211
        if (type === 1) {
11212
          this.attributes = [];
11213
          this.attributes.map = {};
11214
        }
11215
      }
11216
      replace(node) {
11217
        const self = this;
11218
        if (node.parent) {
11219
          node.remove();
11220
        }
11221
        self.insert(node, self);
11222
        self.remove();
11223
        return self;
11224
      }
11225
      attr(name, value) {
11226
        const self = this;
11227
        if (!isString(name)) {
11228
          if (isNonNullable(name)) {
11229
            each$d(name, (value, key) => {
11230
              self.attr(key, value);
11231
            });
11232
          }
11233
          return self;
11234
        }
11235
        const attrs = self.attributes;
11236
        if (attrs) {
11237
          if (value !== undefined) {
11238
            if (value === null) {
11239
              if (name in attrs.map) {
11240
                delete attrs.map[name];
11241
                let i = attrs.length;
11242
                while (i--) {
11243
                  if (attrs[i].name === name) {
11244
                    attrs.splice(i, 1);
11245
                    return self;
11246
                  }
11247
                }
11248
              }
11249
              return self;
11250
            }
11251
            if (name in attrs.map) {
11252
              let i = attrs.length;
11253
              while (i--) {
11254
                if (attrs[i].name === name) {
11255
                  attrs[i].value = value;
11256
                  break;
11257
                }
11258
              }
11259
            } else {
11260
              attrs.push({
11261
                name,
11262
                value
11263
              });
11264
            }
11265
            attrs.map[name] = value;
11266
            return self;
11267
          }
11268
          return attrs.map[name];
11269
        }
11270
        return undefined;
11271
      }
11272
      clone() {
11273
        const self = this;
11274
        const clone = new AstNode(self.name, self.type);
11275
        const selfAttrs = self.attributes;
11276
        if (selfAttrs) {
11277
          const cloneAttrs = [];
11278
          cloneAttrs.map = {};
11279
          for (let i = 0, l = selfAttrs.length; i < l; i++) {
11280
            const selfAttr = selfAttrs[i];
11281
            if (selfAttr.name !== 'id') {
11282
              cloneAttrs[cloneAttrs.length] = {
11283
                name: selfAttr.name,
11284
                value: selfAttr.value
11285
              };
11286
              cloneAttrs.map[selfAttr.name] = selfAttr.value;
11287
            }
11288
          }
11289
          clone.attributes = cloneAttrs;
11290
        }
11291
        clone.value = self.value;
11292
        return clone;
11293
      }
11294
      wrap(wrapper) {
11295
        const self = this;
11296
        if (self.parent) {
11297
          self.parent.insert(wrapper, self);
11298
          wrapper.append(self);
11299
        }
11300
        return self;
11301
      }
11302
      unwrap() {
11303
        const self = this;
11304
        for (let node = self.firstChild; node;) {
11305
          const next = node.next;
11306
          self.insert(node, self, true);
11307
          node = next;
11308
        }
11309
        self.remove();
11310
      }
11311
      remove() {
11312
        const self = this, parent = self.parent, next = self.next, prev = self.prev;
11313
        if (parent) {
11314
          if (parent.firstChild === self) {
11315
            parent.firstChild = next;
11316
            if (next) {
11317
              next.prev = null;
11318
            }
11319
          } else if (prev) {
11320
            prev.next = next;
11321
          }
11322
          if (parent.lastChild === self) {
11323
            parent.lastChild = prev;
11324
            if (prev) {
11325
              prev.next = null;
11326
            }
11327
          } else if (next) {
11328
            next.prev = prev;
11329
          }
11330
          self.parent = self.next = self.prev = null;
11331
        }
11332
        return self;
11333
      }
11334
      append(node) {
11335
        const self = this;
11336
        if (node.parent) {
11337
          node.remove();
11338
        }
11339
        const last = self.lastChild;
11340
        if (last) {
11341
          last.next = node;
11342
          node.prev = last;
11343
          self.lastChild = node;
11344
        } else {
11345
          self.lastChild = self.firstChild = node;
11346
        }
11347
        node.parent = self;
11348
        return node;
11349
      }
11350
      insert(node, refNode, before) {
11351
        if (node.parent) {
11352
          node.remove();
11353
        }
11354
        const parent = refNode.parent || this;
11355
        if (before) {
11356
          if (refNode === parent.firstChild) {
11357
            parent.firstChild = node;
11358
          } else if (refNode.prev) {
11359
            refNode.prev.next = node;
11360
          }
11361
          node.prev = refNode.prev;
11362
          node.next = refNode;
11363
          refNode.prev = node;
11364
        } else {
11365
          if (refNode === parent.lastChild) {
11366
            parent.lastChild = node;
11367
          } else if (refNode.next) {
11368
            refNode.next.prev = node;
11369
          }
11370
          node.next = refNode.next;
11371
          node.prev = refNode;
11372
          refNode.next = node;
11373
        }
11374
        node.parent = parent;
11375
        return node;
11376
      }
11377
      getAll(name) {
11378
        const self = this;
11379
        const collection = [];
11380
        for (let node = self.firstChild; node; node = walk$2(node, self)) {
11381
          if (node.name === name) {
11382
            collection.push(node);
11383
          }
11384
        }
11385
        return collection;
11386
      }
11387
      children() {
11388
        const self = this;
11389
        const collection = [];
11390
        for (let node = self.firstChild; node; node = node.next) {
11391
          collection.push(node);
11392
        }
11393
        return collection;
11394
      }
11395
      empty() {
11396
        const self = this;
11397
        if (self.firstChild) {
11398
          const nodes = [];
11399
          for (let node = self.firstChild; node; node = walk$2(node, self)) {
11400
            nodes.push(node);
11401
          }
11402
          let i = nodes.length;
11403
          while (i--) {
11404
            const node = nodes[i];
11405
            node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
11406
          }
11407
        }
11408
        self.firstChild = self.lastChild = null;
11409
        return self;
11410
      }
11411
      isEmpty(elements, whitespace = {}, predicate) {
11412
        var _a;
11413
        const self = this;
11414
        let node = self.firstChild;
11415
        if (isNonEmptyElement(self)) {
11416
          return false;
11417
        }
11418
        if (node) {
11419
          do {
11420
            if (node.type === 1) {
11421
              if (node.attr('data-mce-bogus')) {
11422
                continue;
11423
              }
11424
              if (elements[node.name]) {
11425
                return false;
11426
              }
11427
              if (isNonEmptyElement(node)) {
11428
                return false;
11429
              }
11430
            }
11431
            if (node.type === 8) {
11432
              return false;
11433
            }
11434
            if (node.type === 3 && !isEmptyTextNode(node)) {
11435
              return false;
11436
            }
11437
            if (node.type === 3 && node.parent && whitespace[node.parent.name] && isWhitespaceText((_a = node.value) !== null && _a !== void 0 ? _a : '')) {
11438
              return false;
11439
            }
11440
            if (predicate && predicate(node)) {
11441
              return false;
11442
            }
11443
          } while (node = walk$2(node, self));
11444
        }
11445
        return true;
11446
      }
11447
      walk(prev) {
11448
        return walk$2(this, null, prev);
11449
      }
11450
    }
11451
 
11452
    const unescapedTextParents = Tools.makeMap('NOSCRIPT STYLE SCRIPT XMP IFRAME NOEMBED NOFRAMES PLAINTEXT', ' ');
11453
    const containsZwsp = node => isString(node.nodeValue) && node.nodeValue.includes(ZWSP$1);
11454
    const getTemporaryNodeSelector = tempAttrs => `${ tempAttrs.length === 0 ? '' : `${ map$3(tempAttrs, attr => `[${ attr }]`).join(',') },` }[data-mce-bogus="all"]`;
11455
    const getTemporaryNodes = (tempAttrs, body) => body.querySelectorAll(getTemporaryNodeSelector(tempAttrs));
11456
    const createZwspCommentWalker = body => document.createTreeWalker(body, NodeFilter.SHOW_COMMENT, node => containsZwsp(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP);
11457
    const createUnescapedZwspTextWalker = body => document.createTreeWalker(body, NodeFilter.SHOW_TEXT, node => {
11458
      if (containsZwsp(node)) {
11459
        const parent = node.parentNode;
11460
        return parent && has$2(unescapedTextParents, parent.nodeName) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
11461
      } else {
11462
        return NodeFilter.FILTER_SKIP;
11463
      }
11464
    });
11465
    const hasZwspComment = body => createZwspCommentWalker(body).nextNode() !== null;
11466
    const hasUnescapedZwspText = body => createUnescapedZwspTextWalker(body).nextNode() !== null;
11467
    const hasTemporaryNode = (tempAttrs, body) => body.querySelector(getTemporaryNodeSelector(tempAttrs)) !== null;
11468
    const trimTemporaryNodes = (tempAttrs, body) => {
11469
      each$e(getTemporaryNodes(tempAttrs, body), elm => {
11470
        const element = SugarElement.fromDom(elm);
11471
        if (get$9(element, 'data-mce-bogus') === 'all') {
1441 ariadna 11472
          remove$4(element);
1 efrain 11473
        } else {
11474
          each$e(tempAttrs, attr => {
11475
            if (has$1(element, attr)) {
1441 ariadna 11476
              remove$9(element, attr);
1 efrain 11477
            }
11478
          });
11479
        }
11480
      });
11481
    };
11482
    const emptyAllNodeValuesInWalker = walker => {
11483
      let curr = walker.nextNode();
11484
      while (curr !== null) {
11485
        curr.nodeValue = null;
11486
        curr = walker.nextNode();
11487
      }
11488
    };
11489
    const emptyZwspComments = compose(emptyAllNodeValuesInWalker, createZwspCommentWalker);
11490
    const emptyUnescapedZwspTexts = compose(emptyAllNodeValuesInWalker, createUnescapedZwspTextWalker);
11491
    const trim$1 = (body, tempAttrs) => {
11492
      const conditionalTrims = [
11493
        {
11494
          condition: curry(hasTemporaryNode, tempAttrs),
11495
          action: curry(trimTemporaryNodes, tempAttrs)
11496
        },
11497
        {
11498
          condition: hasZwspComment,
11499
          action: emptyZwspComments
11500
        },
11501
        {
11502
          condition: hasUnescapedZwspText,
11503
          action: emptyUnescapedZwspTexts
11504
        }
11505
      ];
11506
      let trimmed = body;
11507
      let cloned = false;
11508
      each$e(conditionalTrims, ({condition, action}) => {
11509
        if (condition(trimmed)) {
11510
          if (!cloned) {
11511
            trimmed = body.cloneNode(true);
11512
            cloned = true;
11513
          }
11514
          action(trimmed);
11515
        }
11516
      });
11517
      return trimmed;
11518
    };
11519
 
11520
    const cleanupBogusElements = parent => {
11521
      const bogusElements = descendants(parent, '[data-mce-bogus]');
11522
      each$e(bogusElements, elem => {
11523
        const bogusValue = get$9(elem, 'data-mce-bogus');
11524
        if (bogusValue === 'all') {
1441 ariadna 11525
          remove$4(elem);
1 efrain 11526
        } else if (isBr$5(elem)) {
11527
          before$3(elem, SugarElement.fromText(zeroWidth));
1441 ariadna 11528
          remove$4(elem);
1 efrain 11529
        } else {
11530
          unwrap(elem);
11531
        }
11532
      });
11533
    };
11534
    const cleanupInputNames = parent => {
11535
      const inputs = descendants(parent, 'input');
11536
      each$e(inputs, input => {
1441 ariadna 11537
        remove$9(input, 'name');
1 efrain 11538
      });
11539
    };
11540
 
11541
    const trimEmptyContents = (editor, html) => {
11542
      const blockName = getForcedRootBlock(editor);
11543
      const emptyRegExp = new RegExp(`^(<${ blockName }[^>]*>(&nbsp;|&#160;|\\s|\u00a0|<br \\/>|)<\\/${ blockName }>[\r\n]*|<br \\/>[\r\n]*)$`);
11544
      return html.replace(emptyRegExp, '');
11545
    };
11546
    const getPlainTextContent = (editor, body) => {
11547
      const doc = editor.getDoc();
11548
      const dos = getRootNode(SugarElement.fromDom(editor.getBody()));
11549
      const offscreenDiv = SugarElement.fromTag('div', doc);
1441 ariadna 11550
      set$4(offscreenDiv, 'data-mce-bogus', 'all');
1 efrain 11551
      setAll(offscreenDiv, {
11552
        position: 'fixed',
11553
        left: '-9999999px',
11554
        top: '0'
11555
      });
11556
      set$1(offscreenDiv, body.innerHTML);
11557
      cleanupBogusElements(offscreenDiv);
11558
      cleanupInputNames(offscreenDiv);
11559
      const root = getContentContainer(dos);
11560
      append$1(root, offscreenDiv);
11561
      const content = trim$2(offscreenDiv.dom.innerText);
1441 ariadna 11562
      remove$4(offscreenDiv);
1 efrain 11563
      return content;
11564
    };
11565
    const getContentFromBody = (editor, args, body) => {
11566
      let content;
11567
      if (args.format === 'raw') {
11568
        content = Tools.trim(trim$2(trim$1(body, editor.serializer.getTempAttrs()).innerHTML));
11569
      } else if (args.format === 'text') {
11570
        content = getPlainTextContent(editor, body);
11571
      } else if (args.format === 'tree') {
11572
        content = editor.serializer.serialize(body, args);
11573
      } else {
11574
        content = trimEmptyContents(editor, editor.serializer.serialize(body, args));
11575
      }
11576
      const shouldTrim = args.format !== 'text' && !isWsPreserveElement(SugarElement.fromDom(body));
11577
      return shouldTrim && isString(content) ? Tools.trim(content) : content;
11578
    };
11579
    const getContentInternal = (editor, args) => Optional.from(editor.getBody()).fold(constant(args.format === 'tree' ? new AstNode('body', 11) : ''), body => getContentFromBody(editor, args, body));
11580
 
11581
    const makeMap$1 = Tools.makeMap;
11582
    const Writer = settings => {
11583
      const html = [];
11584
      settings = settings || {};
11585
      const indent = settings.indent;
11586
      const indentBefore = makeMap$1(settings.indent_before || '');
11587
      const indentAfter = makeMap$1(settings.indent_after || '');
11588
      const encode = Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
11589
      const htmlOutput = settings.element_format !== 'xhtml';
11590
      return {
11591
        start: (name, attrs, empty) => {
11592
          if (indent && indentBefore[name] && html.length > 0) {
11593
            const value = html[html.length - 1];
11594
            if (value.length > 0 && value !== '\n') {
11595
              html.push('\n');
11596
            }
11597
          }
11598
          html.push('<', name);
11599
          if (attrs) {
11600
            for (let i = 0, l = attrs.length; i < l; i++) {
11601
              const attr = attrs[i];
11602
              html.push(' ', attr.name, '="', encode(attr.value, true), '"');
11603
            }
11604
          }
11605
          if (!empty || htmlOutput) {
11606
            html[html.length] = '>';
11607
          } else {
11608
            html[html.length] = ' />';
11609
          }
11610
          if (empty && indent && indentAfter[name] && html.length > 0) {
11611
            const value = html[html.length - 1];
11612
            if (value.length > 0 && value !== '\n') {
11613
              html.push('\n');
11614
            }
11615
          }
11616
        },
11617
        end: name => {
11618
          let value;
11619
          html.push('</', name, '>');
11620
          if (indent && indentAfter[name] && html.length > 0) {
11621
            value = html[html.length - 1];
11622
            if (value.length > 0 && value !== '\n') {
11623
              html.push('\n');
11624
            }
11625
          }
11626
        },
11627
        text: (text, raw) => {
11628
          if (text.length > 0) {
11629
            html[html.length] = raw ? text : encode(text);
11630
          }
11631
        },
11632
        cdata: text => {
11633
          html.push('<![CDATA[', text, ']]>');
11634
        },
11635
        comment: text => {
11636
          html.push('<!--', text, '-->');
11637
        },
11638
        pi: (name, text) => {
11639
          if (text) {
11640
            html.push('<?', name, ' ', encode(text), '?>');
11641
          } else {
11642
            html.push('<?', name, '?>');
11643
          }
11644
          if (indent) {
11645
            html.push('\n');
11646
          }
11647
        },
11648
        doctype: text => {
11649
          html.push('<!DOCTYPE', text, '>', indent ? '\n' : '');
11650
        },
11651
        reset: () => {
11652
          html.length = 0;
11653
        },
11654
        getContent: () => {
11655
          return html.join('').replace(/\n$/, '');
11656
        }
11657
      };
11658
    };
11659
 
11660
    const HtmlSerializer = (settings = {}, schema = Schema()) => {
11661
      const writer = Writer(settings);
11662
      settings.validate = 'validate' in settings ? settings.validate : true;
11663
      const serialize = node => {
11664
        const validate = settings.validate;
11665
        const handlers = {
11666
          3: node => {
11667
            var _a;
11668
            writer.text((_a = node.value) !== null && _a !== void 0 ? _a : '', node.raw);
11669
          },
11670
          8: node => {
11671
            var _a;
11672
            writer.comment((_a = node.value) !== null && _a !== void 0 ? _a : '');
11673
          },
11674
          7: node => {
11675
            writer.pi(node.name, node.value);
11676
          },
11677
          10: node => {
11678
            var _a;
11679
            writer.doctype((_a = node.value) !== null && _a !== void 0 ? _a : '');
11680
          },
11681
          4: node => {
11682
            var _a;
11683
            writer.cdata((_a = node.value) !== null && _a !== void 0 ? _a : '');
11684
          },
11685
          11: node => {
11686
            let tempNode = node;
11687
            if (tempNode = tempNode.firstChild) {
11688
              do {
11689
                walk(tempNode);
11690
              } while (tempNode = tempNode.next);
11691
            }
11692
          }
11693
        };
11694
        writer.reset();
11695
        const walk = node => {
11696
          var _a;
11697
          const handler = handlers[node.type];
11698
          if (!handler) {
11699
            const name = node.name;
11700
            const isEmpty = name in schema.getVoidElements();
11701
            let attrs = node.attributes;
11702
            if (validate && attrs && attrs.length > 1) {
11703
              const sortedAttrs = [];
11704
              sortedAttrs.map = {};
11705
              const elementRule = schema.getElementRule(node.name);
11706
              if (elementRule) {
11707
                for (let i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
11708
                  const attrName = elementRule.attributesOrder[i];
11709
                  if (attrName in attrs.map) {
11710
                    const attrValue = attrs.map[attrName];
11711
                    sortedAttrs.map[attrName] = attrValue;
11712
                    sortedAttrs.push({
11713
                      name: attrName,
11714
                      value: attrValue
11715
                    });
11716
                  }
11717
                }
11718
                for (let i = 0, l = attrs.length; i < l; i++) {
11719
                  const attrName = attrs[i].name;
11720
                  if (!(attrName in sortedAttrs.map)) {
11721
                    const attrValue = attrs.map[attrName];
11722
                    sortedAttrs.map[attrName] = attrValue;
11723
                    sortedAttrs.push({
11724
                      name: attrName,
11725
                      value: attrValue
11726
                    });
11727
                  }
11728
                }
11729
                attrs = sortedAttrs;
11730
              }
11731
            }
11732
            writer.start(name, attrs, isEmpty);
11733
            if (isNonHtmlElementRootName(name)) {
11734
              if (isString(node.value)) {
11735
                writer.text(node.value, true);
11736
              }
11737
              writer.end(name);
11738
            } else {
11739
              if (!isEmpty) {
11740
                let child = node.firstChild;
11741
                if (child) {
11742
                  if ((name === 'pre' || name === 'textarea') && child.type === 3 && ((_a = child.value) === null || _a === void 0 ? void 0 : _a[0]) === '\n') {
11743
                    writer.text('\n', true);
11744
                  }
11745
                  do {
11746
                    walk(child);
11747
                  } while (child = child.next);
11748
                }
11749
                writer.end(name);
11750
              }
11751
            }
11752
          } else {
11753
            handler(node);
11754
          }
11755
        };
11756
        if (node.type === 1 && !settings.inner) {
11757
          walk(node);
11758
        } else if (node.type === 3) {
11759
          handlers[3](node);
11760
        } else {
11761
          handlers[11](node);
11762
        }
11763
        return writer.getContent();
11764
      };
11765
      return { serialize };
11766
    };
11767
 
11768
    const nonInheritableStyles = new Set();
11769
    (() => {
11770
      const nonInheritableStylesArr = [
11771
        'margin',
11772
        'margin-left',
11773
        'margin-right',
11774
        'margin-top',
11775
        'margin-bottom',
11776
        'padding',
11777
        'padding-left',
11778
        'padding-right',
11779
        'padding-top',
11780
        'padding-bottom',
11781
        'border',
11782
        'border-width',
11783
        'border-style',
11784
        'border-color',
11785
        'background',
11786
        'background-attachment',
11787
        'background-clip',
11788
        'background-image',
11789
        'background-origin',
11790
        'background-position',
11791
        'background-repeat',
11792
        'background-size',
11793
        'float',
11794
        'position',
11795
        'left',
11796
        'right',
11797
        'top',
11798
        'bottom',
11799
        'z-index',
11800
        'display',
11801
        'transform',
11802
        'width',
11803
        'max-width',
11804
        'min-width',
11805
        'height',
11806
        'max-height',
11807
        'min-height',
11808
        'overflow',
11809
        'overflow-x',
11810
        'overflow-y',
11811
        'text-overflow',
11812
        'vertical-align',
11813
        'transition',
11814
        'transition-delay',
11815
        'transition-duration',
11816
        'transition-property',
11817
        'transition-timing-function'
11818
      ];
11819
      each$e(nonInheritableStylesArr, style => {
11820
        nonInheritableStyles.add(style);
11821
      });
11822
    })();
1441 ariadna 11823
    const conditionalNonInheritableStyles = new Set();
11824
    (() => {
11825
      const conditionalNonInheritableStylesArr = ['background-color'];
11826
      each$e(conditionalNonInheritableStylesArr, style => {
11827
        conditionalNonInheritableStyles.add(style);
11828
      });
11829
    })();
1 efrain 11830
    const shorthandStyleProps = [
11831
      'font',
11832
      'text-decoration',
11833
      'text-emphasis'
11834
    ];
1441 ariadna 11835
    const getStyles$1 = (dom, node) => dom.parseStyle(dom.getAttrib(node, 'style'));
11836
    const getStyleProps = (dom, node) => keys(getStyles$1(dom, node));
1 efrain 11837
    const isNonInheritableStyle = style => nonInheritableStyles.has(style);
1441 ariadna 11838
    const isConditionalNonInheritableStyle = style => conditionalNonInheritableStyles.has(style);
11839
    const hasNonInheritableStyles = (dom, node) => exists(getStyleProps(dom, node), style => isNonInheritableStyle(style));
11840
    const hasConditionalNonInheritableStyles = (dom, node) => hasNonInheritableStyles(dom, node) && exists(getStyleProps(dom, node), style => isConditionalNonInheritableStyle(style));
1 efrain 11841
    const getLonghandStyleProps = styles => filter$5(styles, style => exists(shorthandStyleProps, prop => startsWith(style, prop)));
11842
    const hasStyleConflict = (dom, node, parentNode) => {
11843
      const nodeStyleProps = getStyleProps(dom, node);
11844
      const parentNodeStyleProps = getStyleProps(dom, parentNode);
11845
      const valueMismatch = prop => {
11846
        var _a, _b;
11847
        const nodeValue = (_a = dom.getStyle(node, prop)) !== null && _a !== void 0 ? _a : '';
11848
        const parentValue = (_b = dom.getStyle(parentNode, prop)) !== null && _b !== void 0 ? _b : '';
11849
        return isNotEmpty(nodeValue) && isNotEmpty(parentValue) && nodeValue !== parentValue;
11850
      };
11851
      return exists(nodeStyleProps, nodeStyleProp => {
11852
        const propExists = props => exists(props, prop => prop === nodeStyleProp);
11853
        if (!propExists(parentNodeStyleProps) && propExists(shorthandStyleProps)) {
11854
          const longhandProps = getLonghandStyleProps(parentNodeStyleProps);
11855
          return exists(longhandProps, valueMismatch);
11856
        } else {
11857
          return valueMismatch(nodeStyleProp);
11858
        }
11859
      });
11860
    };
11861
 
1441 ariadna 11862
    const isChar = (forward, predicate, pos) => Optional.from(pos.container()).filter(isText$b).exists(text => {
1 efrain 11863
      const delta = forward ? 0 : -1;
11864
      return predicate(text.data.charAt(pos.offset() + delta));
11865
    });
11866
    const isBeforeSpace = curry(isChar, true, isWhiteSpace);
11867
    const isAfterSpace = curry(isChar, false, isWhiteSpace);
11868
    const isEmptyText = pos => {
11869
      const container = pos.container();
1441 ariadna 11870
      return isText$b(container) && (container.data.length === 0 || isZwsp(container.data) && BookmarkManager.isBookmarkNode(container.parentNode));
1 efrain 11871
    };
11872
    const matchesElementPosition = (before, predicate) => pos => getChildNodeAtRelativeOffset(before ? 0 : -1, pos).filter(predicate).isSome();
11873
    const isImageBlock = node => isImg(node) && get$7(SugarElement.fromDom(node), 'display') === 'block';
1441 ariadna 11874
    const isCefNode = node => isContentEditableFalse$b(node) && !isBogusAll(node);
1 efrain 11875
    const isBeforeImageBlock = matchesElementPosition(true, isImageBlock);
11876
    const isAfterImageBlock = matchesElementPosition(false, isImageBlock);
11877
    const isBeforeMedia = matchesElementPosition(true, isMedia$2);
11878
    const isAfterMedia = matchesElementPosition(false, isMedia$2);
11879
    const isBeforeTable = matchesElementPosition(true, isTable$2);
11880
    const isAfterTable = matchesElementPosition(false, isTable$2);
11881
    const isBeforeContentEditableFalse = matchesElementPosition(true, isCefNode);
11882
    const isAfterContentEditableFalse = matchesElementPosition(false, isCefNode);
11883
 
11884
    const dropLast = xs => xs.slice(0, -1);
11885
    const parentsUntil = (start, root, predicate) => {
11886
      if (contains(root, start)) {
11887
        return dropLast(parents$1(start, elm => {
11888
          return predicate(elm) || eq(elm, root);
11889
        }));
11890
      } else {
11891
        return [];
11892
      }
11893
    };
11894
    const parents = (start, root) => parentsUntil(start, root, never);
11895
    const parentsAndSelf = (start, root) => [start].concat(parents(start, root));
11896
 
11897
    const navigateIgnoreEmptyTextNodes = (forward, root, from) => navigateIgnore(forward, root, from, isEmptyText);
11898
    const isBlock$1 = schema => el => schema.isBlock(name(el));
11899
    const getClosestBlock$1 = (root, pos, schema) => find$2(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$1(schema));
11900
    const isAtBeforeAfterBlockBoundary = (forward, root, pos, schema) => navigateIgnoreEmptyTextNodes(forward, root.dom, pos).forall(newPos => getClosestBlock$1(root, pos, schema).fold(() => !isInSameBlock(newPos, pos, root.dom), fromBlock => !isInSameBlock(newPos, pos, root.dom) && contains(fromBlock, SugarElement.fromDom(newPos.container()))));
11901
    const isAtBlockBoundary = (forward, root, pos, schema) => getClosestBlock$1(root, pos, schema).fold(() => navigateIgnoreEmptyTextNodes(forward, root.dom, pos).forall(newPos => !isInSameBlock(newPos, pos, root.dom)), parent => navigateIgnoreEmptyTextNodes(forward, parent.dom, pos).isNone());
11902
    const isAtStartOfBlock = curry(isAtBlockBoundary, false);
11903
    const isAtEndOfBlock = curry(isAtBlockBoundary, true);
11904
    const isBeforeBlock = curry(isAtBeforeAfterBlockBoundary, false);
11905
    const isAfterBlock = curry(isAtBeforeAfterBlockBoundary, true);
11906
 
11907
    const isBr$1 = pos => getElementFromPosition(pos).exists(isBr$5);
11908
    const findBr = (forward, root, pos, schema) => {
11909
      const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), el => schema.isBlock(name(el)));
11910
      const scope = head(parentBlocks).getOr(root);
11911
      return fromPosition(forward, scope.dom, pos).filter(isBr$1);
11912
    };
11913
    const isBeforeBr$1 = (root, pos, schema) => getElementFromPosition(pos).exists(isBr$5) || findBr(true, root, pos, schema).isSome();
11914
    const isAfterBr = (root, pos, schema) => getElementFromPrevPosition(pos).exists(isBr$5) || findBr(false, root, pos, schema).isSome();
11915
    const findPreviousBr = curry(findBr, false);
11916
    const findNextBr = curry(findBr, true);
11917
 
11918
    const isInMiddleOfText = pos => CaretPosition.isTextPosition(pos) && !pos.isAtStart() && !pos.isAtEnd();
11919
    const getClosestBlock = (root, pos, schema) => {
11920
      const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), el => schema.isBlock(name(el)));
11921
      return head(parentBlocks).getOr(root);
11922
    };
11923
    const hasSpaceBefore = (root, pos, schema) => {
11924
      if (isInMiddleOfText(pos)) {
11925
        return isAfterSpace(pos);
11926
      } else {
11927
        return isAfterSpace(pos) || prevPosition(getClosestBlock(root, pos, schema).dom, pos).exists(isAfterSpace);
11928
      }
11929
    };
11930
    const hasSpaceAfter = (root, pos, schema) => {
11931
      if (isInMiddleOfText(pos)) {
11932
        return isBeforeSpace(pos);
11933
      } else {
11934
        return isBeforeSpace(pos) || nextPosition(getClosestBlock(root, pos, schema).dom, pos).exists(isBeforeSpace);
11935
      }
11936
    };
11937
    const isPreValue = value => contains$2([
11938
      'pre',
11939
      'pre-wrap'
11940
    ], value);
11941
    const isInPre = pos => getElementFromPosition(pos).bind(elm => closest$4(elm, isElement$7)).exists(elm => isPreValue(get$7(elm, 'white-space')));
11942
    const isAtBeginningOfBody = (root, pos) => prevPosition(root.dom, pos).isNone();
11943
    const isAtEndOfBody = (root, pos) => nextPosition(root.dom, pos).isNone();
11944
    const isAtLineBoundary = (root, pos, schema) => isAtBeginningOfBody(root, pos) || isAtEndOfBody(root, pos) || isAtStartOfBlock(root, pos, schema) || isAtEndOfBlock(root, pos, schema) || isAfterBr(root, pos, schema) || isBeforeBr$1(root, pos, schema);
11945
    const isCefBlock = node => isNonNullable(node) && isContentEditableFalse$b(node) && isBlockLike(node);
11946
    const isSiblingCefBlock = (root, direction) => container => {
11947
      return isCefBlock(new DomTreeWalker(container, root)[direction]());
11948
    };
11949
    const isBeforeCefBlock = (root, pos) => {
11950
      const nextPos = nextPosition(root.dom, pos).getOr(pos);
11951
      const isNextCefBlock = isSiblingCefBlock(root.dom, 'next');
11952
      return pos.isAtEnd() && (isNextCefBlock(pos.container()) || isNextCefBlock(nextPos.container()));
11953
    };
11954
    const isAfterCefBlock = (root, pos) => {
11955
      const prevPos = prevPosition(root.dom, pos).getOr(pos);
11956
      const isPrevCefBlock = isSiblingCefBlock(root.dom, 'prev');
11957
      return pos.isAtStart() && (isPrevCefBlock(pos.container()) || isPrevCefBlock(prevPos.container()));
11958
    };
11959
    const needsToHaveNbsp = (root, pos, schema) => {
11960
      if (isInPre(pos)) {
11961
        return false;
11962
      } else {
11963
        return isAtLineBoundary(root, pos, schema) || hasSpaceBefore(root, pos, schema) || hasSpaceAfter(root, pos, schema);
11964
      }
11965
    };
11966
    const needsToBeNbspLeft = (root, pos, schema) => {
11967
      if (isInPre(pos)) {
11968
        return false;
11969
      } else {
11970
        return isAtStartOfBlock(root, pos, schema) || isBeforeBlock(root, pos, schema) || isAfterBr(root, pos, schema) || hasSpaceBefore(root, pos, schema) || isAfterCefBlock(root, pos);
11971
      }
11972
    };
11973
    const leanRight = pos => {
11974
      const container = pos.container();
11975
      const offset = pos.offset();
1441 ariadna 11976
      if (isText$b(container) && offset < container.data.length) {
1 efrain 11977
        return CaretPosition(container, offset + 1);
11978
      } else {
11979
        return pos;
11980
      }
11981
    };
11982
    const needsToBeNbspRight = (root, pos, schema) => {
11983
      if (isInPre(pos)) {
11984
        return false;
11985
      } else {
11986
        return isAtEndOfBlock(root, pos, schema) || isAfterBlock(root, pos, schema) || isBeforeBr$1(root, pos, schema) || hasSpaceAfter(root, pos, schema) || isBeforeCefBlock(root, pos);
11987
      }
11988
    };
11989
    const needsToBeNbsp = (root, pos, schema) => needsToBeNbspLeft(root, pos, schema) || needsToBeNbspRight(root, leanRight(pos), schema);
11990
    const isNbspAt = (text, offset) => isNbsp(text.charAt(offset));
11991
    const isWhiteSpaceAt = (text, offset) => isWhiteSpace(text.charAt(offset));
11992
    const hasNbsp = pos => {
11993
      const container = pos.container();
1441 ariadna 11994
      return isText$b(container) && contains$1(container.data, nbsp);
1 efrain 11995
    };
11996
    const normalizeNbspMiddle = text => {
11997
      const chars = text.split('');
11998
      return map$3(chars, (chr, i) => {
11999
        if (isNbsp(chr) && i > 0 && i < chars.length - 1 && isContent(chars[i - 1]) && isContent(chars[i + 1])) {
12000
          return ' ';
12001
        } else {
12002
          return chr;
12003
        }
12004
      }).join('');
12005
    };
12006
    const normalizeNbspAtStart = (root, node, makeNbsp, schema) => {
12007
      const text = node.data;
12008
      const firstPos = CaretPosition(node, 0);
12009
      if (!makeNbsp && isNbspAt(text, 0) && !needsToBeNbsp(root, firstPos, schema)) {
12010
        node.data = ' ' + text.slice(1);
12011
        return true;
12012
      } else if (makeNbsp && isWhiteSpaceAt(text, 0) && needsToBeNbspLeft(root, firstPos, schema)) {
12013
        node.data = nbsp + text.slice(1);
12014
        return true;
12015
      } else {
12016
        return false;
12017
      }
12018
    };
12019
    const normalizeNbspInMiddleOfTextNode = node => {
12020
      const text = node.data;
12021
      const newText = normalizeNbspMiddle(text);
12022
      if (newText !== text) {
12023
        node.data = newText;
12024
        return true;
12025
      } else {
12026
        return false;
12027
      }
12028
    };
12029
    const normalizeNbspAtEnd = (root, node, makeNbsp, schema) => {
12030
      const text = node.data;
12031
      const lastPos = CaretPosition(node, text.length - 1);
12032
      if (!makeNbsp && isNbspAt(text, text.length - 1) && !needsToBeNbsp(root, lastPos, schema)) {
12033
        node.data = text.slice(0, -1) + ' ';
12034
        return true;
12035
      } else if (makeNbsp && isWhiteSpaceAt(text, text.length - 1) && needsToBeNbspRight(root, lastPos, schema)) {
12036
        node.data = text.slice(0, -1) + nbsp;
12037
        return true;
12038
      } else {
12039
        return false;
12040
      }
12041
    };
1441 ariadna 12042
    const normalizeNbsps$1 = (root, pos, schema) => {
1 efrain 12043
      const container = pos.container();
1441 ariadna 12044
      if (!isText$b(container)) {
1 efrain 12045
        return Optional.none();
12046
      }
12047
      if (hasNbsp(pos)) {
12048
        const normalized = normalizeNbspAtStart(root, container, false, schema) || normalizeNbspInMiddleOfTextNode(container) || normalizeNbspAtEnd(root, container, false, schema);
12049
        return someIf(normalized, pos);
12050
      } else if (needsToBeNbsp(root, pos, schema)) {
12051
        const normalized = normalizeNbspAtStart(root, container, true, schema) || normalizeNbspAtEnd(root, container, true, schema);
12052
        return someIf(normalized, pos);
12053
      } else {
12054
        return Optional.none();
12055
      }
12056
    };
12057
    const normalizeNbspsInEditor = editor => {
12058
      const root = SugarElement.fromDom(editor.getBody());
12059
      if (editor.selection.isCollapsed()) {
1441 ariadna 12060
        normalizeNbsps$1(root, CaretPosition.fromRangeStart(editor.selection.getRng()), editor.schema).each(pos => {
1 efrain 12061
          editor.selection.setRng(pos.toRange());
12062
        });
12063
      }
12064
    };
12065
 
12066
    const normalize$1 = (node, offset, count, schema) => {
12067
      if (count === 0) {
12068
        return;
12069
      }
12070
      const elm = SugarElement.fromDom(node);
12071
      const root = ancestor$4(elm, el => schema.isBlock(name(el))).getOr(elm);
12072
      const whitespace = node.data.slice(offset, offset + count);
12073
      const isEndOfContent = offset + count >= node.data.length && needsToBeNbspRight(root, CaretPosition(node, node.data.length), schema);
12074
      const isStartOfContent = offset === 0 && needsToBeNbspLeft(root, CaretPosition(node, 0), schema);
12075
      node.replaceData(offset, count, normalize$4(whitespace, 4, isStartOfContent, isEndOfContent));
12076
    };
12077
    const normalizeWhitespaceAfter = (node, offset, schema) => {
12078
      const content = node.data.slice(offset);
12079
      const whitespaceCount = content.length - lTrim(content).length;
12080
      normalize$1(node, offset, whitespaceCount, schema);
12081
    };
12082
    const normalizeWhitespaceBefore = (node, offset, schema) => {
12083
      const content = node.data.slice(0, offset);
12084
      const whitespaceCount = content.length - rTrim(content).length;
12085
      normalize$1(node, offset - whitespaceCount, whitespaceCount, schema);
12086
    };
12087
    const mergeTextNodes = (prevNode, nextNode, schema, normalizeWhitespace, mergeToPrev = true) => {
12088
      const whitespaceOffset = rTrim(prevNode.data).length;
12089
      const newNode = mergeToPrev ? prevNode : nextNode;
12090
      const removeNode = mergeToPrev ? nextNode : prevNode;
12091
      if (mergeToPrev) {
12092
        newNode.appendData(removeNode.data);
12093
      } else {
12094
        newNode.insertData(0, removeNode.data);
12095
      }
1441 ariadna 12096
      remove$4(SugarElement.fromDom(removeNode));
1 efrain 12097
      if (normalizeWhitespace) {
12098
        normalizeWhitespaceAfter(newNode, whitespaceOffset, schema);
12099
      }
12100
      return newNode;
12101
    };
12102
 
12103
    const needsReposition = (pos, elm) => {
12104
      const container = pos.container();
12105
      const offset = pos.offset();
12106
      return !CaretPosition.isTextPosition(pos) && container === elm.parentNode && offset > CaretPosition.before(elm).offset();
12107
    };
12108
    const reposition = (elm, pos) => needsReposition(pos, elm) ? CaretPosition(pos.container(), pos.offset() - 1) : pos;
1441 ariadna 12109
    const beforeOrStartOf = node => isText$b(node) ? CaretPosition(node, 0) : CaretPosition.before(node);
12110
    const afterOrEndOf = node => isText$b(node) ? CaretPosition(node, node.data.length) : CaretPosition.after(node);
1 efrain 12111
    const getPreviousSiblingCaretPosition = elm => {
12112
      if (isCaretCandidate$3(elm.previousSibling)) {
12113
        return Optional.some(afterOrEndOf(elm.previousSibling));
12114
      } else {
12115
        return elm.previousSibling ? lastPositionIn(elm.previousSibling) : Optional.none();
12116
      }
12117
    };
12118
    const getNextSiblingCaretPosition = elm => {
12119
      if (isCaretCandidate$3(elm.nextSibling)) {
12120
        return Optional.some(beforeOrStartOf(elm.nextSibling));
12121
      } else {
12122
        return elm.nextSibling ? firstPositionIn(elm.nextSibling) : Optional.none();
12123
      }
12124
    };
12125
    const findCaretPositionBackwardsFromElm = (rootElement, elm) => {
12126
      return Optional.from(elm.previousSibling ? elm.previousSibling : elm.parentNode).bind(node => prevPosition(rootElement, CaretPosition.before(node))).orThunk(() => nextPosition(rootElement, CaretPosition.after(elm)));
12127
    };
12128
    const findCaretPositionForwardsFromElm = (rootElement, elm) => nextPosition(rootElement, CaretPosition.after(elm)).orThunk(() => prevPosition(rootElement, CaretPosition.before(elm)));
12129
    const findCaretPositionBackwards = (rootElement, elm) => getPreviousSiblingCaretPosition(elm).orThunk(() => getNextSiblingCaretPosition(elm)).orThunk(() => findCaretPositionBackwardsFromElm(rootElement, elm));
12130
    const findCaretPositionForward = (rootElement, elm) => getNextSiblingCaretPosition(elm).orThunk(() => getPreviousSiblingCaretPosition(elm)).orThunk(() => findCaretPositionForwardsFromElm(rootElement, elm));
12131
    const findCaretPosition = (forward, rootElement, elm) => forward ? findCaretPositionForward(rootElement, elm) : findCaretPositionBackwards(rootElement, elm);
12132
    const findCaretPosOutsideElmAfterDelete = (forward, rootElement, elm) => findCaretPosition(forward, rootElement, elm).map(curry(reposition, elm));
12133
    const setSelection$1 = (editor, forward, pos) => {
12134
      pos.fold(() => {
12135
        editor.focus();
12136
      }, pos => {
12137
        editor.selection.setRng(pos.toRange(), forward);
12138
      });
12139
    };
12140
    const eqRawNode = rawNode => elm => elm.dom === rawNode;
12141
    const isBlock = (editor, elm) => elm && has$2(editor.schema.getBlockElements(), name(elm));
1441 ariadna 12142
    const paddEmptyBlock = (schema, elm, preserveEmptyCaret) => {
12143
      if (isEmpty$2(schema, elm)) {
1 efrain 12144
        const br = SugarElement.fromHtml('<br data-mce-bogus="1">');
12145
        if (preserveEmptyCaret) {
12146
          each$e(children$1(elm), node => {
12147
            if (!isEmptyCaretFormatElement(node)) {
1441 ariadna 12148
              remove$4(node);
1 efrain 12149
            }
12150
          });
12151
        } else {
12152
          empty(elm);
12153
        }
12154
        append$1(elm, br);
12155
        return Optional.some(CaretPosition.before(br.dom));
12156
      } else {
12157
        return Optional.none();
12158
      }
12159
    };
12160
    const deleteNormalized = (elm, afterDeletePosOpt, schema, normalizeWhitespace) => {
1441 ariadna 12161
      const prevTextOpt = prevSibling(elm).filter(isText$c);
12162
      const nextTextOpt = nextSibling(elm).filter(isText$c);
12163
      remove$4(elm);
1 efrain 12164
      return lift3(prevTextOpt, nextTextOpt, afterDeletePosOpt, (prev, next, pos) => {
12165
        const prevNode = prev.dom, nextNode = next.dom;
12166
        const offset = prevNode.data.length;
12167
        mergeTextNodes(prevNode, nextNode, schema, normalizeWhitespace);
12168
        return pos.container() === nextNode ? CaretPosition(prevNode, offset) : pos;
12169
      }).orThunk(() => {
12170
        if (normalizeWhitespace) {
12171
          prevTextOpt.each(elm => normalizeWhitespaceBefore(elm.dom, elm.dom.length, schema));
12172
          nextTextOpt.each(elm => normalizeWhitespaceAfter(elm.dom, 0, schema));
12173
        }
12174
        return afterDeletePosOpt;
12175
      });
12176
    };
12177
    const isInlineElement = (editor, element) => has$2(editor.schema.getTextInlineElements(), name(element));
12178
    const deleteElement$2 = (editor, forward, elm, moveCaret = true, preserveEmptyCaret = false) => {
12179
      const afterDeletePos = findCaretPosOutsideElmAfterDelete(forward, editor.getBody(), elm.dom);
12180
      const parentBlock = ancestor$4(elm, curry(isBlock, editor), eqRawNode(editor.getBody()));
12181
      const normalizedAfterDeletePos = deleteNormalized(elm, afterDeletePos, editor.schema, isInlineElement(editor, elm));
12182
      if (editor.dom.isEmpty(editor.getBody())) {
12183
        editor.setContent('');
12184
        editor.selection.setCursorLocation();
12185
      } else {
1441 ariadna 12186
        parentBlock.bind(elm => paddEmptyBlock(editor.schema, elm, preserveEmptyCaret)).fold(() => {
1 efrain 12187
          if (moveCaret) {
12188
            setSelection$1(editor, forward, normalizedAfterDeletePos);
12189
          }
12190
        }, paddPos => {
12191
          if (moveCaret) {
12192
            setSelection$1(editor, forward, Optional.some(paddPos));
12193
          }
12194
        });
12195
      }
12196
    };
12197
 
12198
    const strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/;
12199
    const hasStrongRtl = text => strongRtl.test(text);
12200
 
12201
    const isInlineTarget = (editor, elm) => is$1(SugarElement.fromDom(elm), getInlineBoundarySelector(editor)) && !isTransparentBlock(editor.schema, elm) && editor.dom.isEditable(elm);
12202
    const isRtl = element => {
12203
      var _a;
12204
      return DOMUtils.DOM.getStyle(element, 'direction', true) === 'rtl' || hasStrongRtl((_a = element.textContent) !== null && _a !== void 0 ? _a : '');
12205
    };
12206
    const findInlineParents = (isInlineTarget, rootNode, pos) => filter$5(DOMUtils.DOM.getParents(pos.container(), '*', rootNode), isInlineTarget);
12207
    const findRootInline = (isInlineTarget, rootNode, pos) => {
12208
      const parents = findInlineParents(isInlineTarget, rootNode, pos);
12209
      return Optional.from(parents[parents.length - 1]);
12210
    };
12211
    const hasSameParentBlock = (rootNode, node1, node2) => {
12212
      const block1 = getParentBlock$3(node1, rootNode);
12213
      const block2 = getParentBlock$3(node2, rootNode);
12214
      return isNonNullable(block1) && block1 === block2;
12215
    };
12216
    const isAtZwsp = pos => isBeforeInline(pos) || isAfterInline(pos);
12217
    const normalizePosition = (forward, pos) => {
12218
      const container = pos.container(), offset = pos.offset();
12219
      if (forward) {
12220
        if (isCaretContainerInline(container)) {
1441 ariadna 12221
          if (isText$b(container.nextSibling)) {
1 efrain 12222
            return CaretPosition(container.nextSibling, 0);
12223
          } else {
12224
            return CaretPosition.after(container);
12225
          }
12226
        } else {
12227
          return isBeforeInline(pos) ? CaretPosition(container, offset + 1) : pos;
12228
        }
12229
      } else {
12230
        if (isCaretContainerInline(container)) {
1441 ariadna 12231
          if (isText$b(container.previousSibling)) {
1 efrain 12232
            return CaretPosition(container.previousSibling, container.previousSibling.data.length);
12233
          } else {
12234
            return CaretPosition.before(container);
12235
          }
12236
        } else {
12237
          return isAfterInline(pos) ? CaretPosition(container, offset - 1) : pos;
12238
        }
12239
      }
12240
    };
12241
    const normalizeForwards = curry(normalizePosition, true);
12242
    const normalizeBackwards = curry(normalizePosition, false);
12243
 
12244
    const execCommandIgnoreInputEvents = (editor, command) => {
12245
      const inputBlocker = e => e.stopImmediatePropagation();
12246
      editor.on('beforeinput input', inputBlocker, true);
12247
      editor.getDoc().execCommand(command);
12248
      editor.off('beforeinput input', inputBlocker);
12249
    };
12250
    const execEditorDeleteCommand = editor => {
12251
      editor.execCommand('delete');
12252
    };
12253
    const execNativeDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'Delete');
12254
    const execNativeForwardDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'ForwardDelete');
12255
    const isBeforeRoot = rootNode => elm => is$2(parent(elm), rootNode, eq);
12256
    const isTextBlockOrListItem = element => isTextBlock$2(element) || isListItem$1(element);
12257
    const getParentBlock$2 = (rootNode, elm) => {
12258
      if (contains(rootNode, elm)) {
12259
        return closest$4(elm, isTextBlockOrListItem, isBeforeRoot(rootNode));
12260
      } else {
12261
        return Optional.none();
12262
      }
12263
    };
12264
    const paddEmptyBody = (editor, moveSelection = true) => {
12265
      if (editor.dom.isEmpty(editor.getBody())) {
12266
        editor.setContent('', { no_selection: !moveSelection });
12267
      }
12268
    };
12269
    const willDeleteLastPositionInElement = (forward, fromPos, elm) => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
12270
      const normalizedFirstPos = normalizePosition(true, firstPos);
12271
      const normalizedLastPos = normalizePosition(false, lastPos);
12272
      const normalizedFromPos = normalizePosition(false, fromPos);
12273
      if (forward) {
12274
        return nextPosition(elm, normalizedFromPos).exists(nextPos => nextPos.isEqual(normalizedLastPos) && fromPos.isEqual(normalizedFirstPos));
12275
      } else {
12276
        return prevPosition(elm, normalizedFromPos).exists(prevPos => prevPos.isEqual(normalizedFirstPos) && fromPos.isEqual(normalizedLastPos));
12277
      }
12278
    }).getOr(true);
12279
    const freefallRtl = root => {
12280
      const child = isComment$1(root) ? prevSibling(root) : lastChild(root);
12281
      return child.bind(freefallRtl).orThunk(() => Optional.some(root));
12282
    };
12283
    const deleteRangeContents = (editor, rng, root, moveSelection = true) => {
12284
      var _a;
12285
      rng.deleteContents();
12286
      const lastNode = freefallRtl(root).getOr(root);
12287
      const lastBlock = SugarElement.fromDom((_a = editor.dom.getParent(lastNode.dom, editor.dom.isBlock)) !== null && _a !== void 0 ? _a : root.dom);
12288
      if (lastBlock.dom === editor.getBody()) {
12289
        paddEmptyBody(editor, moveSelection);
1441 ariadna 12290
      } else if (isEmpty$2(editor.schema, lastBlock, { checkRootAsContent: false })) {
1 efrain 12291
        fillWithPaddingBr(lastBlock);
12292
        if (moveSelection) {
12293
          editor.selection.setCursorLocation(lastBlock.dom, 0);
12294
        }
12295
      }
12296
      if (!eq(root, lastBlock)) {
12297
        const additionalCleanupNodes = is$2(parent(lastBlock), root) ? [] : siblings(lastBlock);
12298
        each$e(additionalCleanupNodes.concat(children$1(root)), node => {
1441 ariadna 12299
          if (!eq(node, lastBlock) && !contains(node, lastBlock) && isEmpty$2(editor.schema, node)) {
12300
            remove$4(node);
1 efrain 12301
          }
12302
        });
12303
      }
12304
    };
12305
 
12306
    const isRootFromElement = root => cur => eq(root, cur);
12307
    const getTableCells = table => descendants(table, 'td,th');
12308
    const getTable$1 = (node, isRoot) => getClosestTable(SugarElement.fromDom(node), isRoot);
12309
    const selectionInTableWithNestedTable = details => {
12310
      return lift2(details.startTable, details.endTable, (startTable, endTable) => {
12311
        const isStartTableParentOfEndTable = descendant(startTable, t => eq(t, endTable));
12312
        const isEndTableParentOfStartTable = descendant(endTable, t => eq(t, startTable));
12313
        return !isStartTableParentOfEndTable && !isEndTableParentOfStartTable ? details : {
12314
          ...details,
12315
          startTable: isStartTableParentOfEndTable ? Optional.none() : details.startTable,
12316
          endTable: isEndTableParentOfStartTable ? Optional.none() : details.endTable,
12317
          isSameTable: false,
12318
          isMultiTable: false
12319
        };
12320
      }).getOr(details);
12321
    };
12322
    const adjustQuirksInDetails = details => {
12323
      return selectionInTableWithNestedTable(details);
12324
    };
12325
    const getTableDetailsFromRange = (rng, isRoot) => {
12326
      const startTable = getTable$1(rng.startContainer, isRoot);
12327
      const endTable = getTable$1(rng.endContainer, isRoot);
12328
      const isStartInTable = startTable.isSome();
12329
      const isEndInTable = endTable.isSome();
12330
      const isSameTable = lift2(startTable, endTable, eq).getOr(false);
12331
      const isMultiTable = !isSameTable && isStartInTable && isEndInTable;
12332
      return adjustQuirksInDetails({
12333
        startTable,
12334
        endTable,
12335
        isStartInTable,
12336
        isEndInTable,
12337
        isSameTable,
12338
        isMultiTable
12339
      });
12340
    };
12341
 
12342
    const tableCellRng = (start, end) => ({
12343
      start,
12344
      end
12345
    });
12346
    const tableSelection = (rng, table, cells) => ({
12347
      rng,
12348
      table,
12349
      cells
12350
    });
12351
    const deleteAction = Adt.generate([
12352
      {
12353
        singleCellTable: [
12354
          'rng',
12355
          'cell'
12356
        ]
12357
      },
12358
      { fullTable: ['table'] },
12359
      {
12360
        partialTable: [
12361
          'cells',
12362
          'outsideDetails'
12363
        ]
12364
      },
12365
      {
12366
        multiTable: [
12367
          'startTableCells',
12368
          'endTableCells',
12369
          'betweenRng'
12370
        ]
12371
      }
12372
    ]);
12373
    const getClosestCell$1 = (container, isRoot) => closest$3(SugarElement.fromDom(container), 'td,th', isRoot);
12374
    const isExpandedCellRng = cellRng => !eq(cellRng.start, cellRng.end);
12375
    const getTableFromCellRng = (cellRng, isRoot) => getClosestTable(cellRng.start, isRoot).bind(startParentTable => getClosestTable(cellRng.end, isRoot).bind(endParentTable => someIf(eq(startParentTable, endParentTable), startParentTable)));
12376
    const isSingleCellTable = (cellRng, isRoot) => !isExpandedCellRng(cellRng) && getTableFromCellRng(cellRng, isRoot).exists(table => {
12377
      const rows = table.dom.rows;
12378
      return rows.length === 1 && rows[0].cells.length === 1;
12379
    });
12380
    const getCellRng = (rng, isRoot) => {
12381
      const startCell = getClosestCell$1(rng.startContainer, isRoot);
12382
      const endCell = getClosestCell$1(rng.endContainer, isRoot);
12383
      return lift2(startCell, endCell, tableCellRng);
12384
    };
1441 ariadna 12385
    const getCellRangeFromStartTable = isRoot => startCell => getClosestTable(startCell, isRoot).bind(table => last$2(getTableCells(table)).map(endCell => tableCellRng(startCell, endCell)));
1 efrain 12386
    const getCellRangeFromEndTable = isRoot => endCell => getClosestTable(endCell, isRoot).bind(table => head(getTableCells(table)).map(startCell => tableCellRng(startCell, endCell)));
12387
    const getTableSelectionFromCellRng = isRoot => cellRng => getTableFromCellRng(cellRng, isRoot).map(table => tableSelection(cellRng, table, getTableCells(table)));
12388
    const getTableSelections = (cellRng, selectionDetails, rng, isRoot) => {
12389
      if (rng.collapsed || !cellRng.forall(isExpandedCellRng)) {
12390
        return Optional.none();
12391
      } else if (selectionDetails.isSameTable) {
12392
        const sameTableSelection = cellRng.bind(getTableSelectionFromCellRng(isRoot));
12393
        return Optional.some({
12394
          start: sameTableSelection,
12395
          end: sameTableSelection
12396
        });
12397
      } else {
12398
        const startCell = getClosestCell$1(rng.startContainer, isRoot);
12399
        const endCell = getClosestCell$1(rng.endContainer, isRoot);
12400
        const startTableSelection = startCell.bind(getCellRangeFromStartTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
12401
        const endTableSelection = endCell.bind(getCellRangeFromEndTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
12402
        return Optional.some({
12403
          start: startTableSelection,
12404
          end: endTableSelection
12405
        });
12406
      }
12407
    };
12408
    const getCellIndex = (cells, cell) => findIndex$2(cells, x => eq(x, cell));
12409
    const getSelectedCells = tableSelection => lift2(getCellIndex(tableSelection.cells, tableSelection.rng.start), getCellIndex(tableSelection.cells, tableSelection.rng.end), (startIndex, endIndex) => tableSelection.cells.slice(startIndex, endIndex + 1));
12410
    const isSingleCellTableContentSelected = (optCellRng, rng, isRoot) => optCellRng.exists(cellRng => isSingleCellTable(cellRng, isRoot) && hasAllContentsSelected(cellRng.start, rng));
12411
    const unselectCells = (rng, selectionDetails) => {
12412
      const {startTable, endTable} = selectionDetails;
12413
      const otherContentRng = rng.cloneRange();
12414
      startTable.each(table => otherContentRng.setStartAfter(table.dom));
12415
      endTable.each(table => otherContentRng.setEndBefore(table.dom));
12416
      return otherContentRng;
12417
    };
12418
    const handleSingleTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => start.or(end)).bind(tableSelection => {
12419
      const {isSameTable} = selectionDetails;
12420
      const selectedCells = getSelectedCells(tableSelection).getOr([]);
12421
      if (isSameTable && tableSelection.cells.length === selectedCells.length) {
12422
        return Optional.some(deleteAction.fullTable(tableSelection.table));
12423
      } else if (selectedCells.length > 0) {
12424
        if (isSameTable) {
12425
          return Optional.some(deleteAction.partialTable(selectedCells, Optional.none()));
12426
        } else {
12427
          const otherContentRng = unselectCells(rng, selectionDetails);
12428
          return Optional.some(deleteAction.partialTable(selectedCells, Optional.some({
12429
            ...selectionDetails,
12430
            rng: otherContentRng
12431
          })));
12432
        }
12433
      } else {
12434
        return Optional.none();
12435
      }
12436
    });
12437
    const handleMultiTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => {
12438
      const startTableSelectedCells = start.bind(getSelectedCells).getOr([]);
12439
      const endTableSelectedCells = end.bind(getSelectedCells).getOr([]);
12440
      if (startTableSelectedCells.length > 0 && endTableSelectedCells.length > 0) {
12441
        const otherContentRng = unselectCells(rng, selectionDetails);
12442
        return Optional.some(deleteAction.multiTable(startTableSelectedCells, endTableSelectedCells, otherContentRng));
12443
      } else {
12444
        return Optional.none();
12445
      }
12446
    });
12447
    const getActionFromRange = (root, rng) => {
12448
      const isRoot = isRootFromElement(root);
12449
      const optCellRng = getCellRng(rng, isRoot);
12450
      const selectionDetails = getTableDetailsFromRange(rng, isRoot);
12451
      if (isSingleCellTableContentSelected(optCellRng, rng, isRoot)) {
12452
        return optCellRng.map(cellRng => deleteAction.singleCellTable(rng, cellRng.start));
12453
      } else if (selectionDetails.isMultiTable) {
12454
        return handleMultiTable(optCellRng, selectionDetails, rng, isRoot);
12455
      } else {
12456
        return handleSingleTable(optCellRng, selectionDetails, rng, isRoot);
12457
      }
12458
    };
12459
 
12460
    const cleanCells = cells => each$e(cells, cell => {
1441 ariadna 12461
      remove$9(cell, 'contenteditable');
1 efrain 12462
      fillWithPaddingBr(cell);
12463
    });
12464
    const getOutsideBlock = (editor, container) => Optional.from(editor.dom.getParent(container, editor.dom.isBlock)).map(SugarElement.fromDom);
12465
    const handleEmptyBlock = (editor, startInTable, emptyBlock) => {
12466
      emptyBlock.each(block => {
12467
        if (startInTable) {
1441 ariadna 12468
          remove$4(block);
1 efrain 12469
        } else {
12470
          fillWithPaddingBr(block);
12471
          editor.selection.setCursorLocation(block.dom, 0);
12472
        }
12473
      });
12474
    };
12475
    const deleteContentInsideCell = (editor, cell, rng, isFirstCellInSelection) => {
12476
      const insideTableRng = rng.cloneRange();
12477
      if (isFirstCellInSelection) {
12478
        insideTableRng.setStart(rng.startContainer, rng.startOffset);
12479
        insideTableRng.setEndAfter(cell.dom.lastChild);
12480
      } else {
12481
        insideTableRng.setStartBefore(cell.dom.firstChild);
12482
        insideTableRng.setEnd(rng.endContainer, rng.endOffset);
12483
      }
12484
      deleteCellContents(editor, insideTableRng, cell, false).each(action => action());
12485
    };
12486
    const collapseAndRestoreCellSelection = editor => {
12487
      const selectedCells = getCellsFromEditor(editor);
12488
      const selectedNode = SugarElement.fromDom(editor.selection.getNode());
1441 ariadna 12489
      if (isTableCell$3(selectedNode.dom) && isEmpty$2(editor.schema, selectedNode)) {
1 efrain 12490
        editor.selection.setCursorLocation(selectedNode.dom, 0);
12491
      } else {
12492
        editor.selection.collapse(true);
12493
      }
12494
      if (selectedCells.length > 1 && exists(selectedCells, cell => eq(cell, selectedNode))) {
1441 ariadna 12495
        set$4(selectedNode, 'data-mce-selected', '1');
1 efrain 12496
      }
12497
    };
12498
    const emptySingleTableCells = (editor, cells, outsideDetails) => Optional.some(() => {
12499
      const editorRng = editor.selection.getRng();
12500
      const cellsToClean = outsideDetails.bind(({rng, isStartInTable}) => {
12501
        const outsideBlock = getOutsideBlock(editor, isStartInTable ? rng.endContainer : rng.startContainer);
12502
        rng.deleteContents();
1441 ariadna 12503
        handleEmptyBlock(editor, isStartInTable, outsideBlock.filter(curry(isEmpty$2, editor.schema)));
1 efrain 12504
        const endPointCell = isStartInTable ? cells[0] : cells[cells.length - 1];
12505
        deleteContentInsideCell(editor, endPointCell, editorRng, isStartInTable);
1441 ariadna 12506
        if (!isEmpty$2(editor.schema, endPointCell)) {
1 efrain 12507
          return Optional.some(isStartInTable ? cells.slice(1) : cells.slice(0, -1));
12508
        } else {
12509
          return Optional.none();
12510
        }
12511
      }).getOr(cells);
12512
      cleanCells(cellsToClean);
12513
      collapseAndRestoreCellSelection(editor);
12514
    });
12515
    const emptyMultiTableCells = (editor, startTableCells, endTableCells, betweenRng) => Optional.some(() => {
12516
      const rng = editor.selection.getRng();
12517
      const startCell = startTableCells[0];
12518
      const endCell = endTableCells[endTableCells.length - 1];
12519
      deleteContentInsideCell(editor, startCell, rng, true);
12520
      deleteContentInsideCell(editor, endCell, rng, false);
1441 ariadna 12521
      const startTableCellsToClean = isEmpty$2(editor.schema, startCell) ? startTableCells : startTableCells.slice(1);
12522
      const endTableCellsToClean = isEmpty$2(editor.schema, endCell) ? endTableCells : endTableCells.slice(0, -1);
1 efrain 12523
      cleanCells(startTableCellsToClean.concat(endTableCellsToClean));
12524
      betweenRng.deleteContents();
12525
      collapseAndRestoreCellSelection(editor);
12526
    });
12527
    const deleteCellContents = (editor, rng, cell, moveSelection = true) => Optional.some(() => {
12528
      deleteRangeContents(editor, rng, cell, moveSelection);
12529
    });
12530
    const deleteTableElement = (editor, table) => Optional.some(() => deleteElement$2(editor, false, table));
12531
    const deleteCellRange = (editor, rootElm, rng) => getActionFromRange(rootElm, rng).bind(action => action.fold(curry(deleteCellContents, editor), curry(deleteTableElement, editor), curry(emptySingleTableCells, editor), curry(emptyMultiTableCells, editor)));
12532
    const deleteCaptionRange = (editor, caption) => emptyElement(editor, caption);
12533
    const deleteTableRange = (editor, rootElm, rng, startElm) => getParentCaption(rootElm, startElm).fold(() => deleteCellRange(editor, rootElm, rng), caption => deleteCaptionRange(editor, caption));
12534
    const deleteRange$3 = (editor, startElm, selectedCells) => {
12535
      const rootNode = SugarElement.fromDom(editor.getBody());
12536
      const rng = editor.selection.getRng();
12537
      return selectedCells.length !== 0 ? emptySingleTableCells(editor, selectedCells, Optional.none()) : deleteTableRange(editor, rootNode, rng, startElm);
12538
    };
12539
    const getParentCell = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTableCell$2);
12540
    const getParentCaption = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTag('caption'));
12541
    const deleteBetweenCells = (editor, rootElm, forward, fromCell, from) => navigate(forward, editor.getBody(), from).bind(to => getParentCell(rootElm, SugarElement.fromDom(to.getNode())).bind(toCell => eq(toCell, fromCell) ? Optional.none() : Optional.some(noop)));
12542
    const emptyElement = (editor, elm) => Optional.some(() => {
12543
      fillWithPaddingBr(elm);
12544
      editor.selection.setCursorLocation(elm.dom, 0);
12545
    });
12546
    const isDeleteOfLastCharPos = (fromCaption, forward, from, to) => firstPositionIn(fromCaption.dom).bind(first => lastPositionIn(fromCaption.dom).map(last => forward ? from.isEqual(first) && to.isEqual(last) : from.isEqual(last) && to.isEqual(first))).getOr(true);
12547
    const emptyCaretCaption = (editor, elm) => emptyElement(editor, elm);
12548
    const validateCaretCaption = (rootElm, fromCaption, to) => getParentCaption(rootElm, SugarElement.fromDom(to.getNode())).fold(() => Optional.some(noop), toCaption => someIf(!eq(toCaption, fromCaption), noop));
12549
    const deleteCaretInsideCaption = (editor, rootElm, forward, fromCaption, from) => navigate(forward, editor.getBody(), from).fold(() => Optional.some(noop), to => isDeleteOfLastCharPos(fromCaption, forward, from, to) ? emptyCaretCaption(editor, fromCaption) : validateCaretCaption(rootElm, fromCaption, to));
12550
    const deleteCaretCells = (editor, forward, rootElm, startElm) => {
12551
      const from = CaretPosition.fromRangeStart(editor.selection.getRng());
1441 ariadna 12552
      return getParentCell(rootElm, startElm).bind(fromCell => isEmpty$2(editor.schema, fromCell, { checkRootAsContent: false }) ? emptyElement(editor, fromCell) : deleteBetweenCells(editor, rootElm, forward, fromCell, from));
1 efrain 12553
    };
12554
    const deleteCaretCaption = (editor, forward, rootElm, fromCaption) => {
12555
      const from = CaretPosition.fromRangeStart(editor.selection.getRng());
1441 ariadna 12556
      return isEmpty$2(editor.schema, fromCaption) ? emptyElement(editor, fromCaption) : deleteCaretInsideCaption(editor, rootElm, forward, fromCaption, from);
1 efrain 12557
    };
12558
    const isNearTable = (forward, pos) => forward ? isBeforeTable(pos) : isAfterTable(pos);
12559
    const isBeforeOrAfterTable = (editor, forward) => {
12560
      const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
12561
      return isNearTable(forward, fromPos) || fromPosition(forward, editor.getBody(), fromPos).exists(pos => isNearTable(forward, pos));
12562
    };
12563
    const deleteCaret$3 = (editor, forward, startElm) => {
12564
      const rootElm = SugarElement.fromDom(editor.getBody());
12565
      return getParentCaption(rootElm, startElm).fold(() => deleteCaretCells(editor, forward, rootElm, startElm).orThunk(() => someIf(isBeforeOrAfterTable(editor, forward), noop)), fromCaption => deleteCaretCaption(editor, forward, rootElm, fromCaption));
12566
    };
1441 ariadna 12567
    const backspaceDelete$b = (editor, forward) => {
1 efrain 12568
      const startElm = SugarElement.fromDom(editor.selection.getStart(true));
12569
      const cells = getCellsFromEditor(editor);
12570
      return editor.selection.isCollapsed() && cells.length === 0 ? deleteCaret$3(editor, forward, startElm) : deleteRange$3(editor, startElm, cells);
12571
    };
12572
 
12573
    const getContentEditableRoot$1 = (root, node) => {
12574
      let tempNode = node;
12575
      while (tempNode && tempNode !== root) {
12576
        if (isContentEditableTrue$3(tempNode) || isContentEditableFalse$b(tempNode)) {
12577
          return tempNode;
12578
        }
12579
        tempNode = tempNode.parentNode;
12580
      }
12581
      return null;
12582
    };
12583
 
12584
    const internalAttributesPrefixes = [
12585
      'data-ephox-',
12586
      'data-mce-',
12587
      'data-alloy-',
12588
      'data-snooker-',
12589
      '_'
12590
    ];
12591
    const each$9 = Tools.each;
12592
    const ElementUtils = editor => {
12593
      const dom = editor.dom;
12594
      const internalAttributes = new Set(editor.serializer.getTempAttrs());
12595
      const compare = (node1, node2) => {
12596
        if (node1.nodeName !== node2.nodeName || node1.nodeType !== node2.nodeType) {
12597
          return false;
12598
        }
12599
        const getAttribs = node => {
12600
          const attribs = {};
12601
          each$9(dom.getAttribs(node), attr => {
12602
            const name = attr.nodeName.toLowerCase();
12603
            if (name !== 'style' && !isAttributeInternal(name)) {
12604
              attribs[name] = dom.getAttrib(node, name);
12605
            }
12606
          });
12607
          return attribs;
12608
        };
12609
        const compareObjects = (obj1, obj2) => {
12610
          for (const name in obj1) {
12611
            if (has$2(obj1, name)) {
12612
              const value = obj2[name];
12613
              if (isUndefined(value)) {
12614
                return false;
12615
              }
12616
              if (obj1[name] !== value) {
12617
                return false;
12618
              }
12619
              delete obj2[name];
12620
            }
12621
          }
12622
          for (const name in obj2) {
12623
            if (has$2(obj2, name)) {
12624
              return false;
12625
            }
12626
          }
12627
          return true;
12628
        };
12629
        if (isElement$6(node1) && isElement$6(node2)) {
12630
          if (!compareObjects(getAttribs(node1), getAttribs(node2))) {
12631
            return false;
12632
          }
12633
          if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style')))) {
12634
            return false;
12635
          }
12636
        }
12637
        return !isBookmarkNode$1(node1) && !isBookmarkNode$1(node2);
12638
      };
12639
      const isAttributeInternal = attributeName => exists(internalAttributesPrefixes, value => startsWith(attributeName, value)) || internalAttributes.has(attributeName);
12640
      return {
12641
        compare,
12642
        isAttributeInternal
12643
      };
12644
    };
12645
 
12646
    const isHeading = node => [
12647
      'h1',
12648
      'h2',
12649
      'h3',
12650
      'h4',
12651
      'h5',
12652
      'h6'
12653
    ].includes(node.name);
12654
    const isSummary = node => node.name === 'summary';
12655
 
12656
    const traverse = (root, fn) => {
12657
      let node = root;
12658
      while (node = node.walk()) {
12659
        fn(node);
12660
      }
12661
    };
12662
    const matchNode$1 = (nodeFilters, attributeFilters, node, matches) => {
12663
      const name = node.name;
12664
      for (let ni = 0, nl = nodeFilters.length; ni < nl; ni++) {
12665
        const filter = nodeFilters[ni];
12666
        if (filter.name === name) {
12667
          const match = matches.nodes[name];
12668
          if (match) {
12669
            match.nodes.push(node);
12670
          } else {
12671
            matches.nodes[name] = {
12672
              filter,
12673
              nodes: [node]
12674
            };
12675
          }
12676
        }
12677
      }
12678
      if (node.attributes) {
12679
        for (let ai = 0, al = attributeFilters.length; ai < al; ai++) {
12680
          const filter = attributeFilters[ai];
12681
          const attrName = filter.name;
12682
          if (attrName in node.attributes.map) {
12683
            const match = matches.attributes[attrName];
12684
            if (match) {
12685
              match.nodes.push(node);
12686
            } else {
12687
              matches.attributes[attrName] = {
12688
                filter,
12689
                nodes: [node]
12690
              };
12691
            }
12692
          }
12693
        }
12694
      }
12695
    };
12696
    const findMatchingNodes = (nodeFilters, attributeFilters, node) => {
12697
      const matches = {
12698
        nodes: {},
12699
        attributes: {}
12700
      };
12701
      if (node.firstChild) {
12702
        traverse(node, childNode => {
12703
          matchNode$1(nodeFilters, attributeFilters, childNode, matches);
12704
        });
12705
      }
12706
      return matches;
12707
    };
12708
    const runFilters = (matches, args) => {
12709
      const run = (matchRecord, filteringAttributes) => {
12710
        each$d(matchRecord, match => {
12711
          const nodes = from(match.nodes);
12712
          each$e(match.filter.callbacks, callback => {
12713
            for (let i = nodes.length - 1; i >= 0; i--) {
12714
              const node = nodes[i];
12715
              const valueMatches = filteringAttributes ? node.attr(match.filter.name) !== undefined : node.name === match.filter.name;
12716
              if (!valueMatches || isNullable(node.parent)) {
12717
                nodes.splice(i, 1);
12718
              }
12719
            }
12720
            if (nodes.length > 0) {
12721
              callback(nodes, match.filter.name, args);
12722
            }
12723
          });
12724
        });
12725
      };
12726
      run(matches.nodes, false);
12727
      run(matches.attributes, true);
12728
    };
12729
    const filter$2 = (nodeFilters, attributeFilters, node, args = {}) => {
12730
      const matches = findMatchingNodes(nodeFilters, attributeFilters, node);
12731
      runFilters(matches, args);
12732
    };
12733
 
12734
    const paddEmptyNode = (settings, args, isBlock, node) => {
12735
      const brPreferred = settings.pad_empty_with_br || args.insert;
12736
      if (brPreferred && isBlock(node)) {
12737
        const astNode = new AstNode('br', 1);
12738
        if (args.insert) {
12739
          astNode.attr('data-mce-bogus', '1');
12740
        }
12741
        node.empty().append(astNode);
12742
      } else {
12743
        node.empty().append(new AstNode('#text', 3)).value = nbsp;
12744
      }
12745
    };
12746
    const isPaddedWithNbsp = node => {
12747
      var _a;
12748
      return hasOnlyChild(node, '#text') && ((_a = node === null || node === void 0 ? void 0 : node.firstChild) === null || _a === void 0 ? void 0 : _a.value) === nbsp;
12749
    };
12750
    const hasOnlyChild = (node, name) => {
12751
      const firstChild = node === null || node === void 0 ? void 0 : node.firstChild;
12752
      return isNonNullable(firstChild) && firstChild === node.lastChild && firstChild.name === name;
12753
    };
12754
    const isPadded = (schema, node) => {
12755
      const rule = schema.getElementRule(node.name);
12756
      return (rule === null || rule === void 0 ? void 0 : rule.paddEmpty) === true;
12757
    };
12758
    const isEmpty = (schema, nonEmptyElements, whitespaceElements, node) => node.isEmpty(nonEmptyElements, whitespaceElements, node => isPadded(schema, node));
12759
    const isLineBreakNode = (node, isBlock) => isNonNullable(node) && (isBlock(node) || node.name === 'br');
12760
    const findClosestEditingHost = scope => {
12761
      let editableNode;
12762
      for (let node = scope; node; node = node.parent) {
12763
        const contentEditable = node.attr('contenteditable');
12764
        if (contentEditable === 'false') {
12765
          break;
12766
        } else if (contentEditable === 'true') {
12767
          editableNode = node;
12768
        }
12769
      }
12770
      return Optional.from(editableNode);
12771
    };
12772
 
12773
    const removeOrUnwrapInvalidNode = (node, schema, originalNodeParent = node.parent) => {
12774
      if (schema.getSpecialElements()[node.name]) {
12775
        node.empty().remove();
12776
      } else {
12777
        const children = node.children();
12778
        for (const childNode of children) {
12779
          if (originalNodeParent && !schema.isValidChild(originalNodeParent.name, childNode.name)) {
12780
            removeOrUnwrapInvalidNode(childNode, schema, originalNodeParent);
12781
          }
12782
        }
12783
        node.unwrap();
12784
      }
12785
    };
12786
    const cleanInvalidNodes = (nodes, schema, rootNode, onCreate = noop) => {
12787
      const textBlockElements = schema.getTextBlockElements();
12788
      const nonEmptyElements = schema.getNonEmptyElements();
12789
      const whitespaceElements = schema.getWhitespaceElements();
12790
      const nonSplittableElements = Tools.makeMap('tr,td,th,tbody,thead,tfoot,table,summary');
12791
      const fixed = new Set();
12792
      const isSplittableElement = node => node !== rootNode && !nonSplittableElements[node.name];
12793
      for (let ni = 0; ni < nodes.length; ni++) {
12794
        const node = nodes[ni];
12795
        let parent;
12796
        let newParent;
12797
        let tempNode;
12798
        if (!node.parent || fixed.has(node)) {
12799
          continue;
12800
        }
12801
        if (textBlockElements[node.name] && node.parent.name === 'li') {
12802
          let sibling = node.next;
12803
          while (sibling) {
12804
            if (textBlockElements[sibling.name]) {
12805
              sibling.name = 'li';
12806
              fixed.add(sibling);
12807
              node.parent.insert(sibling, node.parent);
12808
            } else {
12809
              break;
12810
            }
12811
            sibling = sibling.next;
12812
          }
12813
          node.unwrap();
12814
          continue;
12815
        }
12816
        const parents = [node];
12817
        for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && isSplittableElement(parent); parent = parent.parent) {
12818
          parents.push(parent);
12819
        }
12820
        if (parent && parents.length > 1) {
12821
          if (!isInvalid(schema, node, parent)) {
12822
            parents.reverse();
12823
            newParent = parents[0].clone();
12824
            onCreate(newParent);
12825
            let currentNode = newParent;
12826
            for (let i = 0; i < parents.length - 1; i++) {
12827
              if (schema.isValidChild(currentNode.name, parents[i].name) && i > 0) {
12828
                tempNode = parents[i].clone();
12829
                onCreate(tempNode);
12830
                currentNode.append(tempNode);
12831
              } else {
12832
                tempNode = currentNode;
12833
              }
12834
              for (let childNode = parents[i].firstChild; childNode && childNode !== parents[i + 1];) {
12835
                const nextNode = childNode.next;
12836
                tempNode.append(childNode);
12837
                childNode = nextNode;
12838
              }
12839
              currentNode = tempNode;
12840
            }
12841
            if (!isEmpty(schema, nonEmptyElements, whitespaceElements, newParent)) {
12842
              parent.insert(newParent, parents[0], true);
12843
              parent.insert(node, newParent);
12844
            } else {
12845
              parent.insert(node, parents[0], true);
12846
            }
12847
            parent = parents[0];
12848
            if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent) || hasOnlyChild(parent, 'br')) {
12849
              parent.empty().remove();
12850
            }
12851
          } else {
12852
            removeOrUnwrapInvalidNode(node, schema);
12853
          }
12854
        } else if (node.parent) {
12855
          if (node.name === 'li') {
12856
            let sibling = node.prev;
12857
            if (sibling && (sibling.name === 'ul' || sibling.name === 'ol')) {
12858
              sibling.append(node);
12859
              continue;
12860
            }
12861
            sibling = node.next;
12862
            if (sibling && (sibling.name === 'ul' || sibling.name === 'ol') && sibling.firstChild) {
12863
              sibling.insert(node, sibling.firstChild, true);
12864
              continue;
12865
            }
12866
            const wrapper = new AstNode('ul', 1);
12867
            onCreate(wrapper);
12868
            node.wrap(wrapper);
12869
            continue;
12870
          }
12871
          if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) {
12872
            const wrapper = new AstNode('div', 1);
12873
            onCreate(wrapper);
12874
            node.wrap(wrapper);
12875
          } else {
12876
            removeOrUnwrapInvalidNode(node, schema);
12877
          }
12878
        }
12879
      }
12880
    };
12881
    const hasClosest = (node, parentName) => {
12882
      let tempNode = node;
12883
      while (tempNode) {
12884
        if (tempNode.name === parentName) {
12885
          return true;
12886
        }
12887
        tempNode = tempNode.parent;
12888
      }
12889
      return false;
12890
    };
12891
    const isInvalid = (schema, node, parent = node.parent) => {
12892
      if (!parent) {
12893
        return false;
12894
      }
12895
      if (schema.children[node.name] && !schema.isValidChild(parent.name, node.name)) {
12896
        return true;
12897
      }
12898
      if (node.name === 'a' && hasClosest(parent, 'a')) {
12899
        return true;
12900
      }
12901
      if (isSummary(parent) && isHeading(node)) {
12902
        return !((parent === null || parent === void 0 ? void 0 : parent.firstChild) === node && (parent === null || parent === void 0 ? void 0 : parent.lastChild) === node);
12903
      }
12904
      return false;
12905
    };
12906
 
12907
    const createRange = (sc, so, ec, eo) => {
12908
      const rng = document.createRange();
12909
      rng.setStart(sc, so);
12910
      rng.setEnd(ec, eo);
12911
      return rng;
12912
    };
12913
    const normalizeBlockSelectionRange = rng => {
12914
      const startPos = CaretPosition.fromRangeStart(rng);
12915
      const endPos = CaretPosition.fromRangeEnd(rng);
12916
      const rootNode = rng.commonAncestorContainer;
12917
      return fromPosition(false, rootNode, endPos).map(newEndPos => {
12918
        if (!isInSameBlock(startPos, endPos, rootNode) && isInSameBlock(startPos, newEndPos, rootNode)) {
12919
          return createRange(startPos.container(), startPos.offset(), newEndPos.container(), newEndPos.offset());
12920
        } else {
12921
          return rng;
12922
        }
12923
      }).getOr(rng);
12924
    };
12925
    const normalize = rng => rng.collapsed ? rng : normalizeBlockSelectionRange(rng);
12926
 
12927
    const hasOnlyOneChild$1 = node => {
12928
      return isNonNullable(node.firstChild) && node.firstChild === node.lastChild;
12929
    };
12930
    const isPaddingNode = node => {
12931
      return node.name === 'br' || node.value === nbsp;
12932
    };
12933
    const isPaddedEmptyBlock = (schema, node) => {
12934
      const blockElements = schema.getBlockElements();
12935
      return blockElements[node.name] && hasOnlyOneChild$1(node) && isPaddingNode(node.firstChild);
12936
    };
12937
    const isEmptyFragmentElement = (schema, node) => {
12938
      const nonEmptyElements = schema.getNonEmptyElements();
12939
      return isNonNullable(node) && (node.isEmpty(nonEmptyElements) || isPaddedEmptyBlock(schema, node));
12940
    };
12941
    const isListFragment = (schema, fragment) => {
12942
      let firstChild = fragment.firstChild;
12943
      let lastChild = fragment.lastChild;
12944
      if (firstChild && firstChild.name === 'meta') {
12945
        firstChild = firstChild.next;
12946
      }
12947
      if (lastChild && lastChild.attr('id') === 'mce_marker') {
12948
        lastChild = lastChild.prev;
12949
      }
12950
      if (isEmptyFragmentElement(schema, lastChild)) {
12951
        lastChild = lastChild === null || lastChild === void 0 ? void 0 : lastChild.prev;
12952
      }
12953
      if (!firstChild || firstChild !== lastChild) {
12954
        return false;
12955
      }
12956
      return firstChild.name === 'ul' || firstChild.name === 'ol';
12957
    };
12958
    const cleanupDomFragment = domFragment => {
12959
      var _a, _b;
12960
      const firstChild = domFragment.firstChild;
12961
      const lastChild = domFragment.lastChild;
12962
      if (firstChild && firstChild.nodeName === 'META') {
12963
        (_a = firstChild.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(firstChild);
12964
      }
12965
      if (lastChild && lastChild.id === 'mce_marker') {
12966
        (_b = lastChild.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(lastChild);
12967
      }
12968
      return domFragment;
12969
    };
12970
    const toDomFragment = (dom, serializer, fragment) => {
12971
      const html = serializer.serialize(fragment);
12972
      const domFragment = dom.createFragment(html);
12973
      return cleanupDomFragment(domFragment);
12974
    };
12975
    const listItems = elm => {
12976
      var _a;
12977
      return filter$5((_a = elm === null || elm === void 0 ? void 0 : elm.childNodes) !== null && _a !== void 0 ? _a : [], child => {
12978
        return child.nodeName === 'LI';
12979
      });
12980
    };
12981
    const isPadding = node => {
12982
      return node.data === nbsp || isBr$6(node);
12983
    };
12984
    const isListItemPadded = node => {
12985
      return isNonNullable(node === null || node === void 0 ? void 0 : node.firstChild) && node.firstChild === node.lastChild && isPadding(node.firstChild);
12986
    };
12987
    const isEmptyOrPadded = elm => {
12988
      return !elm.firstChild || isListItemPadded(elm);
12989
    };
12990
    const trimListItems = elms => {
12991
      return elms.length > 0 && isEmptyOrPadded(elms[elms.length - 1]) ? elms.slice(0, -1) : elms;
12992
    };
12993
    const getParentLi = (dom, node) => {
12994
      const parentBlock = dom.getParent(node, dom.isBlock);
12995
      return parentBlock && parentBlock.nodeName === 'LI' ? parentBlock : null;
12996
    };
12997
    const isParentBlockLi = (dom, node) => {
12998
      return !!getParentLi(dom, node);
12999
    };
13000
    const getSplit = (parentNode, rng) => {
13001
      const beforeRng = rng.cloneRange();
13002
      const afterRng = rng.cloneRange();
13003
      beforeRng.setStartBefore(parentNode);
13004
      afterRng.setEndAfter(parentNode);
13005
      return [
13006
        beforeRng.cloneContents(),
13007
        afterRng.cloneContents()
13008
      ];
13009
    };
13010
    const findFirstIn = (node, rootNode) => {
13011
      const caretPos = CaretPosition.before(node);
13012
      const caretWalker = CaretWalker(rootNode);
13013
      const newCaretPos = caretWalker.next(caretPos);
13014
      return newCaretPos ? newCaretPos.toRange() : null;
13015
    };
13016
    const findLastOf = (node, rootNode) => {
13017
      const caretPos = CaretPosition.after(node);
13018
      const caretWalker = CaretWalker(rootNode);
13019
      const newCaretPos = caretWalker.prev(caretPos);
13020
      return newCaretPos ? newCaretPos.toRange() : null;
13021
    };
13022
    const insertMiddle = (target, elms, rootNode, rng) => {
13023
      const parts = getSplit(target, rng);
13024
      const parentElm = target.parentNode;
13025
      if (parentElm) {
13026
        parentElm.insertBefore(parts[0], target);
13027
        Tools.each(elms, li => {
13028
          parentElm.insertBefore(li, target);
13029
        });
13030
        parentElm.insertBefore(parts[1], target);
13031
        parentElm.removeChild(target);
13032
      }
13033
      return findLastOf(elms[elms.length - 1], rootNode);
13034
    };
13035
    const insertBefore$2 = (target, elms, rootNode) => {
13036
      const parentElm = target.parentNode;
13037
      if (parentElm) {
13038
        Tools.each(elms, elm => {
13039
          parentElm.insertBefore(elm, target);
13040
        });
13041
      }
13042
      return findFirstIn(target, rootNode);
13043
    };
13044
    const insertAfter$2 = (target, elms, rootNode, dom) => {
13045
      dom.insertAfter(elms.reverse(), target);
13046
      return findLastOf(elms[0], rootNode);
13047
    };
13048
    const insertAtCaret$1 = (serializer, dom, rng, fragment) => {
13049
      const domFragment = toDomFragment(dom, serializer, fragment);
13050
      const liTarget = getParentLi(dom, rng.startContainer);
13051
      const liElms = trimListItems(listItems(domFragment.firstChild));
13052
      const BEGINNING = 1, END = 2;
13053
      const rootNode = dom.getRoot();
13054
      const isAt = location => {
13055
        const caretPos = CaretPosition.fromRangeStart(rng);
13056
        const caretWalker = CaretWalker(dom.getRoot());
13057
        const newPos = location === BEGINNING ? caretWalker.prev(caretPos) : caretWalker.next(caretPos);
13058
        const newPosNode = newPos === null || newPos === void 0 ? void 0 : newPos.getNode();
13059
        return newPosNode ? getParentLi(dom, newPosNode) !== liTarget : true;
13060
      };
13061
      if (!liTarget) {
13062
        return null;
13063
      } else if (isAt(BEGINNING)) {
13064
        return insertBefore$2(liTarget, liElms, rootNode);
13065
      } else if (isAt(END)) {
13066
        return insertAfter$2(liTarget, liElms, rootNode, dom);
13067
      } else {
13068
        return insertMiddle(liTarget, liElms, rootNode, rng);
13069
      }
13070
    };
13071
 
13072
    const mergeableWrappedElements = ['pre'];
13073
    const shouldPasteContentOnly = (dom, fragment, parentNode, root) => {
13074
      var _a;
13075
      const firstNode = fragment.firstChild;
13076
      const lastNode = fragment.lastChild;
13077
      const last = lastNode.attr('data-mce-type') === 'bookmark' ? lastNode.prev : lastNode;
13078
      const isPastingSingleElement = firstNode === last;
13079
      const isWrappedElement = contains$2(mergeableWrappedElements, firstNode.name);
13080
      if (isPastingSingleElement && isWrappedElement) {
13081
        const isContentEditable = firstNode.attr('contenteditable') !== 'false';
13082
        const isPastingInTheSameBlockTag = ((_a = dom.getParent(parentNode, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName.toLowerCase()) === firstNode.name;
13083
        const isPastingInContentEditable = Optional.from(getContentEditableRoot$1(root, parentNode)).forall(isContentEditableTrue$3);
13084
        return isContentEditable && isPastingInTheSameBlockTag && isPastingInContentEditable;
13085
      } else {
13086
        return false;
13087
      }
13088
    };
13089
    const isTableCell = isTableCell$3;
13090
    const isTableCellContentSelected = (dom, rng, cell) => {
13091
      if (isNonNullable(cell)) {
13092
        const endCell = dom.getParent(rng.endContainer, isTableCell);
13093
        return cell === endCell && hasAllContentsSelected(SugarElement.fromDom(cell), rng);
13094
      } else {
13095
        return false;
13096
      }
13097
    };
1441 ariadna 13098
    const isEditableEmptyBlock = (dom, node) => {
13099
      if (dom.isBlock(node) && dom.isEditable(node)) {
13100
        const childNodes = node.childNodes;
13101
        return childNodes.length === 1 && isBr$6(childNodes[0]) || childNodes.length === 0;
13102
      } else {
13103
        return false;
13104
      }
13105
    };
1 efrain 13106
    const validInsertion = (editor, value, parentNode) => {
13107
      var _a;
13108
      if (parentNode.getAttribute('data-mce-bogus') === 'all') {
13109
        (_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(editor.dom.createFragment(value), parentNode);
13110
      } else {
1441 ariadna 13111
        if (isEditableEmptyBlock(editor.dom, parentNode)) {
1 efrain 13112
          editor.dom.setHTML(parentNode, value);
13113
        } else {
13114
          editor.selection.setContent(value, { no_events: true });
13115
        }
13116
      }
13117
    };
13118
    const trimBrsFromTableCell = (dom, elm, schema) => {
13119
      Optional.from(dom.getParent(elm, 'td,th')).map(SugarElement.fromDom).each(el => trimBlockTrailingBr(el, schema));
13120
    };
13121
    const reduceInlineTextElements = (editor, merge) => {
13122
      const textInlineElements = editor.schema.getTextInlineElements();
13123
      const dom = editor.dom;
13124
      if (merge) {
13125
        const root = editor.getBody();
13126
        const elementUtils = ElementUtils(editor);
1441 ariadna 13127
        const fragmentSelector = '*[data-mce-fragment]';
13128
        const fragments = dom.select(fragmentSelector);
13129
        Tools.each(fragments, node => {
13130
          const isInline = currentNode => isNonNullable(textInlineElements[currentNode.nodeName.toLowerCase()]);
13131
          const hasOneChild = currentNode => currentNode.childNodes.length === 1;
13132
          const hasNoNonInheritableStyles = currentNode => !(hasNonInheritableStyles(dom, currentNode) || hasConditionalNonInheritableStyles(dom, currentNode));
13133
          if (hasNoNonInheritableStyles(node) && isInline(node) && hasOneChild(node)) {
13134
            const styles = getStyleProps(dom, node);
13135
            const isOverridden = (oldStyles, newStyles) => forall(oldStyles, style => contains$2(newStyles, style));
13136
            const overriddenByAllChildren = childNode => hasOneChild(node) && dom.is(childNode, fragmentSelector) && isInline(childNode) && (childNode.nodeName === node.nodeName && isOverridden(styles, getStyleProps(dom, childNode)) || overriddenByAllChildren(childNode.children[0]));
13137
            const identicalToParent = parentNode => isNonNullable(parentNode) && parentNode !== root && (elementUtils.compare(node, parentNode) || identicalToParent(parentNode.parentElement));
13138
            const conflictWithInsertedParent = parentNode => isNonNullable(parentNode) && parentNode !== root && dom.is(parentNode, fragmentSelector) && (hasStyleConflict(dom, node, parentNode) || conflictWithInsertedParent(parentNode.parentElement));
13139
            if (overriddenByAllChildren(node.children[0]) || identicalToParent(node.parentElement) && !conflictWithInsertedParent(node.parentElement)) {
13140
              dom.remove(node, true);
1 efrain 13141
            }
13142
          }
13143
        });
13144
      }
13145
    };
13146
    const markFragmentElements = fragment => {
13147
      let node = fragment;
13148
      while (node = node.walk()) {
13149
        if (node.type === 1) {
13150
          node.attr('data-mce-fragment', '1');
13151
        }
13152
      }
13153
    };
13154
    const unmarkFragmentElements = elm => {
13155
      Tools.each(elm.getElementsByTagName('*'), elm => {
13156
        elm.removeAttribute('data-mce-fragment');
13157
      });
13158
    };
13159
    const isPartOfFragment = node => {
13160
      return !!node.getAttribute('data-mce-fragment');
13161
    };
13162
    const canHaveChildren = (editor, node) => {
13163
      return isNonNullable(node) && !editor.schema.getVoidElements()[node.nodeName];
13164
    };
13165
    const moveSelectionToMarker = (editor, marker) => {
13166
      var _a, _b, _c;
13167
      let nextRng;
13168
      const dom = editor.dom;
13169
      const selection = editor.selection;
13170
      if (!marker) {
13171
        return;
13172
      }
13173
      selection.scrollIntoView(marker);
13174
      const parentEditableElm = getContentEditableRoot$1(editor.getBody(), marker);
13175
      if (parentEditableElm && dom.getContentEditable(parentEditableElm) === 'false') {
13176
        dom.remove(marker);
13177
        selection.select(parentEditableElm);
13178
        return;
13179
      }
13180
      let rng = dom.createRng();
13181
      const node = marker.previousSibling;
1441 ariadna 13182
      if (isText$b(node)) {
1 efrain 13183
        rng.setStart(node, (_b = (_a = node.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
13184
        const node2 = marker.nextSibling;
1441 ariadna 13185
        if (isText$b(node2)) {
1 efrain 13186
          node.appendData(node2.data);
13187
          (_c = node2.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(node2);
13188
        }
13189
      } else {
13190
        rng.setStartBefore(marker);
13191
        rng.setEndBefore(marker);
13192
      }
13193
      const findNextCaretRng = rng => {
13194
        let caretPos = CaretPosition.fromRangeStart(rng);
13195
        const caretWalker = CaretWalker(editor.getBody());
13196
        caretPos = caretWalker.next(caretPos);
13197
        return caretPos === null || caretPos === void 0 ? void 0 : caretPos.toRange();
13198
      };
13199
      const parentBlock = dom.getParent(marker, dom.isBlock);
13200
      dom.remove(marker);
13201
      if (parentBlock && dom.isEmpty(parentBlock)) {
13202
        const isCell = isTableCell(parentBlock);
13203
        empty(SugarElement.fromDom(parentBlock));
13204
        rng.setStart(parentBlock, 0);
13205
        rng.setEnd(parentBlock, 0);
13206
        if (!isCell && !isPartOfFragment(parentBlock) && (nextRng = findNextCaretRng(rng))) {
13207
          rng = nextRng;
13208
          dom.remove(parentBlock);
13209
        } else {
13210
          dom.add(parentBlock, dom.create('br', isCell ? {} : { 'data-mce-bogus': '1' }));
13211
        }
13212
      }
13213
      selection.setRng(rng);
13214
    };
13215
    const deleteSelectedContent = editor => {
13216
      const dom = editor.dom;
13217
      const rng = normalize(editor.selection.getRng());
13218
      editor.selection.setRng(rng);
13219
      const startCell = dom.getParent(rng.startContainer, isTableCell);
13220
      if (isTableCellContentSelected(dom, rng, startCell)) {
13221
        deleteCellContents(editor, rng, SugarElement.fromDom(startCell));
1441 ariadna 13222
      } else if (rng.startContainer === rng.endContainer && rng.endOffset - rng.startOffset === 1 && isText$b(rng.startContainer.childNodes[rng.startOffset])) {
1 efrain 13223
        rng.deleteContents();
13224
      } else {
13225
        editor.getDoc().execCommand('Delete', false);
13226
      }
13227
    };
13228
    const findMarkerNode = scope => {
13229
      for (let markerNode = scope; markerNode; markerNode = markerNode.walk()) {
13230
        if (markerNode.attr('id') === 'mce_marker') {
13231
          return Optional.some(markerNode);
13232
        }
13233
      }
13234
      return Optional.none();
13235
    };
13236
    const notHeadingsInSummary = (dom, node, fragment) => {
13237
      var _a;
13238
      return exists(fragment.children(), isHeading) && ((_a = dom.getParent(node, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName) === 'SUMMARY';
13239
    };
13240
    const insertHtmlAtCaret = (editor, value, details) => {
13241
      var _a, _b;
13242
      const selection = editor.selection;
13243
      const dom = editor.dom;
13244
      const parser = editor.parser;
13245
      const merge = details.merge;
13246
      const serializer = HtmlSerializer({ validate: true }, editor.schema);
13247
      const bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;</span>';
13248
      if (!details.preserve_zwsp) {
13249
        value = trim$2(value);
13250
      }
13251
      if (value.indexOf('{$caret}') === -1) {
13252
        value += '{$caret}';
13253
      }
13254
      value = value.replace(/\{\$caret\}/, bookmarkHtml);
13255
      let rng = selection.getRng();
13256
      const caretElement = rng.startContainer;
13257
      const body = editor.getBody();
13258
      if (caretElement === body && selection.isCollapsed()) {
13259
        if (dom.isBlock(body.firstChild) && canHaveChildren(editor, body.firstChild) && dom.isEmpty(body.firstChild)) {
13260
          rng = dom.createRng();
13261
          rng.setStart(body.firstChild, 0);
13262
          rng.setEnd(body.firstChild, 0);
13263
          selection.setRng(rng);
13264
        }
13265
      }
13266
      if (!selection.isCollapsed()) {
13267
        deleteSelectedContent(editor);
13268
      }
13269
      const parentNode = selection.getNode();
13270
      const parserArgs = {
13271
        context: parentNode.nodeName.toLowerCase(),
13272
        data: details.data,
13273
        insert: true
13274
      };
13275
      const fragment = parser.parse(value, parserArgs);
13276
      if (details.paste === true && isListFragment(editor.schema, fragment) && isParentBlockLi(dom, parentNode)) {
13277
        rng = insertAtCaret$1(serializer, dom, selection.getRng(), fragment);
13278
        if (rng) {
13279
          selection.setRng(rng);
13280
        }
13281
        return value;
13282
      }
13283
      if (details.paste === true && shouldPasteContentOnly(dom, fragment, parentNode, editor.getBody())) {
13284
        (_a = fragment.firstChild) === null || _a === void 0 ? void 0 : _a.unwrap();
13285
      }
13286
      markFragmentElements(fragment);
13287
      let node = fragment.lastChild;
13288
      if (node && node.attr('id') === 'mce_marker') {
13289
        const marker = node;
13290
        for (node = node.prev; node; node = node.walk(true)) {
1441 ariadna 13291
          if (node.name === 'table') {
13292
            break;
13293
          }
1 efrain 13294
          if (node.type === 3 || !dom.isBlock(node.name)) {
13295
            if (node.parent && editor.schema.isValidChild(node.parent.name, 'span')) {
13296
              node.parent.insert(marker, node, node.name === 'br');
13297
            }
13298
            break;
13299
          }
13300
        }
13301
      }
13302
      editor._selectionOverrides.showBlockCaretContainer(parentNode);
13303
      if (!parserArgs.invalid && !notHeadingsInSummary(dom, parentNode, fragment)) {
13304
        value = serializer.serialize(fragment);
13305
        validInsertion(editor, value, parentNode);
13306
      } else {
13307
        editor.selection.setContent(bookmarkHtml);
13308
        let parentNode = selection.getNode();
13309
        let tempNode;
13310
        const rootNode = editor.getBody();
13311
        if (isDocument$1(parentNode)) {
13312
          parentNode = tempNode = rootNode;
13313
        } else {
13314
          tempNode = parentNode;
13315
        }
13316
        while (tempNode && tempNode !== rootNode) {
13317
          parentNode = tempNode;
13318
          tempNode = tempNode.parentNode;
13319
        }
13320
        value = parentNode === rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode);
13321
        const root = parser.parse(value);
13322
        const markerNode = findMarkerNode(root);
13323
        const editingHost = markerNode.bind(findClosestEditingHost).getOr(root);
13324
        markerNode.each(marker => marker.replace(fragment));
13325
        const toExtract = fragment.children();
13326
        const parent = (_b = fragment.parent) !== null && _b !== void 0 ? _b : root;
13327
        fragment.unwrap();
13328
        const invalidChildren = filter$5(toExtract, node => isInvalid(editor.schema, node, parent));
13329
        cleanInvalidNodes(invalidChildren, editor.schema, editingHost);
13330
        filter$2(parser.getNodeFilters(), parser.getAttributeFilters(), root);
13331
        value = serializer.serialize(root);
13332
        if (parentNode === rootNode) {
13333
          dom.setHTML(rootNode, value);
13334
        } else {
13335
          dom.setOuterHTML(parentNode, value);
13336
        }
13337
      }
13338
      reduceInlineTextElements(editor, merge);
13339
      moveSelectionToMarker(editor, dom.get('mce_marker'));
13340
      unmarkFragmentElements(editor.getBody());
13341
      trimBrsFromTableCell(dom, selection.getStart(), editor.schema);
13342
      updateCaret(editor.schema, editor.getBody(), selection.getStart());
13343
      return value;
13344
    };
13345
 
13346
    const isTreeNode = content => content instanceof AstNode;
13347
 
13348
    const moveSelection = editor => {
13349
      if (hasFocus(editor)) {
13350
        firstPositionIn(editor.getBody()).each(pos => {
13351
          const node = pos.getNode();
13352
          const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
13353
          editor.selection.setRng(caretPos.toRange());
13354
        });
13355
      }
13356
    };
13357
    const setEditorHtml = (editor, html, noSelection) => {
13358
      editor.dom.setHTML(editor.getBody(), html);
13359
      if (noSelection !== true) {
13360
        moveSelection(editor);
13361
      }
13362
    };
13363
    const setContentString = (editor, body, content, args) => {
13364
      content = trim$2(content);
13365
      if (content.length === 0 || /^\s+$/.test(content)) {
13366
        const padd = '<br data-mce-bogus="1">';
13367
        if (body.nodeName === 'TABLE') {
13368
          content = '<tr><td>' + padd + '</td></tr>';
13369
        } else if (/^(UL|OL)$/.test(body.nodeName)) {
13370
          content = '<li>' + padd + '</li>';
13371
        }
13372
        const forcedRootBlockName = getForcedRootBlock(editor);
13373
        if (editor.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
13374
          content = padd;
13375
          content = editor.dom.createHTML(forcedRootBlockName, getForcedRootBlockAttrs(editor), content);
13376
        } else if (!content) {
13377
          content = padd;
13378
        }
13379
        setEditorHtml(editor, content, args.no_selection);
13380
        return {
13381
          content,
13382
          html: content
13383
        };
13384
      } else {
13385
        if (args.format !== 'raw') {
13386
          content = HtmlSerializer({ validate: false }, editor.schema).serialize(editor.parser.parse(content, {
13387
            isRootContent: true,
13388
            insert: true
13389
          }));
13390
        }
13391
        const trimmedHtml = isWsPreserveElement(SugarElement.fromDom(body)) ? content : Tools.trim(content);
13392
        setEditorHtml(editor, trimmedHtml, args.no_selection);
13393
        return {
13394
          content: trimmedHtml,
13395
          html: trimmedHtml
13396
        };
13397
      }
13398
    };
13399
    const setContentTree = (editor, body, content, args) => {
13400
      filter$2(editor.parser.getNodeFilters(), editor.parser.getAttributeFilters(), content);
13401
      const html = HtmlSerializer({ validate: false }, editor.schema).serialize(content);
13402
      const trimmedHtml = trim$2(isWsPreserveElement(SugarElement.fromDom(body)) ? html : Tools.trim(html));
13403
      setEditorHtml(editor, trimmedHtml, args.no_selection);
13404
      return {
13405
        content,
13406
        html: trimmedHtml
13407
      };
13408
    };
13409
    const setContentInternal = (editor, content, args) => {
13410
      return Optional.from(editor.getBody()).map(body => {
13411
        if (isTreeNode(content)) {
13412
          return setContentTree(editor, body, content, args);
13413
        } else {
13414
          return setContentString(editor, body, content, args);
13415
        }
13416
      }).getOr({
13417
        content,
13418
        html: isTreeNode(args.content) ? '' : args.content
13419
      });
13420
    };
13421
 
13422
    const ensureIsRoot = isRoot => isFunction(isRoot) ? isRoot : never;
13423
    const ancestor = (scope, transform, isRoot) => {
13424
      let element = scope.dom;
13425
      const stop = ensureIsRoot(isRoot);
13426
      while (element.parentNode) {
13427
        element = element.parentNode;
13428
        const el = SugarElement.fromDom(element);
13429
        const transformed = transform(el);
13430
        if (transformed.isSome()) {
13431
          return transformed;
13432
        } else if (stop(el)) {
13433
          break;
13434
        }
13435
      }
13436
      return Optional.none();
13437
    };
13438
    const closest$1 = (scope, transform, isRoot) => {
13439
      const current = transform(scope);
13440
      const stop = ensureIsRoot(isRoot);
13441
      return current.orThunk(() => stop(scope) ? Optional.none() : ancestor(scope, transform, stop));
13442
    };
13443
 
13444
    const isEq$3 = isEq$5;
13445
    const matchesUnInheritedFormatSelector = (ed, node, name) => {
13446
      const formatList = ed.formatter.get(name);
13447
      if (formatList) {
13448
        for (let i = 0; i < formatList.length; i++) {
13449
          const format = formatList[i];
13450
          if (isSelectorFormat(format) && format.inherit === false && ed.dom.is(node, format.selector)) {
13451
            return true;
13452
          }
13453
        }
13454
      }
13455
      return false;
13456
    };
13457
    const matchParents = (editor, node, name, vars, similar) => {
13458
      const root = editor.dom.getRoot();
13459
      if (node === root) {
13460
        return false;
13461
      }
13462
      const matchedNode = editor.dom.getParent(node, elm => {
13463
        if (matchesUnInheritedFormatSelector(editor, elm, name)) {
13464
          return true;
13465
        }
13466
        return elm.parentNode === root || !!matchNode(editor, elm, name, vars, true);
13467
      });
13468
      return !!matchNode(editor, matchedNode, name, vars, similar);
13469
    };
13470
    const matchName = (dom, node, format) => {
13471
      if (isInlineFormat(format) && isEq$3(node, format.inline)) {
13472
        return true;
13473
      }
13474
      if (isBlockFormat(format) && isEq$3(node, format.block)) {
13475
        return true;
13476
      }
13477
      if (isSelectorFormat(format)) {
13478
        return isElement$6(node) && dom.is(node, format.selector);
13479
      }
13480
      return false;
13481
    };
13482
    const matchItems = (dom, node, format, itemName, similar, vars) => {
13483
      const items = format[itemName];
13484
      const matchAttributes = itemName === 'attributes';
13485
      if (isFunction(format.onmatch)) {
13486
        return format.onmatch(node, format, itemName);
13487
      }
13488
      if (items) {
13489
        if (!isArrayLike(items)) {
13490
          for (const key in items) {
13491
            if (has$2(items, key)) {
13492
              const value = matchAttributes ? dom.getAttrib(node, key) : getStyle(dom, node, key);
13493
              const expectedValue = replaceVars(items[key], vars);
13494
              const isEmptyValue = isNullable(value) || isEmpty$3(value);
13495
              if (isEmptyValue && isNullable(expectedValue)) {
13496
                continue;
13497
              }
13498
              if (similar && isEmptyValue && !format.exact) {
13499
                return false;
13500
              }
13501
              if ((!similar || format.exact) && !isEq$3(value, normalizeStyleValue(expectedValue, key))) {
13502
                return false;
13503
              }
13504
            }
13505
          }
13506
        } else {
13507
          for (let i = 0; i < items.length; i++) {
13508
            if (matchAttributes ? dom.getAttrib(node, items[i]) : getStyle(dom, node, items[i])) {
13509
              return true;
13510
            }
13511
          }
13512
        }
13513
      }
13514
      return true;
13515
    };
13516
    const matchNode = (ed, node, name, vars, similar) => {
13517
      const formatList = ed.formatter.get(name);
13518
      const dom = ed.dom;
13519
      if (formatList && isElement$6(node)) {
13520
        for (let i = 0; i < formatList.length; i++) {
13521
          const format = formatList[i];
13522
          if (matchName(ed.dom, node, format) && matchItems(dom, node, format, 'attributes', similar, vars) && matchItems(dom, node, format, 'styles', similar, vars)) {
13523
            const classes = format.classes;
13524
            if (classes) {
13525
              for (let x = 0; x < classes.length; x++) {
13526
                if (!ed.dom.hasClass(node, replaceVars(classes[x], vars))) {
13527
                  return;
13528
                }
13529
              }
13530
            }
13531
            return format;
13532
          }
13533
        }
13534
      }
13535
      return undefined;
13536
    };
13537
    const match$2 = (editor, name, vars, node, similar) => {
13538
      if (node) {
13539
        return matchParents(editor, node, name, vars, similar);
13540
      }
13541
      node = editor.selection.getNode();
13542
      if (matchParents(editor, node, name, vars, similar)) {
13543
        return true;
13544
      }
13545
      const startNode = editor.selection.getStart();
13546
      if (startNode !== node) {
13547
        if (matchParents(editor, startNode, name, vars, similar)) {
13548
          return true;
13549
        }
13550
      }
13551
      return false;
13552
    };
13553
    const matchAll = (editor, names, vars) => {
13554
      const matchedFormatNames = [];
13555
      const checkedMap = {};
13556
      const startElement = editor.selection.getStart();
13557
      editor.dom.getParent(startElement, node => {
13558
        for (let i = 0; i < names.length; i++) {
13559
          const name = names[i];
13560
          if (!checkedMap[name] && matchNode(editor, node, name, vars)) {
13561
            checkedMap[name] = true;
13562
            matchedFormatNames.push(name);
13563
          }
13564
        }
13565
      }, editor.dom.getRoot());
13566
      return matchedFormatNames;
13567
    };
13568
    const closest = (editor, names) => {
13569
      const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
13570
      const match = (elm, name) => matchNode(editor, elm.dom, name) ? Optional.some(name) : Optional.none();
13571
      return Optional.from(editor.selection.getStart(true)).bind(rawElm => closest$1(SugarElement.fromDom(rawElm), elm => findMap(names, name => match(elm, name)), isRoot)).getOrNull();
13572
    };
13573
    const canApply = (editor, name) => {
13574
      const formatList = editor.formatter.get(name);
13575
      const dom = editor.dom;
13576
      if (formatList && editor.selection.isEditable()) {
13577
        const startNode = editor.selection.getStart();
13578
        const parents = getParents$2(dom, startNode);
13579
        for (let x = formatList.length - 1; x >= 0; x--) {
13580
          const format = formatList[x];
13581
          if (!isSelectorFormat(format)) {
13582
            return true;
13583
          }
13584
          for (let i = parents.length - 1; i >= 0; i--) {
13585
            if (dom.is(parents[i], format.selector)) {
13586
              return true;
13587
            }
13588
          }
13589
        }
13590
      }
13591
      return false;
13592
    };
13593
    const matchAllOnNode = (editor, node, formatNames) => foldl(formatNames, (acc, name) => {
13594
      const matchSimilar = isVariableFormatName(editor, name);
13595
      if (editor.formatter.matchNode(node, name, {}, matchSimilar)) {
13596
        return acc.concat([name]);
13597
      } else {
13598
        return acc;
13599
      }
13600
    }, []);
13601
 
13602
    const ZWSP = ZWSP$1;
13603
    const importNode = (ownerDocument, node) => {
13604
      return ownerDocument.importNode(node, true);
13605
    };
13606
    const findFirstTextNode = node => {
13607
      if (node) {
13608
        const walker = new DomTreeWalker(node, node);
13609
        for (let tempNode = walker.current(); tempNode; tempNode = walker.next()) {
1441 ariadna 13610
          if (isText$b(tempNode)) {
1 efrain 13611
            return tempNode;
13612
          }
13613
        }
13614
      }
13615
      return null;
13616
    };
13617
    const createCaretContainer = fill => {
13618
      const caretContainer = SugarElement.fromTag('span');
13619
      setAll$1(caretContainer, {
13620
        'id': CARET_ID,
13621
        'data-mce-bogus': '1',
13622
        'data-mce-type': 'format-caret'
13623
      });
13624
      if (fill) {
13625
        append$1(caretContainer, SugarElement.fromText(ZWSP));
13626
      }
13627
      return caretContainer;
13628
    };
13629
    const trimZwspFromCaretContainer = caretContainerNode => {
13630
      const textNode = findFirstTextNode(caretContainerNode);
13631
      if (textNode && textNode.data.charAt(0) === ZWSP) {
13632
        textNode.deleteData(0, 1);
13633
      }
13634
      return textNode;
13635
    };
13636
    const removeCaretContainerNode = (editor, node, moveCaret) => {
13637
      const dom = editor.dom, selection = editor.selection;
13638
      if (isCaretContainerEmpty(node)) {
13639
        deleteElement$2(editor, false, SugarElement.fromDom(node), moveCaret, true);
13640
      } else {
13641
        const rng = selection.getRng();
13642
        const block = dom.getParent(node, dom.isBlock);
13643
        const startContainer = rng.startContainer;
13644
        const startOffset = rng.startOffset;
13645
        const endContainer = rng.endContainer;
13646
        const endOffset = rng.endOffset;
13647
        const textNode = trimZwspFromCaretContainer(node);
13648
        dom.remove(node, true);
13649
        if (startContainer === textNode && startOffset > 0) {
13650
          rng.setStart(textNode, startOffset - 1);
13651
        }
13652
        if (endContainer === textNode && endOffset > 0) {
13653
          rng.setEnd(textNode, endOffset - 1);
13654
        }
13655
        if (block && dom.isEmpty(block)) {
13656
          fillWithPaddingBr(SugarElement.fromDom(block));
13657
        }
13658
        selection.setRng(rng);
13659
      }
13660
    };
13661
    const removeCaretContainer = (editor, node, moveCaret) => {
13662
      const dom = editor.dom, selection = editor.selection;
13663
      if (!node) {
13664
        node = getParentCaretContainer(editor.getBody(), selection.getStart());
13665
        if (!node) {
13666
          while (node = dom.get(CARET_ID)) {
13667
            removeCaretContainerNode(editor, node, moveCaret);
13668
          }
13669
        }
13670
      } else {
13671
        removeCaretContainerNode(editor, node, moveCaret);
13672
      }
13673
    };
13674
    const insertCaretContainerNode = (editor, caretContainer, formatNode) => {
13675
      var _a, _b;
13676
      const dom = editor.dom;
13677
      const block = dom.getParent(formatNode, curry(isTextBlock$1, editor.schema));
13678
      if (block && dom.isEmpty(block)) {
13679
        (_a = formatNode.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(caretContainer, formatNode);
13680
      } else {
13681
        removeTrailingBr(SugarElement.fromDom(formatNode));
13682
        if (dom.isEmpty(formatNode)) {
13683
          (_b = formatNode.parentNode) === null || _b === void 0 ? void 0 : _b.replaceChild(caretContainer, formatNode);
13684
        } else {
13685
          dom.insertAfter(caretContainer, formatNode);
13686
        }
13687
      }
13688
    };
13689
    const appendNode = (parentNode, node) => {
13690
      parentNode.appendChild(node);
13691
      return node;
13692
    };
13693
    const insertFormatNodesIntoCaretContainer = (formatNodes, caretContainer) => {
13694
      var _a;
13695
      const innerMostFormatNode = foldr(formatNodes, (parentNode, formatNode) => {
13696
        return appendNode(parentNode, formatNode.cloneNode(false));
13697
      }, caretContainer);
13698
      const doc = (_a = innerMostFormatNode.ownerDocument) !== null && _a !== void 0 ? _a : document;
13699
      return appendNode(innerMostFormatNode, doc.createTextNode(ZWSP));
13700
    };
13701
    const cleanFormatNode = (editor, caretContainer, formatNode, name, vars, similar) => {
13702
      const formatter = editor.formatter;
13703
      const dom = editor.dom;
13704
      const validFormats = filter$5(keys(formatter.get()), formatName => formatName !== name && !contains$1(formatName, 'removeformat'));
13705
      const matchedFormats = matchAllOnNode(editor, formatNode, validFormats);
13706
      const uniqueFormats = filter$5(matchedFormats, fmtName => !areSimilarFormats(editor, fmtName, name));
13707
      if (uniqueFormats.length > 0) {
13708
        const clonedFormatNode = formatNode.cloneNode(false);
13709
        dom.add(caretContainer, clonedFormatNode);
13710
        formatter.remove(name, vars, clonedFormatNode, similar);
13711
        dom.remove(clonedFormatNode);
13712
        return Optional.some(clonedFormatNode);
13713
      } else {
13714
        return Optional.none();
13715
      }
13716
    };
1441 ariadna 13717
    const normalizeNbsps = node => set(node, get$3(node).replace(new RegExp(`${ nbsp }$`), ' '));
13718
    const normalizeNbspsBetween = (editor, caretContainer) => {
13719
      const handler = () => {
13720
        if (caretContainer !== null && !editor.dom.isEmpty(caretContainer)) {
13721
          prevSibling(SugarElement.fromDom(caretContainer)).each(node => {
13722
            if (isText$c(node)) {
13723
              normalizeNbsps(node);
13724
            } else {
13725
              descendant$2(node, e => isText$c(e)).each(textNode => {
13726
                if (isText$c(textNode)) {
13727
                  normalizeNbsps(textNode);
13728
                }
13729
              });
13730
            }
13731
          });
13732
        }
13733
      };
13734
      editor.once('input', e => {
13735
        if (e.data && !isWhiteSpace(e.data)) {
13736
          if (!e.isComposing) {
13737
            handler();
13738
          } else {
13739
            editor.once('compositionend', () => {
13740
              handler();
13741
            });
13742
          }
13743
        }
13744
      });
13745
    };
1 efrain 13746
    const applyCaretFormat = (editor, name, vars) => {
13747
      let caretContainer;
13748
      const selection = editor.selection;
13749
      const formatList = editor.formatter.get(name);
13750
      if (!formatList) {
13751
        return;
13752
      }
13753
      const selectionRng = selection.getRng();
13754
      let offset = selectionRng.startOffset;
13755
      const container = selectionRng.startContainer;
13756
      const text = container.nodeValue;
13757
      caretContainer = getParentCaretContainer(editor.getBody(), selection.getStart());
13758
      const wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
13759
      if (text && offset > 0 && offset < text.length && wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) {
13760
        const bookmark = selection.getBookmark();
13761
        selectionRng.collapse(true);
13762
        let rng = expandRng(editor.dom, selectionRng, formatList);
13763
        rng = split(rng);
13764
        editor.formatter.apply(name, vars, rng);
13765
        selection.moveToBookmark(bookmark);
13766
      } else {
13767
        let textNode = caretContainer ? findFirstTextNode(caretContainer) : null;
13768
        if (!caretContainer || (textNode === null || textNode === void 0 ? void 0 : textNode.data) !== ZWSP) {
13769
          caretContainer = importNode(editor.getDoc(), createCaretContainer(true).dom);
13770
          textNode = caretContainer.firstChild;
13771
          selectionRng.insertNode(caretContainer);
13772
          offset = 1;
1441 ariadna 13773
          normalizeNbspsBetween(editor, caretContainer);
1 efrain 13774
          editor.formatter.apply(name, vars, caretContainer);
13775
        } else {
13776
          editor.formatter.apply(name, vars, caretContainer);
13777
        }
13778
        selection.setCursorLocation(textNode, offset);
13779
      }
13780
    };
13781
    const removeCaretFormat = (editor, name, vars, similar) => {
13782
      const dom = editor.dom;
13783
      const selection = editor.selection;
13784
      let hasContentAfter = false;
13785
      const formatList = editor.formatter.get(name);
13786
      if (!formatList) {
13787
        return;
13788
      }
13789
      const rng = selection.getRng();
13790
      const container = rng.startContainer;
13791
      const offset = rng.startOffset;
13792
      let node = container;
1441 ariadna 13793
      if (isText$b(container)) {
1 efrain 13794
        if (offset !== container.data.length) {
13795
          hasContentAfter = true;
13796
        }
13797
        node = node.parentNode;
13798
      }
13799
      const parents = [];
13800
      let formatNode;
13801
      while (node) {
13802
        if (matchNode(editor, node, name, vars, similar)) {
13803
          formatNode = node;
13804
          break;
13805
        }
13806
        if (node.nextSibling) {
13807
          hasContentAfter = true;
13808
        }
13809
        parents.push(node);
13810
        node = node.parentNode;
13811
      }
13812
      if (!formatNode) {
13813
        return;
13814
      }
13815
      if (hasContentAfter) {
13816
        const bookmark = selection.getBookmark();
13817
        rng.collapse(true);
1441 ariadna 13818
        let expandedRng = expandRng(dom, rng, formatList, { includeTrailingSpace: true });
1 efrain 13819
        expandedRng = split(expandedRng);
13820
        editor.formatter.remove(name, vars, expandedRng, similar);
13821
        selection.moveToBookmark(bookmark);
13822
      } else {
13823
        const caretContainer = getParentCaretContainer(editor.getBody(), formatNode);
13824
        const parentsAfter = isNonNullable(caretContainer) ? dom.getParents(formatNode.parentNode, always, caretContainer) : [];
13825
        const newCaretContainer = createCaretContainer(false).dom;
13826
        insertCaretContainerNode(editor, newCaretContainer, caretContainer !== null && caretContainer !== void 0 ? caretContainer : formatNode);
13827
        const cleanedFormatNode = cleanFormatNode(editor, newCaretContainer, formatNode, name, vars, similar);
13828
        const caretTextNode = insertFormatNodesIntoCaretContainer([
13829
          ...parents,
13830
          ...cleanedFormatNode.toArray(),
13831
          ...parentsAfter
13832
        ], newCaretContainer);
13833
        if (caretContainer) {
13834
          removeCaretContainerNode(editor, caretContainer, isNonNullable(caretContainer));
13835
        }
13836
        selection.setCursorLocation(caretTextNode, 1);
1441 ariadna 13837
        normalizeNbspsBetween(editor, newCaretContainer);
1 efrain 13838
        if (dom.isEmpty(formatNode)) {
13839
          dom.remove(formatNode);
13840
        }
13841
      }
13842
    };
13843
    const disableCaretContainer = (editor, keyCode, moveCaret) => {
13844
      const selection = editor.selection, body = editor.getBody();
13845
      removeCaretContainer(editor, null, moveCaret);
13846
      if ((keyCode === 8 || keyCode === 46) && selection.isCollapsed() && selection.getStart().innerHTML === ZWSP) {
13847
        removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()), true);
13848
      }
13849
      if (keyCode === 37 || keyCode === 39) {
13850
        removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()), true);
13851
      }
13852
    };
1441 ariadna 13853
    const endsWithNbsp = element => isText$b(element) && endsWith(element.data, nbsp);
1 efrain 13854
    const setup$v = editor => {
13855
      editor.on('mouseup keydown', e => {
13856
        disableCaretContainer(editor, e.keyCode, endsWithNbsp(editor.selection.getRng().endContainer));
13857
      });
13858
    };
13859
    const createCaretFormat = formatNodes => {
13860
      const caretContainer = createCaretContainer(false);
13861
      const innerMost = insertFormatNodesIntoCaretContainer(formatNodes, caretContainer.dom);
13862
      return {
13863
        caretContainer,
13864
        caretPosition: CaretPosition(innerMost, 0)
13865
      };
13866
    };
13867
    const replaceWithCaretFormat = (targetNode, formatNodes) => {
13868
      const {caretContainer, caretPosition} = createCaretFormat(formatNodes);
13869
      before$3(SugarElement.fromDom(targetNode), caretContainer);
1441 ariadna 13870
      remove$4(SugarElement.fromDom(targetNode));
1 efrain 13871
      return caretPosition;
13872
    };
13873
    const createCaretFormatAtStart$1 = (rng, formatNodes) => {
13874
      const {caretContainer, caretPosition} = createCaretFormat(formatNodes);
13875
      rng.insertNode(caretContainer.dom);
13876
      return caretPosition;
13877
    };
13878
    const isFormatElement = (editor, element) => {
13879
      if (isCaretNode(element.dom)) {
13880
        return false;
13881
      }
13882
      const inlineElements = editor.schema.getTextInlineElements();
1441 ariadna 13883
      return has$2(inlineElements, name(element)) && !isCaretNode(element.dom) && !isBogus$1(element.dom);
1 efrain 13884
    };
13885
 
13886
    const postProcessHooks = {};
13887
    const isPre = matchNodeNames(['pre']);
13888
    const addPostProcessHook = (name, hook) => {
13889
      const hooks = postProcessHooks[name];
13890
      if (!hooks) {
13891
        postProcessHooks[name] = [];
13892
      }
13893
      postProcessHooks[name].push(hook);
13894
    };
13895
    const postProcess$1 = (name, editor) => {
13896
      if (has$2(postProcessHooks, name)) {
13897
        each$e(postProcessHooks[name], hook => {
13898
          hook(editor);
13899
        });
13900
      }
13901
    };
13902
    addPostProcessHook('pre', editor => {
13903
      const rng = editor.selection.getRng();
13904
      const hasPreSibling = blocks => pre => {
13905
        const prev = pre.previousSibling;
13906
        return isPre(prev) && contains$2(blocks, prev);
13907
      };
13908
      const joinPre = (pre1, pre2) => {
13909
        const sPre2 = SugarElement.fromDom(pre2);
13910
        const doc = documentOrOwner(sPre2).dom;
1441 ariadna 13911
        remove$4(sPre2);
1 efrain 13912
        append(SugarElement.fromDom(pre1), [
13913
          SugarElement.fromTag('br', doc),
13914
          SugarElement.fromTag('br', doc),
13915
          ...children$1(sPre2)
13916
        ]);
13917
      };
13918
      if (!rng.collapsed) {
13919
        const blocks = editor.selection.getSelectedBlocks();
13920
        const preBlocks = filter$5(filter$5(blocks, isPre), hasPreSibling(blocks));
13921
        each$e(preBlocks, pre => {
13922
          joinPre(pre.previousSibling, pre);
13923
        });
13924
      }
13925
    });
13926
 
13927
    const listItemStyles = [
13928
      'fontWeight',
13929
      'fontStyle',
13930
      'color',
13931
      'fontSize',
13932
      'fontFamily'
13933
    ];
13934
    const hasListStyles = fmt => isObject(fmt.styles) && exists(keys(fmt.styles), name => contains$2(listItemStyles, name));
13935
    const findExpandedListItemFormat = formats => find$2(formats, fmt => isInlineFormat(fmt) && fmt.inline === 'span' && hasListStyles(fmt));
13936
    const getExpandedListItemFormat = (formatter, format) => {
13937
      const formatList = formatter.get(format);
13938
      return isArray$1(formatList) ? findExpandedListItemFormat(formatList) : Optional.none();
13939
    };
13940
    const isRngStartAtStartOfElement = (rng, elm) => prevPosition(elm, CaretPosition.fromRangeStart(rng)).isNone();
13941
    const isRngEndAtEndOfElement = (rng, elm) => {
13942
      return nextPosition(elm, CaretPosition.fromRangeEnd(rng)).exists(pos => !isBr$6(pos.getNode()) || nextPosition(elm, pos).isSome()) === false;
13943
    };
13944
    const isEditableListItem = dom => elm => isListItem$2(elm) && dom.isEditable(elm);
13945
    const getFullySelectedBlocks = selection => {
13946
      const blocks = selection.getSelectedBlocks();
13947
      const rng = selection.getRng();
13948
      if (selection.isCollapsed()) {
13949
        return [];
13950
      }
13951
      if (blocks.length === 1) {
13952
        return isRngStartAtStartOfElement(rng, blocks[0]) && isRngEndAtEndOfElement(rng, blocks[0]) ? blocks : [];
13953
      } else {
13954
        const first = head(blocks).filter(elm => isRngStartAtStartOfElement(rng, elm)).toArray();
1441 ariadna 13955
        const last = last$2(blocks).filter(elm => isRngEndAtEndOfElement(rng, elm)).toArray();
1 efrain 13956
        const middle = blocks.slice(1, -1);
13957
        return first.concat(middle).concat(last);
13958
      }
13959
    };
13960
    const getFullySelectedListItems = selection => filter$5(getFullySelectedBlocks(selection), isEditableListItem(selection.dom));
13961
    const getPartiallySelectedListItems = selection => filter$5(selection.getSelectedBlocks(), isEditableListItem(selection.dom));
13962
 
13963
    const each$8 = Tools.each;
1441 ariadna 13964
    const isElementNode = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node);
1 efrain 13965
    const findElementSibling = (node, siblingName) => {
13966
      for (let sibling = node; sibling; sibling = sibling[siblingName]) {
1441 ariadna 13967
        if (isText$b(sibling) && isNotEmpty(sibling.data)) {
1 efrain 13968
          return node;
13969
        }
13970
        if (isElement$6(sibling) && !isBookmarkNode$1(sibling)) {
13971
          return sibling;
13972
        }
13973
      }
13974
      return node;
13975
    };
13976
    const mergeSiblingsNodes = (editor, prev, next) => {
13977
      const elementUtils = ElementUtils(editor);
13978
      const isPrevEditable = isHTMLElement(prev) && editor.dom.isEditable(prev);
13979
      const isNextEditable = isHTMLElement(next) && editor.dom.isEditable(next);
13980
      if (isPrevEditable && isNextEditable) {
13981
        const prevSibling = findElementSibling(prev, 'previousSibling');
13982
        const nextSibling = findElementSibling(next, 'nextSibling');
13983
        if (elementUtils.compare(prevSibling, nextSibling)) {
13984
          for (let sibling = prevSibling.nextSibling; sibling && sibling !== nextSibling;) {
13985
            const tmpSibling = sibling;
13986
            sibling = sibling.nextSibling;
13987
            prevSibling.appendChild(tmpSibling);
13988
          }
13989
          editor.dom.remove(nextSibling);
13990
          Tools.each(Tools.grep(nextSibling.childNodes), node => {
13991
            prevSibling.appendChild(node);
13992
          });
13993
          return prevSibling;
13994
        }
13995
      }
13996
      return next;
13997
    };
13998
    const mergeSiblings = (editor, format, vars, node) => {
13999
      var _a;
14000
      if (node && format.merge_siblings !== false) {
14001
        const newNode = (_a = mergeSiblingsNodes(editor, getNonWhiteSpaceSibling(node), node)) !== null && _a !== void 0 ? _a : node;
14002
        mergeSiblingsNodes(editor, newNode, getNonWhiteSpaceSibling(newNode, true));
14003
      }
14004
    };
14005
    const clearChildStyles = (dom, format, node) => {
14006
      if (format.clear_child_styles) {
14007
        const selector = format.links ? '*:not(a)' : '*';
14008
        each$8(dom.select(selector, node), childNode => {
14009
          if (isElementNode(childNode) && dom.isEditable(childNode)) {
14010
            each$8(format.styles, (_value, name) => {
14011
              dom.setStyle(childNode, name, '');
14012
            });
14013
          }
14014
        });
14015
      }
14016
    };
14017
    const processChildElements = (node, filter, process) => {
14018
      each$8(node.childNodes, node => {
14019
        if (isElementNode(node)) {
14020
          if (filter(node)) {
14021
            process(node);
14022
          }
14023
          if (node.hasChildNodes()) {
14024
            processChildElements(node, filter, process);
14025
          }
14026
        }
14027
      });
14028
    };
14029
    const unwrapEmptySpan = (dom, node) => {
14030
      if (node.nodeName === 'SPAN' && dom.getAttribs(node).length === 0) {
14031
        dom.remove(node, true);
14032
      }
14033
    };
14034
    const hasStyle = (dom, name) => node => !!(node && getStyle(dom, node, name));
14035
    const applyStyle = (dom, name, value) => node => {
14036
      dom.setStyle(node, name, value);
14037
      if (node.getAttribute('style') === '') {
14038
        node.removeAttribute('style');
14039
      }
14040
      unwrapEmptySpan(dom, node);
14041
    };
14042
 
14043
    const removeResult = Adt.generate([
14044
      { keep: [] },
14045
      { rename: ['name'] },
14046
      { removed: [] }
14047
    ]);
14048
    const MCE_ATTR_RE = /^(src|href|style)$/;
14049
    const each$7 = Tools.each;
14050
    const isEq$2 = isEq$5;
14051
    const isTableCellOrRow = node => /^(TR|TH|TD)$/.test(node.nodeName);
14052
    const isChildOfInlineParent = (dom, node, parent) => dom.isChildOf(node, parent) && node !== parent && !dom.isBlock(parent);
14053
    const getContainer = (ed, rng, start) => {
14054
      let container = rng[start ? 'startContainer' : 'endContainer'];
14055
      let offset = rng[start ? 'startOffset' : 'endOffset'];
14056
      if (isElement$6(container)) {
14057
        const lastIdx = container.childNodes.length - 1;
14058
        if (!start && offset) {
14059
          offset--;
14060
        }
14061
        container = container.childNodes[offset > lastIdx ? lastIdx : offset];
14062
      }
1441 ariadna 14063
      if (isText$b(container) && start && offset >= container.data.length) {
1 efrain 14064
        container = new DomTreeWalker(container, ed.getBody()).next() || container;
14065
      }
1441 ariadna 14066
      if (isText$b(container) && !start && offset === 0) {
1 efrain 14067
        container = new DomTreeWalker(container, ed.getBody()).prev() || container;
14068
      }
14069
      return container;
14070
    };
14071
    const normalizeTableSelection = (node, start) => {
14072
      const prop = start ? 'firstChild' : 'lastChild';
14073
      const childNode = node[prop];
14074
      if (isTableCellOrRow(node) && childNode) {
14075
        if (node.nodeName === 'TR') {
14076
          return childNode[prop] || childNode;
14077
        } else {
14078
          return childNode;
14079
        }
14080
      }
14081
      return node;
14082
    };
14083
    const wrap$1 = (dom, node, name, attrs) => {
14084
      var _a;
14085
      const wrapper = dom.create(name, attrs);
14086
      (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(wrapper, node);
14087
      wrapper.appendChild(node);
14088
      return wrapper;
14089
    };
14090
    const wrapWithSiblings = (dom, node, next, name, attrs) => {
14091
      const start = SugarElement.fromDom(node);
14092
      const wrapper = SugarElement.fromDom(dom.create(name, attrs));
14093
      const siblings = next ? nextSiblings(start) : prevSiblings(start);
14094
      append(wrapper, siblings);
14095
      if (next) {
14096
        before$3(start, wrapper);
14097
        prepend(wrapper, start);
14098
      } else {
14099
        after$4(start, wrapper);
14100
        append$1(wrapper, start);
14101
      }
14102
      return wrapper.dom;
14103
    };
14104
    const isColorFormatAndAnchor = (node, format) => format.links && node.nodeName === 'A';
14105
    const removeNode = (ed, node, format) => {
14106
      const parentNode = node.parentNode;
14107
      let rootBlockElm;
14108
      const dom = ed.dom;
14109
      const forcedRootBlock = getForcedRootBlock(ed);
14110
      if (isBlockFormat(format)) {
14111
        if (parentNode === dom.getRoot()) {
14112
          if (!format.list_block || !isEq$2(node, format.list_block)) {
14113
            each$e(from(node.childNodes), node => {
14114
              if (isValid(ed, forcedRootBlock, node.nodeName.toLowerCase())) {
14115
                if (!rootBlockElm) {
14116
                  rootBlockElm = wrap$1(dom, node, forcedRootBlock);
14117
                  dom.setAttribs(rootBlockElm, getForcedRootBlockAttrs(ed));
14118
                } else {
14119
                  rootBlockElm.appendChild(node);
14120
                }
14121
              } else {
14122
                rootBlockElm = null;
14123
              }
14124
            });
14125
          }
14126
        }
14127
      }
14128
      if (isMixedFormat(format) && !isEq$2(format.inline, node)) {
14129
        return;
14130
      }
14131
      dom.remove(node, true);
14132
    };
14133
    const processFormatAttrOrStyle = (name, value, vars) => {
14134
      if (isNumber(name)) {
14135
        return {
14136
          name: value,
14137
          value: null
14138
        };
14139
      } else {
14140
        return {
14141
          name,
14142
          value: replaceVars(value, vars)
14143
        };
14144
      }
14145
    };
14146
    const removeEmptyStyleAttributeIfNeeded = (dom, elm) => {
14147
      if (dom.getAttrib(elm, 'style') === '') {
14148
        elm.removeAttribute('style');
14149
        elm.removeAttribute('data-mce-style');
14150
      }
14151
    };
14152
    const removeStyles = (dom, elm, format, vars, compareNode) => {
14153
      let stylesModified = false;
14154
      each$7(format.styles, (value, name) => {
14155
        const {
14156
          name: styleName,
14157
          value: styleValue
14158
        } = processFormatAttrOrStyle(name, value, vars);
14159
        const normalizedStyleValue = normalizeStyleValue(styleValue, styleName);
14160
        if (format.remove_similar || isNull(styleValue) || !isElement$6(compareNode) || isEq$2(getStyle(dom, compareNode, styleName), normalizedStyleValue)) {
14161
          dom.setStyle(elm, styleName, '');
14162
        }
14163
        stylesModified = true;
14164
      });
14165
      if (stylesModified) {
14166
        removeEmptyStyleAttributeIfNeeded(dom, elm);
14167
      }
14168
    };
14169
    const removeListStyleFormats = (editor, name, vars) => {
14170
      if (name === 'removeformat') {
14171
        each$e(getPartiallySelectedListItems(editor.selection), li => {
14172
          each$e(listItemStyles, name => editor.dom.setStyle(li, name, ''));
14173
          removeEmptyStyleAttributeIfNeeded(editor.dom, li);
14174
        });
14175
      } else {
14176
        getExpandedListItemFormat(editor.formatter, name).each(liFmt => {
14177
          each$e(getPartiallySelectedListItems(editor.selection), li => removeStyles(editor.dom, li, liFmt, vars, null));
14178
        });
14179
      }
14180
    };
14181
    const removeNodeFormatInternal = (ed, format, vars, node, compareNode) => {
14182
      const dom = ed.dom;
14183
      const elementUtils = ElementUtils(ed);
14184
      const schema = ed.schema;
14185
      if (isInlineFormat(format) && isTransparentElementName(schema, format.inline) && isTransparentBlock(schema, node) && node.parentElement === ed.getBody()) {
14186
        removeNode(ed, node, format);
14187
        return removeResult.removed();
14188
      }
14189
      if (!format.ceFalseOverride && node && dom.getContentEditableParent(node) === 'false') {
14190
        return removeResult.keep();
14191
      }
14192
      if (node && !matchName(dom, node, format) && !isColorFormatAndAnchor(node, format)) {
14193
        return removeResult.keep();
14194
      }
14195
      const elm = node;
14196
      const preserveAttributes = format.preserve_attributes;
14197
      if (isInlineFormat(format) && format.remove === 'all' && isArray$1(preserveAttributes)) {
14198
        const attrsToPreserve = filter$5(dom.getAttribs(elm), attr => contains$2(preserveAttributes, attr.name.toLowerCase()));
14199
        dom.removeAllAttribs(elm);
14200
        each$e(attrsToPreserve, attr => dom.setAttrib(elm, attr.name, attr.value));
14201
        if (attrsToPreserve.length > 0) {
14202
          return removeResult.rename('span');
14203
        }
14204
      }
14205
      if (format.remove !== 'all') {
14206
        removeStyles(dom, elm, format, vars, compareNode);
14207
        each$7(format.attributes, (value, name) => {
14208
          const {
14209
            name: attrName,
14210
            value: attrValue
14211
          } = processFormatAttrOrStyle(name, value, vars);
14212
          if (format.remove_similar || isNull(attrValue) || !isElement$6(compareNode) || isEq$2(dom.getAttrib(compareNode, attrName), attrValue)) {
14213
            if (attrName === 'class') {
14214
              const currentValue = dom.getAttrib(elm, attrName);
14215
              if (currentValue) {
14216
                let valueOut = '';
14217
                each$e(currentValue.split(/\s+/), cls => {
14218
                  if (/mce\-\w+/.test(cls)) {
14219
                    valueOut += (valueOut ? ' ' : '') + cls;
14220
                  }
14221
                });
14222
                if (valueOut) {
14223
                  dom.setAttrib(elm, attrName, valueOut);
14224
                  return;
14225
                }
14226
              }
14227
            }
14228
            if (MCE_ATTR_RE.test(attrName)) {
14229
              elm.removeAttribute('data-mce-' + attrName);
14230
            }
14231
            if (attrName === 'style' && matchNodeNames(['li'])(elm) && dom.getStyle(elm, 'list-style-type') === 'none') {
14232
              elm.removeAttribute(attrName);
14233
              dom.setStyle(elm, 'list-style-type', 'none');
14234
              return;
14235
            }
14236
            if (attrName === 'class') {
14237
              elm.removeAttribute('className');
14238
            }
14239
            elm.removeAttribute(attrName);
14240
          }
14241
        });
14242
        each$7(format.classes, value => {
14243
          value = replaceVars(value, vars);
14244
          if (!isElement$6(compareNode) || dom.hasClass(compareNode, value)) {
14245
            dom.removeClass(elm, value);
14246
          }
14247
        });
14248
        const attrs = dom.getAttribs(elm);
14249
        for (let i = 0; i < attrs.length; i++) {
14250
          const attrName = attrs[i].nodeName;
14251
          if (!elementUtils.isAttributeInternal(attrName)) {
14252
            return removeResult.keep();
14253
          }
14254
        }
14255
      }
14256
      if (format.remove !== 'none') {
14257
        removeNode(ed, elm, format);
14258
        return removeResult.removed();
14259
      }
14260
      return removeResult.keep();
14261
    };
14262
    const findFormatRoot = (editor, container, name, vars, similar) => {
14263
      let formatRoot;
14264
      if (container.parentNode) {
14265
        each$e(getParents$2(editor.dom, container.parentNode).reverse(), parent => {
14266
          if (!formatRoot && isElement$6(parent) && parent.id !== '_start' && parent.id !== '_end') {
14267
            const format = matchNode(editor, parent, name, vars, similar);
14268
            if (format && format.split !== false) {
14269
              formatRoot = parent;
14270
            }
14271
          }
14272
        });
14273
      }
14274
      return formatRoot;
14275
    };
14276
    const removeNodeFormatFromClone = (editor, format, vars, clone) => removeNodeFormatInternal(editor, format, vars, clone, clone).fold(constant(clone), newName => {
14277
      const fragment = editor.dom.createFragment();
14278
      fragment.appendChild(clone);
14279
      return editor.dom.rename(clone, newName);
14280
    }, constant(null));
14281
    const wrapAndSplit = (editor, formatList, formatRoot, container, target, split, format, vars) => {
14282
      var _a, _b;
14283
      let lastClone;
14284
      let firstClone;
14285
      const dom = editor.dom;
14286
      if (formatRoot) {
14287
        const formatRootParent = formatRoot.parentNode;
14288
        for (let parent = container.parentNode; parent && parent !== formatRootParent; parent = parent.parentNode) {
14289
          let clone = dom.clone(parent, false);
14290
          for (let i = 0; i < formatList.length; i++) {
14291
            clone = removeNodeFormatFromClone(editor, formatList[i], vars, clone);
14292
            if (clone === null) {
14293
              break;
14294
            }
14295
          }
14296
          if (clone) {
14297
            if (lastClone) {
14298
              clone.appendChild(lastClone);
14299
            }
14300
            if (!firstClone) {
14301
              firstClone = clone;
14302
            }
14303
            lastClone = clone;
14304
          }
14305
        }
14306
        if (split && (!format.mixed || !dom.isBlock(formatRoot))) {
14307
          container = (_a = dom.split(formatRoot, container)) !== null && _a !== void 0 ? _a : container;
14308
        }
14309
        if (lastClone && firstClone) {
14310
          (_b = target.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(lastClone, target);
14311
          firstClone.appendChild(target);
14312
          if (isInlineFormat(format)) {
14313
            mergeSiblings(editor, format, vars, lastClone);
14314
          }
14315
        }
14316
      }
14317
      return container;
14318
    };
14319
    const removeFormatInternal = (ed, name, vars, node, similar) => {
14320
      const formatList = ed.formatter.get(name);
14321
      const format = formatList[0];
14322
      const dom = ed.dom;
14323
      const selection = ed.selection;
14324
      const splitToFormatRoot = container => {
14325
        const formatRoot = findFormatRoot(ed, container, name, vars, similar);
14326
        return wrapAndSplit(ed, formatList, formatRoot, container, container, true, format, vars);
14327
      };
14328
      const isRemoveBookmarkNode = node => isBookmarkNode$1(node) && isElement$6(node) && (node.id === '_start' || node.id === '_end');
14329
      const removeFormatOnNode = node => exists(formatList, fmt => removeNodeFormat(ed, fmt, vars, node, node));
14330
      const process = node => {
14331
        const children = from(node.childNodes);
14332
        const removed = removeFormatOnNode(node);
14333
        const currentNodeMatches = removed || exists(formatList, f => matchName(dom, node, f));
14334
        const parentNode = node.parentNode;
14335
        if (!currentNodeMatches && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
14336
          removeFormatOnNode(parentNode);
14337
        }
14338
        if (format.deep) {
14339
          if (children.length) {
14340
            for (let i = 0; i < children.length; i++) {
14341
              process(children[i]);
14342
            }
14343
          }
14344
        }
14345
        const textDecorations = [
14346
          'underline',
14347
          'line-through',
14348
          'overline'
14349
        ];
14350
        each$e(textDecorations, decoration => {
14351
          if (isElement$6(node) && ed.dom.getStyle(node, 'text-decoration') === decoration && node.parentNode && getTextDecoration(dom, node.parentNode) === decoration) {
14352
            removeNodeFormat(ed, {
14353
              deep: false,
14354
              exact: true,
14355
              inline: 'span',
14356
              styles: { textDecoration: decoration }
14357
            }, undefined, node);
14358
          }
14359
        });
14360
      };
14361
      const unwrap = start => {
14362
        const node = dom.get(start ? '_start' : '_end');
14363
        if (node) {
14364
          let out = node[start ? 'firstChild' : 'lastChild'];
14365
          if (isRemoveBookmarkNode(out)) {
14366
            out = out[start ? 'firstChild' : 'lastChild'];
14367
          }
1441 ariadna 14368
          if (isText$b(out) && out.data.length === 0) {
1 efrain 14369
            out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling;
14370
          }
14371
          dom.remove(node, true);
14372
          return out;
14373
        } else {
14374
          return null;
14375
        }
14376
      };
14377
      const removeRngStyle = rng => {
14378
        let startContainer;
14379
        let endContainer;
1441 ariadna 14380
        let expandedRng = expandRng(dom, rng, formatList, { includeTrailingSpace: rng.collapsed });
1 efrain 14381
        if (format.split) {
14382
          expandedRng = split(expandedRng);
14383
          startContainer = getContainer(ed, expandedRng, true);
14384
          endContainer = getContainer(ed, expandedRng);
14385
          if (startContainer !== endContainer) {
14386
            startContainer = normalizeTableSelection(startContainer, true);
14387
            endContainer = normalizeTableSelection(endContainer, false);
14388
            if (isChildOfInlineParent(dom, startContainer, endContainer)) {
14389
              const marker = Optional.from(startContainer.firstChild).getOr(startContainer);
14390
              splitToFormatRoot(wrapWithSiblings(dom, marker, true, 'span', {
14391
                'id': '_start',
14392
                'data-mce-type': 'bookmark'
14393
              }));
14394
              unwrap(true);
14395
              return;
14396
            }
14397
            if (isChildOfInlineParent(dom, endContainer, startContainer)) {
14398
              const marker = Optional.from(endContainer.lastChild).getOr(endContainer);
14399
              splitToFormatRoot(wrapWithSiblings(dom, marker, false, 'span', {
14400
                'id': '_end',
14401
                'data-mce-type': 'bookmark'
14402
              }));
14403
              unwrap(false);
14404
              return;
14405
            }
14406
            startContainer = wrap$1(dom, startContainer, 'span', {
14407
              'id': '_start',
14408
              'data-mce-type': 'bookmark'
14409
            });
14410
            endContainer = wrap$1(dom, endContainer, 'span', {
14411
              'id': '_end',
14412
              'data-mce-type': 'bookmark'
14413
            });
14414
            const newRng = dom.createRng();
14415
            newRng.setStartAfter(startContainer);
14416
            newRng.setEndBefore(endContainer);
14417
            walk$3(dom, newRng, nodes => {
14418
              each$e(nodes, n => {
14419
                if (!isBookmarkNode$1(n) && !isBookmarkNode$1(n.parentNode)) {
14420
                  splitToFormatRoot(n);
14421
                }
14422
              });
14423
            });
14424
            splitToFormatRoot(startContainer);
14425
            splitToFormatRoot(endContainer);
14426
            startContainer = unwrap(true);
14427
            endContainer = unwrap();
14428
          } else {
14429
            startContainer = endContainer = splitToFormatRoot(startContainer);
14430
          }
14431
          expandedRng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
14432
          expandedRng.startOffset = dom.nodeIndex(startContainer);
14433
          expandedRng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
14434
          expandedRng.endOffset = dom.nodeIndex(endContainer) + 1;
14435
        }
14436
        walk$3(dom, expandedRng, nodes => {
14437
          each$e(nodes, process);
14438
        });
14439
      };
14440
      if (node) {
14441
        if (isNode(node)) {
14442
          const rng = dom.createRng();
14443
          rng.setStartBefore(node);
14444
          rng.setEndAfter(node);
14445
          removeRngStyle(rng);
14446
        } else {
14447
          removeRngStyle(node);
14448
        }
14449
        fireFormatRemove(ed, name, node, vars);
14450
        return;
14451
      }
14452
      if (!selection.isCollapsed() || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
14453
        preserveSelection(ed, () => runOnRanges(ed, removeRngStyle), startNode => isInlineFormat(format) && match$2(ed, name, vars, startNode));
14454
        ed.nodeChanged();
14455
      } else {
14456
        removeCaretFormat(ed, name, vars, similar);
14457
      }
14458
      removeListStyleFormats(ed, name, vars);
14459
      fireFormatRemove(ed, name, node, vars);
14460
    };
14461
    const removeFormat$1 = (ed, name, vars, node, similar) => {
14462
      if (node || ed.selection.isEditable()) {
14463
        removeFormatInternal(ed, name, vars, node, similar);
14464
      }
14465
    };
14466
    const removeNodeFormat = (editor, format, vars, node, compareNode) => {
14467
      return removeNodeFormatInternal(editor, format, vars, node, compareNode).fold(never, newName => {
14468
        editor.dom.rename(node, newName);
14469
        return true;
14470
      }, always);
14471
    };
14472
 
14473
    const each$6 = Tools.each;
14474
    const mergeTextDecorationsAndColor = (dom, format, vars, node) => {
14475
      const processTextDecorationsAndColor = n => {
14476
        if (isHTMLElement(n) && isElement$6(n.parentNode) && dom.isEditable(n)) {
14477
          const parentTextDecoration = getTextDecoration(dom, n.parentNode);
14478
          if (dom.getStyle(n, 'color') && parentTextDecoration) {
14479
            dom.setStyle(n, 'text-decoration', parentTextDecoration);
14480
          } else if (dom.getStyle(n, 'text-decoration') === parentTextDecoration) {
14481
            dom.setStyle(n, 'text-decoration', null);
14482
          }
14483
        }
14484
      };
14485
      if (format.styles && (format.styles.color || format.styles.textDecoration)) {
14486
        Tools.walk(node, processTextDecorationsAndColor, 'childNodes');
14487
        processTextDecorationsAndColor(node);
14488
      }
14489
    };
14490
    const mergeBackgroundColorAndFontSize = (dom, format, vars, node) => {
14491
      if (format.styles && format.styles.backgroundColor) {
14492
        const hasFontSize = hasStyle(dom, 'fontSize');
14493
        processChildElements(node, elm => hasFontSize(elm) && dom.isEditable(elm), applyStyle(dom, 'backgroundColor', replaceVars(format.styles.backgroundColor, vars)));
14494
      }
14495
    };
14496
    const mergeSubSup = (dom, format, vars, node) => {
14497
      if (isInlineFormat(format) && (format.inline === 'sub' || format.inline === 'sup')) {
14498
        const hasFontSize = hasStyle(dom, 'fontSize');
14499
        processChildElements(node, elm => hasFontSize(elm) && dom.isEditable(elm), applyStyle(dom, 'fontSize', ''));
14500
        const inverseTagDescendants = filter$5(dom.select(format.inline === 'sup' ? 'sub' : 'sup', node), dom.isEditable);
14501
        dom.remove(inverseTagDescendants, true);
14502
      }
14503
    };
14504
    const mergeWithChildren = (editor, formatList, vars, node) => {
14505
      each$6(formatList, format => {
14506
        if (isInlineFormat(format)) {
14507
          each$6(editor.dom.select(format.inline, node), child => {
14508
            if (isElementNode(child)) {
14509
              removeNodeFormat(editor, format, vars, child, format.exact ? child : null);
14510
            }
14511
          });
14512
        }
14513
        clearChildStyles(editor.dom, format, node);
14514
      });
14515
    };
14516
    const mergeWithParents = (editor, format, name, vars, node) => {
14517
      const parentNode = node.parentNode;
14518
      if (matchNode(editor, parentNode, name, vars)) {
14519
        if (removeNodeFormat(editor, format, vars, node)) {
14520
          return;
14521
        }
14522
      }
14523
      if (format.merge_with_parents && parentNode) {
14524
        editor.dom.getParent(parentNode, parent => {
14525
          if (matchNode(editor, parent, name, vars)) {
14526
            removeNodeFormat(editor, format, vars, node);
14527
            return true;
14528
          } else {
14529
            return false;
14530
          }
14531
        });
14532
      }
14533
    };
14534
 
14535
    const each$5 = Tools.each;
14536
    const canFormatBR = (editor, format, node, parentName) => {
14537
      if (canFormatEmptyLines(editor) && isInlineFormat(format) && node.parentNode) {
14538
        const validBRParentElements = getTextRootBlockElements(editor.schema);
14539
        const hasCaretNodeSibling = sibling(SugarElement.fromDom(node), sibling => isCaretNode(sibling.dom));
1441 ariadna 14540
        return hasNonNullableKey(validBRParentElements, parentName) && isEmptyNode(editor.schema, node.parentNode, {
14541
          skipBogus: false,
14542
          includeZwsp: true
14543
        }) && !hasCaretNodeSibling;
1 efrain 14544
      } else {
14545
        return false;
14546
      }
14547
    };
14548
    const applyStyles = (dom, elm, format, vars) => {
14549
      each$5(format.styles, (value, name) => {
14550
        dom.setStyle(elm, name, replaceVars(value, vars));
14551
      });
14552
      if (format.styles) {
14553
        const styleVal = dom.getAttrib(elm, 'style');
14554
        if (styleVal) {
14555
          dom.setAttrib(elm, 'data-mce-style', styleVal);
14556
        }
14557
      }
14558
    };
14559
    const applyFormatAction = (ed, name, vars, node) => {
14560
      const formatList = ed.formatter.get(name);
14561
      const format = formatList[0];
14562
      const isCollapsed = !node && ed.selection.isCollapsed();
14563
      const dom = ed.dom;
14564
      const selection = ed.selection;
14565
      const setElementFormat = (elm, fmt = format) => {
14566
        if (isFunction(fmt.onformat)) {
14567
          fmt.onformat(elm, fmt, vars, node);
14568
        }
14569
        applyStyles(dom, elm, fmt, vars);
14570
        each$5(fmt.attributes, (value, name) => {
14571
          dom.setAttrib(elm, name, replaceVars(value, vars));
14572
        });
14573
        each$5(fmt.classes, value => {
14574
          const newValue = replaceVars(value, vars);
14575
          if (!dom.hasClass(elm, newValue)) {
14576
            dom.addClass(elm, newValue);
14577
          }
14578
        });
14579
      };
14580
      const applyNodeStyle = (formatList, node) => {
14581
        let found = false;
14582
        each$5(formatList, format => {
14583
          if (!isSelectorFormat(format)) {
14584
            return false;
14585
          }
14586
          if (dom.getContentEditable(node) === 'false' && !format.ceFalseOverride) {
14587
            return true;
14588
          }
14589
          if (isNonNullable(format.collapsed) && format.collapsed !== isCollapsed) {
14590
            return true;
14591
          }
14592
          if (dom.is(node, format.selector) && !isCaretNode(node)) {
14593
            setElementFormat(node, format);
14594
            found = true;
14595
            return false;
14596
          }
14597
          return true;
14598
        });
14599
        return found;
14600
      };
14601
      const createWrapElement = wrapName => {
14602
        if (isString(wrapName)) {
14603
          const wrapElm = dom.create(wrapName);
14604
          setElementFormat(wrapElm);
14605
          return wrapElm;
14606
        } else {
14607
          return null;
14608
        }
14609
      };
14610
      const applyRngStyle = (dom, rng, nodeSpecific) => {
14611
        const newWrappers = [];
14612
        let contentEditable = true;
14613
        const wrapName = format.inline || format.block;
14614
        const wrapElm = createWrapElement(wrapName);
14615
        const isMatchingWrappingBlock = node => isWrappingBlockFormat(format) && matchNode(ed, node, name, vars);
14616
        const canRenameBlock = (node, parentName, isEditableDescendant) => {
14617
          const isValidBlockFormatForNode = isNonWrappingBlockFormat(format) && isTextBlock$1(ed.schema, node) && isValid(ed, parentName, wrapName);
14618
          return isEditableDescendant && isValidBlockFormatForNode;
14619
        };
14620
        const canWrapNode = (node, parentName, isEditableDescendant, isWrappableNoneditableElm) => {
14621
          const nodeName = node.nodeName.toLowerCase();
14622
          const isValidWrapNode = isValid(ed, wrapName, nodeName) && isValid(ed, parentName, wrapName);
1441 ariadna 14623
          const isZwsp$1 = !nodeSpecific && isText$b(node) && isZwsp(node.data);
1 efrain 14624
          const isCaret = isCaretNode(node);
14625
          const isCorrectFormatForNode = !isInlineFormat(format) || !dom.isBlock(node);
1441 ariadna 14626
          return (isEditableDescendant || isWrappableNoneditableElm) && isValidWrapNode && !isZwsp$1 && !isCaret && isCorrectFormatForNode;
1 efrain 14627
        };
14628
        walk$3(dom, rng, nodes => {
14629
          let currentWrapElm;
14630
          const process = node => {
14631
            let hasContentEditableState = false;
14632
            let lastContentEditable = contentEditable;
14633
            let isWrappableNoneditableElm = false;
14634
            const parentNode = node.parentNode;
14635
            const parentName = parentNode.nodeName.toLowerCase();
14636
            const contentEditableValue = dom.getContentEditable(node);
14637
            if (isNonNullable(contentEditableValue)) {
14638
              lastContentEditable = contentEditable;
14639
              contentEditable = contentEditableValue === 'true';
14640
              hasContentEditableState = true;
14641
              isWrappableNoneditableElm = isWrappableNoneditable(ed, node);
14642
            }
14643
            const isEditableDescendant = contentEditable && !hasContentEditableState;
14644
            if (isBr$6(node) && !canFormatBR(ed, format, node, parentName)) {
14645
              currentWrapElm = null;
14646
              if (isBlockFormat(format)) {
14647
                dom.remove(node);
14648
              }
14649
              return;
14650
            }
14651
            if (isMatchingWrappingBlock(node)) {
14652
              currentWrapElm = null;
14653
              return;
14654
            }
14655
            if (canRenameBlock(node, parentName, isEditableDescendant)) {
14656
              const elm = dom.rename(node, wrapName);
14657
              setElementFormat(elm);
14658
              newWrappers.push(elm);
14659
              currentWrapElm = null;
14660
              return;
14661
            }
14662
            if (isSelectorFormat(format)) {
14663
              let found = applyNodeStyle(formatList, node);
14664
              if (!found && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
14665
                found = applyNodeStyle(formatList, parentNode);
14666
              }
14667
              if (!isInlineFormat(format) || found) {
14668
                currentWrapElm = null;
14669
                return;
14670
              }
14671
            }
14672
            if (isNonNullable(wrapElm) && canWrapNode(node, parentName, isEditableDescendant, isWrappableNoneditableElm)) {
14673
              if (!currentWrapElm) {
14674
                currentWrapElm = dom.clone(wrapElm, false);
14675
                parentNode.insertBefore(currentWrapElm, node);
14676
                newWrappers.push(currentWrapElm);
14677
              }
14678
              if (isWrappableNoneditableElm && hasContentEditableState) {
14679
                contentEditable = lastContentEditable;
14680
              }
14681
              currentWrapElm.appendChild(node);
14682
            } else {
14683
              currentWrapElm = null;
14684
              each$e(from(node.childNodes), process);
14685
              if (hasContentEditableState) {
14686
                contentEditable = lastContentEditable;
14687
              }
14688
              currentWrapElm = null;
14689
            }
14690
          };
14691
          each$e(nodes, process);
14692
        });
14693
        if (format.links === true) {
14694
          each$e(newWrappers, node => {
14695
            const process = node => {
14696
              if (node.nodeName === 'A') {
14697
                setElementFormat(node, format);
14698
              }
14699
              each$e(from(node.childNodes), process);
14700
            };
14701
            process(node);
14702
          });
14703
        }
14704
        each$e(newWrappers, node => {
14705
          const getChildCount = node => {
14706
            let count = 0;
14707
            each$e(node.childNodes, node => {
14708
              if (!isEmptyTextNode$1(node) && !isBookmarkNode$1(node)) {
14709
                count++;
14710
              }
14711
            });
14712
            return count;
14713
          };
14714
          const mergeStyles = node => {
14715
            const childElement = find$2(node.childNodes, isElementNode$1).filter(child => dom.getContentEditable(child) !== 'false' && matchName(dom, child, format));
14716
            return childElement.map(child => {
14717
              const clone = dom.clone(child, false);
14718
              setElementFormat(clone);
14719
              dom.replace(clone, node, true);
14720
              dom.remove(child, true);
14721
              return clone;
14722
            }).getOr(node);
14723
          };
14724
          const childCount = getChildCount(node);
14725
          if ((newWrappers.length > 1 || !dom.isBlock(node)) && childCount === 0) {
14726
            dom.remove(node, true);
14727
            return;
14728
          }
14729
          if (isInlineFormat(format) || isBlockFormat(format) && format.wrapper) {
14730
            if (!format.exact && childCount === 1) {
14731
              node = mergeStyles(node);
14732
            }
14733
            mergeWithChildren(ed, formatList, vars, node);
14734
            mergeWithParents(ed, format, name, vars, node);
14735
            mergeBackgroundColorAndFontSize(dom, format, vars, node);
14736
            mergeTextDecorationsAndColor(dom, format, vars, node);
14737
            mergeSubSup(dom, format, vars, node);
14738
            mergeSiblings(ed, format, vars, node);
14739
          }
14740
        });
14741
      };
14742
      const targetNode = isNode(node) ? node : selection.getNode();
14743
      if (dom.getContentEditable(targetNode) === 'false' && !isWrappableNoneditable(ed, targetNode)) {
14744
        node = targetNode;
14745
        applyNodeStyle(formatList, node);
14746
        fireFormatApply(ed, name, node, vars);
14747
        return;
14748
      }
14749
      if (format) {
14750
        if (node) {
14751
          if (isNode(node)) {
14752
            if (!applyNodeStyle(formatList, node)) {
14753
              const rng = dom.createRng();
14754
              rng.setStartBefore(node);
14755
              rng.setEndAfter(node);
14756
              applyRngStyle(dom, expandRng(dom, rng, formatList), true);
14757
            }
14758
          } else {
14759
            applyRngStyle(dom, node, true);
14760
          }
14761
        } else {
14762
          if (!isCollapsed || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
14763
            selection.setRng(normalize(selection.getRng()));
14764
            preserveSelection(ed, () => {
14765
              runOnRanges(ed, (selectionRng, fake) => {
14766
                const expandedRng = fake ? selectionRng : expandRng(dom, selectionRng, formatList);
14767
                applyRngStyle(dom, expandedRng, false);
14768
              });
14769
            }, always);
14770
            ed.nodeChanged();
14771
          } else {
14772
            applyCaretFormat(ed, name, vars);
14773
          }
14774
          getExpandedListItemFormat(ed.formatter, name).each(liFmt => {
14775
            each$e(getFullySelectedListItems(ed.selection), li => applyStyles(dom, li, liFmt, vars));
14776
          });
14777
        }
14778
        postProcess$1(name, ed);
14779
      }
14780
      fireFormatApply(ed, name, node, vars);
14781
    };
14782
    const applyFormat$1 = (editor, name, vars, node) => {
14783
      if (node || editor.selection.isEditable()) {
14784
        applyFormatAction(editor, name, vars, node);
14785
      }
14786
    };
14787
 
14788
    const hasVars = value => has$2(value, 'vars');
14789
    const setup$u = (registeredFormatListeners, editor) => {
14790
      registeredFormatListeners.set({});
14791
      editor.on('NodeChange', e => {
14792
        updateAndFireChangeCallbacks(editor, e.element, registeredFormatListeners.get());
14793
      });
14794
      editor.on('FormatApply FormatRemove', e => {
14795
        const element = Optional.from(e.node).map(nodeOrRange => isNode(nodeOrRange) ? nodeOrRange : nodeOrRange.startContainer).bind(node => isElement$6(node) ? Optional.some(node) : Optional.from(node.parentElement)).getOrThunk(() => fallbackElement(editor));
14796
        updateAndFireChangeCallbacks(editor, element, registeredFormatListeners.get());
14797
      });
14798
    };
14799
    const fallbackElement = editor => editor.selection.getStart();
14800
    const matchingNode = (editor, parents, format, similar, vars) => {
14801
      const isMatchingNode = node => {
14802
        const matchingFormat = editor.formatter.matchNode(node, format, vars !== null && vars !== void 0 ? vars : {}, similar);
14803
        return !isUndefined(matchingFormat);
14804
      };
14805
      const isUnableToMatch = node => {
14806
        if (matchesUnInheritedFormatSelector(editor, node, format)) {
14807
          return true;
14808
        } else {
14809
          if (!similar) {
14810
            return isNonNullable(editor.formatter.matchNode(node, format, vars, true));
14811
          } else {
14812
            return false;
14813
          }
14814
        }
14815
      };
14816
      return findUntil$1(parents, isMatchingNode, isUnableToMatch);
14817
    };
14818
    const getParents = (editor, elm) => {
14819
      const element = elm !== null && elm !== void 0 ? elm : fallbackElement(editor);
1441 ariadna 14820
      return filter$5(getParents$2(editor.dom, element), node => isElement$6(node) && !isBogus$1(node));
1 efrain 14821
    };
14822
    const updateAndFireChangeCallbacks = (editor, elm, registeredCallbacks) => {
14823
      const parents = getParents(editor, elm);
14824
      each$d(registeredCallbacks, (data, format) => {
14825
        const runIfChanged = spec => {
14826
          const match = matchingNode(editor, parents, format, spec.similar, hasVars(spec) ? spec.vars : undefined);
14827
          const isSet = match.isSome();
14828
          if (spec.state.get() !== isSet) {
14829
            spec.state.set(isSet);
14830
            const node = match.getOr(elm);
14831
            if (hasVars(spec)) {
14832
              spec.callback(isSet, {
14833
                node,
14834
                format,
14835
                parents
14836
              });
14837
            } else {
14838
              each$e(spec.callbacks, callback => callback(isSet, {
14839
                node,
14840
                format,
14841
                parents
14842
              }));
14843
            }
14844
          }
14845
        };
14846
        each$e([
14847
          data.withSimilar,
14848
          data.withoutSimilar
14849
        ], runIfChanged);
14850
        each$e(data.withVars, runIfChanged);
14851
      });
14852
    };
14853
    const addListeners = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
14854
      const formatChangeItems = registeredFormatListeners.get();
14855
      each$e(formats.split(','), format => {
14856
        const group = get$a(formatChangeItems, format).getOrThunk(() => {
14857
          const base = {
14858
            withSimilar: {
14859
              state: Cell(false),
14860
              similar: true,
14861
              callbacks: []
14862
            },
14863
            withoutSimilar: {
14864
              state: Cell(false),
14865
              similar: false,
14866
              callbacks: []
14867
            },
14868
            withVars: []
14869
          };
14870
          formatChangeItems[format] = base;
14871
          return base;
14872
        });
14873
        const getCurrent = () => {
14874
          const parents = getParents(editor);
14875
          return matchingNode(editor, parents, format, similar, vars).isSome();
14876
        };
14877
        if (isUndefined(vars)) {
14878
          const toAppendTo = similar ? group.withSimilar : group.withoutSimilar;
14879
          toAppendTo.callbacks.push(callback);
14880
          if (toAppendTo.callbacks.length === 1) {
14881
            toAppendTo.state.set(getCurrent());
14882
          }
14883
        } else {
14884
          group.withVars.push({
14885
            state: Cell(getCurrent()),
14886
            similar,
14887
            vars,
14888
            callback
14889
          });
14890
        }
14891
      });
14892
      registeredFormatListeners.set(formatChangeItems);
14893
    };
14894
    const removeListeners = (registeredFormatListeners, formats, callback) => {
14895
      const formatChangeItems = registeredFormatListeners.get();
14896
      each$e(formats.split(','), format => get$a(formatChangeItems, format).each(group => {
14897
        formatChangeItems[format] = {
14898
          withSimilar: {
14899
            ...group.withSimilar,
14900
            callbacks: filter$5(group.withSimilar.callbacks, cb => cb !== callback)
14901
          },
14902
          withoutSimilar: {
14903
            ...group.withoutSimilar,
14904
            callbacks: filter$5(group.withoutSimilar.callbacks, cb => cb !== callback)
14905
          },
14906
          withVars: filter$5(group.withVars, item => item.callback !== callback)
14907
        };
14908
      }));
14909
      registeredFormatListeners.set(formatChangeItems);
14910
    };
14911
    const formatChangedInternal = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
14912
      addListeners(editor, registeredFormatListeners, formats, callback, similar, vars);
14913
      return { unbind: () => removeListeners(registeredFormatListeners, formats, callback) };
14914
    };
14915
 
14916
    const toggle = (editor, name, vars, node) => {
14917
      const fmt = editor.formatter.get(name);
14918
      if (fmt) {
14919
        if (match$2(editor, name, vars, node) && (!('toggle' in fmt[0]) || fmt[0].toggle)) {
14920
          removeFormat$1(editor, name, vars, node);
14921
        } else {
14922
          applyFormat$1(editor, name, vars, node);
14923
        }
14924
      }
14925
    };
14926
 
14927
    const explode$1 = Tools.explode;
14928
    const create$8 = () => {
14929
      const filters = {};
14930
      const addFilter = (name, callback) => {
14931
        each$e(explode$1(name), name => {
14932
          if (!has$2(filters, name)) {
14933
            filters[name] = {
14934
              name,
14935
              callbacks: []
14936
            };
14937
          }
14938
          filters[name].callbacks.push(callback);
14939
        });
14940
      };
14941
      const getFilters = () => values(filters);
14942
      const removeFilter = (name, callback) => {
14943
        each$e(explode$1(name), name => {
14944
          if (has$2(filters, name)) {
14945
            if (isNonNullable(callback)) {
14946
              const filter = filters[name];
14947
              const newCallbacks = filter$5(filter.callbacks, c => c !== callback);
14948
              if (newCallbacks.length > 0) {
14949
                filter.callbacks = newCallbacks;
14950
              } else {
14951
                delete filters[name];
14952
              }
14953
            } else {
14954
              delete filters[name];
14955
            }
14956
          }
14957
        });
14958
      };
14959
      return {
14960
        addFilter,
14961
        getFilters,
14962
        removeFilter
14963
      };
14964
    };
14965
 
14966
    const removeAttrs = (node, names) => {
14967
      each$e(names, name => {
14968
        node.attr(name, null);
14969
      });
14970
    };
14971
    const addFontToSpansFilter = (domParser, styles, fontSizes) => {
14972
      domParser.addNodeFilter('font', nodes => {
14973
        each$e(nodes, node => {
14974
          const props = styles.parse(node.attr('style'));
14975
          const color = node.attr('color');
14976
          const face = node.attr('face');
14977
          const size = node.attr('size');
14978
          if (color) {
14979
            props.color = color;
14980
          }
14981
          if (face) {
14982
            props['font-family'] = face;
14983
          }
14984
          if (size) {
14985
            toInt(size).each(num => {
14986
              props['font-size'] = fontSizes[num - 1];
14987
            });
14988
          }
14989
          node.name = 'span';
14990
          node.attr('style', styles.serialize(props));
14991
          removeAttrs(node, [
14992
            'color',
14993
            'face',
14994
            'size'
14995
          ]);
14996
        });
14997
      });
14998
    };
14999
    const addStrikeFilter = (domParser, schema, styles) => {
15000
      domParser.addNodeFilter('strike', nodes => {
15001
        const convertToSTag = schema.type !== 'html4';
15002
        each$e(nodes, node => {
15003
          if (convertToSTag) {
15004
            node.name = 's';
15005
          } else {
15006
            const props = styles.parse(node.attr('style'));
15007
            props['text-decoration'] = 'line-through';
15008
            node.name = 'span';
15009
            node.attr('style', styles.serialize(props));
15010
          }
15011
        });
15012
      });
15013
    };
15014
    const addFilters = (domParser, settings, schema) => {
15015
      var _a;
15016
      const styles = Styles();
15017
      if (settings.convert_fonts_to_spans) {
15018
        addFontToSpansFilter(domParser, styles, Tools.explode((_a = settings.font_size_legacy_values) !== null && _a !== void 0 ? _a : ''));
15019
      }
15020
      addStrikeFilter(domParser, schema, styles);
15021
    };
15022
    const register$5 = (domParser, settings, schema) => {
15023
      if (settings.inline_styles) {
15024
        addFilters(domParser, settings, schema);
15025
      }
15026
    };
15027
 
15028
    const blobUriToBlob = url => fetch(url).then(res => res.ok ? res.blob() : Promise.reject()).catch(() => Promise.reject({
15029
      message: `Cannot convert ${ url } to Blob. Resource might not exist or is inaccessible.`,
15030
      uriType: 'blob'
15031
    }));
15032
    const extractBase64Data = data => {
15033
      const matches = /([a-z0-9+\/=\s]+)/i.exec(data);
15034
      return matches ? matches[1] : '';
15035
    };
1441 ariadna 15036
    const decodeData = data => {
15037
      try {
15038
        return decodeURIComponent(data);
15039
      } catch (_a) {
15040
        return data;
15041
      }
15042
    };
1 efrain 15043
    const parseDataUri = uri => {
15044
      const [type, ...rest] = uri.split(',');
15045
      const data = rest.join(',');
15046
      const matches = /data:([^/]+\/[^;]+)(;.+)?/.exec(type);
15047
      if (matches) {
15048
        const base64Encoded = matches[2] === ';base64';
1441 ariadna 15049
        const decodedData = decodeData(data);
15050
        const extractedData = base64Encoded ? extractBase64Data(decodedData) : decodedData;
1 efrain 15051
        return Optional.some({
15052
          type: matches[1],
15053
          data: extractedData,
15054
          base64Encoded
15055
        });
15056
      } else {
15057
        return Optional.none();
15058
      }
15059
    };
15060
    const buildBlob = (type, data, base64Encoded = true) => {
15061
      let str = data;
15062
      if (base64Encoded) {
15063
        try {
15064
          str = atob(data);
1441 ariadna 15065
        } catch (_a) {
1 efrain 15066
          return Optional.none();
15067
        }
15068
      }
15069
      const arr = new Uint8Array(str.length);
15070
      for (let i = 0; i < arr.length; i++) {
15071
        arr[i] = str.charCodeAt(i);
15072
      }
15073
      return Optional.some(new Blob([arr], { type }));
15074
    };
15075
    const dataUriToBlob = uri => {
15076
      return new Promise((resolve, reject) => {
15077
        parseDataUri(uri).bind(({type, data, base64Encoded}) => buildBlob(type, data, base64Encoded)).fold(() => reject('Invalid data URI'), resolve);
15078
      });
15079
    };
15080
    const uriToBlob = url => {
15081
      if (startsWith(url, 'blob:')) {
15082
        return blobUriToBlob(url);
15083
      } else if (startsWith(url, 'data:')) {
15084
        return dataUriToBlob(url);
15085
      } else {
15086
        return Promise.reject('Unknown URI format');
15087
      }
15088
    };
15089
    const blobToDataUri = blob => {
15090
      return new Promise((resolve, reject) => {
15091
        const reader = new FileReader();
15092
        reader.onloadend = () => {
15093
          resolve(reader.result);
15094
        };
15095
        reader.onerror = () => {
15096
          var _a;
15097
          reject((_a = reader.error) === null || _a === void 0 ? void 0 : _a.message);
15098
        };
15099
        reader.readAsDataURL(blob);
15100
      });
15101
    };
15102
 
15103
    let count$1 = 0;
15104
    const uniqueId$1 = prefix => {
15105
      return (prefix || 'blobid') + count$1++;
15106
    };
15107
    const processDataUri = (dataUri, base64Only, generateBlobInfo) => {
15108
      return parseDataUri(dataUri).bind(({data, type, base64Encoded}) => {
15109
        if (base64Only && !base64Encoded) {
15110
          return Optional.none();
15111
        } else {
15112
          const base64 = base64Encoded ? data : btoa(data);
15113
          return generateBlobInfo(base64, type);
15114
        }
15115
      });
15116
    };
15117
    const createBlobInfo$1 = (blobCache, blob, base64) => {
15118
      const blobInfo = blobCache.create(uniqueId$1(), blob, base64);
15119
      blobCache.add(blobInfo);
15120
      return blobInfo;
15121
    };
15122
    const dataUriToBlobInfo = (blobCache, dataUri, base64Only = false) => {
15123
      return processDataUri(dataUri, base64Only, (base64, type) => Optional.from(blobCache.getByData(base64, type)).orThunk(() => buildBlob(type, base64).map(blob => createBlobInfo$1(blobCache, blob, base64))));
15124
    };
15125
    const imageToBlobInfo = (blobCache, imageSrc) => {
15126
      const invalidDataUri = () => Promise.reject('Invalid data URI');
15127
      if (startsWith(imageSrc, 'blob:')) {
15128
        const blobInfo = blobCache.getByUri(imageSrc);
15129
        if (isNonNullable(blobInfo)) {
15130
          return Promise.resolve(blobInfo);
15131
        } else {
15132
          return uriToBlob(imageSrc).then(blob => {
15133
            return blobToDataUri(blob).then(dataUri => {
15134
              return processDataUri(dataUri, false, base64 => {
15135
                return Optional.some(createBlobInfo$1(blobCache, blob, base64));
15136
              }).getOrThunk(invalidDataUri);
15137
            });
15138
          });
15139
        }
15140
      } else if (startsWith(imageSrc, 'data:')) {
15141
        return dataUriToBlobInfo(blobCache, imageSrc).fold(invalidDataUri, blobInfo => Promise.resolve(blobInfo));
15142
      } else {
15143
        return Promise.reject('Unknown image data format');
15144
      }
15145
    };
15146
 
1441 ariadna 15147
    const hostCaptureRegex = /^(?:(?:(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)([A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*))(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+)?)?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+)?)?)$/;
15148
    const extractHost = url => Optional.from(url.match(hostCaptureRegex)).bind(ms => get$b(ms, 1)).map(h => startsWith(h, 'www.') ? h.substring(4) : h);
15149
 
15150
    const sandboxIframe = (iframeNode, exclusions) => {
15151
      if (Optional.from(iframeNode.attr('src')).bind(extractHost).forall(host => !contains$2(exclusions, host))) {
15152
        iframeNode.attr('sandbox', '');
1 efrain 15153
      }
15154
    };
15155
    const isMimeType = (mime, type) => startsWith(mime, `${ type }/`);
1441 ariadna 15156
    const getEmbedType = type => {
15157
      if (isUndefined(type)) {
15158
        return 'iframe';
15159
      } else if (isMimeType(type, 'image')) {
15160
        return 'img';
15161
      } else if (isMimeType(type, 'video')) {
15162
        return 'video';
15163
      } else if (isMimeType(type, 'audio')) {
15164
        return 'audio';
1 efrain 15165
      } else {
1441 ariadna 15166
        return 'iframe';
1 efrain 15167
      }
1441 ariadna 15168
    };
15169
    const createSafeEmbed = ({type, src, width, height} = {}, sandboxIframes, sandboxIframesExclusions) => {
15170
      const name = getEmbedType(type);
1 efrain 15171
      const embed = new AstNode(name, 1);
15172
      embed.attr(name === 'audio' ? { src } : {
15173
        src,
15174
        width,
15175
        height
15176
      });
15177
      if (name === 'audio' || name === 'video') {
15178
        embed.attr('controls', '');
15179
      }
15180
      if (name === 'iframe' && sandboxIframes) {
1441 ariadna 15181
        sandboxIframe(embed, sandboxIframesExclusions);
1 efrain 15182
      }
15183
      return embed;
15184
    };
1441 ariadna 15185
 
15186
    const isBogusImage = img => isNonNullable(img.attr('data-mce-bogus'));
15187
    const isInternalImageSource = img => img.attr('src') === Env.transparentSrc || isNonNullable(img.attr('data-mce-placeholder'));
15188
    const registerBase64ImageFilter = (parser, settings) => {
15189
      const {blob_cache: blobCache} = settings;
15190
      if (blobCache) {
15191
        const processImage = img => {
15192
          const inputSrc = img.attr('src');
15193
          if (isInternalImageSource(img) || isBogusImage(img) || isNullable(inputSrc)) {
15194
            return;
15195
          }
15196
          dataUriToBlobInfo(blobCache, inputSrc, true).each(blobInfo => {
15197
            img.attr('src', blobInfo.blobUri());
15198
          });
15199
        };
15200
        parser.addAttributeFilter('src', nodes => each$e(nodes, processImage));
15201
      }
15202
    };
1 efrain 15203
    const register$4 = (parser, settings) => {
1441 ariadna 15204
      var _a, _b;
1 efrain 15205
      const schema = parser.schema;
15206
      parser.addAttributeFilter('href', nodes => {
15207
        let i = nodes.length;
15208
        const appendRel = rel => {
15209
          const parts = rel.split(' ').filter(p => p.length > 0);
15210
          return parts.concat(['noopener']).sort().join(' ');
15211
        };
15212
        const addNoOpener = rel => {
15213
          const newRel = rel ? Tools.trim(rel) : '';
15214
          if (!/\b(noopener)\b/g.test(newRel)) {
15215
            return appendRel(newRel);
15216
          } else {
15217
            return newRel;
15218
          }
15219
        };
15220
        if (!settings.allow_unsafe_link_target) {
15221
          while (i--) {
15222
            const node = nodes[i];
15223
            if (node.name === 'a' && node.attr('target') === '_blank') {
15224
              node.attr('rel', addNoOpener(node.attr('rel')));
15225
            }
15226
          }
15227
        }
15228
      });
15229
      if (!settings.allow_html_in_named_anchor) {
15230
        parser.addAttributeFilter('id,name', nodes => {
15231
          let i = nodes.length, sibling, prevSibling, parent, node;
15232
          while (i--) {
15233
            node = nodes[i];
15234
            if (node.name === 'a' && node.firstChild && !node.attr('href')) {
15235
              parent = node.parent;
15236
              sibling = node.lastChild;
15237
              while (sibling && parent) {
15238
                prevSibling = sibling.prev;
15239
                parent.insert(sibling, node);
15240
                sibling = prevSibling;
15241
              }
15242
            }
15243
          }
15244
        });
15245
      }
15246
      if (settings.fix_list_elements) {
15247
        parser.addNodeFilter('ul,ol', nodes => {
15248
          let i = nodes.length, node, parentNode;
15249
          while (i--) {
15250
            node = nodes[i];
15251
            parentNode = node.parent;
15252
            if (parentNode && (parentNode.name === 'ul' || parentNode.name === 'ol')) {
15253
              if (node.prev && node.prev.name === 'li') {
15254
                node.prev.append(node);
15255
              } else {
15256
                const li = new AstNode('li', 1);
15257
                li.attr('style', 'list-style-type: none');
15258
                node.wrap(li);
15259
              }
15260
            }
15261
          }
15262
        });
15263
      }
15264
      const validClasses = schema.getValidClasses();
15265
      if (settings.validate && validClasses) {
15266
        parser.addAttributeFilter('class', nodes => {
15267
          var _a;
15268
          let i = nodes.length;
15269
          while (i--) {
15270
            const node = nodes[i];
15271
            const clazz = (_a = node.attr('class')) !== null && _a !== void 0 ? _a : '';
15272
            const classList = Tools.explode(clazz, ' ');
15273
            let classValue = '';
15274
            for (let ci = 0; ci < classList.length; ci++) {
15275
              const className = classList[ci];
15276
              let valid = false;
15277
              let validClassesMap = validClasses['*'];
15278
              if (validClassesMap && validClassesMap[className]) {
15279
                valid = true;
15280
              }
15281
              validClassesMap = validClasses[node.name];
15282
              if (!valid && validClassesMap && validClassesMap[className]) {
15283
                valid = true;
15284
              }
15285
              if (valid) {
15286
                if (classValue) {
15287
                  classValue += ' ';
15288
                }
15289
                classValue += className;
15290
              }
15291
            }
15292
            if (!classValue.length) {
15293
              classValue = null;
15294
            }
15295
            node.attr('class', classValue);
15296
          }
15297
        });
15298
      }
15299
      registerBase64ImageFilter(parser, settings);
1441 ariadna 15300
      const shouldSandboxIframes = (_a = settings.sandbox_iframes) !== null && _a !== void 0 ? _a : false;
15301
      const sandboxIframesExclusions = unique$1((_b = settings.sandbox_iframes_exclusions) !== null && _b !== void 0 ? _b : []);
1 efrain 15302
      if (settings.convert_unsafe_embeds) {
15303
        parser.addNodeFilter('object,embed', nodes => each$e(nodes, node => {
1441 ariadna 15304
          node.replace(createSafeEmbed({
15305
            type: node.attr('type'),
15306
            src: node.name === 'object' ? node.attr('data') : node.attr('src'),
15307
            width: node.attr('width'),
15308
            height: node.attr('height')
15309
          }, shouldSandboxIframes, sandboxIframesExclusions));
1 efrain 15310
        }));
15311
      }
1441 ariadna 15312
      if (shouldSandboxIframes) {
15313
        parser.addNodeFilter('iframe', nodes => each$e(nodes, node => sandboxIframe(node, sandboxIframesExclusions)));
1 efrain 15314
      }
15315
    };
15316
 
1441 ariadna 15317
    /*! @license DOMPurify 3.2.4 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.4/LICENSE */
15318
 
15319
    const {
15320
      entries,
15321
      setPrototypeOf,
15322
      isFrozen,
15323
      getPrototypeOf,
15324
      getOwnPropertyDescriptor
15325
    } = Object;
15326
    let {
15327
      freeze,
15328
      seal,
15329
      create: create$7
15330
    } = Object; // eslint-disable-line import/no-mutable-exports
15331
    let {
15332
      apply,
15333
      construct
15334
    } = typeof Reflect !== 'undefined' && Reflect;
1 efrain 15335
    if (!freeze) {
15336
      freeze = function freeze(x) {
15337
        return x;
15338
      };
15339
    }
15340
    if (!seal) {
15341
      seal = function seal(x) {
15342
        return x;
15343
      };
15344
    }
1441 ariadna 15345
    if (!apply) {
15346
      apply = function apply(fun, thisValue, args) {
15347
        return fun.apply(thisValue, args);
15348
      };
15349
    }
1 efrain 15350
    if (!construct) {
15351
      construct = function construct(Func, args) {
15352
        return new Func(...args);
15353
      };
15354
    }
15355
    const arrayForEach = unapply(Array.prototype.forEach);
1441 ariadna 15356
    const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
1 efrain 15357
    const arrayPop = unapply(Array.prototype.pop);
15358
    const arrayPush = unapply(Array.prototype.push);
1441 ariadna 15359
    const arraySplice = unapply(Array.prototype.splice);
1 efrain 15360
    const stringToLowerCase = unapply(String.prototype.toLowerCase);
15361
    const stringToString = unapply(String.prototype.toString);
15362
    const stringMatch = unapply(String.prototype.match);
15363
    const stringReplace = unapply(String.prototype.replace);
15364
    const stringIndexOf = unapply(String.prototype.indexOf);
15365
    const stringTrim = unapply(String.prototype.trim);
1441 ariadna 15366
    const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
1 efrain 15367
    const regExpTest = unapply(RegExp.prototype.test);
15368
    const typeErrorCreate = unconstruct(TypeError);
1441 ariadna 15369
    /**
15370
     * Creates a new function that calls the given function with a specified thisArg and arguments.
15371
     *
15372
     * @param func - The function to be wrapped and called.
15373
     * @returns A new function that calls the given function with a specified thisArg and arguments.
15374
     */
1 efrain 15375
    function unapply(func) {
15376
      return function (thisArg) {
15377
        for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
15378
          args[_key - 1] = arguments[_key];
15379
        }
15380
        return apply(func, thisArg, args);
15381
      };
15382
    }
1441 ariadna 15383
    /**
15384
     * Creates a new function that constructs an instance of the given constructor function with the provided arguments.
15385
     *
15386
     * @param func - The constructor function to be wrapped and called.
15387
     * @returns A new function that constructs an instance of the given constructor function with the provided arguments.
15388
     */
1 efrain 15389
    function unconstruct(func) {
15390
      return function () {
15391
        for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
15392
          args[_key2] = arguments[_key2];
15393
        }
15394
        return construct(func, args);
15395
      };
15396
    }
1441 ariadna 15397
    /**
15398
     * Add properties to a lookup table
15399
     *
15400
     * @param set - The set to which elements will be added.
15401
     * @param array - The array containing elements to be added to the set.
15402
     * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
15403
     * @returns The modified set with added elements.
15404
     */
15405
    function addToSet(set, array) {
15406
      let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
1 efrain 15407
      if (setPrototypeOf) {
1441 ariadna 15408
        // Make 'in' and truthy checks like Boolean(set.constructor)
15409
        // independent of any properties defined on Object.prototype.
15410
        // Prevent prototype setters from intercepting set as a this value.
1 efrain 15411
        setPrototypeOf(set, null);
15412
      }
15413
      let l = array.length;
15414
      while (l--) {
15415
        let element = array[l];
15416
        if (typeof element === 'string') {
15417
          const lcElement = transformCaseFunc(element);
15418
          if (lcElement !== element) {
1441 ariadna 15419
            // Config presets (e.g. tags.js, attrs.js) are immutable.
1 efrain 15420
            if (!isFrozen(array)) {
15421
              array[l] = lcElement;
15422
            }
15423
            element = lcElement;
15424
          }
15425
        }
15426
        set[element] = true;
15427
      }
15428
      return set;
15429
    }
1441 ariadna 15430
    /**
15431
     * Clean up an array to harden against CSPP
15432
     *
15433
     * @param array - The array to be cleaned.
15434
     * @returns The cleaned version of the array
15435
     */
15436
    function cleanArray(array) {
15437
      for (let index = 0; index < array.length; index++) {
15438
        const isPropertyExist = objectHasOwnProperty(array, index);
15439
        if (!isPropertyExist) {
15440
          array[index] = null;
15441
        }
15442
      }
15443
      return array;
15444
    }
15445
    /**
15446
     * Shallow clone an object
15447
     *
15448
     * @param object - The object to be cloned.
15449
     * @returns A new object that copies the original.
15450
     */
1 efrain 15451
    function clone(object) {
15452
      const newObject = create$7(null);
15453
      for (const [property, value] of entries(object)) {
1441 ariadna 15454
        const isPropertyExist = objectHasOwnProperty(object, property);
15455
        if (isPropertyExist) {
15456
          if (Array.isArray(value)) {
15457
            newObject[property] = cleanArray(value);
15458
          } else if (value && typeof value === 'object' && value.constructor === Object) {
15459
            newObject[property] = clone(value);
15460
          } else {
15461
            newObject[property] = value;
15462
          }
15463
        }
1 efrain 15464
      }
15465
      return newObject;
15466
    }
1441 ariadna 15467
    /**
15468
     * This method automatically checks if the prop is function or getter and behaves accordingly.
15469
     *
15470
     * @param object - The object to look up the getter function in its prototype chain.
15471
     * @param prop - The property name for which to find the getter function.
15472
     * @returns The getter function found in the prototype chain or a fallback function.
15473
     */
1 efrain 15474
    function lookupGetter(object, prop) {
15475
      while (object !== null) {
15476
        const desc = getOwnPropertyDescriptor(object, prop);
15477
        if (desc) {
15478
          if (desc.get) {
15479
            return unapply(desc.get);
15480
          }
15481
          if (typeof desc.value === 'function') {
15482
            return unapply(desc.value);
15483
          }
15484
        }
15485
        object = getPrototypeOf(object);
15486
      }
1441 ariadna 15487
      function fallbackValue() {
1 efrain 15488
        return null;
15489
      }
15490
      return fallbackValue;
15491
    }
1441 ariadna 15492
 
15493
    const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
15494
    const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
15495
    const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
15496
    // List of SVG elements that are disallowed by default.
15497
    // We still need to know them so that we can do namespace
15498
    // checks properly in case one wants to add them to
15499
    // allow-list.
15500
    const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);
15501
    const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']);
15502
    // Similarly to SVG, we want to know all MathML elements,
15503
    // even those that we disallow by default.
15504
    const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
1 efrain 15505
    const text = freeze(['#text']);
1441 ariadna 15506
 
15507
    const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
15508
    const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
15509
    const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
15510
    const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
15511
 
15512
    // eslint-disable-next-line unicorn/better-regex
15513
    const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
1 efrain 15514
    const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
1441 ariadna 15515
    const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
15516
    const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
15517
    const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
15518
    const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
15519
    );
1 efrain 15520
    const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
1441 ariadna 15521
    const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
15522
    );
1 efrain 15523
    const DOCTYPE_NAME = seal(/^html$/i);
1441 ariadna 15524
    const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
15525
 
15526
    var EXPRESSIONS = /*#__PURE__*/Object.freeze({
1 efrain 15527
      __proto__: null,
1441 ariadna 15528
      ARIA_ATTR: ARIA_ATTR,
15529
      ATTR_WHITESPACE: ATTR_WHITESPACE,
15530
      CUSTOM_ELEMENT: CUSTOM_ELEMENT,
15531
      DATA_ATTR: DATA_ATTR,
15532
      DOCTYPE_NAME: DOCTYPE_NAME,
1 efrain 15533
      ERB_EXPR: ERB_EXPR,
15534
      IS_ALLOWED_URI: IS_ALLOWED_URI,
15535
      IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
1441 ariadna 15536
      MUSTACHE_EXPR: MUSTACHE_EXPR,
15537
      TMPLIT_EXPR: TMPLIT_EXPR
1 efrain 15538
    });
1441 ariadna 15539
 
15540
    /* eslint-disable @typescript-eslint/indent */
15541
    // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
15542
    const NODE_TYPE = {
15543
      element: 1,
15544
      attribute: 2,
15545
      text: 3,
15546
      cdataSection: 4,
15547
      entityReference: 5,
15548
      // Deprecated
15549
      entityNode: 6,
15550
      // Deprecated
15551
      progressingInstruction: 7,
15552
      comment: 8,
15553
      document: 9,
15554
      documentType: 10,
15555
      documentFragment: 11,
15556
      notation: 12 // Deprecated
15557
    };
15558
    const getGlobal = function getGlobal() {
15559
      return typeof window === 'undefined' ? null : window;
15560
    };
15561
    /**
15562
     * Creates a no-op policy for internal use only.
15563
     * Don't export this function outside this module!
15564
     * @param trustedTypes The policy factory.
15565
     * @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
15566
     * @return The policy created (or null, if Trusted Types
15567
     * are not supported or creating the policy failed).
15568
     */
1 efrain 15569
    const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
15570
      if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
15571
        return null;
15572
      }
1441 ariadna 15573
      // Allow the callers to control the unique policy name
15574
      // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
15575
      // Policy creation with duplicate names throws in Trusted Types.
1 efrain 15576
      let suffix = null;
15577
      const ATTR_NAME = 'data-tt-policy-suffix';
15578
      if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
15579
        suffix = purifyHostElement.getAttribute(ATTR_NAME);
15580
      }
15581
      const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
15582
      try {
15583
        return trustedTypes.createPolicy(policyName, {
15584
          createHTML(html) {
15585
            return html;
15586
          },
15587
          createScriptURL(scriptUrl) {
15588
            return scriptUrl;
15589
          }
15590
        });
15591
      } catch (_) {
1441 ariadna 15592
        // Policy creation failed (most likely another DOMPurify script has
15593
        // already run). Skip creating the policy, as this will only cause errors
15594
        // if TT are enforced.
1 efrain 15595
        console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
15596
        return null;
15597
      }
15598
    };
1441 ariadna 15599
    const _createHooksMap = function _createHooksMap() {
15600
      return {
15601
        afterSanitizeAttributes: [],
15602
        afterSanitizeElements: [],
15603
        afterSanitizeShadowDOM: [],
15604
        beforeSanitizeAttributes: [],
15605
        beforeSanitizeElements: [],
15606
        beforeSanitizeShadowDOM: [],
15607
        uponSanitizeAttribute: [],
15608
        uponSanitizeElement: [],
15609
        uponSanitizeShadowNode: []
15610
      };
15611
    };
1 efrain 15612
    function createDOMPurify() {
15613
      let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
15614
      const DOMPurify = root => createDOMPurify(root);
1441 ariadna 15615
      DOMPurify.version = '3.2.4';
1 efrain 15616
      DOMPurify.removed = [];
1441 ariadna 15617
      if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
15618
        // Not running in a browser, provide a factory function
15619
        // so that you can pass your own Window
1 efrain 15620
        DOMPurify.isSupported = false;
15621
        return DOMPurify;
15622
      }
1441 ariadna 15623
      let {
15624
        document
15625
      } = window;
15626
      const originalDocument = document;
1 efrain 15627
      const currentScript = originalDocument.currentScript;
1441 ariadna 15628
      const {
15629
        DocumentFragment,
15630
        HTMLTemplateElement,
15631
        Node,
15632
        Element,
15633
        NodeFilter,
15634
        NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
15635
        HTMLFormElement,
15636
        DOMParser,
15637
        trustedTypes
15638
      } = window;
1 efrain 15639
      const ElementPrototype = Element.prototype;
15640
      const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
1441 ariadna 15641
      const remove = lookupGetter(ElementPrototype, 'remove');
1 efrain 15642
      const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
15643
      const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
15644
      const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
1441 ariadna 15645
      // As per issue #47, the web-components registry is inherited by a
15646
      // new document created via createHTMLDocument. As per the spec
15647
      // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
15648
      // a new empty registry is used when creating a template contents owner
15649
      // document, so we use that as our parent document to ensure nothing
15650
      // is inherited.
1 efrain 15651
      if (typeof HTMLTemplateElement === 'function') {
15652
        const template = document.createElement('template');
15653
        if (template.content && template.content.ownerDocument) {
15654
          document = template.content.ownerDocument;
15655
        }
15656
      }
15657
      let trustedTypesPolicy;
15658
      let emptyHTML = '';
1441 ariadna 15659
      const {
15660
        implementation,
15661
        createNodeIterator,
15662
        createDocumentFragment,
15663
        getElementsByTagName
15664
      } = document;
15665
      const {
15666
        importNode
15667
      } = originalDocument;
15668
      let hooks = _createHooksMap();
15669
      /**
15670
       * Expose whether this browser supports running the full DOMPurify.
15671
       */
1 efrain 15672
      DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
1441 ariadna 15673
      const {
15674
        MUSTACHE_EXPR,
15675
        ERB_EXPR,
15676
        TMPLIT_EXPR,
15677
        DATA_ATTR,
15678
        ARIA_ATTR,
15679
        IS_SCRIPT_OR_DATA,
15680
        ATTR_WHITESPACE,
15681
        CUSTOM_ELEMENT
15682
      } = EXPRESSIONS;
15683
      let {
15684
        IS_ALLOWED_URI: IS_ALLOWED_URI$1
15685
      } = EXPRESSIONS;
15686
      /**
15687
       * We consider the elements and attributes below to be safe. Ideally
15688
       * don't add any new ones but feel free to remove unwanted ones.
15689
       */
15690
      /* allowed element names */
1 efrain 15691
      let ALLOWED_TAGS = null;
1441 ariadna 15692
      const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
15693
      /* Allowed attribute names */
1 efrain 15694
      let ALLOWED_ATTR = null;
1441 ariadna 15695
      const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
15696
      /*
15697
       * Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.
15698
       * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
15699
       * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
15700
       * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
15701
       */
15702
      let CUSTOM_ELEMENT_HANDLING = Object.seal(create$7(null, {
1 efrain 15703
        tagNameCheck: {
15704
          writable: true,
15705
          configurable: false,
15706
          enumerable: true,
15707
          value: null
15708
        },
15709
        attributeNameCheck: {
15710
          writable: true,
15711
          configurable: false,
15712
          enumerable: true,
15713
          value: null
15714
        },
15715
        allowCustomizedBuiltInElements: {
15716
          writable: true,
15717
          configurable: false,
15718
          enumerable: true,
15719
          value: false
15720
        }
15721
      }));
1441 ariadna 15722
      /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
1 efrain 15723
      let FORBID_TAGS = null;
1441 ariadna 15724
      /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
1 efrain 15725
      let FORBID_ATTR = null;
1441 ariadna 15726
      /* Decide if ARIA attributes are okay */
1 efrain 15727
      let ALLOW_ARIA_ATTR = true;
1441 ariadna 15728
      /* Decide if custom data attributes are okay */
1 efrain 15729
      let ALLOW_DATA_ATTR = true;
1441 ariadna 15730
      /* Decide if unknown protocols are okay */
1 efrain 15731
      let ALLOW_UNKNOWN_PROTOCOLS = false;
1441 ariadna 15732
      /* Decide if self-closing tags in attributes are allowed.
15733
       * Usually removed due to a mXSS issue in jQuery 3.0 */
1 efrain 15734
      let ALLOW_SELF_CLOSE_IN_ATTR = true;
1441 ariadna 15735
      /* Output should be safe for common template engines.
15736
       * This means, DOMPurify removes data attributes, mustaches and ERB
15737
       */
1 efrain 15738
      let SAFE_FOR_TEMPLATES = false;
1441 ariadna 15739
      /* Output should be safe even for XML used within HTML and alike.
15740
       * This means, DOMPurify removes comments when containing risky content.
15741
       */
15742
      let SAFE_FOR_XML = true;
15743
      /* Decide if document with <html>... should be returned */
1 efrain 15744
      let WHOLE_DOCUMENT = false;
1441 ariadna 15745
      /* Track whether config is already set on this instance of DOMPurify. */
1 efrain 15746
      let SET_CONFIG = false;
1441 ariadna 15747
      /* Decide if all elements (e.g. style, script) must be children of
15748
       * document.body. By default, browsers might move them to document.head */
1 efrain 15749
      let FORCE_BODY = false;
1441 ariadna 15750
      /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
15751
       * string (or a TrustedHTML object if Trusted Types are supported).
15752
       * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
15753
       */
1 efrain 15754
      let RETURN_DOM = false;
1441 ariadna 15755
      /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
15756
       * string  (or a TrustedHTML object if Trusted Types are supported) */
1 efrain 15757
      let RETURN_DOM_FRAGMENT = false;
1441 ariadna 15758
      /* Try to return a Trusted Type object instead of a string, return a string in
15759
       * case Trusted Types are not supported  */
1 efrain 15760
      let RETURN_TRUSTED_TYPE = false;
1441 ariadna 15761
      /* Output should be free from DOM clobbering attacks?
15762
       * This sanitizes markups named with colliding, clobberable built-in DOM APIs.
15763
       */
1 efrain 15764
      let SANITIZE_DOM = true;
1441 ariadna 15765
      /* Achieve full DOM Clobbering protection by isolating the namespace of named
15766
       * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
15767
       *
15768
       * HTML/DOM spec rules that enable DOM Clobbering:
15769
       *   - Named Access on Window (§7.3.3)
15770
       *   - DOM Tree Accessors (§3.1.5)
15771
       *   - Form Element Parent-Child Relations (§4.10.3)
15772
       *   - Iframe srcdoc / Nested WindowProxies (§4.8.5)
15773
       *   - HTMLCollection (§4.2.10.2)
15774
       *
15775
       * Namespace isolation is implemented by prefixing `id` and `name` attributes
15776
       * with a constant string, i.e., `user-content-`
15777
       */
1 efrain 15778
      let SANITIZE_NAMED_PROPS = false;
15779
      const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
1441 ariadna 15780
      /* Keep element content when removing element? */
1 efrain 15781
      let KEEP_CONTENT = true;
1441 ariadna 15782
      /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
15783
       * of importing it into a new Document and returning a sanitized copy */
1 efrain 15784
      let IN_PLACE = false;
1441 ariadna 15785
      /* Allow usage of profiles like html, svg and mathMl */
1 efrain 15786
      let USE_PROFILES = {};
1441 ariadna 15787
      /* Tags to ignore content of when KEEP_CONTENT is true */
1 efrain 15788
      let FORBID_CONTENTS = null;
1441 ariadna 15789
      const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
15790
      /* Tags that are safe for data: URIs */
1 efrain 15791
      let DATA_URI_TAGS = null;
1441 ariadna 15792
      const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
15793
      /* Attributes safe for values like "javascript:" */
1 efrain 15794
      let URI_SAFE_ATTRIBUTES = null;
1441 ariadna 15795
      const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
1 efrain 15796
      const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
15797
      const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
15798
      const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
1441 ariadna 15799
      /* Document namespace */
1 efrain 15800
      let NAMESPACE = HTML_NAMESPACE;
15801
      let IS_EMPTY_INPUT = false;
1441 ariadna 15802
      /* Allowed XHTML+XML namespaces */
1 efrain 15803
      let ALLOWED_NAMESPACES = null;
1441 ariadna 15804
      const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
15805
      let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
15806
      let HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
15807
      // Certain elements are allowed in both SVG and HTML
15808
      // namespace. We need to specify them explicitly
15809
      // so that they don't get erroneously deleted from
15810
      // HTML namespace.
15811
      const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
15812
      /* Parsing of strict XHTML documents */
15813
      let PARSER_MEDIA_TYPE = null;
15814
      const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
1 efrain 15815
      const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
1441 ariadna 15816
      let transformCaseFunc = null;
15817
      /* Keep a reference to config to pass to hooks */
1 efrain 15818
      let CONFIG = null;
1441 ariadna 15819
      /* Ideally, do not touch anything below this line */
15820
      /* ______________________________________________ */
1 efrain 15821
      const formElement = document.createElement('form');
15822
      const isRegexOrFunction = function isRegexOrFunction(testValue) {
15823
        return testValue instanceof RegExp || testValue instanceof Function;
15824
      };
1441 ariadna 15825
      /**
15826
       * _parseConfig
15827
       *
15828
       * @param cfg optional config literal
15829
       */
15830
      // eslint-disable-next-line complexity
15831
      const _parseConfig = function _parseConfig() {
15832
        let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1 efrain 15833
        if (CONFIG && CONFIG === cfg) {
15834
          return;
15835
        }
1441 ariadna 15836
        /* Shield configuration object from tampering */
1 efrain 15837
        if (!cfg || typeof cfg !== 'object') {
15838
          cfg = {};
15839
        }
1441 ariadna 15840
        /* Shield configuration object from prototype pollution */
1 efrain 15841
        cfg = clone(cfg);
1441 ariadna 15842
        PARSER_MEDIA_TYPE =
15843
        // eslint-disable-next-line unicorn/prefer-includes
15844
        SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
15845
        // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
1 efrain 15846
        transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
1441 ariadna 15847
        /* Set configuration parameters */
15848
        ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
15849
        ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
15850
        ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
15851
        URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
15852
        DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
15853
        FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
15854
        FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
15855
        FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
15856
        USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
15857
        ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
15858
        ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
15859
        ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
15860
        ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
15861
        SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
15862
        SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true
15863
        WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
15864
        RETURN_DOM = cfg.RETURN_DOM || false; // Default false
15865
        RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
15866
        RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
15867
        FORCE_BODY = cfg.FORCE_BODY || false; // Default false
15868
        SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
15869
        SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
15870
        KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
15871
        IN_PLACE = cfg.IN_PLACE || false; // Default false
1 efrain 15872
        IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
15873
        NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
1441 ariadna 15874
        MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS;
15875
        HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS;
1 efrain 15876
        CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
15877
        if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
15878
          CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
15879
        }
15880
        if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
15881
          CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
15882
        }
15883
        if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
15884
          CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
15885
        }
15886
        if (SAFE_FOR_TEMPLATES) {
15887
          ALLOW_DATA_ATTR = false;
15888
        }
15889
        if (RETURN_DOM_FRAGMENT) {
15890
          RETURN_DOM = true;
15891
        }
1441 ariadna 15892
        /* Parse profile info */
1 efrain 15893
        if (USE_PROFILES) {
1441 ariadna 15894
          ALLOWED_TAGS = addToSet({}, text);
1 efrain 15895
          ALLOWED_ATTR = [];
15896
          if (USE_PROFILES.html === true) {
15897
            addToSet(ALLOWED_TAGS, html$1);
15898
            addToSet(ALLOWED_ATTR, html);
15899
          }
15900
          if (USE_PROFILES.svg === true) {
15901
            addToSet(ALLOWED_TAGS, svg$1);
15902
            addToSet(ALLOWED_ATTR, svg);
15903
            addToSet(ALLOWED_ATTR, xml);
15904
          }
15905
          if (USE_PROFILES.svgFilters === true) {
15906
            addToSet(ALLOWED_TAGS, svgFilters);
15907
            addToSet(ALLOWED_ATTR, svg);
15908
            addToSet(ALLOWED_ATTR, xml);
15909
          }
15910
          if (USE_PROFILES.mathMl === true) {
15911
            addToSet(ALLOWED_TAGS, mathMl$1);
15912
            addToSet(ALLOWED_ATTR, mathMl);
15913
            addToSet(ALLOWED_ATTR, xml);
15914
          }
15915
        }
1441 ariadna 15916
        /* Merge configuration parameters */
1 efrain 15917
        if (cfg.ADD_TAGS) {
15918
          if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
15919
            ALLOWED_TAGS = clone(ALLOWED_TAGS);
15920
          }
15921
          addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
15922
        }
15923
        if (cfg.ADD_ATTR) {
15924
          if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
15925
            ALLOWED_ATTR = clone(ALLOWED_ATTR);
15926
          }
15927
          addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
15928
        }
15929
        if (cfg.ADD_URI_SAFE_ATTR) {
15930
          addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
15931
        }
15932
        if (cfg.FORBID_CONTENTS) {
15933
          if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
15934
            FORBID_CONTENTS = clone(FORBID_CONTENTS);
15935
          }
15936
          addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
15937
        }
1441 ariadna 15938
        /* Add #text in case KEEP_CONTENT is set to true */
1 efrain 15939
        if (KEEP_CONTENT) {
15940
          ALLOWED_TAGS['#text'] = true;
15941
        }
1441 ariadna 15942
        /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
1 efrain 15943
        if (WHOLE_DOCUMENT) {
1441 ariadna 15944
          addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
1 efrain 15945
        }
1441 ariadna 15946
        /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
1 efrain 15947
        if (ALLOWED_TAGS.table) {
15948
          addToSet(ALLOWED_TAGS, ['tbody']);
15949
          delete FORBID_TAGS.tbody;
15950
        }
15951
        if (cfg.TRUSTED_TYPES_POLICY) {
15952
          if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
15953
            throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
15954
          }
15955
          if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
15956
            throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
15957
          }
1441 ariadna 15958
          // Overwrite existing TrustedTypes policy.
1 efrain 15959
          trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
1441 ariadna 15960
          // Sign local variables required by `sanitize`.
1 efrain 15961
          emptyHTML = trustedTypesPolicy.createHTML('');
15962
        } else {
1441 ariadna 15963
          // Uninitialized policy, attempt to initialize the internal dompurify policy.
1 efrain 15964
          if (trustedTypesPolicy === undefined) {
15965
            trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
15966
          }
1441 ariadna 15967
          // If creating the internal policy succeeded sign internal variables.
1 efrain 15968
          if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
15969
            emptyHTML = trustedTypesPolicy.createHTML('');
15970
          }
15971
        }
1441 ariadna 15972
        // Prevent further manipulation of configuration.
15973
        // Not available in IE8, Safari 5, etc.
1 efrain 15974
        if (freeze) {
15975
          freeze(cfg);
15976
        }
15977
        CONFIG = cfg;
15978
      };
1441 ariadna 15979
      /* Keep track of all possible SVG and MathML tags
15980
       * so that we can perform the namespace checks
15981
       * correctly. */
15982
      const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
15983
      const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
15984
      /**
15985
       * @param element a DOM element whose namespace is being checked
15986
       * @returns Return false if the element has a
15987
       *  namespace that a spec-compliant parser would never
15988
       *  return. Return true otherwise.
15989
       */
1 efrain 15990
      const _checkValidNamespace = function _checkValidNamespace(element) {
15991
        let parent = getParentNode(element);
1441 ariadna 15992
        // In JSDOM, if we're inside shadow DOM, then parentNode
15993
        // can be null. We just simulate parent in this case.
1 efrain 15994
        if (!parent || !parent.tagName) {
15995
          parent = {
15996
            namespaceURI: NAMESPACE,
15997
            tagName: 'template'
15998
          };
15999
        }
16000
        const tagName = stringToLowerCase(element.tagName);
16001
        const parentTagName = stringToLowerCase(parent.tagName);
16002
        if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
16003
          return false;
16004
        }
16005
        if (element.namespaceURI === SVG_NAMESPACE) {
1441 ariadna 16006
          // The only way to switch from HTML namespace to SVG
16007
          // is via <svg>. If it happens via any other tag, then
16008
          // it should be killed.
1 efrain 16009
          if (parent.namespaceURI === HTML_NAMESPACE) {
16010
            return tagName === 'svg';
16011
          }
1441 ariadna 16012
          // The only way to switch from MathML to SVG is via`
16013
          // svg if parent is either <annotation-xml> or MathML
16014
          // text integration points.
1 efrain 16015
          if (parent.namespaceURI === MATHML_NAMESPACE) {
16016
            return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
16017
          }
1441 ariadna 16018
          // We only allow elements that are defined in SVG
16019
          // spec. All others are disallowed in SVG namespace.
1 efrain 16020
          return Boolean(ALL_SVG_TAGS[tagName]);
16021
        }
16022
        if (element.namespaceURI === MATHML_NAMESPACE) {
1441 ariadna 16023
          // The only way to switch from HTML namespace to MathML
16024
          // is via <math>. If it happens via any other tag, then
16025
          // it should be killed.
1 efrain 16026
          if (parent.namespaceURI === HTML_NAMESPACE) {
16027
            return tagName === 'math';
16028
          }
1441 ariadna 16029
          // The only way to switch from SVG to MathML is via
16030
          // <math> and HTML integration points
1 efrain 16031
          if (parent.namespaceURI === SVG_NAMESPACE) {
16032
            return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
16033
          }
1441 ariadna 16034
          // We only allow elements that are defined in MathML
16035
          // spec. All others are disallowed in MathML namespace.
1 efrain 16036
          return Boolean(ALL_MATHML_TAGS[tagName]);
16037
        }
16038
        if (element.namespaceURI === HTML_NAMESPACE) {
1441 ariadna 16039
          // The only way to switch from SVG to HTML is via
16040
          // HTML integration points, and from MathML to HTML
16041
          // is via MathML text integration points
1 efrain 16042
          if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
16043
            return false;
16044
          }
16045
          if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
16046
            return false;
16047
          }
1441 ariadna 16048
          // We disallow tags that are specific for MathML
16049
          // or SVG and should never appear in HTML namespace
1 efrain 16050
          return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
16051
        }
1441 ariadna 16052
        // For XHTML and XML documents that support custom namespaces
1 efrain 16053
        if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
16054
          return true;
16055
        }
1441 ariadna 16056
        // The code should never reach this place (this means
16057
        // that the element somehow got namespace that is not
16058
        // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
16059
        // Return false just in case.
1 efrain 16060
        return false;
16061
      };
1441 ariadna 16062
      /**
16063
       * _forceRemove
16064
       *
16065
       * @param node a DOM node
16066
       */
1 efrain 16067
      const _forceRemove = function _forceRemove(node) {
1441 ariadna 16068
        arrayPush(DOMPurify.removed, {
16069
          element: node
16070
        });
1 efrain 16071
        try {
1441 ariadna 16072
          // eslint-disable-next-line unicorn/prefer-dom-node-remove
16073
          getParentNode(node).removeChild(node);
1 efrain 16074
        } catch (_) {
1441 ariadna 16075
          remove(node);
1 efrain 16076
        }
16077
      };
1441 ariadna 16078
      /**
16079
       * _removeAttribute
16080
       *
16081
       * @param name an Attribute name
16082
       * @param element a DOM node
16083
       */
16084
      const _removeAttribute = function _removeAttribute(name, element) {
1 efrain 16085
        try {
16086
          arrayPush(DOMPurify.removed, {
1441 ariadna 16087
            attribute: element.getAttributeNode(name),
16088
            from: element
1 efrain 16089
          });
16090
        } catch (_) {
16091
          arrayPush(DOMPurify.removed, {
16092
            attribute: null,
1441 ariadna 16093
            from: element
1 efrain 16094
          });
16095
        }
1441 ariadna 16096
        element.removeAttribute(name);
16097
        // We void attribute values for unremovable "is" attributes
16098
        if (name === 'is') {
1 efrain 16099
          if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
16100
            try {
1441 ariadna 16101
              _forceRemove(element);
16102
            } catch (_) {}
1 efrain 16103
          } else {
16104
            try {
1441 ariadna 16105
              element.setAttribute(name, '');
16106
            } catch (_) {}
1 efrain 16107
          }
16108
        }
16109
      };
1441 ariadna 16110
      /**
16111
       * _initDocument
16112
       *
16113
       * @param dirty - a string of dirty markup
16114
       * @return a DOM, filled with the dirty markup
16115
       */
1 efrain 16116
      const _initDocument = function _initDocument(dirty) {
1441 ariadna 16117
        /* Create a HTML document */
16118
        let doc = null;
16119
        let leadingWhitespace = null;
1 efrain 16120
        if (FORCE_BODY) {
16121
          dirty = '<remove></remove>' + dirty;
16122
        } else {
1441 ariadna 16123
          /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
1 efrain 16124
          const matches = stringMatch(dirty, /^[\r\n\t ]+/);
16125
          leadingWhitespace = matches && matches[0];
16126
        }
16127
        if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
1441 ariadna 16128
          // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
1 efrain 16129
          dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
16130
        }
16131
        const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
1441 ariadna 16132
        /*
16133
         * Use the DOMParser API by default, fallback later if needs be
16134
         * DOMParser not work for svg when has multiple root element.
16135
         */
1 efrain 16136
        if (NAMESPACE === HTML_NAMESPACE) {
16137
          try {
16138
            doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
1441 ariadna 16139
          } catch (_) {}
1 efrain 16140
        }
1441 ariadna 16141
        /* Use createHTMLDocument in case DOMParser is not available */
1 efrain 16142
        if (!doc || !doc.documentElement) {
16143
          doc = implementation.createDocument(NAMESPACE, 'template', null);
16144
          try {
16145
            doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
16146
          } catch (_) {
1441 ariadna 16147
            // Syntax error if dirtyPayload is invalid xml
1 efrain 16148
          }
16149
        }
16150
        const body = doc.body || doc.documentElement;
16151
        if (dirty && leadingWhitespace) {
16152
          body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
16153
        }
1441 ariadna 16154
        /* Work on whole document or just its body */
1 efrain 16155
        if (NAMESPACE === HTML_NAMESPACE) {
16156
          return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
16157
        }
16158
        return WHOLE_DOCUMENT ? doc.documentElement : body;
16159
      };
1441 ariadna 16160
      /**
16161
       * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
16162
       *
16163
       * @param root The root element or node to start traversing on.
16164
       * @return The created NodeIterator
16165
       */
16166
      const _createNodeIterator = function _createNodeIterator(root) {
16167
        return createNodeIterator.call(root.ownerDocument || root, root,
16168
        // eslint-disable-next-line no-bitwise
16169
        NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
1 efrain 16170
      };
1441 ariadna 16171
      /**
16172
       * _isClobbered
16173
       *
16174
       * @param element element to check for clobbering attacks
16175
       * @return true if clobbered, false if safe
16176
       */
16177
      const _isClobbered = function _isClobbered(element) {
16178
        return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function');
1 efrain 16179
      };
1441 ariadna 16180
      /**
16181
       * Checks whether the given object is a DOM node.
16182
       *
16183
       * @param value object to check whether it's a DOM node
16184
       * @return true is object is a DOM node
16185
       */
16186
      const _isNode = function _isNode(value) {
16187
        return typeof Node === 'function' && value instanceof Node;
1 efrain 16188
      };
1441 ariadna 16189
      function _executeHooks(hooks, currentNode, data) {
16190
        arrayForEach(hooks, hook => {
1 efrain 16191
          hook.call(DOMPurify, currentNode, data, CONFIG);
16192
        });
1441 ariadna 16193
      }
16194
      /**
16195
       * _sanitizeElements
16196
       *
16197
       * @protect nodeName
16198
       * @protect textContent
16199
       * @protect removeChild
16200
       * @param currentNode to check for permission to exist
16201
       * @return true if node was killed, false if left alive
16202
       */
1 efrain 16203
      const _sanitizeElements = function _sanitizeElements(currentNode) {
1441 ariadna 16204
        let content = null;
16205
        /* Execute a hook if present */
16206
        _executeHooks(hooks.beforeSanitizeElements, currentNode, null);
16207
        /* Check if element is clobbered or can clobber */
1 efrain 16208
        if (_isClobbered(currentNode)) {
16209
          _forceRemove(currentNode);
16210
          return true;
16211
        }
1441 ariadna 16212
        /* Now let's check the element's type and name */
1 efrain 16213
        const tagName = transformCaseFunc(currentNode.nodeName);
1441 ariadna 16214
        /* Execute a hook if present */
16215
        _executeHooks(hooks.uponSanitizeElement, currentNode, {
1 efrain 16216
          tagName,
16217
          allowedTags: ALLOWED_TAGS
16218
        });
1441 ariadna 16219
        /* Detect mXSS attempts abusing namespace confusion */
16220
        if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
1 efrain 16221
          _forceRemove(currentNode);
16222
          return true;
16223
        }
1441 ariadna 16224
        /* Remove any occurrence of processing instructions */
16225
        if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
16226
          _forceRemove(currentNode);
16227
          return true;
16228
        }
16229
        /* Remove any kind of possibly harmful comments */
16230
        if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
16231
          _forceRemove(currentNode);
16232
          return true;
16233
        }
16234
        /* Remove element if anything forbids its presence */
1 efrain 16235
        if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
1441 ariadna 16236
          /* Check if we have a custom element to handle */
16237
          if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
16238
            if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
1 efrain 16239
              return false;
1441 ariadna 16240
            }
16241
            if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
1 efrain 16242
              return false;
1441 ariadna 16243
            }
1 efrain 16244
          }
1441 ariadna 16245
          /* Keep content except for bad-listed elements */
1 efrain 16246
          if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
16247
            const parentNode = getParentNode(currentNode) || currentNode.parentNode;
16248
            const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
16249
            if (childNodes && parentNode) {
16250
              const childCount = childNodes.length;
16251
              for (let i = childCount - 1; i >= 0; --i) {
1441 ariadna 16252
                const childClone = cloneNode(childNodes[i], true);
16253
                childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
16254
                parentNode.insertBefore(childClone, getNextSibling(currentNode));
1 efrain 16255
              }
16256
            }
16257
          }
16258
          _forceRemove(currentNode);
16259
          return true;
16260
        }
1441 ariadna 16261
        /* Check whether element has a valid namespace */
1 efrain 16262
        if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
16263
          _forceRemove(currentNode);
16264
          return true;
16265
        }
1441 ariadna 16266
        /* Make sure that older browsers don't get fallback-tag mXSS */
1 efrain 16267
        if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
16268
          _forceRemove(currentNode);
16269
          return true;
16270
        }
1441 ariadna 16271
        /* Sanitize element content to be template-safe */
16272
        if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
16273
          /* Get the element's text content */
1 efrain 16274
          content = currentNode.textContent;
1441 ariadna 16275
          arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
16276
            content = stringReplace(content, expr, ' ');
16277
          });
1 efrain 16278
          if (currentNode.textContent !== content) {
1441 ariadna 16279
            arrayPush(DOMPurify.removed, {
16280
              element: currentNode.cloneNode()
16281
            });
1 efrain 16282
            currentNode.textContent = content;
16283
          }
16284
        }
1441 ariadna 16285
        /* Execute a hook if present */
16286
        _executeHooks(hooks.afterSanitizeElements, currentNode, null);
1 efrain 16287
        return false;
16288
      };
1441 ariadna 16289
      /**
16290
       * _isValidAttribute
16291
       *
16292
       * @param lcTag Lowercase tag name of containing element.
16293
       * @param lcName Lowercase attribute name.
16294
       * @param value Attribute value.
16295
       * @return Returns true if `value` is valid, otherwise false.
16296
       */
16297
      // eslint-disable-next-line complexity
1 efrain 16298
      const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
1441 ariadna 16299
        /* Make sure attribute cannot clobber */
1 efrain 16300
        if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
16301
          return false;
16302
        }
1441 ariadna 16303
        /* Allow valid data-* attributes: At least one character after "-"
16304
            (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
16305
            XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
16306
            We don't need to check the value; it's always URI safe. */
16307
        if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
16308
          if (
16309
          // First condition does a very basic check if a) it's basically a valid custom element tagname AND
16310
          // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
16311
          // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
16312
          _isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) ||
16313
          // Alternative, second condition checks if it's an `is`-attribute, AND
16314
          // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
16315
          lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))) ; else {
1 efrain 16316
            return false;
16317
          }
1441 ariadna 16318
          /* Check value is safe. First, is attr inert? If so, is safe */
16319
        } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {
1 efrain 16320
          return false;
16321
        } else ;
16322
        return true;
16323
      };
1441 ariadna 16324
      /**
16325
       * _isBasicCustomElement
16326
       * checks if at least one dash is included in tagName, and it's not the first char
16327
       * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
16328
       *
16329
       * @param tagName name of the tag of the node to sanitize
16330
       * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
16331
       */
16332
      const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
16333
        return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
1 efrain 16334
      };
1441 ariadna 16335
      /**
16336
       * _sanitizeAttributes
16337
       *
16338
       * @protect attributes
16339
       * @protect nodeName
16340
       * @protect removeAttribute
16341
       * @protect setAttribute
16342
       *
16343
       * @param currentNode to sanitize
16344
       */
1 efrain 16345
      const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
1441 ariadna 16346
        /* Execute a hook if present */
16347
        _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
16348
        const {
16349
          attributes
16350
        } = currentNode;
16351
        /* Check if we have attributes; if not we might have a text node */
16352
        if (!attributes || _isClobbered(currentNode)) {
1 efrain 16353
          return;
16354
        }
16355
        const hookEvent = {
16356
          attrName: '',
16357
          attrValue: '',
16358
          keepAttr: true,
1441 ariadna 16359
          allowedAttributes: ALLOWED_ATTR,
16360
          forceKeepAttr: undefined
1 efrain 16361
        };
1441 ariadna 16362
        let l = attributes.length;
16363
        /* Go backwards over all attributes; safely remove bad ones */
1 efrain 16364
        while (l--) {
1441 ariadna 16365
          const attr = attributes[l];
16366
          const {
16367
            name,
16368
            namespaceURI,
16369
            value: attrValue
16370
          } = attr;
16371
          const lcName = transformCaseFunc(name);
16372
          let value = name === 'value' ? attrValue : stringTrim(attrValue);
1 efrain 16373
          const initValue = value;
1441 ariadna 16374
          /* Execute a hook if present */
1 efrain 16375
          hookEvent.attrName = lcName;
16376
          hookEvent.attrValue = value;
16377
          hookEvent.keepAttr = true;
1441 ariadna 16378
          hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
16379
          _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
1 efrain 16380
          value = hookEvent.attrValue;
1441 ariadna 16381
          /* Full DOM Clobbering protection via namespace isolation,
16382
           * Prefix id and name attributes with `user-content-`
16383
           */
16384
          if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
16385
            // Remove the attribute with this value
16386
            _removeAttribute(name, currentNode);
16387
            // Prefix the value and later re-create the attribute with the sanitized value
16388
            value = SANITIZE_NAMED_PROPS_PREFIX + value;
16389
          }
16390
          /* Work around a security issue with comments inside attributes */
16391
          if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
16392
            _removeAttribute(name, currentNode);
16393
            continue;
16394
          }
16395
          /* Did the hooks approve of the attribute? */
1 efrain 16396
          if (hookEvent.forceKeepAttr) {
16397
            continue;
16398
          }
1441 ariadna 16399
          /* Remove attribute */
16400
          /* Did the hooks approve of the attribute? */
1 efrain 16401
          if (!hookEvent.keepAttr) {
16402
            _removeAttribute(name, currentNode);
16403
            continue;
16404
          }
1441 ariadna 16405
          /* Work around a security issue in jQuery 3.0 */
1 efrain 16406
          if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
16407
            _removeAttribute(name, currentNode);
16408
            continue;
16409
          }
1441 ariadna 16410
          /* Sanitize attribute content to be template-safe */
1 efrain 16411
          if (SAFE_FOR_TEMPLATES) {
1441 ariadna 16412
            arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
16413
              value = stringReplace(value, expr, ' ');
16414
            });
1 efrain 16415
          }
1441 ariadna 16416
          /* Is `value` valid for this attribute? */
1 efrain 16417
          const lcTag = transformCaseFunc(currentNode.nodeName);
16418
          if (!_isValidAttribute(lcTag, lcName, value)) {
16419
            _removeAttribute(name, currentNode);
16420
            continue;
16421
          }
1441 ariadna 16422
          /* Handle attributes that require Trusted Types */
1 efrain 16423
          if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
1441 ariadna 16424
            if (namespaceURI) ; else {
1 efrain 16425
              switch (trustedTypes.getAttributeType(lcTag, lcName)) {
1441 ariadna 16426
                case 'TrustedHTML':
16427
                  {
16428
                    value = trustedTypesPolicy.createHTML(value);
16429
                    break;
16430
                  }
16431
                case 'TrustedScriptURL':
16432
                  {
16433
                    value = trustedTypesPolicy.createScriptURL(value);
16434
                    break;
16435
                  }
1 efrain 16436
              }
16437
            }
16438
          }
1441 ariadna 16439
          /* Handle invalid data-* attribute set by try-catching it */
1 efrain 16440
          if (value !== initValue) {
16441
            try {
16442
              if (namespaceURI) {
16443
                currentNode.setAttributeNS(namespaceURI, name, value);
16444
              } else {
1441 ariadna 16445
                /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
1 efrain 16446
                currentNode.setAttribute(name, value);
16447
              }
1441 ariadna 16448
              if (_isClobbered(currentNode)) {
16449
                _forceRemove(currentNode);
16450
              } else {
16451
                arrayPop(DOMPurify.removed);
16452
              }
16453
            } catch (_) {}
1 efrain 16454
          }
16455
        }
1441 ariadna 16456
        /* Execute a hook if present */
16457
        _executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
1 efrain 16458
      };
1441 ariadna 16459
      /**
16460
       * _sanitizeShadowDOM
16461
       *
16462
       * @param fragment to iterate over recursively
16463
       */
1 efrain 16464
      const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
1441 ariadna 16465
        let shadowNode = null;
16466
        const shadowIterator = _createNodeIterator(fragment);
16467
        /* Execute a hook if present */
16468
        _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
1 efrain 16469
        while (shadowNode = shadowIterator.nextNode()) {
1441 ariadna 16470
          /* Execute a hook if present */
16471
          _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
16472
          /* Sanitize tags and elements */
16473
          _sanitizeElements(shadowNode);
16474
          /* Check attributes next */
16475
          _sanitizeAttributes(shadowNode);
16476
          /* Deep shadow DOM detected */
1 efrain 16477
          if (shadowNode.content instanceof DocumentFragment) {
16478
            _sanitizeShadowDOM(shadowNode.content);
16479
          }
16480
        }
1441 ariadna 16481
        /* Execute a hook if present */
16482
        _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
1 efrain 16483
      };
1441 ariadna 16484
      // eslint-disable-next-line complexity
1 efrain 16485
      DOMPurify.sanitize = function (dirty) {
16486
        let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1441 ariadna 16487
        let body = null;
16488
        let importedNode = null;
16489
        let currentNode = null;
16490
        let returnNode = null;
16491
        /* Make sure we have a string to sanitize.
16492
          DO NOT return early, as this will return the wrong type if
16493
          the user has requested a DOM object rather than a string */
1 efrain 16494
        IS_EMPTY_INPUT = !dirty;
16495
        if (IS_EMPTY_INPUT) {
16496
          dirty = '<!-->';
16497
        }
1441 ariadna 16498
        /* Stringify, in case dirty is an object */
1 efrain 16499
        if (typeof dirty !== 'string' && !_isNode(dirty)) {
16500
          if (typeof dirty.toString === 'function') {
16501
            dirty = dirty.toString();
16502
            if (typeof dirty !== 'string') {
16503
              throw typeErrorCreate('dirty is not a string, aborting');
16504
            }
16505
          } else {
16506
            throw typeErrorCreate('toString is not a function');
16507
          }
16508
        }
1441 ariadna 16509
        /* Return dirty HTML if DOMPurify cannot run */
1 efrain 16510
        if (!DOMPurify.isSupported) {
16511
          return dirty;
16512
        }
1441 ariadna 16513
        /* Assign config vars */
1 efrain 16514
        if (!SET_CONFIG) {
16515
          _parseConfig(cfg);
16516
        }
1441 ariadna 16517
        /* Clean up removed elements */
1 efrain 16518
        DOMPurify.removed = [];
1441 ariadna 16519
        /* Check if dirty is correctly typed for IN_PLACE */
1 efrain 16520
        if (typeof dirty === 'string') {
16521
          IN_PLACE = false;
16522
        }
16523
        if (IN_PLACE) {
1441 ariadna 16524
          /* Do some early pre-sanitization to avoid unsafe root nodes */
1 efrain 16525
          if (dirty.nodeName) {
16526
            const tagName = transformCaseFunc(dirty.nodeName);
16527
            if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
16528
              throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
16529
            }
16530
          }
16531
        } else if (dirty instanceof Node) {
1441 ariadna 16532
          /* If dirty is a DOM element, append to an empty document to avoid
16533
             elements being stripped by the parser */
1 efrain 16534
          body = _initDocument('<!---->');
16535
          importedNode = body.ownerDocument.importNode(dirty, true);
1441 ariadna 16536
          if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
16537
            /* Node is already a body, use as is */
1 efrain 16538
            body = importedNode;
16539
          } else if (importedNode.nodeName === 'HTML') {
16540
            body = importedNode;
16541
          } else {
1441 ariadna 16542
            // eslint-disable-next-line unicorn/prefer-dom-node-append
1 efrain 16543
            body.appendChild(importedNode);
16544
          }
16545
        } else {
1441 ariadna 16546
          /* Exit directly if we have nothing to do */
16547
          if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
16548
          // eslint-disable-next-line unicorn/prefer-includes
16549
          dirty.indexOf('<') === -1) {
1 efrain 16550
            return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
16551
          }
1441 ariadna 16552
          /* Initialize the document to work on */
1 efrain 16553
          body = _initDocument(dirty);
1441 ariadna 16554
          /* Check we have a DOM node from the data */
1 efrain 16555
          if (!body) {
16556
            return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
16557
          }
16558
        }
1441 ariadna 16559
        /* Remove first element node (ours) if FORCE_BODY is set */
1 efrain 16560
        if (body && FORCE_BODY) {
16561
          _forceRemove(body.firstChild);
16562
        }
1441 ariadna 16563
        /* Get node iterator */
16564
        const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);
16565
        /* Now start iterating over the created document */
1 efrain 16566
        while (currentNode = nodeIterator.nextNode()) {
1441 ariadna 16567
          /* Sanitize tags and elements */
16568
          _sanitizeElements(currentNode);
16569
          /* Check attributes next */
16570
          _sanitizeAttributes(currentNode);
16571
          /* Shadow DOM detected, sanitize it */
1 efrain 16572
          if (currentNode.content instanceof DocumentFragment) {
16573
            _sanitizeShadowDOM(currentNode.content);
16574
          }
16575
        }
1441 ariadna 16576
        /* If we sanitized `dirty` in-place, return it. */
1 efrain 16577
        if (IN_PLACE) {
16578
          return dirty;
16579
        }
1441 ariadna 16580
        /* Return sanitized string or DOM */
1 efrain 16581
        if (RETURN_DOM) {
16582
          if (RETURN_DOM_FRAGMENT) {
16583
            returnNode = createDocumentFragment.call(body.ownerDocument);
16584
            while (body.firstChild) {
1441 ariadna 16585
              // eslint-disable-next-line unicorn/prefer-dom-node-append
1 efrain 16586
              returnNode.appendChild(body.firstChild);
16587
            }
16588
          } else {
16589
            returnNode = body;
16590
          }
16591
          if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
1441 ariadna 16592
            /*
16593
              AdoptNode() is not used because internal state is not reset
16594
              (e.g. the past names map of a HTMLFormElement), this is safe
16595
              in theory but we would rather not risk another attack vector.
16596
              The state that is cloned by importNode() is explicitly defined
16597
              by the specs.
16598
            */
1 efrain 16599
            returnNode = importNode.call(originalDocument, returnNode, true);
16600
          }
16601
          return returnNode;
16602
        }
16603
        let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
1441 ariadna 16604
        /* Serialize doctype if allowed */
1 efrain 16605
        if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
16606
          serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
16607
        }
1441 ariadna 16608
        /* Sanitize final string template-safe */
1 efrain 16609
        if (SAFE_FOR_TEMPLATES) {
1441 ariadna 16610
          arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
16611
            serializedHTML = stringReplace(serializedHTML, expr, ' ');
16612
          });
1 efrain 16613
        }
16614
        return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
16615
      };
1441 ariadna 16616
      DOMPurify.setConfig = function () {
16617
        let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1 efrain 16618
        _parseConfig(cfg);
16619
        SET_CONFIG = true;
16620
      };
16621
      DOMPurify.clearConfig = function () {
16622
        CONFIG = null;
16623
        SET_CONFIG = false;
16624
      };
16625
      DOMPurify.isValidAttribute = function (tag, attr, value) {
1441 ariadna 16626
        /* Initialize shared config vars if necessary. */
1 efrain 16627
        if (!CONFIG) {
16628
          _parseConfig({});
16629
        }
16630
        const lcTag = transformCaseFunc(tag);
16631
        const lcName = transformCaseFunc(attr);
16632
        return _isValidAttribute(lcTag, lcName, value);
16633
      };
16634
      DOMPurify.addHook = function (entryPoint, hookFunction) {
16635
        if (typeof hookFunction !== 'function') {
16636
          return;
16637
        }
16638
        arrayPush(hooks[entryPoint], hookFunction);
16639
      };
1441 ariadna 16640
      DOMPurify.removeHook = function (entryPoint, hookFunction) {
16641
        if (hookFunction !== undefined) {
16642
          const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);
16643
          return index === -1 ? undefined : arraySplice(hooks[entryPoint], index, 1)[0];
1 efrain 16644
        }
1441 ariadna 16645
        return arrayPop(hooks[entryPoint]);
1 efrain 16646
      };
16647
      DOMPurify.removeHooks = function (entryPoint) {
1441 ariadna 16648
        hooks[entryPoint] = [];
1 efrain 16649
      };
16650
      DOMPurify.removeAllHooks = function () {
1441 ariadna 16651
        hooks = _createHooksMap();
1 efrain 16652
      };
16653
      return DOMPurify;
16654
    }
16655
    var purify = createDOMPurify();
16656
 
16657
    const each$4 = Tools.each, trim = Tools.trim;
16658
    const queryParts = [
16659
      'source',
16660
      'protocol',
16661
      'authority',
16662
      'userInfo',
16663
      'user',
16664
      'password',
16665
      'host',
16666
      'port',
16667
      'relative',
16668
      'path',
16669
      'directory',
16670
      'file',
16671
      'query',
16672
      'anchor'
16673
    ];
16674
    const DEFAULT_PORTS = {
16675
      ftp: 21,
16676
      http: 80,
16677
      https: 443,
16678
      mailto: 25
16679
    };
16680
    const safeSvgDataUrlElements = [
16681
      'img',
16682
      'video'
16683
    ];
16684
    const blockSvgDataUris = (allowSvgDataUrls, tagName) => {
16685
      if (isNonNullable(allowSvgDataUrls)) {
16686
        return !allowSvgDataUrls;
16687
      } else {
16688
        return isNonNullable(tagName) ? !contains$2(safeSvgDataUrlElements, tagName) : true;
16689
      }
16690
    };
16691
    const decodeUri = encodedUri => {
16692
      try {
16693
        return decodeURIComponent(encodedUri);
1441 ariadna 16694
      } catch (_a) {
1 efrain 16695
        return unescape(encodedUri);
16696
      }
16697
    };
16698
    const isInvalidUri = (settings, uri, tagName) => {
16699
      const decodedUri = decodeUri(uri).replace(/\s/g, '');
16700
      if (settings.allow_script_urls) {
16701
        return false;
16702
      } else if (/((java|vb)script|mhtml):/i.test(decodedUri)) {
16703
        return true;
16704
      } else if (settings.allow_html_data_urls) {
16705
        return false;
16706
      } else if (/^data:image\//i.test(decodedUri)) {
16707
        return blockSvgDataUris(settings.allow_svg_data_urls, tagName) && /^data:image\/svg\+xml/i.test(decodedUri);
16708
      } else {
16709
        return /^data:/i.test(decodedUri);
16710
      }
16711
    };
16712
    class URI {
16713
      static parseDataUri(uri) {
16714
        let type;
16715
        const uriComponents = decodeURIComponent(uri).split(',');
16716
        const matches = /data:([^;]+)/.exec(uriComponents[0]);
16717
        if (matches) {
16718
          type = matches[1];
16719
        }
16720
        return {
16721
          type,
16722
          data: uriComponents[1]
16723
        };
16724
      }
16725
      static isDomSafe(uri, context, options = {}) {
16726
        if (options.allow_script_urls) {
16727
          return true;
16728
        } else {
16729
          const decodedUri = Entities.decode(uri).replace(/[\s\u0000-\u001F]+/g, '');
16730
          return !isInvalidUri(options, decodedUri, context);
16731
        }
16732
      }
16733
      static getDocumentBaseUrl(loc) {
16734
        var _a;
16735
        let baseUrl;
16736
        if (loc.protocol.indexOf('http') !== 0 && loc.protocol !== 'file:') {
16737
          baseUrl = (_a = loc.href) !== null && _a !== void 0 ? _a : '';
16738
        } else {
16739
          baseUrl = loc.protocol + '//' + loc.host + loc.pathname;
16740
        }
16741
        if (/^[^:]+:\/\/\/?[^\/]+\//.test(baseUrl)) {
16742
          baseUrl = baseUrl.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
16743
          if (!/[\/\\]$/.test(baseUrl)) {
16744
            baseUrl += '/';
16745
          }
16746
        }
16747
        return baseUrl;
16748
      }
16749
      constructor(url, settings = {}) {
16750
        this.path = '';
16751
        this.directory = '';
16752
        url = trim(url);
16753
        this.settings = settings;
16754
        const baseUri = settings.base_uri;
16755
        const self = this;
16756
        if (/^([\w\-]+):([^\/]{2})/i.test(url) || /^\s*#/.test(url)) {
16757
          self.source = url;
16758
          return;
16759
        }
16760
        const isProtocolRelative = url.indexOf('//') === 0;
16761
        if (url.indexOf('/') === 0 && !isProtocolRelative) {
16762
          url = (baseUri ? baseUri.protocol || 'http' : 'http') + '://mce_host' + url;
16763
        }
16764
        if (!/^[\w\-]*:?\/\//.test(url)) {
16765
          const baseUrl = baseUri ? baseUri.path : new URI(document.location.href).directory;
16766
          if ((baseUri === null || baseUri === void 0 ? void 0 : baseUri.protocol) === '') {
16767
            url = '//mce_host' + self.toAbsPath(baseUrl, url);
16768
          } else {
16769
            const match = /([^#?]*)([#?]?.*)/.exec(url);
16770
            if (match) {
16771
              url = (baseUri && baseUri.protocol || 'http') + '://mce_host' + self.toAbsPath(baseUrl, match[1]) + match[2];
16772
            }
16773
          }
16774
        }
16775
        url = url.replace(/@@/g, '(mce_at)');
16776
        const urlMatch = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?(\[[a-zA-Z0-9:.%]+\]|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url);
16777
        if (urlMatch) {
16778
          each$4(queryParts, (v, i) => {
16779
            let part = urlMatch[i];
16780
            if (part) {
16781
              part = part.replace(/\(mce_at\)/g, '@@');
16782
            }
16783
            self[v] = part;
16784
          });
16785
        }
16786
        if (baseUri) {
16787
          if (!self.protocol) {
16788
            self.protocol = baseUri.protocol;
16789
          }
16790
          if (!self.userInfo) {
16791
            self.userInfo = baseUri.userInfo;
16792
          }
16793
          if (!self.port && self.host === 'mce_host') {
16794
            self.port = baseUri.port;
16795
          }
16796
          if (!self.host || self.host === 'mce_host') {
16797
            self.host = baseUri.host;
16798
          }
16799
          self.source = '';
16800
        }
16801
        if (isProtocolRelative) {
16802
          self.protocol = '';
16803
        }
16804
      }
16805
      setPath(path) {
16806
        const pathMatch = /^(.*?)\/?(\w+)?$/.exec(path);
16807
        if (pathMatch) {
16808
          this.path = pathMatch[0];
16809
          this.directory = pathMatch[1];
16810
          this.file = pathMatch[2];
16811
        }
16812
        this.source = '';
16813
        this.getURI();
16814
      }
16815
      toRelative(uri) {
16816
        if (uri === './') {
16817
          return uri;
16818
        }
16819
        const relativeUri = new URI(uri, { base_uri: this });
16820
        if (relativeUri.host !== 'mce_host' && this.host !== relativeUri.host && relativeUri.host || this.port !== relativeUri.port || this.protocol !== relativeUri.protocol && relativeUri.protocol !== '') {
16821
          return relativeUri.getURI();
16822
        }
16823
        const tu = this.getURI(), uu = relativeUri.getURI();
16824
        if (tu === uu || tu.charAt(tu.length - 1) === '/' && tu.substr(0, tu.length - 1) === uu) {
16825
          return tu;
16826
        }
16827
        let output = this.toRelPath(this.path, relativeUri.path);
16828
        if (relativeUri.query) {
16829
          output += '?' + relativeUri.query;
16830
        }
16831
        if (relativeUri.anchor) {
16832
          output += '#' + relativeUri.anchor;
16833
        }
16834
        return output;
16835
      }
16836
      toAbsolute(uri, noHost) {
16837
        const absoluteUri = new URI(uri, { base_uri: this });
16838
        return absoluteUri.getURI(noHost && this.isSameOrigin(absoluteUri));
16839
      }
16840
      isSameOrigin(uri) {
16841
        if (this.host == uri.host && this.protocol == uri.protocol) {
16842
          if (this.port == uri.port) {
16843
            return true;
16844
          }
16845
          const defaultPort = this.protocol ? DEFAULT_PORTS[this.protocol] : null;
16846
          if (defaultPort && (this.port || defaultPort) == (uri.port || defaultPort)) {
16847
            return true;
16848
          }
16849
        }
16850
        return false;
16851
      }
16852
      toRelPath(base, path) {
16853
        let breakPoint = 0, out = '', i, l;
16854
        const normalizedBase = base.substring(0, base.lastIndexOf('/')).split('/');
16855
        const items = path.split('/');
16856
        if (normalizedBase.length >= items.length) {
16857
          for (i = 0, l = normalizedBase.length; i < l; i++) {
16858
            if (i >= items.length || normalizedBase[i] !== items[i]) {
16859
              breakPoint = i + 1;
16860
              break;
16861
            }
16862
          }
16863
        }
16864
        if (normalizedBase.length < items.length) {
16865
          for (i = 0, l = items.length; i < l; i++) {
16866
            if (i >= normalizedBase.length || normalizedBase[i] !== items[i]) {
16867
              breakPoint = i + 1;
16868
              break;
16869
            }
16870
          }
16871
        }
16872
        if (breakPoint === 1) {
16873
          return path;
16874
        }
16875
        for (i = 0, l = normalizedBase.length - (breakPoint - 1); i < l; i++) {
16876
          out += '../';
16877
        }
16878
        for (i = breakPoint - 1, l = items.length; i < l; i++) {
16879
          if (i !== breakPoint - 1) {
16880
            out += '/' + items[i];
16881
          } else {
16882
            out += items[i];
16883
          }
16884
        }
16885
        return out;
16886
      }
16887
      toAbsPath(base, path) {
16888
        let nb = 0;
16889
        const tr = /\/$/.test(path) ? '/' : '';
16890
        const normalizedBase = base.split('/');
16891
        const normalizedPath = path.split('/');
16892
        const baseParts = [];
16893
        each$4(normalizedBase, k => {
16894
          if (k) {
16895
            baseParts.push(k);
16896
          }
16897
        });
16898
        const pathParts = [];
16899
        for (let i = normalizedPath.length - 1; i >= 0; i--) {
16900
          if (normalizedPath[i].length === 0 || normalizedPath[i] === '.') {
16901
            continue;
16902
          }
16903
          if (normalizedPath[i] === '..') {
16904
            nb++;
16905
            continue;
16906
          }
16907
          if (nb > 0) {
16908
            nb--;
16909
            continue;
16910
          }
16911
          pathParts.push(normalizedPath[i]);
16912
        }
16913
        const i = baseParts.length - nb;
16914
        let outPath;
16915
        if (i <= 0) {
16916
          outPath = reverse(pathParts).join('/');
16917
        } else {
16918
          outPath = baseParts.slice(0, i).join('/') + '/' + reverse(pathParts).join('/');
16919
        }
16920
        if (outPath.indexOf('/') !== 0) {
16921
          outPath = '/' + outPath;
16922
        }
16923
        if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) {
16924
          outPath += tr;
16925
        }
16926
        return outPath;
16927
      }
16928
      getURI(noProtoHost = false) {
16929
        let s;
16930
        if (!this.source || noProtoHost) {
16931
          s = '';
16932
          if (!noProtoHost) {
16933
            if (this.protocol) {
16934
              s += this.protocol + '://';
16935
            } else {
16936
              s += '//';
16937
            }
16938
            if (this.userInfo) {
16939
              s += this.userInfo + '@';
16940
            }
16941
            if (this.host) {
16942
              s += this.host;
16943
            }
16944
            if (this.port) {
16945
              s += ':' + this.port;
16946
            }
16947
          }
16948
          if (this.path) {
16949
            s += this.path;
16950
          }
16951
          if (this.query) {
16952
            s += '?' + this.query;
16953
          }
16954
          if (this.anchor) {
16955
            s += '#' + this.anchor;
16956
          }
16957
          this.source = s;
16958
        }
16959
        return this.source;
16960
      }
16961
    }
16962
 
16963
    const filteredUrlAttrs = Tools.makeMap('src,href,data,background,action,formaction,poster,xlink:href');
16964
    const internalElementAttr = 'data-mce-type';
16965
    let uid = 0;
16966
    const processNode = (node, settings, schema, scope, evt) => {
16967
      var _a, _b, _c, _d;
16968
      const validate = settings.validate;
16969
      const specialElements = schema.getSpecialElements();
16970
      if (node.nodeType === COMMENT && !settings.allow_conditional_comments && /^\[if/i.test((_a = node.nodeValue) !== null && _a !== void 0 ? _a : '')) {
16971
        node.nodeValue = ' ' + node.nodeValue;
16972
      }
16973
      const lcTagName = (_b = evt === null || evt === void 0 ? void 0 : evt.tagName) !== null && _b !== void 0 ? _b : node.nodeName.toLowerCase();
16974
      if (scope !== 'html' && schema.isValid(scope)) {
16975
        if (isNonNullable(evt)) {
16976
          evt.allowedTags[lcTagName] = true;
16977
        }
16978
        return;
16979
      }
16980
      if (node.nodeType !== ELEMENT || lcTagName === 'body') {
16981
        return;
16982
      }
16983
      const element = SugarElement.fromDom(node);
16984
      const isInternalElement = has$1(element, internalElementAttr);
16985
      const bogus = get$9(element, 'data-mce-bogus');
16986
      if (!isInternalElement && isString(bogus)) {
16987
        if (bogus === 'all') {
1441 ariadna 16988
          remove$4(element);
1 efrain 16989
        } else {
16990
          unwrap(element);
16991
        }
16992
        return;
16993
      }
16994
      const rule = schema.getElementRule(lcTagName);
16995
      if (validate && !rule) {
16996
        if (has$2(specialElements, lcTagName)) {
1441 ariadna 16997
          remove$4(element);
1 efrain 16998
        } else {
16999
          unwrap(element);
17000
        }
17001
        return;
17002
      } else {
17003
        if (isNonNullable(evt)) {
17004
          evt.allowedTags[lcTagName] = true;
17005
        }
17006
      }
17007
      if (validate && rule && !isInternalElement) {
17008
        each$e((_c = rule.attributesForced) !== null && _c !== void 0 ? _c : [], attr => {
1441 ariadna 17009
          set$4(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
1 efrain 17010
        });
17011
        each$e((_d = rule.attributesDefault) !== null && _d !== void 0 ? _d : [], attr => {
17012
          if (!has$1(element, attr.name)) {
1441 ariadna 17013
            set$4(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
1 efrain 17014
          }
17015
        });
17016
        if (rule.attributesRequired && !exists(rule.attributesRequired, attr => has$1(element, attr))) {
17017
          unwrap(element);
17018
          return;
17019
        }
17020
        if (rule.removeEmptyAttrs && hasNone(element)) {
17021
          unwrap(element);
17022
          return;
17023
        }
17024
        if (rule.outputName && rule.outputName !== lcTagName) {
17025
          mutate(element, rule.outputName);
17026
        }
17027
      }
17028
    };
17029
    const processAttr = (ele, settings, schema, scope, evt) => {
17030
      const tagName = ele.tagName.toLowerCase();
17031
      const {attrName, attrValue} = evt;
17032
      evt.keepAttr = shouldKeepAttribute(settings, schema, scope, tagName, attrName, attrValue);
17033
      if (evt.keepAttr) {
17034
        evt.allowedAttributes[attrName] = true;
17035
        if (isBooleanAttribute(attrName, schema)) {
17036
          evt.attrValue = attrName;
17037
        }
17038
        if (settings.allow_svg_data_urls && startsWith(attrValue, 'data:image/svg+xml')) {
17039
          evt.forceKeepAttr = true;
17040
        }
17041
      } else if (isRequiredAttributeOfInternalElement(ele, attrName)) {
17042
        evt.forceKeepAttr = true;
17043
      }
17044
    };
17045
    const shouldKeepAttribute = (settings, schema, scope, tagName, attrName, attrValue) => {
17046
      if (scope !== 'html' && !isNonHtmlElementRootName(tagName)) {
17047
        return true;
17048
      }
17049
      return !(attrName in filteredUrlAttrs && isInvalidUri(settings, attrValue, tagName)) && (!settings.validate || schema.isValid(tagName, attrName) || startsWith(attrName, 'data-') || startsWith(attrName, 'aria-'));
17050
    };
17051
    const isRequiredAttributeOfInternalElement = (ele, attrName) => ele.hasAttribute(internalElementAttr) && (attrName === 'id' || attrName === 'class' || attrName === 'style');
17052
    const isBooleanAttribute = (attrName, schema) => attrName in schema.getBoolAttrs();
17053
    const filterAttributes = (ele, settings, schema, scope) => {
17054
      const {attributes} = ele;
17055
      for (let i = attributes.length - 1; i >= 0; i--) {
17056
        const attr = attributes[i];
17057
        const attrName = attr.name;
17058
        const attrValue = attr.value;
17059
        if (!shouldKeepAttribute(settings, schema, scope, ele.tagName.toLowerCase(), attrName, attrValue) && !isRequiredAttributeOfInternalElement(ele, attrName)) {
17060
          ele.removeAttribute(attrName);
17061
        } else if (isBooleanAttribute(attrName, schema)) {
17062
          ele.setAttribute(attrName, attrName);
17063
        }
17064
      }
17065
    };
17066
    const setupPurify = (settings, schema, namespaceTracker) => {
17067
      const purify$1 = purify();
17068
      purify$1.addHook('uponSanitizeElement', (ele, evt) => {
17069
        processNode(ele, settings, schema, namespaceTracker.track(ele), evt);
17070
      });
17071
      purify$1.addHook('uponSanitizeAttribute', (ele, evt) => {
17072
        processAttr(ele, settings, schema, namespaceTracker.current(), evt);
17073
      });
17074
      return purify$1;
17075
    };
17076
    const getPurifyConfig = (settings, mimeType) => {
17077
      const basePurifyConfig = {
17078
        IN_PLACE: true,
17079
        ALLOW_UNKNOWN_PROTOCOLS: true,
17080
        ALLOWED_TAGS: [
17081
          '#comment',
17082
          '#cdata-section',
17083
          'body'
17084
        ],
1441 ariadna 17085
        ALLOWED_ATTR: [],
17086
        SAFE_FOR_XML: false
1 efrain 17087
      };
17088
      const config = { ...basePurifyConfig };
17089
      config.PARSER_MEDIA_TYPE = mimeType;
17090
      if (settings.allow_script_urls) {
17091
        config.ALLOWED_URI_REGEXP = /.*/;
17092
      } else if (settings.allow_html_data_urls) {
17093
        config.ALLOWED_URI_REGEXP = /^(?!(\w+script|mhtml):)/i;
17094
      }
17095
      return config;
17096
    };
1441 ariadna 17097
    const sanitizeSvgElement = ele => {
1 efrain 17098
      const xlinkAttrs = [
17099
        'type',
17100
        'href',
17101
        'role',
17102
        'arcrole',
17103
        'title',
17104
        'show',
17105
        'actuate',
17106
        'label',
17107
        'from',
17108
        'to'
17109
      ].map(name => `xlink:${ name }`);
17110
      const config = {
17111
        IN_PLACE: true,
17112
        USE_PROFILES: {
17113
          html: true,
17114
          svg: true,
17115
          svgFilters: true
17116
        },
17117
        ALLOWED_ATTR: xlinkAttrs
17118
      };
17119
      purify().sanitize(ele, config);
17120
    };
1441 ariadna 17121
    const sanitizeMathmlElement = (node, settings) => {
17122
      const config = {
17123
        IN_PLACE: true,
17124
        USE_PROFILES: { mathMl: true }
17125
      };
17126
      const purify$1 = purify();
17127
      const allowedEncodings = settings.allow_mathml_annotation_encodings;
17128
      const hasAllowedEncodings = isArray$1(allowedEncodings) && allowedEncodings.length > 0;
17129
      const hasValidEncoding = el => {
17130
        const encoding = el.getAttribute('encoding');
17131
        return hasAllowedEncodings && isString(encoding) && contains$2(allowedEncodings, encoding);
17132
      };
17133
      purify$1.addHook('uponSanitizeElement', (node, evt) => {
17134
        var _a;
17135
        const lcTagName = (_a = evt.tagName) !== null && _a !== void 0 ? _a : node.nodeName.toLowerCase();
17136
        if (hasAllowedEncodings && lcTagName === 'semantics') {
17137
          evt.allowedTags[lcTagName] = true;
17138
        }
17139
        if (lcTagName === 'annotation') {
17140
          const elm = node;
17141
          const keepElement = hasValidEncoding(elm);
17142
          evt.allowedTags[lcTagName] = keepElement;
17143
          if (!keepElement) {
17144
            elm.remove();
17145
          }
17146
        }
17147
      });
17148
      purify$1.sanitize(node, config);
17149
    };
17150
    const mkSanitizeNamespaceElement = settings => ele => {
17151
      const namespaceType = toScopeType(ele);
17152
      if (namespaceType === 'svg') {
17153
        sanitizeSvgElement(ele);
17154
      } else if (namespaceType === 'math') {
17155
        sanitizeMathmlElement(ele, settings);
17156
      } else {
17157
        throw new Error('Not a namespace element');
17158
      }
17159
    };
1 efrain 17160
    const getSanitizer = (settings, schema) => {
17161
      const namespaceTracker = createNamespaceTracker();
17162
      if (settings.sanitize) {
17163
        const purify = setupPurify(settings, schema, namespaceTracker);
17164
        const sanitizeHtmlElement = (body, mimeType) => {
17165
          purify.sanitize(body, getPurifyConfig(settings, mimeType));
17166
          purify.removed = [];
17167
          namespaceTracker.reset();
17168
        };
17169
        return {
17170
          sanitizeHtmlElement,
1441 ariadna 17171
          sanitizeNamespaceElement: mkSanitizeNamespaceElement(settings)
1 efrain 17172
        };
17173
      } else {
17174
        const sanitizeHtmlElement = (body, _mimeType) => {
17175
          const nodeIterator = document.createNodeIterator(body, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT);
17176
          let node;
17177
          while (node = nodeIterator.nextNode()) {
17178
            const currentScope = namespaceTracker.track(node);
17179
            processNode(node, settings, schema, currentScope);
17180
            if (isElement$6(node)) {
17181
              filterAttributes(node, settings, schema, currentScope);
17182
            }
17183
          }
17184
          namespaceTracker.reset();
17185
        };
17186
        const sanitizeNamespaceElement = noop;
17187
        return {
17188
          sanitizeHtmlElement,
17189
          sanitizeNamespaceElement
17190
        };
17191
      }
17192
    };
17193
 
17194
    const makeMap = Tools.makeMap, extend$1 = Tools.extend;
17195
    const transferChildren = (parent, nativeParent, specialElements, nsSanitizer) => {
17196
      const parentName = parent.name;
1441 ariadna 17197
      const isSpecial = parentName in specialElements && parentName !== 'title' && parentName !== 'textarea' && parentName !== 'noscript';
1 efrain 17198
      const childNodes = nativeParent.childNodes;
17199
      for (let ni = 0, nl = childNodes.length; ni < nl; ni++) {
17200
        const nativeChild = childNodes[ni];
17201
        const child = new AstNode(nativeChild.nodeName.toLowerCase(), nativeChild.nodeType);
17202
        if (isElement$6(nativeChild)) {
17203
          const attributes = nativeChild.attributes;
17204
          for (let ai = 0, al = attributes.length; ai < al; ai++) {
17205
            const attr = attributes[ai];
17206
            child.attr(attr.name, attr.value);
17207
          }
17208
          if (isNonHtmlElementRootName(child.name)) {
17209
            nsSanitizer(nativeChild);
17210
            child.value = nativeChild.innerHTML;
17211
          }
1441 ariadna 17212
        } else if (isText$b(nativeChild)) {
1 efrain 17213
          child.value = nativeChild.data;
17214
          if (isSpecial) {
17215
            child.raw = true;
17216
          }
17217
        } else if (isComment(nativeChild) || isCData(nativeChild) || isPi(nativeChild)) {
17218
          child.value = nativeChild.data;
17219
        }
17220
        if (!isNonHtmlElementRootName(child.name)) {
17221
          transferChildren(child, nativeChild, specialElements, nsSanitizer);
17222
        }
17223
        parent.append(child);
17224
      }
17225
    };
17226
    const walkTree = (root, preprocessors, postprocessors) => {
17227
      const traverseOrder = [];
17228
      for (let node = root, lastNode = node; node; lastNode = node, node = node.walk()) {
17229
        const tempNode = node;
17230
        each$e(preprocessors, preprocess => preprocess(tempNode));
17231
        if (isNullable(tempNode.parent) && tempNode !== root) {
17232
          node = lastNode;
17233
        } else {
17234
          traverseOrder.push(tempNode);
17235
        }
17236
      }
17237
      for (let i = traverseOrder.length - 1; i >= 0; i--) {
17238
        const node = traverseOrder[i];
17239
        each$e(postprocessors, postprocess => postprocess(node));
17240
      }
17241
    };
17242
    const whitespaceCleaner = (root, schema, settings, args) => {
17243
      const validate = settings.validate;
17244
      const nonEmptyElements = schema.getNonEmptyElements();
17245
      const whitespaceElements = schema.getWhitespaceElements();
17246
      const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
17247
      const textRootBlockElements = getTextRootBlockElements(schema);
17248
      const allWhiteSpaceRegExp = /[ \t\r\n]+/g;
17249
      const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
17250
      const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
17251
      const hasWhitespaceParent = node => {
17252
        let tempNode = node.parent;
17253
        while (isNonNullable(tempNode)) {
17254
          if (tempNode.name in whitespaceElements) {
17255
            return true;
17256
          } else {
17257
            tempNode = tempNode.parent;
17258
          }
17259
        }
17260
        return false;
17261
      };
17262
      const isTextRootBlockEmpty = node => {
17263
        let tempNode = node;
17264
        while (isNonNullable(tempNode)) {
17265
          if (tempNode.name in textRootBlockElements) {
17266
            return isEmpty(schema, nonEmptyElements, whitespaceElements, tempNode);
17267
          } else {
17268
            tempNode = tempNode.parent;
17269
          }
17270
        }
17271
        return false;
17272
      };
17273
      const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node) || isNonHtmlElementRootName(node.name) && node.parent === root;
17274
      const isAtEdgeOfBlock = (node, start) => {
17275
        const neighbour = start ? node.prev : node.next;
17276
        if (isNonNullable(neighbour) || isNullable(node.parent)) {
17277
          return false;
17278
        }
17279
        return isBlock(node.parent) && (node.parent !== root || args.isRootContent === true);
17280
      };
17281
      const preprocess = node => {
17282
        var _a;
17283
        if (node.type === 3) {
17284
          if (!hasWhitespaceParent(node)) {
17285
            let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
17286
            text = text.replace(allWhiteSpaceRegExp, ' ');
17287
            if (isLineBreakNode(node.prev, isBlock) || isAtEdgeOfBlock(node, true)) {
17288
              text = text.replace(startWhiteSpaceRegExp, '');
17289
            }
17290
            if (text.length === 0) {
17291
              node.remove();
1441 ariadna 17292
            } else if (text === ' ' && node.prev && node.prev.type === COMMENT && node.next && node.next.type === COMMENT) {
17293
              node.remove();
1 efrain 17294
            } else {
17295
              node.value = text;
17296
            }
17297
          }
17298
        }
17299
      };
17300
      const postprocess = node => {
17301
        var _a;
17302
        if (node.type === 1) {
17303
          const elementRule = schema.getElementRule(node.name);
17304
          if (validate && elementRule) {
17305
            const isNodeEmpty = isEmpty(schema, nonEmptyElements, whitespaceElements, node);
17306
            if (elementRule.paddInEmptyBlock && isNodeEmpty && isTextRootBlockEmpty(node)) {
17307
              paddEmptyNode(settings, args, isBlock, node);
17308
            } else if (elementRule.removeEmpty && isNodeEmpty) {
17309
              if (isBlock(node)) {
17310
                node.remove();
17311
              } else {
17312
                node.unwrap();
17313
              }
17314
            } else if (elementRule.paddEmpty && (isNodeEmpty || isPaddedWithNbsp(node))) {
17315
              paddEmptyNode(settings, args, isBlock, node);
17316
            }
17317
          }
17318
        } else if (node.type === 3) {
17319
          if (!hasWhitespaceParent(node)) {
17320
            let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
17321
            if (node.next && isBlock(node.next) || isAtEdgeOfBlock(node, false)) {
17322
              text = text.replace(endWhiteSpaceRegExp, '');
17323
            }
17324
            if (text.length === 0) {
17325
              node.remove();
17326
            } else {
17327
              node.value = text;
17328
            }
17329
          }
17330
        }
17331
      };
17332
      return [
17333
        preprocess,
17334
        postprocess
17335
      ];
17336
    };
17337
    const getRootBlockName = (settings, args) => {
17338
      var _a;
17339
      const name = (_a = args.forced_root_block) !== null && _a !== void 0 ? _a : settings.forced_root_block;
17340
      if (name === false) {
17341
        return '';
17342
      } else if (name === true) {
17343
        return 'p';
17344
      } else {
17345
        return name;
17346
      }
17347
    };
17348
    const DomParser = (settings = {}, schema = Schema()) => {
17349
      const nodeFilterRegistry = create$8();
17350
      const attributeFilterRegistry = create$8();
17351
      const defaultedSettings = {
17352
        validate: true,
17353
        root_name: 'body',
17354
        sanitize: true,
17355
        ...settings
17356
      };
17357
      const parser = new DOMParser();
17358
      const sanitizer = getSanitizer(defaultedSettings, schema);
17359
      const parseAndSanitizeWithContext = (html, rootName, format = 'html') => {
17360
        const mimeType = format === 'xhtml' ? 'application/xhtml+xml' : 'text/html';
17361
        const isSpecialRoot = has$2(schema.getSpecialElements(), rootName.toLowerCase());
17362
        const content = isSpecialRoot ? `<${ rootName }>${ html }</${ rootName }>` : html;
1441 ariadna 17363
        const makeWrap = () => {
17364
          if (format === 'xhtml') {
17365
            return `<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>${ content }</body></html>`;
17366
          } else if (/^[\s]*<head/i.test(html) || /^[\s]*<html/i.test(html) || /^[\s]*<!DOCTYPE/i.test(html)) {
17367
            return `<html>${ content }</html>`;
17368
          } else {
17369
            return `<body>${ content }</body>`;
17370
          }
17371
        };
17372
        const body = parser.parseFromString(makeWrap(), mimeType).body;
1 efrain 17373
        sanitizer.sanitizeHtmlElement(body, mimeType);
17374
        return isSpecialRoot ? body.firstChild : body;
17375
      };
17376
      const addNodeFilter = nodeFilterRegistry.addFilter;
17377
      const getNodeFilters = nodeFilterRegistry.getFilters;
17378
      const removeNodeFilter = nodeFilterRegistry.removeFilter;
17379
      const addAttributeFilter = attributeFilterRegistry.addFilter;
17380
      const getAttributeFilters = attributeFilterRegistry.getFilters;
17381
      const removeAttributeFilter = attributeFilterRegistry.removeFilter;
17382
      const findInvalidChildren = (node, invalidChildren) => {
17383
        if (isInvalid(schema, node)) {
17384
          invalidChildren.push(node);
17385
        }
17386
      };
17387
      const isWrappableNode = (blockElements, node) => {
17388
        const isInternalElement = isString(node.attr(internalElementAttr));
17389
        const isInlineElement = node.type === 1 && (!has$2(blockElements, node.name) && !isTransparentAstBlock(schema, node)) && !isNonHtmlElementRootName(node.name);
17390
        return node.type === 3 || isInlineElement && !isInternalElement;
17391
      };
17392
      const addRootBlocks = (rootNode, rootBlockName) => {
17393
        const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
17394
        const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
17395
        const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
17396
        let node = rootNode.firstChild, rootBlockNode = null;
17397
        const trim = rootBlock => {
17398
          var _a, _b;
17399
          if (rootBlock) {
17400
            node = rootBlock.firstChild;
17401
            if (node && node.type === 3) {
17402
              node.value = (_a = node.value) === null || _a === void 0 ? void 0 : _a.replace(startWhiteSpaceRegExp, '');
17403
            }
17404
            node = rootBlock.lastChild;
17405
            if (node && node.type === 3) {
17406
              node.value = (_b = node.value) === null || _b === void 0 ? void 0 : _b.replace(endWhiteSpaceRegExp, '');
17407
            }
17408
          }
17409
        };
17410
        if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) {
17411
          return;
17412
        }
17413
        while (node) {
17414
          const next = node.next;
17415
          if (isWrappableNode(blockElements, node)) {
17416
            if (!rootBlockNode) {
17417
              rootBlockNode = new AstNode(rootBlockName, 1);
17418
              rootBlockNode.attr(defaultedSettings.forced_root_block_attrs);
17419
              rootNode.insert(rootBlockNode, node);
17420
              rootBlockNode.append(node);
17421
            } else {
17422
              rootBlockNode.append(node);
17423
            }
17424
          } else {
17425
            trim(rootBlockNode);
17426
            rootBlockNode = null;
17427
          }
17428
          node = next;
17429
        }
17430
        trim(rootBlockNode);
17431
      };
17432
      const parse = (html, args = {}) => {
17433
        var _a;
17434
        const validate = defaultedSettings.validate;
17435
        const rootName = (_a = args.context) !== null && _a !== void 0 ? _a : defaultedSettings.root_name;
17436
        const element = parseAndSanitizeWithContext(html, rootName, args.format);
17437
        updateChildren(schema, element);
17438
        const rootNode = new AstNode(rootName, 11);
17439
        transferChildren(rootNode, element, schema.getSpecialElements(), sanitizer.sanitizeNamespaceElement);
17440
        element.innerHTML = '';
17441
        const [whitespacePre, whitespacePost] = whitespaceCleaner(rootNode, schema, defaultedSettings, args);
17442
        const invalidChildren = [];
17443
        const invalidFinder = validate ? node => findInvalidChildren(node, invalidChildren) : noop;
17444
        const matches = {
17445
          nodes: {},
17446
          attributes: {}
17447
        };
17448
        const matchFinder = node => matchNode$1(getNodeFilters(), getAttributeFilters(), node, matches);
17449
        walkTree(rootNode, [
17450
          whitespacePre,
17451
          matchFinder
17452
        ], [
17453
          whitespacePost,
17454
          invalidFinder
17455
        ]);
17456
        invalidChildren.reverse();
17457
        if (validate && invalidChildren.length > 0) {
17458
          if (args.context) {
17459
            const {
17460
              pass: topLevelChildren,
17461
              fail: otherChildren
17462
            } = partition$2(invalidChildren, child => child.parent === rootNode);
17463
            cleanInvalidNodes(otherChildren, schema, rootNode, matchFinder);
17464
            args.invalid = topLevelChildren.length > 0;
17465
          } else {
17466
            cleanInvalidNodes(invalidChildren, schema, rootNode, matchFinder);
17467
          }
17468
        }
17469
        const rootBlockName = getRootBlockName(defaultedSettings, args);
17470
        if (rootBlockName && (rootNode.name === 'body' || args.isRootContent)) {
17471
          addRootBlocks(rootNode, rootBlockName);
17472
        }
17473
        if (!args.invalid) {
17474
          runFilters(matches, args);
17475
        }
17476
        return rootNode;
17477
      };
17478
      const exports = {
17479
        schema,
17480
        addAttributeFilter,
17481
        getAttributeFilters,
17482
        removeAttributeFilter,
17483
        addNodeFilter,
17484
        getNodeFilters,
17485
        removeNodeFilter,
17486
        parse
17487
      };
17488
      register$4(exports, defaultedSettings);
17489
      register$5(exports, defaultedSettings, schema);
17490
      return exports;
17491
    };
17492
 
17493
    const serializeContent = content => isTreeNode(content) ? HtmlSerializer({ validate: false }).serialize(content) : content;
17494
    const withSerializedContent = (content, fireEvent, parserSettings) => {
17495
      const serializedContent = serializeContent(content);
17496
      const eventArgs = fireEvent(serializedContent);
17497
      if (eventArgs.isDefaultPrevented()) {
17498
        return eventArgs;
17499
      } else if (isTreeNode(content)) {
17500
        if (eventArgs.content !== serializedContent) {
17501
          const rootNode = DomParser({
17502
            validate: false,
17503
            forced_root_block: false,
17504
            ...parserSettings
17505
          }).parse(eventArgs.content, { context: content.name });
17506
          return {
17507
            ...eventArgs,
17508
            content: rootNode
17509
          };
17510
        } else {
17511
          return {
17512
            ...eventArgs,
17513
            content
17514
          };
17515
        }
17516
      } else {
17517
        return eventArgs;
17518
      }
17519
    };
1441 ariadna 17520
    const makeParserSettings = editor => ({
17521
      sanitize: shouldSanitizeXss(editor),
17522
      sandbox_iframes: shouldSandboxIframes(editor),
17523
      sandbox_iframes_exclusions: getSandboxIframesExclusions(editor)
17524
    });
1 efrain 17525
    const preProcessGetContent = (editor, args) => {
17526
      if (args.no_events) {
17527
        return Result.value(args);
17528
      } else {
17529
        const eventArgs = fireBeforeGetContent(editor, args);
17530
        if (eventArgs.isDefaultPrevented()) {
17531
          return Result.error(fireGetContent(editor, {
17532
            content: '',
17533
            ...eventArgs
17534
          }).content);
17535
        } else {
17536
          return Result.value(eventArgs);
17537
        }
17538
      }
17539
    };
17540
    const postProcessGetContent = (editor, content, args) => {
17541
      if (args.no_events) {
17542
        return content;
17543
      } else {
17544
        const processedEventArgs = withSerializedContent(content, content => fireGetContent(editor, {
17545
          ...args,
17546
          content
1441 ariadna 17547
        }), makeParserSettings(editor));
1 efrain 17548
        return processedEventArgs.content;
17549
      }
17550
    };
17551
    const preProcessSetContent = (editor, args) => {
17552
      if (args.no_events) {
17553
        return Result.value(args);
17554
      } else {
17555
        const processedEventArgs = withSerializedContent(args.content, content => fireBeforeSetContent(editor, {
17556
          ...args,
17557
          content
1441 ariadna 17558
        }), makeParserSettings(editor));
1 efrain 17559
        if (processedEventArgs.isDefaultPrevented()) {
17560
          fireSetContent(editor, processedEventArgs);
17561
          return Result.error(undefined);
17562
        } else {
17563
          return Result.value(processedEventArgs);
17564
        }
17565
      }
17566
    };
17567
    const postProcessSetContent = (editor, content, args) => {
17568
      if (!args.no_events) {
17569
        fireSetContent(editor, {
17570
          ...args,
17571
          content
17572
        });
17573
      }
17574
    };
17575
 
17576
    const tableModel = (element, width, rows) => ({
17577
      element,
17578
      width,
17579
      rows
17580
    });
17581
    const tableRow = (element, cells) => ({
17582
      element,
17583
      cells
17584
    });
17585
    const cellPosition = (x, y) => ({
17586
      x,
17587
      y
17588
    });
17589
    const getSpan = (td, key) => {
17590
      return getOpt(td, key).bind(toInt).getOr(1);
17591
    };
17592
    const fillout = (table, x, y, tr, td) => {
17593
      const rowspan = getSpan(td, 'rowspan');
17594
      const colspan = getSpan(td, 'colspan');
17595
      const rows = table.rows;
17596
      for (let y2 = y; y2 < y + rowspan; y2++) {
17597
        if (!rows[y2]) {
17598
          rows[y2] = tableRow(deep$1(tr), []);
17599
        }
17600
        for (let x2 = x; x2 < x + colspan; x2++) {
17601
          const cells = rows[y2].cells;
17602
          cells[x2] = y2 === y && x2 === x ? td : shallow$1(td);
17603
        }
17604
      }
17605
    };
17606
    const cellExists = (table, x, y) => {
17607
      const rows = table.rows;
17608
      const cells = rows[y] ? rows[y].cells : [];
17609
      return !!cells[x];
17610
    };
17611
    const skipCellsX = (table, x, y) => {
17612
      while (cellExists(table, x, y)) {
17613
        x++;
17614
      }
17615
      return x;
17616
    };
17617
    const getWidth = rows => {
17618
      return foldl(rows, (acc, row) => {
17619
        return row.cells.length > acc ? row.cells.length : acc;
17620
      }, 0);
17621
    };
17622
    const findElementPos = (table, element) => {
17623
      const rows = table.rows;
17624
      for (let y = 0; y < rows.length; y++) {
17625
        const cells = rows[y].cells;
17626
        for (let x = 0; x < cells.length; x++) {
17627
          if (eq(cells[x], element)) {
17628
            return Optional.some(cellPosition(x, y));
17629
          }
17630
        }
17631
      }
17632
      return Optional.none();
17633
    };
17634
    const extractRows = (table, sx, sy, ex, ey) => {
17635
      const newRows = [];
17636
      const rows = table.rows;
17637
      for (let y = sy; y <= ey; y++) {
17638
        const cells = rows[y].cells;
17639
        const slice = sx < ex ? cells.slice(sx, ex + 1) : cells.slice(ex, sx + 1);
17640
        newRows.push(tableRow(rows[y].element, slice));
17641
      }
17642
      return newRows;
17643
    };
17644
    const subTable = (table, startPos, endPos) => {
17645
      const sx = startPos.x, sy = startPos.y;
17646
      const ex = endPos.x, ey = endPos.y;
17647
      const newRows = sy < ey ? extractRows(table, sx, sy, ex, ey) : extractRows(table, sx, ey, ex, sy);
17648
      return tableModel(table.element, getWidth(newRows), newRows);
17649
    };
17650
    const createDomTable = (table, rows) => {
17651
      const tableElement = shallow$1(table.element);
17652
      const tableBody = SugarElement.fromTag('tbody');
17653
      append(tableBody, rows);
17654
      append$1(tableElement, tableBody);
17655
      return tableElement;
17656
    };
17657
    const modelRowsToDomRows = table => {
17658
      return map$3(table.rows, row => {
17659
        const cells = map$3(row.cells, cell => {
17660
          const td = deep$1(cell);
1441 ariadna 17661
          remove$9(td, 'colspan');
17662
          remove$9(td, 'rowspan');
1 efrain 17663
          return td;
17664
        });
17665
        const tr = shallow$1(row.element);
17666
        append(tr, cells);
17667
        return tr;
17668
      });
17669
    };
17670
    const fromDom = tableElm => {
17671
      const table = tableModel(shallow$1(tableElm), 0, []);
17672
      each$e(descendants(tableElm, 'tr'), (tr, y) => {
17673
        each$e(descendants(tr, 'td,th'), (td, x) => {
17674
          fillout(table, skipCellsX(table, x, y), y, tr, td);
17675
        });
17676
      });
17677
      return tableModel(table.element, getWidth(table.rows), table.rows);
17678
    };
17679
    const toDom = table => {
17680
      return createDomTable(table, modelRowsToDomRows(table));
17681
    };
17682
    const subsection = (table, startElement, endElement) => {
17683
      return findElementPos(table, startElement).bind(startPos => {
17684
        return findElementPos(table, endElement).map(endPos => {
17685
          return subTable(table, startPos, endPos);
17686
        });
17687
      });
17688
    };
17689
 
17690
    const findParentListContainer = parents => find$2(parents, elm => name(elm) === 'ul' || name(elm) === 'ol');
17691
    const getFullySelectedListWrappers = (parents, rng) => find$2(parents, elm => name(elm) === 'li' && hasAllContentsSelected(elm, rng)).fold(constant([]), _li => findParentListContainer(parents).map(listCont => {
17692
      const listElm = SugarElement.fromTag(name(listCont));
17693
      const listStyles = filter$4(getAllRaw(listCont), (_style, name) => startsWith(name, 'list-style'));
17694
      setAll(listElm, listStyles);
17695
      return [
17696
        SugarElement.fromTag('li'),
17697
        listElm
17698
      ];
17699
    }).getOr([]));
17700
    const wrap = (innerElm, elms) => {
17701
      const wrapped = foldl(elms, (acc, elm) => {
17702
        append$1(elm, acc);
17703
        return elm;
17704
      }, innerElm);
17705
      return elms.length > 0 ? fromElements([wrapped]) : wrapped;
17706
    };
17707
    const directListWrappers = commonAnchorContainer => {
17708
      if (isListItem$1(commonAnchorContainer)) {
17709
        return parent(commonAnchorContainer).filter(isList).fold(constant([]), listElm => [
17710
          commonAnchorContainer,
17711
          listElm
17712
        ]);
17713
      } else {
17714
        return isList(commonAnchorContainer) ? [commonAnchorContainer] : [];
17715
      }
17716
    };
17717
    const getWrapElements = (rootNode, rng, schema) => {
17718
      const commonAnchorContainer = SugarElement.fromDom(rng.commonAncestorContainer);
17719
      const parents = parentsAndSelf(commonAnchorContainer, rootNode);
17720
      const wrapElements = filter$5(parents, el => schema.isWrapper(name(el)));
17721
      const listWrappers = getFullySelectedListWrappers(parents, rng);
17722
      const allWrappers = wrapElements.concat(listWrappers.length ? listWrappers : directListWrappers(commonAnchorContainer));
17723
      return map$3(allWrappers, shallow$1);
17724
    };
17725
    const emptyFragment = () => fromElements([]);
17726
    const getFragmentFromRange = (rootNode, rng, schema) => wrap(SugarElement.fromDom(rng.cloneContents()), getWrapElements(rootNode, rng, schema));
17727
    const getParentTable = (rootElm, cell) => ancestor$3(cell, 'table', curry(eq, rootElm));
17728
    const getTableFragment = (rootNode, selectedTableCells) => getParentTable(rootNode, selectedTableCells[0]).bind(tableElm => {
17729
      const firstCell = selectedTableCells[0];
17730
      const lastCell = selectedTableCells[selectedTableCells.length - 1];
17731
      const fullTableModel = fromDom(tableElm);
17732
      return subsection(fullTableModel, firstCell, lastCell).map(sectionedTableModel => fromElements([toDom(sectionedTableModel)]));
17733
    }).getOrThunk(emptyFragment);
17734
    const getSelectionFragment = (rootNode, ranges, schema) => ranges.length > 0 && ranges[0].collapsed ? emptyFragment() : getFragmentFromRange(rootNode, ranges[0], schema);
17735
    const read$3 = (rootNode, ranges, schema) => {
17736
      const selectedCells = getCellsFromElementOrRanges(ranges, rootNode);
17737
      return selectedCells.length > 0 ? getTableFragment(rootNode, selectedCells) : getSelectionFragment(rootNode, ranges, schema);
17738
    };
17739
 
17740
    const isCollapsibleWhitespace = (text, index) => index >= 0 && index < text.length && isWhiteSpace(text.charAt(index));
17741
    const getInnerText = bin => {
17742
      return trim$2(bin.innerText);
17743
    };
17744
    const getContextNodeName = parentBlockOpt => parentBlockOpt.map(block => block.nodeName).getOr('div').toLowerCase();
17745
    const getTextContent = editor => Optional.from(editor.selection.getRng()).map(rng => {
17746
      var _a;
17747
      const parentBlockOpt = Optional.from(editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock));
17748
      const body = editor.getBody();
17749
      const contextNodeName = getContextNodeName(parentBlockOpt);
17750
      const rangeContentClone = SugarElement.fromDom(rng.cloneContents());
17751
      cleanupBogusElements(rangeContentClone);
17752
      cleanupInputNames(rangeContentClone);
17753
      const bin = editor.dom.add(body, contextNodeName, {
17754
        'data-mce-bogus': 'all',
17755
        'style': 'overflow: hidden; opacity: 0;'
17756
      }, rangeContentClone.dom);
17757
      const text = getInnerText(bin);
17758
      const nonRenderedText = trim$2((_a = bin.textContent) !== null && _a !== void 0 ? _a : '');
17759
      editor.dom.remove(bin);
17760
      if (isCollapsibleWhitespace(nonRenderedText, 0) || isCollapsibleWhitespace(nonRenderedText, nonRenderedText.length - 1)) {
17761
        const parentBlock = parentBlockOpt.getOr(body);
17762
        const parentBlockText = getInnerText(parentBlock);
17763
        const textIndex = parentBlockText.indexOf(text);
17764
        if (textIndex === -1) {
17765
          return text;
17766
        } else {
17767
          const hasProceedingSpace = isCollapsibleWhitespace(parentBlockText, textIndex - 1);
17768
          const hasTrailingSpace = isCollapsibleWhitespace(parentBlockText, textIndex + text.length);
17769
          return (hasProceedingSpace ? ' ' : '') + text + (hasTrailingSpace ? ' ' : '');
17770
        }
17771
      } else {
17772
        return text;
17773
      }
17774
    }).getOr('');
17775
    const getSerializedContent = (editor, args) => {
17776
      const rng = editor.selection.getRng(), tmpElm = editor.dom.create('body');
17777
      const sel = editor.selection.getSel();
17778
      const ranges = processRanges(editor, getRanges$1(sel));
17779
      const fragment = args.contextual ? read$3(SugarElement.fromDom(editor.getBody()), ranges, editor.schema).dom : rng.cloneContents();
17780
      if (fragment) {
17781
        tmpElm.appendChild(fragment);
17782
      }
17783
      return editor.selection.serializer.serialize(tmpElm, args);
17784
    };
17785
    const extractSelectedContent = (editor, args) => {
17786
      if (args.format === 'text') {
17787
        return getTextContent(editor);
17788
      } else {
17789
        const content = getSerializedContent(editor, args);
17790
        if (args.format === 'tree') {
17791
          return content;
17792
        } else {
17793
          return editor.selection.isCollapsed() ? '' : content;
17794
        }
17795
      }
17796
    };
17797
    const setupArgs$3 = (args, format) => ({
17798
      ...args,
17799
      format,
17800
      get: true,
17801
      selection: true,
17802
      getInner: true
17803
    });
17804
    const getSelectedContentInternal = (editor, format, args = {}) => {
17805
      const defaultedArgs = setupArgs$3(args, format);
17806
      return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
17807
        const content = extractSelectedContent(editor, updatedArgs);
17808
        return postProcessGetContent(editor, content, updatedArgs);
17809
      });
17810
    };
17811
 
17812
    const KEEP = 0, INSERT = 1, DELETE = 2;
17813
    const diff = (left, right) => {
17814
      const size = left.length + right.length + 2;
17815
      const vDown = new Array(size);
17816
      const vUp = new Array(size);
17817
      const snake = (start, end, diag) => {
17818
        return {
17819
          start,
17820
          end,
17821
          diag
17822
        };
17823
      };
17824
      const buildScript = (start1, end1, start2, end2, script) => {
17825
        const middle = getMiddleSnake(start1, end1, start2, end2);
17826
        if (middle === null || middle.start === end1 && middle.diag === end1 - end2 || middle.end === start1 && middle.diag === start1 - start2) {
17827
          let i = start1;
17828
          let j = start2;
17829
          while (i < end1 || j < end2) {
17830
            if (i < end1 && j < end2 && left[i] === right[j]) {
17831
              script.push([
17832
                KEEP,
17833
                left[i]
17834
              ]);
17835
              ++i;
17836
              ++j;
17837
            } else {
17838
              if (end1 - start1 > end2 - start2) {
17839
                script.push([
17840
                  DELETE,
17841
                  left[i]
17842
                ]);
17843
                ++i;
17844
              } else {
17845
                script.push([
17846
                  INSERT,
17847
                  right[j]
17848
                ]);
17849
                ++j;
17850
              }
17851
            }
17852
          }
17853
        } else {
17854
          buildScript(start1, middle.start, start2, middle.start - middle.diag, script);
17855
          for (let i2 = middle.start; i2 < middle.end; ++i2) {
17856
            script.push([
17857
              KEEP,
17858
              left[i2]
17859
            ]);
17860
          }
17861
          buildScript(middle.end, end1, middle.end - middle.diag, end2, script);
17862
        }
17863
      };
17864
      const buildSnake = (start, diag, end1, end2) => {
17865
        let end = start;
17866
        while (end - diag < end2 && end < end1 && left[end] === right[end - diag]) {
17867
          ++end;
17868
        }
17869
        return snake(start, end, diag);
17870
      };
17871
      const getMiddleSnake = (start1, end1, start2, end2) => {
17872
        const m = end1 - start1;
17873
        const n = end2 - start2;
17874
        if (m === 0 || n === 0) {
17875
          return null;
17876
        }
17877
        const delta = m - n;
17878
        const sum = n + m;
17879
        const offset = (sum % 2 === 0 ? sum : sum + 1) / 2;
17880
        vDown[1 + offset] = start1;
17881
        vUp[1 + offset] = end1 + 1;
17882
        let d, k, i, x, y;
17883
        for (d = 0; d <= offset; ++d) {
17884
          for (k = -d; k <= d; k += 2) {
17885
            i = k + offset;
17886
            if (k === -d || k !== d && vDown[i - 1] < vDown[i + 1]) {
17887
              vDown[i] = vDown[i + 1];
17888
            } else {
17889
              vDown[i] = vDown[i - 1] + 1;
17890
            }
17891
            x = vDown[i];
17892
            y = x - start1 + start2 - k;
17893
            while (x < end1 && y < end2 && left[x] === right[y]) {
17894
              vDown[i] = ++x;
17895
              ++y;
17896
            }
17897
            if (delta % 2 !== 0 && delta - d <= k && k <= delta + d) {
17898
              if (vUp[i - delta] <= vDown[i]) {
17899
                return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
17900
              }
17901
            }
17902
          }
17903
          for (k = delta - d; k <= delta + d; k += 2) {
17904
            i = k + offset - delta;
17905
            if (k === delta - d || k !== delta + d && vUp[i + 1] <= vUp[i - 1]) {
17906
              vUp[i] = vUp[i + 1] - 1;
17907
            } else {
17908
              vUp[i] = vUp[i - 1];
17909
            }
17910
            x = vUp[i] - 1;
17911
            y = x - start1 + start2 - k;
17912
            while (x >= start1 && y >= start2 && left[x] === right[y]) {
17913
              vUp[i] = x--;
17914
              y--;
17915
            }
17916
            if (delta % 2 === 0 && -d <= k && k <= d) {
17917
              if (vUp[i] <= vDown[i + delta]) {
17918
                return buildSnake(vUp[i], k + start1 - start2, end1, end2);
17919
              }
17920
            }
17921
          }
17922
        }
17923
        return null;
17924
      };
17925
      const script = [];
17926
      buildScript(0, left.length, 0, right.length, script);
17927
      return script;
17928
    };
17929
 
17930
    const getOuterHtml = elm => {
17931
      if (isElement$6(elm)) {
17932
        return elm.outerHTML;
1441 ariadna 17933
      } else if (isText$b(elm)) {
1 efrain 17934
        return Entities.encodeRaw(elm.data, false);
17935
      } else if (isComment(elm)) {
17936
        return '<!--' + elm.data + '-->';
17937
      }
17938
      return '';
17939
    };
17940
    const createFragment = html => {
17941
      let node;
17942
      const container = document.createElement('div');
17943
      const frag = document.createDocumentFragment();
17944
      if (html) {
17945
        container.innerHTML = html;
17946
      }
17947
      while (node = container.firstChild) {
17948
        frag.appendChild(node);
17949
      }
17950
      return frag;
17951
    };
17952
    const insertAt = (elm, html, index) => {
17953
      const fragment = createFragment(html);
17954
      if (elm.hasChildNodes() && index < elm.childNodes.length) {
17955
        const target = elm.childNodes[index];
17956
        elm.insertBefore(fragment, target);
17957
      } else {
17958
        elm.appendChild(fragment);
17959
      }
17960
    };
17961
    const removeAt = (elm, index) => {
17962
      if (elm.hasChildNodes() && index < elm.childNodes.length) {
17963
        const target = elm.childNodes[index];
17964
        elm.removeChild(target);
17965
      }
17966
    };
17967
    const applyDiff = (diff, elm) => {
17968
      let index = 0;
17969
      each$e(diff, action => {
17970
        if (action[0] === KEEP) {
17971
          index++;
17972
        } else if (action[0] === INSERT) {
17973
          insertAt(elm, action[1], index);
17974
          index++;
17975
        } else if (action[0] === DELETE) {
17976
          removeAt(elm, index);
17977
        }
17978
      });
17979
    };
17980
    const read$2 = (elm, trimZwsp) => filter$5(map$3(from(elm.childNodes), trimZwsp ? compose(trim$2, getOuterHtml) : getOuterHtml), item => {
17981
      return item.length > 0;
17982
    });
17983
    const write = (fragments, elm) => {
17984
      const currentFragments = map$3(from(elm.childNodes), getOuterHtml);
17985
      applyDiff(diff(currentFragments, fragments), elm);
17986
      return elm;
17987
    };
17988
 
17989
    const lazyTempDocument = cached(() => document.implementation.createHTMLDocument('undo'));
17990
    const hasIframes = body => body.querySelector('iframe') !== null;
17991
    const createFragmentedLevel = fragments => {
17992
      return {
17993
        type: 'fragmented',
17994
        fragments,
17995
        content: '',
17996
        bookmark: null,
17997
        beforeBookmark: null
17998
      };
17999
    };
18000
    const createCompleteLevel = content => {
18001
      return {
18002
        type: 'complete',
18003
        fragments: null,
18004
        content,
18005
        bookmark: null,
18006
        beforeBookmark: null
18007
      };
18008
    };
18009
    const createFromEditor = editor => {
18010
      const tempAttrs = editor.serializer.getTempAttrs();
18011
      const body = trim$1(editor.getBody(), tempAttrs);
18012
      return hasIframes(body) ? createFragmentedLevel(read$2(body, true)) : createCompleteLevel(trim$2(body.innerHTML));
18013
    };
18014
    const applyToEditor = (editor, level, before) => {
18015
      const bookmark = before ? level.beforeBookmark : level.bookmark;
18016
      if (level.type === 'fragmented') {
18017
        write(level.fragments, editor.getBody());
18018
      } else {
18019
        editor.setContent(level.content, {
18020
          format: 'raw',
18021
          no_selection: isNonNullable(bookmark) && isPathBookmark(bookmark) ? !bookmark.isFakeCaret : true
18022
        });
18023
      }
18024
      if (bookmark) {
18025
        editor.selection.moveToBookmark(bookmark);
18026
        editor.selection.scrollIntoView();
18027
      }
18028
    };
18029
    const getLevelContent = level => {
18030
      return level.type === 'fragmented' ? level.fragments.join('') : level.content;
18031
    };
18032
    const getCleanLevelContent = level => {
18033
      const elm = SugarElement.fromTag('body', lazyTempDocument());
18034
      set$1(elm, getLevelContent(level));
18035
      each$e(descendants(elm, '*[data-mce-bogus]'), unwrap);
18036
      return get$6(elm);
18037
    };
18038
    const hasEqualContent = (level1, level2) => getLevelContent(level1) === getLevelContent(level2);
18039
    const hasEqualCleanedContent = (level1, level2) => getCleanLevelContent(level1) === getCleanLevelContent(level2);
18040
    const isEq$1 = (level1, level2) => {
18041
      if (!level1 || !level2) {
18042
        return false;
18043
      } else if (hasEqualContent(level1, level2)) {
18044
        return true;
18045
      } else {
18046
        return hasEqualCleanedContent(level1, level2);
18047
      }
18048
    };
18049
 
18050
    const isUnlocked = locks => locks.get() === 0;
18051
 
18052
    const setTyping = (undoManager, typing, locks) => {
18053
      if (isUnlocked(locks)) {
18054
        undoManager.typing = typing;
18055
      }
18056
    };
18057
    const endTyping = (undoManager, locks) => {
18058
      if (undoManager.typing) {
18059
        setTyping(undoManager, false, locks);
18060
        undoManager.add();
18061
      }
18062
    };
18063
    const endTypingLevelIgnoreLocks = undoManager => {
18064
      if (undoManager.typing) {
18065
        undoManager.typing = false;
18066
        undoManager.add();
18067
      }
18068
    };
18069
 
18070
    const beforeChange$1 = (editor, locks, beforeBookmark) => {
18071
      if (isUnlocked(locks)) {
18072
        beforeBookmark.set(getUndoBookmark(editor.selection));
18073
      }
18074
    };
18075
    const addUndoLevel$1 = (editor, undoManager, index, locks, beforeBookmark, level, event) => {
18076
      const currentLevel = createFromEditor(editor);
18077
      const newLevel = Tools.extend(level || {}, currentLevel);
18078
      if (!isUnlocked(locks) || editor.removed) {
18079
        return null;
18080
      }
18081
      const lastLevel = undoManager.data[index.get()];
18082
      if (editor.dispatch('BeforeAddUndo', {
18083
          level: newLevel,
18084
          lastLevel,
18085
          originalEvent: event
18086
        }).isDefaultPrevented()) {
18087
        return null;
18088
      }
18089
      if (lastLevel && isEq$1(lastLevel, newLevel)) {
18090
        return null;
18091
      }
18092
      if (undoManager.data[index.get()]) {
18093
        beforeBookmark.get().each(bm => {
18094
          undoManager.data[index.get()].beforeBookmark = bm;
18095
        });
18096
      }
18097
      const customUndoRedoLevels = getCustomUndoRedoLevels(editor);
18098
      if (customUndoRedoLevels) {
18099
        if (undoManager.data.length > customUndoRedoLevels) {
18100
          for (let i = 0; i < undoManager.data.length - 1; i++) {
18101
            undoManager.data[i] = undoManager.data[i + 1];
18102
          }
18103
          undoManager.data.length--;
18104
          index.set(undoManager.data.length);
18105
        }
18106
      }
18107
      newLevel.bookmark = getUndoBookmark(editor.selection);
18108
      if (index.get() < undoManager.data.length - 1) {
18109
        undoManager.data.length = index.get() + 1;
18110
      }
18111
      undoManager.data.push(newLevel);
18112
      index.set(undoManager.data.length - 1);
18113
      const args = {
18114
        level: newLevel,
18115
        lastLevel,
18116
        originalEvent: event
18117
      };
18118
      if (index.get() > 0) {
18119
        editor.setDirty(true);
18120
        editor.dispatch('AddUndo', args);
18121
        editor.dispatch('change', args);
18122
      } else {
18123
        editor.dispatch('AddUndo', args);
18124
      }
18125
      return newLevel;
18126
    };
18127
    const clear$1 = (editor, undoManager, index) => {
18128
      undoManager.data = [];
18129
      index.set(0);
18130
      undoManager.typing = false;
18131
      editor.dispatch('ClearUndos');
18132
    };
18133
    const extra$1 = (editor, undoManager, index, callback1, callback2) => {
18134
      if (undoManager.transact(callback1)) {
18135
        const bookmark = undoManager.data[index.get()].bookmark;
18136
        const lastLevel = undoManager.data[index.get() - 1];
18137
        applyToEditor(editor, lastLevel, true);
18138
        if (undoManager.transact(callback2)) {
18139
          undoManager.data[index.get() - 1].beforeBookmark = bookmark;
18140
        }
18141
      }
18142
    };
18143
    const redo$1 = (editor, index, data) => {
18144
      let level;
18145
      if (index.get() < data.length - 1) {
18146
        index.set(index.get() + 1);
18147
        level = data[index.get()];
18148
        applyToEditor(editor, level, false);
18149
        editor.setDirty(true);
18150
        editor.dispatch('Redo', { level });
18151
      }
18152
      return level;
18153
    };
18154
    const undo$1 = (editor, undoManager, locks, index) => {
18155
      let level;
18156
      if (undoManager.typing) {
18157
        undoManager.add();
18158
        undoManager.typing = false;
18159
        setTyping(undoManager, false, locks);
18160
      }
18161
      if (index.get() > 0) {
18162
        index.set(index.get() - 1);
18163
        level = undoManager.data[index.get()];
18164
        applyToEditor(editor, level, true);
18165
        editor.setDirty(true);
18166
        editor.dispatch('Undo', { level });
18167
      }
18168
      return level;
18169
    };
18170
    const reset$1 = undoManager => {
18171
      undoManager.clear();
18172
      undoManager.add();
18173
    };
18174
    const hasUndo$1 = (editor, undoManager, index) => index.get() > 0 || undoManager.typing && undoManager.data[0] && !isEq$1(createFromEditor(editor), undoManager.data[0]);
18175
    const hasRedo$1 = (undoManager, index) => index.get() < undoManager.data.length - 1 && !undoManager.typing;
18176
    const transact$1 = (undoManager, locks, callback) => {
18177
      endTyping(undoManager, locks);
18178
      undoManager.beforeChange();
18179
      undoManager.ignore(callback);
18180
      return undoManager.add();
18181
    };
18182
    const ignore$1 = (locks, callback) => {
18183
      try {
18184
        locks.set(locks.get() + 1);
18185
        callback();
18186
      } finally {
18187
        locks.set(locks.get() - 1);
18188
      }
18189
    };
18190
 
18191
    const addVisualInternal = (editor, elm) => {
18192
      const dom = editor.dom;
18193
      const scope = isNonNullable(elm) ? elm : editor.getBody();
18194
      each$e(dom.select('table,a', scope), matchedElm => {
18195
        switch (matchedElm.nodeName) {
18196
        case 'TABLE':
18197
          const cls = getVisualAidsTableClass(editor);
18198
          const value = dom.getAttrib(matchedElm, 'border');
18199
          if ((!value || value === '0') && editor.hasVisual) {
18200
            dom.addClass(matchedElm, cls);
18201
          } else {
18202
            dom.removeClass(matchedElm, cls);
18203
          }
18204
          break;
18205
        case 'A':
18206
          if (!dom.getAttrib(matchedElm, 'href')) {
18207
            const value = dom.getAttrib(matchedElm, 'name') || matchedElm.id;
18208
            const cls = getVisualAidsAnchorClass(editor);
18209
            if (value && editor.hasVisual) {
18210
              dom.addClass(matchedElm, cls);
18211
            } else {
18212
              dom.removeClass(matchedElm, cls);
18213
            }
18214
          }
18215
          break;
18216
        }
18217
      });
18218
      editor.dispatch('VisualAid', {
18219
        element: elm,
18220
        hasVisual: editor.hasVisual
18221
      });
18222
    };
18223
 
18224
    const makePlainAdaptor = editor => ({
18225
      init: { bindEvents: noop },
18226
      undoManager: {
18227
        beforeChange: (locks, beforeBookmark) => beforeChange$1(editor, locks, beforeBookmark),
18228
        add: (undoManager, index, locks, beforeBookmark, level, event) => addUndoLevel$1(editor, undoManager, index, locks, beforeBookmark, level, event),
18229
        undo: (undoManager, locks, index) => undo$1(editor, undoManager, locks, index),
18230
        redo: (index, data) => redo$1(editor, index, data),
18231
        clear: (undoManager, index) => clear$1(editor, undoManager, index),
18232
        reset: undoManager => reset$1(undoManager),
18233
        hasUndo: (undoManager, index) => hasUndo$1(editor, undoManager, index),
18234
        hasRedo: (undoManager, index) => hasRedo$1(undoManager, index),
18235
        transact: (undoManager, locks, callback) => transact$1(undoManager, locks, callback),
18236
        ignore: (locks, callback) => ignore$1(locks, callback),
18237
        extra: (undoManager, index, callback1, callback2) => extra$1(editor, undoManager, index, callback1, callback2)
18238
      },
18239
      formatter: {
18240
        match: (name, vars, node, similar) => match$2(editor, name, vars, node, similar),
18241
        matchAll: (names, vars) => matchAll(editor, names, vars),
18242
        matchNode: (node, name, vars, similar) => matchNode(editor, node, name, vars, similar),
18243
        canApply: name => canApply(editor, name),
18244
        closest: names => closest(editor, names),
18245
        apply: (name, vars, node) => applyFormat$1(editor, name, vars, node),
18246
        remove: (name, vars, node, similar) => removeFormat$1(editor, name, vars, node, similar),
18247
        toggle: (name, vars, node) => toggle(editor, name, vars, node),
18248
        formatChanged: (registeredFormatListeners, formats, callback, similar, vars) => formatChangedInternal(editor, registeredFormatListeners, formats, callback, similar, vars)
18249
      },
18250
      editor: {
18251
        getContent: args => getContentInternal(editor, args),
18252
        setContent: (content, args) => setContentInternal(editor, content, args),
18253
        insertContent: (value, details) => insertHtmlAtCaret(editor, value, details),
18254
        addVisual: elm => addVisualInternal(editor, elm)
18255
      },
18256
      selection: { getContent: (format, args) => getSelectedContentInternal(editor, format, args) },
18257
      autocompleter: {
1441 ariadna 18258
        addDecoration: noop,
18259
        removeDecoration: noop
1 efrain 18260
      },
18261
      raw: { getModel: () => Optional.none() }
18262
    });
18263
    const makeRtcAdaptor = rtcEditor => {
18264
      const defaultVars = vars => isObject(vars) ? vars : {};
18265
      const {init, undoManager, formatter, editor, selection, autocompleter, raw} = rtcEditor;
18266
      return {
18267
        init: { bindEvents: init.bindEvents },
18268
        undoManager: {
18269
          beforeChange: undoManager.beforeChange,
18270
          add: undoManager.add,
18271
          undo: undoManager.undo,
18272
          redo: undoManager.redo,
18273
          clear: undoManager.clear,
18274
          reset: undoManager.reset,
18275
          hasUndo: undoManager.hasUndo,
18276
          hasRedo: undoManager.hasRedo,
18277
          transact: (_undoManager, _locks, fn) => undoManager.transact(fn),
18278
          ignore: (_locks, callback) => undoManager.ignore(callback),
18279
          extra: (_undoManager, _index, callback1, callback2) => undoManager.extra(callback1, callback2)
18280
        },
18281
        formatter: {
18282
          match: (name, vars, _node, similar) => formatter.match(name, defaultVars(vars), similar),
18283
          matchAll: formatter.matchAll,
18284
          matchNode: formatter.matchNode,
18285
          canApply: name => formatter.canApply(name),
18286
          closest: names => formatter.closest(names),
18287
          apply: (name, vars, _node) => formatter.apply(name, defaultVars(vars)),
18288
          remove: (name, vars, _node, _similar) => formatter.remove(name, defaultVars(vars)),
18289
          toggle: (name, vars, _node) => formatter.toggle(name, defaultVars(vars)),
18290
          formatChanged: (_rfl, formats, callback, similar, vars) => formatter.formatChanged(formats, callback, similar, vars)
18291
        },
18292
        editor: {
18293
          getContent: args => editor.getContent(args),
18294
          setContent: (content, args) => {
18295
            return {
18296
              content: editor.setContent(content, args),
18297
              html: ''
18298
            };
18299
          },
18300
          insertContent: (content, _details) => {
18301
            editor.insertContent(content);
18302
            return '';
18303
          },
18304
          addVisual: editor.addVisual
18305
        },
18306
        selection: { getContent: (_format, args) => selection.getContent(args) },
18307
        autocompleter: {
18308
          addDecoration: autocompleter.addDecoration,
18309
          removeDecoration: autocompleter.removeDecoration
18310
        },
18311
        raw: { getModel: () => Optional.some(raw.getRawModel()) }
18312
      };
18313
    };
18314
    const makeNoopAdaptor = () => {
18315
      const nul = constant(null);
18316
      const empty = constant('');
18317
      return {
18318
        init: { bindEvents: noop },
18319
        undoManager: {
18320
          beforeChange: noop,
18321
          add: nul,
18322
          undo: nul,
18323
          redo: nul,
18324
          clear: noop,
18325
          reset: noop,
18326
          hasUndo: never,
18327
          hasRedo: never,
18328
          transact: nul,
18329
          ignore: noop,
18330
          extra: noop
18331
        },
18332
        formatter: {
18333
          match: never,
18334
          matchAll: constant([]),
18335
          matchNode: constant(undefined),
18336
          canApply: never,
18337
          closest: empty,
18338
          apply: noop,
18339
          remove: noop,
18340
          toggle: noop,
18341
          formatChanged: constant({ unbind: noop })
18342
        },
18343
        editor: {
18344
          getContent: empty,
18345
          setContent: constant({
18346
            content: '',
18347
            html: ''
18348
          }),
18349
          insertContent: constant(''),
18350
          addVisual: noop
18351
        },
18352
        selection: { getContent: empty },
18353
        autocompleter: {
18354
          addDecoration: noop,
18355
          removeDecoration: noop
18356
        },
18357
        raw: { getModel: constant(Optional.none()) }
18358
      };
18359
    };
18360
    const isRtc = editor => has$2(editor.plugins, 'rtc');
18361
    const getRtcSetup = editor => get$a(editor.plugins, 'rtc').bind(rtcPlugin => Optional.from(rtcPlugin.setup));
18362
    const setup$t = editor => {
18363
      const editorCast = editor;
18364
      return getRtcSetup(editor).fold(() => {
18365
        editorCast.rtcInstance = makePlainAdaptor(editor);
18366
        return Optional.none();
18367
      }, setup => {
18368
        editorCast.rtcInstance = makeNoopAdaptor();
18369
        return Optional.some(() => setup().then(rtcEditor => {
18370
          editorCast.rtcInstance = makeRtcAdaptor(rtcEditor);
18371
          return rtcEditor.rtc.isRemote;
18372
        }));
18373
      });
18374
    };
18375
    const getRtcInstanceWithFallback = editor => editor.rtcInstance ? editor.rtcInstance : makePlainAdaptor(editor);
18376
    const getRtcInstanceWithError = editor => {
18377
      const rtcInstance = editor.rtcInstance;
18378
      if (!rtcInstance) {
18379
        throw new Error('Failed to get RTC instance not yet initialized.');
18380
      } else {
18381
        return rtcInstance;
18382
      }
18383
    };
18384
    const beforeChange = (editor, locks, beforeBookmark) => {
18385
      getRtcInstanceWithError(editor).undoManager.beforeChange(locks, beforeBookmark);
18386
    };
18387
    const addUndoLevel = (editor, undoManager, index, locks, beforeBookmark, level, event) => getRtcInstanceWithError(editor).undoManager.add(undoManager, index, locks, beforeBookmark, level, event);
18388
    const undo = (editor, undoManager, locks, index) => getRtcInstanceWithError(editor).undoManager.undo(undoManager, locks, index);
18389
    const redo = (editor, index, data) => getRtcInstanceWithError(editor).undoManager.redo(index, data);
18390
    const clear = (editor, undoManager, index) => {
18391
      getRtcInstanceWithError(editor).undoManager.clear(undoManager, index);
18392
    };
18393
    const reset = (editor, undoManager) => {
18394
      getRtcInstanceWithError(editor).undoManager.reset(undoManager);
18395
    };
18396
    const hasUndo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasUndo(undoManager, index);
18397
    const hasRedo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasRedo(undoManager, index);
18398
    const transact = (editor, undoManager, locks, callback) => getRtcInstanceWithError(editor).undoManager.transact(undoManager, locks, callback);
18399
    const ignore = (editor, locks, callback) => {
18400
      getRtcInstanceWithError(editor).undoManager.ignore(locks, callback);
18401
    };
18402
    const extra = (editor, undoManager, index, callback1, callback2) => {
18403
      getRtcInstanceWithError(editor).undoManager.extra(undoManager, index, callback1, callback2);
18404
    };
18405
    const matchFormat = (editor, name, vars, node, similar) => getRtcInstanceWithError(editor).formatter.match(name, vars, node, similar);
18406
    const matchAllFormats = (editor, names, vars) => getRtcInstanceWithError(editor).formatter.matchAll(names, vars);
18407
    const matchNodeFormat = (editor, node, name, vars, similar) => getRtcInstanceWithError(editor).formatter.matchNode(node, name, vars, similar);
18408
    const canApplyFormat = (editor, name) => getRtcInstanceWithError(editor).formatter.canApply(name);
18409
    const closestFormat = (editor, names) => getRtcInstanceWithError(editor).formatter.closest(names);
18410
    const applyFormat = (editor, name, vars, node) => {
18411
      getRtcInstanceWithError(editor).formatter.apply(name, vars, node);
18412
    };
18413
    const removeFormat = (editor, name, vars, node, similar) => {
18414
      getRtcInstanceWithError(editor).formatter.remove(name, vars, node, similar);
18415
    };
18416
    const toggleFormat = (editor, name, vars, node) => {
18417
      getRtcInstanceWithError(editor).formatter.toggle(name, vars, node);
18418
    };
18419
    const formatChanged = (editor, registeredFormatListeners, formats, callback, similar, vars) => getRtcInstanceWithError(editor).formatter.formatChanged(registeredFormatListeners, formats, callback, similar, vars);
18420
    const getContent$2 = (editor, args) => getRtcInstanceWithFallback(editor).editor.getContent(args);
18421
    const setContent$2 = (editor, content, args) => getRtcInstanceWithFallback(editor).editor.setContent(content, args);
18422
    const insertContent$1 = (editor, value, details) => getRtcInstanceWithFallback(editor).editor.insertContent(value, details);
18423
    const getSelectedContent = (editor, format, args) => getRtcInstanceWithError(editor).selection.getContent(format, args);
18424
    const addVisual$1 = (editor, elm) => getRtcInstanceWithError(editor).editor.addVisual(elm);
18425
    const bindEvents = editor => getRtcInstanceWithError(editor).init.bindEvents();
18426
 
18427
    const getContent$1 = (editor, args = {}) => {
18428
      const format = args.format ? args.format : 'html';
18429
      return getSelectedContent(editor, format, args);
18430
    };
18431
 
18432
    const removeEmpty = text => {
18433
      if (text.dom.length === 0) {
1441 ariadna 18434
        remove$4(text);
1 efrain 18435
        return Optional.none();
18436
      } else {
18437
        return Optional.some(text);
18438
      }
18439
    };
18440
    const walkPastBookmark = (node, start) => node.filter(elm => BookmarkManager.isBookmarkNode(elm.dom)).bind(start ? nextSibling : prevSibling);
18441
    const merge$1 = (outer, inner, rng, start, schema) => {
18442
      const outerElm = outer.dom;
18443
      const innerElm = inner.dom;
18444
      const oldLength = start ? outerElm.length : innerElm.length;
18445
      if (start) {
18446
        mergeTextNodes(outerElm, innerElm, schema, false, !start);
18447
        rng.setStart(innerElm, oldLength);
18448
      } else {
18449
        mergeTextNodes(innerElm, outerElm, schema, false, !start);
18450
        rng.setEnd(innerElm, oldLength);
18451
      }
18452
    };
18453
    const normalizeTextIfRequired = (inner, start, schema) => {
18454
      parent(inner).each(root => {
18455
        const text = inner.dom;
18456
        if (start && needsToBeNbspLeft(root, CaretPosition(text, 0), schema)) {
18457
          normalizeWhitespaceAfter(text, 0, schema);
18458
        } else if (!start && needsToBeNbspRight(root, CaretPosition(text, text.length), schema)) {
18459
          normalizeWhitespaceBefore(text, text.length, schema);
18460
        }
18461
      });
18462
    };
18463
    const mergeAndNormalizeText = (outerNode, innerNode, rng, start, schema) => {
18464
      outerNode.bind(outer => {
18465
        const normalizer = start ? normalizeWhitespaceBefore : normalizeWhitespaceAfter;
18466
        normalizer(outer.dom, start ? outer.dom.length : 0, schema);
1441 ariadna 18467
        return innerNode.filter(isText$c).map(inner => merge$1(outer, inner, rng, start, schema));
1 efrain 18468
      }).orThunk(() => {
1441 ariadna 18469
        const innerTextNode = walkPastBookmark(innerNode, start).or(innerNode).filter(isText$c);
1 efrain 18470
        return innerTextNode.map(inner => normalizeTextIfRequired(inner, start, schema));
18471
      });
18472
    };
18473
    const rngSetContent = (rng, fragment, schema) => {
18474
      const firstChild = Optional.from(fragment.firstChild).map(SugarElement.fromDom);
18475
      const lastChild = Optional.from(fragment.lastChild).map(SugarElement.fromDom);
18476
      rng.deleteContents();
18477
      rng.insertNode(fragment);
1441 ariadna 18478
      const prevText = firstChild.bind(prevSibling).filter(isText$c).bind(removeEmpty);
18479
      const nextText = lastChild.bind(nextSibling).filter(isText$c).bind(removeEmpty);
1 efrain 18480
      mergeAndNormalizeText(prevText, firstChild, rng, true, schema);
18481
      mergeAndNormalizeText(nextText, lastChild, rng, false, schema);
18482
      rng.collapse(false);
18483
    };
18484
    const setupArgs$2 = (args, content) => ({
18485
      format: 'html',
18486
      ...args,
18487
      set: true,
18488
      selection: true,
18489
      content
18490
    });
18491
    const cleanContent = (editor, args) => {
18492
      if (args.format !== 'raw') {
18493
        const rng = editor.selection.getRng();
18494
        const contextBlock = editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock);
18495
        const contextArgs = contextBlock ? { context: contextBlock.nodeName.toLowerCase() } : {};
18496
        const node = editor.parser.parse(args.content, {
18497
          forced_root_block: false,
18498
          ...contextArgs,
18499
          ...args
18500
        });
18501
        return HtmlSerializer({ validate: false }, editor.schema).serialize(node);
18502
      } else {
18503
        return args.content;
18504
      }
18505
    };
18506
    const setContent$1 = (editor, content, args = {}) => {
18507
      const defaultedArgs = setupArgs$2(args, content);
18508
      preProcessSetContent(editor, defaultedArgs).each(updatedArgs => {
18509
        const cleanedContent = cleanContent(editor, updatedArgs);
18510
        const rng = editor.selection.getRng();
18511
        rngSetContent(rng, rng.createContextualFragment(cleanedContent), editor.schema);
18512
        editor.selection.setRng(rng);
18513
        scrollRangeIntoView(editor, rng);
18514
        postProcessSetContent(editor, cleanedContent, updatedArgs);
18515
      });
18516
    };
18517
 
18518
    const deleteFromCallbackMap = (callbackMap, selector, callback) => {
18519
      if (has$2(callbackMap, selector)) {
18520
        const newCallbacks = filter$5(callbackMap[selector], cb => cb !== callback);
18521
        if (newCallbacks.length === 0) {
18522
          delete callbackMap[selector];
18523
        } else {
18524
          callbackMap[selector] = newCallbacks;
18525
        }
18526
      }
18527
    };
18528
    var SelectorChanged = (dom, editor) => {
18529
      let selectorChangedData;
18530
      let currentSelectors;
18531
      const findMatchingNode = (selector, nodes) => find$2(nodes, node => dom.is(node, selector));
18532
      const getParents = elem => dom.getParents(elem, undefined, dom.getRoot());
18533
      const setup = () => {
18534
        selectorChangedData = {};
18535
        currentSelectors = {};
18536
        editor.on('NodeChange', e => {
18537
          const node = e.element;
18538
          const parents = getParents(node);
18539
          const matchedSelectors = {};
18540
          each$d(selectorChangedData, (callbacks, selector) => {
18541
            findMatchingNode(selector, parents).each(node => {
18542
              if (!currentSelectors[selector]) {
18543
                each$e(callbacks, callback => {
18544
                  callback(true, {
18545
                    node,
18546
                    selector,
18547
                    parents
18548
                  });
18549
                });
18550
                currentSelectors[selector] = callbacks;
18551
              }
18552
              matchedSelectors[selector] = callbacks;
18553
            });
18554
          });
18555
          each$d(currentSelectors, (callbacks, selector) => {
18556
            if (!matchedSelectors[selector]) {
18557
              delete currentSelectors[selector];
18558
              each$e(callbacks, callback => {
18559
                callback(false, {
18560
                  node,
18561
                  selector,
18562
                  parents
18563
                });
18564
              });
18565
            }
18566
          });
18567
        });
18568
      };
18569
      return {
18570
        selectorChangedWithUnbind: (selector, callback) => {
18571
          if (!selectorChangedData) {
18572
            setup();
18573
          }
18574
          if (!selectorChangedData[selector]) {
18575
            selectorChangedData[selector] = [];
18576
          }
18577
          selectorChangedData[selector].push(callback);
18578
          findMatchingNode(selector, getParents(editor.selection.getStart())).each(() => {
18579
            currentSelectors[selector] = selectorChangedData[selector];
18580
          });
18581
          return {
18582
            unbind: () => {
18583
              deleteFromCallbackMap(selectorChangedData, selector, callback);
18584
              deleteFromCallbackMap(currentSelectors, selector, callback);
18585
            }
18586
          };
18587
        }
18588
      };
18589
    };
18590
 
18591
    const isAttachedToDom = node => {
18592
      return !!(node && node.ownerDocument) && contains(SugarElement.fromDom(node.ownerDocument), SugarElement.fromDom(node));
18593
    };
18594
    const isValidRange = rng => {
18595
      if (!rng) {
18596
        return false;
18597
      } else {
18598
        return isAttachedToDom(rng.startContainer) && isAttachedToDom(rng.endContainer);
18599
      }
18600
    };
18601
    const EditorSelection = (dom, win, serializer, editor) => {
18602
      let selectedRange;
18603
      let explicitRange;
18604
      const {selectorChangedWithUnbind} = SelectorChanged(dom, editor);
18605
      const setCursorLocation = (node, offset) => {
18606
        const rng = dom.createRng();
18607
        if (isNonNullable(node) && isNonNullable(offset)) {
18608
          rng.setStart(node, offset);
18609
          rng.setEnd(node, offset);
18610
          setRng(rng);
18611
          collapse(false);
18612
        } else {
18613
          moveEndPoint(dom, rng, editor.getBody(), true);
18614
          setRng(rng);
18615
        }
18616
      };
18617
      const getContent = args => getContent$1(editor, args);
18618
      const setContent = (content, args) => setContent$1(editor, content, args);
18619
      const getStart$1 = real => getStart(editor.getBody(), getRng$1(), real);
1441 ariadna 18620
      const getEnd$1 = real => getEnd(editor.getBody(), getRng$1(), real);
1 efrain 18621
      const getBookmark = (type, normalized) => bookmarkManager.getBookmark(type, normalized);
18622
      const moveToBookmark = bookmark => bookmarkManager.moveToBookmark(bookmark);
18623
      const select$1 = (node, content) => {
18624
        select(dom, node, content).each(setRng);
18625
        return node;
18626
      };
18627
      const isCollapsed = () => {
18628
        const rng = getRng$1(), sel = getSel();
18629
        if (!rng || rng.item) {
18630
          return false;
18631
        }
18632
        if (rng.compareEndPoints) {
18633
          return rng.compareEndPoints('StartToEnd', rng) === 0;
18634
        }
18635
        return !sel || rng.collapsed;
18636
      };
18637
      const isEditable = () => {
1441 ariadna 18638
        if (editor.mode.isReadOnly()) {
18639
          return false;
18640
        }
1 efrain 18641
        const rng = getRng$1();
18642
        const fakeSelectedElements = editor.getBody().querySelectorAll('[data-mce-selected="1"]');
18643
        if (fakeSelectedElements.length > 0) {
18644
          return forall(fakeSelectedElements, el => dom.isEditable(el.parentElement));
18645
        } else {
18646
          return isEditableRange(dom, rng);
18647
        }
18648
      };
18649
      const collapse = toStart => {
18650
        const rng = getRng$1();
18651
        rng.collapse(!!toStart);
18652
        setRng(rng);
18653
      };
18654
      const getSel = () => win.getSelection ? win.getSelection() : win.document.selection;
18655
      const getRng$1 = () => {
18656
        let rng;
18657
        const tryCompareBoundaryPoints = (how, sourceRange, destinationRange) => {
18658
          try {
18659
            return sourceRange.compareBoundaryPoints(how, destinationRange);
1441 ariadna 18660
          } catch (_a) {
1 efrain 18661
            return -1;
18662
          }
18663
        };
18664
        const doc = win.document;
18665
        if (isNonNullable(editor.bookmark) && !hasFocus(editor)) {
18666
          const bookmark = getRng(editor);
18667
          if (bookmark.isSome()) {
18668
            return bookmark.map(r => processRanges(editor, [r])[0]).getOr(doc.createRange());
18669
          }
18670
        }
18671
        try {
18672
          const selection = getSel();
18673
          if (selection && !isRestrictedNode(selection.anchorNode)) {
18674
            if (selection.rangeCount > 0) {
18675
              rng = selection.getRangeAt(0);
18676
            } else {
18677
              rng = doc.createRange();
18678
            }
18679
            rng = processRanges(editor, [rng])[0];
18680
          }
1441 ariadna 18681
        } catch (_a) {
1 efrain 18682
        }
18683
        if (!rng) {
18684
          rng = doc.createRange();
18685
        }
18686
        if (isDocument$1(rng.startContainer) && rng.collapsed) {
18687
          const elm = dom.getRoot();
18688
          rng.setStart(elm, 0);
18689
          rng.setEnd(elm, 0);
18690
        }
18691
        if (selectedRange && explicitRange) {
18692
          if (tryCompareBoundaryPoints(rng.START_TO_START, rng, selectedRange) === 0 && tryCompareBoundaryPoints(rng.END_TO_END, rng, selectedRange) === 0) {
18693
            rng = explicitRange;
18694
          } else {
18695
            selectedRange = null;
18696
            explicitRange = null;
18697
          }
18698
        }
18699
        return rng;
18700
      };
18701
      const setRng = (rng, forward) => {
18702
        if (!isValidRange(rng)) {
18703
          return;
18704
        }
18705
        const sel = getSel();
18706
        const evt = editor.dispatch('SetSelectionRange', {
18707
          range: rng,
18708
          forward
18709
        });
18710
        rng = evt.range;
18711
        if (sel) {
18712
          explicitRange = rng;
18713
          try {
18714
            sel.removeAllRanges();
18715
            sel.addRange(rng);
1441 ariadna 18716
          } catch (_a) {
1 efrain 18717
          }
18718
          if (forward === false && sel.extend) {
18719
            sel.collapse(rng.endContainer, rng.endOffset);
18720
            sel.extend(rng.startContainer, rng.startOffset);
18721
          }
18722
          selectedRange = sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
18723
        }
18724
        if (!rng.collapsed && rng.startContainer === rng.endContainer && (sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent)) {
18725
          if (rng.endOffset - rng.startOffset < 2) {
18726
            if (rng.startContainer.hasChildNodes()) {
18727
              const node = rng.startContainer.childNodes[rng.startOffset];
18728
              if (node && node.nodeName === 'IMG') {
18729
                sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset);
18730
                if (sel.anchorNode !== rng.startContainer || sel.focusNode !== rng.endContainer) {
18731
                  sel.setBaseAndExtent(node, 0, node, 1);
18732
                }
18733
              }
18734
            }
18735
          }
18736
        }
18737
        editor.dispatch('AfterSetSelectionRange', {
18738
          range: rng,
18739
          forward
18740
        });
18741
      };
18742
      const setNode = elm => {
18743
        setContent(dom.getOuterHTML(elm));
18744
        return elm;
18745
      };
18746
      const getNode$1 = () => getNode(editor.getBody(), getRng$1());
18747
      const getSelectedBlocks$1 = (startElm, endElm) => getSelectedBlocks(dom, getRng$1(), startElm, endElm);
18748
      const isForward = () => {
18749
        const sel = getSel();
18750
        const anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
18751
        const focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
18752
        if (!sel || !anchorNode || !focusNode || isRestrictedNode(anchorNode) || isRestrictedNode(focusNode)) {
18753
          return true;
18754
        }
18755
        const anchorRange = dom.createRng();
18756
        const focusRange = dom.createRng();
18757
        try {
18758
          anchorRange.setStart(anchorNode, sel.anchorOffset);
18759
          anchorRange.collapse(true);
18760
          focusRange.setStart(focusNode, sel.focusOffset);
18761
          focusRange.collapse(true);
1441 ariadna 18762
        } catch (_a) {
1 efrain 18763
          return true;
18764
        }
18765
        return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
18766
      };
18767
      const normalize = () => {
18768
        const rng = getRng$1();
18769
        const sel = getSel();
18770
        if (!hasMultipleRanges(sel) && hasAnyRanges(editor)) {
18771
          const normRng = normalize$2(dom, rng);
18772
          normRng.each(normRng => {
18773
            setRng(normRng, isForward());
18774
          });
18775
          return normRng.getOr(rng);
18776
        }
18777
        return rng;
18778
      };
18779
      const selectorChanged = (selector, callback) => {
18780
        selectorChangedWithUnbind(selector, callback);
18781
        return exports;
18782
      };
18783
      const getScrollContainer = () => {
18784
        let scrollContainer;
18785
        let node = dom.getRoot();
18786
        while (node && node.nodeName !== 'BODY') {
18787
          if (node.scrollHeight > node.clientHeight) {
18788
            scrollContainer = node;
18789
            break;
18790
          }
18791
          node = node.parentNode;
18792
        }
18793
        return scrollContainer;
18794
      };
18795
      const scrollIntoView = (elm, alignToTop) => {
18796
        if (isNonNullable(elm)) {
18797
          scrollElementIntoView(editor, elm, alignToTop);
18798
        } else {
18799
          scrollRangeIntoView(editor, getRng$1(), alignToTop);
18800
        }
18801
      };
18802
      const placeCaretAt = (clientX, clientY) => setRng(fromPoint(clientX, clientY, editor.getDoc()));
18803
      const getBoundingClientRect = () => {
18804
        const rng = getRng$1();
18805
        return rng.collapsed ? CaretPosition.fromRangeStart(rng).getClientRects()[0] : rng.getBoundingClientRect();
18806
      };
18807
      const destroy = () => {
18808
        win = selectedRange = explicitRange = null;
18809
        controlSelection.destroy();
18810
      };
18811
      const expand = (options = { type: 'word' }) => setRng(RangeUtils(dom).expand(getRng$1(), options));
18812
      const exports = {
18813
        dom,
18814
        win,
18815
        serializer,
18816
        editor,
18817
        expand,
18818
        collapse,
18819
        setCursorLocation,
18820
        getContent,
18821
        setContent,
18822
        getBookmark,
18823
        moveToBookmark,
18824
        select: select$1,
18825
        isCollapsed,
18826
        isEditable,
18827
        isForward,
18828
        setNode,
18829
        getNode: getNode$1,
18830
        getSel,
18831
        setRng,
18832
        getRng: getRng$1,
18833
        getStart: getStart$1,
1441 ariadna 18834
        getEnd: getEnd$1,
1 efrain 18835
        getSelectedBlocks: getSelectedBlocks$1,
18836
        normalize,
18837
        selectorChanged,
18838
        selectorChangedWithUnbind,
18839
        getScrollContainer,
18840
        scrollIntoView,
18841
        placeCaretAt,
18842
        getBoundingClientRect,
18843
        destroy
18844
      };
18845
      const bookmarkManager = BookmarkManager(exports);
18846
      const controlSelection = ControlSelection(exports, editor);
18847
      exports.bookmarkManager = bookmarkManager;
18848
      exports.controlSelection = controlSelection;
18849
      return exports;
18850
    };
18851
 
1441 ariadna 18852
    const addNodeFilter = (settings, htmlParser, schema) => {
18853
      htmlParser.addNodeFilter('br', (nodes, _, args) => {
18854
        const blockElements = Tools.extend({}, schema.getBlockElements());
18855
        const nonEmptyElements = schema.getNonEmptyElements();
18856
        const whitespaceElements = schema.getWhitespaceElements();
18857
        blockElements.body = 1;
18858
        const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node);
18859
        for (let i = 0, l = nodes.length; i < l; i++) {
18860
          let node = nodes[i];
18861
          let parent = node.parent;
18862
          if (parent && isBlock(parent) && node === parent.lastChild) {
18863
            let prev = node.prev;
18864
            while (prev) {
18865
              const prevName = prev.name;
18866
              if (prevName !== 'span' || prev.attr('data-mce-type') !== 'bookmark') {
18867
                if (prevName === 'br') {
18868
                  node = null;
18869
                }
18870
                break;
18871
              }
18872
              prev = prev.prev;
18873
            }
18874
            if (node) {
18875
              node.remove();
18876
              if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent)) {
18877
                const elementRule = schema.getElementRule(parent.name);
18878
                if (elementRule) {
18879
                  if (elementRule.removeEmpty) {
18880
                    parent.remove();
18881
                  } else if (elementRule.paddEmpty) {
18882
                    paddEmptyNode(settings, args, isBlock, parent);
18883
                  }
18884
                }
18885
              }
18886
            }
18887
          } else {
18888
            let lastParent = node;
18889
            while (parent && parent.firstChild === lastParent && parent.lastChild === lastParent) {
18890
              lastParent = parent;
18891
              if (blockElements[parent.name]) {
18892
                break;
18893
              }
18894
              parent = parent.parent;
18895
            }
18896
            if (lastParent === parent) {
18897
              const textNode = new AstNode('#text', 3);
18898
              textNode.value = nbsp;
18899
              node.replace(textNode);
18900
            }
18901
          }
18902
        }
18903
      });
18904
    };
18905
 
1 efrain 18906
    const register$3 = (htmlParser, settings, dom) => {
18907
      htmlParser.addAttributeFilter('data-mce-tabindex', (nodes, name) => {
18908
        let i = nodes.length;
18909
        while (i--) {
18910
          const node = nodes[i];
18911
          node.attr('tabindex', node.attr('data-mce-tabindex'));
18912
          node.attr(name, null);
18913
        }
18914
      });
18915
      htmlParser.addAttributeFilter('src,href,style', (nodes, name) => {
18916
        const internalName = 'data-mce-' + name;
18917
        const urlConverter = settings.url_converter;
18918
        const urlConverterScope = settings.url_converter_scope;
18919
        let i = nodes.length;
18920
        while (i--) {
18921
          const node = nodes[i];
18922
          let value = node.attr(internalName);
18923
          if (value !== undefined) {
18924
            node.attr(name, value.length > 0 ? value : null);
18925
            node.attr(internalName, null);
18926
          } else {
18927
            value = node.attr(name);
18928
            if (name === 'style') {
18929
              value = dom.serializeStyle(dom.parseStyle(value), node.name);
18930
            } else if (urlConverter) {
18931
              value = urlConverter.call(urlConverterScope, value, name, node.name);
18932
            }
18933
            node.attr(name, value.length > 0 ? value : null);
18934
          }
18935
        }
18936
      });
18937
      htmlParser.addAttributeFilter('class', nodes => {
18938
        let i = nodes.length;
18939
        while (i--) {
18940
          const node = nodes[i];
18941
          let value = node.attr('class');
18942
          if (value) {
18943
            value = value.replace(/(?:^|\s)mce-item-\w+(?!\S)/g, '');
18944
            node.attr('class', value.length > 0 ? value : null);
18945
          }
18946
        }
18947
      });
18948
      htmlParser.addAttributeFilter('data-mce-type', (nodes, name, args) => {
18949
        let i = nodes.length;
18950
        while (i--) {
18951
          const node = nodes[i];
18952
          if (node.attr('data-mce-type') === 'bookmark' && !args.cleanup) {
18953
            const hasChildren = Optional.from(node.firstChild).exists(firstChild => {
18954
              var _a;
1441 ariadna 18955
              return !isZwsp((_a = firstChild.value) !== null && _a !== void 0 ? _a : '');
1 efrain 18956
            });
18957
            if (hasChildren) {
18958
              node.unwrap();
18959
            } else {
18960
              node.remove();
18961
            }
18962
          }
18963
        }
18964
      });
18965
      htmlParser.addNodeFilter('script,style', (nodes, name) => {
18966
        var _a;
18967
        const trim = value => {
18968
          return value.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n').replace(/^[\r\n]*|[\r\n]*$/g, '').replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi, '').replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g, '');
18969
        };
18970
        let i = nodes.length;
18971
        while (i--) {
18972
          const node = nodes[i];
18973
          const firstChild = node.firstChild;
18974
          const value = (_a = firstChild === null || firstChild === void 0 ? void 0 : firstChild.value) !== null && _a !== void 0 ? _a : '';
18975
          if (name === 'script') {
18976
            const type = node.attr('type');
18977
            if (type) {
18978
              node.attr('type', type === 'mce-no/type' ? null : type.replace(/^mce\-/, ''));
18979
            }
18980
            if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
18981
              firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
18982
            }
18983
          } else {
18984
            if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
18985
              firstChild.value = '<!--\n' + trim(value) + '\n-->';
18986
            }
18987
          }
18988
        }
18989
      });
18990
      htmlParser.addNodeFilter('#comment', nodes => {
18991
        let i = nodes.length;
18992
        while (i--) {
18993
          const node = nodes[i];
18994
          const value = node.value;
18995
          if (settings.preserve_cdata && (value === null || value === void 0 ? void 0 : value.indexOf('[CDATA[')) === 0) {
18996
            node.name = '#cdata';
18997
            node.type = 4;
18998
            node.value = dom.decode(value.replace(/^\[CDATA\[|\]\]$/g, ''));
18999
          } else if ((value === null || value === void 0 ? void 0 : value.indexOf('mce:protected ')) === 0) {
19000
            node.name = '#text';
19001
            node.type = 3;
19002
            node.raw = true;
19003
            node.value = unescape(value).substr(14);
19004
          }
19005
        }
19006
      });
19007
      htmlParser.addNodeFilter('xml:namespace,input', (nodes, name) => {
19008
        let i = nodes.length;
19009
        while (i--) {
19010
          const node = nodes[i];
19011
          if (node.type === 7) {
19012
            node.remove();
19013
          } else if (node.type === 1) {
19014
            if (name === 'input' && !node.attr('type')) {
19015
              node.attr('type', 'text');
19016
            }
19017
          }
19018
        }
19019
      });
19020
      htmlParser.addAttributeFilter('data-mce-type', nodes => {
19021
        each$e(nodes, node => {
19022
          if (node.attr('data-mce-type') === 'format-caret') {
19023
            if (node.isEmpty(htmlParser.schema.getNonEmptyElements())) {
19024
              node.remove();
19025
            } else {
19026
              node.unwrap();
19027
            }
19028
          }
19029
        });
19030
      });
19031
      htmlParser.addAttributeFilter('data-mce-src,data-mce-href,data-mce-style,' + 'data-mce-selected,data-mce-expando,data-mce-block,' + 'data-mce-type,data-mce-resize,data-mce-placeholder', (nodes, name) => {
19032
        let i = nodes.length;
19033
        while (i--) {
19034
          nodes[i].attr(name, null);
19035
        }
19036
      });
19037
      if (settings.remove_trailing_brs) {
19038
        addNodeFilter(settings, htmlParser, htmlParser.schema);
19039
      }
19040
    };
19041
    const trimTrailingBr = rootNode => {
19042
      const isBr = node => {
19043
        return (node === null || node === void 0 ? void 0 : node.name) === 'br';
19044
      };
19045
      const brNode1 = rootNode.lastChild;
19046
      if (isBr(brNode1)) {
19047
        const brNode2 = brNode1.prev;
19048
        if (isBr(brNode2)) {
19049
          brNode1.remove();
19050
          brNode2.remove();
19051
        }
19052
      }
19053
    };
19054
 
19055
    const preProcess$1 = (editor, node, args) => {
19056
      let oldDoc;
19057
      const dom = editor.dom;
19058
      let clonedNode = node.cloneNode(true);
19059
      const impl = document.implementation;
19060
      if (impl.createHTMLDocument) {
19061
        const doc = impl.createHTMLDocument('');
19062
        Tools.each(clonedNode.nodeName === 'BODY' ? clonedNode.childNodes : [clonedNode], node => {
19063
          doc.body.appendChild(doc.importNode(node, true));
19064
        });
19065
        if (clonedNode.nodeName !== 'BODY') {
19066
          clonedNode = doc.body.firstChild;
19067
        } else {
19068
          clonedNode = doc.body;
19069
        }
19070
        oldDoc = dom.doc;
19071
        dom.doc = doc;
19072
      }
19073
      firePreProcess(editor, {
19074
        ...args,
19075
        node: clonedNode
19076
      });
19077
      if (oldDoc) {
19078
        dom.doc = oldDoc;
19079
      }
19080
      return clonedNode;
19081
    };
19082
    const shouldFireEvent = (editor, args) => {
19083
      return isNonNullable(editor) && editor.hasEventListeners('PreProcess') && !args.no_events;
19084
    };
19085
    const process$1 = (editor, node, args) => {
19086
      return shouldFireEvent(editor, args) ? preProcess$1(editor, node, args) : node;
19087
    };
19088
 
19089
    const addTempAttr = (htmlParser, tempAttrs, name) => {
19090
      if (Tools.inArray(tempAttrs, name) === -1) {
19091
        htmlParser.addAttributeFilter(name, (nodes, name) => {
19092
          let i = nodes.length;
19093
          while (i--) {
19094
            nodes[i].attr(name, null);
19095
          }
19096
        });
19097
        tempAttrs.push(name);
19098
      }
19099
    };
19100
    const postProcess = (editor, args, content) => {
19101
      if (!args.no_events && editor) {
19102
        const outArgs = firePostProcess(editor, {
19103
          ...args,
19104
          content
19105
        });
19106
        return outArgs.content;
19107
      } else {
19108
        return content;
19109
      }
19110
    };
19111
    const getHtmlFromNode = (dom, node, args) => {
19112
      const html = trim$2(args.getInner ? node.innerHTML : dom.getOuterHTML(node));
19113
      return args.selection || isWsPreserveElement(SugarElement.fromDom(node)) ? html : Tools.trim(html);
19114
    };
19115
    const parseHtml = (htmlParser, html, args) => {
19116
      const parserArgs = args.selection ? {
19117
        forced_root_block: false,
19118
        ...args
19119
      } : args;
19120
      const rootNode = htmlParser.parse(html, parserArgs);
19121
      trimTrailingBr(rootNode);
19122
      return rootNode;
19123
    };
19124
    const serializeNode = (settings, schema, node) => {
19125
      const htmlSerializer = HtmlSerializer(settings, schema);
19126
      return htmlSerializer.serialize(node);
19127
    };
19128
    const toHtml = (editor, settings, schema, rootNode, args) => {
19129
      const content = serializeNode(settings, schema, rootNode);
19130
      return postProcess(editor, args, content);
19131
    };
19132
    const DomSerializerImpl = (settings, editor) => {
19133
      const tempAttrs = ['data-mce-selected'];
19134
      const defaultedSettings = {
19135
        entity_encoding: 'named',
19136
        remove_trailing_brs: true,
19137
        pad_empty_with_br: false,
19138
        ...settings
19139
      };
19140
      const dom = editor && editor.dom ? editor.dom : DOMUtils.DOM;
19141
      const schema = editor && editor.schema ? editor.schema : Schema(defaultedSettings);
19142
      const htmlParser = DomParser(defaultedSettings, schema);
19143
      register$3(htmlParser, defaultedSettings, dom);
19144
      const serialize = (node, parserArgs = {}) => {
19145
        const args = {
19146
          format: 'html',
19147
          ...parserArgs
19148
        };
19149
        const targetNode = process$1(editor, node, args);
19150
        const html = getHtmlFromNode(dom, targetNode, args);
19151
        const rootNode = parseHtml(htmlParser, html, args);
19152
        return args.format === 'tree' ? rootNode : toHtml(editor, defaultedSettings, schema, rootNode, args);
19153
      };
19154
      return {
19155
        schema,
19156
        addNodeFilter: htmlParser.addNodeFilter,
19157
        addAttributeFilter: htmlParser.addAttributeFilter,
19158
        serialize: serialize,
19159
        addRules: schema.addValidElements,
19160
        setRules: schema.setValidElements,
19161
        addTempAttr: curry(addTempAttr, htmlParser, tempAttrs),
19162
        getTempAttrs: constant(tempAttrs),
19163
        getNodeFilters: htmlParser.getNodeFilters,
19164
        getAttributeFilters: htmlParser.getAttributeFilters,
19165
        removeNodeFilter: htmlParser.removeNodeFilter,
19166
        removeAttributeFilter: htmlParser.removeAttributeFilter
19167
      };
19168
    };
19169
 
19170
    const DomSerializer = (settings, editor) => {
19171
      const domSerializer = DomSerializerImpl(settings, editor);
19172
      return {
19173
        schema: domSerializer.schema,
19174
        addNodeFilter: domSerializer.addNodeFilter,
19175
        addAttributeFilter: domSerializer.addAttributeFilter,
19176
        serialize: domSerializer.serialize,
19177
        addRules: domSerializer.addRules,
19178
        setRules: domSerializer.setRules,
19179
        addTempAttr: domSerializer.addTempAttr,
19180
        getTempAttrs: domSerializer.getTempAttrs,
19181
        getNodeFilters: domSerializer.getNodeFilters,
19182
        getAttributeFilters: domSerializer.getAttributeFilters,
19183
        removeNodeFilter: domSerializer.removeNodeFilter,
19184
        removeAttributeFilter: domSerializer.removeAttributeFilter
19185
      };
19186
    };
19187
 
19188
    const defaultFormat$1 = 'html';
19189
    const setupArgs$1 = (args, format) => ({
19190
      ...args,
19191
      format,
19192
      get: true,
19193
      getInner: true
19194
    });
19195
    const getContent = (editor, args = {}) => {
19196
      const format = args.format ? args.format : defaultFormat$1;
19197
      const defaultedArgs = setupArgs$1(args, format);
19198
      return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
19199
        const content = getContent$2(editor, updatedArgs);
19200
        return postProcessGetContent(editor, content, updatedArgs);
19201
      });
19202
    };
19203
 
19204
    const defaultFormat = 'html';
19205
    const setupArgs = (args, content) => ({
19206
      format: defaultFormat,
19207
      ...args,
19208
      set: true,
19209
      content
19210
    });
19211
    const setContent = (editor, content, args = {}) => {
19212
      const defaultedArgs = setupArgs(args, content);
19213
      return preProcessSetContent(editor, defaultedArgs).map(updatedArgs => {
19214
        const result = setContent$2(editor, updatedArgs.content, updatedArgs);
19215
        postProcessSetContent(editor, result.html, updatedArgs);
19216
        return result.content;
19217
      }).getOr(content);
19218
    };
19219
 
1441 ariadna 19220
    const removedOptions = ('autoresize_on_init,content_editable_state,padd_empty_with_br,block_elements,' + 'boolean_attributes,editor_deselector,editor_selector,elements,file_browser_callback_types,filepicker_validator_handler,' + 'force_hex_style_colors,force_p_newlines,gecko_spellcheck,images_dataimg_filter,media_scripts,mode,move_caret_before_on_enter_elements,' + 'non_empty_elements,self_closing_elements,short_ended_elements,special,spellchecker_select_languages,spellchecker_whitelist,' + 'tab_focus,tabfocus_elements,table_responsive_width,text_block_elements,text_inline_elements,toolbar_drawer,types,validate,whitespace_elements,' + 'paste_enable_default_filters,paste_filter_drop,paste_word_valid_elements,paste_retain_style_properties,paste_convert_word_fake_lists,' + 'template_cdate_classes,template_mdate_classes,template_selected_content_classes,template_preview_replace_values,template_replace_values,templates,template_cdate_format,template_mdate_format').split(',');
19221
    const deprecatedOptions = [];
19222
    const removedPlugins = 'bbcode,colorpicker,contextmenu,fullpage,legacyoutput,spellchecker,template,textcolor,rtc'.split(',');
19223
    const deprecatedPlugins = [];
1 efrain 19224
    const getMatchingOptions = (options, searchingFor) => {
19225
      const settingNames = filter$5(searchingFor, setting => has$2(options, setting));
19226
      return sort(settingNames);
19227
    };
19228
    const getRemovedOptions = options => {
19229
      const settingNames = getMatchingOptions(options, removedOptions);
19230
      const forcedRootBlock = options.forced_root_block;
19231
      if (forcedRootBlock === false || forcedRootBlock === '') {
19232
        settingNames.push('forced_root_block (false only)');
19233
      }
19234
      return sort(settingNames);
19235
    };
19236
    const getDeprecatedOptions = options => getMatchingOptions(options, deprecatedOptions);
19237
    const getMatchingPlugins = (options, searchingFor) => {
19238
      const plugins = Tools.makeMap(options.plugins, ' ');
19239
      const hasPlugin = plugin => has$2(plugins, plugin);
19240
      const pluginNames = filter$5(searchingFor, hasPlugin);
19241
      return sort(pluginNames);
19242
    };
19243
    const getRemovedPlugins = options => getMatchingPlugins(options, removedPlugins);
19244
    const getDeprecatedPlugins = options => getMatchingPlugins(options, deprecatedPlugins.map(entry => entry.name));
19245
    const logRemovedWarnings = (rawOptions, normalizedOptions) => {
19246
      const removedOptions = getRemovedOptions(rawOptions);
19247
      const removedPlugins = getRemovedPlugins(normalizedOptions);
19248
      const hasRemovedPlugins = removedPlugins.length > 0;
19249
      const hasRemovedOptions = removedOptions.length > 0;
19250
      const isLegacyMobileTheme = normalizedOptions.theme === 'mobile';
19251
      if (hasRemovedPlugins || hasRemovedOptions || isLegacyMobileTheme) {
19252
        const listJoiner = '\n- ';
19253
        const themesMessage = isLegacyMobileTheme ? `\n\nThemes:${ listJoiner }mobile` : '';
19254
        const pluginsMessage = hasRemovedPlugins ? `\n\nPlugins:${ listJoiner }${ removedPlugins.join(listJoiner) }` : '';
19255
        const optionsMessage = hasRemovedOptions ? `\n\nOptions:${ listJoiner }${ removedOptions.join(listJoiner) }` : '';
1441 ariadna 19256
        console.warn('The following deprecated features are currently enabled and have been removed in TinyMCE 7.0. These features will no longer work and should be removed from the TinyMCE configuration. ' + 'See https://www.tiny.cloud/docs/tinymce/7/migration-from-6x/ for more information.' + themesMessage + pluginsMessage + optionsMessage);
1 efrain 19257
      }
19258
    };
19259
    const getPluginDescription = name => find$2(deprecatedPlugins, entry => entry.name === name).fold(() => name, entry => {
19260
      if (entry.replacedWith) {
19261
        return `${ name }, replaced by ${ entry.replacedWith }`;
19262
      } else {
19263
        return name;
19264
      }
19265
    });
19266
    const logDeprecatedWarnings = (rawOptions, normalizedOptions) => {
19267
      const deprecatedOptions = getDeprecatedOptions(rawOptions);
19268
      const deprecatedPlugins = getDeprecatedPlugins(normalizedOptions);
19269
      const hasDeprecatedPlugins = deprecatedPlugins.length > 0;
19270
      const hasDeprecatedOptions = deprecatedOptions.length > 0;
19271
      if (hasDeprecatedPlugins || hasDeprecatedOptions) {
19272
        const listJoiner = '\n- ';
19273
        const pluginsMessage = hasDeprecatedPlugins ? `\n\nPlugins:${ listJoiner }${ deprecatedPlugins.map(getPluginDescription).join(listJoiner) }` : '';
19274
        const optionsMessage = hasDeprecatedOptions ? `\n\nOptions:${ listJoiner }${ deprecatedOptions.join(listJoiner) }` : '';
19275
        console.warn('The following deprecated features are currently enabled but will be removed soon.' + pluginsMessage + optionsMessage);
19276
      }
19277
    };
19278
    const logWarnings = (rawOptions, normalizedOptions) => {
19279
      logRemovedWarnings(rawOptions, normalizedOptions);
19280
      logDeprecatedWarnings(rawOptions, normalizedOptions);
19281
    };
19282
 
19283
    const DOM$8 = DOMUtils.DOM;
19284
    const restoreOriginalStyles = editor => {
19285
      DOM$8.setStyle(editor.id, 'display', editor.orgDisplay);
19286
    };
19287
    const safeDestroy = x => Optional.from(x).each(x => x.destroy());
19288
    const clearDomReferences = editor => {
19289
      const ed = editor;
19290
      ed.contentAreaContainer = ed.formElement = ed.container = ed.editorContainer = null;
19291
      ed.bodyElement = ed.contentDocument = ed.contentWindow = null;
19292
      ed.iframeElement = ed.targetElm = null;
19293
      const selection = editor.selection;
19294
      if (selection) {
19295
        const dom = selection.dom;
19296
        ed.selection = selection.win = selection.dom = dom.doc = null;
19297
      }
19298
    };
19299
    const restoreForm = editor => {
19300
      const form = editor.formElement;
19301
      if (form) {
19302
        if (form._mceOldSubmit) {
19303
          form.submit = form._mceOldSubmit;
19304
          delete form._mceOldSubmit;
19305
        }
19306
        DOM$8.unbind(form, 'submit reset', editor.formEventDelegate);
19307
      }
19308
    };
19309
    const remove$1 = editor => {
19310
      if (!editor.removed) {
19311
        const {_selectionOverrides, editorUpload} = editor;
19312
        const body = editor.getBody();
19313
        const element = editor.getElement();
19314
        if (body) {
19315
          editor.save({ is_removing: true });
19316
        }
19317
        editor.removed = true;
19318
        editor.unbindAllNativeEvents();
19319
        if (editor.hasHiddenInput && isNonNullable(element === null || element === void 0 ? void 0 : element.nextSibling)) {
19320
          DOM$8.remove(element.nextSibling);
19321
        }
19322
        fireRemove(editor);
19323
        editor.editorManager.remove(editor);
19324
        if (!editor.inline && body) {
19325
          restoreOriginalStyles(editor);
19326
        }
19327
        fireDetach(editor);
19328
        DOM$8.remove(editor.getContainer());
19329
        safeDestroy(_selectionOverrides);
19330
        safeDestroy(editorUpload);
19331
        editor.destroy();
19332
      }
19333
    };
19334
    const destroy = (editor, automatic) => {
19335
      const {selection, dom} = editor;
19336
      if (editor.destroyed) {
19337
        return;
19338
      }
19339
      if (!automatic && !editor.removed) {
19340
        editor.remove();
19341
        return;
19342
      }
19343
      if (!automatic) {
19344
        editor.editorManager.off('beforeunload', editor._beforeUnload);
19345
        if (editor.theme && editor.theme.destroy) {
19346
          editor.theme.destroy();
19347
        }
19348
        safeDestroy(selection);
19349
        safeDestroy(dom);
19350
      }
19351
      restoreForm(editor);
19352
      clearDomReferences(editor);
19353
      editor.destroyed = true;
19354
    };
19355
 
19356
    const CreateIconManager = () => {
19357
      const lookup = {};
19358
      const add = (id, iconPack) => {
19359
        lookup[id] = iconPack;
19360
      };
19361
      const get = id => {
19362
        if (lookup[id]) {
19363
          return lookup[id];
19364
        } else {
19365
          return { icons: {} };
19366
        }
19367
      };
19368
      const has = id => has$2(lookup, id);
19369
      return {
19370
        add,
19371
        get,
19372
        has
19373
      };
19374
    };
19375
    const IconManager = CreateIconManager();
19376
 
19377
    const ModelManager = AddOnManager.ModelManager;
19378
 
19379
    const getProp = (propName, elm) => {
19380
      const rawElm = elm.dom;
19381
      return rawElm[propName];
19382
    };
19383
    const getComputedSizeProp = (propName, elm) => parseInt(get$7(elm, propName), 10);
19384
    const getClientWidth = curry(getProp, 'clientWidth');
19385
    const getClientHeight = curry(getProp, 'clientHeight');
19386
    const getMarginTop = curry(getComputedSizeProp, 'margin-top');
19387
    const getMarginLeft = curry(getComputedSizeProp, 'margin-left');
19388
    const getBoundingClientRect = elm => elm.dom.getBoundingClientRect();
19389
    const isInsideElementContentArea = (bodyElm, clientX, clientY) => {
19390
      const clientWidth = getClientWidth(bodyElm);
19391
      const clientHeight = getClientHeight(bodyElm);
19392
      return clientX >= 0 && clientY >= 0 && clientX <= clientWidth && clientY <= clientHeight;
19393
    };
19394
    const transpose = (inline, elm, clientX, clientY) => {
19395
      const clientRect = getBoundingClientRect(elm);
19396
      const deltaX = inline ? clientRect.left + elm.dom.clientLeft + getMarginLeft(elm) : 0;
19397
      const deltaY = inline ? clientRect.top + elm.dom.clientTop + getMarginTop(elm) : 0;
19398
      const x = clientX - deltaX;
19399
      const y = clientY - deltaY;
19400
      return {
19401
        x,
19402
        y
19403
      };
19404
    };
19405
    const isXYInContentArea = (editor, clientX, clientY) => {
19406
      const bodyElm = SugarElement.fromDom(editor.getBody());
19407
      const targetElm = editor.inline ? bodyElm : documentElement(bodyElm);
19408
      const transposedPoint = transpose(editor.inline, targetElm, clientX, clientY);
19409
      return isInsideElementContentArea(targetElm, transposedPoint.x, transposedPoint.y);
19410
    };
19411
    const fromDomSafe = node => Optional.from(node).map(SugarElement.fromDom);
19412
    const isEditorAttachedToDom = editor => {
19413
      const rawContainer = editor.inline ? editor.getBody() : editor.getContentAreaContainer();
19414
      return fromDomSafe(rawContainer).map(inBody).getOr(false);
19415
    };
19416
 
19417
    var NotificationManagerImpl = () => {
19418
      const unimplemented = () => {
19419
        throw new Error('Theme did not provide a NotificationManager implementation.');
19420
      };
19421
      return {
19422
        open: unimplemented,
19423
        close: unimplemented,
19424
        getArgs: unimplemented
19425
      };
19426
    };
19427
 
19428
    const NotificationManager = editor => {
19429
      const notifications = [];
19430
      const getImplementation = () => {
19431
        const theme = editor.theme;
19432
        return theme && theme.getNotificationManagerImpl ? theme.getNotificationManagerImpl() : NotificationManagerImpl();
19433
      };
19434
      const getTopNotification = () => {
19435
        return Optional.from(notifications[0]);
19436
      };
19437
      const isEqual = (a, b) => {
19438
        return a.type === b.type && a.text === b.text && !a.progressBar && !a.timeout && !b.progressBar && !b.timeout;
19439
      };
19440
      const reposition = () => {
1441 ariadna 19441
        getTopNotification().each(notification => {
1 efrain 19442
          notification.reposition();
19443
        });
19444
      };
19445
      const addNotification = notification => {
19446
        notifications.push(notification);
19447
      };
19448
      const closeNotification = notification => {
19449
        findIndex$2(notifications, otherNotification => {
19450
          return otherNotification === notification;
19451
        }).each(index => {
19452
          notifications.splice(index, 1);
19453
        });
19454
      };
19455
      const open = (spec, fireEvent = true) => {
19456
        if (editor.removed || !isEditorAttachedToDom(editor)) {
19457
          return {};
19458
        }
19459
        if (fireEvent) {
19460
          editor.dispatch('BeforeOpenNotification', { notification: spec });
19461
        }
19462
        return find$2(notifications, notification => {
19463
          return isEqual(getImplementation().getArgs(notification), spec);
19464
        }).getOrThunk(() => {
19465
          editor.editorManager.setActive(editor);
19466
          const notification = getImplementation().open(spec, () => {
19467
            closeNotification(notification);
1441 ariadna 19468
          }, () => hasEditorOrUiFocus(editor));
1 efrain 19469
          addNotification(notification);
19470
          reposition();
19471
          editor.dispatch('OpenNotification', { notification: { ...notification } });
19472
          return notification;
19473
        });
19474
      };
19475
      const close = () => {
19476
        getTopNotification().each(notification => {
19477
          getImplementation().close(notification);
19478
          closeNotification(notification);
19479
          reposition();
19480
        });
19481
      };
19482
      const getNotifications = constant(notifications);
19483
      const registerEvents = editor => {
19484
        editor.on('SkinLoaded', () => {
19485
          const serviceMessage = getServiceMessage(editor);
19486
          if (serviceMessage) {
19487
            open({
19488
              text: serviceMessage,
19489
              type: 'warning',
19490
              timeout: 0
19491
            }, false);
19492
          }
19493
          reposition();
19494
        });
1441 ariadna 19495
        editor.on('show ResizeEditor ResizeWindow NodeChange ToggleView FullscreenStateChanged', () => {
1 efrain 19496
          requestAnimationFrame(reposition);
19497
        });
19498
        editor.on('remove', () => {
19499
          each$e(notifications.slice(), notification => {
19500
            getImplementation().close(notification);
19501
          });
19502
        });
1441 ariadna 19503
        editor.on('keydown', e => {
19504
          var _a;
19505
          const isF12 = ((_a = e.key) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'f12' || e.keyCode === 123;
19506
          if (e.altKey && isF12) {
19507
            e.preventDefault();
19508
            getTopNotification().map(notificationApi => SugarElement.fromDom(notificationApi.getEl())).each(elm => focus$1(elm));
19509
          }
19510
        });
1 efrain 19511
      };
19512
      registerEvents(editor);
19513
      return {
19514
        open,
19515
        close,
19516
        getNotifications
19517
      };
19518
    };
19519
 
19520
    const PluginManager = AddOnManager.PluginManager;
19521
 
19522
    const ThemeManager = AddOnManager.ThemeManager;
19523
 
19524
    var WindowManagerImpl = () => {
19525
      const unimplemented = () => {
19526
        throw new Error('Theme did not provide a WindowManager implementation.');
19527
      };
19528
      return {
19529
        open: unimplemented,
19530
        openUrl: unimplemented,
19531
        alert: unimplemented,
19532
        confirm: unimplemented,
19533
        close: unimplemented
19534
      };
19535
    };
19536
 
19537
    const WindowManager = editor => {
19538
      let dialogs = [];
19539
      const getImplementation = () => {
19540
        const theme = editor.theme;
19541
        return theme && theme.getWindowManagerImpl ? theme.getWindowManagerImpl() : WindowManagerImpl();
19542
      };
19543
      const funcBind = (scope, f) => {
19544
        return (...args) => {
19545
          return f ? f.apply(scope, args) : undefined;
19546
        };
19547
      };
19548
      const fireOpenEvent = dialog => {
19549
        editor.dispatch('OpenWindow', { dialog });
19550
      };
19551
      const fireCloseEvent = dialog => {
19552
        editor.dispatch('CloseWindow', { dialog });
19553
      };
19554
      const addDialog = dialog => {
19555
        dialogs.push(dialog);
19556
        fireOpenEvent(dialog);
19557
      };
19558
      const closeDialog = dialog => {
19559
        fireCloseEvent(dialog);
19560
        dialogs = filter$5(dialogs, otherDialog => {
19561
          return otherDialog !== dialog;
19562
        });
19563
        if (dialogs.length === 0) {
19564
          editor.focus();
19565
        }
19566
      };
19567
      const getTopDialog = () => {
19568
        return Optional.from(dialogs[dialogs.length - 1]);
19569
      };
19570
      const storeSelectionAndOpenDialog = openDialog => {
19571
        editor.editorManager.setActive(editor);
19572
        store(editor);
19573
        editor.ui.show();
19574
        const dialog = openDialog();
19575
        addDialog(dialog);
19576
        return dialog;
19577
      };
19578
      const open = (args, params) => {
19579
        return storeSelectionAndOpenDialog(() => getImplementation().open(args, params, closeDialog));
19580
      };
19581
      const openUrl = args => {
19582
        return storeSelectionAndOpenDialog(() => getImplementation().openUrl(args, closeDialog));
19583
      };
19584
      const alert = (message, callback, scope) => {
19585
        const windowManagerImpl = getImplementation();
19586
        windowManagerImpl.alert(message, funcBind(scope ? scope : windowManagerImpl, callback));
19587
      };
19588
      const confirm = (message, callback, scope) => {
19589
        const windowManagerImpl = getImplementation();
19590
        windowManagerImpl.confirm(message, funcBind(scope ? scope : windowManagerImpl, callback));
19591
      };
19592
      const close = () => {
19593
        getTopDialog().each(dialog => {
19594
          getImplementation().close(dialog);
19595
          closeDialog(dialog);
19596
        });
19597
      };
19598
      editor.on('remove', () => {
19599
        each$e(dialogs, dialog => {
19600
          getImplementation().close(dialog);
19601
        });
19602
      });
19603
      return {
19604
        open,
19605
        openUrl,
19606
        alert,
19607
        confirm,
19608
        close
19609
      };
19610
    };
19611
 
19612
    const displayNotification = (editor, message) => {
19613
      editor.notificationManager.open({
19614
        type: 'error',
19615
        text: message
19616
      });
19617
    };
19618
    const displayError = (editor, message) => {
19619
      if (editor._skinLoaded) {
19620
        displayNotification(editor, message);
19621
      } else {
19622
        editor.on('SkinLoaded', () => {
19623
          displayNotification(editor, message);
19624
        });
19625
      }
19626
    };
19627
    const uploadError = (editor, message) => {
19628
      displayError(editor, I18n.translate([
19629
        'Failed to upload image: {0}',
19630
        message
19631
      ]));
19632
    };
19633
    const logError = (editor, errorType, msg) => {
19634
      fireError(editor, errorType, { message: msg });
19635
      console.error(msg);
19636
    };
19637
    const createLoadError = (type, url, name) => name ? `Failed to load ${ type }: ${ name } from url ${ url }` : `Failed to load ${ type } url: ${ url }`;
19638
    const pluginLoadError = (editor, url, name) => {
19639
      logError(editor, 'PluginLoadError', createLoadError('plugin', url, name));
19640
    };
19641
    const iconsLoadError = (editor, url, name) => {
19642
      logError(editor, 'IconsLoadError', createLoadError('icons', url, name));
19643
    };
19644
    const languageLoadError = (editor, url, name) => {
19645
      logError(editor, 'LanguageLoadError', createLoadError('language', url, name));
19646
    };
19647
    const themeLoadError = (editor, url, name) => {
19648
      logError(editor, 'ThemeLoadError', createLoadError('theme', url, name));
19649
    };
19650
    const modelLoadError = (editor, url, name) => {
19651
      logError(editor, 'ModelLoadError', createLoadError('model', url, name));
19652
    };
19653
    const pluginInitError = (editor, name, err) => {
19654
      const message = I18n.translate([
19655
        'Failed to initialize plugin: {0}',
19656
        name
19657
      ]);
19658
      fireError(editor, 'PluginLoadError', { message });
19659
      initError(message, err);
19660
      displayError(editor, message);
19661
    };
19662
    const initError = (message, ...x) => {
19663
      const console = window.console;
19664
      if (console) {
19665
        if (console.error) {
19666
          console.error(message, ...x);
19667
        } else {
19668
          console.log(message, ...x);
19669
        }
19670
      }
19671
    };
19672
 
1441 ariadna 19673
    const removeFakeSelection = editor => {
19674
      Optional.from(editor.selection.getNode()).each(elm => {
19675
        elm.removeAttribute('data-mce-selected');
19676
      });
19677
    };
19678
    const setEditorCommandState = (editor, cmd, state) => {
19679
      try {
19680
        editor.getDoc().execCommand(cmd, false, String(state));
19681
      } catch (_a) {
19682
      }
19683
    };
19684
    const setCommonEditorCommands = (editor, state) => {
19685
      setEditorCommandState(editor, 'StyleWithCSS', state);
19686
      setEditorCommandState(editor, 'enableInlineTableEditing', state);
19687
      setEditorCommandState(editor, 'enableObjectResizing', state);
19688
    };
19689
    const restoreFakeSelection = editor => {
19690
      editor.selection.setRng(editor.selection.getRng());
19691
    };
19692
    const toggleClass = (elm, cls, state) => {
19693
      if (has(elm, cls) && !state) {
19694
        remove$6(elm, cls);
19695
      } else if (state) {
19696
        add$2(elm, cls);
19697
      }
19698
    };
19699
    const disableEditor = editor => {
19700
      const body = SugarElement.fromDom(editor.getBody());
19701
      toggleClass(body, 'mce-content-readonly', true);
19702
      editor.selection.controlSelection.hideResizeRect();
19703
      editor._selectionOverrides.hideFakeCaret();
19704
      removeFakeSelection(editor);
19705
    };
19706
    const enableEditor = editor => {
19707
      const body = SugarElement.fromDom(editor.getBody());
19708
      toggleClass(body, 'mce-content-readonly', false);
19709
      if (editor.hasEditableRoot()) {
19710
        set$3(body, true);
19711
      }
19712
      setCommonEditorCommands(editor, false);
19713
      if (hasEditorOrUiFocus(editor)) {
19714
        editor.focus();
19715
      }
19716
      restoreFakeSelection(editor);
19717
      editor.nodeChanged();
19718
    };
19719
 
19720
    const isDisabled = editor => isDisabled$1(editor);
19721
    const internalContentEditableAttr = 'data-mce-contenteditable';
19722
    const switchOffContentEditableTrue = elm => {
19723
      each$e(descendants(elm, '*[contenteditable="true"]'), elm => {
19724
        set$4(elm, internalContentEditableAttr, 'true');
19725
        set$3(elm, false);
19726
      });
19727
    };
19728
    const switchOnContentEditableTrue = elm => {
19729
      each$e(descendants(elm, `*[${ internalContentEditableAttr }="true"]`), elm => {
19730
        remove$9(elm, internalContentEditableAttr);
19731
        set$3(elm, true);
19732
      });
19733
    };
19734
    const toggleDisabled = (editor, state) => {
19735
      const body = SugarElement.fromDom(editor.getBody());
19736
      if (state) {
19737
        disableEditor(editor);
19738
        set$3(body, false);
19739
        switchOffContentEditableTrue(body);
19740
      } else {
19741
        switchOnContentEditableTrue(body);
19742
        enableEditor(editor);
19743
      }
19744
    };
19745
    const registerDisabledContentFilters = editor => {
19746
      if (editor.serializer) {
19747
        registerFilters(editor);
19748
      } else {
19749
        editor.on('PreInit', () => {
19750
          registerFilters(editor);
19751
        });
19752
      }
19753
    };
19754
    const registerFilters = editor => {
19755
      editor.parser.addAttributeFilter('contenteditable', nodes => {
19756
        if (isDisabled(editor)) {
19757
          each$e(nodes, node => {
19758
            node.attr(internalContentEditableAttr, node.attr('contenteditable'));
19759
            node.attr('contenteditable', 'false');
19760
          });
19761
        }
19762
      });
19763
      editor.serializer.addAttributeFilter(internalContentEditableAttr, nodes => {
19764
        if (isDisabled(editor)) {
19765
          each$e(nodes, node => {
19766
            node.attr('contenteditable', node.attr(internalContentEditableAttr));
19767
          });
19768
        }
19769
      });
19770
      editor.serializer.addTempAttr(internalContentEditableAttr);
19771
    };
19772
    const isClickEvent = e => e.type === 'click';
19773
    const allowedEvents = ['copy'];
19774
    const isAllowedEventInDisabledMode = e => contains$2(allowedEvents, e.type);
19775
    const getAnchorHrefOpt = (editor, elm) => {
19776
      const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
19777
      return closest$3(elm, 'a', isRoot).bind(a => getOpt(a, 'href'));
19778
    };
19779
    const processDisabledEvents = (editor, e) => {
19780
      if (isClickEvent(e) && !VK.metaKeyPressed(e)) {
19781
        const elm = SugarElement.fromDom(e.target);
19782
        getAnchorHrefOpt(editor, elm).each(href => {
19783
          e.preventDefault();
19784
          if (/^#/.test(href)) {
19785
            const targetEl = editor.dom.select(`${ href },[name="${ removeLeading(href, '#') }"]`);
19786
            if (targetEl.length) {
19787
              editor.selection.scrollIntoView(targetEl[0], true);
19788
            }
19789
          } else {
19790
            window.open(href, '_blank', 'rel=noopener noreferrer,menubar=yes,toolbar=yes,location=yes,status=yes,resizable=yes,scrollbars=yes');
19791
          }
19792
        });
19793
      } else if (isAllowedEventInDisabledMode(e)) {
19794
        editor.dispatch(e.type, e);
19795
      }
19796
    };
19797
    const registerDisabledModeEventHandlers = editor => {
19798
      editor.on('ShowCaret ObjectSelected', e => {
19799
        if (isDisabled(editor)) {
19800
          e.preventDefault();
19801
        }
19802
      });
19803
      editor.on('DisabledStateChange', e => {
19804
        if (!e.isDefaultPrevented()) {
19805
          toggleDisabled(editor, e.state);
19806
        }
19807
      });
19808
    };
19809
    const registerEventsAndFilters$1 = editor => {
19810
      registerDisabledContentFilters(editor);
19811
      registerDisabledModeEventHandlers(editor);
19812
    };
19813
 
1 efrain 19814
    const isContentCssSkinName = url => /^[a-z0-9\-]+$/i.test(url);
19815
    const toContentSkinResourceName = url => 'content/' + url + '/content.css';
19816
    const isBundledCssSkinName = url => tinymce.Resource.has(toContentSkinResourceName(url));
19817
    const getContentCssUrls = editor => {
19818
      return transformToUrls(editor, getContentCss(editor));
19819
    };
19820
    const getFontCssUrls = editor => {
19821
      return transformToUrls(editor, getFontCss(editor));
19822
    };
19823
    const transformToUrls = (editor, cssLinks) => {
19824
      const skinUrl = editor.editorManager.baseURL + '/skins/content';
19825
      const suffix = editor.editorManager.suffix;
19826
      const contentCssFile = `content${ suffix }.css`;
19827
      return map$3(cssLinks, url => {
19828
        if (isBundledCssSkinName(url)) {
19829
          return url;
19830
        } else if (isContentCssSkinName(url) && !editor.inline) {
19831
          return `${ skinUrl }/${ url }/${ contentCssFile }`;
19832
        } else {
19833
          return editor.documentBaseURI.toAbsolute(url);
19834
        }
19835
      });
19836
    };
19837
    const appendContentCssFromSettings = editor => {
19838
      editor.contentCSS = editor.contentCSS.concat(getContentCssUrls(editor), getFontCssUrls(editor));
19839
    };
19840
 
19841
    const getAllImages = elm => {
19842
      return elm ? from(elm.getElementsByTagName('img')) : [];
19843
    };
19844
    const ImageScanner = (uploadStatus, blobCache) => {
19845
      const cachedPromises = {};
19846
      const findAll = (elm, predicate = always) => {
19847
        const images = filter$5(getAllImages(elm), img => {
19848
          const src = img.src;
19849
          if (img.hasAttribute('data-mce-bogus')) {
19850
            return false;
19851
          }
19852
          if (img.hasAttribute('data-mce-placeholder')) {
19853
            return false;
19854
          }
19855
          if (!src || src === Env.transparentSrc) {
19856
            return false;
19857
          }
19858
          if (startsWith(src, 'blob:')) {
19859
            return !uploadStatus.isUploaded(src) && predicate(img);
19860
          }
19861
          if (startsWith(src, 'data:')) {
19862
            return predicate(img);
19863
          }
19864
          return false;
19865
        });
19866
        const promises = map$3(images, img => {
19867
          const imageSrc = img.src;
19868
          if (has$2(cachedPromises, imageSrc)) {
19869
            return cachedPromises[imageSrc].then(imageInfo => {
19870
              if (isString(imageInfo)) {
19871
                return imageInfo;
19872
              } else {
19873
                return {
19874
                  image: img,
19875
                  blobInfo: imageInfo.blobInfo
19876
                };
19877
              }
19878
            });
19879
          } else {
19880
            const newPromise = imageToBlobInfo(blobCache, imageSrc).then(blobInfo => {
19881
              delete cachedPromises[imageSrc];
19882
              return {
19883
                image: img,
19884
                blobInfo
19885
              };
19886
            }).catch(error => {
19887
              delete cachedPromises[imageSrc];
19888
              return error;
19889
            });
19890
            cachedPromises[imageSrc] = newPromise;
19891
            return newPromise;
19892
          }
19893
        });
19894
        return Promise.all(promises);
19895
      };
19896
      return { findAll };
19897
    };
19898
 
19899
    const UploadStatus = () => {
19900
      const PENDING = 1, UPLOADED = 2;
19901
      let blobUriStatuses = {};
19902
      const createStatus = (status, resultUri) => {
19903
        return {
19904
          status,
19905
          resultUri
19906
        };
19907
      };
19908
      const hasBlobUri = blobUri => {
19909
        return blobUri in blobUriStatuses;
19910
      };
19911
      const getResultUri = blobUri => {
19912
        const result = blobUriStatuses[blobUri];
19913
        return result ? result.resultUri : null;
19914
      };
19915
      const isPending = blobUri => {
19916
        return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === PENDING : false;
19917
      };
19918
      const isUploaded = blobUri => {
19919
        return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === UPLOADED : false;
19920
      };
19921
      const markPending = blobUri => {
19922
        blobUriStatuses[blobUri] = createStatus(PENDING, null);
19923
      };
19924
      const markUploaded = (blobUri, resultUri) => {
19925
        blobUriStatuses[blobUri] = createStatus(UPLOADED, resultUri);
19926
      };
19927
      const removeFailed = blobUri => {
19928
        delete blobUriStatuses[blobUri];
19929
      };
19930
      const destroy = () => {
19931
        blobUriStatuses = {};
19932
      };
19933
      return {
19934
        hasBlobUri,
19935
        getResultUri,
19936
        isPending,
19937
        isUploaded,
19938
        markPending,
19939
        markUploaded,
19940
        removeFailed,
19941
        destroy
19942
      };
19943
    };
19944
 
19945
    let count = 0;
19946
    const seed = () => {
19947
      const rnd = () => {
1441 ariadna 19948
        return Math.round(random() * 4294967295).toString(36);
1 efrain 19949
      };
19950
      const now = new Date().getTime();
19951
      return 's' + now.toString(36) + rnd() + rnd() + rnd();
19952
    };
19953
    const uuid = prefix => {
19954
      return prefix + count++ + seed();
19955
    };
19956
 
19957
    const BlobCache = () => {
19958
      let cache = [];
19959
      const mimeToExt = mime => {
19960
        const mimes = {
19961
          'image/jpeg': 'jpg',
19962
          'image/jpg': 'jpg',
19963
          'image/gif': 'gif',
19964
          'image/png': 'png',
19965
          'image/apng': 'apng',
19966
          'image/avif': 'avif',
19967
          'image/svg+xml': 'svg',
19968
          'image/webp': 'webp',
19969
          'image/bmp': 'bmp',
19970
          'image/tiff': 'tiff'
19971
        };
19972
        return mimes[mime.toLowerCase()] || 'dat';
19973
      };
19974
      const create = (o, blob, base64, name, filename) => {
19975
        if (isString(o)) {
19976
          const id = o;
19977
          return toBlobInfo({
19978
            id,
19979
            name,
19980
            filename,
19981
            blob: blob,
19982
            base64: base64
19983
          });
19984
        } else if (isObject(o)) {
19985
          return toBlobInfo(o);
19986
        } else {
19987
          throw new Error('Unknown input type');
19988
        }
19989
      };
19990
      const toBlobInfo = o => {
19991
        if (!o.blob || !o.base64) {
19992
          throw new Error('blob and base64 representations of the image are required for BlobInfo to be created');
19993
        }
19994
        const id = o.id || uuid('blobid');
19995
        const name = o.name || id;
19996
        const blob = o.blob;
19997
        return {
19998
          id: constant(id),
19999
          name: constant(name),
20000
          filename: constant(o.filename || name + '.' + mimeToExt(blob.type)),
20001
          blob: constant(blob),
20002
          base64: constant(o.base64),
20003
          blobUri: constant(o.blobUri || URL.createObjectURL(blob)),
20004
          uri: constant(o.uri)
20005
        };
20006
      };
20007
      const add = blobInfo => {
20008
        if (!get(blobInfo.id())) {
20009
          cache.push(blobInfo);
20010
        }
20011
      };
20012
      const findFirst = predicate => find$2(cache, predicate).getOrUndefined();
20013
      const get = id => findFirst(cachedBlobInfo => cachedBlobInfo.id() === id);
20014
      const getByUri = blobUri => findFirst(blobInfo => blobInfo.blobUri() === blobUri);
20015
      const getByData = (base64, type) => findFirst(blobInfo => blobInfo.base64() === base64 && blobInfo.blob().type === type);
20016
      const removeByUri = blobUri => {
20017
        cache = filter$5(cache, blobInfo => {
20018
          if (blobInfo.blobUri() === blobUri) {
20019
            URL.revokeObjectURL(blobInfo.blobUri());
20020
            return false;
20021
          }
20022
          return true;
20023
        });
20024
      };
20025
      const destroy = () => {
20026
        each$e(cache, cachedBlobInfo => {
20027
          URL.revokeObjectURL(cachedBlobInfo.blobUri());
20028
        });
20029
        cache = [];
20030
      };
20031
      return {
20032
        create,
20033
        add,
20034
        get,
20035
        getByUri,
20036
        getByData,
20037
        findFirst,
20038
        removeByUri,
20039
        destroy
20040
      };
20041
    };
20042
 
20043
    const Uploader = (uploadStatus, settings) => {
20044
      const pendingPromises = {};
20045
      const pathJoin = (path1, path2) => {
20046
        if (path1) {
20047
          return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, '');
20048
        }
20049
        return path2;
20050
      };
20051
      const defaultHandler = (blobInfo, progress) => new Promise((success, failure) => {
20052
        const xhr = new XMLHttpRequest();
20053
        xhr.open('POST', settings.url);
20054
        xhr.withCredentials = settings.credentials;
20055
        xhr.upload.onprogress = e => {
20056
          progress(e.loaded / e.total * 100);
20057
        };
20058
        xhr.onerror = () => {
20059
          failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
20060
        };
20061
        xhr.onload = () => {
20062
          if (xhr.status < 200 || xhr.status >= 300) {
20063
            failure('HTTP Error: ' + xhr.status);
20064
            return;
20065
          }
20066
          const json = JSON.parse(xhr.responseText);
20067
          if (!json || !isString(json.location)) {
20068
            failure('Invalid JSON: ' + xhr.responseText);
20069
            return;
20070
          }
20071
          success(pathJoin(settings.basePath, json.location));
20072
        };
20073
        const formData = new FormData();
20074
        formData.append('file', blobInfo.blob(), blobInfo.filename());
20075
        xhr.send(formData);
20076
      });
20077
      const uploadHandler = isFunction(settings.handler) ? settings.handler : defaultHandler;
20078
      const noUpload = () => new Promise(resolve => {
20079
        resolve([]);
20080
      });
20081
      const handlerSuccess = (blobInfo, url) => ({
20082
        url,
20083
        blobInfo,
20084
        status: true
20085
      });
20086
      const handlerFailure = (blobInfo, error) => ({
20087
        url: '',
20088
        blobInfo,
20089
        status: false,
20090
        error
20091
      });
20092
      const resolvePending = (blobUri, result) => {
20093
        Tools.each(pendingPromises[blobUri], resolve => {
20094
          resolve(result);
20095
        });
20096
        delete pendingPromises[blobUri];
20097
      };
20098
      const uploadBlobInfo = (blobInfo, handler, openNotification) => {
20099
        uploadStatus.markPending(blobInfo.blobUri());
20100
        return new Promise(resolve => {
20101
          let notification;
20102
          let progress;
20103
          try {
20104
            const closeNotification = () => {
20105
              if (notification) {
20106
                notification.close();
20107
                progress = noop;
20108
              }
20109
            };
20110
            const success = url => {
20111
              closeNotification();
20112
              uploadStatus.markUploaded(blobInfo.blobUri(), url);
20113
              resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url));
20114
              resolve(handlerSuccess(blobInfo, url));
20115
            };
20116
            const failure = error => {
20117
              closeNotification();
20118
              uploadStatus.removeFailed(blobInfo.blobUri());
20119
              resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, error));
20120
              resolve(handlerFailure(blobInfo, error));
20121
            };
20122
            progress = percent => {
20123
              if (percent < 0 || percent > 100) {
20124
                return;
20125
              }
20126
              Optional.from(notification).orThunk(() => Optional.from(openNotification).map(apply$1)).each(n => {
20127
                notification = n;
20128
                n.progressBar.value(percent);
20129
              });
20130
            };
20131
            handler(blobInfo, progress).then(success, err => {
20132
              failure(isString(err) ? { message: err } : err);
20133
            });
20134
          } catch (ex) {
20135
            resolve(handlerFailure(blobInfo, ex));
20136
          }
20137
        });
20138
      };
20139
      const isDefaultHandler = handler => handler === defaultHandler;
20140
      const pendingUploadBlobInfo = blobInfo => {
20141
        const blobUri = blobInfo.blobUri();
20142
        return new Promise(resolve => {
20143
          pendingPromises[blobUri] = pendingPromises[blobUri] || [];
20144
          pendingPromises[blobUri].push(resolve);
20145
        });
20146
      };
20147
      const uploadBlobs = (blobInfos, openNotification) => {
20148
        blobInfos = Tools.grep(blobInfos, blobInfo => !uploadStatus.isUploaded(blobInfo.blobUri()));
20149
        return Promise.all(Tools.map(blobInfos, blobInfo => uploadStatus.isPending(blobInfo.blobUri()) ? pendingUploadBlobInfo(blobInfo) : uploadBlobInfo(blobInfo, uploadHandler, openNotification)));
20150
      };
20151
      const upload = (blobInfos, openNotification) => !settings.url && isDefaultHandler(uploadHandler) ? noUpload() : uploadBlobs(blobInfos, openNotification);
20152
      return { upload };
20153
    };
20154
 
20155
    const openNotification = editor => () => editor.notificationManager.open({
20156
      text: editor.translate('Image uploading...'),
20157
      type: 'info',
20158
      timeout: -1,
20159
      progressBar: true
20160
    });
20161
    const createUploader = (editor, uploadStatus) => Uploader(uploadStatus, {
20162
      url: getImageUploadUrl(editor),
20163
      basePath: getImageUploadBasePath(editor),
20164
      credentials: getImagesUploadCredentials(editor),
20165
      handler: getImagesUploadHandler(editor)
20166
    });
20167
    const ImageUploader = editor => {
20168
      const uploadStatus = UploadStatus();
20169
      const uploader = createUploader(editor, uploadStatus);
20170
      return { upload: (blobInfos, showNotification = true) => uploader.upload(blobInfos, showNotification ? openNotification(editor) : undefined) };
20171
    };
20172
 
20173
    const isEmptyForPadding = (editor, element) => editor.dom.isEmpty(element.dom) && isNonNullable(editor.schema.getTextBlockElements()[name(element)]);
20174
    const addPaddingToEmpty = editor => element => {
20175
      if (isEmptyForPadding(editor, element)) {
20176
        append$1(element, SugarElement.fromHtml('<br data-mce-bogus="1" />'));
20177
      }
20178
    };
20179
    const EditorUpload = editor => {
20180
      const blobCache = BlobCache();
20181
      let uploader, imageScanner;
20182
      const uploadStatus = UploadStatus();
20183
      const urlFilters = [];
20184
      const aliveGuard = callback => {
20185
        return result => {
20186
          if (editor.selection) {
20187
            return callback(result);
20188
          }
20189
          return [];
20190
        };
20191
      };
20192
      const cacheInvalidator = url => url + (url.indexOf('?') === -1 ? '?' : '&') + new Date().getTime();
20193
      const replaceString = (content, search, replace) => {
20194
        let index = 0;
20195
        do {
20196
          index = content.indexOf(search, index);
20197
          if (index !== -1) {
20198
            content = content.substring(0, index) + replace + content.substr(index + search.length);
20199
            index += replace.length - search.length + 1;
20200
          }
20201
        } while (index !== -1);
20202
        return content;
20203
      };
20204
      const replaceImageUrl = (content, targetUrl, replacementUrl) => {
20205
        const replacementString = `src="${ replacementUrl }"${ replacementUrl === Env.transparentSrc ? ' data-mce-placeholder="1"' : '' }`;
20206
        content = replaceString(content, `src="${ targetUrl }"`, replacementString);
20207
        content = replaceString(content, 'data-mce-src="' + targetUrl + '"', 'data-mce-src="' + replacementUrl + '"');
20208
        return content;
20209
      };
20210
      const replaceUrlInUndoStack = (targetUrl, replacementUrl) => {
20211
        each$e(editor.undoManager.data, level => {
20212
          if (level.type === 'fragmented') {
20213
            level.fragments = map$3(level.fragments, fragment => replaceImageUrl(fragment, targetUrl, replacementUrl));
20214
          } else {
20215
            level.content = replaceImageUrl(level.content, targetUrl, replacementUrl);
20216
          }
20217
        });
20218
      };
20219
      const replaceImageUriInView = (image, resultUri) => {
20220
        const src = editor.convertURL(resultUri, 'src');
20221
        replaceUrlInUndoStack(image.src, resultUri);
20222
        setAll$1(SugarElement.fromDom(image), {
20223
          'src': shouldReuseFileName(editor) ? cacheInvalidator(resultUri) : resultUri,
20224
          'data-mce-src': src
20225
        });
20226
      };
20227
      const uploadImages = () => {
20228
        if (!uploader) {
20229
          uploader = createUploader(editor, uploadStatus);
20230
        }
20231
        return scanForImages().then(aliveGuard(imageInfos => {
20232
          const blobInfos = map$3(imageInfos, imageInfo => imageInfo.blobInfo);
20233
          return uploader.upload(blobInfos, openNotification(editor)).then(aliveGuard(result => {
20234
            const imagesToRemove = [];
20235
            let shouldDispatchChange = false;
20236
            const filteredResult = map$3(result, (uploadInfo, index) => {
20237
              const {blobInfo, image} = imageInfos[index];
20238
              let removed = false;
20239
              if (uploadInfo.status && shouldReplaceBlobUris(editor)) {
20240
                if (uploadInfo.url && !contains$1(image.src, uploadInfo.url)) {
20241
                  shouldDispatchChange = true;
20242
                }
20243
                blobCache.removeByUri(image.src);
20244
                if (isRtc(editor)) ; else {
20245
                  replaceImageUriInView(image, uploadInfo.url);
20246
                }
20247
              } else if (uploadInfo.error) {
20248
                if (uploadInfo.error.remove) {
20249
                  replaceUrlInUndoStack(image.src, Env.transparentSrc);
20250
                  imagesToRemove.push(image);
20251
                  removed = true;
20252
                }
20253
                uploadError(editor, uploadInfo.error.message);
20254
              }
20255
              return {
20256
                element: image,
20257
                status: uploadInfo.status,
20258
                uploadUri: uploadInfo.url,
20259
                blobInfo,
20260
                removed
20261
              };
20262
            });
20263
            if (imagesToRemove.length > 0 && !isRtc(editor)) {
20264
              editor.undoManager.transact(() => {
20265
                each$e(fromDom$1(imagesToRemove), sugarElement => {
20266
                  const parentOpt = parent(sugarElement);
1441 ariadna 20267
                  remove$4(sugarElement);
1 efrain 20268
                  parentOpt.each(addPaddingToEmpty(editor));
20269
                  blobCache.removeByUri(sugarElement.dom.src);
20270
                });
20271
              });
20272
            } else if (shouldDispatchChange) {
20273
              editor.undoManager.dispatchChange();
20274
            }
20275
            return filteredResult;
20276
          }));
20277
        }));
20278
      };
20279
      const uploadImagesAuto = () => isAutomaticUploadsEnabled(editor) ? uploadImages() : Promise.resolve([]);
20280
      const isValidDataUriImage = imgElm => forall(urlFilters, filter => filter(imgElm));
20281
      const addFilter = filter => {
20282
        urlFilters.push(filter);
20283
      };
20284
      const scanForImages = () => {
20285
        if (!imageScanner) {
20286
          imageScanner = ImageScanner(uploadStatus, blobCache);
20287
        }
20288
        return imageScanner.findAll(editor.getBody(), isValidDataUriImage).then(aliveGuard(result => {
20289
          const filteredResult = filter$5(result, resultItem => {
20290
            if (isString(resultItem)) {
20291
              displayError(editor, resultItem);
20292
              return false;
20293
            } else if (resultItem.uriType === 'blob') {
20294
              return false;
20295
            } else {
20296
              return true;
20297
            }
20298
          });
20299
          if (isRtc(editor)) ; else {
20300
            each$e(filteredResult, resultItem => {
20301
              replaceUrlInUndoStack(resultItem.image.src, resultItem.blobInfo.blobUri());
20302
              resultItem.image.src = resultItem.blobInfo.blobUri();
20303
              resultItem.image.removeAttribute('data-mce-src');
20304
            });
20305
          }
20306
          return filteredResult;
20307
        }));
20308
      };
20309
      const destroy = () => {
20310
        blobCache.destroy();
20311
        uploadStatus.destroy();
20312
        imageScanner = uploader = null;
20313
      };
20314
      const replaceBlobUris = content => {
20315
        return content.replace(/src="(blob:[^"]+)"/g, (match, blobUri) => {
20316
          const resultUri = uploadStatus.getResultUri(blobUri);
20317
          if (resultUri) {
20318
            return 'src="' + resultUri + '"';
20319
          }
20320
          let blobInfo = blobCache.getByUri(blobUri);
20321
          if (!blobInfo) {
20322
            blobInfo = foldl(editor.editorManager.get(), (result, editor) => {
20323
              return result || editor.editorUpload && editor.editorUpload.blobCache.getByUri(blobUri);
20324
            }, undefined);
20325
          }
20326
          if (blobInfo) {
20327
            const blob = blobInfo.blob();
20328
            return 'src="data:' + blob.type + ';base64,' + blobInfo.base64() + '"';
20329
          }
20330
          return match;
20331
        });
20332
      };
20333
      editor.on('SetContent', () => {
20334
        if (isAutomaticUploadsEnabled(editor)) {
20335
          uploadImagesAuto();
20336
        } else {
20337
          scanForImages();
20338
        }
20339
      });
20340
      editor.on('RawSaveContent', e => {
20341
        e.content = replaceBlobUris(e.content);
20342
      });
20343
      editor.on('GetContent', e => {
20344
        if (e.source_view || e.format === 'raw' || e.format === 'tree') {
20345
          return;
20346
        }
20347
        e.content = replaceBlobUris(e.content);
20348
      });
20349
      editor.on('PostRender', () => {
20350
        editor.parser.addNodeFilter('img', images => {
20351
          each$e(images, img => {
20352
            const src = img.attr('src');
20353
            if (!src || blobCache.getByUri(src)) {
20354
              return;
20355
            }
20356
            const resultUri = uploadStatus.getResultUri(src);
20357
            if (resultUri) {
20358
              img.attr('src', resultUri);
20359
            }
20360
          });
20361
        });
20362
      });
20363
      return {
20364
        blobCache,
20365
        addFilter,
20366
        uploadImages,
20367
        uploadImagesAuto,
20368
        scanForImages,
20369
        destroy
20370
      };
20371
    };
20372
 
20373
    const get$1 = editor => {
20374
      const dom = editor.dom;
20375
      const schemaType = editor.schema.type;
20376
      const formats = {
20377
        valigntop: [{
20378
            selector: 'td,th',
20379
            styles: { verticalAlign: 'top' }
20380
          }],
20381
        valignmiddle: [{
20382
            selector: 'td,th',
20383
            styles: { verticalAlign: 'middle' }
20384
          }],
20385
        valignbottom: [{
20386
            selector: 'td,th',
20387
            styles: { verticalAlign: 'bottom' }
20388
          }],
20389
        alignleft: [
20390
          {
20391
            selector: 'figure.image',
20392
            collapsed: false,
20393
            classes: 'align-left',
20394
            ceFalseOverride: true,
20395
            preview: 'font-family font-size'
20396
          },
20397
          {
20398
            selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
20399
            styles: { textAlign: 'left' },
20400
            inherit: false,
20401
            preview: false
20402
          },
20403
          {
20404
            selector: 'img,audio,video',
20405
            collapsed: false,
20406
            styles: { float: 'left' },
20407
            preview: 'font-family font-size'
20408
          },
20409
          {
1441 ariadna 20410
            selector: '.mce-placeholder',
20411
            styles: { float: 'left' },
20412
            ceFalseOverride: true
20413
          },
20414
          {
1 efrain 20415
            selector: 'table',
20416
            collapsed: false,
20417
            styles: {
20418
              marginLeft: '0px',
20419
              marginRight: 'auto'
20420
            },
20421
            onformat: table => {
20422
              dom.setStyle(table, 'float', null);
20423
            },
20424
            preview: 'font-family font-size'
20425
          },
20426
          {
20427
            selector: '.mce-preview-object,[data-ephox-embed-iri]',
20428
            ceFalseOverride: true,
20429
            styles: { float: 'left' }
20430
          }
20431
        ],
20432
        aligncenter: [
20433
          {
20434
            selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
20435
            styles: { textAlign: 'center' },
20436
            inherit: false,
20437
            preview: 'font-family font-size'
20438
          },
20439
          {
20440
            selector: 'figure.image',
20441
            collapsed: false,
20442
            classes: 'align-center',
20443
            ceFalseOverride: true,
20444
            preview: 'font-family font-size'
20445
          },
20446
          {
20447
            selector: 'img,audio,video',
20448
            collapsed: false,
20449
            styles: {
20450
              display: 'block',
20451
              marginLeft: 'auto',
20452
              marginRight: 'auto'
20453
            },
20454
            preview: false
20455
          },
20456
          {
1441 ariadna 20457
            selector: '.mce-placeholder',
20458
            styles: {
20459
              display: 'block',
20460
              marginLeft: 'auto',
20461
              marginRight: 'auto'
20462
            },
20463
            ceFalseOverride: true
20464
          },
20465
          {
1 efrain 20466
            selector: 'table',
20467
            collapsed: false,
20468
            styles: {
20469
              marginLeft: 'auto',
20470
              marginRight: 'auto'
20471
            },
20472
            preview: 'font-family font-size'
20473
          },
20474
          {
20475
            selector: '.mce-preview-object',
20476
            ceFalseOverride: true,
20477
            styles: {
20478
              display: 'table',
20479
              marginLeft: 'auto',
20480
              marginRight: 'auto'
20481
            },
20482
            preview: false
20483
          },
20484
          {
20485
            selector: '[data-ephox-embed-iri]',
20486
            ceFalseOverride: true,
20487
            styles: {
20488
              marginLeft: 'auto',
20489
              marginRight: 'auto'
20490
            },
20491
            preview: false
20492
          }
20493
        ],
20494
        alignright: [
20495
          {
20496
            selector: 'figure.image',
20497
            collapsed: false,
20498
            classes: 'align-right',
20499
            ceFalseOverride: true,
20500
            preview: 'font-family font-size'
20501
          },
20502
          {
20503
            selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
20504
            styles: { textAlign: 'right' },
20505
            inherit: false,
20506
            preview: 'font-family font-size'
20507
          },
20508
          {
20509
            selector: 'img,audio,video',
20510
            collapsed: false,
20511
            styles: { float: 'right' },
20512
            preview: 'font-family font-size'
20513
          },
20514
          {
1441 ariadna 20515
            selector: '.mce-placeholder',
20516
            styles: { float: 'right' },
20517
            ceFalseOverride: true
20518
          },
20519
          {
1 efrain 20520
            selector: 'table',
20521
            collapsed: false,
20522
            styles: {
20523
              marginRight: '0px',
20524
              marginLeft: 'auto'
20525
            },
20526
            onformat: table => {
20527
              dom.setStyle(table, 'float', null);
20528
            },
20529
            preview: 'font-family font-size'
20530
          },
20531
          {
20532
            selector: '.mce-preview-object,[data-ephox-embed-iri]',
20533
            ceFalseOverride: true,
20534
            styles: { float: 'right' },
20535
            preview: false
20536
          }
20537
        ],
20538
        alignjustify: [{
20539
            selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
20540
            styles: { textAlign: 'justify' },
20541
            inherit: false,
20542
            preview: 'font-family font-size'
20543
          }],
20544
        bold: [
20545
          {
20546
            inline: 'strong',
20547
            remove: 'all',
20548
            preserve_attributes: [
20549
              'class',
20550
              'style'
20551
            ]
20552
          },
20553
          {
20554
            inline: 'span',
20555
            styles: { fontWeight: 'bold' }
20556
          },
20557
          {
20558
            inline: 'b',
20559
            remove: 'all',
20560
            preserve_attributes: [
20561
              'class',
20562
              'style'
20563
            ]
20564
          }
20565
        ],
20566
        italic: [
20567
          {
20568
            inline: 'em',
20569
            remove: 'all',
20570
            preserve_attributes: [
20571
              'class',
20572
              'style'
20573
            ]
20574
          },
20575
          {
20576
            inline: 'span',
20577
            styles: { fontStyle: 'italic' }
20578
          },
20579
          {
20580
            inline: 'i',
20581
            remove: 'all',
20582
            preserve_attributes: [
20583
              'class',
20584
              'style'
20585
            ]
20586
          }
20587
        ],
20588
        underline: [
20589
          {
20590
            inline: 'span',
20591
            styles: { textDecoration: 'underline' },
20592
            exact: true
20593
          },
20594
          {
20595
            inline: 'u',
20596
            remove: 'all',
20597
            preserve_attributes: [
20598
              'class',
20599
              'style'
20600
            ]
20601
          }
20602
        ],
20603
        strikethrough: (() => {
20604
          const span = {
20605
            inline: 'span',
20606
            styles: { textDecoration: 'line-through' },
20607
            exact: true
20608
          };
20609
          const strike = {
20610
            inline: 'strike',
20611
            remove: 'all',
20612
            preserve_attributes: [
20613
              'class',
20614
              'style'
20615
            ]
20616
          };
20617
          const s = {
20618
            inline: 's',
20619
            remove: 'all',
20620
            preserve_attributes: [
20621
              'class',
20622
              'style'
20623
            ]
20624
          };
20625
          return schemaType !== 'html4' ? [
20626
            s,
20627
            span,
20628
            strike
20629
          ] : [
20630
            span,
20631
            s,
20632
            strike
20633
          ];
20634
        })(),
20635
        forecolor: {
20636
          inline: 'span',
20637
          styles: { color: '%value' },
20638
          links: true,
20639
          remove_similar: true,
20640
          clear_child_styles: true
20641
        },
20642
        hilitecolor: {
20643
          inline: 'span',
20644
          styles: { backgroundColor: '%value' },
20645
          links: true,
20646
          remove_similar: true,
20647
          clear_child_styles: true
20648
        },
20649
        fontname: {
20650
          inline: 'span',
20651
          toggle: false,
20652
          styles: { fontFamily: '%value' },
20653
          clear_child_styles: true
20654
        },
20655
        fontsize: {
20656
          inline: 'span',
20657
          toggle: false,
20658
          styles: { fontSize: '%value' },
20659
          clear_child_styles: true
20660
        },
20661
        lineheight: {
20662
          selector: 'h1,h2,h3,h4,h5,h6,p,li,td,th,div',
20663
          styles: { lineHeight: '%value' }
20664
        },
20665
        fontsize_class: {
20666
          inline: 'span',
20667
          attributes: { class: '%value' }
20668
        },
20669
        blockquote: {
20670
          block: 'blockquote',
20671
          wrapper: true,
20672
          remove: 'all'
20673
        },
20674
        subscript: { inline: 'sub' },
20675
        superscript: { inline: 'sup' },
20676
        code: { inline: 'code' },
1441 ariadna 20677
        samp: { inline: 'samp' },
1 efrain 20678
        link: {
20679
          inline: 'a',
20680
          selector: 'a',
20681
          remove: 'all',
20682
          split: true,
20683
          deep: true,
20684
          onmatch: (node, _fmt, _itemName) => {
20685
            return isElement$6(node) && node.hasAttribute('href');
20686
          },
20687
          onformat: (elm, _fmt, vars) => {
20688
            Tools.each(vars, (value, key) => {
20689
              dom.setAttrib(elm, key, value);
20690
            });
20691
          }
20692
        },
20693
        lang: {
20694
          inline: 'span',
20695
          clear_child_styles: true,
20696
          remove_similar: true,
20697
          attributes: {
20698
            'lang': '%value',
20699
            'data-mce-lang': vars => {
20700
              var _a;
20701
              return (_a = vars === null || vars === void 0 ? void 0 : vars.customValue) !== null && _a !== void 0 ? _a : null;
20702
            }
20703
          }
20704
        },
20705
        removeformat: [
20706
          {
20707
            selector: 'b,strong,em,i,font,u,strike,s,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins,small',
20708
            remove: 'all',
20709
            split: true,
20710
            expand: false,
20711
            block_expand: true,
20712
            deep: true
20713
          },
20714
          {
20715
            selector: 'span',
20716
            attributes: [
20717
              'style',
20718
              'class'
20719
            ],
20720
            remove: 'empty',
20721
            split: true,
20722
            expand: false,
20723
            deep: true
20724
          },
20725
          {
20726
            selector: '*',
20727
            attributes: [
20728
              'style',
20729
              'class'
20730
            ],
20731
            split: false,
20732
            expand: false,
20733
            deep: true
20734
          }
20735
        ]
20736
      };
1441 ariadna 20737
      Tools.each('p h1 h2 h3 h4 h5 h6 div address pre dt dd'.split(/\s/), name => {
1 efrain 20738
        formats[name] = {
20739
          block: name,
20740
          remove: 'all'
20741
        };
20742
      });
20743
      return formats;
20744
    };
20745
 
20746
    const genericBase = {
20747
      remove_similar: true,
20748
      inherit: false
20749
    };
20750
    const cellBase = {
20751
      selector: 'td,th',
20752
      ...genericBase
20753
    };
20754
    const cellFormats = {
20755
      tablecellbackgroundcolor: {
20756
        styles: { backgroundColor: '%value' },
20757
        ...cellBase
20758
      },
20759
      tablecellverticalalign: {
20760
        styles: { 'vertical-align': '%value' },
20761
        ...cellBase
20762
      },
20763
      tablecellbordercolor: {
20764
        styles: { borderColor: '%value' },
20765
        ...cellBase
20766
      },
20767
      tablecellclass: {
20768
        classes: ['%value'],
20769
        ...cellBase
20770
      },
20771
      tableclass: {
20772
        selector: 'table',
20773
        classes: ['%value'],
20774
        ...genericBase
20775
      },
20776
      tablecellborderstyle: {
20777
        styles: { borderStyle: '%value' },
20778
        ...cellBase
20779
      },
20780
      tablecellborderwidth: {
20781
        styles: { borderWidth: '%value' },
20782
        ...cellBase
20783
      }
20784
    };
20785
    const get = constant(cellFormats);
20786
 
20787
    const FormatRegistry = editor => {
20788
      const formats = {};
20789
      const get$2 = name => isNonNullable(name) ? formats[name] : formats;
20790
      const has = name => has$2(formats, name);
20791
      const register = (name, format) => {
20792
        if (name) {
20793
          if (!isString(name)) {
20794
            each$d(name, (format, name) => {
20795
              register(name, format);
20796
            });
20797
          } else {
20798
            if (!isArray$1(format)) {
20799
              format = [format];
20800
            }
20801
            each$e(format, format => {
20802
              if (isUndefined(format.deep)) {
20803
                format.deep = !isSelectorFormat(format);
20804
              }
20805
              if (isUndefined(format.split)) {
20806
                format.split = !isSelectorFormat(format) || isInlineFormat(format);
20807
              }
20808
              if (isUndefined(format.remove) && isSelectorFormat(format) && !isInlineFormat(format)) {
20809
                format.remove = 'none';
20810
              }
20811
              if (isSelectorFormat(format) && isInlineFormat(format)) {
20812
                format.mixed = true;
20813
                format.block_expand = true;
20814
              }
20815
              if (isString(format.classes)) {
20816
                format.classes = format.classes.split(/\s+/);
20817
              }
20818
            });
20819
            formats[name] = format;
20820
          }
20821
        }
20822
      };
20823
      const unregister = name => {
20824
        if (name && formats[name]) {
20825
          delete formats[name];
20826
        }
20827
        return formats;
20828
      };
20829
      register(get$1(editor));
20830
      register(get());
20831
      register(getFormats(editor));
20832
      return {
20833
        get: get$2,
20834
        has,
20835
        register,
20836
        unregister
20837
      };
20838
    };
20839
 
20840
    const each$3 = Tools.each;
20841
    const dom = DOMUtils.DOM;
20842
    const isPreviewItem = item => isNonNullable(item) && isObject(item);
20843
    const parsedSelectorToHtml = (ancestry, editor) => {
20844
      const schema = editor && editor.schema || Schema({});
20845
      const decorate = (elm, item) => {
20846
        if (item.classes.length > 0) {
20847
          dom.addClass(elm, item.classes.join(' '));
20848
        }
20849
        dom.setAttribs(elm, item.attrs);
20850
      };
20851
      const createElement = sItem => {
20852
        const item = isString(sItem) ? {
20853
          name: sItem,
20854
          classes: [],
20855
          attrs: {}
20856
        } : sItem;
20857
        const elm = dom.create(item.name);
20858
        decorate(elm, item);
20859
        return elm;
20860
      };
20861
      const getRequiredParent = (elm, candidate) => {
20862
        const elmRule = schema.getElementRule(elm.nodeName.toLowerCase());
20863
        const parentsRequired = elmRule === null || elmRule === void 0 ? void 0 : elmRule.parentsRequired;
20864
        if (parentsRequired && parentsRequired.length) {
20865
          return candidate && contains$2(parentsRequired, candidate) ? candidate : parentsRequired[0];
20866
        } else {
20867
          return false;
20868
        }
20869
      };
20870
      const wrapInHtml = (elm, ancestors, siblings) => {
20871
        let parentCandidate;
20872
        const ancestor = ancestors[0];
20873
        const ancestorName = isPreviewItem(ancestor) ? ancestor.name : undefined;
20874
        const parentRequired = getRequiredParent(elm, ancestorName);
20875
        if (parentRequired) {
20876
          if (ancestorName === parentRequired) {
20877
            parentCandidate = ancestor;
20878
            ancestors = ancestors.slice(1);
20879
          } else {
20880
            parentCandidate = parentRequired;
20881
          }
20882
        } else if (ancestor) {
20883
          parentCandidate = ancestor;
20884
          ancestors = ancestors.slice(1);
20885
        } else if (!siblings) {
20886
          return elm;
20887
        }
20888
        const parent = parentCandidate ? createElement(parentCandidate) : dom.create('div');
20889
        parent.appendChild(elm);
20890
        if (siblings) {
20891
          Tools.each(siblings, sibling => {
20892
            const siblingElm = createElement(sibling);
20893
            parent.insertBefore(siblingElm, elm);
20894
          });
20895
        }
20896
        const parentSiblings = isPreviewItem(parentCandidate) ? parentCandidate.siblings : undefined;
20897
        return wrapInHtml(parent, ancestors, parentSiblings);
20898
      };
20899
      const fragment = dom.create('div');
20900
      if (ancestry.length > 0) {
20901
        const item = ancestry[0];
20902
        const elm = createElement(item);
20903
        const siblings = isPreviewItem(item) ? item.siblings : undefined;
20904
        fragment.appendChild(wrapInHtml(elm, ancestry.slice(1), siblings));
20905
      }
20906
      return fragment;
20907
    };
20908
    const parseSelectorItem = item => {
20909
      item = Tools.trim(item);
20910
      let tagName = 'div';
20911
      const obj = {
20912
        name: tagName,
20913
        classes: [],
20914
        attrs: {},
20915
        selector: item
20916
      };
20917
      if (item !== '*') {
20918
        tagName = item.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g, ($0, $1, $2, $3, $4) => {
20919
          switch ($1) {
20920
          case '#':
20921
            obj.attrs.id = $2;
20922
            break;
20923
          case '.':
20924
            obj.classes.push($2);
20925
            break;
20926
          case ':':
20927
            if (Tools.inArray('checked disabled enabled read-only required'.split(' '), $2) !== -1) {
20928
              obj.attrs[$2] = $2;
20929
            }
20930
            break;
20931
          }
20932
          if ($3 === '[') {
20933
            const m = $4.match(/([\w\-]+)(?:\=\"([^\"]+))?/);
20934
            if (m) {
20935
              obj.attrs[m[1]] = m[2];
20936
            }
20937
          }
20938
          return '';
20939
        });
20940
      }
20941
      obj.name = tagName || 'div';
20942
      return obj;
20943
    };
20944
    const parseSelector = selector => {
20945
      if (!isString(selector)) {
20946
        return [];
20947
      }
20948
      selector = selector.split(/\s*,\s*/)[0];
20949
      selector = selector.replace(/\s*(~\+|~|\+|>)\s*/g, '$1');
20950
      return Tools.map(selector.split(/(?:>|\s+(?![^\[\]]+\]))/), item => {
20951
        const siblings = Tools.map(item.split(/(?:~\+|~|\+)/), parseSelectorItem);
20952
        const obj = siblings.pop();
20953
        if (siblings.length) {
20954
          obj.siblings = siblings;
20955
        }
20956
        return obj;
20957
      }).reverse();
20958
    };
20959
    const getCssText = (editor, format) => {
20960
      let previewCss = '';
20961
      let previewStyles = getPreviewStyles(editor);
20962
      if (previewStyles === '') {
20963
        return '';
20964
      }
20965
      const removeVars = val => {
20966
        return isString(val) ? val.replace(/%(\w+)/g, '') : '';
20967
      };
20968
      const getComputedStyle = (name, elm) => {
20969
        return dom.getStyle(elm !== null && elm !== void 0 ? elm : editor.getBody(), name, true);
20970
      };
20971
      if (isString(format)) {
20972
        const formats = editor.formatter.get(format);
20973
        if (!formats) {
20974
          return '';
20975
        }
20976
        format = formats[0];
20977
      }
20978
      if ('preview' in format) {
20979
        const preview = format.preview;
20980
        if (preview === false) {
20981
          return '';
20982
        } else {
20983
          previewStyles = preview || previewStyles;
20984
        }
20985
      }
20986
      let name = format.block || format.inline || 'span';
20987
      let previewFrag;
20988
      const items = parseSelector(format.selector);
20989
      if (items.length > 0) {
20990
        if (!items[0].name) {
20991
          items[0].name = name;
20992
        }
20993
        name = format.selector;
20994
        previewFrag = parsedSelectorToHtml(items, editor);
20995
      } else {
20996
        previewFrag = parsedSelectorToHtml([name], editor);
20997
      }
20998
      const previewElm = dom.select(name, previewFrag)[0] || previewFrag.firstChild;
20999
      each$3(format.styles, (value, name) => {
21000
        const newValue = removeVars(value);
21001
        if (newValue) {
21002
          dom.setStyle(previewElm, name, newValue);
21003
        }
21004
      });
21005
      each$3(format.attributes, (value, name) => {
21006
        const newValue = removeVars(value);
21007
        if (newValue) {
21008
          dom.setAttrib(previewElm, name, newValue);
21009
        }
21010
      });
21011
      each$3(format.classes, value => {
21012
        const newValue = removeVars(value);
21013
        if (!dom.hasClass(previewElm, newValue)) {
21014
          dom.addClass(previewElm, newValue);
21015
        }
21016
      });
21017
      editor.dispatch('PreviewFormats');
21018
      dom.setStyles(previewFrag, {
21019
        position: 'absolute',
21020
        left: -65535
21021
      });
21022
      editor.getBody().appendChild(previewFrag);
21023
      const rawParentFontSize = getComputedStyle('fontSize');
21024
      const parentFontSize = /px$/.test(rawParentFontSize) ? parseInt(rawParentFontSize, 10) : 0;
21025
      each$3(previewStyles.split(' '), name => {
21026
        let value = getComputedStyle(name, previewElm);
21027
        if (name === 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
21028
          value = getComputedStyle(name);
21029
          if (rgbaToHexString(value).toLowerCase() === '#ffffff') {
21030
            return;
21031
          }
21032
        }
21033
        if (name === 'color') {
21034
          if (rgbaToHexString(value).toLowerCase() === '#000000') {
21035
            return;
21036
          }
21037
        }
21038
        if (name === 'font-size') {
21039
          if (/em|%$/.test(value)) {
21040
            if (parentFontSize === 0) {
21041
              return;
21042
            }
21043
            const numValue = parseFloat(value) / (/%$/.test(value) ? 100 : 1);
21044
            value = numValue * parentFontSize + 'px';
21045
          }
21046
        }
21047
        if (name === 'border' && value) {
21048
          previewCss += 'padding:0 2px;';
21049
        }
21050
        previewCss += name + ':' + value + ';';
21051
      });
21052
      editor.dispatch('AfterPreviewFormats');
21053
      dom.remove(previewFrag);
21054
      return previewCss;
21055
    };
21056
 
21057
    const setup$s = editor => {
21058
      editor.addShortcut('meta+b', '', 'Bold');
21059
      editor.addShortcut('meta+i', '', 'Italic');
21060
      editor.addShortcut('meta+u', '', 'Underline');
21061
      for (let i = 1; i <= 6; i++) {
21062
        editor.addShortcut('access+' + i, '', [
21063
          'FormatBlock',
21064
          false,
21065
          'h' + i
21066
        ]);
21067
      }
21068
      editor.addShortcut('access+7', '', [
21069
        'FormatBlock',
21070
        false,
21071
        'p'
21072
      ]);
21073
      editor.addShortcut('access+8', '', [
21074
        'FormatBlock',
21075
        false,
21076
        'div'
21077
      ]);
21078
      editor.addShortcut('access+9', '', [
21079
        'FormatBlock',
21080
        false,
21081
        'address'
21082
      ]);
21083
    };
21084
 
21085
    const Formatter = editor => {
21086
      const formats = FormatRegistry(editor);
21087
      const formatChangeState = Cell({});
21088
      setup$s(editor);
21089
      setup$v(editor);
21090
      if (!isRtc(editor)) {
21091
        setup$u(formatChangeState, editor);
21092
      }
21093
      return {
21094
        get: formats.get,
21095
        has: formats.has,
21096
        register: formats.register,
21097
        unregister: formats.unregister,
21098
        apply: (name, vars, node) => {
21099
          applyFormat(editor, name, vars, node);
21100
        },
21101
        remove: (name, vars, node, similar) => {
21102
          removeFormat(editor, name, vars, node, similar);
21103
        },
21104
        toggle: (name, vars, node) => {
21105
          toggleFormat(editor, name, vars, node);
21106
        },
21107
        match: (name, vars, node, similar) => matchFormat(editor, name, vars, node, similar),
21108
        closest: names => closestFormat(editor, names),
21109
        matchAll: (names, vars) => matchAllFormats(editor, names, vars),
21110
        matchNode: (node, name, vars, similar) => matchNodeFormat(editor, node, name, vars, similar),
21111
        canApply: name => canApplyFormat(editor, name),
21112
        formatChanged: (formats, callback, similar, vars) => formatChanged(editor, formatChangeState, formats, callback, similar, vars),
21113
        getCssText: curry(getCssText, editor)
21114
      };
21115
    };
21116
 
21117
    const shouldIgnoreCommand = cmd => {
21118
      switch (cmd.toLowerCase()) {
21119
      case 'undo':
21120
      case 'redo':
21121
      case 'mcefocus':
21122
        return true;
21123
      default:
21124
        return false;
21125
      }
21126
    };
21127
    const registerEvents = (editor, undoManager, locks) => {
21128
      const isFirstTypedCharacter = Cell(false);
21129
      const addNonTypingUndoLevel = e => {
21130
        setTyping(undoManager, false, locks);
21131
        undoManager.add({}, e);
21132
      };
21133
      editor.on('init', () => {
21134
        undoManager.add();
21135
      });
21136
      editor.on('BeforeExecCommand', e => {
21137
        const cmd = e.command;
21138
        if (!shouldIgnoreCommand(cmd)) {
21139
          endTyping(undoManager, locks);
21140
          undoManager.beforeChange();
21141
        }
21142
      });
21143
      editor.on('ExecCommand', e => {
21144
        const cmd = e.command;
21145
        if (!shouldIgnoreCommand(cmd)) {
21146
          addNonTypingUndoLevel(e);
21147
        }
21148
      });
21149
      editor.on('ObjectResizeStart cut', () => {
21150
        undoManager.beforeChange();
21151
      });
21152
      editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
21153
      editor.on('dragend', addNonTypingUndoLevel);
21154
      editor.on('keyup', e => {
21155
        const keyCode = e.keyCode;
21156
        if (e.isDefaultPrevented()) {
21157
          return;
21158
        }
21159
        const isMeta = Env.os.isMacOS() && e.key === 'Meta';
21160
        if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45 || e.ctrlKey || isMeta) {
21161
          addNonTypingUndoLevel();
21162
          editor.nodeChanged();
21163
        }
21164
        if (keyCode === 46 || keyCode === 8) {
21165
          editor.nodeChanged();
21166
        }
21167
        if (isFirstTypedCharacter.get() && undoManager.typing && !isEq$1(createFromEditor(editor), undoManager.data[0])) {
21168
          if (!editor.isDirty()) {
21169
            editor.setDirty(true);
21170
          }
21171
          editor.dispatch('TypingUndo');
21172
          isFirstTypedCharacter.set(false);
21173
          editor.nodeChanged();
21174
        }
21175
      });
21176
      editor.on('keydown', e => {
21177
        const keyCode = e.keyCode;
21178
        if (e.isDefaultPrevented()) {
21179
          return;
21180
        }
21181
        if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45) {
21182
          if (undoManager.typing) {
21183
            addNonTypingUndoLevel(e);
21184
          }
21185
          return;
21186
        }
21187
        const modKey = e.ctrlKey && !e.altKey || e.metaKey;
21188
        if ((keyCode < 16 || keyCode > 20) && keyCode !== 224 && keyCode !== 91 && !undoManager.typing && !modKey) {
21189
          undoManager.beforeChange();
21190
          setTyping(undoManager, true, locks);
21191
          undoManager.add({}, e);
21192
          isFirstTypedCharacter.set(true);
21193
          return;
21194
        }
21195
        const hasOnlyMetaOrCtrlModifier = Env.os.isMacOS() ? e.metaKey : e.ctrlKey && !e.altKey;
21196
        if (hasOnlyMetaOrCtrlModifier) {
21197
          undoManager.beforeChange();
21198
        }
21199
      });
21200
      editor.on('mousedown', e => {
21201
        if (undoManager.typing) {
21202
          addNonTypingUndoLevel(e);
21203
        }
21204
      });
21205
      const isInsertReplacementText = event => event.inputType === 'insertReplacementText';
21206
      const isInsertTextDataNull = event => event.inputType === 'insertText' && event.data === null;
21207
      const isInsertFromPasteOrDrop = event => event.inputType === 'insertFromPaste' || event.inputType === 'insertFromDrop';
21208
      editor.on('input', e => {
21209
        if (e.inputType && (isInsertReplacementText(e) || isInsertTextDataNull(e) || isInsertFromPasteOrDrop(e))) {
21210
          addNonTypingUndoLevel(e);
21211
        }
21212
      });
21213
      editor.on('AddUndo Undo Redo ClearUndos', e => {
21214
        if (!e.isDefaultPrevented()) {
21215
          editor.nodeChanged();
21216
        }
21217
      });
21218
    };
21219
    const addKeyboardShortcuts = editor => {
21220
      editor.addShortcut('meta+z', '', 'Undo');
21221
      editor.addShortcut('meta+y,meta+shift+z', '', 'Redo');
21222
    };
21223
 
21224
    const UndoManager = editor => {
21225
      const beforeBookmark = value$2();
21226
      const locks = Cell(0);
21227
      const index = Cell(0);
21228
      const undoManager = {
21229
        data: [],
21230
        typing: false,
21231
        beforeChange: () => {
21232
          beforeChange(editor, locks, beforeBookmark);
21233
        },
21234
        add: (level, event) => {
21235
          return addUndoLevel(editor, undoManager, index, locks, beforeBookmark, level, event);
21236
        },
21237
        dispatchChange: () => {
21238
          editor.setDirty(true);
21239
          const level = createFromEditor(editor);
21240
          level.bookmark = getUndoBookmark(editor.selection);
21241
          editor.dispatch('change', {
21242
            level,
21243
            lastLevel: get$b(undoManager.data, index.get()).getOrUndefined()
21244
          });
21245
        },
21246
        undo: () => {
21247
          return undo(editor, undoManager, locks, index);
21248
        },
21249
        redo: () => {
21250
          return redo(editor, index, undoManager.data);
21251
        },
21252
        clear: () => {
21253
          clear(editor, undoManager, index);
21254
        },
21255
        reset: () => {
21256
          reset(editor, undoManager);
21257
        },
21258
        hasUndo: () => {
21259
          return hasUndo(editor, undoManager, index);
21260
        },
21261
        hasRedo: () => {
21262
          return hasRedo(editor, undoManager, index);
21263
        },
21264
        transact: callback => {
21265
          return transact(editor, undoManager, locks, callback);
21266
        },
21267
        ignore: callback => {
21268
          ignore(editor, locks, callback);
21269
        },
21270
        extra: (callback1, callback2) => {
21271
          extra(editor, undoManager, index, callback1, callback2);
21272
        }
21273
      };
21274
      if (!isRtc(editor)) {
21275
        registerEvents(editor, undoManager, locks);
21276
      }
21277
      addKeyboardShortcuts(editor);
21278
      return undoManager;
21279
    };
21280
 
21281
    const nonTypingKeycodes = [
21282
      9,
21283
      27,
21284
      VK.HOME,
21285
      VK.END,
21286
      19,
21287
      20,
21288
      44,
21289
      144,
21290
      145,
21291
      33,
21292
      34,
21293
      45,
21294
      16,
21295
      17,
21296
      18,
21297
      91,
21298
      92,
21299
      93,
21300
      VK.DOWN,
21301
      VK.UP,
21302
      VK.LEFT,
21303
      VK.RIGHT
21304
    ].concat(Env.browser.isFirefox() ? [224] : []);
21305
    const placeholderAttr = 'data-mce-placeholder';
21306
    const isKeyboardEvent = e => e.type === 'keydown' || e.type === 'keyup';
21307
    const isDeleteEvent = e => {
21308
      const keyCode = e.keyCode;
21309
      return keyCode === VK.BACKSPACE || keyCode === VK.DELETE;
21310
    };
21311
    const isNonTypingKeyboardEvent = e => {
21312
      if (isKeyboardEvent(e)) {
21313
        const keyCode = e.keyCode;
21314
        return !isDeleteEvent(e) && (VK.metaKeyPressed(e) || e.altKey || keyCode >= 112 && keyCode <= 123 || contains$2(nonTypingKeycodes, keyCode));
21315
      } else {
21316
        return false;
21317
      }
21318
    };
21319
    const isTypingKeyboardEvent = e => isKeyboardEvent(e) && !(isDeleteEvent(e) || e.type === 'keyup' && e.keyCode === 229);
21320
    const isVisuallyEmpty = (dom, rootElm, forcedRootBlock) => {
1441 ariadna 21321
      if (dom.isEmpty(rootElm, undefined, {
21322
          skipBogus: false,
21323
          includeZwsp: true
21324
        })) {
1 efrain 21325
        const firstElement = rootElm.firstElementChild;
21326
        if (!firstElement) {
21327
          return true;
21328
        } else if (dom.getStyle(rootElm.firstElementChild, 'padding-left') || dom.getStyle(rootElm.firstElementChild, 'padding-right')) {
21329
          return false;
21330
        } else {
21331
          return forcedRootBlock === firstElement.nodeName.toLowerCase();
21332
        }
21333
      } else {
21334
        return false;
21335
      }
21336
    };
21337
    const setup$r = editor => {
21338
      var _a;
21339
      const dom = editor.dom;
21340
      const rootBlock = getForcedRootBlock(editor);
21341
      const placeholder = (_a = getPlaceholder(editor)) !== null && _a !== void 0 ? _a : '';
21342
      const updatePlaceholder = (e, initial) => {
21343
        if (isNonTypingKeyboardEvent(e)) {
21344
          return;
21345
        }
21346
        const body = editor.getBody();
21347
        const showPlaceholder = isTypingKeyboardEvent(e) ? false : isVisuallyEmpty(dom, body, rootBlock);
21348
        const isPlaceholderShown = dom.getAttrib(body, placeholderAttr) !== '';
21349
        if (isPlaceholderShown !== showPlaceholder || initial) {
21350
          dom.setAttrib(body, placeholderAttr, showPlaceholder ? placeholder : null);
21351
          firePlaceholderToggle(editor, showPlaceholder);
21352
          editor.on(showPlaceholder ? 'keydown' : 'keyup', updatePlaceholder);
21353
          editor.off(showPlaceholder ? 'keyup' : 'keydown', updatePlaceholder);
21354
        }
21355
      };
21356
      if (isNotEmpty(placeholder)) {
21357
        editor.on('init', e => {
21358
          updatePlaceholder(e, true);
21359
          editor.on('change SetContent ExecCommand', updatePlaceholder);
21360
          editor.on('paste', e => Delay.setEditorTimeout(editor, () => updatePlaceholder(e)));
21361
        });
21362
      }
21363
    };
21364
 
21365
    const blockPosition = (block, position) => ({
21366
      block,
21367
      position
21368
    });
21369
    const blockBoundary = (from, to) => ({
21370
      from,
21371
      to
21372
    });
21373
    const getBlockPosition = (rootNode, pos) => {
21374
      const rootElm = SugarElement.fromDom(rootNode);
21375
      const containerElm = SugarElement.fromDom(pos.container());
21376
      return getParentBlock$2(rootElm, containerElm).map(block => blockPosition(block, pos));
21377
    };
1441 ariadna 21378
    const isNotAncestorial = blockBoundary => !(contains(blockBoundary.to.block, blockBoundary.from.block) || contains(blockBoundary.from.block, blockBoundary.to.block));
1 efrain 21379
    const isDifferentBlocks = blockBoundary => !eq(blockBoundary.from.block, blockBoundary.to.block);
21380
    const getClosestHost = (root, scope) => {
21381
      const isRoot = node => eq(node, root);
21382
      const isHost = node => isTableCell$2(node) || isContentEditableTrue$3(node.dom);
21383
      return closest$4(scope, isHost, isRoot).filter(isElement$7).getOr(root);
21384
    };
21385
    const hasSameHost = (rootNode, blockBoundary) => {
21386
      const root = SugarElement.fromDom(rootNode);
21387
      return eq(getClosestHost(root, blockBoundary.from.block), getClosestHost(root, blockBoundary.to.block));
21388
    };
21389
    const isEditable$1 = blockBoundary => isContentEditableFalse$b(blockBoundary.from.block.dom) === false && isContentEditableFalse$b(blockBoundary.to.block.dom) === false;
21390
    const hasValidBlocks = blockBoundary => {
1441 ariadna 21391
      const isValidBlock = block => isTextBlock$2(block) || hasBlockAttr(block.dom) || isListItem$1(block);
1 efrain 21392
      return isValidBlock(blockBoundary.from.block) && isValidBlock(blockBoundary.to.block);
21393
    };
1441 ariadna 21394
    const skipLastBr = (schema, rootNode, forward, blockPosition) => {
21395
      if (isBr$6(blockPosition.position.getNode()) && !isEmpty$2(schema, blockPosition.block)) {
1 efrain 21396
        return positionIn(false, blockPosition.block.dom).bind(lastPositionInBlock => {
21397
          if (lastPositionInBlock.isEqual(blockPosition.position)) {
21398
            return fromPosition(forward, rootNode, lastPositionInBlock).bind(to => getBlockPosition(rootNode, to));
21399
          } else {
21400
            return Optional.some(blockPosition);
21401
          }
21402
        }).getOr(blockPosition);
21403
      } else {
21404
        return blockPosition;
21405
      }
21406
    };
1441 ariadna 21407
    const readFromRange = (schema, rootNode, forward, rng) => {
1 efrain 21408
      const fromBlockPos = getBlockPosition(rootNode, CaretPosition.fromRangeStart(rng));
1441 ariadna 21409
      const toBlockPos = fromBlockPos.bind(blockPos => fromPosition(forward, rootNode, blockPos.position).bind(to => getBlockPosition(rootNode, to).map(blockPos => skipLastBr(schema, rootNode, forward, blockPos))));
21410
      return lift2(fromBlockPos, toBlockPos, blockBoundary).filter(blockBoundary => isDifferentBlocks(blockBoundary) && hasSameHost(rootNode, blockBoundary) && isEditable$1(blockBoundary) && hasValidBlocks(blockBoundary) && isNotAncestorial(blockBoundary));
1 efrain 21411
    };
1441 ariadna 21412
    const read$1 = (schema, rootNode, forward, rng) => rng.collapsed ? readFromRange(schema, rootNode, forward, rng) : Optional.none();
1 efrain 21413
 
21414
    const getChildrenUntilBlockBoundary = (block, schema) => {
21415
      const children = children$1(block);
21416
      return findIndex$2(children, el => schema.isBlock(name(el))).fold(constant(children), index => children.slice(0, index));
21417
    };
21418
    const extractChildren = (block, schema) => {
21419
      const children = getChildrenUntilBlockBoundary(block, schema);
1441 ariadna 21420
      each$e(children, remove$4);
1 efrain 21421
      return children;
21422
    };
1441 ariadna 21423
    const removeEmptyRoot = (schema, rootNode, block) => {
1 efrain 21424
      const parents = parentsAndSelf(block, rootNode);
1441 ariadna 21425
      return find$2(parents.reverse(), element => isEmpty$2(schema, element)).each(remove$4);
1 efrain 21426
    };
1441 ariadna 21427
    const isEmptyBefore = (schema, el) => filter$5(prevSiblings(el), el => !isEmpty$2(schema, el)).length === 0;
1 efrain 21428
    const nestedBlockMerge = (rootNode, fromBlock, toBlock, schema, insertionPoint) => {
1441 ariadna 21429
      if (isEmpty$2(schema, toBlock)) {
1 efrain 21430
        fillWithPaddingBr(toBlock);
21431
        return firstPositionIn(toBlock.dom);
21432
      }
1441 ariadna 21433
      if (isEmptyBefore(schema, insertionPoint) && isEmpty$2(schema, fromBlock)) {
1 efrain 21434
        before$3(insertionPoint, SugarElement.fromTag('br'));
21435
      }
21436
      const position = prevPosition(toBlock.dom, CaretPosition.before(insertionPoint.dom));
21437
      each$e(extractChildren(fromBlock, schema), child => {
21438
        before$3(insertionPoint, child);
21439
      });
1441 ariadna 21440
      removeEmptyRoot(schema, rootNode, fromBlock);
1 efrain 21441
      return position;
21442
    };
21443
    const isInline = (schema, node) => schema.isInline(name(node));
21444
    const sidelongBlockMerge = (rootNode, fromBlock, toBlock, schema) => {
1441 ariadna 21445
      if (isEmpty$2(schema, toBlock)) {
21446
        if (isEmpty$2(schema, fromBlock)) {
1 efrain 21447
          const getInlineToBlockDescendants = el => {
21448
            const helper = (node, elements) => firstChild(node).fold(() => elements, child => isInline(schema, child) ? helper(child, elements.concat(shallow$1(child))) : elements);
21449
            return helper(el, []);
21450
          };
21451
          const newFromBlockDescendants = foldr(getInlineToBlockDescendants(toBlock), (element, descendant) => {
21452
            wrap$2(element, descendant);
21453
            return descendant;
21454
          }, createPaddingBr());
21455
          empty(fromBlock);
21456
          append$1(fromBlock, newFromBlockDescendants);
21457
        }
1441 ariadna 21458
        remove$4(toBlock);
1 efrain 21459
        return firstPositionIn(fromBlock.dom);
21460
      }
21461
      const position = lastPositionIn(toBlock.dom);
21462
      each$e(extractChildren(fromBlock, schema), child => {
21463
        append$1(toBlock, child);
21464
      });
1441 ariadna 21465
      removeEmptyRoot(schema, rootNode, fromBlock);
1 efrain 21466
      return position;
21467
    };
21468
    const findInsertionPoint = (toBlock, block) => {
21469
      const parentsAndSelf$1 = parentsAndSelf(block, toBlock);
21470
      return Optional.from(parentsAndSelf$1[parentsAndSelf$1.length - 1]);
21471
    };
21472
    const getInsertionPoint = (fromBlock, toBlock) => contains(toBlock, fromBlock) ? findInsertionPoint(toBlock, fromBlock) : Optional.none();
21473
    const trimBr = (first, block) => {
1441 ariadna 21474
      positionIn(first, block.dom).bind(position => Optional.from(position.getNode())).map(SugarElement.fromDom).filter(isBr$5).each(remove$4);
1 efrain 21475
    };
21476
    const mergeBlockInto = (rootNode, fromBlock, toBlock, schema) => {
21477
      trimBr(true, fromBlock);
21478
      trimBr(false, toBlock);
21479
      return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock, schema), curry(nestedBlockMerge, rootNode, fromBlock, toBlock, schema));
21480
    };
21481
    const mergeBlocks = (rootNode, forward, block1, block2, schema) => forward ? mergeBlockInto(rootNode, block2, block1, schema) : mergeBlockInto(rootNode, block1, block2, schema);
21482
 
1441 ariadna 21483
    const backspaceDelete$a = (editor, forward) => {
1 efrain 21484
      const rootNode = SugarElement.fromDom(editor.getBody());
1441 ariadna 21485
      const position = read$1(editor.schema, rootNode.dom, forward, editor.selection.getRng()).map(blockBoundary => () => {
1 efrain 21486
        mergeBlocks(rootNode, forward, blockBoundary.from.block, blockBoundary.to.block, editor.schema).each(pos => {
21487
          editor.selection.setRng(pos.toRange());
21488
        });
21489
      });
21490
      return position;
21491
    };
21492
 
21493
    const deleteRangeMergeBlocks = (rootNode, selection, schema) => {
21494
      const rng = selection.getRng();
21495
      return lift2(getParentBlock$2(rootNode, SugarElement.fromDom(rng.startContainer)), getParentBlock$2(rootNode, SugarElement.fromDom(rng.endContainer)), (block1, block2) => {
21496
        if (!eq(block1, block2)) {
21497
          return Optional.some(() => {
21498
            rng.deleteContents();
21499
            mergeBlocks(rootNode, true, block1, block2, schema).each(pos => {
21500
              selection.setRng(pos.toRange());
21501
            });
21502
          });
21503
        } else {
21504
          return Optional.none();
21505
        }
21506
      }).getOr(Optional.none());
21507
    };
21508
    const isRawNodeInTable = (root, rawNode) => {
21509
      const node = SugarElement.fromDom(rawNode);
21510
      const isRoot = curry(eq, root);
21511
      return ancestor$4(node, isTableCell$2, isRoot).isSome();
21512
    };
21513
    const isSelectionInTable = (root, rng) => isRawNodeInTable(root, rng.startContainer) || isRawNodeInTable(root, rng.endContainer);
21514
    const isEverythingSelected = (root, rng) => {
21515
      const noPrevious = prevPosition(root.dom, CaretPosition.fromRangeStart(rng)).isNone();
21516
      const noNext = nextPosition(root.dom, CaretPosition.fromRangeEnd(rng)).isNone();
21517
      return !isSelectionInTable(root, rng) && noPrevious && noNext;
21518
    };
21519
    const emptyEditor = editor => {
21520
      return Optional.some(() => {
21521
        editor.setContent('');
21522
        editor.selection.setCursorLocation();
21523
      });
21524
    };
21525
    const deleteRange$2 = editor => {
21526
      const rootNode = SugarElement.fromDom(editor.getBody());
21527
      const rng = editor.selection.getRng();
21528
      return isEverythingSelected(rootNode, rng) ? emptyEditor(editor) : deleteRangeMergeBlocks(rootNode, editor.selection, editor.schema);
21529
    };
1441 ariadna 21530
    const backspaceDelete$9 = (editor, _forward) => editor.selection.isCollapsed() ? Optional.none() : deleteRange$2(editor);
1 efrain 21531
 
21532
    const showCaret = (direction, editor, node, before, scrollIntoView) => Optional.from(editor._selectionOverrides.showCaret(direction, node, before, scrollIntoView));
21533
    const getNodeRange = node => {
21534
      const rng = node.ownerDocument.createRange();
21535
      rng.selectNode(node);
21536
      return rng;
21537
    };
21538
    const selectNode = (editor, node) => {
21539
      const e = editor.dispatch('BeforeObjectSelected', { target: node });
21540
      if (e.isDefaultPrevented()) {
21541
        return Optional.none();
21542
      }
21543
      return Optional.some(getNodeRange(node));
21544
    };
21545
    const renderCaretAtRange = (editor, range, scrollIntoView) => {
21546
      const normalizedRange = normalizeRange(1, editor.getBody(), range);
21547
      const caretPosition = CaretPosition.fromRangeStart(normalizedRange);
21548
      const caretPositionNode = caretPosition.getNode();
21549
      if (isInlineFakeCaretTarget(caretPositionNode)) {
21550
        return showCaret(1, editor, caretPositionNode, !caretPosition.isAtEnd(), false);
21551
      }
21552
      const caretPositionBeforeNode = caretPosition.getNode(true);
21553
      if (isInlineFakeCaretTarget(caretPositionBeforeNode)) {
21554
        return showCaret(1, editor, caretPositionBeforeNode, false, false);
21555
      }
21556
      const ceRoot = getContentEditableRoot$1(editor.dom.getRoot(), caretPosition.getNode());
21557
      if (isInlineFakeCaretTarget(ceRoot)) {
21558
        return showCaret(1, editor, ceRoot, false, scrollIntoView);
21559
      }
21560
      return Optional.none();
21561
    };
21562
    const renderRangeCaret = (editor, range, scrollIntoView) => range.collapsed ? renderCaretAtRange(editor, range, scrollIntoView).getOr(range) : range;
21563
 
21564
    const isBeforeBoundary = pos => isBeforeContentEditableFalse(pos) || isBeforeMedia(pos);
21565
    const isAfterBoundary = pos => isAfterContentEditableFalse(pos) || isAfterMedia(pos);
21566
    const trimEmptyTextNode = (dom, node) => {
1441 ariadna 21567
      if (isText$b(node) && node.data.length === 0) {
1 efrain 21568
        dom.remove(node);
21569
      }
21570
    };
21571
    const deleteContentAndShowCaret = (editor, range, node, direction, forward, peekCaretPosition) => {
21572
      showCaret(direction, editor, peekCaretPosition.getNode(!forward), forward, true).each(caretRange => {
21573
        if (range.collapsed) {
21574
          const deleteRange = range.cloneRange();
21575
          if (forward) {
21576
            deleteRange.setEnd(caretRange.startContainer, caretRange.startOffset);
21577
          } else {
21578
            deleteRange.setStart(caretRange.endContainer, caretRange.endOffset);
21579
          }
21580
          deleteRange.deleteContents();
21581
        } else {
21582
          range.deleteContents();
21583
        }
21584
        editor.selection.setRng(caretRange);
21585
      });
21586
      trimEmptyTextNode(editor.dom, node);
21587
    };
21588
    const deleteBoundaryText = (editor, forward) => {
21589
      const range = editor.selection.getRng();
1441 ariadna 21590
      if (!isText$b(range.commonAncestorContainer)) {
1 efrain 21591
        return Optional.none();
21592
      }
1441 ariadna 21593
      const direction = forward ? 1 : -1;
1 efrain 21594
      const caretWalker = CaretWalker(editor.getBody());
21595
      const getNextPosFn = curry(getVisualCaretPosition, forward ? caretWalker.next : caretWalker.prev);
21596
      const isBeforeFn = forward ? isBeforeBoundary : isAfterBoundary;
21597
      const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
21598
      const nextCaretPosition = getNextPosFn(caretPosition);
21599
      const normalizedNextCaretPosition = nextCaretPosition ? normalizePosition(forward, nextCaretPosition) : nextCaretPosition;
21600
      if (!normalizedNextCaretPosition || !isMoveInsideSameBlock(caretPosition, normalizedNextCaretPosition)) {
21601
        return Optional.none();
21602
      } else if (isBeforeFn(normalizedNextCaretPosition)) {
21603
        return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, normalizedNextCaretPosition));
21604
      }
21605
      const peekCaretPosition = getNextPosFn(normalizedNextCaretPosition);
21606
      if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
21607
        if (isMoveInsideSameBlock(normalizedNextCaretPosition, peekCaretPosition)) {
21608
          return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, peekCaretPosition));
21609
        }
21610
      }
21611
      return Optional.none();
21612
    };
1441 ariadna 21613
    const backspaceDelete$8 = (editor, forward) => deleteBoundaryText(editor, forward);
1 efrain 21614
 
21615
    const getEdgeCefPosition = (editor, atStart) => {
21616
      const root = editor.getBody();
21617
      return atStart ? firstPositionIn(root).filter(isBeforeContentEditableFalse) : lastPositionIn(root).filter(isAfterContentEditableFalse);
21618
    };
21619
    const isCefAtEdgeSelected = editor => {
21620
      const rng = editor.selection.getRng();
21621
      return !rng.collapsed && (getEdgeCefPosition(editor, true).exists(pos => pos.isEqual(CaretPosition.fromRangeStart(rng))) || getEdgeCefPosition(editor, false).exists(pos => pos.isEqual(CaretPosition.fromRangeEnd(rng))));
21622
    };
21623
 
21624
    const isCompoundElement = node => isNonNullable(node) && (isTableCell$2(SugarElement.fromDom(node)) || isListItem$1(SugarElement.fromDom(node)));
21625
    const DeleteAction = Adt.generate([
21626
      { remove: ['element'] },
21627
      { moveToElement: ['element'] },
21628
      { moveToPosition: ['position'] }
21629
    ]);
21630
    const isAtContentEditableBlockCaret = (forward, from) => {
21631
      const elm = from.getNode(!forward);
21632
      const caretLocation = forward ? 'after' : 'before';
21633
      return isElement$6(elm) && elm.getAttribute('data-mce-caret') === caretLocation;
21634
    };
21635
    const isDeleteFromCefDifferentBlocks = (root, forward, from, to, schema) => {
21636
      const inSameBlock = elm => schema.isInline(elm.nodeName.toLowerCase()) && !isInSameBlock(from, to, root);
21637
      return getRelativeCefElm(!forward, from).fold(() => getRelativeCefElm(forward, to).fold(never, inSameBlock), inSameBlock);
21638
    };
1441 ariadna 21639
    const deleteEmptyBlockOrMoveToCef = (schema, root, forward, from, to) => {
1 efrain 21640
      const toCefElm = to.getNode(!forward);
1441 ariadna 21641
      return getParentBlock$2(SugarElement.fromDom(root), SugarElement.fromDom(from.getNode())).map(blockElm => isEmpty$2(schema, blockElm) ? DeleteAction.remove(blockElm.dom) : DeleteAction.moveToElement(toCefElm)).orThunk(() => Optional.some(DeleteAction.moveToElement(toCefElm)));
1 efrain 21642
    };
21643
    const findCefPosition = (root, forward, from, schema) => fromPosition(forward, root, from).bind(to => {
21644
      if (isCompoundElement(to.getNode())) {
21645
        return Optional.none();
21646
      } else if (isDeleteFromCefDifferentBlocks(root, forward, from, to, schema)) {
21647
        return Optional.none();
21648
      } else if (forward && isContentEditableFalse$b(to.getNode())) {
1441 ariadna 21649
        return deleteEmptyBlockOrMoveToCef(schema, root, forward, from, to);
1 efrain 21650
      } else if (!forward && isContentEditableFalse$b(to.getNode(true))) {
1441 ariadna 21651
        return deleteEmptyBlockOrMoveToCef(schema, root, forward, from, to);
1 efrain 21652
      } else if (forward && isAfterContentEditableFalse(from)) {
21653
        return Optional.some(DeleteAction.moveToPosition(to));
21654
      } else if (!forward && isBeforeContentEditableFalse(from)) {
21655
        return Optional.some(DeleteAction.moveToPosition(to));
21656
      } else {
21657
        return Optional.none();
21658
      }
21659
    });
21660
    const getContentEditableBlockAction = (forward, elm) => {
21661
      if (isNullable(elm)) {
21662
        return Optional.none();
21663
      } else if (forward && isContentEditableFalse$b(elm.nextSibling)) {
21664
        return Optional.some(DeleteAction.moveToElement(elm.nextSibling));
21665
      } else if (!forward && isContentEditableFalse$b(elm.previousSibling)) {
21666
        return Optional.some(DeleteAction.moveToElement(elm.previousSibling));
21667
      } else {
21668
        return Optional.none();
21669
      }
21670
    };
21671
    const skipMoveToActionFromInlineCefToContent = (root, from, deleteAction) => deleteAction.fold(elm => Optional.some(DeleteAction.remove(elm)), elm => Optional.some(DeleteAction.moveToElement(elm)), to => {
21672
      if (isInSameBlock(from, to, root)) {
21673
        return Optional.none();
21674
      } else {
21675
        return Optional.some(DeleteAction.moveToPosition(to));
21676
      }
21677
    });
21678
    const getContentEditableAction = (root, forward, from, schema) => {
21679
      if (isAtContentEditableBlockCaret(forward, from)) {
21680
        return getContentEditableBlockAction(forward, from.getNode(!forward)).orThunk(() => findCefPosition(root, forward, from, schema));
21681
      } else {
21682
        return findCefPosition(root, forward, from, schema).bind(deleteAction => skipMoveToActionFromInlineCefToContent(root, from, deleteAction));
21683
      }
21684
    };
21685
    const read = (root, forward, rng, schema) => {
21686
      const normalizedRange = normalizeRange(forward ? 1 : -1, root, rng);
21687
      const from = CaretPosition.fromRangeStart(normalizedRange);
21688
      const rootElement = SugarElement.fromDom(root);
21689
      if (!forward && isAfterContentEditableFalse(from)) {
21690
        return Optional.some(DeleteAction.remove(from.getNode(true)));
21691
      } else if (forward && isBeforeContentEditableFalse(from)) {
21692
        return Optional.some(DeleteAction.remove(from.getNode()));
21693
      } else if (!forward && isBeforeContentEditableFalse(from) && isAfterBr(rootElement, from, schema)) {
21694
        return findPreviousBr(rootElement, from, schema).map(br => DeleteAction.remove(br.getNode()));
21695
      } else if (forward && isAfterContentEditableFalse(from) && isBeforeBr$1(rootElement, from, schema)) {
21696
        return findNextBr(rootElement, from, schema).map(br => DeleteAction.remove(br.getNode()));
21697
      } else {
21698
        return getContentEditableAction(root, forward, from, schema);
21699
      }
21700
    };
21701
 
21702
    const deleteElement$1 = (editor, forward) => element => {
21703
      editor._selectionOverrides.hideFakeCaret();
21704
      deleteElement$2(editor, forward, SugarElement.fromDom(element));
21705
      return true;
21706
    };
21707
    const moveToElement = (editor, forward) => element => {
21708
      const pos = forward ? CaretPosition.before(element) : CaretPosition.after(element);
21709
      editor.selection.setRng(pos.toRange());
21710
      return true;
21711
    };
21712
    const moveToPosition = editor => pos => {
21713
      editor.selection.setRng(pos.toRange());
21714
      return true;
21715
    };
21716
    const getAncestorCe = (editor, node) => Optional.from(getContentEditableRoot$1(editor.getBody(), node));
21717
    const backspaceDeleteCaret = (editor, forward) => {
21718
      const selectedNode = editor.selection.getNode();
21719
      return getAncestorCe(editor, selectedNode).filter(isContentEditableFalse$b).fold(() => read(editor.getBody(), forward, editor.selection.getRng(), editor.schema).map(deleteAction => () => deleteAction.fold(deleteElement$1(editor, forward), moveToElement(editor, forward), moveToPosition(editor))), () => Optional.some(noop));
21720
    };
21721
    const deleteOffscreenSelection = rootElement => {
1441 ariadna 21722
      each$e(descendants(rootElement, '.mce-offscreen-selection'), remove$4);
1 efrain 21723
    };
21724
    const backspaceDeleteRange = (editor, forward) => {
21725
      const selectedNode = editor.selection.getNode();
21726
      if (isContentEditableFalse$b(selectedNode) && !isTableCell$3(selectedNode)) {
21727
        const hasCefAncestor = getAncestorCe(editor, selectedNode.parentNode).filter(isContentEditableFalse$b);
21728
        return hasCefAncestor.fold(() => Optional.some(() => {
21729
          deleteOffscreenSelection(SugarElement.fromDom(editor.getBody()));
21730
          deleteElement$2(editor, forward, SugarElement.fromDom(editor.selection.getNode()));
21731
          paddEmptyBody(editor);
21732
        }), () => Optional.some(noop));
21733
      }
21734
      if (isCefAtEdgeSelected(editor)) {
21735
        return Optional.some(() => {
21736
          deleteRangeContents(editor, editor.selection.getRng(), SugarElement.fromDom(editor.getBody()));
21737
        });
21738
      }
21739
      return Optional.none();
21740
    };
21741
    const paddEmptyElement = editor => {
21742
      const dom = editor.dom, selection = editor.selection;
21743
      const ceRoot = getContentEditableRoot$1(editor.getBody(), selection.getNode());
21744
      if (isContentEditableTrue$3(ceRoot) && dom.isBlock(ceRoot) && dom.isEmpty(ceRoot)) {
21745
        const br = dom.create('br', { 'data-mce-bogus': '1' });
21746
        dom.setHTML(ceRoot, '');
21747
        ceRoot.appendChild(br);
21748
        selection.setRng(CaretPosition.before(br).toRange());
21749
      }
21750
      return true;
21751
    };
1441 ariadna 21752
    const backspaceDelete$7 = (editor, forward) => {
1 efrain 21753
      if (editor.selection.isCollapsed()) {
21754
        return backspaceDeleteCaret(editor, forward);
21755
      } else {
21756
        return backspaceDeleteRange(editor, forward);
21757
      }
21758
    };
21759
 
1441 ariadna 21760
    const isTextEndpoint = endpoint => endpoint.hasOwnProperty('text');
21761
    const isElementEndpoint = endpoint => endpoint.hasOwnProperty('marker');
21762
    const getBookmark = (range, createMarker) => {
21763
      const getEndpoint = (container, offset) => {
21764
        if (isText$b(container)) {
21765
          return {
21766
            text: container,
21767
            offset
21768
          };
21769
        } else {
21770
          const marker = createMarker();
21771
          const children = container.childNodes;
21772
          if (offset < children.length) {
21773
            container.insertBefore(marker, children[offset]);
21774
            return {
21775
              marker,
21776
              before: true
21777
            };
21778
          } else {
21779
            container.appendChild(marker);
21780
            return {
21781
              marker,
21782
              before: false
21783
            };
21784
          }
21785
        }
21786
      };
21787
      const end = getEndpoint(range.endContainer, range.endOffset);
21788
      const start = getEndpoint(range.startContainer, range.startOffset);
21789
      return {
21790
        start,
21791
        end
21792
      };
21793
    };
21794
    const resolveBookmark = bm => {
21795
      var _a, _b;
21796
      const {start, end} = bm;
21797
      const rng = new window.Range();
21798
      if (isTextEndpoint(start)) {
21799
        rng.setStart(start.text, start.offset);
21800
      } else {
21801
        if (isElementEndpoint(start)) {
21802
          if (start.before) {
21803
            rng.setStartBefore(start.marker);
21804
          } else {
21805
            rng.setStartAfter(start.marker);
21806
          }
21807
          (_a = start.marker.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(start.marker);
21808
        }
21809
      }
21810
      if (isTextEndpoint(end)) {
21811
        rng.setEnd(end.text, end.offset);
21812
      } else {
21813
        if (isElementEndpoint(end)) {
21814
          if (end.before) {
21815
            rng.setEndBefore(end.marker);
21816
          } else {
21817
            rng.setEndAfter(end.marker);
21818
          }
21819
          (_b = end.marker.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(end.marker);
21820
        }
21821
      }
21822
      return rng;
21823
    };
21824
 
21825
    const backspaceDelete$6 = (editor, forward) => {
21826
      var _a;
21827
      const dom = editor.dom;
21828
      const startBlock = dom.getParent(editor.selection.getStart(), dom.isBlock);
21829
      const endBlock = dom.getParent(editor.selection.getEnd(), dom.isBlock);
21830
      const body = editor.getBody();
21831
      const startBlockName = (_a = startBlock === null || startBlock === void 0 ? void 0 : startBlock.nodeName) === null || _a === void 0 ? void 0 : _a.toLowerCase();
21832
      if (startBlockName === 'div' && startBlock && endBlock && startBlock === body.firstChild && endBlock === body.lastChild && !dom.isEmpty(body)) {
21833
        const wrapper = startBlock.cloneNode(false);
21834
        const deleteAction = () => {
21835
          if (forward) {
21836
            execNativeForwardDeleteCommand(editor);
21837
          } else {
21838
            execNativeDeleteCommand(editor);
21839
          }
21840
          if (body.firstChild !== startBlock) {
21841
            const bookmark = getBookmark(editor.selection.getRng(), () => document.createElement('span'));
21842
            Array.from(body.childNodes).forEach(node => wrapper.appendChild(node));
21843
            body.appendChild(wrapper);
21844
            editor.selection.setRng(resolveBookmark(bookmark));
21845
          }
21846
        };
21847
        return Optional.some(deleteAction);
21848
      }
21849
      return Optional.none();
21850
    };
21851
 
1 efrain 21852
    const deleteCaret$2 = (editor, forward) => {
21853
      const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
21854
      return fromPosition(forward, editor.getBody(), fromPos).filter(pos => forward ? isBeforeImageBlock(pos) : isAfterImageBlock(pos)).bind(pos => getChildNodeAtRelativeOffset(forward ? 0 : -1, pos)).map(elm => () => editor.selection.select(elm));
21855
    };
21856
    const backspaceDelete$5 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$2(editor, forward) : Optional.none();
21857
 
1441 ariadna 21858
    const isText$2 = isText$b;
1 efrain 21859
    const startsWithCaretContainer = node => isText$2(node) && node.data[0] === ZWSP$1;
21860
    const endsWithCaretContainer = node => isText$2(node) && node.data[node.data.length - 1] === ZWSP$1;
21861
    const createZwsp = node => {
21862
      var _a;
21863
      const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
21864
      return doc.createTextNode(ZWSP$1);
21865
    };
21866
    const insertBefore$1 = node => {
21867
      var _a;
21868
      if (isText$2(node.previousSibling)) {
21869
        if (endsWithCaretContainer(node.previousSibling)) {
21870
          return node.previousSibling;
21871
        } else {
21872
          node.previousSibling.appendData(ZWSP$1);
21873
          return node.previousSibling;
21874
        }
21875
      } else if (isText$2(node)) {
21876
        if (startsWithCaretContainer(node)) {
21877
          return node;
21878
        } else {
21879
          node.insertData(0, ZWSP$1);
21880
          return node;
21881
        }
21882
      } else {
21883
        const newNode = createZwsp(node);
21884
        (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node);
21885
        return newNode;
21886
      }
21887
    };
21888
    const insertAfter$1 = node => {
21889
      var _a, _b;
21890
      if (isText$2(node.nextSibling)) {
21891
        if (startsWithCaretContainer(node.nextSibling)) {
21892
          return node.nextSibling;
21893
        } else {
21894
          node.nextSibling.insertData(0, ZWSP$1);
21895
          return node.nextSibling;
21896
        }
21897
      } else if (isText$2(node)) {
21898
        if (endsWithCaretContainer(node)) {
21899
          return node;
21900
        } else {
21901
          node.appendData(ZWSP$1);
21902
          return node;
21903
        }
21904
      } else {
21905
        const newNode = createZwsp(node);
21906
        if (node.nextSibling) {
21907
          (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node.nextSibling);
21908
        } else {
21909
          (_b = node.parentNode) === null || _b === void 0 ? void 0 : _b.appendChild(newNode);
21910
        }
21911
        return newNode;
21912
      }
21913
    };
21914
    const insertInline = (before, node) => before ? insertBefore$1(node) : insertAfter$1(node);
21915
    const insertInlineBefore = curry(insertInline, true);
21916
    const insertInlineAfter = curry(insertInline, false);
21917
 
21918
    const insertInlinePos = (pos, before) => {
1441 ariadna 21919
      if (isText$b(pos.container())) {
1 efrain 21920
        return insertInline(before, pos.container());
21921
      } else {
21922
        return insertInline(before, pos.getNode());
21923
      }
21924
    };
21925
    const isPosCaretContainer = (pos, caret) => {
21926
      const caretNode = caret.get();
21927
      return caretNode && pos.container() === caretNode && isCaretContainerInline(caretNode);
21928
    };
21929
    const renderCaret = (caret, location) => location.fold(element => {
1441 ariadna 21930
      remove$2(caret.get());
1 efrain 21931
      const text = insertInlineBefore(element);
21932
      caret.set(text);
21933
      return Optional.some(CaretPosition(text, text.length - 1));
21934
    }, element => firstPositionIn(element).map(pos => {
21935
      if (!isPosCaretContainer(pos, caret)) {
1441 ariadna 21936
        remove$2(caret.get());
1 efrain 21937
        const text = insertInlinePos(pos, true);
21938
        caret.set(text);
21939
        return CaretPosition(text, 1);
21940
      } else {
21941
        const node = caret.get();
21942
        return CaretPosition(node, 1);
21943
      }
21944
    }), element => lastPositionIn(element).map(pos => {
21945
      if (!isPosCaretContainer(pos, caret)) {
1441 ariadna 21946
        remove$2(caret.get());
1 efrain 21947
        const text = insertInlinePos(pos, false);
21948
        caret.set(text);
21949
        return CaretPosition(text, text.length - 1);
21950
      } else {
21951
        const node = caret.get();
21952
        return CaretPosition(node, node.length - 1);
21953
      }
21954
    }), element => {
1441 ariadna 21955
      remove$2(caret.get());
1 efrain 21956
      const text = insertInlineAfter(element);
21957
      caret.set(text);
21958
      return Optional.some(CaretPosition(text, 1));
21959
    });
21960
 
21961
    const evaluateUntil = (fns, args) => {
21962
      for (let i = 0; i < fns.length; i++) {
21963
        const result = fns[i].apply(null, args);
21964
        if (result.isSome()) {
21965
          return result;
21966
        }
21967
      }
21968
      return Optional.none();
21969
    };
21970
 
21971
    const Location = Adt.generate([
21972
      { before: ['element'] },
21973
      { start: ['element'] },
21974
      { end: ['element'] },
21975
      { after: ['element'] }
21976
    ]);
21977
    const rescope$1 = (rootNode, node) => {
21978
      const parentBlock = getParentBlock$3(node, rootNode);
21979
      return parentBlock ? parentBlock : rootNode;
21980
    };
21981
    const before = (isInlineTarget, rootNode, pos) => {
21982
      const nPos = normalizeForwards(pos);
21983
      const scope = rescope$1(rootNode, nPos.container());
21984
      return findRootInline(isInlineTarget, scope, nPos).fold(() => nextPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.before(inline)), Optional.none);
21985
    };
21986
    const isNotInsideFormatCaretContainer = (rootNode, elm) => getParentCaretContainer(rootNode, elm) === null;
21987
    const findInsideRootInline = (isInlineTarget, rootNode, pos) => findRootInline(isInlineTarget, rootNode, pos).filter(curry(isNotInsideFormatCaretContainer, rootNode));
21988
    const start$1 = (isInlineTarget, rootNode, pos) => {
21989
      const nPos = normalizeBackwards(pos);
21990
      return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
21991
        const prevPos = prevPosition(inline, nPos);
21992
        return prevPos.isNone() ? Optional.some(Location.start(inline)) : Optional.none();
21993
      });
21994
    };
21995
    const end = (isInlineTarget, rootNode, pos) => {
21996
      const nPos = normalizeForwards(pos);
21997
      return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
21998
        const nextPos = nextPosition(inline, nPos);
21999
        return nextPos.isNone() ? Optional.some(Location.end(inline)) : Optional.none();
22000
      });
22001
    };
22002
    const after = (isInlineTarget, rootNode, pos) => {
22003
      const nPos = normalizeBackwards(pos);
22004
      const scope = rescope$1(rootNode, nPos.container());
22005
      return findRootInline(isInlineTarget, scope, nPos).fold(() => prevPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.after(inline)), Optional.none);
22006
    };
22007
    const isValidLocation = location => !isRtl(getElement(location));
22008
    const readLocation = (isInlineTarget, rootNode, pos) => {
22009
      const location = evaluateUntil([
22010
        before,
22011
        start$1,
22012
        end,
22013
        after
22014
      ], [
22015
        isInlineTarget,
22016
        rootNode,
22017
        pos
22018
      ]);
22019
      return location.filter(isValidLocation);
22020
    };
22021
    const getElement = location => location.fold(identity, identity, identity, identity);
22022
    const getName = location => location.fold(constant('before'), constant('start'), constant('end'), constant('after'));
22023
    const outside = location => location.fold(Location.before, Location.before, Location.after, Location.after);
22024
    const inside = location => location.fold(Location.start, Location.start, Location.end, Location.end);
22025
    const isEq = (location1, location2) => getName(location1) === getName(location2) && getElement(location1) === getElement(location2);
22026
    const betweenInlines = (forward, isInlineTarget, rootNode, from, to, location) => lift2(findRootInline(isInlineTarget, rootNode, from), findRootInline(isInlineTarget, rootNode, to), (fromInline, toInline) => {
22027
      if (fromInline !== toInline && hasSameParentBlock(rootNode, fromInline, toInline)) {
22028
        return Location.after(forward ? fromInline : toInline);
22029
      } else {
22030
        return location;
22031
      }
22032
    }).getOr(location);
22033
    const skipNoMovement = (fromLocation, toLocation) => fromLocation.fold(always, fromLocation => !isEq(fromLocation, toLocation));
22034
    const findLocationTraverse = (forward, isInlineTarget, rootNode, fromLocation, pos) => {
22035
      const from = normalizePosition(forward, pos);
22036
      const to = fromPosition(forward, rootNode, from).map(curry(normalizePosition, forward));
22037
      const location = to.fold(() => fromLocation.map(outside), to => readLocation(isInlineTarget, rootNode, to).map(curry(betweenInlines, forward, isInlineTarget, rootNode, from, to)).filter(curry(skipNoMovement, fromLocation)));
22038
      return location.filter(isValidLocation);
22039
    };
22040
    const findLocationSimple = (forward, location) => {
22041
      if (forward) {
22042
        return location.fold(compose(Optional.some, Location.start), Optional.none, compose(Optional.some, Location.after), Optional.none);
22043
      } else {
22044
        return location.fold(Optional.none, compose(Optional.some, Location.before), Optional.none, compose(Optional.some, Location.end));
22045
      }
22046
    };
22047
    const findLocation$1 = (forward, isInlineTarget, rootNode, pos) => {
22048
      const from = normalizePosition(forward, pos);
22049
      const fromLocation = readLocation(isInlineTarget, rootNode, from);
22050
      return readLocation(isInlineTarget, rootNode, from).bind(curry(findLocationSimple, forward)).orThunk(() => findLocationTraverse(forward, isInlineTarget, rootNode, fromLocation, pos));
22051
    };
22052
 
22053
    const hasSelectionModifyApi = editor => {
22054
      return isFunction(editor.selection.getSel().modify);
22055
    };
22056
    const moveRel = (forward, selection, pos) => {
22057
      const delta = forward ? 1 : -1;
22058
      selection.setRng(CaretPosition(pos.container(), pos.offset() + delta).toRange());
22059
      selection.getSel().modify('move', forward ? 'forward' : 'backward', 'word');
22060
      return true;
22061
    };
22062
    const moveByWord = (forward, editor) => {
22063
      const rng = editor.selection.getRng();
22064
      const pos = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
22065
      if (!hasSelectionModifyApi(editor)) {
22066
        return false;
22067
      } else if (forward && isBeforeInline(pos)) {
22068
        return moveRel(true, editor.selection, pos);
22069
      } else if (!forward && isAfterInline(pos)) {
22070
        return moveRel(false, editor.selection, pos);
22071
      } else {
22072
        return false;
22073
      }
22074
    };
22075
 
22076
    var BreakType;
22077
    (function (BreakType) {
22078
      BreakType[BreakType['Br'] = 0] = 'Br';
22079
      BreakType[BreakType['Block'] = 1] = 'Block';
22080
      BreakType[BreakType['Wrap'] = 2] = 'Wrap';
22081
      BreakType[BreakType['Eol'] = 3] = 'Eol';
22082
    }(BreakType || (BreakType = {})));
1441 ariadna 22083
    const flip = (direction, positions) => direction === -1 ? reverse(positions) : positions;
22084
    const walk$1 = (direction, caretWalker, pos) => direction === 1 ? caretWalker.next(pos) : caretWalker.prev(pos);
1 efrain 22085
    const getBreakType = (scope, direction, currentPos, nextPos) => {
1441 ariadna 22086
      if (isBr$6(nextPos.getNode(direction === 1))) {
1 efrain 22087
        return BreakType.Br;
22088
      } else if (isInSameBlock(currentPos, nextPos) === false) {
22089
        return BreakType.Block;
22090
      } else {
22091
        return BreakType.Wrap;
22092
      }
22093
    };
22094
    const getPositionsUntil = (predicate, direction, scope, start) => {
22095
      const caretWalker = CaretWalker(scope);
22096
      let currentPos = start;
22097
      const positions = [];
22098
      while (currentPos) {
22099
        const nextPos = walk$1(direction, caretWalker, currentPos);
22100
        if (!nextPos) {
22101
          break;
22102
        }
22103
        if (isBr$6(nextPos.getNode(false))) {
1441 ariadna 22104
          if (direction === 1) {
1 efrain 22105
            return {
22106
              positions: flip(direction, positions).concat([nextPos]),
22107
              breakType: BreakType.Br,
22108
              breakAt: Optional.some(nextPos)
22109
            };
22110
          } else {
22111
            return {
22112
              positions: flip(direction, positions),
22113
              breakType: BreakType.Br,
22114
              breakAt: Optional.some(nextPos)
22115
            };
22116
          }
22117
        }
22118
        if (!nextPos.isVisible()) {
22119
          currentPos = nextPos;
22120
          continue;
22121
        }
22122
        if (predicate(currentPos, nextPos)) {
22123
          const breakType = getBreakType(scope, direction, currentPos, nextPos);
22124
          return {
22125
            positions: flip(direction, positions),
22126
            breakType,
22127
            breakAt: Optional.some(nextPos)
22128
          };
22129
        }
22130
        positions.push(nextPos);
22131
        currentPos = nextPos;
22132
      }
22133
      return {
22134
        positions: flip(direction, positions),
22135
        breakType: BreakType.Eol,
22136
        breakAt: Optional.none()
22137
      };
22138
    };
22139
    const getAdjacentLinePositions = (direction, getPositionsUntilBreak, scope, start) => getPositionsUntilBreak(scope, start).breakAt.map(pos => {
22140
      const positions = getPositionsUntilBreak(scope, pos).positions;
1441 ariadna 22141
      return direction === -1 ? positions.concat(pos) : [pos].concat(positions);
1 efrain 22142
    }).getOr([]);
22143
    const findClosestHorizontalPositionFromPoint = (positions, x) => foldl(positions, (acc, newPos) => acc.fold(() => Optional.some(newPos), lastPos => lift2(head(lastPos.getClientRects()), head(newPos.getClientRects()), (lastRect, newRect) => {
22144
      const lastDist = Math.abs(x - lastRect.left);
22145
      const newDist = Math.abs(x - newRect.left);
22146
      return newDist <= lastDist ? newPos : lastPos;
22147
    }).or(acc)), Optional.none());
22148
    const findClosestHorizontalPosition = (positions, pos) => head(pos.getClientRects()).bind(targetRect => findClosestHorizontalPositionFromPoint(positions, targetRect.left));
22149
    const getPositionsUntilPreviousLine = curry(getPositionsUntil, CaretPosition.isAbove, -1);
22150
    const getPositionsUntilNextLine = curry(getPositionsUntil, CaretPosition.isBelow, 1);
22151
    const getPositionsAbove = curry(getAdjacentLinePositions, -1, getPositionsUntilPreviousLine);
22152
    const getPositionsBelow = curry(getAdjacentLinePositions, 1, getPositionsUntilNextLine);
22153
    const isAtFirstLine = (scope, pos) => getPositionsUntilPreviousLine(scope, pos).breakAt.isNone();
22154
    const isAtLastLine = (scope, pos) => getPositionsUntilNextLine(scope, pos).breakAt.isNone();
22155
    const getFirstLinePositions = scope => firstPositionIn(scope).map(pos => [pos].concat(getPositionsUntilNextLine(scope, pos).positions)).getOr([]);
22156
    const getLastLinePositions = scope => lastPositionIn(scope).map(pos => getPositionsUntilPreviousLine(scope, pos).positions.concat(pos)).getOr([]);
22157
    const getClosestPositionAbove = (scope, pos) => findClosestHorizontalPosition(getPositionsAbove(scope, pos), pos);
22158
    const getClosestPositionBelow = (scope, pos) => findClosestHorizontalPosition(getPositionsBelow(scope, pos), pos);
22159
 
1441 ariadna 22160
    const isContentEditableFalse$5 = isContentEditableFalse$b;
1 efrain 22161
    const distanceToRectLeft$1 = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
22162
    const distanceToRectRight$1 = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
22163
    const isNodeClientRect = rect => hasNonNullableKey(rect, 'node');
22164
    const findClosestClientRect = (clientRects, clientX) => reduce(clientRects, (oldClientRect, clientRect) => {
22165
      const oldDistance = Math.min(distanceToRectLeft$1(oldClientRect, clientX), distanceToRectRight$1(oldClientRect, clientX));
22166
      const newDistance = Math.min(distanceToRectLeft$1(clientRect, clientX), distanceToRectRight$1(clientRect, clientX));
1441 ariadna 22167
      if (newDistance === oldDistance && isNodeClientRect(clientRect) && isContentEditableFalse$5(clientRect.node)) {
1 efrain 22168
        return clientRect;
22169
      }
22170
      if (newDistance < oldDistance) {
22171
        return clientRect;
22172
      }
22173
      return oldClientRect;
22174
    });
22175
 
22176
    const getNodeClientRects = node => {
22177
      const toArrayWithNode = clientRects => {
22178
        return map$3(clientRects, rect => {
22179
          const clientRect = clone$1(rect);
22180
          clientRect.node = node;
22181
          return clientRect;
22182
        });
22183
      };
22184
      if (isElement$6(node)) {
22185
        return toArrayWithNode(node.getClientRects());
1441 ariadna 22186
      } else if (isText$b(node)) {
1 efrain 22187
        const rng = node.ownerDocument.createRange();
22188
        rng.setStart(node, 0);
22189
        rng.setEnd(node, node.data.length);
22190
        return toArrayWithNode(rng.getClientRects());
22191
      } else {
22192
        return [];
22193
      }
22194
    };
22195
    const getClientRects = nodes => bind$3(nodes, getNodeClientRects);
22196
 
22197
    var VDirection;
22198
    (function (VDirection) {
22199
      VDirection[VDirection['Up'] = -1] = 'Up';
22200
      VDirection[VDirection['Down'] = 1] = 'Down';
22201
    }(VDirection || (VDirection = {})));
22202
    const findUntil = (direction, root, predicateFn, node) => {
22203
      let currentNode = node;
22204
      while (currentNode = findNode(currentNode, direction, isEditableCaretCandidate$1, root)) {
22205
        if (predicateFn(currentNode)) {
22206
          return;
22207
        }
22208
      }
22209
    };
22210
    const walkUntil = (direction, isAboveFn, isBeflowFn, root, predicateFn, caretPosition) => {
22211
      let line = 0;
22212
      const result = [];
22213
      const add = node => {
22214
        let clientRects = getClientRects([node]);
1441 ariadna 22215
        if (direction === VDirection.Up) {
1 efrain 22216
          clientRects = clientRects.reverse();
22217
        }
22218
        for (let i = 0; i < clientRects.length; i++) {
22219
          const clientRect = clientRects[i];
22220
          if (isBeflowFn(clientRect, targetClientRect)) {
22221
            continue;
22222
          }
1441 ariadna 22223
          if (result.length > 0 && isAboveFn(clientRect, last$1(result))) {
1 efrain 22224
            line++;
22225
          }
22226
          clientRect.line = line;
22227
          if (predicateFn(clientRect)) {
22228
            return true;
22229
          }
22230
          result.push(clientRect);
22231
        }
22232
        return false;
22233
      };
1441 ariadna 22234
      const targetClientRect = last$1(caretPosition.getClientRects());
1 efrain 22235
      if (!targetClientRect) {
22236
        return result;
22237
      }
22238
      const node = caretPosition.getNode();
22239
      if (node) {
22240
        add(node);
22241
        findUntil(direction, root, add, node);
22242
      }
22243
      return result;
22244
    };
22245
    const aboveLineNumber = (lineNumber, clientRect) => clientRect.line > lineNumber;
22246
    const isLineNumber = (lineNumber, clientRect) => clientRect.line === lineNumber;
22247
    const upUntil = curry(walkUntil, VDirection.Up, isAbove$1, isBelow$1);
22248
    const downUntil = curry(walkUntil, VDirection.Down, isBelow$1, isAbove$1);
22249
    const getLastClientRect = caretPosition => {
1441 ariadna 22250
      return last$1(caretPosition.getClientRects());
1 efrain 22251
    };
22252
    const positionsUntil = (direction, root, predicateFn, node) => {
22253
      const caretWalker = CaretWalker(root);
22254
      let walkFn;
22255
      let isBelowFn;
22256
      let isAboveFn;
22257
      let caretPosition;
22258
      const result = [];
22259
      let line = 0;
1441 ariadna 22260
      if (direction === VDirection.Down) {
1 efrain 22261
        walkFn = caretWalker.next;
22262
        isBelowFn = isBelow$1;
22263
        isAboveFn = isAbove$1;
22264
        caretPosition = CaretPosition.after(node);
22265
      } else {
22266
        walkFn = caretWalker.prev;
22267
        isBelowFn = isAbove$1;
22268
        isAboveFn = isBelow$1;
22269
        caretPosition = CaretPosition.before(node);
22270
      }
22271
      const targetClientRect = getLastClientRect(caretPosition);
22272
      do {
22273
        if (!caretPosition.isVisible()) {
22274
          continue;
22275
        }
22276
        const rect = getLastClientRect(caretPosition);
22277
        if (isAboveFn(rect, targetClientRect)) {
22278
          continue;
22279
        }
1441 ariadna 22280
        if (result.length > 0 && isBelowFn(rect, last$1(result))) {
1 efrain 22281
          line++;
22282
        }
22283
        const clientRect = clone$1(rect);
22284
        clientRect.position = caretPosition;
22285
        clientRect.line = line;
22286
        if (predicateFn(clientRect)) {
22287
          return result;
22288
        }
22289
        result.push(clientRect);
22290
      } while (caretPosition = walkFn(caretPosition));
22291
      return result;
22292
    };
22293
    const isAboveLine = lineNumber => clientRect => aboveLineNumber(lineNumber, clientRect);
22294
    const isLine = lineNumber => clientRect => isLineNumber(lineNumber, clientRect);
22295
 
22296
    const moveToRange = (editor, rng) => {
22297
      editor.selection.setRng(rng);
22298
      scrollRangeIntoView(editor, editor.selection.getRng());
22299
    };
22300
    const renderRangeCaretOpt = (editor, range, scrollIntoView) => Optional.some(renderRangeCaret(editor, range, scrollIntoView));
22301
    const moveHorizontally = (editor, direction, range, isBefore, isAfter, isElement) => {
1441 ariadna 22302
      const forwards = direction === 1;
1 efrain 22303
      const caretWalker = CaretWalker(editor.getBody());
22304
      const getNextPosFn = curry(getVisualCaretPosition, forwards ? caretWalker.next : caretWalker.prev);
22305
      const isBeforeFn = forwards ? isBefore : isAfter;
22306
      if (!range.collapsed) {
22307
        const node = getSelectedNode(range);
22308
        if (isElement(node)) {
1441 ariadna 22309
          return showCaret(direction, editor, node, direction === -1, false);
1 efrain 22310
        } else if (isCefAtEdgeSelected(editor)) {
22311
          const newRange = range.cloneRange();
1441 ariadna 22312
          newRange.collapse(direction === -1);
1 efrain 22313
          return Optional.from(newRange);
22314
        }
22315
      }
22316
      const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
22317
      if (isBeforeFn(caretPosition)) {
22318
        return selectNode(editor, caretPosition.getNode(!forwards));
22319
      }
22320
      let nextCaretPosition = getNextPosFn(caretPosition);
22321
      const rangeIsInContainerBlock = isRangeInCaretContainerBlock(range);
22322
      if (!nextCaretPosition) {
22323
        return rangeIsInContainerBlock ? Optional.some(range) : Optional.none();
22324
      } else {
22325
        nextCaretPosition = normalizePosition(forwards, nextCaretPosition);
22326
      }
22327
      if (isBeforeFn(nextCaretPosition)) {
22328
        return showCaret(direction, editor, nextCaretPosition.getNode(!forwards), forwards, false);
22329
      }
22330
      const peekCaretPosition = getNextPosFn(nextCaretPosition);
22331
      if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
22332
        if (isMoveInsideSameBlock(nextCaretPosition, peekCaretPosition)) {
22333
          return showCaret(direction, editor, peekCaretPosition.getNode(!forwards), forwards, false);
22334
        }
22335
      }
22336
      if (rangeIsInContainerBlock) {
22337
        return renderRangeCaretOpt(editor, nextCaretPosition.toRange(), false);
22338
      }
22339
      return Optional.none();
22340
    };
22341
    const moveVertically = (editor, direction, range, isBefore, isAfter, isElement) => {
22342
      const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
1441 ariadna 22343
      const caretClientRect = last$1(caretPosition.getClientRects());
1 efrain 22344
      const forwards = direction === VDirection.Down;
22345
      const root = editor.getBody();
22346
      if (!caretClientRect) {
22347
        return Optional.none();
22348
      }
22349
      if (isCefAtEdgeSelected(editor)) {
22350
        const caretPosition = forwards ? CaretPosition.fromRangeEnd(range) : CaretPosition.fromRangeStart(range);
22351
        const getClosestFn = !forwards ? getClosestPositionAbove : getClosestPositionBelow;
22352
        return getClosestFn(root, caretPosition).orThunk(() => Optional.from(caretPosition)).map(pos => pos.toRange());
22353
      }
22354
      const walkerFn = forwards ? downUntil : upUntil;
22355
      const linePositions = walkerFn(root, isAboveLine(1), caretPosition);
22356
      const nextLinePositions = filter$5(linePositions, isLine(1));
22357
      const clientX = caretClientRect.left;
22358
      const nextLineRect = findClosestClientRect(nextLinePositions, clientX);
22359
      if (nextLineRect && isElement(nextLineRect.node)) {
22360
        const dist1 = Math.abs(clientX - nextLineRect.left);
22361
        const dist2 = Math.abs(clientX - nextLineRect.right);
22362
        return showCaret(direction, editor, nextLineRect.node, dist1 < dist2, false);
22363
      }
22364
      let currentNode;
22365
      if (isBefore(caretPosition)) {
22366
        currentNode = caretPosition.getNode();
22367
      } else if (isAfter(caretPosition)) {
22368
        currentNode = caretPosition.getNode(true);
22369
      } else {
22370
        currentNode = getSelectedNode(range);
22371
      }
22372
      if (currentNode) {
22373
        const caretPositions = positionsUntil(direction, root, isAboveLine(1), currentNode);
22374
        let closestNextLineRect = findClosestClientRect(filter$5(caretPositions, isLine(1)), clientX);
22375
        if (closestNextLineRect) {
22376
          return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
22377
        }
1441 ariadna 22378
        closestNextLineRect = last$1(filter$5(caretPositions, isLine(0)));
1 efrain 22379
        if (closestNextLineRect) {
22380
          return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
22381
        }
22382
      }
22383
      if (nextLinePositions.length === 0) {
22384
        return getLineEndPoint(editor, forwards).filter(forwards ? isAfter : isBefore).map(pos => renderRangeCaret(editor, pos.toRange(), false));
22385
      }
22386
      return Optional.none();
22387
    };
22388
    const getLineEndPoint = (editor, forward) => {
22389
      const rng = editor.selection.getRng();
22390
      const from = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
22391
      const host = getEditingHost(from.container(), editor.getBody());
22392
      if (forward) {
22393
        const lineInfo = getPositionsUntilNextLine(host, from);
1441 ariadna 22394
        return last$2(lineInfo.positions);
1 efrain 22395
      } else {
22396
        const lineInfo = getPositionsUntilPreviousLine(host, from);
22397
        return head(lineInfo.positions);
22398
      }
22399
    };
22400
    const moveToLineEndPoint$3 = (editor, forward, isElementPosition) => getLineEndPoint(editor, forward).filter(isElementPosition).exists(pos => {
22401
      editor.selection.setRng(pos.toRange());
22402
      return true;
22403
    });
22404
 
22405
    const setCaretPosition = (editor, pos) => {
22406
      const rng = editor.dom.createRng();
22407
      rng.setStart(pos.container(), pos.offset());
22408
      rng.setEnd(pos.container(), pos.offset());
22409
      editor.selection.setRng(rng);
22410
    };
22411
    const setSelected = (state, elm) => {
22412
      if (state) {
22413
        elm.setAttribute('data-mce-selected', 'inline-boundary');
22414
      } else {
22415
        elm.removeAttribute('data-mce-selected');
22416
      }
22417
    };
22418
    const renderCaretLocation = (editor, caret, location) => renderCaret(caret, location).map(pos => {
22419
      setCaretPosition(editor, pos);
22420
      return location;
22421
    });
22422
    const getPositionFromRange = (range, root, forward) => {
22423
      const start = CaretPosition.fromRangeStart(range);
22424
      if (range.collapsed) {
22425
        return start;
22426
      } else {
22427
        const end = CaretPosition.fromRangeEnd(range);
22428
        return forward ? prevPosition(root, end).getOr(end) : nextPosition(root, start).getOr(start);
22429
      }
22430
    };
22431
    const findLocation = (editor, caret, forward) => {
22432
      const rootNode = editor.getBody();
22433
      const from = getPositionFromRange(editor.selection.getRng(), rootNode, forward);
22434
      const isInlineTarget$1 = curry(isInlineTarget, editor);
22435
      const location = findLocation$1(forward, isInlineTarget$1, rootNode, from);
22436
      return location.bind(location => renderCaretLocation(editor, caret, location));
22437
    };
22438
    const toggleInlines = (isInlineTarget, dom, elms) => {
22439
      const inlineBoundaries = map$3(descendants(SugarElement.fromDom(dom.getRoot()), '*[data-mce-selected="inline-boundary"]'), e => e.dom);
22440
      const selectedInlines = filter$5(inlineBoundaries, isInlineTarget);
22441
      const targetInlines = filter$5(elms, isInlineTarget);
22442
      each$e(difference(selectedInlines, targetInlines), curry(setSelected, false));
22443
      each$e(difference(targetInlines, selectedInlines), curry(setSelected, true));
22444
    };
22445
    const safeRemoveCaretContainer = (editor, caret) => {
22446
      const caretValue = caret.get();
22447
      if (editor.selection.isCollapsed() && !editor.composing && caretValue) {
22448
        const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
22449
        if (CaretPosition.isTextPosition(pos) && !isAtZwsp(pos)) {
22450
          setCaretPosition(editor, removeAndReposition(caretValue, pos));
22451
          caret.set(null);
22452
        }
22453
      }
22454
    };
22455
    const renderInsideInlineCaret = (isInlineTarget, editor, caret, elms) => {
22456
      if (editor.selection.isCollapsed()) {
22457
        const inlines = filter$5(elms, isInlineTarget);
22458
        each$e(inlines, _inline => {
22459
          const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
22460
          readLocation(isInlineTarget, editor.getBody(), pos).bind(location => renderCaretLocation(editor, caret, location));
22461
        });
22462
      }
22463
    };
22464
    const move$3 = (editor, caret, forward) => isInlineBoundariesEnabled(editor) ? findLocation(editor, caret, forward).isSome() : false;
22465
    const moveWord = (forward, editor, _caret) => isInlineBoundariesEnabled(editor) ? moveByWord(forward, editor) : false;
22466
    const setupSelectedState = editor => {
22467
      const caret = Cell(null);
22468
      const isInlineTarget$1 = curry(isInlineTarget, editor);
22469
      editor.on('NodeChange', e => {
22470
        if (isInlineBoundariesEnabled(editor)) {
22471
          toggleInlines(isInlineTarget$1, editor.dom, e.parents);
22472
          safeRemoveCaretContainer(editor, caret);
22473
          renderInsideInlineCaret(isInlineTarget$1, editor, caret, e.parents);
22474
        }
22475
      });
22476
      return caret;
22477
    };
22478
    const moveNextWord = curry(moveWord, true);
22479
    const movePrevWord = curry(moveWord, false);
22480
    const moveToLineEndPoint$2 = (editor, forward, caret) => {
22481
      if (isInlineBoundariesEnabled(editor)) {
22482
        const linePoint = getLineEndPoint(editor, forward).getOrThunk(() => {
22483
          const rng = editor.selection.getRng();
22484
          return forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
22485
        });
22486
        return readLocation(curry(isInlineTarget, editor), editor.getBody(), linePoint).exists(loc => {
22487
          const outsideLoc = outside(loc);
22488
          return renderCaret(caret, outsideLoc).exists(pos => {
22489
            setCaretPosition(editor, pos);
22490
            return true;
22491
          });
22492
        });
22493
      } else {
22494
        return false;
22495
      }
22496
    };
22497
 
22498
    const rangeFromPositions = (from, to) => {
22499
      const range = document.createRange();
22500
      range.setStart(from.container(), from.offset());
22501
      range.setEnd(to.container(), to.offset());
22502
      return range;
22503
    };
22504
    const hasOnlyTwoOrLessPositionsLeft = elm => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
22505
      const normalizedFirstPos = normalizePosition(true, firstPos);
22506
      const normalizedLastPos = normalizePosition(false, lastPos);
22507
      return nextPosition(elm, normalizedFirstPos).forall(pos => pos.isEqual(normalizedLastPos));
22508
    }).getOr(true);
22509
    const setCaretLocation = (editor, caret) => location => renderCaret(caret, location).map(pos => () => setCaretPosition(editor, pos));
22510
    const deleteFromTo = (editor, caret, from, to) => {
22511
      const rootNode = editor.getBody();
22512
      const isInlineTarget$1 = curry(isInlineTarget, editor);
22513
      editor.undoManager.ignore(() => {
22514
        editor.selection.setRng(rangeFromPositions(from, to));
22515
        execNativeDeleteCommand(editor);
22516
        readLocation(isInlineTarget$1, rootNode, CaretPosition.fromRangeStart(editor.selection.getRng())).map(inside).bind(setCaretLocation(editor, caret)).each(call);
22517
      });
22518
      editor.nodeChanged();
22519
    };
22520
    const rescope = (rootNode, node) => {
22521
      const parentBlock = getParentBlock$3(node, rootNode);
22522
      return parentBlock ? parentBlock : rootNode;
22523
    };
22524
    const backspaceDeleteCollapsed = (editor, caret, forward, from) => {
22525
      const rootNode = rescope(editor.getBody(), from.container());
22526
      const isInlineTarget$1 = curry(isInlineTarget, editor);
22527
      const fromLocation = readLocation(isInlineTarget$1, rootNode, from);
22528
      const location = fromLocation.bind(location => {
22529
        if (forward) {
22530
          return location.fold(constant(Optional.some(inside(location))), Optional.none, constant(Optional.some(outside(location))), Optional.none);
22531
        } else {
22532
          return location.fold(Optional.none, constant(Optional.some(outside(location))), Optional.none, constant(Optional.some(inside(location))));
22533
        }
22534
      });
22535
      return location.map(setCaretLocation(editor, caret)).getOrThunk(() => {
22536
        const toPosition = navigate(forward, rootNode, from);
22537
        const toLocation = toPosition.bind(pos => readLocation(isInlineTarget$1, rootNode, pos));
22538
        return lift2(fromLocation, toLocation, () => findRootInline(isInlineTarget$1, rootNode, from).bind(elm => {
22539
          if (hasOnlyTwoOrLessPositionsLeft(elm)) {
22540
            return Optional.some(() => {
22541
              deleteElement$2(editor, forward, SugarElement.fromDom(elm));
22542
            });
22543
          } else {
22544
            return Optional.none();
22545
          }
22546
        })).getOrThunk(() => toLocation.bind(() => toPosition.map(to => {
22547
          return () => {
22548
            if (forward) {
22549
              deleteFromTo(editor, caret, from, to);
22550
            } else {
22551
              deleteFromTo(editor, caret, to, from);
22552
            }
22553
          };
22554
        })));
22555
      });
22556
    };
22557
    const backspaceDelete$4 = (editor, caret, forward) => {
22558
      if (editor.selection.isCollapsed() && isInlineBoundariesEnabled(editor)) {
22559
        const from = CaretPosition.fromRangeStart(editor.selection.getRng());
22560
        return backspaceDeleteCollapsed(editor, caret, forward, from);
22561
      }
22562
      return Optional.none();
22563
    };
22564
 
22565
    const hasMultipleChildren = elm => childNodesCount(elm) > 1;
22566
    const getParentsUntil = (editor, pred) => {
22567
      const rootElm = SugarElement.fromDom(editor.getBody());
22568
      const startElm = SugarElement.fromDom(editor.selection.getStart());
22569
      const parents = parentsAndSelf(startElm, rootElm);
22570
      return findIndex$2(parents, pred).fold(constant(parents), index => parents.slice(0, index));
22571
    };
22572
    const hasOnlyOneChild = elm => childNodesCount(elm) === 1;
22573
    const getParentInlinesUntilMultichildInline = editor => getParentsUntil(editor, elm => editor.schema.isBlock(name(elm)) || hasMultipleChildren(elm));
22574
    const getParentInlines = editor => getParentsUntil(editor, el => editor.schema.isBlock(name(el)));
22575
    const getFormatNodes = (editor, parentInlines) => {
22576
      const isFormatElement$1 = curry(isFormatElement, editor);
22577
      return bind$3(parentInlines, elm => isFormatElement$1(elm) ? [elm.dom] : []);
22578
    };
22579
    const getFormatNodesAtStart = editor => {
22580
      const parentInlines = getParentInlines(editor);
22581
      return getFormatNodes(editor, parentInlines);
22582
    };
22583
    const deleteLastPosition = (forward, editor, target, parentInlines) => {
22584
      const formatNodes = getFormatNodes(editor, parentInlines);
22585
      if (formatNodes.length === 0) {
22586
        deleteElement$2(editor, forward, target);
22587
      } else {
22588
        const pos = replaceWithCaretFormat(target.dom, formatNodes);
22589
        editor.selection.setRng(pos.toRange());
22590
      }
22591
    };
22592
    const deleteCaret$1 = (editor, forward) => {
22593
      const parentInlines = filter$5(getParentInlinesUntilMultichildInline(editor), hasOnlyOneChild);
1441 ariadna 22594
      return last$2(parentInlines).bind(target => {
1 efrain 22595
        const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
22596
        if (willDeleteLastPositionInElement(forward, fromPos, target.dom) && !isEmptyCaretFormatElement(target)) {
22597
          return Optional.some(() => deleteLastPosition(forward, editor, target, parentInlines));
22598
        } else {
22599
          return Optional.none();
22600
        }
22601
      });
22602
    };
22603
    const isBrInEmptyElement = (editor, elm) => {
22604
      const parentElm = elm.parentElement;
22605
      return isBr$6(elm) && !isNull(parentElm) && editor.dom.isEmpty(parentElm);
22606
    };
22607
    const isEmptyCaret = elm => isEmptyCaretFormatElement(SugarElement.fromDom(elm));
22608
    const createCaretFormatAtStart = (editor, formatNodes) => {
22609
      const startElm = editor.selection.getStart();
22610
      const pos = isBrInEmptyElement(editor, startElm) || isEmptyCaret(startElm) ? replaceWithCaretFormat(startElm, formatNodes) : createCaretFormatAtStart$1(editor.selection.getRng(), formatNodes);
22611
      editor.selection.setRng(pos.toRange());
22612
    };
22613
    const updateCaretFormat = (editor, updateFormats) => {
22614
      const missingFormats = difference(updateFormats, getFormatNodesAtStart(editor));
22615
      if (missingFormats.length > 0) {
22616
        createCaretFormatAtStart(editor, missingFormats);
22617
      }
22618
    };
1441 ariadna 22619
    const rangeStartsAtTextContainer = rng => isText$b(rng.startContainer);
1 efrain 22620
    const rangeStartsAtStartOfTextContainer = rng => rng.startOffset === 0 && rangeStartsAtTextContainer(rng);
22621
    const rangeStartParentIsFormatElement = (editor, rng) => {
22622
      const startParent = rng.startContainer.parentElement;
22623
      return !isNull(startParent) && isFormatElement(editor, SugarElement.fromDom(startParent));
22624
    };
22625
    const rangeStartAndEndHaveSameParent = rng => {
22626
      const startParent = rng.startContainer.parentNode;
22627
      const endParent = rng.endContainer.parentNode;
22628
      return !isNull(startParent) && !isNull(endParent) && startParent.isEqualNode(endParent);
22629
    };
22630
    const rangeEndsAtEndOfEndContainer = rng => {
22631
      const endContainer = rng.endContainer;
1441 ariadna 22632
      return rng.endOffset === (isText$b(endContainer) ? endContainer.length : endContainer.childNodes.length);
1 efrain 22633
    };
22634
    const rangeEndsAtEndOfStartContainer = rng => rangeStartAndEndHaveSameParent(rng) && rangeEndsAtEndOfEndContainer(rng);
22635
    const rangeEndsAfterEndOfStartContainer = rng => !rng.endContainer.isEqualNode(rng.commonAncestorContainer);
22636
    const rangeEndsAtOrAfterEndOfStartContainer = rng => rangeEndsAtEndOfStartContainer(rng) || rangeEndsAfterEndOfStartContainer(rng);
22637
    const requiresDeleteRangeOverride = editor => {
22638
      const rng = editor.selection.getRng();
22639
      return rangeStartsAtStartOfTextContainer(rng) && rangeStartParentIsFormatElement(editor, rng) && rangeEndsAtOrAfterEndOfStartContainer(rng);
22640
    };
22641
    const deleteRange$1 = editor => {
22642
      if (requiresDeleteRangeOverride(editor)) {
22643
        const formatNodes = getFormatNodesAtStart(editor);
22644
        return Optional.some(() => {
22645
          execNativeDeleteCommand(editor);
22646
          updateCaretFormat(editor, formatNodes);
22647
        });
22648
      } else {
22649
        return Optional.none();
22650
      }
22651
    };
22652
    const backspaceDelete$3 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$1(editor, forward) : deleteRange$1(editor);
1441 ariadna 22653
    const hasAncestorInlineCaret = (elm, schema) => ancestor$2(elm, node => isCaretNode(node.dom), el => schema.isBlock(name(el)));
1 efrain 22654
    const hasAncestorInlineCaretAtStart = editor => hasAncestorInlineCaret(SugarElement.fromDom(editor.selection.getStart()), editor.schema);
22655
    const requiresRefreshCaretOverride = editor => {
22656
      const rng = editor.selection.getRng();
22657
      return rng.collapsed && (rangeStartsAtTextContainer(rng) || editor.dom.isEmpty(rng.startContainer)) && !hasAncestorInlineCaretAtStart(editor);
22658
    };
22659
    const refreshCaret = editor => {
22660
      if (requiresRefreshCaretOverride(editor)) {
22661
        createCaretFormatAtStart(editor, []);
22662
      }
22663
      return true;
22664
    };
22665
 
22666
    const deleteElement = (editor, forward, element) => {
22667
      if (isNonNullable(element)) {
22668
        return Optional.some(() => {
22669
          editor._selectionOverrides.hideFakeCaret();
22670
          deleteElement$2(editor, forward, SugarElement.fromDom(element));
22671
        });
22672
      } else {
22673
        return Optional.none();
22674
      }
22675
    };
22676
    const deleteCaret = (editor, forward) => {
22677
      const isNearMedia = forward ? isBeforeMedia : isAfterMedia;
1441 ariadna 22678
      const direction = forward ? 1 : -1;
1 efrain 22679
      const fromPos = getNormalizedRangeEndPoint(direction, editor.getBody(), editor.selection.getRng());
22680
      if (isNearMedia(fromPos)) {
22681
        return deleteElement(editor, forward, fromPos.getNode(!forward));
22682
      } else {
22683
        return Optional.from(normalizePosition(forward, fromPos)).filter(pos => isNearMedia(pos) && isMoveInsideSameBlock(fromPos, pos)).bind(pos => deleteElement(editor, forward, pos.getNode(!forward)));
22684
      }
22685
    };
22686
    const deleteRange = (editor, forward) => {
22687
      const selectedNode = editor.selection.getNode();
22688
      return isMedia$2(selectedNode) ? deleteElement(editor, forward, selectedNode) : Optional.none();
22689
    };
22690
    const backspaceDelete$2 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret(editor, forward) : deleteRange(editor, forward);
22691
 
22692
    const isEditable = target => closest$4(target, elm => isContentEditableTrue$3(elm.dom) || isContentEditableFalse$b(elm.dom)).exists(elm => isContentEditableTrue$3(elm.dom));
22693
    const parseIndentValue = value => toInt(value !== null && value !== void 0 ? value : '').getOr(0);
22694
    const getIndentStyleName = (useMargin, element) => {
22695
      const indentStyleName = useMargin || isTable$1(element) ? 'margin' : 'padding';
22696
      const suffix = get$7(element, 'direction') === 'rtl' ? '-right' : '-left';
22697
      return indentStyleName + suffix;
22698
    };
22699
    const indentElement = (dom, command, useMargin, value, unit, element) => {
22700
      const indentStyleName = getIndentStyleName(useMargin, SugarElement.fromDom(element));
22701
      const parsedValue = parseIndentValue(dom.getStyle(element, indentStyleName));
22702
      if (command === 'outdent') {
22703
        const styleValue = Math.max(0, parsedValue - value);
22704
        dom.setStyle(element, indentStyleName, styleValue ? styleValue + unit : '');
22705
      } else {
22706
        const styleValue = parsedValue + value + unit;
22707
        dom.setStyle(element, indentStyleName, styleValue);
22708
      }
22709
    };
22710
    const validateBlocks = (editor, blocks) => forall(blocks, block => {
22711
      const indentStyleName = getIndentStyleName(shouldIndentUseMargin(editor), block);
22712
      const intentValue = getRaw(block, indentStyleName).map(parseIndentValue).getOr(0);
22713
      const contentEditable = editor.dom.getContentEditable(block.dom);
22714
      return contentEditable !== 'false' && intentValue > 0;
22715
    });
22716
    const canOutdent = editor => {
22717
      const blocks = getBlocksToIndent(editor);
22718
      return !editor.mode.isReadOnly() && (blocks.length > 1 || validateBlocks(editor, blocks));
22719
    };
22720
    const isListComponent = el => isList(el) || isListItem$1(el);
22721
    const parentIsListComponent = el => parent(el).exists(isListComponent);
22722
    const getBlocksToIndent = editor => filter$5(fromDom$1(editor.selection.getSelectedBlocks()), el => !isListComponent(el) && !parentIsListComponent(el) && isEditable(el));
22723
    const handle = (editor, command) => {
22724
      var _a, _b;
1441 ariadna 22725
      if (editor.mode.isReadOnly()) {
22726
        return;
22727
      }
1 efrain 22728
      const {dom} = editor;
22729
      const indentation = getIndentation(editor);
22730
      const indentUnit = (_b = (_a = /[a-z%]+$/i.exec(indentation)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 'px';
22731
      const indentValue = parseIndentValue(indentation);
22732
      const useMargin = shouldIndentUseMargin(editor);
22733
      each$e(getBlocksToIndent(editor), block => {
22734
        indentElement(dom, command, useMargin, indentValue, indentUnit, block.dom);
22735
      });
22736
    };
22737
    const indent = editor => handle(editor, 'indent');
22738
    const outdent = editor => handle(editor, 'outdent');
22739
 
22740
    const backspaceDelete$1 = editor => {
22741
      if (editor.selection.isCollapsed() && canOutdent(editor)) {
22742
        const dom = editor.dom;
22743
        const rng = editor.selection.getRng();
22744
        const pos = CaretPosition.fromRangeStart(rng);
22745
        const block = dom.getParent(rng.startContainer, dom.isBlock);
22746
        if (block !== null && isAtStartOfBlock(SugarElement.fromDom(block), pos, editor.schema)) {
22747
          return Optional.some(() => outdent(editor));
22748
        }
22749
      }
22750
      return Optional.none();
22751
    };
22752
 
22753
    const findAction = (editor, caret, forward) => findMap([
22754
      backspaceDelete$1,
22755
      backspaceDelete$7,
1441 ariadna 22756
      backspaceDelete$8,
1 efrain 22757
      (editor, forward) => backspaceDelete$4(editor, caret, forward),
22758
      backspaceDelete$a,
1441 ariadna 22759
      backspaceDelete$b,
1 efrain 22760
      backspaceDelete$5,
22761
      backspaceDelete$2,
1441 ariadna 22762
      backspaceDelete$9,
22763
      backspaceDelete$3,
22764
      backspaceDelete$6
1 efrain 22765
    ], item => item(editor, forward)).filter(_ => editor.selection.isEditable());
22766
    const deleteCommand = (editor, caret) => {
22767
      const result = findAction(editor, caret, false);
22768
      result.fold(() => {
22769
        if (editor.selection.isEditable()) {
22770
          execNativeDeleteCommand(editor);
22771
          paddEmptyBody(editor);
22772
        }
22773
      }, call);
22774
    };
22775
    const forwardDeleteCommand = (editor, caret) => {
22776
      const result = findAction(editor, caret, true);
22777
      result.fold(() => {
22778
        if (editor.selection.isEditable()) {
22779
          execNativeForwardDeleteCommand(editor);
22780
        }
22781
      }, call);
22782
    };
22783
    const setup$q = (editor, caret) => {
22784
      editor.addCommand('delete', () => {
22785
        deleteCommand(editor, caret);
22786
      });
22787
      editor.addCommand('forwardDelete', () => {
22788
        forwardDeleteCommand(editor, caret);
22789
      });
22790
    };
22791
 
22792
    const SIGNIFICANT_MOVE = 5;
22793
    const LONGPRESS_DELAY = 400;
22794
    const getTouch = event => {
22795
      if (event.touches === undefined || event.touches.length !== 1) {
22796
        return Optional.none();
22797
      }
22798
      return Optional.some(event.touches[0]);
22799
    };
22800
    const isFarEnough = (touch, data) => {
22801
      const distX = Math.abs(touch.clientX - data.x);
22802
      const distY = Math.abs(touch.clientY - data.y);
22803
      return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
22804
    };
22805
    const setup$p = editor => {
22806
      const startData = value$2();
22807
      const longpressFired = Cell(false);
1441 ariadna 22808
      const debounceLongpress = last(e => {
1 efrain 22809
        editor.dispatch('longpress', {
22810
          ...e,
22811
          type: 'longpress'
22812
        });
22813
        longpressFired.set(true);
22814
      }, LONGPRESS_DELAY);
22815
      editor.on('touchstart', e => {
22816
        getTouch(e).each(touch => {
22817
          debounceLongpress.cancel();
22818
          const data = {
22819
            x: touch.clientX,
22820
            y: touch.clientY,
22821
            target: e.target
22822
          };
22823
          debounceLongpress.throttle(e);
22824
          longpressFired.set(false);
22825
          startData.set(data);
22826
        });
22827
      }, true);
22828
      editor.on('touchmove', e => {
22829
        debounceLongpress.cancel();
22830
        getTouch(e).each(touch => {
22831
          startData.on(data => {
22832
            if (isFarEnough(touch, data)) {
22833
              startData.clear();
22834
              longpressFired.set(false);
22835
              editor.dispatch('longpresscancel');
22836
            }
22837
          });
22838
        });
22839
      }, true);
22840
      editor.on('touchend touchcancel', e => {
22841
        debounceLongpress.cancel();
22842
        if (e.type === 'touchcancel') {
22843
          return;
22844
        }
22845
        startData.get().filter(data => data.target.isEqualNode(e.target)).each(() => {
22846
          if (longpressFired.get()) {
22847
            e.preventDefault();
22848
          } else {
22849
            editor.dispatch('tap', {
22850
              ...e,
22851
              type: 'tap'
22852
            });
22853
          }
22854
        });
22855
      }, true);
22856
    };
22857
 
22858
    const isBlockElement = (blockElements, node) => has$2(blockElements, node.nodeName);
22859
    const isValidTarget = (schema, node) => {
1441 ariadna 22860
      if (isText$b(node)) {
1 efrain 22861
        return true;
22862
      } else if (isElement$6(node)) {
22863
        return !isBlockElement(schema.getBlockElements(), node) && !isBookmarkNode$1(node) && !isTransparentBlock(schema, node) && !isNonHtmlElementRoot(node);
22864
      } else {
22865
        return false;
22866
      }
22867
    };
22868
    const hasBlockParent = (blockElements, root, node) => {
22869
      return exists(parents(SugarElement.fromDom(node), SugarElement.fromDom(root)), elm => {
22870
        return isBlockElement(blockElements, elm.dom);
22871
      });
22872
    };
22873
    const shouldRemoveTextNode = (blockElements, node) => {
1441 ariadna 22874
      if (isText$b(node)) {
1 efrain 22875
        if (node.data.length === 0) {
22876
          return true;
22877
        } else if (/^\s+$/.test(node.data)) {
22878
          return !node.nextSibling || isBlockElement(blockElements, node.nextSibling) || isNonHtmlElementRoot(node.nextSibling);
22879
        }
22880
      }
22881
      return false;
22882
    };
22883
    const createRootBlock = editor => editor.dom.create(getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
22884
    const addRootBlocks = editor => {
22885
      const dom = editor.dom, selection = editor.selection;
22886
      const schema = editor.schema;
22887
      const blockElements = schema.getBlockElements();
22888
      const startNode = selection.getStart();
22889
      const rootNode = editor.getBody();
22890
      let rootBlockNode;
22891
      let tempNode;
1441 ariadna 22892
      let bm = null;
1 efrain 22893
      const forcedRootBlock = getForcedRootBlock(editor);
22894
      if (!startNode || !isElement$6(startNode)) {
22895
        return;
22896
      }
22897
      const rootNodeName = rootNode.nodeName.toLowerCase();
22898
      if (!schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase()) || hasBlockParent(blockElements, rootNode, startNode)) {
22899
        return;
22900
      }
1441 ariadna 22901
      if (rootNode.firstChild === rootNode.lastChild && isBr$6(rootNode.firstChild)) {
22902
        rootBlockNode = createRootBlock(editor);
22903
        rootBlockNode.appendChild(createPaddingBr().dom);
22904
        rootNode.replaceChild(rootBlockNode, rootNode.firstChild);
22905
        editor.selection.setCursorLocation(rootBlockNode, 0);
22906
        editor.nodeChanged();
22907
        return;
22908
      }
1 efrain 22909
      let node = rootNode.firstChild;
22910
      while (node) {
22911
        if (isElement$6(node)) {
22912
          updateElement(schema, node);
22913
        }
22914
        if (isValidTarget(schema, node)) {
22915
          if (shouldRemoveTextNode(blockElements, node)) {
22916
            tempNode = node;
22917
            node = node.nextSibling;
22918
            dom.remove(tempNode);
22919
            continue;
22920
          }
22921
          if (!rootBlockNode) {
1441 ariadna 22922
            if (!bm && editor.hasFocus()) {
22923
              bm = getBookmark(editor.selection.getRng(), () => document.createElement('span'));
22924
            }
22925
            if (!node.parentNode) {
22926
              node = null;
22927
              break;
22928
            }
1 efrain 22929
            rootBlockNode = createRootBlock(editor);
22930
            rootNode.insertBefore(rootBlockNode, node);
22931
          }
22932
          tempNode = node;
22933
          node = node.nextSibling;
22934
          rootBlockNode.appendChild(tempNode);
22935
        } else {
22936
          rootBlockNode = null;
22937
          node = node.nextSibling;
22938
        }
22939
      }
1441 ariadna 22940
      if (bm) {
22941
        editor.selection.setRng(resolveBookmark(bm));
1 efrain 22942
        editor.nodeChanged();
22943
      }
22944
    };
22945
    const insertEmptyLine = (editor, root, insertBlock) => {
22946
      const block = SugarElement.fromDom(createRootBlock(editor));
22947
      const br = createPaddingBr();
22948
      append$1(block, br);
22949
      insertBlock(root, block);
22950
      const rng = document.createRange();
22951
      rng.setStartBefore(br.dom);
22952
      rng.setEndBefore(br.dom);
22953
      return rng;
22954
    };
22955
    const setup$o = editor => {
1441 ariadna 22956
      editor.on('NodeChange', () => addRootBlocks(editor));
1 efrain 22957
    };
22958
 
22959
    const hasClass = checkClassName => node => (' ' + node.attr('class') + ' ').indexOf(checkClassName) !== -1;
22960
    const replaceMatchWithSpan = (editor, content, cls) => {
22961
      return function (match) {
22962
        const args = arguments, index = args[args.length - 2];
22963
        const prevChar = index > 0 ? content.charAt(index - 1) : '';
22964
        if (prevChar === '"') {
22965
          return match;
22966
        }
22967
        if (prevChar === '>') {
22968
          const findStartTagIndex = content.lastIndexOf('<', index);
22969
          if (findStartTagIndex !== -1) {
22970
            const tagHtml = content.substring(findStartTagIndex, index);
22971
            if (tagHtml.indexOf('contenteditable="false"') !== -1) {
22972
              return match;
22973
            }
22974
          }
22975
        }
22976
        return '<span class="' + cls + '" data-mce-content="' + editor.dom.encode(args[0]) + '">' + editor.dom.encode(typeof args[1] === 'string' ? args[1] : args[0]) + '</span>';
22977
      };
22978
    };
22979
    const convertRegExpsToNonEditable = (editor, nonEditableRegExps, e) => {
22980
      let i = nonEditableRegExps.length, content = e.content;
22981
      if (e.format === 'raw') {
22982
        return;
22983
      }
22984
      while (i--) {
22985
        content = content.replace(nonEditableRegExps[i], replaceMatchWithSpan(editor, content, getNonEditableClass(editor)));
22986
      }
22987
      e.content = content;
22988
    };
1441 ariadna 22989
    const isValidContent = (nonEditableRegExps, content) => {
22990
      return forall(nonEditableRegExps, re => {
22991
        const matches = content.match(re);
22992
        return matches !== null && matches[0].length === content.length;
22993
      });
22994
    };
1 efrain 22995
    const setup$n = editor => {
22996
      const contentEditableAttrName = 'contenteditable';
22997
      const editClass = ' ' + Tools.trim(getEditableClass(editor)) + ' ';
22998
      const nonEditClass = ' ' + Tools.trim(getNonEditableClass(editor)) + ' ';
22999
      const hasEditClass = hasClass(editClass);
23000
      const hasNonEditClass = hasClass(nonEditClass);
23001
      const nonEditableRegExps = getNonEditableRegExps(editor);
23002
      if (nonEditableRegExps.length > 0) {
23003
        editor.on('BeforeSetContent', e => {
23004
          convertRegExpsToNonEditable(editor, nonEditableRegExps, e);
23005
        });
23006
      }
23007
      editor.parser.addAttributeFilter('class', nodes => {
23008
        let i = nodes.length;
23009
        while (i--) {
23010
          const node = nodes[i];
23011
          if (hasEditClass(node)) {
23012
            node.attr(contentEditableAttrName, 'true');
23013
          } else if (hasNonEditClass(node)) {
23014
            node.attr(contentEditableAttrName, 'false');
23015
          }
23016
        }
23017
      });
23018
      editor.serializer.addAttributeFilter(contentEditableAttrName, nodes => {
23019
        let i = nodes.length;
23020
        while (i--) {
23021
          const node = nodes[i];
23022
          if (!hasEditClass(node) && !hasNonEditClass(node)) {
23023
            continue;
23024
          }
1441 ariadna 23025
          const content = node.attr('data-mce-content');
23026
          if (nonEditableRegExps.length > 0 && content) {
23027
            if (isValidContent(nonEditableRegExps, content)) {
23028
              node.name = '#text';
23029
              node.type = 3;
23030
              node.raw = true;
23031
              node.value = content;
23032
            } else {
23033
              node.remove();
23034
            }
1 efrain 23035
          } else {
23036
            node.attr(contentEditableAttrName, null);
23037
          }
23038
        }
23039
      });
23040
    };
23041
 
23042
    const findBlockCaretContainer = editor => descendant$1(SugarElement.fromDom(editor.getBody()), '*[data-mce-caret]').map(elm => elm.dom).getOrNull();
23043
    const showBlockCaretContainer = (editor, blockCaretContainer) => {
23044
      if (blockCaretContainer.hasAttribute('data-mce-caret')) {
23045
        showCaretContainerBlock(blockCaretContainer);
23046
        editor.selection.setRng(editor.selection.getRng());
23047
        editor.selection.scrollIntoView(blockCaretContainer);
23048
      }
23049
    };
23050
    const handleBlockContainer = (editor, e) => {
23051
      const blockCaretContainer = findBlockCaretContainer(editor);
23052
      if (!blockCaretContainer) {
23053
        return;
23054
      }
23055
      if (e.type === 'compositionstart') {
23056
        e.preventDefault();
23057
        e.stopPropagation();
23058
        showBlockCaretContainer(editor, blockCaretContainer);
23059
        return;
23060
      }
23061
      if (hasContent(blockCaretContainer)) {
23062
        showBlockCaretContainer(editor, blockCaretContainer);
23063
        editor.undoManager.add();
23064
      }
23065
    };
23066
    const setup$m = editor => {
23067
      editor.on('keyup compositionstart', curry(handleBlockContainer, editor));
23068
    };
23069
 
1441 ariadna 23070
    const isContentEditableFalse$4 = isContentEditableFalse$b;
23071
    const moveToCeFalseHorizontally = (direction, editor, range) => moveHorizontally(editor, direction, range, isBeforeContentEditableFalse, isAfterContentEditableFalse, isContentEditableFalse$4);
1 efrain 23072
    const moveToCeFalseVertically = (direction, editor, range) => {
23073
      const isBefore = caretPosition => isBeforeContentEditableFalse(caretPosition) || isBeforeTable(caretPosition);
23074
      const isAfter = caretPosition => isAfterContentEditableFalse(caretPosition) || isAfterTable(caretPosition);
1441 ariadna 23075
      return moveVertically(editor, direction, range, isBefore, isAfter, isContentEditableFalse$4);
1 efrain 23076
    };
23077
    const createTextBlock = editor => {
23078
      const textBlock = editor.dom.create(getForcedRootBlock(editor));
23079
      textBlock.innerHTML = '<br data-mce-bogus="1">';
23080
      return textBlock;
23081
    };
23082
    const exitPreBlock = (editor, direction, range) => {
23083
      const caretWalker = CaretWalker(editor.getBody());
23084
      const getVisualCaretPosition$1 = curry(getVisualCaretPosition, direction === 1 ? caretWalker.next : caretWalker.prev);
23085
      if (range.collapsed) {
23086
        const pre = editor.dom.getParent(range.startContainer, 'PRE');
23087
        if (!pre) {
23088
          return;
23089
        }
23090
        const caretPos = getVisualCaretPosition$1(CaretPosition.fromRangeStart(range));
23091
        if (!caretPos) {
23092
          const newBlock = SugarElement.fromDom(createTextBlock(editor));
23093
          if (direction === 1) {
23094
            after$4(SugarElement.fromDom(pre), newBlock);
23095
          } else {
23096
            before$3(SugarElement.fromDom(pre), newBlock);
23097
          }
23098
          editor.selection.select(newBlock.dom, true);
23099
          editor.selection.collapse();
23100
        }
23101
      }
23102
    };
23103
    const getHorizontalRange = (editor, forward) => {
1441 ariadna 23104
      const direction = forward ? 1 : -1;
1 efrain 23105
      const range = editor.selection.getRng();
23106
      return moveToCeFalseHorizontally(direction, editor, range).orThunk(() => {
23107
        exitPreBlock(editor, direction, range);
23108
        return Optional.none();
23109
      });
23110
    };
23111
    const getVerticalRange = (editor, down) => {
23112
      const direction = down ? 1 : -1;
23113
      const range = editor.selection.getRng();
23114
      return moveToCeFalseVertically(direction, editor, range).orThunk(() => {
23115
        exitPreBlock(editor, direction, range);
23116
        return Optional.none();
23117
      });
23118
    };
23119
    const flipDirection = (selection, forward) => {
23120
      const elm = forward ? selection.getEnd(true) : selection.getStart(true);
23121
      return isRtl(elm) ? !forward : forward;
23122
    };
23123
    const moveH$2 = (editor, forward) => getHorizontalRange(editor, flipDirection(editor.selection, forward)).exists(newRange => {
23124
      moveToRange(editor, newRange);
23125
      return true;
23126
    });
23127
    const moveV$4 = (editor, down) => getVerticalRange(editor, down).exists(newRange => {
23128
      moveToRange(editor, newRange);
23129
      return true;
23130
    });
23131
    const moveToLineEndPoint$1 = (editor, forward) => {
23132
      const isCefPosition = forward ? isAfterContentEditableFalse : isBeforeContentEditableFalse;
23133
      return moveToLineEndPoint$3(editor, forward, isCefPosition);
23134
    };
23135
    const selectToEndPoint = (editor, forward) => getEdgeCefPosition(editor, !forward).map(pos => {
23136
      const rng = pos.toRange();
23137
      const curRng = editor.selection.getRng();
23138
      if (forward) {
23139
        rng.setStart(curRng.startContainer, curRng.startOffset);
23140
      } else {
23141
        rng.setEnd(curRng.endContainer, curRng.endOffset);
23142
      }
23143
      return rng;
23144
    }).exists(rng => {
23145
      moveToRange(editor, rng);
23146
      return true;
23147
    });
23148
 
23149
    const isTarget = node => contains$2(['figcaption'], name(node));
23150
    const getClosestTargetBlock = (pos, root, schema) => {
23151
      const isRoot = curry(eq, root);
23152
      return closest$4(SugarElement.fromDom(pos.container()), el => schema.isBlock(name(el)), isRoot).filter(isTarget);
23153
    };
23154
    const isAtFirstOrLastLine = (root, forward, pos) => forward ? isAtLastLine(root.dom, pos) : isAtFirstLine(root.dom, pos);
23155
    const moveCaretToNewEmptyLine = (editor, forward) => {
23156
      const root = SugarElement.fromDom(editor.getBody());
23157
      const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
23158
      return getClosestTargetBlock(pos, root, editor.schema).exists(() => {
23159
        if (isAtFirstOrLastLine(root, forward, pos)) {
23160
          const insertFn = forward ? append$1 : prepend;
23161
          const rng = insertEmptyLine(editor, root, insertFn);
23162
          editor.selection.setRng(rng);
23163
          return true;
23164
        } else {
23165
          return false;
23166
        }
23167
      });
23168
    };
23169
    const moveV$3 = (editor, forward) => {
23170
      if (editor.selection.isCollapsed()) {
23171
        return moveCaretToNewEmptyLine(editor, forward);
23172
      } else {
23173
        return false;
23174
      }
23175
    };
23176
 
23177
    const moveUp = (editor, details, summary) => {
23178
      const rng = editor.selection.getRng();
23179
      const pos = CaretPosition.fromRangeStart(rng);
23180
      const root = editor.getBody();
23181
      if (root.firstChild === details && isAtFirstLine(summary, pos)) {
23182
        editor.execCommand('InsertNewBlockBefore');
23183
        return true;
23184
      } else {
23185
        return false;
23186
      }
23187
    };
23188
    const moveDown = (editor, details) => {
23189
      const rng = editor.selection.getRng();
23190
      const pos = CaretPosition.fromRangeStart(rng);
23191
      const root = editor.getBody();
23192
      if (root.lastChild === details && isAtLastLine(details, pos)) {
23193
        editor.execCommand('InsertNewBlockAfter');
23194
        return true;
23195
      } else {
23196
        return false;
23197
      }
23198
    };
23199
    const move$2 = (editor, forward) => {
23200
      if (forward) {
23201
        return Optional.from(editor.dom.getParent(editor.selection.getNode(), 'details')).map(details => moveDown(editor, details)).getOr(false);
23202
      } else {
23203
        return Optional.from(editor.dom.getParent(editor.selection.getNode(), 'summary')).bind(summary => Optional.from(editor.dom.getParent(summary, 'details')).map(details => moveUp(editor, details, summary))).getOr(false);
23204
      }
23205
    };
23206
    const moveV$2 = (editor, forward) => move$2(editor, forward);
23207
 
23208
    const baseKeyPattern = {
23209
      shiftKey: false,
23210
      altKey: false,
23211
      ctrlKey: false,
23212
      metaKey: false,
23213
      keyCode: 0
23214
    };
23215
    const defaultPatterns = patterns => map$3(patterns, pattern => ({
23216
      ...baseKeyPattern,
23217
      ...pattern
23218
    }));
23219
    const defaultDelayedPatterns = patterns => map$3(patterns, pattern => ({
23220
      ...baseKeyPattern,
23221
      ...pattern
23222
    }));
23223
    const matchesEvent = (pattern, evt) => evt.keyCode === pattern.keyCode && evt.shiftKey === pattern.shiftKey && evt.altKey === pattern.altKey && evt.ctrlKey === pattern.ctrlKey && evt.metaKey === pattern.metaKey;
23224
    const match$1 = (patterns, evt) => bind$3(defaultPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
23225
    const matchDelayed = (patterns, evt) => bind$3(defaultDelayedPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
23226
    const action = (f, ...x) => () => f.apply(null, x);
23227
    const execute = (patterns, evt) => find$2(match$1(patterns, evt), pattern => pattern.action());
23228
    const executeWithDelayedAction = (patterns, evt) => findMap(matchDelayed(patterns, evt), pattern => pattern.action());
23229
 
23230
    const moveH$1 = (editor, forward) => {
1441 ariadna 23231
      const direction = forward ? 1 : -1;
1 efrain 23232
      const range = editor.selection.getRng();
23233
      return moveHorizontally(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
23234
        moveToRange(editor, newRange);
23235
        return true;
23236
      });
23237
    };
23238
    const moveV$1 = (editor, down) => {
23239
      const direction = down ? 1 : -1;
23240
      const range = editor.selection.getRng();
23241
      return moveVertically(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
23242
        moveToRange(editor, newRange);
23243
        return true;
23244
      });
23245
    };
23246
    const moveToLineEndPoint = (editor, forward) => {
23247
      const isNearMedia = forward ? isAfterMedia : isBeforeMedia;
23248
      return moveToLineEndPoint$3(editor, forward, isNearMedia);
23249
    };
23250
 
23251
    const adt = Adt.generate([
23252
      { none: ['current'] },
23253
      { first: ['current'] },
23254
      {
23255
        middle: [
23256
          'current',
23257
          'target'
23258
        ]
23259
      },
23260
      { last: ['current'] }
23261
    ]);
23262
    const none = current => adt.none(current);
23263
    const CellLocation = {
23264
      ...adt,
23265
      none
23266
    };
23267
 
23268
    const firstLayer = (scope, selector) => {
23269
      return filterFirstLayer(scope, selector, always);
23270
    };
23271
    const filterFirstLayer = (scope, selector, predicate) => {
23272
      return bind$3(children$1(scope), x => {
23273
        if (is$1(x, selector)) {
23274
          return predicate(x) ? [x] : [];
23275
        } else {
23276
          return filterFirstLayer(x, selector, predicate);
23277
        }
23278
      });
23279
    };
23280
 
23281
    const lookup$1 = (tags, element, isRoot = never) => {
23282
      if (isRoot(element)) {
23283
        return Optional.none();
23284
      }
23285
      if (contains$2(tags, name(element))) {
23286
        return Optional.some(element);
23287
      }
23288
      const isRootOrUpperTable = elm => is$1(elm, 'table') || isRoot(elm);
23289
      return ancestor$3(element, tags.join(','), isRootOrUpperTable);
23290
    };
23291
    const cell = (element, isRoot) => lookup$1([
23292
      'td',
23293
      'th'
23294
    ], element, isRoot);
23295
    const cells = ancestor => firstLayer(ancestor, 'th,td');
23296
    const table = (element, isRoot) => closest$3(element, 'table', isRoot);
23297
 
23298
    const walk = (all, current, index, direction, isEligible = always) => {
23299
      const forwards = direction === 1;
23300
      if (!forwards && index <= 0) {
23301
        return CellLocation.first(all[0]);
23302
      } else if (forwards && index >= all.length - 1) {
23303
        return CellLocation.last(all[all.length - 1]);
23304
      } else {
23305
        const newIndex = index + direction;
23306
        const elem = all[newIndex];
23307
        return isEligible(elem) ? CellLocation.middle(current, elem) : walk(all, current, newIndex, direction, isEligible);
23308
      }
23309
    };
23310
    const detect = (current, isRoot) => {
23311
      return table(current, isRoot).bind(table => {
23312
        const all = cells(table);
23313
        const index = findIndex$2(all, x => eq(current, x));
23314
        return index.map(index => ({
23315
          index,
23316
          all
23317
        }));
23318
      });
23319
    };
23320
    const next = (current, isEligible, isRoot) => {
23321
      const detection = detect(current, isRoot);
23322
      return detection.fold(() => {
23323
        return CellLocation.none(current);
23324
      }, info => {
23325
        return walk(info.all, current, info.index, 1, isEligible);
23326
      });
23327
    };
23328
    const prev = (current, isEligible, isRoot) => {
23329
      const detection = detect(current, isRoot);
23330
      return detection.fold(() => {
23331
        return CellLocation.none();
23332
      }, info => {
23333
        return walk(info.all, current, info.index, -1, isEligible);
23334
      });
23335
    };
23336
 
1441 ariadna 23337
    const isTextNodeWithCursorPosition = el => getOption(el).filter(text => text.trim().length !== 0 || text.indexOf(nbsp) > -1).isSome();
23338
    const isContentEditableFalse$3 = elem => isHTMLElement$1(elem) && get$9(elem, 'contenteditable') === 'false';
23339
    const elementsWithCursorPosition = [
23340
      'img',
23341
      'br'
23342
    ];
23343
    const isCursorPosition = elem => {
23344
      const hasCursorPosition = isTextNodeWithCursorPosition(elem);
23345
      return hasCursorPosition || contains$2(elementsWithCursorPosition, name(elem)) || isContentEditableFalse$3(elem);
23346
    };
23347
 
23348
    const first = element => descendant$2(element, isCursorPosition);
23349
 
1 efrain 23350
    const deflate = (rect, delta) => ({
23351
      left: rect.left - delta,
23352
      top: rect.top - delta,
23353
      right: rect.right + delta * 2,
23354
      bottom: rect.bottom + delta * 2,
23355
      width: rect.width + delta,
23356
      height: rect.height + delta
23357
    });
23358
    const getCorners = (getYAxisValue, tds) => bind$3(tds, td => {
23359
      const rect = deflate(clone$1(td.getBoundingClientRect()), -1);
23360
      return [
23361
        {
23362
          x: rect.left,
23363
          y: getYAxisValue(rect),
23364
          cell: td
23365
        },
23366
        {
23367
          x: rect.right,
23368
          y: getYAxisValue(rect),
23369
          cell: td
23370
        }
23371
      ];
23372
    });
23373
    const findClosestCorner = (corners, x, y) => foldl(corners, (acc, newCorner) => acc.fold(() => Optional.some(newCorner), oldCorner => {
23374
      const oldDist = Math.sqrt(Math.abs(oldCorner.x - x) + Math.abs(oldCorner.y - y));
23375
      const newDist = Math.sqrt(Math.abs(newCorner.x - x) + Math.abs(newCorner.y - y));
23376
      return Optional.some(newDist < oldDist ? newCorner : oldCorner);
23377
    }), Optional.none());
23378
    const getClosestCell = (getYAxisValue, isTargetCorner, table, x, y) => {
23379
      const cells = descendants(SugarElement.fromDom(table), 'td,th,caption').map(e => e.dom);
23380
      const corners = filter$5(getCorners(getYAxisValue, cells), corner => isTargetCorner(corner, y));
23381
      return findClosestCorner(corners, x, y).map(corner => corner.cell);
23382
    };
23383
    const getBottomValue = rect => rect.bottom;
23384
    const getTopValue = rect => rect.top;
23385
    const isAbove = (corner, y) => corner.y < y;
23386
    const isBelow = (corner, y) => corner.y > y;
23387
    const getClosestCellAbove = curry(getClosestCell, getBottomValue, isAbove);
23388
    const getClosestCellBelow = curry(getClosestCell, getTopValue, isBelow);
23389
    const findClosestPositionInAboveCell = (table, pos) => head(pos.getClientRects()).bind(rect => getClosestCellAbove(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getLastLinePositions(cell), pos));
1441 ariadna 23390
    const findClosestPositionInBelowCell = (table, pos) => last$2(pos.getClientRects()).bind(rect => getClosestCellBelow(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getFirstLinePositions(cell), pos));
1 efrain 23391
 
23392
    const hasNextBreak = (getPositionsUntil, scope, lineInfo) => lineInfo.breakAt.exists(breakPos => getPositionsUntil(scope, breakPos).breakAt.isSome());
23393
    const startsWithWrapBreak = lineInfo => lineInfo.breakType === BreakType.Wrap && lineInfo.positions.length === 0;
23394
    const startsWithBrBreak = lineInfo => lineInfo.breakType === BreakType.Br && lineInfo.positions.length === 1;
23395
    const isAtTableCellLine = (getPositionsUntil, scope, pos) => {
23396
      const lineInfo = getPositionsUntil(scope, pos);
23397
      if (startsWithWrapBreak(lineInfo) || !isBr$6(pos.getNode()) && startsWithBrBreak(lineInfo)) {
23398
        return !hasNextBreak(getPositionsUntil, scope, lineInfo);
23399
      } else {
23400
        return lineInfo.breakAt.isNone();
23401
      }
23402
    };
23403
    const isAtFirstTableCellLine = curry(isAtTableCellLine, getPositionsUntilPreviousLine);
23404
    const isAtLastTableCellLine = curry(isAtTableCellLine, getPositionsUntilNextLine);
23405
    const isCaretAtStartOrEndOfTable = (forward, rng, table) => {
23406
      const caretPos = CaretPosition.fromRangeStart(rng);
23407
      return positionIn(!forward, table).exists(pos => pos.isEqual(caretPos));
23408
    };
23409
    const navigateHorizontally = (editor, forward, table, _td) => {
23410
      const rng = editor.selection.getRng();
23411
      const direction = forward ? 1 : -1;
23412
      if (isFakeCaretTableBrowser() && isCaretAtStartOrEndOfTable(forward, rng, table)) {
23413
        showCaret(direction, editor, table, !forward, false).each(newRng => {
23414
          moveToRange(editor, newRng);
23415
        });
23416
        return true;
23417
      }
23418
      return false;
23419
    };
23420
    const getClosestAbovePosition = (root, table, start) => findClosestPositionInAboveCell(table, start).orThunk(() => head(start.getClientRects()).bind(rect => findClosestHorizontalPositionFromPoint(getPositionsAbove(root, CaretPosition.before(table)), rect.left))).getOr(CaretPosition.before(table));
23421
    const getClosestBelowPosition = (root, table, start) => findClosestPositionInBelowCell(table, start).orThunk(() => head(start.getClientRects()).bind(rect => findClosestHorizontalPositionFromPoint(getPositionsBelow(root, CaretPosition.after(table)), rect.left))).getOr(CaretPosition.after(table));
23422
    const getTable = (previous, pos) => {
23423
      const node = pos.getNode(previous);
23424
      return isTable$2(node) ? Optional.some(node) : Optional.none();
23425
    };
23426
    const renderBlock = (down, editor, table) => {
23427
      editor.undoManager.transact(() => {
23428
        const insertFn = down ? after$4 : before$3;
23429
        const rng = insertEmptyLine(editor, SugarElement.fromDom(table), insertFn);
23430
        moveToRange(editor, rng);
23431
      });
23432
    };
23433
    const moveCaret = (editor, down, pos) => {
23434
      const table = down ? getTable(true, pos) : getTable(false, pos);
23435
      const last = down === false;
23436
      table.fold(() => moveToRange(editor, pos.toRange()), table => positionIn(last, editor.getBody()).filter(lastPos => lastPos.isEqual(pos)).fold(() => moveToRange(editor, pos.toRange()), _ => renderBlock(down, editor, table)));
23437
    };
23438
    const navigateVertically = (editor, down, table, td) => {
23439
      const rng = editor.selection.getRng();
23440
      const pos = CaretPosition.fromRangeStart(rng);
23441
      const root = editor.getBody();
23442
      if (!down && isAtFirstTableCellLine(td, pos)) {
23443
        const newPos = getClosestAbovePosition(root, table, pos);
23444
        moveCaret(editor, down, newPos);
23445
        return true;
23446
      } else if (down && isAtLastTableCellLine(td, pos)) {
23447
        const newPos = getClosestBelowPosition(root, table, pos);
23448
        moveCaret(editor, down, newPos);
23449
        return true;
23450
      } else {
23451
        return false;
23452
      }
23453
    };
23454
    const move$1 = (editor, forward, mover) => Optional.from(editor.dom.getParent(editor.selection.getNode(), 'td,th')).bind(td => Optional.from(editor.dom.getParent(td, 'table')).map(table => mover(editor, forward, table, td))).getOr(false);
23455
    const moveH = (editor, forward) => move$1(editor, forward, navigateHorizontally);
23456
    const moveV = (editor, forward) => move$1(editor, forward, navigateVertically);
23457
    const getCellFirstCursorPosition = cell => {
23458
      const selection = SimSelection.exact(cell, 0, cell, 0);
23459
      return toNative(selection);
23460
    };
23461
    const tabGo = (editor, isRoot, cell) => {
23462
      return cell.fold(Optional.none, Optional.none, (_current, next) => {
23463
        return first(next).map(cell => {
23464
          return getCellFirstCursorPosition(cell);
23465
        });
23466
      }, current => {
1441 ariadna 23467
        if (editor.mode.isReadOnly()) {
23468
          return Optional.none();
23469
        }
1 efrain 23470
        editor.execCommand('mceTableInsertRowAfter');
23471
        return tabForward(editor, isRoot, current);
23472
      });
23473
    };
23474
    const tabForward = (editor, isRoot, cell) => tabGo(editor, isRoot, next(cell, isEditable$2));
23475
    const tabBackward = (editor, isRoot, cell) => tabGo(editor, isRoot, prev(cell, isEditable$2));
23476
    const handleTab = (editor, forward) => {
23477
      const rootElements = [
23478
        'table',
23479
        'li',
23480
        'dl'
23481
      ];
23482
      const body = SugarElement.fromDom(editor.getBody());
23483
      const isRoot = element => {
23484
        const name$1 = name(element);
23485
        return eq(element, body) || contains$2(rootElements, name$1);
23486
      };
23487
      const rng = editor.selection.getRng();
23488
      const container = SugarElement.fromDom(!forward ? rng.startContainer : rng.endContainer);
23489
      return cell(container, isRoot).map(cell => {
23490
        table(cell, isRoot).each(table => {
23491
          editor.model.table.clearSelectedCells(table.dom);
23492
        });
23493
        editor.selection.collapse(!forward);
23494
        const navigation = !forward ? tabBackward : tabForward;
23495
        const rng = navigation(editor, isRoot, cell);
23496
        rng.each(range => {
23497
          editor.selection.setRng(range);
23498
        });
23499
        return true;
23500
      }).getOr(false);
23501
    };
23502
 
23503
    const executeKeydownOverride$4 = (editor, caret, evt) => {
23504
      const isMac = Env.os.isMacOS() || Env.os.isiOS();
23505
      execute([
23506
        {
23507
          keyCode: VK.RIGHT,
23508
          action: action(moveH$2, editor, true)
23509
        },
23510
        {
23511
          keyCode: VK.LEFT,
23512
          action: action(moveH$2, editor, false)
23513
        },
23514
        {
23515
          keyCode: VK.UP,
23516
          action: action(moveV$4, editor, false)
23517
        },
23518
        {
23519
          keyCode: VK.DOWN,
23520
          action: action(moveV$4, editor, true)
23521
        },
23522
        ...isMac ? [
23523
          {
23524
            keyCode: VK.UP,
23525
            action: action(selectToEndPoint, editor, false),
23526
            metaKey: true,
23527
            shiftKey: true
23528
          },
23529
          {
23530
            keyCode: VK.DOWN,
23531
            action: action(selectToEndPoint, editor, true),
23532
            metaKey: true,
23533
            shiftKey: true
23534
          }
23535
        ] : [],
23536
        {
23537
          keyCode: VK.RIGHT,
23538
          action: action(moveH, editor, true)
23539
        },
23540
        {
23541
          keyCode: VK.LEFT,
23542
          action: action(moveH, editor, false)
23543
        },
23544
        {
23545
          keyCode: VK.UP,
23546
          action: action(moveV, editor, false)
23547
        },
23548
        {
23549
          keyCode: VK.DOWN,
23550
          action: action(moveV, editor, true)
23551
        },
23552
        {
23553
          keyCode: VK.UP,
23554
          action: action(moveV, editor, false)
23555
        },
23556
        {
23557
          keyCode: VK.UP,
23558
          action: action(moveV$2, editor, false)
23559
        },
23560
        {
23561
          keyCode: VK.DOWN,
23562
          action: action(moveV$2, editor, true)
23563
        },
23564
        {
23565
          keyCode: VK.RIGHT,
23566
          action: action(moveH$1, editor, true)
23567
        },
23568
        {
23569
          keyCode: VK.LEFT,
23570
          action: action(moveH$1, editor, false)
23571
        },
23572
        {
23573
          keyCode: VK.UP,
23574
          action: action(moveV$1, editor, false)
23575
        },
23576
        {
23577
          keyCode: VK.DOWN,
23578
          action: action(moveV$1, editor, true)
23579
        },
23580
        {
23581
          keyCode: VK.RIGHT,
23582
          action: action(move$3, editor, caret, true)
23583
        },
23584
        {
23585
          keyCode: VK.LEFT,
23586
          action: action(move$3, editor, caret, false)
23587
        },
23588
        {
23589
          keyCode: VK.RIGHT,
23590
          ctrlKey: !isMac,
23591
          altKey: isMac,
23592
          action: action(moveNextWord, editor, caret)
23593
        },
23594
        {
23595
          keyCode: VK.LEFT,
23596
          ctrlKey: !isMac,
23597
          altKey: isMac,
23598
          action: action(movePrevWord, editor, caret)
23599
        },
23600
        {
23601
          keyCode: VK.UP,
23602
          action: action(moveV$3, editor, false)
23603
        },
23604
        {
23605
          keyCode: VK.DOWN,
23606
          action: action(moveV$3, editor, true)
23607
        }
23608
      ], evt).each(_ => {
23609
        evt.preventDefault();
23610
      });
23611
    };
23612
    const setup$l = (editor, caret) => {
23613
      editor.on('keydown', evt => {
23614
        if (!evt.isDefaultPrevented()) {
23615
          executeKeydownOverride$4(editor, caret, evt);
23616
        }
23617
      });
23618
    };
23619
 
23620
    const point = (container, offset) => ({
23621
      container,
23622
      offset
23623
    });
23624
 
23625
    const DOM$7 = DOMUtils.DOM;
23626
    const alwaysNext = startNode => node => startNode === node ? -1 : 0;
23627
    const isBoundary = dom => node => dom.isBlock(node) || contains$2([
23628
      'BR',
23629
      'IMG',
23630
      'HR',
23631
      'INPUT'
23632
    ], node.nodeName) || dom.getContentEditable(node) === 'false';
23633
    const textBefore = (node, offset, rootNode) => {
1441 ariadna 23634
      if (isText$b(node) && offset >= 0) {
1 efrain 23635
        return Optional.some(point(node, offset));
23636
      } else {
23637
        const textSeeker = TextSeeker(DOM$7);
23638
        return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, prev.container.data.length));
23639
      }
23640
    };
23641
    const textAfter = (node, offset, rootNode) => {
1441 ariadna 23642
      if (isText$b(node) && offset >= node.length) {
1 efrain 23643
        return Optional.some(point(node, offset));
23644
      } else {
23645
        const textSeeker = TextSeeker(DOM$7);
23646
        return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, 0));
23647
      }
23648
    };
23649
    const scanLeft = (node, offset, rootNode) => {
1441 ariadna 23650
      if (!isText$b(node)) {
1 efrain 23651
        return Optional.none();
23652
      }
23653
      const text = node.data;
23654
      if (offset >= 0 && offset <= text.length) {
23655
        return Optional.some(point(node, offset));
23656
      } else {
23657
        const textSeeker = TextSeeker(DOM$7);
23658
        return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).bind(prev => {
23659
          const prevText = prev.container.data;
23660
          return scanLeft(prev.container, offset + prevText.length, rootNode);
23661
        });
23662
      }
23663
    };
23664
    const scanRight = (node, offset, rootNode) => {
1441 ariadna 23665
      if (!isText$b(node)) {
1 efrain 23666
        return Optional.none();
23667
      }
23668
      const text = node.data;
23669
      if (offset <= text.length) {
23670
        return Optional.some(point(node, offset));
23671
      } else {
23672
        const textSeeker = TextSeeker(DOM$7);
23673
        return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).bind(next => scanRight(next.container, offset - text.length, rootNode));
23674
      }
23675
    };
23676
    const repeatLeft = (dom, node, offset, process, rootNode) => {
23677
      const search = TextSeeker(dom, isBoundary(dom));
23678
      return Optional.from(search.backwards(node, offset, process, rootNode));
23679
    };
23680
 
1441 ariadna 23681
    const isValidTextRange = rng => rng.collapsed && isText$b(rng.startContainer);
1 efrain 23682
    const getText = rng => trim$2(rng.toString().replace(/\u00A0/g, ' '));
1441 ariadna 23683
    const isWhitespace = chr => chr !== '' && ' \xA0\uFEFF\f\n\r\t\x0B'.indexOf(chr) !== -1;
1 efrain 23684
 
23685
    const stripTrigger = (text, trigger) => text.substring(trigger.length);
1441 ariadna 23686
    const findTrigger = (text, index, trigger, includeWhitespace = false) => {
1 efrain 23687
      let i;
23688
      const firstChar = trigger.charAt(0);
23689
      for (i = index - 1; i >= 0; i--) {
23690
        const char = text.charAt(i);
1441 ariadna 23691
        if (!includeWhitespace && isWhitespace(char)) {
1 efrain 23692
          return Optional.none();
23693
        }
23694
        if (firstChar === char && contains$1(text, trigger, i, index)) {
23695
          break;
23696
        }
23697
      }
23698
      return Optional.some(i);
23699
    };
1441 ariadna 23700
    const getContext = (dom, initRange, trigger, includeWhitespace = false) => {
1 efrain 23701
      if (!isValidTextRange(initRange)) {
23702
        return Optional.none();
23703
      }
23704
      const buffer = {
23705
        text: '',
23706
        offset: 0
23707
      };
23708
      const findTriggerIndex = (element, offset, text) => {
23709
        buffer.text = text + buffer.text;
23710
        buffer.offset += offset;
1441 ariadna 23711
        return findTrigger(buffer.text, buffer.offset, trigger, includeWhitespace).getOr(offset);
1 efrain 23712
      };
23713
      const root = dom.getParent(initRange.startContainer, dom.isBlock) || dom.getRoot();
23714
      return repeatLeft(dom, initRange.startContainer, initRange.startOffset, findTriggerIndex, root).bind(spot => {
23715
        const range = initRange.cloneRange();
23716
        range.setStart(spot.container, spot.offset);
23717
        range.setEnd(initRange.endContainer, initRange.endOffset);
23718
        if (range.collapsed) {
23719
          return Optional.none();
23720
        }
23721
        const text = getText(range);
23722
        const triggerIndex = text.lastIndexOf(trigger);
1441 ariadna 23723
        if (triggerIndex !== 0) {
1 efrain 23724
          return Optional.none();
23725
        } else {
23726
          return Optional.some({
23727
            text: stripTrigger(text, trigger),
23728
            range,
23729
            trigger
23730
          });
23731
        }
23732
      });
23733
    };
23734
 
23735
    const isText$1 = node => node.nodeType === TEXT;
23736
    const isElement = node => node.nodeType === ELEMENT;
23737
    const toLast = node => {
23738
      if (isText$1(node)) {
23739
        return point(node, node.data.length);
23740
      } else {
23741
        const children = node.childNodes;
23742
        return children.length > 0 ? toLast(children[children.length - 1]) : point(node, children.length);
23743
      }
23744
    };
23745
    const toLeaf = (node, offset) => {
23746
      const children = node.childNodes;
23747
      if (children.length > 0 && offset < children.length) {
23748
        return toLeaf(children[offset], 0);
23749
      } else if (children.length > 0 && isElement(node) && children.length === offset) {
23750
        return toLast(children[children.length - 1]);
23751
      } else {
23752
        return point(node, offset);
23753
      }
23754
    };
23755
 
23756
    const isPreviousCharContent = (dom, leaf) => {
23757
      var _a;
23758
      const root = (_a = dom.getParent(leaf.container, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot();
23759
      return repeatLeft(dom, leaf.container, leaf.offset, (_element, offset) => offset === 0 ? -1 : offset, root).filter(spot => {
23760
        const char = spot.container.data.charAt(spot.offset - 1);
23761
        return !isWhitespace(char);
23762
      }).isSome();
23763
    };
23764
    const isStartOfWord = dom => rng => {
23765
      const leaf = toLeaf(rng.startContainer, rng.startOffset);
23766
      return !isPreviousCharContent(dom, leaf);
23767
    };
23768
    const getTriggerContext = (dom, initRange, database) => findMap(database.triggers, trigger => getContext(dom, initRange, trigger));
23769
    const lookup = (editor, getDatabase) => {
23770
      const database = getDatabase();
23771
      const rng = editor.selection.getRng();
23772
      return getTriggerContext(editor.dom, rng, database).bind(context => lookupWithContext(editor, getDatabase, context));
23773
    };
23774
    const lookupWithContext = (editor, getDatabase, context, fetchOptions = {}) => {
23775
      var _a;
23776
      const database = getDatabase();
23777
      const rng = editor.selection.getRng();
23778
      const startText = (_a = rng.startContainer.nodeValue) !== null && _a !== void 0 ? _a : '';
23779
      const autocompleters = filter$5(database.lookupByTrigger(context.trigger), autocompleter => context.text.length >= autocompleter.minChars && autocompleter.matches.getOrThunk(() => isStartOfWord(editor.dom))(context.range, startText, context.text));
23780
      if (autocompleters.length === 0) {
23781
        return Optional.none();
23782
      }
23783
      const lookupData = Promise.all(map$3(autocompleters, ac => {
23784
        const fetchResult = ac.fetch(context.text, ac.maxResults, fetchOptions);
23785
        return fetchResult.then(results => ({
23786
          matchText: context.text,
23787
          items: results,
23788
          columns: ac.columns,
23789
          onAction: ac.onAction,
23790
          highlightOn: ac.highlightOn
23791
        }));
23792
      }));
23793
      return Optional.some({
23794
        lookupData,
23795
        context
23796
      });
23797
    };
23798
 
23799
    var SimpleResultType;
23800
    (function (SimpleResultType) {
23801
      SimpleResultType[SimpleResultType['Error'] = 0] = 'Error';
23802
      SimpleResultType[SimpleResultType['Value'] = 1] = 'Value';
23803
    }(SimpleResultType || (SimpleResultType = {})));
23804
    const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
23805
    const partition = results => {
23806
      const values = [];
23807
      const errors = [];
23808
      each$e(results, obj => {
23809
        fold$1(obj, err => errors.push(err), val => values.push(val));
23810
      });
23811
      return {
23812
        values,
23813
        errors
23814
      };
23815
    };
23816
    const mapError = (res, f) => {
23817
      if (res.stype === SimpleResultType.Error) {
23818
        return {
23819
          stype: SimpleResultType.Error,
23820
          serror: f(res.serror)
23821
        };
23822
      } else {
23823
        return res;
23824
      }
23825
    };
23826
    const map = (res, f) => {
23827
      if (res.stype === SimpleResultType.Value) {
23828
        return {
23829
          stype: SimpleResultType.Value,
23830
          svalue: f(res.svalue)
23831
        };
23832
      } else {
23833
        return res;
23834
      }
23835
    };
23836
    const bind$1 = (res, f) => {
23837
      if (res.stype === SimpleResultType.Value) {
23838
        return f(res.svalue);
23839
      } else {
23840
        return res;
23841
      }
23842
    };
23843
    const bindError = (res, f) => {
23844
      if (res.stype === SimpleResultType.Error) {
23845
        return f(res.serror);
23846
      } else {
23847
        return res;
23848
      }
23849
    };
23850
    const svalue = v => ({
23851
      stype: SimpleResultType.Value,
23852
      svalue: v
23853
    });
23854
    const serror = e => ({
23855
      stype: SimpleResultType.Error,
23856
      serror: e
23857
    });
23858
    const toResult = res => fold$1(res, Result.error, Result.value);
23859
    const fromResult = res => res.fold(serror, svalue);
23860
    const SimpleResult = {
23861
      fromResult,
23862
      toResult,
23863
      svalue,
23864
      partition,
23865
      serror,
23866
      bind: bind$1,
23867
      bindError,
23868
      map,
23869
      mapError,
23870
      fold: fold$1
23871
    };
23872
 
23873
    const formatObj = input => {
23874
      return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
23875
    };
23876
    const formatErrors = errors => {
23877
      const es = errors.length > 10 ? errors.slice(0, 10).concat([{
23878
          path: [],
23879
          getErrorInfo: constant('... (only showing first ten failures)')
23880
        }]) : errors;
23881
      return map$3(es, e => {
23882
        return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
23883
      });
23884
    };
23885
 
23886
    const nu = (path, getErrorInfo) => {
23887
      return SimpleResult.serror([{
23888
          path,
23889
          getErrorInfo
23890
        }]);
23891
    };
23892
    const missingRequired = (path, key, obj) => nu(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
23893
    const missingKey = (path, key) => nu(path, () => 'Choice schema did not contain choice key: "' + key + '"');
23894
    const missingBranch = (path, branches, branch) => nu(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
23895
    const custom = (path, err) => nu(path, constant(err));
23896
 
23897
    const chooseFrom = (path, input, branches, ch) => {
23898
      const fields = get$a(branches, ch);
23899
      return fields.fold(() => missingBranch(path, branches, ch), vp => vp.extract(path.concat(['branch: ' + ch]), input));
23900
    };
23901
    const choose$1 = (key, branches) => {
23902
      const extract = (path, input) => {
23903
        const choice = get$a(input, key);
23904
        return choice.fold(() => missingKey(path, key), chosen => chooseFrom(path, input, branches, chosen));
23905
      };
23906
      const toString = () => 'chooseOn(' + key + '). Possible values: ' + keys(branches);
23907
      return {
23908
        extract,
23909
        toString
23910
      };
23911
    };
23912
 
23913
    const shallow = (old, nu) => {
23914
      return nu;
23915
    };
23916
    const deep = (old, nu) => {
23917
      const bothObjects = isPlainObject(old) && isPlainObject(nu);
23918
      return bothObjects ? deepMerge(old, nu) : nu;
23919
    };
23920
    const baseMerge = merger => {
23921
      return (...objects) => {
23922
        if (objects.length === 0) {
23923
          throw new Error(`Can't merge zero objects`);
23924
        }
23925
        const ret = {};
23926
        for (let j = 0; j < objects.length; j++) {
23927
          const curObject = objects[j];
23928
          for (const key in curObject) {
23929
            if (has$2(curObject, key)) {
23930
              ret[key] = merger(ret[key], curObject[key]);
23931
            }
23932
          }
23933
        }
23934
        return ret;
23935
      };
23936
    };
23937
    const deepMerge = baseMerge(deep);
23938
    const merge = baseMerge(shallow);
23939
 
23940
    const required = () => ({
23941
      tag: 'required',
23942
      process: {}
23943
    });
23944
    const defaultedThunk = fallbackThunk => ({
23945
      tag: 'defaultedThunk',
23946
      process: fallbackThunk
23947
    });
23948
    const defaulted$1 = fallback => defaultedThunk(constant(fallback));
23949
    const asOption = () => ({
23950
      tag: 'option',
23951
      process: {}
23952
    });
23953
 
23954
    const mergeValues = (values, base) => values.length > 0 ? SimpleResult.svalue(deepMerge(base, merge.apply(undefined, values))) : SimpleResult.svalue(base);
23955
    const mergeErrors = errors => compose(SimpleResult.serror, flatten)(errors);
23956
    const consolidateObj = (objects, base) => {
23957
      const partition = SimpleResult.partition(objects);
23958
      return partition.errors.length > 0 ? mergeErrors(partition.errors) : mergeValues(partition.values, base);
23959
    };
23960
    const consolidateArr = objects => {
23961
      const partitions = SimpleResult.partition(objects);
23962
      return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : SimpleResult.svalue(partitions.values);
23963
    };
23964
    const ResultCombine = {
23965
      consolidateObj,
23966
      consolidateArr
23967
    };
23968
 
23969
    const field$1 = (key, newKey, presence, prop) => ({
23970
      tag: 'field',
23971
      key,
23972
      newKey,
23973
      presence,
23974
      prop
23975
    });
23976
    const customField$1 = (newKey, instantiator) => ({
23977
      tag: 'custom',
23978
      newKey,
23979
      instantiator
23980
    });
23981
    const fold = (value, ifField, ifCustom) => {
23982
      switch (value.tag) {
23983
      case 'field':
23984
        return ifField(value.key, value.newKey, value.presence, value.prop);
23985
      case 'custom':
23986
        return ifCustom(value.newKey, value.instantiator);
23987
      }
23988
    };
23989
 
23990
    const value = validator => {
23991
      const extract = (path, val) => {
23992
        return SimpleResult.bindError(validator(val), err => custom(path, err));
23993
      };
23994
      const toString = constant('val');
23995
      return {
23996
        extract,
23997
        toString
23998
      };
23999
    };
24000
    const anyValue$1 = value(SimpleResult.svalue);
24001
 
24002
    const requiredAccess = (path, obj, key, bundle) => get$a(obj, key).fold(() => missingRequired(path, key, obj), bundle);
24003
    const fallbackAccess = (obj, key, fallback, bundle) => {
24004
      const v = get$a(obj, key).getOrThunk(() => fallback(obj));
24005
      return bundle(v);
24006
    };
24007
    const optionAccess = (obj, key, bundle) => bundle(get$a(obj, key));
24008
    const optionDefaultedAccess = (obj, key, fallback, bundle) => {
24009
      const opt = get$a(obj, key).map(val => val === true ? fallback(obj) : val);
24010
      return bundle(opt);
24011
    };
24012
    const extractField = (field, path, obj, key, prop) => {
24013
      const bundle = av => prop.extract(path.concat([key]), av);
24014
      const bundleAsOption = optValue => optValue.fold(() => SimpleResult.svalue(Optional.none()), ov => {
24015
        const result = prop.extract(path.concat([key]), ov);
24016
        return SimpleResult.map(result, Optional.some);
24017
      });
24018
      switch (field.tag) {
24019
      case 'required':
24020
        return requiredAccess(path, obj, key, bundle);
24021
      case 'defaultedThunk':
24022
        return fallbackAccess(obj, key, field.process, bundle);
24023
      case 'option':
24024
        return optionAccess(obj, key, bundleAsOption);
24025
      case 'defaultedOptionThunk':
24026
        return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
24027
      case 'mergeWithThunk': {
24028
          return fallbackAccess(obj, key, constant({}), v => {
24029
            const result = deepMerge(field.process(obj), v);
24030
            return bundle(result);
24031
          });
24032
        }
24033
      }
24034
    };
24035
    const extractFields = (path, obj, fields) => {
24036
      const success = {};
24037
      const errors = [];
24038
      for (const field of fields) {
24039
        fold(field, (key, newKey, presence, prop) => {
24040
          const result = extractField(presence, path, obj, key, prop);
24041
          SimpleResult.fold(result, err => {
24042
            errors.push(...err);
24043
          }, res => {
24044
            success[newKey] = res;
24045
          });
24046
        }, (newKey, instantiator) => {
24047
          success[newKey] = instantiator(obj);
24048
        });
24049
      }
24050
      return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
24051
    };
24052
    const objOf = values => {
24053
      const extract = (path, o) => extractFields(path, o, values);
24054
      const toString = () => {
24055
        const fieldStrings = map$3(values, value => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
24056
        return 'obj{\n' + fieldStrings.join('\n') + '}';
24057
      };
24058
      return {
24059
        extract,
24060
        toString
24061
      };
24062
    };
24063
    const arrOf = prop => {
24064
      const extract = (path, array) => {
24065
        const results = map$3(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
24066
        return ResultCombine.consolidateArr(results);
24067
      };
24068
      const toString = () => 'array(' + prop.toString() + ')';
24069
      return {
24070
        extract,
24071
        toString
24072
      };
24073
    };
1441 ariadna 24074
    const oneOf = (props, rawF) => {
24075
      const f = rawF !== undefined ? rawF : identity;
24076
      const extract = (path, val) => {
24077
        const errors = [];
24078
        for (const prop of props) {
24079
          const res = prop.extract(path, val);
24080
          if (res.stype === SimpleResultType.Value) {
24081
            return {
24082
              stype: SimpleResultType.Value,
24083
              svalue: f(res.svalue)
24084
            };
24085
          }
24086
          errors.push(res);
24087
        }
24088
        return ResultCombine.consolidateArr(errors);
24089
      };
24090
      const toString = () => 'oneOf(' + map$3(props, prop => prop.toString()).join(', ') + ')';
24091
      return {
24092
        extract,
24093
        toString
24094
      };
24095
    };
24096
    const arrOfObj = compose(arrOf, objOf);
1 efrain 24097
 
24098
    const valueOf = validator => value(v => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
24099
    const extractValue = (label, prop, obj) => {
24100
      const res = prop.extract([label], obj);
24101
      return SimpleResult.mapError(res, errs => ({
24102
        input: obj,
24103
        errors: errs
24104
      }));
24105
    };
24106
    const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
24107
    const formatError = errInfo => {
24108
      return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input);
24109
    };
24110
    const choose = (key, branches) => choose$1(key, map$2(branches, objOf));
24111
 
24112
    const anyValue = constant(anyValue$1);
24113
    const typedValue = (validator, expectedType) => value(a => {
24114
      const actualType = typeof a;
24115
      return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${ expectedType } but got: ${ actualType }`);
24116
    });
24117
    const number = typedValue(isNumber, 'number');
24118
    const string = typedValue(isString, 'string');
24119
    const boolean = typedValue(isBoolean, 'boolean');
24120
    const functionProcessor = typedValue(isFunction, 'function');
24121
 
24122
    const field = field$1;
24123
    const customField = customField$1;
24124
    const validateEnum = values => valueOf(value => contains$2(values, value) ? Result.value(value) : Result.error(`Unsupported value: "${ value }", choose one of "${ values.join(', ') }".`));
24125
    const requiredOf = (key, schema) => field(key, key, required(), schema);
24126
    const requiredString = key => requiredOf(key, string);
1441 ariadna 24127
    const requiredStringEnum = (key, values) => field(key, key, required(), validateEnum(values));
1 efrain 24128
    const requiredFunction = key => requiredOf(key, functionProcessor);
24129
    const requiredArrayOf = (key, schema) => field(key, key, required(), arrOf(schema));
24130
    const optionOf = (key, schema) => field(key, key, asOption(), schema);
24131
    const optionString = key => optionOf(key, string);
24132
    const optionFunction = key => optionOf(key, functionProcessor);
24133
    const defaulted = (key, fallback) => field(key, key, defaulted$1(fallback), anyValue());
24134
    const defaultedOf = (key, fallback, schema) => field(key, key, defaulted$1(fallback), schema);
24135
    const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
24136
    const defaultedString = (key, fallback) => defaultedOf(key, fallback, string);
24137
    const defaultedStringEnum = (key, fallback, values) => defaultedOf(key, fallback, validateEnum(values));
24138
    const defaultedBoolean = (key, fallback) => defaultedOf(key, fallback, boolean);
24139
    const defaultedFunction = (key, fallback) => defaultedOf(key, fallback, functionProcessor);
24140
    const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
24141
 
24142
    const type = requiredString('type');
24143
    const fetch$1 = requiredFunction('fetch');
24144
    const onAction = requiredFunction('onAction');
24145
    const onSetup = defaultedFunction('onSetup', () => noop);
24146
    const optionalText = optionString('text');
24147
    const optionalIcon = optionString('icon');
24148
    const optionalTooltip = optionString('tooltip');
24149
    const optionalLabel = optionString('label');
24150
    const active = defaultedBoolean('active', false);
24151
    const enabled = defaultedBoolean('enabled', true);
24152
    const primary = defaultedBoolean('primary', false);
24153
    const defaultedColumns = num => defaulted('columns', num);
24154
    const defaultedType = type => defaultedString('type', type);
24155
 
24156
    const autocompleterSchema = objOf([
24157
      type,
24158
      requiredString('trigger'),
24159
      defaultedNumber('minChars', 1),
24160
      defaultedColumns(1),
24161
      defaultedNumber('maxResults', 10),
24162
      optionFunction('matches'),
24163
      fetch$1,
24164
      onAction,
24165
      defaultedArrayOf('highlightOn', [], string)
24166
    ]);
1441 ariadna 24167
    const createAutocompleter = spec => asRaw('Autocompleter', autocompleterSchema, spec);
1 efrain 24168
 
24169
    const baseToolbarButtonFields = [
24170
      enabled,
24171
      optionalTooltip,
24172
      optionalIcon,
24173
      optionalText,
1441 ariadna 24174
      onSetup,
24175
      defaultedString('context', 'mode:design')
1 efrain 24176
    ];
24177
 
24178
    const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
24179
 
24180
    const contextBarFields = [
24181
      defaultedFunction('predicate', never),
24182
      defaultedStringEnum('scope', 'node', [
24183
        'node',
24184
        'editor'
24185
      ]),
24186
      defaultedStringEnum('position', 'selection', [
24187
        'node',
24188
        'selection',
24189
        'line'
24190
      ])
24191
    ];
24192
 
24193
    const contextButtonFields = baseToolbarButtonFields.concat([
24194
      defaultedType('contextformbutton'),
1441 ariadna 24195
      defaultedString('align', 'end'),
1 efrain 24196
      primary,
24197
      onAction,
24198
      customField('original', identity)
24199
    ]);
24200
    const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
24201
      defaultedType('contextformbutton'),
1441 ariadna 24202
      defaultedString('align', 'end'),
1 efrain 24203
      primary,
24204
      onAction,
24205
      customField('original', identity)
24206
    ]);
24207
    const launchButtonFields = baseToolbarButtonFields.concat([defaultedType('contextformbutton')]);
24208
    const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType('contextformtogglebutton')]);
24209
    const toggleOrNormal = choose('type', {
24210
      contextformbutton: contextButtonFields,
24211
      contextformtogglebutton: contextToggleButtonFields
24212
    });
1441 ariadna 24213
    const baseContextFormFields = [
1 efrain 24214
      optionalLabel,
24215
      requiredArrayOf('commands', toggleOrNormal),
24216
      optionOf('launch', choose('type', {
24217
        contextformbutton: launchButtonFields,
24218
        contextformtogglebutton: launchToggleButtonFields
1441 ariadna 24219
      })),
24220
      defaultedFunction('onInput', noop),
24221
      defaultedFunction('onSetup', noop)
24222
    ];
24223
    const contextFormFields = [
24224
      ...contextBarFields,
24225
      ...baseContextFormFields,
24226
      requiredStringEnum('type', ['contextform']),
24227
      defaultedFunction('initValue', constant('')),
24228
      optionString('placeholder')
24229
    ];
24230
    const contextSliderFormFields = [
24231
      ...contextBarFields,
24232
      ...baseContextFormFields,
24233
      requiredStringEnum('type', ['contextsliderform']),
24234
      defaultedFunction('initValue', constant(0)),
24235
      defaultedFunction('min', constant(0)),
24236
      defaultedFunction('max', constant(100))
24237
    ];
24238
    const contextSizeInputFormFields = [
24239
      ...contextBarFields,
24240
      ...baseContextFormFields,
24241
      requiredStringEnum('type', ['contextsizeinputform']),
24242
      defaultedFunction('initValue', constant({
24243
        width: '',
24244
        height: ''
1 efrain 24245
      }))
1441 ariadna 24246
    ];
24247
    choose('type', {
24248
      contextform: contextFormFields,
24249
      contextsliderform: contextSliderFormFields,
24250
      contextsizeinputform: contextSizeInputFormFields
24251
    });
24252
 
24253
    objOf([
24254
      defaultedType('contexttoolbar'),
24255
      requiredOf('items', oneOf([
24256
        string,
24257
        arrOfObj([
24258
          optionString('name'),
24259
          optionString('label'),
24260
          requiredArrayOf('items', string)
24261
        ])
24262
      ]))
1 efrain 24263
    ].concat(contextBarFields));
24264
 
24265
    const register$2 = editor => {
24266
      const popups = editor.ui.registry.getAll().popups;
24267
      const dataset = map$2(popups, popup => createAutocompleter(popup).fold(err => {
24268
        throw new Error(formatError(err));
24269
      }, identity));
24270
      const triggers = stringArray(mapToArray(dataset, v => v.trigger));
24271
      const datasetValues = values(dataset);
24272
      const lookupByTrigger = trigger => filter$5(datasetValues, dv => dv.trigger === trigger);
24273
      return {
24274
        dataset,
24275
        triggers,
24276
        lookupByTrigger
24277
      };
24278
    };
24279
 
24280
    const setupEditorInput = (editor, api) => {
1441 ariadna 24281
      const update = last(api.load, 50);
24282
      editor.on('input', e => {
24283
        if (e.inputType === 'insertCompositionText' && !editor.composing) {
1 efrain 24284
          return;
24285
        }
24286
        update.throttle();
24287
      });
24288
      editor.on('keydown', e => {
24289
        const keyCode = e.which;
24290
        if (keyCode === 8) {
24291
          update.throttle();
24292
        } else if (keyCode === 27) {
1441 ariadna 24293
          update.cancel();
1 efrain 24294
          api.cancelIfNecessary();
1441 ariadna 24295
        } else if (keyCode === 38 || keyCode === 40) {
24296
          update.cancel();
1 efrain 24297
        }
1441 ariadna 24298
      }, true);
1 efrain 24299
      editor.on('remove', update.cancel);
24300
    };
24301
    const setup$k = editor => {
24302
      const activeAutocompleter = value$2();
24303
      const uiActive = Cell(false);
24304
      const isActive = activeAutocompleter.isSet;
24305
      const cancelIfNecessary = () => {
24306
        if (isActive()) {
24307
          fireAutocompleterEnd(editor);
24308
          uiActive.set(false);
24309
          activeAutocompleter.clear();
24310
        }
24311
      };
24312
      const commenceIfNecessary = context => {
24313
        if (!isActive()) {
24314
          activeAutocompleter.set({
24315
            trigger: context.trigger,
24316
            matchLength: context.text.length
24317
          });
24318
        }
24319
      };
24320
      const getAutocompleters = cached(() => register$2(editor));
1441 ariadna 24321
      const doLookup = fetchOptions => activeAutocompleter.get().map(ac => getContext(editor.dom, editor.selection.getRng(), ac.trigger, true).bind(newContext => lookupWithContext(editor, getAutocompleters, newContext, fetchOptions))).getOrThunk(() => lookup(editor, getAutocompleters));
1 efrain 24322
      const load = fetchOptions => {
24323
        doLookup(fetchOptions).fold(cancelIfNecessary, lookupInfo => {
24324
          commenceIfNecessary(lookupInfo.context);
24325
          lookupInfo.lookupData.then(lookupData => {
24326
            activeAutocompleter.get().map(ac => {
24327
              const context = lookupInfo.context;
1441 ariadna 24328
              if (ac.trigger !== context.trigger) {
24329
                return;
1 efrain 24330
              }
1441 ariadna 24331
              activeAutocompleter.set({
24332
                ...ac,
24333
                matchLength: context.text.length
24334
              });
24335
              if (uiActive.get()) {
24336
                fireAutocompleterUpdateActiveRange(editor, { range: context.range });
24337
                fireAutocompleterUpdate(editor, { lookupData });
24338
              } else {
24339
                uiActive.set(true);
24340
                fireAutocompleterUpdateActiveRange(editor, { range: context.range });
24341
                fireAutocompleterStart(editor, { lookupData });
24342
              }
1 efrain 24343
            });
24344
          });
24345
        });
24346
      };
1441 ariadna 24347
      const isRangeInsideOrEqual = (innerRange, outerRange) => {
24348
        const startComparison = innerRange.compareBoundaryPoints(window.Range.START_TO_START, outerRange);
24349
        const endComparison = innerRange.compareBoundaryPoints(window.Range.END_TO_END, outerRange);
24350
        return startComparison >= 0 && endComparison <= 0;
24351
      };
24352
      const readActiveRange = () => {
24353
        return activeAutocompleter.get().bind(({trigger}) => {
24354
          const selRange = editor.selection.getRng();
24355
          return getContext(editor.dom, selRange, trigger, uiActive.get()).filter(({range}) => isRangeInsideOrEqual(selRange, range)).map(({range}) => range);
24356
        });
24357
      };
1 efrain 24358
      editor.addCommand('mceAutocompleterReload', (_ui, value) => {
24359
        const fetchOptions = isObject(value) ? value.fetchOptions : {};
24360
        load(fetchOptions);
24361
      });
24362
      editor.addCommand('mceAutocompleterClose', cancelIfNecessary);
1441 ariadna 24363
      editor.addCommand('mceAutocompleterRefreshActiveRange', () => {
24364
        readActiveRange().each(range => {
24365
          fireAutocompleterUpdateActiveRange(editor, { range });
24366
        });
24367
      });
24368
      editor.editorCommands.addQueryStateHandler('mceAutoCompleterInRange', () => readActiveRange().isSome());
1 efrain 24369
      setupEditorInput(editor, {
24370
        cancelIfNecessary,
24371
        load
24372
      });
24373
    };
24374
 
1441 ariadna 24375
    const browser$1 = detect$1().browser;
1 efrain 24376
    const isSafari = browser$1.isSafari();
24377
    const emptyNodeContents = node => fillWithPaddingBr(SugarElement.fromDom(node));
24378
    const isEntireNodeSelected = (rng, node) => {
24379
      var _a;
24380
      return rng.startOffset === 0 && rng.endOffset === ((_a = node.textContent) === null || _a === void 0 ? void 0 : _a.length);
24381
    };
24382
    const getParentDetailsElementAtPos = (dom, pos) => Optional.from(dom.getParent(pos.container(), 'details'));
24383
    const isInDetailsElement = (dom, pos) => getParentDetailsElementAtPos(dom, pos).isSome();
24384
    const getDetailsElements = (dom, rng) => {
24385
      const startDetails = Optional.from(dom.getParent(rng.startContainer, 'details'));
24386
      const endDetails = Optional.from(dom.getParent(rng.endContainer, 'details'));
24387
      if (startDetails.isSome() || endDetails.isSome()) {
24388
        const startSummary = startDetails.bind(details => Optional.from(dom.select('summary', details)[0]));
24389
        return Optional.some({
24390
          startSummary,
24391
          startDetails,
24392
          endDetails
24393
        });
24394
      } else {
24395
        return Optional.none();
24396
      }
24397
    };
24398
    const isCaretInTheBeginningOf = (caretPos, element) => firstPositionIn(element).exists(pos => pos.isEqual(caretPos));
24399
    const isCaretInTheEndOf = (caretPos, element) => {
24400
      return lastPositionIn(element).exists(pos => {
24401
        if (isBr$6(pos.getNode())) {
24402
          return prevPosition(element, pos).exists(pos2 => pos2.isEqual(caretPos)) || pos.isEqual(caretPos);
24403
        } else {
24404
          return pos.isEqual(caretPos);
24405
        }
24406
      });
24407
    };
24408
    const isCaretAtStartOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheBeginningOf(caretPos, summary));
24409
    const isCaretAtEndOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheEndOf(caretPos, summary));
24410
    const isCaretInFirstPositionInBody = (caretPos, detailsElements) => detailsElements.startDetails.exists(details => prevPosition(details, caretPos).forall(pos => detailsElements.startSummary.exists(summary => !summary.contains(caretPos.container()) && summary.contains(pos.container()))));
24411
    const isCaretInLastPositionInBody = (root, caretPos, detailsElements) => detailsElements.startDetails.exists(details => nextPosition(root, caretPos).forall(pos => !details.contains(pos.container())));
24412
    const setCaretToPosition = (editor, position) => {
24413
      const node = position.getNode();
24414
      if (!isUndefined(node)) {
24415
        editor.selection.setCursorLocation(node, position.offset());
24416
      }
24417
    };
24418
    const moveCaretToDetailsPos = (editor, pos, forward) => {
24419
      const details = editor.dom.getParent(pos.container(), 'details');
24420
      if (details && !details.open) {
24421
        const summary = editor.dom.select('summary', details)[0];
24422
        if (summary) {
24423
          const newPos = forward ? firstPositionIn(summary) : lastPositionIn(summary);
24424
          newPos.each(pos => setCaretToPosition(editor, pos));
24425
        }
24426
      } else {
24427
        setCaretToPosition(editor, pos);
24428
      }
24429
    };
24430
    const isPartialDelete = (rng, detailsElements) => {
24431
      const containsStart = element => element.contains(rng.startContainer);
24432
      const containsEnd = element => element.contains(rng.endContainer);
24433
      const startInSummary = detailsElements.startSummary.exists(containsStart);
24434
      const endInSummary = detailsElements.startSummary.exists(containsEnd);
24435
      const isPartiallySelectedDetailsElements = detailsElements.startDetails.forall(startDetails => detailsElements.endDetails.forall(endDetails => startDetails !== endDetails));
24436
      const isInPartiallySelectedSummary = (startInSummary || endInSummary) && !(startInSummary && endInSummary);
24437
      return isInPartiallySelectedSummary || isPartiallySelectedDetailsElements;
24438
    };
24439
    const shouldPreventDeleteIntoDetails = (editor, forward, granularity) => {
24440
      const {dom, selection} = editor;
24441
      const root = editor.getBody();
24442
      if (granularity === 'character') {
24443
        const caretPos = CaretPosition.fromRangeStart(selection.getRng());
24444
        const parentBlock = dom.getParent(caretPos.container(), dom.isBlock);
24445
        const parentDetailsAtCaret = getParentDetailsElementAtPos(dom, caretPos);
24446
        const inEmptyParentBlock = parentBlock && dom.isEmpty(parentBlock);
24447
        const isFirstBlock = isNull(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.previousSibling);
24448
        const isLastBlock = isNull(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.nextSibling);
24449
        if (inEmptyParentBlock) {
24450
          const firstOrLast = forward ? isLastBlock : isFirstBlock;
24451
          if (firstOrLast) {
24452
            const isBeforeAfterDetails = navigate(!forward, root, caretPos).exists(pos => {
24453
              return isInDetailsElement(dom, pos) && !equals(parentDetailsAtCaret, getParentDetailsElementAtPos(dom, pos));
24454
            });
24455
            if (isBeforeAfterDetails) {
24456
              return true;
24457
            }
24458
          }
24459
        }
24460
        return navigate(forward, root, caretPos).fold(never, pos => {
24461
          const parentDetailsAtNewPos = getParentDetailsElementAtPos(dom, pos);
24462
          if (isInDetailsElement(dom, pos) && !equals(parentDetailsAtCaret, parentDetailsAtNewPos)) {
24463
            if (!forward) {
24464
              moveCaretToDetailsPos(editor, pos, false);
24465
            }
24466
            if (parentBlock && inEmptyParentBlock) {
24467
              if (forward && isFirstBlock) {
24468
                return true;
24469
              } else if (!forward && isLastBlock) {
24470
                return true;
24471
              }
24472
              moveCaretToDetailsPos(editor, pos, forward);
24473
              editor.dom.remove(parentBlock);
24474
            }
24475
            return true;
24476
          } else {
24477
            return false;
24478
          }
24479
        });
24480
      } else {
24481
        return false;
24482
      }
24483
    };
24484
    const shouldPreventDeleteSummaryAction = (editor, detailElements, forward, granularity) => {
24485
      const selection = editor.selection;
24486
      const rng = selection.getRng();
24487
      const caretPos = CaretPosition.fromRangeStart(rng);
24488
      const root = editor.getBody();
24489
      if (granularity === 'selection') {
24490
        return isPartialDelete(rng, detailElements);
24491
      } else if (forward) {
24492
        return isCaretAtEndOfSummary(caretPos, detailElements) || isCaretInLastPositionInBody(root, caretPos, detailElements);
24493
      } else {
24494
        return isCaretAtStartOfSummary(caretPos, detailElements) || isCaretInFirstPositionInBody(caretPos, detailElements);
24495
      }
24496
    };
24497
    const shouldPreventDeleteAction = (editor, forward, granularity) => getDetailsElements(editor.dom, editor.selection.getRng()).fold(() => shouldPreventDeleteIntoDetails(editor, forward, granularity), detailsElements => shouldPreventDeleteSummaryAction(editor, detailsElements, forward, granularity) || shouldPreventDeleteIntoDetails(editor, forward, granularity));
24498
    const handleDeleteActionSafari = (editor, forward, granularity) => {
24499
      const selection = editor.selection;
24500
      const node = selection.getNode();
24501
      const rng = selection.getRng();
24502
      const caretPos = CaretPosition.fromRangeStart(rng);
24503
      if (isSummary$1(node)) {
24504
        if (granularity === 'selection' && isEntireNodeSelected(rng, node) || willDeleteLastPositionInElement(forward, caretPos, node)) {
24505
          emptyNodeContents(node);
24506
        } else {
24507
          editor.undoManager.transact(() => {
24508
            const sel = selection.getSel();
24509
            let {anchorNode, anchorOffset, focusNode, focusOffset} = sel !== null && sel !== void 0 ? sel : {};
24510
            const applySelection = () => {
24511
              if (isNonNullable(anchorNode) && isNonNullable(anchorOffset) && isNonNullable(focusNode) && isNonNullable(focusOffset)) {
24512
                sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
24513
              }
24514
            };
24515
            const updateSelection = () => {
24516
              anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
24517
              anchorOffset = sel === null || sel === void 0 ? void 0 : sel.anchorOffset;
24518
              focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
24519
              focusOffset = sel === null || sel === void 0 ? void 0 : sel.focusOffset;
24520
            };
24521
            const appendAllChildNodes = (from, to) => {
24522
              each$e(from.childNodes, child => {
24523
                if (isNode(child)) {
24524
                  to.appendChild(child);
24525
                }
24526
              });
24527
            };
24528
            const container = editor.dom.create('span', { 'data-mce-bogus': '1' });
24529
            appendAllChildNodes(node, container);
24530
            node.appendChild(container);
24531
            applySelection();
24532
            if (granularity === 'word' || granularity === 'line') {
24533
              sel === null || sel === void 0 ? void 0 : sel.modify('extend', forward ? 'right' : 'left', granularity);
24534
            }
24535
            if (!selection.isCollapsed() && isEntireNodeSelected(selection.getRng(), container)) {
24536
              emptyNodeContents(node);
24537
            } else {
24538
              editor.execCommand(forward ? 'ForwardDelete' : 'Delete');
24539
              updateSelection();
24540
              appendAllChildNodes(container, node);
24541
              applySelection();
24542
            }
24543
            editor.dom.remove(container);
24544
          });
24545
        }
24546
        return true;
24547
      } else {
24548
        return false;
24549
      }
24550
    };
24551
    const backspaceDelete = (editor, forward, granularity) => shouldPreventDeleteAction(editor, forward, granularity) || isSafari && handleDeleteActionSafari(editor, forward, granularity) ? Optional.some(noop) : Optional.none();
24552
 
24553
    const createAndFireInputEvent = eventType => (editor, inputType, specifics = {}) => {
24554
      const target = editor.getBody();
24555
      const overrides = {
24556
        bubbles: true,
24557
        composed: true,
24558
        data: null,
24559
        isComposing: false,
24560
        detail: 0,
24561
        view: null,
24562
        target,
24563
        currentTarget: target,
24564
        eventPhase: Event.AT_TARGET,
24565
        originalTarget: target,
24566
        explicitOriginalTarget: target,
24567
        isTrusted: false,
24568
        srcElement: target,
24569
        cancelable: false,
24570
        preventDefault: noop,
24571
        inputType
24572
      };
24573
      const input = clone$3(new InputEvent(eventType));
24574
      return editor.dispatch(eventType, {
24575
        ...input,
24576
        ...overrides,
24577
        ...specifics
24578
      });
24579
    };
24580
    const fireInputEvent = createAndFireInputEvent('input');
24581
    const fireBeforeInputEvent = createAndFireInputEvent('beforeinput');
24582
 
1441 ariadna 24583
    const platform$2 = detect$1();
1 efrain 24584
    const os = platform$2.os;
24585
    const isMacOSOriOS = os.isMacOS() || os.isiOS();
24586
    const browser = platform$2.browser;
24587
    const isFirefox = browser.isFirefox();
24588
    const executeKeydownOverride$3 = (editor, caret, evt) => {
24589
      const inputType = evt.keyCode === VK.BACKSPACE ? 'deleteContentBackward' : 'deleteContentForward';
24590
      const isCollapsed = editor.selection.isCollapsed();
24591
      const unmodifiedGranularity = isCollapsed ? 'character' : 'selection';
24592
      const getModifiedGranularity = isWord => {
24593
        if (isCollapsed) {
24594
          return isWord ? 'word' : 'line';
24595
        } else {
24596
          return 'selection';
24597
        }
24598
      };
24599
      executeWithDelayedAction([
24600
        {
24601
          keyCode: VK.BACKSPACE,
24602
          action: action(backspaceDelete$1, editor)
24603
        },
24604
        {
24605
          keyCode: VK.BACKSPACE,
1441 ariadna 24606
          action: action(backspaceDelete$7, editor, false)
1 efrain 24607
        },
24608
        {
24609
          keyCode: VK.DELETE,
1441 ariadna 24610
          action: action(backspaceDelete$7, editor, true)
1 efrain 24611
        },
24612
        {
24613
          keyCode: VK.BACKSPACE,
1441 ariadna 24614
          action: action(backspaceDelete$8, editor, false)
1 efrain 24615
        },
24616
        {
24617
          keyCode: VK.DELETE,
1441 ariadna 24618
          action: action(backspaceDelete$8, editor, true)
1 efrain 24619
        },
24620
        {
24621
          keyCode: VK.BACKSPACE,
24622
          action: action(backspaceDelete$4, editor, caret, false)
24623
        },
24624
        {
24625
          keyCode: VK.DELETE,
24626
          action: action(backspaceDelete$4, editor, caret, true)
24627
        },
24628
        {
24629
          keyCode: VK.BACKSPACE,
1441 ariadna 24630
          action: action(backspaceDelete$b, editor, false)
1 efrain 24631
        },
24632
        {
24633
          keyCode: VK.DELETE,
1441 ariadna 24634
          action: action(backspaceDelete$b, editor, true)
1 efrain 24635
        },
24636
        {
24637
          keyCode: VK.BACKSPACE,
24638
          action: action(backspaceDelete, editor, false, unmodifiedGranularity)
24639
        },
24640
        {
24641
          keyCode: VK.DELETE,
24642
          action: action(backspaceDelete, editor, true, unmodifiedGranularity)
24643
        },
24644
        ...isMacOSOriOS ? [
24645
          {
24646
            keyCode: VK.BACKSPACE,
24647
            altKey: true,
24648
            action: action(backspaceDelete, editor, false, getModifiedGranularity(true))
24649
          },
24650
          {
24651
            keyCode: VK.DELETE,
24652
            altKey: true,
24653
            action: action(backspaceDelete, editor, true, getModifiedGranularity(true))
24654
          },
24655
          {
24656
            keyCode: VK.BACKSPACE,
24657
            metaKey: true,
24658
            action: action(backspaceDelete, editor, false, getModifiedGranularity(false))
24659
          }
24660
        ] : [
24661
          {
24662
            keyCode: VK.BACKSPACE,
24663
            ctrlKey: true,
24664
            action: action(backspaceDelete, editor, false, getModifiedGranularity(true))
24665
          },
24666
          {
24667
            keyCode: VK.DELETE,
24668
            ctrlKey: true,
24669
            action: action(backspaceDelete, editor, true, getModifiedGranularity(true))
24670
          }
24671
        ],
24672
        {
24673
          keyCode: VK.BACKSPACE,
24674
          action: action(backspaceDelete$5, editor, false)
24675
        },
24676
        {
24677
          keyCode: VK.DELETE,
24678
          action: action(backspaceDelete$5, editor, true)
24679
        },
24680
        {
24681
          keyCode: VK.BACKSPACE,
24682
          action: action(backspaceDelete$2, editor, false)
24683
        },
24684
        {
24685
          keyCode: VK.DELETE,
24686
          action: action(backspaceDelete$2, editor, true)
24687
        },
24688
        {
24689
          keyCode: VK.BACKSPACE,
1441 ariadna 24690
          action: action(backspaceDelete$9, editor, false)
1 efrain 24691
        },
24692
        {
24693
          keyCode: VK.DELETE,
1441 ariadna 24694
          action: action(backspaceDelete$9, editor, true)
1 efrain 24695
        },
24696
        {
24697
          keyCode: VK.BACKSPACE,
1441 ariadna 24698
          action: action(backspaceDelete$a, editor, false)
1 efrain 24699
        },
24700
        {
24701
          keyCode: VK.DELETE,
1441 ariadna 24702
          action: action(backspaceDelete$a, editor, true)
1 efrain 24703
        },
24704
        {
24705
          keyCode: VK.BACKSPACE,
24706
          action: action(backspaceDelete$3, editor, false)
24707
        },
24708
        {
24709
          keyCode: VK.DELETE,
24710
          action: action(backspaceDelete$3, editor, true)
1441 ariadna 24711
        },
24712
        {
24713
          keyCode: VK.BACKSPACE,
24714
          action: action(backspaceDelete$6, editor, false)
24715
        },
24716
        {
24717
          keyCode: VK.DELETE,
24718
          action: action(backspaceDelete$6, editor, true)
1 efrain 24719
        }
24720
      ], evt).filter(_ => editor.selection.isEditable()).each(applyAction => {
24721
        evt.preventDefault();
24722
        const beforeInput = fireBeforeInputEvent(editor, inputType);
24723
        if (!beforeInput.isDefaultPrevented()) {
24724
          applyAction();
24725
          fireInputEvent(editor, inputType);
24726
        }
24727
      });
24728
    };
24729
    const executeKeyupOverride = (editor, evt, isBackspaceKeydown) => execute([
24730
      {
24731
        keyCode: VK.BACKSPACE,
24732
        action: action(paddEmptyElement, editor)
24733
      },
24734
      {
24735
        keyCode: VK.DELETE,
24736
        action: action(paddEmptyElement, editor)
24737
      },
24738
      ...isMacOSOriOS ? [
24739
        {
24740
          keyCode: VK.BACKSPACE,
24741
          altKey: true,
24742
          action: action(refreshCaret, editor)
24743
        },
24744
        {
24745
          keyCode: VK.DELETE,
24746
          altKey: true,
24747
          action: action(refreshCaret, editor)
24748
        },
24749
        ...isBackspaceKeydown ? [{
24750
            keyCode: isFirefox ? 224 : 91,
24751
            action: action(refreshCaret, editor)
24752
          }] : []
24753
      ] : [
24754
        {
24755
          keyCode: VK.BACKSPACE,
24756
          ctrlKey: true,
24757
          action: action(refreshCaret, editor)
24758
        },
24759
        {
24760
          keyCode: VK.DELETE,
24761
          ctrlKey: true,
24762
          action: action(refreshCaret, editor)
24763
        }
24764
      ]
24765
    ], evt);
24766
    const setup$j = (editor, caret) => {
24767
      let isBackspaceKeydown = false;
24768
      editor.on('keydown', evt => {
24769
        isBackspaceKeydown = evt.keyCode === VK.BACKSPACE;
24770
        if (!evt.isDefaultPrevented()) {
24771
          executeKeydownOverride$3(editor, caret, evt);
24772
        }
24773
      });
24774
      editor.on('keyup', evt => {
24775
        if (!evt.isDefaultPrevented()) {
24776
          executeKeyupOverride(editor, evt, isBackspaceKeydown);
24777
        }
24778
        isBackspaceKeydown = false;
24779
      });
24780
    };
24781
 
24782
    const firstNonWhiteSpaceNodeSibling = node => {
24783
      while (node) {
1441 ariadna 24784
        if (isElement$6(node) || isText$b(node) && node.data && /[\r\n\s]/.test(node.data)) {
1 efrain 24785
          return node;
24786
        }
24787
        node = node.nextSibling;
24788
      }
24789
      return null;
24790
    };
24791
    const moveToCaretPosition = (editor, root) => {
24792
      const dom = editor.dom;
24793
      const moveCaretBeforeOnEnterElementsMap = editor.schema.getMoveCaretBeforeOnEnterElements();
24794
      if (!root) {
24795
        return;
24796
      }
24797
      if (/^(LI|DT|DD)$/.test(root.nodeName)) {
24798
        const firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild);
24799
        if (firstChild && /^(UL|OL|DL)$/.test(firstChild.nodeName)) {
24800
          root.insertBefore(dom.doc.createTextNode(nbsp), root.firstChild);
24801
        }
24802
      }
24803
      const rng = dom.createRng();
24804
      root.normalize();
24805
      if (root.hasChildNodes()) {
24806
        const walker = new DomTreeWalker(root, root);
24807
        let lastNode = root;
24808
        let node;
24809
        while (node = walker.current()) {
1441 ariadna 24810
          if (isText$b(node)) {
1 efrain 24811
            rng.setStart(node, 0);
24812
            rng.setEnd(node, 0);
24813
            break;
24814
          }
24815
          if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
24816
            rng.setStartBefore(node);
24817
            rng.setEndBefore(node);
24818
            break;
24819
          }
24820
          lastNode = node;
24821
          node = walker.next();
24822
        }
24823
        if (!node) {
24824
          rng.setStart(lastNode, 0);
24825
          rng.setEnd(lastNode, 0);
24826
        }
24827
      } else {
24828
        if (isBr$6(root)) {
24829
          if (root.nextSibling && dom.isBlock(root.nextSibling)) {
24830
            rng.setStartBefore(root);
24831
            rng.setEndBefore(root);
24832
          } else {
24833
            rng.setStartAfter(root);
24834
            rng.setEndAfter(root);
24835
          }
24836
        } else {
24837
          rng.setStart(root, 0);
24838
          rng.setEnd(root, 0);
24839
        }
24840
      }
24841
      editor.selection.setRng(rng);
24842
      scrollRangeIntoView(editor, rng);
24843
    };
24844
    const getEditableRoot = (dom, node) => {
24845
      const root = dom.getRoot();
24846
      let editableRoot;
24847
      let parent = node;
24848
      while (parent !== root && parent && dom.getContentEditable(parent) !== 'false') {
24849
        if (dom.getContentEditable(parent) === 'true') {
24850
          editableRoot = parent;
24851
          break;
24852
        }
24853
        parent = parent.parentNode;
24854
      }
24855
      return parent !== root ? editableRoot : root;
24856
    };
24857
    const getParentBlock$1 = editor => {
24858
      return Optional.from(editor.dom.getParent(editor.selection.getStart(true), editor.dom.isBlock));
24859
    };
24860
    const getParentBlockName = editor => {
24861
      return getParentBlock$1(editor).fold(constant(''), parentBlock => {
24862
        return parentBlock.nodeName.toUpperCase();
24863
      });
24864
    };
24865
    const isListItemParentBlock = editor => {
24866
      return getParentBlock$1(editor).filter(elm => {
24867
        return isListItem$1(SugarElement.fromDom(elm));
24868
      }).isSome();
24869
    };
24870
    const emptyBlock = elm => {
24871
      elm.innerHTML = '<br data-mce-bogus="1">';
24872
    };
24873
    const applyAttributes = (editor, node, forcedRootBlockAttrs) => {
24874
      const dom = editor.dom;
24875
      Optional.from(forcedRootBlockAttrs.style).map(dom.parseStyle).each(attrStyles => {
24876
        const currentStyles = getAllRaw(SugarElement.fromDom(node));
24877
        const newStyles = {
24878
          ...currentStyles,
24879
          ...attrStyles
24880
        };
24881
        dom.setStyles(node, newStyles);
24882
      });
24883
      const attrClassesOpt = Optional.from(forcedRootBlockAttrs.class).map(attrClasses => attrClasses.split(/\s+/));
24884
      const currentClassesOpt = Optional.from(node.className).map(currentClasses => filter$5(currentClasses.split(/\s+/), clazz => clazz !== ''));
24885
      lift2(attrClassesOpt, currentClassesOpt, (attrClasses, currentClasses) => {
24886
        const filteredClasses = filter$5(currentClasses, clazz => !contains$2(attrClasses, clazz));
24887
        const newClasses = [
24888
          ...attrClasses,
24889
          ...filteredClasses
24890
        ];
24891
        dom.setAttrib(node, 'class', newClasses.join(' '));
24892
      });
24893
      const appliedAttrs = [
24894
        'style',
24895
        'class'
24896
      ];
24897
      const remainingAttrs = filter$4(forcedRootBlockAttrs, (_, attrs) => !contains$2(appliedAttrs, attrs));
24898
      dom.setAttribs(node, remainingAttrs);
24899
    };
24900
    const setForcedBlockAttrs = (editor, node) => {
24901
      const forcedRootBlockName = getForcedRootBlock(editor);
24902
      if (forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) {
24903
        const forcedRootBlockAttrs = getForcedRootBlockAttrs(editor);
24904
        applyAttributes(editor, node, forcedRootBlockAttrs);
24905
      }
24906
    };
24907
    const createNewBlock = (editor, container, parentBlock, editableRoot, keepStyles = true, name, styles) => {
24908
      const dom = editor.dom;
24909
      const schema = editor.schema;
24910
      const newBlockName = getForcedRootBlock(editor);
24911
      const parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
24912
      let node = container;
24913
      const textInlineElements = schema.getTextInlineElements();
24914
      let block;
24915
      if (name || parentBlockName === 'TABLE' || parentBlockName === 'HR') {
24916
        block = dom.create(name || newBlockName, styles || {});
24917
      } else {
24918
        block = parentBlock.cloneNode(false);
24919
      }
24920
      let caretNode = block;
24921
      if (!keepStyles) {
24922
        dom.setAttrib(block, 'style', null);
24923
        dom.setAttrib(block, 'class', null);
24924
      } else {
24925
        do {
24926
          if (textInlineElements[node.nodeName]) {
24927
            if (isCaretNode(node) || isBookmarkNode$1(node)) {
24928
              continue;
24929
            }
24930
            const clonedNode = node.cloneNode(false);
24931
            dom.setAttrib(clonedNode, 'id', '');
24932
            if (block.hasChildNodes()) {
24933
              clonedNode.appendChild(block.firstChild);
24934
              block.appendChild(clonedNode);
24935
            } else {
24936
              caretNode = clonedNode;
24937
              block.appendChild(clonedNode);
24938
            }
24939
          }
24940
        } while ((node = node.parentNode) && node !== editableRoot);
24941
      }
24942
      setForcedBlockAttrs(editor, block);
24943
      emptyBlock(caretNode);
24944
      return block;
24945
    };
24946
 
24947
    const getDetailsRoot = (editor, element) => editor.dom.getParent(element, isDetails);
24948
    const isAtDetailsEdge = (root, element, isTextBlock) => {
24949
      let node = element;
24950
      while (node && node !== root && isNull(node.nextSibling)) {
24951
        const parent = node.parentElement;
24952
        if (!parent || !isTextBlock(parent)) {
24953
          return isDetails(parent);
24954
        }
24955
        node = parent;
24956
      }
24957
      return false;
24958
    };
24959
    const isLastEmptyBlockInDetails = (editor, shiftKey, element) => !shiftKey && element.nodeName.toLowerCase() === getForcedRootBlock(editor) && editor.dom.isEmpty(element) && isAtDetailsEdge(editor.getBody(), element, el => has$2(editor.schema.getTextBlockElements(), el.nodeName.toLowerCase()));
24960
    const insertNewLine = (editor, createNewBlock, parentBlock) => {
24961
      var _a, _b, _c;
24962
      const newBlock = createNewBlock(getForcedRootBlock(editor));
24963
      const root = getDetailsRoot(editor, parentBlock);
24964
      if (!root) {
24965
        return;
24966
      }
24967
      editor.dom.insertAfter(newBlock, root);
24968
      moveToCaretPosition(editor, newBlock);
24969
      if (((_c = (_b = (_a = parentBlock.parentElement) === null || _a === void 0 ? void 0 : _a.childNodes) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) > 1) {
24970
        editor.dom.remove(parentBlock);
24971
      }
24972
    };
24973
 
24974
    const hasFirstChild = (elm, name) => {
24975
      return elm.firstChild && elm.firstChild.nodeName === name;
24976
    };
24977
    const isFirstChild = elm => {
24978
      var _a;
24979
      return ((_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === elm;
24980
    };
24981
    const hasParent = (elm, parentName) => {
24982
      const parentNode = elm === null || elm === void 0 ? void 0 : elm.parentNode;
24983
      return isNonNullable(parentNode) && parentNode.nodeName === parentName;
24984
    };
24985
    const isListBlock = elm => {
24986
      return isNonNullable(elm) && /^(OL|UL|LI)$/.test(elm.nodeName);
24987
    };
24988
    const isListItem = elm => {
24989
      return isNonNullable(elm) && /^(LI|DT|DD)$/.test(elm.nodeName);
24990
    };
24991
    const isNestedList = elm => {
24992
      return isListBlock(elm) && isListBlock(elm.parentNode);
24993
    };
24994
    const getContainerBlock = containerBlock => {
24995
      const containerBlockParent = containerBlock.parentNode;
24996
      return isListItem(containerBlockParent) ? containerBlockParent : containerBlock;
24997
    };
24998
    const isFirstOrLastLi = (containerBlock, parentBlock, first) => {
24999
      let node = containerBlock[first ? 'firstChild' : 'lastChild'];
25000
      while (node) {
25001
        if (isElement$6(node)) {
25002
          break;
25003
        }
25004
        node = node[first ? 'nextSibling' : 'previousSibling'];
25005
      }
25006
      return node === parentBlock;
25007
    };
25008
    const getStyles = elm => foldl(mapToArray(getAllRaw(SugarElement.fromDom(elm)), (style, styleName) => `${ styleName }: ${ style };`), (acc, s) => acc + s, '');
25009
    const insert$4 = (editor, createNewBlock, containerBlock, parentBlock, newBlockName) => {
25010
      const dom = editor.dom;
25011
      const rng = editor.selection.getRng();
25012
      const containerParent = containerBlock.parentNode;
25013
      if (containerBlock === editor.getBody() || !containerParent) {
25014
        return;
25015
      }
25016
      if (isNestedList(containerBlock)) {
25017
        newBlockName = 'LI';
25018
      }
25019
      const parentBlockStyles = isListItem(parentBlock) ? getStyles(parentBlock) : undefined;
25020
      let newBlock = isListItem(parentBlock) && parentBlockStyles ? createNewBlock(newBlockName, { style: getStyles(parentBlock) }) : createNewBlock(newBlockName);
25021
      if (isFirstOrLastLi(containerBlock, parentBlock, true) && isFirstOrLastLi(containerBlock, parentBlock, false)) {
25022
        if (hasParent(containerBlock, 'LI')) {
25023
          const containerBlockParent = getContainerBlock(containerBlock);
25024
          dom.insertAfter(newBlock, containerBlockParent);
25025
          if (isFirstChild(containerBlock)) {
25026
            dom.remove(containerBlockParent);
25027
          } else {
25028
            dom.remove(containerBlock);
25029
          }
25030
        } else {
25031
          dom.replace(newBlock, containerBlock);
25032
        }
25033
      } else if (isFirstOrLastLi(containerBlock, parentBlock, true)) {
25034
        if (hasParent(containerBlock, 'LI')) {
25035
          dom.insertAfter(newBlock, getContainerBlock(containerBlock));
25036
          newBlock.appendChild(dom.doc.createTextNode(' '));
25037
          newBlock.appendChild(containerBlock);
25038
        } else {
25039
          containerParent.insertBefore(newBlock, containerBlock);
25040
        }
25041
        dom.remove(parentBlock);
25042
      } else if (isFirstOrLastLi(containerBlock, parentBlock, false)) {
25043
        dom.insertAfter(newBlock, getContainerBlock(containerBlock));
25044
        dom.remove(parentBlock);
25045
      } else {
25046
        containerBlock = getContainerBlock(containerBlock);
25047
        const tmpRng = rng.cloneRange();
25048
        tmpRng.setStartAfter(parentBlock);
25049
        tmpRng.setEndAfter(containerBlock);
25050
        const fragment = tmpRng.extractContents();
25051
        if (newBlockName === 'LI' && hasFirstChild(fragment, 'LI')) {
25052
          const previousChildren = filter$5(map$3(newBlock.children, SugarElement.fromDom), not(isTag('br')));
25053
          newBlock = fragment.firstChild;
25054
          dom.insertAfter(fragment, containerBlock);
25055
          each$e(previousChildren, child => prepend(SugarElement.fromDom(newBlock), child));
25056
          if (parentBlockStyles) {
25057
            newBlock.setAttribute('style', parentBlockStyles);
25058
          }
25059
        } else {
25060
          dom.insertAfter(fragment, containerBlock);
25061
          dom.insertAfter(newBlock, containerBlock);
25062
        }
25063
        dom.remove(parentBlock);
25064
      }
25065
      moveToCaretPosition(editor, newBlock);
25066
    };
25067
 
25068
    const trimZwsp = fragment => {
1441 ariadna 25069
      each$e(descendants$1(SugarElement.fromDom(fragment), isText$c), text => {
1 efrain 25070
        const rawNode = text.dom;
25071
        rawNode.nodeValue = trim$2(rawNode.data);
25072
      });
25073
    };
25074
    const isWithinNonEditableList = (editor, node) => {
25075
      const parentList = editor.dom.getParent(node, 'ol,ul,dl');
25076
      return parentList !== null && editor.dom.getContentEditableParent(parentList) === 'false';
25077
    };
25078
    const isEmptyAnchor = (dom, elm) => {
25079
      return elm && elm.nodeName === 'A' && dom.isEmpty(elm);
25080
    };
1441 ariadna 25081
    const containerAndPreviousSiblingName = (container, nodeName) => {
1 efrain 25082
      return container.nodeName === nodeName || container.previousSibling && container.previousSibling.nodeName === nodeName;
25083
    };
1441 ariadna 25084
    const containerAndNextSiblingName = (container, nodeName) => {
25085
      return container.nodeName === nodeName || container.nextSibling && container.nextSibling.nodeName === nodeName;
25086
    };
1 efrain 25087
    const canSplitBlock = (dom, node) => {
25088
      return isNonNullable(node) && dom.isBlock(node) && !/^(TD|TH|CAPTION|FORM)$/.test(node.nodeName) && !/^(fixed|absolute)/i.test(node.style.position) && dom.isEditable(node.parentNode) && dom.getContentEditable(node) !== 'false';
25089
    };
25090
    const trimInlineElementsOnLeftSideOfBlock = (dom, nonEmptyElementsMap, block) => {
25091
      var _a;
25092
      const firstChilds = [];
25093
      if (!block) {
25094
        return;
25095
      }
25096
      let currentNode = block;
25097
      while (currentNode = currentNode.firstChild) {
25098
        if (dom.isBlock(currentNode)) {
25099
          return;
25100
        }
25101
        if (isElement$6(currentNode) && !nonEmptyElementsMap[currentNode.nodeName.toLowerCase()]) {
25102
          firstChilds.push(currentNode);
25103
        }
25104
      }
25105
      let i = firstChilds.length;
25106
      while (i--) {
25107
        currentNode = firstChilds[i];
25108
        if (!currentNode.hasChildNodes() || currentNode.firstChild === currentNode.lastChild && ((_a = currentNode.firstChild) === null || _a === void 0 ? void 0 : _a.nodeValue) === '') {
25109
          dom.remove(currentNode);
25110
        } else {
25111
          if (isEmptyAnchor(dom, currentNode)) {
25112
            dom.remove(currentNode);
25113
          }
25114
        }
25115
      }
25116
    };
25117
    const normalizeZwspOffset = (start, container, offset) => {
1441 ariadna 25118
      if (!isText$b(container)) {
1 efrain 25119
        return offset;
25120
      } else if (start) {
25121
        return offset === 1 && container.data.charAt(offset - 1) === ZWSP$1 ? 0 : offset;
25122
      } else {
25123
        return offset === container.data.length - 1 && container.data.charAt(offset) === ZWSP$1 ? container.data.length : offset;
25124
      }
25125
    };
25126
    const includeZwspInRange = rng => {
25127
      const newRng = rng.cloneRange();
25128
      newRng.setStart(rng.startContainer, normalizeZwspOffset(true, rng.startContainer, rng.startOffset));
25129
      newRng.setEnd(rng.endContainer, normalizeZwspOffset(false, rng.endContainer, rng.endOffset));
25130
      return newRng;
25131
    };
25132
    const trimLeadingLineBreaks = node => {
25133
      let currentNode = node;
25134
      do {
1441 ariadna 25135
        if (isText$b(currentNode)) {
1 efrain 25136
          currentNode.data = currentNode.data.replace(/^[\r\n]+/, '');
25137
        }
25138
        currentNode = currentNode.firstChild;
25139
      } while (currentNode);
25140
    };
25141
    const wrapSelfAndSiblingsInDefaultBlock = (editor, newBlockName, rng, container, offset) => {
25142
      var _a, _b;
25143
      const dom = editor.dom;
25144
      const editableRoot = (_a = getEditableRoot(dom, container)) !== null && _a !== void 0 ? _a : dom.getRoot();
25145
      let parentBlock = dom.getParent(container, dom.isBlock);
25146
      if (!parentBlock || !canSplitBlock(dom, parentBlock)) {
25147
        parentBlock = parentBlock || editableRoot;
25148
        if (!parentBlock.hasChildNodes()) {
25149
          const newBlock = dom.create(newBlockName);
25150
          setForcedBlockAttrs(editor, newBlock);
25151
          parentBlock.appendChild(newBlock);
25152
          rng.setStart(newBlock, 0);
25153
          rng.setEnd(newBlock, 0);
25154
          return newBlock;
25155
        }
25156
        let node = container;
25157
        while (node && node.parentNode !== parentBlock) {
25158
          node = node.parentNode;
25159
        }
25160
        let startNode;
25161
        while (node && !dom.isBlock(node)) {
25162
          startNode = node;
25163
          node = node.previousSibling;
25164
        }
25165
        const startNodeName = (_b = startNode === null || startNode === void 0 ? void 0 : startNode.parentElement) === null || _b === void 0 ? void 0 : _b.nodeName;
25166
        if (startNode && startNodeName && editor.schema.isValidChild(startNodeName, newBlockName.toLowerCase())) {
25167
          const startNodeParent = startNode.parentNode;
25168
          const newBlock = dom.create(newBlockName);
25169
          setForcedBlockAttrs(editor, newBlock);
25170
          startNodeParent.insertBefore(newBlock, startNode);
25171
          node = startNode;
25172
          while (node && !dom.isBlock(node)) {
25173
            const next = node.nextSibling;
25174
            newBlock.appendChild(node);
25175
            node = next;
25176
          }
25177
          rng.setStart(container, offset);
25178
          rng.setEnd(container, offset);
25179
        }
25180
      }
25181
      return container;
25182
    };
25183
    const addBrToBlockIfNeeded = (dom, block) => {
25184
      block.normalize();
25185
      const lastChild = block.lastChild;
25186
      if (!lastChild || isElement$6(lastChild) && /^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true))) {
25187
        dom.add(block, 'br');
25188
      }
25189
    };
25190
    const shouldEndContainer = (editor, container) => {
25191
      const optionValue = shouldEndContainerOnEmptyBlock(editor);
25192
      if (isNullable(container)) {
25193
        return false;
25194
      } else if (isString(optionValue)) {
25195
        return contains$2(Tools.explode(optionValue), container.nodeName.toLowerCase());
25196
      } else {
25197
        return optionValue;
25198
      }
25199
    };
25200
    const insert$3 = (editor, evt) => {
25201
      let container;
25202
      let offset;
25203
      let parentBlockName;
25204
      let containerBlock;
25205
      let isAfterLastNodeInContainer = false;
25206
      const dom = editor.dom;
25207
      const schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
25208
      const rng = editor.selection.getRng();
25209
      const newBlockName = getForcedRootBlock(editor);
25210
      const start = SugarElement.fromDom(rng.startContainer);
25211
      const child = child$1(start, rng.startOffset);
25212
      const isCef = child.exists(element => isHTMLElement$1(element) && !isEditable$2(element));
25213
      const collapsedAndCef = rng.collapsed && isCef;
25214
      const createNewBlock$1 = (name, styles) => {
25215
        return createNewBlock(editor, container, parentBlock, editableRoot, shouldKeepStyles(editor), name, styles);
25216
      };
25217
      const isCaretAtStartOrEndOfBlock = start => {
25218
        const normalizedOffset = normalizeZwspOffset(start, container, offset);
1441 ariadna 25219
        if (isText$b(container) && (start ? normalizedOffset > 0 : normalizedOffset < container.data.length)) {
1 efrain 25220
          return false;
25221
        }
1441 ariadna 25222
        if ((container.parentNode === parentBlock || container === parentBlock) && isAfterLastNodeInContainer && !start) {
1 efrain 25223
          return true;
25224
        }
25225
        if (start && isElement$6(container) && container === parentBlock.firstChild) {
25226
          return true;
25227
        }
1441 ariadna 25228
        if (containerAndPreviousSiblingName(container, 'TABLE') || containerAndPreviousSiblingName(container, 'HR')) {
25229
          if (containerAndNextSiblingName(container, 'BR')) {
25230
            return !start;
25231
          }
1 efrain 25232
          return isAfterLastNodeInContainer && !start || !isAfterLastNodeInContainer && start;
25233
        }
25234
        const walker = new DomTreeWalker(container, parentBlock);
1441 ariadna 25235
        if (isText$b(container)) {
1 efrain 25236
          if (start && normalizedOffset === 0) {
25237
            walker.prev();
25238
          } else if (!start && normalizedOffset === container.data.length) {
25239
            walker.next();
25240
          }
25241
        }
25242
        let node;
25243
        while (node = walker.current()) {
25244
          if (isElement$6(node)) {
25245
            if (!node.getAttribute('data-mce-bogus')) {
25246
              const name = node.nodeName.toLowerCase();
25247
              if (nonEmptyElementsMap[name] && name !== 'br') {
25248
                return false;
25249
              }
25250
            }
1441 ariadna 25251
          } else if (isText$b(node) && !isWhitespaceText(node.data)) {
1 efrain 25252
            return false;
25253
          }
25254
          if (start) {
25255
            walker.prev();
25256
          } else {
25257
            walker.next();
25258
          }
25259
        }
25260
        return true;
25261
      };
25262
      const insertNewBlockAfter = () => {
25263
        let block;
25264
        if (/^(H[1-6]|PRE|FIGURE)$/.test(parentBlockName) && containerBlockName !== 'HGROUP') {
25265
          block = createNewBlock$1(newBlockName);
25266
        } else {
25267
          block = createNewBlock$1();
25268
        }
25269
        if (shouldEndContainer(editor, containerBlock) && canSplitBlock(dom, containerBlock) && dom.isEmpty(parentBlock, undefined, { includeZwsp: true })) {
25270
          block = dom.split(containerBlock, parentBlock);
25271
        } else {
25272
          dom.insertAfter(block, parentBlock);
25273
        }
25274
        moveToCaretPosition(editor, block);
25275
        return block;
25276
      };
25277
      normalize$2(dom, rng).each(normRng => {
25278
        rng.setStart(normRng.startContainer, normRng.startOffset);
25279
        rng.setEnd(normRng.endContainer, normRng.endOffset);
25280
      });
25281
      container = rng.startContainer;
25282
      offset = rng.startOffset;
25283
      const shiftKey = !!(evt && evt.shiftKey);
25284
      const ctrlKey = !!(evt && evt.ctrlKey);
25285
      if (isElement$6(container) && container.hasChildNodes() && !collapsedAndCef) {
25286
        isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
25287
        container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
1441 ariadna 25288
        if (isAfterLastNodeInContainer && isText$b(container)) {
1 efrain 25289
          offset = container.data.length;
25290
        } else {
25291
          offset = 0;
25292
        }
25293
      }
25294
      const editableRoot = getEditableRoot(dom, container);
25295
      if (!editableRoot || isWithinNonEditableList(editor, container)) {
25296
        return;
25297
      }
25298
      if (!shiftKey) {
25299
        container = wrapSelfAndSiblingsInDefaultBlock(editor, newBlockName, rng, container, offset);
25300
      }
25301
      let parentBlock = dom.getParent(container, dom.isBlock) || dom.getRoot();
25302
      containerBlock = isNonNullable(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.parentNode) ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
25303
      parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
25304
      const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
25305
      if (containerBlockName === 'LI' && !ctrlKey) {
25306
        const liBlock = containerBlock;
25307
        parentBlock = liBlock;
25308
        containerBlock = liBlock.parentNode;
25309
        parentBlockName = containerBlockName;
25310
      }
25311
      if (isElement$6(containerBlock) && isLastEmptyBlockInDetails(editor, shiftKey, parentBlock)) {
25312
        return insertNewLine(editor, createNewBlock$1, parentBlock);
25313
      }
25314
      if (/^(LI|DT|DD)$/.test(parentBlockName) && isElement$6(containerBlock)) {
25315
        if (dom.isEmpty(parentBlock)) {
25316
          insert$4(editor, createNewBlock$1, containerBlock, parentBlock, newBlockName);
25317
          return;
25318
        }
25319
      }
25320
      if (!collapsedAndCef && (parentBlock === editor.getBody() || !canSplitBlock(dom, parentBlock))) {
25321
        return;
25322
      }
25323
      const parentBlockParent = parentBlock.parentNode;
25324
      let newBlock;
25325
      if (collapsedAndCef) {
25326
        newBlock = createNewBlock$1(newBlockName);
25327
        child.fold(() => {
25328
          append$1(start, SugarElement.fromDom(newBlock));
25329
        }, child => {
25330
          before$3(child, SugarElement.fromDom(newBlock));
25331
        });
25332
        editor.selection.setCursorLocation(newBlock, 0);
25333
      } else if (isCaretContainerBlock$1(parentBlock)) {
25334
        newBlock = showCaretContainerBlock(parentBlock);
25335
        if (dom.isEmpty(parentBlock)) {
25336
          emptyBlock(parentBlock);
25337
        }
25338
        setForcedBlockAttrs(editor, newBlock);
25339
        moveToCaretPosition(editor, newBlock);
25340
      } else if (isCaretAtStartOrEndOfBlock(false)) {
25341
        newBlock = insertNewBlockAfter();
25342
      } else if (isCaretAtStartOrEndOfBlock(true) && parentBlockParent) {
1441 ariadna 25343
        const caretPos = CaretPosition.fromRangeStart(rng);
25344
        const afterTable = isAfterTable(caretPos);
25345
        const parentBlockSugar = SugarElement.fromDom(parentBlock);
25346
        const afterBr = isAfterBr(parentBlockSugar, caretPos, editor.schema);
25347
        const prevBrOpt = afterBr ? findPreviousBr(parentBlockSugar, caretPos, editor.schema).bind(pos => Optional.from(pos.getNode())) : Optional.none();
1 efrain 25348
        newBlock = parentBlockParent.insertBefore(createNewBlock$1(), parentBlock);
1441 ariadna 25349
        const root = containerAndPreviousSiblingName(parentBlock, 'HR') || afterTable ? newBlock : prevBrOpt.getOr(parentBlock);
25350
        moveToCaretPosition(editor, root);
1 efrain 25351
      } else {
25352
        const tmpRng = includeZwspInRange(rng).cloneRange();
25353
        tmpRng.setEndAfter(parentBlock);
25354
        const fragment = tmpRng.extractContents();
25355
        trimZwsp(fragment);
25356
        trimLeadingLineBreaks(fragment);
25357
        newBlock = fragment.firstChild;
25358
        dom.insertAfter(fragment, parentBlock);
25359
        trimInlineElementsOnLeftSideOfBlock(dom, nonEmptyElementsMap, newBlock);
25360
        addBrToBlockIfNeeded(dom, parentBlock);
25361
        if (dom.isEmpty(parentBlock)) {
25362
          emptyBlock(parentBlock);
25363
        }
25364
        newBlock.normalize();
25365
        if (dom.isEmpty(newBlock)) {
25366
          dom.remove(newBlock);
25367
          insertNewBlockAfter();
25368
        } else {
25369
          setForcedBlockAttrs(editor, newBlock);
25370
          moveToCaretPosition(editor, newBlock);
25371
        }
25372
      }
25373
      dom.setAttrib(newBlock, 'id', '');
25374
      editor.dispatch('NewBlock', { newBlock });
25375
    };
25376
    const fakeEventName$1 = 'insertParagraph';
25377
    const blockbreak = {
25378
      insert: insert$3,
25379
      fakeEventName: fakeEventName$1
25380
    };
25381
 
25382
    const hasRightSideContent = (schema, container, parentBlock) => {
25383
      const walker = new DomTreeWalker(container, parentBlock);
25384
      let node;
25385
      const nonEmptyElementsMap = schema.getNonEmptyElements();
25386
      while (node = walker.next()) {
1441 ariadna 25387
        if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || isText$b(node) && node.length > 0) {
1 efrain 25388
          return true;
25389
        }
25390
      }
25391
      return false;
25392
    };
25393
    const moveSelectionToBr = (editor, brElm, extraBr) => {
25394
      const rng = editor.dom.createRng();
25395
      if (!extraBr) {
25396
        rng.setStartAfter(brElm);
25397
        rng.setEndAfter(brElm);
25398
      } else {
25399
        rng.setStartBefore(brElm);
25400
        rng.setEndBefore(brElm);
25401
      }
25402
      editor.selection.setRng(rng);
25403
      scrollRangeIntoView(editor, rng);
25404
    };
25405
    const insertBrAtCaret = (editor, evt) => {
25406
      const selection = editor.selection;
25407
      const dom = editor.dom;
25408
      const rng = selection.getRng();
25409
      let brElm;
25410
      let extraBr = false;
25411
      normalize$2(dom, rng).each(normRng => {
25412
        rng.setStart(normRng.startContainer, normRng.startOffset);
25413
        rng.setEnd(normRng.endContainer, normRng.endOffset);
25414
      });
25415
      let offset = rng.startOffset;
25416
      let container = rng.startContainer;
25417
      if (isElement$6(container) && container.hasChildNodes()) {
25418
        const isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
25419
        container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
1441 ariadna 25420
        if (isAfterLastNodeInContainer && isText$b(container)) {
1 efrain 25421
          offset = container.data.length;
25422
        } else {
25423
          offset = 0;
25424
        }
25425
      }
25426
      let parentBlock = dom.getParent(container, dom.isBlock);
25427
      const containerBlock = parentBlock && parentBlock.parentNode ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
25428
      const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
25429
      const isControlKey = !!(evt && evt.ctrlKey);
25430
      if (containerBlockName === 'LI' && !isControlKey) {
25431
        parentBlock = containerBlock;
25432
      }
1441 ariadna 25433
      if (isText$b(container) && offset >= container.data.length) {
1 efrain 25434
        if (!hasRightSideContent(editor.schema, container, parentBlock || dom.getRoot())) {
25435
          brElm = dom.create('br');
25436
          rng.insertNode(brElm);
25437
          rng.setStartAfter(brElm);
25438
          rng.setEndAfter(brElm);
25439
          extraBr = true;
25440
        }
25441
      }
25442
      brElm = dom.create('br');
25443
      rangeInsertNode(dom, rng, brElm);
25444
      moveSelectionToBr(editor, brElm, extraBr);
25445
      editor.undoManager.add();
25446
    };
25447
    const insertBrBefore = (editor, inline) => {
25448
      const br = SugarElement.fromTag('br');
25449
      before$3(SugarElement.fromDom(inline), br);
25450
      editor.undoManager.add();
25451
    };
25452
    const insertBrAfter = (editor, inline) => {
25453
      if (!hasBrAfter(editor.getBody(), inline)) {
25454
        after$4(SugarElement.fromDom(inline), SugarElement.fromTag('br'));
25455
      }
25456
      const br = SugarElement.fromTag('br');
25457
      after$4(SugarElement.fromDom(inline), br);
25458
      moveSelectionToBr(editor, br.dom, false);
25459
      editor.undoManager.add();
25460
    };
25461
    const isBeforeBr = pos => {
25462
      return isBr$6(pos.getNode());
25463
    };
25464
    const hasBrAfter = (rootNode, startNode) => {
25465
      if (isBeforeBr(CaretPosition.after(startNode))) {
25466
        return true;
25467
      } else {
25468
        return nextPosition(rootNode, CaretPosition.after(startNode)).map(pos => {
25469
          return isBr$6(pos.getNode());
25470
        }).getOr(false);
25471
      }
25472
    };
25473
    const isAnchorLink = elm => {
25474
      return elm && elm.nodeName === 'A' && 'href' in elm;
25475
    };
25476
    const isInsideAnchor = location => {
25477
      return location.fold(never, isAnchorLink, isAnchorLink, never);
25478
    };
25479
    const readInlineAnchorLocation = editor => {
25480
      const isInlineTarget$1 = curry(isInlineTarget, editor);
25481
      const position = CaretPosition.fromRangeStart(editor.selection.getRng());
25482
      return readLocation(isInlineTarget$1, editor.getBody(), position).filter(isInsideAnchor);
25483
    };
25484
    const insertBrOutsideAnchor = (editor, location) => {
25485
      location.fold(noop, curry(insertBrBefore, editor), curry(insertBrAfter, editor), noop);
25486
    };
25487
    const insert$2 = (editor, evt) => {
25488
      const anchorLocation = readInlineAnchorLocation(editor);
25489
      if (anchorLocation.isSome()) {
25490
        anchorLocation.each(curry(insertBrOutsideAnchor, editor));
25491
      } else {
25492
        insertBrAtCaret(editor, evt);
25493
      }
25494
    };
25495
    const fakeEventName = 'insertLineBreak';
25496
    const linebreak = {
25497
      insert: insert$2,
25498
      fakeEventName
25499
    };
25500
 
25501
    const matchesSelector = (editor, selector) => {
25502
      return getParentBlock$1(editor).filter(parentBlock => {
25503
        return selector.length > 0 && is$1(SugarElement.fromDom(parentBlock), selector);
25504
      }).isSome();
25505
    };
25506
    const shouldInsertBr = editor => {
25507
      return matchesSelector(editor, getBrNewLineSelector(editor));
25508
    };
25509
    const shouldBlockNewLine$1 = editor => {
25510
      return matchesSelector(editor, getNoNewLineSelector(editor));
25511
    };
25512
 
25513
    const newLineAction = Adt.generate([
25514
      { br: [] },
25515
      { block: [] },
25516
      { none: [] }
25517
    ]);
25518
    const shouldBlockNewLine = (editor, _shiftKey) => {
25519
      return shouldBlockNewLine$1(editor);
25520
    };
25521
    const inListBlock = requiredState => {
25522
      return (editor, _shiftKey) => {
25523
        return isListItemParentBlock(editor) === requiredState;
25524
      };
25525
    };
25526
    const inBlock = (blockName, requiredState) => (editor, _shiftKey) => {
25527
      const state = getParentBlockName(editor) === blockName.toUpperCase();
25528
      return state === requiredState;
25529
    };
25530
    const inCefBlock = editor => {
25531
      const editableRoot = getEditableRoot(editor.dom, editor.selection.getStart());
25532
      return isNullable(editableRoot);
25533
    };
25534
    const inPreBlock = requiredState => inBlock('pre', requiredState);
25535
    const inSummaryBlock = () => inBlock('summary', true);
25536
    const shouldPutBrInPre = requiredState => {
25537
      return (editor, _shiftKey) => {
25538
        return shouldPutBrInPre$1(editor) === requiredState;
25539
      };
25540
    };
25541
    const inBrContext = (editor, _shiftKey) => {
25542
      return shouldInsertBr(editor);
25543
    };
25544
    const hasShiftKey = (_editor, shiftKey) => {
25545
      return shiftKey;
25546
    };
25547
    const canInsertIntoEditableRoot = editor => {
25548
      const forcedRootBlock = getForcedRootBlock(editor);
25549
      const rootEditable = getEditableRoot(editor.dom, editor.selection.getStart());
25550
      return isNonNullable(rootEditable) && editor.schema.isValidChild(rootEditable.nodeName, forcedRootBlock);
25551
    };
25552
    const isInRootWithEmptyOrCEF = editor => {
25553
      const rng = editor.selection.getRng();
25554
      const start = SugarElement.fromDom(rng.startContainer);
25555
      const child = child$1(start, rng.startOffset);
25556
      const isCefOpt = child.map(element => isHTMLElement$1(element) && !isEditable$2(element));
25557
      return rng.collapsed && isCefOpt.getOr(true);
25558
    };
25559
    const match = (predicates, action) => {
25560
      return (editor, shiftKey) => {
25561
        const isMatch = foldl(predicates, (res, p) => {
25562
          return res && p(editor, shiftKey);
25563
        }, true);
25564
        return isMatch ? Optional.some(action) : Optional.none();
25565
      };
25566
    };
25567
    const getAction = (editor, evt) => {
25568
      return evaluateUntil([
25569
        match([shouldBlockNewLine], newLineAction.none()),
25570
        match([
25571
          inPreBlock(true),
25572
          inCefBlock
25573
        ], newLineAction.none()),
25574
        match([inSummaryBlock()], newLineAction.br()),
25575
        match([
25576
          inPreBlock(true),
25577
          shouldPutBrInPre(false),
25578
          hasShiftKey
25579
        ], newLineAction.br()),
25580
        match([
25581
          inPreBlock(true),
25582
          shouldPutBrInPre(false)
25583
        ], newLineAction.block()),
25584
        match([
25585
          inPreBlock(true),
25586
          shouldPutBrInPre(true),
25587
          hasShiftKey
25588
        ], newLineAction.block()),
25589
        match([
25590
          inPreBlock(true),
25591
          shouldPutBrInPre(true)
25592
        ], newLineAction.br()),
25593
        match([
25594
          inListBlock(true),
25595
          hasShiftKey
25596
        ], newLineAction.br()),
25597
        match([inListBlock(true)], newLineAction.block()),
25598
        match([inBrContext], newLineAction.br()),
25599
        match([hasShiftKey], newLineAction.br()),
25600
        match([canInsertIntoEditableRoot], newLineAction.block()),
25601
        match([isInRootWithEmptyOrCEF], newLineAction.block())
25602
      ], [
25603
        editor,
25604
        !!(evt && evt.shiftKey)
25605
      ]).getOr(newLineAction.none());
25606
    };
25607
 
25608
    const insertBreak = (breakType, editor, evt) => {
1441 ariadna 25609
      if (editor.mode.isReadOnly()) {
25610
        return;
25611
      }
1 efrain 25612
      if (!editor.selection.isCollapsed()) {
25613
        execEditorDeleteCommand(editor);
25614
      }
25615
      if (isNonNullable(evt)) {
25616
        const event = fireBeforeInputEvent(editor, breakType.fakeEventName);
25617
        if (event.isDefaultPrevented()) {
25618
          return;
25619
        }
25620
      }
25621
      breakType.insert(editor, evt);
25622
      if (isNonNullable(evt)) {
25623
        fireInputEvent(editor, breakType.fakeEventName);
25624
      }
25625
    };
25626
    const insert$1 = (editor, evt) => {
1441 ariadna 25627
      if (editor.mode.isReadOnly()) {
25628
        return;
25629
      }
1 efrain 25630
      const br = () => insertBreak(linebreak, editor, evt);
25631
      const block = () => insertBreak(blockbreak, editor, evt);
25632
      const logicalAction = getAction(editor, evt);
25633
      switch (getNewlineBehavior(editor)) {
25634
      case 'linebreak':
25635
        logicalAction.fold(br, br, noop);
25636
        break;
25637
      case 'block':
25638
        logicalAction.fold(block, block, noop);
25639
        break;
25640
      case 'invert':
25641
        logicalAction.fold(block, br, noop);
25642
        break;
25643
      default:
25644
        logicalAction.fold(br, block, noop);
25645
        break;
25646
      }
25647
    };
25648
 
1441 ariadna 25649
    const platform$1 = detect$1();
1 efrain 25650
    const isIOSSafari = platform$1.os.isiOS() && platform$1.browser.isSafari();
25651
    const handleEnterKeyEvent = (editor, event) => {
25652
      if (event.isDefaultPrevented()) {
25653
        return;
25654
      }
25655
      event.preventDefault();
25656
      endTypingLevelIgnoreLocks(editor.undoManager);
25657
      editor.undoManager.transact(() => {
25658
        insert$1(editor, event);
25659
      });
25660
    };
25661
    const isCaretAfterKoreanCharacter = rng => {
25662
      if (!rng.collapsed) {
25663
        return false;
25664
      }
25665
      const startContainer = rng.startContainer;
1441 ariadna 25666
      if (isText$b(startContainer)) {
1 efrain 25667
        const koreanCharRegex = /^[\uAC00-\uD7AF\u1100-\u11FF\u3130-\u318F\uA960-\uA97F\uD7B0-\uD7FF]$/;
25668
        const char = startContainer.data.charAt(rng.startOffset - 1);
25669
        return koreanCharRegex.test(char);
25670
      } else {
25671
        return false;
25672
      }
25673
    };
25674
    const setup$i = editor => {
25675
      let iOSSafariKeydownBookmark = Optional.none();
25676
      const iOSSafariKeydownOverride = editor => {
25677
        iOSSafariKeydownBookmark = Optional.some(editor.selection.getBookmark());
25678
        editor.undoManager.add();
25679
      };
25680
      const iOSSafariKeyupOverride = (editor, event) => {
25681
        editor.undoManager.undo();
25682
        iOSSafariKeydownBookmark.fold(noop, b => editor.selection.moveToBookmark(b));
25683
        handleEnterKeyEvent(editor, event);
25684
        iOSSafariKeydownBookmark = Optional.none();
25685
      };
25686
      editor.on('keydown', event => {
25687
        if (event.keyCode === VK.ENTER) {
25688
          if (isIOSSafari && isCaretAfterKoreanCharacter(editor.selection.getRng())) {
25689
            iOSSafariKeydownOverride(editor);
25690
          } else {
25691
            handleEnterKeyEvent(editor, event);
25692
          }
25693
        }
25694
      });
25695
      editor.on('keyup', event => {
25696
        if (event.keyCode === VK.ENTER) {
25697
          iOSSafariKeydownBookmark.each(() => iOSSafariKeyupOverride(editor, event));
25698
        }
25699
      });
25700
    };
25701
 
25702
    const executeKeydownOverride$2 = (editor, caret, evt) => {
25703
      const isMac = Env.os.isMacOS() || Env.os.isiOS();
25704
      execute([
25705
        {
25706
          keyCode: VK.END,
25707
          action: action(moveToLineEndPoint$1, editor, true)
25708
        },
25709
        {
25710
          keyCode: VK.HOME,
25711
          action: action(moveToLineEndPoint$1, editor, false)
25712
        },
25713
        ...!isMac ? [
25714
          {
25715
            keyCode: VK.HOME,
25716
            action: action(selectToEndPoint, editor, false),
25717
            ctrlKey: true,
25718
            shiftKey: true
25719
          },
25720
          {
25721
            keyCode: VK.END,
25722
            action: action(selectToEndPoint, editor, true),
25723
            ctrlKey: true,
25724
            shiftKey: true
25725
          }
25726
        ] : [],
25727
        {
25728
          keyCode: VK.END,
25729
          action: action(moveToLineEndPoint, editor, true)
25730
        },
25731
        {
25732
          keyCode: VK.HOME,
25733
          action: action(moveToLineEndPoint, editor, false)
25734
        },
25735
        {
25736
          keyCode: VK.END,
25737
          action: action(moveToLineEndPoint$2, editor, true, caret)
25738
        },
25739
        {
25740
          keyCode: VK.HOME,
25741
          action: action(moveToLineEndPoint$2, editor, false, caret)
25742
        }
25743
      ], evt).each(_ => {
25744
        evt.preventDefault();
25745
      });
25746
    };
25747
    const setup$h = (editor, caret) => {
25748
      editor.on('keydown', evt => {
25749
        if (!evt.isDefaultPrevented()) {
25750
          executeKeydownOverride$2(editor, caret, evt);
25751
        }
25752
      });
25753
    };
25754
 
25755
    const setup$g = editor => {
25756
      editor.on('input', e => {
25757
        if (!e.isComposing) {
25758
          normalizeNbspsInEditor(editor);
25759
        }
25760
      });
25761
    };
25762
 
1441 ariadna 25763
    const platform = detect$1();
1 efrain 25764
    const executeKeyupAction = (editor, caret, evt) => {
25765
      execute([
25766
        {
25767
          keyCode: VK.PAGE_UP,
25768
          action: action(moveToLineEndPoint$2, editor, false, caret)
25769
        },
25770
        {
25771
          keyCode: VK.PAGE_DOWN,
25772
          action: action(moveToLineEndPoint$2, editor, true, caret)
25773
        }
25774
      ], evt);
25775
    };
25776
    const stopImmediatePropagation = e => e.stopImmediatePropagation();
25777
    const isPageUpDown = evt => evt.keyCode === VK.PAGE_UP || evt.keyCode === VK.PAGE_DOWN;
25778
    const setNodeChangeBlocker = (blocked, editor, block) => {
25779
      if (block && !blocked.get()) {
25780
        editor.on('NodeChange', stopImmediatePropagation, true);
25781
      } else if (!block && blocked.get()) {
25782
        editor.off('NodeChange', stopImmediatePropagation);
25783
      }
25784
      blocked.set(block);
25785
    };
25786
    const setup$f = (editor, caret) => {
25787
      if (platform.os.isMacOS()) {
25788
        return;
25789
      }
25790
      const blocked = Cell(false);
25791
      editor.on('keydown', evt => {
25792
        if (isPageUpDown(evt)) {
25793
          setNodeChangeBlocker(blocked, editor, true);
25794
        }
25795
      });
25796
      editor.on('keyup', evt => {
25797
        if (!evt.isDefaultPrevented()) {
25798
          executeKeyupAction(editor, caret, evt);
25799
        }
25800
        if (isPageUpDown(evt) && blocked.get()) {
25801
          setNodeChangeBlocker(blocked, editor, false);
25802
          editor.nodeChanged();
25803
        }
25804
      });
25805
    };
25806
 
1441 ariadna 25807
    const isValidContainer = (root, container) => root === container || root.contains(container);
25808
    const isInEditableRange = (editor, range) => {
25809
      if (!isValidContainer(editor.getBody(), range.startContainer) || !isValidContainer(editor.getBody(), range.endContainer)) {
25810
        return true;
25811
      }
25812
      return isEditableRange(editor.dom, range);
25813
    };
1 efrain 25814
    const setup$e = editor => {
25815
      editor.on('beforeinput', e => {
1441 ariadna 25816
        if (!editor.selection.isEditable() || exists(e.getTargetRanges(), rng => !isInEditableRange(editor, rng))) {
1 efrain 25817
          e.preventDefault();
25818
        }
25819
      });
25820
    };
25821
 
25822
    const insertTextAtPosition = (text, pos) => {
25823
      const container = pos.container();
25824
      const offset = pos.offset();
1441 ariadna 25825
      if (isText$b(container)) {
1 efrain 25826
        container.insertData(offset, text);
25827
        return Optional.some(CaretPosition(container, offset + text.length));
25828
      } else {
25829
        return getElementFromPosition(pos).map(elm => {
25830
          const textNode = SugarElement.fromText(text);
25831
          if (pos.isAtEnd()) {
25832
            after$4(elm, textNode);
25833
          } else {
25834
            before$3(elm, textNode);
25835
          }
25836
          return CaretPosition(textNode.dom, text.length);
25837
        });
25838
      }
25839
    };
25840
    const insertNbspAtPosition = curry(insertTextAtPosition, nbsp);
25841
    const insertSpaceAtPosition = curry(insertTextAtPosition, ' ');
25842
 
25843
    const insertSpaceOrNbspAtPosition = (root, pos, schema) => needsToHaveNbsp(root, pos, schema) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
25844
    const locationToCaretPosition = root => location => location.fold(element => prevPosition(root.dom, CaretPosition.before(element)), element => firstPositionIn(element), element => lastPositionIn(element), element => nextPosition(root.dom, CaretPosition.after(element)));
25845
    const insertInlineBoundarySpaceOrNbsp = (root, pos, schema) => checkPos => needsToHaveNbsp(root, checkPos, schema) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
25846
    const setSelection = editor => pos => {
25847
      editor.selection.setRng(pos.toRange());
25848
      editor.nodeChanged();
25849
    };
25850
    const isInsideSummary = (domUtils, node) => domUtils.isEditable(domUtils.getParent(node, 'summary'));
25851
    const insertSpaceOrNbspAtSelection = editor => {
25852
      const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
25853
      const root = SugarElement.fromDom(editor.getBody());
25854
      if (editor.selection.isCollapsed()) {
25855
        const isInlineTarget$1 = curry(isInlineTarget, editor);
25856
        const caretPosition = CaretPosition.fromRangeStart(editor.selection.getRng());
25857
        return readLocation(isInlineTarget$1, editor.getBody(), caretPosition).bind(locationToCaretPosition(root)).map(checkPos => () => insertInlineBoundarySpaceOrNbsp(root, pos, editor.schema)(checkPos).each(setSelection(editor)));
25858
      } else {
25859
        return Optional.none();
25860
      }
25861
    };
25862
    const insertSpaceInSummaryAtSelectionOnFirefox = editor => {
25863
      const insertSpaceThunk = () => {
25864
        const root = SugarElement.fromDom(editor.getBody());
25865
        if (!editor.selection.isCollapsed()) {
25866
          editor.getDoc().execCommand('Delete');
25867
        }
25868
        const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
25869
        insertSpaceOrNbspAtPosition(root, pos, editor.schema).each(setSelection(editor));
25870
      };
25871
      return someIf(Env.browser.isFirefox() && editor.selection.isEditable() && isInsideSummary(editor.dom, editor.selection.getRng().startContainer), insertSpaceThunk);
25872
    };
25873
 
25874
    const executeKeydownOverride$1 = (editor, evt) => {
25875
      executeWithDelayedAction([
25876
        {
25877
          keyCode: VK.SPACEBAR,
25878
          action: action(insertSpaceOrNbspAtSelection, editor)
25879
        },
25880
        {
25881
          keyCode: VK.SPACEBAR,
25882
          action: action(insertSpaceInSummaryAtSelectionOnFirefox, editor)
25883
        }
25884
      ], evt).each(applyAction => {
25885
        evt.preventDefault();
25886
        const event = fireBeforeInputEvent(editor, 'insertText', { data: ' ' });
25887
        if (!event.isDefaultPrevented()) {
25888
          applyAction();
25889
          fireInputEvent(editor, 'insertText', { data: ' ' });
25890
        }
25891
      });
25892
    };
25893
    const setup$d = editor => {
25894
      editor.on('keydown', evt => {
25895
        if (!evt.isDefaultPrevented()) {
25896
          executeKeydownOverride$1(editor, evt);
25897
        }
25898
      });
25899
    };
25900
 
25901
    const tableTabNavigation = editor => {
25902
      if (hasTableTabNavigation(editor)) {
25903
        return [
25904
          {
25905
            keyCode: VK.TAB,
25906
            action: action(handleTab, editor, true)
25907
          },
25908
          {
25909
            keyCode: VK.TAB,
25910
            shiftKey: true,
25911
            action: action(handleTab, editor, false)
25912
          }
25913
        ];
25914
      } else {
25915
        return [];
25916
      }
25917
    };
25918
    const executeKeydownOverride = (editor, evt) => {
25919
      execute([...tableTabNavigation(editor)], evt).each(_ => {
25920
        evt.preventDefault();
25921
      });
25922
    };
25923
    const setup$c = editor => {
25924
      editor.on('keydown', evt => {
25925
        if (!evt.isDefaultPrevented()) {
25926
          executeKeydownOverride(editor, evt);
25927
        }
25928
      });
25929
    };
25930
 
25931
    const setup$b = editor => {
25932
      editor.addShortcut('Meta+P', '', 'mcePrint');
25933
      setup$k(editor);
25934
      if (isRtc(editor)) {
25935
        return Cell(null);
25936
      } else {
25937
        const caret = setupSelectedState(editor);
25938
        setup$e(editor);
25939
        setup$m(editor);
25940
        setup$l(editor, caret);
25941
        setup$j(editor, caret);
25942
        setup$i(editor);
25943
        setup$d(editor);
25944
        setup$g(editor);
25945
        setup$c(editor);
25946
        setup$h(editor, caret);
25947
        setup$f(editor, caret);
25948
        return caret;
25949
      }
25950
    };
25951
 
25952
    class NodeChange {
25953
      constructor(editor) {
25954
        this.lastPath = [];
25955
        this.editor = editor;
25956
        let lastRng;
25957
        const self = this;
25958
        if (!('onselectionchange' in editor.getDoc())) {
25959
          editor.on('NodeChange click mouseup keyup focus', e => {
25960
            const nativeRng = editor.selection.getRng();
25961
            const fakeRng = {
25962
              startContainer: nativeRng.startContainer,
25963
              startOffset: nativeRng.startOffset,
25964
              endContainer: nativeRng.endContainer,
25965
              endOffset: nativeRng.endOffset
25966
            };
25967
            if (e.type === 'nodechange' || !isEq$4(fakeRng, lastRng)) {
25968
              editor.dispatch('SelectionChange');
25969
            }
25970
            lastRng = fakeRng;
25971
          });
25972
        }
25973
        editor.on('contextmenu', () => {
1441 ariadna 25974
          store(editor);
1 efrain 25975
          editor.dispatch('SelectionChange');
25976
        });
25977
        editor.on('SelectionChange', () => {
25978
          const startElm = editor.selection.getStart(true);
25979
          if (!startElm) {
25980
            return;
25981
          }
25982
          if (hasAnyRanges(editor) && !self.isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
25983
            editor.nodeChanged({ selectionChange: true });
25984
          }
25985
        });
25986
        editor.on('mouseup', e => {
25987
          if (!e.isDefaultPrevented() && hasAnyRanges(editor)) {
25988
            if (editor.selection.getNode().nodeName === 'IMG') {
25989
              Delay.setEditorTimeout(editor, () => {
25990
                editor.nodeChanged();
25991
              });
25992
            } else {
25993
              editor.nodeChanged();
25994
            }
25995
          }
25996
        });
25997
      }
25998
      nodeChanged(args = {}) {
1441 ariadna 25999
        const editor = this.editor;
26000
        const selection = editor.selection;
1 efrain 26001
        let node;
1441 ariadna 26002
        if (editor.initialized && selection && !shouldDisableNodeChange(editor) && !isDisabled$1(editor)) {
26003
          const root = editor.getBody();
1 efrain 26004
          node = selection.getStart(true) || root;
1441 ariadna 26005
          if (node.ownerDocument !== editor.getDoc() || !editor.dom.isChildOf(node, root)) {
1 efrain 26006
            node = root;
26007
          }
26008
          const parents = [];
1441 ariadna 26009
          editor.dom.getParent(node, node => {
1 efrain 26010
            if (node === root) {
26011
              return true;
26012
            } else {
26013
              parents.push(node);
26014
              return false;
26015
            }
26016
          });
1441 ariadna 26017
          editor.dispatch('NodeChange', {
1 efrain 26018
            ...args,
26019
            element: node,
26020
            parents
26021
          });
26022
        }
26023
      }
26024
      isSameElementPath(startElm) {
26025
        let i;
26026
        const editor = this.editor;
26027
        const currentPath = reverse(editor.dom.getParents(startElm, always, editor.getBody()));
26028
        if (currentPath.length === this.lastPath.length) {
26029
          for (i = currentPath.length; i >= 0; i--) {
26030
            if (currentPath[i] !== this.lastPath[i]) {
26031
              break;
26032
            }
26033
          }
26034
          if (i === -1) {
26035
            this.lastPath = currentPath;
26036
            return true;
26037
          }
26038
        }
26039
        this.lastPath = currentPath;
26040
        return false;
26041
      }
26042
    }
26043
 
26044
    const imageId = generate$1('image');
26045
    const getDragImage = transfer => {
26046
      const dt = transfer;
26047
      return Optional.from(dt[imageId]);
26048
    };
26049
    const setDragImage = (transfer, imageData) => {
26050
      const dt = transfer;
26051
      dt[imageId] = imageData;
26052
    };
26053
 
26054
    const eventId = generate$1('event');
26055
    const getEvent = transfer => {
26056
      const dt = transfer;
26057
      return Optional.from(dt[eventId]);
26058
    };
26059
    const mkSetEventFn = type => transfer => {
26060
      const dt = transfer;
26061
      dt[eventId] = type;
26062
    };
26063
    const setEvent = (transfer, type) => mkSetEventFn(type)(transfer);
26064
    const setDragstartEvent = mkSetEventFn(0);
26065
    const setDropEvent = mkSetEventFn(2);
26066
    const setDragendEvent = mkSetEventFn(1);
26067
    const checkEvent = expectedType => transfer => {
26068
      const dt = transfer;
26069
      return Optional.from(dt[eventId]).exists(type => type === expectedType);
26070
    };
26071
    const isInDragStartEvent = checkEvent(0);
26072
 
26073
    const createEmptyFileList = () => Object.freeze({
26074
      length: 0,
26075
      item: _ => null
26076
    });
26077
 
26078
    const modeId = generate$1('mode');
26079
    const getMode = transfer => {
26080
      const dt = transfer;
26081
      return Optional.from(dt[modeId]);
26082
    };
26083
    const mkSetModeFn = mode => transfer => {
26084
      const dt = transfer;
26085
      dt[modeId] = mode;
26086
    };
26087
    const setMode$1 = (transfer, mode) => mkSetModeFn(mode)(transfer);
26088
    const setReadWriteMode = mkSetModeFn(0);
26089
    const setReadOnlyMode = mkSetModeFn(2);
26090
    const setProtectedMode = mkSetModeFn(1);
26091
    const checkMode = expectedMode => transfer => {
26092
      const dt = transfer;
26093
      return Optional.from(dt[modeId]).exists(mode => mode === expectedMode);
26094
    };
26095
    const isInReadWriteMode = checkMode(0);
26096
    const isInProtectedMode = checkMode(1);
26097
 
26098
    const normalizeItems = (dataTransfer, itemsImpl) => ({
26099
      ...itemsImpl,
26100
      get length() {
26101
        return itemsImpl.length;
26102
      },
26103
      add: (data, type) => {
26104
        if (isInReadWriteMode(dataTransfer)) {
26105
          if (isString(data)) {
26106
            if (!isUndefined(type)) {
26107
              return itemsImpl.add(data, type);
26108
            }
26109
          } else {
26110
            return itemsImpl.add(data);
26111
          }
26112
        }
26113
        return null;
26114
      },
26115
      remove: idx => {
26116
        if (isInReadWriteMode(dataTransfer)) {
26117
          itemsImpl.remove(idx);
26118
        }
26119
      },
26120
      clear: () => {
26121
        if (isInReadWriteMode(dataTransfer)) {
26122
          itemsImpl.clear();
26123
        }
26124
      }
26125
    });
26126
 
26127
    const validDropEffects = [
26128
      'none',
26129
      'copy',
26130
      'link',
26131
      'move'
26132
    ];
26133
    const validEffectAlloweds = [
26134
      'none',
26135
      'copy',
26136
      'copyLink',
26137
      'copyMove',
26138
      'link',
26139
      'linkMove',
26140
      'move',
26141
      'all',
26142
      'uninitialized'
26143
    ];
26144
    const createDataTransfer = () => {
26145
      const dataTransferImpl = new window.DataTransfer();
26146
      let dropEffect = 'move';
26147
      let effectAllowed = 'all';
26148
      const dataTransfer = {
26149
        get dropEffect() {
26150
          return dropEffect;
26151
        },
26152
        set dropEffect(effect) {
26153
          if (contains$2(validDropEffects, effect)) {
26154
            dropEffect = effect;
26155
          }
26156
        },
26157
        get effectAllowed() {
26158
          return effectAllowed;
26159
        },
26160
        set effectAllowed(allowed) {
26161
          if (isInDragStartEvent(dataTransfer) && contains$2(validEffectAlloweds, allowed)) {
26162
            effectAllowed = allowed;
26163
          }
26164
        },
26165
        get items() {
26166
          return normalizeItems(dataTransfer, dataTransferImpl.items);
26167
        },
26168
        get files() {
26169
          if (isInProtectedMode(dataTransfer)) {
26170
            return createEmptyFileList();
26171
          } else {
26172
            return dataTransferImpl.files;
26173
          }
26174
        },
26175
        get types() {
26176
          return dataTransferImpl.types;
26177
        },
26178
        setDragImage: (image, x, y) => {
26179
          if (isInReadWriteMode(dataTransfer)) {
26180
            setDragImage(dataTransfer, {
26181
              image,
26182
              x,
26183
              y
26184
            });
26185
            dataTransferImpl.setDragImage(image, x, y);
26186
          }
26187
        },
26188
        getData: format => {
26189
          if (isInProtectedMode(dataTransfer)) {
26190
            return '';
26191
          } else {
26192
            return dataTransferImpl.getData(format);
26193
          }
26194
        },
26195
        setData: (format, data) => {
26196
          if (isInReadWriteMode(dataTransfer)) {
26197
            dataTransferImpl.setData(format, data);
26198
          }
26199
        },
26200
        clearData: format => {
26201
          if (isInReadWriteMode(dataTransfer)) {
26202
            dataTransferImpl.clearData(format);
26203
          }
26204
        }
26205
      };
26206
      setReadWriteMode(dataTransfer);
26207
      return dataTransfer;
26208
    };
26209
    const cloneDataTransfer = original => {
26210
      const clone = createDataTransfer();
26211
      const originalMode = getMode(original);
26212
      setReadOnlyMode(original);
26213
      setDragstartEvent(clone);
26214
      clone.dropEffect = original.dropEffect;
26215
      clone.effectAllowed = original.effectAllowed;
26216
      getDragImage(original).each(imageData => clone.setDragImage(imageData.image, imageData.x, imageData.y));
26217
      each$e(original.types, type => {
26218
        if (type !== 'Files') {
26219
          clone.setData(type, original.getData(type));
26220
        }
26221
      });
26222
      each$e(original.files, file => clone.items.add(file));
26223
      getEvent(original).each(type => {
26224
        setEvent(clone, type);
26225
      });
26226
      originalMode.each(mode => {
26227
        setMode$1(original, mode);
26228
        setMode$1(clone, mode);
26229
      });
26230
      return clone;
26231
    };
26232
 
26233
    const getHtmlData = dataTransfer => {
26234
      const html = dataTransfer.getData('text/html');
26235
      return html === '' ? Optional.none() : Optional.some(html);
26236
    };
26237
    const setHtmlData = (dataTransfer, html) => dataTransfer.setData('text/html', html);
26238
 
26239
    const internalMimeType = 'x-tinymce/html';
26240
    const internalHtmlMime = constant(internalMimeType);
26241
    const internalMark = '<!-- ' + internalMimeType + ' -->';
26242
    const mark = html => internalMark + html;
26243
    const unmark = html => html.replace(internalMark, '');
26244
    const isMarked = html => html.indexOf(internalMark) !== -1;
26245
 
26246
    const isPlainText = text => {
26247
      return !/<(?:\/?(?!(?:div|p|br|span)>)\w+|(?:(?!(?:span style="white-space:\s?pre;?">)|br\s?\/>))\w+\s[^>]+)>/i.test(text);
26248
    };
26249
    const openContainer = (rootTag, rootAttrs) => {
26250
      let tag = '<' + rootTag;
26251
      const attrs = mapToArray(rootAttrs, (value, key) => key + '="' + Entities.encodeAllRaw(value) + '"');
26252
      if (attrs.length) {
26253
        tag += ' ' + attrs.join(' ');
26254
      }
26255
      return tag + '>';
26256
    };
26257
    const toBlockElements = (text, rootTag, rootAttrs) => {
26258
      const blocks = text.split(/\n\n/);
26259
      const tagOpen = openContainer(rootTag, rootAttrs);
26260
      const tagClose = '</' + rootTag + '>';
26261
      const paragraphs = map$3(blocks, p => {
26262
        return p.split(/\n/).join('<br />');
26263
      });
26264
      const stitch = p => {
26265
        return tagOpen + p + tagClose;
26266
      };
26267
      return paragraphs.length === 1 ? paragraphs[0] : map$3(paragraphs, stitch).join('');
26268
    };
26269
 
26270
    const pasteBinDefaultContent = '%MCEPASTEBIN%';
26271
    const create$6 = (editor, lastRngCell) => {
26272
      const {dom, selection} = editor;
26273
      const body = editor.getBody();
26274
      lastRngCell.set(selection.getRng());
26275
      const pasteBinElm = dom.add(editor.getBody(), 'div', {
26276
        'id': 'mcepastebin',
26277
        'class': 'mce-pastebin',
26278
        'contentEditable': true,
26279
        'data-mce-bogus': 'all',
26280
        'style': 'position: fixed; top: 50%; width: 10px; height: 10px; overflow: hidden; opacity: 0'
26281
      }, pasteBinDefaultContent);
26282
      if (Env.browser.isFirefox()) {
26283
        dom.setStyle(pasteBinElm, 'left', dom.getStyle(body, 'direction', true) === 'rtl' ? 65535 : -65535);
26284
      }
26285
      dom.bind(pasteBinElm, 'beforedeactivate focusin focusout', e => {
26286
        e.stopPropagation();
26287
      });
26288
      pasteBinElm.focus();
26289
      selection.select(pasteBinElm, true);
26290
    };
26291
    const remove = (editor, lastRngCell) => {
26292
      const dom = editor.dom;
26293
      if (getEl(editor)) {
26294
        let pasteBinClone;
26295
        const lastRng = lastRngCell.get();
26296
        while (pasteBinClone = getEl(editor)) {
26297
          dom.remove(pasteBinClone);
26298
          dom.unbind(pasteBinClone);
26299
        }
26300
        if (lastRng) {
26301
          editor.selection.setRng(lastRng);
26302
        }
26303
      }
26304
      lastRngCell.set(null);
26305
    };
26306
    const getEl = editor => editor.dom.get('mcepastebin');
26307
    const isPasteBin = elm => isNonNullable(elm) && elm.id === 'mcepastebin';
26308
    const getHtml = editor => {
26309
      const dom = editor.dom;
26310
      const copyAndRemove = (toElm, fromElm) => {
26311
        toElm.appendChild(fromElm);
26312
        dom.remove(fromElm, true);
26313
      };
26314
      const [pasteBinElm, ...pasteBinClones] = filter$5(editor.getBody().childNodes, isPasteBin);
26315
      each$e(pasteBinClones, pasteBinClone => {
26316
        copyAndRemove(pasteBinElm, pasteBinClone);
26317
      });
26318
      const dirtyWrappers = dom.select('div[id=mcepastebin]', pasteBinElm);
26319
      for (let i = dirtyWrappers.length - 1; i >= 0; i--) {
26320
        const cleanWrapper = dom.create('div');
26321
        pasteBinElm.insertBefore(cleanWrapper, dirtyWrappers[i]);
26322
        copyAndRemove(cleanWrapper, dirtyWrappers[i]);
26323
      }
26324
      return pasteBinElm ? pasteBinElm.innerHTML : '';
26325
    };
26326
    const isDefaultPasteBinContent = content => content === pasteBinDefaultContent;
26327
    const PasteBin = editor => {
26328
      const lastRng = Cell(null);
26329
      return {
26330
        create: () => create$6(editor, lastRng),
26331
        remove: () => remove(editor, lastRng),
26332
        getEl: () => getEl(editor),
26333
        getHtml: () => getHtml(editor),
26334
        getLastRng: lastRng.get
26335
      };
26336
    };
26337
 
26338
    const filter$1 = (content, items) => {
26339
      Tools.each(items, v => {
26340
        if (is$4(v, RegExp)) {
26341
          content = content.replace(v, '');
26342
        } else {
26343
          content = content.replace(v[0], v[1]);
26344
        }
26345
      });
26346
      return content;
26347
    };
26348
    const innerText = html => {
26349
      const schema = Schema();
26350
      const domParser = DomParser({}, schema);
26351
      let text = '';
26352
      const voidElements = schema.getVoidElements();
26353
      const ignoreElements = Tools.makeMap('script noscript style textarea video audio iframe object', ' ');
26354
      const blockElements = schema.getBlockElements();
26355
      const walk = node => {
26356
        const name = node.name, currentNode = node;
26357
        if (name === 'br') {
26358
          text += '\n';
26359
          return;
26360
        }
26361
        if (name === 'wbr') {
26362
          return;
26363
        }
26364
        if (voidElements[name]) {
26365
          text += ' ';
26366
        }
26367
        if (ignoreElements[name]) {
26368
          text += ' ';
26369
          return;
26370
        }
26371
        if (node.type === 3) {
26372
          text += node.value;
26373
        }
26374
        if (!(node.name in schema.getVoidElements())) {
26375
          let currentNode = node.firstChild;
26376
          if (currentNode) {
26377
            do {
26378
              walk(currentNode);
26379
            } while (currentNode = currentNode.next);
26380
          }
26381
        }
26382
        if (blockElements[name] && currentNode.next) {
26383
          text += '\n';
26384
          if (name === 'p') {
26385
            text += '\n';
26386
          }
26387
        }
26388
      };
26389
      html = filter$1(html, [/<!\[[^\]]+\]>/g]);
26390
      walk(domParser.parse(html));
26391
      return text;
26392
    };
26393
    const trimHtml = html => {
26394
      const trimSpaces = (all, s1, s2) => {
26395
        if (!s1 && !s2) {
26396
          return ' ';
26397
        }
26398
        return nbsp;
26399
      };
26400
      html = filter$1(html, [
26401
        /^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/ig,
26402
        /<!--StartFragment-->|<!--EndFragment-->/g,
26403
        [
26404
          /( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g,
26405
          trimSpaces
26406
        ],
26407
        /<br class="Apple-interchange-newline">/g,
26408
        /<br>$/i
26409
      ]);
26410
      return html;
26411
    };
26412
    const createIdGenerator = prefix => {
26413
      let count = 0;
26414
      return () => {
26415
        return prefix + count++;
26416
      };
26417
    };
26418
    const getImageMimeType = ext => {
26419
      const lowerExt = ext.toLowerCase();
26420
      const mimeOverrides = {
26421
        jpg: 'jpeg',
26422
        jpe: 'jpeg',
26423
        jfi: 'jpeg',
26424
        jif: 'jpeg',
26425
        jfif: 'jpeg',
26426
        pjpeg: 'jpeg',
26427
        pjp: 'jpeg',
26428
        svg: 'svg+xml'
26429
      };
26430
      return Tools.hasOwn(mimeOverrides, lowerExt) ? 'image/' + mimeOverrides[lowerExt] : 'image/' + lowerExt;
26431
    };
26432
 
26433
    const preProcess = (editor, html) => {
26434
      const parser = DomParser({
26435
        sanitize: shouldSanitizeXss(editor),
1441 ariadna 26436
        sandbox_iframes: shouldSandboxIframes(editor),
26437
        sandbox_iframes_exclusions: getSandboxIframesExclusions(editor),
26438
        convert_unsafe_embeds: shouldConvertUnsafeEmbeds(editor)
1 efrain 26439
      }, editor.schema);
26440
      parser.addNodeFilter('meta', nodes => {
26441
        Tools.each(nodes, node => {
26442
          node.remove();
26443
        });
26444
      });
26445
      const fragment = parser.parse(html, {
26446
        forced_root_block: false,
26447
        isRootContent: true
26448
      });
26449
      return HtmlSerializer({ validate: true }, editor.schema).serialize(fragment);
26450
    };
26451
    const processResult = (content, cancelled) => ({
26452
      content,
26453
      cancelled
26454
    });
26455
    const postProcessFilter = (editor, html, internal) => {
26456
      const tempBody = editor.dom.create('div', { style: 'display:none' }, html);
26457
      const postProcessArgs = firePastePostProcess(editor, tempBody, internal);
26458
      return processResult(postProcessArgs.node.innerHTML, postProcessArgs.isDefaultPrevented());
26459
    };
26460
    const filterContent = (editor, content, internal) => {
26461
      const preProcessArgs = firePastePreProcess(editor, content, internal);
26462
      const filteredContent = preProcess(editor, preProcessArgs.content);
26463
      if (editor.hasEventListeners('PastePostProcess') && !preProcessArgs.isDefaultPrevented()) {
26464
        return postProcessFilter(editor, filteredContent, internal);
26465
      } else {
26466
        return processResult(filteredContent, preProcessArgs.isDefaultPrevented());
26467
      }
26468
    };
26469
    const process = (editor, html, internal) => {
26470
      return filterContent(editor, html, internal);
26471
    };
26472
 
26473
    const pasteHtml$1 = (editor, html) => {
26474
      editor.insertContent(html, {
26475
        merge: shouldPasteMergeFormats(editor),
26476
        paste: true
26477
      });
26478
      return true;
26479
    };
26480
    const isAbsoluteUrl = url => /^https?:\/\/[\w\-\/+=.,!;:&%@^~(){}?#]+$/i.test(url);
26481
    const isImageUrl = (editor, url) => {
26482
      return isAbsoluteUrl(url) && exists(getAllowedImageFileTypes(editor), type => endsWith(url.toLowerCase(), `.${ type.toLowerCase() }`));
26483
    };
26484
    const createImage = (editor, url, pasteHtmlFn) => {
26485
      editor.undoManager.extra(() => {
26486
        pasteHtmlFn(editor, url);
26487
      }, () => {
26488
        editor.insertContent('<img src="' + url + '">');
26489
      });
26490
      return true;
26491
    };
26492
    const createLink = (editor, url, pasteHtmlFn) => {
26493
      editor.undoManager.extra(() => {
26494
        pasteHtmlFn(editor, url);
26495
      }, () => {
26496
        editor.execCommand('mceInsertLink', false, url);
26497
      });
26498
      return true;
26499
    };
26500
    const linkSelection = (editor, html, pasteHtmlFn) => !editor.selection.isCollapsed() && isAbsoluteUrl(html) ? createLink(editor, html, pasteHtmlFn) : false;
26501
    const insertImage = (editor, html, pasteHtmlFn) => isImageUrl(editor, html) ? createImage(editor, html, pasteHtmlFn) : false;
26502
    const smartInsertContent = (editor, html) => {
26503
      Tools.each([
26504
        linkSelection,
26505
        insertImage,
26506
        pasteHtml$1
26507
      ], action => {
26508
        return !action(editor, html, pasteHtml$1);
26509
      });
26510
    };
26511
    const insertContent = (editor, html, pasteAsText) => {
26512
      if (pasteAsText || !isSmartPasteEnabled(editor)) {
26513
        pasteHtml$1(editor, html);
26514
      } else {
26515
        smartInsertContent(editor, html);
26516
      }
26517
    };
26518
 
26519
    const uniqueId = createIdGenerator('mceclip');
26520
    const createPasteDataTransfer = html => {
26521
      const dataTransfer = createDataTransfer();
26522
      setHtmlData(dataTransfer, html);
26523
      setReadOnlyMode(dataTransfer);
26524
      return dataTransfer;
26525
    };
26526
    const doPaste = (editor, content, internal, pasteAsText, shouldSimulateInputEvent) => {
26527
      const res = process(editor, content, internal);
26528
      if (!res.cancelled) {
26529
        const content = res.content;
26530
        const doPasteAction = () => insertContent(editor, content, pasteAsText);
26531
        if (shouldSimulateInputEvent) {
26532
          const args = fireBeforeInputEvent(editor, 'insertFromPaste', { dataTransfer: createPasteDataTransfer(content) });
26533
          if (!args.isDefaultPrevented()) {
26534
            doPasteAction();
26535
            fireInputEvent(editor, 'insertFromPaste');
26536
          }
26537
        } else {
26538
          doPasteAction();
26539
        }
26540
      }
26541
    };
26542
    const pasteHtml = (editor, html, internalFlag, shouldSimulateInputEvent) => {
26543
      const internal = internalFlag ? internalFlag : isMarked(html);
26544
      doPaste(editor, unmark(html), internal, false, shouldSimulateInputEvent);
26545
    };
26546
    const pasteText = (editor, text, shouldSimulateInputEvent) => {
26547
      const encodedText = editor.dom.encode(text).replace(/\r\n/g, '\n');
26548
      const normalizedText = normalize$4(encodedText, getPasteTabSpaces(editor));
26549
      const html = toBlockElements(normalizedText, getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
26550
      doPaste(editor, html, false, true, shouldSimulateInputEvent);
26551
    };
26552
    const getDataTransferItems = dataTransfer => {
26553
      const items = {};
26554
      if (dataTransfer && dataTransfer.types) {
26555
        for (let i = 0; i < dataTransfer.types.length; i++) {
26556
          const contentType = dataTransfer.types[i];
26557
          try {
26558
            items[contentType] = dataTransfer.getData(contentType);
1441 ariadna 26559
          } catch (_a) {
1 efrain 26560
            items[contentType] = '';
26561
          }
26562
        }
26563
      }
26564
      return items;
26565
    };
26566
    const hasContentType = (clipboardContent, mimeType) => mimeType in clipboardContent && clipboardContent[mimeType].length > 0;
26567
    const hasHtmlOrText = content => hasContentType(content, 'text/html') || hasContentType(content, 'text/plain');
26568
    const extractFilename = (editor, str) => {
26569
      const m = str.match(/([\s\S]+?)(?:\.[a-z0-9.]+)$/i);
26570
      return isNonNullable(m) ? editor.dom.encode(m[1]) : undefined;
26571
    };
26572
    const createBlobInfo = (editor, blobCache, file, base64) => {
26573
      const id = uniqueId();
26574
      const useFileName = shouldReuseFileName(editor) && isNonNullable(file.name);
26575
      const name = useFileName ? extractFilename(editor, file.name) : id;
26576
      const filename = useFileName ? file.name : undefined;
26577
      const blobInfo = blobCache.create(id, file, base64, name, filename);
26578
      blobCache.add(blobInfo);
26579
      return blobInfo;
26580
    };
26581
    const pasteImage = (editor, imageItem) => {
26582
      parseDataUri(imageItem.uri).each(({data, type, base64Encoded}) => {
26583
        const base64 = base64Encoded ? data : btoa(data);
26584
        const file = imageItem.file;
26585
        const blobCache = editor.editorUpload.blobCache;
26586
        const existingBlobInfo = blobCache.getByData(base64, type);
26587
        const blobInfo = existingBlobInfo !== null && existingBlobInfo !== void 0 ? existingBlobInfo : createBlobInfo(editor, blobCache, file, base64);
26588
        pasteHtml(editor, `<img src="${ blobInfo.blobUri() }">`, false, true);
26589
      });
26590
    };
26591
    const isClipboardEvent = event => event.type === 'paste';
26592
    const readFilesAsDataUris = items => Promise.all(map$3(items, file => {
26593
      return blobToDataUri(file).then(uri => ({
26594
        file,
26595
        uri
26596
      }));
26597
    }));
26598
    const isImage = editor => {
26599
      const allowedExtensions = getAllowedImageFileTypes(editor);
26600
      return file => startsWith(file.type, 'image/') && exists(allowedExtensions, extension => {
26601
        return getImageMimeType(extension) === file.type;
26602
      });
26603
    };
26604
    const getImagesFromDataTransfer = (editor, dataTransfer) => {
26605
      const items = dataTransfer.items ? bind$3(from(dataTransfer.items), item => {
26606
        return item.kind === 'file' ? [item.getAsFile()] : [];
26607
      }) : [];
26608
      const files = dataTransfer.files ? from(dataTransfer.files) : [];
26609
      return filter$5(items.length > 0 ? items : files, isImage(editor));
26610
    };
26611
    const pasteImageData = (editor, e, rng) => {
26612
      const dataTransfer = isClipboardEvent(e) ? e.clipboardData : e.dataTransfer;
26613
      if (shouldPasteDataImages(editor) && dataTransfer) {
26614
        const images = getImagesFromDataTransfer(editor, dataTransfer);
26615
        if (images.length > 0) {
26616
          e.preventDefault();
26617
          readFilesAsDataUris(images).then(fileResults => {
26618
            if (rng) {
26619
              editor.selection.setRng(rng);
26620
            }
26621
            each$e(fileResults, result => {
26622
              pasteImage(editor, result);
26623
            });
26624
          });
26625
          return true;
26626
        }
26627
      }
26628
      return false;
26629
    };
26630
    const isBrokenAndroidClipboardEvent = e => {
26631
      var _a, _b;
26632
      return Env.os.isAndroid() && ((_b = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.items) === null || _b === void 0 ? void 0 : _b.length) === 0;
26633
    };
26634
    const isKeyboardPasteEvent = e => VK.metaKeyPressed(e) && e.keyCode === 86 || e.shiftKey && e.keyCode === 45;
26635
    const insertClipboardContent = (editor, clipboardContent, html, plainTextMode, shouldSimulateInputEvent) => {
26636
      let content = trimHtml(html);
26637
      const isInternal = hasContentType(clipboardContent, internalHtmlMime()) || isMarked(html);
26638
      const isPlainTextHtml = !isInternal && isPlainText(content);
26639
      const isAbsoluteUrl$1 = isAbsoluteUrl(content);
26640
      if (isDefaultPasteBinContent(content) || !content.length || isPlainTextHtml && !isAbsoluteUrl$1) {
26641
        plainTextMode = true;
26642
      }
26643
      if (plainTextMode || isAbsoluteUrl$1) {
26644
        if (hasContentType(clipboardContent, 'text/plain') && isPlainTextHtml) {
26645
          content = clipboardContent['text/plain'];
26646
        } else {
26647
          content = innerText(content);
26648
        }
26649
      }
26650
      if (isDefaultPasteBinContent(content)) {
26651
        return;
26652
      }
26653
      if (plainTextMode) {
26654
        pasteText(editor, content, shouldSimulateInputEvent);
26655
      } else {
26656
        pasteHtml(editor, content, isInternal, shouldSimulateInputEvent);
26657
      }
26658
    };
26659
    const registerEventHandlers = (editor, pasteBin, pasteFormat) => {
26660
      let keyboardPastePlainTextState;
26661
      const getLastRng = () => pasteBin.getLastRng() || editor.selection.getRng();
26662
      editor.on('keydown', e => {
26663
        if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
26664
          keyboardPastePlainTextState = e.shiftKey && e.keyCode === 86;
26665
        }
26666
      });
26667
      editor.on('paste', e => {
26668
        if (e.isDefaultPrevented() || isBrokenAndroidClipboardEvent(e)) {
26669
          return;
26670
        }
26671
        const plainTextMode = pasteFormat.get() === 'text' || keyboardPastePlainTextState;
26672
        keyboardPastePlainTextState = false;
26673
        const clipboardContent = getDataTransferItems(e.clipboardData);
26674
        if (!hasHtmlOrText(clipboardContent) && pasteImageData(editor, e, getLastRng())) {
26675
          return;
26676
        }
26677
        if (hasContentType(clipboardContent, 'text/html')) {
26678
          e.preventDefault();
26679
          insertClipboardContent(editor, clipboardContent, clipboardContent['text/html'], plainTextMode, true);
26680
        } else if (hasContentType(clipboardContent, 'text/plain') && hasContentType(clipboardContent, 'text/uri-list')) {
26681
          e.preventDefault();
26682
          insertClipboardContent(editor, clipboardContent, clipboardContent['text/plain'], plainTextMode, true);
26683
        } else {
26684
          pasteBin.create();
26685
          Delay.setEditorTimeout(editor, () => {
26686
            const html = pasteBin.getHtml();
26687
            pasteBin.remove();
26688
            insertClipboardContent(editor, clipboardContent, html, plainTextMode, false);
26689
          }, 0);
26690
        }
26691
      });
26692
    };
26693
    const registerDataImageFilter = editor => {
26694
      const isWebKitFakeUrl = src => startsWith(src, 'webkit-fake-url');
26695
      const isDataUri = src => startsWith(src, 'data:');
26696
      const isPasteInsert = args => {
26697
        var _a;
26698
        return ((_a = args.data) === null || _a === void 0 ? void 0 : _a.paste) === true;
26699
      };
26700
      editor.parser.addNodeFilter('img', (nodes, name, args) => {
26701
        if (!shouldPasteDataImages(editor) && isPasteInsert(args)) {
26702
          for (const node of nodes) {
26703
            const src = node.attr('src');
26704
            if (isString(src) && !node.attr('data-mce-object') && src !== Env.transparentSrc) {
26705
              if (isWebKitFakeUrl(src)) {
26706
                node.remove();
26707
              } else if (!shouldAllowHtmlDataUrls(editor) && isDataUri(src)) {
26708
                node.remove();
26709
              }
26710
            }
26711
          }
26712
        }
26713
      });
26714
    };
26715
    const registerEventsAndFilters = (editor, pasteBin, pasteFormat) => {
26716
      registerEventHandlers(editor, pasteBin, pasteFormat);
26717
      registerDataImageFilter(editor);
26718
    };
26719
 
26720
    const togglePlainTextPaste = (editor, pasteFormat) => {
26721
      if (pasteFormat.get() === 'text') {
26722
        pasteFormat.set('html');
26723
        firePastePlainTextToggle(editor, false);
26724
      } else {
26725
        pasteFormat.set('text');
26726
        firePastePlainTextToggle(editor, true);
26727
      }
26728
      editor.focus();
26729
    };
26730
    const register$1 = (editor, pasteFormat) => {
26731
      editor.addCommand('mceTogglePlainTextPaste', () => {
26732
        togglePlainTextPaste(editor, pasteFormat);
26733
      });
26734
      editor.addCommand('mceInsertClipboardContent', (ui, value) => {
26735
        if (value.html) {
26736
          pasteHtml(editor, value.html, value.internal, false);
26737
        }
26738
        if (value.text) {
26739
          pasteText(editor, value.text, false);
26740
        }
26741
      });
26742
    };
26743
 
26744
    const setHtml5Clipboard = (clipboardData, html, text) => {
26745
      if (clipboardData) {
26746
        try {
26747
          clipboardData.clearData();
26748
          clipboardData.setData('text/html', html);
26749
          clipboardData.setData('text/plain', text);
26750
          clipboardData.setData(internalHtmlMime(), html);
26751
          return true;
1441 ariadna 26752
        } catch (_a) {
1 efrain 26753
          return false;
26754
        }
26755
      } else {
26756
        return false;
26757
      }
26758
    };
26759
    const setClipboardData = (evt, data, fallback, done) => {
26760
      if (setHtml5Clipboard(evt.clipboardData, data.html, data.text)) {
26761
        evt.preventDefault();
26762
        done();
26763
      } else {
26764
        fallback(data.html, done);
26765
      }
26766
    };
26767
    const fallback = editor => (html, done) => {
26768
      const {dom, selection} = editor;
26769
      const outer = dom.create('div', {
26770
        'contenteditable': 'false',
26771
        'data-mce-bogus': 'all'
26772
      });
26773
      const inner = dom.create('div', { contenteditable: 'true' }, html);
26774
      dom.setStyles(outer, {
26775
        position: 'fixed',
26776
        top: '0',
26777
        left: '-3000px',
26778
        width: '1000px',
26779
        overflow: 'hidden'
26780
      });
26781
      outer.appendChild(inner);
26782
      dom.add(editor.getBody(), outer);
26783
      const range = selection.getRng();
26784
      inner.focus();
26785
      const offscreenRange = dom.createRng();
26786
      offscreenRange.selectNodeContents(inner);
26787
      selection.setRng(offscreenRange);
26788
      Delay.setEditorTimeout(editor, () => {
26789
        selection.setRng(range);
26790
        dom.remove(outer);
26791
        done();
26792
      }, 0);
26793
    };
26794
    const getData = editor => ({
26795
      html: mark(editor.selection.getContent({ contextual: true })),
26796
      text: editor.selection.getContent({ format: 'text' })
26797
    });
26798
    const isTableSelection = editor => !!editor.dom.getParent(editor.selection.getStart(), 'td[data-mce-selected],th[data-mce-selected]', editor.getBody());
26799
    const hasSelectedContent = editor => !editor.selection.isCollapsed() || isTableSelection(editor);
26800
    const cut = editor => evt => {
26801
      if (!evt.isDefaultPrevented() && hasSelectedContent(editor) && editor.selection.isEditable()) {
26802
        setClipboardData(evt, getData(editor), fallback(editor), () => {
26803
          if (Env.browser.isChromium() || Env.browser.isFirefox()) {
26804
            const rng = editor.selection.getRng();
26805
            Delay.setEditorTimeout(editor, () => {
26806
              editor.selection.setRng(rng);
26807
              editor.execCommand('Delete');
26808
            }, 0);
26809
          } else {
26810
            editor.execCommand('Delete');
26811
          }
26812
        });
26813
      }
26814
    };
26815
    const copy = editor => evt => {
26816
      if (!evt.isDefaultPrevented() && hasSelectedContent(editor)) {
26817
        setClipboardData(evt, getData(editor), fallback(editor), noop);
26818
      }
26819
    };
26820
    const register = editor => {
26821
      editor.on('cut', cut(editor));
26822
      editor.on('copy', copy(editor));
26823
    };
26824
 
26825
    const getCaretRangeFromEvent = (editor, e) => {
26826
      var _a, _b;
26827
      return RangeUtils.getCaretRangeFromPoint((_a = e.clientX) !== null && _a !== void 0 ? _a : 0, (_b = e.clientY) !== null && _b !== void 0 ? _b : 0, editor.getDoc());
26828
    };
26829
    const isPlainTextFileUrl = content => {
26830
      const plainTextContent = content['text/plain'];
26831
      return plainTextContent ? plainTextContent.indexOf('file://') === 0 : false;
26832
    };
26833
    const setFocusedRange = (editor, rng) => {
26834
      editor.focus();
26835
      if (rng) {
26836
        editor.selection.setRng(rng);
26837
      }
26838
    };
26839
    const hasImage = dataTransfer => exists(dataTransfer.files, file => /^image\//.test(file.type));
26840
    const needsCustomInternalDrop = (dom, schema, target, dropContent) => {
26841
      const parentTransparent = dom.getParent(target, node => isTransparentBlock(schema, node));
26842
      const inSummary = !isNull(dom.getParent(target, 'summary'));
26843
      if (inSummary) {
26844
        return true;
26845
      } else if (parentTransparent && has$2(dropContent, 'text/html')) {
26846
        const fragment = new DOMParser().parseFromString(dropContent['text/html'], 'text/html').body;
26847
        return !isNull(fragment.querySelector(parentTransparent.nodeName.toLowerCase()));
26848
      } else {
26849
        return false;
26850
      }
26851
    };
26852
    const setupSummaryDeleteByDragFix = editor => {
26853
      editor.on('input', e => {
26854
        const hasNoSummary = el => isNull(el.querySelector('summary'));
26855
        if (e.inputType === 'deleteByDrag') {
26856
          const brokenDetailElements = filter$5(editor.dom.select('details'), hasNoSummary);
26857
          each$e(brokenDetailElements, details => {
26858
            if (isBr$6(details.firstChild)) {
26859
              details.firstChild.remove();
26860
            }
26861
            const summary = editor.dom.create('summary');
26862
            summary.appendChild(createPaddingBr().dom);
26863
            details.prepend(summary);
26864
          });
26865
        }
26866
      });
26867
    };
26868
    const setup$a = (editor, draggingInternallyState) => {
26869
      if (shouldPasteBlockDrop(editor)) {
26870
        editor.on('dragend dragover draggesture dragdrop drop drag', e => {
26871
          e.preventDefault();
26872
          e.stopPropagation();
26873
        });
26874
      }
26875
      if (!shouldPasteDataImages(editor)) {
26876
        editor.on('drop', e => {
26877
          const dataTransfer = e.dataTransfer;
26878
          if (dataTransfer && hasImage(dataTransfer)) {
26879
            e.preventDefault();
26880
          }
26881
        });
26882
      }
26883
      editor.on('drop', e => {
26884
        if (e.isDefaultPrevented()) {
26885
          return;
26886
        }
26887
        const rng = getCaretRangeFromEvent(editor, e);
26888
        if (isNullable(rng)) {
26889
          return;
26890
        }
26891
        const dropContent = getDataTransferItems(e.dataTransfer);
26892
        const internal = hasContentType(dropContent, internalHtmlMime());
26893
        if ((!hasHtmlOrText(dropContent) || isPlainTextFileUrl(dropContent)) && pasteImageData(editor, e, rng)) {
26894
          return;
26895
        }
26896
        const internalContent = dropContent[internalHtmlMime()];
26897
        const content = internalContent || dropContent['text/html'] || dropContent['text/plain'];
26898
        const needsInternalDrop = needsCustomInternalDrop(editor.dom, editor.schema, rng.startContainer, dropContent);
26899
        const isInternalDrop = draggingInternallyState.get();
26900
        if (isInternalDrop && !needsInternalDrop) {
26901
          return;
26902
        }
26903
        if (content) {
26904
          e.preventDefault();
26905
          Delay.setEditorTimeout(editor, () => {
26906
            editor.undoManager.transact(() => {
26907
              if (internalContent || isInternalDrop && needsInternalDrop) {
26908
                editor.execCommand('Delete');
26909
              }
26910
              setFocusedRange(editor, rng);
26911
              const trimmedContent = trimHtml(content);
26912
              if (dropContent['text/html']) {
26913
                pasteHtml(editor, trimmedContent, internal, true);
26914
              } else {
26915
                pasteText(editor, trimmedContent, true);
26916
              }
26917
            });
26918
          });
26919
        }
26920
      });
26921
      editor.on('dragstart', _e => {
26922
        draggingInternallyState.set(true);
26923
      });
26924
      editor.on('dragover dragend', e => {
26925
        if (shouldPasteDataImages(editor) && !draggingInternallyState.get()) {
26926
          e.preventDefault();
26927
          setFocusedRange(editor, getCaretRangeFromEvent(editor, e));
26928
        }
26929
        if (e.type === 'dragend') {
26930
          draggingInternallyState.set(false);
26931
        }
26932
      });
26933
      setupSummaryDeleteByDragFix(editor);
26934
    };
26935
 
26936
    const setup$9 = editor => {
26937
      const processEvent = f => e => {
26938
        f(editor, e);
26939
      };
26940
      const preProcess = getPastePreProcess(editor);
26941
      if (isFunction(preProcess)) {
26942
        editor.on('PastePreProcess', processEvent(preProcess));
26943
      }
26944
      const postProcess = getPastePostProcess(editor);
26945
      if (isFunction(postProcess)) {
26946
        editor.on('PastePostProcess', processEvent(postProcess));
26947
      }
26948
    };
26949
 
26950
    const addPreProcessFilter = (editor, filterFunc) => {
26951
      editor.on('PastePreProcess', e => {
26952
        e.content = filterFunc(editor, e.content, e.internal);
26953
      });
26954
    };
26955
    const rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi;
26956
    const rgbToHex = value => Tools.trim(value).replace(rgbRegExp, rgbaToHexString).toLowerCase();
26957
    const removeWebKitStyles = (editor, content, internal) => {
26958
      const webKitStylesOption = getPasteWebkitStyles(editor);
26959
      if (internal || webKitStylesOption === 'all' || !shouldPasteRemoveWebKitStyles(editor)) {
26960
        return content;
26961
      }
26962
      const webKitStyles = webKitStylesOption ? webKitStylesOption.split(/[, ]/) : [];
26963
      if (webKitStyles && webKitStylesOption !== 'none') {
26964
        const dom = editor.dom, node = editor.selection.getNode();
26965
        content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, (all, before, value, after) => {
26966
          const inputStyles = dom.parseStyle(dom.decode(value));
26967
          const outputStyles = {};
26968
          for (let i = 0; i < webKitStyles.length; i++) {
26969
            const inputValue = inputStyles[webKitStyles[i]];
26970
            let compareInput = inputValue;
26971
            let currentValue = dom.getStyle(node, webKitStyles[i], true);
26972
            if (/color/.test(webKitStyles[i])) {
26973
              compareInput = rgbToHex(compareInput);
26974
              currentValue = rgbToHex(currentValue);
26975
            }
26976
            if (currentValue !== compareInput) {
26977
              outputStyles[webKitStyles[i]] = inputValue;
26978
            }
26979
          }
26980
          const outputStyle = dom.serializeStyle(outputStyles, 'span');
26981
          if (outputStyle) {
26982
            return before + ' style="' + outputStyle + '"' + after;
26983
          }
26984
          return before + after;
26985
        });
26986
      } else {
26987
        content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, '$1$3');
26988
      }
26989
      content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, (all, before, value, after) => {
26990
        return before + ' style="' + value + '"' + after;
26991
      });
26992
      return content;
26993
    };
26994
    const setup$8 = editor => {
26995
      if (Env.browser.isChromium() || Env.browser.isSafari()) {
26996
        addPreProcessFilter(editor, removeWebKitStyles);
26997
      }
26998
    };
26999
 
27000
    const setup$7 = editor => {
27001
      const draggingInternallyState = Cell(false);
27002
      const pasteFormat = Cell(isPasteAsTextEnabled(editor) ? 'text' : 'html');
27003
      const pasteBin = PasteBin(editor);
27004
      setup$8(editor);
27005
      register$1(editor, pasteFormat);
27006
      setup$9(editor);
1441 ariadna 27007
      editor.addQueryStateHandler('mceTogglePlainTextPaste', () => pasteFormat.get() === 'text');
1 efrain 27008
      editor.on('PreInit', () => {
27009
        register(editor);
27010
        setup$a(editor, draggingInternallyState);
27011
        registerEventsAndFilters(editor, pasteBin, pasteFormat);
27012
      });
27013
    };
27014
 
27015
    const preventSummaryToggle = editor => {
27016
      editor.on('click', e => {
27017
        if (editor.dom.getParent(e.target, 'details')) {
27018
          e.preventDefault();
27019
        }
27020
      });
27021
    };
27022
    const filterDetails = editor => {
27023
      editor.parser.addNodeFilter('details', elms => {
27024
        const initialStateOption = getDetailsInitialState(editor);
27025
        each$e(elms, details => {
27026
          if (initialStateOption === 'expanded') {
27027
            details.attr('open', 'open');
27028
          } else if (initialStateOption === 'collapsed') {
27029
            details.attr('open', null);
27030
          }
27031
        });
27032
      });
27033
      editor.serializer.addNodeFilter('details', elms => {
27034
        const serializedStateOption = getDetailsSerializedState(editor);
27035
        each$e(elms, details => {
27036
          if (serializedStateOption === 'expanded') {
27037
            details.attr('open', 'open');
27038
          } else if (serializedStateOption === 'collapsed') {
27039
            details.attr('open', null);
27040
          }
27041
        });
27042
      });
27043
    };
27044
    const setup$6 = editor => {
27045
      preventSummaryToggle(editor);
27046
      filterDetails(editor);
27047
    };
27048
 
27049
    const isBr = isBr$6;
1441 ariadna 27050
    const isText = isText$b;
1 efrain 27051
    const isContentEditableFalse$2 = elm => isContentEditableFalse$b(elm.dom);
27052
    const isContentEditableTrue = elm => isContentEditableTrue$3(elm.dom);
27053
    const isRoot = rootNode => elm => eq(SugarElement.fromDom(rootNode), elm);
27054
    const getClosestScope = (node, rootNode, schema) => closest$4(SugarElement.fromDom(node), elm => isContentEditableTrue(elm) || schema.isBlock(name(elm)), isRoot(rootNode)).getOr(SugarElement.fromDom(rootNode)).dom;
27055
    const getClosestCef = (node, rootNode) => closest$4(SugarElement.fromDom(node), isContentEditableFalse$2, isRoot(rootNode));
27056
    const findEdgeCaretCandidate = (startNode, scope, forward) => {
27057
      const walker = new DomTreeWalker(startNode, scope);
27058
      const next = forward ? walker.next.bind(walker) : walker.prev.bind(walker);
27059
      let result = startNode;
27060
      for (let current = forward ? startNode : next(); current && !isBr(current); current = next()) {
27061
        if (isCaretCandidate$3(current)) {
27062
          result = current;
27063
        }
27064
      }
27065
      return result;
27066
    };
27067
    const findClosestBlockRange = (startRng, rootNode, schema) => {
27068
      const startPos = CaretPosition.fromRangeStart(startRng);
27069
      const clickNode = startPos.getNode();
27070
      const scope = getClosestScope(clickNode, rootNode, schema);
27071
      const startNode = findEdgeCaretCandidate(clickNode, scope, false);
27072
      const endNode = findEdgeCaretCandidate(clickNode, scope, true);
27073
      const rng = document.createRange();
27074
      getClosestCef(startNode, scope).fold(() => {
27075
        if (isText(startNode)) {
27076
          rng.setStart(startNode, 0);
27077
        } else {
27078
          rng.setStartBefore(startNode);
27079
        }
27080
      }, cef => rng.setStartBefore(cef.dom));
27081
      getClosestCef(endNode, scope).fold(() => {
27082
        if (isText(endNode)) {
27083
          rng.setEnd(endNode, endNode.data.length);
27084
        } else {
27085
          rng.setEndAfter(endNode);
27086
        }
27087
      }, cef => rng.setEndAfter(cef.dom));
27088
      return rng;
27089
    };
27090
    const onTripleClickSelect = editor => {
27091
      const rng = findClosestBlockRange(editor.selection.getRng(), editor.getBody(), editor.schema);
27092
      editor.selection.setRng(normalize(rng));
27093
    };
27094
    const setup$5 = editor => {
27095
      editor.on('mousedown', e => {
27096
        if (e.detail >= 3) {
27097
          e.preventDefault();
27098
          onTripleClickSelect(editor);
27099
        }
27100
      });
27101
    };
27102
 
27103
    var FakeCaretPosition;
27104
    (function (FakeCaretPosition) {
27105
      FakeCaretPosition['Before'] = 'before';
27106
      FakeCaretPosition['After'] = 'after';
27107
    }(FakeCaretPosition || (FakeCaretPosition = {})));
27108
    const distanceToRectLeft = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
27109
    const distanceToRectRight = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
27110
    const isInsideY = (clientY, clientRect) => clientY >= clientRect.top && clientY <= clientRect.bottom;
27111
    const collidesY = (r1, r2) => r1.top < r2.bottom && r1.bottom > r2.top;
27112
    const isOverlapping = (r1, r2) => {
27113
      const overlap = overlapY(r1, r2) / Math.min(r1.height, r2.height);
27114
      return collidesY(r1, r2) && overlap > 0.5;
27115
    };
27116
    const splitRectsPerAxis = (rects, y) => {
27117
      const intersectingRects = filter$5(rects, rect => isInsideY(y, rect));
27118
      return boundingClientRectFromRects(intersectingRects).fold(() => [
27119
        [],
27120
        rects
27121
      ], boundingRect => {
27122
        const {
27123
          pass: horizontal,
27124
          fail: vertical
27125
        } = partition$2(rects, rect => isOverlapping(rect, boundingRect));
27126
        return [
27127
          horizontal,
27128
          vertical
27129
        ];
27130
      });
27131
    };
27132
    const clientInfo = (rect, clientX) => {
27133
      return {
27134
        node: rect.node,
27135
        position: distanceToRectLeft(rect, clientX) < distanceToRectRight(rect, clientX) ? FakeCaretPosition.Before : FakeCaretPosition.After
27136
      };
27137
    };
27138
    const horizontalDistance = (rect, x, _y) => x > rect.left && x < rect.right ? 0 : Math.min(Math.abs(rect.left - x), Math.abs(rect.right - x));
27139
    const closestChildCaretCandidateNodeRect = (children, clientX, clientY, findCloserTextNode) => {
27140
      const caretCandidateRect = rect => {
27141
        if (isCaretCandidate$3(rect.node)) {
27142
          return Optional.some(rect);
27143
        } else if (isElement$6(rect.node)) {
27144
          return closestChildCaretCandidateNodeRect(from(rect.node.childNodes), clientX, clientY, false);
27145
        } else {
27146
          return Optional.none();
27147
        }
27148
      };
27149
      const tryFindSecondBestTextNode = (closest, sndClosest, distance) => {
27150
        return caretCandidateRect(sndClosest).filter(rect => {
27151
          const deltaDistance = Math.abs(distance(closest, clientX, clientY) - distance(rect, clientX, clientY));
1441 ariadna 27152
          return deltaDistance < 2 && isText$b(rect.node);
1 efrain 27153
        });
27154
      };
27155
      const findClosestCaretCandidateNodeRect = (rects, distance) => {
27156
        const sortedRects = sort(rects, (r1, r2) => distance(r1, clientX, clientY) - distance(r2, clientX, clientY));
27157
        return findMap(sortedRects, caretCandidateRect).map(closest => {
1441 ariadna 27158
          if (findCloserTextNode && !isText$b(closest.node) && sortedRects.length > 1) {
1 efrain 27159
            return tryFindSecondBestTextNode(closest, sortedRects[1], distance).getOr(closest);
27160
          } else {
27161
            return closest;
27162
          }
27163
        });
27164
      };
27165
      const [horizontalRects, verticalRects] = splitRectsPerAxis(getClientRects(children), clientY);
27166
      const {
27167
        pass: above,
27168
        fail: below
27169
      } = partition$2(verticalRects, rect => rect.top < clientY);
27170
      return findClosestCaretCandidateNodeRect(horizontalRects, horizontalDistance).orThunk(() => findClosestCaretCandidateNodeRect(below, distanceToRectEdgeFromXY)).orThunk(() => findClosestCaretCandidateNodeRect(above, distanceToRectEdgeFromXY));
27171
    };
27172
    const traverseUp = (rootElm, scope, clientX, clientY) => {
27173
      const helper = (scope, prevScope) => {
27174
        const isDragGhostContainer = node => isElement$6(node) && node.classList.contains('mce-drag-container');
27175
        const childNodesWithoutGhost = filter$5(scope.dom.childNodes, not(isDragGhostContainer));
27176
        return prevScope.fold(() => closestChildCaretCandidateNodeRect(childNodesWithoutGhost, clientX, clientY, true), prevScope => {
27177
          const uncheckedChildren = filter$5(childNodesWithoutGhost, node => node !== prevScope.dom);
27178
          return closestChildCaretCandidateNodeRect(uncheckedChildren, clientX, clientY, true);
27179
        }).orThunk(() => {
27180
          const parent = eq(scope, rootElm) ? Optional.none() : parentElement(scope);
27181
          return parent.bind(newScope => helper(newScope, Optional.some(scope)));
27182
        });
27183
      };
27184
      return helper(scope, Optional.none());
27185
    };
27186
    const closestCaretCandidateNodeRect = (root, clientX, clientY) => {
27187
      const rootElm = SugarElement.fromDom(root);
27188
      const ownerDoc = documentOrOwner(rootElm);
27189
      const elementAtPoint = SugarElement.fromPoint(ownerDoc, clientX, clientY).filter(elm => contains(rootElm, elm));
27190
      const element = elementAtPoint.getOr(rootElm);
27191
      return traverseUp(rootElm, element, clientX, clientY);
27192
    };
27193
    const closestFakeCaretCandidate = (root, clientX, clientY) => closestCaretCandidateNodeRect(root, clientX, clientY).filter(rect => isFakeCaretTarget(rect.node)).map(rect => clientInfo(rect, clientX));
27194
 
27195
    const getAbsolutePosition = elm => {
27196
      var _a, _b;
27197
      const clientRect = elm.getBoundingClientRect();
27198
      const doc = elm.ownerDocument;
27199
      const docElem = doc.documentElement;
27200
      const win = doc.defaultView;
27201
      return {
27202
        top: clientRect.top + ((_a = win === null || win === void 0 ? void 0 : win.scrollY) !== null && _a !== void 0 ? _a : 0) - docElem.clientTop,
27203
        left: clientRect.left + ((_b = win === null || win === void 0 ? void 0 : win.scrollX) !== null && _b !== void 0 ? _b : 0) - docElem.clientLeft
27204
      };
27205
    };
27206
    const getBodyPosition = editor => editor.inline ? getAbsolutePosition(editor.getBody()) : {
27207
      left: 0,
27208
      top: 0
27209
    };
27210
    const getScrollPosition = editor => {
27211
      const body = editor.getBody();
27212
      return editor.inline ? {
27213
        left: body.scrollLeft,
27214
        top: body.scrollTop
27215
      } : {
27216
        left: 0,
27217
        top: 0
27218
      };
27219
    };
27220
    const getBodyScroll = editor => {
27221
      const body = editor.getBody(), docElm = editor.getDoc().documentElement;
27222
      const inlineScroll = {
27223
        left: body.scrollLeft,
27224
        top: body.scrollTop
27225
      };
27226
      const iframeScroll = {
27227
        left: body.scrollLeft || docElm.scrollLeft,
27228
        top: body.scrollTop || docElm.scrollTop
27229
      };
27230
      return editor.inline ? inlineScroll : iframeScroll;
27231
    };
27232
    const getMousePosition = (editor, event) => {
27233
      if (event.target.ownerDocument !== editor.getDoc()) {
27234
        const iframePosition = getAbsolutePosition(editor.getContentAreaContainer());
27235
        const scrollPosition = getBodyScroll(editor);
27236
        return {
27237
          left: event.pageX - iframePosition.left + scrollPosition.left,
27238
          top: event.pageY - iframePosition.top + scrollPosition.top
27239
        };
27240
      }
27241
      return {
27242
        left: event.pageX,
27243
        top: event.pageY
27244
      };
27245
    };
27246
    const calculatePosition = (bodyPosition, scrollPosition, mousePosition) => ({
27247
      pageX: mousePosition.left - bodyPosition.left + scrollPosition.left,
27248
      pageY: mousePosition.top - bodyPosition.top + scrollPosition.top
27249
    });
27250
    const calc = (editor, event) => calculatePosition(getBodyPosition(editor), getScrollPosition(editor), getMousePosition(editor, event));
27251
 
27252
    const getTargetProps = target => ({
27253
      target,
27254
      srcElement: target
27255
    });
27256
    const makeDndEventFromMouseEvent = (type, mouseEvent, target, dataTransfer) => ({
27257
      ...mouseEvent,
27258
      dataTransfer,
27259
      type,
27260
      ...getTargetProps(target)
27261
    });
27262
    const makeDndEvent = (type, target, dataTransfer) => {
27263
      const fail = die('Function not supported on simulated event.');
27264
      const event = {
27265
        bubbles: true,
27266
        cancelBubble: false,
27267
        cancelable: true,
27268
        composed: false,
27269
        currentTarget: null,
27270
        defaultPrevented: false,
27271
        eventPhase: 0,
27272
        isTrusted: true,
27273
        returnValue: false,
27274
        timeStamp: 0,
27275
        type,
27276
        composedPath: fail,
27277
        initEvent: fail,
27278
        preventDefault: noop,
27279
        stopImmediatePropagation: noop,
27280
        stopPropagation: noop,
27281
        AT_TARGET: window.Event.AT_TARGET,
27282
        BUBBLING_PHASE: window.Event.BUBBLING_PHASE,
27283
        CAPTURING_PHASE: window.Event.CAPTURING_PHASE,
27284
        NONE: window.Event.NONE,
27285
        altKey: false,
27286
        button: 0,
27287
        buttons: 0,
27288
        clientX: 0,
27289
        clientY: 0,
27290
        ctrlKey: false,
1441 ariadna 27291
        layerX: 0,
27292
        layerY: 0,
1 efrain 27293
        metaKey: false,
27294
        movementX: 0,
27295
        movementY: 0,
27296
        offsetX: 0,
27297
        offsetY: 0,
27298
        pageX: 0,
27299
        pageY: 0,
27300
        relatedTarget: null,
27301
        screenX: 0,
27302
        screenY: 0,
27303
        shiftKey: false,
27304
        x: 0,
27305
        y: 0,
27306
        detail: 0,
27307
        view: null,
27308
        which: 0,
27309
        initUIEvent: fail,
27310
        initMouseEvent: fail,
27311
        getModifierState: fail,
27312
        dataTransfer,
27313
        ...getTargetProps(target)
27314
      };
27315
      return event;
27316
    };
27317
    const makeDataTransferCopyForDragEvent = (dataTransfer, eventType) => {
27318
      const copy = cloneDataTransfer(dataTransfer);
27319
      if (eventType === 'dragstart') {
27320
        setDragstartEvent(copy);
27321
        setReadWriteMode(copy);
27322
      } else if (eventType === 'drop') {
27323
        setDropEvent(copy);
27324
        setReadOnlyMode(copy);
27325
      } else {
27326
        setDragendEvent(copy);
27327
        setProtectedMode(copy);
27328
      }
27329
      return copy;
27330
    };
27331
    const makeDragEvent = (type, target, dataTransfer, mouseEvent) => {
27332
      const dataTransferForDispatch = makeDataTransferCopyForDragEvent(dataTransfer, type);
27333
      return isUndefined(mouseEvent) ? makeDndEvent(type, target, dataTransferForDispatch) : makeDndEventFromMouseEvent(type, mouseEvent, target, dataTransferForDispatch);
27334
    };
27335
 
27336
    const scrollPixelsPerInterval = 32;
27337
    const scrollIntervalValue = 100;
27338
    const mouseRangeToTriggerScrollInsideEditor = 8;
27339
    const mouseRangeToTriggerScrollOutsideEditor = 16;
27340
    const isContentEditableFalse$1 = isContentEditableFalse$b;
27341
    const isContentEditable = or(isContentEditableFalse$1, isContentEditableTrue$3);
27342
    const isDraggable = (dom, rootElm, elm) => isContentEditableFalse$1(elm) && elm !== rootElm && dom.isEditable(elm.parentElement);
27343
    const isValidDropTarget = (editor, targetElement, dragElement) => {
27344
      if (isNullable(targetElement)) {
27345
        return false;
27346
      } else if (targetElement === dragElement || editor.dom.isChildOf(targetElement, dragElement)) {
27347
        return false;
27348
      } else {
27349
        return editor.dom.isEditable(targetElement);
27350
      }
27351
    };
27352
    const createGhost = (editor, elm, width, height) => {
27353
      const dom = editor.dom;
27354
      const clonedElm = elm.cloneNode(true);
27355
      dom.setStyles(clonedElm, {
27356
        width,
27357
        height
27358
      });
27359
      dom.setAttrib(clonedElm, 'data-mce-selected', null);
27360
      const ghostElm = dom.create('div', {
27361
        'class': 'mce-drag-container',
27362
        'data-mce-bogus': 'all',
27363
        'unselectable': 'on',
27364
        'contenteditable': 'false'
27365
      });
27366
      dom.setStyles(ghostElm, {
27367
        position: 'absolute',
27368
        opacity: 0.5,
27369
        overflow: 'hidden',
27370
        border: 0,
27371
        padding: 0,
27372
        margin: 0,
27373
        width,
27374
        height
27375
      });
27376
      dom.setStyles(clonedElm, {
27377
        margin: 0,
27378
        boxSizing: 'border-box'
27379
      });
27380
      ghostElm.appendChild(clonedElm);
27381
      return ghostElm;
27382
    };
27383
    const appendGhostToBody = (ghostElm, bodyElm) => {
27384
      if (ghostElm.parentNode !== bodyElm) {
27385
        bodyElm.appendChild(ghostElm);
27386
      }
27387
    };
27388
    const scrollEditor = (direction, amount) => win => () => {
27389
      const current = direction === 'left' ? win.scrollX : win.scrollY;
27390
      win.scroll({
27391
        [direction]: current + amount,
27392
        behavior: 'smooth'
27393
      });
27394
    };
27395
    const scrollLeft = scrollEditor('left', -scrollPixelsPerInterval);
27396
    const scrollRight = scrollEditor('left', scrollPixelsPerInterval);
27397
    const scrollUp = scrollEditor('top', -scrollPixelsPerInterval);
27398
    const scrollDown = scrollEditor('top', scrollPixelsPerInterval);
27399
    const moveGhost = (ghostElm, position, width, height, maxX, maxY, mouseY, mouseX, contentAreaContainer, win, state, mouseEventOriginatedFromWithinTheEditor) => {
27400
      let overflowX = 0, overflowY = 0;
27401
      ghostElm.style.left = position.pageX + 'px';
27402
      ghostElm.style.top = position.pageY + 'px';
27403
      if (position.pageX + width > maxX) {
27404
        overflowX = position.pageX + width - maxX;
27405
      }
27406
      if (position.pageY + height > maxY) {
27407
        overflowY = position.pageY + height - maxY;
27408
      }
27409
      ghostElm.style.width = width - overflowX + 'px';
27410
      ghostElm.style.height = height - overflowY + 'px';
27411
      const clientHeight = contentAreaContainer.clientHeight;
27412
      const clientWidth = contentAreaContainer.clientWidth;
27413
      const outerMouseY = mouseY + contentAreaContainer.getBoundingClientRect().top;
27414
      const outerMouseX = mouseX + contentAreaContainer.getBoundingClientRect().left;
27415
      state.on(state => {
27416
        state.intervalId.clear();
27417
        if (state.dragging && mouseEventOriginatedFromWithinTheEditor) {
27418
          if (mouseY + mouseRangeToTriggerScrollInsideEditor >= clientHeight) {
27419
            state.intervalId.set(scrollDown(win));
27420
          } else if (mouseY - mouseRangeToTriggerScrollInsideEditor <= 0) {
27421
            state.intervalId.set(scrollUp(win));
27422
          } else if (mouseX + mouseRangeToTriggerScrollInsideEditor >= clientWidth) {
27423
            state.intervalId.set(scrollRight(win));
27424
          } else if (mouseX - mouseRangeToTriggerScrollInsideEditor <= 0) {
27425
            state.intervalId.set(scrollLeft(win));
27426
          } else if (outerMouseY + mouseRangeToTriggerScrollOutsideEditor >= window.innerHeight) {
27427
            state.intervalId.set(scrollDown(window));
27428
          } else if (outerMouseY - mouseRangeToTriggerScrollOutsideEditor <= 0) {
27429
            state.intervalId.set(scrollUp(window));
27430
          } else if (outerMouseX + mouseRangeToTriggerScrollOutsideEditor >= window.innerWidth) {
27431
            state.intervalId.set(scrollRight(window));
27432
          } else if (outerMouseX - mouseRangeToTriggerScrollOutsideEditor <= 0) {
27433
            state.intervalId.set(scrollLeft(window));
27434
          }
27435
        }
27436
      });
27437
    };
27438
    const removeElement = elm => {
27439
      if (elm && elm.parentNode) {
27440
        elm.parentNode.removeChild(elm);
27441
      }
27442
    };
27443
    const removeElementWithPadding = (dom, elm) => {
27444
      const parentBlock = dom.getParent(elm.parentNode, dom.isBlock);
27445
      removeElement(elm);
27446
      if (parentBlock && parentBlock !== dom.getRoot() && dom.isEmpty(parentBlock)) {
27447
        fillWithPaddingBr(SugarElement.fromDom(parentBlock));
27448
      }
27449
    };
27450
    const isLeftMouseButtonPressed = e => e.button === 0;
27451
    const applyRelPos = (state, position) => ({
27452
      pageX: position.pageX - state.relX,
27453
      pageY: position.pageY + 5
27454
    });
27455
    const start = (state, editor) => e => {
27456
      if (isLeftMouseButtonPressed(e)) {
27457
        const ceElm = find$2(editor.dom.getParents(e.target), isContentEditable).getOr(null);
27458
        if (isNonNullable(ceElm) && isDraggable(editor.dom, editor.getBody(), ceElm)) {
27459
          const elmPos = editor.dom.getPos(ceElm);
27460
          const bodyElm = editor.getBody();
27461
          const docElm = editor.getDoc().documentElement;
27462
          state.set({
27463
            element: ceElm,
27464
            dataTransfer: createDataTransfer(),
27465
            dragging: false,
27466
            screenX: e.screenX,
27467
            screenY: e.screenY,
27468
            maxX: (editor.inline ? bodyElm.scrollWidth : docElm.offsetWidth) - 2,
27469
            maxY: (editor.inline ? bodyElm.scrollHeight : docElm.offsetHeight) - 2,
27470
            relX: e.pageX - elmPos.x,
27471
            relY: e.pageY - elmPos.y,
27472
            width: ceElm.offsetWidth,
27473
            height: ceElm.offsetHeight,
27474
            ghost: createGhost(editor, ceElm, ceElm.offsetWidth, ceElm.offsetHeight),
27475
            intervalId: repeatable(scrollIntervalValue)
27476
          });
27477
        }
27478
      }
27479
    };
27480
    const placeCaretAt = (editor, clientX, clientY) => {
27481
      editor._selectionOverrides.hideFakeCaret();
27482
      closestFakeCaretCandidate(editor.getBody(), clientX, clientY).fold(() => editor.selection.placeCaretAt(clientX, clientY), caretInfo => {
27483
        const range = editor._selectionOverrides.showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
27484
        if (range) {
27485
          editor.selection.setRng(range);
27486
        } else {
27487
          editor.selection.placeCaretAt(clientX, clientY);
27488
        }
27489
      });
27490
    };
27491
    const dispatchDragEvent = (editor, type, target, dataTransfer, mouseEvent) => {
27492
      if (type === 'dragstart') {
27493
        setHtmlData(dataTransfer, editor.dom.getOuterHTML(target));
27494
      }
27495
      const event = makeDragEvent(type, target, dataTransfer, mouseEvent);
27496
      const args = editor.dispatch(type, event);
27497
      return args;
27498
    };
27499
    const move = (state, editor) => {
27500
      const throttledPlaceCaretAt = first$1((clientX, clientY) => placeCaretAt(editor, clientX, clientY), 0);
27501
      editor.on('remove', throttledPlaceCaretAt.cancel);
27502
      const state_ = state;
27503
      return e => state.on(state => {
27504
        const movement = Math.max(Math.abs(e.screenX - state.screenX), Math.abs(e.screenY - state.screenY));
27505
        if (!state.dragging && movement > 10) {
27506
          const args = dispatchDragEvent(editor, 'dragstart', state.element, state.dataTransfer, e);
27507
          if (isNonNullable(args.dataTransfer)) {
27508
            state.dataTransfer = args.dataTransfer;
27509
          }
27510
          if (args.isDefaultPrevented()) {
27511
            return;
27512
          }
27513
          state.dragging = true;
27514
          editor.focus();
27515
        }
27516
        if (state.dragging) {
27517
          const mouseEventOriginatedFromWithinTheEditor = e.currentTarget === editor.getDoc().documentElement;
27518
          const targetPos = applyRelPos(state, calc(editor, e));
27519
          appendGhostToBody(state.ghost, editor.getBody());
27520
          moveGhost(state.ghost, targetPos, state.width, state.height, state.maxX, state.maxY, e.clientY, e.clientX, editor.getContentAreaContainer(), editor.getWin(), state_, mouseEventOriginatedFromWithinTheEditor);
27521
          throttledPlaceCaretAt.throttle(e.clientX, e.clientY);
27522
        }
27523
      });
27524
    };
27525
    const getRawTarget = selection => {
27526
      const sel = selection.getSel();
27527
      if (isNonNullable(sel)) {
27528
        const rng = sel.getRangeAt(0);
27529
        const startContainer = rng.startContainer;
1441 ariadna 27530
        return isText$b(startContainer) ? startContainer.parentNode : startContainer;
1 efrain 27531
      } else {
27532
        return null;
27533
      }
27534
    };
27535
    const drop = (state, editor) => e => {
27536
      state.on(state => {
27537
        var _a;
27538
        state.intervalId.clear();
27539
        if (state.dragging) {
27540
          if (isValidDropTarget(editor, getRawTarget(editor.selection), state.element)) {
27541
            const dropTarget = (_a = editor.getDoc().elementFromPoint(e.clientX, e.clientY)) !== null && _a !== void 0 ? _a : editor.getBody();
27542
            const args = dispatchDragEvent(editor, 'drop', dropTarget, state.dataTransfer, e);
27543
            if (!args.isDefaultPrevented()) {
27544
              editor.undoManager.transact(() => {
27545
                removeElementWithPadding(editor.dom, state.element);
27546
                getHtmlData(state.dataTransfer).each(content => editor.insertContent(content));
27547
                editor._selectionOverrides.hideFakeCaret();
27548
              });
27549
            }
27550
          }
27551
          dispatchDragEvent(editor, 'dragend', editor.getBody(), state.dataTransfer, e);
27552
        }
27553
      });
27554
      removeDragState(state);
27555
    };
27556
    const stopDragging = (state, editor, e) => {
27557
      state.on(state => {
27558
        state.intervalId.clear();
27559
        if (state.dragging) {
27560
          e.fold(() => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer), mouseEvent => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer, mouseEvent));
27561
        }
27562
      });
27563
      removeDragState(state);
27564
    };
27565
    const stop = (state, editor) => e => stopDragging(state, editor, Optional.some(e));
27566
    const removeDragState = state => {
27567
      state.on(state => {
27568
        state.intervalId.clear();
27569
        removeElement(state.ghost);
27570
      });
27571
      state.clear();
27572
    };
27573
    const bindFakeDragEvents = editor => {
27574
      const state = value$2();
27575
      const pageDom = DOMUtils.DOM;
27576
      const rootDocument = document;
27577
      const dragStartHandler = start(state, editor);
27578
      const dragHandler = move(state, editor);
27579
      const dropHandler = drop(state, editor);
27580
      const dragEndHandler = stop(state, editor);
27581
      editor.on('mousedown', dragStartHandler);
27582
      editor.on('mousemove', dragHandler);
27583
      editor.on('mouseup', dropHandler);
27584
      pageDom.bind(rootDocument, 'mousemove', dragHandler);
27585
      pageDom.bind(rootDocument, 'mouseup', dragEndHandler);
27586
      editor.on('remove', () => {
27587
        pageDom.unbind(rootDocument, 'mousemove', dragHandler);
27588
        pageDom.unbind(rootDocument, 'mouseup', dragEndHandler);
27589
      });
27590
      editor.on('keydown', e => {
27591
        if (e.keyCode === VK.ESC) {
27592
          stopDragging(state, editor, Optional.none());
27593
        }
27594
      });
27595
    };
27596
    const blockUnsupportedFileDrop = editor => {
27597
      const preventFileDrop = e => {
27598
        if (!e.isDefaultPrevented()) {
27599
          const dataTransfer = e.dataTransfer;
27600
          if (dataTransfer && (contains$2(dataTransfer.types, 'Files') || dataTransfer.files.length > 0)) {
27601
            e.preventDefault();
27602
            if (e.type === 'drop') {
27603
              displayError(editor, 'Dropped file type is not supported');
27604
            }
27605
          }
27606
        }
27607
      };
27608
      const preventFileDropIfUIElement = e => {
27609
        if (isUIElement(editor, e.target)) {
27610
          preventFileDrop(e);
27611
        }
27612
      };
27613
      const setup = () => {
27614
        const pageDom = DOMUtils.DOM;
27615
        const dom = editor.dom;
27616
        const doc = document;
27617
        const editorRoot = editor.inline ? editor.getBody() : editor.getDoc();
27618
        const eventNames = [
27619
          'drop',
27620
          'dragover'
27621
        ];
27622
        each$e(eventNames, name => {
27623
          pageDom.bind(doc, name, preventFileDropIfUIElement);
27624
          dom.bind(editorRoot, name, preventFileDrop);
27625
        });
27626
        editor.on('remove', () => {
27627
          each$e(eventNames, name => {
27628
            pageDom.unbind(doc, name, preventFileDropIfUIElement);
27629
            dom.unbind(editorRoot, name, preventFileDrop);
27630
          });
27631
        });
27632
      };
27633
      editor.on('init', () => {
27634
        Delay.setEditorTimeout(editor, setup, 0);
27635
      });
27636
    };
27637
    const init$2 = editor => {
27638
      bindFakeDragEvents(editor);
27639
      if (shouldBlockUnsupportedDrop(editor)) {
27640
        blockUnsupportedFileDrop(editor);
27641
      }
27642
    };
27643
 
27644
    const setup$4 = editor => {
27645
      const renderFocusCaret = first$1(() => {
27646
        if (!editor.removed && editor.getBody().contains(document.activeElement)) {
27647
          const rng = editor.selection.getRng();
27648
          if (rng.collapsed) {
27649
            const caretRange = renderRangeCaret(editor, rng, false);
27650
            editor.selection.setRng(caretRange);
27651
          }
27652
        }
27653
      }, 0);
27654
      editor.on('focus', () => {
27655
        renderFocusCaret.throttle();
27656
      });
27657
      editor.on('blur', () => {
27658
        renderFocusCaret.cancel();
27659
      });
27660
    };
27661
 
27662
    const setup$3 = editor => {
27663
      editor.on('init', () => {
27664
        editor.on('focusin', e => {
27665
          const target = e.target;
27666
          if (isMedia$2(target)) {
27667
            const ceRoot = getContentEditableRoot$1(editor.getBody(), target);
27668
            const node = isContentEditableFalse$b(ceRoot) ? ceRoot : target;
27669
            if (editor.selection.getNode() !== node) {
27670
              selectNode(editor, node).each(rng => editor.selection.setRng(rng));
27671
            }
27672
          }
27673
        });
27674
      });
27675
    };
27676
 
27677
    const isContentEditableFalse = isContentEditableFalse$b;
27678
    const getContentEditableRoot = (editor, node) => getContentEditableRoot$1(editor.getBody(), node);
27679
    const SelectionOverrides = editor => {
27680
      const selection = editor.selection, dom = editor.dom;
27681
      const rootNode = editor.getBody();
27682
      const fakeCaret = FakeCaret(editor, rootNode, dom.isBlock, () => hasFocus(editor));
27683
      const realSelectionId = 'sel-' + dom.uniqueId();
27684
      const elementSelectionAttr = 'data-mce-selected';
27685
      let selectedElement;
27686
      const isFakeSelectionElement = node => isNonNullable(node) && dom.hasClass(node, 'mce-offscreen-selection');
27687
      const isFakeSelectionTargetElement = node => node !== rootNode && (isContentEditableFalse(node) || isMedia$2(node)) && dom.isChildOf(node, rootNode) && dom.isEditable(node.parentNode);
27688
      const setRange = range => {
27689
        if (range) {
27690
          selection.setRng(range);
27691
        }
27692
      };
27693
      const showCaret = (direction, node, before, scrollIntoView = true) => {
27694
        const e = editor.dispatch('ShowCaret', {
27695
          target: node,
27696
          direction,
27697
          before
27698
        });
27699
        if (e.isDefaultPrevented()) {
27700
          return null;
27701
        }
27702
        if (scrollIntoView) {
27703
          selection.scrollIntoView(node, direction === -1);
27704
        }
27705
        return fakeCaret.show(before, node);
27706
      };
27707
      const showBlockCaretContainer = blockCaretContainer => {
27708
        if (blockCaretContainer.hasAttribute('data-mce-caret')) {
27709
          showCaretContainerBlock(blockCaretContainer);
27710
          selection.scrollIntoView(blockCaretContainer);
27711
        }
27712
      };
27713
      const registerEvents = () => {
27714
        editor.on('click', e => {
27715
          if (!dom.isEditable(e.target)) {
27716
            e.preventDefault();
27717
            editor.focus();
27718
          }
27719
        });
27720
        editor.on('blur NewBlock', removeElementSelection);
27721
        editor.on('ResizeWindow FullscreenStateChanged', fakeCaret.reposition);
27722
        editor.on('tap', e => {
27723
          const targetElm = e.target;
27724
          const contentEditableRoot = getContentEditableRoot(editor, targetElm);
27725
          if (isContentEditableFalse(contentEditableRoot)) {
27726
            e.preventDefault();
27727
            selectNode(editor, contentEditableRoot).each(setElementSelection);
27728
          } else if (isFakeSelectionTargetElement(targetElm)) {
27729
            selectNode(editor, targetElm).each(setElementSelection);
27730
          }
27731
        }, true);
27732
        editor.on('mousedown', e => {
27733
          const targetElm = e.target;
27734
          if (targetElm !== rootNode && targetElm.nodeName !== 'HTML' && !dom.isChildOf(targetElm, rootNode)) {
27735
            return;
27736
          }
27737
          if (!isXYInContentArea(editor, e.clientX, e.clientY)) {
27738
            return;
27739
          }
27740
          removeElementSelection();
27741
          hideFakeCaret();
27742
          const closestContentEditable = getContentEditableRoot(editor, targetElm);
27743
          if (isContentEditableFalse(closestContentEditable)) {
27744
            e.preventDefault();
27745
            selectNode(editor, closestContentEditable).each(setElementSelection);
27746
          } else {
27747
            closestFakeCaretCandidate(rootNode, e.clientX, e.clientY).each(caretInfo => {
27748
              e.preventDefault();
27749
              const range = showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
27750
              setRange(range);
27751
              if (isHTMLElement(closestContentEditable)) {
27752
                closestContentEditable.focus();
27753
              } else {
27754
                editor.getBody().focus();
27755
              }
27756
            });
27757
          }
27758
        });
27759
        editor.on('keypress', e => {
27760
          if (VK.modifierPressed(e)) {
27761
            return;
27762
          }
27763
          if (isContentEditableFalse(selection.getNode())) {
27764
            e.preventDefault();
27765
          }
27766
        });
27767
        editor.on('GetSelectionRange', e => {
27768
          let rng = e.range;
27769
          if (selectedElement) {
27770
            if (!selectedElement.parentNode) {
27771
              selectedElement = null;
27772
              return;
27773
            }
27774
            rng = rng.cloneRange();
27775
            rng.selectNode(selectedElement);
27776
            e.range = rng;
27777
          }
27778
        });
27779
        editor.on('SetSelectionRange', e => {
27780
          e.range = normalizeVoidElementSelection(e.range);
27781
          const rng = setElementSelection(e.range, e.forward);
27782
          if (rng) {
27783
            e.range = rng;
27784
          }
27785
        });
27786
        const isPasteBin = node => isElement$6(node) && node.id === 'mcepastebin';
27787
        editor.on('AfterSetSelectionRange', e => {
27788
          const rng = e.range;
27789
          const parent = rng.startContainer.parentElement;
27790
          if (!isRangeInCaretContainer(rng) && !isPasteBin(parent)) {
27791
            hideFakeCaret();
27792
          }
27793
          if (!isFakeSelectionElement(parent)) {
27794
            removeElementSelection();
27795
          }
27796
        });
27797
        init$2(editor);
27798
        setup$4(editor);
27799
        setup$3(editor);
27800
      };
27801
      const isWithinCaretContainer = node => isCaretContainer$2(node) || startsWithCaretContainer$1(node) || endsWithCaretContainer$1(node);
27802
      const isRangeInCaretContainer = rng => isWithinCaretContainer(rng.startContainer) || isWithinCaretContainer(rng.endContainer);
27803
      const normalizeVoidElementSelection = rng => {
27804
        const voidElements = editor.schema.getVoidElements();
27805
        const newRng = dom.createRng();
27806
        const startContainer = rng.startContainer;
27807
        const startOffset = rng.startOffset;
27808
        const endContainer = rng.endContainer;
27809
        const endOffset = rng.endOffset;
27810
        if (has$2(voidElements, startContainer.nodeName.toLowerCase())) {
27811
          if (startOffset === 0) {
27812
            newRng.setStartBefore(startContainer);
27813
          } else {
27814
            newRng.setStartAfter(startContainer);
27815
          }
27816
        } else {
27817
          newRng.setStart(startContainer, startOffset);
27818
        }
27819
        if (has$2(voidElements, endContainer.nodeName.toLowerCase())) {
27820
          if (endOffset === 0) {
27821
            newRng.setEndBefore(endContainer);
27822
          } else {
27823
            newRng.setEndAfter(endContainer);
27824
          }
27825
        } else {
27826
          newRng.setEnd(endContainer, endOffset);
27827
        }
27828
        return newRng;
27829
      };
27830
      const setupOffscreenSelection = (node, targetClone) => {
27831
        const body = SugarElement.fromDom(editor.getBody());
27832
        const doc = editor.getDoc();
27833
        const realSelectionContainer = descendant$1(body, '#' + realSelectionId).getOrThunk(() => {
27834
          const newContainer = SugarElement.fromHtml('<div data-mce-bogus="all" class="mce-offscreen-selection"></div>', doc);
1441 ariadna 27835
          set$4(newContainer, 'id', realSelectionId);
1 efrain 27836
          append$1(body, newContainer);
27837
          return newContainer;
27838
        });
27839
        const newRange = dom.createRng();
27840
        empty(realSelectionContainer);
27841
        append(realSelectionContainer, [
27842
          SugarElement.fromText(nbsp, doc),
27843
          SugarElement.fromDom(targetClone),
27844
          SugarElement.fromText(nbsp, doc)
27845
        ]);
27846
        newRange.setStart(realSelectionContainer.dom.firstChild, 1);
27847
        newRange.setEnd(realSelectionContainer.dom.lastChild, 0);
27848
        setAll(realSelectionContainer, { top: dom.getPos(node, editor.getBody()).y + 'px' });
27849
        focus$1(realSelectionContainer);
27850
        const sel = selection.getSel();
27851
        if (sel) {
27852
          sel.removeAllRanges();
27853
          sel.addRange(newRange);
27854
        }
27855
        return newRange;
27856
      };
27857
      const selectElement = elm => {
27858
        const targetClone = elm.cloneNode(true);
27859
        const e = editor.dispatch('ObjectSelected', {
27860
          target: elm,
27861
          targetClone
27862
        });
27863
        if (e.isDefaultPrevented()) {
27864
          return null;
27865
        }
27866
        const range = setupOffscreenSelection(elm, e.targetClone);
27867
        const nodeElm = SugarElement.fromDom(elm);
27868
        each$e(descendants(SugarElement.fromDom(editor.getBody()), `*[${ elementSelectionAttr }]`), elm => {
27869
          if (!eq(nodeElm, elm)) {
1441 ariadna 27870
            remove$9(elm, elementSelectionAttr);
1 efrain 27871
          }
27872
        });
27873
        if (!dom.getAttrib(elm, elementSelectionAttr)) {
27874
          elm.setAttribute(elementSelectionAttr, '1');
27875
        }
27876
        selectedElement = elm;
27877
        hideFakeCaret();
27878
        return range;
27879
      };
27880
      const setElementSelection = (range, forward) => {
27881
        if (!range) {
27882
          return null;
27883
        }
27884
        if (range.collapsed) {
27885
          if (!isRangeInCaretContainer(range)) {
27886
            const dir = forward ? 1 : -1;
27887
            const caretPosition = getNormalizedRangeEndPoint(dir, rootNode, range);
27888
            const beforeNode = caretPosition.getNode(!forward);
27889
            if (isNonNullable(beforeNode)) {
27890
              if (isFakeCaretTarget(beforeNode)) {
27891
                return showCaret(dir, beforeNode, forward ? !caretPosition.isAtEnd() : false, false);
27892
              }
27893
              if (isCaretContainerInline(beforeNode) && isContentEditableFalse$b(beforeNode.nextSibling)) {
27894
                const rng = dom.createRng();
27895
                rng.setStart(beforeNode, 0);
27896
                rng.setEnd(beforeNode, 0);
27897
                return rng;
27898
              }
27899
            }
27900
            const afterNode = caretPosition.getNode(forward);
27901
            if (isNonNullable(afterNode)) {
27902
              if (isFakeCaretTarget(afterNode)) {
27903
                return showCaret(dir, afterNode, forward ? false : !caretPosition.isAtEnd(), false);
27904
              }
27905
              if (isCaretContainerInline(afterNode) && isContentEditableFalse$b(afterNode.previousSibling)) {
27906
                const rng = dom.createRng();
27907
                rng.setStart(afterNode, 1);
27908
                rng.setEnd(afterNode, 1);
27909
                return rng;
27910
              }
27911
            }
27912
          }
27913
          return null;
27914
        }
27915
        let startContainer = range.startContainer;
27916
        let startOffset = range.startOffset;
27917
        const endOffset = range.endOffset;
1441 ariadna 27918
        if (isText$b(startContainer) && startOffset === 0 && isContentEditableFalse(startContainer.parentNode)) {
1 efrain 27919
          startContainer = startContainer.parentNode;
27920
          startOffset = dom.nodeIndex(startContainer);
27921
          startContainer = startContainer.parentNode;
27922
        }
27923
        if (!isElement$6(startContainer)) {
27924
          return null;
27925
        }
27926
        if (endOffset === startOffset + 1 && startContainer === range.endContainer) {
27927
          const node = startContainer.childNodes[startOffset];
27928
          if (isFakeSelectionTargetElement(node)) {
27929
            return selectElement(node);
27930
          }
27931
        }
27932
        return null;
27933
      };
27934
      const removeElementSelection = () => {
27935
        if (selectedElement) {
27936
          selectedElement.removeAttribute(elementSelectionAttr);
27937
        }
1441 ariadna 27938
        descendant$1(SugarElement.fromDom(editor.getBody()), '#' + realSelectionId).each(remove$4);
1 efrain 27939
        selectedElement = null;
27940
      };
27941
      const destroy = () => {
27942
        fakeCaret.destroy();
27943
        selectedElement = null;
27944
      };
27945
      const hideFakeCaret = () => {
27946
        fakeCaret.hide();
27947
      };
27948
      if (!isRtc(editor)) {
27949
        registerEvents();
27950
      }
27951
      return {
27952
        showCaret,
27953
        showBlockCaretContainer,
27954
        hideFakeCaret,
27955
        destroy
27956
      };
27957
    };
27958
 
27959
    const getNormalizedTextOffset = (container, offset) => {
27960
      let normalizedOffset = offset;
1441 ariadna 27961
      for (let node = container.previousSibling; isText$b(node); node = node.previousSibling) {
1 efrain 27962
        normalizedOffset += node.data.length;
27963
      }
27964
      return normalizedOffset;
27965
    };
27966
    const generatePath = (dom, root, node, offset, normalized) => {
1441 ariadna 27967
      if (isText$b(node) && (offset < 0 || offset > node.data.length)) {
1 efrain 27968
        return [];
27969
      }
1441 ariadna 27970
      const p = normalized && isText$b(node) ? [getNormalizedTextOffset(node, offset)] : [offset];
1 efrain 27971
      let current = node;
27972
      while (current !== root && current.parentNode) {
27973
        p.push(dom.nodeIndex(current, normalized));
27974
        current = current.parentNode;
27975
      }
27976
      return current === root ? p.reverse() : [];
27977
    };
27978
    const generatePathRange = (dom, root, startNode, startOffset, endNode, endOffset, normalized = false) => {
27979
      const start = generatePath(dom, root, startNode, startOffset, normalized);
27980
      const end = generatePath(dom, root, endNode, endOffset, normalized);
27981
      return {
27982
        start,
27983
        end
27984
      };
27985
    };
27986
    const resolvePath = (root, path) => {
27987
      const nodePath = path.slice();
27988
      const offset = nodePath.pop();
27989
      if (!isNumber(offset)) {
27990
        return Optional.none();
27991
      } else {
27992
        const resolvedNode = foldl(nodePath, (optNode, index) => optNode.bind(node => Optional.from(node.childNodes[index])), Optional.some(root));
27993
        return resolvedNode.bind(node => {
1441 ariadna 27994
          if (isText$b(node) && (offset < 0 || offset > node.data.length)) {
1 efrain 27995
            return Optional.none();
27996
          } else {
27997
            return Optional.some({
27998
              node,
27999
              offset
28000
            });
28001
          }
28002
        });
28003
      }
28004
    };
28005
    const resolvePathRange = (root, range) => resolvePath(root, range.start).bind(({
28006
      node: startNode,
28007
      offset: startOffset
28008
    }) => resolvePath(root, range.end).map(({
28009
      node: endNode,
28010
      offset: endOffset
28011
    }) => {
28012
      const rng = document.createRange();
28013
      rng.setStart(startNode, startOffset);
28014
      rng.setEnd(endNode, endOffset);
28015
      return rng;
28016
    }));
28017
    const generatePathRangeFromRange = (dom, root, range, normalized = false) => generatePathRange(dom, root, range.startContainer, range.startOffset, range.endContainer, range.endOffset, normalized);
28018
 
28019
    const cleanEmptyNodes = (dom, node, isRoot) => {
28020
      if (node && dom.isEmpty(node) && !isRoot(node)) {
28021
        const parent = node.parentNode;
1441 ariadna 28022
        dom.remove(node, isText$b(node.firstChild) && isWhitespaceText(node.firstChild.data));
1 efrain 28023
        cleanEmptyNodes(dom, parent, isRoot);
28024
      }
28025
    };
28026
    const deleteRng = (dom, rng, isRoot, clean = true) => {
28027
      const startParent = rng.startContainer.parentNode;
28028
      const endParent = rng.endContainer.parentNode;
28029
      rng.deleteContents();
28030
      if (clean && !isRoot(rng.startContainer)) {
1441 ariadna 28031
        if (isText$b(rng.startContainer) && rng.startContainer.data.length === 0) {
1 efrain 28032
          dom.remove(rng.startContainer);
28033
        }
1441 ariadna 28034
        if (isText$b(rng.endContainer) && rng.endContainer.data.length === 0) {
1 efrain 28035
          dom.remove(rng.endContainer);
28036
        }
28037
        cleanEmptyNodes(dom, startParent, isRoot);
28038
        if (startParent !== endParent) {
28039
          cleanEmptyNodes(dom, endParent, isRoot);
28040
        }
28041
      }
28042
    };
28043
    const getParentBlock = (editor, rng) => Optional.from(editor.dom.getParent(rng.startContainer, editor.dom.isBlock));
28044
    const resolveFromDynamicPatterns = (patternSet, block, beforeText) => {
28045
      const dynamicPatterns = patternSet.dynamicPatternsLookup({
28046
        text: beforeText,
28047
        block
28048
      });
28049
      return {
28050
        ...patternSet,
28051
        blockPatterns: getBlockPatterns(dynamicPatterns).concat(patternSet.blockPatterns),
28052
        inlinePatterns: getInlinePatterns(dynamicPatterns).concat(patternSet.inlinePatterns)
28053
      };
28054
    };
28055
    const getBeforeText = (dom, block, node, offset) => {
28056
      const rng = dom.createRng();
28057
      rng.setStart(block, 0);
28058
      rng.setEnd(node, offset);
28059
      return rng.toString();
28060
    };
28061
 
28062
    const newMarker = (dom, id) => dom.create('span', {
28063
      'data-mce-type': 'bookmark',
28064
      id
28065
    });
28066
    const rangeFromMarker = (dom, marker) => {
28067
      const rng = dom.createRng();
28068
      rng.setStartAfter(marker.start);
28069
      rng.setEndBefore(marker.end);
28070
      return rng;
28071
    };
28072
    const createMarker = (dom, markerPrefix, pathRange) => {
28073
      const rng = resolvePathRange(dom.getRoot(), pathRange).getOrDie('Unable to resolve path range');
28074
      const startNode = rng.startContainer;
28075
      const endNode = rng.endContainer;
28076
      const textEnd = rng.endOffset === 0 ? endNode : endNode.splitText(rng.endOffset);
28077
      const textStart = rng.startOffset === 0 ? startNode : startNode.splitText(rng.startOffset);
28078
      const startParentNode = textStart.parentNode;
28079
      const endParentNode = textEnd.parentNode;
28080
      return {
28081
        prefix: markerPrefix,
28082
        end: endParentNode.insertBefore(newMarker(dom, markerPrefix + '-end'), textEnd),
28083
        start: startParentNode.insertBefore(newMarker(dom, markerPrefix + '-start'), textStart)
28084
      };
28085
    };
28086
    const removeMarker = (dom, marker, isRoot) => {
28087
      cleanEmptyNodes(dom, dom.get(marker.prefix + '-end'), isRoot);
28088
      cleanEmptyNodes(dom, dom.get(marker.prefix + '-start'), isRoot);
28089
    };
28090
 
28091
    const isReplacementPattern = pattern => pattern.start.length === 0;
28092
    const matchesPattern = patternContent => (element, offset) => {
28093
      const text = element.data;
28094
      const searchText = text.substring(0, offset);
28095
      const startEndIndex = searchText.lastIndexOf(patternContent.charAt(patternContent.length - 1));
28096
      const startIndex = searchText.lastIndexOf(patternContent);
28097
      if (startIndex !== -1) {
28098
        return startIndex + patternContent.length;
28099
      } else if (startEndIndex !== -1) {
28100
        return startEndIndex + 1;
28101
      } else {
28102
        return -1;
28103
      }
28104
    };
28105
    const findPatternStartFromSpot = (dom, pattern, block, spot) => {
28106
      const startPattern = pattern.start;
28107
      const startSpot = repeatLeft(dom, spot.container, spot.offset, matchesPattern(startPattern), block);
28108
      return startSpot.bind(spot => {
28109
        var _a, _b;
28110
        const startPatternIndex = (_b = (_a = block.textContent) === null || _a === void 0 ? void 0 : _a.indexOf(startPattern)) !== null && _b !== void 0 ? _b : -1;
28111
        const isCompleteMatch = startPatternIndex !== -1 && spot.offset >= startPatternIndex + startPattern.length;
28112
        if (isCompleteMatch) {
28113
          const rng = dom.createRng();
28114
          rng.setStart(spot.container, spot.offset - startPattern.length);
28115
          rng.setEnd(spot.container, spot.offset);
28116
          return Optional.some(rng);
28117
        } else {
28118
          const offset = spot.offset - startPattern.length;
28119
          return scanLeft(spot.container, offset, block).map(nextSpot => {
28120
            const rng = dom.createRng();
28121
            rng.setStart(nextSpot.container, nextSpot.offset);
28122
            rng.setEnd(spot.container, spot.offset);
28123
            return rng;
28124
          }).filter(rng => rng.toString() === startPattern).orThunk(() => findPatternStartFromSpot(dom, pattern, block, point(spot.container, 0)));
28125
        }
28126
      });
28127
    };
28128
    const findPatternStart = (dom, pattern, node, offset, block, requireGap = false) => {
28129
      if (pattern.start.length === 0 && !requireGap) {
28130
        const rng = dom.createRng();
28131
        rng.setStart(node, offset);
28132
        rng.setEnd(node, offset);
28133
        return Optional.some(rng);
28134
      }
28135
      return textBefore(node, offset, block).bind(spot => {
28136
        const start = findPatternStartFromSpot(dom, pattern, block, spot);
28137
        return start.bind(startRange => {
28138
          var _a;
28139
          if (requireGap) {
28140
            if (startRange.endContainer === spot.container && startRange.endOffset === spot.offset) {
28141
              return Optional.none();
28142
            } else if (spot.offset === 0 && ((_a = startRange.endContainer.textContent) === null || _a === void 0 ? void 0 : _a.length) === startRange.endOffset) {
28143
              return Optional.none();
28144
            }
28145
          }
28146
          return Optional.some(startRange);
28147
        });
28148
      });
28149
    };
1441 ariadna 28150
    const findPattern$3 = (editor, block, details, normalizedMatches) => {
1 efrain 28151
      const dom = editor.dom;
28152
      const root = dom.getRoot();
28153
      const pattern = details.pattern;
28154
      const endNode = details.position.container;
28155
      const endOffset = details.position.offset;
28156
      return scanLeft(endNode, endOffset - details.pattern.end.length, block).bind(spot => {
28157
        const endPathRng = generatePathRange(dom, root, spot.container, spot.offset, endNode, endOffset, normalizedMatches);
28158
        if (isReplacementPattern(pattern)) {
28159
          return Optional.some({
28160
            matches: [{
28161
                pattern,
28162
                startRng: endPathRng,
28163
                endRng: endPathRng
28164
              }],
28165
            position: spot
28166
          });
28167
        } else {
28168
          const resultsOpt = findPatternsRec(editor, details.remainingPatterns, spot.container, spot.offset, block, normalizedMatches);
28169
          const results = resultsOpt.getOr({
28170
            matches: [],
28171
            position: spot
28172
          });
28173
          const pos = results.position;
28174
          const start = findPatternStart(dom, pattern, pos.container, pos.offset, block, resultsOpt.isNone());
28175
          return start.map(startRng => {
28176
            const startPathRng = generatePathRangeFromRange(dom, root, startRng, normalizedMatches);
28177
            return {
28178
              matches: results.matches.concat([{
28179
                  pattern,
28180
                  startRng: startPathRng,
28181
                  endRng: endPathRng
28182
                }]),
28183
              position: point(startRng.startContainer, startRng.startOffset)
28184
            };
28185
          });
28186
        }
28187
      });
28188
    };
28189
    const findPatternsRec = (editor, patterns, node, offset, block, normalizedMatches) => {
28190
      const dom = editor.dom;
28191
      return textBefore(node, offset, dom.getRoot()).bind(endSpot => {
28192
        const text = getBeforeText(dom, block, node, offset);
28193
        for (let i = 0; i < patterns.length; i++) {
28194
          const pattern = patterns[i];
28195
          if (!endsWith(text, pattern.end)) {
28196
            continue;
28197
          }
28198
          const patternsWithoutCurrent = patterns.slice();
28199
          patternsWithoutCurrent.splice(i, 1);
1441 ariadna 28200
          const result = findPattern$3(editor, block, {
1 efrain 28201
            pattern,
28202
            remainingPatterns: patternsWithoutCurrent,
28203
            position: endSpot
28204
          }, normalizedMatches);
28205
          if (result.isNone() && offset > 0) {
28206
            return findPatternsRec(editor, patterns, node, offset - 1, block, normalizedMatches);
28207
          }
28208
          if (result.isSome()) {
28209
            return result;
28210
          }
28211
        }
28212
        return Optional.none();
28213
      });
28214
    };
1441 ariadna 28215
    const applyPattern$2 = (editor, pattern, patternRange) => {
1 efrain 28216
      editor.selection.setRng(patternRange);
28217
      if (pattern.type === 'inline-format') {
28218
        each$e(pattern.format, format => {
28219
          editor.formatter.apply(format);
28220
        });
28221
      } else {
28222
        editor.execCommand(pattern.cmd, false, pattern.value);
28223
      }
28224
    };
28225
    const applyReplacementPattern = (editor, pattern, marker, isRoot) => {
28226
      const markerRange = rangeFromMarker(editor.dom, marker);
28227
      deleteRng(editor.dom, markerRange, isRoot);
1441 ariadna 28228
      applyPattern$2(editor, pattern, markerRange);
1 efrain 28229
    };
28230
    const applyPatternWithContent = (editor, pattern, startMarker, endMarker, isRoot) => {
28231
      const dom = editor.dom;
28232
      const markerEndRange = rangeFromMarker(dom, endMarker);
28233
      const markerStartRange = rangeFromMarker(dom, startMarker);
28234
      deleteRng(dom, markerStartRange, isRoot);
28235
      deleteRng(dom, markerEndRange, isRoot);
28236
      const patternMarker = {
28237
        prefix: startMarker.prefix,
28238
        start: startMarker.end,
28239
        end: endMarker.start
28240
      };
28241
      const patternRange = rangeFromMarker(dom, patternMarker);
1441 ariadna 28242
      applyPattern$2(editor, pattern, patternRange);
1 efrain 28243
    };
28244
    const addMarkers = (dom, matches) => {
28245
      const markerPrefix = generate$1('mce_textpattern');
28246
      const matchesWithEnds = foldr(matches, (acc, match) => {
28247
        const endMarker = createMarker(dom, markerPrefix + `_end${ acc.length }`, match.endRng);
28248
        return acc.concat([{
28249
            ...match,
28250
            endMarker
28251
          }]);
28252
      }, []);
28253
      return foldr(matchesWithEnds, (acc, match) => {
28254
        const idx = matchesWithEnds.length - acc.length - 1;
28255
        const startMarker = isReplacementPattern(match.pattern) ? match.endMarker : createMarker(dom, markerPrefix + `_start${ idx }`, match.startRng);
28256
        return acc.concat([{
28257
            ...match,
28258
            startMarker
28259
          }]);
28260
      }, []);
28261
    };
1441 ariadna 28262
    const sortPatterns$1 = patterns => sort(patterns, (a, b) => b.end.length - a.end.length);
1 efrain 28263
    const getBestMatches = (matches, matchesWithSortedPatterns) => {
28264
      const hasSameMatches = forall(matches, match => exists(matchesWithSortedPatterns, sortedMatch => match.pattern.start === sortedMatch.pattern.start && match.pattern.end === sortedMatch.pattern.end));
28265
      if (matches.length === matchesWithSortedPatterns.length) {
28266
        if (hasSameMatches) {
28267
          return matches;
28268
        } else {
28269
          return matchesWithSortedPatterns;
28270
        }
28271
      }
28272
      return matches.length > matchesWithSortedPatterns.length ? matches : matchesWithSortedPatterns;
28273
    };
1441 ariadna 28274
    const findPatterns$2 = (editor, block, node, offset, patternSet, normalizedMatches) => {
1 efrain 28275
      const matches = findPatternsRec(editor, patternSet.inlinePatterns, node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
1441 ariadna 28276
      const matchesWithSortedPatterns = findPatternsRec(editor, sortPatterns$1(patternSet.inlinePatterns), node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
1 efrain 28277
      return getBestMatches(matches, matchesWithSortedPatterns);
28278
    };
1441 ariadna 28279
    const applyMatches$2 = (editor, matches) => {
1 efrain 28280
      if (matches.length === 0) {
28281
        return;
28282
      }
28283
      const dom = editor.dom;
28284
      const bookmark = editor.selection.getBookmark();
28285
      const matchesWithMarkers = addMarkers(dom, matches);
28286
      each$e(matchesWithMarkers, match => {
28287
        const block = dom.getParent(match.startMarker.start, dom.isBlock);
28288
        const isRoot = node => node === block;
28289
        if (isReplacementPattern(match.pattern)) {
28290
          applyReplacementPattern(editor, match.pattern, match.endMarker, isRoot);
28291
        } else {
28292
          applyPatternWithContent(editor, match.pattern, match.startMarker, match.endMarker, isRoot);
28293
        }
28294
        removeMarker(dom, match.endMarker, isRoot);
28295
        removeMarker(dom, match.startMarker, isRoot);
28296
      });
28297
      editor.selection.moveToBookmark(bookmark);
28298
    };
28299
 
1441 ariadna 28300
    const stripPattern$1 = (dom, block, pattern) => {
28301
      return textAfter(block, 0, block).map(spot => {
28302
        const node = spot.container;
28303
        scanRight(node, pattern.start.length, block).each(end => {
28304
          const rng = dom.createRng();
28305
          rng.setStart(node, 0);
28306
          rng.setEnd(end.container, end.offset);
28307
          deleteRng(dom, rng, e => e === block);
28308
        });
28309
        return node;
28310
      });
28311
    };
28312
    const createApplyPattern = stripPattern => (editor, match) => {
28313
      const dom = editor.dom;
28314
      const pattern = match.pattern;
28315
      const rng = resolvePathRange(dom.getRoot(), match.range).getOrDie('Unable to resolve path range');
28316
      const isBlockFormatName = (name, formatter) => {
28317
        const formatSet = formatter.get(name);
28318
        return isArray$1(formatSet) && head(formatSet).exists(format => has$2(format, 'block'));
28319
      };
28320
      getParentBlock(editor, rng).each(block => {
28321
        if (pattern.type === 'block-format') {
28322
          if (isBlockFormatName(pattern.format, editor.formatter)) {
28323
            editor.undoManager.transact(() => {
28324
              stripPattern(editor.dom, block, pattern);
28325
              editor.formatter.apply(pattern.format);
28326
            });
28327
          }
28328
        } else if (pattern.type === 'block-command') {
28329
          editor.undoManager.transact(() => {
28330
            stripPattern(editor.dom, block, pattern);
28331
            editor.execCommand(pattern.cmd, false, pattern.value);
28332
          });
28333
        }
28334
      });
28335
      return true;
28336
    };
28337
    const sortPatterns = patterns => sort(patterns, (a, b) => b.start.length - a.start.length);
28338
    const findPattern$2 = predicate => (patterns, text) => {
28339
      const sortedPatterns = sortPatterns(patterns);
28340
      const nuText = text.replace(nbsp, ' ');
28341
      return find$2(sortedPatterns, pattern => predicate(pattern, text, nuText));
28342
    };
28343
    const createFindPatterns = (findPattern, skipFullMatch) => (editor, block, patternSet, normalizedMatches, text) => {
28344
      var _a;
28345
      if (text === void 0) {
28346
        text = (_a = block.textContent) !== null && _a !== void 0 ? _a : '';
28347
      }
28348
      const dom = editor.dom;
28349
      const forcedRootBlock = getForcedRootBlock(editor);
28350
      if (!dom.is(block, forcedRootBlock)) {
28351
        return [];
28352
      }
28353
      return findPattern(patternSet.blockPatterns, text).map(pattern => {
28354
        if (skipFullMatch && Tools.trim(text).length === pattern.start.length) {
28355
          return [];
28356
        }
28357
        return [{
28358
            pattern,
28359
            range: generatePathRange(dom, dom.getRoot(), block, 0, block, 0, normalizedMatches)
28360
          }];
28361
      }).getOr([]);
28362
    };
28363
 
28364
    const startsWithSingleSpace = s => /^\s[^\s]/.test(s);
28365
    const stripPattern = (dom, block, pattern) => {
28366
      stripPattern$1(dom, block, pattern).each(node => {
28367
        const text = SugarElement.fromDom(node);
28368
        const textContent = get$3(text);
28369
        if (startsWithSingleSpace(textContent)) {
28370
          set(text, textContent.slice(1));
28371
        }
28372
      });
28373
    };
28374
    const applyPattern$1 = createApplyPattern(stripPattern);
28375
    const findPattern$1 = findPattern$2((pattern, text, nuText) => text.indexOf(pattern.start) === 0 || nuText.indexOf(pattern.start) === 0);
28376
    const findPatterns$1 = createFindPatterns(findPattern$1, true);
28377
    const getMatches$1 = (editor, patternSet) => {
1 efrain 28378
      const rng = editor.selection.getRng();
28379
      return getParentBlock(editor, rng).map(block => {
28380
        var _a;
28381
        const offset = Math.max(0, rng.startOffset);
28382
        const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, (_a = block.textContent) !== null && _a !== void 0 ? _a : '');
1441 ariadna 28383
        const inlineMatches = findPatterns$2(editor, block, rng.startContainer, offset, dynamicPatternSet, true);
1 efrain 28384
        const blockMatches = findPatterns$1(editor, block, dynamicPatternSet, true);
1441 ariadna 28385
        return {
28386
          inlineMatches,
28387
          blockMatches
28388
        };
28389
      }).filter(({inlineMatches, blockMatches}) => blockMatches.length > 0 || inlineMatches.length > 0);
1 efrain 28390
    };
1441 ariadna 28391
    const applyMatches$1 = (editor, matches) => {
28392
      if (matches.length === 0) {
28393
        return;
28394
      }
28395
      const bookmark = editor.selection.getBookmark();
28396
      each$e(matches, match => applyPattern$1(editor, match));
28397
      editor.selection.moveToBookmark(bookmark);
28398
    };
28399
 
28400
    const applyPattern = createApplyPattern(stripPattern$1);
28401
    const findPattern = findPattern$2((pattern, text, nuText) => text === pattern.start || nuText === pattern.start);
28402
    const findPatterns = createFindPatterns(findPattern, false);
28403
    const getMatches = (editor, patternSet) => {
28404
      const rng = editor.selection.getRng();
28405
      return getParentBlock(editor, rng).map(block => {
28406
        const offset = Math.max(0, rng.startOffset);
28407
        const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset);
28408
        const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText);
28409
        return findPatterns(editor, block, dynamicPatternSet, false, beforeText);
28410
      }).filter(matches => matches.length > 0);
28411
    };
28412
    const applyMatches = (editor, matches) => {
28413
      each$e(matches, match => applyPattern(editor, match));
28414
    };
28415
 
28416
    const handleEnter = (editor, patternSet) => getMatches$1(editor, patternSet).fold(never, ({inlineMatches, blockMatches}) => {
28417
      editor.undoManager.add();
28418
      editor.undoManager.extra(() => {
28419
        editor.execCommand('mceInsertNewLine');
28420
      }, () => {
28421
        insert$5(editor);
28422
        applyMatches$2(editor, inlineMatches);
28423
        applyMatches$1(editor, blockMatches);
28424
        const range = editor.selection.getRng();
28425
        const spot = textBefore(range.startContainer, range.startOffset, editor.dom.getRoot());
28426
        editor.execCommand('mceInsertNewLine');
28427
        spot.each(s => {
28428
          const node = s.container;
28429
          if (node.data.charAt(s.offset - 1) === zeroWidth) {
28430
            node.deleteData(s.offset - 1, 1);
28431
            cleanEmptyNodes(editor.dom, node.parentNode, e => e === editor.dom.getRoot());
28432
          }
28433
        });
28434
      });
28435
      return true;
28436
    });
1 efrain 28437
    const handleInlineKey = (editor, patternSet) => {
28438
      const rng = editor.selection.getRng();
28439
      getParentBlock(editor, rng).map(block => {
28440
        const offset = Math.max(0, rng.startOffset - 1);
28441
        const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset);
28442
        const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText);
1441 ariadna 28443
        const inlineMatches = findPatterns$2(editor, block, rng.startContainer, offset, dynamicPatternSet, false);
1 efrain 28444
        if (inlineMatches.length > 0) {
28445
          editor.undoManager.transact(() => {
1441 ariadna 28446
            applyMatches$2(editor, inlineMatches);
1 efrain 28447
          });
28448
        }
28449
      });
28450
    };
1441 ariadna 28451
    const handleBlockPatternOnSpace = (editor, patternSet) => getMatches(editor, patternSet).fold(never, matches => {
28452
      editor.undoManager.transact(() => {
28453
        applyMatches(editor, matches);
28454
      });
28455
      return true;
28456
    });
1 efrain 28457
    const checkKeyEvent = (codes, event, predicate) => {
28458
      for (let i = 0; i < codes.length; i++) {
28459
        if (predicate(codes[i], event)) {
28460
          return true;
28461
        }
28462
      }
28463
      return false;
28464
    };
28465
    const checkKeyCode = (codes, event) => checkKeyEvent(codes, event, (code, event) => {
28466
      return code === event.keyCode && !VK.modifierPressed(event);
28467
    });
28468
    const checkCharCode = (chars, event) => checkKeyEvent(chars, event, (chr, event) => {
28469
      return chr.charCodeAt(0) === event.charCode;
28470
    });
28471
 
28472
    const setup$2 = editor => {
28473
      const charCodes = [
28474
        ',',
28475
        '.',
28476
        ';',
28477
        ':',
28478
        '!',
28479
        '?'
28480
      ];
28481
      const keyCodes = [32];
1441 ariadna 28482
      const getPatternSet = () => createPatternSet(getTextPatterns(editor).filter(pattern => {
28483
        if (pattern.type === 'inline-command' || pattern.type === 'block-command') {
28484
          return editor.queryCommandSupported(pattern.cmd);
28485
        }
28486
        return true;
28487
      }), getTextPatternsLookup(editor));
1 efrain 28488
      const hasDynamicPatterns = () => hasTextPatternsLookup(editor);
28489
      editor.on('keydown', e => {
1441 ariadna 28490
        if (e.keyCode === 13 && !VK.modifierPressed(e) && editor.selection.isCollapsed() && editor.selection.isEditable()) {
28491
          const patternSet = filterByTrigger(getPatternSet(), 'enter');
1 efrain 28492
          const hasPatterns = patternSet.inlinePatterns.length > 0 || patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
28493
          if (hasPatterns && handleEnter(editor, patternSet)) {
28494
            e.preventDefault();
28495
          }
28496
        }
28497
      }, true);
1441 ariadna 28498
      editor.on('keydown', e => {
28499
        if (e.keyCode === 32 && editor.selection.isCollapsed() && editor.selection.isEditable()) {
28500
          const patternSet = filterByTrigger(getPatternSet(), 'space');
28501
          const hasPatterns = patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
28502
          if (hasPatterns && handleBlockPatternOnSpace(editor, patternSet)) {
28503
            e.preventDefault();
28504
          }
28505
        }
28506
      }, true);
1 efrain 28507
      const handleInlineTrigger = () => {
1441 ariadna 28508
        if (editor.selection.isCollapsed() && editor.selection.isEditable()) {
28509
          const patternSet = filterByTrigger(getPatternSet(), 'space');
1 efrain 28510
          const hasPatterns = patternSet.inlinePatterns.length > 0 || hasDynamicPatterns();
28511
          if (hasPatterns) {
28512
            handleInlineKey(editor, patternSet);
28513
          }
28514
        }
28515
      };
28516
      editor.on('keyup', e => {
28517
        if (checkKeyCode(keyCodes, e)) {
28518
          handleInlineTrigger();
28519
        }
28520
      });
28521
      editor.on('keypress', e => {
28522
        if (checkCharCode(charCodes, e)) {
28523
          Delay.setEditorTimeout(editor, handleInlineTrigger);
28524
        }
28525
      });
28526
    };
28527
 
28528
    const setup$1 = editor => {
28529
      setup$2(editor);
28530
    };
28531
 
28532
    const Quirks = editor => {
28533
      const each = Tools.each;
28534
      const BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, parser = editor.parser;
28535
      const browser = Env.browser;
28536
      const isGecko = browser.isFirefox();
28537
      const isWebKit = browser.isChromium() || browser.isSafari();
28538
      const isiOS = Env.deviceType.isiPhone() || Env.deviceType.isiPad();
28539
      const isMac = Env.os.isMacOS() || Env.os.isiOS();
28540
      const setEditorCommandState = (cmd, state) => {
28541
        try {
28542
          editor.getDoc().execCommand(cmd, false, String(state));
1441 ariadna 28543
        } catch (_a) {
1 efrain 28544
        }
28545
      };
28546
      const isDefaultPrevented = e => {
28547
        return e.isDefaultPrevented();
28548
      };
28549
      const emptyEditorWhenDeleting = () => {
28550
        const serializeRng = rng => {
28551
          const body = dom.create('body');
28552
          const contents = rng.cloneContents();
28553
          body.appendChild(contents);
28554
          return selection.serializer.serialize(body, { format: 'html' });
28555
        };
28556
        const allContentsSelected = rng => {
28557
          const selection = serializeRng(rng);
28558
          const allRng = dom.createRng();
28559
          allRng.selectNode(editor.getBody());
28560
          const allSelection = serializeRng(allRng);
28561
          return selection === allSelection;
28562
        };
28563
        editor.on('keydown', e => {
28564
          const keyCode = e.keyCode;
28565
          if (!isDefaultPrevented(e) && (keyCode === DELETE || keyCode === BACKSPACE) && editor.selection.isEditable()) {
28566
            const isCollapsed = editor.selection.isCollapsed();
28567
            const body = editor.getBody();
1441 ariadna 28568
            if (isCollapsed && !isEmptyNode(editor.schema, body)) {
1 efrain 28569
              return;
28570
            }
28571
            if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) {
28572
              return;
28573
            }
28574
            e.preventDefault();
28575
            editor.setContent('');
28576
            if (body.firstChild && dom.isBlock(body.firstChild)) {
28577
              editor.selection.setCursorLocation(body.firstChild, 0);
28578
            } else {
28579
              editor.selection.setCursorLocation(body, 0);
28580
            }
28581
            editor.nodeChanged();
28582
          }
28583
        });
28584
      };
28585
      const selectAll = () => {
28586
        editor.shortcuts.add('meta+a', null, 'SelectAll');
28587
      };
28588
      const documentElementEditingFocus = () => {
28589
        if (!editor.inline) {
28590
          dom.bind(editor.getDoc(), 'mousedown mouseup', e => {
28591
            let rng;
28592
            if (e.target === editor.getDoc().documentElement) {
28593
              rng = selection.getRng();
28594
              editor.getBody().focus();
28595
              if (e.type === 'mousedown') {
28596
                if (isCaretContainer$2(rng.startContainer)) {
28597
                  return;
28598
                }
28599
                selection.placeCaretAt(e.clientX, e.clientY);
28600
              } else {
28601
                selection.setRng(rng);
28602
              }
28603
            }
28604
          });
28605
        }
28606
      };
28607
      const removeHrOnBackspace = () => {
28608
        editor.on('keydown', e => {
28609
          if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
28610
            if (!editor.getBody().getElementsByTagName('hr').length) {
28611
              return;
28612
            }
28613
            if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
28614
              const node = selection.getNode();
28615
              const previousSibling = node.previousSibling;
28616
              if (node.nodeName === 'HR') {
28617
                dom.remove(node);
28618
                e.preventDefault();
28619
                return;
28620
              }
28621
              if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'hr') {
28622
                dom.remove(previousSibling);
28623
                e.preventDefault();
28624
              }
28625
            }
28626
          }
28627
        });
28628
      };
28629
      const focusBody = () => {
28630
        if (!Range.prototype.getClientRects) {
28631
          editor.on('mousedown', e => {
28632
            if (!isDefaultPrevented(e) && e.target.nodeName === 'HTML') {
28633
              const body = editor.getBody();
28634
              body.blur();
28635
              Delay.setEditorTimeout(editor, () => {
28636
                body.focus();
28637
              });
28638
            }
28639
          });
28640
        }
28641
      };
28642
      const selectControlElements = () => {
28643
        const visualAidsAnchorClass = getVisualAidsAnchorClass(editor);
28644
        editor.on('click', e => {
28645
          const target = e.target;
28646
          if (/^(IMG|HR)$/.test(target.nodeName) && dom.isEditable(target)) {
28647
            e.preventDefault();
28648
            editor.selection.select(target);
28649
            editor.nodeChanged();
28650
          }
28651
          if (target.nodeName === 'A' && dom.hasClass(target, visualAidsAnchorClass) && target.childNodes.length === 0 && dom.isEditable(target.parentNode)) {
28652
            e.preventDefault();
28653
            selection.select(target);
28654
          }
28655
        });
28656
      };
28657
      const removeStylesWhenDeletingAcrossBlockElements = () => {
28658
        const getAttributeApplyFunction = () => {
28659
          const template = dom.getAttribs(selection.getStart().cloneNode(false));
28660
          return () => {
28661
            const target = selection.getStart();
28662
            if (target !== editor.getBody()) {
28663
              dom.setAttrib(target, 'style', null);
28664
              each(template, attr => {
28665
                target.setAttributeNode(attr.cloneNode(true));
28666
              });
28667
            }
28668
          };
28669
        };
28670
        const isSelectionAcrossElements = () => {
28671
          return !selection.isCollapsed() && dom.getParent(selection.getStart(), dom.isBlock) !== dom.getParent(selection.getEnd(), dom.isBlock);
28672
        };
28673
        editor.on('keypress', e => {
28674
          let applyAttributes;
28675
          if (!isDefaultPrevented(e) && (e.keyCode === 8 || e.keyCode === 46) && isSelectionAcrossElements()) {
28676
            applyAttributes = getAttributeApplyFunction();
28677
            editor.getDoc().execCommand('delete', false);
28678
            applyAttributes();
28679
            e.preventDefault();
28680
            return false;
28681
          } else {
28682
            return true;
28683
          }
28684
        });
28685
        dom.bind(editor.getDoc(), 'cut', e => {
28686
          if (!isDefaultPrevented(e) && isSelectionAcrossElements()) {
28687
            const applyAttributes = getAttributeApplyFunction();
28688
            Delay.setEditorTimeout(editor, () => {
28689
              applyAttributes();
28690
            });
28691
          }
28692
        });
28693
      };
28694
      const disableBackspaceIntoATable = () => {
28695
        editor.on('keydown', e => {
28696
          if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
28697
            if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
28698
              const previousSibling = selection.getNode().previousSibling;
28699
              if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'table') {
28700
                e.preventDefault();
28701
                return false;
28702
              }
28703
            }
28704
          }
28705
          return true;
28706
        });
28707
      };
28708
      const removeBlockQuoteOnBackSpace = () => {
28709
        editor.on('keydown', e => {
28710
          if (isDefaultPrevented(e) || e.keyCode !== VK.BACKSPACE) {
28711
            return;
28712
          }
28713
          let rng = selection.getRng();
28714
          const container = rng.startContainer;
28715
          const offset = rng.startOffset;
28716
          const root = dom.getRoot();
28717
          let parent = container;
28718
          if (!rng.collapsed || offset !== 0) {
28719
            return;
28720
          }
28721
          while (parent.parentNode && parent.parentNode.firstChild === parent && parent.parentNode !== root) {
28722
            parent = parent.parentNode;
28723
          }
28724
          if (parent.nodeName === 'BLOCKQUOTE') {
28725
            editor.formatter.toggle('blockquote', undefined, parent);
28726
            rng = dom.createRng();
28727
            rng.setStart(container, 0);
28728
            rng.setEnd(container, 0);
28729
            selection.setRng(rng);
28730
          }
28731
        });
28732
      };
28733
      const setGeckoEditingOptions = () => {
28734
        const setOpts = () => {
28735
          setEditorCommandState('StyleWithCSS', false);
28736
          setEditorCommandState('enableInlineTableEditing', false);
28737
          if (!getObjectResizing(editor)) {
28738
            setEditorCommandState('enableObjectResizing', false);
28739
          }
28740
        };
28741
        if (!isReadOnly$1(editor)) {
28742
          editor.on('BeforeExecCommand mousedown', setOpts);
28743
        }
28744
      };
28745
      const addBrAfterLastLinks = () => {
28746
        const fixLinks = () => {
28747
          each(dom.select('a:not([data-mce-block])'), node => {
28748
            var _a;
28749
            let parentNode = node.parentNode;
28750
            const root = dom.getRoot();
28751
            if ((parentNode === null || parentNode === void 0 ? void 0 : parentNode.lastChild) === node) {
28752
              while (parentNode && !dom.isBlock(parentNode)) {
28753
                if (((_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.lastChild) !== parentNode || parentNode === root) {
28754
                  return;
28755
                }
28756
                parentNode = parentNode.parentNode;
28757
              }
28758
              dom.add(parentNode, 'br', { 'data-mce-bogus': 1 });
28759
            }
28760
          });
28761
        };
28762
        editor.on('SetContent ExecCommand', e => {
28763
          if (e.type === 'setcontent' || e.command === 'mceInsertLink') {
28764
            fixLinks();
28765
          }
28766
        });
28767
      };
28768
      const setDefaultBlockType = () => {
28769
        editor.on('init', () => {
28770
          setEditorCommandState('DefaultParagraphSeparator', getForcedRootBlock(editor));
28771
        });
28772
      };
28773
      const isAllContentSelected = editor => {
28774
        const body = editor.getBody();
28775
        const rng = editor.selection.getRng();
28776
        return rng.startContainer === rng.endContainer && rng.startContainer === body && rng.startOffset === 0 && rng.endOffset === body.childNodes.length;
28777
      };
28778
      const normalizeSelection = () => {
28779
        editor.on('keyup focusin mouseup', e => {
28780
          if (!VK.modifierPressed(e) && !isAllContentSelected(editor)) {
28781
            selection.normalize();
28782
          }
28783
        }, true);
28784
      };
28785
      const showBrokenImageIcon = () => {
28786
        editor.contentStyles.push('img:-moz-broken {' + '-moz-force-broken-image-icon:1;' + 'min-width:24px;' + 'min-height:24px' + '}');
28787
      };
28788
      const restoreFocusOnKeyDown = () => {
28789
        if (!editor.inline) {
28790
          editor.on('keydown', () => {
28791
            if (document.activeElement === document.body) {
28792
              editor.getWin().focus();
28793
            }
28794
          });
28795
        }
28796
      };
28797
      const bodyHeight = () => {
28798
        if (!editor.inline) {
28799
          editor.contentStyles.push('body {min-height: 150px}');
28800
          editor.on('click', e => {
28801
            let rng;
28802
            if (e.target.nodeName === 'HTML') {
28803
              rng = editor.selection.getRng();
28804
              editor.getBody().focus();
28805
              editor.selection.setRng(rng);
28806
              editor.selection.normalize();
28807
              editor.nodeChanged();
28808
            }
28809
          });
28810
        }
28811
      };
28812
      const blockCmdArrowNavigation = () => {
28813
        if (isMac) {
28814
          editor.on('keydown', e => {
28815
            if (VK.metaKeyPressed(e) && !e.shiftKey && (e.keyCode === 37 || e.keyCode === 39)) {
28816
              e.preventDefault();
28817
              const selection = editor.selection.getSel();
28818
              selection.modify('move', e.keyCode === 37 ? 'backward' : 'forward', 'lineboundary');
28819
            }
28820
          });
28821
        }
28822
      };
28823
      const tapLinksAndImages = () => {
28824
        editor.on('click', e => {
28825
          let elm = e.target;
28826
          do {
28827
            if (elm.tagName === 'A') {
28828
              e.preventDefault();
28829
              return;
28830
            }
28831
          } while (elm = elm.parentNode);
28832
        });
28833
        editor.contentStyles.push('.mce-content-body {-webkit-touch-callout: none}');
28834
      };
28835
      const blockFormSubmitInsideEditor = () => {
28836
        editor.on('init', () => {
28837
          editor.dom.bind(editor.getBody(), 'submit', e => {
28838
            e.preventDefault();
28839
          });
28840
        });
28841
      };
28842
      const removeAppleInterchangeBrs = () => {
28843
        parser.addNodeFilter('br', nodes => {
28844
          let i = nodes.length;
28845
          while (i--) {
28846
            if (nodes[i].attr('class') === 'Apple-interchange-newline') {
28847
              nodes[i].remove();
28848
            }
28849
          }
28850
        });
28851
      };
28852
      const refreshContentEditable = noop;
28853
      const isHidden = () => {
28854
        if (!isGecko || editor.removed) {
28855
          return false;
28856
        }
28857
        const sel = editor.selection.getSel();
28858
        return !sel || !sel.rangeCount || sel.rangeCount === 0;
28859
      };
28860
      const setupRtc = () => {
28861
        if (isWebKit) {
28862
          documentElementEditingFocus();
28863
          selectControlElements();
28864
          blockFormSubmitInsideEditor();
28865
          selectAll();
28866
          if (isiOS) {
28867
            restoreFocusOnKeyDown();
28868
            bodyHeight();
28869
            tapLinksAndImages();
28870
          }
28871
        }
28872
        if (isGecko) {
28873
          focusBody();
28874
          setGeckoEditingOptions();
28875
          showBrokenImageIcon();
28876
          blockCmdArrowNavigation();
28877
        }
28878
      };
28879
      const setup = () => {
28880
        removeBlockQuoteOnBackSpace();
28881
        emptyEditorWhenDeleting();
28882
        if (!Env.windowsPhone) {
28883
          normalizeSelection();
28884
        }
28885
        if (isWebKit) {
28886
          documentElementEditingFocus();
28887
          selectControlElements();
28888
          setDefaultBlockType();
28889
          blockFormSubmitInsideEditor();
28890
          disableBackspaceIntoATable();
28891
          removeAppleInterchangeBrs();
28892
          if (isiOS) {
28893
            restoreFocusOnKeyDown();
28894
            bodyHeight();
28895
            tapLinksAndImages();
28896
          } else {
28897
            selectAll();
28898
          }
28899
        }
28900
        if (isGecko) {
28901
          removeHrOnBackspace();
28902
          focusBody();
28903
          removeStylesWhenDeletingAcrossBlockElements();
28904
          setGeckoEditingOptions();
28905
          addBrAfterLastLinks();
28906
          showBrokenImageIcon();
28907
          blockCmdArrowNavigation();
28908
          disableBackspaceIntoATable();
28909
        }
28910
      };
28911
      if (isRtc(editor)) {
28912
        setupRtc();
28913
      } else {
28914
        setup();
28915
      }
28916
      return {
28917
        refreshContentEditable,
28918
        isHidden
28919
      };
28920
    };
28921
 
1441 ariadna 28922
    const isGplKey = key => key.toLowerCase() === 'gpl';
28923
    const isValidGeneratedKey = key => key.length >= 64 && key.length <= 255;
28924
    const validateLicenseKey = key => isGplKey(key) || isValidGeneratedKey(key) ? 'VALID' : 'INVALID';
28925
    const validateEditorLicenseKey = editor => {
28926
      const licenseKey = getLicenseKey(editor);
28927
      const hasApiKey = isString(getApiKey(editor));
28928
      if (!hasApiKey && (isUndefined(licenseKey) || validateLicenseKey(licenseKey) === 'INVALID')) {
28929
        console.warn(`TinyMCE is running in evaluation mode. Provide a valid license key or add license_key: 'gpl' to the init config to agree to the open source license terms. Read more at https://www.tiny.cloud/license-key/`);
28930
      }
28931
    };
28932
 
1 efrain 28933
    const DOM$6 = DOMUtils.DOM;
28934
    const appendStyle = (editor, text) => {
28935
      const body = SugarElement.fromDom(editor.getBody());
28936
      const container = getStyleContainer(getRootNode(body));
28937
      const style = SugarElement.fromTag('style');
1441 ariadna 28938
      set$4(style, 'type', 'text/css');
1 efrain 28939
      append$1(style, SugarElement.fromText(text));
28940
      append$1(container, style);
28941
      editor.on('remove', () => {
1441 ariadna 28942
        remove$4(style);
1 efrain 28943
      });
28944
    };
28945
    const getRootName = editor => editor.inline ? editor.getElement().nodeName.toLowerCase() : undefined;
28946
    const removeUndefined = obj => filter$4(obj, v => isUndefined(v) === false);
28947
    const mkParserSettings = editor => {
28948
      const getOption = editor.options.get;
28949
      const blobCache = editor.editorUpload.blobCache;
28950
      return removeUndefined({
28951
        allow_conditional_comments: getOption('allow_conditional_comments'),
28952
        allow_html_data_urls: getOption('allow_html_data_urls'),
28953
        allow_svg_data_urls: getOption('allow_svg_data_urls'),
28954
        allow_html_in_named_anchor: getOption('allow_html_in_named_anchor'),
28955
        allow_script_urls: getOption('allow_script_urls'),
1441 ariadna 28956
        allow_mathml_annotation_encodings: getOption('allow_mathml_annotation_encodings'),
1 efrain 28957
        allow_unsafe_link_target: getOption('allow_unsafe_link_target'),
28958
        convert_unsafe_embeds: getOption('convert_unsafe_embeds'),
28959
        convert_fonts_to_spans: getOption('convert_fonts_to_spans'),
28960
        fix_list_elements: getOption('fix_list_elements'),
28961
        font_size_legacy_values: getOption('font_size_legacy_values'),
28962
        forced_root_block: getOption('forced_root_block'),
28963
        forced_root_block_attrs: getOption('forced_root_block_attrs'),
28964
        preserve_cdata: getOption('preserve_cdata'),
28965
        inline_styles: getOption('inline_styles'),
28966
        root_name: getRootName(editor),
28967
        sandbox_iframes: getOption('sandbox_iframes'),
1441 ariadna 28968
        sandbox_iframes_exclusions: getSandboxIframesExclusions(editor),
1 efrain 28969
        sanitize: getOption('xss_sanitization'),
28970
        validate: true,
28971
        blob_cache: blobCache,
28972
        document: editor.getDoc()
28973
      });
28974
    };
28975
    const mkSchemaSettings = editor => {
28976
      const getOption = editor.options.get;
28977
      return removeUndefined({
28978
        custom_elements: getOption('custom_elements'),
28979
        extended_valid_elements: getOption('extended_valid_elements'),
28980
        invalid_elements: getOption('invalid_elements'),
28981
        invalid_styles: getOption('invalid_styles'),
28982
        schema: getOption('schema'),
28983
        valid_children: getOption('valid_children'),
28984
        valid_classes: getOption('valid_classes'),
28985
        valid_elements: getOption('valid_elements'),
28986
        valid_styles: getOption('valid_styles'),
28987
        verify_html: getOption('verify_html'),
28988
        padd_empty_block_inline_children: getOption('format_empty_lines')
28989
      });
28990
    };
28991
    const mkSerializerSettings = editor => {
28992
      const getOption = editor.options.get;
28993
      return {
28994
        ...mkParserSettings(editor),
28995
        ...mkSchemaSettings(editor),
28996
        ...removeUndefined({
28997
          remove_trailing_brs: getOption('remove_trailing_brs'),
28998
          pad_empty_with_br: getOption('pad_empty_with_br'),
28999
          url_converter: getOption('url_converter'),
29000
          url_converter_scope: getOption('url_converter_scope'),
29001
          element_format: getOption('element_format'),
29002
          entities: getOption('entities'),
29003
          entity_encoding: getOption('entity_encoding'),
29004
          indent: getOption('indent'),
29005
          indent_after: getOption('indent_after'),
29006
          indent_before: getOption('indent_before')
29007
        })
29008
      };
29009
    };
29010
    const createParser = editor => {
29011
      const parser = DomParser(mkParserSettings(editor), editor.schema);
29012
      parser.addAttributeFilter('src,href,style,tabindex', (nodes, name) => {
29013
        const dom = editor.dom;
29014
        const internalName = 'data-mce-' + name;
29015
        let i = nodes.length;
29016
        while (i--) {
29017
          const node = nodes[i];
29018
          let value = node.attr(name);
29019
          if (value && !node.attr(internalName)) {
29020
            if (value.indexOf('data:') === 0 || value.indexOf('blob:') === 0) {
29021
              continue;
29022
            }
29023
            if (name === 'style') {
29024
              value = dom.serializeStyle(dom.parseStyle(value), node.name);
29025
              if (!value.length) {
29026
                value = null;
29027
              }
29028
              node.attr(internalName, value);
29029
              node.attr(name, value);
29030
            } else if (name === 'tabindex') {
29031
              node.attr(internalName, value);
29032
              node.attr(name, null);
29033
            } else {
29034
              node.attr(internalName, editor.convertURL(value, name, node.name));
29035
            }
29036
          }
29037
        }
29038
      });
29039
      parser.addNodeFilter('script', nodes => {
29040
        let i = nodes.length;
29041
        while (i--) {
29042
          const node = nodes[i];
29043
          const type = node.attr('type') || 'no/type';
29044
          if (type.indexOf('mce-') !== 0) {
29045
            node.attr('type', 'mce-' + type);
29046
          }
29047
        }
29048
      });
29049
      if (shouldPreserveCData(editor)) {
29050
        parser.addNodeFilter('#cdata', nodes => {
29051
          var _a;
29052
          let i = nodes.length;
29053
          while (i--) {
29054
            const node = nodes[i];
29055
            node.type = 8;
29056
            node.name = '#comment';
29057
            node.value = '[CDATA[' + editor.dom.encode((_a = node.value) !== null && _a !== void 0 ? _a : '') + ']]';
29058
          }
29059
        });
29060
      }
29061
      parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', nodes => {
29062
        let i = nodes.length;
29063
        const nonEmptyElements = editor.schema.getNonEmptyElements();
29064
        while (i--) {
29065
          const node = nodes[i];
29066
          if (node.isEmpty(nonEmptyElements) && node.getAll('br').length === 0) {
29067
            node.append(new AstNode('br', 1));
29068
          }
29069
        }
29070
      });
29071
      return parser;
29072
    };
29073
    const autoFocus = editor => {
29074
      const autoFocus = getAutoFocus(editor);
29075
      if (autoFocus) {
29076
        Delay.setEditorTimeout(editor, () => {
29077
          let focusEditor;
29078
          if (autoFocus === true) {
29079
            focusEditor = editor;
29080
          } else {
29081
            focusEditor = editor.editorManager.get(autoFocus);
29082
          }
29083
          if (focusEditor && !focusEditor.destroyed) {
29084
            focusEditor.focus();
29085
            focusEditor.selection.scrollIntoView();
29086
          }
29087
        }, 100);
29088
      }
29089
    };
29090
    const moveSelectionToFirstCaretPosition = editor => {
29091
      const root = editor.dom.getRoot();
29092
      if (!editor.inline && (!hasAnyRanges(editor) || editor.selection.getStart(true) === root)) {
29093
        firstPositionIn(root).each(pos => {
29094
          const node = pos.getNode();
29095
          const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
29096
          editor.selection.setRng(caretPos.toRange());
29097
        });
29098
      }
29099
    };
29100
    const initEditor = editor => {
29101
      editor.bindPendingEventDelegates();
29102
      editor.initialized = true;
29103
      fireInit(editor);
29104
      editor.focus(true);
29105
      moveSelectionToFirstCaretPosition(editor);
29106
      editor.nodeChanged({ initial: true });
29107
      const initInstanceCallback = getInitInstanceCallback(editor);
29108
      if (isFunction(initInstanceCallback)) {
29109
        initInstanceCallback.call(editor, editor);
29110
      }
29111
      autoFocus(editor);
1441 ariadna 29112
      if (isDisabled(editor)) {
29113
        toggleDisabled(editor, true);
29114
      }
1 efrain 29115
    };
29116
    const getStyleSheetLoader$1 = editor => editor.inline ? editor.ui.styleSheetLoader : editor.dom.styleSheetLoader;
29117
    const makeStylesheetLoadingPromises = (editor, css, framedFonts) => {
29118
      const {
29119
        pass: bundledCss,
29120
        fail: normalCss
29121
      } = partition$2(css, name => tinymce.Resource.has(toContentSkinResourceName(name)));
29122
      const bundledPromises = bundledCss.map(url => {
29123
        const css = tinymce.Resource.get(toContentSkinResourceName(url));
29124
        if (isString(css)) {
29125
          return Promise.resolve(getStyleSheetLoader$1(editor).loadRawCss(url, css));
29126
        }
29127
        return Promise.resolve();
29128
      });
29129
      const promises = [
29130
        ...bundledPromises,
29131
        getStyleSheetLoader$1(editor).loadAll(normalCss)
29132
      ];
29133
      if (editor.inline) {
29134
        return promises;
29135
      } else {
29136
        return promises.concat([editor.ui.styleSheetLoader.loadAll(framedFonts)]);
29137
      }
29138
    };
29139
    const loadContentCss = editor => {
29140
      const styleSheetLoader = getStyleSheetLoader$1(editor);
29141
      const fontCss = getFontCss(editor);
29142
      const css = editor.contentCSS;
29143
      const removeCss = () => {
29144
        styleSheetLoader.unloadAll(css);
29145
        if (!editor.inline) {
29146
          editor.ui.styleSheetLoader.unloadAll(fontCss);
29147
        }
29148
      };
29149
      const loaded = () => {
29150
        if (editor.removed) {
29151
          removeCss();
29152
        } else {
29153
          editor.on('remove', removeCss);
29154
        }
29155
      };
29156
      if (editor.contentStyles.length > 0) {
29157
        let contentCssText = '';
29158
        Tools.each(editor.contentStyles, style => {
29159
          contentCssText += style + '\r\n';
29160
        });
29161
        editor.dom.addStyle(contentCssText);
29162
      }
29163
      const allStylesheets = Promise.all(makeStylesheetLoadingPromises(editor, css, fontCss)).then(loaded).catch(loaded);
29164
      const contentStyle = getContentStyle(editor);
29165
      if (contentStyle) {
29166
        appendStyle(editor, contentStyle);
29167
      }
29168
      return allStylesheets;
29169
    };
29170
    const preInit = editor => {
29171
      const doc = editor.getDoc(), body = editor.getBody();
29172
      firePreInit(editor);
29173
      if (!shouldBrowserSpellcheck(editor)) {
29174
        doc.body.spellcheck = false;
29175
        DOM$6.setAttrib(body, 'spellcheck', 'false');
29176
      }
29177
      editor.quirks = Quirks(editor);
29178
      firePostRender(editor);
29179
      const directionality = getDirectionality(editor);
29180
      if (directionality !== undefined) {
29181
        body.dir = directionality;
29182
      }
29183
      const protect = getProtect(editor);
29184
      if (protect) {
29185
        editor.on('BeforeSetContent', e => {
29186
          Tools.each(protect, pattern => {
29187
            e.content = e.content.replace(pattern, str => {
29188
              return '<!--mce:protected ' + escape(str) + '-->';
29189
            });
29190
          });
29191
        });
29192
      }
29193
      editor.on('SetContent', () => {
29194
        editor.addVisual(editor.getBody());
29195
      });
29196
      editor.on('compositionstart compositionend', e => {
29197
        editor.composing = e.type === 'compositionstart';
29198
      });
29199
    };
29200
    const loadInitialContent = editor => {
29201
      if (!isRtc(editor)) {
29202
        editor.load({
29203
          initial: true,
29204
          format: 'html'
29205
        });
29206
      }
29207
      editor.startContent = editor.getContent({ format: 'raw' });
29208
    };
29209
    const initEditorWithInitialContent = editor => {
29210
      if (editor.removed !== true) {
29211
        loadInitialContent(editor);
29212
        initEditor(editor);
29213
      }
29214
    };
29215
    const startProgress = editor => {
29216
      let canceled = false;
29217
      const progressTimeout = setTimeout(() => {
29218
        if (!canceled) {
29219
          editor.setProgressState(true);
29220
        }
29221
      }, 500);
29222
      return () => {
29223
        clearTimeout(progressTimeout);
29224
        canceled = true;
29225
        editor.setProgressState(false);
29226
      };
29227
    };
29228
    const contentBodyLoaded = editor => {
29229
      const targetElm = editor.getElement();
29230
      let doc = editor.getDoc();
29231
      if (editor.inline) {
29232
        DOM$6.addClass(targetElm, 'mce-content-body');
29233
        editor.contentDocument = doc = document;
29234
        editor.contentWindow = window;
29235
        editor.bodyElement = targetElm;
29236
        editor.contentAreaContainer = targetElm;
29237
      }
29238
      const body = editor.getBody();
29239
      body.disabled = true;
29240
      editor.readonly = isReadOnly$1(editor);
29241
      editor._editableRoot = hasEditableRoot$1(editor);
1441 ariadna 29242
      if (!isDisabled$1(editor) && editor.hasEditableRoot()) {
1 efrain 29243
        if (editor.inline && DOM$6.getStyle(body, 'position', true) === 'static') {
29244
          body.style.position = 'relative';
29245
        }
29246
        body.contentEditable = 'true';
29247
      }
29248
      body.disabled = false;
29249
      editor.editorUpload = EditorUpload(editor);
29250
      editor.schema = Schema(mkSchemaSettings(editor));
29251
      editor.dom = DOMUtils(doc, {
29252
        keep_values: true,
29253
        url_converter: editor.convertURL,
29254
        url_converter_scope: editor,
29255
        update_styles: true,
29256
        root_element: editor.inline ? editor.getBody() : null,
29257
        collect: editor.inline,
29258
        schema: editor.schema,
29259
        contentCssCors: shouldUseContentCssCors(editor),
29260
        referrerPolicy: getReferrerPolicy(editor),
29261
        onSetAttrib: e => {
29262
          editor.dispatch('SetAttrib', e);
1441 ariadna 29263
        }
1 efrain 29264
      });
29265
      editor.parser = createParser(editor);
29266
      editor.serializer = DomSerializer(mkSerializerSettings(editor), editor);
29267
      editor.selection = EditorSelection(editor.dom, editor.getWin(), editor.serializer, editor);
29268
      editor.annotator = Annotator(editor);
29269
      editor.formatter = Formatter(editor);
29270
      editor.undoManager = UndoManager(editor);
29271
      editor._nodeChangeDispatcher = new NodeChange(editor);
29272
      editor._selectionOverrides = SelectionOverrides(editor);
29273
      setup$p(editor);
29274
      setup$6(editor);
29275
      setup$n(editor);
29276
      if (!isRtc(editor)) {
29277
        setup$5(editor);
29278
        setup$1(editor);
29279
      }
29280
      const caret = setup$b(editor);
29281
      setup$q(editor, caret);
29282
      setup$o(editor);
29283
      setup$r(editor);
29284
      setup$7(editor);
29285
      const setupRtcThunk = setup$t(editor);
29286
      preInit(editor);
1441 ariadna 29287
      validateEditorLicenseKey(editor);
1 efrain 29288
      setupRtcThunk.fold(() => {
29289
        const cancelProgress = startProgress(editor);
29290
        loadContentCss(editor).then(() => {
29291
          initEditorWithInitialContent(editor);
29292
          cancelProgress();
29293
        });
29294
      }, setupRtc => {
29295
        editor.setProgressState(true);
29296
        loadContentCss(editor).then(() => {
29297
          setupRtc().then(_rtcMode => {
29298
            editor.setProgressState(false);
29299
            initEditorWithInitialContent(editor);
29300
            bindEvents(editor);
29301
          }, err => {
29302
            editor.notificationManager.open({
29303
              type: 'error',
29304
              text: String(err)
29305
            });
29306
            initEditorWithInitialContent(editor);
29307
            bindEvents(editor);
29308
          });
29309
        });
29310
      });
29311
    };
29312
 
29313
    const filter = always;
29314
    const bind = (element, event, handler) => bind$2(element, event, filter, handler);
29315
 
29316
    const DOM$5 = DOMUtils.DOM;
29317
    const createIframeElement = (id, title, customAttrs, tabindex) => {
29318
      const iframe = SugarElement.fromTag('iframe');
1441 ariadna 29319
      tabindex.each(t => set$4(iframe, 'tabindex', t));
1 efrain 29320
      setAll$1(iframe, customAttrs);
29321
      setAll$1(iframe, {
29322
        id: id + '_ifr',
29323
        frameBorder: '0',
29324
        allowTransparency: 'true',
29325
        title
29326
      });
29327
      add$2(iframe, 'tox-edit-area__iframe');
29328
      return iframe;
29329
    };
29330
    const getIframeHtml = editor => {
29331
      let iframeHTML = getDocType(editor) + '<html><head>';
29332
      if (getDocumentBaseUrl(editor) !== editor.documentBaseUrl) {
29333
        iframeHTML += '<base href="' + editor.documentBaseURI.getURI() + '" />';
29334
      }
29335
      iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
29336
      const bodyId = getBodyId(editor);
29337
      const bodyClass = getBodyClass(editor);
29338
      const translatedAriaText = editor.translate(getIframeAriaText(editor));
29339
      if (getContentSecurityPolicy(editor)) {
29340
        iframeHTML += '<meta http-equiv="Content-Security-Policy" content="' + getContentSecurityPolicy(editor) + '" />';
29341
      }
29342
      iframeHTML += '</head>' + `<body id="${ bodyId }" class="mce-content-body ${ bodyClass }" data-id="${ editor.id }" aria-label="${ translatedAriaText }">` + '<br>' + '</body></html>';
29343
      return iframeHTML;
29344
    };
29345
    const createIframe = (editor, boxInfo) => {
1441 ariadna 29346
      const iframeTitle = Env.browser.isFirefox() ? getIframeAriaText(editor) : 'Rich Text Area';
29347
      const translatedTitle = editor.translate(iframeTitle);
1 efrain 29348
      const tabindex = getOpt(SugarElement.fromDom(editor.getElement()), 'tabindex').bind(toInt);
1441 ariadna 29349
      const ifr = createIframeElement(editor.id, translatedTitle, getIframeAttrs(editor), tabindex).dom;
1 efrain 29350
      ifr.onload = () => {
29351
        ifr.onload = null;
29352
        editor.dispatch('load');
29353
      };
29354
      editor.contentAreaContainer = boxInfo.iframeContainer;
29355
      editor.iframeElement = ifr;
29356
      editor.iframeHTML = getIframeHtml(editor);
29357
      DOM$5.add(boxInfo.iframeContainer, ifr);
29358
    };
29359
    const setupIframeBody = editor => {
29360
      const iframe = editor.iframeElement;
29361
      const ready = () => {
29362
        editor.contentDocument = iframe.contentDocument;
29363
        contentBodyLoaded(editor);
29364
      };
29365
      if (shouldUseDocumentWrite(editor) || Env.browser.isFirefox()) {
29366
        const doc = editor.getDoc();
29367
        doc.open();
29368
        doc.write(editor.iframeHTML);
29369
        doc.close();
29370
        ready();
29371
      } else {
29372
        const binder = bind(SugarElement.fromDom(iframe), 'load', () => {
29373
          binder.unbind();
29374
          ready();
29375
        });
29376
        iframe.srcdoc = editor.iframeHTML;
29377
      }
29378
    };
29379
    const init$1 = (editor, boxInfo) => {
29380
      createIframe(editor, boxInfo);
29381
      if (boxInfo.editorContainer) {
29382
        boxInfo.editorContainer.style.display = editor.orgDisplay;
29383
        editor.hidden = DOM$5.isHidden(boxInfo.editorContainer);
29384
      }
29385
      editor.getElement().style.display = 'none';
29386
      DOM$5.setAttrib(editor.id, 'aria-hidden', 'true');
29387
      editor.getElement().style.visibility = editor.orgVisibility;
29388
      setupIframeBody(editor);
29389
    };
29390
 
29391
    const DOM$4 = DOMUtils.DOM;
29392
    const initPlugin = (editor, initializedPlugins, plugin) => {
29393
      const Plugin = PluginManager.get(plugin);
29394
      const pluginUrl = PluginManager.urls[plugin] || editor.documentBaseUrl.replace(/\/$/, '');
29395
      plugin = Tools.trim(plugin);
29396
      if (Plugin && Tools.inArray(initializedPlugins, plugin) === -1) {
29397
        if (editor.plugins[plugin]) {
29398
          return;
29399
        }
29400
        try {
29401
          const pluginInstance = Plugin(editor, pluginUrl) || {};
29402
          editor.plugins[plugin] = pluginInstance;
29403
          if (isFunction(pluginInstance.init)) {
29404
            pluginInstance.init(editor, pluginUrl);
29405
            initializedPlugins.push(plugin);
29406
          }
29407
        } catch (e) {
29408
          pluginInitError(editor, plugin, e);
29409
        }
29410
      }
29411
    };
29412
    const trimLegacyPrefix = name => {
29413
      return name.replace(/^\-/, '');
29414
    };
29415
    const initPlugins = editor => {
29416
      const initializedPlugins = [];
29417
      each$e(getPlugins(editor), name => {
29418
        initPlugin(editor, initializedPlugins, trimLegacyPrefix(name));
29419
      });
29420
    };
29421
    const initIcons = editor => {
29422
      const iconPackName = Tools.trim(getIconPackName(editor));
29423
      const currentIcons = editor.ui.registry.getAll().icons;
29424
      const loadIcons = {
29425
        ...IconManager.get('default').icons,
29426
        ...IconManager.get(iconPackName).icons
29427
      };
29428
      each$d(loadIcons, (svgData, icon) => {
29429
        if (!has$2(currentIcons, icon)) {
29430
          editor.ui.registry.addIcon(icon, svgData);
29431
        }
29432
      });
29433
    };
29434
    const initTheme = editor => {
29435
      const theme = getTheme(editor);
29436
      if (isString(theme)) {
29437
        const Theme = ThemeManager.get(theme);
29438
        editor.theme = Theme(editor, ThemeManager.urls[theme]) || {};
29439
        if (isFunction(editor.theme.init)) {
29440
          editor.theme.init(editor, ThemeManager.urls[theme] || editor.documentBaseUrl.replace(/\/$/, ''));
29441
        }
29442
      } else {
29443
        editor.theme = {};
29444
      }
29445
    };
29446
    const initModel = editor => {
29447
      const model = getModel(editor);
29448
      const Model = ModelManager.get(model);
29449
      editor.model = Model(editor, ModelManager.urls[model]);
29450
    };
29451
    const renderFromLoadedTheme = editor => {
29452
      const render = editor.theme.renderUI;
29453
      return render ? render() : renderThemeFalse(editor);
29454
    };
29455
    const renderFromThemeFunc = editor => {
29456
      const elm = editor.getElement();
29457
      const theme = getTheme(editor);
29458
      const info = theme(editor, elm);
29459
      if (info.editorContainer.nodeType) {
29460
        info.editorContainer.id = info.editorContainer.id || editor.id + '_parent';
29461
      }
29462
      if (info.iframeContainer && info.iframeContainer.nodeType) {
29463
        info.iframeContainer.id = info.iframeContainer.id || editor.id + '_iframecontainer';
29464
      }
29465
      info.height = info.iframeHeight ? info.iframeHeight : elm.offsetHeight;
29466
      return info;
29467
    };
29468
    const createThemeFalseResult = (element, iframe) => {
29469
      return {
29470
        editorContainer: element,
29471
        iframeContainer: iframe,
29472
        api: {}
29473
      };
29474
    };
29475
    const renderThemeFalseIframe = targetElement => {
29476
      const iframeContainer = DOM$4.create('div');
29477
      DOM$4.insertAfter(iframeContainer, targetElement);
29478
      return createThemeFalseResult(iframeContainer, iframeContainer);
29479
    };
29480
    const renderThemeFalse = editor => {
29481
      const targetElement = editor.getElement();
29482
      return editor.inline ? createThemeFalseResult(null) : renderThemeFalseIframe(targetElement);
29483
    };
29484
    const renderThemeUi = editor => {
29485
      const elm = editor.getElement();
29486
      editor.orgDisplay = elm.style.display;
29487
      if (isString(getTheme(editor))) {
29488
        return renderFromLoadedTheme(editor);
29489
      } else if (isFunction(getTheme(editor))) {
29490
        return renderFromThemeFunc(editor);
29491
      } else {
29492
        return renderThemeFalse(editor);
29493
      }
29494
    };
29495
    const augmentEditorUiApi = (editor, api) => {
29496
      const uiApiFacade = {
29497
        show: Optional.from(api.show).getOr(noop),
29498
        hide: Optional.from(api.hide).getOr(noop),
29499
        isEnabled: Optional.from(api.isEnabled).getOr(always),
29500
        setEnabled: state => {
1441 ariadna 29501
          const shouldSkip = state && (editor.mode.get() === 'readonly' || isDisabled(editor));
29502
          if (!shouldSkip) {
1 efrain 29503
            Optional.from(api.setEnabled).each(f => f(state));
29504
          }
29505
        }
29506
      };
29507
      editor.ui = {
29508
        ...editor.ui,
29509
        ...uiApiFacade
29510
      };
29511
    };
29512
    const init = async editor => {
29513
      editor.dispatch('ScriptsLoaded');
29514
      initIcons(editor);
29515
      initTheme(editor);
29516
      initModel(editor);
29517
      initPlugins(editor);
29518
      const renderInfo = await renderThemeUi(editor);
29519
      augmentEditorUiApi(editor, Optional.from(renderInfo.api).getOr({}));
29520
      editor.editorContainer = renderInfo.editorContainer;
29521
      appendContentCssFromSettings(editor);
29522
      if (editor.inline) {
29523
        contentBodyLoaded(editor);
29524
      } else {
29525
        init$1(editor, {
29526
          editorContainer: renderInfo.editorContainer,
29527
          iframeContainer: renderInfo.iframeContainer
29528
        });
29529
      }
29530
    };
29531
 
29532
    const DOM$3 = DOMUtils.DOM;
29533
    const hasSkipLoadPrefix = name => name.charAt(0) === '-';
29534
    const loadLanguage = (scriptLoader, editor) => {
29535
      const languageCode = getLanguageCode(editor);
29536
      const languageUrl = getLanguageUrl(editor);
29537
      if (!I18n.hasCode(languageCode) && languageCode !== 'en') {
29538
        const url = isNotEmpty(languageUrl) ? languageUrl : `${ editor.editorManager.baseURL }/langs/${ languageCode }.js`;
29539
        scriptLoader.add(url).catch(() => {
29540
          languageLoadError(editor, url, languageCode);
29541
        });
29542
      }
29543
    };
29544
    const loadTheme = (editor, suffix) => {
29545
      const theme = getTheme(editor);
29546
      if (isString(theme) && !hasSkipLoadPrefix(theme) && !has$2(ThemeManager.urls, theme)) {
29547
        const themeUrl = getThemeUrl(editor);
29548
        const url = themeUrl ? editor.documentBaseURI.toAbsolute(themeUrl) : `themes/${ theme }/theme${ suffix }.js`;
29549
        ThemeManager.load(theme, url).catch(() => {
29550
          themeLoadError(editor, url, theme);
29551
        });
29552
      }
29553
    };
29554
    const loadModel = (editor, suffix) => {
29555
      const model = getModel(editor);
29556
      if (model !== 'plugin' && !has$2(ModelManager.urls, model)) {
29557
        const modelUrl = getModelUrl(editor);
29558
        const url = isString(modelUrl) ? editor.documentBaseURI.toAbsolute(modelUrl) : `models/${ model }/model${ suffix }.js`;
29559
        ModelManager.load(model, url).catch(() => {
29560
          modelLoadError(editor, url, model);
29561
        });
29562
      }
29563
    };
29564
    const getIconsUrlMetaFromUrl = editor => Optional.from(getIconsUrl(editor)).filter(isNotEmpty).map(url => ({
29565
      url,
29566
      name: Optional.none()
29567
    }));
29568
    const getIconsUrlMetaFromName = (editor, name, suffix) => Optional.from(name).filter(name => isNotEmpty(name) && !IconManager.has(name)).map(name => ({
29569
      url: `${ editor.editorManager.baseURL }/icons/${ name }/icons${ suffix }.js`,
29570
      name: Optional.some(name)
29571
    }));
29572
    const loadIcons = (scriptLoader, editor, suffix) => {
29573
      const defaultIconsUrl = getIconsUrlMetaFromName(editor, 'default', suffix);
29574
      const customIconsUrl = getIconsUrlMetaFromUrl(editor).orThunk(() => getIconsUrlMetaFromName(editor, getIconPackName(editor), ''));
29575
      each$e(cat([
29576
        defaultIconsUrl,
29577
        customIconsUrl
29578
      ]), urlMeta => {
29579
        scriptLoader.add(urlMeta.url).catch(() => {
29580
          iconsLoadError(editor, urlMeta.url, urlMeta.name.getOrUndefined());
29581
        });
29582
      });
29583
    };
29584
    const loadPlugins = (editor, suffix) => {
29585
      const loadPlugin = (name, url) => {
29586
        PluginManager.load(name, url).catch(() => {
29587
          pluginLoadError(editor, url, name);
29588
        });
29589
      };
29590
      each$d(getExternalPlugins$1(editor), (url, name) => {
29591
        loadPlugin(name, url);
29592
        editor.options.set('plugins', getPlugins(editor).concat(name));
29593
      });
29594
      each$e(getPlugins(editor), plugin => {
29595
        plugin = Tools.trim(plugin);
29596
        if (plugin && !PluginManager.urls[plugin] && !hasSkipLoadPrefix(plugin)) {
29597
          loadPlugin(plugin, `plugins/${ plugin }/plugin${ suffix }.js`);
29598
        }
29599
      });
29600
    };
29601
    const isThemeLoaded = editor => {
29602
      const theme = getTheme(editor);
29603
      return !isString(theme) || isNonNullable(ThemeManager.get(theme));
29604
    };
29605
    const isModelLoaded = editor => {
29606
      const model = getModel(editor);
29607
      return isNonNullable(ModelManager.get(model));
29608
    };
29609
    const loadScripts = (editor, suffix) => {
29610
      const scriptLoader = ScriptLoader.ScriptLoader;
29611
      const initEditor = () => {
29612
        if (!editor.removed && isThemeLoaded(editor) && isModelLoaded(editor)) {
29613
          init(editor);
29614
        }
29615
      };
29616
      loadTheme(editor, suffix);
29617
      loadModel(editor, suffix);
29618
      loadLanguage(scriptLoader, editor);
29619
      loadIcons(scriptLoader, editor, suffix);
29620
      loadPlugins(editor, suffix);
29621
      scriptLoader.loadQueue().then(initEditor, initEditor);
29622
    };
29623
    const getStyleSheetLoader = (element, editor) => instance.forElement(element, {
29624
      contentCssCors: hasContentCssCors(editor),
29625
      referrerPolicy: getReferrerPolicy(editor)
29626
    });
29627
    const render = editor => {
29628
      const id = editor.id;
29629
      I18n.setCode(getLanguageCode(editor));
29630
      const readyHandler = () => {
29631
        DOM$3.unbind(window, 'ready', readyHandler);
29632
        editor.render();
29633
      };
29634
      if (!EventUtils.Event.domLoaded) {
29635
        DOM$3.bind(window, 'ready', readyHandler);
29636
        return;
29637
      }
29638
      if (!editor.getElement()) {
29639
        return;
29640
      }
29641
      const element = SugarElement.fromDom(editor.getElement());
29642
      const snapshot = clone$4(element);
29643
      editor.on('remove', () => {
1441 ariadna 29644
        eachr(element.dom.attributes, attr => remove$9(element, attr.name));
1 efrain 29645
        setAll$1(element, snapshot);
29646
      });
29647
      editor.ui.styleSheetLoader = getStyleSheetLoader(element, editor);
29648
      if (!isInline$1(editor)) {
29649
        editor.orgVisibility = editor.getElement().style.visibility;
29650
        editor.getElement().style.visibility = 'hidden';
29651
      } else {
29652
        editor.inline = true;
29653
      }
29654
      const form = editor.getElement().form || DOM$3.getParent(id, 'form');
29655
      if (form) {
29656
        editor.formElement = form;
29657
        if (hasHiddenInput(editor) && !isTextareaOrInput(editor.getElement())) {
29658
          DOM$3.insertAfter(DOM$3.create('input', {
29659
            type: 'hidden',
29660
            name: id
29661
          }), id);
29662
          editor.hasHiddenInput = true;
29663
        }
29664
        editor.formEventDelegate = e => {
29665
          editor.dispatch(e.type, e);
29666
        };
29667
        DOM$3.bind(form, 'submit reset', editor.formEventDelegate);
29668
        editor.on('reset', () => {
29669
          editor.resetContent();
29670
        });
29671
        if (shouldPatchSubmit(editor) && !form.submit.nodeType && !form.submit.length && !form._mceOldSubmit) {
29672
          form._mceOldSubmit = form.submit;
29673
          form.submit = () => {
29674
            editor.editorManager.triggerSave();
29675
            editor.setDirty(false);
29676
            return form._mceOldSubmit(form);
29677
          };
29678
        }
29679
      }
29680
      editor.windowManager = WindowManager(editor);
29681
      editor.notificationManager = NotificationManager(editor);
29682
      if (isEncodingXml(editor)) {
29683
        editor.on('GetContent', e => {
29684
          if (e.save) {
29685
            e.content = DOM$3.encode(e.content);
29686
          }
29687
        });
29688
      }
29689
      if (shouldAddFormSubmitTrigger(editor)) {
29690
        editor.on('submit', () => {
29691
          if (editor.initialized) {
29692
            editor.save();
29693
          }
29694
        });
29695
      }
29696
      if (shouldAddUnloadTrigger(editor)) {
29697
        editor._beforeUnload = () => {
29698
          if (editor.initialized && !editor.destroyed && !editor.isHidden()) {
29699
            editor.save({
29700
              format: 'raw',
29701
              no_events: true,
29702
              set_dirty: false
29703
            });
29704
          }
29705
        };
29706
        editor.editorManager.on('BeforeUnload', editor._beforeUnload);
29707
      }
29708
      editor.editorManager.add(editor);
29709
      loadScripts(editor, editor.suffix);
29710
    };
29711
 
29712
    const setEditableRoot = (editor, state) => {
29713
      if (editor._editableRoot !== state) {
29714
        editor._editableRoot = state;
1441 ariadna 29715
        if (!isDisabled(editor)) {
1 efrain 29716
          editor.getBody().contentEditable = String(editor.hasEditableRoot());
29717
          editor.nodeChanged();
29718
        }
29719
        fireEditableRootStateChange(editor, state);
29720
      }
29721
    };
29722
    const hasEditableRoot = editor => editor._editableRoot;
29723
 
29724
    const sectionResult = (sections, settings) => ({
29725
      sections: constant(sections),
29726
      options: constant(settings)
29727
    });
1441 ariadna 29728
    const deviceDetection = detect$1().deviceType;
1 efrain 29729
    const isPhone = deviceDetection.isPhone();
29730
    const isTablet = deviceDetection.isTablet();
29731
    const normalizePlugins = plugins => {
29732
      if (isNullable(plugins)) {
29733
        return [];
29734
      } else {
29735
        const pluginNames = isArray$1(plugins) ? plugins : plugins.split(/[ ,]/);
29736
        const trimmedPlugins = map$3(pluginNames, trim$4);
29737
        return filter$5(trimmedPlugins, isNotEmpty);
29738
      }
29739
    };
29740
    const extractSections = (keys, options) => {
29741
      const result = bifilter(options, (value, key) => {
29742
        return contains$2(keys, key);
29743
      });
29744
      return sectionResult(result.t, result.f);
29745
    };
29746
    const getSection = (sectionResult, name, defaults = {}) => {
29747
      const sections = sectionResult.sections();
29748
      const sectionOptions = get$a(sections, name).getOr({});
29749
      return Tools.extend({}, defaults, sectionOptions);
29750
    };
29751
    const hasSection = (sectionResult, name) => {
29752
      return has$2(sectionResult.sections(), name);
29753
    };
29754
    const getSectionConfig = (sectionResult, name) => {
29755
      return hasSection(sectionResult, name) ? sectionResult.sections()[name] : {};
29756
    };
29757
    const getMobileOverrideOptions = (mobileOptions, isPhone) => {
29758
      const defaultMobileOptions = {
29759
        table_grid: false,
29760
        object_resizing: false,
29761
        resize: false,
29762
        toolbar_mode: get$a(mobileOptions, 'toolbar_mode').getOr('scrolling'),
29763
        toolbar_sticky: false
29764
      };
29765
      const defaultPhoneOptions = { menubar: false };
29766
      return {
29767
        ...defaultMobileOptions,
29768
        ...isPhone ? defaultPhoneOptions : {}
29769
      };
29770
    };
29771
    const getExternalPlugins = (overrideOptions, options) => {
29772
      var _a;
29773
      const userDefinedExternalPlugins = (_a = options.external_plugins) !== null && _a !== void 0 ? _a : {};
29774
      if (overrideOptions && overrideOptions.external_plugins) {
29775
        return Tools.extend({}, overrideOptions.external_plugins, userDefinedExternalPlugins);
29776
      } else {
29777
        return userDefinedExternalPlugins;
29778
      }
29779
    };
29780
    const combinePlugins = (forcedPlugins, plugins) => [
29781
      ...normalizePlugins(forcedPlugins),
29782
      ...normalizePlugins(plugins)
29783
    ];
29784
    const getPlatformPlugins = (isMobileDevice, sectionResult, desktopPlugins, mobilePlugins) => {
29785
      if (isMobileDevice && hasSection(sectionResult, 'mobile')) {
29786
        return mobilePlugins;
29787
      } else {
29788
        return desktopPlugins;
29789
      }
29790
    };
29791
    const processPlugins = (isMobileDevice, sectionResult, defaultOverrideOptions, options) => {
29792
      const forcedPlugins = normalizePlugins(defaultOverrideOptions.forced_plugins);
29793
      const desktopPlugins = normalizePlugins(options.plugins);
29794
      const mobileConfig = getSectionConfig(sectionResult, 'mobile');
29795
      const mobilePlugins = mobileConfig.plugins ? normalizePlugins(mobileConfig.plugins) : desktopPlugins;
29796
      const platformPlugins = getPlatformPlugins(isMobileDevice, sectionResult, desktopPlugins, mobilePlugins);
29797
      const combinedPlugins = combinePlugins(forcedPlugins, platformPlugins);
29798
      return Tools.extend(options, {
29799
        forced_plugins: forcedPlugins,
29800
        plugins: combinedPlugins
29801
      });
29802
    };
29803
    const isOnMobile = (isMobileDevice, sectionResult) => {
29804
      return isMobileDevice && hasSection(sectionResult, 'mobile');
29805
    };
29806
    const combineOptions = (isMobileDevice, isPhone, defaultOptions, defaultOverrideOptions, options) => {
29807
      var _a;
29808
      const deviceOverrideOptions = isMobileDevice ? { mobile: getMobileOverrideOptions((_a = options.mobile) !== null && _a !== void 0 ? _a : {}, isPhone) } : {};
29809
      const sectionResult = extractSections(['mobile'], deepMerge(deviceOverrideOptions, options));
29810
      const extendedOptions = Tools.extend(defaultOptions, defaultOverrideOptions, sectionResult.options(), isOnMobile(isMobileDevice, sectionResult) ? getSection(sectionResult, 'mobile') : {}, { external_plugins: getExternalPlugins(defaultOverrideOptions, sectionResult.options()) });
29811
      return processPlugins(isMobileDevice, sectionResult, defaultOverrideOptions, extendedOptions);
29812
    };
1441 ariadna 29813
    const normalizeOptions = (defaultOverrideOptions, options) => {
29814
      const copiedOptions = merge(options);
29815
      return combineOptions(isPhone || isTablet, isPhone, copiedOptions, defaultOverrideOptions, copiedOptions);
29816
    };
1 efrain 29817
 
29818
    const addVisual = (editor, elm) => addVisual$1(editor, elm);
29819
 
1441 ariadna 29820
    const registerExecCommands$2 = editor => {
1 efrain 29821
      const toggleFormat = (name, value) => {
29822
        editor.formatter.toggle(name, value);
29823
        editor.nodeChanged();
29824
      };
29825
      const toggleAlign = align => () => {
29826
        each$e('left,center,right,justify'.split(','), name => {
29827
          if (align !== name) {
29828
            editor.formatter.remove('align' + name);
29829
          }
29830
        });
29831
        if (align !== 'none') {
29832
          toggleFormat('align' + align);
29833
        }
29834
      };
29835
      editor.editorCommands.addCommands({
29836
        JustifyLeft: toggleAlign('left'),
29837
        JustifyCenter: toggleAlign('center'),
29838
        JustifyRight: toggleAlign('right'),
29839
        JustifyFull: toggleAlign('justify'),
29840
        JustifyNone: toggleAlign('none')
29841
      });
29842
    };
1441 ariadna 29843
    const registerQueryStateCommands = editor => {
1 efrain 29844
      const alignStates = name => () => {
29845
        const selection = editor.selection;
29846
        const nodes = selection.isCollapsed() ? [editor.dom.getParent(selection.getNode(), editor.dom.isBlock)] : selection.getSelectedBlocks();
29847
        return exists(nodes, node => isNonNullable(editor.formatter.matchNode(node, name)));
29848
      };
29849
      editor.editorCommands.addCommands({
29850
        JustifyLeft: alignStates('alignleft'),
29851
        JustifyCenter: alignStates('aligncenter'),
29852
        JustifyRight: alignStates('alignright'),
29853
        JustifyFull: alignStates('alignjustify')
29854
      }, 'state');
29855
    };
1441 ariadna 29856
    const registerCommands$a = editor => {
29857
      registerExecCommands$2(editor);
29858
      registerQueryStateCommands(editor);
1 efrain 29859
    };
29860
 
1441 ariadna 29861
    const registerCommands$9 = editor => {
1 efrain 29862
      editor.editorCommands.addCommands({
29863
        'Cut,Copy,Paste': command => {
29864
          const doc = editor.getDoc();
29865
          let failed;
29866
          try {
29867
            doc.execCommand(command);
1441 ariadna 29868
          } catch (_a) {
1 efrain 29869
            failed = true;
29870
          }
29871
          if (command === 'paste' && !doc.queryCommandEnabled(command)) {
29872
            failed = true;
29873
          }
29874
          if (failed || !doc.queryCommandSupported(command)) {
29875
            let msg = editor.translate(`Your browser doesn't support direct access to the clipboard. ` + 'Please use the Ctrl+X/C/V keyboard shortcuts instead.');
29876
            if (Env.os.isMacOS() || Env.os.isiOS()) {
29877
              msg = msg.replace(/Ctrl\+/g, '\u2318+');
29878
            }
29879
            editor.notificationManager.open({
29880
              text: msg,
29881
              type: 'error'
29882
            });
29883
          }
29884
        }
29885
      });
29886
    };
29887
 
29888
    const trimOrPadLeftRight = (dom, rng, html, schema) => {
29889
      const root = SugarElement.fromDom(dom.getRoot());
29890
      if (needsToBeNbspLeft(root, CaretPosition.fromRangeStart(rng), schema)) {
29891
        html = html.replace(/^ /, '&nbsp;');
29892
      } else {
29893
        html = html.replace(/^&nbsp;/, ' ');
29894
      }
29895
      if (needsToBeNbspRight(root, CaretPosition.fromRangeEnd(rng), schema)) {
29896
        html = html.replace(/(&nbsp;| )(<br( \/)>)?$/, '&nbsp;');
29897
      } else {
29898
        html = html.replace(/&nbsp;(<br( \/)?>)?$/, ' ');
29899
      }
29900
      return html;
29901
    };
29902
 
29903
    const processValue$1 = value => {
29904
      if (typeof value !== 'string') {
29905
        const details = Tools.extend({
29906
          paste: value.paste,
29907
          data: { paste: value.paste }
29908
        }, value);
29909
        return {
29910
          content: value.content,
29911
          details
29912
        };
29913
      }
29914
      return {
29915
        content: value,
29916
        details: {}
29917
      };
29918
    };
29919
    const trimOrPad = (editor, value) => {
29920
      const selection = editor.selection;
29921
      const dom = editor.dom;
29922
      if (/^ | $/.test(value)) {
29923
        return trimOrPadLeftRight(dom, selection.getRng(), value, editor.schema);
29924
      } else {
29925
        return value;
29926
      }
29927
    };
29928
    const insertAtCaret = (editor, value) => {
29929
      if (editor.selection.isEditable()) {
29930
        const {content, details} = processValue$1(value);
29931
        preProcessSetContent(editor, {
29932
          ...details,
29933
          content: trimOrPad(editor, content),
29934
          format: 'html',
29935
          set: false,
29936
          selection: true
29937
        }).each(args => {
29938
          const insertedContent = insertContent$1(editor, args.content, details);
29939
          postProcessSetContent(editor, insertedContent, args);
29940
          editor.addVisual();
29941
        });
29942
      }
29943
    };
29944
 
1441 ariadna 29945
    const registerCommands$8 = editor => {
1 efrain 29946
      editor.editorCommands.addCommands({
29947
        mceCleanup: () => {
29948
          const bm = editor.selection.getBookmark();
29949
          editor.setContent(editor.getContent());
29950
          editor.selection.moveToBookmark(bm);
29951
        },
29952
        insertImage: (_command, _ui, value) => {
29953
          insertAtCaret(editor, editor.dom.createHTML('img', { src: value }));
29954
        },
29955
        insertHorizontalRule: () => {
29956
          editor.execCommand('mceInsertContent', false, '<hr>');
29957
        },
29958
        insertText: (_command, _ui, value) => {
29959
          insertAtCaret(editor, editor.dom.encode(value));
29960
        },
29961
        insertHTML: (_command, _ui, value) => {
29962
          insertAtCaret(editor, value);
29963
        },
29964
        mceInsertContent: (_command, _ui, value) => {
29965
          insertAtCaret(editor, value);
29966
        },
29967
        mceSetContent: (_command, _ui, value) => {
29968
          editor.setContent(value);
29969
        },
29970
        mceReplaceContent: (_command, _ui, value) => {
29971
          editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, editor.selection.getContent({ format: 'text' })));
29972
        },
29973
        mceNewDocument: () => {
29974
          editor.setContent(getNewDocumentContent(editor));
29975
        }
29976
      });
29977
    };
29978
 
29979
    const legacyPropNames = {
29980
      'font-size': 'size',
29981
      'font-family': 'face'
29982
    };
29983
    const isFont = isTag('font');
29984
    const getSpecifiedFontProp = (propName, rootElm, elm) => {
29985
      const getProperty = elm => getRaw(elm, propName).orThunk(() => {
29986
        if (isFont(elm)) {
29987
          return get$a(legacyPropNames, propName).bind(legacyPropName => getOpt(elm, legacyPropName));
29988
        } else {
29989
          return Optional.none();
29990
        }
29991
      });
29992
      const isRoot = elm => eq(SugarElement.fromDom(rootElm), elm);
29993
      return closest$1(SugarElement.fromDom(elm), elm => getProperty(elm), isRoot);
29994
    };
29995
    const normalizeFontFamily = fontFamily => fontFamily.replace(/[\'\"\\]/g, '').replace(/,\s+/g, ',');
29996
    const getComputedFontProp = (propName, elm) => Optional.from(DOMUtils.DOM.getStyle(elm, propName, true));
29997
    const getFontProp = propName => (rootElm, elm) => Optional.from(elm).map(SugarElement.fromDom).filter(isElement$7).bind(element => getSpecifiedFontProp(propName, rootElm, element.dom).or(getComputedFontProp(propName, element.dom))).getOr('');
29998
    const getFontSize = getFontProp('font-size');
29999
    const getFontFamily = compose(normalizeFontFamily, getFontProp('font-family'));
30000
 
30001
    const findFirstCaretElement = editor => firstPositionIn(editor.getBody()).bind(caret => {
30002
      const container = caret.container();
1441 ariadna 30003
      return Optional.from(isText$b(container) ? container.parentNode : container);
1 efrain 30004
    });
30005
    const getCaretElement = editor => Optional.from(editor.selection.getRng()).bind(rng => {
30006
      const root = editor.getBody();
30007
      const atStartOfNode = rng.startContainer === root && rng.startOffset === 0;
30008
      return atStartOfNode ? Optional.none() : Optional.from(editor.selection.getStart(true));
30009
    });
30010
    const bindRange = (editor, binder) => getCaretElement(editor).orThunk(curry(findFirstCaretElement, editor)).map(SugarElement.fromDom).filter(isElement$7).bind(binder);
30011
    const mapRange = (editor, mapper) => bindRange(editor, compose1(Optional.some, mapper));
30012
 
30013
    const fromFontSizeNumber = (editor, value) => {
30014
      if (/^[0-9.]+$/.test(value)) {
30015
        const fontSizeNumber = parseInt(value, 10);
30016
        if (fontSizeNumber >= 1 && fontSizeNumber <= 7) {
30017
          const fontSizes = getFontStyleValues(editor);
30018
          const fontClasses = getFontSizeClasses(editor);
30019
          if (fontClasses.length > 0) {
30020
            return fontClasses[fontSizeNumber - 1] || value;
30021
          } else {
30022
            return fontSizes[fontSizeNumber - 1] || value;
30023
          }
30024
        } else {
30025
          return value;
30026
        }
30027
      } else {
30028
        return value;
30029
      }
30030
    };
30031
    const normalizeFontNames = font => {
30032
      const fonts = font.split(/\s*,\s*/);
30033
      return map$3(fonts, font => {
30034
        if (font.indexOf(' ') !== -1 && !(startsWith(font, '"') || startsWith(font, `'`))) {
30035
          return `'${ font }'`;
30036
        } else {
30037
          return font;
30038
        }
30039
      }).join(',');
30040
    };
30041
    const fontNameAction = (editor, value) => {
30042
      const font = fromFontSizeNumber(editor, value);
30043
      editor.formatter.toggle('fontname', { value: normalizeFontNames(font) });
30044
      editor.nodeChanged();
30045
    };
30046
    const fontNameQuery = editor => mapRange(editor, elm => getFontFamily(editor.getBody(), elm.dom)).getOr('');
30047
    const fontSizeAction = (editor, value) => {
30048
      editor.formatter.toggle('fontsize', { value: fromFontSizeNumber(editor, value) });
30049
      editor.nodeChanged();
30050
    };
30051
    const fontSizeQuery = editor => mapRange(editor, elm => getFontSize(editor.getBody(), elm.dom)).getOr('');
30052
 
30053
    const lineHeightQuery = editor => mapRange(editor, elm => {
30054
      const root = SugarElement.fromDom(editor.getBody());
30055
      const specifiedStyle = closest$1(elm, elm => getRaw(elm, 'line-height'), curry(eq, root));
30056
      const computedStyle = () => {
30057
        const lineHeight = parseFloat(get$7(elm, 'line-height'));
30058
        const fontSize = parseFloat(get$7(elm, 'font-size'));
30059
        return String(lineHeight / fontSize);
30060
      };
30061
      return specifiedStyle.getOrThunk(computedStyle);
30062
    }).getOr('');
30063
    const lineHeightAction = (editor, lineHeight) => {
30064
      editor.formatter.toggle('lineheight', { value: String(lineHeight) });
30065
      editor.nodeChanged();
30066
    };
30067
 
1441 ariadna 30068
    const registerExecCommands$1 = editor => {
1 efrain 30069
      const toggleFormat = (name, value) => {
30070
        editor.formatter.toggle(name, value);
30071
        editor.nodeChanged();
30072
      };
30073
      editor.editorCommands.addCommands({
30074
        'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => {
30075
          toggleFormat(command);
30076
        },
30077
        'ForeColor,HiliteColor': (command, _ui, value) => {
30078
          toggleFormat(command, { value });
30079
        },
30080
        'BackColor': (_command, _ui, value) => {
30081
          toggleFormat('hilitecolor', { value });
30082
        },
30083
        'FontName': (_command, _ui, value) => {
30084
          fontNameAction(editor, value);
30085
        },
30086
        'FontSize': (_command, _ui, value) => {
30087
          fontSizeAction(editor, value);
30088
        },
30089
        'LineHeight': (_command, _ui, value) => {
30090
          lineHeightAction(editor, value);
30091
        },
30092
        'Lang': (command, _ui, lang) => {
30093
          var _a;
30094
          toggleFormat(command, {
30095
            value: lang.code,
30096
            customValue: (_a = lang.customCode) !== null && _a !== void 0 ? _a : null
30097
          });
30098
        },
30099
        'RemoveFormat': command => {
30100
          editor.formatter.remove(command);
30101
        },
30102
        'mceBlockQuote': () => {
30103
          toggleFormat('blockquote');
30104
        },
30105
        'FormatBlock': (_command, _ui, value) => {
30106
          toggleFormat(isString(value) ? value : 'p');
30107
        },
30108
        'mceToggleFormat': (_command, _ui, value) => {
30109
          toggleFormat(value);
30110
        }
30111
      });
30112
    };
30113
    const registerQueryValueCommands = editor => {
30114
      const isFormatMatch = name => editor.formatter.match(name);
30115
      editor.editorCommands.addCommands({
30116
        'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => isFormatMatch(command),
30117
        'mceBlockQuote': () => isFormatMatch('blockquote')
30118
      }, 'state');
30119
      editor.editorCommands.addQueryValueHandler('FontName', () => fontNameQuery(editor));
30120
      editor.editorCommands.addQueryValueHandler('FontSize', () => fontSizeQuery(editor));
30121
      editor.editorCommands.addQueryValueHandler('LineHeight', () => lineHeightQuery(editor));
30122
    };
1441 ariadna 30123
    const registerCommands$7 = editor => {
30124
      registerExecCommands$1(editor);
1 efrain 30125
      registerQueryValueCommands(editor);
30126
    };
30127
 
1441 ariadna 30128
    const registerCommands$6 = editor => {
1 efrain 30129
      editor.editorCommands.addCommands({
30130
        mceAddUndoLevel: () => {
30131
          editor.undoManager.add();
30132
        },
30133
        mceEndUndoLevel: () => {
30134
          editor.undoManager.add();
30135
        },
30136
        Undo: () => {
30137
          editor.undoManager.undo();
30138
        },
30139
        Redo: () => {
30140
          editor.undoManager.redo();
30141
        }
30142
      });
30143
    };
30144
 
1441 ariadna 30145
    const registerCommands$5 = editor => {
1 efrain 30146
      editor.editorCommands.addCommands({
30147
        Indent: () => {
30148
          indent(editor);
30149
        },
30150
        Outdent: () => {
30151
          outdent(editor);
30152
        }
30153
      });
30154
      editor.editorCommands.addCommands({ Outdent: () => canOutdent(editor) }, 'state');
30155
    };
30156
 
1441 ariadna 30157
    const registerCommands$4 = editor => {
1 efrain 30158
      const applyLinkToSelection = (_command, _ui, value) => {
1441 ariadna 30159
        if (editor.mode.isReadOnly()) {
30160
          return;
30161
        }
1 efrain 30162
        const linkDetails = isString(value) ? { href: value } : value;
30163
        const anchor = editor.dom.getParent(editor.selection.getNode(), 'a');
30164
        if (isObject(linkDetails) && isString(linkDetails.href)) {
30165
          linkDetails.href = linkDetails.href.replace(/ /g, '%20');
30166
          if (!anchor || !linkDetails.href) {
30167
            editor.formatter.remove('link');
30168
          }
30169
          if (linkDetails.href) {
30170
            editor.formatter.apply('link', linkDetails, anchor);
30171
          }
30172
        }
30173
      };
30174
      editor.editorCommands.addCommands({
30175
        unlink: () => {
30176
          if (editor.selection.isEditable()) {
30177
            if (editor.selection.isCollapsed()) {
30178
              const elm = editor.dom.getParent(editor.selection.getStart(), 'a');
30179
              if (elm) {
30180
                editor.dom.remove(elm, true);
30181
              }
30182
              return;
30183
            }
30184
            editor.formatter.remove('link');
30185
          }
30186
        },
30187
        mceInsertLink: applyLinkToSelection,
30188
        createLink: applyLinkToSelection
30189
      });
30190
    };
30191
 
30192
    const getTopParentBlock = (editor, node, root, container) => {
30193
      const dom = editor.dom;
30194
      const selector = node => dom.isBlock(node) && node.parentElement === root;
30195
      const topParentBlock = selector(node) ? node : dom.getParent(container, selector, root);
30196
      return Optional.from(topParentBlock).map(SugarElement.fromDom);
30197
    };
30198
    const insert = (editor, before) => {
1441 ariadna 30199
      if (editor.mode.isReadOnly()) {
30200
        return;
30201
      }
1 efrain 30202
      const dom = editor.dom;
30203
      const rng = editor.selection.getRng();
30204
      const node = before ? editor.selection.getStart() : editor.selection.getEnd();
30205
      const container = before ? rng.startContainer : rng.endContainer;
30206
      const root = getEditableRoot(dom, container);
30207
      if (!root || !root.isContentEditable) {
30208
        return;
30209
      }
30210
      const insertFn = before ? before$3 : after$4;
30211
      const newBlockName = getForcedRootBlock(editor);
30212
      getTopParentBlock(editor, node, root, container).each(parentBlock => {
30213
        const newBlock = createNewBlock(editor, container, parentBlock.dom, root, false, newBlockName);
30214
        insertFn(parentBlock, SugarElement.fromDom(newBlock));
30215
        editor.selection.setCursorLocation(newBlock, 0);
30216
        editor.dispatch('NewBlock', { newBlock });
30217
        fireInputEvent(editor, 'insertParagraph');
30218
      });
30219
    };
30220
    const insertBefore = editor => insert(editor, true);
30221
    const insertAfter = editor => insert(editor, false);
30222
 
30223
    const registerCommands$3 = editor => {
30224
      editor.editorCommands.addCommands({
30225
        InsertNewBlockBefore: () => {
30226
          insertBefore(editor);
30227
        },
30228
        InsertNewBlockAfter: () => {
30229
          insertAfter(editor);
30230
        }
30231
      });
30232
    };
30233
 
30234
    const registerCommands$2 = editor => {
30235
      editor.editorCommands.addCommands({
30236
        insertParagraph: () => {
30237
          insertBreak(blockbreak, editor);
30238
        },
30239
        mceInsertNewLine: (_command, _ui, value) => {
30240
          insert$1(editor, value);
30241
        },
30242
        InsertLineBreak: (_command, _ui, _value) => {
30243
          insertBreak(linebreak, editor);
30244
        }
30245
      });
30246
    };
30247
 
30248
    const registerCommands$1 = editor => {
30249
      editor.editorCommands.addCommands({
30250
        mceSelectNodeDepth: (_command, _ui, value) => {
30251
          let counter = 0;
30252
          editor.dom.getParent(editor.selection.getNode(), node => {
30253
            if (isElement$6(node) && counter++ === value) {
30254
              editor.selection.select(node);
30255
              return false;
30256
            } else {
30257
              return true;
30258
            }
30259
          }, editor.getBody());
30260
        },
30261
        mceSelectNode: (_command, _ui, value) => {
30262
          editor.selection.select(value);
30263
        },
30264
        selectAll: () => {
30265
          const editingHost = editor.dom.getParent(editor.selection.getStart(), isContentEditableTrue$3);
30266
          if (editingHost) {
30267
            const rng = editor.dom.createRng();
30268
            rng.selectNodeContents(editingHost);
30269
            editor.selection.setRng(rng);
30270
          }
30271
        }
30272
      });
30273
    };
30274
 
30275
    const registerExecCommands = editor => {
30276
      editor.editorCommands.addCommands({
30277
        mceRemoveNode: (_command, _ui, value) => {
30278
          const node = value !== null && value !== void 0 ? value : editor.selection.getNode();
30279
          if (node !== editor.getBody()) {
30280
            const bm = editor.selection.getBookmark();
30281
            editor.dom.remove(node, true);
30282
            editor.selection.moveToBookmark(bm);
30283
          }
30284
        },
30285
        mcePrint: () => {
30286
          editor.getWin().print();
30287
        },
30288
        mceFocus: (_command, _ui, value) => {
30289
          focus(editor, value === true);
30290
        },
30291
        mceToggleVisualAid: () => {
30292
          editor.hasVisual = !editor.hasVisual;
30293
          editor.addVisual();
30294
        }
30295
      });
30296
    };
30297
    const registerCommands = editor => {
30298
      registerCommands$a(editor);
1441 ariadna 30299
      registerCommands$9(editor);
30300
      registerCommands$6(editor);
1 efrain 30301
      registerCommands$1(editor);
1441 ariadna 30302
      registerCommands$8(editor);
30303
      registerCommands$4(editor);
1 efrain 30304
      registerCommands$5(editor);
30305
      registerCommands$3(editor);
30306
      registerCommands$2(editor);
1441 ariadna 30307
      registerCommands$7(editor);
1 efrain 30308
      registerExecCommands(editor);
30309
    };
30310
 
30311
    const selectionSafeCommands = ['toggleview'];
30312
    const isSelectionSafeCommand = command => contains$2(selectionSafeCommands, command.toLowerCase());
30313
    class EditorCommands {
30314
      constructor(editor) {
30315
        this.commands = {
30316
          state: {},
30317
          exec: {},
30318
          value: {}
30319
        };
30320
        this.editor = editor;
30321
      }
30322
      execCommand(command, ui = false, value, args) {
30323
        const editor = this.editor;
30324
        const lowerCaseCommand = command.toLowerCase();
30325
        const skipFocus = args === null || args === void 0 ? void 0 : args.skip_focus;
30326
        if (editor.removed) {
30327
          return false;
30328
        }
30329
        if (lowerCaseCommand !== 'mcefocus') {
30330
          if (!/^(mceAddUndoLevel|mceEndUndoLevel)$/i.test(lowerCaseCommand) && !skipFocus) {
30331
            editor.focus();
30332
          } else {
30333
            restore(editor);
30334
          }
30335
        }
30336
        const eventArgs = editor.dispatch('BeforeExecCommand', {
30337
          command,
30338
          ui,
30339
          value
30340
        });
30341
        if (eventArgs.isDefaultPrevented()) {
30342
          return false;
30343
        }
30344
        const func = this.commands.exec[lowerCaseCommand];
30345
        if (isFunction(func)) {
30346
          func(lowerCaseCommand, ui, value);
30347
          editor.dispatch('ExecCommand', {
30348
            command,
30349
            ui,
30350
            value
30351
          });
30352
          return true;
30353
        }
30354
        return false;
30355
      }
30356
      queryCommandState(command) {
30357
        if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
30358
          return false;
30359
        }
30360
        const lowerCaseCommand = command.toLowerCase();
30361
        const func = this.commands.state[lowerCaseCommand];
30362
        if (isFunction(func)) {
30363
          return func(lowerCaseCommand);
30364
        }
30365
        return false;
30366
      }
30367
      queryCommandValue(command) {
30368
        if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
30369
          return '';
30370
        }
30371
        const lowerCaseCommand = command.toLowerCase();
30372
        const func = this.commands.value[lowerCaseCommand];
30373
        if (isFunction(func)) {
30374
          return func(lowerCaseCommand);
30375
        }
30376
        return '';
30377
      }
30378
      addCommands(commandList, type = 'exec') {
30379
        const commands = this.commands;
30380
        each$d(commandList, (callback, command) => {
30381
          each$e(command.toLowerCase().split(','), command => {
30382
            commands[type][command] = callback;
30383
          });
30384
        });
30385
      }
30386
      addCommand(command, callback, scope) {
30387
        const lowerCaseCommand = command.toLowerCase();
30388
        this.commands.exec[lowerCaseCommand] = (_command, ui, value) => callback.call(scope !== null && scope !== void 0 ? scope : this.editor, ui, value);
30389
      }
30390
      queryCommandSupported(command) {
30391
        const lowerCaseCommand = command.toLowerCase();
30392
        if (this.commands.exec[lowerCaseCommand]) {
30393
          return true;
30394
        } else {
30395
          return false;
30396
        }
30397
      }
30398
      addQueryStateHandler(command, callback, scope) {
30399
        this.commands.state[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
30400
      }
30401
      addQueryValueHandler(command, callback, scope) {
30402
        this.commands.value[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
30403
      }
30404
    }
30405
 
30406
    const nativeEvents = Tools.makeMap('focus blur focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange ' + 'mouseout mouseenter mouseleave wheel keydown keypress keyup input beforeinput contextmenu dragstart dragend dragover ' + 'draggesture dragdrop drop drag submit ' + 'compositionstart compositionend compositionupdate touchstart touchmove touchend touchcancel', ' ');
30407
    class EventDispatcher {
30408
      static isNative(name) {
30409
        return !!nativeEvents[name.toLowerCase()];
30410
      }
30411
      constructor(settings) {
30412
        this.bindings = {};
30413
        this.settings = settings || {};
30414
        this.scope = this.settings.scope || this;
30415
        this.toggleEvent = this.settings.toggleEvent || never;
30416
      }
30417
      fire(name, args) {
30418
        return this.dispatch(name, args);
30419
      }
30420
      dispatch(name, args) {
30421
        const lcName = name.toLowerCase();
30422
        const event = normalize$3(lcName, args !== null && args !== void 0 ? args : {}, this.scope);
30423
        if (this.settings.beforeFire) {
30424
          this.settings.beforeFire(event);
30425
        }
30426
        const handlers = this.bindings[lcName];
30427
        if (handlers) {
30428
          for (let i = 0, l = handlers.length; i < l; i++) {
30429
            const callback = handlers[i];
30430
            if (callback.removed) {
30431
              continue;
30432
            }
30433
            if (callback.once) {
30434
              this.off(lcName, callback.func);
30435
            }
30436
            if (event.isImmediatePropagationStopped()) {
30437
              return event;
30438
            }
30439
            if (callback.func.call(this.scope, event) === false) {
30440
              event.preventDefault();
30441
              return event;
30442
            }
30443
          }
30444
        }
30445
        return event;
30446
      }
30447
      on(name, callback, prepend, extra) {
30448
        if (callback === false) {
30449
          callback = never;
30450
        }
30451
        if (callback) {
30452
          const wrappedCallback = {
30453
            func: callback,
30454
            removed: false
30455
          };
30456
          if (extra) {
30457
            Tools.extend(wrappedCallback, extra);
30458
          }
30459
          const names = name.toLowerCase().split(' ');
30460
          let i = names.length;
30461
          while (i--) {
30462
            const currentName = names[i];
30463
            let handlers = this.bindings[currentName];
30464
            if (!handlers) {
30465
              handlers = [];
30466
              this.toggleEvent(currentName, true);
30467
            }
30468
            if (prepend) {
30469
              handlers = [
30470
                wrappedCallback,
30471
                ...handlers
30472
              ];
30473
            } else {
30474
              handlers = [
30475
                ...handlers,
30476
                wrappedCallback
30477
              ];
30478
            }
30479
            this.bindings[currentName] = handlers;
30480
          }
30481
        }
30482
        return this;
30483
      }
30484
      off(name, callback) {
30485
        if (name) {
30486
          const names = name.toLowerCase().split(' ');
30487
          let i = names.length;
30488
          while (i--) {
30489
            const currentName = names[i];
30490
            let handlers = this.bindings[currentName];
30491
            if (!currentName) {
30492
              each$d(this.bindings, (_value, bindingName) => {
30493
                this.toggleEvent(bindingName, false);
30494
                delete this.bindings[bindingName];
30495
              });
30496
              return this;
30497
            }
30498
            if (handlers) {
30499
              if (!callback) {
30500
                handlers.length = 0;
30501
              } else {
30502
                const filteredHandlers = partition$2(handlers, handler => handler.func === callback);
30503
                handlers = filteredHandlers.fail;
30504
                this.bindings[currentName] = handlers;
30505
                each$e(filteredHandlers.pass, handler => {
30506
                  handler.removed = true;
30507
                });
30508
              }
30509
              if (!handlers.length) {
30510
                this.toggleEvent(name, false);
30511
                delete this.bindings[currentName];
30512
              }
30513
            }
30514
          }
30515
        } else {
30516
          each$d(this.bindings, (_value, name) => {
30517
            this.toggleEvent(name, false);
30518
          });
30519
          this.bindings = {};
30520
        }
30521
        return this;
30522
      }
30523
      once(name, callback, prepend) {
30524
        return this.on(name, callback, prepend, { once: true });
30525
      }
30526
      has(name) {
30527
        name = name.toLowerCase();
30528
        const binding = this.bindings[name];
30529
        return !(!binding || binding.length === 0);
30530
      }
30531
    }
30532
 
30533
    const getEventDispatcher = obj => {
30534
      if (!obj._eventDispatcher) {
30535
        obj._eventDispatcher = new EventDispatcher({
30536
          scope: obj,
30537
          toggleEvent: (name, state) => {
30538
            if (EventDispatcher.isNative(name) && obj.toggleNativeEvent) {
30539
              obj.toggleNativeEvent(name, state);
30540
            }
30541
          }
30542
        });
30543
      }
30544
      return obj._eventDispatcher;
30545
    };
30546
    const Observable = {
30547
      fire(name, args, bubble) {
30548
        return this.dispatch(name, args, bubble);
30549
      },
30550
      dispatch(name, args, bubble) {
30551
        const self = this;
30552
        if (self.removed && name !== 'remove' && name !== 'detach') {
30553
          return normalize$3(name.toLowerCase(), args !== null && args !== void 0 ? args : {}, self);
30554
        }
30555
        const dispatcherArgs = getEventDispatcher(self).dispatch(name, args);
30556
        if (bubble !== false && self.parent) {
30557
          let parent = self.parent();
30558
          while (parent && !dispatcherArgs.isPropagationStopped()) {
30559
            parent.dispatch(name, dispatcherArgs, false);
30560
            parent = parent.parent ? parent.parent() : undefined;
30561
          }
30562
        }
30563
        return dispatcherArgs;
30564
      },
30565
      on(name, callback, prepend) {
30566
        return getEventDispatcher(this).on(name, callback, prepend);
30567
      },
30568
      off(name, callback) {
30569
        return getEventDispatcher(this).off(name, callback);
30570
      },
30571
      once(name, callback) {
30572
        return getEventDispatcher(this).once(name, callback);
30573
      },
30574
      hasEventListeners(name) {
30575
        return getEventDispatcher(this).has(name);
30576
      }
30577
    };
30578
 
30579
    const DOM$2 = DOMUtils.DOM;
30580
    let customEventRootDelegates;
30581
    const getEventTarget = (editor, eventName) => {
30582
      if (eventName === 'selectionchange') {
30583
        return editor.getDoc();
30584
      }
30585
      if (!editor.inline && /^(?:mouse|touch|click|contextmenu|drop|dragover|dragend)/.test(eventName)) {
30586
        return editor.getDoc().documentElement;
30587
      }
30588
      const eventRoot = getEventRoot(editor);
30589
      if (eventRoot) {
30590
        if (!editor.eventRoot) {
30591
          editor.eventRoot = DOM$2.select(eventRoot)[0];
30592
        }
30593
        return editor.eventRoot;
30594
      }
30595
      return editor.getBody();
30596
    };
1441 ariadna 30597
    const isListening = editor => !editor.hidden && !isDisabled(editor);
1 efrain 30598
    const fireEvent = (editor, eventName, e) => {
30599
      if (isListening(editor)) {
30600
        editor.dispatch(eventName, e);
1441 ariadna 30601
      } else if (isDisabled(editor)) {
30602
        processDisabledEvents(editor, e);
1 efrain 30603
      }
30604
    };
30605
    const bindEventDelegate = (editor, eventName) => {
30606
      if (!editor.delegates) {
30607
        editor.delegates = {};
30608
      }
30609
      if (editor.delegates[eventName] || editor.removed) {
30610
        return;
30611
      }
30612
      const eventRootElm = getEventTarget(editor, eventName);
30613
      if (getEventRoot(editor)) {
30614
        if (!customEventRootDelegates) {
30615
          customEventRootDelegates = {};
30616
          editor.editorManager.on('removeEditor', () => {
30617
            if (!editor.editorManager.activeEditor) {
30618
              if (customEventRootDelegates) {
30619
                each$d(customEventRootDelegates, (_value, name) => {
30620
                  editor.dom.unbind(getEventTarget(editor, name));
30621
                });
30622
                customEventRootDelegates = null;
30623
              }
30624
            }
30625
          });
30626
        }
30627
        if (customEventRootDelegates[eventName]) {
30628
          return;
30629
        }
30630
        const delegate = e => {
30631
          const target = e.target;
30632
          const editors = editor.editorManager.get();
30633
          let i = editors.length;
30634
          while (i--) {
30635
            const body = editors[i].getBody();
30636
            if (body === target || DOM$2.isChildOf(target, body)) {
30637
              fireEvent(editors[i], eventName, e);
30638
            }
30639
          }
30640
        };
30641
        customEventRootDelegates[eventName] = delegate;
30642
        DOM$2.bind(eventRootElm, eventName, delegate);
30643
      } else {
30644
        const delegate = e => {
30645
          fireEvent(editor, eventName, e);
30646
        };
30647
        DOM$2.bind(eventRootElm, eventName, delegate);
30648
        editor.delegates[eventName] = delegate;
30649
      }
30650
    };
30651
    const EditorObservable = {
30652
      ...Observable,
30653
      bindPendingEventDelegates() {
30654
        const self = this;
30655
        Tools.each(self._pendingNativeEvents, name => {
30656
          bindEventDelegate(self, name);
30657
        });
30658
      },
30659
      toggleNativeEvent(name, state) {
30660
        const self = this;
30661
        if (name === 'focus' || name === 'blur') {
30662
          return;
30663
        }
30664
        if (self.removed) {
30665
          return;
30666
        }
30667
        if (state) {
30668
          if (self.initialized) {
30669
            bindEventDelegate(self, name);
30670
          } else {
30671
            if (!self._pendingNativeEvents) {
30672
              self._pendingNativeEvents = [name];
30673
            } else {
30674
              self._pendingNativeEvents.push(name);
30675
            }
30676
          }
30677
        } else if (self.initialized && self.delegates) {
30678
          self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]);
30679
          delete self.delegates[name];
30680
        }
30681
      },
30682
      unbindAllNativeEvents() {
30683
        const self = this;
30684
        const body = self.getBody();
30685
        const dom = self.dom;
30686
        if (self.delegates) {
30687
          each$d(self.delegates, (value, name) => {
30688
            self.dom.unbind(getEventTarget(self, name), name, value);
30689
          });
30690
          delete self.delegates;
30691
        }
30692
        if (!self.inline && body && dom) {
30693
          body.onload = null;
30694
          dom.unbind(self.getWin());
30695
          dom.unbind(self.getDoc());
30696
        }
30697
        if (dom) {
30698
          dom.unbind(body);
30699
          dom.unbind(self.getContainer());
30700
        }
30701
      }
30702
    };
30703
 
30704
    const stringListProcessor = value => {
30705
      if (isString(value)) {
30706
        return {
30707
          value: value.split(/[ ,]/),
30708
          valid: true
30709
        };
30710
      } else if (isArrayOf(value, isString)) {
30711
        return {
30712
          value,
30713
          valid: true
30714
        };
30715
      } else {
30716
        return {
30717
          valid: false,
30718
          message: `The value must be a string[] or a comma/space separated string.`
30719
        };
30720
      }
30721
    };
30722
    const getBuiltInProcessor = type => {
30723
      const validator = (() => {
30724
        switch (type) {
30725
        case 'array':
30726
          return isArray$1;
30727
        case 'boolean':
30728
          return isBoolean;
30729
        case 'function':
30730
          return isFunction;
30731
        case 'number':
30732
          return isNumber;
30733
        case 'object':
30734
          return isObject;
30735
        case 'string':
30736
          return isString;
30737
        case 'string[]':
30738
          return stringListProcessor;
30739
        case 'object[]':
30740
          return val => isArrayOf(val, isObject);
30741
        case 'regexp':
30742
          return val => is$4(val, RegExp);
30743
        default:
30744
          return always;
30745
        }
30746
      })();
30747
      return value => processValue(value, validator, `The value must be a ${ type }.`);
30748
    };
30749
    const isBuiltInSpec = spec => isString(spec.processor);
30750
    const getErrorMessage = (message, result) => {
30751
      const additionalText = isEmpty$3(result.message) ? '' : `. ${ result.message }`;
30752
      return message + additionalText;
30753
    };
30754
    const isValidResult = result => result.valid;
30755
    const processValue = (value, processor, message = '') => {
30756
      const result = processor(value);
30757
      if (isBoolean(result)) {
30758
        return result ? {
30759
          value: value,
30760
          valid: true
30761
        } : {
30762
          valid: false,
30763
          message
30764
        };
30765
      } else {
30766
        return result;
30767
      }
30768
    };
30769
    const processDefaultValue = (name, defaultValue, processor) => {
30770
      if (!isUndefined(defaultValue)) {
30771
        const result = processValue(defaultValue, processor);
30772
        if (isValidResult(result)) {
30773
          return result.value;
30774
        } else {
30775
          console.error(getErrorMessage(`Invalid default value passed for the "${ name }" option`, result));
30776
        }
30777
      }
30778
      return undefined;
30779
    };
1441 ariadna 30780
    const create$5 = (editor, initialOptions, rawInitialOptions = initialOptions) => {
1 efrain 30781
      const registry = {};
30782
      const values = {};
30783
      const setValue = (name, value, processor) => {
30784
        const result = processValue(value, processor);
30785
        if (isValidResult(result)) {
30786
          values[name] = result.value;
30787
          return true;
30788
        } else {
30789
          console.warn(getErrorMessage(`Invalid value passed for the ${ name } option`, result));
30790
          return false;
30791
        }
30792
      };
30793
      const register = (name, spec) => {
30794
        const processor = isBuiltInSpec(spec) ? getBuiltInProcessor(spec.processor) : spec.processor;
30795
        const defaultValue = processDefaultValue(name, spec.default, processor);
30796
        registry[name] = {
30797
          ...spec,
30798
          default: defaultValue,
30799
          processor
30800
        };
30801
        const initValue = get$a(values, name).orThunk(() => get$a(initialOptions, name));
30802
        initValue.each(value => setValue(name, value, processor));
30803
      };
30804
      const isRegistered = name => has$2(registry, name);
30805
      const get = name => get$a(values, name).orThunk(() => get$a(registry, name).map(spec => spec.default)).getOrUndefined();
30806
      const set = (name, value) => {
30807
        if (!isRegistered(name)) {
30808
          console.warn(`"${ name }" is not a registered option. Ensure the option has been registered before setting a value.`);
30809
          return false;
30810
        } else {
30811
          const spec = registry[name];
30812
          if (spec.immutable) {
30813
            console.error(`"${ name }" is an immutable option and cannot be updated`);
30814
            return false;
30815
          } else {
30816
            return setValue(name, value, spec.processor);
30817
          }
30818
        }
30819
      };
30820
      const unset = name => {
30821
        const registered = isRegistered(name);
30822
        if (registered) {
30823
          delete values[name];
30824
        }
30825
        return registered;
30826
      };
30827
      const isSet = name => has$2(values, name);
1441 ariadna 30828
      const debug = () => {
30829
        try {
30830
          console.log(JSON.parse(JSON.stringify(rawInitialOptions, (_key, value) => {
30831
            if (isBoolean(value) || isNumber(value) || isString(value) || isNull(value) || isArray$1(value) || isPlainObject(value)) {
30832
              return value;
30833
            }
30834
            return Object.prototype.toString.call(value);
30835
          })));
30836
        } catch (error) {
30837
          console.error(error);
30838
        }
30839
      };
1 efrain 30840
      return {
30841
        register,
30842
        isRegistered,
30843
        get,
30844
        set,
30845
        unset,
1441 ariadna 30846
        isSet,
30847
        debug
1 efrain 30848
      };
30849
    };
30850
 
1441 ariadna 30851
    const setContentEditable = (elm, state) => {
30852
      elm.dom.contentEditable = state ? 'true' : 'false';
30853
    };
30854
    const toggleReadOnly = (editor, state) => {
30855
      const body = SugarElement.fromDom(editor.getBody());
30856
      if (state) {
30857
        editor.readonly = true;
30858
        if (editor.hasEditableRoot()) {
30859
          setContentEditable(body, true);
30860
        }
30861
        disableEditor(editor);
30862
      } else {
30863
        editor.readonly = false;
30864
        enableEditor(editor);
30865
      }
30866
    };
30867
    const isReadOnly = editor => editor.readonly;
30868
    const registerReadOnlyInputBlockers = editor => {
30869
      editor.on('beforeinput paste cut dragend dragover draggesture dragdrop drop drag', e => {
30870
        if (isReadOnly(editor)) {
30871
          e.preventDefault();
30872
        }
30873
      });
30874
      editor.on('BeforeExecCommand', e => {
30875
        if ((e.command === 'Undo' || e.command === 'Redo') && isReadOnly(editor)) {
30876
          e.preventDefault();
30877
        }
30878
      });
30879
      editor.on('input', e => {
30880
        if (!e.isComposing && isReadOnly(editor)) {
30881
          const undoLevel = editor.undoManager.add();
30882
          if (isNonNullable(undoLevel)) {
30883
            editor.undoManager.undo();
30884
          }
30885
        }
30886
      });
30887
      editor.on('compositionend', () => {
30888
        if (isReadOnly(editor)) {
30889
          const undoLevel = editor.undoManager.add();
30890
          if (isNonNullable(undoLevel)) {
30891
            editor.undoManager.undo();
30892
          }
30893
        }
30894
      });
30895
    };
30896
 
1 efrain 30897
    const defaultModes = [
30898
      'design',
30899
      'readonly'
30900
    ];
30901
    const switchToMode = (editor, activeMode, availableModes, mode) => {
30902
      const oldMode = availableModes[activeMode.get()];
30903
      const newMode = availableModes[mode];
30904
      try {
30905
        newMode.activate();
30906
      } catch (e) {
30907
        console.error(`problem while activating editor mode ${ mode }:`, e);
30908
        return;
30909
      }
30910
      oldMode.deactivate();
30911
      if (oldMode.editorReadOnly !== newMode.editorReadOnly) {
30912
        toggleReadOnly(editor, newMode.editorReadOnly);
30913
      }
30914
      activeMode.set(mode);
30915
      fireSwitchMode(editor, mode);
30916
    };
30917
    const setMode = (editor, availableModes, activeMode, mode) => {
1441 ariadna 30918
      if (mode === activeMode.get() || editor.initialized && isDisabled(editor)) {
1 efrain 30919
        return;
30920
      } else if (!has$2(availableModes, mode)) {
30921
        throw new Error(`Editor mode '${ mode }' is invalid`);
30922
      }
30923
      if (editor.initialized) {
30924
        switchToMode(editor, activeMode, availableModes, mode);
30925
      } else {
30926
        editor.on('init', () => switchToMode(editor, activeMode, availableModes, mode));
30927
      }
30928
    };
30929
    const registerMode = (availableModes, mode, api) => {
30930
      if (contains$2(defaultModes, mode)) {
30931
        throw new Error(`Cannot override default mode ${ mode }`);
30932
      }
30933
      return {
30934
        ...availableModes,
30935
        [mode]: {
30936
          ...api,
30937
          deactivate: () => {
30938
            try {
30939
              api.deactivate();
30940
            } catch (e) {
30941
              console.error(`problem while deactivating editor mode ${ mode }:`, e);
30942
            }
30943
          }
30944
        }
30945
      };
30946
    };
30947
 
30948
    const create$4 = editor => {
30949
      const activeMode = Cell('design');
30950
      const availableModes = Cell({
30951
        design: {
30952
          activate: noop,
30953
          deactivate: noop,
30954
          editorReadOnly: false
30955
        },
30956
        readonly: {
30957
          activate: noop,
30958
          deactivate: noop,
30959
          editorReadOnly: true
30960
        }
30961
      });
1441 ariadna 30962
      registerReadOnlyInputBlockers(editor);
30963
      registerEventsAndFilters$1(editor);
1 efrain 30964
      return {
30965
        isReadOnly: () => isReadOnly(editor),
30966
        set: mode => setMode(editor, availableModes.get(), activeMode, mode),
30967
        get: () => activeMode.get(),
30968
        register: (mode, api) => {
30969
          availableModes.set(registerMode(availableModes.get(), mode, api));
30970
        }
30971
      };
30972
    };
30973
 
30974
    const each$2 = Tools.each, explode = Tools.explode;
30975
    const keyCodeLookup = {
30976
      f1: 112,
30977
      f2: 113,
30978
      f3: 114,
30979
      f4: 115,
30980
      f5: 116,
30981
      f6: 117,
30982
      f7: 118,
30983
      f8: 119,
30984
      f9: 120,
30985
      f10: 121,
30986
      f11: 122,
30987
      f12: 123
30988
    };
30989
    const modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access');
30990
    const isModifier = key => key in modifierNames;
30991
    const parseShortcut = pattern => {
30992
      const shortcut = {};
30993
      const isMac = Env.os.isMacOS() || Env.os.isiOS();
30994
      each$2(explode(pattern.toLowerCase(), '+'), value => {
30995
        if (isModifier(value)) {
30996
          shortcut[value] = true;
30997
        } else {
30998
          if (/^[0-9]{2,}$/.test(value)) {
30999
            shortcut.keyCode = parseInt(value, 10);
31000
          } else {
31001
            shortcut.charCode = value.charCodeAt(0);
31002
            shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
31003
          }
31004
        }
31005
      });
31006
      const id = [shortcut.keyCode];
31007
      let key;
31008
      for (key in modifierNames) {
31009
        if (shortcut[key]) {
31010
          id.push(key);
31011
        } else {
31012
          shortcut[key] = false;
31013
        }
31014
      }
31015
      shortcut.id = id.join(',');
31016
      if (shortcut.access) {
31017
        shortcut.alt = true;
31018
        if (isMac) {
31019
          shortcut.ctrl = true;
31020
        } else {
31021
          shortcut.shift = true;
31022
        }
31023
      }
31024
      if (shortcut.meta) {
31025
        if (isMac) {
31026
          shortcut.meta = true;
31027
        } else {
31028
          shortcut.ctrl = true;
31029
          shortcut.meta = false;
31030
        }
31031
      }
31032
      return shortcut;
31033
    };
31034
    class Shortcuts {
31035
      constructor(editor) {
31036
        this.shortcuts = {};
31037
        this.pendingPatterns = [];
31038
        this.editor = editor;
31039
        const self = this;
31040
        editor.on('keyup keypress keydown', e => {
31041
          if ((self.hasModifier(e) || self.isFunctionKey(e)) && !e.isDefaultPrevented()) {
31042
            each$2(self.shortcuts, shortcut => {
31043
              if (self.matchShortcut(e, shortcut)) {
31044
                self.pendingPatterns = shortcut.subpatterns.slice(0);
31045
                if (e.type === 'keydown') {
31046
                  self.executeShortcutAction(shortcut);
31047
                }
31048
              }
31049
            });
31050
            if (self.matchShortcut(e, self.pendingPatterns[0])) {
31051
              if (self.pendingPatterns.length === 1) {
31052
                if (e.type === 'keydown') {
31053
                  self.executeShortcutAction(self.pendingPatterns[0]);
31054
                }
31055
              }
31056
              self.pendingPatterns.shift();
31057
            }
31058
          }
31059
        });
31060
      }
31061
      add(pattern, desc, cmdFunc, scope) {
31062
        const self = this;
31063
        const func = self.normalizeCommandFunc(cmdFunc);
31064
        each$2(explode(Tools.trim(pattern)), pattern => {
31065
          const shortcut = self.createShortcut(pattern, desc, func, scope);
31066
          self.shortcuts[shortcut.id] = shortcut;
31067
        });
31068
        return true;
31069
      }
31070
      remove(pattern) {
31071
        const shortcut = this.createShortcut(pattern);
31072
        if (this.shortcuts[shortcut.id]) {
31073
          delete this.shortcuts[shortcut.id];
31074
          return true;
31075
        }
31076
        return false;
31077
      }
31078
      normalizeCommandFunc(cmdFunc) {
31079
        const self = this;
31080
        const cmd = cmdFunc;
31081
        if (typeof cmd === 'string') {
31082
          return () => {
31083
            self.editor.execCommand(cmd, false, null);
31084
          };
31085
        } else if (Tools.isArray(cmd)) {
31086
          return () => {
31087
            self.editor.execCommand(cmd[0], cmd[1], cmd[2]);
31088
          };
31089
        } else {
31090
          return cmd;
31091
        }
31092
      }
31093
      createShortcut(pattern, desc, cmdFunc, scope) {
31094
        const shortcuts = Tools.map(explode(pattern, '>'), parseShortcut);
31095
        shortcuts[shortcuts.length - 1] = Tools.extend(shortcuts[shortcuts.length - 1], {
31096
          func: cmdFunc,
31097
          scope: scope || this.editor
31098
        });
31099
        return Tools.extend(shortcuts[0], {
31100
          desc: this.editor.translate(desc),
31101
          subpatterns: shortcuts.slice(1)
31102
        });
31103
      }
31104
      hasModifier(e) {
31105
        return e.altKey || e.ctrlKey || e.metaKey;
31106
      }
31107
      isFunctionKey(e) {
31108
        return e.type === 'keydown' && e.keyCode >= 112 && e.keyCode <= 123;
31109
      }
31110
      matchShortcut(e, shortcut) {
31111
        if (!shortcut) {
31112
          return false;
31113
        }
31114
        if (shortcut.ctrl !== e.ctrlKey || shortcut.meta !== e.metaKey) {
31115
          return false;
31116
        }
31117
        if (shortcut.alt !== e.altKey || shortcut.shift !== e.shiftKey) {
31118
          return false;
31119
        }
31120
        if (e.keyCode === shortcut.keyCode || e.charCode && e.charCode === shortcut.charCode) {
31121
          e.preventDefault();
31122
          return true;
31123
        }
31124
        return false;
31125
      }
31126
      executeShortcutAction(shortcut) {
31127
        return shortcut.func ? shortcut.func.call(shortcut.scope) : null;
31128
      }
31129
    }
31130
 
31131
    const create$3 = () => {
31132
      const buttons = {};
31133
      const menuItems = {};
31134
      const popups = {};
31135
      const icons = {};
31136
      const contextMenus = {};
31137
      const contextToolbars = {};
1441 ariadna 31138
      const contexts = {};
1 efrain 31139
      const sidebars = {};
31140
      const views = {};
31141
      const add = (collection, type) => (name, spec) => {
31142
        collection[name.toLowerCase()] = {
31143
          ...spec,
31144
          type
31145
        };
31146
      };
1441 ariadna 31147
      const addDefaulted = (collection, type) => (name, spec) => {
31148
        collection[name.toLowerCase()] = {
31149
          type,
31150
          ...spec
31151
        };
31152
      };
1 efrain 31153
      const addIcon = (name, svgData) => icons[name.toLowerCase()] = svgData;
1441 ariadna 31154
      const addContext = (name, pred) => contexts[name.toLowerCase()] = pred;
1 efrain 31155
      return {
31156
        addButton: add(buttons, 'button'),
31157
        addGroupToolbarButton: add(buttons, 'grouptoolbarbutton'),
31158
        addToggleButton: add(buttons, 'togglebutton'),
31159
        addMenuButton: add(buttons, 'menubutton'),
31160
        addSplitButton: add(buttons, 'splitbutton'),
31161
        addMenuItem: add(menuItems, 'menuitem'),
31162
        addNestedMenuItem: add(menuItems, 'nestedmenuitem'),
31163
        addToggleMenuItem: add(menuItems, 'togglemenuitem'),
31164
        addAutocompleter: add(popups, 'autocompleter'),
31165
        addContextMenu: add(contextMenus, 'contextmenu'),
31166
        addContextToolbar: add(contextToolbars, 'contexttoolbar'),
1441 ariadna 31167
        addContextForm: addDefaulted(contextToolbars, 'contextform'),
1 efrain 31168
        addSidebar: add(sidebars, 'sidebar'),
31169
        addView: add(views, 'views'),
31170
        addIcon,
1441 ariadna 31171
        addContext,
1 efrain 31172
        getAll: () => ({
31173
          buttons,
31174
          menuItems,
31175
          icons,
31176
          popups,
31177
          contextMenus,
31178
          contextToolbars,
31179
          sidebars,
1441 ariadna 31180
          views,
31181
          contexts
1 efrain 31182
        })
31183
      };
31184
    };
31185
 
31186
    const registry = () => {
31187
      const bridge = create$3();
31188
      return {
31189
        addAutocompleter: bridge.addAutocompleter,
31190
        addButton: bridge.addButton,
31191
        addContextForm: bridge.addContextForm,
31192
        addContextMenu: bridge.addContextMenu,
31193
        addContextToolbar: bridge.addContextToolbar,
31194
        addIcon: bridge.addIcon,
31195
        addMenuButton: bridge.addMenuButton,
31196
        addMenuItem: bridge.addMenuItem,
31197
        addNestedMenuItem: bridge.addNestedMenuItem,
31198
        addSidebar: bridge.addSidebar,
31199
        addSplitButton: bridge.addSplitButton,
31200
        addToggleButton: bridge.addToggleButton,
31201
        addGroupToolbarButton: bridge.addGroupToolbarButton,
31202
        addToggleMenuItem: bridge.addToggleMenuItem,
31203
        addView: bridge.addView,
1441 ariadna 31204
        addContext: bridge.addContext,
1 efrain 31205
        getAll: bridge.getAll
31206
      };
31207
    };
31208
 
31209
    const DOM$1 = DOMUtils.DOM;
31210
    const extend = Tools.extend, each$1 = Tools.each;
31211
    class Editor {
31212
      constructor(id, options, editorManager) {
31213
        this.plugins = {};
31214
        this.contentCSS = [];
31215
        this.contentStyles = [];
31216
        this.loadedCSS = {};
31217
        this.isNotDirty = false;
31218
        this.composing = false;
31219
        this.destroyed = false;
31220
        this.hasHiddenInput = false;
31221
        this.iframeElement = null;
31222
        this.initialized = false;
31223
        this.readonly = false;
31224
        this.removed = false;
31225
        this.startContent = '';
31226
        this._pendingNativeEvents = [];
31227
        this._skinLoaded = false;
31228
        this._editableRoot = true;
31229
        this.editorManager = editorManager;
31230
        this.documentBaseUrl = editorManager.documentBaseURL;
31231
        extend(this, EditorObservable);
31232
        const self = this;
31233
        this.id = id;
31234
        this.hidden = false;
31235
        const normalizedOptions = normalizeOptions(editorManager.defaultOptions, options);
1441 ariadna 31236
        this.options = create$5(self, normalizedOptions, options);
1 efrain 31237
        register$7(self);
31238
        const getOption = this.options.get;
31239
        if (getOption('deprecation_warnings')) {
31240
          logWarnings(options, normalizedOptions);
31241
        }
31242
        const suffix = getOption('suffix');
31243
        if (suffix) {
31244
          editorManager.suffix = suffix;
31245
        }
31246
        this.suffix = editorManager.suffix;
31247
        const baseUrl = getOption('base_url');
31248
        if (baseUrl) {
31249
          editorManager._setBaseUrl(baseUrl);
31250
        }
31251
        this.baseUri = editorManager.baseURI;
31252
        const referrerPolicy = getReferrerPolicy(self);
31253
        if (referrerPolicy) {
31254
          ScriptLoader.ScriptLoader._setReferrerPolicy(referrerPolicy);
31255
          DOMUtils.DOM.styleSheetLoader._setReferrerPolicy(referrerPolicy);
31256
        }
31257
        const contentCssCors = hasContentCssCors(self);
31258
        if (isNonNullable(contentCssCors)) {
31259
          DOMUtils.DOM.styleSheetLoader._setContentCssCors(contentCssCors);
31260
        }
31261
        AddOnManager.languageLoad = getOption('language_load');
31262
        AddOnManager.baseURL = editorManager.baseURL;
31263
        this.setDirty(false);
31264
        this.documentBaseURI = new URI(getDocumentBaseUrl(self), { base_uri: this.baseUri });
31265
        this.baseURI = this.baseUri;
31266
        this.inline = isInline$1(self);
31267
        this.hasVisual = isVisualAidsEnabled(self);
31268
        this.shortcuts = new Shortcuts(this);
31269
        this.editorCommands = new EditorCommands(this);
31270
        registerCommands(this);
31271
        const cacheSuffix = getOption('cache_suffix');
31272
        if (cacheSuffix) {
31273
          Env.cacheSuffix = cacheSuffix.replace(/^[\?\&]+/, '');
31274
        }
31275
        this.ui = {
31276
          registry: registry(),
31277
          styleSheetLoader: undefined,
31278
          show: noop,
31279
          hide: noop,
31280
          setEnabled: noop,
31281
          isEnabled: always
31282
        };
31283
        this.mode = create$4(self);
31284
        editorManager.dispatch('SetupEditor', { editor: this });
31285
        const setupCallback = getSetupCallback(self);
31286
        if (isFunction(setupCallback)) {
31287
          setupCallback.call(self, self);
31288
        }
31289
      }
31290
      render() {
31291
        render(this);
31292
      }
31293
      focus(skipFocus) {
31294
        this.execCommand('mceFocus', false, skipFocus);
31295
      }
31296
      hasFocus() {
31297
        return hasFocus(this);
31298
      }
31299
      translate(text) {
31300
        return I18n.translate(text);
31301
      }
31302
      getParam(name, defaultVal, type) {
31303
        const options = this.options;
31304
        if (!options.isRegistered(name)) {
31305
          if (isNonNullable(type)) {
31306
            options.register(name, {
31307
              processor: type,
31308
              default: defaultVal
31309
            });
31310
          } else {
31311
            options.register(name, {
31312
              processor: always,
31313
              default: defaultVal
31314
            });
31315
          }
31316
        }
31317
        return !options.isSet(name) && !isUndefined(defaultVal) ? defaultVal : options.get(name);
31318
      }
31319
      hasPlugin(name, loaded) {
31320
        const hasPlugin = contains$2(getPlugins(this), name);
31321
        if (hasPlugin) {
31322
          return loaded ? PluginManager.get(name) !== undefined : true;
31323
        } else {
31324
          return false;
31325
        }
31326
      }
31327
      nodeChanged(args) {
31328
        this._nodeChangeDispatcher.nodeChanged(args);
31329
      }
31330
      addCommand(name, callback, scope) {
31331
        this.editorCommands.addCommand(name, callback, scope);
31332
      }
31333
      addQueryStateHandler(name, callback, scope) {
31334
        this.editorCommands.addQueryStateHandler(name, callback, scope);
31335
      }
31336
      addQueryValueHandler(name, callback, scope) {
31337
        this.editorCommands.addQueryValueHandler(name, callback, scope);
31338
      }
31339
      addShortcut(pattern, desc, cmdFunc, scope) {
31340
        this.shortcuts.add(pattern, desc, cmdFunc, scope);
31341
      }
31342
      execCommand(cmd, ui, value, args) {
31343
        return this.editorCommands.execCommand(cmd, ui, value, args);
31344
      }
31345
      queryCommandState(cmd) {
31346
        return this.editorCommands.queryCommandState(cmd);
31347
      }
31348
      queryCommandValue(cmd) {
31349
        return this.editorCommands.queryCommandValue(cmd);
31350
      }
31351
      queryCommandSupported(cmd) {
31352
        return this.editorCommands.queryCommandSupported(cmd);
31353
      }
31354
      show() {
31355
        const self = this;
31356
        if (self.hidden) {
31357
          self.hidden = false;
31358
          if (self.inline) {
31359
            self.getBody().contentEditable = 'true';
31360
          } else {
31361
            DOM$1.show(self.getContainer());
31362
            DOM$1.hide(self.id);
31363
          }
31364
          self.load();
31365
          self.dispatch('show');
31366
        }
31367
      }
31368
      hide() {
31369
        const self = this;
31370
        if (!self.hidden) {
31371
          self.save();
31372
          if (self.inline) {
31373
            self.getBody().contentEditable = 'false';
31374
            if (self === self.editorManager.focusedEditor) {
31375
              self.editorManager.focusedEditor = null;
31376
            }
31377
          } else {
31378
            DOM$1.hide(self.getContainer());
31379
            DOM$1.setStyle(self.id, 'display', self.orgDisplay);
31380
          }
31381
          self.hidden = true;
31382
          self.dispatch('hide');
31383
        }
31384
      }
31385
      isHidden() {
31386
        return this.hidden;
31387
      }
31388
      setProgressState(state, time) {
31389
        this.dispatch('ProgressState', {
31390
          state,
31391
          time
31392
        });
31393
      }
31394
      load(args = {}) {
31395
        const self = this;
31396
        const elm = self.getElement();
31397
        if (self.removed) {
31398
          return '';
31399
        }
31400
        if (elm) {
31401
          const loadArgs = {
31402
            ...args,
31403
            load: true
31404
          };
31405
          const value = isTextareaOrInput(elm) ? elm.value : elm.innerHTML;
31406
          const html = self.setContent(value, loadArgs);
31407
          if (!loadArgs.no_events) {
31408
            self.dispatch('LoadContent', {
31409
              ...loadArgs,
31410
              element: elm
31411
            });
31412
          }
31413
          return html;
31414
        } else {
31415
          return '';
31416
        }
31417
      }
31418
      save(args = {}) {
31419
        const self = this;
31420
        let elm = self.getElement();
31421
        if (!elm || !self.initialized || self.removed) {
31422
          return '';
31423
        }
31424
        const getArgs = {
31425
          ...args,
31426
          save: true,
31427
          element: elm
31428
        };
31429
        let html = self.getContent(getArgs);
31430
        const saveArgs = {
31431
          ...getArgs,
31432
          content: html
31433
        };
31434
        if (!saveArgs.no_events) {
31435
          self.dispatch('SaveContent', saveArgs);
31436
        }
31437
        if (saveArgs.format === 'raw') {
31438
          self.dispatch('RawSaveContent', saveArgs);
31439
        }
31440
        html = saveArgs.content;
31441
        if (!isTextareaOrInput(elm)) {
31442
          if (args.is_removing || !self.inline) {
31443
            elm.innerHTML = html;
31444
          }
31445
          const form = DOM$1.getParent(self.id, 'form');
31446
          if (form) {
31447
            each$1(form.elements, elm => {
31448
              if (elm.name === self.id) {
31449
                elm.value = html;
31450
                return false;
31451
              } else {
31452
                return true;
31453
              }
31454
            });
31455
          }
31456
        } else {
31457
          elm.value = html;
31458
        }
31459
        saveArgs.element = getArgs.element = elm = null;
31460
        if (saveArgs.set_dirty !== false) {
31461
          self.setDirty(false);
31462
        }
31463
        return html;
31464
      }
31465
      setContent(content, args) {
31466
        return setContent(this, content, args);
31467
      }
31468
      getContent(args) {
31469
        return getContent(this, args);
31470
      }
31471
      insertContent(content, args) {
31472
        if (args) {
31473
          content = extend({ content }, args);
31474
        }
31475
        this.execCommand('mceInsertContent', false, content);
31476
      }
31477
      resetContent(initialContent) {
31478
        if (initialContent === undefined) {
31479
          setContent(this, this.startContent, { format: 'raw' });
31480
        } else {
31481
          setContent(this, initialContent);
31482
        }
31483
        this.undoManager.reset();
31484
        this.setDirty(false);
31485
        this.nodeChanged();
31486
      }
31487
      isDirty() {
31488
        return !this.isNotDirty;
31489
      }
31490
      setDirty(state) {
31491
        const oldState = !this.isNotDirty;
31492
        this.isNotDirty = !state;
31493
        if (state && state !== oldState) {
31494
          this.dispatch('dirty');
31495
        }
31496
      }
31497
      getContainer() {
31498
        const self = this;
31499
        if (!self.container) {
31500
          self.container = self.editorContainer || DOM$1.get(self.id + '_parent');
31501
        }
31502
        return self.container;
31503
      }
31504
      getContentAreaContainer() {
31505
        return this.contentAreaContainer;
31506
      }
31507
      getElement() {
31508
        if (!this.targetElm) {
31509
          this.targetElm = DOM$1.get(this.id);
31510
        }
31511
        return this.targetElm;
31512
      }
31513
      getWin() {
31514
        const self = this;
31515
        if (!self.contentWindow) {
31516
          const elm = self.iframeElement;
31517
          if (elm) {
31518
            self.contentWindow = elm.contentWindow;
31519
          }
31520
        }
31521
        return self.contentWindow;
31522
      }
31523
      getDoc() {
31524
        const self = this;
31525
        if (!self.contentDocument) {
31526
          const win = self.getWin();
31527
          if (win) {
31528
            self.contentDocument = win.document;
31529
          }
31530
        }
31531
        return self.contentDocument;
31532
      }
31533
      getBody() {
31534
        var _a, _b;
31535
        const doc = this.getDoc();
31536
        return (_b = (_a = this.bodyElement) !== null && _a !== void 0 ? _a : doc === null || doc === void 0 ? void 0 : doc.body) !== null && _b !== void 0 ? _b : null;
31537
      }
31538
      convertURL(url, name, elm) {
31539
        const self = this, getOption = self.options.get;
31540
        const urlConverterCallback = getUrlConverterCallback(self);
31541
        if (isFunction(urlConverterCallback)) {
31542
          return urlConverterCallback.call(self, url, elm, true, name);
31543
        }
31544
        if (!getOption('convert_urls') || elm === 'link' || isObject(elm) && elm.nodeName === 'LINK' || url.indexOf('file:') === 0 || url.length === 0) {
31545
          return url;
31546
        }
31547
        const urlObject = new URI(url);
31548
        if (urlObject.protocol !== 'http' && urlObject.protocol !== 'https' && urlObject.protocol !== '') {
31549
          return url;
31550
        }
31551
        if (getOption('relative_urls')) {
31552
          return self.documentBaseURI.toRelative(url);
31553
        }
31554
        url = self.documentBaseURI.toAbsolute(url, getOption('remove_script_host'));
31555
        return url;
31556
      }
31557
      addVisual(elm) {
31558
        addVisual(this, elm);
31559
      }
31560
      setEditableRoot(state) {
31561
        setEditableRoot(this, state);
31562
      }
31563
      hasEditableRoot() {
31564
        return hasEditableRoot(this);
31565
      }
31566
      remove() {
31567
        remove$1(this);
31568
      }
31569
      destroy(automatic) {
31570
        destroy(this, automatic);
31571
      }
31572
      uploadImages() {
31573
        return this.editorUpload.uploadImages();
31574
      }
31575
      _scanForImages() {
31576
        return this.editorUpload.scanForImages();
31577
      }
31578
    }
31579
 
31580
    const DOM = DOMUtils.DOM;
31581
    const each = Tools.each;
31582
    let boundGlobalEvents = false;
31583
    let beforeUnloadDelegate;
31584
    let editors = [];
31585
    const globalEventDelegate = e => {
31586
      const type = e.type;
31587
      each(EditorManager.get(), editor => {
31588
        switch (type) {
31589
        case 'scroll':
31590
          editor.dispatch('ScrollWindow', e);
31591
          break;
31592
        case 'resize':
31593
          editor.dispatch('ResizeWindow', e);
31594
          break;
31595
        }
31596
      });
31597
    };
31598
    const toggleGlobalEvents = state => {
31599
      if (state !== boundGlobalEvents) {
31600
        const DOM = DOMUtils.DOM;
31601
        if (state) {
31602
          DOM.bind(window, 'resize', globalEventDelegate);
31603
          DOM.bind(window, 'scroll', globalEventDelegate);
31604
        } else {
31605
          DOM.unbind(window, 'resize', globalEventDelegate);
31606
          DOM.unbind(window, 'scroll', globalEventDelegate);
31607
        }
31608
        boundGlobalEvents = state;
31609
      }
31610
    };
31611
    const removeEditorFromList = targetEditor => {
31612
      const oldEditors = editors;
31613
      editors = filter$5(editors, editor => {
31614
        return targetEditor !== editor;
31615
      });
31616
      if (EditorManager.activeEditor === targetEditor) {
31617
        EditorManager.activeEditor = editors.length > 0 ? editors[0] : null;
31618
      }
31619
      if (EditorManager.focusedEditor === targetEditor) {
31620
        EditorManager.focusedEditor = null;
31621
      }
31622
      return oldEditors.length !== editors.length;
31623
    };
31624
    const purgeDestroyedEditor = editor => {
31625
      if (editor && editor.initialized && !(editor.getContainer() || editor.getBody()).parentNode) {
31626
        removeEditorFromList(editor);
31627
        editor.unbindAllNativeEvents();
31628
        editor.destroy(true);
31629
        editor.removed = true;
31630
      }
31631
    };
31632
    const isQuirksMode = document.compatMode !== 'CSS1Compat';
31633
    const EditorManager = {
31634
      ...Observable,
31635
      baseURI: null,
31636
      baseURL: null,
31637
      defaultOptions: {},
31638
      documentBaseURL: null,
31639
      suffix: null,
1441 ariadna 31640
      majorVersion: '7',
31641
      minorVersion: '7.1',
31642
      releaseDate: '2025-03-05',
1 efrain 31643
      i18n: I18n,
31644
      activeEditor: null,
31645
      focusedEditor: null,
31646
      setup() {
31647
        const self = this;
31648
        let baseURL = '';
31649
        let suffix = '';
31650
        let documentBaseURL = URI.getDocumentBaseUrl(document.location);
31651
        if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) {
31652
          documentBaseURL = documentBaseURL.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
31653
          if (!/[\/\\]$/.test(documentBaseURL)) {
31654
            documentBaseURL += '/';
31655
          }
31656
        }
31657
        const preInit = window.tinymce || window.tinyMCEPreInit;
31658
        if (preInit) {
31659
          baseURL = preInit.base || preInit.baseURL;
31660
          suffix = preInit.suffix;
31661
        } else {
31662
          const scripts = document.getElementsByTagName('script');
31663
          for (let i = 0; i < scripts.length; i++) {
31664
            const src = scripts[i].src || '';
31665
            if (src === '') {
31666
              continue;
31667
            }
31668
            const srcScript = src.substring(src.lastIndexOf('/'));
31669
            if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
31670
              if (srcScript.indexOf('.min') !== -1) {
31671
                suffix = '.min';
31672
              }
31673
              baseURL = src.substring(0, src.lastIndexOf('/'));
31674
              break;
31675
            }
31676
          }
31677
          if (!baseURL && document.currentScript) {
31678
            const src = document.currentScript.src;
31679
            if (src.indexOf('.min') !== -1) {
31680
              suffix = '.min';
31681
            }
31682
            baseURL = src.substring(0, src.lastIndexOf('/'));
31683
          }
31684
        }
31685
        self.baseURL = new URI(documentBaseURL).toAbsolute(baseURL);
31686
        self.documentBaseURL = documentBaseURL;
31687
        self.baseURI = new URI(self.baseURL);
31688
        self.suffix = suffix;
31689
        setup$w(self);
31690
      },
31691
      overrideDefaults(defaultOptions) {
31692
        const baseUrl = defaultOptions.base_url;
31693
        if (baseUrl) {
31694
          this._setBaseUrl(baseUrl);
31695
        }
31696
        const suffix = defaultOptions.suffix;
31697
        if (suffix) {
31698
          this.suffix = suffix;
31699
        }
31700
        this.defaultOptions = defaultOptions;
31701
        const pluginBaseUrls = defaultOptions.plugin_base_urls;
31702
        if (pluginBaseUrls !== undefined) {
31703
          each$d(pluginBaseUrls, (pluginBaseUrl, pluginName) => {
31704
            AddOnManager.PluginManager.urls[pluginName] = pluginBaseUrl;
31705
          });
31706
        }
31707
      },
31708
      init(options) {
31709
        const self = this;
31710
        let result;
31711
        const invalidInlineTargets = Tools.makeMap('area base basefont br col frame hr img input isindex link meta param embed source wbr track ' + 'colgroup option table tbody tfoot thead tr th td script noscript style textarea video audio iframe object menu', ' ');
31712
        const isInvalidInlineTarget = (options, elm) => options.inline && elm.tagName.toLowerCase() in invalidInlineTargets;
31713
        const createId = elm => {
31714
          let id = elm.id;
31715
          if (!id) {
31716
            id = get$a(elm, 'name').filter(name => !DOM.get(name)).getOrThunk(DOM.uniqueId);
31717
            elm.setAttribute('id', id);
31718
          }
31719
          return id;
31720
        };
31721
        const execCallback = name => {
31722
          const callback = options[name];
31723
          if (!callback) {
31724
            return;
31725
          }
31726
          return callback.apply(self, []);
31727
        };
31728
        const findTargets = options => {
31729
          if (Env.browser.isIE() || Env.browser.isEdge()) {
1441 ariadna 31730
            initError('TinyMCE does not support the browser you are using. For a list of supported' + ' browsers please see: https://www.tiny.cloud/docs/tinymce/7/support/#supportedwebbrowsers');
1 efrain 31731
            return [];
31732
          } else if (isQuirksMode) {
31733
            initError('Failed to initialize the editor as the document is not in standards mode. ' + 'TinyMCE requires standards mode.');
31734
            return [];
31735
          } else if (isString(options.selector)) {
31736
            return DOM.select(options.selector);
31737
          } else if (isNonNullable(options.target)) {
31738
            return [options.target];
31739
          } else {
31740
            return [];
31741
          }
31742
        };
31743
        let provideResults = editors => {
31744
          result = editors;
31745
        };
31746
        const initEditors = () => {
31747
          let initCount = 0;
31748
          const editors = [];
31749
          let targets;
31750
          const createEditor = (id, options, targetElm) => {
31751
            const editor = new Editor(id, options, self);
31752
            editors.push(editor);
31753
            editor.on('init', () => {
31754
              if (++initCount === targets.length) {
31755
                provideResults(editors);
31756
              }
31757
            });
31758
            editor.targetElm = editor.targetElm || targetElm;
31759
            editor.render();
31760
          };
31761
          DOM.unbind(window, 'ready', initEditors);
31762
          execCallback('onpageload');
31763
          targets = unique$1(findTargets(options));
31764
          Tools.each(targets, elm => {
31765
            purgeDestroyedEditor(self.get(elm.id));
31766
          });
31767
          targets = Tools.grep(targets, elm => {
31768
            return !self.get(elm.id);
31769
          });
31770
          if (targets.length === 0) {
31771
            provideResults([]);
31772
          } else {
31773
            each(targets, elm => {
31774
              if (isInvalidInlineTarget(options, elm)) {
31775
                initError('Could not initialize inline editor on invalid inline target element', elm);
31776
              } else {
31777
                createEditor(createId(elm), options, elm);
31778
              }
31779
            });
31780
          }
31781
        };
31782
        DOM.bind(window, 'ready', initEditors);
31783
        return new Promise(resolve => {
31784
          if (result) {
31785
            resolve(result);
31786
          } else {
31787
            provideResults = editors => {
31788
              resolve(editors);
31789
            };
31790
          }
31791
        });
31792
      },
31793
      get(id) {
31794
        if (arguments.length === 0) {
31795
          return editors.slice(0);
31796
        } else if (isString(id)) {
31797
          return find$2(editors, editor => {
31798
            return editor.id === id;
31799
          }).getOr(null);
31800
        } else if (isNumber(id)) {
31801
          return editors[id] ? editors[id] : null;
31802
        } else {
31803
          return null;
31804
        }
31805
      },
31806
      add(editor) {
31807
        const self = this;
31808
        const existingEditor = self.get(editor.id);
31809
        if (existingEditor === editor) {
31810
          return editor;
31811
        }
31812
        if (existingEditor === null) {
31813
          editors.push(editor);
31814
        }
31815
        toggleGlobalEvents(true);
31816
        self.activeEditor = editor;
31817
        self.dispatch('AddEditor', { editor });
31818
        if (!beforeUnloadDelegate) {
31819
          beforeUnloadDelegate = e => {
31820
            const event = self.dispatch('BeforeUnload');
31821
            if (event.returnValue) {
31822
              e.preventDefault();
31823
              e.returnValue = event.returnValue;
31824
              return event.returnValue;
31825
            }
31826
          };
31827
          window.addEventListener('beforeunload', beforeUnloadDelegate);
31828
        }
31829
        return editor;
31830
      },
31831
      createEditor(id, options) {
31832
        return this.add(new Editor(id, options, this));
31833
      },
31834
      remove(selector) {
31835
        const self = this;
31836
        let editor;
31837
        if (!selector) {
31838
          for (let i = editors.length - 1; i >= 0; i--) {
31839
            self.remove(editors[i]);
31840
          }
31841
          return;
31842
        }
31843
        if (isString(selector)) {
31844
          each(DOM.select(selector), elm => {
31845
            editor = self.get(elm.id);
31846
            if (editor) {
31847
              self.remove(editor);
31848
            }
31849
          });
31850
          return;
31851
        }
31852
        editor = selector;
31853
        if (isNull(self.get(editor.id))) {
31854
          return null;
31855
        }
31856
        if (removeEditorFromList(editor)) {
31857
          self.dispatch('RemoveEditor', { editor });
31858
        }
31859
        if (editors.length === 0) {
31860
          window.removeEventListener('beforeunload', beforeUnloadDelegate);
31861
        }
31862
        editor.remove();
31863
        toggleGlobalEvents(editors.length > 0);
31864
        return editor;
31865
      },
31866
      execCommand(cmd, ui, value) {
31867
        var _a;
31868
        const self = this;
31869
        const editorId = isObject(value) ? (_a = value.id) !== null && _a !== void 0 ? _a : value.index : value;
31870
        switch (cmd) {
31871
        case 'mceAddEditor': {
31872
            if (!self.get(editorId)) {
31873
              const editorOptions = value.options;
31874
              new Editor(editorId, editorOptions, self).render();
31875
            }
31876
            return true;
31877
          }
31878
        case 'mceRemoveEditor': {
31879
            const editor = self.get(editorId);
31880
            if (editor) {
31881
              editor.remove();
31882
            }
31883
            return true;
31884
          }
31885
        case 'mceToggleEditor': {
31886
            const editor = self.get(editorId);
31887
            if (!editor) {
31888
              self.execCommand('mceAddEditor', false, value);
31889
              return true;
31890
            }
31891
            if (editor.isHidden()) {
31892
              editor.show();
31893
            } else {
31894
              editor.hide();
31895
            }
31896
            return true;
31897
          }
31898
        }
31899
        if (self.activeEditor) {
31900
          return self.activeEditor.execCommand(cmd, ui, value);
31901
        }
31902
        return false;
31903
      },
31904
      triggerSave: () => {
31905
        each(editors, editor => {
31906
          editor.save();
31907
        });
31908
      },
31909
      addI18n: (code, items) => {
31910
        I18n.add(code, items);
31911
      },
31912
      translate: text => {
31913
        return I18n.translate(text);
31914
      },
31915
      setActive(editor) {
31916
        const activeEditor = this.activeEditor;
31917
        if (this.activeEditor !== editor) {
31918
          if (activeEditor) {
31919
            activeEditor.dispatch('deactivate', { relatedTarget: editor });
31920
          }
31921
          editor.dispatch('activate', { relatedTarget: activeEditor });
31922
        }
31923
        this.activeEditor = editor;
31924
      },
31925
      _setBaseUrl(baseUrl) {
31926
        this.baseURL = new URI(this.documentBaseURL).toAbsolute(baseUrl.replace(/\/+$/, ''));
31927
        this.baseURI = new URI(this.baseURL);
31928
      }
31929
    };
31930
    EditorManager.setup();
31931
 
31932
    const setup = () => {
31933
      const dataValue = value$2();
31934
      const FakeClipboardItem = items => ({
31935
        items,
31936
        types: keys(items),
31937
        getType: type => get$a(items, type).getOrUndefined()
31938
      });
31939
      const write = data => {
31940
        dataValue.set(data);
31941
      };
31942
      const read = () => dataValue.get().getOrUndefined();
31943
      const clear = dataValue.clear;
31944
      return {
31945
        FakeClipboardItem,
31946
        write,
31947
        read,
31948
        clear
31949
      };
31950
    };
31951
    const FakeClipboard = setup();
31952
 
31953
    const min = Math.min, max = Math.max, round = Math.round;
31954
    const relativePosition = (rect, targetRect, rel) => {
31955
      let x = targetRect.x;
31956
      let y = targetRect.y;
31957
      const w = rect.w;
31958
      const h = rect.h;
31959
      const targetW = targetRect.w;
31960
      const targetH = targetRect.h;
31961
      const relChars = (rel || '').split('');
31962
      if (relChars[0] === 'b') {
31963
        y += targetH;
31964
      }
31965
      if (relChars[1] === 'r') {
31966
        x += targetW;
31967
      }
31968
      if (relChars[0] === 'c') {
31969
        y += round(targetH / 2);
31970
      }
31971
      if (relChars[1] === 'c') {
31972
        x += round(targetW / 2);
31973
      }
31974
      if (relChars[3] === 'b') {
31975
        y -= h;
31976
      }
31977
      if (relChars[4] === 'r') {
31978
        x -= w;
31979
      }
31980
      if (relChars[3] === 'c') {
31981
        y -= round(h / 2);
31982
      }
31983
      if (relChars[4] === 'c') {
31984
        x -= round(w / 2);
31985
      }
31986
      return create$2(x, y, w, h);
31987
    };
31988
    const findBestRelativePosition = (rect, targetRect, constrainRect, rels) => {
31989
      for (let i = 0; i < rels.length; i++) {
31990
        const pos = relativePosition(rect, targetRect, rels[i]);
31991
        if (pos.x >= constrainRect.x && pos.x + pos.w <= constrainRect.w + constrainRect.x && pos.y >= constrainRect.y && pos.y + pos.h <= constrainRect.h + constrainRect.y) {
31992
          return rels[i];
31993
        }
31994
      }
31995
      return null;
31996
    };
31997
    const inflate = (rect, w, h) => {
31998
      return create$2(rect.x - w, rect.y - h, rect.w + w * 2, rect.h + h * 2);
31999
    };
32000
    const intersect = (rect, cropRect) => {
32001
      const x1 = max(rect.x, cropRect.x);
32002
      const y1 = max(rect.y, cropRect.y);
32003
      const x2 = min(rect.x + rect.w, cropRect.x + cropRect.w);
32004
      const y2 = min(rect.y + rect.h, cropRect.y + cropRect.h);
32005
      if (x2 - x1 < 0 || y2 - y1 < 0) {
32006
        return null;
32007
      }
32008
      return create$2(x1, y1, x2 - x1, y2 - y1);
32009
    };
32010
    const clamp = (rect, clampRect, fixedSize) => {
32011
      let x1 = rect.x;
32012
      let y1 = rect.y;
32013
      let x2 = rect.x + rect.w;
32014
      let y2 = rect.y + rect.h;
32015
      const cx2 = clampRect.x + clampRect.w;
32016
      const cy2 = clampRect.y + clampRect.h;
32017
      const underflowX1 = max(0, clampRect.x - x1);
32018
      const underflowY1 = max(0, clampRect.y - y1);
32019
      const overflowX2 = max(0, x2 - cx2);
32020
      const overflowY2 = max(0, y2 - cy2);
32021
      x1 += underflowX1;
32022
      y1 += underflowY1;
32023
      if (fixedSize) {
32024
        x2 += underflowX1;
32025
        y2 += underflowY1;
32026
        x1 -= overflowX2;
32027
        y1 -= overflowY2;
32028
      }
32029
      x2 -= overflowX2;
32030
      y2 -= overflowY2;
32031
      return create$2(x1, y1, x2 - x1, y2 - y1);
32032
    };
32033
    const create$2 = (x, y, w, h) => {
32034
      return {
32035
        x,
32036
        y,
32037
        w,
32038
        h
32039
      };
32040
    };
32041
    const fromClientRect = clientRect => {
32042
      return create$2(clientRect.left, clientRect.top, clientRect.width, clientRect.height);
32043
    };
32044
    const Rect = {
32045
      inflate,
32046
      relativePosition,
32047
      findBestRelativePosition,
32048
      intersect,
32049
      clamp,
32050
      create: create$2,
32051
      fromClientRect
32052
    };
32053
 
32054
    const awaiter = (resolveCb, rejectCb, timeout = 1000) => {
32055
      let done = false;
32056
      let timer = null;
32057
      const complete = completer => (...args) => {
32058
        if (!done) {
32059
          done = true;
32060
          if (timer !== null) {
32061
            clearTimeout(timer);
32062
            timer = null;
32063
          }
32064
          completer.apply(null, args);
32065
        }
32066
      };
32067
      const resolve = complete(resolveCb);
32068
      const reject = complete(rejectCb);
32069
      const start = (...args) => {
32070
        if (!done && timer === null) {
32071
          timer = setTimeout(() => reject.apply(null, args), timeout);
32072
        }
32073
      };
32074
      return {
32075
        start,
32076
        resolve,
32077
        reject
32078
      };
32079
    };
32080
    const create$1 = () => {
32081
      const tasks = {};
32082
      const resultFns = {};
32083
      const resources = {};
32084
      const load = (id, url) => {
32085
        const loadErrMsg = `Script at URL "${ url }" failed to load`;
32086
        const runErrMsg = `Script at URL "${ url }" did not call \`tinymce.Resource.add('${ id }', data)\` within 1 second`;
32087
        if (tasks[id] !== undefined) {
32088
          return tasks[id];
32089
        } else {
32090
          const task = new Promise((resolve, reject) => {
32091
            const waiter = awaiter(resolve, reject);
32092
            resultFns[id] = waiter.resolve;
32093
            ScriptLoader.ScriptLoader.loadScript(url).then(() => waiter.start(runErrMsg), () => waiter.reject(loadErrMsg));
32094
          });
32095
          tasks[id] = task;
32096
          return task;
32097
        }
32098
      };
32099
      const add = (id, data) => {
32100
        if (resultFns[id] !== undefined) {
32101
          resultFns[id](data);
32102
          delete resultFns[id];
32103
        }
32104
        tasks[id] = Promise.resolve(data);
32105
        resources[id] = data;
32106
      };
32107
      const has = id => {
32108
        return id in resources;
32109
      };
32110
      const unload = id => {
32111
        delete tasks[id];
1441 ariadna 32112
        delete resources[id];
1 efrain 32113
      };
32114
      const get = id => resources[id];
32115
      return {
32116
        load,
32117
        add,
32118
        has,
32119
        get,
32120
        unload
32121
      };
32122
    };
32123
    const Resource = create$1();
32124
 
32125
    const create = () => (() => {
32126
      let data = {};
32127
      let keys = [];
32128
      const storage = {
32129
        getItem: key => {
32130
          const item = data[key];
32131
          return item ? item : null;
32132
        },
32133
        setItem: (key, value) => {
32134
          keys.push(key);
32135
          data[key] = String(value);
32136
        },
32137
        key: index => {
32138
          return keys[index];
32139
        },
32140
        removeItem: key => {
32141
          keys = keys.filter(k => k === key);
32142
          delete data[key];
32143
        },
32144
        clear: () => {
32145
          keys = [];
32146
          data = {};
32147
        },
32148
        length: 0
32149
      };
32150
      Object.defineProperty(storage, 'length', {
32151
        get: () => keys.length,
32152
        configurable: false,
32153
        enumerable: false
32154
      });
32155
      return storage;
32156
    })();
32157
 
32158
    let localStorage;
32159
    try {
32160
      const test = '__storage_test__';
32161
      localStorage = window.localStorage;
32162
      localStorage.setItem(test, test);
32163
      localStorage.removeItem(test);
1441 ariadna 32164
    } catch (_a) {
1 efrain 32165
      localStorage = create();
32166
    }
32167
    var LocalStorage = localStorage;
32168
 
32169
    const publicApi = {
32170
      geom: { Rect },
32171
      util: {
32172
        Delay,
32173
        Tools,
32174
        VK,
32175
        URI,
32176
        EventDispatcher,
32177
        Observable,
32178
        I18n,
32179
        LocalStorage,
32180
        ImageUploader
32181
      },
32182
      dom: {
32183
        EventUtils,
32184
        TreeWalker: DomTreeWalker,
32185
        TextSeeker,
32186
        DOMUtils,
32187
        ScriptLoader,
32188
        RangeUtils,
32189
        Serializer: DomSerializer,
32190
        StyleSheetLoader,
32191
        ControlSelection,
32192
        BookmarkManager,
32193
        Selection: EditorSelection,
32194
        Event: EventUtils.Event
32195
      },
32196
      html: {
32197
        Styles,
32198
        Entities,
32199
        Node: AstNode,
32200
        Schema,
32201
        DomParser,
32202
        Writer,
32203
        Serializer: HtmlSerializer
32204
      },
32205
      Env,
32206
      AddOnManager,
32207
      Annotator,
32208
      Formatter,
32209
      UndoManager,
32210
      EditorCommands,
32211
      WindowManager,
32212
      NotificationManager,
32213
      EditorObservable,
32214
      Shortcuts,
32215
      Editor,
32216
      FocusManager,
32217
      EditorManager,
32218
      DOM: DOMUtils.DOM,
32219
      ScriptLoader: ScriptLoader.ScriptLoader,
32220
      PluginManager,
32221
      ThemeManager,
32222
      ModelManager,
32223
      IconManager,
32224
      Resource,
32225
      FakeClipboard,
32226
      trim: Tools.trim,
32227
      isArray: Tools.isArray,
32228
      is: Tools.is,
32229
      toArray: Tools.toArray,
32230
      makeMap: Tools.makeMap,
32231
      each: Tools.each,
32232
      map: Tools.map,
32233
      grep: Tools.grep,
32234
      inArray: Tools.inArray,
32235
      extend: Tools.extend,
32236
      walk: Tools.walk,
32237
      resolve: Tools.resolve,
32238
      explode: Tools.explode,
32239
      _addCacheSuffix: Tools._addCacheSuffix
32240
    };
32241
    const tinymce$1 = Tools.extend(EditorManager, publicApi);
32242
 
32243
    const exportToModuleLoaders = tinymce => {
32244
      if (typeof module === 'object') {
32245
        try {
32246
          module.exports = tinymce;
1441 ariadna 32247
        } catch (_a) {
1 efrain 32248
        }
32249
      }
32250
    };
32251
    const exportToWindowGlobal = tinymce => {
32252
      window.tinymce = tinymce;
32253
      window.tinyMCE = tinymce;
32254
    };
32255
    exportToWindowGlobal(tinymce$1);
32256
    exportToModuleLoaders(tinymce$1);
32257
 
32258
})();