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
    const getPrototypeOf$2 = Object.getPrototypeOf;
9
    const hasProto = (v, constructor, predicate) => {
10
      var _a;
11
      if (predicate(v, constructor.prototype)) {
12
        return true;
13
      } else {
14
        return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
15
      }
16
    };
17
    const typeOf = x => {
18
      const t = typeof x;
19
      if (x === null) {
20
        return 'null';
21
      } else if (t === 'object' && Array.isArray(x)) {
22
        return 'array';
23
      } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
24
        return 'string';
25
      } else {
26
        return t;
27
      }
28
    };
29
    const isType$1 = type => value => typeOf(value) === type;
30
    const isSimpleType = type => value => typeof value === type;
31
    const eq$1 = t => a => t === a;
32
    const is$2 = (value, constructor) => isObject(value) && hasProto(value, constructor, (o, proto) => getPrototypeOf$2(o) === proto);
33
    const isString = isType$1('string');
34
    const isObject = isType$1('object');
35
    const isPlainObject = value => is$2(value, Object);
36
    const isArray = isType$1('array');
37
    const isNull = eq$1(null);
38
    const isBoolean = isSimpleType('boolean');
39
    const isUndefined = eq$1(undefined);
40
    const isNullable = a => a === null || a === undefined;
41
    const isNonNullable = a => !isNullable(a);
42
    const isFunction = isSimpleType('function');
43
    const isNumber = isSimpleType('number');
44
    const isArrayOf = (value, pred) => {
45
      if (isArray(value)) {
46
        for (let i = 0, len = value.length; i < len; ++i) {
47
          if (!pred(value[i])) {
48
            return false;
49
          }
50
        }
51
        return true;
52
      }
53
      return false;
54
    };
55
 
56
    const noop = () => {
57
    };
58
    const noarg = f => () => f();
59
    const compose = (fa, fb) => {
60
      return (...args) => {
61
        return fa(fb.apply(null, args));
62
      };
63
    };
64
    const compose1 = (fbc, fab) => a => fbc(fab(a));
65
    const constant$1 = value => {
66
      return () => {
67
        return value;
68
      };
69
    };
70
    const identity = x => {
71
      return x;
72
    };
73
    const tripleEquals = (a, b) => {
74
      return a === b;
75
    };
76
    function curry(fn, ...initialArgs) {
77
      return (...restArgs) => {
78
        const all = initialArgs.concat(restArgs);
79
        return fn.apply(null, all);
80
      };
81
    }
82
    const not = f => t => !f(t);
83
    const die = msg => {
84
      return () => {
85
        throw new Error(msg);
86
      };
87
    };
88
    const apply$1 = f => {
89
      return f();
90
    };
91
    const never = constant$1(false);
92
    const always = constant$1(true);
93
 
94
    class Optional {
95
      constructor(tag, value) {
96
        this.tag = tag;
97
        this.value = value;
98
      }
99
      static some(value) {
100
        return new Optional(true, value);
101
      }
102
      static none() {
103
        return Optional.singletonNone;
104
      }
105
      fold(onNone, onSome) {
106
        if (this.tag) {
107
          return onSome(this.value);
108
        } else {
109
          return onNone();
110
        }
111
      }
112
      isSome() {
113
        return this.tag;
114
      }
115
      isNone() {
116
        return !this.tag;
117
      }
118
      map(mapper) {
119
        if (this.tag) {
120
          return Optional.some(mapper(this.value));
121
        } else {
122
          return Optional.none();
123
        }
124
      }
125
      bind(binder) {
126
        if (this.tag) {
127
          return binder(this.value);
128
        } else {
129
          return Optional.none();
130
        }
131
      }
132
      exists(predicate) {
133
        return this.tag && predicate(this.value);
134
      }
135
      forall(predicate) {
136
        return !this.tag || predicate(this.value);
137
      }
138
      filter(predicate) {
139
        if (!this.tag || predicate(this.value)) {
140
          return this;
141
        } else {
142
          return Optional.none();
143
        }
144
      }
145
      getOr(replacement) {
146
        return this.tag ? this.value : replacement;
147
      }
148
      or(replacement) {
149
        return this.tag ? this : replacement;
150
      }
151
      getOrThunk(thunk) {
152
        return this.tag ? this.value : thunk();
153
      }
154
      orThunk(thunk) {
155
        return this.tag ? this : thunk();
156
      }
157
      getOrDie(message) {
158
        if (!this.tag) {
159
          throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
160
        } else {
161
          return this.value;
162
        }
163
      }
164
      static from(value) {
165
        return isNonNullable(value) ? Optional.some(value) : Optional.none();
166
      }
167
      getOrNull() {
168
        return this.tag ? this.value : null;
169
      }
170
      getOrUndefined() {
171
        return this.value;
172
      }
173
      each(worker) {
174
        if (this.tag) {
175
          worker(this.value);
176
        }
177
      }
178
      toArray() {
179
        return this.tag ? [this.value] : [];
180
      }
181
      toString() {
182
        return this.tag ? `some(${ this.value })` : 'none()';
183
      }
184
    }
185
    Optional.singletonNone = new Optional(false);
186
 
187
    const nativeSlice = Array.prototype.slice;
188
    const nativeIndexOf = Array.prototype.indexOf;
189
    const nativePush = Array.prototype.push;
190
    const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
191
    const indexOf = (xs, x) => {
192
      const r = rawIndexOf(xs, x);
193
      return r === -1 ? Optional.none() : Optional.some(r);
194
    };
195
    const contains$2 = (xs, x) => rawIndexOf(xs, x) > -1;
196
    const exists = (xs, pred) => {
197
      for (let i = 0, len = xs.length; i < len; i++) {
198
        const x = xs[i];
199
        if (pred(x, i)) {
200
          return true;
201
        }
202
      }
203
      return false;
204
    };
205
    const range$2 = (num, f) => {
206
      const r = [];
207
      for (let i = 0; i < num; i++) {
208
        r.push(f(i));
209
      }
210
      return r;
211
    };
212
    const chunk$1 = (array, size) => {
213
      const r = [];
214
      for (let i = 0; i < array.length; i += size) {
215
        const s = nativeSlice.call(array, i, i + size);
216
        r.push(s);
217
      }
218
      return r;
219
    };
220
    const map$2 = (xs, f) => {
221
      const len = xs.length;
222
      const r = new Array(len);
223
      for (let i = 0; i < len; i++) {
224
        const x = xs[i];
225
        r[i] = f(x, i);
226
      }
227
      return r;
228
    };
229
    const each$1 = (xs, f) => {
230
      for (let i = 0, len = xs.length; i < len; i++) {
231
        const x = xs[i];
232
        f(x, i);
233
      }
234
    };
235
    const eachr = (xs, f) => {
236
      for (let i = xs.length - 1; i >= 0; i--) {
237
        const x = xs[i];
238
        f(x, i);
239
      }
240
    };
241
    const partition$3 = (xs, pred) => {
242
      const pass = [];
243
      const fail = [];
244
      for (let i = 0, len = xs.length; i < len; i++) {
245
        const x = xs[i];
246
        const arr = pred(x, i) ? pass : fail;
247
        arr.push(x);
248
      }
249
      return {
250
        pass,
251
        fail
252
      };
253
    };
254
    const filter$2 = (xs, pred) => {
255
      const r = [];
256
      for (let i = 0, len = xs.length; i < len; i++) {
257
        const x = xs[i];
258
        if (pred(x, i)) {
259
          r.push(x);
260
        }
261
      }
262
      return r;
263
    };
264
    const foldr = (xs, f, acc) => {
265
      eachr(xs, (x, i) => {
266
        acc = f(acc, x, i);
267
      });
268
      return acc;
269
    };
270
    const foldl = (xs, f, acc) => {
271
      each$1(xs, (x, i) => {
272
        acc = f(acc, x, i);
273
      });
274
      return acc;
275
    };
276
    const findUntil = (xs, pred, until) => {
277
      for (let i = 0, len = xs.length; i < len; i++) {
278
        const x = xs[i];
279
        if (pred(x, i)) {
280
          return Optional.some(x);
281
        } else if (until(x, i)) {
282
          break;
283
        }
284
      }
285
      return Optional.none();
286
    };
287
    const find$5 = (xs, pred) => {
288
      return findUntil(xs, pred, never);
289
    };
290
    const findIndex$1 = (xs, pred) => {
291
      for (let i = 0, len = xs.length; i < len; i++) {
292
        const x = xs[i];
293
        if (pred(x, i)) {
294
          return Optional.some(i);
295
        }
296
      }
297
      return Optional.none();
298
    };
299
    const flatten = xs => {
300
      const r = [];
301
      for (let i = 0, len = xs.length; i < len; ++i) {
302
        if (!isArray(xs[i])) {
303
          throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
304
        }
305
        nativePush.apply(r, xs[i]);
306
      }
307
      return r;
308
    };
309
    const bind$3 = (xs, f) => flatten(map$2(xs, f));
310
    const forall = (xs, pred) => {
311
      for (let i = 0, len = xs.length; i < len; ++i) {
312
        const x = xs[i];
313
        if (pred(x, i) !== true) {
314
          return false;
315
        }
316
      }
317
      return true;
318
    };
319
    const reverse = xs => {
320
      const r = nativeSlice.call(xs, 0);
321
      r.reverse();
322
      return r;
323
    };
324
    const difference = (a1, a2) => filter$2(a1, x => !contains$2(a2, x));
325
    const mapToObject = (xs, f) => {
326
      const r = {};
327
      for (let i = 0, len = xs.length; i < len; i++) {
328
        const x = xs[i];
329
        r[String(x)] = f(x, i);
330
      }
331
      return r;
332
    };
333
    const pure$2 = x => [x];
334
    const sort = (xs, comparator) => {
335
      const copy = nativeSlice.call(xs, 0);
336
      copy.sort(comparator);
337
      return copy;
338
    };
1441 ariadna 339
    const get$i = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
340
    const head = xs => get$i(xs, 0);
341
    const last$1 = xs => get$i(xs, xs.length - 1);
1 efrain 342
    const from = isFunction(Array.from) ? Array.from : x => nativeSlice.call(x);
343
    const findMap = (arr, f) => {
344
      for (let i = 0; i < arr.length; i++) {
345
        const r = f(arr[i], i);
346
        if (r.isSome()) {
347
          return r;
348
        }
349
      }
350
      return Optional.none();
351
    };
352
 
353
    const keys = Object.keys;
354
    const hasOwnProperty = Object.hasOwnProperty;
355
    const each = (obj, f) => {
356
      const props = keys(obj);
357
      for (let k = 0, len = props.length; k < len; k++) {
358
        const i = props[k];
359
        const x = obj[i];
360
        f(x, i);
361
      }
362
    };
363
    const map$1 = (obj, f) => {
364
      return tupleMap(obj, (x, i) => ({
365
        k: i,
366
        v: f(x, i)
367
      }));
368
    };
369
    const tupleMap = (obj, f) => {
370
      const r = {};
371
      each(obj, (x, i) => {
372
        const tuple = f(x, i);
373
        r[tuple.k] = tuple.v;
374
      });
375
      return r;
376
    };
377
    const objAcc = r => (x, i) => {
378
      r[i] = x;
379
    };
380
    const internalFilter = (obj, pred, onTrue, onFalse) => {
381
      each(obj, (x, i) => {
382
        (pred(x, i) ? onTrue : onFalse)(x, i);
383
      });
384
    };
385
    const bifilter = (obj, pred) => {
386
      const t = {};
387
      const f = {};
388
      internalFilter(obj, pred, objAcc(t), objAcc(f));
389
      return {
390
        t,
391
        f
392
      };
393
    };
394
    const filter$1 = (obj, pred) => {
395
      const t = {};
396
      internalFilter(obj, pred, objAcc(t), noop);
397
      return t;
398
    };
399
    const mapToArray = (obj, f) => {
400
      const r = [];
401
      each(obj, (value, name) => {
402
        r.push(f(value, name));
403
      });
404
      return r;
405
    };
406
    const find$4 = (obj, pred) => {
407
      const props = keys(obj);
408
      for (let k = 0, len = props.length; k < len; k++) {
409
        const i = props[k];
410
        const x = obj[i];
411
        if (pred(x, i, obj)) {
412
          return Optional.some(x);
413
        }
414
      }
415
      return Optional.none();
416
    };
417
    const values = obj => {
418
      return mapToArray(obj, identity);
419
    };
1441 ariadna 420
    const get$h = (obj, key) => {
1 efrain 421
      return has$2(obj, key) ? Optional.from(obj[key]) : Optional.none();
422
    };
423
    const has$2 = (obj, key) => hasOwnProperty.call(obj, key);
424
    const hasNonNullableKey = (obj, key) => has$2(obj, key) && obj[key] !== undefined && obj[key] !== null;
425
 
426
    const is$1 = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
427
    const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
428
    const cat = arr => {
429
      const r = [];
430
      const push = x => {
431
        r.push(x);
432
      };
433
      for (let i = 0; i < arr.length; i++) {
434
        arr[i].each(push);
435
      }
436
      return r;
437
    };
438
    const sequence = arr => {
439
      const r = [];
440
      for (let i = 0; i < arr.length; i++) {
441
        const x = arr[i];
442
        if (x.isSome()) {
443
          r.push(x.getOrDie());
444
        } else {
445
          return Optional.none();
446
        }
447
      }
448
      return Optional.some(r);
449
    };
450
    const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
451
    const lift3 = (oa, ob, oc, f) => oa.isSome() && ob.isSome() && oc.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Optional.none();
452
    const mapFrom = (a, f) => a !== undefined && a !== null ? Optional.some(f(a)) : Optional.none();
453
    const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
454
 
455
    const addToEnd = (str, suffix) => {
456
      return str + suffix;
457
    };
458
    const removeFromStart = (str, numChars) => {
459
      return str.substring(numChars);
460
    };
461
 
462
    const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
463
    const removeLeading = (str, prefix) => {
464
      return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
465
    };
466
    const ensureTrailing = (str, suffix) => {
467
      return endsWith(str, suffix) ? str : addToEnd(str, suffix);
468
    };
469
    const contains$1 = (str, substr, start = 0, end) => {
470
      const idx = str.indexOf(substr, start);
471
      if (idx !== -1) {
472
        return isUndefined(end) ? true : idx + substr.length <= end;
473
      } else {
474
        return false;
475
      }
476
    };
477
    const startsWith = (str, prefix) => {
478
      return checkRange(str, prefix, 0);
479
    };
480
    const endsWith = (str, suffix) => {
481
      return checkRange(str, suffix, str.length - suffix.length);
482
    };
483
    const blank = r => s => s.replace(r, '');
484
    const trim$1 = blank(/^\s+|\s+$/g);
485
    const isNotEmpty = s => s.length > 0;
486
    const isEmpty = s => !isNotEmpty(s);
1441 ariadna 487
    const toFloat = value => {
488
      const num = parseFloat(value);
489
      return isNaN(num) ? Optional.none() : Optional.some(num);
490
    };
1 efrain 491
 
1441 ariadna 492
    const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
1 efrain 493
 
494
    const fromHtml$2 = (html, scope) => {
495
      const doc = scope || document;
496
      const div = doc.createElement('div');
497
      div.innerHTML = html;
498
      if (!div.hasChildNodes() || div.childNodes.length > 1) {
499
        const message = 'HTML does not have a single root node';
500
        console.error(message, html);
501
        throw new Error(message);
502
      }
503
      return fromDom(div.childNodes[0]);
504
    };
505
    const fromTag = (tag, scope) => {
506
      const doc = scope || document;
507
      const node = doc.createElement(tag);
508
      return fromDom(node);
509
    };
510
    const fromText = (text, scope) => {
511
      const doc = scope || document;
512
      const node = doc.createTextNode(text);
513
      return fromDom(node);
514
    };
515
    const fromDom = node => {
516
      if (node === null || node === undefined) {
517
        throw new Error('Node cannot be null or undefined');
518
      }
519
      return { dom: node };
520
    };
521
    const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
522
    const SugarElement = {
523
      fromHtml: fromHtml$2,
524
      fromTag,
525
      fromText,
526
      fromDom,
527
      fromPoint
528
    };
529
 
530
    const Global = typeof window !== 'undefined' ? window : Function('return this;')();
531
 
532
    const path$1 = (parts, scope) => {
533
      let o = scope !== undefined && scope !== null ? scope : Global;
534
      for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) {
535
        o = o[parts[i]];
536
      }
537
      return o;
538
    };
539
    const resolve = (p, scope) => {
540
      const parts = p.split('.');
541
      return path$1(parts, scope);
542
    };
543
 
544
    const unsafe = (name, scope) => {
545
      return resolve(name, scope);
546
    };
547
    const getOrDie$1 = (name, scope) => {
548
      const actual = unsafe(name, scope);
549
      if (actual === undefined || actual === null) {
550
        throw new Error(name + ' not available on this browser');
551
      }
552
      return actual;
553
    };
554
 
555
    const getPrototypeOf$1 = Object.getPrototypeOf;
556
    const sandHTMLElement = scope => {
557
      return getOrDie$1('HTMLElement', scope);
558
    };
559
    const isPrototypeOf = x => {
560
      const scope = resolve('ownerDocument.defaultView', x);
561
      return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf$1(x).constructor.name));
562
    };
563
 
564
    const DOCUMENT = 9;
565
    const DOCUMENT_FRAGMENT = 11;
566
    const ELEMENT = 1;
567
    const TEXT = 3;
568
 
569
    const name$3 = element => {
570
      const r = element.dom.nodeName;
571
      return r.toLowerCase();
572
    };
573
    const type$1 = element => element.dom.nodeType;
574
    const isType = t => element => type$1(element) === t;
575
    const isHTMLElement = element => isElement$1(element) && isPrototypeOf(element.dom);
576
    const isElement$1 = isType(ELEMENT);
577
    const isText = isType(TEXT);
578
    const isDocument = isType(DOCUMENT);
579
    const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
580
    const isTag = tag => e => isElement$1(e) && name$3(e) === tag;
581
 
582
    const is = (element, selector) => {
583
      const dom = element.dom;
584
      if (dom.nodeType !== ELEMENT) {
585
        return false;
586
      } else {
587
        const elem = dom;
588
        if (elem.matches !== undefined) {
589
          return elem.matches(selector);
590
        } else if (elem.msMatchesSelector !== undefined) {
591
          return elem.msMatchesSelector(selector);
592
        } else if (elem.webkitMatchesSelector !== undefined) {
593
          return elem.webkitMatchesSelector(selector);
594
        } else if (elem.mozMatchesSelector !== undefined) {
595
          return elem.mozMatchesSelector(selector);
596
        } else {
597
          throw new Error('Browser lacks native selectors');
598
        }
599
      }
600
    };
601
    const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
602
    const all$3 = (selector, scope) => {
603
      const base = scope === undefined ? document : scope.dom;
604
      return bypassSelector(base) ? [] : map$2(base.querySelectorAll(selector), SugarElement.fromDom);
605
    };
606
    const one = (selector, scope) => {
607
      const base = scope === undefined ? document : scope.dom;
608
      return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
609
    };
610
 
611
    const eq = (e1, e2) => e1.dom === e2.dom;
612
    const contains = (e1, e2) => {
613
      const d1 = e1.dom;
614
      const d2 = e2.dom;
615
      return d1 === d2 ? false : d1.contains(d2);
616
    };
617
 
618
    const owner$4 = element => SugarElement.fromDom(element.dom.ownerDocument);
619
    const documentOrOwner = dos => isDocument(dos) ? dos : owner$4(dos);
620
    const documentElement = element => SugarElement.fromDom(documentOrOwner(element).dom.documentElement);
621
    const defaultView = element => SugarElement.fromDom(documentOrOwner(element).dom.defaultView);
622
    const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
623
    const parentNode = element => parent(element);
624
    const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
625
    const parents = (element, isRoot) => {
626
      const stop = isFunction(isRoot) ? isRoot : never;
627
      let dom = element.dom;
628
      const ret = [];
629
      while (dom.parentNode !== null && dom.parentNode !== undefined) {
630
        const rawParent = dom.parentNode;
631
        const p = SugarElement.fromDom(rawParent);
632
        ret.push(p);
633
        if (stop(p) === true) {
634
          break;
635
        } else {
636
          dom = rawParent;
637
        }
638
      }
639
      return ret;
640
    };
641
    const offsetParent = element => Optional.from(element.dom.offsetParent).map(SugarElement.fromDom);
642
    const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
643
    const children = element => map$2(element.dom.childNodes, SugarElement.fromDom);
644
    const child$2 = (element, index) => {
645
      const cs = element.dom.childNodes;
646
      return Optional.from(cs[index]).map(SugarElement.fromDom);
647
    };
648
    const firstChild = element => child$2(element, 0);
649
    const spot = (element, offset) => ({
650
      element,
651
      offset
652
    });
653
    const leaf = (element, offset) => {
654
      const cs = children(element);
655
      return cs.length > 0 && offset < cs.length ? spot(cs[offset], 0) : spot(element, offset);
656
    };
657
 
658
    const isShadowRoot = dos => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
1441 ariadna 659
    const getRootNode = e => SugarElement.fromDom(e.dom.getRootNode());
1 efrain 660
    const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
661
    const isInShadowRoot = e => getShadowRoot(e).isSome();
662
    const getShadowRoot = e => {
663
      const r = getRootNode(e);
664
      return isShadowRoot(r) ? Optional.some(r) : Optional.none();
665
    };
666
    const getShadowHost = e => SugarElement.fromDom(e.dom.host);
667
    const getOriginalEventTarget = event => {
1441 ariadna 668
      if (isNonNullable(event.target)) {
1 efrain 669
        const el = SugarElement.fromDom(event.target);
670
        if (isElement$1(el) && isOpenShadowHost(el)) {
671
          if (event.composed && event.composedPath) {
672
            const composedPath = event.composedPath();
673
            if (composedPath) {
674
              return head(composedPath);
675
            }
676
          }
677
        }
678
      }
679
      return Optional.from(event.target);
680
    };
681
    const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot);
682
 
683
    const inBody = element => {
684
      const dom = isText(element) ? element.dom.parentNode : element.dom;
685
      if (dom === undefined || dom === null || dom.ownerDocument === null) {
686
        return false;
687
      }
688
      const doc = dom.ownerDocument;
689
      return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
690
    };
691
    const body = () => getBody(SugarElement.fromDom(document));
692
    const getBody = doc => {
693
      const b = doc.dom.body;
694
      if (b === null || b === undefined) {
695
        throw new Error('Body is not available yet');
696
      }
697
      return SugarElement.fromDom(b);
698
    };
699
 
700
    const rawSet = (dom, key, value) => {
701
      if (isString(value) || isBoolean(value) || isNumber(value)) {
702
        dom.setAttribute(key, value + '');
703
      } else {
704
        console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
705
        throw new Error('Attribute value was not simple');
706
      }
707
    };
708
    const set$9 = (element, key, value) => {
709
      rawSet(element.dom, key, value);
710
    };
711
    const setAll$1 = (element, attrs) => {
712
      const dom = element.dom;
713
      each(attrs, (v, k) => {
714
        rawSet(dom, k, v);
715
      });
716
    };
1441 ariadna 717
    const get$g = (element, key) => {
1 efrain 718
      const v = element.dom.getAttribute(key);
719
      return v === null ? undefined : v;
720
    };
1441 ariadna 721
    const getOpt = (element, key) => Optional.from(get$g(element, key));
1 efrain 722
    const has$1 = (element, key) => {
723
      const dom = element.dom;
724
      return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
725
    };
1441 ariadna 726
    const remove$8 = (element, key) => {
1 efrain 727
      element.dom.removeAttribute(key);
728
    };
729
    const clone$2 = element => foldl(element.dom.attributes, (acc, attr) => {
730
      acc[attr.name] = attr.value;
731
      return acc;
732
    }, {});
733
 
734
    const internalSet = (dom, property, value) => {
735
      if (!isString(value)) {
736
        console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
737
        throw new Error('CSS value must be a string: ' + value);
738
      }
1441 ariadna 739
      if (isSupported(dom)) {
1 efrain 740
        dom.style.setProperty(property, value);
741
      }
742
    };
743
    const internalRemove = (dom, property) => {
1441 ariadna 744
      if (isSupported(dom)) {
1 efrain 745
        dom.style.removeProperty(property);
746
      }
747
    };
748
    const set$8 = (element, property, value) => {
749
      const dom = element.dom;
750
      internalSet(dom, property, value);
751
    };
752
    const setAll = (element, css) => {
753
      const dom = element.dom;
754
      each(css, (v, k) => {
755
        internalSet(dom, k, v);
756
      });
757
    };
758
    const setOptions = (element, css) => {
759
      const dom = element.dom;
760
      each(css, (v, k) => {
761
        v.fold(() => {
762
          internalRemove(dom, k);
763
        }, value => {
764
          internalSet(dom, k, value);
765
        });
766
      });
767
    };
1441 ariadna 768
    const get$f = (element, property) => {
1 efrain 769
      const dom = element.dom;
770
      const styles = window.getComputedStyle(dom);
771
      const r = styles.getPropertyValue(property);
772
      return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
773
    };
1441 ariadna 774
    const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : '';
1 efrain 775
    const getRaw = (element, property) => {
776
      const dom = element.dom;
777
      const raw = getUnsafeProperty(dom, property);
778
      return Optional.from(raw).filter(r => r.length > 0);
779
    };
780
    const getAllRaw = element => {
781
      const css = {};
782
      const dom = element.dom;
1441 ariadna 783
      if (isSupported(dom)) {
1 efrain 784
        for (let i = 0; i < dom.style.length; i++) {
785
          const ruleName = dom.style.item(i);
786
          css[ruleName] = dom.style[ruleName];
787
        }
788
      }
789
      return css;
790
    };
791
    const isValidValue$1 = (tag, property, value) => {
792
      const element = SugarElement.fromTag(tag);
793
      set$8(element, property, value);
794
      const style = getRaw(element, property);
795
      return style.isSome();
796
    };
1441 ariadna 797
    const remove$7 = (element, property) => {
1 efrain 798
      const dom = element.dom;
799
      internalRemove(dom, property);
800
      if (is$1(getOpt(element, 'style').map(trim$1), '')) {
1441 ariadna 801
        remove$8(element, 'style');
1 efrain 802
      }
803
    };
804
    const reflow = e => e.dom.offsetWidth;
805
 
806
    const Dimension = (name, getOffset) => {
807
      const set = (element, h) => {
808
        if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
809
          throw new Error(name + '.set accepts only positive integer values. Value was ' + h);
810
        }
811
        const dom = element.dom;
1441 ariadna 812
        if (isSupported(dom)) {
1 efrain 813
          dom.style[name] = h + 'px';
814
        }
815
      };
816
      const get = element => {
817
        const r = getOffset(element);
818
        if (r <= 0 || r === null) {
1441 ariadna 819
          const css = get$f(element, name);
1 efrain 820
          return parseFloat(css) || 0;
821
        }
822
        return r;
823
      };
824
      const getOuter = get;
825
      const aggregate = (element, properties) => foldl(properties, (acc, property) => {
1441 ariadna 826
        const val = get$f(element, property);
1 efrain 827
        const value = val === undefined ? 0 : parseInt(val, 10);
828
        return isNaN(value) ? acc : acc + value;
829
      }, 0);
830
      const max = (element, value, properties) => {
831
        const cumulativeInclusions = aggregate(element, properties);
832
        const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0;
833
        return absoluteMax;
834
      };
835
      return {
836
        set,
837
        get,
838
        getOuter,
839
        aggregate,
840
        max
841
      };
842
    };
843
 
844
    const api$2 = Dimension('height', element => {
845
      const dom = element.dom;
846
      return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
847
    });
1441 ariadna 848
    const get$e = element => api$2.get(element);
1 efrain 849
    const getOuter$2 = element => api$2.getOuter(element);
850
    const setMax$1 = (element, value) => {
851
      const inclusions = [
852
        'margin-top',
853
        'border-top-width',
854
        'padding-top',
855
        'padding-bottom',
856
        'border-bottom-width',
857
        'margin-bottom'
858
      ];
859
      const absMax = api$2.max(element, value, inclusions);
860
      set$8(element, 'max-height', absMax + 'px');
861
    };
862
 
863
    const r$1 = (left, top) => {
864
      const translate = (x, y) => r$1(left + x, top + y);
865
      return {
866
        left,
867
        top,
868
        translate
869
      };
870
    };
871
    const SugarPosition = r$1;
872
 
873
    const boxPosition = dom => {
874
      const box = dom.getBoundingClientRect();
875
      return SugarPosition(box.left, box.top);
876
    };
877
    const firstDefinedOrZero = (a, b) => {
878
      if (a !== undefined) {
879
        return a;
880
      } else {
881
        return b !== undefined ? b : 0;
882
      }
883
    };
884
    const absolute$3 = element => {
885
      const doc = element.dom.ownerDocument;
886
      const body = doc.body;
887
      const win = doc.defaultView;
888
      const html = doc.documentElement;
889
      if (body === element.dom) {
890
        return SugarPosition(body.offsetLeft, body.offsetTop);
891
      }
892
      const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html.scrollTop);
893
      const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html.scrollLeft);
894
      const clientTop = firstDefinedOrZero(html.clientTop, body.clientTop);
895
      const clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft);
896
      return viewport$1(element).translate(scrollLeft - clientLeft, scrollTop - clientTop);
897
    };
898
    const viewport$1 = element => {
899
      const dom = element.dom;
900
      const doc = dom.ownerDocument;
901
      const body = doc.body;
902
      if (body === dom) {
903
        return SugarPosition(body.offsetLeft, body.offsetTop);
904
      }
905
      if (!inBody(element)) {
906
        return SugarPosition(0, 0);
907
      }
908
      return boxPosition(dom);
909
    };
910
 
911
    const api$1 = Dimension('width', element => element.dom.offsetWidth);
912
    const set$7 = (element, h) => api$1.set(element, h);
1441 ariadna 913
    const get$d = element => api$1.get(element);
1 efrain 914
    const getOuter$1 = element => api$1.getOuter(element);
915
    const setMax = (element, value) => {
916
      const inclusions = [
917
        'margin-left',
918
        'border-left-width',
919
        'padding-left',
920
        'padding-right',
921
        'border-right-width',
922
        'margin-right'
923
      ];
924
      const absMax = api$1.max(element, value, inclusions);
925
      set$8(element, 'max-width', absMax + 'px');
926
    };
927
 
928
    const cached = f => {
929
      let called = false;
930
      let r;
931
      return (...args) => {
932
        if (!called) {
933
          called = true;
934
          r = f.apply(null, args);
935
        }
936
        return r;
937
      };
938
    };
939
 
940
    const DeviceType = (os, browser, userAgent, mediaMatch) => {
941
      const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
942
      const isiPhone = os.isiOS() && !isiPad;
943
      const isMobile = os.isiOS() || os.isAndroid();
944
      const isTouch = isMobile || mediaMatch('(pointer:coarse)');
945
      const isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)');
946
      const isPhone = isiPhone || isMobile && !isTablet;
947
      const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
948
      const isDesktop = !isPhone && !isTablet && !iOSwebview;
949
      return {
950
        isiPad: constant$1(isiPad),
951
        isiPhone: constant$1(isiPhone),
952
        isTablet: constant$1(isTablet),
953
        isPhone: constant$1(isPhone),
954
        isTouch: constant$1(isTouch),
955
        isAndroid: os.isAndroid,
956
        isiOS: os.isiOS,
957
        isWebView: constant$1(iOSwebview),
958
        isDesktop: constant$1(isDesktop)
959
      };
960
    };
961
 
962
    const firstMatch = (regexes, s) => {
963
      for (let i = 0; i < regexes.length; i++) {
964
        const x = regexes[i];
965
        if (x.test(s)) {
966
          return x;
967
        }
968
      }
969
      return undefined;
970
    };
971
    const find$3 = (regexes, agent) => {
972
      const r = firstMatch(regexes, agent);
973
      if (!r) {
974
        return {
975
          major: 0,
976
          minor: 0
977
        };
978
      }
979
      const group = i => {
980
        return Number(agent.replace(r, '$' + i));
981
      };
982
      return nu$d(group(1), group(2));
983
    };
1441 ariadna 984
    const detect$4 = (versionRegexes, agent) => {
1 efrain 985
      const cleanedAgent = String(agent).toLowerCase();
986
      if (versionRegexes.length === 0) {
987
        return unknown$3();
988
      }
989
      return find$3(versionRegexes, cleanedAgent);
990
    };
991
    const unknown$3 = () => {
992
      return nu$d(0, 0);
993
    };
994
    const nu$d = (major, minor) => {
995
      return {
996
        major,
997
        minor
998
      };
999
    };
1000
    const Version = {
1001
      nu: nu$d,
1441 ariadna 1002
      detect: detect$4,
1 efrain 1003
      unknown: unknown$3
1004
    };
1005
 
1006
    const detectBrowser$1 = (browsers, userAgentData) => {
1007
      return findMap(userAgentData.brands, uaBrand => {
1008
        const lcBrand = uaBrand.brand.toLowerCase();
1009
        return find$5(browsers, browser => {
1010
          var _a;
1011
          return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase());
1012
        }).map(info => ({
1013
          current: info.name,
1014
          version: Version.nu(parseInt(uaBrand.version, 10), 0)
1015
        }));
1016
      });
1017
    };
1018
 
1441 ariadna 1019
    const detect$3 = (candidates, userAgent) => {
1 efrain 1020
      const agent = String(userAgent).toLowerCase();
1021
      return find$5(candidates, candidate => {
1022
        return candidate.search(agent);
1023
      });
1024
    };
1025
    const detectBrowser = (browsers, userAgent) => {
1441 ariadna 1026
      return detect$3(browsers, userAgent).map(browser => {
1 efrain 1027
        const version = Version.detect(browser.versionRegexes, userAgent);
1028
        return {
1029
          current: browser.name,
1030
          version
1031
        };
1032
      });
1033
    };
1034
    const detectOs = (oses, userAgent) => {
1441 ariadna 1035
      return detect$3(oses, userAgent).map(os => {
1 efrain 1036
        const version = Version.detect(os.versionRegexes, userAgent);
1037
        return {
1038
          current: os.name,
1039
          version
1040
        };
1041
      });
1042
    };
1043
 
1044
    const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
1045
    const checkContains = target => {
1046
      return uastring => {
1047
        return contains$1(uastring, target);
1048
      };
1049
    };
1050
    const browsers = [
1051
      {
1052
        name: 'Edge',
1053
        versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
1054
        search: uastring => {
1055
          return contains$1(uastring, 'edge/') && contains$1(uastring, 'chrome') && contains$1(uastring, 'safari') && contains$1(uastring, 'applewebkit');
1056
        }
1057
      },
1058
      {
1059
        name: 'Chromium',
1060
        brand: 'Chromium',
1061
        versionRegexes: [
1062
          /.*?chrome\/([0-9]+)\.([0-9]+).*/,
1063
          normalVersionRegex
1064
        ],
1065
        search: uastring => {
1066
          return contains$1(uastring, 'chrome') && !contains$1(uastring, 'chromeframe');
1067
        }
1068
      },
1069
      {
1070
        name: 'IE',
1071
        versionRegexes: [
1072
          /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
1073
          /.*?rv:([0-9]+)\.([0-9]+).*/
1074
        ],
1075
        search: uastring => {
1076
          return contains$1(uastring, 'msie') || contains$1(uastring, 'trident');
1077
        }
1078
      },
1079
      {
1080
        name: 'Opera',
1081
        versionRegexes: [
1082
          normalVersionRegex,
1083
          /.*?opera\/([0-9]+)\.([0-9]+).*/
1084
        ],
1085
        search: checkContains('opera')
1086
      },
1087
      {
1088
        name: 'Firefox',
1089
        versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
1090
        search: checkContains('firefox')
1091
      },
1092
      {
1093
        name: 'Safari',
1094
        versionRegexes: [
1095
          normalVersionRegex,
1096
          /.*?cpu os ([0-9]+)_([0-9]+).*/
1097
        ],
1098
        search: uastring => {
1099
          return (contains$1(uastring, 'safari') || contains$1(uastring, 'mobile/')) && contains$1(uastring, 'applewebkit');
1100
        }
1101
      }
1102
    ];
1103
    const oses = [
1104
      {
1105
        name: 'Windows',
1106
        search: checkContains('win'),
1107
        versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
1108
      },
1109
      {
1110
        name: 'iOS',
1111
        search: uastring => {
1112
          return contains$1(uastring, 'iphone') || contains$1(uastring, 'ipad');
1113
        },
1114
        versionRegexes: [
1115
          /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
1116
          /.*cpu os ([0-9]+)_([0-9]+).*/,
1117
          /.*cpu iphone os ([0-9]+)_([0-9]+).*/
1118
        ]
1119
      },
1120
      {
1121
        name: 'Android',
1122
        search: checkContains('android'),
1123
        versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
1124
      },
1125
      {
1126
        name: 'macOS',
1127
        search: checkContains('mac os x'),
1128
        versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
1129
      },
1130
      {
1131
        name: 'Linux',
1132
        search: checkContains('linux'),
1133
        versionRegexes: []
1134
      },
1135
      {
1136
        name: 'Solaris',
1137
        search: checkContains('sunos'),
1138
        versionRegexes: []
1139
      },
1140
      {
1141
        name: 'FreeBSD',
1142
        search: checkContains('freebsd'),
1143
        versionRegexes: []
1144
      },
1145
      {
1146
        name: 'ChromeOS',
1147
        search: checkContains('cros'),
1148
        versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
1149
      }
1150
    ];
1151
    const PlatformInfo = {
1152
      browsers: constant$1(browsers),
1153
      oses: constant$1(oses)
1154
    };
1155
 
1156
    const edge = 'Edge';
1157
    const chromium = 'Chromium';
1158
    const ie = 'IE';
1159
    const opera = 'Opera';
1160
    const firefox = 'Firefox';
1161
    const safari = 'Safari';
1162
    const unknown$2 = () => {
1163
      return nu$c({
1164
        current: undefined,
1165
        version: Version.unknown()
1166
      });
1167
    };
1168
    const nu$c = info => {
1169
      const current = info.current;
1170
      const version = info.version;
1171
      const isBrowser = name => () => current === name;
1172
      return {
1173
        current,
1174
        version,
1175
        isEdge: isBrowser(edge),
1176
        isChromium: isBrowser(chromium),
1177
        isIE: isBrowser(ie),
1178
        isOpera: isBrowser(opera),
1179
        isFirefox: isBrowser(firefox),
1180
        isSafari: isBrowser(safari)
1181
      };
1182
    };
1183
    const Browser = {
1184
      unknown: unknown$2,
1185
      nu: nu$c,
1186
      edge: constant$1(edge),
1187
      chromium: constant$1(chromium),
1188
      ie: constant$1(ie),
1189
      opera: constant$1(opera),
1190
      firefox: constant$1(firefox),
1191
      safari: constant$1(safari)
1192
    };
1193
 
1194
    const windows = 'Windows';
1195
    const ios = 'iOS';
1196
    const android = 'Android';
1197
    const linux = 'Linux';
1198
    const macos = 'macOS';
1199
    const solaris = 'Solaris';
1200
    const freebsd = 'FreeBSD';
1201
    const chromeos = 'ChromeOS';
1202
    const unknown$1 = () => {
1203
      return nu$b({
1204
        current: undefined,
1205
        version: Version.unknown()
1206
      });
1207
    };
1208
    const nu$b = info => {
1209
      const current = info.current;
1210
      const version = info.version;
1211
      const isOS = name => () => current === name;
1212
      return {
1213
        current,
1214
        version,
1215
        isWindows: isOS(windows),
1216
        isiOS: isOS(ios),
1217
        isAndroid: isOS(android),
1218
        isMacOS: isOS(macos),
1219
        isLinux: isOS(linux),
1220
        isSolaris: isOS(solaris),
1221
        isFreeBSD: isOS(freebsd),
1222
        isChromeOS: isOS(chromeos)
1223
      };
1224
    };
1225
    const OperatingSystem = {
1226
      unknown: unknown$1,
1227
      nu: nu$b,
1228
      windows: constant$1(windows),
1229
      ios: constant$1(ios),
1230
      android: constant$1(android),
1231
      linux: constant$1(linux),
1232
      macos: constant$1(macos),
1233
      solaris: constant$1(solaris),
1234
      freebsd: constant$1(freebsd),
1235
      chromeos: constant$1(chromeos)
1236
    };
1237
 
1441 ariadna 1238
    const detect$2 = (userAgent, userAgentDataOpt, mediaMatch) => {
1 efrain 1239
      const browsers = PlatformInfo.browsers();
1240
      const oses = PlatformInfo.oses();
1241
      const browser = userAgentDataOpt.bind(userAgentData => detectBrowser$1(browsers, userAgentData)).orThunk(() => detectBrowser(browsers, userAgent)).fold(Browser.unknown, Browser.nu);
1242
      const os = detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
1243
      const deviceType = DeviceType(os, browser, userAgent, mediaMatch);
1244
      return {
1245
        browser,
1246
        os,
1247
        deviceType
1248
      };
1249
    };
1441 ariadna 1250
    const PlatformDetection = { detect: detect$2 };
1 efrain 1251
 
1252
    const mediaMatch = query => window.matchMedia(query).matches;
1441 ariadna 1253
    let platform = cached(() => PlatformDetection.detect(window.navigator.userAgent, Optional.from(window.navigator.userAgentData), mediaMatch));
1254
    const detect$1 = () => platform();
1 efrain 1255
 
1256
    const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({
1257
      target,
1258
      x,
1259
      y,
1260
      stop,
1261
      prevent,
1262
      kill,
1263
      raw
1264
    });
1265
    const fromRawEvent$1 = rawEvent => {
1266
      const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
1267
      const stop = () => rawEvent.stopPropagation();
1268
      const prevent = () => rawEvent.preventDefault();
1269
      const kill = compose(prevent, stop);
1270
      return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent);
1271
    };
1272
    const handle = (filter, handler) => rawEvent => {
1273
      if (filter(rawEvent)) {
1274
        handler(fromRawEvent$1(rawEvent));
1275
      }
1276
    };
1277
    const binder = (element, event, filter, handler, useCapture) => {
1278
      const wrapped = handle(filter, handler);
1279
      element.dom.addEventListener(event, wrapped, useCapture);
1280
      return { unbind: curry(unbind, element, event, wrapped, useCapture) };
1281
    };
1282
    const bind$2 = (element, event, filter, handler) => binder(element, event, filter, handler, false);
1283
    const capture$1 = (element, event, filter, handler) => binder(element, event, filter, handler, true);
1284
    const unbind = (element, event, handler, useCapture) => {
1285
      element.dom.removeEventListener(event, handler, useCapture);
1286
    };
1287
 
1288
    const before$1 = (marker, element) => {
1289
      const parent$1 = parent(marker);
1290
      parent$1.each(v => {
1291
        v.dom.insertBefore(element.dom, marker.dom);
1292
      });
1293
    };
1294
    const after$2 = (marker, element) => {
1295
      const sibling = nextSibling(marker);
1296
      sibling.fold(() => {
1297
        const parent$1 = parent(marker);
1298
        parent$1.each(v => {
1299
          append$2(v, element);
1300
        });
1301
      }, v => {
1302
        before$1(v, element);
1303
      });
1304
    };
1305
    const prepend$1 = (parent, element) => {
1306
      const firstChild$1 = firstChild(parent);
1307
      firstChild$1.fold(() => {
1308
        append$2(parent, element);
1309
      }, v => {
1310
        parent.dom.insertBefore(element.dom, v.dom);
1311
      });
1312
    };
1313
    const append$2 = (parent, element) => {
1314
      parent.dom.appendChild(element.dom);
1315
    };
1316
    const appendAt = (parent, element, index) => {
1317
      child$2(parent, index).fold(() => {
1318
        append$2(parent, element);
1319
      }, v => {
1320
        before$1(v, element);
1321
      });
1322
    };
1323
 
1324
    const append$1 = (parent, elements) => {
1325
      each$1(elements, x => {
1326
        append$2(parent, x);
1327
      });
1328
    };
1329
 
1330
    const empty = element => {
1331
      element.dom.textContent = '';
1332
      each$1(children(element), rogue => {
1441 ariadna 1333
        remove$6(rogue);
1 efrain 1334
      });
1335
    };
1441 ariadna 1336
    const remove$6 = element => {
1 efrain 1337
      const dom = element.dom;
1338
      if (dom.parentNode !== null) {
1339
        dom.parentNode.removeChild(dom);
1340
      }
1341
    };
1342
 
1441 ariadna 1343
    const get$c = _DOC => {
1 efrain 1344
      const doc = _DOC !== undefined ? _DOC.dom : document;
1345
      const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
1346
      const y = doc.body.scrollTop || doc.documentElement.scrollTop;
1347
      return SugarPosition(x, y);
1348
    };
1349
    const to = (x, y, _DOC) => {
1350
      const doc = _DOC !== undefined ? _DOC.dom : document;
1351
      const win = doc.defaultView;
1352
      if (win) {
1353
        win.scrollTo(x, y);
1354
      }
1355
    };
1356
 
1441 ariadna 1357
    const get$b = _win => {
1 efrain 1358
      const win = _win === undefined ? window : _win;
1441 ariadna 1359
      if (detect$1().browser.isFirefox()) {
1 efrain 1360
        return Optional.none();
1361
      } else {
1362
        return Optional.from(win.visualViewport);
1363
      }
1364
    };
1365
    const bounds$1 = (x, y, width, height) => ({
1366
      x,
1367
      y,
1368
      width,
1369
      height,
1370
      right: x + width,
1371
      bottom: y + height
1372
    });
1373
    const getBounds$3 = _win => {
1374
      const win = _win === undefined ? window : _win;
1375
      const doc = win.document;
1441 ariadna 1376
      const scroll = get$c(SugarElement.fromDom(doc));
1377
      return get$b(win).fold(() => {
1 efrain 1378
        const html = win.document.documentElement;
1379
        const width = html.clientWidth;
1380
        const height = html.clientHeight;
1381
        return bounds$1(scroll.left, scroll.top, width, height);
1382
      }, visualViewport => bounds$1(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
1383
    };
1384
 
1385
    const getDocument = () => SugarElement.fromDom(document);
1386
 
1387
    const walkUp = (navigation, doc) => {
1388
      const frame = navigation.view(doc);
1389
      return frame.fold(constant$1([]), f => {
1390
        const parent = navigation.owner(f);
1391
        const rest = walkUp(navigation, parent);
1392
        return [f].concat(rest);
1393
      });
1394
    };
1395
    const pathTo = (element, navigation) => {
1396
      const d = navigation.owner(element);
1397
      const paths = walkUp(navigation, d);
1398
      return Optional.some(paths);
1399
    };
1400
 
1401
    const view = doc => {
1402
      var _a;
1403
      const element = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement);
1404
      return element.map(SugarElement.fromDom);
1405
    };
1406
    const owner$3 = element => owner$4(element);
1407
 
1408
    var Navigation = /*#__PURE__*/Object.freeze({
1409
        __proto__: null,
1410
        view: view,
1411
        owner: owner$3
1412
    });
1413
 
1414
    const find$2 = element => {
1415
      const doc = getDocument();
1441 ariadna 1416
      const scroll = get$c(doc);
1 efrain 1417
      const path = pathTo(element, Navigation);
1418
      return path.fold(curry(absolute$3, element), frames => {
1419
        const offset = viewport$1(element);
1420
        const r = foldr(frames, (b, a) => {
1421
          const loc = viewport$1(a);
1422
          return {
1423
            left: b.left + loc.left,
1424
            top: b.top + loc.top
1425
          };
1426
        }, {
1427
          left: 0,
1428
          top: 0
1429
        });
1430
        return SugarPosition(r.left + offset.left + scroll.left, r.top + offset.top + scroll.top);
1431
      });
1432
    };
1433
 
1434
    const pointed = (point, width, height) => ({
1435
      point,
1436
      width,
1437
      height
1438
    });
1439
    const rect = (x, y, width, height) => ({
1440
      x,
1441
      y,
1442
      width,
1443
      height
1444
    });
1445
    const bounds = (x, y, width, height) => ({
1446
      x,
1447
      y,
1448
      width,
1449
      height,
1450
      right: x + width,
1451
      bottom: y + height
1452
    });
1453
    const box$1 = element => {
1454
      const xy = absolute$3(element);
1455
      const w = getOuter$1(element);
1456
      const h = getOuter$2(element);
1457
      return bounds(xy.left, xy.top, w, h);
1458
    };
1459
    const absolute$2 = element => {
1460
      const position = find$2(element);
1461
      const width = getOuter$1(element);
1462
      const height = getOuter$2(element);
1463
      return bounds(position.left, position.top, width, height);
1464
    };
1465
    const constrain = (original, constraint) => {
1466
      const left = Math.max(original.x, constraint.x);
1467
      const top = Math.max(original.y, constraint.y);
1468
      const right = Math.min(original.right, constraint.right);
1469
      const bottom = Math.min(original.bottom, constraint.bottom);
1470
      const width = right - left;
1471
      const height = bottom - top;
1472
      return bounds(left, top, width, height);
1473
    };
1474
    const constrainByMany = (original, constraints) => {
1475
      return foldl(constraints, (acc, c) => constrain(acc, c), original);
1476
    };
1477
    const win = () => getBounds$3(window);
1478
 
1441 ariadna 1479
    const Cell = initial => {
1480
      let value = initial;
1481
      const get = () => {
1482
        return value;
1483
      };
1484
      const set = v => {
1485
        value = v;
1486
      };
1487
      return {
1488
        get,
1489
        set
1490
      };
1491
    };
1492
 
1493
    const singleton$1 = doRevoke => {
1494
      const subject = Cell(Optional.none());
1495
      const revoke = () => subject.get().each(doRevoke);
1496
      const clear = () => {
1497
        revoke();
1498
        subject.set(Optional.none());
1499
      };
1500
      const isSet = () => subject.get().isSome();
1501
      const get = () => subject.get();
1502
      const set = s => {
1503
        revoke();
1504
        subject.set(Optional.some(s));
1505
      };
1506
      return {
1507
        clear,
1508
        isSet,
1509
        get,
1510
        set
1511
      };
1512
    };
1513
    const destroyable = () => singleton$1(s => s.destroy());
1514
    const unbindable = () => singleton$1(s => s.unbind());
1515
    const value$4 = () => {
1516
      const subject = singleton$1(noop);
1517
      const on = f => subject.get().each(f);
1518
      return {
1519
        ...subject,
1520
        on
1521
      };
1522
    };
1523
 
1 efrain 1524
    var global$a = tinymce.util.Tools.resolve('tinymce.ThemeManager');
1525
 
1441 ariadna 1526
    const value$3 = value => {
1 efrain 1527
      const applyHelper = fn => fn(value);
1528
      const constHelper = constant$1(value);
1529
      const outputHelper = () => output;
1530
      const output = {
1531
        tag: true,
1532
        inner: value,
1533
        fold: (_onError, onValue) => onValue(value),
1534
        isValue: always,
1535
        isError: never,
1536
        map: mapper => Result.value(mapper(value)),
1537
        mapError: outputHelper,
1538
        bind: applyHelper,
1539
        exists: applyHelper,
1540
        forall: applyHelper,
1541
        getOr: constHelper,
1542
        or: outputHelper,
1543
        getOrThunk: constHelper,
1544
        orThunk: outputHelper,
1545
        getOrDie: constHelper,
1546
        each: fn => {
1547
          fn(value);
1548
        },
1549
        toOptional: () => Optional.some(value)
1550
      };
1551
      return output;
1552
    };
1553
    const error$1 = error => {
1554
      const outputHelper = () => output;
1555
      const output = {
1556
        tag: false,
1557
        inner: error,
1558
        fold: (onError, _onValue) => onError(error),
1559
        isValue: never,
1560
        isError: always,
1561
        map: outputHelper,
1562
        mapError: mapper => Result.error(mapper(error)),
1563
        bind: outputHelper,
1564
        exists: never,
1565
        forall: always,
1566
        getOr: identity,
1567
        or: identity,
1568
        getOrThunk: apply$1,
1569
        orThunk: apply$1,
1570
        getOrDie: die(String(error)),
1571
        each: noop,
1572
        toOptional: Optional.none
1573
      };
1574
      return output;
1575
    };
1441 ariadna 1576
    const fromOption = (optional, err) => optional.fold(() => error$1(err), value$3);
1 efrain 1577
    const Result = {
1441 ariadna 1578
      value: value$3,
1 efrain 1579
      error: error$1,
1580
      fromOption
1581
    };
1582
 
1583
    var SimpleResultType;
1584
    (function (SimpleResultType) {
1585
      SimpleResultType[SimpleResultType['Error'] = 0] = 'Error';
1586
      SimpleResultType[SimpleResultType['Value'] = 1] = 'Value';
1587
    }(SimpleResultType || (SimpleResultType = {})));
1588
    const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
1589
    const partition$2 = results => {
1590
      const values = [];
1591
      const errors = [];
1592
      each$1(results, obj => {
1593
        fold$1(obj, err => errors.push(err), val => values.push(val));
1594
      });
1595
      return {
1596
        values,
1597
        errors
1598
      };
1599
    };
1600
    const mapError = (res, f) => {
1601
      if (res.stype === SimpleResultType.Error) {
1602
        return {
1603
          stype: SimpleResultType.Error,
1604
          serror: f(res.serror)
1605
        };
1606
      } else {
1607
        return res;
1608
      }
1609
    };
1610
    const map = (res, f) => {
1611
      if (res.stype === SimpleResultType.Value) {
1612
        return {
1613
          stype: SimpleResultType.Value,
1614
          svalue: f(res.svalue)
1615
        };
1616
      } else {
1617
        return res;
1618
      }
1619
    };
1620
    const bind$1 = (res, f) => {
1621
      if (res.stype === SimpleResultType.Value) {
1622
        return f(res.svalue);
1623
      } else {
1624
        return res;
1625
      }
1626
    };
1627
    const bindError = (res, f) => {
1628
      if (res.stype === SimpleResultType.Error) {
1629
        return f(res.serror);
1630
      } else {
1631
        return res;
1632
      }
1633
    };
1634
    const svalue = v => ({
1635
      stype: SimpleResultType.Value,
1636
      svalue: v
1637
    });
1638
    const serror = e => ({
1639
      stype: SimpleResultType.Error,
1640
      serror: e
1641
    });
1642
    const toResult$1 = res => fold$1(res, Result.error, Result.value);
1643
    const fromResult$1 = res => res.fold(serror, svalue);
1644
    const SimpleResult = {
1645
      fromResult: fromResult$1,
1646
      toResult: toResult$1,
1647
      svalue,
1648
      partition: partition$2,
1649
      serror,
1650
      bind: bind$1,
1651
      bindError,
1652
      map,
1653
      mapError,
1654
      fold: fold$1
1655
    };
1656
 
1657
    const field$2 = (key, newKey, presence, prop) => ({
1658
      tag: 'field',
1659
      key,
1660
      newKey,
1661
      presence,
1662
      prop
1663
    });
1664
    const customField$1 = (newKey, instantiator) => ({
1665
      tag: 'custom',
1666
      newKey,
1667
      instantiator
1668
    });
1669
    const fold = (value, ifField, ifCustom) => {
1670
      switch (value.tag) {
1671
      case 'field':
1672
        return ifField(value.key, value.newKey, value.presence, value.prop);
1673
      case 'custom':
1674
        return ifCustom(value.newKey, value.instantiator);
1675
      }
1676
    };
1677
 
1678
    const shallow$1 = (old, nu) => {
1679
      return nu;
1680
    };
1681
    const deep$1 = (old, nu) => {
1682
      const bothObjects = isPlainObject(old) && isPlainObject(nu);
1683
      return bothObjects ? deepMerge(old, nu) : nu;
1684
    };
1685
    const baseMerge = merger => {
1686
      return (...objects) => {
1687
        if (objects.length === 0) {
1688
          throw new Error(`Can't merge zero objects`);
1689
        }
1690
        const ret = {};
1691
        for (let j = 0; j < objects.length; j++) {
1692
          const curObject = objects[j];
1693
          for (const key in curObject) {
1694
            if (has$2(curObject, key)) {
1695
              ret[key] = merger(ret[key], curObject[key]);
1696
            }
1697
          }
1698
        }
1699
        return ret;
1700
      };
1701
    };
1702
    const deepMerge = baseMerge(deep$1);
1703
    const merge$1 = baseMerge(shallow$1);
1704
 
1705
    const required$2 = () => ({
1706
      tag: 'required',
1707
      process: {}
1708
    });
1709
    const defaultedThunk = fallbackThunk => ({
1710
      tag: 'defaultedThunk',
1711
      process: fallbackThunk
1712
    });
1713
    const defaulted$1 = fallback => defaultedThunk(constant$1(fallback));
1714
    const asOption = () => ({
1715
      tag: 'option',
1716
      process: {}
1717
    });
1718
    const mergeWithThunk = baseThunk => ({
1719
      tag: 'mergeWithThunk',
1720
      process: baseThunk
1721
    });
1722
    const mergeWith = base => mergeWithThunk(constant$1(base));
1723
 
1724
    const mergeValues$1 = (values, base) => values.length > 0 ? SimpleResult.svalue(deepMerge(base, merge$1.apply(undefined, values))) : SimpleResult.svalue(base);
1725
    const mergeErrors$1 = errors => compose(SimpleResult.serror, flatten)(errors);
1726
    const consolidateObj = (objects, base) => {
1727
      const partition = SimpleResult.partition(objects);
1728
      return partition.errors.length > 0 ? mergeErrors$1(partition.errors) : mergeValues$1(partition.values, base);
1729
    };
1730
    const consolidateArr = objects => {
1731
      const partitions = SimpleResult.partition(objects);
1732
      return partitions.errors.length > 0 ? mergeErrors$1(partitions.errors) : SimpleResult.svalue(partitions.values);
1733
    };
1734
    const ResultCombine = {
1735
      consolidateObj,
1736
      consolidateArr
1737
    };
1738
 
1739
    const formatObj = input => {
1740
      return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
1741
    };
1742
    const formatErrors = errors => {
1743
      const es = errors.length > 10 ? errors.slice(0, 10).concat([{
1744
          path: [],
1745
          getErrorInfo: constant$1('... (only showing first ten failures)')
1746
        }]) : errors;
1747
      return map$2(es, e => {
1748
        return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
1749
      });
1750
    };
1751
 
1752
    const nu$a = (path, getErrorInfo) => {
1753
      return SimpleResult.serror([{
1754
          path,
1755
          getErrorInfo
1756
        }]);
1757
    };
1758
    const missingRequired = (path, key, obj) => nu$a(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
1759
    const missingKey = (path, key) => nu$a(path, () => 'Choice schema did not contain choice key: "' + key + '"');
1760
    const missingBranch = (path, branches, branch) => nu$a(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
1761
    const unsupportedFields = (path, unsupported) => nu$a(path, () => 'There are unsupported fields: [' + unsupported.join(', ') + '] specified');
1762
    const custom = (path, err) => nu$a(path, constant$1(err));
1763
 
1441 ariadna 1764
    const value$2 = validator => {
1 efrain 1765
      const extract = (path, val) => {
1766
        return SimpleResult.bindError(validator(val), err => custom(path, err));
1767
      };
1768
      const toString = constant$1('val');
1769
      return {
1770
        extract,
1771
        toString
1772
      };
1773
    };
1441 ariadna 1774
    const anyValue$1 = value$2(SimpleResult.svalue);
1 efrain 1775
 
1441 ariadna 1776
    const requiredAccess = (path, obj, key, bundle) => get$h(obj, key).fold(() => missingRequired(path, key, obj), bundle);
1 efrain 1777
    const fallbackAccess = (obj, key, fallback, bundle) => {
1441 ariadna 1778
      const v = get$h(obj, key).getOrThunk(() => fallback(obj));
1 efrain 1779
      return bundle(v);
1780
    };
1441 ariadna 1781
    const optionAccess = (obj, key, bundle) => bundle(get$h(obj, key));
1 efrain 1782
    const optionDefaultedAccess = (obj, key, fallback, bundle) => {
1441 ariadna 1783
      const opt = get$h(obj, key).map(val => val === true ? fallback(obj) : val);
1 efrain 1784
      return bundle(opt);
1785
    };
1786
    const extractField = (field, path, obj, key, prop) => {
1787
      const bundle = av => prop.extract(path.concat([key]), av);
1788
      const bundleAsOption = optValue => optValue.fold(() => SimpleResult.svalue(Optional.none()), ov => {
1789
        const result = prop.extract(path.concat([key]), ov);
1790
        return SimpleResult.map(result, Optional.some);
1791
      });
1792
      switch (field.tag) {
1793
      case 'required':
1794
        return requiredAccess(path, obj, key, bundle);
1795
      case 'defaultedThunk':
1796
        return fallbackAccess(obj, key, field.process, bundle);
1797
      case 'option':
1798
        return optionAccess(obj, key, bundleAsOption);
1799
      case 'defaultedOptionThunk':
1800
        return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
1801
      case 'mergeWithThunk': {
1802
          return fallbackAccess(obj, key, constant$1({}), v => {
1803
            const result = deepMerge(field.process(obj), v);
1804
            return bundle(result);
1805
          });
1806
        }
1807
      }
1808
    };
1809
    const extractFields = (path, obj, fields) => {
1810
      const success = {};
1811
      const errors = [];
1812
      for (const field of fields) {
1813
        fold(field, (key, newKey, presence, prop) => {
1814
          const result = extractField(presence, path, obj, key, prop);
1815
          SimpleResult.fold(result, err => {
1816
            errors.push(...err);
1817
          }, res => {
1818
            success[newKey] = res;
1819
          });
1820
        }, (newKey, instantiator) => {
1821
          success[newKey] = instantiator(obj);
1822
        });
1823
      }
1824
      return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
1825
    };
1826
    const valueThunk = getDelegate => {
1827
      const extract = (path, val) => getDelegate().extract(path, val);
1828
      const toString = () => getDelegate().toString();
1829
      return {
1830
        extract,
1831
        toString
1832
      };
1833
    };
1834
    const getSetKeys = obj => keys(filter$1(obj, isNonNullable));
1835
    const objOfOnly = fields => {
1836
      const delegate = objOf(fields);
1837
      const fieldNames = foldr(fields, (acc, value) => {
1838
        return fold(value, key => deepMerge(acc, { [key]: true }), constant$1(acc));
1839
      }, {});
1840
      const extract = (path, o) => {
1841
        const keys = isBoolean(o) ? [] : getSetKeys(o);
1842
        const extra = filter$2(keys, k => !hasNonNullableKey(fieldNames, k));
1843
        return extra.length === 0 ? delegate.extract(path, o) : unsupportedFields(path, extra);
1844
      };
1845
      return {
1846
        extract,
1847
        toString: delegate.toString
1848
      };
1849
    };
1850
    const objOf = values => {
1851
      const extract = (path, o) => extractFields(path, o, values);
1852
      const toString = () => {
1853
        const fieldStrings = map$2(values, value => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
1854
        return 'obj{\n' + fieldStrings.join('\n') + '}';
1855
      };
1856
      return {
1857
        extract,
1858
        toString
1859
      };
1860
    };
1861
    const arrOf = prop => {
1862
      const extract = (path, array) => {
1863
        const results = map$2(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
1864
        return ResultCombine.consolidateArr(results);
1865
      };
1866
      const toString = () => 'array(' + prop.toString() + ')';
1867
      return {
1868
        extract,
1869
        toString
1870
      };
1871
    };
1872
    const oneOf = (props, rawF) => {
1873
      const f = rawF !== undefined ? rawF : identity;
1874
      const extract = (path, val) => {
1875
        const errors = [];
1876
        for (const prop of props) {
1877
          const res = prop.extract(path, val);
1878
          if (res.stype === SimpleResultType.Value) {
1879
            return {
1880
              stype: SimpleResultType.Value,
1881
              svalue: f(res.svalue)
1882
            };
1883
          }
1884
          errors.push(res);
1885
        }
1886
        return ResultCombine.consolidateArr(errors);
1887
      };
1888
      const toString = () => 'oneOf(' + map$2(props, prop => prop.toString()).join(', ') + ')';
1889
      return {
1890
        extract,
1891
        toString
1892
      };
1893
    };
1894
    const setOf$1 = (validator, prop) => {
1441 ariadna 1895
      const validateKeys = (path, keys) => arrOf(value$2(validator)).extract(path, keys);
1 efrain 1896
      const extract = (path, o) => {
1897
        const keys$1 = keys(o);
1898
        const validatedKeys = validateKeys(path, keys$1);
1899
        return SimpleResult.bind(validatedKeys, validKeys => {
1900
          const schema = map$2(validKeys, vk => {
1901
            return field$2(vk, vk, required$2(), prop);
1902
          });
1903
          return objOf(schema).extract(path, o);
1904
        });
1905
      };
1906
      const toString = () => 'setOf(' + prop.toString() + ')';
1907
      return {
1908
        extract,
1909
        toString
1910
      };
1911
    };
1912
    const thunk = (_desc, processor) => {
1913
      const getP = cached(processor);
1914
      const extract = (path, val) => getP().extract(path, val);
1915
      const toString = () => getP().toString();
1916
      return {
1917
        extract,
1918
        toString
1919
      };
1920
    };
1921
    const arrOfObj = compose(arrOf, objOf);
1922
 
1923
    const anyValue = constant$1(anyValue$1);
1441 ariadna 1924
    const typedValue = (validator, expectedType) => value$2(a => {
1 efrain 1925
      const actualType = typeof a;
1926
      return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${ expectedType } but got: ${ actualType }`);
1927
    });
1928
    const number = typedValue(isNumber, 'number');
1929
    const string = typedValue(isString, 'string');
1930
    const boolean = typedValue(isBoolean, 'boolean');
1931
    const functionProcessor = typedValue(isFunction, 'function');
1932
    const isPostMessageable = val => {
1933
      if (Object(val) !== val) {
1934
        return true;
1935
      }
1936
      switch ({}.toString.call(val).slice(8, -1)) {
1937
      case 'Boolean':
1938
      case 'Number':
1939
      case 'String':
1940
      case 'Date':
1941
      case 'RegExp':
1942
      case 'Blob':
1943
      case 'FileList':
1944
      case 'ImageData':
1945
      case 'ImageBitmap':
1946
      case 'ArrayBuffer':
1947
        return true;
1948
      case 'Array':
1949
      case 'Object':
1950
        return Object.keys(val).every(prop => isPostMessageable(val[prop]));
1951
      default:
1952
        return false;
1953
      }
1954
    };
1441 ariadna 1955
    const postMessageable = value$2(a => {
1 efrain 1956
      if (isPostMessageable(a)) {
1957
        return SimpleResult.svalue(a);
1958
      } else {
1959
        return SimpleResult.serror('Expected value to be acceptable for sending via postMessage');
1960
      }
1961
    });
1962
 
1963
    const chooseFrom = (path, input, branches, ch) => {
1441 ariadna 1964
      const fields = get$h(branches, ch);
1 efrain 1965
      return fields.fold(() => missingBranch(path, branches, ch), vp => vp.extract(path.concat(['branch: ' + ch]), input));
1966
    };
1967
    const choose$2 = (key, branches) => {
1968
      const extract = (path, input) => {
1441 ariadna 1969
        const choice = get$h(input, key);
1 efrain 1970
        return choice.fold(() => missingKey(path, key), chosen => chooseFrom(path, input, branches, chosen));
1971
      };
1972
      const toString = () => 'chooseOn(' + key + '). Possible values: ' + keys(branches);
1973
      return {
1974
        extract,
1975
        toString
1976
      };
1977
    };
1978
 
1979
    const arrOfVal = () => arrOf(anyValue$1);
1441 ariadna 1980
    const valueOf = validator => value$2(v => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
1 efrain 1981
    const setOf = (validator, prop) => setOf$1(v => SimpleResult.fromResult(validator(v)), prop);
1982
    const extractValue = (label, prop, obj) => {
1983
      const res = prop.extract([label], obj);
1984
      return SimpleResult.mapError(res, errs => ({
1985
        input: obj,
1986
        errors: errs
1987
      }));
1988
    };
1989
    const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
1990
    const getOrDie = extraction => {
1991
      return extraction.fold(errInfo => {
1992
        throw new Error(formatError(errInfo));
1993
      }, identity);
1994
    };
1995
    const asRawOrDie$1 = (label, prop, obj) => getOrDie(asRaw(label, prop, obj));
1996
    const formatError = errInfo => {
1997
      return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input);
1998
    };
1999
    const choose$1 = (key, branches) => choose$2(key, map$1(branches, objOf));
2000
    const thunkOf = (desc, schema) => thunk(desc, schema);
2001
 
2002
    const field$1 = field$2;
2003
    const customField = customField$1;
2004
    const validateEnum = values => valueOf(value => contains$2(values, value) ? Result.value(value) : Result.error(`Unsupported value: "${ value }", choose one of "${ values.join(', ') }".`));
2005
    const required$1 = key => field$1(key, key, required$2(), anyValue());
2006
    const requiredOf = (key, schema) => field$1(key, key, required$2(), schema);
2007
    const requiredNumber = key => requiredOf(key, number);
2008
    const requiredString = key => requiredOf(key, string);
2009
    const requiredStringEnum = (key, values) => field$1(key, key, required$2(), validateEnum(values));
2010
    const requiredFunction = key => requiredOf(key, functionProcessor);
1441 ariadna 2011
    const forbid = (key, message) => field$1(key, key, asOption(), value$2(_v => SimpleResult.serror('The field: ' + key + ' is forbidden. ' + message)));
1 efrain 2012
    const requiredObjOf = (key, objSchema) => field$1(key, key, required$2(), objOf(objSchema));
2013
    const requiredArrayOfObj = (key, objFields) => field$1(key, key, required$2(), arrOfObj(objFields));
2014
    const requiredArrayOf = (key, schema) => field$1(key, key, required$2(), arrOf(schema));
2015
    const option$3 = key => field$1(key, key, asOption(), anyValue());
2016
    const optionOf = (key, schema) => field$1(key, key, asOption(), schema);
2017
    const optionNumber = key => optionOf(key, number);
2018
    const optionString = key => optionOf(key, string);
2019
    const optionStringEnum = (key, values) => optionOf(key, validateEnum(values));
2020
    const optionFunction = key => optionOf(key, functionProcessor);
2021
    const optionArrayOf = (key, schema) => optionOf(key, arrOf(schema));
2022
    const optionObjOf = (key, objSchema) => optionOf(key, objOf(objSchema));
2023
    const optionObjOfOnly = (key, objSchema) => optionOf(key, objOfOnly(objSchema));
2024
    const defaulted = (key, fallback) => field$1(key, key, defaulted$1(fallback), anyValue());
2025
    const defaultedOf = (key, fallback, schema) => field$1(key, key, defaulted$1(fallback), schema);
2026
    const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
2027
    const defaultedString = (key, fallback) => defaultedOf(key, fallback, string);
2028
    const defaultedStringEnum = (key, fallback, values) => defaultedOf(key, fallback, validateEnum(values));
2029
    const defaultedBoolean = (key, fallback) => defaultedOf(key, fallback, boolean);
2030
    const defaultedFunction = (key, fallback) => defaultedOf(key, fallback, functionProcessor);
2031
    const defaultedPostMsg = (key, fallback) => defaultedOf(key, fallback, postMessageable);
2032
    const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
2033
    const defaultedObjOf = (key, fallback, objSchema) => defaultedOf(key, fallback, objOf(objSchema));
2034
 
2035
    const generate$7 = cases => {
2036
      if (!isArray(cases)) {
2037
        throw new Error('cases must be an array');
2038
      }
2039
      if (cases.length === 0) {
2040
        throw new Error('there must be at least one case');
2041
      }
2042
      const constructors = [];
2043
      const adt = {};
2044
      each$1(cases, (acase, count) => {
2045
        const keys$1 = keys(acase);
2046
        if (keys$1.length !== 1) {
2047
          throw new Error('one and only one name per case');
2048
        }
2049
        const key = keys$1[0];
2050
        const value = acase[key];
2051
        if (adt[key] !== undefined) {
2052
          throw new Error('duplicate key detected:' + key);
2053
        } else if (key === 'cata') {
2054
          throw new Error('cannot have a case named cata (sorry)');
2055
        } else if (!isArray(value)) {
2056
          throw new Error('case arguments must be an array');
2057
        }
2058
        constructors.push(key);
2059
        adt[key] = (...args) => {
2060
          const argLength = args.length;
2061
          if (argLength !== value.length) {
2062
            throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
2063
          }
2064
          const match = branches => {
2065
            const branchKeys = keys(branches);
2066
            if (constructors.length !== branchKeys.length) {
2067
              throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
2068
            }
2069
            const allReqd = forall(constructors, reqKey => {
2070
              return contains$2(branchKeys, reqKey);
2071
            });
2072
            if (!allReqd) {
2073
              throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
2074
            }
2075
            return branches[key].apply(null, args);
2076
          };
2077
          return {
2078
            fold: (...foldArgs) => {
2079
              if (foldArgs.length !== cases.length) {
2080
                throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
2081
              }
2082
              const target = foldArgs[count];
2083
              return target.apply(null, args);
2084
            },
2085
            match,
2086
            log: label => {
2087
              console.log(label, {
2088
                constructors,
2089
                constructor: key,
2090
                params: args
2091
              });
2092
            }
2093
          };
2094
        };
2095
      });
2096
      return adt;
2097
    };
2098
    const Adt = { generate: generate$7 };
2099
 
2100
    Adt.generate([
2101
      {
2102
        bothErrors: [
2103
          'error1',
2104
          'error2'
2105
        ]
2106
      },
2107
      {
2108
        firstError: [
2109
          'error1',
2110
          'value2'
2111
        ]
2112
      },
2113
      {
2114
        secondError: [
2115
          'value1',
2116
          'error2'
2117
        ]
2118
      },
2119
      {
2120
        bothValues: [
2121
          'value1',
2122
          'value2'
2123
        ]
2124
      }
2125
    ]);
2126
    const partition$1 = results => {
2127
      const errors = [];
2128
      const values = [];
2129
      each$1(results, result => {
2130
        result.fold(err => {
2131
          errors.push(err);
2132
        }, value => {
2133
          values.push(value);
2134
        });
2135
      });
2136
      return {
2137
        errors,
2138
        values
2139
      };
2140
    };
2141
 
2142
    const exclude$1 = (obj, fields) => {
2143
      const r = {};
2144
      each(obj, (v, k) => {
2145
        if (!contains$2(fields, k)) {
2146
          r[k] = v;
2147
        }
2148
      });
2149
      return r;
2150
    };
2151
 
2152
    const wrap$2 = (key, value) => ({ [key]: value });
2153
    const wrapAll$1 = keyvalues => {
2154
      const r = {};
2155
      each$1(keyvalues, kv => {
2156
        r[kv.key] = kv.value;
2157
      });
2158
      return r;
2159
    };
2160
 
2161
    const exclude = (obj, fields) => exclude$1(obj, fields);
2162
    const wrap$1 = (key, value) => wrap$2(key, value);
2163
    const wrapAll = keyvalues => wrapAll$1(keyvalues);
2164
    const mergeValues = (values, base) => {
2165
      return values.length === 0 ? Result.value(base) : Result.value(deepMerge(base, merge$1.apply(undefined, values)));
2166
    };
2167
    const mergeErrors = errors => Result.error(flatten(errors));
2168
    const consolidate = (objs, base) => {
2169
      const partitions = partition$1(objs);
2170
      return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : mergeValues(partitions.values, base);
2171
    };
2172
 
2173
    const ensureIsRoot = isRoot => isFunction(isRoot) ? isRoot : never;
2174
    const ancestor$2 = (scope, transform, isRoot) => {
2175
      let element = scope.dom;
2176
      const stop = ensureIsRoot(isRoot);
2177
      while (element.parentNode) {
2178
        element = element.parentNode;
2179
        const el = SugarElement.fromDom(element);
2180
        const transformed = transform(el);
2181
        if (transformed.isSome()) {
2182
          return transformed;
2183
        } else if (stop(el)) {
2184
          break;
2185
        }
2186
      }
2187
      return Optional.none();
2188
    };
2189
    const closest$4 = (scope, transform, isRoot) => {
2190
      const current = transform(scope);
2191
      const stop = ensureIsRoot(isRoot);
2192
      return current.orThunk(() => stop(scope) ? Optional.none() : ancestor$2(scope, transform, stop));
2193
    };
2194
 
2195
    const isSource = (component, simulatedEvent) => eq(component.element, simulatedEvent.event.target);
2196
 
2197
    const defaultEventHandler = {
2198
      can: always,
2199
      abort: never,
2200
      run: noop
2201
    };
2202
    const nu$9 = parts => {
2203
      if (!hasNonNullableKey(parts, 'can') && !hasNonNullableKey(parts, 'abort') && !hasNonNullableKey(parts, 'run')) {
2204
        throw new Error('EventHandler defined by: ' + JSON.stringify(parts, null, 2) + ' does not have can, abort, or run!');
2205
      }
2206
      return {
2207
        ...defaultEventHandler,
2208
        ...parts
2209
      };
2210
    };
2211
    const all$2 = (handlers, f) => (...args) => foldl(handlers, (acc, handler) => acc && f(handler).apply(undefined, args), true);
2212
    const any = (handlers, f) => (...args) => foldl(handlers, (acc, handler) => acc || f(handler).apply(undefined, args), false);
2213
    const read$2 = handler => isFunction(handler) ? {
2214
      can: always,
2215
      abort: never,
2216
      run: handler
2217
    } : handler;
2218
    const fuse$1 = handlers => {
2219
      const can = all$2(handlers, handler => handler.can);
2220
      const abort = any(handlers, handler => handler.abort);
2221
      const run = (...args) => {
2222
        each$1(handlers, handler => {
2223
          handler.run.apply(undefined, args);
2224
        });
2225
      };
2226
      return {
2227
        can,
2228
        abort,
2229
        run
2230
      };
2231
    };
2232
 
2233
    const constant = constant$1;
2234
    const touchstart = constant('touchstart');
2235
    const touchmove = constant('touchmove');
2236
    const touchend = constant('touchend');
2237
    const touchcancel = constant('touchcancel');
2238
    const mousedown = constant('mousedown');
2239
    const mousemove = constant('mousemove');
2240
    const mouseout = constant('mouseout');
2241
    const mouseup = constant('mouseup');
2242
    const mouseover = constant('mouseover');
2243
    const focusin = constant('focusin');
2244
    const focusout = constant('focusout');
2245
    const keydown = constant('keydown');
2246
    const keyup = constant('keyup');
2247
    const input = constant('input');
2248
    const change = constant('change');
2249
    const click = constant('click');
2250
    const transitioncancel = constant('transitioncancel');
2251
    const transitionend = constant('transitionend');
2252
    const transitionstart = constant('transitionstart');
2253
    const selectstart = constant('selectstart');
2254
 
2255
    const prefixName = name => constant$1('alloy.' + name);
2256
    const alloy = { tap: prefixName('tap') };
2257
    const focus$4 = prefixName('focus');
2258
    const postBlur = prefixName('blur.post');
2259
    const postPaste = prefixName('paste.post');
2260
    const receive = prefixName('receive');
2261
    const execute$5 = prefixName('execute');
2262
    const focusItem = prefixName('focus.item');
2263
    const tap = alloy.tap;
2264
    const longpress = prefixName('longpress');
2265
    const sandboxClose = prefixName('sandbox.close');
2266
    const typeaheadCancel = prefixName('typeahead.cancel');
2267
    const systemInit = prefixName('system.init');
2268
    const documentTouchmove = prefixName('system.touchmove');
2269
    const documentTouchend = prefixName('system.touchend');
2270
    const windowScroll = prefixName('system.scroll');
2271
    const windowResize = prefixName('system.resize');
2272
    const attachedToDom = prefixName('system.attached');
2273
    const detachedFromDom = prefixName('system.detached');
2274
    const dismissRequested = prefixName('system.dismissRequested');
2275
    const repositionRequested = prefixName('system.repositionRequested');
2276
    const focusShifted = prefixName('focusmanager.shifted');
2277
    const slotVisibility = prefixName('slotcontainer.visibility');
2278
    const externalElementScroll = prefixName('system.external.element.scroll');
2279
    const changeTab = prefixName('change.tab');
2280
    const dismissTab = prefixName('dismiss.tab');
2281
    const highlight$1 = prefixName('highlight');
2282
    const dehighlight$1 = prefixName('dehighlight');
2283
 
2284
    const emit = (component, event) => {
2285
      dispatchWith(component, component.element, event, {});
2286
    };
2287
    const emitWith = (component, event, properties) => {
2288
      dispatchWith(component, component.element, event, properties);
2289
    };
2290
    const emitExecute = component => {
2291
      emit(component, execute$5());
2292
    };
2293
    const dispatch = (component, target, event) => {
2294
      dispatchWith(component, target, event, {});
2295
    };
2296
    const dispatchWith = (component, target, event, properties) => {
2297
      const data = {
2298
        target,
2299
        ...properties
2300
      };
2301
      component.getSystem().triggerEvent(event, target, data);
2302
    };
2303
    const retargetAndDispatchWith = (component, target, eventName, properties) => {
2304
      const data = {
2305
        ...properties,
2306
        target
2307
      };
2308
      component.getSystem().triggerEvent(eventName, target, data);
2309
    };
2310
    const dispatchEvent = (component, target, event, simulatedEvent) => {
2311
      component.getSystem().triggerEvent(event, target, simulatedEvent.event);
2312
    };
2313
 
2314
    const derive$2 = configs => wrapAll(configs);
2315
    const abort = (name, predicate) => {
2316
      return {
2317
        key: name,
2318
        value: nu$9({ abort: predicate })
2319
      };
2320
    };
2321
    const can = (name, predicate) => {
2322
      return {
2323
        key: name,
2324
        value: nu$9({ can: predicate })
2325
      };
2326
    };
2327
    const preventDefault = name => {
2328
      return {
2329
        key: name,
2330
        value: nu$9({
2331
          run: (component, simulatedEvent) => {
2332
            simulatedEvent.event.prevent();
2333
          }
2334
        })
2335
      };
2336
    };
2337
    const run$1 = (name, handler) => {
2338
      return {
2339
        key: name,
2340
        value: nu$9({ run: handler })
2341
      };
2342
    };
2343
    const runActionExtra = (name, action, extra) => {
2344
      return {
2345
        key: name,
2346
        value: nu$9({
2347
          run: (component, simulatedEvent) => {
2348
            action.apply(undefined, [
2349
              component,
2350
              simulatedEvent
2351
            ].concat(extra));
2352
          }
2353
        })
2354
      };
2355
    };
2356
    const runOnName = name => {
2357
      return handler => run$1(name, handler);
2358
    };
2359
    const runOnSourceName = name => {
2360
      return handler => ({
2361
        key: name,
2362
        value: nu$9({
2363
          run: (component, simulatedEvent) => {
2364
            if (isSource(component, simulatedEvent)) {
2365
              handler(component, simulatedEvent);
2366
            }
2367
          }
2368
        })
2369
      });
2370
    };
2371
    const redirectToUid = (name, uid) => {
2372
      return run$1(name, (component, simulatedEvent) => {
2373
        component.getSystem().getByUid(uid).each(redirectee => {
2374
          dispatchEvent(redirectee, redirectee.element, name, simulatedEvent);
2375
        });
2376
      });
2377
    };
2378
    const redirectToPart = (name, detail, partName) => {
2379
      const uid = detail.partUids[partName];
2380
      return redirectToUid(name, uid);
2381
    };
2382
    const runWithTarget = (name, f) => {
2383
      return run$1(name, (component, simulatedEvent) => {
2384
        const ev = simulatedEvent.event;
2385
        const target = component.getSystem().getByDom(ev.target).getOrThunk(() => {
2386
          const closest = closest$4(ev.target, el => component.getSystem().getByDom(el).toOptional(), never);
2387
          return closest.getOr(component);
2388
        });
2389
        f(component, target, simulatedEvent);
2390
      });
2391
    };
2392
    const cutter = name => {
2393
      return run$1(name, (component, simulatedEvent) => {
2394
        simulatedEvent.cut();
2395
      });
2396
    };
2397
    const stopper = name => {
2398
      return run$1(name, (component, simulatedEvent) => {
2399
        simulatedEvent.stop();
2400
      });
2401
    };
2402
    const runOnSource = (name, f) => {
2403
      return runOnSourceName(name)(f);
2404
    };
2405
    const runOnAttached = runOnSourceName(attachedToDom());
2406
    const runOnDetached = runOnSourceName(detachedFromDom());
2407
    const runOnInit = runOnSourceName(systemInit());
2408
    const runOnExecute$1 = runOnName(execute$5());
2409
 
1441 ariadna 2410
    const markAsBehaviourApi = (f, apiName, apiFunction) => {
2411
      const delegate = apiFunction.toString();
2412
      const endIndex = delegate.indexOf(')') + 1;
2413
      const openBracketIndex = delegate.indexOf('(');
2414
      const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
2415
      f.toFunctionAnnotation = () => ({
2416
        name: apiName,
2417
        parameters: cleanParameters(parameters.slice(0, 1).concat(parameters.slice(3)))
2418
      });
2419
      return f;
2420
    };
2421
    const cleanParameters = parameters => map$2(parameters, p => endsWith(p, '/*') ? p.substring(0, p.length - '/*'.length) : p);
2422
    const markAsExtraApi = (f, extraName) => {
2423
      const delegate = f.toString();
2424
      const endIndex = delegate.indexOf(')') + 1;
2425
      const openBracketIndex = delegate.indexOf('(');
2426
      const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
2427
      f.toFunctionAnnotation = () => ({
2428
        name: extraName,
2429
        parameters: cleanParameters(parameters)
2430
      });
2431
      return f;
2432
    };
2433
    const markAsSketchApi = (f, apiFunction) => {
2434
      const delegate = apiFunction.toString();
2435
      const endIndex = delegate.indexOf(')') + 1;
2436
      const openBracketIndex = delegate.indexOf('(');
2437
      const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
2438
      f.toFunctionAnnotation = () => ({
2439
        name: 'OVERRIDE',
2440
        parameters: cleanParameters(parameters.slice(1))
2441
      });
2442
      return f;
2443
    };
2444
 
2445
    const nu$8 = s => ({
2446
      classes: isUndefined(s.classes) ? [] : s.classes,
2447
      attributes: isUndefined(s.attributes) ? {} : s.attributes,
2448
      styles: isUndefined(s.styles) ? {} : s.styles
2449
    });
2450
    const merge = (defnA, mod) => ({
2451
      ...defnA,
2452
      attributes: {
2453
        ...defnA.attributes,
2454
        ...mod.attributes
2455
      },
2456
      styles: {
2457
        ...defnA.styles,
2458
        ...mod.styles
2459
      },
2460
      classes: defnA.classes.concat(mod.classes)
2461
    });
2462
 
2463
    const executeEvent = (bConfig, bState, executor) => runOnExecute$1(component => {
2464
      executor(component, bConfig, bState);
2465
    });
2466
    const loadEvent = (bConfig, bState, f) => runOnInit((component, _simulatedEvent) => {
2467
      f(component, bConfig, bState);
2468
    });
2469
    const create$5 = (schema, name, active, apis, extra, state) => {
2470
      const configSchema = objOfOnly(schema);
2471
      const schemaSchema = optionObjOf(name, [optionObjOfOnly('config', schema)]);
2472
      return doCreate(configSchema, schemaSchema, name, active, apis, extra, state);
2473
    };
2474
    const createModes$1 = (modes, name, active, apis, extra, state) => {
2475
      const configSchema = modes;
2476
      const schemaSchema = optionObjOf(name, [optionOf('config', modes)]);
2477
      return doCreate(configSchema, schemaSchema, name, active, apis, extra, state);
2478
    };
2479
    const wrapApi = (bName, apiFunction, apiName) => {
2480
      const f = (component, ...rest) => {
2481
        const args = [component].concat(rest);
2482
        return component.config({ name: constant$1(bName) }).fold(() => {
2483
          throw new Error('We could not find any behaviour configuration for: ' + bName + '. Using API: ' + apiName);
2484
        }, info => {
2485
          const rest = Array.prototype.slice.call(args, 1);
2486
          return apiFunction.apply(undefined, [
2487
            component,
2488
            info.config,
2489
            info.state
2490
          ].concat(rest));
2491
        });
2492
      };
2493
      return markAsBehaviourApi(f, apiName, apiFunction);
2494
    };
2495
    const revokeBehaviour = name => ({
2496
      key: name,
2497
      value: undefined
2498
    });
2499
    const doCreate = (configSchema, schemaSchema, name, active, apis, extra, state) => {
2500
      const getConfig = info => hasNonNullableKey(info, name) ? info[name]() : Optional.none();
2501
      const wrappedApis = map$1(apis, (apiF, apiName) => wrapApi(name, apiF, apiName));
2502
      const wrappedExtra = map$1(extra, (extraF, extraName) => markAsExtraApi(extraF, extraName));
2503
      const me = {
2504
        ...wrappedExtra,
2505
        ...wrappedApis,
2506
        revoke: curry(revokeBehaviour, name),
2507
        config: spec => {
2508
          const prepared = asRawOrDie$1(name + '-config', configSchema, spec);
2509
          return {
2510
            key: name,
2511
            value: {
2512
              config: prepared,
2513
              me,
2514
              configAsRaw: cached(() => asRawOrDie$1(name + '-config', configSchema, spec)),
2515
              initialConfig: spec,
2516
              state
2517
            }
2518
          };
2519
        },
2520
        schema: constant$1(schemaSchema),
2521
        exhibit: (info, base) => {
2522
          return lift2(getConfig(info), get$h(active, 'exhibit'), (behaviourInfo, exhibitor) => {
2523
            return exhibitor(base, behaviourInfo.config, behaviourInfo.state);
2524
          }).getOrThunk(() => nu$8({}));
2525
        },
2526
        name: constant$1(name),
2527
        handlers: info => {
2528
          return getConfig(info).map(behaviourInfo => {
2529
            const getEvents = get$h(active, 'events').getOr(() => ({}));
2530
            return getEvents(behaviourInfo.config, behaviourInfo.state);
2531
          }).getOr({});
2532
        }
2533
      };
2534
      return me;
2535
    };
2536
 
2537
    const NoState = { init: () => nu$7({ readState: constant$1('No State required') }) };
2538
    const nu$7 = spec => spec;
2539
 
2540
    const derive$1 = capabilities => wrapAll(capabilities);
2541
    const simpleSchema = objOfOnly([
2542
      required$1('fields'),
2543
      required$1('name'),
2544
      defaulted('active', {}),
2545
      defaulted('apis', {}),
2546
      defaulted('state', NoState),
2547
      defaulted('extra', {})
2548
    ]);
2549
    const create$4 = data => {
2550
      const value = asRawOrDie$1('Creating behaviour: ' + data.name, simpleSchema, data);
2551
      return create$5(value.fields, value.name, value.active, value.apis, value.extra, value.state);
2552
    };
2553
    const modeSchema = objOfOnly([
2554
      required$1('branchKey'),
2555
      required$1('branches'),
2556
      required$1('name'),
2557
      defaulted('active', {}),
2558
      defaulted('apis', {}),
2559
      defaulted('state', NoState),
2560
      defaulted('extra', {})
2561
    ]);
2562
    const createModes = data => {
2563
      const value = asRawOrDie$1('Creating behaviour: ' + data.name, modeSchema, data);
2564
      return createModes$1(choose$1(value.branchKey, value.branches), value.name, value.active, value.apis, value.extra, value.state);
2565
    };
2566
    const revoke = constant$1(undefined);
2567
 
2568
    const read$1 = (element, attr) => {
2569
      const value = get$g(element, attr);
2570
      return value === undefined || value === '' ? [] : value.split(' ');
2571
    };
2572
    const add$4 = (element, attr, id) => {
2573
      const old = read$1(element, attr);
2574
      const nu = old.concat([id]);
2575
      set$9(element, attr, nu.join(' '));
2576
      return true;
2577
    };
2578
    const remove$5 = (element, attr, id) => {
2579
      const nu = filter$2(read$1(element, attr), v => v !== id);
2580
      if (nu.length > 0) {
2581
        set$9(element, attr, nu.join(' '));
2582
      } else {
2583
        remove$8(element, attr);
2584
      }
2585
      return false;
2586
    };
2587
 
2588
    const supports = element => element.dom.classList !== undefined;
2589
    const get$a = element => read$1(element, 'class');
2590
    const add$3 = (element, clazz) => add$4(element, 'class', clazz);
2591
    const remove$4 = (element, clazz) => remove$5(element, 'class', clazz);
2592
    const toggle$5 = (element, clazz) => {
2593
      if (contains$2(get$a(element), clazz)) {
2594
        return remove$4(element, clazz);
2595
      } else {
2596
        return add$3(element, clazz);
2597
      }
2598
    };
2599
 
2600
    const add$2 = (element, clazz) => {
2601
      if (supports(element)) {
2602
        element.dom.classList.add(clazz);
2603
      } else {
2604
        add$3(element, clazz);
2605
      }
2606
    };
2607
    const cleanClass = element => {
2608
      const classList = supports(element) ? element.dom.classList : get$a(element);
2609
      if (classList.length === 0) {
2610
        remove$8(element, 'class');
2611
      }
2612
    };
2613
    const remove$3 = (element, clazz) => {
2614
      if (supports(element)) {
2615
        const classList = element.dom.classList;
2616
        classList.remove(clazz);
2617
      } else {
2618
        remove$4(element, clazz);
2619
      }
2620
      cleanClass(element);
2621
    };
2622
    const toggle$4 = (element, clazz) => {
2623
      const result = supports(element) ? element.dom.classList.toggle(clazz) : toggle$5(element, clazz);
2624
      cleanClass(element);
2625
      return result;
2626
    };
2627
    const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz);
2628
 
2629
    const add$1 = (element, classes) => {
2630
      each$1(classes, x => {
2631
        add$2(element, x);
2632
      });
2633
    };
2634
    const remove$2 = (element, classes) => {
2635
      each$1(classes, x => {
2636
        remove$3(element, x);
2637
      });
2638
    };
2639
    const toggle$3 = (element, classes) => {
2640
      each$1(classes, x => {
2641
        toggle$4(element, x);
2642
      });
2643
    };
2644
    const hasAll = (element, classes) => forall(classes, clazz => has(element, clazz));
2645
    const getNative = element => {
2646
      const classList = element.dom.classList;
2647
      const r = new Array(classList.length);
2648
      for (let i = 0; i < classList.length; i++) {
2649
        const item = classList.item(i);
2650
        if (item !== null) {
2651
          r[i] = item;
2652
        }
2653
      }
2654
      return r;
2655
    };
2656
    const get$9 = element => supports(element) ? getNative(element) : get$a(element);
2657
 
2658
    const NuPositionCss = (position, left, top, right, bottom) => {
2659
      const toPx = num => num + 'px';
2660
      return {
2661
        position,
2662
        left: left.map(toPx),
2663
        top: top.map(toPx),
2664
        right: right.map(toPx),
2665
        bottom: bottom.map(toPx)
2666
      };
2667
    };
2668
    const toOptions = position => ({
2669
      ...position,
2670
      position: Optional.some(position.position)
2671
    });
2672
    const applyPositionCss = (element, position) => {
2673
      setOptions(element, toOptions(position));
2674
    };
2675
 
2676
    const getOffsetParent = element => {
2677
      const isFixed = is$1(getRaw(element, 'position'), 'fixed');
2678
      const offsetParent$1 = isFixed ? Optional.none() : offsetParent(element);
2679
      return offsetParent$1.orThunk(() => {
2680
        const marker = SugarElement.fromTag('span');
2681
        return parent(element).bind(parent => {
2682
          append$2(parent, marker);
2683
          const offsetParent$1 = offsetParent(marker);
2684
          remove$6(marker);
2685
          return offsetParent$1;
2686
        });
2687
      });
2688
    };
2689
    const getOrigin = element => getOffsetParent(element).map(absolute$3).getOrThunk(() => SugarPosition(0, 0));
2690
 
2691
    const appear = (component, contextualInfo) => {
2692
      const elem = component.element;
2693
      add$2(elem, contextualInfo.transitionClass);
2694
      remove$3(elem, contextualInfo.fadeOutClass);
2695
      add$2(elem, contextualInfo.fadeInClass);
2696
      contextualInfo.onShow(component);
2697
    };
2698
    const disappear = (component, contextualInfo) => {
2699
      const elem = component.element;
2700
      add$2(elem, contextualInfo.transitionClass);
2701
      remove$3(elem, contextualInfo.fadeInClass);
2702
      add$2(elem, contextualInfo.fadeOutClass);
2703
      contextualInfo.onHide(component);
2704
    };
2705
    const isPartiallyVisible = (box, bounds) => box.y < bounds.bottom && box.bottom > bounds.y;
2706
    const isTopCompletelyVisible = (box, bounds) => box.y >= bounds.y;
2707
    const isBottomCompletelyVisible = (box, bounds) => box.bottom <= bounds.bottom;
2708
    const forceTopPosition = (winBox, leftX, viewport) => ({
2709
      location: 'top',
2710
      leftX,
2711
      topY: viewport.bounds.y - winBox.y
2712
    });
2713
    const forceBottomPosition = (winBox, leftX, viewport) => ({
2714
      location: 'bottom',
2715
      leftX,
2716
      bottomY: winBox.bottom - viewport.bounds.bottom
2717
    });
2718
    const getDockedLeftPosition = bounds => {
2719
      return bounds.box.x - bounds.win.x;
2720
    };
2721
    const tryDockingPosition = (modes, bounds, viewport) => {
2722
      const winBox = bounds.win;
2723
      const box = bounds.box;
2724
      const leftX = getDockedLeftPosition(bounds);
2725
      return findMap(modes, mode => {
2726
        switch (mode) {
2727
        case 'bottom':
2728
          return !isBottomCompletelyVisible(box, viewport.bounds) ? Optional.some(forceBottomPosition(winBox, leftX, viewport)) : Optional.none();
2729
        case 'top':
2730
          return !isTopCompletelyVisible(box, viewport.bounds) ? Optional.some(forceTopPosition(winBox, leftX, viewport)) : Optional.none();
2731
        default:
2732
          return Optional.none();
2733
        }
2734
      }).getOr({ location: 'no-dock' });
2735
    };
2736
    const isVisibleForModes = (modes, box, viewport) => forall(modes, mode => {
2737
      switch (mode) {
2738
      case 'bottom':
2739
        return isBottomCompletelyVisible(box, viewport.bounds);
2740
      case 'top':
2741
        return isTopCompletelyVisible(box, viewport.bounds);
2742
      }
2743
    });
2744
    const getXYForRestoring = (pos, viewport) => {
2745
      const priorY = viewport.optScrollEnv.fold(constant$1(pos.bounds.y), scrollEnv => scrollEnv.scrollElmTop + (pos.bounds.y - scrollEnv.currentScrollTop));
2746
      return SugarPosition(pos.bounds.x, priorY);
2747
    };
2748
    const getXYForSaving = (box, viewport) => {
2749
      const priorY = viewport.optScrollEnv.fold(constant$1(box.y), scrollEnv => box.y + scrollEnv.currentScrollTop - scrollEnv.scrollElmTop);
2750
      return SugarPosition(box.x, priorY);
2751
    };
2752
    const getPrior = (elem, viewport, state) => state.getInitialPos().map(pos => {
2753
      const xy = getXYForRestoring(pos, viewport);
2754
      return {
2755
        box: bounds(xy.left, xy.top, get$d(elem), get$e(elem)),
2756
        location: pos.location
2757
      };
2758
    });
2759
    const storePrior = (elem, box, viewport, state, decision) => {
2760
      const xy = getXYForSaving(box, viewport);
2761
      const bounds$1 = bounds(xy.left, xy.top, box.width, box.height);
2762
      state.setInitialPos({
2763
        style: getAllRaw(elem),
2764
        position: get$f(elem, 'position') || 'static',
2765
        bounds: bounds$1,
2766
        location: decision.location
2767
      });
2768
    };
2769
    const storePriorIfNone = (elem, box, viewport, state, decision) => {
2770
      state.getInitialPos().fold(() => storePrior(elem, box, viewport, state, decision), () => noop);
2771
    };
2772
    const revertToOriginal = (elem, box, state) => state.getInitialPos().bind(position => {
2773
      var _a;
2774
      state.clearInitialPos();
2775
      switch (position.position) {
2776
      case 'static':
2777
        return Optional.some({ morph: 'static' });
2778
      case 'absolute':
2779
        const offsetParent = getOffsetParent(elem).getOr(body());
2780
        const offsetBox = box$1(offsetParent);
2781
        const scrollDelta = (_a = offsetParent.dom.scrollTop) !== null && _a !== void 0 ? _a : 0;
2782
        return Optional.some({
2783
          morph: 'absolute',
2784
          positionCss: NuPositionCss('absolute', get$h(position.style, 'left').map(_left => box.x - offsetBox.x), get$h(position.style, 'top').map(_top => box.y - offsetBox.y + scrollDelta), get$h(position.style, 'right').map(_right => offsetBox.right - box.right), get$h(position.style, 'bottom').map(_bottom => offsetBox.bottom - box.bottom))
2785
        });
2786
      default:
2787
        return Optional.none();
2788
      }
2789
    });
2790
    const tryMorphToOriginal = (elem, viewport, state) => getPrior(elem, viewport, state).filter(({box}) => isVisibleForModes(state.getModes(), box, viewport)).bind(({box}) => revertToOriginal(elem, box, state));
2791
    const tryDecisionToFixedMorph = decision => {
2792
      switch (decision.location) {
2793
      case 'top': {
2794
          return Optional.some({
2795
            morph: 'fixed',
2796
            positionCss: NuPositionCss('fixed', Optional.some(decision.leftX), Optional.some(decision.topY), Optional.none(), Optional.none())
2797
          });
2798
        }
2799
      case 'bottom': {
2800
          return Optional.some({
2801
            morph: 'fixed',
2802
            positionCss: NuPositionCss('fixed', Optional.some(decision.leftX), Optional.none(), Optional.none(), Optional.some(decision.bottomY))
2803
          });
2804
        }
2805
      default:
2806
        return Optional.none();
2807
      }
2808
    };
2809
    const tryMorphToFixed = (elem, viewport, state) => {
2810
      const box = box$1(elem);
2811
      const winBox = win();
2812
      const decision = tryDockingPosition(state.getModes(), {
2813
        win: winBox,
2814
        box
2815
      }, viewport);
2816
      if (decision.location === 'top' || decision.location === 'bottom') {
2817
        storePrior(elem, box, viewport, state, decision);
2818
        return tryDecisionToFixedMorph(decision);
2819
      } else {
2820
        return Optional.none();
2821
      }
2822
    };
2823
    const tryMorphToOriginalOrUpdateFixed = (elem, viewport, state) => {
2824
      return tryMorphToOriginal(elem, viewport, state).orThunk(() => {
2825
        return viewport.optScrollEnv.bind(_ => getPrior(elem, viewport, state)).bind(({box, location}) => {
2826
          const winBox = win();
2827
          const leftX = getDockedLeftPosition({
2828
            win: winBox,
2829
            box
2830
          });
2831
          const decision = location === 'top' ? forceTopPosition(winBox, leftX, viewport) : forceBottomPosition(winBox, leftX, viewport);
2832
          return tryDecisionToFixedMorph(decision);
2833
        });
2834
      });
2835
    };
2836
    const tryMorph = (component, viewport, state) => {
2837
      const elem = component.element;
2838
      const isDocked = is$1(getRaw(elem, 'position'), 'fixed');
2839
      return isDocked ? tryMorphToOriginalOrUpdateFixed(elem, viewport, state) : tryMorphToFixed(elem, viewport, state);
2840
    };
2841
    const calculateMorphToOriginal = (component, viewport, state) => {
2842
      const elem = component.element;
2843
      return getPrior(elem, viewport, state).bind(({box}) => revertToOriginal(elem, box, state));
2844
    };
2845
    const forceDockWith = (elem, viewport, state, getDecision) => {
2846
      const box = box$1(elem);
2847
      const winBox = win();
2848
      const leftX = getDockedLeftPosition({
2849
        win: winBox,
2850
        box
2851
      });
2852
      const decision = getDecision(winBox, leftX, viewport);
2853
      if (decision.location === 'bottom' || decision.location === 'top') {
2854
        storePriorIfNone(elem, box, viewport, state, decision);
2855
        return tryDecisionToFixedMorph(decision);
2856
      } else {
2857
        return Optional.none();
2858
      }
2859
    };
2860
 
2861
    const morphToStatic = (component, config, state) => {
2862
      state.setDocked(false);
2863
      each$1([
2864
        'left',
2865
        'right',
2866
        'top',
2867
        'bottom',
2868
        'position'
2869
      ], prop => remove$7(component.element, prop));
2870
      config.onUndocked(component);
2871
    };
2872
    const morphToCoord = (component, config, state, position) => {
2873
      const isDocked = position.position === 'fixed';
2874
      state.setDocked(isDocked);
2875
      applyPositionCss(component.element, position);
2876
      const method = isDocked ? config.onDocked : config.onUndocked;
2877
      method(component);
2878
    };
2879
    const updateVisibility = (component, config, state, viewport, morphToDocked = false) => {
2880
      config.contextual.each(contextInfo => {
2881
        contextInfo.lazyContext(component).each(box => {
2882
          const isVisible = isPartiallyVisible(box, viewport.bounds);
2883
          if (isVisible !== state.isVisible()) {
2884
            state.setVisible(isVisible);
2885
            if (morphToDocked && !isVisible) {
2886
              add$1(component.element, [contextInfo.fadeOutClass]);
2887
              contextInfo.onHide(component);
2888
            } else {
2889
              const method = isVisible ? appear : disappear;
2890
              method(component, contextInfo);
2891
            }
2892
          }
2893
        });
2894
      });
2895
    };
2896
    const applyFixedMorph = (component, config, state, viewport, morph) => {
2897
      updateVisibility(component, config, state, viewport, true);
2898
      morphToCoord(component, config, state, morph.positionCss);
2899
    };
2900
    const applyMorph = (component, config, state, viewport, morph) => {
2901
      switch (morph.morph) {
2902
      case 'static': {
2903
          return morphToStatic(component, config, state);
2904
        }
2905
      case 'absolute': {
2906
          return morphToCoord(component, config, state, morph.positionCss);
2907
        }
2908
      case 'fixed': {
2909
          return applyFixedMorph(component, config, state, viewport, morph);
2910
        }
2911
      }
2912
    };
2913
    const refreshInternal = (component, config, state) => {
2914
      const viewport = config.lazyViewport(component);
2915
      updateVisibility(component, config, state, viewport);
2916
      tryMorph(component, viewport, state).each(morph => {
2917
        applyMorph(component, config, state, viewport, morph);
2918
      });
2919
    };
2920
    const resetInternal = (component, config, state) => {
2921
      const elem = component.element;
2922
      state.setDocked(false);
2923
      const viewport = config.lazyViewport(component);
2924
      calculateMorphToOriginal(component, viewport, state).each(staticOrAbsoluteMorph => {
2925
        switch (staticOrAbsoluteMorph.morph) {
2926
        case 'static': {
2927
            morphToStatic(component, config, state);
2928
            break;
2929
          }
2930
        case 'absolute': {
2931
            morphToCoord(component, config, state, staticOrAbsoluteMorph.positionCss);
2932
            break;
2933
          }
2934
        }
2935
      });
2936
      state.setVisible(true);
2937
      config.contextual.each(contextInfo => {
2938
        remove$2(elem, [
2939
          contextInfo.fadeInClass,
2940
          contextInfo.fadeOutClass,
2941
          contextInfo.transitionClass
2942
        ]);
2943
        contextInfo.onShow(component);
2944
      });
2945
      refresh$4(component, config, state);
2946
    };
2947
    const refresh$4 = (component, config, state) => {
2948
      if (component.getSystem().isConnected()) {
2949
        refreshInternal(component, config, state);
2950
      }
2951
    };
2952
    const reset$2 = (component, config, state) => {
2953
      if (state.isDocked()) {
2954
        resetInternal(component, config, state);
2955
      }
2956
    };
2957
    const forceDockWithDecision = getDecision => (component, config, state) => {
2958
      const viewport = config.lazyViewport(component);
2959
      const optMorph = forceDockWith(component.element, viewport, state, getDecision);
2960
      optMorph.each(morph => {
2961
        applyFixedMorph(component, config, state, viewport, morph);
2962
      });
2963
    };
2964
    const forceDockToTop = forceDockWithDecision(forceTopPosition);
2965
    const forceDockToBottom = forceDockWithDecision(forceBottomPosition);
2966
    const isDocked$2 = (component, config, state) => state.isDocked();
2967
    const setModes = (component, config, state, modes) => state.setModes(modes);
2968
    const getModes = (component, config, state) => state.getModes();
2969
 
2970
    var DockingApis = /*#__PURE__*/Object.freeze({
2971
        __proto__: null,
2972
        refresh: refresh$4,
2973
        reset: reset$2,
2974
        isDocked: isDocked$2,
2975
        getModes: getModes,
2976
        setModes: setModes,
2977
        forceDockToTop: forceDockToTop,
2978
        forceDockToBottom: forceDockToBottom
2979
    });
2980
 
2981
    const events$i = (dockInfo, dockState) => derive$2([
2982
      runOnSource(transitionend(), (component, simulatedEvent) => {
2983
        dockInfo.contextual.each(contextInfo => {
2984
          if (has(component.element, contextInfo.transitionClass)) {
2985
            remove$2(component.element, [
2986
              contextInfo.transitionClass,
2987
              contextInfo.fadeInClass
2988
            ]);
2989
            const notify = dockState.isVisible() ? contextInfo.onShown : contextInfo.onHidden;
2990
            notify(component);
2991
          }
2992
          simulatedEvent.stop();
2993
        });
2994
      }),
2995
      run$1(windowScroll(), (component, _) => {
2996
        refresh$4(component, dockInfo, dockState);
2997
      }),
2998
      run$1(externalElementScroll(), (component, _) => {
2999
        refresh$4(component, dockInfo, dockState);
3000
      }),
3001
      run$1(windowResize(), (component, _) => {
3002
        reset$2(component, dockInfo, dockState);
3003
      })
3004
    ]);
3005
 
3006
    var ActiveDocking = /*#__PURE__*/Object.freeze({
3007
        __proto__: null,
3008
        events: events$i
3009
    });
3010
 
1 efrain 3011
    const fromHtml$1 = (html, scope) => {
3012
      const doc = scope || document;
3013
      const div = doc.createElement('div');
3014
      div.innerHTML = html;
3015
      return children(SugarElement.fromDom(div));
3016
    };
3017
 
1441 ariadna 3018
    const get$8 = element => element.dom.innerHTML;
1 efrain 3019
    const set$6 = (element, content) => {
3020
      const owner = owner$4(element);
3021
      const docDom = owner.dom;
3022
      const fragment = SugarElement.fromDom(docDom.createDocumentFragment());
3023
      const contentElements = fromHtml$1(content, docDom);
3024
      append$1(fragment, contentElements);
3025
      empty(element);
3026
      append$2(element, fragment);
3027
    };
3028
    const getOuter = element => {
3029
      const container = SugarElement.fromTag('div');
3030
      const clone = SugarElement.fromDom(element.dom.cloneNode(true));
3031
      append$2(container, clone);
1441 ariadna 3032
      return get$8(container);
1 efrain 3033
    };
3034
 
3035
    const clone$1 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
3036
    const shallow = original => clone$1(original, false);
3037
    const deep = original => clone$1(original, true);
3038
 
3039
    const getHtml = element => {
3040
      if (isShadowRoot(element)) {
3041
        return '#shadow-root';
3042
      } else {
3043
        const clone = shallow(element);
3044
        return getOuter(clone);
3045
      }
3046
    };
3047
 
3048
    const element = elem => getHtml(elem);
3049
 
1441 ariadna 3050
    const unknown = 'unknown';
3051
    var EventConfiguration;
3052
    (function (EventConfiguration) {
3053
      EventConfiguration[EventConfiguration['STOP'] = 0] = 'STOP';
3054
      EventConfiguration[EventConfiguration['NORMAL'] = 1] = 'NORMAL';
3055
      EventConfiguration[EventConfiguration['LOGGING'] = 2] = 'LOGGING';
3056
    }(EventConfiguration || (EventConfiguration = {})));
3057
    const eventConfig = Cell({});
3058
    const makeEventLogger = (eventName, initialTarget) => {
3059
      const sequence = [];
3060
      const startTime = new Date().getTime();
3061
      return {
3062
        logEventCut: (_name, target, purpose) => {
3063
          sequence.push({
3064
            outcome: 'cut',
3065
            target,
3066
            purpose
3067
          });
3068
        },
3069
        logEventStopped: (_name, target, purpose) => {
3070
          sequence.push({
3071
            outcome: 'stopped',
3072
            target,
3073
            purpose
3074
          });
3075
        },
3076
        logNoParent: (_name, target, purpose) => {
3077
          sequence.push({
3078
            outcome: 'no-parent',
3079
            target,
3080
            purpose
3081
          });
3082
        },
3083
        logEventNoHandlers: (_name, target) => {
3084
          sequence.push({
3085
            outcome: 'no-handlers-left',
3086
            target
3087
          });
3088
        },
3089
        logEventResponse: (_name, target, purpose) => {
3090
          sequence.push({
3091
            outcome: 'response',
3092
            purpose,
3093
            target
3094
          });
3095
        },
3096
        write: () => {
3097
          const finishTime = new Date().getTime();
3098
          if (contains$2([
3099
              'mousemove',
3100
              'mouseover',
3101
              'mouseout',
3102
              systemInit()
3103
            ], eventName)) {
3104
            return;
3105
          }
3106
          console.log(eventName, {
3107
            event: eventName,
3108
            time: finishTime - startTime,
3109
            target: initialTarget.dom,
3110
            sequence: map$2(sequence, s => {
3111
              if (!contains$2([
3112
                  'cut',
3113
                  'stopped',
3114
                  'response'
3115
                ], s.outcome)) {
3116
                return s.outcome;
3117
              } else {
3118
                return '{' + s.purpose + '} ' + s.outcome + ' at (' + element(s.target) + ')';
3119
              }
3120
            })
3121
          });
3122
        }
3123
      };
3124
    };
3125
    const processEvent = (eventName, initialTarget, f) => {
3126
      const status = get$h(eventConfig.get(), eventName).orThunk(() => {
3127
        const patterns = keys(eventConfig.get());
3128
        return findMap(patterns, p => eventName.indexOf(p) > -1 ? Optional.some(eventConfig.get()[p]) : Optional.none());
3129
      }).getOr(EventConfiguration.NORMAL);
3130
      switch (status) {
3131
      case EventConfiguration.NORMAL:
3132
        return f(noLogger());
3133
      case EventConfiguration.LOGGING: {
3134
          const logger = makeEventLogger(eventName, initialTarget);
3135
          const output = f(logger);
3136
          logger.write();
3137
          return output;
3138
        }
3139
      case EventConfiguration.STOP:
3140
        return true;
3141
      }
3142
    };
3143
    const path = [
3144
      'alloy/data/Fields',
3145
      'alloy/debugging/Debugging'
3146
    ];
3147
    const getTrace = () => {
3148
      const err = new Error();
3149
      if (err.stack !== undefined) {
3150
        const lines = err.stack.split('\n');
3151
        return find$5(lines, line => line.indexOf('alloy') > 0 && !exists(path, p => line.indexOf(p) > -1)).getOr(unknown);
3152
      } else {
3153
        return unknown;
3154
      }
3155
    };
3156
    const ignoreEvent = {
3157
      logEventCut: noop,
3158
      logEventStopped: noop,
3159
      logNoParent: noop,
3160
      logEventNoHandlers: noop,
3161
      logEventResponse: noop,
3162
      write: noop
3163
    };
3164
    const monitorEvent = (eventName, initialTarget, f) => processEvent(eventName, initialTarget, f);
3165
    const noLogger = constant$1(ignoreEvent);
3166
 
3167
    const menuFields = constant$1([
3168
      required$1('menu'),
3169
      required$1('selectedMenu')
3170
    ]);
3171
    const itemFields = constant$1([
3172
      required$1('item'),
3173
      required$1('selectedItem')
3174
    ]);
3175
    constant$1(objOf(itemFields().concat(menuFields())));
3176
    const itemSchema$3 = constant$1(objOf(itemFields()));
3177
 
3178
    const _initSize = requiredObjOf('initSize', [
3179
      required$1('numColumns'),
3180
      required$1('numRows')
3181
    ]);
3182
    const itemMarkers = () => requiredOf('markers', itemSchema$3());
3183
    const tieredMenuMarkers = () => requiredObjOf('markers', [required$1('backgroundMenu')].concat(menuFields()).concat(itemFields()));
3184
    const markers$1 = required => requiredObjOf('markers', map$2(required, required$1));
3185
    const onPresenceHandler = (label, fieldName, presence) => {
3186
      getTrace();
3187
      return field$1(fieldName, fieldName, presence, valueOf(f => Result.value((...args) => {
3188
        return f.apply(undefined, args);
3189
      })));
3190
    };
3191
    const onHandler = fieldName => onPresenceHandler('onHandler', fieldName, defaulted$1(noop));
3192
    const onKeyboardHandler = fieldName => onPresenceHandler('onKeyboardHandler', fieldName, defaulted$1(Optional.none));
3193
    const onStrictHandler = fieldName => onPresenceHandler('onHandler', fieldName, required$2());
3194
    const onStrictKeyboardHandler = fieldName => onPresenceHandler('onKeyboardHandler', fieldName, required$2());
3195
    const output$1 = (name, value) => customField(name, constant$1(value));
3196
    const snapshot = name => customField(name, identity);
3197
    const initSize = constant$1(_initSize);
3198
 
3199
    var DockingSchema = [
3200
      optionObjOf('contextual', [
3201
        requiredString('fadeInClass'),
3202
        requiredString('fadeOutClass'),
3203
        requiredString('transitionClass'),
3204
        requiredFunction('lazyContext'),
3205
        onHandler('onShow'),
3206
        onHandler('onShown'),
3207
        onHandler('onHide'),
3208
        onHandler('onHidden')
3209
      ]),
3210
      defaultedFunction('lazyViewport', () => ({
3211
        bounds: win(),
3212
        optScrollEnv: Optional.none()
3213
      })),
3214
      defaultedArrayOf('modes', [
3215
        'top',
3216
        'bottom'
3217
      ], string),
3218
      onHandler('onDocked'),
3219
      onHandler('onUndocked')
3220
    ];
3221
 
3222
    const init$g = spec => {
3223
      const docked = Cell(false);
3224
      const visible = Cell(true);
3225
      const initialBounds = value$4();
3226
      const modes = Cell(spec.modes);
3227
      const readState = () => `docked:  ${ docked.get() }, visible: ${ visible.get() }, modes: ${ modes.get().join(',') }`;
3228
      return nu$7({
3229
        isDocked: docked.get,
3230
        setDocked: docked.set,
3231
        getInitialPos: initialBounds.get,
3232
        setInitialPos: initialBounds.set,
3233
        clearInitialPos: initialBounds.clear,
3234
        isVisible: visible.get,
3235
        setVisible: visible.set,
3236
        getModes: modes.get,
3237
        setModes: modes.set,
3238
        readState
3239
      });
3240
    };
3241
 
3242
    var DockingState = /*#__PURE__*/Object.freeze({
3243
        __proto__: null,
3244
        init: init$g
3245
    });
3246
 
3247
    const Docking = create$4({
3248
      fields: DockingSchema,
3249
      name: 'docking',
3250
      active: ActiveDocking,
3251
      apis: DockingApis,
3252
      state: DockingState
3253
    });
3254
 
1 efrain 3255
    const isRecursive = (component, originator, target) => eq(originator, component.element) && !eq(originator, target);
1441 ariadna 3256
    const events$h = derive$2([can(focus$4(), (component, simulatedEvent) => {
1 efrain 3257
        const event = simulatedEvent.event;
3258
        const originator = event.originator;
3259
        const target = event.target;
3260
        if (isRecursive(component, originator, target)) {
3261
          console.warn(focus$4() + ' did not get interpreted by the desired target. ' + '\nOriginator: ' + element(originator) + '\nTarget: ' + element(target) + '\nCheck the ' + focus$4() + ' event handlers');
3262
          return false;
3263
        } else {
3264
          return true;
3265
        }
3266
      })]);
3267
 
3268
    var DefaultEvents = /*#__PURE__*/Object.freeze({
3269
        __proto__: null,
1441 ariadna 3270
        events: events$h
1 efrain 3271
    });
3272
 
1441 ariadna 3273
    const cycleBy = (value, delta, min, max) => {
3274
      const r = value + delta;
3275
      if (r > max) {
3276
        return min;
3277
      } else if (r < min) {
3278
        return max;
3279
      } else {
3280
        return r;
3281
      }
3282
    };
3283
    const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
3284
    const random = () => window.crypto.getRandomValues(new Uint32Array(1))[0] / 4294967295;
3285
 
1 efrain 3286
    let unique = 0;
3287
    const generate$6 = prefix => {
3288
      const date = new Date();
3289
      const time = date.getTime();
1441 ariadna 3290
      const random$1 = Math.floor(random() * 1000000000);
1 efrain 3291
      unique++;
1441 ariadna 3292
      return prefix + '_' + random$1 + unique + String(time);
1 efrain 3293
    };
3294
 
3295
    const prefix$1 = constant$1('alloy-id-');
3296
    const idAttr$1 = constant$1('data-alloy-id');
3297
 
3298
    const prefix = prefix$1();
3299
    const idAttr = idAttr$1();
3300
    const write = (label, elem) => {
3301
      const id = generate$6(prefix + label);
3302
      writeOnly(elem, id);
3303
      return id;
3304
    };
3305
    const writeOnly = (elem, uid) => {
3306
      Object.defineProperty(elem.dom, idAttr, {
3307
        value: uid,
3308
        writable: true
3309
      });
3310
    };
1441 ariadna 3311
    const read = elem => {
1 efrain 3312
      const id = isElement$1(elem) ? elem.dom[idAttr] : null;
3313
      return Optional.from(id);
3314
    };
3315
    const generate$5 = prefix => generate$6(prefix);
3316
 
3317
    const make$8 = identity;
3318
 
3319
    const NoContextApi = getComp => {
3320
      const getMessage = event => `The component must be in a context to execute: ${ event }` + (getComp ? '\n' + element(getComp().element) + ' is not in context.' : '');
3321
      const fail = event => () => {
3322
        throw new Error(getMessage(event));
3323
      };
3324
      const warn = event => () => {
3325
        console.warn(getMessage(event));
3326
      };
3327
      return {
3328
        debugInfo: constant$1('fake'),
3329
        triggerEvent: warn('triggerEvent'),
3330
        triggerFocus: warn('triggerFocus'),
3331
        triggerEscape: warn('triggerEscape'),
3332
        broadcast: warn('broadcast'),
3333
        broadcastOn: warn('broadcastOn'),
3334
        broadcastEvent: warn('broadcastEvent'),
3335
        build: fail('build'),
3336
        buildOrPatch: fail('buildOrPatch'),
3337
        addToWorld: fail('addToWorld'),
3338
        removeFromWorld: fail('removeFromWorld'),
3339
        addToGui: fail('addToGui'),
3340
        removeFromGui: fail('removeFromGui'),
3341
        getByUid: fail('getByUid'),
3342
        getByDom: fail('getByDom'),
3343
        isConnected: never
3344
      };
3345
    };
1441 ariadna 3346
    const singleton = NoContextApi();
1 efrain 3347
 
3348
    const premadeTag = generate$6('alloy-premade');
3349
    const premade$1 = comp => {
3350
      Object.defineProperty(comp.element.dom, premadeTag, {
3351
        value: comp.uid,
3352
        writable: true
3353
      });
3354
      return wrap$1(premadeTag, comp);
3355
    };
3356
    const isPremade = element => has$2(element.dom, premadeTag);
1441 ariadna 3357
    const getPremade = spec => get$h(spec, premadeTag);
1 efrain 3358
    const makeApi = f => markAsSketchApi((component, ...rest) => f(component.getApis(), component, ...rest), f);
3359
 
3360
    const generateFrom$1 = (spec, all) => {
3361
      const schema = map$2(all, a => optionObjOf(a.name(), [
3362
        required$1('config'),
3363
        defaulted('state', NoState)
3364
      ]));
3365
      const validated = asRaw('component.behaviours', objOf(schema), spec.behaviours).fold(errInfo => {
3366
        throw new Error(formatError(errInfo) + '\nComplete spec:\n' + JSON.stringify(spec, null, 2));
3367
      }, identity);
3368
      return {
3369
        list: all,
3370
        data: map$1(validated, optBlobThunk => {
3371
          const output = optBlobThunk.map(blob => ({
3372
            config: blob.config,
3373
            state: blob.state.init(blob.config)
3374
          }));
3375
          return constant$1(output);
3376
        })
3377
      };
3378
    };
3379
    const getBehaviours$3 = bData => bData.list;
3380
    const getData$2 = bData => bData.data;
3381
 
3382
    const byInnerKey = (data, tuple) => {
3383
      const r = {};
3384
      each(data, (detail, key) => {
3385
        each(detail, (value, indexKey) => {
1441 ariadna 3386
          const chain = get$h(r, indexKey).getOr([]);
1 efrain 3387
          r[indexKey] = chain.concat([tuple(key, value)]);
3388
        });
3389
      });
3390
      return r;
3391
    };
3392
 
3393
    const combine$2 = (info, baseMod, behaviours, base) => {
3394
      const modsByBehaviour = { ...baseMod };
3395
      each$1(behaviours, behaviour => {
3396
        modsByBehaviour[behaviour.name()] = behaviour.exhibit(info, base);
3397
      });
3398
      const byAspect = byInnerKey(modsByBehaviour, (name, modification) => ({
3399
        name,
3400
        modification
3401
      }));
3402
      const combineObjects = objects => foldr(objects, (b, a) => ({
3403
        ...a.modification,
3404
        ...b
3405
      }), {});
3406
      const combinedClasses = foldr(byAspect.classes, (b, a) => a.modification.concat(b), []);
3407
      const combinedAttributes = combineObjects(byAspect.attributes);
3408
      const combinedStyles = combineObjects(byAspect.styles);
1441 ariadna 3409
      return nu$8({
1 efrain 3410
        classes: combinedClasses,
3411
        attributes: combinedAttributes,
3412
        styles: combinedStyles
3413
      });
3414
    };
3415
 
3416
    const sortKeys = (label, keyName, array, order) => {
3417
      try {
3418
        const sorted = sort(array, (a, b) => {
3419
          const aKey = a[keyName];
3420
          const bKey = b[keyName];
3421
          const aIndex = order.indexOf(aKey);
3422
          const bIndex = order.indexOf(bKey);
3423
          if (aIndex === -1) {
3424
            throw new Error('The ordering for ' + label + ' does not have an entry for ' + aKey + '.\nOrder specified: ' + JSON.stringify(order, null, 2));
3425
          }
3426
          if (bIndex === -1) {
3427
            throw new Error('The ordering for ' + label + ' does not have an entry for ' + bKey + '.\nOrder specified: ' + JSON.stringify(order, null, 2));
3428
          }
3429
          if (aIndex < bIndex) {
3430
            return -1;
3431
          } else if (bIndex < aIndex) {
3432
            return 1;
3433
          } else {
3434
            return 0;
3435
          }
3436
        });
3437
        return Result.value(sorted);
3438
      } catch (err) {
3439
        return Result.error([err]);
3440
      }
3441
    };
3442
 
3443
    const uncurried = (handler, purpose) => ({
3444
      handler,
3445
      purpose
3446
    });
3447
    const curried = (handler, purpose) => ({
3448
      cHandler: handler,
3449
      purpose
3450
    });
3451
    const curryArgs = (descHandler, extraArgs) => curried(curry.apply(undefined, [descHandler.handler].concat(extraArgs)), descHandler.purpose);
3452
    const getCurried = descHandler => descHandler.cHandler;
3453
 
3454
    const behaviourTuple = (name, handler) => ({
3455
      name,
3456
      handler
3457
    });
3458
    const nameToHandlers = (behaviours, info) => {
3459
      const r = {};
3460
      each$1(behaviours, behaviour => {
3461
        r[behaviour.name()] = behaviour.handlers(info);
3462
      });
3463
      return r;
3464
    };
3465
    const groupByEvents = (info, behaviours, base) => {
3466
      const behaviourEvents = {
3467
        ...base,
3468
        ...nameToHandlers(behaviours, info)
3469
      };
3470
      return byInnerKey(behaviourEvents, behaviourTuple);
3471
    };
3472
    const combine$1 = (info, eventOrder, behaviours, base) => {
3473
      const byEventName = groupByEvents(info, behaviours, base);
3474
      return combineGroups(byEventName, eventOrder);
3475
    };
3476
    const assemble = rawHandler => {
3477
      const handler = read$2(rawHandler);
3478
      return (component, simulatedEvent, ...rest) => {
3479
        const args = [
3480
          component,
3481
          simulatedEvent
3482
        ].concat(rest);
3483
        if (handler.abort.apply(undefined, args)) {
3484
          simulatedEvent.stop();
3485
        } else if (handler.can.apply(undefined, args)) {
3486
          handler.run.apply(undefined, args);
3487
        }
3488
      };
3489
    };
3490
    const missingOrderError = (eventName, tuples) => Result.error(['The event (' + eventName + ') has more than one behaviour that listens to it.\nWhen this occurs, you must ' + 'specify an event ordering for the behaviours in your spec (e.g. [ "listing", "toggling" ]).\nThe behaviours that ' + 'can trigger it are: ' + JSON.stringify(map$2(tuples, c => c.name), null, 2)]);
3491
    const fuse = (tuples, eventOrder, eventName) => {
3492
      const order = eventOrder[eventName];
3493
      if (!order) {
3494
        return missingOrderError(eventName, tuples);
3495
      } else {
3496
        return sortKeys('Event: ' + eventName, 'name', tuples, order).map(sortedTuples => {
3497
          const handlers = map$2(sortedTuples, tuple => tuple.handler);
3498
          return fuse$1(handlers);
3499
        });
3500
      }
3501
    };
3502
    const combineGroups = (byEventName, eventOrder) => {
3503
      const r = mapToArray(byEventName, (tuples, eventName) => {
3504
        const combined = tuples.length === 1 ? Result.value(tuples[0].handler) : fuse(tuples, eventOrder, eventName);
3505
        return combined.map(handler => {
3506
          const assembled = assemble(handler);
3507
          const purpose = tuples.length > 1 ? filter$2(eventOrder[eventName], o => exists(tuples, t => t.name === o)).join(' > ') : tuples[0].name;
3508
          return wrap$1(eventName, uncurried(assembled, purpose));
3509
        });
3510
      });
3511
      return consolidate(r, {});
3512
    };
3513
 
3514
    const baseBehaviour = 'alloy.base.behaviour';
3515
    const schema$z = objOf([
3516
      field$1('dom', 'dom', required$2(), objOf([
3517
        required$1('tag'),
3518
        defaulted('styles', {}),
3519
        defaulted('classes', []),
3520
        defaulted('attributes', {}),
3521
        option$3('value'),
3522
        option$3('innerHtml')
3523
      ])),
3524
      required$1('components'),
3525
      required$1('uid'),
3526
      defaulted('events', {}),
3527
      defaulted('apis', {}),
3528
      field$1('eventOrder', 'eventOrder', mergeWith({
3529
        [execute$5()]: [
3530
          'disabling',
3531
          baseBehaviour,
3532
          'toggling',
3533
          'typeaheadevents'
3534
        ],
3535
        [focus$4()]: [
3536
          baseBehaviour,
3537
          'focusing',
3538
          'keying'
3539
        ],
3540
        [systemInit()]: [
3541
          baseBehaviour,
3542
          'disabling',
3543
          'toggling',
1441 ariadna 3544
          'representing',
3545
          'tooltipping'
1 efrain 3546
        ],
3547
        [input()]: [
3548
          baseBehaviour,
3549
          'representing',
3550
          'streaming',
3551
          'invalidating'
3552
        ],
3553
        [detachedFromDom()]: [
3554
          baseBehaviour,
3555
          'representing',
3556
          'item-events',
1441 ariadna 3557
          'toolbar-button-events',
1 efrain 3558
          'tooltipping'
3559
        ],
3560
        [mousedown()]: [
3561
          'focusing',
3562
          baseBehaviour,
3563
          'item-type-events'
3564
        ],
3565
        [touchstart()]: [
3566
          'focusing',
3567
          baseBehaviour,
3568
          'item-type-events'
3569
        ],
3570
        [mouseover()]: [
3571
          'item-type-events',
3572
          'tooltipping'
3573
        ],
3574
        [receive()]: [
3575
          'receiving',
3576
          'reflecting',
3577
          'tooltipping'
3578
        ]
3579
      }), anyValue()),
3580
      option$3('domModification')
3581
    ]);
3582
    const toInfo = spec => asRaw('custom.definition', schema$z, spec);
3583
    const toDefinition = detail => ({
3584
      ...detail.dom,
3585
      uid: detail.uid,
3586
      domChildren: map$2(detail.components, comp => comp.element)
3587
    });
1441 ariadna 3588
    const toModification = detail => detail.domModification.fold(() => nu$8({}), nu$8);
1 efrain 3589
    const toEvents = info => info.events;
3590
 
1441 ariadna 3591
    const get$7 = element => element.dom.value;
1 efrain 3592
    const set$5 = (element, value) => {
3593
      if (value === undefined) {
3594
        throw new Error('Value.set was undefined');
3595
      }
3596
      element.dom.value = value;
3597
    };
3598
 
3599
    const determineObsoleted = (parent, index, oldObsoleted) => {
3600
      const newObsoleted = child$2(parent, index);
3601
      return newObsoleted.map(newObs => {
3602
        const elemChanged = oldObsoleted.exists(o => !eq(o, newObs));
3603
        if (elemChanged) {
3604
          const oldTag = oldObsoleted.map(name$3).getOr('span');
3605
          const marker = SugarElement.fromTag(oldTag);
3606
          before$1(newObs, marker);
3607
          return marker;
3608
        } else {
3609
          return newObs;
3610
        }
3611
      });
3612
    };
3613
    const ensureInDom = (parent, child, obsoleted) => {
3614
      obsoleted.fold(() => append$2(parent, child), obs => {
3615
        if (!eq(obs, child)) {
3616
          before$1(obs, child);
1441 ariadna 3617
          remove$6(obs);
1 efrain 3618
        }
3619
      });
3620
    };
3621
    const patchChildrenWith = (parent, nu, f) => {
3622
      const builtChildren = map$2(nu, f);
3623
      const currentChildren = children(parent);
1441 ariadna 3624
      each$1(currentChildren.slice(builtChildren.length), remove$6);
1 efrain 3625
      return builtChildren;
3626
    };
3627
    const patchSpecChild = (parent, index, spec, build) => {
3628
      const oldObsoleted = child$2(parent, index);
3629
      const childComp = build(spec, oldObsoleted);
3630
      const obsoleted = determineObsoleted(parent, index, oldObsoleted);
3631
      ensureInDom(parent, childComp.element, obsoleted);
3632
      return childComp;
3633
    };
3634
    const patchSpecChildren = (parent, specs, build) => patchChildrenWith(parent, specs, (spec, index) => patchSpecChild(parent, index, spec, build));
3635
    const patchDomChildren = (parent, nodes) => patchChildrenWith(parent, nodes, (node, index) => {
3636
      const optObsoleted = child$2(parent, index);
3637
      ensureInDom(parent, node, optObsoleted);
3638
      return node;
3639
    });
3640
 
3641
    const diffKeyValueSet = (newObj, oldObj) => {
3642
      const newKeys = keys(newObj);
3643
      const oldKeys = keys(oldObj);
3644
      const toRemove = difference(oldKeys, newKeys);
3645
      const toSet = bifilter(newObj, (v, k) => {
3646
        return !has$2(oldObj, k) || v !== oldObj[k];
3647
      }).t;
3648
      return {
3649
        toRemove,
3650
        toSet
3651
      };
3652
    };
3653
    const reconcileToDom = (definition, obsoleted) => {
3654
      const {
3655
        class: clazz,
3656
        style,
3657
        ...existingAttributes
3658
      } = clone$2(obsoleted);
3659
      const {
3660
        toSet: attrsToSet,
3661
        toRemove: attrsToRemove
3662
      } = diffKeyValueSet(definition.attributes, existingAttributes);
3663
      const updateAttrs = () => {
1441 ariadna 3664
        each$1(attrsToRemove, a => remove$8(obsoleted, a));
1 efrain 3665
        setAll$1(obsoleted, attrsToSet);
3666
      };
3667
      const existingStyles = getAllRaw(obsoleted);
3668
      const {
3669
        toSet: stylesToSet,
3670
        toRemove: stylesToRemove
3671
      } = diffKeyValueSet(definition.styles, existingStyles);
3672
      const updateStyles = () => {
1441 ariadna 3673
        each$1(stylesToRemove, s => remove$7(obsoleted, s));
1 efrain 3674
        setAll(obsoleted, stylesToSet);
3675
      };
1441 ariadna 3676
      const existingClasses = get$9(obsoleted);
1 efrain 3677
      const classesToRemove = difference(existingClasses, definition.classes);
3678
      const classesToAdd = difference(definition.classes, existingClasses);
3679
      const updateClasses = () => {
3680
        add$1(obsoleted, classesToAdd);
1441 ariadna 3681
        remove$2(obsoleted, classesToRemove);
1 efrain 3682
      };
3683
      const updateHtml = html => {
3684
        set$6(obsoleted, html);
3685
      };
3686
      const updateChildren = () => {
3687
        const children = definition.domChildren;
3688
        patchDomChildren(obsoleted, children);
3689
      };
3690
      const updateValue = () => {
3691
        const valueElement = obsoleted;
3692
        const value = definition.value.getOrUndefined();
1441 ariadna 3693
        if (value !== get$7(valueElement)) {
1 efrain 3694
          set$5(valueElement, value !== null && value !== void 0 ? value : '');
3695
        }
3696
      };
3697
      updateAttrs();
3698
      updateClasses();
3699
      updateStyles();
3700
      definition.innerHtml.fold(updateChildren, updateHtml);
3701
      updateValue();
3702
      return obsoleted;
3703
    };
3704
 
3705
    const introduceToDom = definition => {
3706
      const subject = SugarElement.fromTag(definition.tag);
3707
      setAll$1(subject, definition.attributes);
3708
      add$1(subject, definition.classes);
3709
      setAll(subject, definition.styles);
3710
      definition.innerHtml.each(html => set$6(subject, html));
3711
      const children = definition.domChildren;
3712
      append$1(subject, children);
3713
      definition.value.each(value => {
3714
        set$5(subject, value);
3715
      });
3716
      return subject;
3717
    };
3718
    const attemptPatch = (definition, obsoleted) => {
3719
      try {
3720
        const e = reconcileToDom(definition, obsoleted);
3721
        return Optional.some(e);
1441 ariadna 3722
      } catch (_a) {
1 efrain 3723
        return Optional.none();
3724
      }
3725
    };
3726
    const hasMixedChildren = definition => definition.innerHtml.isSome() && definition.domChildren.length > 0;
3727
    const renderToDom = (definition, optObsoleted) => {
3728
      const canBePatched = candidate => name$3(candidate) === definition.tag && !hasMixedChildren(definition) && !isPremade(candidate);
3729
      const elem = optObsoleted.filter(canBePatched).bind(obsoleted => attemptPatch(definition, obsoleted)).getOrThunk(() => introduceToDom(definition));
3730
      writeOnly(elem, definition.uid);
3731
      return elem;
3732
    };
3733
 
3734
    const getBehaviours$2 = spec => {
1441 ariadna 3735
      const behaviours = get$h(spec, 'behaviours').getOr({});
1 efrain 3736
      return bind$3(keys(behaviours), name => {
3737
        const behaviour = behaviours[name];
3738
        return isNonNullable(behaviour) ? [behaviour.me] : [];
3739
      });
3740
    };
3741
    const generateFrom = (spec, all) => generateFrom$1(spec, all);
3742
    const generate$4 = spec => {
3743
      const all = getBehaviours$2(spec);
3744
      return generateFrom(spec, all);
3745
    };
3746
 
3747
    const getDomDefinition = (info, bList, bData) => {
3748
      const definition = toDefinition(info);
3749
      const infoModification = toModification(info);
3750
      const baseModification = { 'alloy.base.modification': infoModification };
3751
      const modification = bList.length > 0 ? combine$2(bData, baseModification, bList, definition) : infoModification;
3752
      return merge(definition, modification);
3753
    };
3754
    const getEvents = (info, bList, bData) => {
3755
      const baseEvents = { 'alloy.base.behaviour': toEvents(info) };
3756
      return combine$1(bData, info.eventOrder, bList, baseEvents).getOrDie();
3757
    };
3758
    const build$2 = (spec, obsoleted) => {
3759
      const getMe = () => me;
1441 ariadna 3760
      const systemApi = Cell(singleton);
1 efrain 3761
      const info = getOrDie(toInfo(spec));
3762
      const bBlob = generate$4(spec);
3763
      const bList = getBehaviours$3(bBlob);
3764
      const bData = getData$2(bBlob);
3765
      const modDefinition = getDomDefinition(info, bList, bData);
3766
      const item = renderToDom(modDefinition, obsoleted);
3767
      const events = getEvents(info, bList, bData);
3768
      const subcomponents = Cell(info.components);
3769
      const connect = newApi => {
3770
        systemApi.set(newApi);
3771
      };
3772
      const disconnect = () => {
3773
        systemApi.set(NoContextApi(getMe));
3774
      };
3775
      const syncComponents = () => {
3776
        const children$1 = children(item);
3777
        const subs = bind$3(children$1, child => systemApi.get().getByDom(child).fold(() => [], pure$2));
3778
        subcomponents.set(subs);
3779
      };
3780
      const config = behaviour => {
3781
        const b = bData;
3782
        const f = isFunction(b[behaviour.name()]) ? b[behaviour.name()] : () => {
3783
          throw new Error('Could not find ' + behaviour.name() + ' in ' + JSON.stringify(spec, null, 2));
3784
        };
3785
        return f();
3786
      };
3787
      const hasConfigured = behaviour => isFunction(bData[behaviour.name()]);
3788
      const getApis = () => info.apis;
3789
      const readState = behaviourName => bData[behaviourName]().map(b => b.state.readState()).getOr('not enabled');
3790
      const me = {
3791
        uid: spec.uid,
3792
        getSystem: systemApi.get,
3793
        config,
3794
        hasConfigured,
3795
        spec,
3796
        readState,
3797
        getApis,
3798
        connect,
3799
        disconnect,
3800
        element: item,
3801
        syncComponents,
3802
        components: subcomponents.get,
3803
        events
3804
      };
3805
      return me;
3806
    };
3807
 
3808
    const buildSubcomponents = (spec, obsoleted) => {
1441 ariadna 3809
      const components = get$h(spec, 'components').getOr([]);
1 efrain 3810
      return obsoleted.fold(() => map$2(components, build$1), obs => map$2(components, (c, i) => {
3811
        return buildOrPatch(c, child$2(obs, i));
3812
      }));
3813
    };
3814
    const buildFromSpec = (userSpec, obsoleted) => {
3815
      const {
3816
        events: specEvents,
3817
        ...spec
3818
      } = make$8(userSpec);
3819
      const components = buildSubcomponents(spec, obsoleted);
3820
      const completeSpec = {
3821
        ...spec,
3822
        events: {
3823
          ...DefaultEvents,
3824
          ...specEvents
3825
        },
3826
        components
3827
      };
3828
      return Result.value(build$2(completeSpec, obsoleted));
3829
    };
3830
    const text$2 = textContent => {
3831
      const element = SugarElement.fromText(textContent);
3832
      return external$1({ element });
3833
    };
3834
    const external$1 = spec => {
3835
      const extSpec = asRawOrDie$1('external.component', objOfOnly([
3836
        required$1('element'),
3837
        option$3('uid')
3838
      ]), spec);
3839
      const systemApi = Cell(NoContextApi());
3840
      const connect = newApi => {
3841
        systemApi.set(newApi);
3842
      };
3843
      const disconnect = () => {
3844
        systemApi.set(NoContextApi(() => me));
3845
      };
3846
      const uid = extSpec.uid.getOrThunk(() => generate$5('external'));
3847
      writeOnly(extSpec.element, uid);
3848
      const me = {
3849
        uid,
3850
        getSystem: systemApi.get,
3851
        config: Optional.none,
3852
        hasConfigured: never,
3853
        connect,
3854
        disconnect,
3855
        getApis: () => ({}),
3856
        element: extSpec.element,
3857
        spec,
3858
        readState: constant$1('No state'),
3859
        syncComponents: noop,
3860
        components: constant$1([]),
3861
        events: {}
3862
      };
3863
      return premade$1(me);
3864
    };
3865
    const uids = generate$5;
3866
    const isSketchSpec$1 = spec => has$2(spec, 'uid');
3867
    const buildOrPatch = (spec, obsoleted) => getPremade(spec).getOrThunk(() => {
3868
      const userSpecWithUid = isSketchSpec$1(spec) ? spec : {
3869
        uid: uids(''),
3870
        ...spec
3871
      };
3872
      return buildFromSpec(userSpecWithUid, obsoleted).getOrDie();
3873
    });
3874
    const build$1 = spec => buildOrPatch(spec, Optional.none());
3875
    const premade = premade$1;
3876
 
3877
    var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
3878
      if (is(scope, a)) {
3879
        return Optional.some(scope);
3880
      } else if (isFunction(isRoot) && isRoot(scope)) {
3881
        return Optional.none();
3882
      } else {
3883
        return ancestor(scope, a, isRoot);
3884
      }
3885
    };
3886
 
3887
    const ancestor$1 = (scope, predicate, isRoot) => {
3888
      let element = scope.dom;
3889
      const stop = isFunction(isRoot) ? isRoot : never;
3890
      while (element.parentNode) {
3891
        element = element.parentNode;
3892
        const el = SugarElement.fromDom(element);
3893
        if (predicate(el)) {
3894
          return Optional.some(el);
3895
        } else if (stop(el)) {
3896
          break;
3897
        }
3898
      }
3899
      return Optional.none();
3900
    };
3901
    const closest$3 = (scope, predicate, isRoot) => {
3902
      const is = (s, test) => test(s);
3903
      return ClosestOrAncestor(is, ancestor$1, scope, predicate, isRoot);
3904
    };
1441 ariadna 3905
    const sibling$1 = (scope, predicate) => {
3906
      const element = scope.dom;
3907
      if (!element.parentNode) {
3908
        return Optional.none();
3909
      }
3910
      return child$1(SugarElement.fromDom(element.parentNode), x => !eq(scope, x) && predicate(x));
3911
    };
1 efrain 3912
    const child$1 = (scope, predicate) => {
3913
      const pred = node => predicate(SugarElement.fromDom(node));
3914
      const result = find$5(scope.dom.childNodes, pred);
3915
      return result.map(SugarElement.fromDom);
3916
    };
3917
    const descendant$1 = (scope, predicate) => {
3918
      const descend = node => {
3919
        for (let i = 0; i < node.childNodes.length; i++) {
3920
          const child = SugarElement.fromDom(node.childNodes[i]);
3921
          if (predicate(child)) {
3922
            return Optional.some(child);
3923
          }
3924
          const res = descend(node.childNodes[i]);
3925
          if (res.isSome()) {
3926
            return res;
3927
          }
3928
        }
3929
        return Optional.none();
3930
      };
3931
      return descend(scope.dom);
3932
    };
3933
 
3934
    const closest$2 = (scope, predicate, isRoot) => closest$3(scope, predicate, isRoot).isSome();
3935
 
1441 ariadna 3936
    const first$1 = selector => one(selector);
1 efrain 3937
    const ancestor = (scope, selector, isRoot) => ancestor$1(scope, e => is(e, selector), isRoot);
1441 ariadna 3938
    const sibling = (scope, selector) => sibling$1(scope, e => is(e, selector));
1 efrain 3939
    const child = (scope, selector) => child$1(scope, e => is(e, selector));
3940
    const descendant = (scope, selector) => one(selector, scope);
3941
    const closest$1 = (scope, selector, isRoot) => {
3942
      const is$1 = (element, selector) => is(element, selector);
3943
      return ClosestOrAncestor(is$1, ancestor, scope, selector, isRoot);
3944
    };
3945
 
3946
    const attribute = 'aria-controls';
3947
    const find$1 = queryElem => {
3948
      const dependent = closest$3(queryElem, elem => {
3949
        if (!isElement$1(elem)) {
3950
          return false;
3951
        }
1441 ariadna 3952
        const id = get$g(elem, 'id');
1 efrain 3953
        return id !== undefined && id.indexOf(attribute) > -1;
3954
      });
3955
      return dependent.bind(dep => {
1441 ariadna 3956
        const id = get$g(dep, 'id');
1 efrain 3957
        const dos = getRootNode(dep);
3958
        return descendant(dos, `[${ attribute }="${ id }"]`);
3959
      });
3960
    };
3961
    const manager = () => {
3962
      const ariaId = generate$6(attribute);
3963
      const link = elem => {
3964
        set$9(elem, attribute, ariaId);
3965
      };
3966
      const unlink = elem => {
1441 ariadna 3967
        remove$8(elem, attribute);
1 efrain 3968
      };
3969
      return {
3970
        id: ariaId,
3971
        link,
3972
        unlink
3973
      };
3974
    };
3975
 
3976
    const isAriaPartOf = (component, queryElem) => find$1(queryElem).exists(owner => isPartOf$1(component, owner));
3977
    const isPartOf$1 = (component, queryElem) => closest$2(queryElem, el => eq(el, component.element), never) || isAriaPartOf(component, queryElem);
3978
 
3979
    const nu$6 = (x, y, bubble, direction, placement, boundsRestriction, labelPrefix, alwaysFit = false) => ({
3980
      x,
3981
      y,
3982
      bubble,
3983
      direction,
3984
      placement,
3985
      restriction: boundsRestriction,
3986
      label: `${ labelPrefix }-${ placement }`,
3987
      alwaysFit
3988
    });
3989
 
3990
    const adt$a = Adt.generate([
3991
      { southeast: [] },
3992
      { southwest: [] },
3993
      { northeast: [] },
3994
      { northwest: [] },
3995
      { south: [] },
3996
      { north: [] },
3997
      { east: [] },
3998
      { west: [] }
3999
    ]);
4000
    const cata$2 = (subject, southeast, southwest, northeast, northwest, south, north, east, west) => subject.fold(southeast, southwest, northeast, northwest, south, north, east, west);
4001
    const cataVertical = (subject, south, middle, north) => subject.fold(south, south, north, north, south, north, middle, middle);
4002
    const cataHorizontal = (subject, east, middle, west) => subject.fold(east, west, east, west, middle, middle, east, west);
4003
    const southeast$3 = adt$a.southeast;
4004
    const southwest$3 = adt$a.southwest;
4005
    const northeast$3 = adt$a.northeast;
4006
    const northwest$3 = adt$a.northwest;
4007
    const south$3 = adt$a.south;
4008
    const north$3 = adt$a.north;
4009
    const east$3 = adt$a.east;
4010
    const west$3 = adt$a.west;
4011
 
4012
    const getRestriction = (anchor, restriction) => {
4013
      switch (restriction) {
4014
      case 1:
4015
        return anchor.x;
4016
      case 0:
4017
        return anchor.x + anchor.width;
4018
      case 2:
4019
        return anchor.y;
4020
      case 3:
4021
        return anchor.y + anchor.height;
4022
      }
4023
    };
4024
    const boundsRestriction = (anchor, restrictions) => mapToObject([
4025
      'left',
4026
      'right',
4027
      'top',
4028
      'bottom'
1441 ariadna 4029
    ], dir => get$h(restrictions, dir).map(restriction => getRestriction(anchor, restriction)));
1 efrain 4030
    const adjustBounds = (bounds$1, restriction, bubbleOffset) => {
4031
      const applyRestriction = (dir, current) => restriction[dir].map(pos => {
4032
        const isVerticalAxis = dir === 'top' || dir === 'bottom';
4033
        const offset = isVerticalAxis ? bubbleOffset.top : bubbleOffset.left;
4034
        const comparator = dir === 'left' || dir === 'top' ? Math.max : Math.min;
4035
        const newPos = comparator(pos, current) + offset;
4036
        return isVerticalAxis ? clamp(newPos, bounds$1.y, bounds$1.bottom) : clamp(newPos, bounds$1.x, bounds$1.right);
4037
      }).getOr(current);
4038
      const adjustedLeft = applyRestriction('left', bounds$1.x);
4039
      const adjustedTop = applyRestriction('top', bounds$1.y);
4040
      const adjustedRight = applyRestriction('right', bounds$1.right);
4041
      const adjustedBottom = applyRestriction('bottom', bounds$1.bottom);
4042
      return bounds(adjustedLeft, adjustedTop, adjustedRight - adjustedLeft, adjustedBottom - adjustedTop);
4043
    };
4044
 
4045
    const labelPrefix$2 = 'layout';
4046
    const eastX$1 = anchor => anchor.x;
4047
    const middleX$1 = (anchor, element) => anchor.x + anchor.width / 2 - element.width / 2;
4048
    const westX$1 = (anchor, element) => anchor.x + anchor.width - element.width;
4049
    const northY$2 = (anchor, element) => anchor.y - element.height;
4050
    const southY$2 = anchor => anchor.y + anchor.height;
4051
    const centreY$1 = (anchor, element) => anchor.y + anchor.height / 2 - element.height / 2;
4052
    const eastEdgeX$1 = anchor => anchor.x + anchor.width;
4053
    const westEdgeX$1 = (anchor, element) => anchor.x - element.width;
4054
    const southeast$2 = (anchor, element, bubbles) => nu$6(eastX$1(anchor), southY$2(anchor), bubbles.southeast(), southeast$3(), 'southeast', boundsRestriction(anchor, {
4055
      left: 1,
4056
      top: 3
4057
    }), labelPrefix$2);
4058
    const southwest$2 = (anchor, element, bubbles) => nu$6(westX$1(anchor, element), southY$2(anchor), bubbles.southwest(), southwest$3(), 'southwest', boundsRestriction(anchor, {
4059
      right: 0,
4060
      top: 3
4061
    }), labelPrefix$2);
4062
    const northeast$2 = (anchor, element, bubbles) => nu$6(eastX$1(anchor), northY$2(anchor, element), bubbles.northeast(), northeast$3(), 'northeast', boundsRestriction(anchor, {
4063
      left: 1,
4064
      bottom: 2
4065
    }), labelPrefix$2);
4066
    const northwest$2 = (anchor, element, bubbles) => nu$6(westX$1(anchor, element), northY$2(anchor, element), bubbles.northwest(), northwest$3(), 'northwest', boundsRestriction(anchor, {
4067
      right: 0,
4068
      bottom: 2
4069
    }), labelPrefix$2);
4070
    const north$2 = (anchor, element, bubbles) => nu$6(middleX$1(anchor, element), northY$2(anchor, element), bubbles.north(), north$3(), 'north', boundsRestriction(anchor, { bottom: 2 }), labelPrefix$2);
4071
    const south$2 = (anchor, element, bubbles) => nu$6(middleX$1(anchor, element), southY$2(anchor), bubbles.south(), south$3(), 'south', boundsRestriction(anchor, { top: 3 }), labelPrefix$2);
4072
    const east$2 = (anchor, element, bubbles) => nu$6(eastEdgeX$1(anchor), centreY$1(anchor, element), bubbles.east(), east$3(), 'east', boundsRestriction(anchor, { left: 0 }), labelPrefix$2);
4073
    const west$2 = (anchor, element, bubbles) => nu$6(westEdgeX$1(anchor, element), centreY$1(anchor, element), bubbles.west(), west$3(), 'west', boundsRestriction(anchor, { right: 1 }), labelPrefix$2);
4074
    const all$1 = () => [
4075
      southeast$2,
4076
      southwest$2,
4077
      northeast$2,
4078
      northwest$2,
4079
      south$2,
4080
      north$2,
4081
      east$2,
4082
      west$2
4083
    ];
4084
    const allRtl$1 = () => [
4085
      southwest$2,
4086
      southeast$2,
4087
      northwest$2,
4088
      northeast$2,
4089
      south$2,
4090
      north$2,
4091
      east$2,
4092
      west$2
4093
    ];
4094
    const aboveOrBelow = () => [
4095
      northeast$2,
4096
      northwest$2,
4097
      southeast$2,
4098
      southwest$2,
4099
      north$2,
4100
      south$2
4101
    ];
4102
    const aboveOrBelowRtl = () => [
4103
      northwest$2,
4104
      northeast$2,
4105
      southwest$2,
4106
      southeast$2,
4107
      north$2,
4108
      south$2
4109
    ];
4110
    const belowOrAbove = () => [
4111
      southeast$2,
4112
      southwest$2,
4113
      northeast$2,
4114
      northwest$2,
4115
      south$2,
4116
      north$2
4117
    ];
4118
    const belowOrAboveRtl = () => [
4119
      southwest$2,
4120
      southeast$2,
4121
      northwest$2,
4122
      northeast$2,
4123
      south$2,
4124
      north$2
4125
    ];
4126
 
4127
    const chooseChannels = (channels, message) => message.universal ? channels : filter$2(channels, ch => contains$2(message.channels, ch));
1441 ariadna 4128
    const events$g = receiveConfig => derive$2([run$1(receive(), (component, message) => {
1 efrain 4129
        const channelMap = receiveConfig.channels;
4130
        const channels = keys(channelMap);
4131
        const receivingData = message;
4132
        const targetChannels = chooseChannels(channels, receivingData);
4133
        each$1(targetChannels, ch => {
4134
          const channelInfo = channelMap[ch];
4135
          const channelSchema = channelInfo.schema;
4136
          const data = asRawOrDie$1('channel[' + ch + '] data\nReceiver: ' + element(component.element), channelSchema, receivingData.data);
4137
          channelInfo.onReceive(component, data);
4138
        });
4139
      })]);
4140
 
4141
    var ActiveReceiving = /*#__PURE__*/Object.freeze({
4142
        __proto__: null,
1441 ariadna 4143
        events: events$g
1 efrain 4144
    });
4145
 
4146
    var ReceivingSchema = [requiredOf('channels', setOf(Result.value, objOfOnly([
4147
        onStrictHandler('onReceive'),
4148
        defaulted('schema', anyValue())
4149
      ])))];
4150
 
4151
    const Receiving = create$4({
4152
      fields: ReceivingSchema,
4153
      name: 'receiving',
4154
      active: ActiveReceiving
4155
    });
4156
 
1441 ariadna 4157
    const exhibit$6 = (base, posConfig) => nu$8({
1 efrain 4158
      classes: [],
4159
      styles: posConfig.useFixed() ? {} : { position: 'relative' }
4160
    });
4161
 
4162
    var ActivePosition = /*#__PURE__*/Object.freeze({
4163
        __proto__: null,
4164
        exhibit: exhibit$6
4165
    });
4166
 
4167
    const focus$3 = (element, preventScroll = false) => element.dom.focus({ preventScroll });
4168
    const blur$1 = element => element.dom.blur();
4169
    const hasFocus = element => {
4170
      const root = getRootNode(element).dom;
4171
      return element.dom === root.activeElement;
4172
    };
4173
    const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
4174
    const search = element => active$1(getRootNode(element)).filter(e => element.dom.contains(e.dom));
4175
 
4176
    const preserve$1 = (f, container) => {
4177
      const dos = getRootNode(container);
4178
      const refocus = active$1(dos).bind(focused => {
4179
        const hasFocus = elem => eq(focused, elem);
4180
        return hasFocus(container) ? Optional.some(container) : descendant$1(container, hasFocus);
4181
      });
4182
      const result = f(container);
4183
      refocus.each(oldFocus => {
4184
        active$1(dos).filter(newFocus => eq(newFocus, oldFocus)).fold(() => {
4185
          focus$3(oldFocus);
4186
        }, noop);
4187
      });
4188
      return result;
4189
    };
4190
 
4191
    const adt$9 = Adt.generate([
4192
      { none: [] },
4193
      {
4194
        relative: [
4195
          'x',
4196
          'y',
4197
          'width',
4198
          'height'
4199
        ]
4200
      },
4201
      {
4202
        fixed: [
4203
          'x',
4204
          'y',
4205
          'width',
4206
          'height'
4207
        ]
4208
      }
4209
    ]);
4210
    const positionWithDirection = (posName, decision, x, y, width, height) => {
4211
      const decisionRect = decision.rect;
4212
      const decisionX = decisionRect.x - x;
4213
      const decisionY = decisionRect.y - y;
4214
      const decisionWidth = decisionRect.width;
4215
      const decisionHeight = decisionRect.height;
4216
      const decisionRight = width - (decisionX + decisionWidth);
4217
      const decisionBottom = height - (decisionY + decisionHeight);
4218
      const left = Optional.some(decisionX);
4219
      const top = Optional.some(decisionY);
4220
      const right = Optional.some(decisionRight);
4221
      const bottom = Optional.some(decisionBottom);
4222
      const none = Optional.none();
4223
      return cata$2(decision.direction, () => NuPositionCss(posName, left, top, none, none), () => NuPositionCss(posName, none, top, right, none), () => NuPositionCss(posName, left, none, none, bottom), () => NuPositionCss(posName, none, none, right, bottom), () => NuPositionCss(posName, left, top, none, none), () => NuPositionCss(posName, left, none, none, bottom), () => NuPositionCss(posName, left, top, none, none), () => NuPositionCss(posName, none, top, right, none));
4224
    };
4225
    const reposition = (origin, decision) => origin.fold(() => {
4226
      const decisionRect = decision.rect;
4227
      return NuPositionCss('absolute', Optional.some(decisionRect.x), Optional.some(decisionRect.y), Optional.none(), Optional.none());
4228
    }, (x, y, width, height) => {
4229
      return positionWithDirection('absolute', decision, x, y, width, height);
4230
    }, (x, y, width, height) => {
4231
      return positionWithDirection('fixed', decision, x, y, width, height);
4232
    });
4233
    const toBox = (origin, element) => {
4234
      const rel = curry(find$2, element);
4235
      const position = origin.fold(rel, rel, () => {
1441 ariadna 4236
        const scroll = get$c();
1 efrain 4237
        return find$2(element).translate(-scroll.left, -scroll.top);
4238
      });
4239
      const width = getOuter$1(element);
4240
      const height = getOuter$2(element);
4241
      return bounds(position.left, position.top, width, height);
4242
    };
4243
    const viewport = (origin, optBounds) => optBounds.fold(() => origin.fold(win, win, bounds), bounds$1 => origin.fold(constant$1(bounds$1), constant$1(bounds$1), () => {
4244
      const pos = translate$2(origin, bounds$1.x, bounds$1.y);
4245
      return bounds(pos.left, pos.top, bounds$1.width, bounds$1.height);
4246
    }));
4247
    const translate$2 = (origin, x, y) => {
4248
      const pos = SugarPosition(x, y);
4249
      const removeScroll = () => {
1441 ariadna 4250
        const outerScroll = get$c();
1 efrain 4251
        return pos.translate(-outerScroll.left, -outerScroll.top);
4252
      };
4253
      return origin.fold(constant$1(pos), constant$1(pos), removeScroll);
4254
    };
4255
    const cata$1 = (subject, onNone, onRelative, onFixed) => subject.fold(onNone, onRelative, onFixed);
4256
    adt$9.none;
4257
    const relative$1 = adt$9.relative;
4258
    const fixed$1 = adt$9.fixed;
4259
 
4260
    const anchor = (anchorBox, origin) => ({
4261
      anchorBox,
4262
      origin
4263
    });
4264
    const box = (anchorBox, origin) => anchor(anchorBox, origin);
4265
 
4266
    const placementAttribute = 'data-alloy-placement';
4267
    const setPlacement$1 = (element, placement) => {
4268
      set$9(element, placementAttribute, placement);
4269
    };
4270
    const getPlacement = element => getOpt(element, placementAttribute);
1441 ariadna 4271
    const reset$1 = element => remove$8(element, placementAttribute);
1 efrain 4272
 
4273
    const adt$8 = Adt.generate([
4274
      { fit: ['reposition'] },
4275
      {
4276
        nofit: [
4277
          'reposition',
4278
          'visibleW',
4279
          'visibleH',
4280
          'isVisible'
4281
        ]
4282
      }
4283
    ]);
4284
    const determinePosition = (box, bounds) => {
4285
      const {
4286
        x: boundsX,
4287
        y: boundsY,
4288
        right: boundsRight,
4289
        bottom: boundsBottom
4290
      } = bounds;
4291
      const {x, y, right, bottom, width, height} = box;
4292
      const xInBounds = x >= boundsX && x <= boundsRight;
4293
      const yInBounds = y >= boundsY && y <= boundsBottom;
4294
      const originInBounds = xInBounds && yInBounds;
4295
      const rightInBounds = right <= boundsRight && right >= boundsX;
4296
      const bottomInBounds = bottom <= boundsBottom && bottom >= boundsY;
4297
      const sizeInBounds = rightInBounds && bottomInBounds;
4298
      const visibleW = Math.min(width, x >= boundsX ? boundsRight - x : right - boundsX);
4299
      const visibleH = Math.min(height, y >= boundsY ? boundsBottom - y : bottom - boundsY);
4300
      return {
4301
        originInBounds,
4302
        sizeInBounds,
4303
        visibleW,
4304
        visibleH
4305
      };
4306
    };
4307
    const calcReposition = (box, bounds$1) => {
4308
      const {
4309
        x: boundsX,
4310
        y: boundsY,
4311
        right: boundsRight,
4312
        bottom: boundsBottom
4313
      } = bounds$1;
4314
      const {x, y, width, height} = box;
4315
      const maxX = Math.max(boundsX, boundsRight - width);
4316
      const maxY = Math.max(boundsY, boundsBottom - height);
4317
      const restrictedX = clamp(x, boundsX, maxX);
4318
      const restrictedY = clamp(y, boundsY, maxY);
4319
      const restrictedWidth = Math.min(restrictedX + width, boundsRight) - restrictedX;
4320
      const restrictedHeight = Math.min(restrictedY + height, boundsBottom) - restrictedY;
4321
      return bounds(restrictedX, restrictedY, restrictedWidth, restrictedHeight);
4322
    };
4323
    const calcMaxSizes = (direction, box, bounds) => {
4324
      const upAvailable = constant$1(box.bottom - bounds.y);
4325
      const downAvailable = constant$1(bounds.bottom - box.y);
4326
      const maxHeight = cataVertical(direction, downAvailable, downAvailable, upAvailable);
4327
      const westAvailable = constant$1(box.right - bounds.x);
4328
      const eastAvailable = constant$1(bounds.right - box.x);
4329
      const maxWidth = cataHorizontal(direction, eastAvailable, eastAvailable, westAvailable);
4330
      return {
4331
        maxWidth,
4332
        maxHeight
4333
      };
4334
    };
4335
    const attempt = (candidate, width, height, bounds$1) => {
4336
      const bubble = candidate.bubble;
4337
      const bubbleOffset = bubble.offset;
4338
      const adjustedBounds = adjustBounds(bounds$1, candidate.restriction, bubbleOffset);
4339
      const newX = candidate.x + bubbleOffset.left;
4340
      const newY = candidate.y + bubbleOffset.top;
4341
      const box = bounds(newX, newY, width, height);
4342
      const {originInBounds, sizeInBounds, visibleW, visibleH} = determinePosition(box, adjustedBounds);
4343
      const fits = originInBounds && sizeInBounds;
4344
      const fittedBox = fits ? box : calcReposition(box, adjustedBounds);
4345
      const isPartlyVisible = fittedBox.width > 0 && fittedBox.height > 0;
4346
      const {maxWidth, maxHeight} = calcMaxSizes(candidate.direction, fittedBox, bounds$1);
4347
      const reposition = {
4348
        rect: fittedBox,
4349
        maxHeight,
4350
        maxWidth,
4351
        direction: candidate.direction,
4352
        placement: candidate.placement,
4353
        classes: {
4354
          on: bubble.classesOn,
4355
          off: bubble.classesOff
4356
        },
4357
        layout: candidate.label,
4358
        testY: newY
4359
      };
4360
      return fits || candidate.alwaysFit ? adt$8.fit(reposition) : adt$8.nofit(reposition, visibleW, visibleH, isPartlyVisible);
4361
    };
4362
    const attempts = (element, candidates, anchorBox, elementBox, bubbles, bounds) => {
4363
      const panelWidth = elementBox.width;
4364
      const panelHeight = elementBox.height;
4365
      const attemptBestFit = (layout, reposition, visibleW, visibleH, isVisible) => {
4366
        const next = layout(anchorBox, elementBox, bubbles, element, bounds);
4367
        const attemptLayout = attempt(next, panelWidth, panelHeight, bounds);
4368
        return attemptLayout.fold(constant$1(attemptLayout), (newReposition, newVisibleW, newVisibleH, newIsVisible) => {
4369
          const improved = isVisible === newIsVisible ? newVisibleH > visibleH || newVisibleW > visibleW : !isVisible && newIsVisible;
4370
          return improved ? attemptLayout : adt$8.nofit(reposition, visibleW, visibleH, isVisible);
4371
        });
4372
      };
4373
      const abc = foldl(candidates, (b, a) => {
4374
        const bestNext = curry(attemptBestFit, a);
4375
        return b.fold(constant$1(b), bestNext);
4376
      }, adt$8.nofit({
4377
        rect: anchorBox,
4378
        maxHeight: elementBox.height,
4379
        maxWidth: elementBox.width,
4380
        direction: southeast$3(),
4381
        placement: 'southeast',
4382
        classes: {
4383
          on: [],
4384
          off: []
4385
        },
4386
        layout: 'none',
4387
        testY: anchorBox.y
4388
      }, -1, -1, false));
4389
      return abc.fold(identity, identity);
4390
    };
4391
 
4392
    const filter = always;
4393
    const bind = (element, event, handler) => bind$2(element, event, filter, handler);
4394
    const capture = (element, event, handler) => capture$1(element, event, filter, handler);
4395
    const fromRawEvent = fromRawEvent$1;
4396
 
4397
    const properties = [
4398
      'top',
4399
      'bottom',
4400
      'right',
4401
      'left'
4402
    ];
4403
    const timerAttr = 'data-alloy-transition-timer';
4404
    const isTransitioning$1 = (element, transition) => hasAll(element, transition.classes);
4405
    const shouldApplyTransitionCss = (transition, decision, lastPlacement) => {
4406
      return lastPlacement.exists(placer => {
4407
        const mode = transition.mode;
4408
        return mode === 'all' ? true : placer[mode] !== decision[mode];
4409
      });
4410
    };
4411
    const hasChanges = (position, intermediate) => {
4412
      const round = value => parseFloat(value).toFixed(3);
4413
      return find$4(intermediate, (value, key) => {
4414
        const newValue = position[key].map(round);
4415
        const val = value.map(round);
4416
        return !equals(newValue, val);
4417
      }).isSome();
4418
    };
4419
    const getTransitionDuration = element => {
4420
      const get = name => {
1441 ariadna 4421
        const style = get$f(element, name);
1 efrain 4422
        const times = style.split(/\s*,\s*/);
4423
        return filter$2(times, isNotEmpty);
4424
      };
4425
      const parse = value => {
4426
        if (isString(value) && /^[\d.]+/.test(value)) {
4427
          const num = parseFloat(value);
4428
          return endsWith(value, 'ms') ? num : num * 1000;
4429
        } else {
4430
          return 0;
4431
        }
4432
      };
4433
      const delay = get('transition-delay');
4434
      const duration = get('transition-duration');
4435
      return foldl(duration, (acc, dur, i) => {
4436
        const time = parse(delay[i]) + parse(dur);
4437
        return Math.max(acc, time);
4438
      }, 0);
4439
    };
4440
    const setupTransitionListeners = (element, transition) => {
4441
      const transitionEnd = unbindable();
4442
      const transitionCancel = unbindable();
4443
      let timer;
4444
      const isSourceTransition = e => {
4445
        var _a;
4446
        const pseudoElement = (_a = e.raw.pseudoElement) !== null && _a !== void 0 ? _a : '';
4447
        return eq(e.target, element) && isEmpty(pseudoElement) && contains$2(properties, e.raw.propertyName);
4448
      };
4449
      const transitionDone = e => {
4450
        if (isNullable(e) || isSourceTransition(e)) {
4451
          transitionEnd.clear();
4452
          transitionCancel.clear();
4453
          const type = e === null || e === void 0 ? void 0 : e.raw.type;
4454
          if (isNullable(type) || type === transitionend()) {
4455
            clearTimeout(timer);
1441 ariadna 4456
            remove$8(element, timerAttr);
4457
            remove$2(element, transition.classes);
1 efrain 4458
          }
4459
        }
4460
      };
4461
      const transitionStart = bind(element, transitionstart(), e => {
4462
        if (isSourceTransition(e)) {
4463
          transitionStart.unbind();
4464
          transitionEnd.set(bind(element, transitionend(), transitionDone));
4465
          transitionCancel.set(bind(element, transitioncancel(), transitionDone));
4466
        }
4467
      });
4468
      const duration = getTransitionDuration(element);
4469
      requestAnimationFrame(() => {
4470
        timer = setTimeout(transitionDone, duration + 17);
4471
        set$9(element, timerAttr, timer);
4472
      });
4473
    };
4474
    const startTransitioning = (element, transition) => {
4475
      add$1(element, transition.classes);
4476
      getOpt(element, timerAttr).each(timerId => {
4477
        clearTimeout(parseInt(timerId, 10));
1441 ariadna 4478
        remove$8(element, timerAttr);
1 efrain 4479
      });
4480
      setupTransitionListeners(element, transition);
4481
    };
4482
    const applyTransitionCss = (element, origin, position, transition, decision, lastPlacement) => {
4483
      const shouldTransition = shouldApplyTransitionCss(transition, decision, lastPlacement);
4484
      if (shouldTransition || isTransitioning$1(element, transition)) {
4485
        set$8(element, 'position', position.position);
4486
        const rect = toBox(origin, element);
4487
        const intermediatePosition = reposition(origin, {
4488
          ...decision,
4489
          rect
4490
        });
4491
        const intermediateCssOptions = mapToObject(properties, prop => intermediatePosition[prop]);
4492
        if (hasChanges(position, intermediateCssOptions)) {
4493
          setOptions(element, intermediateCssOptions);
4494
          if (shouldTransition) {
4495
            startTransitioning(element, transition);
4496
          }
4497
          reflow(element);
4498
        }
4499
      } else {
1441 ariadna 4500
        remove$2(element, transition.classes);
1 efrain 4501
      }
4502
    };
4503
 
4504
    const elementSize = p => ({
4505
      width: getOuter$1(p),
4506
      height: getOuter$2(p)
4507
    });
4508
    const layout = (anchorBox, element, bubbles, options) => {
1441 ariadna 4509
      remove$7(element, 'max-height');
4510
      remove$7(element, 'max-width');
1 efrain 4511
      const elementBox = elementSize(element);
4512
      return attempts(element, options.preference, anchorBox, elementBox, bubbles, options.bounds);
4513
    };
4514
    const setClasses = (element, decision) => {
4515
      const classInfo = decision.classes;
1441 ariadna 4516
      remove$2(element, classInfo.off);
1 efrain 4517
      add$1(element, classInfo.on);
4518
    };
4519
    const setHeight = (element, decision, options) => {
4520
      const maxHeightFunction = options.maxHeightFunction;
4521
      maxHeightFunction(element, decision.maxHeight);
4522
    };
4523
    const setWidth = (element, decision, options) => {
4524
      const maxWidthFunction = options.maxWidthFunction;
4525
      maxWidthFunction(element, decision.maxWidth);
4526
    };
4527
    const position$2 = (element, decision, options) => {
4528
      const positionCss = reposition(options.origin, decision);
4529
      options.transition.each(transition => {
4530
        applyTransitionCss(element, options.origin, positionCss, transition, decision, options.lastPlacement);
4531
      });
4532
      applyPositionCss(element, positionCss);
4533
    };
4534
    const setPlacement = (element, decision) => {
4535
      setPlacement$1(element, decision.placement);
4536
    };
4537
 
4538
    const setMaxHeight = (element, maxHeight) => {
4539
      setMax$1(element, Math.floor(maxHeight));
4540
    };
4541
    const anchored = constant$1((element, available) => {
4542
      setMaxHeight(element, available);
4543
      setAll(element, {
4544
        'overflow-x': 'hidden',
4545
        'overflow-y': 'auto'
4546
      });
4547
    });
4548
    const expandable$1 = constant$1((element, available) => {
4549
      setMaxHeight(element, available);
4550
    });
4551
 
4552
    const defaultOr = (options, key, dephault) => options[key] === undefined ? dephault : options[key];
4553
    const simple = (anchor, element, bubble, layouts, lastPlacement, optBounds, overrideOptions, transition) => {
4554
      const maxHeightFunction = defaultOr(overrideOptions, 'maxHeightFunction', anchored());
4555
      const maxWidthFunction = defaultOr(overrideOptions, 'maxWidthFunction', noop);
4556
      const anchorBox = anchor.anchorBox;
4557
      const origin = anchor.origin;
4558
      const options = {
4559
        bounds: viewport(origin, optBounds),
4560
        origin,
4561
        preference: layouts,
4562
        maxHeightFunction,
4563
        maxWidthFunction,
4564
        lastPlacement,
4565
        transition
4566
      };
4567
      return go(anchorBox, element, bubble, options);
4568
    };
4569
    const go = (anchorBox, element, bubble, options) => {
4570
      const decision = layout(anchorBox, element, bubble, options);
4571
      position$2(element, decision, options);
4572
      setPlacement(element, decision);
4573
      setClasses(element, decision);
4574
      setHeight(element, decision, options);
4575
      setWidth(element, decision, options);
4576
      return {
4577
        layout: decision.layout,
4578
        placement: decision.placement
4579
      };
4580
    };
4581
 
4582
    const allAlignments = [
4583
      'valignCentre',
4584
      'alignLeft',
4585
      'alignRight',
4586
      'alignCentre',
4587
      'top',
4588
      'bottom',
4589
      'left',
4590
      'right',
4591
      'inset'
4592
    ];
4593
    const nu$5 = (xOffset, yOffset, classes, insetModifier = 1) => {
4594
      const insetXOffset = xOffset * insetModifier;
4595
      const insetYOffset = yOffset * insetModifier;
1441 ariadna 4596
      const getClasses = prop => get$h(classes, prop).getOr([]);
1 efrain 4597
      const make = (xDelta, yDelta, alignmentsOn) => {
4598
        const alignmentsOff = difference(allAlignments, alignmentsOn);
4599
        return {
4600
          offset: SugarPosition(xDelta, yDelta),
4601
          classesOn: bind$3(alignmentsOn, getClasses),
4602
          classesOff: bind$3(alignmentsOff, getClasses)
4603
        };
4604
      };
4605
      return {
4606
        southeast: () => make(-xOffset, yOffset, [
4607
          'top',
4608
          'alignLeft'
4609
        ]),
4610
        southwest: () => make(xOffset, yOffset, [
4611
          'top',
4612
          'alignRight'
4613
        ]),
4614
        south: () => make(-xOffset / 2, yOffset, [
4615
          'top',
4616
          'alignCentre'
4617
        ]),
4618
        northeast: () => make(-xOffset, -yOffset, [
4619
          'bottom',
4620
          'alignLeft'
4621
        ]),
4622
        northwest: () => make(xOffset, -yOffset, [
4623
          'bottom',
4624
          'alignRight'
4625
        ]),
4626
        north: () => make(-xOffset / 2, -yOffset, [
4627
          'bottom',
4628
          'alignCentre'
4629
        ]),
4630
        east: () => make(xOffset, -yOffset / 2, [
4631
          'valignCentre',
4632
          'left'
4633
        ]),
4634
        west: () => make(-xOffset, -yOffset / 2, [
4635
          'valignCentre',
4636
          'right'
4637
        ]),
4638
        insetNortheast: () => make(insetXOffset, insetYOffset, [
4639
          'top',
4640
          'alignLeft',
4641
          'inset'
4642
        ]),
4643
        insetNorthwest: () => make(-insetXOffset, insetYOffset, [
4644
          'top',
4645
          'alignRight',
4646
          'inset'
4647
        ]),
4648
        insetNorth: () => make(-insetXOffset / 2, insetYOffset, [
4649
          'top',
4650
          'alignCentre',
4651
          'inset'
4652
        ]),
4653
        insetSoutheast: () => make(insetXOffset, -insetYOffset, [
4654
          'bottom',
4655
          'alignLeft',
4656
          'inset'
4657
        ]),
4658
        insetSouthwest: () => make(-insetXOffset, -insetYOffset, [
4659
          'bottom',
4660
          'alignRight',
4661
          'inset'
4662
        ]),
4663
        insetSouth: () => make(-insetXOffset / 2, -insetYOffset, [
4664
          'bottom',
4665
          'alignCentre',
4666
          'inset'
4667
        ]),
4668
        insetEast: () => make(-insetXOffset, -insetYOffset / 2, [
4669
          'valignCentre',
4670
          'right',
4671
          'inset'
4672
        ]),
4673
        insetWest: () => make(insetXOffset, -insetYOffset / 2, [
4674
          'valignCentre',
4675
          'left',
4676
          'inset'
4677
        ])
4678
      };
4679
    };
4680
    const fallback = () => nu$5(0, 0, {});
4681
 
4682
    const nu$4 = identity;
4683
 
4684
    const onDirection = (isLtr, isRtl) => element => getDirection(element) === 'rtl' ? isRtl : isLtr;
1441 ariadna 4685
    const getDirection = element => get$f(element, 'direction') === 'rtl' ? 'rtl' : 'ltr';
1 efrain 4686
 
4687
    var AttributeValue;
4688
    (function (AttributeValue) {
4689
      AttributeValue['TopToBottom'] = 'toptobottom';
4690
      AttributeValue['BottomToTop'] = 'bottomtotop';
4691
    }(AttributeValue || (AttributeValue = {})));
4692
    const Attribute = 'data-alloy-vertical-dir';
1441 ariadna 4693
    const isBottomToTopDir = el => closest$2(el, current => isElement$1(current) && get$g(current, 'data-alloy-vertical-dir') === AttributeValue.BottomToTop);
1 efrain 4694
 
4695
    const schema$y = () => optionObjOf('layouts', [
4696
      required$1('onLtr'),
4697
      required$1('onRtl'),
4698
      option$3('onBottomLtr'),
4699
      option$3('onBottomRtl')
4700
    ]);
1441 ariadna 4701
    const get$6 = (elem, info, defaultLtr, defaultRtl, defaultBottomLtr, defaultBottomRtl, dirElement) => {
1 efrain 4702
      const isBottomToTop = dirElement.map(isBottomToTopDir).getOr(false);
4703
      const customLtr = info.layouts.map(ls => ls.onLtr(elem));
4704
      const customRtl = info.layouts.map(ls => ls.onRtl(elem));
4705
      const ltr = isBottomToTop ? info.layouts.bind(ls => ls.onBottomLtr.map(f => f(elem))).or(customLtr).getOr(defaultBottomLtr) : customLtr.getOr(defaultLtr);
4706
      const rtl = isBottomToTop ? info.layouts.bind(ls => ls.onBottomRtl.map(f => f(elem))).or(customRtl).getOr(defaultBottomRtl) : customRtl.getOr(defaultRtl);
4707
      const f = onDirection(ltr, rtl);
4708
      return f(elem);
4709
    };
4710
 
4711
    const placement$4 = (component, anchorInfo, origin) => {
4712
      const hotspot = anchorInfo.hotspot;
4713
      const anchorBox = toBox(origin, hotspot.element);
1441 ariadna 4714
      const layouts = get$6(component.element, anchorInfo, belowOrAbove(), belowOrAboveRtl(), aboveOrBelow(), aboveOrBelowRtl(), Optional.some(anchorInfo.hotspot.element));
1 efrain 4715
      return Optional.some(nu$4({
4716
        anchorBox,
4717
        bubble: anchorInfo.bubble.getOr(fallback()),
4718
        overrides: anchorInfo.overrides,
4719
        layouts
4720
      }));
4721
    };
4722
    var HotspotAnchor = [
4723
      required$1('hotspot'),
4724
      option$3('bubble'),
4725
      defaulted('overrides', {}),
4726
      schema$y(),
4727
      output$1('placement', placement$4)
4728
    ];
4729
 
4730
    const placement$3 = (component, anchorInfo, origin) => {
4731
      const pos = translate$2(origin, anchorInfo.x, anchorInfo.y);
4732
      const anchorBox = bounds(pos.left, pos.top, anchorInfo.width, anchorInfo.height);
1441 ariadna 4733
      const layouts = get$6(component.element, anchorInfo, all$1(), allRtl$1(), all$1(), allRtl$1(), Optional.none());
1 efrain 4734
      return Optional.some(nu$4({
4735
        anchorBox,
4736
        bubble: anchorInfo.bubble,
4737
        overrides: anchorInfo.overrides,
4738
        layouts
4739
      }));
4740
    };
4741
    var MakeshiftAnchor = [
4742
      required$1('x'),
4743
      required$1('y'),
4744
      defaulted('height', 0),
4745
      defaulted('width', 0),
4746
      defaulted('bubble', fallback()),
4747
      defaulted('overrides', {}),
4748
      schema$y(),
4749
      output$1('placement', placement$3)
4750
    ];
4751
 
4752
    const adt$7 = Adt.generate([
4753
      { screen: ['point'] },
4754
      {
4755
        absolute: [
4756
          'point',
4757
          'scrollLeft',
4758
          'scrollTop'
4759
        ]
4760
      }
4761
    ]);
4762
    const toFixed = pos => pos.fold(identity, (point, scrollLeft, scrollTop) => point.translate(-scrollLeft, -scrollTop));
4763
    const toAbsolute = pos => pos.fold(identity, identity);
4764
    const sum = points => foldl(points, (b, a) => b.translate(a.left, a.top), SugarPosition(0, 0));
4765
    const sumAsFixed = positions => {
4766
      const points = map$2(positions, toFixed);
4767
      return sum(points);
4768
    };
4769
    const sumAsAbsolute = positions => {
4770
      const points = map$2(positions, toAbsolute);
4771
      return sum(points);
4772
    };
4773
    const screen = adt$7.screen;
4774
    const absolute$1 = adt$7.absolute;
4775
 
4776
    const getOffset = (component, origin, anchorInfo) => {
4777
      const win = defaultView(anchorInfo.root).dom;
4778
      const hasSameOwner = frame => {
4779
        const frameOwner = owner$4(frame);
4780
        const compOwner = owner$4(component.element);
4781
        return eq(frameOwner, compOwner);
4782
      };
4783
      return Optional.from(win.frameElement).map(SugarElement.fromDom).filter(hasSameOwner).map(absolute$3);
4784
    };
4785
    const getRootPoint = (component, origin, anchorInfo) => {
4786
      const doc = owner$4(component.element);
1441 ariadna 4787
      const outerScroll = get$c(doc);
1 efrain 4788
      const offset = getOffset(component, origin, anchorInfo).getOr(outerScroll);
4789
      return absolute$1(offset, outerScroll.left, outerScroll.top);
4790
    };
4791
 
4792
    const getBox = (left, top, width, height) => {
4793
      const point = screen(SugarPosition(left, top));
4794
      return Optional.some(pointed(point, width, height));
4795
    };
4796
    const calcNewAnchor = (optBox, rootPoint, anchorInfo, origin, elem) => optBox.map(box => {
4797
      const points = [
4798
        rootPoint,
4799
        box.point
4800
      ];
4801
      const topLeft = cata$1(origin, () => sumAsAbsolute(points), () => sumAsAbsolute(points), () => sumAsFixed(points));
4802
      const anchorBox = rect(topLeft.left, topLeft.top, box.width, box.height);
4803
      const layoutsLtr = anchorInfo.showAbove ? aboveOrBelow() : belowOrAbove();
4804
      const layoutsRtl = anchorInfo.showAbove ? aboveOrBelowRtl() : belowOrAboveRtl();
1441 ariadna 4805
      const layouts = get$6(elem, anchorInfo, layoutsLtr, layoutsRtl, layoutsLtr, layoutsRtl, Optional.none());
1 efrain 4806
      return nu$4({
4807
        anchorBox,
4808
        bubble: anchorInfo.bubble.getOr(fallback()),
4809
        overrides: anchorInfo.overrides,
4810
        layouts
4811
      });
4812
    });
4813
 
4814
    const placement$2 = (component, anchorInfo, origin) => {
4815
      const rootPoint = getRootPoint(component, origin, anchorInfo);
4816
      return anchorInfo.node.filter(inBody).bind(target => {
4817
        const rect = target.dom.getBoundingClientRect();
4818
        const nodeBox = getBox(rect.left, rect.top, rect.width, rect.height);
4819
        const elem = anchorInfo.node.getOr(component.element);
4820
        return calcNewAnchor(nodeBox, rootPoint, anchorInfo, origin, elem);
4821
      });
4822
    };
4823
    var NodeAnchor = [
4824
      required$1('node'),
4825
      required$1('root'),
4826
      option$3('bubble'),
4827
      schema$y(),
4828
      defaulted('overrides', {}),
4829
      defaulted('showAbove', false),
4830
      output$1('placement', placement$2)
4831
    ];
4832
 
4833
    const zeroWidth = '\uFEFF';
4834
    const nbsp = '\xA0';
4835
 
4836
    const create$3 = (start, soffset, finish, foffset) => ({
4837
      start,
4838
      soffset,
4839
      finish,
4840
      foffset
4841
    });
4842
    const SimRange = { create: create$3 };
4843
 
4844
    const adt$6 = Adt.generate([
4845
      { before: ['element'] },
4846
      {
4847
        on: [
4848
          'element',
4849
          'offset'
4850
        ]
4851
      },
4852
      { after: ['element'] }
4853
    ]);
4854
    const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
4855
    const getStart$1 = situ => situ.fold(identity, identity, identity);
4856
    const before = adt$6.before;
4857
    const on$1 = adt$6.on;
4858
    const after$1 = adt$6.after;
4859
    const Situ = {
4860
      before,
4861
      on: on$1,
4862
      after: after$1,
4863
      cata,
4864
      getStart: getStart$1
4865
    };
4866
 
4867
    const adt$5 = Adt.generate([
4868
      { domRange: ['rng'] },
4869
      {
4870
        relative: [
4871
          'startSitu',
4872
          'finishSitu'
4873
        ]
4874
      },
4875
      {
4876
        exact: [
4877
          'start',
4878
          'soffset',
4879
          'finish',
4880
          'foffset'
4881
        ]
4882
      }
4883
    ]);
4884
    const exactFromRange = simRange => adt$5.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
4885
    const getStart = selection => selection.match({
4886
      domRange: rng => SugarElement.fromDom(rng.startContainer),
4887
      relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
4888
      exact: (start, _soffset, _finish, _foffset) => start
4889
    });
4890
    const domRange = adt$5.domRange;
4891
    const relative = adt$5.relative;
4892
    const exact = adt$5.exact;
4893
    const getWin = selection => {
4894
      const start = getStart(selection);
4895
      return defaultView(start);
4896
    };
4897
    const range$1 = SimRange.create;
4898
    const SimSelection = {
4899
      domRange,
4900
      relative,
4901
      exact,
4902
      exactFromRange,
4903
      getWin,
4904
      range: range$1
4905
    };
4906
 
4907
    const setStart = (rng, situ) => {
4908
      situ.fold(e => {
4909
        rng.setStartBefore(e.dom);
4910
      }, (e, o) => {
4911
        rng.setStart(e.dom, o);
4912
      }, e => {
4913
        rng.setStartAfter(e.dom);
4914
      });
4915
    };
4916
    const setFinish = (rng, situ) => {
4917
      situ.fold(e => {
4918
        rng.setEndBefore(e.dom);
4919
      }, (e, o) => {
4920
        rng.setEnd(e.dom, o);
4921
      }, e => {
4922
        rng.setEndAfter(e.dom);
4923
      });
4924
    };
4925
    const relativeToNative = (win, startSitu, finishSitu) => {
4926
      const range = win.document.createRange();
4927
      setStart(range, startSitu);
4928
      setFinish(range, finishSitu);
4929
      return range;
4930
    };
4931
    const exactToNative = (win, start, soffset, finish, foffset) => {
4932
      const rng = win.document.createRange();
4933
      rng.setStart(start.dom, soffset);
4934
      rng.setEnd(finish.dom, foffset);
4935
      return rng;
4936
    };
4937
    const toRect = rect => ({
4938
      left: rect.left,
4939
      top: rect.top,
4940
      right: rect.right,
4941
      bottom: rect.bottom,
4942
      width: rect.width,
4943
      height: rect.height
4944
    });
4945
    const getFirstRect$1 = rng => {
4946
      const rects = rng.getClientRects();
4947
      const rect = rects.length > 0 ? rects[0] : rng.getBoundingClientRect();
4948
      return rect.width > 0 || rect.height > 0 ? Optional.some(rect).map(toRect) : Optional.none();
4949
    };
4950
    const getBounds$2 = rng => {
4951
      const rect = rng.getBoundingClientRect();
4952
      return rect.width > 0 || rect.height > 0 ? Optional.some(rect).map(toRect) : Optional.none();
4953
    };
4954
 
4955
    const adt$4 = Adt.generate([
4956
      {
4957
        ltr: [
4958
          'start',
4959
          'soffset',
4960
          'finish',
4961
          'foffset'
4962
        ]
4963
      },
4964
      {
4965
        rtl: [
4966
          'start',
4967
          'soffset',
4968
          'finish',
4969
          'foffset'
4970
        ]
4971
      }
4972
    ]);
4973
    const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset);
4974
    const getRanges = (win, selection) => selection.match({
4975
      domRange: rng => {
4976
        return {
4977
          ltr: constant$1(rng),
4978
          rtl: Optional.none
4979
        };
4980
      },
4981
      relative: (startSitu, finishSitu) => {
4982
        return {
4983
          ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
4984
          rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
4985
        };
4986
      },
4987
      exact: (start, soffset, finish, foffset) => {
4988
        return {
4989
          ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)),
4990
          rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset)))
4991
        };
4992
      }
4993
    });
4994
    const doDiagnose = (win, ranges) => {
4995
      const rng = ranges.ltr();
4996
      if (rng.collapsed) {
4997
        const reversed = ranges.rtl().filter(rev => rev.collapsed === false);
4998
        return reversed.map(rev => adt$4.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$4.ltr, rng));
4999
      } else {
5000
        return fromRange(win, adt$4.ltr, rng);
5001
      }
5002
    };
5003
    const diagnose = (win, selection) => {
5004
      const ranges = getRanges(win, selection);
5005
      return doDiagnose(win, ranges);
5006
    };
5007
    const asLtrRange = (win, selection) => {
5008
      const diagnosis = diagnose(win, selection);
5009
      return diagnosis.match({
5010
        ltr: (start, soffset, finish, foffset) => {
5011
          const rng = win.document.createRange();
5012
          rng.setStart(start.dom, soffset);
5013
          rng.setEnd(finish.dom, foffset);
5014
          return rng;
5015
        },
5016
        rtl: (start, soffset, finish, foffset) => {
5017
          const rng = win.document.createRange();
5018
          rng.setStart(finish.dom, foffset);
5019
          rng.setEnd(start.dom, soffset);
5020
          return rng;
5021
        }
5022
      });
5023
    };
5024
    adt$4.ltr;
5025
    adt$4.rtl;
5026
 
5027
    const ancestors = (scope, predicate, isRoot) => filter$2(parents(scope, isRoot), predicate);
5028
 
5029
    const descendants = (scope, selector) => all$3(selector, scope);
5030
 
5031
    const makeRange = (start, soffset, finish, foffset) => {
5032
      const doc = owner$4(start);
5033
      const rng = doc.dom.createRange();
5034
      rng.setStart(start.dom, soffset);
5035
      rng.setEnd(finish.dom, foffset);
5036
      return rng;
5037
    };
5038
    const after = (start, soffset, finish, foffset) => {
5039
      const r = makeRange(start, soffset, finish, foffset);
5040
      const same = eq(start, finish) && soffset === foffset;
5041
      return r.collapsed && !same;
5042
    };
5043
 
5044
    const getNativeSelection = win => Optional.from(win.getSelection());
5045
    const readRange = selection => {
5046
      if (selection.rangeCount > 0) {
5047
        const firstRng = selection.getRangeAt(0);
5048
        const lastRng = selection.getRangeAt(selection.rangeCount - 1);
5049
        return Optional.some(SimRange.create(SugarElement.fromDom(firstRng.startContainer), firstRng.startOffset, SugarElement.fromDom(lastRng.endContainer), lastRng.endOffset));
5050
      } else {
5051
        return Optional.none();
5052
      }
5053
    };
5054
    const doGetExact = selection => {
5055
      if (selection.anchorNode === null || selection.focusNode === null) {
5056
        return readRange(selection);
5057
      } else {
5058
        const anchor = SugarElement.fromDom(selection.anchorNode);
5059
        const focus = SugarElement.fromDom(selection.focusNode);
5060
        return after(anchor, selection.anchorOffset, focus, selection.focusOffset) ? Optional.some(SimRange.create(anchor, selection.anchorOffset, focus, selection.focusOffset)) : readRange(selection);
5061
      }
5062
    };
5063
    const getExact = win => getNativeSelection(win).filter(sel => sel.rangeCount > 0).bind(doGetExact);
5064
    const getFirstRect = (win, selection) => {
5065
      const rng = asLtrRange(win, selection);
5066
      return getFirstRect$1(rng);
5067
    };
5068
    const getBounds$1 = (win, selection) => {
5069
      const rng = asLtrRange(win, selection);
5070
      return getBounds$2(rng);
5071
    };
5072
 
5073
    const NodeValue = (is, name) => {
5074
      const get = element => {
5075
        if (!is(element)) {
5076
          throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
5077
        }
5078
        return getOption(element).getOr('');
5079
      };
5080
      const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
5081
      const set = (element, value) => {
5082
        if (!is(element)) {
5083
          throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
5084
        }
5085
        element.dom.nodeValue = value;
5086
      };
5087
      return {
5088
        get,
5089
        getOption,
5090
        set
5091
      };
5092
    };
5093
 
5094
    const api = NodeValue(isText, 'text');
1441 ariadna 5095
    const get$5 = element => api.get(element);
1 efrain 5096
 
5097
    const point = (element, offset) => ({
5098
      element,
5099
      offset
5100
    });
5101
    const descendOnce$1 = (element, offset) => {
5102
      const children$1 = children(element);
5103
      if (children$1.length === 0) {
5104
        return point(element, offset);
5105
      } else if (offset < children$1.length) {
5106
        return point(children$1[offset], 0);
5107
      } else {
5108
        const last = children$1[children$1.length - 1];
1441 ariadna 5109
        const len = isText(last) ? get$5(last).length : children(last).length;
1 efrain 5110
        return point(last, len);
5111
      }
5112
    };
5113
 
5114
    const descendOnce = (element, offset) => isText(element) ? point(element, offset) : descendOnce$1(element, offset);
5115
    const isSimRange = detail => detail.foffset !== undefined;
5116
    const getAnchorSelection = (win, anchorInfo) => {
5117
      const getSelection = anchorInfo.getSelection.getOrThunk(() => () => getExact(win));
5118
      return getSelection().map(sel => {
5119
        if (isSimRange(sel)) {
5120
          const modStart = descendOnce(sel.start, sel.soffset);
5121
          const modFinish = descendOnce(sel.finish, sel.foffset);
5122
          return SimSelection.range(modStart.element, modStart.offset, modFinish.element, modFinish.offset);
5123
        } else {
5124
          return sel;
5125
        }
5126
      });
5127
    };
5128
    const placement$1 = (component, anchorInfo, origin) => {
5129
      const win = defaultView(anchorInfo.root).dom;
5130
      const rootPoint = getRootPoint(component, origin, anchorInfo);
5131
      const selectionBox = getAnchorSelection(win, anchorInfo).bind(sel => {
5132
        if (isSimRange(sel)) {
5133
          const optRect = getBounds$1(win, SimSelection.exactFromRange(sel)).orThunk(() => {
5134
            const zeroWidth$1 = SugarElement.fromText(zeroWidth);
5135
            before$1(sel.start, zeroWidth$1);
5136
            const rect = getFirstRect(win, SimSelection.exact(zeroWidth$1, 0, zeroWidth$1, 1));
1441 ariadna 5137
            remove$6(zeroWidth$1);
1 efrain 5138
            return rect;
5139
          });
5140
          return optRect.bind(rawRect => {
5141
            return getBox(rawRect.left, rawRect.top, rawRect.width, rawRect.height);
5142
          });
5143
        } else {
5144
          const selectionRect = map$1(sel, cell => cell.dom.getBoundingClientRect());
5145
          const bounds = {
5146
            left: Math.min(selectionRect.firstCell.left, selectionRect.lastCell.left),
5147
            right: Math.max(selectionRect.firstCell.right, selectionRect.lastCell.right),
5148
            top: Math.min(selectionRect.firstCell.top, selectionRect.lastCell.top),
5149
            bottom: Math.max(selectionRect.firstCell.bottom, selectionRect.lastCell.bottom)
5150
          };
5151
          return getBox(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top);
5152
        }
5153
      });
5154
      const targetElement = getAnchorSelection(win, anchorInfo).bind(sel => {
5155
        if (isSimRange(sel)) {
5156
          return isElement$1(sel.start) ? Optional.some(sel.start) : parentElement(sel.start);
5157
        } else {
5158
          return Optional.some(sel.firstCell);
5159
        }
5160
      });
5161
      const elem = targetElement.getOr(component.element);
5162
      return calcNewAnchor(selectionBox, rootPoint, anchorInfo, origin, elem);
5163
    };
5164
    var SelectionAnchor = [
5165
      option$3('getSelection'),
5166
      required$1('root'),
5167
      option$3('bubble'),
5168
      schema$y(),
5169
      defaulted('overrides', {}),
5170
      defaulted('showAbove', false),
5171
      output$1('placement', placement$1)
5172
    ];
5173
 
5174
    const labelPrefix$1 = 'link-layout';
5175
    const eastX = anchor => anchor.x + anchor.width;
5176
    const westX = (anchor, element) => anchor.x - element.width;
5177
    const northY$1 = (anchor, element) => anchor.y - element.height + anchor.height;
5178
    const southY$1 = anchor => anchor.y;
5179
    const southeast$1 = (anchor, element, bubbles) => nu$6(eastX(anchor), southY$1(anchor), bubbles.southeast(), southeast$3(), 'southeast', boundsRestriction(anchor, {
5180
      left: 0,
5181
      top: 2
5182
    }), labelPrefix$1);
5183
    const southwest$1 = (anchor, element, bubbles) => nu$6(westX(anchor, element), southY$1(anchor), bubbles.southwest(), southwest$3(), 'southwest', boundsRestriction(anchor, {
5184
      right: 1,
5185
      top: 2
5186
    }), labelPrefix$1);
5187
    const northeast$1 = (anchor, element, bubbles) => nu$6(eastX(anchor), northY$1(anchor, element), bubbles.northeast(), northeast$3(), 'northeast', boundsRestriction(anchor, {
5188
      left: 0,
5189
      bottom: 3
5190
    }), labelPrefix$1);
5191
    const northwest$1 = (anchor, element, bubbles) => nu$6(westX(anchor, element), northY$1(anchor, element), bubbles.northwest(), northwest$3(), 'northwest', boundsRestriction(anchor, {
5192
      right: 1,
5193
      bottom: 3
5194
    }), labelPrefix$1);
5195
    const all = () => [
5196
      southeast$1,
5197
      southwest$1,
5198
      northeast$1,
5199
      northwest$1
5200
    ];
5201
    const allRtl = () => [
5202
      southwest$1,
5203
      southeast$1,
5204
      northwest$1,
5205
      northeast$1
5206
    ];
5207
 
5208
    const placement = (component, submenuInfo, origin) => {
5209
      const anchorBox = toBox(origin, submenuInfo.item.element);
1441 ariadna 5210
      const layouts = get$6(component.element, submenuInfo, all(), allRtl(), all(), allRtl(), Optional.none());
1 efrain 5211
      return Optional.some(nu$4({
5212
        anchorBox,
5213
        bubble: fallback(),
5214
        overrides: submenuInfo.overrides,
5215
        layouts
5216
      }));
5217
    };
5218
    var SubmenuAnchor = [
5219
      required$1('item'),
5220
      schema$y(),
5221
      defaulted('overrides', {}),
5222
      output$1('placement', placement)
5223
    ];
5224
 
5225
    var AnchorSchema = choose$1('type', {
5226
      selection: SelectionAnchor,
5227
      node: NodeAnchor,
5228
      hotspot: HotspotAnchor,
5229
      submenu: SubmenuAnchor,
5230
      makeshift: MakeshiftAnchor
5231
    });
5232
 
5233
    const TransitionSchema = [
5234
      requiredArrayOf('classes', string),
5235
      defaultedStringEnum('mode', 'all', [
5236
        'all',
5237
        'layout',
5238
        'placement'
5239
      ])
5240
    ];
5241
    const PositionSchema = [
5242
      defaulted('useFixed', never),
5243
      option$3('getBounds')
5244
    ];
5245
    const PlacementSchema = [
5246
      requiredOf('anchor', AnchorSchema),
5247
      optionObjOf('transition', TransitionSchema)
5248
    ];
5249
 
5250
    const getFixedOrigin = () => {
5251
      const html = document.documentElement;
5252
      return fixed$1(0, 0, html.clientWidth, html.clientHeight);
5253
    };
5254
    const getRelativeOrigin = component => {
5255
      const position = absolute$3(component.element);
5256
      const bounds = component.element.dom.getBoundingClientRect();
5257
      return relative$1(position.left, position.top, bounds.width, bounds.height);
5258
    };
5259
    const place = (origin, anchoring, optBounds, placee, lastPlace, transition) => {
5260
      const anchor = box(anchoring.anchorBox, origin);
5261
      return simple(anchor, placee.element, anchoring.bubble, anchoring.layouts, lastPlace, optBounds, anchoring.overrides, transition);
5262
    };
5263
    const position$1 = (component, posConfig, posState, placee, placementSpec) => {
5264
      const optWithinBounds = Optional.none();
5265
      positionWithinBounds(component, posConfig, posState, placee, placementSpec, optWithinBounds);
5266
    };
5267
    const positionWithinBounds = (component, posConfig, posState, placee, placementSpec, optWithinBounds) => {
5268
      const placeeDetail = asRawOrDie$1('placement.info', objOf(PlacementSchema), placementSpec);
5269
      const anchorage = placeeDetail.anchor;
5270
      const element = placee.element;
5271
      const placeeState = posState.get(placee.uid);
5272
      preserve$1(() => {
5273
        set$8(element, 'position', 'fixed');
5274
        const oldVisibility = getRaw(element, 'visibility');
5275
        set$8(element, 'visibility', 'hidden');
5276
        const origin = posConfig.useFixed() ? getFixedOrigin() : getRelativeOrigin(component);
5277
        anchorage.placement(component, anchorage, origin).each(anchoring => {
5278
          const optBounds = optWithinBounds.orThunk(() => posConfig.getBounds.map(apply$1));
5279
          const newState = place(origin, anchoring, optBounds, placee, placeeState, placeeDetail.transition);
5280
          posState.set(placee.uid, newState);
5281
        });
5282
        oldVisibility.fold(() => {
1441 ariadna 5283
          remove$7(element, 'visibility');
1 efrain 5284
        }, vis => {
5285
          set$8(element, 'visibility', vis);
5286
        });
5287
        if (getRaw(element, 'left').isNone() && getRaw(element, 'top').isNone() && getRaw(element, 'right').isNone() && getRaw(element, 'bottom').isNone() && is$1(getRaw(element, 'position'), 'fixed')) {
1441 ariadna 5288
          remove$7(element, 'position');
1 efrain 5289
        }
5290
      }, element);
5291
    };
5292
    const getMode = (component, pConfig, _pState) => pConfig.useFixed() ? 'fixed' : 'absolute';
1441 ariadna 5293
    const reset = (component, pConfig, posState, placee) => {
1 efrain 5294
      const element = placee.element;
5295
      each$1([
5296
        'position',
5297
        'left',
5298
        'right',
5299
        'top',
5300
        'bottom'
1441 ariadna 5301
      ], prop => remove$7(element, prop));
5302
      reset$1(element);
1 efrain 5303
      posState.clear(placee.uid);
5304
    };
5305
 
5306
    var PositionApis = /*#__PURE__*/Object.freeze({
5307
        __proto__: null,
5308
        position: position$1,
5309
        positionWithinBounds: positionWithinBounds,
5310
        getMode: getMode,
1441 ariadna 5311
        reset: reset
1 efrain 5312
    });
5313
 
1441 ariadna 5314
    const init$f = () => {
1 efrain 5315
      let state = {};
5316
      const set = (id, data) => {
5317
        state[id] = data;
5318
      };
1441 ariadna 5319
      const get = id => get$h(state, id);
1 efrain 5320
      const clear = id => {
5321
        if (isNonNullable(id)) {
5322
          delete state[id];
5323
        } else {
5324
          state = {};
5325
        }
5326
      };
1441 ariadna 5327
      return nu$7({
1 efrain 5328
        readState: () => state,
5329
        clear,
5330
        set,
5331
        get
5332
      });
5333
    };
5334
 
5335
    var PositioningState = /*#__PURE__*/Object.freeze({
5336
        __proto__: null,
1441 ariadna 5337
        init: init$f
1 efrain 5338
    });
5339
 
5340
    const Positioning = create$4({
5341
      fields: PositionSchema,
5342
      name: 'positioning',
5343
      active: ActivePosition,
5344
      apis: PositionApis,
5345
      state: PositioningState
5346
    });
5347
 
5348
    const isConnected = comp => comp.getSystem().isConnected();
5349
    const fireDetaching = component => {
5350
      emit(component, detachedFromDom());
5351
      const children = component.components();
5352
      each$1(children, fireDetaching);
5353
    };
5354
    const fireAttaching = component => {
5355
      const children = component.components();
5356
      each$1(children, fireAttaching);
5357
      emit(component, attachedToDom());
5358
    };
5359
    const virtualAttach = (parent, child) => {
5360
      parent.getSystem().addToWorld(child);
5361
      if (inBody(parent.element)) {
5362
        fireAttaching(child);
5363
      }
5364
    };
5365
    const virtualDetach = comp => {
5366
      fireDetaching(comp);
5367
      comp.getSystem().removeFromWorld(comp);
5368
    };
5369
    const attach$1 = (parent, child) => {
5370
      append$2(parent.element, child.element);
5371
    };
5372
    const detachChildren$1 = component => {
1441 ariadna 5373
      each$1(component.components(), childComp => remove$6(childComp.element));
1 efrain 5374
      empty(component.element);
5375
      component.syncComponents();
5376
    };
5377
    const replaceChildren = (component, newSpecs, buildNewChildren) => {
5378
      const subs = component.components();
5379
      detachChildren$1(component);
5380
      const newChildren = buildNewChildren(newSpecs);
5381
      const deleted = difference(subs, newChildren);
5382
      each$1(deleted, comp => {
5383
        fireDetaching(comp);
5384
        component.getSystem().removeFromWorld(comp);
5385
      });
5386
      each$1(newChildren, childComp => {
5387
        if (!isConnected(childComp)) {
5388
          component.getSystem().addToWorld(childComp);
5389
          attach$1(component, childComp);
5390
          if (inBody(component.element)) {
5391
            fireAttaching(childComp);
5392
          }
5393
        } else {
5394
          attach$1(component, childComp);
5395
        }
5396
      });
5397
      component.syncComponents();
5398
    };
5399
    const virtualReplaceChildren = (component, newSpecs, buildNewChildren) => {
5400
      const subs = component.components();
5401
      const existingComps = bind$3(newSpecs, spec => getPremade(spec).toArray());
5402
      each$1(subs, childComp => {
5403
        if (!contains$2(existingComps, childComp)) {
5404
          virtualDetach(childComp);
5405
        }
5406
      });
5407
      const newChildren = buildNewChildren(newSpecs);
5408
      const deleted = difference(subs, newChildren);
5409
      each$1(deleted, deletedComp => {
5410
        if (isConnected(deletedComp)) {
5411
          virtualDetach(deletedComp);
5412
        }
5413
      });
5414
      each$1(newChildren, childComp => {
5415
        if (!isConnected(childComp)) {
5416
          virtualAttach(component, childComp);
5417
        }
5418
      });
5419
      component.syncComponents();
5420
    };
5421
 
5422
    const attach = (parent, child) => {
5423
      attachWith(parent, child, append$2);
5424
    };
5425
    const attachWith = (parent, child, insertion) => {
5426
      parent.getSystem().addToWorld(child);
5427
      insertion(parent.element, child.element);
5428
      if (inBody(parent.element)) {
5429
        fireAttaching(child);
5430
      }
5431
      parent.syncComponents();
5432
    };
5433
    const doDetach = component => {
5434
      fireDetaching(component);
1441 ariadna 5435
      remove$6(component.element);
1 efrain 5436
      component.getSystem().removeFromWorld(component);
5437
    };
5438
    const detach = component => {
5439
      const parent$1 = parent(component.element).bind(p => component.getSystem().getByDom(p).toOptional());
5440
      doDetach(component);
5441
      parent$1.each(p => {
5442
        p.syncComponents();
5443
      });
5444
    };
5445
    const detachChildren = component => {
5446
      const subs = component.components();
5447
      each$1(subs, doDetach);
5448
      empty(component.element);
5449
      component.syncComponents();
5450
    };
5451
    const attachSystem = (element, guiSystem) => {
5452
      attachSystemWith(element, guiSystem, append$2);
5453
    };
5454
    const attachSystemAfter = (element, guiSystem) => {
5455
      attachSystemWith(element, guiSystem, after$2);
5456
    };
5457
    const attachSystemWith = (element, guiSystem, inserter) => {
5458
      inserter(element, guiSystem.element);
5459
      const children$1 = children(guiSystem.element);
5460
      each$1(children$1, child => {
5461
        guiSystem.getByDom(child).each(fireAttaching);
5462
      });
5463
    };
5464
    const detachSystem = guiSystem => {
5465
      const children$1 = children(guiSystem.element);
5466
      each$1(children$1, child => {
5467
        guiSystem.getByDom(child).each(fireDetaching);
5468
      });
1441 ariadna 5469
      remove$6(guiSystem.element);
1 efrain 5470
    };
5471
 
5472
    const rebuild = (sandbox, sConfig, sState, data) => {
5473
      sState.get().each(_data => {
5474
        detachChildren(sandbox);
5475
      });
5476
      const point = sConfig.getAttachPoint(sandbox);
5477
      attach(point, sandbox);
5478
      const built = sandbox.getSystem().build(data);
5479
      attach(sandbox, built);
5480
      sState.set(built);
5481
      return built;
5482
    };
5483
    const open$1 = (sandbox, sConfig, sState, data) => {
5484
      const newState = rebuild(sandbox, sConfig, sState, data);
5485
      sConfig.onOpen(sandbox, newState);
5486
      return newState;
5487
    };
5488
    const setContent = (sandbox, sConfig, sState, data) => sState.get().map(() => rebuild(sandbox, sConfig, sState, data));
5489
    const openWhileCloaked = (sandbox, sConfig, sState, data, transaction) => {
5490
      cloak(sandbox, sConfig);
5491
      open$1(sandbox, sConfig, sState, data);
5492
      transaction();
5493
      decloak(sandbox, sConfig);
5494
    };
5495
    const close$1 = (sandbox, sConfig, sState) => {
5496
      sState.get().each(data => {
5497
        detachChildren(sandbox);
5498
        detach(sandbox);
5499
        sConfig.onClose(sandbox, data);
5500
        sState.clear();
5501
      });
5502
    };
5503
    const isOpen$1 = (_sandbox, _sConfig, sState) => sState.isOpen();
5504
    const isPartOf = (sandbox, sConfig, sState, queryElem) => isOpen$1(sandbox, sConfig, sState) && sState.get().exists(data => sConfig.isPartOf(sandbox, data, queryElem));
5505
    const getState$2 = (_sandbox, _sConfig, sState) => sState.get();
5506
    const store = (sandbox, cssKey, attr, newValue) => {
5507
      getRaw(sandbox.element, cssKey).fold(() => {
1441 ariadna 5508
        remove$8(sandbox.element, attr);
1 efrain 5509
      }, v => {
5510
        set$9(sandbox.element, attr, v);
5511
      });
5512
      set$8(sandbox.element, cssKey, newValue);
5513
    };
5514
    const restore = (sandbox, cssKey, attr) => {
1441 ariadna 5515
      getOpt(sandbox.element, attr).fold(() => remove$7(sandbox.element, cssKey), oldValue => set$8(sandbox.element, cssKey, oldValue));
1 efrain 5516
    };
5517
    const cloak = (sandbox, sConfig, _sState) => {
5518
      const sink = sConfig.getAttachPoint(sandbox);
5519
      set$8(sandbox.element, 'position', Positioning.getMode(sink));
5520
      store(sandbox, 'visibility', sConfig.cloakVisibilityAttr, 'hidden');
5521
    };
5522
    const hasPosition = element => exists([
5523
      'top',
5524
      'left',
5525
      'right',
5526
      'bottom'
5527
    ], pos => getRaw(element, pos).isSome());
5528
    const decloak = (sandbox, sConfig, _sState) => {
5529
      if (!hasPosition(sandbox.element)) {
1441 ariadna 5530
        remove$7(sandbox.element, 'position');
1 efrain 5531
      }
5532
      restore(sandbox, 'visibility', sConfig.cloakVisibilityAttr);
5533
    };
5534
 
5535
    var SandboxApis = /*#__PURE__*/Object.freeze({
5536
        __proto__: null,
5537
        cloak: cloak,
5538
        decloak: decloak,
5539
        open: open$1,
5540
        openWhileCloaked: openWhileCloaked,
5541
        close: close$1,
5542
        isOpen: isOpen$1,
5543
        isPartOf: isPartOf,
5544
        getState: getState$2,
5545
        setContent: setContent
5546
    });
5547
 
1441 ariadna 5548
    const events$f = (sandboxConfig, sandboxState) => derive$2([run$1(sandboxClose(), (sandbox, _simulatedEvent) => {
1 efrain 5549
        close$1(sandbox, sandboxConfig, sandboxState);
5550
      })]);
5551
 
5552
    var ActiveSandbox = /*#__PURE__*/Object.freeze({
5553
        __proto__: null,
1441 ariadna 5554
        events: events$f
1 efrain 5555
    });
5556
 
5557
    var SandboxSchema = [
5558
      onHandler('onOpen'),
5559
      onHandler('onClose'),
5560
      required$1('isPartOf'),
5561
      required$1('getAttachPoint'),
5562
      defaulted('cloakVisibilityAttr', 'data-precloak-visibility')
5563
    ];
5564
 
1441 ariadna 5565
    const init$e = () => {
5566
      const contents = value$4();
1 efrain 5567
      const readState = constant$1('not-implemented');
1441 ariadna 5568
      return nu$7({
1 efrain 5569
        readState,
5570
        isOpen: contents.isSet,
5571
        clear: contents.clear,
5572
        set: contents.set,
5573
        get: contents.get
5574
      });
5575
    };
5576
 
5577
    var SandboxState = /*#__PURE__*/Object.freeze({
5578
        __proto__: null,
1441 ariadna 5579
        init: init$e
1 efrain 5580
    });
5581
 
5582
    const Sandboxing = create$4({
5583
      fields: SandboxSchema,
5584
      name: 'sandboxing',
5585
      active: ActiveSandbox,
5586
      apis: SandboxApis,
5587
      state: SandboxState
5588
    });
5589
 
5590
    const dismissPopups = constant$1('dismiss.popups');
5591
    const repositionPopups = constant$1('reposition.popups');
5592
    const mouseReleased = constant$1('mouse.released');
5593
 
5594
    const schema$x = objOfOnly([
5595
      defaulted('isExtraPart', never),
5596
      optionObjOf('fireEventInstead', [defaulted('event', dismissRequested())])
5597
    ]);
5598
    const receivingChannel$1 = rawSpec => {
5599
      const detail = asRawOrDie$1('Dismissal', schema$x, rawSpec);
5600
      return {
5601
        [dismissPopups()]: {
5602
          schema: objOfOnly([required$1('target')]),
5603
          onReceive: (sandbox, data) => {
5604
            if (Sandboxing.isOpen(sandbox)) {
5605
              const isPart = Sandboxing.isPartOf(sandbox, data.target) || detail.isExtraPart(sandbox, data.target);
5606
              if (!isPart) {
5607
                detail.fireEventInstead.fold(() => Sandboxing.close(sandbox), fe => emit(sandbox, fe.event));
5608
              }
5609
            }
5610
          }
5611
        }
5612
      };
5613
    };
5614
 
5615
    const schema$w = objOfOnly([
5616
      optionObjOf('fireEventInstead', [defaulted('event', repositionRequested())]),
5617
      requiredFunction('doReposition')
5618
    ]);
5619
    const receivingChannel = rawSpec => {
5620
      const detail = asRawOrDie$1('Reposition', schema$w, rawSpec);
5621
      return {
5622
        [repositionPopups()]: {
5623
          onReceive: sandbox => {
5624
            if (Sandboxing.isOpen(sandbox)) {
5625
              detail.fireEventInstead.fold(() => detail.doReposition(sandbox), fe => emit(sandbox, fe.event));
5626
            }
5627
          }
5628
        }
5629
      };
5630
    };
5631
 
5632
    const onLoad$5 = (component, repConfig, repState) => {
5633
      repConfig.store.manager.onLoad(component, repConfig, repState);
5634
    };
5635
    const onUnload$2 = (component, repConfig, repState) => {
5636
      repConfig.store.manager.onUnload(component, repConfig, repState);
5637
    };
5638
    const setValue$3 = (component, repConfig, repState, data) => {
5639
      repConfig.store.manager.setValue(component, repConfig, repState, data);
5640
    };
5641
    const getValue$3 = (component, repConfig, repState) => repConfig.store.manager.getValue(component, repConfig, repState);
5642
    const getState$1 = (component, repConfig, repState) => repState;
5643
 
5644
    var RepresentApis = /*#__PURE__*/Object.freeze({
5645
        __proto__: null,
5646
        onLoad: onLoad$5,
5647
        onUnload: onUnload$2,
5648
        setValue: setValue$3,
5649
        getValue: getValue$3,
5650
        getState: getState$1
5651
    });
5652
 
1441 ariadna 5653
    const events$e = (repConfig, repState) => {
1 efrain 5654
      const es = repConfig.resetOnDom ? [
5655
        runOnAttached((comp, _se) => {
5656
          onLoad$5(comp, repConfig, repState);
5657
        }),
5658
        runOnDetached((comp, _se) => {
5659
          onUnload$2(comp, repConfig, repState);
5660
        })
5661
      ] : [loadEvent(repConfig, repState, onLoad$5)];
5662
      return derive$2(es);
5663
    };
5664
 
5665
    var ActiveRepresenting = /*#__PURE__*/Object.freeze({
5666
        __proto__: null,
1441 ariadna 5667
        events: events$e
1 efrain 5668
    });
5669
 
5670
    const memory$1 = () => {
5671
      const data = Cell(null);
5672
      const readState = () => ({
5673
        mode: 'memory',
5674
        value: data.get()
5675
      });
5676
      const isNotSet = () => data.get() === null;
5677
      const clear = () => {
5678
        data.set(null);
5679
      };
1441 ariadna 5680
      return nu$7({
1 efrain 5681
        set: data.set,
5682
        get: data.get,
5683
        isNotSet,
5684
        clear,
5685
        readState
5686
      });
5687
    };
5688
    const manual = () => {
5689
      const readState = noop;
1441 ariadna 5690
      return nu$7({ readState });
1 efrain 5691
    };
5692
    const dataset = () => {
5693
      const dataByValue = Cell({});
5694
      const dataByText = Cell({});
5695
      const readState = () => ({
5696
        mode: 'dataset',
5697
        dataByValue: dataByValue.get(),
5698
        dataByText: dataByText.get()
5699
      });
5700
      const clear = () => {
5701
        dataByValue.set({});
5702
        dataByText.set({});
5703
      };
1441 ariadna 5704
      const lookup = itemString => get$h(dataByValue.get(), itemString).orThunk(() => get$h(dataByText.get(), itemString));
1 efrain 5705
      const update = items => {
5706
        const currentDataByValue = dataByValue.get();
5707
        const currentDataByText = dataByText.get();
5708
        const newDataByValue = {};
5709
        const newDataByText = {};
5710
        each$1(items, item => {
5711
          newDataByValue[item.value] = item;
1441 ariadna 5712
          get$h(item, 'meta').each(meta => {
5713
            get$h(meta, 'text').each(text => {
1 efrain 5714
              newDataByText[text] = item;
5715
            });
5716
          });
5717
        });
5718
        dataByValue.set({
5719
          ...currentDataByValue,
5720
          ...newDataByValue
5721
        });
5722
        dataByText.set({
5723
          ...currentDataByText,
5724
          ...newDataByText
5725
        });
5726
      };
1441 ariadna 5727
      return nu$7({
1 efrain 5728
        readState,
5729
        lookup,
5730
        update,
5731
        clear
5732
      });
5733
    };
1441 ariadna 5734
    const init$d = spec => spec.store.manager.state(spec);
1 efrain 5735
 
5736
    var RepresentState = /*#__PURE__*/Object.freeze({
5737
        __proto__: null,
5738
        memory: memory$1,
5739
        dataset: dataset,
5740
        manual: manual,
1441 ariadna 5741
        init: init$d
1 efrain 5742
    });
5743
 
5744
    const setValue$2 = (component, repConfig, repState, data) => {
5745
      const store = repConfig.store;
5746
      repState.update([data]);
5747
      store.setValue(component, data);
5748
      repConfig.onSetValue(component, data);
5749
    };
5750
    const getValue$2 = (component, repConfig, repState) => {
5751
      const store = repConfig.store;
5752
      const key = store.getDataKey(component);
5753
      return repState.lookup(key).getOrThunk(() => store.getFallbackEntry(key));
5754
    };
5755
    const onLoad$4 = (component, repConfig, repState) => {
5756
      const store = repConfig.store;
5757
      store.initialValue.each(data => {
5758
        setValue$2(component, repConfig, repState, data);
5759
      });
5760
    };
5761
    const onUnload$1 = (component, repConfig, repState) => {
5762
      repState.clear();
5763
    };
5764
    var DatasetStore = [
5765
      option$3('initialValue'),
5766
      required$1('getFallbackEntry'),
5767
      required$1('getDataKey'),
5768
      required$1('setValue'),
5769
      output$1('manager', {
5770
        setValue: setValue$2,
5771
        getValue: getValue$2,
5772
        onLoad: onLoad$4,
5773
        onUnload: onUnload$1,
5774
        state: dataset
5775
      })
5776
    ];
5777
 
5778
    const getValue$1 = (component, repConfig, _repState) => repConfig.store.getValue(component);
5779
    const setValue$1 = (component, repConfig, _repState, data) => {
5780
      repConfig.store.setValue(component, data);
5781
      repConfig.onSetValue(component, data);
5782
    };
5783
    const onLoad$3 = (component, repConfig, _repState) => {
5784
      repConfig.store.initialValue.each(data => {
5785
        repConfig.store.setValue(component, data);
5786
      });
5787
    };
5788
    var ManualStore = [
5789
      required$1('getValue'),
5790
      defaulted('setValue', noop),
5791
      option$3('initialValue'),
5792
      output$1('manager', {
5793
        setValue: setValue$1,
5794
        getValue: getValue$1,
5795
        onLoad: onLoad$3,
5796
        onUnload: noop,
5797
        state: NoState.init
5798
      })
5799
    ];
5800
 
5801
    const setValue = (component, repConfig, repState, data) => {
5802
      repState.set(data);
5803
      repConfig.onSetValue(component, data);
5804
    };
5805
    const getValue = (component, repConfig, repState) => repState.get();
5806
    const onLoad$2 = (component, repConfig, repState) => {
5807
      repConfig.store.initialValue.each(initVal => {
5808
        if (repState.isNotSet()) {
5809
          repState.set(initVal);
5810
        }
5811
      });
5812
    };
5813
    const onUnload = (component, repConfig, repState) => {
5814
      repState.clear();
5815
    };
5816
    var MemoryStore = [
5817
      option$3('initialValue'),
5818
      output$1('manager', {
5819
        setValue,
5820
        getValue,
5821
        onLoad: onLoad$2,
5822
        onUnload,
5823
        state: memory$1
5824
      })
5825
    ];
5826
 
5827
    var RepresentSchema = [
5828
      defaultedOf('store', { mode: 'memory' }, choose$1('mode', {
5829
        memory: MemoryStore,
5830
        manual: ManualStore,
5831
        dataset: DatasetStore
5832
      })),
5833
      onHandler('onSetValue'),
5834
      defaulted('resetOnDom', false)
5835
    ];
5836
 
5837
    const Representing = create$4({
5838
      fields: RepresentSchema,
5839
      name: 'representing',
5840
      active: ActiveRepresenting,
5841
      apis: RepresentApis,
5842
      extra: {
5843
        setValueFrom: (component, source) => {
5844
          const value = Representing.getValue(source);
5845
          Representing.setValue(component, value);
5846
        }
5847
      },
5848
      state: RepresentState
5849
    });
5850
 
5851
    const field = (name, forbidden) => defaultedObjOf(name, {}, map$2(forbidden, f => forbid(f.name(), 'Cannot configure ' + f.name() + ' for ' + name)).concat([customField('dump', identity)]));
1441 ariadna 5852
    const get$4 = data => data.dump;
1 efrain 5853
    const augment = (data, original) => ({
5854
      ...derive$1(original),
5855
      ...data.dump
5856
    });
5857
    const SketchBehaviours = {
5858
      field,
5859
      augment,
1441 ariadna 5860
      get: get$4
1 efrain 5861
    };
5862
 
5863
    const _placeholder = 'placeholder';
5864
    const adt$3 = Adt.generate([
5865
      {
5866
        single: [
5867
          'required',
5868
          'valueThunk'
5869
        ]
5870
      },
5871
      {
5872
        multiple: [
5873
          'required',
5874
          'valueThunks'
5875
        ]
5876
      }
5877
    ]);
5878
    const isSubstituted = spec => has$2(spec, 'uiType');
5879
    const subPlaceholder = (owner, detail, compSpec, placeholders) => {
5880
      if (owner.exists(o => o !== compSpec.owner)) {
5881
        return adt$3.single(true, constant$1(compSpec));
5882
      }
1441 ariadna 5883
      return get$h(placeholders, compSpec.name).fold(() => {
1 efrain 5884
        throw new Error('Unknown placeholder component: ' + compSpec.name + '\nKnown: [' + keys(placeholders) + ']\nNamespace: ' + owner.getOr('none') + '\nSpec: ' + JSON.stringify(compSpec, null, 2));
5885
      }, newSpec => newSpec.replace());
5886
    };
5887
    const scan = (owner, detail, compSpec, placeholders) => {
5888
      if (isSubstituted(compSpec) && compSpec.uiType === _placeholder) {
5889
        return subPlaceholder(owner, detail, compSpec, placeholders);
5890
      } else {
5891
        return adt$3.single(false, constant$1(compSpec));
5892
      }
5893
    };
5894
    const substitute = (owner, detail, compSpec, placeholders) => {
5895
      const base = scan(owner, detail, compSpec, placeholders);
5896
      return base.fold((req, valueThunk) => {
5897
        const value = isSubstituted(compSpec) ? valueThunk(detail, compSpec.config, compSpec.validated) : valueThunk(detail);
1441 ariadna 5898
        const childSpecs = get$h(value, 'components').getOr([]);
1 efrain 5899
        const substituted = bind$3(childSpecs, c => substitute(owner, detail, c, placeholders));
5900
        return [{
5901
            ...value,
5902
            components: substituted
5903
          }];
5904
      }, (req, valuesThunk) => {
5905
        if (isSubstituted(compSpec)) {
5906
          const values = valuesThunk(detail, compSpec.config, compSpec.validated);
5907
          const preprocessor = compSpec.validated.preprocess.getOr(identity);
5908
          return preprocessor(values);
5909
        } else {
5910
          return valuesThunk(detail);
5911
        }
5912
      });
5913
    };
5914
    const substituteAll = (owner, detail, components, placeholders) => bind$3(components, c => substitute(owner, detail, c, placeholders));
5915
    const oneReplace = (label, replacements) => {
5916
      let called = false;
5917
      const used = () => called;
5918
      const replace = () => {
5919
        if (called) {
5920
          throw new Error('Trying to use the same placeholder more than once: ' + label);
5921
        }
5922
        called = true;
5923
        return replacements;
5924
      };
5925
      const required = () => replacements.fold((req, _) => req, (req, _) => req);
5926
      return {
5927
        name: constant$1(label),
5928
        required,
5929
        used,
5930
        replace
5931
      };
5932
    };
5933
    const substitutePlaces = (owner, detail, components, placeholders) => {
5934
      const ps = map$1(placeholders, (ph, name) => oneReplace(name, ph));
5935
      const outcome = substituteAll(owner, detail, components, ps);
5936
      each(ps, p => {
5937
        if (p.used() === false && p.required()) {
5938
          throw new Error('Placeholder: ' + p.name() + ' was not found in components list\nNamespace: ' + owner.getOr('none') + '\nComponents: ' + JSON.stringify(detail.components, null, 2));
5939
        }
5940
      });
5941
      return outcome;
5942
    };
5943
    const single$2 = adt$3.single;
5944
    const multiple = adt$3.multiple;
5945
    const placeholder = constant$1(_placeholder);
5946
 
5947
    const adt$2 = Adt.generate([
5948
      { required: ['data'] },
5949
      { external: ['data'] },
5950
      { optional: ['data'] },
5951
      { group: ['data'] }
5952
    ]);
5953
    const fFactory = defaulted('factory', { sketch: identity });
5954
    const fSchema = defaulted('schema', []);
5955
    const fName = required$1('name');
5956
    const fPname = field$1('pname', 'pname', defaultedThunk(typeSpec => '<alloy.' + generate$6(typeSpec.name) + '>'), anyValue());
5957
    const fGroupSchema = customField('schema', () => [option$3('preprocess')]);
5958
    const fDefaults = defaulted('defaults', constant$1({}));
5959
    const fOverrides = defaulted('overrides', constant$1({}));
5960
    const requiredSpec = objOf([
5961
      fFactory,
5962
      fSchema,
5963
      fName,
5964
      fPname,
5965
      fDefaults,
5966
      fOverrides
5967
    ]);
5968
    const externalSpec = objOf([
5969
      fFactory,
5970
      fSchema,
5971
      fName,
5972
      fDefaults,
5973
      fOverrides
5974
    ]);
5975
    const optionalSpec = objOf([
5976
      fFactory,
5977
      fSchema,
5978
      fName,
5979
      fPname,
5980
      fDefaults,
5981
      fOverrides
5982
    ]);
5983
    const groupSpec = objOf([
5984
      fFactory,
5985
      fGroupSchema,
5986
      fName,
5987
      required$1('unit'),
5988
      fPname,
5989
      fDefaults,
5990
      fOverrides
5991
    ]);
5992
    const asNamedPart = part => {
5993
      return part.fold(Optional.some, Optional.none, Optional.some, Optional.some);
5994
    };
5995
    const name$2 = part => {
5996
      const get = data => data.name;
5997
      return part.fold(get, get, get, get);
5998
    };
5999
    const asCommon = part => {
6000
      return part.fold(identity, identity, identity, identity);
6001
    };
6002
    const convert = (adtConstructor, partSchema) => spec => {
6003
      const data = asRawOrDie$1('Converting part type', partSchema, spec);
6004
      return adtConstructor(data);
6005
    };
6006
    const required = convert(adt$2.required, requiredSpec);
6007
    const external = convert(adt$2.external, externalSpec);
6008
    const optional = convert(adt$2.optional, optionalSpec);
6009
    const group = convert(adt$2.group, groupSpec);
6010
    const original = constant$1('entirety');
6011
 
6012
    var PartType = /*#__PURE__*/Object.freeze({
6013
        __proto__: null,
6014
        required: required,
6015
        external: external,
6016
        optional: optional,
6017
        group: group,
6018
        asNamedPart: asNamedPart,
6019
        name: name$2,
6020
        asCommon: asCommon,
6021
        original: original
6022
    });
6023
 
6024
    const combine = (detail, data, partSpec, partValidated) => deepMerge(data.defaults(detail, partSpec, partValidated), partSpec, { uid: detail.partUids[data.name] }, data.overrides(detail, partSpec, partValidated));
6025
    const subs = (owner, detail, parts) => {
6026
      const internals = {};
6027
      const externals = {};
6028
      each$1(parts, part => {
6029
        part.fold(data => {
6030
          internals[data.pname] = single$2(true, (detail, partSpec, partValidated) => data.factory.sketch(combine(detail, data, partSpec, partValidated)));
6031
        }, data => {
6032
          const partSpec = detail.parts[data.name];
6033
          externals[data.name] = constant$1(data.factory.sketch(combine(detail, data, partSpec[original()]), partSpec));
6034
        }, data => {
6035
          internals[data.pname] = single$2(false, (detail, partSpec, partValidated) => data.factory.sketch(combine(detail, data, partSpec, partValidated)));
6036
        }, data => {
6037
          internals[data.pname] = multiple(true, (detail, _partSpec, _partValidated) => {
6038
            const units = detail[data.name];
6039
            return map$2(units, u => data.factory.sketch(deepMerge(data.defaults(detail, u, _partValidated), u, data.overrides(detail, u))));
6040
          });
6041
        });
6042
      });
6043
      return {
6044
        internals: constant$1(internals),
6045
        externals: constant$1(externals)
6046
      };
6047
    };
6048
 
6049
    const generate$3 = (owner, parts) => {
6050
      const r = {};
6051
      each$1(parts, part => {
6052
        asNamedPart(part).each(np => {
6053
          const g = doGenerateOne(owner, np.pname);
6054
          r[np.name] = config => {
6055
            const validated = asRawOrDie$1('Part: ' + np.name + ' in ' + owner, objOf(np.schema), config);
6056
            return {
6057
              ...g,
6058
              config,
6059
              validated
6060
            };
6061
          };
6062
        });
6063
      });
6064
      return r;
6065
    };
6066
    const doGenerateOne = (owner, pname) => ({
6067
      uiType: placeholder(),
6068
      owner,
6069
      name: pname
6070
    });
6071
    const generateOne$1 = (owner, pname, config) => ({
6072
      uiType: placeholder(),
6073
      owner,
6074
      name: pname,
6075
      config,
6076
      validated: {}
6077
    });
6078
    const schemas = parts => bind$3(parts, part => part.fold(Optional.none, Optional.some, Optional.none, Optional.none).map(data => requiredObjOf(data.name, data.schema.concat([snapshot(original())]))).toArray());
6079
    const names = parts => map$2(parts, name$2);
6080
    const substitutes = (owner, detail, parts) => subs(owner, detail, parts);
6081
    const components$1 = (owner, detail, internals) => substitutePlaces(Optional.some(owner), detail, detail.components, internals);
6082
    const getPart = (component, detail, partKey) => {
6083
      const uid = detail.partUids[partKey];
6084
      return component.getSystem().getByUid(uid).toOptional();
6085
    };
6086
    const getPartOrDie = (component, detail, partKey) => getPart(component, detail, partKey).getOrDie('Could not find part: ' + partKey);
6087
    const getParts = (component, detail, partKeys) => {
6088
      const r = {};
6089
      const uids = detail.partUids;
6090
      const system = component.getSystem();
6091
      each$1(partKeys, pk => {
6092
        r[pk] = constant$1(system.getByUid(uids[pk]));
6093
      });
6094
      return r;
6095
    };
6096
    const getAllParts = (component, detail) => {
6097
      const system = component.getSystem();
6098
      return map$1(detail.partUids, (pUid, _k) => constant$1(system.getByUid(pUid)));
6099
    };
6100
    const getAllPartNames = detail => keys(detail.partUids);
6101
    const getPartsOrDie = (component, detail, partKeys) => {
6102
      const r = {};
6103
      const uids = detail.partUids;
6104
      const system = component.getSystem();
6105
      each$1(partKeys, pk => {
6106
        r[pk] = constant$1(system.getByUid(uids[pk]).getOrDie());
6107
      });
6108
      return r;
6109
    };
6110
    const defaultUids = (baseUid, partTypes) => {
6111
      const partNames = names(partTypes);
6112
      return wrapAll(map$2(partNames, pn => ({
6113
        key: pn,
6114
        value: baseUid + '-' + pn
6115
      })));
6116
    };
6117
    const defaultUidsSchema = partTypes => field$1('partUids', 'partUids', mergeWithThunk(spec => defaultUids(spec.uid, partTypes)), anyValue());
6118
 
6119
    var AlloyParts = /*#__PURE__*/Object.freeze({
6120
        __proto__: null,
6121
        generate: generate$3,
6122
        generateOne: generateOne$1,
6123
        schemas: schemas,
6124
        names: names,
6125
        substitutes: substitutes,
6126
        components: components$1,
6127
        defaultUids: defaultUids,
6128
        defaultUidsSchema: defaultUidsSchema,
6129
        getAllParts: getAllParts,
6130
        getAllPartNames: getAllPartNames,
6131
        getPart: getPart,
6132
        getPartOrDie: getPartOrDie,
6133
        getParts: getParts,
6134
        getPartsOrDie: getPartsOrDie
6135
    });
6136
 
6137
    const base = (partSchemas, partUidsSchemas) => {
6138
      const ps = partSchemas.length > 0 ? [requiredObjOf('parts', partSchemas)] : [];
6139
      return ps.concat([
6140
        required$1('uid'),
6141
        defaulted('dom', {}),
6142
        defaulted('components', []),
6143
        snapshot('originalSpec'),
6144
        defaulted('debug.sketcher', {})
6145
      ]).concat(partUidsSchemas);
6146
    };
6147
    const asRawOrDie = (label, schema, spec, partSchemas, partUidsSchemas) => {
6148
      const baseS = base(partSchemas, partUidsSchemas);
6149
      return asRawOrDie$1(label + ' [SpecSchema]', objOfOnly(baseS.concat(schema)), spec);
6150
    };
6151
 
6152
    const single$1 = (owner, schema, factory, spec) => {
6153
      const specWithUid = supplyUid(spec);
6154
      const detail = asRawOrDie(owner, schema, specWithUid, [], []);
6155
      return factory(detail, specWithUid);
6156
    };
6157
    const composite$1 = (owner, schema, partTypes, factory, spec) => {
6158
      const specWithUid = supplyUid(spec);
6159
      const partSchemas = schemas(partTypes);
6160
      const partUidsSchema = defaultUidsSchema(partTypes);
6161
      const detail = asRawOrDie(owner, schema, specWithUid, partSchemas, [partUidsSchema]);
6162
      const subs = substitutes(owner, detail, partTypes);
6163
      const components = components$1(owner, detail, subs.internals());
6164
      return factory(detail, components, specWithUid, subs.externals());
6165
    };
6166
    const hasUid = spec => has$2(spec, 'uid');
6167
    const supplyUid = spec => {
6168
      return hasUid(spec) ? spec : {
6169
        ...spec,
6170
        uid: generate$5('uid')
6171
      };
6172
    };
6173
 
6174
    const isSketchSpec = spec => {
6175
      return spec.uid !== undefined;
6176
    };
6177
    const singleSchema = objOfOnly([
6178
      required$1('name'),
6179
      required$1('factory'),
6180
      required$1('configFields'),
6181
      defaulted('apis', {}),
6182
      defaulted('extraApis', {})
6183
    ]);
6184
    const compositeSchema = objOfOnly([
6185
      required$1('name'),
6186
      required$1('factory'),
6187
      required$1('configFields'),
6188
      required$1('partFields'),
6189
      defaulted('apis', {}),
6190
      defaulted('extraApis', {})
6191
    ]);
6192
    const single = rawConfig => {
6193
      const config = asRawOrDie$1('Sketcher for ' + rawConfig.name, singleSchema, rawConfig);
6194
      const sketch = spec => single$1(config.name, config.configFields, config.factory, spec);
6195
      const apis = map$1(config.apis, makeApi);
6196
      const extraApis = map$1(config.extraApis, (f, k) => markAsExtraApi(f, k));
6197
      return {
6198
        name: config.name,
6199
        configFields: config.configFields,
6200
        sketch,
6201
        ...apis,
6202
        ...extraApis
6203
      };
6204
    };
6205
    const composite = rawConfig => {
6206
      const config = asRawOrDie$1('Sketcher for ' + rawConfig.name, compositeSchema, rawConfig);
6207
      const sketch = spec => composite$1(config.name, config.configFields, config.partFields, config.factory, spec);
6208
      const parts = generate$3(config.name, config.partFields);
6209
      const apis = map$1(config.apis, makeApi);
6210
      const extraApis = map$1(config.extraApis, (f, k) => markAsExtraApi(f, k));
6211
      return {
6212
        name: config.name,
6213
        partFields: config.partFields,
6214
        configFields: config.configFields,
6215
        sketch,
6216
        parts,
6217
        ...apis,
6218
        ...extraApis
6219
      };
6220
    };
6221
 
1441 ariadna 6222
    const inside = target => isTag('input')(target) && get$g(target, 'type') !== 'radio' || isTag('textarea')(target);
1 efrain 6223
 
6224
    const getCurrent = (component, composeConfig, _composeState) => composeConfig.find(component);
6225
 
6226
    var ComposeApis = /*#__PURE__*/Object.freeze({
6227
        __proto__: null,
6228
        getCurrent: getCurrent
6229
    });
6230
 
6231
    const ComposeSchema = [required$1('find')];
6232
 
6233
    const Composing = create$4({
6234
      fields: ComposeSchema,
6235
      name: 'composing',
6236
      apis: ComposeApis
6237
    });
6238
 
6239
    const nativeDisabled = [
6240
      'input',
6241
      'button',
6242
      'textarea',
6243
      'select'
6244
    ];
6245
    const onLoad$1 = (component, disableConfig, disableState) => {
6246
      const f = disableConfig.disabled() ? disable : enable;
6247
      f(component, disableConfig);
6248
    };
6249
    const hasNative = (component, config) => config.useNative === true && contains$2(nativeDisabled, name$3(component.element));
6250
    const nativeIsDisabled = component => has$1(component.element, 'disabled');
6251
    const nativeDisable = component => {
6252
      set$9(component.element, 'disabled', 'disabled');
6253
    };
6254
    const nativeEnable = component => {
1441 ariadna 6255
      remove$8(component.element, 'disabled');
1 efrain 6256
    };
1441 ariadna 6257
    const ariaIsDisabled = component => get$g(component.element, 'aria-disabled') === 'true';
1 efrain 6258
    const ariaDisable = component => {
6259
      set$9(component.element, 'aria-disabled', 'true');
6260
    };
6261
    const ariaEnable = component => {
6262
      set$9(component.element, 'aria-disabled', 'false');
6263
    };
6264
    const disable = (component, disableConfig, _disableState) => {
6265
      disableConfig.disableClass.each(disableClass => {
6266
        add$2(component.element, disableClass);
6267
      });
6268
      const f = hasNative(component, disableConfig) ? nativeDisable : ariaDisable;
6269
      f(component);
6270
      disableConfig.onDisabled(component);
6271
    };
6272
    const enable = (component, disableConfig, _disableState) => {
6273
      disableConfig.disableClass.each(disableClass => {
1441 ariadna 6274
        remove$3(component.element, disableClass);
1 efrain 6275
      });
6276
      const f = hasNative(component, disableConfig) ? nativeEnable : ariaEnable;
6277
      f(component);
6278
      disableConfig.onEnabled(component);
6279
    };
1441 ariadna 6280
    const isDisabled$1 = (component, disableConfig) => hasNative(component, disableConfig) ? nativeIsDisabled(component) : ariaIsDisabled(component);
1 efrain 6281
    const set$4 = (component, disableConfig, disableState, disabled) => {
6282
      const f = disabled ? disable : enable;
6283
      f(component, disableConfig);
6284
    };
6285
 
6286
    var DisableApis = /*#__PURE__*/Object.freeze({
6287
        __proto__: null,
6288
        enable: enable,
6289
        disable: disable,
1441 ariadna 6290
        isDisabled: isDisabled$1,
1 efrain 6291
        onLoad: onLoad$1,
6292
        set: set$4
6293
    });
6294
 
1441 ariadna 6295
    const exhibit$5 = (base, disableConfig) => nu$8({ classes: disableConfig.disabled() ? disableConfig.disableClass.toArray() : [] });
6296
    const events$d = (disableConfig, disableState) => derive$2([
6297
      abort(execute$5(), (component, _simulatedEvent) => isDisabled$1(component, disableConfig)),
1 efrain 6298
      loadEvent(disableConfig, disableState, onLoad$1)
6299
    ]);
6300
 
6301
    var ActiveDisable = /*#__PURE__*/Object.freeze({
6302
        __proto__: null,
6303
        exhibit: exhibit$5,
1441 ariadna 6304
        events: events$d
1 efrain 6305
    });
6306
 
6307
    var DisableSchema = [
6308
      defaultedFunction('disabled', never),
6309
      defaulted('useNative', true),
6310
      option$3('disableClass'),
6311
      onHandler('onDisabled'),
6312
      onHandler('onEnabled')
6313
    ];
6314
 
6315
    const Disabling = create$4({
6316
      fields: DisableSchema,
6317
      name: 'disabling',
6318
      active: ActiveDisable,
6319
      apis: DisableApis
6320
    });
6321
 
6322
    const dehighlightAllExcept = (component, hConfig, hState, skip) => {
6323
      const highlighted = descendants(component.element, '.' + hConfig.highlightClass);
6324
      each$1(highlighted, h => {
6325
        const shouldSkip = exists(skip, skipComp => eq(skipComp.element, h));
6326
        if (!shouldSkip) {
1441 ariadna 6327
          remove$3(h, hConfig.highlightClass);
1 efrain 6328
          component.getSystem().getByDom(h).each(target => {
6329
            hConfig.onDehighlight(component, target);
6330
            emit(target, dehighlight$1());
6331
          });
6332
        }
6333
      });
6334
    };
6335
    const dehighlightAll = (component, hConfig, hState) => dehighlightAllExcept(component, hConfig, hState, []);
6336
    const dehighlight = (component, hConfig, hState, target) => {
6337
      if (isHighlighted(component, hConfig, hState, target)) {
1441 ariadna 6338
        remove$3(target.element, hConfig.highlightClass);
1 efrain 6339
        hConfig.onDehighlight(component, target);
6340
        emit(target, dehighlight$1());
6341
      }
6342
    };
6343
    const highlight = (component, hConfig, hState, target) => {
6344
      dehighlightAllExcept(component, hConfig, hState, [target]);
6345
      if (!isHighlighted(component, hConfig, hState, target)) {
6346
        add$2(target.element, hConfig.highlightClass);
6347
        hConfig.onHighlight(component, target);
6348
        emit(target, highlight$1());
6349
      }
6350
    };
6351
    const highlightFirst = (component, hConfig, hState) => {
6352
      getFirst(component, hConfig).each(firstComp => {
6353
        highlight(component, hConfig, hState, firstComp);
6354
      });
6355
    };
6356
    const highlightLast = (component, hConfig, hState) => {
6357
      getLast(component, hConfig).each(lastComp => {
6358
        highlight(component, hConfig, hState, lastComp);
6359
      });
6360
    };
6361
    const highlightAt = (component, hConfig, hState, index) => {
6362
      getByIndex(component, hConfig, hState, index).fold(err => {
6363
        throw err;
6364
      }, firstComp => {
6365
        highlight(component, hConfig, hState, firstComp);
6366
      });
6367
    };
6368
    const highlightBy = (component, hConfig, hState, predicate) => {
6369
      const candidates = getCandidates(component, hConfig);
6370
      const targetComp = find$5(candidates, predicate);
6371
      targetComp.each(c => {
6372
        highlight(component, hConfig, hState, c);
6373
      });
6374
    };
6375
    const isHighlighted = (component, hConfig, hState, queryTarget) => has(queryTarget.element, hConfig.highlightClass);
6376
    const getHighlighted = (component, hConfig, _hState) => descendant(component.element, '.' + hConfig.highlightClass).bind(e => component.getSystem().getByDom(e).toOptional());
6377
    const getByIndex = (component, hConfig, hState, index) => {
6378
      const items = descendants(component.element, '.' + hConfig.itemClass);
6379
      return Optional.from(items[index]).fold(() => Result.error(new Error('No element found with index ' + index)), component.getSystem().getByDom);
6380
    };
6381
    const getFirst = (component, hConfig, _hState) => descendant(component.element, '.' + hConfig.itemClass).bind(e => component.getSystem().getByDom(e).toOptional());
6382
    const getLast = (component, hConfig, _hState) => {
6383
      const items = descendants(component.element, '.' + hConfig.itemClass);
6384
      const last = items.length > 0 ? Optional.some(items[items.length - 1]) : Optional.none();
6385
      return last.bind(c => component.getSystem().getByDom(c).toOptional());
6386
    };
6387
    const getDelta$2 = (component, hConfig, hState, delta) => {
6388
      const items = descendants(component.element, '.' + hConfig.itemClass);
6389
      const current = findIndex$1(items, item => has(item, hConfig.highlightClass));
6390
      return current.bind(selected => {
6391
        const dest = cycleBy(selected, delta, 0, items.length - 1);
6392
        return component.getSystem().getByDom(items[dest]).toOptional();
6393
      });
6394
    };
6395
    const getPrevious = (component, hConfig, hState) => getDelta$2(component, hConfig, hState, -1);
6396
    const getNext = (component, hConfig, hState) => getDelta$2(component, hConfig, hState, +1);
6397
    const getCandidates = (component, hConfig, _hState) => {
6398
      const items = descendants(component.element, '.' + hConfig.itemClass);
6399
      return cat(map$2(items, i => component.getSystem().getByDom(i).toOptional()));
6400
    };
6401
 
6402
    var HighlightApis = /*#__PURE__*/Object.freeze({
6403
        __proto__: null,
6404
        dehighlightAll: dehighlightAll,
6405
        dehighlight: dehighlight,
6406
        highlight: highlight,
6407
        highlightFirst: highlightFirst,
6408
        highlightLast: highlightLast,
6409
        highlightAt: highlightAt,
6410
        highlightBy: highlightBy,
6411
        isHighlighted: isHighlighted,
6412
        getHighlighted: getHighlighted,
6413
        getFirst: getFirst,
6414
        getLast: getLast,
6415
        getPrevious: getPrevious,
6416
        getNext: getNext,
6417
        getCandidates: getCandidates
6418
    });
6419
 
6420
    var HighlightSchema = [
6421
      required$1('highlightClass'),
6422
      required$1('itemClass'),
6423
      onHandler('onHighlight'),
6424
      onHandler('onDehighlight')
6425
    ];
6426
 
6427
    const Highlighting = create$4({
6428
      fields: HighlightSchema,
6429
      name: 'highlighting',
6430
      apis: HighlightApis
6431
    });
6432
 
6433
    const BACKSPACE = [8];
6434
    const TAB = [9];
6435
    const ENTER = [13];
6436
    const ESCAPE = [27];
6437
    const SPACE = [32];
6438
    const LEFT = [37];
6439
    const UP = [38];
6440
    const RIGHT = [39];
6441
    const DOWN = [40];
6442
 
6443
    const cyclePrev = (values, index, predicate) => {
6444
      const before = reverse(values.slice(0, index));
6445
      const after = reverse(values.slice(index + 1));
6446
      return find$5(before.concat(after), predicate);
6447
    };
6448
    const tryPrev = (values, index, predicate) => {
6449
      const before = reverse(values.slice(0, index));
6450
      return find$5(before, predicate);
6451
    };
6452
    const cycleNext = (values, index, predicate) => {
6453
      const before = values.slice(0, index);
6454
      const after = values.slice(index + 1);
6455
      return find$5(after.concat(before), predicate);
6456
    };
6457
    const tryNext = (values, index, predicate) => {
6458
      const after = values.slice(index + 1);
6459
      return find$5(after, predicate);
6460
    };
6461
 
6462
    const inSet = keys => event => {
6463
      const raw = event.raw;
6464
      return contains$2(keys, raw.which);
6465
    };
6466
    const and = preds => event => forall(preds, pred => pred(event));
6467
    const isShift$1 = event => {
6468
      const raw = event.raw;
6469
      return raw.shiftKey === true;
6470
    };
6471
    const isControl = event => {
6472
      const raw = event.raw;
6473
      return raw.ctrlKey === true;
6474
    };
6475
    const isNotShift = not(isShift$1);
6476
 
6477
    const rule = (matches, action) => ({
6478
      matches,
6479
      classification: action
6480
    });
6481
    const choose = (transitions, event) => {
6482
      const transition = find$5(transitions, t => t.matches(event));
6483
      return transition.map(t => t.classification);
6484
    };
6485
 
6486
    const reportFocusShifting = (component, prevFocus, newFocus) => {
6487
      const noChange = prevFocus.exists(p => newFocus.exists(n => eq(n, p)));
6488
      if (!noChange) {
6489
        emitWith(component, focusShifted(), {
6490
          prevFocus,
6491
          newFocus
6492
        });
6493
      }
6494
    };
6495
    const dom$2 = () => {
6496
      const get = component => search(component.element);
6497
      const set = (component, focusee) => {
6498
        const prevFocus = get(component);
6499
        component.getSystem().triggerFocus(focusee, component.element);
6500
        const newFocus = get(component);
6501
        reportFocusShifting(component, prevFocus, newFocus);
6502
      };
6503
      return {
6504
        get,
6505
        set
6506
      };
6507
    };
6508
    const highlights = () => {
6509
      const get = component => Highlighting.getHighlighted(component).map(item => item.element);
6510
      const set = (component, element) => {
6511
        const prevFocus = get(component);
6512
        component.getSystem().getByDom(element).fold(noop, item => {
6513
          Highlighting.highlight(component, item);
6514
        });
6515
        const newFocus = get(component);
6516
        reportFocusShifting(component, prevFocus, newFocus);
6517
      };
6518
      return {
6519
        get,
6520
        set
6521
      };
6522
    };
6523
 
6524
    var FocusInsideModes;
6525
    (function (FocusInsideModes) {
6526
      FocusInsideModes['OnFocusMode'] = 'onFocus';
6527
      FocusInsideModes['OnEnterOrSpaceMode'] = 'onEnterOrSpace';
6528
      FocusInsideModes['OnApiMode'] = 'onApi';
6529
    }(FocusInsideModes || (FocusInsideModes = {})));
6530
 
6531
    const typical = (infoSchema, stateInit, getKeydownRules, getKeyupRules, optFocusIn) => {
6532
      const schema = () => infoSchema.concat([
6533
        defaulted('focusManager', dom$2()),
6534
        defaultedOf('focusInside', 'onFocus', valueOf(val => contains$2([
6535
          'onFocus',
6536
          'onEnterOrSpace',
6537
          'onApi'
6538
        ], val) ? Result.value(val) : Result.error('Invalid value for focusInside'))),
6539
        output$1('handler', me),
6540
        output$1('state', stateInit),
6541
        output$1('sendFocusIn', optFocusIn)
6542
      ]);
6543
      const processKey = (component, simulatedEvent, getRules, keyingConfig, keyingState) => {
6544
        const rules = getRules(component, simulatedEvent, keyingConfig, keyingState);
6545
        return choose(rules, simulatedEvent.event).bind(rule => rule(component, simulatedEvent, keyingConfig, keyingState));
6546
      };
6547
      const toEvents = (keyingConfig, keyingState) => {
6548
        const onFocusHandler = keyingConfig.focusInside !== FocusInsideModes.OnFocusMode ? Optional.none() : optFocusIn(keyingConfig).map(focusIn => run$1(focus$4(), (component, simulatedEvent) => {
6549
          focusIn(component, keyingConfig, keyingState);
6550
          simulatedEvent.stop();
6551
        }));
6552
        const tryGoInsideComponent = (component, simulatedEvent) => {
6553
          const isEnterOrSpace = inSet(SPACE.concat(ENTER))(simulatedEvent.event);
6554
          if (keyingConfig.focusInside === FocusInsideModes.OnEnterOrSpaceMode && isEnterOrSpace && isSource(component, simulatedEvent)) {
6555
            optFocusIn(keyingConfig).each(focusIn => {
6556
              focusIn(component, keyingConfig, keyingState);
6557
              simulatedEvent.stop();
6558
            });
6559
          }
6560
        };
6561
        const keyboardEvents = [
6562
          run$1(keydown(), (component, simulatedEvent) => {
6563
            processKey(component, simulatedEvent, getKeydownRules, keyingConfig, keyingState).fold(() => {
6564
              tryGoInsideComponent(component, simulatedEvent);
6565
            }, _ => {
6566
              simulatedEvent.stop();
6567
            });
6568
          }),
6569
          run$1(keyup(), (component, simulatedEvent) => {
6570
            processKey(component, simulatedEvent, getKeyupRules, keyingConfig, keyingState).each(_ => {
6571
              simulatedEvent.stop();
6572
            });
6573
          })
6574
        ];
6575
        return derive$2(onFocusHandler.toArray().concat(keyboardEvents));
6576
      };
6577
      const me = {
6578
        schema,
6579
        processKey,
6580
        toEvents
6581
      };
6582
      return me;
6583
    };
6584
 
6585
    const create$2 = cyclicField => {
6586
      const schema = [
6587
        option$3('onEscape'),
6588
        option$3('onEnter'),
6589
        defaulted('selector', '[data-alloy-tabstop="true"]:not(:disabled)'),
6590
        defaulted('firstTabstop', 0),
6591
        defaulted('useTabstopAt', always),
6592
        option$3('visibilitySelector')
6593
      ].concat([cyclicField]);
6594
      const isVisible = (tabbingConfig, element) => {
6595
        const target = tabbingConfig.visibilitySelector.bind(sel => closest$1(element, sel)).getOr(element);
1441 ariadna 6596
        return get$e(target) > 0;
1 efrain 6597
      };
6598
      const findInitial = (component, tabbingConfig) => {
6599
        const tabstops = descendants(component.element, tabbingConfig.selector);
6600
        const visibles = filter$2(tabstops, elem => isVisible(tabbingConfig, elem));
6601
        return Optional.from(visibles[tabbingConfig.firstTabstop]);
6602
      };
6603
      const findCurrent = (component, tabbingConfig) => tabbingConfig.focusManager.get(component).bind(elem => closest$1(elem, tabbingConfig.selector));
6604
      const isTabstop = (tabbingConfig, element) => isVisible(tabbingConfig, element) && tabbingConfig.useTabstopAt(element);
6605
      const focusIn = (component, tabbingConfig, _tabbingState) => {
6606
        findInitial(component, tabbingConfig).each(target => {
6607
          tabbingConfig.focusManager.set(component, target);
6608
        });
6609
      };
6610
      const goFromTabstop = (component, tabstops, stopIndex, tabbingConfig, cycle) => cycle(tabstops, stopIndex, elem => isTabstop(tabbingConfig, elem)).fold(() => tabbingConfig.cyclic ? Optional.some(true) : Optional.none(), target => {
6611
        tabbingConfig.focusManager.set(component, target);
6612
        return Optional.some(true);
6613
      });
6614
      const go = (component, _simulatedEvent, tabbingConfig, cycle) => {
1441 ariadna 6615
        const tabstops = filter$2(descendants(component.element, tabbingConfig.selector), element => isVisible(tabbingConfig, element));
1 efrain 6616
        return findCurrent(component, tabbingConfig).bind(tabstop => {
6617
          const optStopIndex = findIndex$1(tabstops, curry(eq, tabstop));
6618
          return optStopIndex.bind(stopIndex => goFromTabstop(component, tabstops, stopIndex, tabbingConfig, cycle));
6619
        });
6620
      };
6621
      const goBackwards = (component, simulatedEvent, tabbingConfig) => {
6622
        const navigate = tabbingConfig.cyclic ? cyclePrev : tryPrev;
6623
        return go(component, simulatedEvent, tabbingConfig, navigate);
6624
      };
6625
      const goForwards = (component, simulatedEvent, tabbingConfig) => {
6626
        const navigate = tabbingConfig.cyclic ? cycleNext : tryNext;
6627
        return go(component, simulatedEvent, tabbingConfig, navigate);
6628
      };
6629
      const isFirstChild = elem => parentNode(elem).bind(firstChild).exists(child => eq(child, elem));
6630
      const goFromPseudoTabstop = (component, simulatedEvent, tabbingConfig) => findCurrent(component, tabbingConfig).filter(elem => !tabbingConfig.useTabstopAt(elem)).bind(elem => (isFirstChild(elem) ? goBackwards : goForwards)(component, simulatedEvent, tabbingConfig));
6631
      const execute = (component, simulatedEvent, tabbingConfig) => tabbingConfig.onEnter.bind(f => f(component, simulatedEvent));
6632
      const exit = (component, simulatedEvent, tabbingConfig) => tabbingConfig.onEscape.bind(f => f(component, simulatedEvent));
6633
      const getKeydownRules = constant$1([
6634
        rule(and([
6635
          isShift$1,
6636
          inSet(TAB)
6637
        ]), goBackwards),
6638
        rule(inSet(TAB), goForwards),
6639
        rule(and([
6640
          isNotShift,
6641
          inSet(ENTER)
6642
        ]), execute)
6643
      ]);
6644
      const getKeyupRules = constant$1([
6645
        rule(inSet(ESCAPE), exit),
6646
        rule(inSet(TAB), goFromPseudoTabstop)
6647
      ]);
6648
      return typical(schema, NoState.init, getKeydownRules, getKeyupRules, () => Optional.some(focusIn));
6649
    };
6650
 
6651
    var AcyclicType = create$2(customField('cyclic', never));
6652
 
6653
    var CyclicType = create$2(customField('cyclic', always));
6654
 
6655
    const doDefaultExecute = (component, _simulatedEvent, focused) => {
6656
      dispatch(component, focused, execute$5());
6657
      return Optional.some(true);
6658
    };
6659
    const defaultExecute = (component, simulatedEvent, focused) => {
6660
      const isComplex = inside(focused) && inSet(SPACE)(simulatedEvent.event);
6661
      return isComplex ? Optional.none() : doDefaultExecute(component, simulatedEvent, focused);
6662
    };
6663
    const stopEventForFirefox = (_component, _simulatedEvent) => Optional.some(true);
6664
 
6665
    const schema$v = [
6666
      defaulted('execute', defaultExecute),
6667
      defaulted('useSpace', false),
6668
      defaulted('useEnter', true),
6669
      defaulted('useControlEnter', false),
6670
      defaulted('useDown', false)
6671
    ];
6672
    const execute$4 = (component, simulatedEvent, executeConfig) => executeConfig.execute(component, simulatedEvent, component.element);
6673
    const getKeydownRules$5 = (component, _simulatedEvent, executeConfig, _executeState) => {
6674
      const spaceExec = executeConfig.useSpace && !inside(component.element) ? SPACE : [];
6675
      const enterExec = executeConfig.useEnter ? ENTER : [];
6676
      const downExec = executeConfig.useDown ? DOWN : [];
6677
      const execKeys = spaceExec.concat(enterExec).concat(downExec);
6678
      return [rule(inSet(execKeys), execute$4)].concat(executeConfig.useControlEnter ? [rule(and([
6679
          isControl,
6680
          inSet(ENTER)
6681
        ]), execute$4)] : []);
6682
    };
6683
    const getKeyupRules$5 = (component, _simulatedEvent, executeConfig, _executeState) => executeConfig.useSpace && !inside(component.element) ? [rule(inSet(SPACE), stopEventForFirefox)] : [];
6684
    var ExecutionType = typical(schema$v, NoState.init, getKeydownRules$5, getKeyupRules$5, () => Optional.none());
6685
 
6686
    const flatgrid$1 = () => {
1441 ariadna 6687
      const dimensions = value$4();
1 efrain 6688
      const setGridSize = (numRows, numColumns) => {
6689
        dimensions.set({
6690
          numRows,
6691
          numColumns
6692
        });
6693
      };
6694
      const getNumRows = () => dimensions.get().map(d => d.numRows);
6695
      const getNumColumns = () => dimensions.get().map(d => d.numColumns);
1441 ariadna 6696
      return nu$7({
1 efrain 6697
        readState: () => dimensions.get().map(d => ({
6698
          numRows: String(d.numRows),
6699
          numColumns: String(d.numColumns)
6700
        })).getOr({
6701
          numRows: '?',
6702
          numColumns: '?'
6703
        }),
6704
        setGridSize,
6705
        getNumRows,
6706
        getNumColumns
6707
      });
6708
    };
1441 ariadna 6709
    const init$c = spec => spec.state(spec);
1 efrain 6710
 
6711
    var KeyingState = /*#__PURE__*/Object.freeze({
6712
        __proto__: null,
6713
        flatgrid: flatgrid$1,
1441 ariadna 6714
        init: init$c
1 efrain 6715
    });
6716
 
6717
    const useH = movement => (component, simulatedEvent, config, state) => {
6718
      const move = movement(component.element);
6719
      return use(move, component, simulatedEvent, config, state);
6720
    };
6721
    const west$1 = (moveLeft, moveRight) => {
6722
      const movement = onDirection(moveLeft, moveRight);
6723
      return useH(movement);
6724
    };
6725
    const east$1 = (moveLeft, moveRight) => {
6726
      const movement = onDirection(moveRight, moveLeft);
6727
      return useH(movement);
6728
    };
6729
    const useV = move => (component, simulatedEvent, config, state) => use(move, component, simulatedEvent, config, state);
6730
    const use = (move, component, simulatedEvent, config, state) => {
6731
      const outcome = config.focusManager.get(component).bind(focused => move(component.element, focused, config, state));
6732
      return outcome.map(newFocus => {
6733
        config.focusManager.set(component, newFocus);
6734
        return true;
6735
      });
6736
    };
6737
    const north$1 = useV;
6738
    const south$1 = useV;
6739
    const move$1 = useV;
6740
 
6741
    const isHidden$1 = dom => dom.offsetWidth <= 0 && dom.offsetHeight <= 0;
6742
    const isVisible = element => !isHidden$1(element.dom);
6743
 
6744
    const locate = (candidates, predicate) => findIndex$1(candidates, predicate).map(index => ({
6745
      index,
6746
      candidates
6747
    }));
6748
 
6749
    const locateVisible = (container, current, selector) => {
6750
      const predicate = x => eq(x, current);
6751
      const candidates = descendants(container, selector);
6752
      const visible = filter$2(candidates, isVisible);
6753
      return locate(visible, predicate);
6754
    };
6755
    const findIndex = (elements, target) => findIndex$1(elements, elem => eq(target, elem));
6756
 
6757
    const withGrid = (values, index, numCols, f) => {
6758
      const oldRow = Math.floor(index / numCols);
6759
      const oldColumn = index % numCols;
6760
      return f(oldRow, oldColumn).bind(address => {
6761
        const newIndex = address.row * numCols + address.column;
6762
        return newIndex >= 0 && newIndex < values.length ? Optional.some(values[newIndex]) : Optional.none();
6763
      });
6764
    };
6765
    const cycleHorizontal$1 = (values, index, numRows, numCols, delta) => withGrid(values, index, numCols, (oldRow, oldColumn) => {
6766
      const onLastRow = oldRow === numRows - 1;
6767
      const colsInRow = onLastRow ? values.length - oldRow * numCols : numCols;
6768
      const newColumn = cycleBy(oldColumn, delta, 0, colsInRow - 1);
6769
      return Optional.some({
6770
        row: oldRow,
6771
        column: newColumn
6772
      });
6773
    });
6774
    const cycleVertical$1 = (values, index, numRows, numCols, delta) => withGrid(values, index, numCols, (oldRow, oldColumn) => {
6775
      const newRow = cycleBy(oldRow, delta, 0, numRows - 1);
6776
      const onLastRow = newRow === numRows - 1;
6777
      const colsInRow = onLastRow ? values.length - newRow * numCols : numCols;
6778
      const newCol = clamp(oldColumn, 0, colsInRow - 1);
6779
      return Optional.some({
6780
        row: newRow,
6781
        column: newCol
6782
      });
6783
    });
6784
    const cycleRight$1 = (values, index, numRows, numCols) => cycleHorizontal$1(values, index, numRows, numCols, +1);
6785
    const cycleLeft$1 = (values, index, numRows, numCols) => cycleHorizontal$1(values, index, numRows, numCols, -1);
6786
    const cycleUp$1 = (values, index, numRows, numCols) => cycleVertical$1(values, index, numRows, numCols, -1);
6787
    const cycleDown$1 = (values, index, numRows, numCols) => cycleVertical$1(values, index, numRows, numCols, +1);
6788
 
6789
    const schema$u = [
6790
      required$1('selector'),
6791
      defaulted('execute', defaultExecute),
6792
      onKeyboardHandler('onEscape'),
6793
      defaulted('captureTab', false),
6794
      initSize()
6795
    ];
1441 ariadna 6796
    const focusIn$4 = (component, gridConfig, _gridState) => {
1 efrain 6797
      descendant(component.element, gridConfig.selector).each(first => {
6798
        gridConfig.focusManager.set(component, first);
6799
      });
6800
    };
6801
    const findCurrent$1 = (component, gridConfig) => gridConfig.focusManager.get(component).bind(elem => closest$1(elem, gridConfig.selector));
6802
    const execute$3 = (component, simulatedEvent, gridConfig, _gridState) => findCurrent$1(component, gridConfig).bind(focused => gridConfig.execute(component, simulatedEvent, focused));
6803
    const doMove$2 = cycle => (element, focused, gridConfig, gridState) => locateVisible(element, focused, gridConfig.selector).bind(identified => cycle(identified.candidates, identified.index, gridState.getNumRows().getOr(gridConfig.initSize.numRows), gridState.getNumColumns().getOr(gridConfig.initSize.numColumns)));
6804
    const handleTab = (_component, _simulatedEvent, gridConfig) => gridConfig.captureTab ? Optional.some(true) : Optional.none();
6805
    const doEscape$1 = (component, simulatedEvent, gridConfig) => gridConfig.onEscape(component, simulatedEvent);
6806
    const moveLeft$3 = doMove$2(cycleLeft$1);
6807
    const moveRight$3 = doMove$2(cycleRight$1);
6808
    const moveNorth$1 = doMove$2(cycleUp$1);
6809
    const moveSouth$1 = doMove$2(cycleDown$1);
6810
    const getKeydownRules$4 = constant$1([
6811
      rule(inSet(LEFT), west$1(moveLeft$3, moveRight$3)),
6812
      rule(inSet(RIGHT), east$1(moveLeft$3, moveRight$3)),
6813
      rule(inSet(UP), north$1(moveNorth$1)),
6814
      rule(inSet(DOWN), south$1(moveSouth$1)),
6815
      rule(and([
6816
        isShift$1,
6817
        inSet(TAB)
6818
      ]), handleTab),
6819
      rule(and([
6820
        isNotShift,
6821
        inSet(TAB)
6822
      ]), handleTab),
6823
      rule(inSet(SPACE.concat(ENTER)), execute$3)
6824
    ]);
6825
    const getKeyupRules$4 = constant$1([
6826
      rule(inSet(ESCAPE), doEscape$1),
6827
      rule(inSet(SPACE), stopEventForFirefox)
6828
    ]);
1441 ariadna 6829
    var FlatgridType = typical(schema$u, flatgrid$1, getKeydownRules$4, getKeyupRules$4, () => Optional.some(focusIn$4));
1 efrain 6830
 
6831
    const f = (container, selector, current, delta, getNewIndex) => {
1441 ariadna 6832
      const isDisabledButton = candidate => name$3(candidate) === 'button' && get$g(candidate, 'disabled') === 'disabled';
1 efrain 6833
      const tryNewIndex = (initial, index, candidates) => getNewIndex(initial, index, delta, 0, candidates.length - 1, candidates[index], newIndex => isDisabledButton(candidates[newIndex]) ? tryNewIndex(initial, newIndex, candidates) : Optional.from(candidates[newIndex]));
6834
      return locateVisible(container, current, selector).bind(identified => {
6835
        const index = identified.index;
6836
        const candidates = identified.candidates;
6837
        return tryNewIndex(index, index, candidates);
6838
      });
6839
    };
6840
    const horizontalWithoutCycles = (container, selector, current, delta) => f(container, selector, current, delta, (prevIndex, v, d, min, max, oldCandidate, onNewIndex) => {
6841
      const newIndex = clamp(v + d, min, max);
6842
      return newIndex === prevIndex ? Optional.from(oldCandidate) : onNewIndex(newIndex);
6843
    });
6844
    const horizontal = (container, selector, current, delta) => f(container, selector, current, delta, (prevIndex, v, d, min, max, _oldCandidate, onNewIndex) => {
6845
      const newIndex = cycleBy(v, d, min, max);
6846
      return newIndex === prevIndex ? Optional.none() : onNewIndex(newIndex);
6847
    });
6848
 
6849
    const schema$t = [
6850
      required$1('selector'),
6851
      defaulted('getInitial', Optional.none),
6852
      defaulted('execute', defaultExecute),
6853
      onKeyboardHandler('onEscape'),
6854
      defaulted('executeOnMove', false),
6855
      defaulted('allowVertical', true),
6856
      defaulted('allowHorizontal', true),
6857
      defaulted('cycles', true)
6858
    ];
6859
    const findCurrent = (component, flowConfig) => flowConfig.focusManager.get(component).bind(elem => closest$1(elem, flowConfig.selector));
6860
    const execute$2 = (component, simulatedEvent, flowConfig) => findCurrent(component, flowConfig).bind(focused => flowConfig.execute(component, simulatedEvent, focused));
1441 ariadna 6861
    const focusIn$3 = (component, flowConfig, _state) => {
1 efrain 6862
      flowConfig.getInitial(component).orThunk(() => descendant(component.element, flowConfig.selector)).each(first => {
6863
        flowConfig.focusManager.set(component, first);
6864
      });
6865
    };
6866
    const moveLeft$2 = (element, focused, info) => (info.cycles ? horizontal : horizontalWithoutCycles)(element, info.selector, focused, -1);
6867
    const moveRight$2 = (element, focused, info) => (info.cycles ? horizontal : horizontalWithoutCycles)(element, info.selector, focused, +1);
6868
    const doMove$1 = movement => (component, simulatedEvent, flowConfig, flowState) => movement(component, simulatedEvent, flowConfig, flowState).bind(() => flowConfig.executeOnMove ? execute$2(component, simulatedEvent, flowConfig) : Optional.some(true));
6869
    const doEscape = (component, simulatedEvent, flowConfig) => flowConfig.onEscape(component, simulatedEvent);
6870
    const getKeydownRules$3 = (_component, _se, flowConfig, _flowState) => {
6871
      const westMovers = [...flowConfig.allowHorizontal ? LEFT : []].concat(flowConfig.allowVertical ? UP : []);
6872
      const eastMovers = [...flowConfig.allowHorizontal ? RIGHT : []].concat(flowConfig.allowVertical ? DOWN : []);
6873
      return [
6874
        rule(inSet(westMovers), doMove$1(west$1(moveLeft$2, moveRight$2))),
6875
        rule(inSet(eastMovers), doMove$1(east$1(moveLeft$2, moveRight$2))),
6876
        rule(inSet(ENTER), execute$2),
6877
        rule(inSet(SPACE), execute$2)
6878
      ];
6879
    };
6880
    const getKeyupRules$3 = constant$1([
6881
      rule(inSet(SPACE), stopEventForFirefox),
6882
      rule(inSet(ESCAPE), doEscape)
6883
    ]);
1441 ariadna 6884
    var FlowType = typical(schema$t, NoState.init, getKeydownRules$3, getKeyupRules$3, () => Optional.some(focusIn$3));
1 efrain 6885
 
6886
    const toCell = (matrix, rowIndex, columnIndex) => Optional.from(matrix[rowIndex]).bind(row => Optional.from(row[columnIndex]).map(cell => ({
6887
      rowIndex,
6888
      columnIndex,
6889
      cell
6890
    })));
6891
    const cycleHorizontal = (matrix, rowIndex, startCol, deltaCol) => {
6892
      const row = matrix[rowIndex];
6893
      const colsInRow = row.length;
6894
      const newColIndex = cycleBy(startCol, deltaCol, 0, colsInRow - 1);
6895
      return toCell(matrix, rowIndex, newColIndex);
6896
    };
6897
    const cycleVertical = (matrix, colIndex, startRow, deltaRow) => {
6898
      const nextRowIndex = cycleBy(startRow, deltaRow, 0, matrix.length - 1);
6899
      const colsInNextRow = matrix[nextRowIndex].length;
6900
      const nextColIndex = clamp(colIndex, 0, colsInNextRow - 1);
6901
      return toCell(matrix, nextRowIndex, nextColIndex);
6902
    };
6903
    const moveHorizontal = (matrix, rowIndex, startCol, deltaCol) => {
6904
      const row = matrix[rowIndex];
6905
      const colsInRow = row.length;
6906
      const newColIndex = clamp(startCol + deltaCol, 0, colsInRow - 1);
6907
      return toCell(matrix, rowIndex, newColIndex);
6908
    };
6909
    const moveVertical = (matrix, colIndex, startRow, deltaRow) => {
6910
      const nextRowIndex = clamp(startRow + deltaRow, 0, matrix.length - 1);
6911
      const colsInNextRow = matrix[nextRowIndex].length;
6912
      const nextColIndex = clamp(colIndex, 0, colsInNextRow - 1);
6913
      return toCell(matrix, nextRowIndex, nextColIndex);
6914
    };
6915
    const cycleRight = (matrix, startRow, startCol) => cycleHorizontal(matrix, startRow, startCol, +1);
6916
    const cycleLeft = (matrix, startRow, startCol) => cycleHorizontal(matrix, startRow, startCol, -1);
6917
    const cycleUp = (matrix, startRow, startCol) => cycleVertical(matrix, startCol, startRow, -1);
6918
    const cycleDown = (matrix, startRow, startCol) => cycleVertical(matrix, startCol, startRow, +1);
6919
    const moveLeft$1 = (matrix, startRow, startCol) => moveHorizontal(matrix, startRow, startCol, -1);
6920
    const moveRight$1 = (matrix, startRow, startCol) => moveHorizontal(matrix, startRow, startCol, +1);
6921
    const moveUp$1 = (matrix, startRow, startCol) => moveVertical(matrix, startCol, startRow, -1);
6922
    const moveDown$1 = (matrix, startRow, startCol) => moveVertical(matrix, startCol, startRow, +1);
6923
 
6924
    const schema$s = [
6925
      requiredObjOf('selectors', [
6926
        required$1('row'),
6927
        required$1('cell')
6928
      ]),
6929
      defaulted('cycles', true),
6930
      defaulted('previousSelector', Optional.none),
6931
      defaulted('execute', defaultExecute)
6932
    ];
1441 ariadna 6933
    const focusIn$2 = (component, matrixConfig, _state) => {
1 efrain 6934
      const focused = matrixConfig.previousSelector(component).orThunk(() => {
6935
        const selectors = matrixConfig.selectors;
6936
        return descendant(component.element, selectors.cell);
6937
      });
6938
      focused.each(cell => {
6939
        matrixConfig.focusManager.set(component, cell);
6940
      });
6941
    };
6942
    const execute$1 = (component, simulatedEvent, matrixConfig) => search(component.element).bind(focused => matrixConfig.execute(component, simulatedEvent, focused));
6943
    const toMatrix = (rows, matrixConfig) => map$2(rows, row => descendants(row, matrixConfig.selectors.cell));
6944
    const doMove = (ifCycle, ifMove) => (element, focused, matrixConfig) => {
6945
      const move = matrixConfig.cycles ? ifCycle : ifMove;
6946
      return closest$1(focused, matrixConfig.selectors.row).bind(inRow => {
6947
        const cellsInRow = descendants(inRow, matrixConfig.selectors.cell);
6948
        return findIndex(cellsInRow, focused).bind(colIndex => {
6949
          const allRows = descendants(element, matrixConfig.selectors.row);
6950
          return findIndex(allRows, inRow).bind(rowIndex => {
6951
            const matrix = toMatrix(allRows, matrixConfig);
6952
            return move(matrix, rowIndex, colIndex).map(next => next.cell);
6953
          });
6954
        });
6955
      });
6956
    };
6957
    const moveLeft = doMove(cycleLeft, moveLeft$1);
6958
    const moveRight = doMove(cycleRight, moveRight$1);
6959
    const moveNorth = doMove(cycleUp, moveUp$1);
6960
    const moveSouth = doMove(cycleDown, moveDown$1);
6961
    const getKeydownRules$2 = constant$1([
6962
      rule(inSet(LEFT), west$1(moveLeft, moveRight)),
6963
      rule(inSet(RIGHT), east$1(moveLeft, moveRight)),
6964
      rule(inSet(UP), north$1(moveNorth)),
6965
      rule(inSet(DOWN), south$1(moveSouth)),
6966
      rule(inSet(SPACE.concat(ENTER)), execute$1)
6967
    ]);
6968
    const getKeyupRules$2 = constant$1([rule(inSet(SPACE), stopEventForFirefox)]);
1441 ariadna 6969
    var MatrixType = typical(schema$s, NoState.init, getKeydownRules$2, getKeyupRules$2, () => Optional.some(focusIn$2));
1 efrain 6970
 
6971
    const schema$r = [
6972
      required$1('selector'),
6973
      defaulted('execute', defaultExecute),
6974
      defaulted('moveOnTab', false)
6975
    ];
6976
    const execute = (component, simulatedEvent, menuConfig) => menuConfig.focusManager.get(component).bind(focused => menuConfig.execute(component, simulatedEvent, focused));
1441 ariadna 6977
    const focusIn$1 = (component, menuConfig, _state) => {
1 efrain 6978
      descendant(component.element, menuConfig.selector).each(first => {
6979
        menuConfig.focusManager.set(component, first);
6980
      });
6981
    };
6982
    const moveUp = (element, focused, info) => horizontal(element, info.selector, focused, -1);
6983
    const moveDown = (element, focused, info) => horizontal(element, info.selector, focused, +1);
6984
    const fireShiftTab = (component, simulatedEvent, menuConfig, menuState) => menuConfig.moveOnTab ? move$1(moveUp)(component, simulatedEvent, menuConfig, menuState) : Optional.none();
6985
    const fireTab = (component, simulatedEvent, menuConfig, menuState) => menuConfig.moveOnTab ? move$1(moveDown)(component, simulatedEvent, menuConfig, menuState) : Optional.none();
6986
    const getKeydownRules$1 = constant$1([
6987
      rule(inSet(UP), move$1(moveUp)),
6988
      rule(inSet(DOWN), move$1(moveDown)),
6989
      rule(and([
6990
        isShift$1,
6991
        inSet(TAB)
6992
      ]), fireShiftTab),
6993
      rule(and([
6994
        isNotShift,
6995
        inSet(TAB)
6996
      ]), fireTab),
6997
      rule(inSet(ENTER), execute),
6998
      rule(inSet(SPACE), execute)
6999
    ]);
7000
    const getKeyupRules$1 = constant$1([rule(inSet(SPACE), stopEventForFirefox)]);
1441 ariadna 7001
    var MenuType = typical(schema$r, NoState.init, getKeydownRules$1, getKeyupRules$1, () => Optional.some(focusIn$1));
1 efrain 7002
 
7003
    const schema$q = [
7004
      onKeyboardHandler('onSpace'),
7005
      onKeyboardHandler('onEnter'),
7006
      onKeyboardHandler('onShiftEnter'),
7007
      onKeyboardHandler('onLeft'),
7008
      onKeyboardHandler('onRight'),
7009
      onKeyboardHandler('onTab'),
7010
      onKeyboardHandler('onShiftTab'),
7011
      onKeyboardHandler('onUp'),
7012
      onKeyboardHandler('onDown'),
7013
      onKeyboardHandler('onEscape'),
7014
      defaulted('stopSpaceKeyup', false),
7015
      option$3('focusIn')
7016
    ];
7017
    const getKeydownRules = (component, simulatedEvent, specialInfo) => [
7018
      rule(inSet(SPACE), specialInfo.onSpace),
7019
      rule(and([
7020
        isNotShift,
7021
        inSet(ENTER)
7022
      ]), specialInfo.onEnter),
7023
      rule(and([
7024
        isShift$1,
7025
        inSet(ENTER)
7026
      ]), specialInfo.onShiftEnter),
7027
      rule(and([
7028
        isShift$1,
7029
        inSet(TAB)
7030
      ]), specialInfo.onShiftTab),
7031
      rule(and([
7032
        isNotShift,
7033
        inSet(TAB)
7034
      ]), specialInfo.onTab),
7035
      rule(inSet(UP), specialInfo.onUp),
7036
      rule(inSet(DOWN), specialInfo.onDown),
7037
      rule(inSet(LEFT), specialInfo.onLeft),
7038
      rule(inSet(RIGHT), specialInfo.onRight),
7039
      rule(inSet(SPACE), specialInfo.onSpace)
7040
    ];
7041
    const getKeyupRules = (component, simulatedEvent, specialInfo) => [
7042
      ...specialInfo.stopSpaceKeyup ? [rule(inSet(SPACE), stopEventForFirefox)] : [],
7043
      rule(inSet(ESCAPE), specialInfo.onEscape)
7044
    ];
7045
    var SpecialType = typical(schema$q, NoState.init, getKeydownRules, getKeyupRules, specialInfo => specialInfo.focusIn);
7046
 
7047
    const acyclic = AcyclicType.schema();
7048
    const cyclic = CyclicType.schema();
7049
    const flow = FlowType.schema();
7050
    const flatgrid = FlatgridType.schema();
7051
    const matrix = MatrixType.schema();
7052
    const execution = ExecutionType.schema();
7053
    const menu = MenuType.schema();
7054
    const special = SpecialType.schema();
7055
 
7056
    var KeyboardBranches = /*#__PURE__*/Object.freeze({
7057
        __proto__: null,
7058
        acyclic: acyclic,
7059
        cyclic: cyclic,
7060
        flow: flow,
7061
        flatgrid: flatgrid,
7062
        matrix: matrix,
7063
        execution: execution,
7064
        menu: menu,
7065
        special: special
7066
    });
7067
 
7068
    const isFlatgridState = keyState => hasNonNullableKey(keyState, 'setGridSize');
7069
    const Keying = createModes({
7070
      branchKey: 'mode',
7071
      branches: KeyboardBranches,
7072
      name: 'keying',
7073
      active: {
7074
        events: (keyingConfig, keyingState) => {
7075
          const handler = keyingConfig.handler;
7076
          return handler.toEvents(keyingConfig, keyingState);
7077
        }
7078
      },
7079
      apis: {
7080
        focusIn: (component, keyConfig, keyState) => {
7081
          keyConfig.sendFocusIn(keyConfig).fold(() => {
7082
            component.getSystem().triggerFocus(component.element, component.element);
7083
          }, sendFocusIn => {
7084
            sendFocusIn(component, keyConfig, keyState);
7085
          });
7086
        },
7087
        setGridSize: (component, keyConfig, keyState, numRows, numColumns) => {
7088
          if (!isFlatgridState(keyState)) {
7089
            console.error('Layout does not support setGridSize');
7090
          } else {
7091
            keyState.setGridSize(numRows, numColumns);
7092
          }
7093
        }
7094
      },
7095
      state: KeyingState
7096
    });
7097
 
7098
    const withoutReuse = (parent, data) => {
7099
      preserve$1(() => {
7100
        replaceChildren(parent, data, () => map$2(data, parent.getSystem().build));
7101
      }, parent.element);
7102
    };
7103
    const withReuse = (parent, data) => {
7104
      preserve$1(() => {
7105
        virtualReplaceChildren(parent, data, () => {
7106
          return patchSpecChildren(parent.element, data, parent.getSystem().buildOrPatch);
7107
        });
7108
      }, parent.element);
7109
    };
7110
 
7111
    const virtualReplace = (component, replacee, replaceeIndex, childSpec) => {
7112
      virtualDetach(replacee);
7113
      const child = patchSpecChild(component.element, replaceeIndex, childSpec, component.getSystem().buildOrPatch);
7114
      virtualAttach(component, child);
7115
      component.syncComponents();
7116
    };
7117
    const insert = (component, insertion, childSpec) => {
7118
      const child = component.getSystem().build(childSpec);
7119
      attachWith(component, child, insertion);
7120
    };
7121
    const replace = (component, replacee, replaceeIndex, childSpec) => {
7122
      detach(replacee);
7123
      insert(component, (p, c) => appendAt(p, c, replaceeIndex), childSpec);
7124
    };
7125
    const set$3 = (component, replaceConfig, replaceState, data) => {
7126
      const replacer = replaceConfig.reuseDom ? withReuse : withoutReuse;
7127
      return replacer(component, data);
7128
    };
7129
    const append = (component, replaceConfig, replaceState, appendee) => {
7130
      insert(component, append$2, appendee);
7131
    };
7132
    const prepend = (component, replaceConfig, replaceState, prependee) => {
7133
      insert(component, prepend$1, prependee);
7134
    };
1441 ariadna 7135
    const remove$1 = (component, replaceConfig, replaceState, removee) => {
1 efrain 7136
      const children = contents(component);
7137
      const foundChild = find$5(children, child => eq(removee.element, child.element));
7138
      foundChild.each(detach);
7139
    };
7140
    const contents = (component, _replaceConfig) => component.components();
7141
    const replaceAt = (component, replaceConfig, replaceState, replaceeIndex, replacer) => {
7142
      const children = contents(component);
7143
      return Optional.from(children[replaceeIndex]).map(replacee => {
7144
        replacer.fold(() => detach(replacee), r => {
7145
          const replacer = replaceConfig.reuseDom ? virtualReplace : replace;
7146
          replacer(component, replacee, replaceeIndex, r);
7147
        });
7148
        return replacee;
7149
      });
7150
    };
7151
    const replaceBy = (component, replaceConfig, replaceState, replaceePred, replacer) => {
7152
      const children = contents(component);
7153
      return findIndex$1(children, replaceePred).bind(replaceeIndex => replaceAt(component, replaceConfig, replaceState, replaceeIndex, replacer));
7154
    };
7155
 
7156
    var ReplaceApis = /*#__PURE__*/Object.freeze({
7157
        __proto__: null,
7158
        append: append,
7159
        prepend: prepend,
1441 ariadna 7160
        remove: remove$1,
1 efrain 7161
        replaceAt: replaceAt,
7162
        replaceBy: replaceBy,
7163
        set: set$3,
7164
        contents: contents
7165
    });
7166
 
7167
    const Replacing = create$4({
7168
      fields: [defaultedBoolean('reuseDom', true)],
7169
      name: 'replacing',
7170
      apis: ReplaceApis
7171
    });
7172
 
1441 ariadna 7173
    const events$c = (name, eventHandlers) => {
1 efrain 7174
      const events = derive$2(eventHandlers);
7175
      return create$4({
7176
        fields: [required$1('enabled')],
7177
        name,
7178
        active: { events: constant$1(events) }
7179
      });
7180
    };
7181
    const config = (name, eventHandlers) => {
1441 ariadna 7182
      const me = events$c(name, eventHandlers);
1 efrain 7183
      return {
7184
        key: name,
7185
        value: {
7186
          config: {},
7187
          me,
7188
          configAsRaw: constant$1({}),
7189
          initialConfig: {},
7190
          state: NoState
7191
        }
7192
      };
7193
    };
7194
 
7195
    const focus$2 = (component, focusConfig) => {
7196
      if (!focusConfig.ignore) {
7197
        focus$3(component.element);
7198
        focusConfig.onFocus(component);
7199
      }
7200
    };
7201
    const blur = (component, focusConfig) => {
7202
      if (!focusConfig.ignore) {
7203
        blur$1(component.element);
7204
      }
7205
    };
7206
    const isFocused = component => hasFocus(component.element);
7207
 
7208
    var FocusApis = /*#__PURE__*/Object.freeze({
7209
        __proto__: null,
7210
        focus: focus$2,
7211
        blur: blur,
7212
        isFocused: isFocused
7213
    });
7214
 
7215
    const exhibit$4 = (base, focusConfig) => {
7216
      const mod = focusConfig.ignore ? {} : { attributes: { tabindex: '-1' } };
1441 ariadna 7217
      return nu$8(mod);
1 efrain 7218
    };
1441 ariadna 7219
    const events$b = focusConfig => derive$2([run$1(focus$4(), (component, simulatedEvent) => {
1 efrain 7220
        focus$2(component, focusConfig);
7221
        simulatedEvent.stop();
7222
      })].concat(focusConfig.stopMousedown ? [run$1(mousedown(), (_, simulatedEvent) => {
7223
        simulatedEvent.event.prevent();
7224
      })] : []));
7225
 
7226
    var ActiveFocus = /*#__PURE__*/Object.freeze({
7227
        __proto__: null,
7228
        exhibit: exhibit$4,
1441 ariadna 7229
        events: events$b
1 efrain 7230
    });
7231
 
7232
    var FocusSchema = [
7233
      onHandler('onFocus'),
7234
      defaulted('stopMousedown', false),
7235
      defaulted('ignore', false)
7236
    ];
7237
 
7238
    const Focusing = create$4({
7239
      fields: FocusSchema,
7240
      name: 'focusing',
7241
      active: ActiveFocus,
7242
      apis: FocusApis
7243
    });
7244
 
7245
    const SetupBehaviourCellState = initialState => {
7246
      const init = () => {
7247
        const cell = Cell(initialState);
7248
        const get = () => cell.get();
7249
        const set = newState => cell.set(newState);
7250
        const clear = () => cell.set(initialState);
7251
        const readState = () => cell.get();
7252
        return {
7253
          get,
7254
          set,
7255
          clear,
7256
          readState
7257
        };
7258
      };
7259
      return { init };
7260
    };
7261
 
7262
    const updateAriaState = (component, toggleConfig, toggleState) => {
7263
      const ariaInfo = toggleConfig.aria;
7264
      ariaInfo.update(component, ariaInfo, toggleState.get());
7265
    };
7266
    const updateClass = (component, toggleConfig, toggleState) => {
7267
      toggleConfig.toggleClass.each(toggleClass => {
7268
        if (toggleState.get()) {
7269
          add$2(component.element, toggleClass);
7270
        } else {
1441 ariadna 7271
          remove$3(component.element, toggleClass);
1 efrain 7272
        }
7273
      });
7274
    };
7275
    const set$2 = (component, toggleConfig, toggleState, state) => {
7276
      const initialState = toggleState.get();
7277
      toggleState.set(state);
7278
      updateClass(component, toggleConfig, toggleState);
7279
      updateAriaState(component, toggleConfig, toggleState);
7280
      if (initialState !== state) {
7281
        toggleConfig.onToggled(component, state);
7282
      }
7283
    };
7284
    const toggle$2 = (component, toggleConfig, toggleState) => {
7285
      set$2(component, toggleConfig, toggleState, !toggleState.get());
7286
    };
7287
    const on = (component, toggleConfig, toggleState) => {
7288
      set$2(component, toggleConfig, toggleState, true);
7289
    };
7290
    const off = (component, toggleConfig, toggleState) => {
7291
      set$2(component, toggleConfig, toggleState, false);
7292
    };
7293
    const isOn = (component, toggleConfig, toggleState) => toggleState.get();
7294
    const onLoad = (component, toggleConfig, toggleState) => {
7295
      set$2(component, toggleConfig, toggleState, toggleConfig.selected);
7296
    };
7297
 
7298
    var ToggleApis = /*#__PURE__*/Object.freeze({
7299
        __proto__: null,
7300
        onLoad: onLoad,
7301
        toggle: toggle$2,
7302
        isOn: isOn,
7303
        on: on,
7304
        off: off,
7305
        set: set$2
7306
    });
7307
 
1441 ariadna 7308
    const exhibit$3 = () => nu$8({});
7309
    const events$a = (toggleConfig, toggleState) => {
1 efrain 7310
      const execute = executeEvent(toggleConfig, toggleState, toggle$2);
7311
      const load = loadEvent(toggleConfig, toggleState, onLoad);
7312
      return derive$2(flatten([
7313
        toggleConfig.toggleOnExecute ? [execute] : [],
7314
        [load]
7315
      ]));
7316
    };
7317
 
7318
    var ActiveToggle = /*#__PURE__*/Object.freeze({
7319
        __proto__: null,
7320
        exhibit: exhibit$3,
1441 ariadna 7321
        events: events$a
1 efrain 7322
    });
7323
 
7324
    const updatePressed = (component, ariaInfo, status) => {
7325
      set$9(component.element, 'aria-pressed', status);
7326
      if (ariaInfo.syncWithExpanded) {
7327
        updateExpanded(component, ariaInfo, status);
7328
      }
7329
    };
7330
    const updateSelected = (component, ariaInfo, status) => {
7331
      set$9(component.element, 'aria-selected', status);
7332
    };
7333
    const updateChecked = (component, ariaInfo, status) => {
7334
      set$9(component.element, 'aria-checked', status);
7335
    };
7336
    const updateExpanded = (component, ariaInfo, status) => {
7337
      set$9(component.element, 'aria-expanded', status);
7338
    };
7339
 
7340
    var ToggleSchema = [
7341
      defaulted('selected', false),
7342
      option$3('toggleClass'),
7343
      defaulted('toggleOnExecute', true),
7344
      onHandler('onToggled'),
7345
      defaultedOf('aria', { mode: 'none' }, choose$1('mode', {
7346
        pressed: [
7347
          defaulted('syncWithExpanded', false),
7348
          output$1('update', updatePressed)
7349
        ],
7350
        checked: [output$1('update', updateChecked)],
7351
        expanded: [output$1('update', updateExpanded)],
7352
        selected: [output$1('update', updateSelected)],
7353
        none: [output$1('update', noop)]
7354
      }))
7355
    ];
7356
 
7357
    const Toggling = create$4({
7358
      fields: ToggleSchema,
7359
      name: 'toggling',
7360
      active: ActiveToggle,
7361
      apis: ToggleApis,
7362
      state: SetupBehaviourCellState(false)
7363
    });
7364
 
7365
    const pointerEvents = () => {
7366
      const onClick = (component, simulatedEvent) => {
7367
        simulatedEvent.stop();
7368
        emitExecute(component);
7369
      };
7370
      return [
7371
        run$1(click(), onClick),
7372
        run$1(tap(), onClick),
7373
        cutter(touchstart()),
7374
        cutter(mousedown())
7375
      ];
7376
    };
1441 ariadna 7377
    const events$9 = optAction => {
1 efrain 7378
      const executeHandler = action => runOnExecute$1((component, simulatedEvent) => {
7379
        action(component);
7380
        simulatedEvent.stop();
7381
      });
7382
      return derive$2(flatten([
7383
        optAction.map(executeHandler).toArray(),
7384
        pointerEvents()
7385
      ]));
7386
    };
7387
 
7388
    const hoverEvent = 'alloy.item-hover';
7389
    const focusEvent = 'alloy.item-focus';
7390
    const toggledEvent = 'alloy.item-toggled';
7391
    const onHover = item => {
7392
      if (search(item.element).isNone() || Focusing.isFocused(item)) {
7393
        if (!Focusing.isFocused(item)) {
7394
          Focusing.focus(item);
7395
        }
7396
        emitWith(item, hoverEvent, { item });
7397
      }
7398
    };
7399
    const onFocus$1 = item => {
7400
      emitWith(item, focusEvent, { item });
7401
    };
7402
    const onToggled = (item, state) => {
7403
      emitWith(item, toggledEvent, {
7404
        item,
7405
        state
7406
      });
7407
    };
7408
    const hover = constant$1(hoverEvent);
7409
    const focus$1 = constant$1(focusEvent);
7410
    const toggled = constant$1(toggledEvent);
7411
 
1441 ariadna 7412
    const getItemRole = detail => detail.role.fold(() => detail.toggling.map(toggling => toggling.exclusive ? 'menuitemradio' : 'menuitemcheckbox').getOr('menuitem'), identity);
7413
    const getTogglingSpec = (tConfig, isOption) => ({
7414
      aria: { mode: isOption ? 'selected' : 'checked' },
1 efrain 7415
      ...filter$1(tConfig, (_value, name) => name !== 'exclusive'),
7416
      onToggled: (component, state) => {
7417
        if (isFunction(tConfig.onToggled)) {
7418
          tConfig.onToggled(component, state);
7419
        }
7420
        onToggled(component, state);
7421
      }
7422
    });
7423
    const builder$2 = detail => ({
7424
      dom: detail.dom,
7425
      domModification: {
7426
        ...detail.domModification,
7427
        attributes: {
7428
          'role': getItemRole(detail),
7429
          ...detail.domModification.attributes,
7430
          'aria-haspopup': detail.hasSubmenu,
7431
          ...detail.hasSubmenu ? { 'aria-expanded': false } : {}
7432
        }
7433
      },
7434
      behaviours: SketchBehaviours.augment(detail.itemBehaviours, [
1441 ariadna 7435
        detail.toggling.fold(Toggling.revoke, tConfig => Toggling.config(getTogglingSpec(tConfig, detail.role.exists(role => role === 'option')))),
1 efrain 7436
        Focusing.config({
7437
          ignore: detail.ignoreFocus,
7438
          stopMousedown: detail.ignoreFocus,
7439
          onFocus: component => {
7440
            onFocus$1(component);
7441
          }
7442
        }),
7443
        Keying.config({ mode: 'execution' }),
7444
        Representing.config({
7445
          store: {
7446
            mode: 'memory',
7447
            initialValue: detail.data
7448
          }
7449
        }),
7450
        config('item-type-events', [
7451
          ...pointerEvents(),
7452
          run$1(mouseover(), onHover),
7453
          run$1(focusItem(), Focusing.focus)
7454
        ])
7455
      ]),
7456
      components: detail.components,
7457
      eventOrder: detail.eventOrder
7458
    });
7459
    const schema$p = [
7460
      required$1('data'),
7461
      required$1('components'),
7462
      required$1('dom'),
7463
      defaulted('hasSubmenu', false),
7464
      option$3('toggling'),
1441 ariadna 7465
      option$3('role'),
1 efrain 7466
      SketchBehaviours.field('itemBehaviours', [
7467
        Toggling,
7468
        Focusing,
7469
        Keying,
7470
        Representing
7471
      ]),
7472
      defaulted('ignoreFocus', false),
7473
      defaulted('domModification', {}),
7474
      output$1('builder', builder$2),
7475
      defaulted('eventOrder', {})
7476
    ];
7477
 
7478
    const builder$1 = detail => ({
7479
      dom: detail.dom,
7480
      components: detail.components,
7481
      events: derive$2([stopper(focusItem())])
7482
    });
7483
    const schema$o = [
7484
      required$1('dom'),
7485
      required$1('components'),
7486
      output$1('builder', builder$1)
7487
    ];
7488
 
7489
    const owner$2 = constant$1('item-widget');
7490
    const parts$h = constant$1([required({
7491
        name: 'widget',
7492
        overrides: detail => {
7493
          return {
7494
            behaviours: derive$1([Representing.config({
7495
                store: {
7496
                  mode: 'manual',
7497
                  getValue: _component => {
7498
                    return detail.data;
7499
                  },
7500
                  setValue: noop
7501
                }
7502
              })])
7503
          };
7504
        }
7505
      })]);
7506
 
7507
    const builder = detail => {
7508
      const subs = substitutes(owner$2(), detail, parts$h());
7509
      const components = components$1(owner$2(), detail, subs.internals());
7510
      const focusWidget = component => getPart(component, detail, 'widget').map(widget => {
7511
        Keying.focusIn(widget);
7512
        return widget;
7513
      });
7514
      const onHorizontalArrow = (component, simulatedEvent) => inside(simulatedEvent.event.target) ? Optional.none() : (() => {
7515
        if (detail.autofocus) {
7516
          simulatedEvent.setSource(component.element);
7517
          return Optional.none();
7518
        } else {
7519
          return Optional.none();
7520
        }
7521
      })();
7522
      return {
7523
        dom: detail.dom,
7524
        components,
7525
        domModification: detail.domModification,
7526
        events: derive$2([
7527
          runOnExecute$1((component, simulatedEvent) => {
7528
            focusWidget(component).each(_widget => {
7529
              simulatedEvent.stop();
7530
            });
7531
          }),
7532
          run$1(mouseover(), onHover),
7533
          run$1(focusItem(), (component, _simulatedEvent) => {
7534
            if (detail.autofocus) {
7535
              focusWidget(component);
7536
            } else {
7537
              Focusing.focus(component);
7538
            }
7539
          })
7540
        ]),
7541
        behaviours: SketchBehaviours.augment(detail.widgetBehaviours, [
7542
          Representing.config({
7543
            store: {
7544
              mode: 'memory',
7545
              initialValue: detail.data
7546
            }
7547
          }),
7548
          Focusing.config({
7549
            ignore: detail.ignoreFocus,
7550
            onFocus: component => {
7551
              onFocus$1(component);
7552
            }
7553
          }),
7554
          Keying.config({
7555
            mode: 'special',
7556
            focusIn: detail.autofocus ? component => {
7557
              focusWidget(component);
7558
            } : revoke(),
7559
            onLeft: onHorizontalArrow,
7560
            onRight: onHorizontalArrow,
7561
            onEscape: (component, simulatedEvent) => {
7562
              if (!Focusing.isFocused(component) && !detail.autofocus) {
7563
                Focusing.focus(component);
7564
                return Optional.some(true);
7565
              } else if (detail.autofocus) {
7566
                simulatedEvent.setSource(component.element);
7567
                return Optional.none();
7568
              } else {
7569
                return Optional.none();
7570
              }
7571
            }
7572
          })
7573
        ])
7574
      };
7575
    };
7576
    const schema$n = [
7577
      required$1('uid'),
7578
      required$1('data'),
7579
      required$1('components'),
7580
      required$1('dom'),
7581
      defaulted('autofocus', false),
7582
      defaulted('ignoreFocus', false),
7583
      SketchBehaviours.field('widgetBehaviours', [
7584
        Representing,
7585
        Focusing,
7586
        Keying
7587
      ]),
7588
      defaulted('domModification', {}),
7589
      defaultUidsSchema(parts$h()),
7590
      output$1('builder', builder)
7591
    ];
7592
 
7593
    const itemSchema$2 = choose$1('type', {
7594
      widget: schema$n,
7595
      item: schema$p,
7596
      separator: schema$o
7597
    });
7598
    const configureGrid = (detail, movementInfo) => ({
7599
      mode: 'flatgrid',
7600
      selector: '.' + detail.markers.item,
7601
      initSize: {
7602
        numColumns: movementInfo.initSize.numColumns,
7603
        numRows: movementInfo.initSize.numRows
7604
      },
7605
      focusManager: detail.focusManager
7606
    });
7607
    const configureMatrix = (detail, movementInfo) => ({
7608
      mode: 'matrix',
7609
      selectors: {
7610
        row: movementInfo.rowSelector,
7611
        cell: '.' + detail.markers.item
7612
      },
7613
      previousSelector: movementInfo.previousSelector,
7614
      focusManager: detail.focusManager
7615
    });
7616
    const configureMenu = (detail, movementInfo) => ({
7617
      mode: 'menu',
7618
      selector: '.' + detail.markers.item,
7619
      moveOnTab: movementInfo.moveOnTab,
7620
      focusManager: detail.focusManager
7621
    });
7622
    const parts$g = constant$1([group({
7623
        factory: {
7624
          sketch: spec => {
7625
            const itemInfo = asRawOrDie$1('menu.spec item', itemSchema$2, spec);
7626
            return itemInfo.builder(itemInfo);
7627
          }
7628
        },
7629
        name: 'items',
7630
        unit: 'item',
7631
        defaults: (detail, u) => {
7632
          return has$2(u, 'uid') ? u : {
7633
            ...u,
7634
            uid: generate$5('item')
7635
          };
7636
        },
7637
        overrides: (detail, u) => {
7638
          return {
7639
            type: u.type,
7640
            ignoreFocus: detail.fakeFocus,
7641
            domModification: { classes: [detail.markers.item] }
7642
          };
7643
        }
7644
      })]);
7645
    const schema$m = constant$1([
1441 ariadna 7646
      optionString('role'),
1 efrain 7647
      required$1('value'),
7648
      required$1('items'),
7649
      required$1('dom'),
7650
      required$1('components'),
7651
      defaulted('eventOrder', {}),
7652
      field('menuBehaviours', [
7653
        Highlighting,
7654
        Representing,
7655
        Composing,
7656
        Keying
7657
      ]),
7658
      defaultedOf('movement', {
7659
        mode: 'menu',
7660
        moveOnTab: true
7661
      }, choose$1('mode', {
7662
        grid: [
7663
          initSize(),
7664
          output$1('config', configureGrid)
7665
        ],
7666
        matrix: [
7667
          output$1('config', configureMatrix),
7668
          required$1('rowSelector'),
7669
          defaulted('previousSelector', Optional.none)
7670
        ],
7671
        menu: [
7672
          defaulted('moveOnTab', true),
7673
          output$1('config', configureMenu)
7674
        ]
7675
      })),
7676
      itemMarkers(),
7677
      defaulted('fakeFocus', false),
7678
      defaulted('focusManager', dom$2()),
7679
      onHandler('onHighlight'),
1441 ariadna 7680
      onHandler('onDehighlight'),
7681
      defaulted('showMenuRole', true)
1 efrain 7682
    ]);
7683
 
7684
    const focus = constant$1('alloy.menu-focus');
7685
 
7686
    const deselectOtherRadioItems = (menu, item) => {
7687
      const checkedRadioItems = descendants(menu.element, '[role="menuitemradio"][aria-checked="true"]');
7688
      each$1(checkedRadioItems, ele => {
7689
        if (!eq(ele, item.element)) {
7690
          menu.getSystem().getByDom(ele).each(c => {
7691
            Toggling.off(c);
7692
          });
7693
        }
7694
      });
7695
    };
7696
    const make$7 = (detail, components, _spec, _externals) => ({
7697
      uid: detail.uid,
7698
      dom: detail.dom,
7699
      markers: detail.markers,
7700
      behaviours: augment(detail.menuBehaviours, [
7701
        Highlighting.config({
7702
          highlightClass: detail.markers.selectedItem,
7703
          itemClass: detail.markers.item,
7704
          onHighlight: detail.onHighlight,
7705
          onDehighlight: detail.onDehighlight
7706
        }),
7707
        Representing.config({
7708
          store: {
7709
            mode: 'memory',
7710
            initialValue: detail.value
7711
          }
7712
        }),
7713
        Composing.config({ find: Optional.some }),
7714
        Keying.config(detail.movement.config(detail, detail.movement))
7715
      ]),
7716
      events: derive$2([
7717
        run$1(focus$1(), (menu, simulatedEvent) => {
7718
          const event = simulatedEvent.event;
7719
          menu.getSystem().getByDom(event.target).each(item => {
7720
            Highlighting.highlight(menu, item);
7721
            simulatedEvent.stop();
7722
            emitWith(menu, focus(), {
7723
              menu,
7724
              item
7725
            });
7726
          });
7727
        }),
7728
        run$1(hover(), (menu, simulatedEvent) => {
7729
          const item = simulatedEvent.event.item;
7730
          Highlighting.highlight(menu, item);
7731
        }),
7732
        run$1(toggled(), (menu, simulatedEvent) => {
7733
          const {item, state} = simulatedEvent.event;
1441 ariadna 7734
          if (state && get$g(item.element, 'role') === 'menuitemradio') {
1 efrain 7735
            deselectOtherRadioItems(menu, item);
7736
          }
7737
        })
7738
      ]),
7739
      components,
7740
      eventOrder: detail.eventOrder,
1441 ariadna 7741
      ...detail.showMenuRole ? { domModification: { attributes: { role: detail.role.getOr('menu') } } } : {}
1 efrain 7742
    });
7743
 
7744
    const Menu = composite({
7745
      name: 'Menu',
7746
      configFields: schema$m(),
7747
      partFields: parts$g(),
7748
      factory: make$7
7749
    });
7750
 
7751
    const transpose$1 = obj => tupleMap(obj, (v, k) => ({
7752
      k: v,
7753
      v: k
7754
    }));
1441 ariadna 7755
    const trace = (items, byItem, byMenu, finish) => get$h(byMenu, finish).bind(triggerItem => get$h(items, triggerItem).bind(triggerMenu => {
1 efrain 7756
      const rest = trace(items, byItem, byMenu, triggerMenu);
7757
      return Optional.some([triggerMenu].concat(rest));
7758
    })).getOr([]);
7759
    const generate$2 = (menus, expansions) => {
7760
      const items = {};
7761
      each(menus, (menuItems, menu) => {
7762
        each$1(menuItems, item => {
7763
          items[item] = menu;
7764
        });
7765
      });
7766
      const byItem = expansions;
7767
      const byMenu = transpose$1(expansions);
7768
      const menuPaths = map$1(byMenu, (_triggerItem, submenu) => [submenu].concat(trace(items, byItem, byMenu, submenu)));
1441 ariadna 7769
      return map$1(items, menu => get$h(menuPaths, menu).getOr([menu]));
1 efrain 7770
    };
7771
 
1441 ariadna 7772
    const init$b = () => {
1 efrain 7773
      const expansions = Cell({});
7774
      const menus = Cell({});
7775
      const paths = Cell({});
1441 ariadna 7776
      const primary = value$4();
1 efrain 7777
      const directory = Cell({});
7778
      const clear = () => {
7779
        expansions.set({});
7780
        menus.set({});
7781
        paths.set({});
7782
        primary.clear();
7783
      };
7784
      const isClear = () => primary.get().isNone();
7785
      const setMenuBuilt = (menuName, built) => {
7786
        menus.set({
7787
          ...menus.get(),
7788
          [menuName]: {
7789
            type: 'prepared',
7790
            menu: built
7791
          }
7792
        });
7793
      };
7794
      const setContents = (sPrimary, sMenus, sExpansions, dir) => {
7795
        primary.set(sPrimary);
7796
        expansions.set(sExpansions);
7797
        menus.set(sMenus);
7798
        directory.set(dir);
7799
        const sPaths = generate$2(dir, sExpansions);
7800
        paths.set(sPaths);
7801
      };
7802
      const getTriggeringItem = menuValue => find$4(expansions.get(), (v, _k) => v === menuValue);
7803
      const getTriggerData = (menuValue, getItemByValue, path) => getPreparedMenu(menuValue).bind(menu => getTriggeringItem(menuValue).bind(triggeringItemValue => getItemByValue(triggeringItemValue).map(triggeredItem => ({
7804
        triggeredMenu: menu,
7805
        triggeringItem: triggeredItem,
7806
        triggeringPath: path
7807
      }))));
7808
      const getTriggeringPath = (itemValue, getItemByValue) => {
7809
        const extraPath = filter$2(lookupItem(itemValue).toArray(), menuValue => getPreparedMenu(menuValue).isSome());
1441 ariadna 7810
        return get$h(paths.get(), itemValue).bind(path => {
1 efrain 7811
          const revPath = reverse(extraPath.concat(path));
7812
          const triggers = bind$3(revPath, (menuValue, menuIndex) => getTriggerData(menuValue, getItemByValue, revPath.slice(0, menuIndex + 1)).fold(() => is$1(primary.get(), menuValue) ? [] : [Optional.none()], data => [Optional.some(data)]));
7813
          return sequence(triggers);
7814
        });
7815
      };
1441 ariadna 7816
      const expand = itemValue => get$h(expansions.get(), itemValue).map(menu => {
7817
        const current = get$h(paths.get(), itemValue).getOr([]);
1 efrain 7818
        return [menu].concat(current);
7819
      });
1441 ariadna 7820
      const collapse = itemValue => get$h(paths.get(), itemValue).bind(path => path.length > 1 ? Optional.some(path.slice(1)) : Optional.none());
7821
      const refresh = itemValue => get$h(paths.get(), itemValue);
1 efrain 7822
      const getPreparedMenu = menuValue => lookupMenu(menuValue).bind(extractPreparedMenu);
1441 ariadna 7823
      const lookupMenu = menuValue => get$h(menus.get(), menuValue);
7824
      const lookupItem = itemValue => get$h(expansions.get(), itemValue);
1 efrain 7825
      const otherMenus = path => {
7826
        const menuValues = directory.get();
7827
        return difference(keys(menuValues), path);
7828
      };
7829
      const getPrimary = () => primary.get().bind(getPreparedMenu);
7830
      const getMenus = () => menus.get();
7831
      return {
7832
        setMenuBuilt,
7833
        setContents,
7834
        expand,
7835
        refresh,
7836
        collapse,
7837
        lookupMenu,
7838
        lookupItem,
7839
        otherMenus,
7840
        getPrimary,
7841
        getMenus,
7842
        clear,
7843
        isClear,
7844
        getTriggeringPath
7845
      };
7846
    };
7847
    const extractPreparedMenu = prep => prep.type === 'prepared' ? Optional.some(prep.menu) : Optional.none();
7848
    const LayeredState = {
1441 ariadna 7849
      init: init$b,
1 efrain 7850
      extractPreparedMenu
7851
    };
7852
 
7853
    const onMenuItemHighlightedEvent = generate$6('tiered-menu-item-highlight');
7854
    const onMenuItemDehighlightedEvent = generate$6('tiered-menu-item-dehighlight');
7855
 
7856
    var HighlightOnOpen;
7857
    (function (HighlightOnOpen) {
7858
      HighlightOnOpen[HighlightOnOpen['HighlightMenuAndItem'] = 0] = 'HighlightMenuAndItem';
7859
      HighlightOnOpen[HighlightOnOpen['HighlightJustMenu'] = 1] = 'HighlightJustMenu';
7860
      HighlightOnOpen[HighlightOnOpen['HighlightNone'] = 2] = 'HighlightNone';
7861
    }(HighlightOnOpen || (HighlightOnOpen = {})));
7862
 
7863
    const make$6 = (detail, _rawUiSpec) => {
1441 ariadna 7864
      const submenuParentItems = value$4();
1 efrain 7865
      const buildMenus = (container, primaryName, menus) => map$1(menus, (spec, name) => {
7866
        const makeSketch = () => Menu.sketch({
7867
          ...spec,
7868
          value: name,
7869
          markers: detail.markers,
7870
          fakeFocus: detail.fakeFocus,
7871
          onHighlight: (menuComp, itemComp) => {
7872
            const highlightData = {
7873
              menuComp,
7874
              itemComp
7875
            };
7876
            emitWith(menuComp, onMenuItemHighlightedEvent, highlightData);
7877
          },
7878
          onDehighlight: (menuComp, itemComp) => {
7879
            const dehighlightData = {
7880
              menuComp,
7881
              itemComp
7882
            };
7883
            emitWith(menuComp, onMenuItemDehighlightedEvent, dehighlightData);
7884
          },
7885
          focusManager: detail.fakeFocus ? highlights() : dom$2()
7886
        });
7887
        return name === primaryName ? {
7888
          type: 'prepared',
7889
          menu: container.getSystem().build(makeSketch())
7890
        } : {
7891
          type: 'notbuilt',
7892
          nbMenu: makeSketch
7893
        };
7894
      });
7895
      const layeredState = LayeredState.init();
7896
      const setup = container => {
7897
        const componentMap = buildMenus(container, detail.data.primary, detail.data.menus);
7898
        const directory = toDirectory();
7899
        layeredState.setContents(detail.data.primary, componentMap, detail.data.expansions, directory);
7900
        return layeredState.getPrimary();
7901
      };
7902
      const getItemValue = item => Representing.getValue(item).value;
7903
      const getItemByValue = (_container, menus, itemValue) => findMap(menus, menu => {
7904
        if (!menu.getSystem().isConnected()) {
7905
          return Optional.none();
7906
        }
7907
        const candidates = Highlighting.getCandidates(menu);
7908
        return find$5(candidates, c => getItemValue(c) === itemValue);
7909
      });
7910
      const toDirectory = _container => map$1(detail.data.menus, (data, _menuName) => bind$3(data.items, item => item.type === 'separator' ? [] : [item.data.value]));
7911
      const setActiveMenu = Highlighting.highlight;
7912
      const setActiveMenuAndItem = (container, menu) => {
7913
        setActiveMenu(container, menu);
7914
        Highlighting.getHighlighted(menu).orThunk(() => Highlighting.getFirst(menu)).each(item => {
7915
          if (detail.fakeFocus) {
7916
            Highlighting.highlight(menu, item);
7917
          } else {
7918
            dispatch(container, item.element, focusItem());
7919
          }
7920
        });
7921
      };
7922
      const getMenus = (state, menuValues) => cat(map$2(menuValues, mv => state.lookupMenu(mv).bind(prep => prep.type === 'prepared' ? Optional.some(prep.menu) : Optional.none())));
7923
      const closeOthers = (container, state, path) => {
7924
        const others = getMenus(state, state.otherMenus(path));
7925
        each$1(others, o => {
1441 ariadna 7926
          remove$2(o.element, [detail.markers.backgroundMenu]);
1 efrain 7927
          if (!detail.stayInDom) {
7928
            Replacing.remove(container, o);
7929
          }
7930
        });
7931
      };
7932
      const getSubmenuParents = container => submenuParentItems.get().getOrThunk(() => {
7933
        const r = {};
7934
        const items = descendants(container.element, `.${ detail.markers.item }`);
1441 ariadna 7935
        const parentItems = filter$2(items, i => get$g(i, 'aria-haspopup') === 'true');
1 efrain 7936
        each$1(parentItems, i => {
7937
          container.getSystem().getByDom(i).each(itemComp => {
7938
            const key = getItemValue(itemComp);
7939
            r[key] = itemComp;
7940
          });
7941
        });
7942
        submenuParentItems.set(r);
7943
        return r;
7944
      });
7945
      const updateAriaExpansions = (container, path) => {
7946
        const parentItems = getSubmenuParents(container);
7947
        each(parentItems, (v, k) => {
7948
          const expanded = contains$2(path, k);
7949
          set$9(v.element, 'aria-expanded', expanded);
7950
        });
7951
      };
7952
      const updateMenuPath = (container, state, path) => Optional.from(path[0]).bind(latestMenuName => state.lookupMenu(latestMenuName).bind(menuPrep => {
7953
        if (menuPrep.type === 'notbuilt') {
7954
          return Optional.none();
7955
        } else {
7956
          const activeMenu = menuPrep.menu;
7957
          const rest = getMenus(state, path.slice(1));
7958
          each$1(rest, r => {
7959
            add$2(r.element, detail.markers.backgroundMenu);
7960
          });
7961
          if (!inBody(activeMenu.element)) {
7962
            Replacing.append(container, premade(activeMenu));
7963
          }
1441 ariadna 7964
          remove$2(activeMenu.element, [detail.markers.backgroundMenu]);
1 efrain 7965
          setActiveMenuAndItem(container, activeMenu);
7966
          closeOthers(container, state, path);
7967
          return Optional.some(activeMenu);
7968
        }
7969
      }));
7970
      let ExpandHighlightDecision;
7971
      (function (ExpandHighlightDecision) {
7972
        ExpandHighlightDecision[ExpandHighlightDecision['HighlightSubmenu'] = 0] = 'HighlightSubmenu';
7973
        ExpandHighlightDecision[ExpandHighlightDecision['HighlightParent'] = 1] = 'HighlightParent';
7974
      }(ExpandHighlightDecision || (ExpandHighlightDecision = {})));
7975
      const buildIfRequired = (container, menuName, menuPrep) => {
7976
        if (menuPrep.type === 'notbuilt') {
7977
          const menu = container.getSystem().build(menuPrep.nbMenu());
7978
          layeredState.setMenuBuilt(menuName, menu);
7979
          return menu;
7980
        } else {
7981
          return menuPrep.menu;
7982
        }
7983
      };
7984
      const expandRight = (container, item, decision = ExpandHighlightDecision.HighlightSubmenu) => {
7985
        if (item.hasConfigured(Disabling) && Disabling.isDisabled(item)) {
7986
          return Optional.some(item);
7987
        } else {
7988
          const value = getItemValue(item);
7989
          return layeredState.expand(value).bind(path => {
7990
            updateAriaExpansions(container, path);
7991
            return Optional.from(path[0]).bind(menuName => layeredState.lookupMenu(menuName).bind(activeMenuPrep => {
7992
              const activeMenu = buildIfRequired(container, menuName, activeMenuPrep);
7993
              if (!inBody(activeMenu.element)) {
7994
                Replacing.append(container, premade(activeMenu));
7995
              }
7996
              detail.onOpenSubmenu(container, item, activeMenu, reverse(path));
7997
              if (decision === ExpandHighlightDecision.HighlightSubmenu) {
7998
                Highlighting.highlightFirst(activeMenu);
7999
                return updateMenuPath(container, layeredState, path);
8000
              } else {
8001
                Highlighting.dehighlightAll(activeMenu);
8002
                return Optional.some(item);
8003
              }
8004
            }));
8005
          });
8006
        }
8007
      };
8008
      const collapseLeft = (container, item) => {
8009
        const value = getItemValue(item);
8010
        return layeredState.collapse(value).bind(path => {
8011
          updateAriaExpansions(container, path);
8012
          return updateMenuPath(container, layeredState, path).map(activeMenu => {
8013
            detail.onCollapseMenu(container, item, activeMenu);
8014
            return activeMenu;
8015
          });
8016
        });
8017
      };
8018
      const updateView = (container, item) => {
8019
        const value = getItemValue(item);
8020
        return layeredState.refresh(value).bind(path => {
8021
          updateAriaExpansions(container, path);
8022
          return updateMenuPath(container, layeredState, path);
8023
        });
8024
      };
8025
      const onRight = (container, item) => inside(item.element) ? Optional.none() : expandRight(container, item, ExpandHighlightDecision.HighlightSubmenu);
8026
      const onLeft = (container, item) => inside(item.element) ? Optional.none() : collapseLeft(container, item);
8027
      const onEscape = (container, item) => collapseLeft(container, item).orThunk(() => detail.onEscape(container, item).map(() => container));
8028
      const keyOnItem = f => (container, simulatedEvent) => {
8029
        return closest$1(simulatedEvent.getSource(), `.${ detail.markers.item }`).bind(target => container.getSystem().getByDom(target).toOptional().bind(item => f(container, item).map(always)));
8030
      };
8031
      const events = derive$2([
8032
        run$1(focus(), (tmenu, simulatedEvent) => {
8033
          const item = simulatedEvent.event.item;
8034
          layeredState.lookupItem(getItemValue(item)).each(() => {
8035
            const menu = simulatedEvent.event.menu;
8036
            Highlighting.highlight(tmenu, menu);
8037
            const value = getItemValue(simulatedEvent.event.item);
8038
            layeredState.refresh(value).each(path => closeOthers(tmenu, layeredState, path));
8039
          });
8040
        }),
8041
        runOnExecute$1((component, simulatedEvent) => {
8042
          const target = simulatedEvent.event.target;
8043
          component.getSystem().getByDom(target).each(item => {
8044
            const itemValue = getItemValue(item);
8045
            if (itemValue.indexOf('collapse-item') === 0) {
8046
              collapseLeft(component, item);
8047
            }
8048
            expandRight(component, item, ExpandHighlightDecision.HighlightSubmenu).fold(() => {
8049
              detail.onExecute(component, item);
8050
            }, noop);
8051
          });
8052
        }),
8053
        runOnAttached((container, _simulatedEvent) => {
8054
          setup(container).each(primary => {
8055
            Replacing.append(container, premade(primary));
8056
            detail.onOpenMenu(container, primary);
8057
            if (detail.highlightOnOpen === HighlightOnOpen.HighlightMenuAndItem) {
8058
              setActiveMenuAndItem(container, primary);
8059
            } else if (detail.highlightOnOpen === HighlightOnOpen.HighlightJustMenu) {
8060
              setActiveMenu(container, primary);
8061
            }
8062
          });
8063
        }),
8064
        run$1(onMenuItemHighlightedEvent, (tmenuComp, se) => {
8065
          detail.onHighlightItem(tmenuComp, se.event.menuComp, se.event.itemComp);
8066
        }),
8067
        run$1(onMenuItemDehighlightedEvent, (tmenuComp, se) => {
8068
          detail.onDehighlightItem(tmenuComp, se.event.menuComp, se.event.itemComp);
8069
        }),
8070
        ...detail.navigateOnHover ? [run$1(hover(), (tmenu, simulatedEvent) => {
8071
            const item = simulatedEvent.event.item;
8072
            updateView(tmenu, item);
8073
            expandRight(tmenu, item, ExpandHighlightDecision.HighlightParent);
8074
            detail.onHover(tmenu, item);
8075
          })] : []
8076
      ]);
8077
      const getActiveItem = container => Highlighting.getHighlighted(container).bind(Highlighting.getHighlighted);
8078
      const collapseMenuApi = container => {
8079
        getActiveItem(container).each(currentItem => {
8080
          collapseLeft(container, currentItem);
8081
        });
8082
      };
8083
      const highlightPrimary = container => {
8084
        layeredState.getPrimary().each(primary => {
8085
          setActiveMenuAndItem(container, primary);
8086
        });
8087
      };
1441 ariadna 8088
      const extractMenuFromContainer = container => Optional.from(container.components()[0]).filter(comp => get$g(comp.element, 'role') === 'menu');
1 efrain 8089
      const repositionMenus = container => {
8090
        const maybeActivePrimary = layeredState.getPrimary().bind(primary => getActiveItem(container).bind(currentItem => {
8091
          const itemValue = getItemValue(currentItem);
8092
          const allMenus = values(layeredState.getMenus());
8093
          const preparedMenus = cat(map$2(allMenus, LayeredState.extractPreparedMenu));
8094
          return layeredState.getTriggeringPath(itemValue, v => getItemByValue(container, preparedMenus, v));
8095
        }).map(triggeringPath => ({
8096
          primary,
8097
          triggeringPath
8098
        })));
8099
        maybeActivePrimary.fold(() => {
8100
          extractMenuFromContainer(container).each(primaryMenu => {
8101
            detail.onRepositionMenu(container, primaryMenu, []);
8102
          });
8103
        }, ({primary, triggeringPath}) => {
8104
          detail.onRepositionMenu(container, primary, triggeringPath);
8105
        });
8106
      };
8107
      const apis = {
8108
        collapseMenu: collapseMenuApi,
8109
        highlightPrimary,
8110
        repositionMenus
8111
      };
8112
      return {
8113
        uid: detail.uid,
8114
        dom: detail.dom,
8115
        markers: detail.markers,
8116
        behaviours: augment(detail.tmenuBehaviours, [
8117
          Keying.config({
8118
            mode: 'special',
8119
            onRight: keyOnItem(onRight),
8120
            onLeft: keyOnItem(onLeft),
8121
            onEscape: keyOnItem(onEscape),
8122
            focusIn: (container, _keyInfo) => {
8123
              layeredState.getPrimary().each(primary => {
8124
                dispatch(container, primary.element, focusItem());
8125
              });
8126
            }
8127
          }),
8128
          Highlighting.config({
8129
            highlightClass: detail.markers.selectedMenu,
8130
            itemClass: detail.markers.menu
8131
          }),
8132
          Composing.config({
8133
            find: container => {
8134
              return Highlighting.getHighlighted(container);
8135
            }
8136
          }),
8137
          Replacing.config({})
8138
        ]),
8139
        eventOrder: detail.eventOrder,
8140
        apis,
8141
        events
8142
      };
8143
    };
8144
    const collapseItem$1 = constant$1('collapse-item');
8145
 
8146
    const tieredData = (primary, menus, expansions) => ({
8147
      primary,
8148
      menus,
8149
      expansions
8150
    });
8151
    const singleData = (name, menu) => ({
8152
      primary: name,
8153
      menus: wrap$1(name, menu),
8154
      expansions: {}
8155
    });
8156
    const collapseItem = text => ({
8157
      value: generate$6(collapseItem$1()),
8158
      meta: { text }
8159
    });
8160
    const tieredMenu = single({
8161
      name: 'TieredMenu',
8162
      configFields: [
8163
        onStrictKeyboardHandler('onExecute'),
8164
        onStrictKeyboardHandler('onEscape'),
8165
        onStrictHandler('onOpenMenu'),
8166
        onStrictHandler('onOpenSubmenu'),
8167
        onHandler('onRepositionMenu'),
8168
        onHandler('onCollapseMenu'),
8169
        defaulted('highlightOnOpen', HighlightOnOpen.HighlightMenuAndItem),
8170
        requiredObjOf('data', [
8171
          required$1('primary'),
8172
          required$1('menus'),
8173
          required$1('expansions')
8174
        ]),
8175
        defaulted('fakeFocus', false),
8176
        onHandler('onHighlightItem'),
8177
        onHandler('onDehighlightItem'),
8178
        onHandler('onHover'),
8179
        tieredMenuMarkers(),
8180
        required$1('dom'),
8181
        defaulted('navigateOnHover', true),
8182
        defaulted('stayInDom', false),
8183
        field('tmenuBehaviours', [
8184
          Keying,
8185
          Highlighting,
8186
          Composing,
8187
          Replacing
8188
        ]),
8189
        defaulted('eventOrder', {})
8190
      ],
8191
      apis: {
8192
        collapseMenu: (apis, tmenu) => {
8193
          apis.collapseMenu(tmenu);
8194
        },
8195
        highlightPrimary: (apis, tmenu) => {
8196
          apis.highlightPrimary(tmenu);
8197
        },
8198
        repositionMenus: (apis, tmenu) => {
8199
          apis.repositionMenus(tmenu);
8200
        }
8201
      },
8202
      factory: make$6,
8203
      extraApis: {
8204
        tieredData,
8205
        singleData,
8206
        collapseItem
8207
      }
8208
    });
8209
 
8210
    const makeMenu = (detail, menuSandbox, placementSpec, menuSpec, getBounds) => {
8211
      const lazySink = () => detail.lazySink(menuSandbox);
8212
      const layouts = menuSpec.type === 'horizontal' ? {
8213
        layouts: {
8214
          onLtr: () => belowOrAbove(),
8215
          onRtl: () => belowOrAboveRtl()
8216
        }
8217
      } : {};
8218
      const isFirstTierSubmenu = triggeringPaths => triggeringPaths.length === 2;
8219
      const getSubmenuLayouts = triggeringPaths => isFirstTierSubmenu(triggeringPaths) ? layouts : {};
8220
      return tieredMenu.sketch({
8221
        dom: { tag: 'div' },
8222
        data: menuSpec.data,
8223
        markers: menuSpec.menu.markers,
8224
        highlightOnOpen: menuSpec.menu.highlightOnOpen,
8225
        fakeFocus: menuSpec.menu.fakeFocus,
8226
        onEscape: () => {
8227
          Sandboxing.close(menuSandbox);
8228
          detail.onEscape.map(handler => handler(menuSandbox));
8229
          return Optional.some(true);
8230
        },
8231
        onExecute: () => {
8232
          return Optional.some(true);
8233
        },
8234
        onOpenMenu: (tmenu, menu) => {
8235
          Positioning.positionWithinBounds(lazySink().getOrDie(), menu, placementSpec, getBounds());
8236
        },
8237
        onOpenSubmenu: (tmenu, item, submenu, triggeringPaths) => {
8238
          const sink = lazySink().getOrDie();
8239
          Positioning.position(sink, submenu, {
8240
            anchor: {
8241
              type: 'submenu',
8242
              item,
8243
              ...getSubmenuLayouts(triggeringPaths)
8244
            }
8245
          });
8246
        },
8247
        onRepositionMenu: (tmenu, primaryMenu, submenuTriggers) => {
8248
          const sink = lazySink().getOrDie();
8249
          Positioning.positionWithinBounds(sink, primaryMenu, placementSpec, getBounds());
8250
          each$1(submenuTriggers, st => {
8251
            const submenuLayouts = getSubmenuLayouts(st.triggeringPath);
8252
            Positioning.position(sink, st.triggeredMenu, {
8253
              anchor: {
8254
                type: 'submenu',
8255
                item: st.triggeringItem,
8256
                ...submenuLayouts
8257
              }
8258
            });
8259
          });
8260
        }
8261
      });
8262
    };
8263
    const factory$o = (detail, spec) => {
8264
      const isPartOfRelated = (sandbox, queryElem) => {
8265
        const related = detail.getRelated(sandbox);
8266
        return related.exists(rel => isPartOf$1(rel, queryElem));
8267
      };
8268
      const setContent = (sandbox, thing) => {
8269
        Sandboxing.setContent(sandbox, thing);
8270
      };
8271
      const showAt = (sandbox, thing, placementSpec) => {
8272
        const getBounds = Optional.none;
8273
        showWithinBounds(sandbox, thing, placementSpec, getBounds);
8274
      };
8275
      const showWithinBounds = (sandbox, thing, placementSpec, getBounds) => {
8276
        const sink = detail.lazySink(sandbox).getOrDie();
8277
        Sandboxing.openWhileCloaked(sandbox, thing, () => Positioning.positionWithinBounds(sink, sandbox, placementSpec, getBounds()));
8278
        Representing.setValue(sandbox, Optional.some({
8279
          mode: 'position',
8280
          config: placementSpec,
8281
          getBounds
8282
        }));
8283
      };
8284
      const showMenuAt = (sandbox, placementSpec, menuSpec) => {
8285
        showMenuWithinBounds(sandbox, placementSpec, menuSpec, Optional.none);
8286
      };
8287
      const showMenuWithinBounds = (sandbox, placementSpec, menuSpec, getBounds) => {
8288
        const menu = makeMenu(detail, sandbox, placementSpec, menuSpec, getBounds);
8289
        Sandboxing.open(sandbox, menu);
8290
        Representing.setValue(sandbox, Optional.some({
8291
          mode: 'menu',
8292
          menu
8293
        }));
8294
      };
8295
      const hide = sandbox => {
8296
        if (Sandboxing.isOpen(sandbox)) {
8297
          Representing.setValue(sandbox, Optional.none());
8298
          Sandboxing.close(sandbox);
8299
        }
8300
      };
8301
      const getContent = sandbox => Sandboxing.getState(sandbox);
8302
      const reposition = sandbox => {
8303
        if (Sandboxing.isOpen(sandbox)) {
8304
          Representing.getValue(sandbox).each(state => {
8305
            switch (state.mode) {
8306
            case 'menu':
8307
              Sandboxing.getState(sandbox).each(tieredMenu.repositionMenus);
8308
              break;
8309
            case 'position':
8310
              const sink = detail.lazySink(sandbox).getOrDie();
8311
              Positioning.positionWithinBounds(sink, sandbox, state.config, state.getBounds());
8312
              break;
8313
            }
8314
          });
8315
        }
8316
      };
8317
      const apis = {
8318
        setContent,
8319
        showAt,
8320
        showWithinBounds,
8321
        showMenuAt,
8322
        showMenuWithinBounds,
8323
        hide,
8324
        getContent,
8325
        reposition,
8326
        isOpen: Sandboxing.isOpen
8327
      };
8328
      return {
8329
        uid: detail.uid,
8330
        dom: detail.dom,
8331
        behaviours: augment(detail.inlineBehaviours, [
8332
          Sandboxing.config({
8333
            isPartOf: (sandbox, data, queryElem) => {
8334
              return isPartOf$1(data, queryElem) || isPartOfRelated(sandbox, queryElem);
8335
            },
8336
            getAttachPoint: sandbox => {
8337
              return detail.lazySink(sandbox).getOrDie();
8338
            },
8339
            onOpen: sandbox => {
8340
              detail.onShow(sandbox);
8341
            },
8342
            onClose: sandbox => {
8343
              detail.onHide(sandbox);
8344
            }
8345
          }),
8346
          Representing.config({
8347
            store: {
8348
              mode: 'memory',
8349
              initialValue: Optional.none()
8350
            }
8351
          }),
8352
          Receiving.config({
8353
            channels: {
8354
              ...receivingChannel$1({
8355
                isExtraPart: spec.isExtraPart,
8356
                ...detail.fireDismissalEventInstead.map(fe => ({ fireEventInstead: { event: fe.event } })).getOr({})
8357
              }),
8358
              ...receivingChannel({
8359
                ...detail.fireRepositionEventInstead.map(fe => ({ fireEventInstead: { event: fe.event } })).getOr({}),
8360
                doReposition: reposition
8361
              })
8362
            }
8363
          })
8364
        ]),
8365
        eventOrder: detail.eventOrder,
8366
        apis
8367
      };
8368
    };
8369
    const InlineView = single({
8370
      name: 'InlineView',
8371
      configFields: [
8372
        required$1('lazySink'),
8373
        onHandler('onShow'),
8374
        onHandler('onHide'),
8375
        optionFunction('onEscape'),
8376
        field('inlineBehaviours', [
8377
          Sandboxing,
8378
          Representing,
8379
          Receiving
8380
        ]),
8381
        optionObjOf('fireDismissalEventInstead', [defaulted('event', dismissRequested())]),
8382
        optionObjOf('fireRepositionEventInstead', [defaulted('event', repositionRequested())]),
8383
        defaulted('getRelated', Optional.none),
8384
        defaulted('isExtraPart', never),
8385
        defaulted('eventOrder', Optional.none)
8386
      ],
8387
      factory: factory$o,
8388
      apis: {
8389
        showAt: (apis, component, anchor, thing) => {
8390
          apis.showAt(component, anchor, thing);
8391
        },
8392
        showWithinBounds: (apis, component, anchor, thing, bounds) => {
8393
          apis.showWithinBounds(component, anchor, thing, bounds);
8394
        },
8395
        showMenuAt: (apis, component, anchor, menuSpec) => {
8396
          apis.showMenuAt(component, anchor, menuSpec);
8397
        },
8398
        showMenuWithinBounds: (apis, component, anchor, menuSpec, bounds) => {
8399
          apis.showMenuWithinBounds(component, anchor, menuSpec, bounds);
8400
        },
8401
        hide: (apis, component) => {
8402
          apis.hide(component);
8403
        },
8404
        isOpen: (apis, component) => apis.isOpen(component),
8405
        getContent: (apis, component) => apis.getContent(component),
8406
        setContent: (apis, component, thing) => {
8407
          apis.setContent(component, thing);
8408
        },
8409
        reposition: (apis, component) => {
8410
          apis.reposition(component);
8411
        }
8412
      }
8413
    });
8414
 
8415
    var global$9 = tinymce.util.Tools.resolve('tinymce.util.Delay');
8416
 
1441 ariadna 8417
    var global$8 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
8418
 
8419
    var global$7 = tinymce.util.Tools.resolve('tinymce.EditorManager');
8420
 
8421
    var global$6 = tinymce.util.Tools.resolve('tinymce.Env');
8422
 
8423
    var ToolbarMode$1;
8424
    (function (ToolbarMode) {
8425
      ToolbarMode['default'] = 'wrap';
8426
      ToolbarMode['floating'] = 'floating';
8427
      ToolbarMode['sliding'] = 'sliding';
8428
      ToolbarMode['scrolling'] = 'scrolling';
8429
    }(ToolbarMode$1 || (ToolbarMode$1 = {})));
8430
    var ToolbarLocation$1;
8431
    (function (ToolbarLocation) {
8432
      ToolbarLocation['auto'] = 'auto';
8433
      ToolbarLocation['top'] = 'top';
8434
      ToolbarLocation['bottom'] = 'bottom';
8435
    }(ToolbarLocation$1 || (ToolbarLocation$1 = {})));
8436
    const option$2 = name => editor => editor.options.get(name);
8437
    const wrapOptional = fn => editor => Optional.from(fn(editor));
8438
    const register$f = editor => {
8439
      const isPhone = global$6.deviceType.isPhone();
8440
      const isMobile = global$6.deviceType.isTablet() || isPhone;
8441
      const registerOption = editor.options.register;
8442
      const stringOrFalseProcessor = value => isString(value) || value === false;
8443
      const stringOrNumberProcessor = value => isString(value) || isNumber(value);
8444
      registerOption('skin', {
8445
        processor: value => isString(value) || value === false,
8446
        default: 'oxide'
8447
      });
8448
      registerOption('skin_url', { processor: 'string' });
8449
      registerOption('height', {
8450
        processor: stringOrNumberProcessor,
8451
        default: Math.max(editor.getElement().offsetHeight, 400)
8452
      });
8453
      registerOption('width', {
8454
        processor: stringOrNumberProcessor,
8455
        default: global$8.DOM.getStyle(editor.getElement(), 'width')
8456
      });
8457
      registerOption('min_height', {
8458
        processor: 'number',
8459
        default: 100
8460
      });
8461
      registerOption('min_width', { processor: 'number' });
8462
      registerOption('max_height', { processor: 'number' });
8463
      registerOption('max_width', { processor: 'number' });
8464
      registerOption('style_formats', { processor: 'object[]' });
8465
      registerOption('style_formats_merge', {
8466
        processor: 'boolean',
8467
        default: false
8468
      });
8469
      registerOption('style_formats_autohide', {
8470
        processor: 'boolean',
8471
        default: false
8472
      });
8473
      registerOption('line_height_formats', {
8474
        processor: 'string',
8475
        default: '1 1.1 1.2 1.3 1.4 1.5 2'
8476
      });
8477
      registerOption('font_family_formats', {
8478
        processor: 'string',
8479
        default: 'Andale Mono=andale mono,monospace;' + 'Arial=arial,helvetica,sans-serif;' + 'Arial Black=arial black,sans-serif;' + 'Book Antiqua=book antiqua,palatino,serif;' + 'Comic Sans MS=comic sans ms,sans-serif;' + 'Courier New=courier new,courier,monospace;' + 'Georgia=georgia,palatino,serif;' + 'Helvetica=helvetica,arial,sans-serif;' + 'Impact=impact,sans-serif;' + 'Symbol=symbol;' + 'Tahoma=tahoma,arial,helvetica,sans-serif;' + 'Terminal=terminal,monaco,monospace;' + 'Times New Roman=times new roman,times,serif;' + 'Trebuchet MS=trebuchet ms,geneva,sans-serif;' + 'Verdana=verdana,geneva,sans-serif;' + 'Webdings=webdings;' + 'Wingdings=wingdings,zapf dingbats'
8480
      });
8481
      registerOption('font_size_formats', {
8482
        processor: 'string',
8483
        default: '8pt 10pt 12pt 14pt 18pt 24pt 36pt'
8484
      });
8485
      registerOption('font_size_input_default_unit', {
8486
        processor: 'string',
8487
        default: 'pt'
8488
      });
8489
      registerOption('block_formats', {
8490
        processor: 'string',
8491
        default: 'Paragraph=p;' + 'Heading 1=h1;' + 'Heading 2=h2;' + 'Heading 3=h3;' + 'Heading 4=h4;' + 'Heading 5=h5;' + 'Heading 6=h6;' + 'Preformatted=pre'
8492
      });
8493
      registerOption('content_langs', { processor: 'object[]' });
8494
      registerOption('removed_menuitems', {
8495
        processor: 'string',
8496
        default: ''
8497
      });
8498
      registerOption('menubar', {
8499
        processor: value => isString(value) || isBoolean(value),
8500
        default: !isPhone
8501
      });
8502
      registerOption('menu', {
8503
        processor: 'object',
8504
        default: {}
8505
      });
8506
      registerOption('toolbar', {
8507
        processor: value => {
8508
          if (isBoolean(value) || isString(value) || isArray(value)) {
8509
            return {
8510
              value,
8511
              valid: true
8512
            };
8513
          } else {
8514
            return {
8515
              valid: false,
8516
              message: 'Must be a boolean, string or array.'
8517
            };
8518
          }
8519
        },
8520
        default: true
8521
      });
8522
      range$2(9, num => {
8523
        registerOption('toolbar' + (num + 1), { processor: 'string' });
8524
      });
8525
      registerOption('toolbar_mode', {
8526
        processor: 'string',
8527
        default: isMobile ? 'scrolling' : 'floating'
8528
      });
8529
      registerOption('toolbar_groups', {
8530
        processor: 'object',
8531
        default: {}
8532
      });
8533
      registerOption('toolbar_location', {
8534
        processor: 'string',
8535
        default: ToolbarLocation$1.auto
8536
      });
8537
      registerOption('toolbar_persist', {
8538
        processor: 'boolean',
8539
        default: false
8540
      });
8541
      registerOption('toolbar_sticky', {
8542
        processor: 'boolean',
8543
        default: editor.inline
8544
      });
8545
      registerOption('toolbar_sticky_offset', {
8546
        processor: 'number',
8547
        default: 0
8548
      });
8549
      registerOption('fixed_toolbar_container', {
8550
        processor: 'string',
8551
        default: ''
8552
      });
8553
      registerOption('fixed_toolbar_container_target', { processor: 'object' });
8554
      registerOption('ui_mode', {
8555
        processor: 'string',
8556
        default: 'combined'
8557
      });
8558
      registerOption('file_picker_callback', { processor: 'function' });
8559
      registerOption('file_picker_validator_handler', { processor: 'function' });
8560
      registerOption('file_picker_types', { processor: 'string' });
8561
      registerOption('typeahead_urls', {
8562
        processor: 'boolean',
8563
        default: true
8564
      });
8565
      registerOption('anchor_top', {
8566
        processor: stringOrFalseProcessor,
8567
        default: '#top'
8568
      });
8569
      registerOption('anchor_bottom', {
8570
        processor: stringOrFalseProcessor,
8571
        default: '#bottom'
8572
      });
8573
      registerOption('draggable_modal', {
8574
        processor: 'boolean',
8575
        default: false
8576
      });
8577
      registerOption('statusbar', {
8578
        processor: 'boolean',
8579
        default: true
8580
      });
8581
      registerOption('elementpath', {
8582
        processor: 'boolean',
8583
        default: true
8584
      });
8585
      registerOption('branding', {
8586
        processor: 'boolean',
8587
        default: true
8588
      });
8589
      registerOption('promotion', {
8590
        processor: 'boolean',
8591
        default: true
8592
      });
8593
      registerOption('resize', {
8594
        processor: value => value === 'both' || isBoolean(value),
8595
        default: !global$6.deviceType.isTouch()
8596
      });
8597
      registerOption('sidebar_show', { processor: 'string' });
8598
      registerOption('help_accessibility', {
8599
        processor: 'boolean',
8600
        default: editor.hasPlugin('help')
8601
      });
8602
      registerOption('default_font_stack', {
8603
        processor: 'string[]',
8604
        default: []
8605
      });
8606
    };
8607
    const isReadOnly = option$2('readonly');
8608
    const isDisabled = option$2('disabled');
8609
    const getHeightOption = option$2('height');
8610
    const getWidthOption = option$2('width');
8611
    const getMinWidthOption = wrapOptional(option$2('min_width'));
8612
    const getMinHeightOption = wrapOptional(option$2('min_height'));
8613
    const getMaxWidthOption = wrapOptional(option$2('max_width'));
8614
    const getMaxHeightOption = wrapOptional(option$2('max_height'));
8615
    const getUserStyleFormats = wrapOptional(option$2('style_formats'));
8616
    const shouldMergeStyleFormats = option$2('style_formats_merge');
8617
    const shouldAutoHideStyleFormats = option$2('style_formats_autohide');
8618
    const getContentLanguages = option$2('content_langs');
8619
    const getRemovedMenuItems = option$2('removed_menuitems');
8620
    const getToolbarMode = option$2('toolbar_mode');
8621
    const getToolbarGroups = option$2('toolbar_groups');
8622
    const getToolbarLocation = option$2('toolbar_location');
8623
    const fixedContainerSelector = option$2('fixed_toolbar_container');
8624
    const fixedToolbarContainerTarget = option$2('fixed_toolbar_container_target');
8625
    const isToolbarPersist = option$2('toolbar_persist');
8626
    const getStickyToolbarOffset = option$2('toolbar_sticky_offset');
8627
    const getMenubar = option$2('menubar');
8628
    const getToolbar = option$2('toolbar');
8629
    const getFilePickerCallback = option$2('file_picker_callback');
8630
    const getFilePickerValidatorHandler = option$2('file_picker_validator_handler');
8631
    const getFontSizeInputDefaultUnit = option$2('font_size_input_default_unit');
8632
    const getFilePickerTypes = option$2('file_picker_types');
8633
    const useTypeaheadUrls = option$2('typeahead_urls');
8634
    const getAnchorTop = option$2('anchor_top');
8635
    const getAnchorBottom = option$2('anchor_bottom');
8636
    const isDraggableModal$1 = option$2('draggable_modal');
8637
    const useStatusBar = option$2('statusbar');
8638
    const useElementPath = option$2('elementpath');
8639
    const useBranding = option$2('branding');
8640
    const getResize = option$2('resize');
8641
    const getPasteAsText = option$2('paste_as_text');
8642
    const getSidebarShow = option$2('sidebar_show');
8643
    const promotionEnabled = option$2('promotion');
8644
    const useHelpAccessibility = option$2('help_accessibility');
8645
    const getDefaultFontStack = option$2('default_font_stack');
8646
    const getSkin = option$2('skin');
8647
    const isSkinDisabled = editor => editor.options.get('skin') === false;
8648
    const isMenubarEnabled = editor => editor.options.get('menubar') !== false;
8649
    const getSkinUrl = editor => {
8650
      const skinUrl = editor.options.get('skin_url');
8651
      if (isSkinDisabled(editor)) {
8652
        return skinUrl;
8653
      } else {
8654
        if (skinUrl) {
8655
          return editor.documentBaseURI.toAbsolute(skinUrl);
8656
        } else {
8657
          const skin = editor.options.get('skin');
8658
          return global$7.baseURL + '/skins/ui/' + skin;
8659
        }
8660
      }
8661
    };
8662
    const getSkinUrlOption = editor => Optional.from(editor.options.get('skin_url'));
8663
    const getLineHeightFormats = editor => editor.options.get('line_height_formats').split(' ');
8664
    const isToolbarEnabled = editor => {
8665
      const toolbar = getToolbar(editor);
8666
      const isToolbarString = isString(toolbar);
8667
      const isToolbarObjectArray = isArray(toolbar) && toolbar.length > 0;
8668
      return !isMultipleToolbars(editor) && (isToolbarObjectArray || isToolbarString || toolbar === true);
8669
    };
8670
    const getMultipleToolbarsOption = editor => {
8671
      const toolbars = range$2(9, num => editor.options.get('toolbar' + (num + 1)));
8672
      const toolbarArray = filter$2(toolbars, isString);
8673
      return someIf(toolbarArray.length > 0, toolbarArray);
8674
    };
8675
    const isMultipleToolbars = editor => getMultipleToolbarsOption(editor).fold(() => {
8676
      const toolbar = getToolbar(editor);
8677
      return isArrayOf(toolbar, isString) && toolbar.length > 0;
8678
    }, always);
8679
    const isToolbarLocationBottom = editor => getToolbarLocation(editor) === ToolbarLocation$1.bottom;
8680
    const fixedContainerTarget = editor => {
8681
      var _a;
8682
      if (!editor.inline) {
8683
        return Optional.none();
8684
      }
8685
      const selector = (_a = fixedContainerSelector(editor)) !== null && _a !== void 0 ? _a : '';
8686
      if (selector.length > 0) {
8687
        return descendant(body(), selector);
8688
      }
8689
      const element = fixedToolbarContainerTarget(editor);
8690
      if (isNonNullable(element)) {
8691
        return Optional.some(SugarElement.fromDom(element));
8692
      }
8693
      return Optional.none();
8694
    };
8695
    const useFixedContainer = editor => editor.inline && fixedContainerTarget(editor).isSome();
8696
    const getUiContainer = editor => {
8697
      const fixedContainer = fixedContainerTarget(editor);
8698
      return fixedContainer.getOrThunk(() => getContentContainer(getRootNode(SugarElement.fromDom(editor.getElement()))));
8699
    };
8700
    const isDistractionFree = editor => editor.inline && !isMenubarEnabled(editor) && !isToolbarEnabled(editor) && !isMultipleToolbars(editor);
8701
    const isStickyToolbar = editor => {
8702
      const isStickyToolbar = editor.options.get('toolbar_sticky');
8703
      return (isStickyToolbar || editor.inline) && !useFixedContainer(editor) && !isDistractionFree(editor);
8704
    };
8705
    const isSplitUiMode = editor => !useFixedContainer(editor) && editor.options.get('ui_mode') === 'split';
8706
    const getMenus = editor => {
8707
      const menu = editor.options.get('menu');
8708
      return map$1(menu, menu => ({
8709
        ...menu,
8710
        items: menu.items
8711
      }));
8712
    };
8713
 
8714
    var Options = /*#__PURE__*/Object.freeze({
8715
        __proto__: null,
8716
        get ToolbarMode () { return ToolbarMode$1; },
8717
        get ToolbarLocation () { return ToolbarLocation$1; },
8718
        register: register$f,
8719
        getSkinUrl: getSkinUrl,
8720
        getSkinUrlOption: getSkinUrlOption,
8721
        isReadOnly: isReadOnly,
8722
        isDisabled: isDisabled,
8723
        getSkin: getSkin,
8724
        isSkinDisabled: isSkinDisabled,
8725
        getHeightOption: getHeightOption,
8726
        getWidthOption: getWidthOption,
8727
        getMinWidthOption: getMinWidthOption,
8728
        getMinHeightOption: getMinHeightOption,
8729
        getMaxWidthOption: getMaxWidthOption,
8730
        getMaxHeightOption: getMaxHeightOption,
8731
        getUserStyleFormats: getUserStyleFormats,
8732
        shouldMergeStyleFormats: shouldMergeStyleFormats,
8733
        shouldAutoHideStyleFormats: shouldAutoHideStyleFormats,
8734
        getLineHeightFormats: getLineHeightFormats,
8735
        getContentLanguages: getContentLanguages,
8736
        getRemovedMenuItems: getRemovedMenuItems,
8737
        isMenubarEnabled: isMenubarEnabled,
8738
        isMultipleToolbars: isMultipleToolbars,
8739
        isToolbarEnabled: isToolbarEnabled,
8740
        isToolbarPersist: isToolbarPersist,
8741
        getMultipleToolbarsOption: getMultipleToolbarsOption,
8742
        getUiContainer: getUiContainer,
8743
        useFixedContainer: useFixedContainer,
8744
        isSplitUiMode: isSplitUiMode,
8745
        getToolbarMode: getToolbarMode,
8746
        isDraggableModal: isDraggableModal$1,
8747
        isDistractionFree: isDistractionFree,
8748
        isStickyToolbar: isStickyToolbar,
8749
        getStickyToolbarOffset: getStickyToolbarOffset,
8750
        getToolbarLocation: getToolbarLocation,
8751
        isToolbarLocationBottom: isToolbarLocationBottom,
8752
        getToolbarGroups: getToolbarGroups,
8753
        getMenus: getMenus,
8754
        getMenubar: getMenubar,
8755
        getToolbar: getToolbar,
8756
        getFilePickerCallback: getFilePickerCallback,
8757
        getFilePickerTypes: getFilePickerTypes,
8758
        useTypeaheadUrls: useTypeaheadUrls,
8759
        getAnchorTop: getAnchorTop,
8760
        getAnchorBottom: getAnchorBottom,
8761
        getFilePickerValidatorHandler: getFilePickerValidatorHandler,
8762
        getFontSizeInputDefaultUnit: getFontSizeInputDefaultUnit,
8763
        useStatusBar: useStatusBar,
8764
        useElementPath: useElementPath,
8765
        promotionEnabled: promotionEnabled,
8766
        useBranding: useBranding,
8767
        getResize: getResize,
8768
        getPasteAsText: getPasteAsText,
8769
        getSidebarShow: getSidebarShow,
8770
        useHelpAccessibility: useHelpAccessibility,
8771
        getDefaultFontStack: getDefaultFontStack
8772
    });
8773
 
8774
    const nonScrollingOverflows = [
8775
      'visible',
8776
      'hidden',
8777
      'clip'
8778
    ];
8779
    const isScrollingOverflowValue = value => trim$1(value).length > 0 && !contains$2(nonScrollingOverflows, value);
8780
    const isScroller = elem => {
8781
      if (isHTMLElement(elem)) {
8782
        const overflowX = get$f(elem, 'overflow-x');
8783
        const overflowY = get$f(elem, 'overflow-y');
8784
        return isScrollingOverflowValue(overflowX) || isScrollingOverflowValue(overflowY);
8785
      } else {
8786
        return false;
8787
      }
8788
    };
8789
    const isFullscreen = editor => editor.plugins.fullscreen && editor.plugins.fullscreen.isFullscreen();
8790
    const detect = (editor, popupSinkElem) => {
8791
      const ancestorsScrollers = ancestors(popupSinkElem, isScroller);
8792
      const scrollers = ancestorsScrollers.length === 0 ? getShadowRoot(popupSinkElem).map(getShadowHost).map(x => ancestors(x, isScroller)).getOr([]) : ancestorsScrollers;
8793
      return head(scrollers).map(element => ({
8794
        element,
8795
        others: scrollers.slice(1),
8796
        isFullscreen: () => isFullscreen(editor)
8797
      }));
8798
    };
8799
    const detectWhenSplitUiMode = (editor, popupSinkElem) => isSplitUiMode(editor) ? detect(editor, popupSinkElem) : Optional.none();
8800
    const getBoundsFrom = sc => {
8801
      const scrollableBoxes = [
8802
        ...map$2(sc.others, box$1),
8803
        win()
8804
      ];
8805
      return sc.isFullscreen() ? win() : constrainByMany(box$1(sc.element), scrollableBoxes);
8806
    };
8807
 
1 efrain 8808
    const factory$n = detail => {
1441 ariadna 8809
      const events = events$9(detail.action);
1 efrain 8810
      const tag = detail.dom.tag;
1441 ariadna 8811
      const lookupAttr = attr => get$h(detail.dom, 'attributes').bind(attrs => get$h(attrs, attr));
1 efrain 8812
      const getModAttributes = () => {
8813
        if (tag === 'button') {
8814
          const type = lookupAttr('type').getOr('button');
8815
          const roleAttrs = lookupAttr('role').map(role => ({ role })).getOr({});
8816
          return {
8817
            type,
8818
            ...roleAttrs
8819
          };
8820
        } else {
8821
          const role = detail.role.getOr(lookupAttr('role').getOr('button'));
8822
          return { role };
8823
        }
8824
      };
8825
      return {
8826
        uid: detail.uid,
8827
        dom: detail.dom,
8828
        components: detail.components,
8829
        events,
8830
        behaviours: SketchBehaviours.augment(detail.buttonBehaviours, [
8831
          Focusing.config({}),
8832
          Keying.config({
8833
            mode: 'execution',
8834
            useSpace: true,
8835
            useEnter: true
8836
          })
8837
        ]),
8838
        domModification: { attributes: getModAttributes() },
8839
        eventOrder: detail.eventOrder
8840
      };
8841
    };
8842
    const Button = single({
8843
      name: 'Button',
8844
      factory: factory$n,
8845
      configFields: [
8846
        defaulted('uid', undefined),
8847
        required$1('dom'),
8848
        defaulted('components', []),
8849
        SketchBehaviours.field('buttonBehaviours', [
8850
          Focusing,
8851
          Keying
8852
        ]),
8853
        option$3('action'),
8854
        option$3('role'),
8855
        defaulted('eventOrder', {})
8856
      ]
8857
    });
8858
 
8859
    const getAttrs = elem => {
8860
      const attributes = elem.dom.attributes !== undefined ? elem.dom.attributes : [];
8861
      return foldl(attributes, (b, attr) => {
8862
        if (attr.name === 'class') {
8863
          return b;
8864
        } else {
8865
          return {
8866
            ...b,
8867
            [attr.name]: attr.value
8868
          };
8869
        }
8870
      }, {});
8871
    };
8872
    const getClasses = elem => Array.prototype.slice.call(elem.dom.classList, 0);
8873
    const fromHtml = html => {
8874
      const elem = SugarElement.fromHtml(html);
8875
      const children$1 = children(elem);
8876
      const attrs = getAttrs(elem);
8877
      const classes = getClasses(elem);
1441 ariadna 8878
      const contents = children$1.length === 0 ? {} : { innerHtml: get$8(elem) };
1 efrain 8879
      return {
8880
        tag: name$3(elem),
8881
        classes,
8882
        attributes: attrs,
8883
        ...contents
8884
      };
8885
    };
8886
 
8887
    const record = spec => {
8888
      const uid = isSketchSpec(spec) && hasNonNullableKey(spec, 'uid') ? spec.uid : generate$5('memento');
8889
      const get = anyInSystem => anyInSystem.getSystem().getByUid(uid).getOrDie();
8890
      const getOpt = anyInSystem => anyInSystem.getSystem().getByUid(uid).toOptional();
8891
      const asSpec = () => ({
8892
        ...spec,
8893
        uid
8894
      });
8895
      return {
8896
        get,
8897
        getOpt,
8898
        asSpec
8899
      };
8900
    };
8901
 
1441 ariadna 8902
    const exhibit$2 = (base, tabConfig) => nu$8({
8903
      attributes: wrapAll([{
8904
          key: tabConfig.tabAttr,
8905
          value: 'true'
8906
        }])
8907
    });
8908
 
8909
    var ActiveTabstopping = /*#__PURE__*/Object.freeze({
8910
        __proto__: null,
8911
        exhibit: exhibit$2
8912
    });
8913
 
8914
    var TabstopSchema = [defaulted('tabAttr', 'data-alloy-tabstop')];
8915
 
8916
    const Tabstopping = create$4({
8917
      fields: TabstopSchema,
8918
      name: 'tabstopping',
8919
      active: ActiveTabstopping
8920
    });
8921
 
8922
    const ExclusivityChannel = generate$6('tooltip.exclusive');
8923
    const ShowTooltipEvent = generate$6('tooltip.show');
8924
    const HideTooltipEvent = generate$6('tooltip.hide');
8925
    const ImmediateHideTooltipEvent = generate$6('tooltip.immediateHide');
8926
    const ImmediateShowTooltipEvent = generate$6('tooltip.immediateShow');
8927
 
8928
    const hideAllExclusive = (component, _tConfig, _tState) => {
8929
      component.getSystem().broadcastOn([ExclusivityChannel], {});
8930
    };
8931
    const setComponents = (_component, _tConfig, tState, specs) => {
8932
      tState.getTooltip().each(tooltip => {
8933
        if (tooltip.getSystem().isConnected()) {
8934
          Replacing.set(tooltip, specs);
8935
        }
8936
      });
8937
    };
8938
    const isEnabled = (_component, _tConfig, tState) => tState.isEnabled();
8939
    const setEnabled = (_component, _tConfig, tState, enabled) => tState.setEnabled(enabled);
8940
    const immediateOpenClose = (component, _tConfig, _tState, open) => emit(component, open ? ImmediateShowTooltipEvent : ImmediateHideTooltipEvent);
8941
 
8942
    var TooltippingApis = /*#__PURE__*/Object.freeze({
8943
        __proto__: null,
8944
        hideAllExclusive: hideAllExclusive,
8945
        immediateOpenClose: immediateOpenClose,
8946
        isEnabled: isEnabled,
8947
        setComponents: setComponents,
8948
        setEnabled: setEnabled
8949
    });
8950
 
8951
    const events$8 = (tooltipConfig, state) => {
8952
      const hide = comp => {
8953
        state.getTooltip().each(p => {
8954
          if (p.getSystem().isConnected()) {
8955
            detach(p);
8956
            tooltipConfig.onHide(comp, p);
8957
            state.clearTooltip();
8958
          }
8959
        });
8960
        state.clearTimer();
1 efrain 8961
      };
1441 ariadna 8962
      const show = comp => {
8963
        if (!state.isShowing() && state.isEnabled()) {
8964
          hideAllExclusive(comp);
8965
          const sink = tooltipConfig.lazySink(comp).getOrDie();
8966
          const popup = comp.getSystem().build({
8967
            dom: tooltipConfig.tooltipDom,
8968
            components: tooltipConfig.tooltipComponents,
8969
            events: derive$2(tooltipConfig.mode === 'normal' ? [
8970
              run$1(mouseover(), _ => {
8971
                emit(comp, ShowTooltipEvent);
8972
              }),
8973
              run$1(mouseout(), _ => {
8974
                emit(comp, HideTooltipEvent);
8975
              })
8976
            ] : []),
8977
            behaviours: derive$1([Replacing.config({})])
8978
          });
8979
          state.setTooltip(popup);
8980
          attach(sink, popup);
8981
          tooltipConfig.onShow(comp, popup);
8982
          Positioning.position(sink, popup, { anchor: tooltipConfig.anchor(comp) });
8983
        }
8984
      };
8985
      const reposition = comp => {
8986
        state.getTooltip().each(tooltip => {
8987
          const sink = tooltipConfig.lazySink(comp).getOrDie();
8988
          Positioning.position(sink, tooltip, { anchor: tooltipConfig.anchor(comp) });
8989
        });
8990
      };
8991
      const getEvents = () => {
8992
        switch (tooltipConfig.mode) {
8993
        case 'normal':
8994
          return [
8995
            run$1(focusin(), comp => {
8996
              emit(comp, ImmediateShowTooltipEvent);
8997
            }),
8998
            run$1(postBlur(), comp => {
8999
              emit(comp, ImmediateHideTooltipEvent);
9000
            }),
9001
            run$1(mouseover(), comp => {
9002
              emit(comp, ShowTooltipEvent);
9003
            }),
9004
            run$1(mouseout(), comp => {
9005
              emit(comp, HideTooltipEvent);
9006
            })
9007
          ];
9008
        case 'follow-highlight':
9009
          return [
9010
            run$1(highlight$1(), (comp, _se) => {
9011
              emit(comp, ShowTooltipEvent);
9012
            }),
9013
            run$1(dehighlight$1(), comp => {
9014
              emit(comp, HideTooltipEvent);
9015
            })
9016
          ];
9017
        case 'children-normal':
9018
          return [
9019
            run$1(focusin(), (comp, se) => {
9020
              search(comp.element).each(_ => {
9021
                if (is(se.event.target, '[data-mce-tooltip]')) {
9022
                  state.getTooltip().fold(() => {
9023
                    emit(comp, ImmediateShowTooltipEvent);
9024
                  }, tooltip => {
9025
                    if (state.isShowing()) {
9026
                      tooltipConfig.onShow(comp, tooltip);
9027
                      reposition(comp);
9028
                    }
9029
                  });
9030
                }
9031
              });
9032
            }),
9033
            run$1(postBlur(), comp => {
9034
              search(comp.element).fold(() => {
9035
                emit(comp, ImmediateHideTooltipEvent);
9036
              }, noop);
9037
            }),
9038
            run$1(mouseover(), comp => {
9039
              descendant(comp.element, '[data-mce-tooltip]:hover').each(_ => {
9040
                state.getTooltip().fold(() => {
9041
                  emit(comp, ShowTooltipEvent);
9042
                }, tooltip => {
9043
                  if (state.isShowing()) {
9044
                    tooltipConfig.onShow(comp, tooltip);
9045
                    reposition(comp);
9046
                  }
9047
                });
9048
              });
9049
            }),
9050
            run$1(mouseout(), comp => {
9051
              descendant(comp.element, '[data-mce-tooltip]:hover').fold(() => {
9052
                emit(comp, HideTooltipEvent);
9053
              }, noop);
9054
            })
9055
          ];
9056
        default:
9057
          return [
9058
            run$1(focusin(), (comp, se) => {
9059
              search(comp.element).each(_ => {
9060
                if (is(se.event.target, '[data-mce-tooltip]')) {
9061
                  state.getTooltip().fold(() => {
9062
                    emit(comp, ImmediateShowTooltipEvent);
9063
                  }, tooltip => {
9064
                    if (state.isShowing()) {
9065
                      tooltipConfig.onShow(comp, tooltip);
9066
                      reposition(comp);
9067
                    }
9068
                  });
9069
                }
9070
              });
9071
            }),
9072
            run$1(postBlur(), comp => {
9073
              search(comp.element).fold(() => {
9074
                emit(comp, ImmediateHideTooltipEvent);
9075
              }, noop);
9076
            })
9077
          ];
9078
        }
9079
      };
9080
      return derive$2(flatten([
9081
        [
9082
          runOnInit(component => {
9083
            tooltipConfig.onSetup(component);
9084
          }),
9085
          run$1(ShowTooltipEvent, comp => {
9086
            state.resetTimer(() => {
9087
              show(comp);
9088
            }, tooltipConfig.delayForShow());
9089
          }),
9090
          run$1(HideTooltipEvent, comp => {
9091
            state.resetTimer(() => {
9092
              hide(comp);
9093
            }, tooltipConfig.delayForHide());
9094
          }),
9095
          run$1(ImmediateShowTooltipEvent, comp => {
9096
            state.resetTimer(() => {
9097
              show(comp);
9098
            }, 0);
9099
          }),
9100
          run$1(ImmediateHideTooltipEvent, comp => {
9101
            state.resetTimer(() => {
9102
              hide(comp);
9103
            }, 0);
9104
          }),
9105
          run$1(receive(), (comp, message) => {
9106
            const receivingData = message;
9107
            if (!receivingData.universal) {
9108
              if (contains$2(receivingData.channels, ExclusivityChannel)) {
9109
                hide(comp);
9110
              }
9111
            }
9112
          }),
9113
          runOnDetached(comp => {
9114
            hide(comp);
9115
          })
9116
        ],
9117
        getEvents()
9118
      ]));
9119
    };
9120
 
9121
    var ActiveTooltipping = /*#__PURE__*/Object.freeze({
9122
        __proto__: null,
9123
        events: events$8
9124
    });
9125
 
9126
    var TooltippingSchema = [
9127
      required$1('lazySink'),
9128
      required$1('tooltipDom'),
9129
      defaulted('exclusive', true),
9130
      defaulted('tooltipComponents', []),
9131
      defaultedFunction('delayForShow', constant$1(300)),
9132
      defaultedFunction('delayForHide', constant$1(100)),
9133
      defaultedFunction('onSetup', noop),
9134
      defaultedStringEnum('mode', 'normal', [
9135
        'normal',
9136
        'follow-highlight',
9137
        'children-keyboard-focus',
9138
        'children-normal'
9139
      ]),
9140
      defaulted('anchor', comp => ({
9141
        type: 'hotspot',
9142
        hotspot: comp,
9143
        layouts: {
9144
          onLtr: constant$1([
9145
            south$2,
9146
            north$2,
9147
            southeast$2,
9148
            northeast$2,
9149
            southwest$2,
9150
            northwest$2
9151
          ]),
9152
          onRtl: constant$1([
9153
            south$2,
9154
            north$2,
9155
            southeast$2,
9156
            northeast$2,
9157
            southwest$2,
9158
            northwest$2
9159
          ])
9160
        },
9161
        bubble: nu$5(0, -2, {})
9162
      })),
9163
      onHandler('onHide'),
9164
      onHandler('onShow')
9165
    ];
9166
 
9167
    const init$a = () => {
9168
      const enabled = Cell(true);
9169
      const timer = value$4();
9170
      const popup = value$4();
9171
      const clearTimer = () => {
9172
        timer.on(clearTimeout);
9173
      };
9174
      const resetTimer = (f, delay) => {
9175
        clearTimer();
9176
        timer.set(setTimeout(f, delay));
9177
      };
9178
      const readState = constant$1('not-implemented');
9179
      return nu$7({
9180
        getTooltip: popup.get,
9181
        isShowing: popup.isSet,
9182
        setTooltip: popup.set,
9183
        clearTooltip: popup.clear,
9184
        clearTimer,
9185
        resetTimer,
9186
        readState,
9187
        isEnabled: () => enabled.get(),
9188
        setEnabled: setToEnabled => enabled.set(setToEnabled)
9189
      });
9190
    };
9191
 
9192
    var TooltippingState = /*#__PURE__*/Object.freeze({
9193
        __proto__: null,
9194
        init: init$a
9195
    });
9196
 
9197
    const Tooltipping = create$4({
9198
      fields: TooltippingSchema,
9199
      name: 'tooltipping',
9200
      active: ActiveTooltipping,
9201
      state: TooltippingState,
9202
      apis: TooltippingApis
9203
    });
9204
 
9205
    /*! @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 */
9206
 
9207
    const {
9208
      entries,
9209
      setPrototypeOf,
9210
      isFrozen,
9211
      getPrototypeOf,
9212
      getOwnPropertyDescriptor
9213
    } = Object;
9214
    let {
9215
      freeze,
9216
      seal,
9217
      create: create$1
9218
    } = Object; // eslint-disable-line import/no-mutable-exports
9219
    let {
9220
      apply,
9221
      construct
9222
    } = typeof Reflect !== 'undefined' && Reflect;
1 efrain 9223
    if (!freeze) {
9224
      freeze = function freeze(x) {
9225
        return x;
9226
      };
9227
    }
9228
    if (!seal) {
9229
      seal = function seal(x) {
9230
        return x;
9231
      };
9232
    }
1441 ariadna 9233
    if (!apply) {
9234
      apply = function apply(fun, thisValue, args) {
9235
        return fun.apply(thisValue, args);
9236
      };
9237
    }
1 efrain 9238
    if (!construct) {
9239
      construct = function construct(Func, args) {
9240
        return new Func(...args);
9241
      };
9242
    }
9243
    const arrayForEach = unapply(Array.prototype.forEach);
1441 ariadna 9244
    const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
1 efrain 9245
    const arrayPop = unapply(Array.prototype.pop);
9246
    const arrayPush = unapply(Array.prototype.push);
1441 ariadna 9247
    const arraySplice = unapply(Array.prototype.splice);
1 efrain 9248
    const stringToLowerCase = unapply(String.prototype.toLowerCase);
9249
    const stringToString = unapply(String.prototype.toString);
9250
    const stringMatch = unapply(String.prototype.match);
9251
    const stringReplace = unapply(String.prototype.replace);
9252
    const stringIndexOf = unapply(String.prototype.indexOf);
9253
    const stringTrim = unapply(String.prototype.trim);
1441 ariadna 9254
    const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
1 efrain 9255
    const regExpTest = unapply(RegExp.prototype.test);
9256
    const typeErrorCreate = unconstruct(TypeError);
1441 ariadna 9257
    /**
9258
     * Creates a new function that calls the given function with a specified thisArg and arguments.
9259
     *
9260
     * @param func - The function to be wrapped and called.
9261
     * @returns A new function that calls the given function with a specified thisArg and arguments.
9262
     */
1 efrain 9263
    function unapply(func) {
9264
      return function (thisArg) {
9265
        for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
9266
          args[_key - 1] = arguments[_key];
9267
        }
9268
        return apply(func, thisArg, args);
9269
      };
9270
    }
1441 ariadna 9271
    /**
9272
     * Creates a new function that constructs an instance of the given constructor function with the provided arguments.
9273
     *
9274
     * @param func - The constructor function to be wrapped and called.
9275
     * @returns A new function that constructs an instance of the given constructor function with the provided arguments.
9276
     */
1 efrain 9277
    function unconstruct(func) {
9278
      return function () {
9279
        for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
9280
          args[_key2] = arguments[_key2];
9281
        }
9282
        return construct(func, args);
9283
      };
9284
    }
1441 ariadna 9285
    /**
9286
     * Add properties to a lookup table
9287
     *
9288
     * @param set - The set to which elements will be added.
9289
     * @param array - The array containing elements to be added to the set.
9290
     * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
9291
     * @returns The modified set with added elements.
9292
     */
9293
    function addToSet(set, array) {
9294
      let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
1 efrain 9295
      if (setPrototypeOf) {
1441 ariadna 9296
        // Make 'in' and truthy checks like Boolean(set.constructor)
9297
        // independent of any properties defined on Object.prototype.
9298
        // Prevent prototype setters from intercepting set as a this value.
1 efrain 9299
        setPrototypeOf(set, null);
9300
      }
9301
      let l = array.length;
9302
      while (l--) {
9303
        let element = array[l];
9304
        if (typeof element === 'string') {
9305
          const lcElement = transformCaseFunc(element);
9306
          if (lcElement !== element) {
1441 ariadna 9307
            // Config presets (e.g. tags.js, attrs.js) are immutable.
1 efrain 9308
            if (!isFrozen(array)) {
9309
              array[l] = lcElement;
9310
            }
9311
            element = lcElement;
9312
          }
9313
        }
9314
        set[element] = true;
9315
      }
9316
      return set;
9317
    }
1441 ariadna 9318
    /**
9319
     * Clean up an array to harden against CSPP
9320
     *
9321
     * @param array - The array to be cleaned.
9322
     * @returns The cleaned version of the array
9323
     */
9324
    function cleanArray(array) {
9325
      for (let index = 0; index < array.length; index++) {
9326
        const isPropertyExist = objectHasOwnProperty(array, index);
9327
        if (!isPropertyExist) {
9328
          array[index] = null;
9329
        }
9330
      }
9331
      return array;
9332
    }
9333
    /**
9334
     * Shallow clone an object
9335
     *
9336
     * @param object - The object to be cloned.
9337
     * @returns A new object that copies the original.
9338
     */
1 efrain 9339
    function clone(object) {
9340
      const newObject = create$1(null);
9341
      for (const [property, value] of entries(object)) {
1441 ariadna 9342
        const isPropertyExist = objectHasOwnProperty(object, property);
9343
        if (isPropertyExist) {
9344
          if (Array.isArray(value)) {
9345
            newObject[property] = cleanArray(value);
9346
          } else if (value && typeof value === 'object' && value.constructor === Object) {
9347
            newObject[property] = clone(value);
9348
          } else {
9349
            newObject[property] = value;
9350
          }
9351
        }
1 efrain 9352
      }
9353
      return newObject;
9354
    }
1441 ariadna 9355
    /**
9356
     * This method automatically checks if the prop is function or getter and behaves accordingly.
9357
     *
9358
     * @param object - The object to look up the getter function in its prototype chain.
9359
     * @param prop - The property name for which to find the getter function.
9360
     * @returns The getter function found in the prototype chain or a fallback function.
9361
     */
1 efrain 9362
    function lookupGetter(object, prop) {
9363
      while (object !== null) {
9364
        const desc = getOwnPropertyDescriptor(object, prop);
9365
        if (desc) {
9366
          if (desc.get) {
9367
            return unapply(desc.get);
9368
          }
9369
          if (typeof desc.value === 'function') {
9370
            return unapply(desc.value);
9371
          }
9372
        }
9373
        object = getPrototypeOf(object);
9374
      }
1441 ariadna 9375
      function fallbackValue() {
1 efrain 9376
        return null;
9377
      }
9378
      return fallbackValue;
9379
    }
1441 ariadna 9380
 
9381
    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']);
9382
    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']);
9383
    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']);
9384
    // List of SVG elements that are disallowed by default.
9385
    // We still need to know them so that we can do namespace
9386
    // checks properly in case one wants to add them to
9387
    // allow-list.
9388
    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']);
9389
    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']);
9390
    // Similarly to SVG, we want to know all MathML elements,
9391
    // even those that we disallow by default.
9392
    const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
1 efrain 9393
    const text$1 = freeze(['#text']);
1441 ariadna 9394
 
9395
    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']);
9396
    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']);
9397
    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']);
9398
    const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
9399
 
9400
    // eslint-disable-next-line unicorn/better-regex
9401
    const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
1 efrain 9402
    const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
1441 ariadna 9403
    const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
9404
    const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
9405
    const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
9406
    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
9407
    );
1 efrain 9408
    const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
1441 ariadna 9409
    const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
9410
    );
1 efrain 9411
    const DOCTYPE_NAME = seal(/^html$/i);
1441 ariadna 9412
    const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
9413
 
9414
    var EXPRESSIONS = /*#__PURE__*/Object.freeze({
1 efrain 9415
      __proto__: null,
1441 ariadna 9416
      ARIA_ATTR: ARIA_ATTR,
9417
      ATTR_WHITESPACE: ATTR_WHITESPACE,
9418
      CUSTOM_ELEMENT: CUSTOM_ELEMENT,
9419
      DATA_ATTR: DATA_ATTR,
9420
      DOCTYPE_NAME: DOCTYPE_NAME,
1 efrain 9421
      ERB_EXPR: ERB_EXPR,
9422
      IS_ALLOWED_URI: IS_ALLOWED_URI,
9423
      IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
1441 ariadna 9424
      MUSTACHE_EXPR: MUSTACHE_EXPR,
9425
      TMPLIT_EXPR: TMPLIT_EXPR
1 efrain 9426
    });
1441 ariadna 9427
 
9428
    /* eslint-disable @typescript-eslint/indent */
9429
    // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
9430
    const NODE_TYPE = {
9431
      element: 1,
9432
      attribute: 2,
9433
      text: 3,
9434
      cdataSection: 4,
9435
      entityReference: 5,
9436
      // Deprecated
9437
      entityNode: 6,
9438
      // Deprecated
9439
      progressingInstruction: 7,
9440
      comment: 8,
9441
      document: 9,
9442
      documentType: 10,
9443
      documentFragment: 11,
9444
      notation: 12 // Deprecated
9445
    };
9446
    const getGlobal = function getGlobal() {
9447
      return typeof window === 'undefined' ? null : window;
9448
    };
9449
    /**
9450
     * Creates a no-op policy for internal use only.
9451
     * Don't export this function outside this module!
9452
     * @param trustedTypes The policy factory.
9453
     * @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
9454
     * @return The policy created (or null, if Trusted Types
9455
     * are not supported or creating the policy failed).
9456
     */
1 efrain 9457
    const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
9458
      if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
9459
        return null;
9460
      }
1441 ariadna 9461
      // Allow the callers to control the unique policy name
9462
      // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
9463
      // Policy creation with duplicate names throws in Trusted Types.
1 efrain 9464
      let suffix = null;
9465
      const ATTR_NAME = 'data-tt-policy-suffix';
9466
      if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
9467
        suffix = purifyHostElement.getAttribute(ATTR_NAME);
9468
      }
9469
      const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
9470
      try {
9471
        return trustedTypes.createPolicy(policyName, {
9472
          createHTML(html) {
9473
            return html;
9474
          },
9475
          createScriptURL(scriptUrl) {
9476
            return scriptUrl;
9477
          }
9478
        });
9479
      } catch (_) {
1441 ariadna 9480
        // Policy creation failed (most likely another DOMPurify script has
9481
        // already run). Skip creating the policy, as this will only cause errors
9482
        // if TT are enforced.
1 efrain 9483
        console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
9484
        return null;
9485
      }
9486
    };
1441 ariadna 9487
    const _createHooksMap = function _createHooksMap() {
9488
      return {
9489
        afterSanitizeAttributes: [],
9490
        afterSanitizeElements: [],
9491
        afterSanitizeShadowDOM: [],
9492
        beforeSanitizeAttributes: [],
9493
        beforeSanitizeElements: [],
9494
        beforeSanitizeShadowDOM: [],
9495
        uponSanitizeAttribute: [],
9496
        uponSanitizeElement: [],
9497
        uponSanitizeShadowNode: []
9498
      };
9499
    };
1 efrain 9500
    function createDOMPurify() {
9501
      let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
9502
      const DOMPurify = root => createDOMPurify(root);
1441 ariadna 9503
      DOMPurify.version = '3.2.4';
1 efrain 9504
      DOMPurify.removed = [];
1441 ariadna 9505
      if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
9506
        // Not running in a browser, provide a factory function
9507
        // so that you can pass your own Window
1 efrain 9508
        DOMPurify.isSupported = false;
9509
        return DOMPurify;
9510
      }
1441 ariadna 9511
      let {
9512
        document
9513
      } = window;
9514
      const originalDocument = document;
1 efrain 9515
      const currentScript = originalDocument.currentScript;
1441 ariadna 9516
      const {
9517
        DocumentFragment,
9518
        HTMLTemplateElement,
9519
        Node,
9520
        Element,
9521
        NodeFilter,
9522
        NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
9523
        HTMLFormElement,
9524
        DOMParser,
9525
        trustedTypes
9526
      } = window;
1 efrain 9527
      const ElementPrototype = Element.prototype;
9528
      const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
1441 ariadna 9529
      const remove = lookupGetter(ElementPrototype, 'remove');
1 efrain 9530
      const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
9531
      const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
9532
      const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
1441 ariadna 9533
      // As per issue #47, the web-components registry is inherited by a
9534
      // new document created via createHTMLDocument. As per the spec
9535
      // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
9536
      // a new empty registry is used when creating a template contents owner
9537
      // document, so we use that as our parent document to ensure nothing
9538
      // is inherited.
1 efrain 9539
      if (typeof HTMLTemplateElement === 'function') {
9540
        const template = document.createElement('template');
9541
        if (template.content && template.content.ownerDocument) {
9542
          document = template.content.ownerDocument;
9543
        }
9544
      }
9545
      let trustedTypesPolicy;
9546
      let emptyHTML = '';
1441 ariadna 9547
      const {
9548
        implementation,
9549
        createNodeIterator,
9550
        createDocumentFragment,
9551
        getElementsByTagName
9552
      } = document;
9553
      const {
9554
        importNode
9555
      } = originalDocument;
9556
      let hooks = _createHooksMap();
9557
      /**
9558
       * Expose whether this browser supports running the full DOMPurify.
9559
       */
1 efrain 9560
      DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
1441 ariadna 9561
      const {
9562
        MUSTACHE_EXPR,
9563
        ERB_EXPR,
9564
        TMPLIT_EXPR,
9565
        DATA_ATTR,
9566
        ARIA_ATTR,
9567
        IS_SCRIPT_OR_DATA,
9568
        ATTR_WHITESPACE,
9569
        CUSTOM_ELEMENT
9570
      } = EXPRESSIONS;
9571
      let {
9572
        IS_ALLOWED_URI: IS_ALLOWED_URI$1
9573
      } = EXPRESSIONS;
9574
      /**
9575
       * We consider the elements and attributes below to be safe. Ideally
9576
       * don't add any new ones but feel free to remove unwanted ones.
9577
       */
9578
      /* allowed element names */
1 efrain 9579
      let ALLOWED_TAGS = null;
1441 ariadna 9580
      const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text$1]);
9581
      /* Allowed attribute names */
1 efrain 9582
      let ALLOWED_ATTR = null;
1441 ariadna 9583
      const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
9584
      /*
9585
       * Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.
9586
       * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
9587
       * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
9588
       * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
9589
       */
9590
      let CUSTOM_ELEMENT_HANDLING = Object.seal(create$1(null, {
1 efrain 9591
        tagNameCheck: {
9592
          writable: true,
9593
          configurable: false,
9594
          enumerable: true,
9595
          value: null
9596
        },
9597
        attributeNameCheck: {
9598
          writable: true,
9599
          configurable: false,
9600
          enumerable: true,
9601
          value: null
9602
        },
9603
        allowCustomizedBuiltInElements: {
9604
          writable: true,
9605
          configurable: false,
9606
          enumerable: true,
9607
          value: false
9608
        }
9609
      }));
1441 ariadna 9610
      /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
1 efrain 9611
      let FORBID_TAGS = null;
1441 ariadna 9612
      /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
1 efrain 9613
      let FORBID_ATTR = null;
1441 ariadna 9614
      /* Decide if ARIA attributes are okay */
1 efrain 9615
      let ALLOW_ARIA_ATTR = true;
1441 ariadna 9616
      /* Decide if custom data attributes are okay */
1 efrain 9617
      let ALLOW_DATA_ATTR = true;
1441 ariadna 9618
      /* Decide if unknown protocols are okay */
1 efrain 9619
      let ALLOW_UNKNOWN_PROTOCOLS = false;
1441 ariadna 9620
      /* Decide if self-closing tags in attributes are allowed.
9621
       * Usually removed due to a mXSS issue in jQuery 3.0 */
1 efrain 9622
      let ALLOW_SELF_CLOSE_IN_ATTR = true;
1441 ariadna 9623
      /* Output should be safe for common template engines.
9624
       * This means, DOMPurify removes data attributes, mustaches and ERB
9625
       */
1 efrain 9626
      let SAFE_FOR_TEMPLATES = false;
1441 ariadna 9627
      /* Output should be safe even for XML used within HTML and alike.
9628
       * This means, DOMPurify removes comments when containing risky content.
9629
       */
9630
      let SAFE_FOR_XML = true;
9631
      /* Decide if document with <html>... should be returned */
1 efrain 9632
      let WHOLE_DOCUMENT = false;
1441 ariadna 9633
      /* Track whether config is already set on this instance of DOMPurify. */
1 efrain 9634
      let SET_CONFIG = false;
1441 ariadna 9635
      /* Decide if all elements (e.g. style, script) must be children of
9636
       * document.body. By default, browsers might move them to document.head */
1 efrain 9637
      let FORCE_BODY = false;
1441 ariadna 9638
      /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
9639
       * string (or a TrustedHTML object if Trusted Types are supported).
9640
       * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
9641
       */
1 efrain 9642
      let RETURN_DOM = false;
1441 ariadna 9643
      /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
9644
       * string  (or a TrustedHTML object if Trusted Types are supported) */
1 efrain 9645
      let RETURN_DOM_FRAGMENT = false;
1441 ariadna 9646
      /* Try to return a Trusted Type object instead of a string, return a string in
9647
       * case Trusted Types are not supported  */
1 efrain 9648
      let RETURN_TRUSTED_TYPE = false;
1441 ariadna 9649
      /* Output should be free from DOM clobbering attacks?
9650
       * This sanitizes markups named with colliding, clobberable built-in DOM APIs.
9651
       */
1 efrain 9652
      let SANITIZE_DOM = true;
1441 ariadna 9653
      /* Achieve full DOM Clobbering protection by isolating the namespace of named
9654
       * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
9655
       *
9656
       * HTML/DOM spec rules that enable DOM Clobbering:
9657
       *   - Named Access on Window (§7.3.3)
9658
       *   - DOM Tree Accessors (§3.1.5)
9659
       *   - Form Element Parent-Child Relations (§4.10.3)
9660
       *   - Iframe srcdoc / Nested WindowProxies (§4.8.5)
9661
       *   - HTMLCollection (§4.2.10.2)
9662
       *
9663
       * Namespace isolation is implemented by prefixing `id` and `name` attributes
9664
       * with a constant string, i.e., `user-content-`
9665
       */
1 efrain 9666
      let SANITIZE_NAMED_PROPS = false;
9667
      const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
1441 ariadna 9668
      /* Keep element content when removing element? */
1 efrain 9669
      let KEEP_CONTENT = true;
1441 ariadna 9670
      /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
9671
       * of importing it into a new Document and returning a sanitized copy */
1 efrain 9672
      let IN_PLACE = false;
1441 ariadna 9673
      /* Allow usage of profiles like html, svg and mathMl */
1 efrain 9674
      let USE_PROFILES = {};
1441 ariadna 9675
      /* Tags to ignore content of when KEEP_CONTENT is true */
1 efrain 9676
      let FORBID_CONTENTS = null;
1441 ariadna 9677
      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']);
9678
      /* Tags that are safe for data: URIs */
1 efrain 9679
      let DATA_URI_TAGS = null;
1441 ariadna 9680
      const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
9681
      /* Attributes safe for values like "javascript:" */
1 efrain 9682
      let URI_SAFE_ATTRIBUTES = null;
1441 ariadna 9683
      const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
1 efrain 9684
      const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
9685
      const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
9686
      const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
1441 ariadna 9687
      /* Document namespace */
1 efrain 9688
      let NAMESPACE = HTML_NAMESPACE;
9689
      let IS_EMPTY_INPUT = false;
1441 ariadna 9690
      /* Allowed XHTML+XML namespaces */
1 efrain 9691
      let ALLOWED_NAMESPACES = null;
1441 ariadna 9692
      const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
9693
      let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
9694
      let HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
9695
      // Certain elements are allowed in both SVG and HTML
9696
      // namespace. We need to specify them explicitly
9697
      // so that they don't get erroneously deleted from
9698
      // HTML namespace.
9699
      const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
9700
      /* Parsing of strict XHTML documents */
9701
      let PARSER_MEDIA_TYPE = null;
9702
      const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
1 efrain 9703
      const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
1441 ariadna 9704
      let transformCaseFunc = null;
9705
      /* Keep a reference to config to pass to hooks */
1 efrain 9706
      let CONFIG = null;
1441 ariadna 9707
      /* Ideally, do not touch anything below this line */
9708
      /* ______________________________________________ */
1 efrain 9709
      const formElement = document.createElement('form');
9710
      const isRegexOrFunction = function isRegexOrFunction(testValue) {
9711
        return testValue instanceof RegExp || testValue instanceof Function;
9712
      };
1441 ariadna 9713
      /**
9714
       * _parseConfig
9715
       *
9716
       * @param cfg optional config literal
9717
       */
9718
      // eslint-disable-next-line complexity
9719
      const _parseConfig = function _parseConfig() {
9720
        let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1 efrain 9721
        if (CONFIG && CONFIG === cfg) {
9722
          return;
9723
        }
1441 ariadna 9724
        /* Shield configuration object from tampering */
1 efrain 9725
        if (!cfg || typeof cfg !== 'object') {
9726
          cfg = {};
9727
        }
1441 ariadna 9728
        /* Shield configuration object from prototype pollution */
1 efrain 9729
        cfg = clone(cfg);
1441 ariadna 9730
        PARSER_MEDIA_TYPE =
9731
        // eslint-disable-next-line unicorn/prefer-includes
9732
        SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
9733
        // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
1 efrain 9734
        transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
1441 ariadna 9735
        /* Set configuration parameters */
9736
        ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
9737
        ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
9738
        ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
9739
        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;
9740
        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;
9741
        FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
9742
        FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
9743
        FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
9744
        USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
9745
        ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
9746
        ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
9747
        ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
9748
        ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
9749
        SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
9750
        SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true
9751
        WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
9752
        RETURN_DOM = cfg.RETURN_DOM || false; // Default false
9753
        RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
9754
        RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
9755
        FORCE_BODY = cfg.FORCE_BODY || false; // Default false
9756
        SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
9757
        SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
9758
        KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
9759
        IN_PLACE = cfg.IN_PLACE || false; // Default false
1 efrain 9760
        IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
9761
        NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
1441 ariadna 9762
        MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS;
9763
        HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS;
1 efrain 9764
        CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
9765
        if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
9766
          CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
9767
        }
9768
        if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
9769
          CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
9770
        }
9771
        if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
9772
          CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
9773
        }
9774
        if (SAFE_FOR_TEMPLATES) {
9775
          ALLOW_DATA_ATTR = false;
9776
        }
9777
        if (RETURN_DOM_FRAGMENT) {
9778
          RETURN_DOM = true;
9779
        }
1441 ariadna 9780
        /* Parse profile info */
1 efrain 9781
        if (USE_PROFILES) {
1441 ariadna 9782
          ALLOWED_TAGS = addToSet({}, text$1);
1 efrain 9783
          ALLOWED_ATTR = [];
9784
          if (USE_PROFILES.html === true) {
9785
            addToSet(ALLOWED_TAGS, html$1);
9786
            addToSet(ALLOWED_ATTR, html);
9787
          }
9788
          if (USE_PROFILES.svg === true) {
9789
            addToSet(ALLOWED_TAGS, svg$1);
9790
            addToSet(ALLOWED_ATTR, svg);
9791
            addToSet(ALLOWED_ATTR, xml);
9792
          }
9793
          if (USE_PROFILES.svgFilters === true) {
9794
            addToSet(ALLOWED_TAGS, svgFilters);
9795
            addToSet(ALLOWED_ATTR, svg);
9796
            addToSet(ALLOWED_ATTR, xml);
9797
          }
9798
          if (USE_PROFILES.mathMl === true) {
9799
            addToSet(ALLOWED_TAGS, mathMl$1);
9800
            addToSet(ALLOWED_ATTR, mathMl);
9801
            addToSet(ALLOWED_ATTR, xml);
9802
          }
9803
        }
1441 ariadna 9804
        /* Merge configuration parameters */
1 efrain 9805
        if (cfg.ADD_TAGS) {
9806
          if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
9807
            ALLOWED_TAGS = clone(ALLOWED_TAGS);
9808
          }
9809
          addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
9810
        }
9811
        if (cfg.ADD_ATTR) {
9812
          if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
9813
            ALLOWED_ATTR = clone(ALLOWED_ATTR);
9814
          }
9815
          addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
9816
        }
9817
        if (cfg.ADD_URI_SAFE_ATTR) {
9818
          addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
9819
        }
9820
        if (cfg.FORBID_CONTENTS) {
9821
          if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
9822
            FORBID_CONTENTS = clone(FORBID_CONTENTS);
9823
          }
9824
          addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
9825
        }
1441 ariadna 9826
        /* Add #text in case KEEP_CONTENT is set to true */
1 efrain 9827
        if (KEEP_CONTENT) {
9828
          ALLOWED_TAGS['#text'] = true;
9829
        }
1441 ariadna 9830
        /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
1 efrain 9831
        if (WHOLE_DOCUMENT) {
1441 ariadna 9832
          addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
1 efrain 9833
        }
1441 ariadna 9834
        /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
1 efrain 9835
        if (ALLOWED_TAGS.table) {
9836
          addToSet(ALLOWED_TAGS, ['tbody']);
9837
          delete FORBID_TAGS.tbody;
9838
        }
9839
        if (cfg.TRUSTED_TYPES_POLICY) {
9840
          if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
9841
            throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
9842
          }
9843
          if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
9844
            throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
9845
          }
1441 ariadna 9846
          // Overwrite existing TrustedTypes policy.
1 efrain 9847
          trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
1441 ariadna 9848
          // Sign local variables required by `sanitize`.
1 efrain 9849
          emptyHTML = trustedTypesPolicy.createHTML('');
9850
        } else {
1441 ariadna 9851
          // Uninitialized policy, attempt to initialize the internal dompurify policy.
1 efrain 9852
          if (trustedTypesPolicy === undefined) {
9853
            trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
9854
          }
1441 ariadna 9855
          // If creating the internal policy succeeded sign internal variables.
1 efrain 9856
          if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
9857
            emptyHTML = trustedTypesPolicy.createHTML('');
9858
          }
9859
        }
1441 ariadna 9860
        // Prevent further manipulation of configuration.
9861
        // Not available in IE8, Safari 5, etc.
1 efrain 9862
        if (freeze) {
9863
          freeze(cfg);
9864
        }
9865
        CONFIG = cfg;
9866
      };
1441 ariadna 9867
      /* Keep track of all possible SVG and MathML tags
9868
       * so that we can perform the namespace checks
9869
       * correctly. */
9870
      const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
9871
      const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
9872
      /**
9873
       * @param element a DOM element whose namespace is being checked
9874
       * @returns Return false if the element has a
9875
       *  namespace that a spec-compliant parser would never
9876
       *  return. Return true otherwise.
9877
       */
1 efrain 9878
      const _checkValidNamespace = function _checkValidNamespace(element) {
9879
        let parent = getParentNode(element);
1441 ariadna 9880
        // In JSDOM, if we're inside shadow DOM, then parentNode
9881
        // can be null. We just simulate parent in this case.
1 efrain 9882
        if (!parent || !parent.tagName) {
9883
          parent = {
9884
            namespaceURI: NAMESPACE,
9885
            tagName: 'template'
9886
          };
9887
        }
9888
        const tagName = stringToLowerCase(element.tagName);
9889
        const parentTagName = stringToLowerCase(parent.tagName);
9890
        if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
9891
          return false;
9892
        }
9893
        if (element.namespaceURI === SVG_NAMESPACE) {
1441 ariadna 9894
          // The only way to switch from HTML namespace to SVG
9895
          // is via <svg>. If it happens via any other tag, then
9896
          // it should be killed.
1 efrain 9897
          if (parent.namespaceURI === HTML_NAMESPACE) {
9898
            return tagName === 'svg';
9899
          }
1441 ariadna 9900
          // The only way to switch from MathML to SVG is via`
9901
          // svg if parent is either <annotation-xml> or MathML
9902
          // text integration points.
1 efrain 9903
          if (parent.namespaceURI === MATHML_NAMESPACE) {
9904
            return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
9905
          }
1441 ariadna 9906
          // We only allow elements that are defined in SVG
9907
          // spec. All others are disallowed in SVG namespace.
1 efrain 9908
          return Boolean(ALL_SVG_TAGS[tagName]);
9909
        }
9910
        if (element.namespaceURI === MATHML_NAMESPACE) {
1441 ariadna 9911
          // The only way to switch from HTML namespace to MathML
9912
          // is via <math>. If it happens via any other tag, then
9913
          // it should be killed.
1 efrain 9914
          if (parent.namespaceURI === HTML_NAMESPACE) {
9915
            return tagName === 'math';
9916
          }
1441 ariadna 9917
          // The only way to switch from SVG to MathML is via
9918
          // <math> and HTML integration points
1 efrain 9919
          if (parent.namespaceURI === SVG_NAMESPACE) {
9920
            return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
9921
          }
1441 ariadna 9922
          // We only allow elements that are defined in MathML
9923
          // spec. All others are disallowed in MathML namespace.
1 efrain 9924
          return Boolean(ALL_MATHML_TAGS[tagName]);
9925
        }
9926
        if (element.namespaceURI === HTML_NAMESPACE) {
1441 ariadna 9927
          // The only way to switch from SVG to HTML is via
9928
          // HTML integration points, and from MathML to HTML
9929
          // is via MathML text integration points
1 efrain 9930
          if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
9931
            return false;
9932
          }
9933
          if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
9934
            return false;
9935
          }
1441 ariadna 9936
          // We disallow tags that are specific for MathML
9937
          // or SVG and should never appear in HTML namespace
1 efrain 9938
          return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
9939
        }
1441 ariadna 9940
        // For XHTML and XML documents that support custom namespaces
1 efrain 9941
        if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
9942
          return true;
9943
        }
1441 ariadna 9944
        // The code should never reach this place (this means
9945
        // that the element somehow got namespace that is not
9946
        // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
9947
        // Return false just in case.
1 efrain 9948
        return false;
9949
      };
1441 ariadna 9950
      /**
9951
       * _forceRemove
9952
       *
9953
       * @param node a DOM node
9954
       */
1 efrain 9955
      const _forceRemove = function _forceRemove(node) {
1441 ariadna 9956
        arrayPush(DOMPurify.removed, {
9957
          element: node
9958
        });
1 efrain 9959
        try {
1441 ariadna 9960
          // eslint-disable-next-line unicorn/prefer-dom-node-remove
9961
          getParentNode(node).removeChild(node);
1 efrain 9962
        } catch (_) {
1441 ariadna 9963
          remove(node);
1 efrain 9964
        }
9965
      };
1441 ariadna 9966
      /**
9967
       * _removeAttribute
9968
       *
9969
       * @param name an Attribute name
9970
       * @param element a DOM node
9971
       */
9972
      const _removeAttribute = function _removeAttribute(name, element) {
1 efrain 9973
        try {
9974
          arrayPush(DOMPurify.removed, {
1441 ariadna 9975
            attribute: element.getAttributeNode(name),
9976
            from: element
1 efrain 9977
          });
9978
        } catch (_) {
9979
          arrayPush(DOMPurify.removed, {
9980
            attribute: null,
1441 ariadna 9981
            from: element
1 efrain 9982
          });
9983
        }
1441 ariadna 9984
        element.removeAttribute(name);
9985
        // We void attribute values for unremovable "is" attributes
9986
        if (name === 'is') {
1 efrain 9987
          if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
9988
            try {
1441 ariadna 9989
              _forceRemove(element);
9990
            } catch (_) {}
1 efrain 9991
          } else {
9992
            try {
1441 ariadna 9993
              element.setAttribute(name, '');
9994
            } catch (_) {}
1 efrain 9995
          }
9996
        }
9997
      };
1441 ariadna 9998
      /**
9999
       * _initDocument
10000
       *
10001
       * @param dirty - a string of dirty markup
10002
       * @return a DOM, filled with the dirty markup
10003
       */
1 efrain 10004
      const _initDocument = function _initDocument(dirty) {
1441 ariadna 10005
        /* Create a HTML document */
10006
        let doc = null;
10007
        let leadingWhitespace = null;
1 efrain 10008
        if (FORCE_BODY) {
10009
          dirty = '<remove></remove>' + dirty;
10010
        } else {
1441 ariadna 10011
          /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
1 efrain 10012
          const matches = stringMatch(dirty, /^[\r\n\t ]+/);
10013
          leadingWhitespace = matches && matches[0];
10014
        }
10015
        if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
1441 ariadna 10016
          // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
1 efrain 10017
          dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
10018
        }
10019
        const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
1441 ariadna 10020
        /*
10021
         * Use the DOMParser API by default, fallback later if needs be
10022
         * DOMParser not work for svg when has multiple root element.
10023
         */
1 efrain 10024
        if (NAMESPACE === HTML_NAMESPACE) {
10025
          try {
10026
            doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
1441 ariadna 10027
          } catch (_) {}
1 efrain 10028
        }
1441 ariadna 10029
        /* Use createHTMLDocument in case DOMParser is not available */
1 efrain 10030
        if (!doc || !doc.documentElement) {
10031
          doc = implementation.createDocument(NAMESPACE, 'template', null);
10032
          try {
10033
            doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
10034
          } catch (_) {
1441 ariadna 10035
            // Syntax error if dirtyPayload is invalid xml
1 efrain 10036
          }
10037
        }
10038
        const body = doc.body || doc.documentElement;
10039
        if (dirty && leadingWhitespace) {
10040
          body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
10041
        }
1441 ariadna 10042
        /* Work on whole document or just its body */
1 efrain 10043
        if (NAMESPACE === HTML_NAMESPACE) {
10044
          return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
10045
        }
10046
        return WHOLE_DOCUMENT ? doc.documentElement : body;
10047
      };
1441 ariadna 10048
      /**
10049
       * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
10050
       *
10051
       * @param root The root element or node to start traversing on.
10052
       * @return The created NodeIterator
10053
       */
10054
      const _createNodeIterator = function _createNodeIterator(root) {
10055
        return createNodeIterator.call(root.ownerDocument || root, root,
10056
        // eslint-disable-next-line no-bitwise
10057
        NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
1 efrain 10058
      };
1441 ariadna 10059
      /**
10060
       * _isClobbered
10061
       *
10062
       * @param element element to check for clobbering attacks
10063
       * @return true if clobbered, false if safe
10064
       */
10065
      const _isClobbered = function _isClobbered(element) {
10066
        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 10067
      };
1441 ariadna 10068
      /**
10069
       * Checks whether the given object is a DOM node.
10070
       *
10071
       * @param value object to check whether it's a DOM node
10072
       * @return true is object is a DOM node
10073
       */
10074
      const _isNode = function _isNode(value) {
10075
        return typeof Node === 'function' && value instanceof Node;
1 efrain 10076
      };
1441 ariadna 10077
      function _executeHooks(hooks, currentNode, data) {
10078
        arrayForEach(hooks, hook => {
1 efrain 10079
          hook.call(DOMPurify, currentNode, data, CONFIG);
10080
        });
1441 ariadna 10081
      }
10082
      /**
10083
       * _sanitizeElements
10084
       *
10085
       * @protect nodeName
10086
       * @protect textContent
10087
       * @protect removeChild
10088
       * @param currentNode to check for permission to exist
10089
       * @return true if node was killed, false if left alive
10090
       */
1 efrain 10091
      const _sanitizeElements = function _sanitizeElements(currentNode) {
1441 ariadna 10092
        let content = null;
10093
        /* Execute a hook if present */
10094
        _executeHooks(hooks.beforeSanitizeElements, currentNode, null);
10095
        /* Check if element is clobbered or can clobber */
1 efrain 10096
        if (_isClobbered(currentNode)) {
10097
          _forceRemove(currentNode);
10098
          return true;
10099
        }
1441 ariadna 10100
        /* Now let's check the element's type and name */
1 efrain 10101
        const tagName = transformCaseFunc(currentNode.nodeName);
1441 ariadna 10102
        /* Execute a hook if present */
10103
        _executeHooks(hooks.uponSanitizeElement, currentNode, {
1 efrain 10104
          tagName,
10105
          allowedTags: ALLOWED_TAGS
10106
        });
1441 ariadna 10107
        /* Detect mXSS attempts abusing namespace confusion */
10108
        if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
1 efrain 10109
          _forceRemove(currentNode);
10110
          return true;
10111
        }
1441 ariadna 10112
        /* Remove any occurrence of processing instructions */
10113
        if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
10114
          _forceRemove(currentNode);
10115
          return true;
10116
        }
10117
        /* Remove any kind of possibly harmful comments */
10118
        if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
10119
          _forceRemove(currentNode);
10120
          return true;
10121
        }
10122
        /* Remove element if anything forbids its presence */
1 efrain 10123
        if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
1441 ariadna 10124
          /* Check if we have a custom element to handle */
10125
          if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
10126
            if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
1 efrain 10127
              return false;
1441 ariadna 10128
            }
10129
            if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
1 efrain 10130
              return false;
1441 ariadna 10131
            }
1 efrain 10132
          }
1441 ariadna 10133
          /* Keep content except for bad-listed elements */
1 efrain 10134
          if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
10135
            const parentNode = getParentNode(currentNode) || currentNode.parentNode;
10136
            const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
10137
            if (childNodes && parentNode) {
10138
              const childCount = childNodes.length;
10139
              for (let i = childCount - 1; i >= 0; --i) {
1441 ariadna 10140
                const childClone = cloneNode(childNodes[i], true);
10141
                childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
10142
                parentNode.insertBefore(childClone, getNextSibling(currentNode));
1 efrain 10143
              }
10144
            }
10145
          }
10146
          _forceRemove(currentNode);
10147
          return true;
10148
        }
1441 ariadna 10149
        /* Check whether element has a valid namespace */
1 efrain 10150
        if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
10151
          _forceRemove(currentNode);
10152
          return true;
10153
        }
1441 ariadna 10154
        /* Make sure that older browsers don't get fallback-tag mXSS */
1 efrain 10155
        if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
10156
          _forceRemove(currentNode);
10157
          return true;
10158
        }
1441 ariadna 10159
        /* Sanitize element content to be template-safe */
10160
        if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
10161
          /* Get the element's text content */
1 efrain 10162
          content = currentNode.textContent;
1441 ariadna 10163
          arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
10164
            content = stringReplace(content, expr, ' ');
10165
          });
1 efrain 10166
          if (currentNode.textContent !== content) {
1441 ariadna 10167
            arrayPush(DOMPurify.removed, {
10168
              element: currentNode.cloneNode()
10169
            });
1 efrain 10170
            currentNode.textContent = content;
10171
          }
10172
        }
1441 ariadna 10173
        /* Execute a hook if present */
10174
        _executeHooks(hooks.afterSanitizeElements, currentNode, null);
1 efrain 10175
        return false;
10176
      };
1441 ariadna 10177
      /**
10178
       * _isValidAttribute
10179
       *
10180
       * @param lcTag Lowercase tag name of containing element.
10181
       * @param lcName Lowercase attribute name.
10182
       * @param value Attribute value.
10183
       * @return Returns true if `value` is valid, otherwise false.
10184
       */
10185
      // eslint-disable-next-line complexity
1 efrain 10186
      const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
1441 ariadna 10187
        /* Make sure attribute cannot clobber */
1 efrain 10188
        if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
10189
          return false;
10190
        }
1441 ariadna 10191
        /* Allow valid data-* attributes: At least one character after "-"
10192
            (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
10193
            XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
10194
            We don't need to check the value; it's always URI safe. */
10195
        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]) {
10196
          if (
10197
          // First condition does a very basic check if a) it's basically a valid custom element tagname AND
10198
          // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
10199
          // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
10200
          _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)) ||
10201
          // Alternative, second condition checks if it's an `is`-attribute, AND
10202
          // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
10203
          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 10204
            return false;
10205
          }
1441 ariadna 10206
          /* Check value is safe. First, is attr inert? If so, is safe */
10207
        } 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 10208
          return false;
10209
        } else ;
10210
        return true;
10211
      };
1441 ariadna 10212
      /**
10213
       * _isBasicCustomElement
10214
       * checks if at least one dash is included in tagName, and it's not the first char
10215
       * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
10216
       *
10217
       * @param tagName name of the tag of the node to sanitize
10218
       * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
10219
       */
10220
      const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
10221
        return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
1 efrain 10222
      };
1441 ariadna 10223
      /**
10224
       * _sanitizeAttributes
10225
       *
10226
       * @protect attributes
10227
       * @protect nodeName
10228
       * @protect removeAttribute
10229
       * @protect setAttribute
10230
       *
10231
       * @param currentNode to sanitize
10232
       */
1 efrain 10233
      const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
1441 ariadna 10234
        /* Execute a hook if present */
10235
        _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
10236
        const {
10237
          attributes
10238
        } = currentNode;
10239
        /* Check if we have attributes; if not we might have a text node */
10240
        if (!attributes || _isClobbered(currentNode)) {
1 efrain 10241
          return;
10242
        }
10243
        const hookEvent = {
10244
          attrName: '',
10245
          attrValue: '',
10246
          keepAttr: true,
1441 ariadna 10247
          allowedAttributes: ALLOWED_ATTR,
10248
          forceKeepAttr: undefined
1 efrain 10249
        };
1441 ariadna 10250
        let l = attributes.length;
10251
        /* Go backwards over all attributes; safely remove bad ones */
1 efrain 10252
        while (l--) {
1441 ariadna 10253
          const attr = attributes[l];
10254
          const {
10255
            name,
10256
            namespaceURI,
10257
            value: attrValue
10258
          } = attr;
10259
          const lcName = transformCaseFunc(name);
10260
          let value = name === 'value' ? attrValue : stringTrim(attrValue);
1 efrain 10261
          const initValue = value;
1441 ariadna 10262
          /* Execute a hook if present */
1 efrain 10263
          hookEvent.attrName = lcName;
10264
          hookEvent.attrValue = value;
10265
          hookEvent.keepAttr = true;
1441 ariadna 10266
          hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
10267
          _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
1 efrain 10268
          value = hookEvent.attrValue;
1441 ariadna 10269
          /* Full DOM Clobbering protection via namespace isolation,
10270
           * Prefix id and name attributes with `user-content-`
10271
           */
10272
          if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
10273
            // Remove the attribute with this value
10274
            _removeAttribute(name, currentNode);
10275
            // Prefix the value and later re-create the attribute with the sanitized value
10276
            value = SANITIZE_NAMED_PROPS_PREFIX + value;
10277
          }
10278
          /* Work around a security issue with comments inside attributes */
10279
          if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
10280
            _removeAttribute(name, currentNode);
10281
            continue;
10282
          }
10283
          /* Did the hooks approve of the attribute? */
1 efrain 10284
          if (hookEvent.forceKeepAttr) {
10285
            continue;
10286
          }
1441 ariadna 10287
          /* Remove attribute */
10288
          /* Did the hooks approve of the attribute? */
1 efrain 10289
          if (!hookEvent.keepAttr) {
10290
            _removeAttribute(name, currentNode);
10291
            continue;
10292
          }
1441 ariadna 10293
          /* Work around a security issue in jQuery 3.0 */
1 efrain 10294
          if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
10295
            _removeAttribute(name, currentNode);
10296
            continue;
10297
          }
1441 ariadna 10298
          /* Sanitize attribute content to be template-safe */
1 efrain 10299
          if (SAFE_FOR_TEMPLATES) {
1441 ariadna 10300
            arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
10301
              value = stringReplace(value, expr, ' ');
10302
            });
1 efrain 10303
          }
1441 ariadna 10304
          /* Is `value` valid for this attribute? */
1 efrain 10305
          const lcTag = transformCaseFunc(currentNode.nodeName);
10306
          if (!_isValidAttribute(lcTag, lcName, value)) {
10307
            _removeAttribute(name, currentNode);
10308
            continue;
10309
          }
1441 ariadna 10310
          /* Handle attributes that require Trusted Types */
1 efrain 10311
          if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
1441 ariadna 10312
            if (namespaceURI) ; else {
1 efrain 10313
              switch (trustedTypes.getAttributeType(lcTag, lcName)) {
1441 ariadna 10314
                case 'TrustedHTML':
10315
                  {
10316
                    value = trustedTypesPolicy.createHTML(value);
10317
                    break;
10318
                  }
10319
                case 'TrustedScriptURL':
10320
                  {
10321
                    value = trustedTypesPolicy.createScriptURL(value);
10322
                    break;
10323
                  }
1 efrain 10324
              }
10325
            }
10326
          }
1441 ariadna 10327
          /* Handle invalid data-* attribute set by try-catching it */
1 efrain 10328
          if (value !== initValue) {
10329
            try {
10330
              if (namespaceURI) {
10331
                currentNode.setAttributeNS(namespaceURI, name, value);
10332
              } else {
1441 ariadna 10333
                /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
1 efrain 10334
                currentNode.setAttribute(name, value);
10335
              }
1441 ariadna 10336
              if (_isClobbered(currentNode)) {
10337
                _forceRemove(currentNode);
10338
              } else {
10339
                arrayPop(DOMPurify.removed);
10340
              }
10341
            } catch (_) {}
1 efrain 10342
          }
10343
        }
1441 ariadna 10344
        /* Execute a hook if present */
10345
        _executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
1 efrain 10346
      };
1441 ariadna 10347
      /**
10348
       * _sanitizeShadowDOM
10349
       *
10350
       * @param fragment to iterate over recursively
10351
       */
1 efrain 10352
      const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
1441 ariadna 10353
        let shadowNode = null;
10354
        const shadowIterator = _createNodeIterator(fragment);
10355
        /* Execute a hook if present */
10356
        _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
1 efrain 10357
        while (shadowNode = shadowIterator.nextNode()) {
1441 ariadna 10358
          /* Execute a hook if present */
10359
          _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
10360
          /* Sanitize tags and elements */
10361
          _sanitizeElements(shadowNode);
10362
          /* Check attributes next */
10363
          _sanitizeAttributes(shadowNode);
10364
          /* Deep shadow DOM detected */
1 efrain 10365
          if (shadowNode.content instanceof DocumentFragment) {
10366
            _sanitizeShadowDOM(shadowNode.content);
10367
          }
10368
        }
1441 ariadna 10369
        /* Execute a hook if present */
10370
        _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
1 efrain 10371
      };
1441 ariadna 10372
      // eslint-disable-next-line complexity
1 efrain 10373
      DOMPurify.sanitize = function (dirty) {
10374
        let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1441 ariadna 10375
        let body = null;
10376
        let importedNode = null;
10377
        let currentNode = null;
10378
        let returnNode = null;
10379
        /* Make sure we have a string to sanitize.
10380
          DO NOT return early, as this will return the wrong type if
10381
          the user has requested a DOM object rather than a string */
1 efrain 10382
        IS_EMPTY_INPUT = !dirty;
10383
        if (IS_EMPTY_INPUT) {
10384
          dirty = '<!-->';
10385
        }
1441 ariadna 10386
        /* Stringify, in case dirty is an object */
1 efrain 10387
        if (typeof dirty !== 'string' && !_isNode(dirty)) {
10388
          if (typeof dirty.toString === 'function') {
10389
            dirty = dirty.toString();
10390
            if (typeof dirty !== 'string') {
10391
              throw typeErrorCreate('dirty is not a string, aborting');
10392
            }
10393
          } else {
10394
            throw typeErrorCreate('toString is not a function');
10395
          }
10396
        }
1441 ariadna 10397
        /* Return dirty HTML if DOMPurify cannot run */
1 efrain 10398
        if (!DOMPurify.isSupported) {
10399
          return dirty;
10400
        }
1441 ariadna 10401
        /* Assign config vars */
1 efrain 10402
        if (!SET_CONFIG) {
10403
          _parseConfig(cfg);
10404
        }
1441 ariadna 10405
        /* Clean up removed elements */
1 efrain 10406
        DOMPurify.removed = [];
1441 ariadna 10407
        /* Check if dirty is correctly typed for IN_PLACE */
1 efrain 10408
        if (typeof dirty === 'string') {
10409
          IN_PLACE = false;
10410
        }
10411
        if (IN_PLACE) {
1441 ariadna 10412
          /* Do some early pre-sanitization to avoid unsafe root nodes */
1 efrain 10413
          if (dirty.nodeName) {
10414
            const tagName = transformCaseFunc(dirty.nodeName);
10415
            if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
10416
              throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
10417
            }
10418
          }
10419
        } else if (dirty instanceof Node) {
1441 ariadna 10420
          /* If dirty is a DOM element, append to an empty document to avoid
10421
             elements being stripped by the parser */
1 efrain 10422
          body = _initDocument('<!---->');
10423
          importedNode = body.ownerDocument.importNode(dirty, true);
1441 ariadna 10424
          if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
10425
            /* Node is already a body, use as is */
1 efrain 10426
            body = importedNode;
10427
          } else if (importedNode.nodeName === 'HTML') {
10428
            body = importedNode;
10429
          } else {
1441 ariadna 10430
            // eslint-disable-next-line unicorn/prefer-dom-node-append
1 efrain 10431
            body.appendChild(importedNode);
10432
          }
10433
        } else {
1441 ariadna 10434
          /* Exit directly if we have nothing to do */
10435
          if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
10436
          // eslint-disable-next-line unicorn/prefer-includes
10437
          dirty.indexOf('<') === -1) {
1 efrain 10438
            return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
10439
          }
1441 ariadna 10440
          /* Initialize the document to work on */
1 efrain 10441
          body = _initDocument(dirty);
1441 ariadna 10442
          /* Check we have a DOM node from the data */
1 efrain 10443
          if (!body) {
10444
            return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
10445
          }
10446
        }
1441 ariadna 10447
        /* Remove first element node (ours) if FORCE_BODY is set */
1 efrain 10448
        if (body && FORCE_BODY) {
10449
          _forceRemove(body.firstChild);
10450
        }
1441 ariadna 10451
        /* Get node iterator */
10452
        const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);
10453
        /* Now start iterating over the created document */
1 efrain 10454
        while (currentNode = nodeIterator.nextNode()) {
1441 ariadna 10455
          /* Sanitize tags and elements */
10456
          _sanitizeElements(currentNode);
10457
          /* Check attributes next */
10458
          _sanitizeAttributes(currentNode);
10459
          /* Shadow DOM detected, sanitize it */
1 efrain 10460
          if (currentNode.content instanceof DocumentFragment) {
10461
            _sanitizeShadowDOM(currentNode.content);
10462
          }
10463
        }
1441 ariadna 10464
        /* If we sanitized `dirty` in-place, return it. */
1 efrain 10465
        if (IN_PLACE) {
10466
          return dirty;
10467
        }
1441 ariadna 10468
        /* Return sanitized string or DOM */
1 efrain 10469
        if (RETURN_DOM) {
10470
          if (RETURN_DOM_FRAGMENT) {
10471
            returnNode = createDocumentFragment.call(body.ownerDocument);
10472
            while (body.firstChild) {
1441 ariadna 10473
              // eslint-disable-next-line unicorn/prefer-dom-node-append
1 efrain 10474
              returnNode.appendChild(body.firstChild);
10475
            }
10476
          } else {
10477
            returnNode = body;
10478
          }
10479
          if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
1441 ariadna 10480
            /*
10481
              AdoptNode() is not used because internal state is not reset
10482
              (e.g. the past names map of a HTMLFormElement), this is safe
10483
              in theory but we would rather not risk another attack vector.
10484
              The state that is cloned by importNode() is explicitly defined
10485
              by the specs.
10486
            */
1 efrain 10487
            returnNode = importNode.call(originalDocument, returnNode, true);
10488
          }
10489
          return returnNode;
10490
        }
10491
        let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
1441 ariadna 10492
        /* Serialize doctype if allowed */
1 efrain 10493
        if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
10494
          serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
10495
        }
1441 ariadna 10496
        /* Sanitize final string template-safe */
1 efrain 10497
        if (SAFE_FOR_TEMPLATES) {
1441 ariadna 10498
          arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
10499
            serializedHTML = stringReplace(serializedHTML, expr, ' ');
10500
          });
1 efrain 10501
        }
10502
        return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
10503
      };
1441 ariadna 10504
      DOMPurify.setConfig = function () {
10505
        let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1 efrain 10506
        _parseConfig(cfg);
10507
        SET_CONFIG = true;
10508
      };
10509
      DOMPurify.clearConfig = function () {
10510
        CONFIG = null;
10511
        SET_CONFIG = false;
10512
      };
10513
      DOMPurify.isValidAttribute = function (tag, attr, value) {
1441 ariadna 10514
        /* Initialize shared config vars if necessary. */
1 efrain 10515
        if (!CONFIG) {
10516
          _parseConfig({});
10517
        }
10518
        const lcTag = transformCaseFunc(tag);
10519
        const lcName = transformCaseFunc(attr);
10520
        return _isValidAttribute(lcTag, lcName, value);
10521
      };
10522
      DOMPurify.addHook = function (entryPoint, hookFunction) {
10523
        if (typeof hookFunction !== 'function') {
10524
          return;
10525
        }
10526
        arrayPush(hooks[entryPoint], hookFunction);
10527
      };
1441 ariadna 10528
      DOMPurify.removeHook = function (entryPoint, hookFunction) {
10529
        if (hookFunction !== undefined) {
10530
          const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);
10531
          return index === -1 ? undefined : arraySplice(hooks[entryPoint], index, 1)[0];
1 efrain 10532
        }
1441 ariadna 10533
        return arrayPop(hooks[entryPoint]);
1 efrain 10534
      };
10535
      DOMPurify.removeHooks = function (entryPoint) {
1441 ariadna 10536
        hooks[entryPoint] = [];
1 efrain 10537
      };
10538
      DOMPurify.removeAllHooks = function () {
1441 ariadna 10539
        hooks = _createHooksMap();
1 efrain 10540
      };
10541
      return DOMPurify;
10542
    }
10543
    var purify = createDOMPurify();
10544
 
10545
    const sanitizeHtmlString = html => purify().sanitize(html);
10546
 
1441 ariadna 10547
    var global$5 = tinymce.util.Tools.resolve('tinymce.util.I18n');
1 efrain 10548
 
10549
    const rtlTransform = {
10550
      'indent': true,
10551
      'outdent': true,
10552
      'table-insert-column-after': true,
10553
      'table-insert-column-before': true,
10554
      'paste-column-after': true,
10555
      'paste-column-before': true,
10556
      'unordered-list': true,
10557
      'list-bull-circle': true,
10558
      'list-bull-default': true,
10559
      'list-bull-square': true
10560
    };
10561
    const defaultIconName = 'temporary-placeholder';
1441 ariadna 10562
    const defaultIcon = icons => () => get$h(icons, defaultIconName).getOr('!not found!');
1 efrain 10563
    const getIconName = (name, icons) => {
10564
      const lcName = name.toLowerCase();
1441 ariadna 10565
      if (global$5.isRtl()) {
1 efrain 10566
        const rtlName = ensureTrailing(lcName, '-rtl');
10567
        return has$2(icons, rtlName) ? rtlName : lcName;
10568
      } else {
10569
        return lcName;
10570
      }
10571
    };
1441 ariadna 10572
    const lookupIcon = (name, icons) => get$h(icons, getIconName(name, icons));
10573
    const get$3 = (name, iconProvider) => {
1 efrain 10574
      const icons = iconProvider();
10575
      return lookupIcon(name, icons).getOrThunk(defaultIcon(icons));
10576
    };
10577
    const getOr = (name, iconProvider, fallbackIcon) => {
10578
      const icons = iconProvider();
10579
      return lookupIcon(name, icons).or(fallbackIcon).getOrThunk(defaultIcon(icons));
10580
    };
1441 ariadna 10581
    const needsRtlTransform = iconName => global$5.isRtl() ? has$2(rtlTransform, iconName) : false;
1 efrain 10582
    const addFocusableBehaviour = () => config('add-focusable', [runOnAttached(comp => {
10583
        child(comp.element, 'svg').each(svg => set$9(svg, 'focusable', 'false'));
10584
      })]);
10585
    const renderIcon$3 = (spec, iconName, icons, fallbackIcon) => {
10586
      var _a, _b;
10587
      const rtlIconClasses = needsRtlTransform(iconName) ? ['tox-icon--flip'] : [];
1441 ariadna 10588
      const iconHtml = get$h(icons, getIconName(iconName, icons)).or(fallbackIcon).getOrThunk(defaultIcon(icons));
1 efrain 10589
      return {
10590
        dom: {
10591
          tag: spec.tag,
10592
          attributes: (_a = spec.attributes) !== null && _a !== void 0 ? _a : {},
10593
          classes: spec.classes.concat(rtlIconClasses),
10594
          innerHtml: iconHtml
10595
        },
10596
        behaviours: derive$1([
10597
          ...(_b = spec.behaviours) !== null && _b !== void 0 ? _b : [],
10598
          addFocusableBehaviour()
10599
        ])
10600
      };
10601
    };
10602
    const render$3 = (iconName, spec, iconProvider, fallbackIcon = Optional.none()) => renderIcon$3(spec, iconName, iconProvider(), fallbackIcon);
10603
    const renderFirst = (iconNames, spec, iconProvider) => {
10604
      const icons = iconProvider();
10605
      const iconName = find$5(iconNames, name => has$2(icons, getIconName(name, icons)));
10606
      return renderIcon$3(spec, iconName.getOr(defaultIconName), icons, Optional.none());
10607
    };
10608
 
10609
    const notificationIconMap = {
10610
      success: 'checkmark',
10611
      error: 'warning',
10612
      err: 'error',
10613
      warning: 'warning',
10614
      warn: 'warning',
10615
      info: 'info'
10616
    };
10617
    const factory$m = detail => {
1441 ariadna 10618
      const notificationTextId = generate$6('notification-text');
1 efrain 10619
      const memBannerText = record({
1441 ariadna 10620
        dom: fromHtml(`<p id=${ notificationTextId }>${ sanitizeHtmlString(detail.backstageProvider.translate(detail.text)) }</p>`),
1 efrain 10621
        behaviours: derive$1([Replacing.config({})])
10622
      });
10623
      const renderPercentBar = percent => ({
10624
        dom: {
10625
          tag: 'div',
10626
          classes: ['tox-bar'],
10627
          styles: { width: `${ percent }%` }
10628
        }
10629
      });
10630
      const renderPercentText = percent => ({
10631
        dom: {
10632
          tag: 'div',
10633
          classes: ['tox-text'],
10634
          innerHtml: `${ percent }%`
10635
        }
10636
      });
10637
      const memBannerProgress = record({
10638
        dom: {
10639
          tag: 'div',
10640
          classes: detail.progress ? [
10641
            'tox-progress-bar',
10642
            'tox-progress-indicator'
10643
          ] : ['tox-progress-bar']
10644
        },
10645
        components: [
10646
          {
10647
            dom: {
10648
              tag: 'div',
10649
              classes: ['tox-bar-container']
10650
            },
10651
            components: [renderPercentBar(0)]
10652
          },
10653
          renderPercentText(0)
10654
        ],
10655
        behaviours: derive$1([Replacing.config({})])
10656
      });
10657
      const updateProgress = (comp, percent) => {
10658
        if (comp.getSystem().isConnected()) {
10659
          memBannerProgress.getOpt(comp).each(progress => {
10660
            Replacing.set(progress, [
10661
              {
10662
                dom: {
10663
                  tag: 'div',
10664
                  classes: ['tox-bar-container']
10665
                },
10666
                components: [renderPercentBar(percent)]
10667
              },
10668
              renderPercentText(percent)
10669
            ]);
10670
          });
10671
        }
10672
      };
10673
      const updateText = (comp, text) => {
10674
        if (comp.getSystem().isConnected()) {
10675
          const banner = memBannerText.get(comp);
10676
          Replacing.set(banner, [text$2(text)]);
10677
        }
10678
      };
10679
      const apis = {
10680
        updateProgress,
10681
        updateText
10682
      };
10683
      const iconChoices = flatten([
10684
        detail.icon.toArray(),
1441 ariadna 10685
        [detail.level],
10686
        Optional.from(notificationIconMap[detail.level]).toArray()
1 efrain 10687
      ]);
10688
      const memButton = record(Button.sketch({
10689
        dom: {
10690
          tag: 'button',
10691
          classes: [
10692
            'tox-notification__dismiss',
10693
            'tox-button',
10694
            'tox-button--naked',
10695
            'tox-button--icon'
1441 ariadna 10696
          ],
10697
          attributes: { 'aria-label': detail.backstageProvider.translate('Close') }
1 efrain 10698
        },
10699
        components: [render$3('close', {
10700
            tag: 'span',
1441 ariadna 10701
            classes: ['tox-icon']
1 efrain 10702
          }, detail.iconProvider)],
1441 ariadna 10703
        buttonBehaviours: derive$1([
10704
          Tabstopping.config({}),
10705
          Tooltipping.config({ ...detail.backstageProvider.tooltips.getConfig({ tooltipText: detail.backstageProvider.translate('Close') }) })
10706
        ]),
1 efrain 10707
        action: comp => {
10708
          detail.onAction(comp);
10709
        }
10710
      }));
10711
      const notificationIconSpec = renderFirst(iconChoices, {
10712
        tag: 'div',
10713
        classes: ['tox-notification__icon']
10714
      }, detail.iconProvider);
10715
      const notificationBodySpec = {
10716
        dom: {
10717
          tag: 'div',
10718
          classes: ['tox-notification__body']
10719
        },
10720
        components: [memBannerText.asSpec()],
10721
        behaviours: derive$1([Replacing.config({})])
10722
      };
10723
      const components = [
10724
        notificationIconSpec,
10725
        notificationBodySpec
10726
      ];
10727
      return {
10728
        uid: detail.uid,
10729
        dom: {
10730
          tag: 'div',
1441 ariadna 10731
          attributes: {
10732
            'role': 'alert',
10733
            'aria-labelledby': notificationTextId
10734
          },
10735
          classes: [
1 efrain 10736
            'tox-notification',
10737
            'tox-notification--in',
1441 ariadna 10738
            `tox-notification--${ detail.level }`
10739
          ]
1 efrain 10740
        },
10741
        behaviours: derive$1([
1441 ariadna 10742
          Tabstopping.config({}),
1 efrain 10743
          Focusing.config({}),
1441 ariadna 10744
          Keying.config({
10745
            mode: 'special',
10746
            onEscape: comp => {
10747
              detail.onAction(comp);
10748
              return Optional.some(true);
10749
            }
10750
          })
1 efrain 10751
        ]),
1441 ariadna 10752
        components: components.concat(detail.progress ? [memBannerProgress.asSpec()] : []).concat([memButton.asSpec()]),
1 efrain 10753
        apis
10754
      };
10755
    };
10756
    const Notification = single({
10757
      name: 'Notification',
10758
      factory: factory$m,
10759
      configFields: [
1441 ariadna 10760
        defaultedStringEnum('level', 'info', [
10761
          'success',
10762
          'error',
10763
          'warning',
10764
          'warn',
10765
          'info'
10766
        ]),
1 efrain 10767
        required$1('progress'),
10768
        option$3('icon'),
10769
        required$1('onAction'),
10770
        required$1('text'),
10771
        required$1('iconProvider'),
1441 ariadna 10772
        required$1('backstageProvider')
1 efrain 10773
      ],
10774
      apis: {
10775
        updateProgress: (apis, comp, percent) => {
10776
          apis.updateProgress(comp, percent);
10777
        },
10778
        updateText: (apis, comp, text) => {
10779
          apis.updateText(comp, text);
10780
        }
10781
      }
10782
    });
10783
 
1441 ariadna 10784
    var NotificationManagerImpl = (editor, extras, uiMothership, notificationRegion) => {
1 efrain 10785
      const sharedBackstage = extras.backstage.shared;
1441 ariadna 10786
      const getBoundsContainer = () => SugarElement.fromDom(editor.queryCommandValue('ToggleView') === '' ? editor.getContentAreaContainer() : editor.getContainer());
1 efrain 10787
      const getBounds = () => {
1441 ariadna 10788
        const contentArea = box$1(getBoundsContainer());
10789
        return Optional.some(contentArea);
1 efrain 10790
      };
1441 ariadna 10791
      const clampComponentsToBounds = components => {
10792
        getBounds().each(bounds => {
10793
          each$1(components, comp => {
10794
            remove$7(comp.element, 'width');
10795
            if (get$d(comp.element) > bounds.width) {
10796
              set$8(comp.element, 'width', bounds.width + 'px');
10797
            }
10798
          });
10799
        });
10800
      };
10801
      const open = (settings, closeCallback, isEditorOrUIFocused) => {
1 efrain 10802
        const close = () => {
1441 ariadna 10803
          const removeNotificationAndReposition = region => {
10804
            Replacing.remove(region, notification);
10805
            reposition();
10806
          };
10807
          const manageRegionVisibility = (region, editorOrUiFocused) => {
10808
            if (children(region.element).length === 0) {
10809
              handleEmptyRegion(region, editorOrUiFocused);
10810
            } else {
10811
              handleRegionWithChildren(region, editorOrUiFocused);
10812
            }
10813
          };
10814
          const handleEmptyRegion = (region, editorOrUIFocused) => {
10815
            InlineView.hide(region);
10816
            notificationRegion.clear();
10817
            if (editorOrUIFocused) {
10818
              editor.focus();
10819
            }
10820
          };
10821
          const handleRegionWithChildren = (region, editorOrUIFocused) => {
10822
            if (editorOrUIFocused) {
10823
              Keying.focusIn(region);
10824
            }
10825
          };
10826
          notificationRegion.on(region => {
10827
            closeCallback();
10828
            const editorOrUIFocused = isEditorOrUIFocused();
10829
            removeNotificationAndReposition(region);
10830
            manageRegionVisibility(region, editorOrUIFocused);
10831
          });
1 efrain 10832
        };
1441 ariadna 10833
        const shouldApplyDocking = () => !isStickyToolbar(editor) || !sharedBackstage.header.isPositionedAtTop();
1 efrain 10834
        const notification = build$1(Notification.sketch({
10835
          text: settings.text,
10836
          level: contains$2([
10837
            'success',
10838
            'error',
10839
            'warning',
10840
            'warn',
10841
            'info'
10842
          ], settings.type) ? settings.type : undefined,
10843
          progress: settings.progressBar === true,
10844
          icon: settings.icon,
10845
          onAction: close,
10846
          iconProvider: sharedBackstage.providers.icons,
1441 ariadna 10847
          backstageProvider: sharedBackstage.providers
1 efrain 10848
        }));
1441 ariadna 10849
        if (!notificationRegion.isSet()) {
10850
          const notificationWrapper = build$1(InlineView.sketch({
10851
            dom: {
10852
              tag: 'div',
10853
              classes: ['tox-notifications-container'],
10854
              attributes: {
10855
                'aria-label': 'Notifications',
10856
                'role': 'region'
10857
              }
10858
            },
10859
            lazySink: sharedBackstage.getSink,
10860
            fireDismissalEventInstead: {},
10861
            ...sharedBackstage.header.isPositionedAtTop() ? {} : { fireRepositionEventInstead: {} },
10862
            inlineBehaviours: derive$1([
10863
              Keying.config({
10864
                mode: 'cyclic',
10865
                selector: '.tox-notification, .tox-notification a, .tox-notification button'
10866
              }),
10867
              Replacing.config({}),
10868
              ...shouldApplyDocking() ? [Docking.config({
10869
                  contextual: {
10870
                    lazyContext: () => Optional.some(box$1(getBoundsContainer())),
10871
                    fadeInClass: 'tox-notification-container-dock-fadein',
10872
                    fadeOutClass: 'tox-notification-container-dock-fadeout',
10873
                    transitionClass: 'tox-notification-container-dock-transition'
10874
                  },
10875
                  modes: ['top'],
10876
                  lazyViewport: comp => {
10877
                    const optScrollingContext = detectWhenSplitUiMode(editor, comp.element);
10878
                    return optScrollingContext.map(sc => {
10879
                      const combinedBounds = getBoundsFrom(sc);
10880
                      return {
10881
                        bounds: combinedBounds,
10882
                        optScrollEnv: Optional.some({
10883
                          currentScrollTop: sc.element.dom.scrollTop,
10884
                          scrollElmTop: absolute$3(sc.element).top
10885
                        })
10886
                      };
10887
                    }).getOrThunk(() => ({
10888
                      bounds: win(),
10889
                      optScrollEnv: Optional.none()
10890
                    }));
10891
                  }
10892
                })] : []
10893
            ])
10894
          }));
10895
          const notificationSpec = premade(notification);
10896
          const anchorOverrides = { maxHeightFunction: expandable$1() };
10897
          const anchor = {
10898
            ...sharedBackstage.anchors.banner(),
10899
            overrides: anchorOverrides
10900
          };
10901
          notificationRegion.set(notificationWrapper);
10902
          uiMothership.add(notificationWrapper);
10903
          InlineView.showWithinBounds(notificationWrapper, notificationSpec, { anchor }, getBounds);
10904
        } else {
10905
          const notificationSpec = premade(notification);
10906
          notificationRegion.on(notificationWrapper => {
10907
            Replacing.append(notificationWrapper, notificationSpec);
10908
            InlineView.reposition(notificationWrapper);
10909
            if (notification.hasConfigured(Docking)) {
10910
              Docking.refresh(notificationWrapper);
10911
            }
10912
            clampComponentsToBounds(notificationWrapper.components());
10913
          });
10914
        }
1 efrain 10915
        if (isNumber(settings.timeout) && settings.timeout > 0) {
10916
          global$9.setEditorTimeout(editor, () => {
10917
            close();
10918
          }, settings.timeout);
10919
        }
10920
        const reposition = () => {
1441 ariadna 10921
          notificationRegion.on(region => {
10922
            InlineView.reposition(region);
10923
            if (region.hasConfigured(Docking)) {
10924
              Docking.refresh(region);
10925
            }
10926
            clampComponentsToBounds(region.components());
10927
          });
1 efrain 10928
        };
10929
        const thisNotification = {
10930
          close,
10931
          reposition,
10932
          text: nuText => {
10933
            Notification.updateText(notification, nuText);
10934
          },
10935
          settings,
10936
          getEl: () => notification.element.dom,
10937
          progressBar: {
10938
            value: percent => {
10939
              Notification.updateProgress(notification, percent);
10940
            }
10941
          }
10942
        };
10943
        return thisNotification;
10944
      };
10945
      const close = notification => {
10946
        notification.close();
10947
      };
10948
      const getArgs = notification => {
10949
        return notification.settings;
10950
      };
10951
      return {
10952
        open,
10953
        close,
10954
        getArgs
10955
      };
10956
    };
10957
 
10958
    const setup$e = (api, editor) => {
10959
      const redirectKeyToItem = (item, e) => {
10960
        emitWith(item, keydown(), { raw: e });
10961
      };
10962
      const getItem = () => api.getMenu().bind(Highlighting.getHighlighted);
10963
      editor.on('keydown', e => {
10964
        const keyCode = e.which;
10965
        if (!api.isActive()) {
10966
          return;
10967
        }
10968
        if (api.isMenuOpen()) {
10969
          if (keyCode === 13) {
10970
            getItem().each(emitExecute);
10971
            e.preventDefault();
10972
          } else if (keyCode === 40) {
10973
            getItem().fold(() => {
10974
              api.getMenu().each(Highlighting.highlightFirst);
10975
            }, item => {
10976
              redirectKeyToItem(item, e);
10977
            });
10978
            e.preventDefault();
10979
            e.stopImmediatePropagation();
10980
          } else if (keyCode === 37 || keyCode === 38 || keyCode === 39) {
10981
            getItem().each(item => {
10982
              redirectKeyToItem(item, e);
10983
              e.preventDefault();
10984
              e.stopImmediatePropagation();
10985
            });
10986
          }
10987
        } else {
10988
          if (keyCode === 13 || keyCode === 38 || keyCode === 40) {
10989
            api.cancelIfNecessary();
10990
          }
10991
        }
10992
      });
1441 ariadna 10993
      editor.on('NodeChange', () => {
10994
        if (api.isActive() && !api.isProcessingAction() && !editor.queryCommandState('mceAutoCompleterInRange')) {
1 efrain 10995
          api.cancelIfNecessary();
10996
        }
10997
      });
10998
    };
10999
    const AutocompleterEditorEvents = { setup: setup$e };
11000
 
11001
    var ItemResponse;
11002
    (function (ItemResponse) {
11003
      ItemResponse[ItemResponse['CLOSE_ON_EXECUTE'] = 0] = 'CLOSE_ON_EXECUTE';
11004
      ItemResponse[ItemResponse['BUBBLE_TO_SANDBOX'] = 1] = 'BUBBLE_TO_SANDBOX';
11005
    }(ItemResponse || (ItemResponse = {})));
11006
    var ItemResponse$1 = ItemResponse;
11007
 
11008
    const navClass = 'tox-menu-nav__js';
11009
    const selectableClass = 'tox-collection__item';
11010
    const colorClass = 'tox-swatch';
11011
    const presetClasses = {
11012
      normal: navClass,
11013
      color: colorClass
11014
    };
11015
    const tickedClass = 'tox-collection__item--enabled';
11016
    const groupHeadingClass = 'tox-collection__group-heading';
11017
    const iconClass = 'tox-collection__item-icon';
11018
    const textClass = 'tox-collection__item-label';
11019
    const accessoryClass = 'tox-collection__item-accessory';
11020
    const caretClass = 'tox-collection__item-caret';
11021
    const checkmarkClass = 'tox-collection__item-checkmark';
11022
    const activeClass = 'tox-collection__item--active';
11023
    const containerClass = 'tox-collection__item-container';
11024
    const containerColumnClass = 'tox-collection__item-container--column';
11025
    const containerRowClass = 'tox-collection__item-container--row';
11026
    const containerAlignRightClass = 'tox-collection__item-container--align-right';
11027
    const containerAlignLeftClass = 'tox-collection__item-container--align-left';
11028
    const containerValignTopClass = 'tox-collection__item-container--valign-top';
11029
    const containerValignMiddleClass = 'tox-collection__item-container--valign-middle';
11030
    const containerValignBottomClass = 'tox-collection__item-container--valign-bottom';
1441 ariadna 11031
    const classForPreset = presets => get$h(presetClasses, presets).getOr(navClass);
1 efrain 11032
 
11033
    const forMenu = presets => {
11034
      if (presets === 'color') {
11035
        return 'tox-swatches';
11036
      } else {
11037
        return 'tox-menu';
11038
      }
11039
    };
11040
    const classes = presets => ({
11041
      backgroundMenu: 'tox-background-menu',
11042
      selectedMenu: 'tox-selected-menu',
11043
      selectedItem: 'tox-collection__item--active',
11044
      hasIcons: 'tox-menu--has-icons',
11045
      menu: forMenu(presets),
11046
      tieredMenu: 'tox-tiered-menu'
11047
    });
11048
 
11049
    const markers = presets => {
11050
      const menuClasses = classes(presets);
11051
      return {
11052
        backgroundMenu: menuClasses.backgroundMenu,
11053
        selectedMenu: menuClasses.selectedMenu,
11054
        menu: menuClasses.menu,
11055
        selectedItem: menuClasses.selectedItem,
11056
        item: classForPreset(presets)
11057
      };
11058
    };
11059
    const dom$1 = (hasIcons, columns, presets) => {
11060
      const menuClasses = classes(presets);
11061
      return {
11062
        tag: 'div',
11063
        classes: flatten([
11064
          [
11065
            menuClasses.menu,
11066
            `tox-menu-${ columns }-column`
11067
          ],
11068
          hasIcons ? [menuClasses.hasIcons] : []
11069
        ])
11070
      };
11071
    };
11072
    const components = [Menu.parts.items({})];
11073
    const part = (hasIcons, columns, presets) => {
11074
      const menuClasses = classes(presets);
11075
      const d = {
11076
        tag: 'div',
11077
        classes: flatten([[menuClasses.tieredMenu]])
11078
      };
11079
      return {
11080
        dom: d,
11081
        markers: markers(presets)
11082
      };
11083
    };
11084
 
11085
    const schema$l = constant$1([
1441 ariadna 11086
      defaultedString('type', 'text'),
1 efrain 11087
      option$3('data'),
11088
      defaulted('inputAttributes', {}),
11089
      defaulted('inputStyles', {}),
11090
      defaulted('tag', 'input'),
11091
      defaulted('inputClasses', []),
11092
      onHandler('onSetValue'),
1441 ariadna 11093
      defaultedFunction('fromInputValue', identity),
11094
      defaultedFunction('toInputValue', identity),
1 efrain 11095
      defaulted('styles', {}),
11096
      defaulted('eventOrder', {}),
11097
      field('inputBehaviours', [
11098
        Representing,
11099
        Focusing
11100
      ]),
11101
      defaulted('selectOnFocus', true)
11102
    ]);
11103
    const focusBehaviours = detail => derive$1([Focusing.config({
11104
        onFocus: !detail.selectOnFocus ? noop : component => {
11105
          const input = component.element;
1441 ariadna 11106
          const value = get$7(input);
11107
          if (detail.type !== 'range') {
11108
            input.dom.setSelectionRange(0, value.length);
11109
          }
1 efrain 11110
        }
11111
      })]);
11112
    const behaviours = detail => ({
11113
      ...focusBehaviours(detail),
11114
      ...augment(detail.inputBehaviours, [Representing.config({
11115
          store: {
11116
            mode: 'manual',
11117
            ...detail.data.map(data => ({ initialValue: data })).getOr({}),
11118
            getValue: input => {
1441 ariadna 11119
              return detail.fromInputValue(get$7(input.element));
1 efrain 11120
            },
11121
            setValue: (input, data) => {
1441 ariadna 11122
              const current = get$7(input.element);
1 efrain 11123
              if (current !== data) {
1441 ariadna 11124
                set$5(input.element, detail.toInputValue(data));
1 efrain 11125
              }
11126
            }
11127
          },
11128
          onSetValue: detail.onSetValue
11129
        })])
11130
    });
11131
    const dom = detail => ({
11132
      tag: detail.tag,
11133
      attributes: {
1441 ariadna 11134
        type: detail.type,
1 efrain 11135
        ...detail.inputAttributes
11136
      },
11137
      styles: detail.inputStyles,
11138
      classes: detail.inputClasses
11139
    });
11140
 
11141
    const factory$l = (detail, _spec) => ({
11142
      uid: detail.uid,
11143
      dom: dom(detail),
11144
      components: [],
11145
      behaviours: behaviours(detail),
11146
      eventOrder: detail.eventOrder
11147
    });
11148
    const Input = single({
11149
      name: 'Input',
11150
      configFields: schema$l(),
11151
      factory: factory$l
11152
    });
11153
 
11154
    const refetchTriggerEvent = generate$6('refetch-trigger-event');
11155
    const redirectMenuItemInteractionEvent = generate$6('redirect-menu-item-interaction');
11156
 
11157
    const menuSearcherClass = 'tox-menu__searcher';
11158
    const findWithinSandbox = sandboxComp => {
11159
      return descendant(sandboxComp.element, `.${ menuSearcherClass }`).bind(inputElem => sandboxComp.getSystem().getByDom(inputElem).toOptional());
11160
    };
11161
    const findWithinMenu = findWithinSandbox;
11162
    const restoreState = (inputComp, searcherState) => {
11163
      Representing.setValue(inputComp, searcherState.fetchPattern);
11164
      inputComp.element.dom.selectionStart = searcherState.selectionStart;
11165
      inputComp.element.dom.selectionEnd = searcherState.selectionEnd;
11166
    };
11167
    const saveState = inputComp => {
11168
      const fetchPattern = Representing.getValue(inputComp);
11169
      const selectionStart = inputComp.element.dom.selectionStart;
11170
      const selectionEnd = inputComp.element.dom.selectionEnd;
11171
      return {
11172
        fetchPattern,
11173
        selectionStart,
11174
        selectionEnd
11175
      };
11176
    };
11177
    const setActiveDescendant = (inputComp, active) => {
11178
      getOpt(active.element, 'id').each(id => set$9(inputComp.element, 'aria-activedescendant', id));
11179
    };
11180
    const renderMenuSearcher = spec => {
11181
      const handleByBrowser = (comp, se) => {
11182
        se.cut();
11183
        return Optional.none();
11184
      };
11185
      const handleByHighlightedItem = (comp, se) => {
11186
        const eventData = {
11187
          interactionEvent: se.event,
11188
          eventType: se.event.raw.type
11189
        };
11190
        emitWith(comp, redirectMenuItemInteractionEvent, eventData);
11191
        return Optional.some(true);
11192
      };
11193
      const customSearcherEventsName = 'searcher-events';
11194
      return {
11195
        dom: {
11196
          tag: 'div',
11197
          classes: [selectableClass]
11198
        },
11199
        components: [Input.sketch({
11200
            inputClasses: [
11201
              menuSearcherClass,
11202
              'tox-textfield'
11203
            ],
11204
            inputAttributes: {
11205
              ...spec.placeholder.map(placeholder => ({ placeholder: spec.i18n(placeholder) })).getOr({}),
11206
              'type': 'search',
11207
              'aria-autocomplete': 'list'
11208
            },
11209
            inputBehaviours: derive$1([
11210
              config(customSearcherEventsName, [
11211
                run$1(input(), inputComp => {
11212
                  emit(inputComp, refetchTriggerEvent);
11213
                }),
11214
                run$1(keydown(), (inputComp, se) => {
11215
                  if (se.event.raw.key === 'Escape') {
11216
                    se.stop();
11217
                  }
11218
                })
11219
              ]),
11220
              Keying.config({
11221
                mode: 'special',
11222
                onLeft: handleByBrowser,
11223
                onRight: handleByBrowser,
11224
                onSpace: handleByBrowser,
11225
                onEnter: handleByHighlightedItem,
11226
                onEscape: handleByHighlightedItem,
11227
                onUp: handleByHighlightedItem,
11228
                onDown: handleByHighlightedItem
11229
              })
11230
            ]),
11231
            eventOrder: {
11232
              keydown: [
11233
                customSearcherEventsName,
11234
                Keying.name()
11235
              ]
11236
            }
11237
          })]
11238
      };
11239
    };
11240
 
11241
    const searchResultsClass = 'tox-collection--results__js';
11242
    const augmentWithAria = item => {
11243
      var _a;
11244
      if (item.dom) {
11245
        return {
11246
          ...item,
11247
          dom: {
11248
            ...item.dom,
11249
            attributes: {
11250
              ...(_a = item.dom.attributes) !== null && _a !== void 0 ? _a : {},
11251
              'id': generate$6('aria-item-search-result-id'),
11252
              'aria-selected': 'false'
11253
            }
11254
          }
11255
        };
11256
      } else {
11257
        return item;
11258
      }
11259
    };
11260
 
11261
    const chunk = (rowDom, numColumns) => items => {
11262
      const chunks = chunk$1(items, numColumns);
11263
      return map$2(chunks, c => ({
11264
        dom: rowDom,
11265
        components: c
11266
      }));
11267
    };
11268
    const forSwatch = columns => ({
11269
      dom: {
11270
        tag: 'div',
11271
        classes: [
11272
          'tox-menu',
11273
          'tox-swatches-menu'
11274
        ]
11275
      },
11276
      components: [{
11277
          dom: {
11278
            tag: 'div',
11279
            classes: ['tox-swatches']
11280
          },
11281
          components: [Menu.parts.items({
11282
              preprocess: columns !== 'auto' ? chunk({
11283
                tag: 'div',
11284
                classes: ['tox-swatches__row']
11285
              }, columns) : identity
11286
            })]
11287
        }]
11288
    });
11289
    const forToolbar = columns => ({
11290
      dom: {
11291
        tag: 'div',
11292
        classes: [
11293
          'tox-menu',
11294
          'tox-collection',
11295
          'tox-collection--toolbar',
11296
          'tox-collection--toolbar-lg'
11297
        ]
11298
      },
11299
      components: [Menu.parts.items({
11300
          preprocess: chunk({
11301
            tag: 'div',
11302
            classes: ['tox-collection__group']
11303
          }, columns)
11304
        })]
11305
    });
11306
    const preprocessCollection = (items, isSeparator) => {
11307
      const allSplits = [];
11308
      let currentSplit = [];
11309
      each$1(items, (item, i) => {
11310
        if (isSeparator(item, i)) {
11311
          if (currentSplit.length > 0) {
11312
            allSplits.push(currentSplit);
11313
          }
11314
          currentSplit = [];
11315
          if (has$2(item.dom, 'innerHtml') || item.components && item.components.length > 0) {
11316
            currentSplit.push(item);
11317
          }
11318
        } else {
11319
          currentSplit.push(item);
11320
        }
11321
      });
11322
      if (currentSplit.length > 0) {
11323
        allSplits.push(currentSplit);
11324
      }
11325
      return map$2(allSplits, s => ({
11326
        dom: {
11327
          tag: 'div',
11328
          classes: ['tox-collection__group']
11329
        },
11330
        components: s
11331
      }));
11332
    };
11333
    const insertItemsPlaceholder = (columns, initItems, onItem) => {
11334
      return Menu.parts.items({
11335
        preprocess: rawItems => {
11336
          const enrichedItems = map$2(rawItems, onItem);
11337
          if (columns !== 'auto' && columns > 1) {
11338
            return chunk({
11339
              tag: 'div',
11340
              classes: ['tox-collection__group']
11341
            }, columns)(enrichedItems);
11342
          } else {
11343
            return preprocessCollection(enrichedItems, (_item, i) => initItems[i].type === 'separator');
11344
          }
11345
        }
11346
      });
11347
    };
11348
    const forCollection = (columns, initItems, _hasIcons = true) => ({
11349
      dom: {
11350
        tag: 'div',
11351
        classes: [
11352
          'tox-menu',
11353
          'tox-collection'
11354
        ].concat(columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid'])
11355
      },
11356
      components: [insertItemsPlaceholder(columns, initItems, identity)]
11357
    });
11358
    const forCollectionWithSearchResults = (columns, initItems, _hasIcons = true) => {
11359
      const ariaControlsSearchResults = generate$6('aria-controls-search-results');
11360
      return {
11361
        dom: {
11362
          tag: 'div',
11363
          classes: [
11364
            'tox-menu',
11365
            'tox-collection',
11366
            searchResultsClass
11367
          ].concat(columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid']),
11368
          attributes: { id: ariaControlsSearchResults }
11369
        },
11370
        components: [insertItemsPlaceholder(columns, initItems, augmentWithAria)]
11371
      };
11372
    };
11373
    const forCollectionWithSearchField = (columns, initItems, searchField) => {
11374
      const ariaControlsSearchResults = generate$6('aria-controls-search-results');
11375
      return {
11376
        dom: {
11377
          tag: 'div',
11378
          classes: [
11379
            'tox-menu',
11380
            'tox-collection'
11381
          ].concat(columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid'])
11382
        },
11383
        components: [
11384
          renderMenuSearcher({
1441 ariadna 11385
            i18n: global$5.translate,
1 efrain 11386
            placeholder: searchField.placeholder
11387
          }),
11388
          {
11389
            dom: {
11390
              tag: 'div',
11391
              classes: [
11392
                ...columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid'],
11393
                searchResultsClass
11394
              ],
11395
              attributes: { id: ariaControlsSearchResults }
11396
            },
11397
            components: [insertItemsPlaceholder(columns, initItems, augmentWithAria)]
11398
          }
11399
        ]
11400
      };
11401
    };
11402
    const forHorizontalCollection = (initItems, _hasIcons = true) => ({
11403
      dom: {
11404
        tag: 'div',
11405
        classes: [
11406
          'tox-collection',
11407
          'tox-collection--horizontal'
11408
        ]
11409
      },
11410
      components: [Menu.parts.items({ preprocess: items => preprocessCollection(items, (_item, i) => initItems[i].type === 'separator') })]
11411
    });
11412
 
11413
    const menuHasIcons = xs => exists(xs, item => 'icon' in item && item.icon !== undefined);
11414
    const handleError = error => {
11415
      console.error(formatError(error));
11416
      console.log(error);
11417
      return Optional.none();
11418
    };
11419
    const createHorizontalPartialMenuWithAlloyItems = (value, _hasIcons, items, _columns, _menuLayout) => {
11420
      const structure = forHorizontalCollection(items);
11421
      return {
11422
        value,
11423
        dom: structure.dom,
11424
        components: structure.components,
11425
        items
11426
      };
11427
    };
11428
    const createPartialMenuWithAlloyItems = (value, hasIcons, items, columns, menuLayout) => {
11429
      const getNormalStructure = () => {
11430
        if (menuLayout.menuType !== 'searchable') {
11431
          return forCollection(columns, items);
11432
        } else {
11433
          return menuLayout.searchMode.searchMode === 'search-with-field' ? forCollectionWithSearchField(columns, items, menuLayout.searchMode) : forCollectionWithSearchResults(columns, items);
11434
        }
11435
      };
11436
      if (menuLayout.menuType === 'color') {
11437
        const structure = forSwatch(columns);
11438
        return {
11439
          value,
11440
          dom: structure.dom,
11441
          components: structure.components,
11442
          items
11443
        };
11444
      } else if (menuLayout.menuType === 'normal' && columns === 'auto') {
11445
        const structure = forCollection(columns, items);
11446
        return {
11447
          value,
11448
          dom: structure.dom,
11449
          components: structure.components,
11450
          items
11451
        };
11452
      } else if (menuLayout.menuType === 'normal' || menuLayout.menuType === 'searchable') {
11453
        const structure = getNormalStructure();
11454
        return {
11455
          value,
11456
          dom: structure.dom,
11457
          components: structure.components,
11458
          items
11459
        };
11460
      } else if (menuLayout.menuType === 'listpreview' && columns !== 'auto') {
11461
        const structure = forToolbar(columns);
11462
        return {
11463
          value,
11464
          dom: structure.dom,
11465
          components: structure.components,
11466
          items
11467
        };
11468
      } else {
11469
        return {
11470
          value,
11471
          dom: dom$1(hasIcons, columns, menuLayout.menuType),
11472
          components: components,
11473
          items
11474
        };
11475
      }
11476
    };
11477
 
11478
    const type = requiredString('type');
11479
    const name$1 = requiredString('name');
11480
    const label = requiredString('label');
11481
    const text = requiredString('text');
11482
    const title = requiredString('title');
11483
    const icon = requiredString('icon');
11484
    const value$1 = requiredString('value');
11485
    const fetch$1 = requiredFunction('fetch');
11486
    const getSubmenuItems = requiredFunction('getSubmenuItems');
11487
    const onAction = requiredFunction('onAction');
11488
    const onItemAction = requiredFunction('onItemAction');
11489
    const onSetup = defaultedFunction('onSetup', () => noop);
11490
    const optionalName = optionString('name');
11491
    const optionalText = optionString('text');
1441 ariadna 11492
    const optionalRole = optionString('role');
1 efrain 11493
    const optionalIcon = optionString('icon');
11494
    const optionalTooltip = optionString('tooltip');
11495
    const optionalLabel = optionString('label');
11496
    const optionalShortcut = optionString('shortcut');
11497
    const optionalSelect = optionFunction('select');
11498
    const active = defaultedBoolean('active', false);
11499
    const borderless = defaultedBoolean('borderless', false);
11500
    const enabled = defaultedBoolean('enabled', true);
11501
    const primary = defaultedBoolean('primary', false);
11502
    const defaultedColumns = num => defaulted('columns', num);
11503
    const defaultedMeta = defaulted('meta', {});
11504
    const defaultedOnAction = defaultedFunction('onAction', noop);
11505
    const defaultedType = type => defaultedString('type', type);
11506
    const generatedName = namePrefix => field$1('name', 'name', defaultedThunk(() => generate$6(`${ namePrefix }-name`)), string);
11507
    const generatedValue = valuePrefix => field$1('value', 'value', defaultedThunk(() => generate$6(`${ valuePrefix }-value`)), anyValue());
11508
 
11509
    const separatorMenuItemSchema = objOf([
11510
      type,
11511
      optionalText
11512
    ]);
11513
    const createSeparatorMenuItem = spec => asRaw('separatormenuitem', separatorMenuItemSchema, spec);
11514
 
11515
    const autocompleterItemSchema = objOf([
11516
      defaultedType('autocompleteitem'),
11517
      active,
11518
      enabled,
11519
      defaultedMeta,
11520
      value$1,
11521
      optionalText,
11522
      optionalIcon
11523
    ]);
11524
    const createSeparatorItem = spec => asRaw('Autocompleter.Separator', separatorMenuItemSchema, spec);
11525
    const createAutocompleterItem = spec => asRaw('Autocompleter.Item', autocompleterItemSchema, spec);
11526
 
11527
    const baseToolbarButtonFields = [
11528
      enabled,
11529
      optionalTooltip,
11530
      optionalIcon,
11531
      optionalText,
1441 ariadna 11532
      onSetup,
11533
      defaultedString('context', 'mode:design')
1 efrain 11534
    ];
11535
    const toolbarButtonSchema = objOf([
11536
      type,
1441 ariadna 11537
      onAction,
11538
      optionalShortcut
1 efrain 11539
    ].concat(baseToolbarButtonFields));
11540
    const createToolbarButton = spec => asRaw('toolbarbutton', toolbarButtonSchema, spec);
11541
 
11542
    const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
11543
    const toggleButtonSchema = objOf(baseToolbarToggleButtonFields.concat([
11544
      type,
1441 ariadna 11545
      onAction,
11546
      optionalShortcut
1 efrain 11547
    ]));
11548
    const createToggleButton = spec => asRaw('ToggleButton', toggleButtonSchema, spec);
11549
 
11550
    const contextBarFields = [
11551
      defaultedFunction('predicate', never),
11552
      defaultedStringEnum('scope', 'node', [
11553
        'node',
11554
        'editor'
11555
      ]),
11556
      defaultedStringEnum('position', 'selection', [
11557
        'node',
11558
        'selection',
11559
        'line'
11560
      ])
11561
    ];
11562
 
11563
    const contextButtonFields = baseToolbarButtonFields.concat([
11564
      defaultedType('contextformbutton'),
1441 ariadna 11565
      defaultedString('align', 'end'),
1 efrain 11566
      primary,
11567
      onAction,
11568
      customField('original', identity)
11569
    ]);
11570
    const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
11571
      defaultedType('contextformbutton'),
1441 ariadna 11572
      defaultedString('align', 'end'),
1 efrain 11573
      primary,
11574
      onAction,
11575
      customField('original', identity)
11576
    ]);
11577
    const launchButtonFields = baseToolbarButtonFields.concat([defaultedType('contextformbutton')]);
11578
    const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType('contextformtogglebutton')]);
11579
    const toggleOrNormal = choose$1('type', {
11580
      contextformbutton: contextButtonFields,
11581
      contextformtogglebutton: contextToggleButtonFields
11582
    });
1441 ariadna 11583
    const baseContextFormFields = [
1 efrain 11584
      optionalLabel,
11585
      requiredArrayOf('commands', toggleOrNormal),
11586
      optionOf('launch', choose$1('type', {
11587
        contextformbutton: launchButtonFields,
11588
        contextformtogglebutton: launchToggleButtonFields
1441 ariadna 11589
      })),
11590
      defaultedFunction('onInput', noop),
11591
      defaultedFunction('onSetup', noop)
11592
    ];
11593
    const contextFormFields = [
11594
      ...contextBarFields,
11595
      ...baseContextFormFields,
11596
      requiredStringEnum('type', ['contextform']),
11597
      defaultedFunction('initValue', constant$1('')),
11598
      optionString('placeholder')
11599
    ];
11600
    const contextSliderFormFields = [
11601
      ...contextBarFields,
11602
      ...baseContextFormFields,
11603
      requiredStringEnum('type', ['contextsliderform']),
11604
      defaultedFunction('initValue', constant$1(0)),
11605
      defaultedFunction('min', constant$1(0)),
11606
      defaultedFunction('max', constant$1(100))
11607
    ];
11608
    const contextSizeInputFormFields = [
11609
      ...contextBarFields,
11610
      ...baseContextFormFields,
11611
      requiredStringEnum('type', ['contextsizeinputform']),
11612
      defaultedFunction('initValue', constant$1({
11613
        width: '',
11614
        height: ''
1 efrain 11615
      }))
1441 ariadna 11616
    ];
11617
    const contextFormSchema = choose$1('type', {
11618
      contextform: contextFormFields,
11619
      contextsliderform: contextSliderFormFields,
11620
      contextsizeinputform: contextSizeInputFormFields
11621
    });
1 efrain 11622
    const createContextForm = spec => asRaw('ContextForm', contextFormSchema, spec);
11623
 
11624
    const contextToolbarSchema = objOf([
11625
      defaultedType('contexttoolbar'),
1441 ariadna 11626
      requiredOf('items', oneOf([
11627
        string,
11628
        arrOfObj([
11629
          optionString('name'),
11630
          optionString('label'),
11631
          requiredArrayOf('items', string)
11632
        ])
11633
      ]))
1 efrain 11634
    ].concat(contextBarFields));
1441 ariadna 11635
    const toolbarGroupBackToSpec = toolbarGroup => ({
11636
      name: toolbarGroup.name.getOrUndefined(),
11637
      label: toolbarGroup.label.getOrUndefined(),
11638
      items: toolbarGroup.items
11639
    });
11640
    const contextToolbarToSpec = contextToolbar => ({
11641
      ...contextToolbar,
11642
      items: isString(contextToolbar.items) ? contextToolbar.items : map$2(contextToolbar.items, toolbarGroupBackToSpec)
11643
    });
1 efrain 11644
    const createContextToolbar = spec => asRaw('ContextToolbar', contextToolbarSchema, spec);
11645
 
11646
    const cardImageFields = [
11647
      type,
11648
      requiredString('src'),
11649
      optionString('alt'),
11650
      defaultedArrayOf('classes', [], string)
11651
    ];
11652
    const cardImageSchema = objOf(cardImageFields);
11653
 
11654
    const cardTextFields = [
11655
      type,
11656
      text,
11657
      optionalName,
11658
      defaultedArrayOf('classes', ['tox-collection__item-label'], string)
11659
    ];
11660
    const cardTextSchema = objOf(cardTextFields);
11661
 
11662
    const itemSchema$1 = valueThunk(() => choose$2('type', {
11663
      cardimage: cardImageSchema,
11664
      cardtext: cardTextSchema,
11665
      cardcontainer: cardContainerSchema
11666
    }));
11667
    const cardContainerSchema = objOf([
11668
      type,
11669
      defaultedString('direction', 'horizontal'),
11670
      defaultedString('align', 'left'),
11671
      defaultedString('valign', 'middle'),
11672
      requiredArrayOf('items', itemSchema$1)
11673
    ]);
11674
 
11675
    const commonMenuItemFields = [
11676
      enabled,
11677
      optionalText,
1441 ariadna 11678
      optionalRole,
1 efrain 11679
      optionalShortcut,
11680
      generatedValue('menuitem'),
1441 ariadna 11681
      defaultedMeta,
11682
      defaultedString('context', 'mode:design')
1 efrain 11683
    ];
11684
 
11685
    const cardMenuItemSchema = objOf([
11686
      type,
11687
      optionalLabel,
11688
      requiredArrayOf('items', itemSchema$1),
11689
      onSetup,
11690
      defaultedOnAction
11691
    ].concat(commonMenuItemFields));
11692
    const createCardMenuItem = spec => asRaw('cardmenuitem', cardMenuItemSchema, spec);
11693
 
11694
    const choiceMenuItemSchema = objOf([
11695
      type,
11696
      active,
11697
      optionalIcon
11698
    ].concat(commonMenuItemFields));
11699
    const createChoiceMenuItem = spec => asRaw('choicemenuitem', choiceMenuItemSchema, spec);
11700
 
11701
    const baseFields = [
11702
      type,
11703
      requiredString('fancytype'),
11704
      defaultedOnAction
11705
    ];
11706
    const insertTableFields = [defaulted('initData', {})].concat(baseFields);
11707
    const colorSwatchFields = [
11708
      optionFunction('select'),
11709
      defaultedObjOf('initData', {}, [
11710
        defaultedBoolean('allowCustomColors', true),
11711
        defaultedString('storageKey', 'default'),
11712
        optionArrayOf('colors', anyValue())
11713
      ])
11714
    ].concat(baseFields);
11715
    const fancyMenuItemSchema = choose$1('fancytype', {
11716
      inserttable: insertTableFields,
11717
      colorswatch: colorSwatchFields
11718
    });
11719
    const createFancyMenuItem = spec => asRaw('fancymenuitem', fancyMenuItemSchema, spec);
11720
 
11721
    const menuItemSchema = objOf([
11722
      type,
11723
      onSetup,
11724
      defaultedOnAction,
11725
      optionalIcon
11726
    ].concat(commonMenuItemFields));
11727
    const createMenuItem = spec => asRaw('menuitem', menuItemSchema, spec);
11728
 
11729
    const nestedMenuItemSchema = objOf([
11730
      type,
11731
      getSubmenuItems,
11732
      onSetup,
11733
      optionalIcon
11734
    ].concat(commonMenuItemFields));
11735
    const createNestedMenuItem = spec => asRaw('nestedmenuitem', nestedMenuItemSchema, spec);
11736
 
11737
    const toggleMenuItemSchema = objOf([
11738
      type,
11739
      optionalIcon,
11740
      active,
11741
      onSetup,
11742
      onAction
11743
    ].concat(commonMenuItemFields));
11744
    const createToggleMenuItem = spec => asRaw('togglemenuitem', toggleMenuItemSchema, spec);
11745
 
11746
    const detectSize = (comp, margin, selectorClass) => {
11747
      const descendants$1 = descendants(comp.element, '.' + selectorClass);
11748
      if (descendants$1.length > 0) {
11749
        const columnLength = findIndex$1(descendants$1, c => {
11750
          const thisTop = c.dom.getBoundingClientRect().top;
11751
          const cTop = descendants$1[0].dom.getBoundingClientRect().top;
11752
          return Math.abs(thisTop - cTop) > margin;
11753
        }).getOr(descendants$1.length);
11754
        return Optional.some({
11755
          numColumns: columnLength,
11756
          numRows: Math.ceil(descendants$1.length / columnLength)
11757
        });
11758
      } else {
11759
        return Optional.none();
11760
      }
11761
    };
11762
 
11763
    const namedEvents = (name, handlers) => derive$1([config(name, handlers)]);
11764
    const unnamedEvents = handlers => namedEvents(generate$6('unnamed-events'), handlers);
11765
    const SimpleBehaviours = {
11766
      namedEvents,
11767
      unnamedEvents
11768
    };
11769
 
11770
    const escape = text => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
11771
 
11772
    const item = disabled => Disabling.config({
11773
      disabled,
11774
      disableClass: 'tox-collection__item--state-disabled'
11775
    });
11776
    const button = disabled => Disabling.config({ disabled });
11777
    const splitButton = disabled => Disabling.config({
11778
      disabled,
11779
      disableClass: 'tox-tbtn--disabled'
11780
    });
11781
    const toolbarButton = disabled => Disabling.config({
11782
      disabled,
11783
      disableClass: 'tox-tbtn--disabled',
11784
      useNative: false
11785
    });
11786
    const DisablingConfigs = {
11787
      item,
11788
      button,
11789
      splitButton,
11790
      toolbarButton
11791
    };
11792
 
11793
    const runWithApi = (info, comp) => {
11794
      const api = info.getApi(comp);
11795
      return f => {
11796
        f(api);
11797
      };
11798
    };
11799
    const onControlAttached = (info, editorOffCell) => runOnAttached(comp => {
1441 ariadna 11800
      if (isFunction(info.onBeforeSetup)) {
11801
        info.onBeforeSetup(comp);
11802
      }
1 efrain 11803
      const run = runWithApi(info, comp);
11804
      run(api => {
11805
        const onDestroy = info.onSetup(api);
11806
        if (isFunction(onDestroy)) {
11807
          editorOffCell.set(onDestroy);
11808
        }
11809
      });
11810
    });
11811
    const onControlDetached = (getApi, editorOffCell) => runOnDetached(comp => runWithApi(getApi, comp)(editorOffCell.get()));
11812
 
1441 ariadna 11813
    const UiStateChannel = 'silver.uistate';
11814
    const messageSetDisabled = 'setDisabled';
11815
    const messageSetEnabled = 'setEnabled';
11816
    const messageInit = 'init';
11817
    const messageSwitchMode = 'switchmode';
11818
    const modeContextMessages = [
11819
      messageSwitchMode,
11820
      messageInit
11821
    ];
11822
    const broadcastEvents = (uiRefs, messageType) => {
11823
      const outerContainer = uiRefs.mainUi.outerContainer;
11824
      const motherships = [
11825
        uiRefs.mainUi.mothership,
11826
        ...uiRefs.uiMotherships
11827
      ];
11828
      if (messageType === messageSetDisabled) {
11829
        each$1(motherships, m => {
11830
          m.broadcastOn([dismissPopups()], { target: outerContainer.element });
11831
        });
11832
      }
11833
      each$1(motherships, m => {
11834
        m.broadcastOn([UiStateChannel], messageType);
11835
      });
11836
    };
11837
    const setupEventsForUi = (editor, uiRefs) => {
11838
      editor.on('init SwitchMode', event => {
11839
        broadcastEvents(uiRefs, event.type);
11840
      });
11841
      editor.on('DisabledStateChange', event => {
11842
        if (!event.isDefaultPrevented()) {
11843
          const messageType = event.state ? messageSetDisabled : messageInit;
11844
          broadcastEvents(uiRefs, messageType);
11845
          if (!event.state) {
11846
            editor.nodeChanged();
11847
          }
11848
        }
11849
      });
11850
      editor.on('NodeChange', e => {
11851
        const messageType = editor.ui.isEnabled() ? e.type : messageSetDisabled;
11852
        broadcastEvents(uiRefs, messageType);
11853
      });
11854
      if (isReadOnly(editor)) {
11855
        editor.mode.set('readonly');
11856
      }
11857
    };
11858
    const toggleOnReceive = getContext => Receiving.config({
11859
      channels: {
11860
        [UiStateChannel]: {
11861
          onReceive: (comp, messageType) => {
11862
            if (messageType === messageSetDisabled || messageType === messageSetEnabled) {
11863
              Disabling.set(comp, messageType === messageSetDisabled);
11864
              return;
11865
            }
11866
            const {contextType, shouldDisable} = getContext();
11867
            if (contextType === 'mode' && !contains$2(modeContextMessages, messageType)) {
11868
              return;
11869
            }
11870
            Disabling.set(comp, shouldDisable);
11871
          }
11872
        }
11873
      }
11874
    });
11875
 
1 efrain 11876
    const onMenuItemExecute = (info, itemResponse) => runOnExecute$1((comp, simulatedEvent) => {
11877
      runWithApi(info, comp)(info.onAction);
11878
      if (!info.triggersSubmenu && itemResponse === ItemResponse$1.CLOSE_ON_EXECUTE) {
11879
        if (comp.getSystem().isConnected()) {
11880
          emit(comp, sandboxClose());
11881
        }
11882
        simulatedEvent.stop();
11883
      }
11884
    });
11885
    const menuItemEventOrder = {
11886
      [execute$5()]: [
11887
        'disabling',
11888
        'alloy.base.behaviour',
11889
        'toggling',
11890
        'item-events'
11891
      ]
11892
    };
11893
 
11894
    const componentRenderPipeline = cat;
11895
    const renderCommonItem = (spec, structure, itemResponse, providersBackstage) => {
11896
      const editorOffCell = Cell(noop);
11897
      return {
11898
        type: 'item',
11899
        dom: structure.dom,
11900
        components: componentRenderPipeline(structure.optComponents),
11901
        data: spec.data,
11902
        eventOrder: menuItemEventOrder,
11903
        hasSubmenu: spec.triggersSubmenu,
11904
        itemBehaviours: derive$1([
11905
          config('item-events', [
11906
            onMenuItemExecute(spec, itemResponse),
11907
            onControlAttached(spec, editorOffCell),
11908
            onControlDetached(spec, editorOffCell)
11909
          ]),
1441 ariadna 11910
          DisablingConfigs.item(() => !spec.enabled || providersBackstage.checkUiComponentContext(spec.context).shouldDisable),
11911
          toggleOnReceive(() => providersBackstage.checkUiComponentContext(spec.context)),
1 efrain 11912
          Replacing.config({})
11913
        ].concat(spec.itemBehaviours))
11914
      };
11915
    };
11916
    const buildData = source => ({
11917
      value: source.value,
11918
      meta: {
11919
        text: source.text.getOr(''),
11920
        ...source.meta
11921
      }
11922
    });
11923
 
11924
    const convertText = source => {
1441 ariadna 11925
      const isMac = global$6.os.isMacOS() || global$6.os.isiOS();
1 efrain 11926
      const mac = {
11927
        alt: '\u2325',
11928
        ctrl: '\u2303',
11929
        shift: '\u21E7',
11930
        meta: '\u2318',
11931
        access: '\u2303\u2325'
11932
      };
11933
      const other = {
11934
        meta: 'Ctrl',
11935
        access: 'Shift+Alt'
11936
      };
11937
      const replace = isMac ? mac : other;
11938
      const shortcut = source.split('+');
11939
      const updated = map$2(shortcut, segment => {
11940
        const search = segment.toLowerCase().trim();
11941
        return has$2(replace, search) ? replace[search] : segment;
11942
      });
11943
      return isMac ? updated.join('') : updated.join('+');
11944
    };
11945
 
11946
    const renderIcon$2 = (name, icons, classes = [iconClass]) => render$3(name, {
11947
      tag: 'div',
11948
      classes
11949
    }, icons);
11950
    const renderText = text => ({
11951
      dom: {
11952
        tag: 'div',
11953
        classes: [textClass]
11954
      },
1441 ariadna 11955
      components: [text$2(global$5.translate(text))]
1 efrain 11956
    });
11957
    const renderHtml = (html, classes) => ({
11958
      dom: {
11959
        tag: 'div',
11960
        classes,
11961
        innerHtml: html
11962
      }
11963
    });
11964
    const renderStyledText = (style, text) => ({
11965
      dom: {
11966
        tag: 'div',
11967
        classes: [textClass]
11968
      },
11969
      components: [{
11970
          dom: {
11971
            tag: style.tag,
11972
            styles: style.styles
11973
          },
1441 ariadna 11974
          components: [text$2(global$5.translate(text))]
1 efrain 11975
        }]
11976
    });
11977
    const renderShortcut = shortcut => ({
11978
      dom: {
11979
        tag: 'div',
11980
        classes: [accessoryClass]
11981
      },
11982
      components: [text$2(convertText(shortcut))]
11983
    });
11984
    const renderCheckmark = icons => renderIcon$2('checkmark', icons, [checkmarkClass]);
11985
    const renderSubmenuCaret = icons => renderIcon$2('chevron-right', icons, [caretClass]);
11986
    const renderDownwardsCaret = icons => renderIcon$2('chevron-down', icons, [caretClass]);
11987
    const renderContainer = (container, components) => {
11988
      const directionClass = container.direction === 'vertical' ? containerColumnClass : containerRowClass;
11989
      const alignClass = container.align === 'left' ? containerAlignLeftClass : containerAlignRightClass;
11990
      const getValignClass = () => {
11991
        switch (container.valign) {
11992
        case 'top':
11993
          return containerValignTopClass;
11994
        case 'middle':
11995
          return containerValignMiddleClass;
11996
        case 'bottom':
11997
          return containerValignBottomClass;
11998
        }
11999
      };
12000
      return {
12001
        dom: {
12002
          tag: 'div',
12003
          classes: [
12004
            containerClass,
12005
            directionClass,
12006
            alignClass,
12007
            getValignClass()
12008
          ]
12009
        },
12010
        components
12011
      };
12012
    };
12013
    const renderImage = (src, classes, alt) => ({
12014
      dom: {
12015
        tag: 'img',
12016
        classes,
12017
        attributes: {
12018
          src,
12019
          alt: alt.getOr('')
12020
        }
12021
      }
12022
    });
12023
 
12024
    const renderColorStructure = (item, providerBackstage, fallbackIcon) => {
12025
      const colorPickerCommand = 'custom';
12026
      const removeColorCommand = 'remove';
12027
      const itemValue = item.value;
12028
      const iconSvg = item.iconContent.map(name => getOr(name, providerBackstage.icons, fallbackIcon));
1441 ariadna 12029
      const attributes = item.ariaLabel.map(al => ({
12030
        'aria-label': providerBackstage.translate(al),
12031
        'data-mce-name': al
12032
      })).getOr({});
1 efrain 12033
      const getDom = () => {
12034
        const common = colorClass;
12035
        const icon = iconSvg.getOr('');
12036
        const baseDom = {
12037
          tag: 'div',
12038
          attributes,
12039
          classes: [common]
12040
        };
12041
        if (itemValue === colorPickerCommand) {
12042
          return {
12043
            ...baseDom,
12044
            tag: 'button',
12045
            classes: [
12046
              ...baseDom.classes,
12047
              'tox-swatches__picker-btn'
12048
            ],
12049
            innerHtml: icon
12050
          };
12051
        } else if (itemValue === removeColorCommand) {
12052
          return {
12053
            ...baseDom,
12054
            classes: [
12055
              ...baseDom.classes,
12056
              'tox-swatch--remove'
12057
            ],
12058
            innerHtml: icon
12059
          };
12060
        } else if (isNonNullable(itemValue)) {
12061
          return {
12062
            ...baseDom,
12063
            attributes: {
12064
              ...baseDom.attributes,
12065
              'data-mce-color': itemValue
12066
            },
12067
            styles: { 'background-color': itemValue },
12068
            innerHtml: icon
12069
          };
12070
        } else {
12071
          return baseDom;
12072
        }
12073
      };
12074
      return {
12075
        dom: getDom(),
12076
        optComponents: []
12077
      };
12078
    };
12079
    const renderItemDomStructure = ariaLabel => {
12080
      const domTitle = ariaLabel.map(label => ({
12081
        attributes: {
1441 ariadna 12082
          'id': generate$6('menu-item'),
12083
          'aria-label': global$5.translate(label)
1 efrain 12084
        }
12085
      })).getOr({});
12086
      return {
12087
        tag: 'div',
12088
        classes: [
12089
          navClass,
12090
          selectableClass
12091
        ],
12092
        ...domTitle
12093
      };
12094
    };
12095
    const renderNormalItemStructure = (info, providersBackstage, renderIcons, fallbackIcon) => {
12096
      const iconSpec = {
12097
        tag: 'div',
12098
        classes: [iconClass]
12099
      };
12100
      const renderIcon = iconName => render$3(iconName, iconSpec, providersBackstage.icons, fallbackIcon);
12101
      const renderEmptyIcon = () => Optional.some({ dom: iconSpec });
12102
      const leftIcon = renderIcons ? info.iconContent.map(renderIcon).orThunk(renderEmptyIcon) : Optional.none();
12103
      const checkmark = info.checkMark;
12104
      const textRender = Optional.from(info.meta).fold(() => renderText, meta => has$2(meta, 'style') ? curry(renderStyledText, meta.style) : renderText);
12105
      const content = info.htmlContent.fold(() => info.textContent.map(textRender), html => Optional.some(renderHtml(html, [textClass])));
12106
      const menuItem = {
12107
        dom: renderItemDomStructure(info.ariaLabel),
12108
        optComponents: [
12109
          leftIcon,
12110
          content,
12111
          info.shortcutContent.map(renderShortcut),
12112
          checkmark,
12113
          info.caret
12114
        ]
12115
      };
12116
      return menuItem;
12117
    };
12118
    const renderItemStructure = (info, providersBackstage, renderIcons, fallbackIcon = Optional.none()) => {
12119
      if (info.presets === 'color') {
12120
        return renderColorStructure(info, providersBackstage, fallbackIcon);
12121
      } else {
12122
        return renderNormalItemStructure(info, providersBackstage, renderIcons, fallbackIcon);
12123
      }
12124
    };
12125
 
1441 ariadna 12126
    const tooltipBehaviour = (meta, sharedBackstage, tooltipText) => get$h(meta, 'tooltipWorker').map(tooltipWorker => [Tooltipping.config({
1 efrain 12127
        lazySink: sharedBackstage.getSink,
12128
        tooltipDom: {
12129
          tag: 'div',
12130
          classes: ['tox-tooltip-worker-container']
12131
        },
12132
        tooltipComponents: [],
12133
        anchor: comp => ({
12134
          type: 'submenu',
12135
          item: comp,
12136
          overrides: { maxHeightFunction: expandable$1 }
12137
        }),
12138
        mode: 'follow-highlight',
12139
        onShow: (component, _tooltip) => {
12140
          tooltipWorker(elm => {
12141
            Tooltipping.setComponents(component, [external$1({ element: SugarElement.fromDom(elm) })]);
12142
          });
12143
        }
1441 ariadna 12144
      })]).getOrThunk(() => {
12145
      return tooltipText.map(text => [Tooltipping.config({
12146
          ...sharedBackstage.providers.tooltips.getConfig({ tooltipText: text }),
12147
          mode: 'follow-highlight'
12148
        })]).getOr([]);
12149
    });
12150
    const encodeText = text => global$8.DOM.encode(text);
1 efrain 12151
    const replaceText = (text, matchText) => {
1441 ariadna 12152
      const translated = global$5.translate(text);
1 efrain 12153
      const encoded = encodeText(translated);
12154
      if (matchText.length > 0) {
12155
        const escapedMatchRegex = new RegExp(escape(matchText), 'gi');
12156
        return encoded.replace(escapedMatchRegex, match => `<span class="tox-autocompleter-highlight">${ match }</span>`);
12157
      } else {
12158
        return encoded;
12159
      }
12160
    };
12161
    const renderAutocompleteItem = (spec, matchText, useText, presets, onItemValueHandler, itemResponse, sharedBackstage, renderIcons = true) => {
12162
      const structure = renderItemStructure({
12163
        presets,
12164
        textContent: Optional.none(),
12165
        htmlContent: useText ? spec.text.map(text => replaceText(text, matchText)) : Optional.none(),
12166
        ariaLabel: spec.text,
12167
        iconContent: spec.icon,
12168
        shortcutContent: Optional.none(),
12169
        checkMark: Optional.none(),
12170
        caret: Optional.none(),
12171
        value: spec.value
12172
      }, sharedBackstage.providers, renderIcons, spec.icon);
1441 ariadna 12173
      const tooltipString = spec.text.filter(text => !useText && text !== '');
1 efrain 12174
      return renderCommonItem({
1441 ariadna 12175
        context: 'mode:design',
1 efrain 12176
        data: buildData(spec),
12177
        enabled: spec.enabled,
12178
        getApi: constant$1({}),
12179
        onAction: _api => onItemValueHandler(spec.value, spec.meta),
12180
        onSetup: constant$1(noop),
12181
        triggersSubmenu: false,
1441 ariadna 12182
        itemBehaviours: tooltipBehaviour(spec, sharedBackstage, tooltipString)
1 efrain 12183
      }, structure, itemResponse, sharedBackstage.providers);
12184
    };
12185
 
12186
    const render$2 = (items, extras) => map$2(items, item => {
12187
      switch (item.type) {
12188
      case 'cardcontainer':
12189
        return renderContainer(item, render$2(item.items, extras));
12190
      case 'cardimage':
12191
        return renderImage(item.src, item.classes, item.alt);
12192
      case 'cardtext':
12193
        const shouldHighlight = item.name.exists(name => contains$2(extras.cardText.highlightOn, name));
12194
        const matchText = shouldHighlight ? Optional.from(extras.cardText.matchText).getOr('') : '';
12195
        return renderHtml(replaceText(item.text, matchText), item.classes);
12196
      }
12197
    });
12198
    const renderCardMenuItem = (spec, itemResponse, sharedBackstage, extras) => {
12199
      const getApi = component => ({
12200
        isEnabled: () => !Disabling.isDisabled(component),
12201
        setEnabled: state => {
12202
          Disabling.set(component, !state);
12203
          each$1(descendants(component.element, '*'), elm => {
12204
            component.getSystem().getByDom(elm).each(comp => {
12205
              if (comp.hasConfigured(Disabling)) {
12206
                Disabling.set(comp, !state);
12207
              }
12208
            });
12209
          });
12210
        }
12211
      });
12212
      const structure = {
12213
        dom: renderItemDomStructure(spec.label),
12214
        optComponents: [Optional.some({
12215
            dom: {
12216
              tag: 'div',
12217
              classes: [
12218
                containerClass,
12219
                containerRowClass
12220
              ]
12221
            },
12222
            components: render$2(spec.items, extras)
12223
          })]
12224
      };
12225
      return renderCommonItem({
1441 ariadna 12226
        context: 'mode:design',
1 efrain 12227
        data: buildData({
12228
          text: Optional.none(),
12229
          ...spec
12230
        }),
12231
        enabled: spec.enabled,
12232
        getApi,
12233
        onAction: spec.onAction,
12234
        onSetup: spec.onSetup,
12235
        triggersSubmenu: false,
12236
        itemBehaviours: Optional.from(extras.itemBehaviours).getOr([])
12237
      }, structure, itemResponse, sharedBackstage.providers);
12238
    };
12239
 
12240
    const renderChoiceItem = (spec, useText, presets, onItemValueHandler, isSelected, itemResponse, providersBackstage, renderIcons = true) => {
12241
      const getApi = component => ({
12242
        setActive: state => {
12243
          Toggling.set(component, state);
12244
        },
12245
        isActive: () => Toggling.isOn(component),
12246
        isEnabled: () => !Disabling.isDisabled(component),
12247
        setEnabled: state => Disabling.set(component, !state)
12248
      });
12249
      const structure = renderItemStructure({
12250
        presets,
12251
        textContent: useText ? spec.text : Optional.none(),
12252
        htmlContent: Optional.none(),
12253
        ariaLabel: spec.text,
12254
        iconContent: spec.icon,
12255
        shortcutContent: useText ? spec.shortcut : Optional.none(),
12256
        checkMark: useText ? Optional.some(renderCheckmark(providersBackstage.icons)) : Optional.none(),
12257
        caret: Optional.none(),
12258
        value: spec.value
12259
      }, providersBackstage, renderIcons);
1441 ariadna 12260
      const optTooltipping = spec.text.filter(constant$1(!useText)).map(t => Tooltipping.config(providersBackstage.tooltips.getConfig({ tooltipText: providersBackstage.translate(t) })));
1 efrain 12261
      return deepMerge(renderCommonItem({
1441 ariadna 12262
        context: spec.context,
1 efrain 12263
        data: buildData(spec),
12264
        enabled: spec.enabled,
12265
        getApi,
12266
        onAction: _api => onItemValueHandler(spec.value),
12267
        onSetup: api => {
12268
          api.setActive(isSelected);
12269
          return noop;
12270
        },
12271
        triggersSubmenu: false,
1441 ariadna 12272
        itemBehaviours: [...optTooltipping.toArray()]
1 efrain 12273
      }, structure, itemResponse, providersBackstage), {
12274
        toggling: {
12275
          toggleClass: tickedClass,
12276
          toggleOnExecute: false,
12277
          selected: spec.active,
12278
          exclusive: true
12279
        }
12280
      });
12281
    };
12282
 
12283
    const parts$f = generate$3(owner$2(), parts$h());
12284
 
12285
    const hexColour = value => ({ value: normalizeHex(value) });
12286
    const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
12287
    const longformRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
12288
    const isHexString = hex => shorthandRegex.test(hex) || longformRegex.test(hex);
12289
    const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();
12290
    const fromString$1 = hex => isHexString(hex) ? Optional.some({ value: normalizeHex(hex) }) : Optional.none();
12291
    const getLongForm = hex => {
12292
      const hexString = hex.value.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
12293
      return { value: hexString };
12294
    };
12295
    const extractValues = hex => {
12296
      const longForm = getLongForm(hex);
12297
      const splitForm = longformRegex.exec(longForm.value);
12298
      return splitForm === null ? [
12299
        'FFFFFF',
12300
        'FF',
12301
        'FF',
12302
        'FF'
12303
      ] : splitForm;
12304
    };
12305
    const toHex = component => {
12306
      const hex = component.toString(16);
12307
      return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
12308
    };
12309
    const fromRgba = rgbaColour => {
12310
      const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
12311
      return hexColour(value);
12312
    };
12313
 
12314
    const min = Math.min;
12315
    const max = Math.max;
12316
    const round$1 = Math.round;
1441 ariadna 12317
    const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*\)\s*$/i;
12318
    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 12319
    const rgbaColour = (red, green, blue, alpha) => ({
12320
      red,
12321
      green,
12322
      blue,
12323
      alpha
12324
    });
12325
    const isRgbaComponent = value => {
12326
      const num = parseInt(value, 10);
12327
      return num.toString() === value && num >= 0 && num <= 255;
12328
    };
12329
    const fromHsv = hsv => {
12330
      let r;
12331
      let g;
12332
      let b;
12333
      const hue = (hsv.hue || 0) % 360;
12334
      let saturation = hsv.saturation / 100;
12335
      let brightness = hsv.value / 100;
12336
      saturation = max(0, min(saturation, 1));
12337
      brightness = max(0, min(brightness, 1));
12338
      if (saturation === 0) {
12339
        r = g = b = round$1(255 * brightness);
12340
        return rgbaColour(r, g, b, 1);
12341
      }
12342
      const side = hue / 60;
12343
      const chroma = brightness * saturation;
12344
      const x = chroma * (1 - Math.abs(side % 2 - 1));
12345
      const match = brightness - chroma;
12346
      switch (Math.floor(side)) {
12347
      case 0:
12348
        r = chroma;
12349
        g = x;
12350
        b = 0;
12351
        break;
12352
      case 1:
12353
        r = x;
12354
        g = chroma;
12355
        b = 0;
12356
        break;
12357
      case 2:
12358
        r = 0;
12359
        g = chroma;
12360
        b = x;
12361
        break;
12362
      case 3:
12363
        r = 0;
12364
        g = x;
12365
        b = chroma;
12366
        break;
12367
      case 4:
12368
        r = x;
12369
        g = 0;
12370
        b = chroma;
12371
        break;
12372
      case 5:
12373
        r = chroma;
12374
        g = 0;
12375
        b = x;
12376
        break;
12377
      default:
12378
        r = g = b = 0;
12379
      }
12380
      r = round$1(255 * (r + match));
12381
      g = round$1(255 * (g + match));
12382
      b = round$1(255 * (b + match));
12383
      return rgbaColour(r, g, b, 1);
12384
    };
12385
    const fromHex = hexColour => {
12386
      const result = extractValues(hexColour);
12387
      const red = parseInt(result[1], 16);
12388
      const green = parseInt(result[2], 16);
12389
      const blue = parseInt(result[3], 16);
12390
      return rgbaColour(red, green, blue, 1);
12391
    };
12392
    const fromStringValues = (red, green, blue, alpha) => {
12393
      const r = parseInt(red, 10);
12394
      const g = parseInt(green, 10);
12395
      const b = parseInt(blue, 10);
12396
      const a = parseFloat(alpha);
12397
      return rgbaColour(r, g, b, a);
12398
    };
12399
    const fromString = rgbaString => {
12400
      const rgbMatch = rgbRegex.exec(rgbaString);
12401
      if (rgbMatch !== null) {
12402
        return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
12403
      }
12404
      const rgbaMatch = rgbaRegex.exec(rgbaString);
12405
      if (rgbaMatch !== null) {
12406
        return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
12407
      }
12408
      return Optional.none();
12409
    };
12410
    const toString = rgba => `rgba(${ rgba.red },${ rgba.green },${ rgba.blue },${ rgba.alpha })`;
12411
    const red = rgbaColour(255, 0, 0, 1);
12412
 
12413
    const fireSkinLoaded$1 = editor => {
12414
      editor.dispatch('SkinLoaded');
12415
    };
12416
    const fireSkinLoadError$1 = (editor, error) => {
12417
      editor.dispatch('SkinLoadError', error);
12418
    };
12419
    const fireResizeEditor = editor => {
12420
      editor.dispatch('ResizeEditor');
12421
    };
12422
    const fireResizeContent = (editor, e) => {
12423
      editor.dispatch('ResizeContent', e);
12424
    };
12425
    const fireScrollContent = (editor, e) => {
12426
      editor.dispatch('ScrollContent', e);
12427
    };
12428
    const fireTextColorChange = (editor, data) => {
12429
      editor.dispatch('TextColorChange', data);
12430
    };
12431
    const fireAfterProgressState = (editor, state) => {
12432
      editor.dispatch('AfterProgressState', { state });
12433
    };
12434
    const fireResolveName = (editor, node) => editor.dispatch('ResolveName', {
12435
      name: node.nodeName.toLowerCase(),
12436
      target: node
12437
    });
12438
    const fireToggleToolbarDrawer = (editor, state) => {
12439
      editor.dispatch('ToggleToolbarDrawer', { state });
12440
    };
12441
    const fireStylesTextUpdate = (editor, data) => {
12442
      editor.dispatch('StylesTextUpdate', data);
12443
    };
12444
    const fireAlignTextUpdate = (editor, data) => {
12445
      editor.dispatch('AlignTextUpdate', data);
12446
    };
12447
    const fireFontSizeTextUpdate = (editor, data) => {
12448
      editor.dispatch('FontSizeTextUpdate', data);
12449
    };
12450
    const fireFontSizeInputTextUpdate = (editor, data) => {
12451
      editor.dispatch('FontSizeInputTextUpdate', data);
12452
    };
12453
    const fireBlocksTextUpdate = (editor, data) => {
12454
      editor.dispatch('BlocksTextUpdate', data);
12455
    };
12456
    const fireFontFamilyTextUpdate = (editor, data) => {
12457
      editor.dispatch('FontFamilyTextUpdate', data);
12458
    };
1441 ariadna 12459
    const fireToggleSidebar = editor => {
12460
      editor.dispatch('ToggleSidebar');
12461
    };
12462
    const fireToggleView = editor => {
12463
      editor.dispatch('ToggleView');
12464
    };
12465
    const fireContextToolbarClose = editor => {
12466
      editor.dispatch('ContextToolbarClose');
12467
    };
12468
    const fireContextFormSlideBack = editor => {
12469
      editor.dispatch('ContextFormSlideBack');
12470
    };
1 efrain 12471
 
12472
    const composeUnbinders = (f, g) => () => {
12473
      f();
12474
      g();
12475
    };
12476
    const onSetupEditableToggle = editor => onSetupEvent(editor, 'NodeChange', api => {
12477
      api.setEnabled(editor.selection.isEditable());
12478
    });
12479
    const onSetupFormatToggle = (editor, name) => api => {
12480
      const boundFormatChangeCallback = unbindable();
12481
      const init = () => {
12482
        api.setActive(editor.formatter.match(name));
12483
        const binding = editor.formatter.formatChanged(name, api.setActive);
12484
        boundFormatChangeCallback.set(binding);
12485
      };
12486
      editor.initialized ? init() : editor.once('init', init);
12487
      return () => {
12488
        editor.off('init', init);
12489
        boundFormatChangeCallback.clear();
12490
      };
12491
    };
12492
    const onSetupStateToggle = (editor, name) => api => {
12493
      const unbindEditableToogle = onSetupEditableToggle(editor)(api);
12494
      const unbindFormatToggle = onSetupFormatToggle(editor, name)(api);
12495
      return () => {
12496
        unbindEditableToogle();
12497
        unbindFormatToggle();
12498
      };
12499
    };
12500
    const onSetupEvent = (editor, event, f) => api => {
12501
      const handleEvent = () => f(api);
12502
      const init = () => {
12503
        f(api);
12504
        editor.on(event, handleEvent);
12505
      };
12506
      editor.initialized ? init() : editor.once('init', init);
12507
      return () => {
12508
        editor.off('init', init);
12509
        editor.off(event, handleEvent);
12510
      };
12511
    };
12512
    const onActionToggleFormat$1 = editor => rawItem => () => {
12513
      editor.undoManager.transact(() => {
12514
        editor.focus();
12515
        editor.execCommand('mceToggleFormat', false, rawItem.format);
12516
      });
12517
    };
12518
    const onActionExecCommand = (editor, command) => () => editor.execCommand(command);
12519
 
12520
    var global$4 = tinymce.util.Tools.resolve('tinymce.util.LocalStorage');
12521
 
12522
    const cacheStorage = {};
12523
    const ColorCache = (storageId, max = 10) => {
12524
      const storageString = global$4.getItem(storageId);
12525
      const localstorage = isString(storageString) ? JSON.parse(storageString) : [];
12526
      const prune = list => {
12527
        const diff = max - list.length;
12528
        return diff < 0 ? list.slice(0, max) : list;
12529
      };
12530
      const cache = prune(localstorage);
12531
      const add = key => {
12532
        indexOf(cache, key).each(remove);
12533
        cache.unshift(key);
12534
        if (cache.length > max) {
12535
          cache.pop();
12536
        }
12537
        global$4.setItem(storageId, JSON.stringify(cache));
12538
      };
12539
      const remove = idx => {
12540
        cache.splice(idx, 1);
12541
      };
12542
      const state = () => cache.slice(0);
12543
      return {
12544
        add,
12545
        state
12546
      };
12547
    };
1441 ariadna 12548
    const getCacheForId = id => get$h(cacheStorage, id).getOrThunk(() => {
1 efrain 12549
      const storageId = `tinymce-custom-colors-${ id }`;
12550
      const currentData = global$4.getItem(storageId);
12551
      if (isNullable(currentData)) {
12552
        const legacyDefault = global$4.getItem('tinymce-custom-colors');
12553
        global$4.setItem(storageId, isNonNullable(legacyDefault) ? legacyDefault : '[]');
12554
      }
12555
      const storage = ColorCache(storageId, 10);
12556
      cacheStorage[id] = storage;
12557
      return storage;
12558
    });
12559
    const getCurrentColors = id => map$2(getCacheForId(id).state(), color => ({
12560
      type: 'choiceitem',
12561
      text: color,
12562
      icon: 'checkmark',
12563
      value: color
12564
    }));
12565
    const addColor = (id, color) => {
12566
      getCacheForId(id).add(color);
12567
    };
12568
 
12569
    const hsvColour = (hue, saturation, value) => ({
12570
      hue,
12571
      saturation,
12572
      value
12573
    });
12574
    const fromRgb = rgbaColour => {
12575
      let h = 0;
12576
      let s = 0;
12577
      let v = 0;
12578
      const r = rgbaColour.red / 255;
12579
      const g = rgbaColour.green / 255;
12580
      const b = rgbaColour.blue / 255;
12581
      const minRGB = Math.min(r, Math.min(g, b));
12582
      const maxRGB = Math.max(r, Math.max(g, b));
12583
      if (minRGB === maxRGB) {
12584
        v = minRGB;
12585
        return hsvColour(0, 0, v * 100);
12586
      }
12587
      const d = r === minRGB ? g - b : b === minRGB ? r - g : b - r;
12588
      h = r === minRGB ? 3 : b === minRGB ? 1 : 5;
12589
      h = 60 * (h - d / (maxRGB - minRGB));
12590
      s = (maxRGB - minRGB) / maxRGB;
12591
      v = maxRGB;
12592
      return hsvColour(Math.round(h), Math.round(s * 100), Math.round(v * 100));
12593
    };
12594
 
12595
    const hexToHsv = hex => fromRgb(fromHex(hex));
12596
    const hsvToHex = hsv => fromRgba(fromHsv(hsv));
12597
    const anyToHex = color => fromString$1(color).orThunk(() => fromString(color).map(fromRgba)).getOrThunk(() => {
12598
      const canvas = document.createElement('canvas');
12599
      canvas.height = 1;
12600
      canvas.width = 1;
12601
      const canvasContext = canvas.getContext('2d');
12602
      canvasContext.clearRect(0, 0, canvas.width, canvas.height);
12603
      canvasContext.fillStyle = '#FFFFFF';
12604
      canvasContext.fillStyle = color;
12605
      canvasContext.fillRect(0, 0, 1, 1);
12606
      const rgba = canvasContext.getImageData(0, 0, 1, 1).data;
12607
      const r = rgba[0];
12608
      const g = rgba[1];
12609
      const b = rgba[2];
12610
      const a = rgba[3];
12611
      return fromRgba(rgbaColour(r, g, b, a));
12612
    });
12613
 
12614
    const foregroundId = 'forecolor';
12615
    const backgroundId = 'hilitecolor';
12616
    const fallbackCols = 5;
1441 ariadna 12617
    const mapColors = colorMap => mapColorsRaw(colorMap.map((color, index) => {
12618
      if (index % 2 === 0) {
12619
        return '#' + anyToHex(color).value;
12620
      }
12621
      return color;
12622
    }));
12623
    const mapColorsRaw = colorMap => {
1 efrain 12624
      const colors = [];
12625
      for (let i = 0; i < colorMap.length; i += 2) {
12626
        colors.push({
12627
          text: colorMap[i + 1],
1441 ariadna 12628
          value: colorMap[i],
1 efrain 12629
          icon: 'checkmark',
12630
          type: 'choiceitem'
12631
        });
12632
      }
12633
      return colors;
12634
    };
12635
    const option$1 = name => editor => editor.options.get(name);
12636
    const fallbackColor = '#000000';
1441 ariadna 12637
    const register$e = editor => {
1 efrain 12638
      const registerOption = editor.options.register;
12639
      const colorProcessor = value => {
12640
        if (isArrayOf(value, isString)) {
12641
          return {
12642
            value: mapColors(value),
12643
            valid: true
12644
          };
12645
        } else {
12646
          return {
12647
            valid: false,
12648
            message: 'Must be an array of strings.'
12649
          };
12650
        }
12651
      };
1441 ariadna 12652
      const colorProcessorRaw = value => {
12653
        if (isArrayOf(value, isString)) {
12654
          return {
12655
            value: mapColorsRaw(value),
12656
            valid: true
12657
          };
12658
        } else {
12659
          return {
12660
            valid: false,
12661
            message: 'Must be an array of strings.'
12662
          };
12663
        }
12664
      };
1 efrain 12665
      const colorColsProcessor = value => {
12666
        if (isNumber(value) && value > 0) {
12667
          return {
12668
            value,
12669
            valid: true
12670
          };
12671
        } else {
12672
          return {
12673
            valid: false,
12674
            message: 'Must be a positive number.'
12675
          };
12676
        }
12677
      };
12678
      registerOption('color_map', {
12679
        processor: colorProcessor,
12680
        default: [
12681
          '#BFEDD2',
12682
          'Light Green',
12683
          '#FBEEB8',
12684
          'Light Yellow',
12685
          '#F8CAC6',
12686
          'Light Red',
12687
          '#ECCAFA',
12688
          'Light Purple',
12689
          '#C2E0F4',
12690
          'Light Blue',
12691
          '#2DC26B',
12692
          'Green',
12693
          '#F1C40F',
12694
          'Yellow',
12695
          '#E03E2D',
12696
          'Red',
12697
          '#B96AD9',
12698
          'Purple',
12699
          '#3598DB',
12700
          'Blue',
12701
          '#169179',
12702
          'Dark Turquoise',
12703
          '#E67E23',
12704
          'Orange',
12705
          '#BA372A',
12706
          'Dark Red',
12707
          '#843FA1',
12708
          'Dark Purple',
12709
          '#236FA1',
12710
          'Dark Blue',
12711
          '#ECF0F1',
12712
          'Light Gray',
12713
          '#CED4D9',
12714
          'Medium Gray',
12715
          '#95A5A6',
12716
          'Gray',
12717
          '#7E8C8D',
12718
          'Dark Gray',
12719
          '#34495E',
12720
          'Navy Blue',
12721
          '#000000',
12722
          'Black',
12723
          '#ffffff',
12724
          'White'
12725
        ]
12726
      });
1441 ariadna 12727
      registerOption('color_map_raw', { processor: colorProcessorRaw });
1 efrain 12728
      registerOption('color_map_background', { processor: colorProcessor });
12729
      registerOption('color_map_foreground', { processor: colorProcessor });
12730
      registerOption('color_cols', {
12731
        processor: colorColsProcessor,
12732
        default: calcCols(editor)
12733
      });
12734
      registerOption('color_cols_foreground', {
12735
        processor: colorColsProcessor,
12736
        default: defaultCols(editor, foregroundId)
12737
      });
12738
      registerOption('color_cols_background', {
12739
        processor: colorColsProcessor,
12740
        default: defaultCols(editor, backgroundId)
12741
      });
12742
      registerOption('custom_colors', {
12743
        processor: 'boolean',
12744
        default: true
12745
      });
12746
      registerOption('color_default_foreground', {
12747
        processor: 'string',
12748
        default: fallbackColor
12749
      });
12750
      registerOption('color_default_background', {
12751
        processor: 'string',
12752
        default: fallbackColor
12753
      });
12754
    };
12755
    const getColors$2 = (editor, id) => {
12756
      if (id === foregroundId && editor.options.isSet('color_map_foreground')) {
12757
        return option$1('color_map_foreground')(editor);
12758
      } else if (id === backgroundId && editor.options.isSet('color_map_background')) {
12759
        return option$1('color_map_background')(editor);
1441 ariadna 12760
      } else if (editor.options.isSet('color_map_raw')) {
12761
        return option$1('color_map_raw')(editor);
1 efrain 12762
      } else {
12763
        return option$1('color_map')(editor);
12764
      }
12765
    };
12766
    const calcCols = (editor, id = 'default') => Math.max(fallbackCols, Math.ceil(Math.sqrt(getColors$2(editor, id).length)));
12767
    const defaultCols = (editor, id) => {
12768
      const defaultCols = option$1('color_cols')(editor);
12769
      const calculatedCols = calcCols(editor, id);
12770
      if (defaultCols === calcCols(editor)) {
12771
        return calculatedCols;
12772
      } else {
12773
        return defaultCols;
12774
      }
12775
    };
12776
    const getColorCols$1 = (editor, id = 'default') => {
12777
      const getCols = () => {
12778
        if (id === foregroundId) {
12779
          return option$1('color_cols_foreground')(editor);
12780
        } else if (id === backgroundId) {
12781
          return option$1('color_cols_background')(editor);
12782
        } else {
12783
          return option$1('color_cols')(editor);
12784
        }
12785
      };
12786
      return Math.round(getCols());
12787
    };
12788
    const hasCustomColors$1 = option$1('custom_colors');
12789
    const getDefaultForegroundColor = option$1('color_default_foreground');
12790
    const getDefaultBackgroundColor = option$1('color_default_background');
12791
 
12792
    const defaultBackgroundColor = 'rgba(0, 0, 0, 0)';
12793
    const isValidBackgroundColor = value => fromString(value).exists(c => c.alpha !== 0);
12794
    const getClosestCssBackgroundColorValue = scope => {
12795
      return closest$4(scope, node => {
12796
        if (isElement$1(node)) {
1441 ariadna 12797
          const color = get$f(node, 'background-color');
1 efrain 12798
          return someIf(isValidBackgroundColor(color), color);
12799
        } else {
12800
          return Optional.none();
12801
        }
12802
      }).getOr(defaultBackgroundColor);
12803
    };
12804
    const getCurrentColor = (editor, format) => {
12805
      const node = SugarElement.fromDom(editor.selection.getStart());
1441 ariadna 12806
      const cssRgbValue = format === 'hilitecolor' ? getClosestCssBackgroundColorValue(node) : get$f(node, 'color');
1 efrain 12807
      return fromString(cssRgbValue).map(rgba => '#' + fromRgba(rgba).value);
12808
    };
12809
    const applyFormat = (editor, format, value) => {
12810
      editor.undoManager.transact(() => {
12811
        editor.focus();
12812
        editor.formatter.apply(format, { value });
12813
        editor.nodeChanged();
12814
      });
12815
    };
12816
    const removeFormat = (editor, format) => {
12817
      editor.undoManager.transact(() => {
12818
        editor.focus();
12819
        editor.formatter.remove(format, { value: null }, undefined, true);
12820
        editor.nodeChanged();
12821
      });
12822
    };
12823
    const registerCommands = editor => {
12824
      editor.addCommand('mceApplyTextcolor', (format, value) => {
12825
        applyFormat(editor, format, value);
12826
      });
12827
      editor.addCommand('mceRemoveTextcolor', format => {
12828
        removeFormat(editor, format);
12829
      });
12830
    };
12831
    const getAdditionalColors = hasCustom => {
12832
      const type = 'choiceitem';
12833
      const remove = {
12834
        type,
12835
        text: 'Remove color',
12836
        icon: 'color-swatch-remove-color',
12837
        value: 'remove'
12838
      };
12839
      const custom = {
12840
        type,
12841
        text: 'Custom color',
12842
        icon: 'color-picker',
12843
        value: 'custom'
12844
      };
12845
      return hasCustom ? [
12846
        remove,
12847
        custom
12848
      ] : [remove];
12849
    };
12850
    const applyColor = (editor, format, value, onChoice) => {
12851
      if (value === 'custom') {
12852
        const dialog = colorPickerDialog(editor);
12853
        dialog(colorOpt => {
12854
          colorOpt.each(color => {
12855
            addColor(format, color);
12856
            editor.execCommand('mceApplyTextcolor', format, color);
12857
            onChoice(color);
12858
          });
12859
        }, getCurrentColor(editor, format).getOr(fallbackColor));
12860
      } else if (value === 'remove') {
12861
        onChoice('');
12862
        editor.execCommand('mceRemoveTextcolor', format);
12863
      } else {
12864
        onChoice(value);
12865
        editor.execCommand('mceApplyTextcolor', format, value);
12866
      }
12867
    };
12868
    const getColors$1 = (colors, id, hasCustom) => colors.concat(getCurrentColors(id).concat(getAdditionalColors(hasCustom)));
12869
    const getFetch$1 = (colors, id, hasCustom) => callback => {
12870
      callback(getColors$1(colors, id, hasCustom));
12871
    };
12872
    const setIconColor = (splitButtonApi, name, newColor) => {
12873
      const id = name === 'forecolor' ? 'tox-icon-text-color__color' : 'tox-icon-highlight-bg-color__color';
12874
      splitButtonApi.setIconFill(id, newColor);
12875
    };
12876
    const setTooltip = (buttonApi, tooltip) => {
12877
      buttonApi.setTooltip(tooltip);
12878
    };
12879
    const select$1 = (editor, format) => value => {
12880
      const optCurrentHex = getCurrentColor(editor, format);
12881
      return is$1(optCurrentHex, value.toUpperCase());
12882
    };
12883
    const getToolTipText = (editor, format, lastColor) => {
12884
      if (isEmpty(lastColor)) {
12885
        return format === 'forecolor' ? 'Text color' : 'Background color';
12886
      }
12887
      const tooltipPrefix = format === 'forecolor' ? 'Text color {0}' : 'Background color {0}';
12888
      const colors = getColors$1(getColors$2(editor, format), format, false);
12889
      const colorText = find$5(colors, c => c.value === lastColor).getOr({ text: '' }).text;
12890
      return editor.translate([
12891
        tooltipPrefix,
12892
        editor.translate(colorText)
12893
      ]);
12894
    };
12895
    const registerTextColorButton = (editor, name, format, lastColor) => {
12896
      editor.ui.registry.addSplitButton(name, {
12897
        tooltip: getToolTipText(editor, format, lastColor.get()),
12898
        presets: 'color',
12899
        icon: name === 'forecolor' ? 'text-color' : 'highlight-bg-color',
12900
        select: select$1(editor, format),
12901
        columns: getColorCols$1(editor, format),
12902
        fetch: getFetch$1(getColors$2(editor, format), format, hasCustomColors$1(editor)),
12903
        onAction: _splitButtonApi => {
12904
          applyColor(editor, format, lastColor.get(), noop);
12905
        },
12906
        onItemAction: (_splitButtonApi, value) => {
12907
          applyColor(editor, format, value, newColor => {
12908
            lastColor.set(newColor);
12909
            fireTextColorChange(editor, {
12910
              name,
12911
              color: newColor
12912
            });
12913
          });
12914
        },
12915
        onSetup: splitButtonApi => {
12916
          setIconColor(splitButtonApi, name, lastColor.get());
12917
          const handler = e => {
12918
            if (e.name === name) {
12919
              setIconColor(splitButtonApi, e.name, e.color);
12920
              setTooltip(splitButtonApi, getToolTipText(editor, format, e.color));
12921
            }
12922
          };
12923
          editor.on('TextColorChange', handler);
12924
          return composeUnbinders(onSetupEditableToggle(editor)(splitButtonApi), () => {
12925
            editor.off('TextColorChange', handler);
12926
          });
12927
        }
12928
      });
12929
    };
12930
    const registerTextColorMenuItem = (editor, name, format, text, lastColor) => {
12931
      editor.ui.registry.addNestedMenuItem(name, {
12932
        text,
12933
        icon: name === 'forecolor' ? 'text-color' : 'highlight-bg-color',
12934
        onSetup: api => {
12935
          setTooltip(api, getToolTipText(editor, format, lastColor.get()));
12936
          setIconColor(api, name, lastColor.get());
12937
          return onSetupEditableToggle(editor)(api);
12938
        },
12939
        getSubmenuItems: () => [{
12940
            type: 'fancymenuitem',
12941
            fancytype: 'colorswatch',
12942
            select: select$1(editor, format),
12943
            initData: { storageKey: format },
12944
            onAction: data => {
12945
              applyColor(editor, format, data.value, newColor => {
12946
                lastColor.set(newColor);
12947
                fireTextColorChange(editor, {
12948
                  name,
12949
                  color: newColor
12950
                });
12951
              });
12952
            }
12953
          }]
12954
      });
12955
    };
12956
    const colorPickerDialog = editor => (callback, value) => {
12957
      let isValid = false;
12958
      const onSubmit = api => {
12959
        const data = api.getData();
12960
        const hex = data.colorpicker;
12961
        if (isValid) {
12962
          callback(Optional.from(hex));
12963
          api.close();
12964
        } else {
12965
          editor.windowManager.alert(editor.translate([
12966
            'Invalid hex color code: {0}',
12967
            hex
12968
          ]));
12969
        }
12970
      };
12971
      const onAction = (_api, details) => {
12972
        if (details.name === 'hex-valid') {
12973
          isValid = details.value;
12974
        }
12975
      };
12976
      const initialData = { colorpicker: value };
12977
      editor.windowManager.open({
12978
        title: 'Color Picker',
12979
        size: 'normal',
12980
        body: {
12981
          type: 'panel',
12982
          items: [{
12983
              type: 'colorpicker',
12984
              name: 'colorpicker',
12985
              label: 'Color'
12986
            }]
12987
        },
12988
        buttons: [
12989
          {
12990
            type: 'cancel',
12991
            name: 'cancel',
12992
            text: 'Cancel'
12993
          },
12994
          {
12995
            type: 'submit',
12996
            name: 'save',
12997
            text: 'Save',
12998
            primary: true
12999
          }
13000
        ],
13001
        initialData,
13002
        onAction,
13003
        onSubmit,
13004
        onClose: noop,
13005
        onCancel: () => {
13006
          callback(Optional.none());
13007
        }
13008
      });
13009
    };
1441 ariadna 13010
    const register$d = editor => {
1 efrain 13011
      registerCommands(editor);
13012
      const fallbackColorForeground = getDefaultForegroundColor(editor);
13013
      const fallbackColorBackground = getDefaultBackgroundColor(editor);
13014
      const lastForeColor = Cell(fallbackColorForeground);
13015
      const lastBackColor = Cell(fallbackColorBackground);
13016
      registerTextColorButton(editor, 'forecolor', 'forecolor', lastForeColor);
13017
      registerTextColorButton(editor, 'backcolor', 'hilitecolor', lastBackColor);
13018
      registerTextColorMenuItem(editor, 'forecolor', 'forecolor', 'Text color', lastForeColor);
13019
      registerTextColorMenuItem(editor, 'backcolor', 'hilitecolor', 'Background color', lastBackColor);
13020
    };
13021
 
13022
    const createPartialChoiceMenu = (value, items, onItemValueHandler, columns, presets, itemResponse, select, providersBackstage) => {
13023
      const hasIcons = menuHasIcons(items);
13024
      const presetItemTypes = presets !== 'color' ? 'normal' : 'color';
13025
      const alloyItems = createChoiceItems(items, onItemValueHandler, columns, presetItemTypes, itemResponse, select, providersBackstage);
13026
      const menuLayout = { menuType: presets };
13027
      return createPartialMenuWithAlloyItems(value, hasIcons, alloyItems, columns, menuLayout);
13028
    };
13029
    const createChoiceItems = (items, onItemValueHandler, columns, itemPresets, itemResponse, select, providersBackstage) => cat(map$2(items, item => {
13030
      if (item.type === 'choiceitem') {
13031
        return createChoiceMenuItem(item).fold(handleError, d => Optional.some(renderChoiceItem(d, columns === 1, itemPresets, onItemValueHandler, select(d.value), itemResponse, providersBackstage, menuHasIcons(items))));
13032
      } else {
13033
        return Optional.none();
13034
      }
13035
    }));
13036
 
13037
    const deriveMenuMovement = (columns, presets) => {
13038
      const menuMarkers = markers(presets);
13039
      if (columns === 1) {
13040
        return {
13041
          mode: 'menu',
13042
          moveOnTab: true
13043
        };
13044
      } else if (columns === 'auto') {
13045
        return {
13046
          mode: 'grid',
13047
          selector: '.' + menuMarkers.item,
13048
          initSize: {
13049
            numColumns: 1,
13050
            numRows: 1
13051
          }
13052
        };
13053
      } else {
13054
        const rowClass = presets === 'color' ? 'tox-swatches__row' : 'tox-collection__group';
13055
        return {
13056
          mode: 'matrix',
13057
          rowSelector: '.' + rowClass,
13058
          previousSelector: menu => {
13059
            return presets === 'color' ? descendant(menu.element, '[aria-checked=true]') : Optional.none();
13060
          }
13061
        };
13062
      }
13063
    };
13064
    const deriveCollectionMovement = (columns, presets) => {
13065
      if (columns === 1) {
13066
        return {
13067
          mode: 'menu',
13068
          moveOnTab: false,
13069
          selector: '.tox-collection__item'
13070
        };
13071
      } else if (columns === 'auto') {
13072
        return {
13073
          mode: 'flatgrid',
13074
          selector: '.' + 'tox-collection__item',
13075
          initSize: {
13076
            numColumns: 1,
13077
            numRows: 1
13078
          }
13079
        };
13080
      } else {
13081
        return {
13082
          mode: 'matrix',
13083
          selectors: {
13084
            row: presets === 'color' ? '.tox-swatches__row' : '.tox-collection__group',
13085
            cell: presets === 'color' ? `.${ colorClass }` : `.${ selectableClass }`
13086
          }
13087
        };
13088
      }
13089
    };
13090
 
13091
    const renderColorSwatchItem = (spec, backstage) => {
13092
      const items = getColorItems(spec, backstage);
13093
      const columns = backstage.colorinput.getColorCols(spec.initData.storageKey);
13094
      const presets = 'color';
13095
      const menuSpec = createPartialChoiceMenu(generate$6('menu-value'), items, value => {
13096
        spec.onAction({ value });
13097
      }, columns, presets, ItemResponse$1.CLOSE_ON_EXECUTE, spec.select.getOr(never), backstage.shared.providers);
13098
      const widgetSpec = {
13099
        ...menuSpec,
13100
        markers: markers(presets),
1441 ariadna 13101
        movement: deriveMenuMovement(columns, presets),
13102
        showMenuRole: false
1 efrain 13103
      };
13104
      return {
13105
        type: 'widget',
13106
        data: { value: generate$6('widget-id') },
13107
        dom: {
13108
          tag: 'div',
13109
          classes: ['tox-fancymenuitem']
13110
        },
13111
        autofocus: true,
13112
        components: [parts$f.widget(Menu.sketch(widgetSpec))]
13113
      };
13114
    };
13115
    const getColorItems = (spec, backstage) => {
13116
      const useCustomColors = spec.initData.allowCustomColors && backstage.colorinput.hasCustomColors();
13117
      return spec.initData.colors.fold(() => getColors$1(backstage.colorinput.getColors(spec.initData.storageKey), spec.initData.storageKey, useCustomColors), colors => colors.concat(getAdditionalColors(useCustomColors)));
13118
    };
13119
 
13120
    const cellOverEvent = generate$6('cell-over');
13121
    const cellExecuteEvent = generate$6('cell-execute');
13122
    const makeAnnouncementText = backstage => (row, col) => backstage.shared.providers.translate([
13123
      '{0} columns, {1} rows',
13124
      col,
13125
      row
13126
    ]);
13127
    const makeCell = (row, col, label) => {
13128
      const emitCellOver = c => emitWith(c, cellOverEvent, {
13129
        row,
13130
        col
13131
      });
13132
      const emitExecute = c => emitWith(c, cellExecuteEvent, {
13133
        row,
13134
        col
13135
      });
13136
      const onClick = (c, se) => {
13137
        se.stop();
13138
        emitExecute(c);
13139
      };
13140
      return build$1({
13141
        dom: {
13142
          tag: 'div',
13143
          attributes: {
13144
            role: 'button',
13145
            ['aria-label']: label
13146
          }
13147
        },
13148
        behaviours: derive$1([
13149
          config('insert-table-picker-cell', [
13150
            run$1(mouseover(), Focusing.focus),
13151
            run$1(execute$5(), emitExecute),
13152
            run$1(click(), onClick),
13153
            run$1(tap(), onClick)
13154
          ]),
13155
          Toggling.config({
13156
            toggleClass: 'tox-insert-table-picker__selected',
13157
            toggleOnExecute: false
13158
          }),
13159
          Focusing.config({ onFocus: emitCellOver })
13160
        ])
13161
      });
13162
    };
13163
    const makeCells = (getCellLabel, numRows, numCols) => {
13164
      const cells = [];
13165
      for (let i = 0; i < numRows; i++) {
13166
        const row = [];
13167
        for (let j = 0; j < numCols; j++) {
13168
          const label = getCellLabel(i + 1, j + 1);
13169
          row.push(makeCell(i, j, label));
13170
        }
13171
        cells.push(row);
13172
      }
13173
      return cells;
13174
    };
13175
    const selectCells = (cells, selectedRow, selectedColumn, numRows, numColumns) => {
13176
      for (let i = 0; i < numRows; i++) {
13177
        for (let j = 0; j < numColumns; j++) {
13178
          Toggling.set(cells[i][j], i <= selectedRow && j <= selectedColumn);
13179
        }
13180
      }
13181
    };
13182
    const makeComponents = cells => bind$3(cells, cellRow => map$2(cellRow, premade));
13183
    const makeLabelText = (row, col) => text$2(`${ col }x${ row }`);
13184
    const renderInsertTableMenuItem = (spec, backstage) => {
13185
      const numRows = 10;
13186
      const numColumns = 10;
13187
      const getCellLabel = makeAnnouncementText(backstage);
13188
      const cells = makeCells(getCellLabel, numRows, numColumns);
13189
      const emptyLabelText = makeLabelText(0, 0);
13190
      const memLabel = record({
13191
        dom: {
13192
          tag: 'span',
13193
          classes: ['tox-insert-table-picker__label']
13194
        },
13195
        components: [emptyLabelText],
13196
        behaviours: derive$1([Replacing.config({})])
13197
      });
13198
      return {
13199
        type: 'widget',
13200
        data: { value: generate$6('widget-id') },
13201
        dom: {
13202
          tag: 'div',
13203
          classes: ['tox-fancymenuitem']
13204
        },
13205
        autofocus: true,
13206
        components: [parts$f.widget({
13207
            dom: {
13208
              tag: 'div',
13209
              classes: ['tox-insert-table-picker']
13210
            },
13211
            components: makeComponents(cells).concat(memLabel.asSpec()),
13212
            behaviours: derive$1([
13213
              config('insert-table-picker', [
13214
                runOnAttached(c => {
13215
                  Replacing.set(memLabel.get(c), [emptyLabelText]);
13216
                }),
13217
                runWithTarget(cellOverEvent, (c, t, e) => {
13218
                  const {row, col} = e.event;
13219
                  selectCells(cells, row, col, numRows, numColumns);
13220
                  Replacing.set(memLabel.get(c), [makeLabelText(row + 1, col + 1)]);
13221
                }),
13222
                runWithTarget(cellExecuteEvent, (c, _, e) => {
13223
                  const {row, col} = e.event;
1441 ariadna 13224
                  emit(c, sandboxClose());
1 efrain 13225
                  spec.onAction({
13226
                    numRows: row + 1,
13227
                    numColumns: col + 1
13228
                  });
13229
                })
13230
              ]),
13231
              Keying.config({
13232
                initSize: {
13233
                  numRows,
13234
                  numColumns
13235
                },
13236
                mode: 'flatgrid',
13237
                selector: '[role="button"]'
13238
              })
13239
            ])
13240
          })]
13241
      };
13242
    };
13243
 
13244
    const fancyMenuItems = {
13245
      inserttable: renderInsertTableMenuItem,
13246
      colorswatch: renderColorSwatchItem
13247
    };
1441 ariadna 13248
    const renderFancyMenuItem = (spec, backstage) => get$h(fancyMenuItems, spec.fancytype).map(render => render(spec, backstage));
1 efrain 13249
 
13250
    const renderNestedItem = (spec, itemResponse, providersBackstage, renderIcons = true, downwardsCaret = false) => {
13251
      const caret = downwardsCaret ? renderDownwardsCaret(providersBackstage.icons) : renderSubmenuCaret(providersBackstage.icons);
13252
      const getApi = component => ({
13253
        isEnabled: () => !Disabling.isDisabled(component),
13254
        setEnabled: state => Disabling.set(component, !state),
13255
        setIconFill: (id, value) => {
13256
          descendant(component.element, `svg path[class="${ id }"], rect[class="${ id }"]`).each(underlinePath => {
13257
            set$9(underlinePath, 'fill', value);
13258
          });
13259
        },
13260
        setTooltip: tooltip => {
13261
          const translatedTooltip = providersBackstage.translate(tooltip);
1441 ariadna 13262
          set$9(component.element, 'aria-label', translatedTooltip);
1 efrain 13263
        }
13264
      });
13265
      const structure = renderItemStructure({
13266
        presets: 'normal',
13267
        iconContent: spec.icon,
13268
        textContent: spec.text,
13269
        htmlContent: Optional.none(),
13270
        ariaLabel: spec.text,
13271
        caret: Optional.some(caret),
13272
        checkMark: Optional.none(),
13273
        shortcutContent: spec.shortcut
13274
      }, providersBackstage, renderIcons);
13275
      return renderCommonItem({
1441 ariadna 13276
        context: spec.context,
1 efrain 13277
        data: buildData(spec),
13278
        getApi,
13279
        enabled: spec.enabled,
13280
        onAction: noop,
13281
        onSetup: spec.onSetup,
13282
        triggersSubmenu: true,
13283
        itemBehaviours: []
13284
      }, structure, itemResponse, providersBackstage);
13285
    };
13286
 
13287
    const renderNormalItem = (spec, itemResponse, providersBackstage, renderIcons = true) => {
13288
      const getApi = component => ({
13289
        isEnabled: () => !Disabling.isDisabled(component),
13290
        setEnabled: state => Disabling.set(component, !state)
13291
      });
13292
      const structure = renderItemStructure({
13293
        presets: 'normal',
13294
        iconContent: spec.icon,
13295
        textContent: spec.text,
13296
        htmlContent: Optional.none(),
13297
        ariaLabel: spec.text,
13298
        caret: Optional.none(),
13299
        checkMark: Optional.none(),
13300
        shortcutContent: spec.shortcut
13301
      }, providersBackstage, renderIcons);
13302
      return renderCommonItem({
1441 ariadna 13303
        context: spec.context,
1 efrain 13304
        data: buildData(spec),
13305
        getApi,
13306
        enabled: spec.enabled,
13307
        onAction: spec.onAction,
13308
        onSetup: spec.onSetup,
13309
        triggersSubmenu: false,
13310
        itemBehaviours: []
13311
      }, structure, itemResponse, providersBackstage);
13312
    };
13313
 
13314
    const renderSeparatorItem = spec => ({
13315
      type: 'separator',
13316
      dom: {
13317
        tag: 'div',
13318
        classes: [
13319
          selectableClass,
13320
          groupHeadingClass
13321
        ]
13322
      },
13323
      components: spec.text.map(text$2).toArray()
13324
    });
13325
 
13326
    const renderToggleMenuItem = (spec, itemResponse, providersBackstage, renderIcons = true) => {
13327
      const getApi = component => ({
13328
        setActive: state => {
13329
          Toggling.set(component, state);
13330
        },
13331
        isActive: () => Toggling.isOn(component),
13332
        isEnabled: () => !Disabling.isDisabled(component),
13333
        setEnabled: state => Disabling.set(component, !state)
13334
      });
13335
      const structure = renderItemStructure({
13336
        iconContent: spec.icon,
13337
        textContent: spec.text,
13338
        htmlContent: Optional.none(),
13339
        ariaLabel: spec.text,
13340
        checkMark: Optional.some(renderCheckmark(providersBackstage.icons)),
13341
        caret: Optional.none(),
13342
        shortcutContent: spec.shortcut,
13343
        presets: 'normal',
13344
        meta: spec.meta
13345
      }, providersBackstage, renderIcons);
13346
      return deepMerge(renderCommonItem({
1441 ariadna 13347
        context: spec.context,
1 efrain 13348
        data: buildData(spec),
13349
        enabled: spec.enabled,
13350
        getApi,
13351
        onAction: spec.onAction,
13352
        onSetup: spec.onSetup,
13353
        triggersSubmenu: false,
13354
        itemBehaviours: []
13355
      }, structure, itemResponse, providersBackstage), {
13356
        toggling: {
13357
          toggleClass: tickedClass,
13358
          toggleOnExecute: false,
13359
          selected: spec.active
1441 ariadna 13360
        },
13361
        role: spec.role.getOrUndefined()
1 efrain 13362
      });
13363
    };
13364
 
13365
    const autocomplete = renderAutocompleteItem;
13366
    const separator$3 = renderSeparatorItem;
13367
    const normal = renderNormalItem;
13368
    const nested = renderNestedItem;
13369
    const toggle$1 = renderToggleMenuItem;
13370
    const fancy = renderFancyMenuItem;
13371
    const card = renderCardMenuItem;
13372
 
13373
    const getCoupled = (component, coupleConfig, coupleState, name) => coupleState.getOrCreate(component, coupleConfig, name);
13374
    const getExistingCoupled = (component, coupleConfig, coupleState, name) => coupleState.getExisting(component, coupleConfig, name);
13375
 
13376
    var CouplingApis = /*#__PURE__*/Object.freeze({
13377
        __proto__: null,
13378
        getCoupled: getCoupled,
13379
        getExistingCoupled: getExistingCoupled
13380
    });
13381
 
13382
    var CouplingSchema = [requiredOf('others', setOf(Result.value, anyValue()))];
13383
 
1441 ariadna 13384
    const init$9 = () => {
1 efrain 13385
      const coupled = {};
13386
      const lookupCoupled = (coupleConfig, coupledName) => {
13387
        const available = keys(coupleConfig.others);
13388
        if (available.length === 0) {
13389
          throw new Error('Cannot find any known coupled components');
13390
        } else {
1441 ariadna 13391
          return get$h(coupled, coupledName);
1 efrain 13392
        }
13393
      };
13394
      const getOrCreate = (component, coupleConfig, name) => {
13395
        return lookupCoupled(coupleConfig, name).getOrThunk(() => {
1441 ariadna 13396
          const builder = get$h(coupleConfig.others, name).getOrDie('No information found for coupled component: ' + name);
1 efrain 13397
          const spec = builder(component);
13398
          const built = component.getSystem().build(spec);
13399
          coupled[name] = built;
13400
          return built;
13401
        });
13402
      };
13403
      const getExisting = (component, coupleConfig, name) => {
13404
        return lookupCoupled(coupleConfig, name).orThunk(() => {
1441 ariadna 13405
          get$h(coupleConfig.others, name).getOrDie('No information found for coupled component: ' + name);
1 efrain 13406
          return Optional.none();
13407
        });
13408
      };
13409
      const readState = constant$1({});
1441 ariadna 13410
      return nu$7({
1 efrain 13411
        readState,
13412
        getExisting,
13413
        getOrCreate
13414
      });
13415
    };
13416
 
13417
    var CouplingState = /*#__PURE__*/Object.freeze({
13418
        __proto__: null,
1441 ariadna 13419
        init: init$9
1 efrain 13420
    });
13421
 
13422
    const Coupling = create$4({
13423
      fields: CouplingSchema,
13424
      name: 'coupling',
13425
      apis: CouplingApis,
13426
      state: CouplingState
13427
    });
13428
 
13429
    const nu$3 = baseFn => {
13430
      let data = Optional.none();
13431
      let callbacks = [];
13432
      const map = f => nu$3(nCallback => {
13433
        get(data => {
13434
          nCallback(f(data));
13435
        });
13436
      });
13437
      const get = nCallback => {
13438
        if (isReady()) {
13439
          call(nCallback);
13440
        } else {
13441
          callbacks.push(nCallback);
13442
        }
13443
      };
13444
      const set = x => {
13445
        if (!isReady()) {
13446
          data = Optional.some(x);
13447
          run(callbacks);
13448
          callbacks = [];
13449
        }
13450
      };
13451
      const isReady = () => data.isSome();
13452
      const run = cbs => {
13453
        each$1(cbs, call);
13454
      };
13455
      const call = cb => {
13456
        data.each(x => {
13457
          setTimeout(() => {
13458
            cb(x);
13459
          }, 0);
13460
        });
13461
      };
13462
      baseFn(set);
13463
      return {
13464
        get,
13465
        map,
13466
        isReady
13467
      };
13468
    };
13469
    const pure$1 = a => nu$3(callback => {
13470
      callback(a);
13471
    });
13472
    const LazyValue = {
13473
      nu: nu$3,
13474
      pure: pure$1
13475
    };
13476
 
13477
    const errorReporter = err => {
13478
      setTimeout(() => {
13479
        throw err;
13480
      }, 0);
13481
    };
13482
    const make$5 = run => {
13483
      const get = callback => {
13484
        run().then(callback, errorReporter);
13485
      };
13486
      const map = fab => {
13487
        return make$5(() => run().then(fab));
13488
      };
13489
      const bind = aFutureB => {
13490
        return make$5(() => run().then(v => aFutureB(v).toPromise()));
13491
      };
13492
      const anonBind = futureB => {
13493
        return make$5(() => run().then(() => futureB.toPromise()));
13494
      };
13495
      const toLazy = () => {
13496
        return LazyValue.nu(get);
13497
      };
13498
      const toCached = () => {
13499
        let cache = null;
13500
        return make$5(() => {
13501
          if (cache === null) {
13502
            cache = run();
13503
          }
13504
          return cache;
13505
        });
13506
      };
13507
      const toPromise = run;
13508
      return {
13509
        map,
13510
        bind,
13511
        anonBind,
13512
        toLazy,
13513
        toCached,
13514
        toPromise,
13515
        get
13516
      };
13517
    };
13518
    const nu$2 = baseFn => {
13519
      return make$5(() => new Promise(baseFn));
13520
    };
13521
    const pure = a => {
13522
      return make$5(() => Promise.resolve(a));
13523
    };
13524
    const Future = {
13525
      nu: nu$2,
13526
      pure
13527
    };
13528
 
13529
    const suffix = constant$1('sink');
13530
    const partType$1 = constant$1(optional({
13531
      name: suffix(),
13532
      overrides: constant$1({
13533
        dom: { tag: 'div' },
13534
        behaviours: derive$1([Positioning.config({ useFixed: always })]),
13535
        events: derive$2([
13536
          cutter(keydown()),
13537
          cutter(mousedown()),
13538
          cutter(click())
13539
        ])
13540
      })
13541
    }));
13542
 
13543
    const getAnchor = (detail, component) => {
13544
      const hotspot = detail.getHotspot(component).getOr(component);
13545
      const type = 'hotspot';
13546
      const overrides = detail.getAnchorOverrides();
13547
      return detail.layouts.fold(() => ({
13548
        type,
13549
        hotspot,
13550
        overrides
13551
      }), layouts => ({
13552
        type,
13553
        hotspot,
13554
        overrides,
13555
        layouts
13556
      }));
13557
    };
13558
    const fetch = (detail, mapFetch, component) => {
13559
      const fetcher = detail.fetch;
13560
      return fetcher(component).map(mapFetch);
13561
    };
13562
    const openF = (detail, mapFetch, anchor, component, sandbox, externals, highlightOnOpen) => {
13563
      const futureData = fetch(detail, mapFetch, component);
13564
      const getLazySink = getSink(component, detail);
1441 ariadna 13565
      return futureData.map(tdata => tdata.bind(data => {
13566
        const primaryMenu = data.menus[data.primary];
13567
        Optional.from(primaryMenu).each(menu => {
13568
          detail.listRole.each(listRole => {
13569
            menu.role = listRole;
1 efrain 13570
          });
1441 ariadna 13571
        });
13572
        return Optional.from(tieredMenu.sketch({
13573
          ...externals.menu(),
13574
          uid: generate$5(''),
13575
          data,
13576
          highlightOnOpen,
13577
          onOpenMenu: (tmenu, menu) => {
13578
            const sink = getLazySink().getOrDie();
13579
            Positioning.position(sink, menu, { anchor });
13580
            Sandboxing.decloak(sandbox);
13581
          },
13582
          onOpenSubmenu: (tmenu, item, submenu) => {
13583
            const sink = getLazySink().getOrDie();
13584
            Positioning.position(sink, submenu, {
1 efrain 13585
              anchor: {
13586
                type: 'submenu',
1441 ariadna 13587
                item
1 efrain 13588
              }
13589
            });
1441 ariadna 13590
            Sandboxing.decloak(sandbox);
13591
          },
13592
          onRepositionMenu: (tmenu, primaryMenu, submenuTriggers) => {
13593
            const sink = getLazySink().getOrDie();
13594
            Positioning.position(sink, primaryMenu, { anchor });
13595
            each$1(submenuTriggers, st => {
13596
              Positioning.position(sink, st.triggeredMenu, {
13597
                anchor: {
13598
                  type: 'submenu',
13599
                  item: st.triggeringItem
13600
                }
13601
              });
13602
            });
13603
          },
13604
          onEscape: () => {
13605
            Focusing.focus(component);
13606
            Sandboxing.close(sandbox);
13607
            return Optional.some(true);
13608
          }
13609
        }));
13610
      }));
1 efrain 13611
    };
13612
    const open = (detail, mapFetch, hotspot, sandbox, externals, onOpenSync, highlightOnOpen) => {
13613
      const anchor = getAnchor(detail, hotspot);
13614
      const processed = openF(detail, mapFetch, anchor, hotspot, sandbox, externals, highlightOnOpen);
13615
      return processed.map(tdata => {
13616
        tdata.fold(() => {
13617
          if (Sandboxing.isOpen(sandbox)) {
13618
            Sandboxing.close(sandbox);
13619
          }
13620
        }, data => {
13621
          Sandboxing.cloak(sandbox);
13622
          Sandboxing.open(sandbox, data);
13623
          onOpenSync(sandbox);
13624
        });
13625
        return sandbox;
13626
      });
13627
    };
13628
    const close = (detail, mapFetch, component, sandbox, _externals, _onOpenSync, _highlightOnOpen) => {
13629
      Sandboxing.close(sandbox);
13630
      return Future.pure(sandbox);
13631
    };
13632
    const togglePopup = (detail, mapFetch, hotspot, externals, onOpenSync, highlightOnOpen) => {
13633
      const sandbox = Coupling.getCoupled(hotspot, 'sandbox');
13634
      const showing = Sandboxing.isOpen(sandbox);
13635
      const action = showing ? close : open;
13636
      return action(detail, mapFetch, hotspot, sandbox, externals, onOpenSync, highlightOnOpen);
13637
    };
13638
    const matchWidth = (hotspot, container, useMinWidth) => {
13639
      const menu = Composing.getCurrent(container).getOr(container);
1441 ariadna 13640
      const buttonWidth = get$d(hotspot.element);
1 efrain 13641
      if (useMinWidth) {
13642
        set$8(menu.element, 'min-width', buttonWidth + 'px');
13643
      } else {
13644
        set$7(menu.element, buttonWidth);
13645
      }
13646
    };
13647
    const getSink = (anyInSystem, sinkDetail) => anyInSystem.getSystem().getByUid(sinkDetail.uid + '-' + suffix()).map(internalSink => () => Result.value(internalSink)).getOrThunk(() => sinkDetail.lazySink.fold(() => () => Result.error(new Error('No internal sink is specified, nor could an external sink be found')), lazySinkFn => () => lazySinkFn(anyInSystem)));
13648
    const doRepositionMenus = sandbox => {
13649
      Sandboxing.getState(sandbox).each(tmenu => {
13650
        tieredMenu.repositionMenus(tmenu);
13651
      });
13652
    };
13653
    const makeSandbox$1 = (detail, hotspot, extras) => {
13654
      const ariaControls = manager();
13655
      const onOpen = (component, menu) => {
13656
        const anchor = getAnchor(detail, hotspot);
13657
        ariaControls.link(hotspot.element);
13658
        if (detail.matchWidth) {
13659
          matchWidth(anchor.hotspot, menu, detail.useMinWidth);
13660
        }
13661
        detail.onOpen(anchor, component, menu);
13662
        if (extras !== undefined && extras.onOpen !== undefined) {
13663
          extras.onOpen(component, menu);
13664
        }
13665
      };
13666
      const onClose = (component, menu) => {
13667
        ariaControls.unlink(hotspot.element);
1441 ariadna 13668
        lazySink().getOr(menu).element.dom.dispatchEvent(new window.FocusEvent('focusout'));
1 efrain 13669
        if (extras !== undefined && extras.onClose !== undefined) {
13670
          extras.onClose(component, menu);
13671
        }
13672
      };
13673
      const lazySink = getSink(hotspot, detail);
13674
      return {
13675
        dom: {
13676
          tag: 'div',
13677
          classes: detail.sandboxClasses,
1441 ariadna 13678
          attributes: { id: ariaControls.id }
1 efrain 13679
        },
13680
        behaviours: SketchBehaviours.augment(detail.sandboxBehaviours, [
13681
          Representing.config({
13682
            store: {
13683
              mode: 'memory',
13684
              initialValue: hotspot
13685
            }
13686
          }),
13687
          Sandboxing.config({
13688
            onOpen,
13689
            onClose,
13690
            isPartOf: (container, data, queryElem) => {
13691
              return isPartOf$1(data, queryElem) || isPartOf$1(hotspot, queryElem);
13692
            },
13693
            getAttachPoint: () => {
13694
              return lazySink().getOrDie();
13695
            }
13696
          }),
13697
          Composing.config({
13698
            find: sandbox => {
13699
              return Sandboxing.getState(sandbox).bind(menu => Composing.getCurrent(menu));
13700
            }
13701
          }),
13702
          Receiving.config({
13703
            channels: {
13704
              ...receivingChannel$1({ isExtraPart: never }),
13705
              ...receivingChannel({ doReposition: doRepositionMenus })
13706
            }
13707
          })
13708
        ])
13709
      };
13710
    };
13711
    const repositionMenus = comp => {
13712
      const sandbox = Coupling.getCoupled(comp, 'sandbox');
13713
      doRepositionMenus(sandbox);
13714
    };
13715
 
13716
    const sandboxFields = () => [
13717
      defaulted('sandboxClasses', []),
13718
      SketchBehaviours.field('sandboxBehaviours', [
13719
        Composing,
13720
        Receiving,
13721
        Sandboxing,
13722
        Representing
13723
      ])
13724
    ];
13725
 
13726
    const schema$k = constant$1([
13727
      required$1('dom'),
13728
      required$1('fetch'),
13729
      onHandler('onOpen'),
13730
      onKeyboardHandler('onExecute'),
13731
      defaulted('getHotspot', Optional.some),
13732
      defaulted('getAnchorOverrides', constant$1({})),
13733
      schema$y(),
13734
      field('dropdownBehaviours', [
13735
        Toggling,
13736
        Coupling,
13737
        Keying,
13738
        Focusing
13739
      ]),
13740
      required$1('toggleClass'),
13741
      defaulted('eventOrder', {}),
13742
      option$3('lazySink'),
13743
      defaulted('matchWidth', false),
13744
      defaulted('useMinWidth', false),
1441 ariadna 13745
      option$3('role'),
13746
      option$3('listRole')
1 efrain 13747
    ].concat(sandboxFields()));
13748
    const parts$e = constant$1([
13749
      external({
13750
        schema: [
13751
          tieredMenuMarkers(),
13752
          defaulted('fakeFocus', false)
13753
        ],
13754
        name: 'menu',
13755
        defaults: detail => {
13756
          return { onExecute: detail.onExecute };
13757
        }
13758
      }),
13759
      partType$1()
13760
    ]);
13761
 
13762
    const factory$k = (detail, components, _spec, externals) => {
1441 ariadna 13763
      const lookupAttr = attr => get$h(detail.dom, 'attributes').bind(attrs => get$h(attrs, attr));
1 efrain 13764
      const switchToMenu = sandbox => {
13765
        Sandboxing.getState(sandbox).each(tmenu => {
13766
          tieredMenu.highlightPrimary(tmenu);
13767
        });
13768
      };
13769
      const togglePopup$1 = (dropdownComp, onOpenSync, highlightOnOpen) => {
13770
        return togglePopup(detail, identity, dropdownComp, externals, onOpenSync, highlightOnOpen);
13771
      };
13772
      const action = component => {
13773
        const onOpenSync = switchToMenu;
13774
        togglePopup$1(component, onOpenSync, HighlightOnOpen.HighlightMenuAndItem).get(noop);
13775
      };
13776
      const apis = {
13777
        expand: comp => {
13778
          if (!Toggling.isOn(comp)) {
13779
            togglePopup$1(comp, noop, HighlightOnOpen.HighlightNone).get(noop);
13780
          }
13781
        },
13782
        open: comp => {
13783
          if (!Toggling.isOn(comp)) {
13784
            togglePopup$1(comp, noop, HighlightOnOpen.HighlightMenuAndItem).get(noop);
13785
          }
13786
        },
13787
        refetch: comp => {
13788
          const optSandbox = Coupling.getExistingCoupled(comp, 'sandbox');
13789
          return optSandbox.fold(() => {
13790
            return togglePopup$1(comp, noop, HighlightOnOpen.HighlightMenuAndItem).map(noop);
13791
          }, sandboxComp => {
13792
            return open(detail, identity, comp, sandboxComp, externals, noop, HighlightOnOpen.HighlightMenuAndItem).map(noop);
13793
          });
13794
        },
13795
        isOpen: Toggling.isOn,
13796
        close: comp => {
13797
          if (Toggling.isOn(comp)) {
13798
            togglePopup$1(comp, noop, HighlightOnOpen.HighlightMenuAndItem).get(noop);
13799
          }
13800
        },
13801
        repositionMenus: comp => {
13802
          if (Toggling.isOn(comp)) {
13803
            repositionMenus(comp);
13804
          }
13805
        }
13806
      };
13807
      const triggerExecute = (comp, _se) => {
13808
        emitExecute(comp);
13809
        return Optional.some(true);
13810
      };
13811
      return {
13812
        uid: detail.uid,
13813
        dom: detail.dom,
13814
        components,
13815
        behaviours: augment(detail.dropdownBehaviours, [
13816
          Toggling.config({
13817
            toggleClass: detail.toggleClass,
13818
            aria: { mode: 'expanded' }
13819
          }),
13820
          Coupling.config({
13821
            others: {
13822
              sandbox: hotspot => {
13823
                return makeSandbox$1(detail, hotspot, {
13824
                  onOpen: () => Toggling.on(hotspot),
13825
                  onClose: () => Toggling.off(hotspot)
13826
                });
13827
              }
13828
            }
13829
          }),
13830
          Keying.config({
13831
            mode: 'special',
13832
            onSpace: triggerExecute,
13833
            onEnter: triggerExecute,
13834
            onDown: (comp, _se) => {
13835
              if (Dropdown.isOpen(comp)) {
13836
                const sandbox = Coupling.getCoupled(comp, 'sandbox');
13837
                switchToMenu(sandbox);
13838
              } else {
13839
                Dropdown.open(comp);
13840
              }
13841
              return Optional.some(true);
13842
            },
13843
            onEscape: (comp, _se) => {
13844
              if (Dropdown.isOpen(comp)) {
13845
                Dropdown.close(comp);
13846
                return Optional.some(true);
13847
              } else {
13848
                return Optional.none();
13849
              }
13850
            }
13851
          }),
13852
          Focusing.config({})
13853
        ]),
1441 ariadna 13854
        events: events$9(Optional.some(action)),
1 efrain 13855
        eventOrder: {
13856
          ...detail.eventOrder,
13857
          [execute$5()]: [
13858
            'disabling',
13859
            'toggling',
13860
            'alloy.base.behaviour'
13861
          ]
13862
        },
13863
        apis,
13864
        domModification: {
13865
          attributes: {
1441 ariadna 13866
            'aria-haspopup': detail.listRole.getOr('true'),
1 efrain 13867
            ...detail.role.fold(() => ({}), role => ({ role })),
13868
            ...detail.dom.tag === 'button' ? { type: lookupAttr('type').getOr('button') } : {}
13869
          }
13870
        }
13871
      };
13872
    };
13873
    const Dropdown = composite({
13874
      name: 'Dropdown',
13875
      configFields: schema$k(),
13876
      partFields: parts$e(),
13877
      factory: factory$k,
13878
      apis: {
13879
        open: (apis, comp) => apis.open(comp),
13880
        refetch: (apis, comp) => apis.refetch(comp),
13881
        expand: (apis, comp) => apis.expand(comp),
13882
        close: (apis, comp) => apis.close(comp),
13883
        isOpen: (apis, comp) => apis.isOpen(comp),
13884
        repositionMenus: (apis, comp) => apis.repositionMenus(comp)
13885
      }
13886
    });
13887
 
13888
    const identifyMenuLayout = searchMode => {
13889
      switch (searchMode.searchMode) {
13890
      case 'no-search': {
13891
          return { menuType: 'normal' };
13892
        }
13893
      default: {
13894
          return {
13895
            menuType: 'searchable',
13896
            searchMode
13897
          };
13898
        }
13899
      }
13900
    };
13901
    const handleRefetchTrigger = originalSandboxComp => {
13902
      const dropdown = Representing.getValue(originalSandboxComp);
13903
      const optSearcherState = findWithinSandbox(originalSandboxComp).map(saveState);
13904
      Dropdown.refetch(dropdown).get(() => {
13905
        const newSandboxComp = Coupling.getCoupled(dropdown, 'sandbox');
13906
        optSearcherState.each(searcherState => findWithinSandbox(newSandboxComp).each(inputComp => restoreState(inputComp, searcherState)));
13907
      });
13908
    };
13909
    const handleRedirectToMenuItem = (sandboxComp, se) => {
13910
      getActiveMenuItemFrom(sandboxComp).each(activeItem => {
13911
        retargetAndDispatchWith(sandboxComp, activeItem.element, se.event.eventType, se.event.interactionEvent);
13912
      });
13913
    };
13914
    const getActiveMenuItemFrom = sandboxComp => {
13915
      return Sandboxing.getState(sandboxComp).bind(Highlighting.getHighlighted).bind(Highlighting.getHighlighted);
13916
    };
13917
    const getSearchResults = activeMenuComp => {
13918
      return has(activeMenuComp.element, searchResultsClass) ? Optional.some(activeMenuComp.element) : descendant(activeMenuComp.element, '.' + searchResultsClass);
13919
    };
13920
    const updateAriaOnHighlight = (tmenuComp, menuComp, itemComp) => {
13921
      findWithinMenu(tmenuComp).each(inputComp => {
13922
        setActiveDescendant(inputComp, itemComp);
13923
        const optActiveResults = getSearchResults(menuComp);
13924
        optActiveResults.each(resultsElem => {
13925
          getOpt(resultsElem, 'id').each(controlledId => set$9(inputComp.element, 'aria-controls', controlledId));
13926
        });
13927
      });
13928
      set$9(itemComp.element, 'aria-selected', 'true');
13929
    };
13930
    const updateAriaOnDehighlight = (tmenuComp, menuComp, itemComp) => {
13931
      set$9(itemComp.element, 'aria-selected', 'false');
13932
    };
13933
    const focusSearchField = tmenuComp => {
13934
      findWithinMenu(tmenuComp).each(searcherComp => Focusing.focus(searcherComp));
13935
    };
13936
    const getSearchPattern = dropdownComp => {
13937
      const optSandboxComp = Coupling.getExistingCoupled(dropdownComp, 'sandbox');
13938
      return optSandboxComp.bind(findWithinSandbox).map(saveState).map(state => state.fetchPattern).getOr('');
13939
    };
13940
 
13941
    var FocusMode;
13942
    (function (FocusMode) {
13943
      FocusMode[FocusMode['ContentFocus'] = 0] = 'ContentFocus';
13944
      FocusMode[FocusMode['UiFocus'] = 1] = 'UiFocus';
13945
    }(FocusMode || (FocusMode = {})));
13946
    const createMenuItemFromBridge = (item, itemResponse, backstage, menuHasIcons, isHorizontalMenu) => {
13947
      const providersBackstage = backstage.shared.providers;
13948
      const parseForHorizontalMenu = menuitem => !isHorizontalMenu ? menuitem : {
13949
        ...menuitem,
13950
        shortcut: Optional.none(),
13951
        icon: menuitem.text.isSome() ? Optional.none() : menuitem.icon
13952
      };
13953
      switch (item.type) {
13954
      case 'menuitem':
13955
        return createMenuItem(item).fold(handleError, d => Optional.some(normal(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons)));
13956
      case 'nestedmenuitem':
13957
        return createNestedMenuItem(item).fold(handleError, d => Optional.some(nested(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons, isHorizontalMenu)));
13958
      case 'togglemenuitem':
13959
        return createToggleMenuItem(item).fold(handleError, d => Optional.some(toggle$1(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons)));
13960
      case 'separator':
13961
        return createSeparatorMenuItem(item).fold(handleError, d => Optional.some(separator$3(d)));
13962
      case 'fancymenuitem':
13963
        return createFancyMenuItem(item).fold(handleError, d => fancy(d, backstage));
13964
      default: {
13965
          console.error('Unknown item in general menu', item);
13966
          return Optional.none();
13967
        }
13968
      }
13969
    };
13970
    const createAutocompleteItems = (items, matchText, onItemValueHandler, columns, itemResponse, sharedBackstage, highlightOn) => {
13971
      const renderText = columns === 1;
13972
      const renderIcons = !renderText || menuHasIcons(items);
13973
      return cat(map$2(items, item => {
13974
        switch (item.type) {
13975
        case 'separator':
13976
          return createSeparatorItem(item).fold(handleError, d => Optional.some(separator$3(d)));
13977
        case 'cardmenuitem':
13978
          return createCardMenuItem(item).fold(handleError, d => Optional.some(card({
13979
            ...d,
13980
            onAction: api => {
13981
              d.onAction(api);
13982
              onItemValueHandler(d.value, d.meta);
13983
            }
13984
          }, itemResponse, sharedBackstage, {
1441 ariadna 13985
            itemBehaviours: tooltipBehaviour(d.meta, sharedBackstage, Optional.none()),
1 efrain 13986
            cardText: {
13987
              matchText,
13988
              highlightOn
13989
            }
13990
          })));
13991
        case 'autocompleteitem':
13992
        default:
13993
          return createAutocompleterItem(item).fold(handleError, d => Optional.some(autocomplete(d, matchText, renderText, 'normal', onItemValueHandler, itemResponse, sharedBackstage, renderIcons)));
13994
        }
13995
      }));
13996
    };
13997
    const createPartialMenu = (value, items, itemResponse, backstage, isHorizontalMenu, searchMode) => {
13998
      const hasIcons = menuHasIcons(items);
13999
      const alloyItems = cat(map$2(items, item => {
14000
        const itemHasIcon = i => isHorizontalMenu ? !has$2(i, 'text') : hasIcons;
14001
        const createItem = i => createMenuItemFromBridge(i, itemResponse, backstage, itemHasIcon(i), isHorizontalMenu);
14002
        if (item.type === 'nestedmenuitem' && item.getSubmenuItems().length <= 0) {
14003
          return createItem({
14004
            ...item,
14005
            enabled: false
14006
          });
14007
        } else {
14008
          return createItem(item);
14009
        }
14010
      }));
14011
      const menuLayout = identifyMenuLayout(searchMode);
14012
      const createPartial = isHorizontalMenu ? createHorizontalPartialMenuWithAlloyItems : createPartialMenuWithAlloyItems;
14013
      return createPartial(value, hasIcons, alloyItems, 1, menuLayout);
14014
    };
14015
    const createTieredDataFrom = partialMenu => tieredMenu.singleData(partialMenu.value, partialMenu);
14016
    const createInlineMenuFrom = (partialMenu, columns, focusMode, presets) => {
14017
      const movement = deriveMenuMovement(columns, presets);
14018
      const menuMarkers = markers(presets);
14019
      return {
14020
        data: createTieredDataFrom({
14021
          ...partialMenu,
14022
          movement,
14023
          menuBehaviours: SimpleBehaviours.unnamedEvents(columns !== 'auto' ? [] : [runOnAttached((comp, _se) => {
14024
              detectSize(comp, 4, menuMarkers.item).each(({numColumns, numRows}) => {
14025
                Keying.setGridSize(comp, numRows, numColumns);
14026
              });
14027
            })])
14028
        }),
14029
        menu: {
14030
          markers: markers(presets),
14031
          fakeFocus: focusMode === FocusMode.ContentFocus
14032
        }
14033
      };
14034
    };
14035
 
1441 ariadna 14036
    const rangeToSimRange = r => SimRange.create(SugarElement.fromDom(r.startContainer), r.startOffset, SugarElement.fromDom(r.endContainer), r.endOffset);
14037
    const register$c = (editor, sharedBackstage) => {
1 efrain 14038
      const autocompleterId = generate$6('autocompleter');
14039
      const processingAction = Cell(false);
14040
      const activeState = Cell(false);
1441 ariadna 14041
      const activeRange = value$4();
1 efrain 14042
      const autocompleter = build$1(InlineView.sketch({
14043
        dom: {
14044
          tag: 'div',
14045
          classes: ['tox-autocompleter'],
14046
          attributes: { id: autocompleterId }
14047
        },
14048
        components: [],
14049
        fireDismissalEventInstead: {},
14050
        inlineBehaviours: derive$1([config('dismissAutocompleter', [
14051
            run$1(dismissRequested(), () => cancelIfNecessary()),
14052
            run$1(highlight$1(), (_, se) => {
14053
              getOpt(se.event.target, 'id').each(id => set$9(SugarElement.fromDom(editor.getBody()), 'aria-activedescendant', id));
14054
            })
14055
          ])]),
14056
        lazySink: sharedBackstage.getSink
14057
      }));
14058
      const isMenuOpen = () => InlineView.isOpen(autocompleter);
14059
      const isActive = activeState.get;
14060
      const hideIfNecessary = () => {
14061
        if (isMenuOpen()) {
14062
          InlineView.hide(autocompleter);
14063
          editor.dom.remove(autocompleterId, false);
14064
          const editorBody = SugarElement.fromDom(editor.getBody());
14065
          getOpt(editorBody, 'aria-owns').filter(ariaOwnsAttr => ariaOwnsAttr === autocompleterId).each(() => {
1441 ariadna 14066
            remove$8(editorBody, 'aria-owns');
14067
            remove$8(editorBody, 'aria-activedescendant');
1 efrain 14068
          });
14069
        }
14070
      };
14071
      const getMenu = () => InlineView.getContent(autocompleter).bind(tmenu => {
1441 ariadna 14072
        return get$i(tmenu.components(), 0);
1 efrain 14073
      });
14074
      const cancelIfNecessary = () => editor.execCommand('mceAutocompleterClose');
14075
      const getCombinedItems = matches => {
14076
        const columns = findMap(matches, m => Optional.from(m.columns)).getOr(1);
14077
        return bind$3(matches, match => {
14078
          const choices = match.items;
14079
          return createAutocompleteItems(choices, match.matchText, (itemValue, itemMeta) => {
1441 ariadna 14080
            const autocompleterApi = {
14081
              hide: () => cancelIfNecessary(),
14082
              reload: fetchOptions => {
14083
                hideIfNecessary();
14084
                editor.execCommand('mceAutocompleterReload', false, { fetchOptions });
14085
              }
14086
            };
14087
            editor.execCommand('mceAutocompleterRefreshActiveRange');
14088
            activeRange.get().each(range => {
1 efrain 14089
              processingAction.set(true);
14090
              match.onAction(autocompleterApi, range, itemValue, itemMeta);
14091
              processingAction.set(false);
14092
            });
14093
          }, columns, ItemResponse$1.BUBBLE_TO_SANDBOX, sharedBackstage, match.highlightOn);
14094
        });
14095
      };
14096
      const display = (lookupData, items) => {
1441 ariadna 14097
        const columns = findMap(lookupData, ld => Optional.from(ld.columns)).getOr(1);
14098
        InlineView.showMenuAt(autocompleter, {
14099
          anchor: {
14100
            type: 'selection',
14101
            getSelection: () => activeRange.get().map(rangeToSimRange),
14102
            root: SugarElement.fromDom(editor.getBody())
14103
          }
14104
        }, createInlineMenuFrom(createPartialMenuWithAlloyItems('autocompleter-value', true, items, columns, { menuType: 'normal' }), columns, FocusMode.ContentFocus, 'normal'));
1 efrain 14105
        getMenu().each(Highlighting.highlightFirst);
14106
      };
14107
      const updateDisplay = lookupData => {
14108
        const combinedItems = getCombinedItems(lookupData);
14109
        if (combinedItems.length > 0) {
14110
          display(lookupData, combinedItems);
14111
          set$9(SugarElement.fromDom(editor.getBody()), 'aria-owns', autocompleterId);
14112
          if (!editor.inline) {
14113
            cloneAutocompleterToEditorDoc();
14114
          }
14115
        } else {
14116
          hideIfNecessary();
14117
        }
14118
      };
14119
      const cloneAutocompleterToEditorDoc = () => {
14120
        if (editor.dom.get(autocompleterId)) {
14121
          editor.dom.remove(autocompleterId, false);
14122
        }
14123
        const docElm = editor.getDoc().documentElement;
14124
        const selection = editor.selection.getNode();
14125
        const newElm = deep(autocompleter.element);
14126
        setAll(newElm, {
14127
          border: '0',
14128
          clip: 'rect(0 0 0 0)',
14129
          height: '1px',
14130
          margin: '-1px',
14131
          overflow: 'hidden',
14132
          padding: '0',
14133
          position: 'absolute',
14134
          width: '1px',
14135
          top: `${ selection.offsetTop }px`,
14136
          left: `${ selection.offsetLeft }px`
14137
        });
14138
        editor.dom.add(docElm, newElm.dom);
14139
        descendant(newElm, '[role="menu"]').each(child => {
1441 ariadna 14140
          remove$7(child, 'position');
14141
          remove$7(child, 'max-height');
1 efrain 14142
        });
14143
      };
14144
      editor.on('AutocompleterStart', ({lookupData}) => {
14145
        activeState.set(true);
14146
        processingAction.set(false);
14147
        updateDisplay(lookupData);
14148
      });
14149
      editor.on('AutocompleterUpdate', ({lookupData}) => updateDisplay(lookupData));
1441 ariadna 14150
      editor.on('AutocompleterUpdateActiveRange', ({range}) => activeRange.set(range));
1 efrain 14151
      editor.on('AutocompleterEnd', () => {
14152
        hideIfNecessary();
14153
        activeState.set(false);
14154
        processingAction.set(false);
1441 ariadna 14155
        activeRange.clear();
1 efrain 14156
      });
14157
      const autocompleterUiApi = {
14158
        cancelIfNecessary,
14159
        isMenuOpen,
14160
        isActive,
14161
        isProcessingAction: processingAction.get,
14162
        getMenu
14163
      };
14164
      AutocompleterEditorEvents.setup(autocompleterUiApi, editor);
14165
    };
1441 ariadna 14166
    const Autocompleter = { register: register$c };
1 efrain 14167
 
14168
    const closest = (scope, selector, isRoot) => closest$1(scope, selector, isRoot).isSome();
14169
 
14170
    const DelayedFunction = (fun, delay) => {
14171
      let ref = null;
14172
      const schedule = (...args) => {
14173
        ref = setTimeout(() => {
14174
          fun.apply(null, args);
14175
          ref = null;
14176
        }, delay);
14177
      };
14178
      const cancel = () => {
14179
        if (ref !== null) {
14180
          clearTimeout(ref);
14181
          ref = null;
14182
        }
14183
      };
14184
      return {
14185
        cancel,
14186
        schedule
14187
      };
14188
    };
14189
 
14190
    const SIGNIFICANT_MOVE = 5;
14191
    const LONGPRESS_DELAY = 400;
14192
    const getTouch = event => {
14193
      const raw = event.raw;
14194
      if (raw.touches === undefined || raw.touches.length !== 1) {
14195
        return Optional.none();
14196
      }
14197
      return Optional.some(raw.touches[0]);
14198
    };
14199
    const isFarEnough = (touch, data) => {
14200
      const distX = Math.abs(touch.clientX - data.x);
14201
      const distY = Math.abs(touch.clientY - data.y);
14202
      return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
14203
    };
14204
    const monitor = settings => {
1441 ariadna 14205
      const startData = value$4();
1 efrain 14206
      const longpressFired = Cell(false);
14207
      const longpress$1 = DelayedFunction(event => {
14208
        settings.triggerEvent(longpress(), event);
14209
        longpressFired.set(true);
14210
      }, LONGPRESS_DELAY);
14211
      const handleTouchstart = event => {
14212
        getTouch(event).each(touch => {
14213
          longpress$1.cancel();
14214
          const data = {
14215
            x: touch.clientX,
14216
            y: touch.clientY,
14217
            target: event.target
14218
          };
14219
          longpress$1.schedule(event);
14220
          longpressFired.set(false);
14221
          startData.set(data);
14222
        });
14223
        return Optional.none();
14224
      };
14225
      const handleTouchmove = event => {
14226
        longpress$1.cancel();
14227
        getTouch(event).each(touch => {
14228
          startData.on(data => {
14229
            if (isFarEnough(touch, data)) {
14230
              startData.clear();
14231
            }
14232
          });
14233
        });
14234
        return Optional.none();
14235
      };
14236
      const handleTouchend = event => {
14237
        longpress$1.cancel();
14238
        const isSame = data => eq(data.target, event.target);
14239
        return startData.get().filter(isSame).map(_data => {
14240
          if (longpressFired.get()) {
14241
            event.prevent();
14242
            return false;
14243
          } else {
14244
            return settings.triggerEvent(tap(), event);
14245
          }
14246
        });
14247
      };
14248
      const handlers = wrapAll([
14249
        {
14250
          key: touchstart(),
14251
          value: handleTouchstart
14252
        },
14253
        {
14254
          key: touchmove(),
14255
          value: handleTouchmove
14256
        },
14257
        {
14258
          key: touchend(),
14259
          value: handleTouchend
14260
        }
14261
      ]);
1441 ariadna 14262
      const fireIfReady = (event, type) => get$h(handlers, type).bind(handler => handler(event));
1 efrain 14263
      return { fireIfReady };
14264
    };
14265
 
14266
    const isDangerous = event => {
14267
      const keyEv = event.raw;
14268
      return keyEv.which === BACKSPACE[0] && !contains$2([
14269
        'input',
14270
        'textarea'
14271
      ], name$3(event.target)) && !closest(event.target, '[contenteditable="true"]');
14272
    };
14273
    const setup$d = (container, rawSettings) => {
14274
      const settings = {
14275
        stopBackspace: true,
14276
        ...rawSettings
14277
      };
14278
      const pointerEvents = [
14279
        'touchstart',
14280
        'touchmove',
14281
        'touchend',
14282
        'touchcancel',
14283
        'gesturestart',
14284
        'mousedown',
14285
        'mouseup',
14286
        'mouseover',
14287
        'mousemove',
14288
        'mouseout',
14289
        'click'
14290
      ];
14291
      const tapEvent = monitor(settings);
14292
      const simpleEvents = map$2(pointerEvents.concat([
14293
        'selectstart',
14294
        'input',
14295
        'contextmenu',
14296
        'change',
14297
        'transitionend',
14298
        'transitioncancel',
14299
        'drag',
14300
        'dragstart',
14301
        'dragend',
14302
        'dragenter',
14303
        'dragleave',
14304
        'dragover',
14305
        'drop',
14306
        'keyup'
14307
      ]), type => bind(container, type, event => {
14308
        tapEvent.fireIfReady(event, type).each(tapStopped => {
14309
          if (tapStopped) {
14310
            event.kill();
14311
          }
14312
        });
14313
        const stopped = settings.triggerEvent(type, event);
14314
        if (stopped) {
14315
          event.kill();
14316
        }
14317
      }));
1441 ariadna 14318
      const pasteTimeout = value$4();
1 efrain 14319
      const onPaste = bind(container, 'paste', event => {
14320
        tapEvent.fireIfReady(event, 'paste').each(tapStopped => {
14321
          if (tapStopped) {
14322
            event.kill();
14323
          }
14324
        });
14325
        const stopped = settings.triggerEvent('paste', event);
14326
        if (stopped) {
14327
          event.kill();
14328
        }
14329
        pasteTimeout.set(setTimeout(() => {
14330
          settings.triggerEvent(postPaste(), event);
14331
        }, 0));
14332
      });
14333
      const onKeydown = bind(container, 'keydown', event => {
14334
        const stopped = settings.triggerEvent('keydown', event);
14335
        if (stopped) {
14336
          event.kill();
14337
        } else if (settings.stopBackspace && isDangerous(event)) {
14338
          event.prevent();
14339
        }
14340
      });
14341
      const onFocusIn = bind(container, 'focusin', event => {
14342
        const stopped = settings.triggerEvent('focusin', event);
14343
        if (stopped) {
14344
          event.kill();
14345
        }
14346
      });
1441 ariadna 14347
      const focusoutTimeout = value$4();
1 efrain 14348
      const onFocusOut = bind(container, 'focusout', event => {
14349
        const stopped = settings.triggerEvent('focusout', event);
14350
        if (stopped) {
14351
          event.kill();
14352
        }
14353
        focusoutTimeout.set(setTimeout(() => {
14354
          settings.triggerEvent(postBlur(), event);
14355
        }, 0));
14356
      });
14357
      const unbind = () => {
14358
        each$1(simpleEvents, e => {
14359
          e.unbind();
14360
        });
14361
        onKeydown.unbind();
14362
        onFocusIn.unbind();
14363
        onFocusOut.unbind();
14364
        onPaste.unbind();
14365
        pasteTimeout.on(clearTimeout);
14366
        focusoutTimeout.on(clearTimeout);
14367
      };
14368
      return { unbind };
14369
    };
14370
 
14371
    const derive = (rawEvent, rawTarget) => {
1441 ariadna 14372
      const source = get$h(rawEvent, 'target').getOr(rawTarget);
1 efrain 14373
      return Cell(source);
14374
    };
14375
 
14376
    const fromSource = (event, source) => {
14377
      const stopper = Cell(false);
14378
      const cutter = Cell(false);
14379
      const stop = () => {
14380
        stopper.set(true);
14381
      };
14382
      const cut = () => {
14383
        cutter.set(true);
14384
      };
14385
      return {
14386
        stop,
14387
        cut,
14388
        isStopped: stopper.get,
14389
        isCut: cutter.get,
14390
        event,
14391
        setSource: source.set,
14392
        getSource: source.get
14393
      };
14394
    };
14395
    const fromExternal = event => {
14396
      const stopper = Cell(false);
14397
      const stop = () => {
14398
        stopper.set(true);
14399
      };
14400
      return {
14401
        stop,
14402
        cut: noop,
14403
        isStopped: stopper.get,
14404
        isCut: never,
14405
        event,
14406
        setSource: die('Cannot set source of a broadcasted event'),
14407
        getSource: die('Cannot get source of a broadcasted event')
14408
      };
14409
    };
14410
 
14411
    const adt$1 = Adt.generate([
14412
      { stopped: [] },
14413
      { resume: ['element'] },
14414
      { complete: [] }
14415
    ]);
14416
    const doTriggerHandler = (lookup, eventType, rawEvent, target, source, logger) => {
14417
      const handler = lookup(eventType, target);
14418
      const simulatedEvent = fromSource(rawEvent, source);
14419
      return handler.fold(() => {
14420
        logger.logEventNoHandlers(eventType, target);
14421
        return adt$1.complete();
14422
      }, handlerInfo => {
14423
        const descHandler = handlerInfo.descHandler;
14424
        const eventHandler = getCurried(descHandler);
14425
        eventHandler(simulatedEvent);
14426
        if (simulatedEvent.isStopped()) {
14427
          logger.logEventStopped(eventType, handlerInfo.element, descHandler.purpose);
14428
          return adt$1.stopped();
14429
        } else if (simulatedEvent.isCut()) {
14430
          logger.logEventCut(eventType, handlerInfo.element, descHandler.purpose);
14431
          return adt$1.complete();
14432
        } else {
14433
          return parent(handlerInfo.element).fold(() => {
14434
            logger.logNoParent(eventType, handlerInfo.element, descHandler.purpose);
14435
            return adt$1.complete();
14436
          }, parent => {
14437
            logger.logEventResponse(eventType, handlerInfo.element, descHandler.purpose);
14438
            return adt$1.resume(parent);
14439
          });
14440
        }
14441
      });
14442
    };
14443
    const doTriggerOnUntilStopped = (lookup, eventType, rawEvent, rawTarget, source, logger) => doTriggerHandler(lookup, eventType, rawEvent, rawTarget, source, logger).fold(always, parent => doTriggerOnUntilStopped(lookup, eventType, rawEvent, parent, source, logger), never);
14444
    const triggerHandler = (lookup, eventType, rawEvent, target, logger) => {
14445
      const source = derive(rawEvent, target);
14446
      return doTriggerHandler(lookup, eventType, rawEvent, target, source, logger);
14447
    };
14448
    const broadcast = (listeners, rawEvent, _logger) => {
14449
      const simulatedEvent = fromExternal(rawEvent);
14450
      each$1(listeners, listener => {
14451
        const descHandler = listener.descHandler;
14452
        const handler = getCurried(descHandler);
14453
        handler(simulatedEvent);
14454
      });
14455
      return simulatedEvent.isStopped();
14456
    };
14457
    const triggerUntilStopped = (lookup, eventType, rawEvent, logger) => triggerOnUntilStopped(lookup, eventType, rawEvent, rawEvent.target, logger);
14458
    const triggerOnUntilStopped = (lookup, eventType, rawEvent, rawTarget, logger) => {
14459
      const source = derive(rawEvent, rawTarget);
14460
      return doTriggerOnUntilStopped(lookup, eventType, rawEvent, rawTarget, source, logger);
14461
    };
14462
 
14463
    const eventHandler = (element, descHandler) => ({
14464
      element,
14465
      descHandler
14466
    });
14467
    const broadcastHandler = (id, handler) => ({
14468
      id,
14469
      descHandler: handler
14470
    });
14471
    const EventRegistry = () => {
14472
      const registry = {};
14473
      const registerId = (extraArgs, id, events) => {
14474
        each(events, (v, k) => {
14475
          const handlers = registry[k] !== undefined ? registry[k] : {};
14476
          handlers[id] = curryArgs(v, extraArgs);
14477
          registry[k] = handlers;
14478
        });
14479
      };
1441 ariadna 14480
      const findHandler = (handlers, elem) => read(elem).bind(id => get$h(handlers, id)).map(descHandler => eventHandler(elem, descHandler));
14481
      const filterByType = type => get$h(registry, type).map(handlers => mapToArray(handlers, (f, id) => broadcastHandler(id, f))).getOr([]);
14482
      const find = (isAboveRoot, type, target) => get$h(registry, type).bind(handlers => closest$4(target, elem => findHandler(handlers, elem), isAboveRoot));
1 efrain 14483
      const unregisterId = id => {
14484
        each(registry, (handlersById, _eventName) => {
14485
          if (has$2(handlersById, id)) {
14486
            delete handlersById[id];
14487
          }
14488
        });
14489
      };
14490
      return {
14491
        registerId,
14492
        unregisterId,
14493
        filterByType,
14494
        find
14495
      };
14496
    };
14497
 
14498
    const Registry = () => {
14499
      const events = EventRegistry();
14500
      const components = {};
14501
      const readOrTag = component => {
14502
        const elem = component.element;
1441 ariadna 14503
        return read(elem).getOrThunk(() => write('uid-', component.element));
1 efrain 14504
      };
14505
      const failOnDuplicate = (component, tagId) => {
14506
        const conflict = components[tagId];
14507
        if (conflict === component) {
14508
          unregister(component);
14509
        } else {
14510
          throw new Error('The tagId "' + tagId + '" is already used by: ' + element(conflict.element) + '\nCannot use it for: ' + element(component.element) + '\n' + 'The conflicting element is' + (inBody(conflict.element) ? ' ' : ' not ') + 'already in the DOM');
14511
        }
14512
      };
14513
      const register = component => {
14514
        const tagId = readOrTag(component);
14515
        if (hasNonNullableKey(components, tagId)) {
14516
          failOnDuplicate(component, tagId);
14517
        }
14518
        const extraArgs = [component];
14519
        events.registerId(extraArgs, tagId, component.events);
14520
        components[tagId] = component;
14521
      };
14522
      const unregister = component => {
1441 ariadna 14523
        read(component.element).each(tagId => {
1 efrain 14524
          delete components[tagId];
14525
          events.unregisterId(tagId);
14526
        });
14527
      };
14528
      const filter = type => events.filterByType(type);
14529
      const find = (isAboveRoot, type, target) => events.find(isAboveRoot, type, target);
1441 ariadna 14530
      const getById = id => get$h(components, id);
1 efrain 14531
      return {
14532
        find,
14533
        filter,
14534
        register,
14535
        unregister,
14536
        getById
14537
      };
14538
    };
14539
 
14540
    const factory$j = detail => {
14541
      const {attributes, ...domWithoutAttributes} = detail.dom;
14542
      return {
14543
        uid: detail.uid,
14544
        dom: {
14545
          tag: 'div',
14546
          attributes: {
14547
            role: 'presentation',
14548
            ...attributes
14549
          },
14550
          ...domWithoutAttributes
14551
        },
14552
        components: detail.components,
1441 ariadna 14553
        behaviours: get$4(detail.containerBehaviours),
1 efrain 14554
        events: detail.events,
14555
        domModification: detail.domModification,
14556
        eventOrder: detail.eventOrder
14557
      };
14558
    };
14559
    const Container = single({
14560
      name: 'Container',
14561
      factory: factory$j,
14562
      configFields: [
14563
        defaulted('components', []),
14564
        field('containerBehaviours', []),
14565
        defaulted('events', {}),
14566
        defaulted('domModification', {}),
14567
        defaulted('eventOrder', {})
14568
      ]
14569
    });
14570
 
14571
    const takeover = root => {
14572
      const isAboveRoot = el => parent(root.element).fold(always, parent => eq(el, parent));
14573
      const registry = Registry();
14574
      const lookup = (eventName, target) => registry.find(isAboveRoot, eventName, target);
14575
      const domEvents = setup$d(root.element, {
14576
        triggerEvent: (eventName, event) => {
14577
          return monitorEvent(eventName, event.target, logger => triggerUntilStopped(lookup, eventName, event, logger));
14578
        }
14579
      });
14580
      const systemApi = {
14581
        debugInfo: constant$1('real'),
14582
        triggerEvent: (eventName, target, data) => {
14583
          monitorEvent(eventName, target, logger => triggerOnUntilStopped(lookup, eventName, data, target, logger));
14584
        },
14585
        triggerFocus: (target, originator) => {
1441 ariadna 14586
          read(target).fold(() => {
1 efrain 14587
            focus$3(target);
14588
          }, _alloyId => {
14589
            monitorEvent(focus$4(), target, logger => {
14590
              triggerHandler(lookup, focus$4(), {
14591
                originator,
14592
                kill: noop,
14593
                prevent: noop,
14594
                target
14595
              }, target, logger);
14596
              return false;
14597
            });
14598
          });
14599
        },
14600
        triggerEscape: (comp, simulatedEvent) => {
14601
          systemApi.triggerEvent('keydown', comp.element, simulatedEvent.event);
14602
        },
14603
        getByUid: uid => {
14604
          return getByUid(uid);
14605
        },
14606
        getByDom: elem => {
14607
          return getByDom(elem);
14608
        },
14609
        build: build$1,
14610
        buildOrPatch: buildOrPatch,
14611
        addToGui: c => {
14612
          add(c);
14613
        },
14614
        removeFromGui: c => {
14615
          remove(c);
14616
        },
14617
        addToWorld: c => {
14618
          addToWorld(c);
14619
        },
14620
        removeFromWorld: c => {
14621
          removeFromWorld(c);
14622
        },
14623
        broadcast: message => {
14624
          broadcast$1(message);
14625
        },
14626
        broadcastOn: (channels, message) => {
14627
          broadcastOn(channels, message);
14628
        },
14629
        broadcastEvent: (eventName, event) => {
14630
          broadcastEvent(eventName, event);
14631
        },
14632
        isConnected: always
14633
      };
14634
      const addToWorld = component => {
14635
        component.connect(systemApi);
14636
        if (!isText(component.element)) {
14637
          registry.register(component);
14638
          each$1(component.components(), addToWorld);
14639
          systemApi.triggerEvent(systemInit(), component.element, { target: component.element });
14640
        }
14641
      };
14642
      const removeFromWorld = component => {
14643
        if (!isText(component.element)) {
14644
          each$1(component.components(), removeFromWorld);
14645
          registry.unregister(component);
14646
        }
14647
        component.disconnect();
14648
      };
14649
      const add = component => {
14650
        attach(root, component);
14651
      };
14652
      const remove = component => {
14653
        detach(component);
14654
      };
14655
      const destroy = () => {
14656
        domEvents.unbind();
1441 ariadna 14657
        remove$6(root.element);
1 efrain 14658
      };
14659
      const broadcastData = data => {
14660
        const receivers = registry.filter(receive());
14661
        each$1(receivers, receiver => {
14662
          const descHandler = receiver.descHandler;
14663
          const handler = getCurried(descHandler);
14664
          handler(data);
14665
        });
14666
      };
14667
      const broadcast$1 = message => {
14668
        broadcastData({
14669
          universal: true,
14670
          data: message
14671
        });
14672
      };
14673
      const broadcastOn = (channels, message) => {
14674
        broadcastData({
14675
          universal: false,
14676
          channels,
14677
          data: message
14678
        });
14679
      };
14680
      const broadcastEvent = (eventName, event) => {
14681
        const listeners = registry.filter(eventName);
14682
        return broadcast(listeners, event);
14683
      };
14684
      const getByUid = uid => registry.getById(uid).fold(() => Result.error(new Error('Could not find component with uid: "' + uid + '" in system.')), Result.value);
14685
      const getByDom = elem => {
1441 ariadna 14686
        const uid = read(elem).getOr('not found');
1 efrain 14687
        return getByUid(uid);
14688
      };
14689
      addToWorld(root);
14690
      return {
14691
        root,
14692
        element: root.element,
14693
        destroy,
14694
        add,
14695
        remove,
14696
        getByUid,
14697
        getByDom,
14698
        addToWorld,
14699
        removeFromWorld,
14700
        broadcast: broadcast$1,
14701
        broadcastOn,
14702
        broadcastEvent
14703
      };
14704
    };
14705
 
14706
    const renderBar = (spec, backstage) => ({
14707
      dom: {
14708
        tag: 'div',
14709
        classes: [
14710
          'tox-bar',
14711
          'tox-form__controls-h-stack'
14712
        ]
14713
      },
14714
      components: map$2(spec.items, backstage.interpreter)
14715
    });
14716
 
14717
    const schema$j = constant$1([
14718
      defaulted('prefix', 'form-field'),
14719
      field('fieldBehaviours', [
14720
        Composing,
14721
        Representing
14722
      ])
14723
    ]);
14724
    const parts$d = constant$1([
14725
      optional({
14726
        schema: [required$1('dom')],
14727
        name: 'label'
14728
      }),
14729
      optional({
14730
        factory: {
14731
          sketch: spec => {
14732
            return {
14733
              uid: spec.uid,
14734
              dom: {
14735
                tag: 'span',
14736
                styles: { display: 'none' },
14737
                attributes: { 'aria-hidden': 'true' },
14738
                innerHtml: spec.text
14739
              }
14740
            };
14741
          }
14742
        },
14743
        schema: [required$1('text')],
14744
        name: 'aria-descriptor'
14745
      }),
14746
      required({
14747
        factory: {
14748
          sketch: spec => {
14749
            const excludeFactory = exclude(spec, ['factory']);
14750
            return spec.factory.sketch(excludeFactory);
14751
          }
14752
        },
14753
        schema: [required$1('factory')],
14754
        name: 'field'
14755
      })
14756
    ]);
14757
 
14758
    const factory$i = (detail, components, _spec, _externals) => {
14759
      const behaviours = augment(detail.fieldBehaviours, [
14760
        Composing.config({
14761
          find: container => {
14762
            return getPart(container, detail, 'field');
14763
          }
14764
        }),
14765
        Representing.config({
14766
          store: {
14767
            mode: 'manual',
14768
            getValue: field => {
14769
              return Composing.getCurrent(field).bind(Representing.getValue);
14770
            },
14771
            setValue: (field, value) => {
14772
              Composing.getCurrent(field).each(current => {
14773
                Representing.setValue(current, value);
14774
              });
14775
            }
14776
          }
14777
        })
14778
      ]);
14779
      const events = derive$2([runOnAttached((component, _simulatedEvent) => {
14780
          const ps = getParts(component, detail, [
14781
            'label',
14782
            'field',
14783
            'aria-descriptor'
14784
          ]);
14785
          ps.field().each(field => {
14786
            const id = generate$6(detail.prefix);
14787
            ps.label().each(label => {
14788
              set$9(label.element, 'for', id);
14789
              set$9(field.element, 'id', id);
14790
            });
14791
            ps['aria-descriptor']().each(descriptor => {
14792
              const descriptorId = generate$6(detail.prefix);
14793
              set$9(descriptor.element, 'id', descriptorId);
14794
              set$9(field.element, 'aria-describedby', descriptorId);
14795
            });
14796
          });
14797
        })]);
14798
      const apis = {
14799
        getField: container => getPart(container, detail, 'field'),
14800
        getLabel: container => getPart(container, detail, 'label')
14801
      };
14802
      return {
14803
        uid: detail.uid,
14804
        dom: detail.dom,
14805
        components,
14806
        behaviours,
14807
        events,
14808
        apis
14809
      };
14810
    };
14811
    const FormField = composite({
14812
      name: 'FormField',
14813
      configFields: schema$j(),
14814
      partFields: parts$d(),
14815
      factory: factory$i,
14816
      apis: {
14817
        getField: (apis, comp) => apis.getField(comp),
14818
        getLabel: (apis, comp) => apis.getLabel(comp)
14819
      }
14820
    });
14821
 
14822
    var global$3 = tinymce.util.Tools.resolve('tinymce.html.Entities');
14823
 
14824
    const renderFormFieldWith = (pLabel, pField, extraClasses, extraBehaviours) => {
14825
      const spec = renderFormFieldSpecWith(pLabel, pField, extraClasses, extraBehaviours);
14826
      return FormField.sketch(spec);
14827
    };
14828
    const renderFormField = (pLabel, pField) => renderFormFieldWith(pLabel, pField, [], []);
14829
    const renderFormFieldSpecWith = (pLabel, pField, extraClasses, extraBehaviours) => ({
14830
      dom: renderFormFieldDomWith(extraClasses),
14831
      components: pLabel.toArray().concat([pField]),
14832
      fieldBehaviours: derive$1(extraBehaviours)
14833
    });
14834
    const renderFormFieldDom = () => renderFormFieldDomWith([]);
14835
    const renderFormFieldDomWith = extraClasses => ({
14836
      tag: 'div',
14837
      classes: ['tox-form__group'].concat(extraClasses)
14838
    });
14839
    const renderLabel$3 = (label, providersBackstage) => FormField.parts.label({
14840
      dom: {
14841
        tag: 'label',
14842
        classes: ['tox-label']
14843
      },
14844
      components: [text$2(providersBackstage.translate(label))]
14845
    });
14846
 
14847
    const formChangeEvent = generate$6('form-component-change');
1441 ariadna 14848
    const formInputEvent = generate$6('form-component-input');
1 efrain 14849
    const formCloseEvent = generate$6('form-close');
14850
    const formCancelEvent = generate$6('form-cancel');
14851
    const formActionEvent = generate$6('form-action');
14852
    const formSubmitEvent = generate$6('form-submit');
14853
    const formBlockEvent = generate$6('form-block');
14854
    const formUnblockEvent = generate$6('form-unblock');
14855
    const formTabChangeEvent = generate$6('form-tabchange');
14856
    const formResizeEvent = generate$6('form-resize');
14857
 
14858
    const renderCollection = (spec, providersBackstage, initialData) => {
14859
      const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
14860
      const icons = providersBackstage.icons();
14861
      const getIcon = icon => {
14862
        var _a;
14863
        return (_a = icons[icon]) !== null && _a !== void 0 ? _a : icon;
14864
      };
14865
      const runOnItem = f => (comp, se) => {
14866
        closest$1(se.event.target, '[data-collection-item-value]').each(target => {
1441 ariadna 14867
          f(comp, se, target, get$g(target, 'data-collection-item-value'));
1 efrain 14868
        });
14869
      };
14870
      const setContents = (comp, items) => {
1441 ariadna 14871
        const disabled = providersBackstage.checkUiComponentContext('mode:design').shouldDisable || providersBackstage.isDisabled();
14872
        const disabledClass = disabled ? ' tox-collection__item--state-disabled' : '';
1 efrain 14873
        const htmlLines = map$2(items, item => {
1441 ariadna 14874
          const itemText = global$5.translate(item.text);
1 efrain 14875
          const textContent = spec.columns === 1 ? `<div class="tox-collection__item-label">${ itemText }</div>` : '';
14876
          const iconContent = `<div class="tox-collection__item-icon">${ getIcon(item.icon) }</div>`;
14877
          const mapItemName = {
14878
            '_': ' ',
14879
            ' - ': ' ',
14880
            '-': ' '
14881
          };
14882
          const ariaLabel = itemText.replace(/\_| \- |\-/g, match => mapItemName[match]);
1441 ariadna 14883
          return `<div data-mce-tooltip="${ ariaLabel }" class="tox-collection__item${ disabledClass }" tabindex="-1" data-collection-item-value="${ global$3.encodeAllRaw(item.value) }" aria-label="${ ariaLabel }">${ iconContent }${ textContent }</div>`;
1 efrain 14884
        });
14885
        const chunks = spec.columns !== 'auto' && spec.columns > 1 ? chunk$1(htmlLines, spec.columns) : [htmlLines];
14886
        const html = map$2(chunks, ch => `<div class="tox-collection__group">${ ch.join('') }</div>`);
14887
        set$6(comp.element, html.join(''));
14888
      };
14889
      const onClick = runOnItem((comp, se, tgt, itemValue) => {
14890
        se.stop();
1441 ariadna 14891
        if (!(providersBackstage.checkUiComponentContext('mode:design').shouldDisable || providersBackstage.isDisabled())) {
1 efrain 14892
          emitWith(comp, formActionEvent, {
14893
            name: spec.name,
14894
            value: itemValue
14895
          });
14896
        }
14897
      });
14898
      const collectionEvents = [
14899
        run$1(mouseover(), runOnItem((comp, se, tgt) => {
1441 ariadna 14900
          focus$3(tgt, true);
1 efrain 14901
        })),
14902
        run$1(click(), onClick),
14903
        run$1(tap(), onClick),
14904
        run$1(focusin(), runOnItem((comp, se, tgt) => {
14905
          descendant(comp.element, '.' + activeClass).each(currentActive => {
1441 ariadna 14906
            remove$3(currentActive, activeClass);
1 efrain 14907
          });
14908
          add$2(tgt, activeClass);
14909
        })),
14910
        run$1(focusout(), runOnItem(comp => {
14911
          descendant(comp.element, '.' + activeClass).each(currentActive => {
1441 ariadna 14912
            remove$3(currentActive, activeClass);
14913
            blur$1(currentActive);
1 efrain 14914
          });
14915
        })),
14916
        runOnExecute$1(runOnItem((comp, se, tgt, itemValue) => {
14917
          emitWith(comp, formActionEvent, {
14918
            name: spec.name,
14919
            value: itemValue
14920
          });
14921
        }))
14922
      ];
14923
      const iterCollectionItems = (comp, applyAttributes) => map$2(descendants(comp.element, '.tox-collection__item'), applyAttributes);
14924
      const pField = FormField.parts.field({
14925
        dom: {
14926
          tag: 'div',
14927
          classes: ['tox-collection'].concat(spec.columns !== 1 ? ['tox-collection--grid'] : ['tox-collection--list'])
14928
        },
14929
        components: [],
14930
        factory: { sketch: identity },
14931
        behaviours: derive$1([
14932
          Disabling.config({
1441 ariadna 14933
            disabled: () => providersBackstage.checkUiComponentContext(spec.context).shouldDisable,
1 efrain 14934
            onDisabled: comp => {
14935
              iterCollectionItems(comp, childElm => {
14936
                add$2(childElm, 'tox-collection__item--state-disabled');
14937
                set$9(childElm, 'aria-disabled', true);
14938
              });
14939
            },
14940
            onEnabled: comp => {
14941
              iterCollectionItems(comp, childElm => {
1441 ariadna 14942
                remove$3(childElm, 'tox-collection__item--state-disabled');
14943
                remove$8(childElm, 'aria-disabled');
1 efrain 14944
              });
14945
            }
14946
          }),
1441 ariadna 14947
          toggleOnReceive(() => providersBackstage.checkUiComponentContext(spec.context)),
1 efrain 14948
          Replacing.config({}),
1441 ariadna 14949
          Tooltipping.config({
14950
            ...providersBackstage.tooltips.getConfig({
14951
              tooltipText: '',
14952
              onShow: comp => {
14953
                descendant(comp.element, '.' + activeClass + '[data-mce-tooltip]').each(current => {
14954
                  getOpt(current, 'data-mce-tooltip').each(text => {
14955
                    Tooltipping.setComponents(comp, providersBackstage.tooltips.getComponents({ tooltipText: text }));
14956
                  });
14957
                });
14958
              }
14959
            }),
14960
            mode: 'children-keyboard-focus',
14961
            anchor: comp => ({
14962
              type: 'node',
14963
              node: descendant(comp.element, '.' + activeClass).orThunk(() => first$1('.tox-collection__item')),
14964
              root: comp.element,
14965
              layouts: {
14966
                onLtr: constant$1([
14967
                  south$2,
14968
                  north$2,
14969
                  southeast$2,
14970
                  northeast$2,
14971
                  southwest$2,
14972
                  northwest$2
14973
                ]),
14974
                onRtl: constant$1([
14975
                  south$2,
14976
                  north$2,
14977
                  southeast$2,
14978
                  northeast$2,
14979
                  southwest$2,
14980
                  northwest$2
14981
                ])
14982
              },
14983
              bubble: nu$5(0, -2, {})
14984
            })
14985
          }),
1 efrain 14986
          Representing.config({
14987
            store: {
14988
              mode: 'memory',
14989
              initialValue: initialData.getOr([])
14990
            },
14991
            onSetValue: (comp, items) => {
14992
              setContents(comp, items);
14993
              if (spec.columns === 'auto') {
14994
                detectSize(comp, 5, 'tox-collection__item').each(({numRows, numColumns}) => {
14995
                  Keying.setGridSize(comp, numRows, numColumns);
14996
                });
14997
              }
14998
              emit(comp, formResizeEvent);
14999
            }
15000
          }),
15001
          Tabstopping.config({}),
15002
          Keying.config(deriveCollectionMovement(spec.columns, 'normal')),
15003
          config('collection-events', collectionEvents)
15004
        ]),
15005
        eventOrder: {
15006
          [execute$5()]: [
15007
            'disabling',
15008
            'alloy.base.behaviour',
15009
            'collection-events'
1441 ariadna 15010
          ],
15011
          [focusin()]: [
15012
            'collection-events',
15013
            'tooltipping'
1 efrain 15014
          ]
15015
        }
15016
      });
15017
      const extraClasses = ['tox-form__group--collection'];
15018
      return renderFormFieldWith(pLabel, pField, extraClasses, []);
15019
    };
15020
 
15021
    const ariaElements = [
15022
      'input',
15023
      'textarea'
15024
    ];
15025
    const isAriaElement = elem => {
15026
      const name = name$3(elem);
15027
      return contains$2(ariaElements, name);
15028
    };
15029
    const markValid = (component, invalidConfig) => {
15030
      const elem = invalidConfig.getRoot(component).getOr(component.element);
1441 ariadna 15031
      remove$3(elem, invalidConfig.invalidClass);
1 efrain 15032
      invalidConfig.notify.each(notifyInfo => {
15033
        if (isAriaElement(component.element)) {
15034
          set$9(component.element, 'aria-invalid', false);
15035
        }
15036
        notifyInfo.getContainer(component).each(container => {
15037
          set$6(container, notifyInfo.validHtml);
15038
        });
15039
        notifyInfo.onValid(component);
15040
      });
15041
    };
15042
    const markInvalid = (component, invalidConfig, invalidState, text) => {
15043
      const elem = invalidConfig.getRoot(component).getOr(component.element);
15044
      add$2(elem, invalidConfig.invalidClass);
15045
      invalidConfig.notify.each(notifyInfo => {
15046
        if (isAriaElement(component.element)) {
15047
          set$9(component.element, 'aria-invalid', true);
15048
        }
15049
        notifyInfo.getContainer(component).each(container => {
15050
          set$6(container, text);
15051
        });
15052
        notifyInfo.onInvalid(component, text);
15053
      });
15054
    };
15055
    const query = (component, invalidConfig, _invalidState) => invalidConfig.validator.fold(() => Future.pure(Result.value(true)), validatorInfo => validatorInfo.validate(component));
15056
    const run = (component, invalidConfig, invalidState) => {
15057
      invalidConfig.notify.each(notifyInfo => {
15058
        notifyInfo.onValidate(component);
15059
      });
15060
      return query(component, invalidConfig).map(valid => {
15061
        if (component.getSystem().isConnected()) {
15062
          return valid.fold(err => {
15063
            markInvalid(component, invalidConfig, invalidState, err);
15064
            return Result.error(err);
15065
          }, v => {
15066
            markValid(component, invalidConfig);
15067
            return Result.value(v);
15068
          });
15069
        } else {
15070
          return Result.error('No longer in system');
15071
        }
15072
      });
15073
    };
15074
    const isInvalid = (component, invalidConfig) => {
15075
      const elem = invalidConfig.getRoot(component).getOr(component.element);
15076
      return has(elem, invalidConfig.invalidClass);
15077
    };
15078
 
15079
    var InvalidateApis = /*#__PURE__*/Object.freeze({
15080
        __proto__: null,
15081
        markValid: markValid,
15082
        markInvalid: markInvalid,
15083
        query: query,
15084
        run: run,
15085
        isInvalid: isInvalid
15086
    });
15087
 
1441 ariadna 15088
    const events$7 = (invalidConfig, invalidState) => invalidConfig.validator.map(validatorInfo => derive$2([run$1(validatorInfo.onEvent, component => {
1 efrain 15089
        run(component, invalidConfig, invalidState).get(identity);
15090
      })].concat(validatorInfo.validateOnLoad ? [runOnAttached(component => {
15091
        run(component, invalidConfig, invalidState).get(noop);
15092
      })] : []))).getOr({});
15093
 
15094
    var ActiveInvalidate = /*#__PURE__*/Object.freeze({
15095
        __proto__: null,
1441 ariadna 15096
        events: events$7
1 efrain 15097
    });
15098
 
15099
    var InvalidateSchema = [
15100
      required$1('invalidClass'),
15101
      defaulted('getRoot', Optional.none),
15102
      optionObjOf('notify', [
15103
        defaulted('aria', 'alert'),
15104
        defaulted('getContainer', Optional.none),
15105
        defaulted('validHtml', ''),
15106
        onHandler('onValid'),
15107
        onHandler('onInvalid'),
15108
        onHandler('onValidate')
15109
      ]),
15110
      optionObjOf('validator', [
15111
        required$1('validate'),
15112
        defaulted('onEvent', 'input'),
15113
        defaulted('validateOnLoad', true)
15114
      ])
15115
    ];
15116
 
15117
    const Invalidating = create$4({
15118
      fields: InvalidateSchema,
15119
      name: 'invalidating',
15120
      active: ActiveInvalidate,
15121
      apis: InvalidateApis,
15122
      extra: {
15123
        validation: validator => {
15124
          return component => {
15125
            const v = Representing.getValue(component);
15126
            return Future.pure(validator(v));
15127
          };
15128
        }
15129
      }
15130
    });
15131
 
1441 ariadna 15132
    const exhibit$1 = () => nu$8({
1 efrain 15133
      styles: {
15134
        '-webkit-user-select': 'none',
15135
        'user-select': 'none',
15136
        '-ms-user-select': 'none',
15137
        '-moz-user-select': '-moz-none'
15138
      },
15139
      attributes: { unselectable: 'on' }
15140
    });
1441 ariadna 15141
    const events$6 = () => derive$2([abort(selectstart(), always)]);
1 efrain 15142
 
15143
    var ActiveUnselecting = /*#__PURE__*/Object.freeze({
15144
        __proto__: null,
1441 ariadna 15145
        events: events$6,
1 efrain 15146
        exhibit: exhibit$1
15147
    });
15148
 
15149
    const Unselecting = create$4({
15150
      fields: [],
15151
      name: 'unselecting',
15152
      active: ActiveUnselecting
15153
    });
15154
 
15155
    const renderPanelButton = (spec, sharedBackstage) => Dropdown.sketch({
15156
      dom: spec.dom,
15157
      components: spec.components,
15158
      toggleClass: 'mce-active',
15159
      dropdownBehaviours: derive$1([
1441 ariadna 15160
        DisablingConfigs.button(() => sharedBackstage.providers.isDisabled() || sharedBackstage.providers.checkUiComponentContext(spec.context).shouldDisable),
15161
        toggleOnReceive(() => sharedBackstage.providers.checkUiComponentContext(spec.context)),
1 efrain 15162
        Unselecting.config({}),
15163
        Tabstopping.config({})
15164
      ]),
15165
      layouts: spec.layouts,
15166
      sandboxClasses: ['tox-dialog__popups'],
15167
      lazySink: sharedBackstage.getSink,
15168
      fetch: comp => Future.nu(callback => spec.fetch(callback)).map(items => Optional.from(createTieredDataFrom(deepMerge(createPartialChoiceMenu(generate$6('menu-value'), items, value => {
15169
        spec.onItemAction(comp, value);
15170
      }, spec.columns, spec.presets, ItemResponse$1.CLOSE_ON_EXECUTE, never, sharedBackstage.providers), { movement: deriveMenuMovement(spec.columns, spec.presets) })))),
15171
      parts: { menu: part(false, 1, spec.presets) }
15172
    });
15173
 
15174
    const colorInputChangeEvent = generate$6('color-input-change');
15175
    const colorSwatchChangeEvent = generate$6('color-swatch-change');
15176
    const colorPickerCancelEvent = generate$6('color-picker-cancel');
15177
    const renderColorInput = (spec, sharedBackstage, colorInputBackstage, initialData) => {
15178
      const pField = FormField.parts.field({
15179
        factory: Input,
15180
        inputClasses: ['tox-textfield'],
15181
        data: initialData,
15182
        onSetValue: c => Invalidating.run(c).get(noop),
15183
        inputBehaviours: derive$1([
1441 ariadna 15184
          Disabling.config({ disabled: () => sharedBackstage.providers.isDisabled() || sharedBackstage.providers.checkUiComponentContext(spec.context).shouldDisable }),
15185
          toggleOnReceive(() => sharedBackstage.providers.checkUiComponentContext(spec.context)),
1 efrain 15186
          Tabstopping.config({}),
15187
          Invalidating.config({
15188
            invalidClass: 'tox-textbox-field-invalid',
15189
            getRoot: comp => parentElement(comp.element),
15190
            notify: {
15191
              onValid: comp => {
15192
                const val = Representing.getValue(comp);
15193
                emitWith(comp, colorInputChangeEvent, { color: val });
15194
              }
15195
            },
15196
            validator: {
15197
              validateOnLoad: false,
15198
              validate: input => {
15199
                const inputValue = Representing.getValue(input);
15200
                if (inputValue.length === 0) {
15201
                  return Future.pure(Result.value(true));
15202
                } else {
15203
                  const span = SugarElement.fromTag('span');
15204
                  set$8(span, 'background-color', inputValue);
15205
                  const res = getRaw(span, 'background-color').fold(() => Result.error('blah'), _ => Result.value(inputValue));
15206
                  return Future.pure(res);
15207
                }
15208
              }
15209
            }
15210
          })
15211
        ]),
15212
        selectOnFocus: false
15213
      });
15214
      const pLabel = spec.label.map(label => renderLabel$3(label, sharedBackstage.providers));
15215
      const emitSwatchChange = (colorBit, value) => {
15216
        emitWith(colorBit, colorSwatchChangeEvent, { value });
15217
      };
15218
      const onItemAction = (comp, value) => {
15219
        memColorButton.getOpt(comp).each(colorBit => {
15220
          if (value === 'custom') {
15221
            colorInputBackstage.colorPicker(valueOpt => {
15222
              valueOpt.fold(() => emit(colorBit, colorPickerCancelEvent), value => {
15223
                emitSwatchChange(colorBit, value);
15224
                addColor(spec.storageKey, value);
15225
              });
15226
            }, '#ffffff');
15227
          } else if (value === 'remove') {
15228
            emitSwatchChange(colorBit, '');
15229
          } else {
15230
            emitSwatchChange(colorBit, value);
15231
          }
15232
        });
15233
      };
15234
      const memColorButton = record(renderPanelButton({
15235
        dom: {
15236
          tag: 'span',
15237
          attributes: { 'aria-label': sharedBackstage.providers.translate('Color swatch') }
15238
        },
15239
        layouts: {
15240
          onRtl: () => [
15241
            southwest$2,
15242
            southeast$2,
15243
            south$2
15244
          ],
15245
          onLtr: () => [
15246
            southeast$2,
15247
            southwest$2,
15248
            south$2
15249
          ]
15250
        },
15251
        components: [],
15252
        fetch: getFetch$1(colorInputBackstage.getColors(spec.storageKey), spec.storageKey, colorInputBackstage.hasCustomColors()),
15253
        columns: colorInputBackstage.getColorCols(spec.storageKey),
15254
        presets: 'color',
1441 ariadna 15255
        onItemAction,
15256
        context: spec.context
1 efrain 15257
      }, sharedBackstage));
15258
      return FormField.sketch({
15259
        dom: {
15260
          tag: 'div',
15261
          classes: ['tox-form__group']
15262
        },
15263
        components: pLabel.toArray().concat([{
15264
            dom: {
15265
              tag: 'div',
15266
              classes: ['tox-color-input']
15267
            },
15268
            components: [
15269
              pField,
15270
              memColorButton.asSpec()
15271
            ]
15272
          }]),
15273
        fieldBehaviours: derive$1([config('form-field-events', [
15274
            run$1(colorInputChangeEvent, (comp, se) => {
15275
              memColorButton.getOpt(comp).each(colorButton => {
15276
                set$8(colorButton.element, 'background-color', se.event.color);
15277
              });
15278
              emitWith(comp, formChangeEvent, { name: spec.name });
15279
            }),
15280
            run$1(colorSwatchChangeEvent, (comp, se) => {
15281
              FormField.getField(comp).each(field => {
15282
                Representing.setValue(field, se.event.value);
15283
                Composing.getCurrent(comp).each(Focusing.focus);
15284
              });
15285
            }),
15286
            run$1(colorPickerCancelEvent, (comp, _se) => {
15287
              FormField.getField(comp).each(_field => {
15288
                Composing.getCurrent(comp).each(Focusing.focus);
15289
              });
15290
            })
15291
          ])])
15292
      });
15293
    };
15294
 
15295
    const labelPart = optional({
15296
      schema: [required$1('dom')],
15297
      name: 'label'
15298
    });
15299
    const edgePart = name => optional({
15300
      name: '' + name + '-edge',
15301
      overrides: detail => {
15302
        const action = detail.model.manager.edgeActions[name];
15303
        return action.fold(() => ({}), a => ({
15304
          events: derive$2([
15305
            runActionExtra(touchstart(), (comp, se, d) => a(comp, d), [detail]),
15306
            runActionExtra(mousedown(), (comp, se, d) => a(comp, d), [detail]),
15307
            runActionExtra(mousemove(), (comp, se, det) => {
15308
              if (det.mouseIsDown.get()) {
15309
                a(comp, det);
15310
              }
15311
            }, [detail])
15312
          ])
15313
        }));
15314
      }
15315
    });
15316
    const tlEdgePart = edgePart('top-left');
15317
    const tedgePart = edgePart('top');
15318
    const trEdgePart = edgePart('top-right');
15319
    const redgePart = edgePart('right');
15320
    const brEdgePart = edgePart('bottom-right');
15321
    const bedgePart = edgePart('bottom');
15322
    const blEdgePart = edgePart('bottom-left');
15323
    const ledgePart = edgePart('left');
15324
    const thumbPart = required({
15325
      name: 'thumb',
15326
      defaults: constant$1({ dom: { styles: { position: 'absolute' } } }),
15327
      overrides: detail => {
15328
        return {
15329
          events: derive$2([
15330
            redirectToPart(touchstart(), detail, 'spectrum'),
15331
            redirectToPart(touchmove(), detail, 'spectrum'),
15332
            redirectToPart(touchend(), detail, 'spectrum'),
15333
            redirectToPart(mousedown(), detail, 'spectrum'),
15334
            redirectToPart(mousemove(), detail, 'spectrum'),
15335
            redirectToPart(mouseup(), detail, 'spectrum')
15336
          ])
15337
        };
15338
      }
15339
    });
15340
    const isShift = event => isShift$1(event.event);
15341
    const spectrumPart = required({
15342
      schema: [customField('mouseIsDown', () => Cell(false))],
15343
      name: 'spectrum',
15344
      overrides: detail => {
15345
        const modelDetail = detail.model;
15346
        const model = modelDetail.manager;
15347
        const setValueFrom = (component, simulatedEvent) => model.getValueFromEvent(simulatedEvent).map(value => model.setValueFrom(component, detail, value));
15348
        return {
15349
          behaviours: derive$1([
15350
            Keying.config({
15351
              mode: 'special',
15352
              onLeft: (spectrum, event) => model.onLeft(spectrum, detail, isShift(event)),
15353
              onRight: (spectrum, event) => model.onRight(spectrum, detail, isShift(event)),
15354
              onUp: (spectrum, event) => model.onUp(spectrum, detail, isShift(event)),
15355
              onDown: (spectrum, event) => model.onDown(spectrum, detail, isShift(event))
15356
            }),
15357
            Tabstopping.config({}),
15358
            Focusing.config({})
15359
          ]),
15360
          events: derive$2([
15361
            run$1(touchstart(), setValueFrom),
15362
            run$1(touchmove(), setValueFrom),
15363
            run$1(mousedown(), setValueFrom),
15364
            run$1(mousemove(), (spectrum, se) => {
15365
              if (detail.mouseIsDown.get()) {
15366
                setValueFrom(spectrum, se);
15367
              }
15368
            })
15369
          ])
15370
        };
15371
      }
15372
    });
15373
    var SliderParts = [
15374
      labelPart,
15375
      ledgePart,
15376
      redgePart,
15377
      tedgePart,
15378
      bedgePart,
15379
      tlEdgePart,
15380
      trEdgePart,
15381
      blEdgePart,
15382
      brEdgePart,
15383
      thumbPart,
15384
      spectrumPart
15385
    ];
15386
 
15387
    const _sliderChangeEvent = 'slider.change.value';
15388
    const sliderChangeEvent = constant$1(_sliderChangeEvent);
15389
    const isTouchEvent$2 = evt => evt.type.indexOf('touch') !== -1;
15390
    const getEventSource = simulatedEvent => {
15391
      const evt = simulatedEvent.event.raw;
15392
      if (isTouchEvent$2(evt)) {
15393
        const touchEvent = evt;
15394
        return touchEvent.touches !== undefined && touchEvent.touches.length === 1 ? Optional.some(touchEvent.touches[0]).map(t => SugarPosition(t.clientX, t.clientY)) : Optional.none();
15395
      } else {
15396
        const mouseEvent = evt;
15397
        return mouseEvent.clientX !== undefined ? Optional.some(mouseEvent).map(me => SugarPosition(me.clientX, me.clientY)) : Optional.none();
15398
      }
15399
    };
15400
 
15401
    const t = 'top', r = 'right', b = 'bottom', l = 'left';
15402
    const minX = detail => detail.model.minX;
15403
    const minY = detail => detail.model.minY;
15404
    const min1X = detail => detail.model.minX - 1;
15405
    const min1Y = detail => detail.model.minY - 1;
15406
    const maxX = detail => detail.model.maxX;
15407
    const maxY = detail => detail.model.maxY;
15408
    const max1X = detail => detail.model.maxX + 1;
15409
    const max1Y = detail => detail.model.maxY + 1;
15410
    const range = (detail, max, min) => max(detail) - min(detail);
15411
    const xRange = detail => range(detail, maxX, minX);
15412
    const yRange = detail => range(detail, maxY, minY);
15413
    const halfX = detail => xRange(detail) / 2;
15414
    const halfY = detail => yRange(detail) / 2;
15415
    const step = (detail, useMultiplier) => useMultiplier ? detail.stepSize * detail.speedMultiplier : detail.stepSize;
15416
    const snap = detail => detail.snapToGrid;
15417
    const snapStart = detail => detail.snapStart;
15418
    const rounded = detail => detail.rounded;
15419
    const hasEdge = (detail, edgeName) => detail[edgeName + '-edge'] !== undefined;
15420
    const hasLEdge = detail => hasEdge(detail, l);
15421
    const hasREdge = detail => hasEdge(detail, r);
15422
    const hasTEdge = detail => hasEdge(detail, t);
15423
    const hasBEdge = detail => hasEdge(detail, b);
15424
    const currentValue = detail => detail.model.value.get();
15425
 
15426
    const xyValue = (x, y) => ({
15427
      x,
15428
      y
15429
    });
15430
    const fireSliderChange$3 = (component, value) => {
15431
      emitWith(component, sliderChangeEvent(), { value });
15432
    };
15433
    const setToTLEdgeXY = (edge, detail) => {
15434
      fireSliderChange$3(edge, xyValue(min1X(detail), min1Y(detail)));
15435
    };
15436
    const setToTEdge = (edge, detail) => {
15437
      fireSliderChange$3(edge, min1Y(detail));
15438
    };
15439
    const setToTEdgeXY = (edge, detail) => {
15440
      fireSliderChange$3(edge, xyValue(halfX(detail), min1Y(detail)));
15441
    };
15442
    const setToTREdgeXY = (edge, detail) => {
15443
      fireSliderChange$3(edge, xyValue(max1X(detail), min1Y(detail)));
15444
    };
15445
    const setToREdge = (edge, detail) => {
15446
      fireSliderChange$3(edge, max1X(detail));
15447
    };
15448
    const setToREdgeXY = (edge, detail) => {
15449
      fireSliderChange$3(edge, xyValue(max1X(detail), halfY(detail)));
15450
    };
15451
    const setToBREdgeXY = (edge, detail) => {
15452
      fireSliderChange$3(edge, xyValue(max1X(detail), max1Y(detail)));
15453
    };
15454
    const setToBEdge = (edge, detail) => {
15455
      fireSliderChange$3(edge, max1Y(detail));
15456
    };
15457
    const setToBEdgeXY = (edge, detail) => {
15458
      fireSliderChange$3(edge, xyValue(halfX(detail), max1Y(detail)));
15459
    };
15460
    const setToBLEdgeXY = (edge, detail) => {
15461
      fireSliderChange$3(edge, xyValue(min1X(detail), max1Y(detail)));
15462
    };
15463
    const setToLEdge = (edge, detail) => {
15464
      fireSliderChange$3(edge, min1X(detail));
15465
    };
15466
    const setToLEdgeXY = (edge, detail) => {
15467
      fireSliderChange$3(edge, xyValue(min1X(detail), halfY(detail)));
15468
    };
15469
 
15470
    const reduceBy = (value, min, max, step) => {
15471
      if (value < min) {
15472
        return value;
15473
      } else if (value > max) {
15474
        return max;
15475
      } else if (value === min) {
15476
        return min - 1;
15477
      } else {
15478
        return Math.max(min, value - step);
15479
      }
15480
    };
15481
    const increaseBy = (value, min, max, step) => {
15482
      if (value > max) {
15483
        return value;
15484
      } else if (value < min) {
15485
        return min;
15486
      } else if (value === max) {
15487
        return max + 1;
15488
      } else {
15489
        return Math.min(max, value + step);
15490
      }
15491
    };
15492
    const capValue = (value, min, max) => Math.max(min, Math.min(max, value));
15493
    const snapValueOf = (value, min, max, step, snapStart) => snapStart.fold(() => {
15494
      const initValue = value - min;
15495
      const extraValue = Math.round(initValue / step) * step;
15496
      return capValue(min + extraValue, min - 1, max + 1);
15497
    }, start => {
15498
      const remainder = (value - start) % step;
15499
      const adjustment = Math.round(remainder / step);
15500
      const rawSteps = Math.floor((value - start) / step);
15501
      const maxSteps = Math.floor((max - start) / step);
15502
      const numSteps = Math.min(maxSteps, rawSteps + adjustment);
15503
      const r = start + numSteps * step;
15504
      return Math.max(start, r);
15505
    });
15506
    const findOffsetOf = (value, min, max) => Math.min(max, Math.max(value, min)) - min;
15507
    const findValueOf = args => {
15508
      const {min, max, range, value, step, snap, snapStart, rounded, hasMinEdge, hasMaxEdge, minBound, maxBound, screenRange} = args;
15509
      const capMin = hasMinEdge ? min - 1 : min;
15510
      const capMax = hasMaxEdge ? max + 1 : max;
15511
      if (value < minBound) {
15512
        return capMin;
15513
      } else if (value > maxBound) {
15514
        return capMax;
15515
      } else {
15516
        const offset = findOffsetOf(value, minBound, maxBound);
15517
        const newValue = capValue(offset / screenRange * range + min, capMin, capMax);
15518
        if (snap && newValue >= min && newValue <= max) {
15519
          return snapValueOf(newValue, min, max, step, snapStart);
15520
        } else if (rounded) {
15521
          return Math.round(newValue);
15522
        } else {
15523
          return newValue;
15524
        }
15525
      }
15526
    };
15527
    const findOffsetOfValue$2 = args => {
15528
      const {min, max, range, value, hasMinEdge, hasMaxEdge, maxBound, maxOffset, centerMinEdge, centerMaxEdge} = args;
15529
      if (value < min) {
15530
        return hasMinEdge ? 0 : centerMinEdge;
15531
      } else if (value > max) {
15532
        return hasMaxEdge ? maxBound : centerMaxEdge;
15533
      } else {
15534
        return (value - min) / range * maxOffset;
15535
      }
15536
    };
15537
 
15538
    const top = 'top', right = 'right', bottom = 'bottom', left = 'left', width = 'width', height = 'height';
15539
    const getBounds = component => component.element.dom.getBoundingClientRect();
15540
    const getBoundsProperty = (bounds, property) => bounds[property];
15541
    const getMinXBounds = component => {
15542
      const bounds = getBounds(component);
15543
      return getBoundsProperty(bounds, left);
15544
    };
15545
    const getMaxXBounds = component => {
15546
      const bounds = getBounds(component);
15547
      return getBoundsProperty(bounds, right);
15548
    };
15549
    const getMinYBounds = component => {
15550
      const bounds = getBounds(component);
15551
      return getBoundsProperty(bounds, top);
15552
    };
15553
    const getMaxYBounds = component => {
15554
      const bounds = getBounds(component);
15555
      return getBoundsProperty(bounds, bottom);
15556
    };
15557
    const getXScreenRange = component => {
15558
      const bounds = getBounds(component);
15559
      return getBoundsProperty(bounds, width);
15560
    };
15561
    const getYScreenRange = component => {
15562
      const bounds = getBounds(component);
15563
      return getBoundsProperty(bounds, height);
15564
    };
15565
    const getCenterOffsetOf = (componentMinEdge, componentMaxEdge, spectrumMinEdge) => (componentMinEdge + componentMaxEdge) / 2 - spectrumMinEdge;
15566
    const getXCenterOffSetOf = (component, spectrum) => {
15567
      const componentBounds = getBounds(component);
15568
      const spectrumBounds = getBounds(spectrum);
15569
      const componentMinEdge = getBoundsProperty(componentBounds, left);
15570
      const componentMaxEdge = getBoundsProperty(componentBounds, right);
15571
      const spectrumMinEdge = getBoundsProperty(spectrumBounds, left);
15572
      return getCenterOffsetOf(componentMinEdge, componentMaxEdge, spectrumMinEdge);
15573
    };
15574
    const getYCenterOffSetOf = (component, spectrum) => {
15575
      const componentBounds = getBounds(component);
15576
      const spectrumBounds = getBounds(spectrum);
15577
      const componentMinEdge = getBoundsProperty(componentBounds, top);
15578
      const componentMaxEdge = getBoundsProperty(componentBounds, bottom);
15579
      const spectrumMinEdge = getBoundsProperty(spectrumBounds, top);
15580
      return getCenterOffsetOf(componentMinEdge, componentMaxEdge, spectrumMinEdge);
15581
    };
15582
 
15583
    const fireSliderChange$2 = (spectrum, value) => {
15584
      emitWith(spectrum, sliderChangeEvent(), { value });
15585
    };
15586
    const findValueOfOffset$1 = (spectrum, detail, left) => {
15587
      const args = {
15588
        min: minX(detail),
15589
        max: maxX(detail),
15590
        range: xRange(detail),
15591
        value: left,
15592
        step: step(detail),
15593
        snap: snap(detail),
15594
        snapStart: snapStart(detail),
15595
        rounded: rounded(detail),
15596
        hasMinEdge: hasLEdge(detail),
15597
        hasMaxEdge: hasREdge(detail),
15598
        minBound: getMinXBounds(spectrum),
15599
        maxBound: getMaxXBounds(spectrum),
15600
        screenRange: getXScreenRange(spectrum)
15601
      };
15602
      return findValueOf(args);
15603
    };
15604
    const setValueFrom$2 = (spectrum, detail, value) => {
15605
      const xValue = findValueOfOffset$1(spectrum, detail, value);
15606
      const sliderVal = xValue;
15607
      fireSliderChange$2(spectrum, sliderVal);
15608
      return xValue;
15609
    };
15610
    const setToMin$2 = (spectrum, detail) => {
15611
      const min = minX(detail);
15612
      fireSliderChange$2(spectrum, min);
15613
    };
15614
    const setToMax$2 = (spectrum, detail) => {
15615
      const max = maxX(detail);
15616
      fireSliderChange$2(spectrum, max);
15617
    };
15618
    const moveBy$2 = (direction, spectrum, detail, useMultiplier) => {
15619
      const f = direction > 0 ? increaseBy : reduceBy;
15620
      const xValue = f(currentValue(detail), minX(detail), maxX(detail), step(detail, useMultiplier));
15621
      fireSliderChange$2(spectrum, xValue);
15622
      return Optional.some(xValue);
15623
    };
15624
    const handleMovement$2 = direction => (spectrum, detail, useMultiplier) => moveBy$2(direction, spectrum, detail, useMultiplier).map(always);
15625
    const getValueFromEvent$2 = simulatedEvent => {
15626
      const pos = getEventSource(simulatedEvent);
15627
      return pos.map(p => p.left);
15628
    };
15629
    const findOffsetOfValue$1 = (spectrum, detail, value, minEdge, maxEdge) => {
15630
      const minOffset = 0;
15631
      const maxOffset = getXScreenRange(spectrum);
15632
      const centerMinEdge = minEdge.bind(edge => Optional.some(getXCenterOffSetOf(edge, spectrum))).getOr(minOffset);
15633
      const centerMaxEdge = maxEdge.bind(edge => Optional.some(getXCenterOffSetOf(edge, spectrum))).getOr(maxOffset);
15634
      const args = {
15635
        min: minX(detail),
15636
        max: maxX(detail),
15637
        range: xRange(detail),
15638
        value,
15639
        hasMinEdge: hasLEdge(detail),
15640
        hasMaxEdge: hasREdge(detail),
15641
        minBound: getMinXBounds(spectrum),
15642
        minOffset,
15643
        maxBound: getMaxXBounds(spectrum),
15644
        maxOffset,
15645
        centerMinEdge,
15646
        centerMaxEdge
15647
      };
15648
      return findOffsetOfValue$2(args);
15649
    };
15650
    const findPositionOfValue$1 = (slider, spectrum, value, minEdge, maxEdge, detail) => {
15651
      const offset = findOffsetOfValue$1(spectrum, detail, value, minEdge, maxEdge);
15652
      return getMinXBounds(spectrum) - getMinXBounds(slider) + offset;
15653
    };
15654
    const setPositionFromValue$2 = (slider, thumb, detail, edges) => {
15655
      const value = currentValue(detail);
15656
      const pos = findPositionOfValue$1(slider, edges.getSpectrum(slider), value, edges.getLeftEdge(slider), edges.getRightEdge(slider), detail);
1441 ariadna 15657
      const thumbRadius = get$d(thumb.element) / 2;
1 efrain 15658
      set$8(thumb.element, 'left', pos - thumbRadius + 'px');
15659
    };
15660
    const onLeft$2 = handleMovement$2(-1);
15661
    const onRight$2 = handleMovement$2(1);
15662
    const onUp$2 = Optional.none;
15663
    const onDown$2 = Optional.none;
15664
    const edgeActions$2 = {
15665
      'top-left': Optional.none(),
15666
      'top': Optional.none(),
15667
      'top-right': Optional.none(),
15668
      'right': Optional.some(setToREdge),
15669
      'bottom-right': Optional.none(),
15670
      'bottom': Optional.none(),
15671
      'bottom-left': Optional.none(),
15672
      'left': Optional.some(setToLEdge)
15673
    };
15674
 
15675
    var HorizontalModel = /*#__PURE__*/Object.freeze({
15676
        __proto__: null,
15677
        setValueFrom: setValueFrom$2,
15678
        setToMin: setToMin$2,
15679
        setToMax: setToMax$2,
15680
        findValueOfOffset: findValueOfOffset$1,
15681
        getValueFromEvent: getValueFromEvent$2,
15682
        findPositionOfValue: findPositionOfValue$1,
15683
        setPositionFromValue: setPositionFromValue$2,
15684
        onLeft: onLeft$2,
15685
        onRight: onRight$2,
15686
        onUp: onUp$2,
15687
        onDown: onDown$2,
15688
        edgeActions: edgeActions$2
15689
    });
15690
 
15691
    const fireSliderChange$1 = (spectrum, value) => {
15692
      emitWith(spectrum, sliderChangeEvent(), { value });
15693
    };
15694
    const findValueOfOffset = (spectrum, detail, top) => {
15695
      const args = {
15696
        min: minY(detail),
15697
        max: maxY(detail),
15698
        range: yRange(detail),
15699
        value: top,
15700
        step: step(detail),
15701
        snap: snap(detail),
15702
        snapStart: snapStart(detail),
15703
        rounded: rounded(detail),
15704
        hasMinEdge: hasTEdge(detail),
15705
        hasMaxEdge: hasBEdge(detail),
15706
        minBound: getMinYBounds(spectrum),
15707
        maxBound: getMaxYBounds(spectrum),
15708
        screenRange: getYScreenRange(spectrum)
15709
      };
15710
      return findValueOf(args);
15711
    };
15712
    const setValueFrom$1 = (spectrum, detail, value) => {
15713
      const yValue = findValueOfOffset(spectrum, detail, value);
15714
      const sliderVal = yValue;
15715
      fireSliderChange$1(spectrum, sliderVal);
15716
      return yValue;
15717
    };
15718
    const setToMin$1 = (spectrum, detail) => {
15719
      const min = minY(detail);
15720
      fireSliderChange$1(spectrum, min);
15721
    };
15722
    const setToMax$1 = (spectrum, detail) => {
15723
      const max = maxY(detail);
15724
      fireSliderChange$1(spectrum, max);
15725
    };
15726
    const moveBy$1 = (direction, spectrum, detail, useMultiplier) => {
15727
      const f = direction > 0 ? increaseBy : reduceBy;
15728
      const yValue = f(currentValue(detail), minY(detail), maxY(detail), step(detail, useMultiplier));
15729
      fireSliderChange$1(spectrum, yValue);
15730
      return Optional.some(yValue);
15731
    };
15732
    const handleMovement$1 = direction => (spectrum, detail, useMultiplier) => moveBy$1(direction, spectrum, detail, useMultiplier).map(always);
15733
    const getValueFromEvent$1 = simulatedEvent => {
15734
      const pos = getEventSource(simulatedEvent);
15735
      return pos.map(p => {
15736
        return p.top;
15737
      });
15738
    };
15739
    const findOffsetOfValue = (spectrum, detail, value, minEdge, maxEdge) => {
15740
      const minOffset = 0;
15741
      const maxOffset = getYScreenRange(spectrum);
15742
      const centerMinEdge = minEdge.bind(edge => Optional.some(getYCenterOffSetOf(edge, spectrum))).getOr(minOffset);
15743
      const centerMaxEdge = maxEdge.bind(edge => Optional.some(getYCenterOffSetOf(edge, spectrum))).getOr(maxOffset);
15744
      const args = {
15745
        min: minY(detail),
15746
        max: maxY(detail),
15747
        range: yRange(detail),
15748
        value,
15749
        hasMinEdge: hasTEdge(detail),
15750
        hasMaxEdge: hasBEdge(detail),
15751
        minBound: getMinYBounds(spectrum),
15752
        minOffset,
15753
        maxBound: getMaxYBounds(spectrum),
15754
        maxOffset,
15755
        centerMinEdge,
15756
        centerMaxEdge
15757
      };
15758
      return findOffsetOfValue$2(args);
15759
    };
15760
    const findPositionOfValue = (slider, spectrum, value, minEdge, maxEdge, detail) => {
15761
      const offset = findOffsetOfValue(spectrum, detail, value, minEdge, maxEdge);
15762
      return getMinYBounds(spectrum) - getMinYBounds(slider) + offset;
15763
    };
15764
    const setPositionFromValue$1 = (slider, thumb, detail, edges) => {
15765
      const value = currentValue(detail);
15766
      const pos = findPositionOfValue(slider, edges.getSpectrum(slider), value, edges.getTopEdge(slider), edges.getBottomEdge(slider), detail);
1441 ariadna 15767
      const thumbRadius = get$e(thumb.element) / 2;
1 efrain 15768
      set$8(thumb.element, 'top', pos - thumbRadius + 'px');
15769
    };
15770
    const onLeft$1 = Optional.none;
15771
    const onRight$1 = Optional.none;
15772
    const onUp$1 = handleMovement$1(-1);
15773
    const onDown$1 = handleMovement$1(1);
15774
    const edgeActions$1 = {
15775
      'top-left': Optional.none(),
15776
      'top': Optional.some(setToTEdge),
15777
      'top-right': Optional.none(),
15778
      'right': Optional.none(),
15779
      'bottom-right': Optional.none(),
15780
      'bottom': Optional.some(setToBEdge),
15781
      'bottom-left': Optional.none(),
15782
      'left': Optional.none()
15783
    };
15784
 
15785
    var VerticalModel = /*#__PURE__*/Object.freeze({
15786
        __proto__: null,
15787
        setValueFrom: setValueFrom$1,
15788
        setToMin: setToMin$1,
15789
        setToMax: setToMax$1,
15790
        findValueOfOffset: findValueOfOffset,
15791
        getValueFromEvent: getValueFromEvent$1,
15792
        findPositionOfValue: findPositionOfValue,
15793
        setPositionFromValue: setPositionFromValue$1,
15794
        onLeft: onLeft$1,
15795
        onRight: onRight$1,
15796
        onUp: onUp$1,
15797
        onDown: onDown$1,
15798
        edgeActions: edgeActions$1
15799
    });
15800
 
15801
    const fireSliderChange = (spectrum, value) => {
15802
      emitWith(spectrum, sliderChangeEvent(), { value });
15803
    };
15804
    const sliderValue = (x, y) => ({
15805
      x,
15806
      y
15807
    });
15808
    const setValueFrom = (spectrum, detail, value) => {
15809
      const xValue = findValueOfOffset$1(spectrum, detail, value.left);
15810
      const yValue = findValueOfOffset(spectrum, detail, value.top);
15811
      const val = sliderValue(xValue, yValue);
15812
      fireSliderChange(spectrum, val);
15813
      return val;
15814
    };
15815
    const moveBy = (direction, isVerticalMovement, spectrum, detail, useMultiplier) => {
15816
      const f = direction > 0 ? increaseBy : reduceBy;
15817
      const xValue = isVerticalMovement ? currentValue(detail).x : f(currentValue(detail).x, minX(detail), maxX(detail), step(detail, useMultiplier));
15818
      const yValue = !isVerticalMovement ? currentValue(detail).y : f(currentValue(detail).y, minY(detail), maxY(detail), step(detail, useMultiplier));
15819
      fireSliderChange(spectrum, sliderValue(xValue, yValue));
15820
      return Optional.some(xValue);
15821
    };
15822
    const handleMovement = (direction, isVerticalMovement) => (spectrum, detail, useMultiplier) => moveBy(direction, isVerticalMovement, spectrum, detail, useMultiplier).map(always);
15823
    const setToMin = (spectrum, detail) => {
15824
      const mX = minX(detail);
15825
      const mY = minY(detail);
15826
      fireSliderChange(spectrum, sliderValue(mX, mY));
15827
    };
15828
    const setToMax = (spectrum, detail) => {
15829
      const mX = maxX(detail);
15830
      const mY = maxY(detail);
15831
      fireSliderChange(spectrum, sliderValue(mX, mY));
15832
    };
15833
    const getValueFromEvent = simulatedEvent => getEventSource(simulatedEvent);
15834
    const setPositionFromValue = (slider, thumb, detail, edges) => {
15835
      const value = currentValue(detail);
15836
      const xPos = findPositionOfValue$1(slider, edges.getSpectrum(slider), value.x, edges.getLeftEdge(slider), edges.getRightEdge(slider), detail);
15837
      const yPos = findPositionOfValue(slider, edges.getSpectrum(slider), value.y, edges.getTopEdge(slider), edges.getBottomEdge(slider), detail);
1441 ariadna 15838
      const thumbXRadius = get$d(thumb.element) / 2;
15839
      const thumbYRadius = get$e(thumb.element) / 2;
1 efrain 15840
      set$8(thumb.element, 'left', xPos - thumbXRadius + 'px');
15841
      set$8(thumb.element, 'top', yPos - thumbYRadius + 'px');
15842
    };
15843
    const onLeft = handleMovement(-1, false);
15844
    const onRight = handleMovement(1, false);
15845
    const onUp = handleMovement(-1, true);
15846
    const onDown = handleMovement(1, true);
15847
    const edgeActions = {
15848
      'top-left': Optional.some(setToTLEdgeXY),
15849
      'top': Optional.some(setToTEdgeXY),
15850
      'top-right': Optional.some(setToTREdgeXY),
15851
      'right': Optional.some(setToREdgeXY),
15852
      'bottom-right': Optional.some(setToBREdgeXY),
15853
      'bottom': Optional.some(setToBEdgeXY),
15854
      'bottom-left': Optional.some(setToBLEdgeXY),
15855
      'left': Optional.some(setToLEdgeXY)
15856
    };
15857
 
15858
    var TwoDModel = /*#__PURE__*/Object.freeze({
15859
        __proto__: null,
15860
        setValueFrom: setValueFrom,
15861
        setToMin: setToMin,
15862
        setToMax: setToMax,
15863
        getValueFromEvent: getValueFromEvent,
15864
        setPositionFromValue: setPositionFromValue,
15865
        onLeft: onLeft,
15866
        onRight: onRight,
15867
        onUp: onUp,
15868
        onDown: onDown,
15869
        edgeActions: edgeActions
15870
    });
15871
 
15872
    const SliderSchema = [
15873
      defaulted('stepSize', 1),
15874
      defaulted('speedMultiplier', 10),
15875
      defaulted('onChange', noop),
15876
      defaulted('onChoose', noop),
15877
      defaulted('onInit', noop),
15878
      defaulted('onDragStart', noop),
15879
      defaulted('onDragEnd', noop),
15880
      defaulted('snapToGrid', false),
15881
      defaulted('rounded', true),
15882
      option$3('snapStart'),
15883
      requiredOf('model', choose$1('mode', {
15884
        x: [
15885
          defaulted('minX', 0),
15886
          defaulted('maxX', 100),
15887
          customField('value', spec => Cell(spec.mode.minX)),
15888
          required$1('getInitialValue'),
15889
          output$1('manager', HorizontalModel)
15890
        ],
15891
        y: [
15892
          defaulted('minY', 0),
15893
          defaulted('maxY', 100),
15894
          customField('value', spec => Cell(spec.mode.minY)),
15895
          required$1('getInitialValue'),
15896
          output$1('manager', VerticalModel)
15897
        ],
15898
        xy: [
15899
          defaulted('minX', 0),
15900
          defaulted('maxX', 100),
15901
          defaulted('minY', 0),
15902
          defaulted('maxY', 100),
15903
          customField('value', spec => Cell({
15904
            x: spec.mode.minX,
15905
            y: spec.mode.minY
15906
          })),
15907
          required$1('getInitialValue'),
15908
          output$1('manager', TwoDModel)
15909
        ]
15910
      })),
15911
      field('sliderBehaviours', [
15912
        Keying,
15913
        Representing
15914
      ]),
15915
      customField('mouseIsDown', () => Cell(false))
15916
    ];
15917
 
15918
    const sketch$2 = (detail, components, _spec, _externals) => {
15919
      const getThumb = component => getPartOrDie(component, detail, 'thumb');
15920
      const getSpectrum = component => getPartOrDie(component, detail, 'spectrum');
15921
      const getLeftEdge = component => getPart(component, detail, 'left-edge');
15922
      const getRightEdge = component => getPart(component, detail, 'right-edge');
15923
      const getTopEdge = component => getPart(component, detail, 'top-edge');
15924
      const getBottomEdge = component => getPart(component, detail, 'bottom-edge');
15925
      const modelDetail = detail.model;
15926
      const model = modelDetail.manager;
15927
      const refresh = (slider, thumb) => {
15928
        model.setPositionFromValue(slider, thumb, detail, {
15929
          getLeftEdge,
15930
          getRightEdge,
15931
          getTopEdge,
15932
          getBottomEdge,
15933
          getSpectrum
15934
        });
15935
      };
15936
      const setValue = (slider, newValue) => {
15937
        modelDetail.value.set(newValue);
15938
        const thumb = getThumb(slider);
15939
        refresh(slider, thumb);
15940
      };
15941
      const changeValue = (slider, newValue) => {
15942
        setValue(slider, newValue);
15943
        const thumb = getThumb(slider);
15944
        detail.onChange(slider, thumb, newValue);
15945
        return Optional.some(true);
15946
      };
15947
      const resetToMin = slider => {
15948
        model.setToMin(slider, detail);
15949
      };
15950
      const resetToMax = slider => {
15951
        model.setToMax(slider, detail);
15952
      };
15953
      const choose = slider => {
15954
        const fireOnChoose = () => {
15955
          getPart(slider, detail, 'thumb').each(thumb => {
15956
            const value = modelDetail.value.get();
15957
            detail.onChoose(slider, thumb, value);
15958
          });
15959
        };
15960
        const wasDown = detail.mouseIsDown.get();
15961
        detail.mouseIsDown.set(false);
15962
        if (wasDown) {
15963
          fireOnChoose();
15964
        }
15965
      };
15966
      const onDragStart = (slider, simulatedEvent) => {
15967
        simulatedEvent.stop();
15968
        detail.mouseIsDown.set(true);
15969
        detail.onDragStart(slider, getThumb(slider));
15970
      };
15971
      const onDragEnd = (slider, simulatedEvent) => {
15972
        simulatedEvent.stop();
15973
        detail.onDragEnd(slider, getThumb(slider));
15974
        choose(slider);
15975
      };
15976
      const focusWidget = component => {
15977
        getPart(component, detail, 'spectrum').map(Keying.focusIn);
15978
      };
15979
      return {
15980
        uid: detail.uid,
15981
        dom: detail.dom,
15982
        components,
15983
        behaviours: augment(detail.sliderBehaviours, [
15984
          Keying.config({
15985
            mode: 'special',
15986
            focusIn: focusWidget
15987
          }),
15988
          Representing.config({
15989
            store: {
15990
              mode: 'manual',
15991
              getValue: _ => {
15992
                return modelDetail.value.get();
15993
              },
15994
              setValue
15995
            }
15996
          }),
15997
          Receiving.config({ channels: { [mouseReleased()]: { onReceive: choose } } })
15998
        ]),
15999
        events: derive$2([
16000
          run$1(sliderChangeEvent(), (slider, simulatedEvent) => {
16001
            changeValue(slider, simulatedEvent.event.value);
16002
          }),
16003
          runOnAttached((slider, _simulatedEvent) => {
16004
            const getInitial = modelDetail.getInitialValue();
16005
            modelDetail.value.set(getInitial);
16006
            const thumb = getThumb(slider);
16007
            refresh(slider, thumb);
16008
            const spectrum = getSpectrum(slider);
16009
            detail.onInit(slider, thumb, spectrum, modelDetail.value.get());
16010
          }),
16011
          run$1(touchstart(), onDragStart),
16012
          run$1(touchend(), onDragEnd),
16013
          run$1(mousedown(), (component, event) => {
16014
            focusWidget(component);
16015
            onDragStart(component, event);
16016
          }),
16017
          run$1(mouseup(), onDragEnd)
16018
        ]),
16019
        apis: {
16020
          resetToMin,
16021
          resetToMax,
16022
          setValue,
16023
          refresh
16024
        },
16025
        domModification: { styles: { position: 'relative' } }
16026
      };
16027
    };
16028
 
16029
    const Slider = composite({
16030
      name: 'Slider',
16031
      configFields: SliderSchema,
16032
      partFields: SliderParts,
16033
      factory: sketch$2,
16034
      apis: {
16035
        setValue: (apis, slider, value) => {
16036
          apis.setValue(slider, value);
16037
        },
16038
        resetToMin: (apis, slider) => {
16039
          apis.resetToMin(slider);
16040
        },
16041
        resetToMax: (apis, slider) => {
16042
          apis.resetToMax(slider);
16043
        },
16044
        refresh: (apis, slider) => {
16045
          apis.refresh(slider);
16046
        }
16047
      }
16048
    });
16049
 
16050
    const fieldsUpdate = generate$6('rgb-hex-update');
16051
    const sliderUpdate = generate$6('slider-update');
16052
    const paletteUpdate = generate$6('palette-update');
16053
 
16054
    const sliderFactory = (translate, getClass) => {
16055
      const spectrum = Slider.parts.spectrum({
16056
        dom: {
16057
          tag: 'div',
16058
          classes: [getClass('hue-slider-spectrum')],
16059
          attributes: { role: 'presentation' }
16060
        }
16061
      });
16062
      const thumb = Slider.parts.thumb({
16063
        dom: {
16064
          tag: 'div',
16065
          classes: [getClass('hue-slider-thumb')],
16066
          attributes: { role: 'presentation' }
16067
        }
16068
      });
16069
      return Slider.sketch({
16070
        dom: {
16071
          tag: 'div',
16072
          classes: [getClass('hue-slider')],
16073
          attributes: {
16074
            'role': 'slider',
16075
            'aria-valuemin': 0,
16076
            'aria-valuemax': 360,
16077
            'aria-valuenow': 120
16078
          }
16079
        },
16080
        rounded: false,
16081
        model: {
16082
          mode: 'y',
16083
          getInitialValue: constant$1(0)
16084
        },
16085
        components: [
16086
          spectrum,
16087
          thumb
16088
        ],
16089
        sliderBehaviours: derive$1([Focusing.config({})]),
16090
        onChange: (slider, _thumb, value) => {
16091
          set$9(slider.element, 'aria-valuenow', Math.floor(360 - value * 3.6));
16092
          emitWith(slider, sliderUpdate, { value });
16093
        }
16094
      });
16095
    };
16096
 
16097
    const owner$1 = 'form';
16098
    const schema$i = [field('formBehaviours', [Representing])];
16099
    const getPartName$1 = name => '<alloy.field.' + name + '>';
16100
    const sketch$1 = fSpec => {
16101
      const parts = (() => {
16102
        const record = [];
16103
        const field = (name, config) => {
16104
          record.push(name);
16105
          return generateOne$1(owner$1, getPartName$1(name), config);
16106
        };
16107
        return {
16108
          field,
16109
          record: constant$1(record)
16110
        };
16111
      })();
16112
      const spec = fSpec(parts);
16113
      const partNames = parts.record();
16114
      const fieldParts = map$2(partNames, n => required({
16115
        name: n,
16116
        pname: getPartName$1(n)
16117
      }));
16118
      return composite$1(owner$1, schema$i, fieldParts, make$4, spec);
16119
    };
16120
    const toResult = (o, e) => o.fold(() => Result.error(e), Result.value);
16121
    const make$4 = (detail, components) => ({
16122
      uid: detail.uid,
16123
      dom: detail.dom,
16124
      components,
16125
      behaviours: augment(detail.formBehaviours, [Representing.config({
16126
          store: {
16127
            mode: 'manual',
16128
            getValue: form => {
16129
              const resPs = getAllParts(form, detail);
16130
              return map$1(resPs, (resPThunk, pName) => resPThunk().bind(v => {
16131
                const opt = Composing.getCurrent(v);
16132
                return toResult(opt, new Error(`Cannot find a current component to extract the value from for form part '${ pName }': ` + element(v.element)));
16133
              }).map(Representing.getValue));
16134
            },
16135
            setValue: (form, values) => {
16136
              each(values, (newValue, key) => {
16137
                getPart(form, detail, key).each(wrapper => {
16138
                  Composing.getCurrent(wrapper).each(field => {
16139
                    Representing.setValue(field, newValue);
16140
                  });
16141
                });
16142
              });
16143
            }
16144
          }
16145
        })]),
16146
      apis: {
16147
        getField: (form, key) => {
16148
          return getPart(form, detail, key).bind(Composing.getCurrent);
16149
        }
16150
      }
16151
    });
16152
    const Form = {
16153
      getField: makeApi((apis, component, key) => apis.getField(component, key)),
16154
      sketch: sketch$1
16155
    };
16156
 
16157
    const validInput = generate$6('valid-input');
16158
    const invalidInput = generate$6('invalid-input');
16159
    const validatingInput = generate$6('validating-input');
16160
    const translatePrefix = 'colorcustom.rgb.';
1441 ariadna 16161
    const uninitiatedTooltipApi = {
16162
      isEnabled: always,
16163
      setEnabled: noop,
16164
      immediatelyShow: noop,
16165
      immediatelyHide: noop
16166
    };
16167
    const rgbFormFactory = (translate, getClass, onValidHexx, onInvalidHexx, tooltipGetConfig, makeIcon) => {
16168
      const setTooltipEnabled = (enabled, tooltipApi) => {
16169
        const api = tooltipApi.get();
16170
        if (enabled === api.isEnabled()) {
16171
          return;
16172
        }
16173
        api.setEnabled(enabled);
16174
        if (enabled) {
16175
          api.immediatelyShow();
16176
        } else {
16177
          api.immediatelyHide();
16178
        }
16179
      };
16180
      const invalidation = (label, isValid, tooltipApi) => Invalidating.config({
1 efrain 16181
        invalidClass: getClass('invalid'),
16182
        notify: {
16183
          onValidate: comp => {
16184
            emitWith(comp, validatingInput, { type: label });
16185
          },
16186
          onValid: comp => {
1441 ariadna 16187
            setTooltipEnabled(false, tooltipApi);
1 efrain 16188
            emitWith(comp, validInput, {
16189
              type: label,
16190
              value: Representing.getValue(comp)
16191
            });
16192
          },
16193
          onInvalid: comp => {
1441 ariadna 16194
            setTooltipEnabled(true, tooltipApi);
1 efrain 16195
            emitWith(comp, invalidInput, {
16196
              type: label,
16197
              value: Representing.getValue(comp)
16198
            });
16199
          }
16200
        },
16201
        validator: {
16202
          validate: comp => {
16203
            const value = Representing.getValue(comp);
16204
            const res = isValid(value) ? Result.value(true) : Result.error(translate('aria.input.invalid'));
16205
            return Future.pure(res);
16206
          },
16207
          validateOnLoad: false
16208
        }
16209
      });
16210
      const renderTextField = (isValid, name, label, description, data) => {
1441 ariadna 16211
        const tooltipApi = Cell(uninitiatedTooltipApi);
1 efrain 16212
        const helptext = translate(translatePrefix + 'range');
16213
        const pLabel = FormField.parts.label({
1441 ariadna 16214
          dom: { tag: 'label' },
1 efrain 16215
          components: [text$2(label)]
16216
        });
16217
        const pField = FormField.parts.field({
16218
          data,
16219
          factory: Input,
16220
          inputAttributes: {
1441 ariadna 16221
            'type': 'text',
16222
            'aria-label': description,
1 efrain 16223
            ...name === 'hex' ? { 'aria-live': 'polite' } : {}
16224
          },
16225
          inputClasses: [getClass('textfield')],
16226
          inputBehaviours: derive$1([
1441 ariadna 16227
            invalidation(name, isValid, tooltipApi),
16228
            Tabstopping.config({}),
16229
            Tooltipping.config({
16230
              ...tooltipGetConfig({
16231
                tooltipText: '',
16232
                onSetup: comp => {
16233
                  tooltipApi.set({
16234
                    isEnabled: () => {
16235
                      return Tooltipping.isEnabled(comp);
16236
                    },
16237
                    setEnabled: enabled => {
16238
                      return Tooltipping.setEnabled(comp, enabled);
16239
                    },
16240
                    immediatelyShow: () => {
16241
                      return Tooltipping.immediateOpenClose(comp, true);
16242
                    },
16243
                    immediatelyHide: () => {
16244
                      return Tooltipping.immediateOpenClose(comp, false);
16245
                    }
16246
                  });
16247
                  Tooltipping.setEnabled(comp, false);
16248
                },
16249
                onShow: (component, _tooltip) => {
16250
                  Tooltipping.setComponents(component, [{
16251
                      dom: {
16252
                        tag: 'p',
16253
                        classes: [getClass('rgb-warning-note')]
16254
                      },
16255
                      components: [text$2(translate(name === 'hex' ? 'colorcustom.rgb.invalidHex' : 'colorcustom.rgb.invalid'))]
16256
                    }]);
16257
                }
16258
              })
16259
            })
1 efrain 16260
          ]),
16261
          onSetValue: input => {
16262
            if (Invalidating.isInvalid(input)) {
16263
              const run = Invalidating.run(input);
16264
              run.get(noop);
16265
            }
16266
          }
16267
        });
1441 ariadna 16268
        const errorId = generate$6('aria-invalid');
16269
        const memInvalidIcon = record(makeIcon('invalid', Optional.some(errorId), 'warning'));
16270
        const memStatus = record({
16271
          dom: {
16272
            tag: 'div',
16273
            classes: [getClass('invalid-icon')]
16274
          },
16275
          components: [memInvalidIcon.asSpec()]
16276
        });
1 efrain 16277
        const comps = [
16278
          pLabel,
1441 ariadna 16279
          pField,
16280
          memStatus.asSpec()
1 efrain 16281
        ];
16282
        const concats = name !== 'hex' ? [FormField.parts['aria-descriptor']({ text: helptext })] : [];
16283
        const components = comps.concat(concats);
16284
        return {
16285
          dom: {
16286
            tag: 'div',
1441 ariadna 16287
            attributes: { role: 'presentation' },
16288
            classes: [getClass('rgb-container')]
1 efrain 16289
          },
16290
          components
16291
        };
16292
      };
16293
      const copyRgbToHex = (form, rgba) => {
16294
        const hex = fromRgba(rgba);
16295
        Form.getField(form, 'hex').each(hexField => {
16296
          if (!Focusing.isFocused(hexField)) {
16297
            Representing.setValue(form, { hex: hex.value });
16298
          }
16299
        });
16300
        return hex;
16301
      };
16302
      const copyRgbToForm = (form, rgb) => {
16303
        const red = rgb.red;
16304
        const green = rgb.green;
16305
        const blue = rgb.blue;
16306
        Representing.setValue(form, {
16307
          red,
16308
          green,
16309
          blue
16310
        });
16311
      };
16312
      const memPreview = record({
16313
        dom: {
16314
          tag: 'div',
16315
          classes: [getClass('rgba-preview')],
16316
          styles: { 'background-color': 'white' },
16317
          attributes: { role: 'presentation' }
16318
        }
16319
      });
16320
      const updatePreview = (anyInSystem, hex) => {
16321
        memPreview.getOpt(anyInSystem).each(preview => {
16322
          set$8(preview.element, 'background-color', '#' + hex.value);
16323
        });
16324
      };
16325
      const factory = () => {
16326
        const state = {
16327
          red: Cell(Optional.some(255)),
16328
          green: Cell(Optional.some(255)),
16329
          blue: Cell(Optional.some(255)),
16330
          hex: Cell(Optional.some('ffffff'))
16331
        };
16332
        const copyHexToRgb = (form, hex) => {
16333
          const rgb = fromHex(hex);
16334
          copyRgbToForm(form, rgb);
16335
          setValueRgb(rgb);
16336
        };
16337
        const get = prop => state[prop].get();
16338
        const set = (prop, value) => {
16339
          state[prop].set(value);
16340
        };
16341
        const getValueRgb = () => get('red').bind(red => get('green').bind(green => get('blue').map(blue => rgbaColour(red, green, blue, 1))));
16342
        const setValueRgb = rgb => {
16343
          const red = rgb.red;
16344
          const green = rgb.green;
16345
          const blue = rgb.blue;
16346
          set('red', Optional.some(red));
16347
          set('green', Optional.some(green));
16348
          set('blue', Optional.some(blue));
16349
        };
16350
        const onInvalidInput = (form, simulatedEvent) => {
16351
          const data = simulatedEvent.event;
16352
          if (data.type !== 'hex') {
16353
            set(data.type, Optional.none());
16354
          } else {
16355
            onInvalidHexx(form);
16356
          }
16357
        };
16358
        const onValidHex = (form, value) => {
16359
          onValidHexx(form);
16360
          const hex = hexColour(value);
16361
          set('hex', Optional.some(hex.value));
16362
          const rgb = fromHex(hex);
16363
          copyRgbToForm(form, rgb);
16364
          setValueRgb(rgb);
16365
          emitWith(form, fieldsUpdate, { hex });
16366
          updatePreview(form, hex);
16367
        };
16368
        const onValidRgb = (form, prop, value) => {
16369
          const val = parseInt(value, 10);
16370
          set(prop, Optional.some(val));
16371
          getValueRgb().each(rgb => {
16372
            const hex = copyRgbToHex(form, rgb);
16373
            emitWith(form, fieldsUpdate, { hex });
16374
            updatePreview(form, hex);
16375
          });
16376
        };
16377
        const isHexInputEvent = data => data.type === 'hex';
16378
        const onValidInput = (form, simulatedEvent) => {
16379
          const data = simulatedEvent.event;
16380
          if (isHexInputEvent(data)) {
16381
            onValidHex(form, data.value);
16382
          } else {
16383
            onValidRgb(form, data.type, data.value);
16384
          }
16385
        };
16386
        const formPartStrings = key => ({
16387
          label: translate(translatePrefix + key + '.label'),
16388
          description: translate(translatePrefix + key + '.description')
16389
        });
16390
        const redStrings = formPartStrings('red');
16391
        const greenStrings = formPartStrings('green');
16392
        const blueStrings = formPartStrings('blue');
16393
        const hexStrings = formPartStrings('hex');
16394
        return deepMerge(Form.sketch(parts => ({
16395
          dom: {
16396
            tag: 'form',
16397
            classes: [getClass('rgb-form')],
16398
            attributes: { 'aria-label': translate('aria.color.picker') }
16399
          },
16400
          components: [
16401
            parts.field('red', FormField.sketch(renderTextField(isRgbaComponent, 'red', redStrings.label, redStrings.description, 255))),
16402
            parts.field('green', FormField.sketch(renderTextField(isRgbaComponent, 'green', greenStrings.label, greenStrings.description, 255))),
16403
            parts.field('blue', FormField.sketch(renderTextField(isRgbaComponent, 'blue', blueStrings.label, blueStrings.description, 255))),
16404
            parts.field('hex', FormField.sketch(renderTextField(isHexString, 'hex', hexStrings.label, hexStrings.description, 'ffffff'))),
16405
            memPreview.asSpec()
16406
          ],
16407
          formBehaviours: derive$1([
16408
            Invalidating.config({ invalidClass: getClass('form-invalid') }),
16409
            config('rgb-form-events', [
16410
              run$1(validInput, onValidInput),
16411
              run$1(invalidInput, onInvalidInput),
16412
              run$1(validatingInput, onInvalidInput)
16413
            ])
16414
          ])
16415
        })), {
16416
          apis: {
16417
            updateHex: (form, hex) => {
16418
              Representing.setValue(form, { hex: hex.value });
16419
              copyHexToRgb(form, hex);
16420
              updatePreview(form, hex);
16421
            }
16422
          }
16423
        });
16424
      };
16425
      const rgbFormSketcher = single({
16426
        factory,
16427
        name: 'RgbForm',
16428
        configFields: [],
16429
        apis: {
16430
          updateHex: (apis, form, hex) => {
16431
            apis.updateHex(form, hex);
16432
          }
16433
        },
16434
        extraApis: {}
16435
      });
16436
      return rgbFormSketcher;
16437
    };
16438
 
16439
    const paletteFactory = (translate, getClass) => {
16440
      const spectrumPart = Slider.parts.spectrum({
16441
        dom: {
16442
          tag: 'canvas',
16443
          attributes: { role: 'presentation' },
16444
          classes: [getClass('sv-palette-spectrum')]
16445
        }
16446
      });
16447
      const thumbPart = Slider.parts.thumb({
16448
        dom: {
16449
          tag: 'div',
16450
          attributes: { role: 'presentation' },
16451
          classes: [getClass('sv-palette-thumb')],
16452
          innerHtml: `<div class=${ getClass('sv-palette-inner-thumb') } role="presentation"></div>`
16453
        }
16454
      });
16455
      const setColour = (canvas, rgba) => {
16456
        const {width, height} = canvas;
16457
        const ctx = canvas.getContext('2d');
16458
        if (ctx === null) {
16459
          return;
16460
        }
16461
        ctx.fillStyle = rgba;
16462
        ctx.fillRect(0, 0, width, height);
16463
        const grdWhite = ctx.createLinearGradient(0, 0, width, 0);
16464
        grdWhite.addColorStop(0, 'rgba(255,255,255,1)');
16465
        grdWhite.addColorStop(1, 'rgba(255,255,255,0)');
16466
        ctx.fillStyle = grdWhite;
16467
        ctx.fillRect(0, 0, width, height);
16468
        const grdBlack = ctx.createLinearGradient(0, 0, 0, height);
16469
        grdBlack.addColorStop(0, 'rgba(0,0,0,0)');
16470
        grdBlack.addColorStop(1, 'rgba(0,0,0,1)');
16471
        ctx.fillStyle = grdBlack;
16472
        ctx.fillRect(0, 0, width, height);
16473
      };
16474
      const setPaletteHue = (slider, hue) => {
16475
        const canvas = slider.components()[0].element.dom;
16476
        const hsv = hsvColour(hue, 100, 100);
16477
        const rgba = fromHsv(hsv);
16478
        setColour(canvas, toString(rgba));
16479
      };
16480
      const setPaletteThumb = (slider, hex) => {
16481
        const hsv = fromRgb(fromHex(hex));
16482
        Slider.setValue(slider, {
16483
          x: hsv.saturation,
16484
          y: 100 - hsv.value
16485
        });
16486
        set$9(slider.element, 'aria-valuetext', translate([
16487
          'Saturation {0}%, Brightness {1}%',
16488
          hsv.saturation,
16489
          hsv.value
16490
        ]));
16491
      };
16492
      const factory = _detail => {
16493
        const getInitialValue = constant$1({
16494
          x: 0,
16495
          y: 0
16496
        });
16497
        const onChange = (slider, _thumb, value) => {
16498
          if (!isNumber(value)) {
16499
            set$9(slider.element, 'aria-valuetext', translate([
16500
              'Saturation {0}%, Brightness {1}%',
16501
              Math.floor(value.x),
16502
              Math.floor(100 - value.y)
16503
            ]));
16504
          }
16505
          emitWith(slider, paletteUpdate, { value });
16506
        };
16507
        const onInit = (_slider, _thumb, spectrum, _value) => {
16508
          setColour(spectrum.element.dom, toString(red));
16509
        };
16510
        const sliderBehaviours = derive$1([
16511
          Composing.config({ find: Optional.some }),
16512
          Focusing.config({})
16513
        ]);
16514
        return Slider.sketch({
16515
          dom: {
16516
            tag: 'div',
16517
            attributes: {
16518
              'role': 'slider',
16519
              'aria-valuetext': translate([
16520
                'Saturation {0}%, Brightness {1}%',
16521
                0,
16522
 
16523
              ])
16524
            },
16525
            classes: [getClass('sv-palette')]
16526
          },
16527
          model: {
16528
            mode: 'xy',
16529
            getInitialValue
16530
          },
16531
          rounded: false,
16532
          components: [
16533
            spectrumPart,
16534
            thumbPart
16535
          ],
16536
          onChange,
16537
          onInit,
16538
          sliderBehaviours
16539
        });
16540
      };
16541
      const saturationBrightnessPaletteSketcher = single({
16542
        factory,
16543
        name: 'SaturationBrightnessPalette',
16544
        configFields: [],
16545
        apis: {
16546
          setHue: (_apis, slider, hue) => {
16547
            setPaletteHue(slider, hue);
16548
          },
16549
          setThumb: (_apis, slider, hex) => {
16550
            setPaletteThumb(slider, hex);
16551
          }
16552
        },
16553
        extraApis: {}
16554
      });
16555
      return saturationBrightnessPaletteSketcher;
16556
    };
16557
 
1441 ariadna 16558
    const makeFactory = (translate, getClass, tooltipConfig, makeIcon) => {
1 efrain 16559
      const factory = detail => {
1441 ariadna 16560
        const rgbForm = rgbFormFactory(translate, getClass, detail.onValidHex, detail.onInvalidHex, tooltipConfig, makeIcon);
1 efrain 16561
        const sbPalette = paletteFactory(translate, getClass);
16562
        const hueSliderToDegrees = hue => (100 - hue) / 100 * 360;
16563
        const hueDegreesToSlider = hue => 100 - hue / 360 * 100;
16564
        const state = {
16565
          paletteRgba: Cell(red),
16566
          paletteHue: Cell(0)
16567
        };
16568
        const memSlider = record(sliderFactory(translate, getClass));
16569
        const memPalette = record(sbPalette.sketch({}));
16570
        const memRgb = record(rgbForm.sketch({}));
16571
        const updatePalette = (anyInSystem, _hex, hue) => {
16572
          memPalette.getOpt(anyInSystem).each(palette => {
16573
            sbPalette.setHue(palette, hue);
16574
          });
16575
        };
16576
        const updateFields = (anyInSystem, hex) => {
16577
          memRgb.getOpt(anyInSystem).each(form => {
16578
            rgbForm.updateHex(form, hex);
16579
          });
16580
        };
16581
        const updateSlider = (anyInSystem, _hex, hue) => {
16582
          memSlider.getOpt(anyInSystem).each(slider => {
16583
            Slider.setValue(slider, hueDegreesToSlider(hue));
16584
          });
16585
        };
16586
        const updatePaletteThumb = (anyInSystem, hex) => {
16587
          memPalette.getOpt(anyInSystem).each(palette => {
16588
            sbPalette.setThumb(palette, hex);
16589
          });
16590
        };
16591
        const updateState = (hex, hue) => {
16592
          const rgba = fromHex(hex);
16593
          state.paletteRgba.set(rgba);
16594
          state.paletteHue.set(hue);
16595
        };
16596
        const runUpdates = (anyInSystem, hex, hue, updates) => {
16597
          updateState(hex, hue);
16598
          each$1(updates, update => {
16599
            update(anyInSystem, hex, hue);
16600
          });
16601
        };
16602
        const onPaletteUpdate = () => {
16603
          const updates = [updateFields];
16604
          return (form, simulatedEvent) => {
16605
            const value = simulatedEvent.event.value;
16606
            const oldHue = state.paletteHue.get();
16607
            const newHsv = hsvColour(oldHue, value.x, 100 - value.y);
16608
            const newHex = hsvToHex(newHsv);
16609
            runUpdates(form, newHex, oldHue, updates);
16610
          };
16611
        };
16612
        const onSliderUpdate = () => {
16613
          const updates = [
16614
            updatePalette,
16615
            updateFields
16616
          ];
16617
          return (form, simulatedEvent) => {
16618
            const hue = hueSliderToDegrees(simulatedEvent.event.value);
16619
            const oldRgb = state.paletteRgba.get();
16620
            const oldHsv = fromRgb(oldRgb);
16621
            const newHsv = hsvColour(hue, oldHsv.saturation, oldHsv.value);
16622
            const newHex = hsvToHex(newHsv);
16623
            runUpdates(form, newHex, hue, updates);
16624
          };
16625
        };
16626
        const onFieldsUpdate = () => {
16627
          const updates = [
16628
            updatePalette,
16629
            updateSlider,
16630
            updatePaletteThumb
16631
          ];
16632
          return (form, simulatedEvent) => {
16633
            const hex = simulatedEvent.event.hex;
16634
            const hsv = hexToHsv(hex);
16635
            runUpdates(form, hex, hsv.hue, updates);
16636
          };
16637
        };
16638
        return {
16639
          uid: detail.uid,
16640
          dom: detail.dom,
16641
          components: [
16642
            memPalette.asSpec(),
16643
            memSlider.asSpec(),
16644
            memRgb.asSpec()
16645
          ],
16646
          behaviours: derive$1([
16647
            config('colour-picker-events', [
16648
              run$1(fieldsUpdate, onFieldsUpdate()),
16649
              run$1(paletteUpdate, onPaletteUpdate()),
16650
              run$1(sliderUpdate, onSliderUpdate())
16651
            ]),
16652
            Composing.config({ find: comp => memRgb.getOpt(comp) }),
16653
            Keying.config({ mode: 'acyclic' })
16654
          ])
16655
        };
16656
      };
16657
      const colourPickerSketcher = single({
16658
        name: 'ColourPicker',
16659
        configFields: [
16660
          required$1('dom'),
16661
          defaulted('onValidHex', noop),
16662
          defaulted('onInvalidHex', noop)
16663
        ],
16664
        factory
16665
      });
16666
      return colourPickerSketcher;
16667
    };
16668
 
16669
    const self = () => Composing.config({ find: Optional.some });
16670
    const memento$1 = mem => Composing.config({ find: mem.getOpt });
16671
    const childAt = index => Composing.config({ find: comp => child$2(comp.element, index).bind(element => comp.getSystem().getByDom(element).toOptional()) });
16672
    const ComposingConfigs = {
16673
      self,
16674
      memento: memento$1,
16675
      childAt
16676
    };
16677
 
16678
    const processors = objOf([
16679
      defaulted('preprocess', identity),
16680
      defaulted('postprocess', identity)
16681
    ]);
16682
    const memento = (mem, rawProcessors) => {
16683
      const ps = asRawOrDie$1('RepresentingConfigs.memento processors', processors, rawProcessors);
16684
      return Representing.config({
16685
        store: {
16686
          mode: 'manual',
16687
          getValue: comp => {
16688
            const other = mem.get(comp);
16689
            const rawValue = Representing.getValue(other);
16690
            return ps.postprocess(rawValue);
16691
          },
16692
          setValue: (comp, rawValue) => {
16693
            const newValue = ps.preprocess(rawValue);
16694
            const other = mem.get(comp);
16695
            Representing.setValue(other, newValue);
16696
          }
16697
        }
16698
      });
16699
    };
16700
    const withComp = (optInitialValue, getter, setter) => Representing.config({
16701
      store: {
16702
        mode: 'manual',
16703
        ...optInitialValue.map(initialValue => ({ initialValue })).getOr({}),
16704
        getValue: getter,
16705
        setValue: setter
16706
      }
16707
    });
16708
    const withElement = (initialValue, getter, setter) => withComp(initialValue, c => getter(c.element), (c, v) => setter(c.element, v));
1441 ariadna 16709
    const domHtml = optInitialValue => withElement(optInitialValue, get$8, set$6);
1 efrain 16710
    const memory = initialValue => Representing.config({
16711
      store: {
16712
        mode: 'memory',
16713
        initialValue
16714
      }
16715
    });
16716
 
16717
    const english = {
16718
      'colorcustom.rgb.red.label': 'R',
1441 ariadna 16719
      'colorcustom.rgb.red.description': 'Red channel',
1 efrain 16720
      'colorcustom.rgb.green.label': 'G',
1441 ariadna 16721
      'colorcustom.rgb.green.description': 'Green channel',
1 efrain 16722
      'colorcustom.rgb.blue.label': 'B',
1441 ariadna 16723
      'colorcustom.rgb.blue.description': 'Blue channel',
1 efrain 16724
      'colorcustom.rgb.hex.label': '#',
16725
      'colorcustom.rgb.hex.description': 'Hex color code',
16726
      'colorcustom.rgb.range': 'Range 0 to 255',
1441 ariadna 16727
      'colorcustom.rgb.invalid': 'Numbers only, 0 to 255',
16728
      'colorcustom.rgb.invalidHex': 'Hexadecimal only, 000000 to FFFFFF',
1 efrain 16729
      'aria.color.picker': 'Color Picker',
16730
      'aria.input.invalid': 'Invalid input'
16731
    };
16732
    const translate$1 = providerBackstage => key => {
16733
      if (isString(key)) {
16734
        return providerBackstage.translate(english[key]);
16735
      } else {
16736
        return providerBackstage.translate(key);
16737
      }
16738
    };
16739
    const renderColorPicker = (_spec, providerBackstage, initialData) => {
16740
      const getClass = key => 'tox-' + key;
1441 ariadna 16741
      const renderIcon = (name, errId, icon = name, label = name) => render$3(icon, {
16742
        tag: 'div',
16743
        classes: [
16744
          'tox-icon',
16745
          'tox-control-wrap__status-icon-' + name
16746
        ],
16747
        attributes: {
16748
          'title': providerBackstage.translate(label),
16749
          'aria-live': 'polite',
16750
          ...errId.fold(() => ({}), id => ({ id }))
16751
        }
16752
      }, providerBackstage.icons);
16753
      const colourPickerFactory = makeFactory(translate$1(providerBackstage), getClass, providerBackstage.tooltips.getConfig, renderIcon);
1 efrain 16754
      const onValidHex = form => {
16755
        emitWith(form, formActionEvent, {
16756
          name: 'hex-valid',
16757
          value: true
16758
        });
16759
      };
16760
      const onInvalidHex = form => {
16761
        emitWith(form, formActionEvent, {
16762
          name: 'hex-valid',
16763
          value: false
16764
        });
16765
      };
16766
      const memPicker = record(colourPickerFactory.sketch({
16767
        dom: {
16768
          tag: 'div',
16769
          classes: [getClass('color-picker-container')],
16770
          attributes: { role: 'presentation' }
16771
        },
16772
        onValidHex,
16773
        onInvalidHex
16774
      }));
16775
      return {
16776
        dom: { tag: 'div' },
16777
        components: [memPicker.asSpec()],
16778
        behaviours: derive$1([
16779
          withComp(initialData, comp => {
16780
            const picker = memPicker.get(comp);
16781
            const optRgbForm = Composing.getCurrent(picker);
16782
            const optHex = optRgbForm.bind(rgbForm => {
16783
              const formValues = Representing.getValue(rgbForm);
16784
              return formValues.hex;
16785
            });
16786
            return optHex.map(hex => '#' + removeLeading(hex, '#')).getOr('');
16787
          }, (comp, newValue) => {
16788
            const pattern = /^#([a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?)/;
1441 ariadna 16789
            const valOpt = Optional.from(pattern.exec(newValue)).bind(matches => get$i(matches, 1));
1 efrain 16790
            const picker = memPicker.get(comp);
16791
            const optRgbForm = Composing.getCurrent(picker);
16792
            optRgbForm.fold(() => {
16793
              console.log('Can not find form');
16794
            }, rgbForm => {
16795
              Representing.setValue(rgbForm, { hex: valOpt.getOr('') });
16796
              Form.getField(rgbForm, 'hex').each(hexField => {
16797
                emit(hexField, input());
16798
              });
16799
            });
16800
          }),
16801
          ComposingConfigs.self()
16802
        ])
16803
      };
16804
    };
16805
 
16806
    var global$2 = tinymce.util.Tools.resolve('tinymce.Resource');
16807
 
16808
    const isOldCustomEditor = spec => has$2(spec, 'init');
16809
    const renderCustomEditor = spec => {
1441 ariadna 16810
      const editorApi = value$4();
1 efrain 16811
      const memReplaced = record({ dom: { tag: spec.tag } });
1441 ariadna 16812
      const initialValue = value$4();
16813
      const focusBehaviour = !isOldCustomEditor(spec) && spec.onFocus.isSome() ? [
16814
        Focusing.config({
16815
          onFocus: comp => {
16816
            spec.onFocus.each(onFocusFn => {
16817
              onFocusFn(comp.element.dom);
16818
            });
16819
          }
16820
        }),
16821
        Tabstopping.config({})
16822
      ] : [];
1 efrain 16823
      return {
16824
        dom: {
16825
          tag: 'div',
16826
          classes: ['tox-custom-editor']
16827
        },
16828
        behaviours: derive$1([
16829
          config('custom-editor-events', [runOnAttached(component => {
16830
              memReplaced.getOpt(component).each(ta => {
16831
                (isOldCustomEditor(spec) ? spec.init(ta.element.dom) : global$2.load(spec.scriptId, spec.scriptUrl).then(init => init(ta.element.dom, spec.settings))).then(ea => {
16832
                  initialValue.on(cvalue => {
16833
                    ea.setValue(cvalue);
16834
                  });
16835
                  initialValue.clear();
16836
                  editorApi.set(ea);
16837
                });
16838
              });
16839
            })]),
1441 ariadna 16840
          withComp(Optional.none(), () => editorApi.get().fold(() => initialValue.get().getOr(''), ed => ed.getValue()), (_component, value) => {
1 efrain 16841
            editorApi.get().fold(() => initialValue.set(value), ed => ed.setValue(value));
16842
          }),
16843
          ComposingConfigs.self()
1441 ariadna 16844
        ].concat(focusBehaviour)),
1 efrain 16845
        components: [memReplaced.asSpec()]
16846
      };
16847
    };
16848
 
16849
    var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
16850
 
1441 ariadna 16851
    const browseFilesEvent = generate$6('browse.files.event');
1 efrain 16852
    const filterByExtension = (files, providersBackstage) => {
16853
      const allowedImageFileTypes = global$1.explode(providersBackstage.getOption('images_file_types'));
16854
      const isFileInAllowedTypes = file => exists(allowedImageFileTypes, type => endsWith(file.name.toLowerCase(), `.${ type.toLowerCase() }`));
16855
      return filter$2(from(files), isFileInAllowedTypes);
16856
    };
16857
    const renderDropZone = (spec, providersBackstage, initialData) => {
16858
      const stopper = (_, se) => {
16859
        se.stop();
16860
      };
16861
      const sequence = actions => (comp, se) => {
16862
        each$1(actions, a => {
16863
          a(comp, se);
16864
        });
16865
      };
16866
      const onDrop = (comp, se) => {
16867
        var _a;
16868
        if (!Disabling.isDisabled(comp)) {
16869
          const transferEvent = se.event.raw;
1441 ariadna 16870
          emitWith(comp, browseFilesEvent, { files: (_a = transferEvent.dataTransfer) === null || _a === void 0 ? void 0 : _a.files });
1 efrain 16871
        }
16872
      };
16873
      const onSelect = (component, simulatedEvent) => {
16874
        const input = simulatedEvent.event.raw.target;
1441 ariadna 16875
        emitWith(component, browseFilesEvent, { files: input.files });
1 efrain 16876
      };
16877
      const handleFiles = (component, files) => {
16878
        if (files) {
16879
          Representing.setValue(component, filterByExtension(files, providersBackstage));
16880
          emitWith(component, formChangeEvent, { name: spec.name });
16881
        }
16882
      };
16883
      const memInput = record({
16884
        dom: {
16885
          tag: 'input',
16886
          attributes: {
16887
            type: 'file',
16888
            accept: 'image/*'
16889
          },
16890
          styles: { display: 'none' }
16891
        },
16892
        behaviours: derive$1([config('input-file-events', [
16893
            cutter(click()),
16894
            cutter(tap())
16895
          ])])
16896
      });
1441 ariadna 16897
      const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
16898
      const pField = FormField.parts.field({
16899
        factory: Button,
1 efrain 16900
        dom: {
1441 ariadna 16901
          tag: 'button',
16902
          styles: { position: 'relative' },
16903
          classes: [
16904
            'tox-button',
16905
            'tox-button--secondary'
16906
          ]
16907
        },
16908
        components: [
16909
          text$2(providersBackstage.translate('Browse for an image')),
16910
          memInput.asSpec()
16911
        ],
16912
        action: comp => {
16913
          const inputComp = memInput.get(comp);
16914
          inputComp.element.dom.click();
16915
        },
16916
        buttonBehaviours: derive$1([
16917
          ComposingConfigs.self(),
16918
          memory(initialData.getOr([])),
16919
          Tabstopping.config({}),
16920
          DisablingConfigs.button(() => providersBackstage.checkUiComponentContext(spec.context).shouldDisable),
16921
          toggleOnReceive(() => providersBackstage.checkUiComponentContext(spec.context))
16922
        ])
16923
      });
16924
      const wrapper = {
16925
        dom: {
1 efrain 16926
          tag: 'div',
16927
          classes: ['tox-dropzone-container']
16928
        },
16929
        behaviours: derive$1([
1441 ariadna 16930
          Disabling.config({ disabled: () => providersBackstage.checkUiComponentContext(spec.context).shouldDisable }),
16931
          toggleOnReceive(() => providersBackstage.checkUiComponentContext(spec.context)),
1 efrain 16932
          Toggling.config({
16933
            toggleClass: 'dragenter',
16934
            toggleOnExecute: false
16935
          }),
16936
          config('dropzone-events', [
16937
            run$1('dragenter', sequence([
16938
              stopper,
16939
              Toggling.toggle
16940
            ])),
16941
            run$1('dragleave', sequence([
16942
              stopper,
16943
              Toggling.toggle
16944
            ])),
16945
            run$1('dragover', stopper),
16946
            run$1('drop', sequence([
16947
              stopper,
16948
              onDrop
16949
            ])),
16950
            run$1(change(), onSelect)
16951
          ])
16952
        ]),
16953
        components: [{
16954
            dom: {
16955
              tag: 'div',
16956
              classes: ['tox-dropzone'],
16957
              styles: {}
16958
            },
16959
            components: [
16960
              {
16961
                dom: { tag: 'p' },
16962
                components: [text$2(providersBackstage.translate('Drop an image here'))]
16963
              },
1441 ariadna 16964
              pField
1 efrain 16965
            ]
16966
          }]
1441 ariadna 16967
      };
16968
      return renderFormFieldWith(pLabel, wrapper, ['tox-form__group--stretched'], [config('handle-files', [run$1(browseFilesEvent, (comp, se) => {
16969
            FormField.getField(comp).each(field => {
16970
              handleFiles(field, se.event.files);
16971
            });
16972
          })])]);
1 efrain 16973
    };
16974
 
16975
    const renderGrid = (spec, backstage) => ({
16976
      dom: {
16977
        tag: 'div',
16978
        classes: [
16979
          'tox-form__grid',
16980
          `tox-form__grid--${ spec.columns }col`
16981
        ]
16982
      },
16983
      components: map$2(spec.items, backstage.interpreter)
16984
    });
16985
 
16986
    const adaptable = (fn, rate) => {
16987
      let timer = null;
16988
      let args = null;
16989
      const cancel = () => {
16990
        if (!isNull(timer)) {
16991
          clearTimeout(timer);
16992
          timer = null;
16993
          args = null;
16994
        }
16995
      };
16996
      const throttle = (...newArgs) => {
16997
        args = newArgs;
16998
        if (isNull(timer)) {
16999
          timer = setTimeout(() => {
17000
            const tempArgs = args;
17001
            timer = null;
17002
            args = null;
17003
            fn.apply(null, tempArgs);
17004
          }, rate);
17005
        }
17006
      };
17007
      return {
17008
        cancel,
17009
        throttle
17010
      };
17011
    };
17012
    const first = (fn, rate) => {
17013
      let timer = null;
17014
      const cancel = () => {
17015
        if (!isNull(timer)) {
17016
          clearTimeout(timer);
17017
          timer = null;
17018
        }
17019
      };
17020
      const throttle = (...args) => {
17021
        if (isNull(timer)) {
17022
          timer = setTimeout(() => {
17023
            timer = null;
17024
            fn.apply(null, args);
17025
          }, rate);
17026
        }
17027
      };
17028
      return {
17029
        cancel,
17030
        throttle
17031
      };
17032
    };
17033
    const last = (fn, rate) => {
17034
      let timer = null;
17035
      const cancel = () => {
17036
        if (!isNull(timer)) {
17037
          clearTimeout(timer);
17038
          timer = null;
17039
        }
17040
      };
17041
      const throttle = (...args) => {
17042
        cancel();
17043
        timer = setTimeout(() => {
17044
          timer = null;
17045
          fn.apply(null, args);
17046
        }, rate);
17047
      };
17048
      return {
17049
        cancel,
17050
        throttle
17051
      };
17052
    };
17053
 
17054
    const beforeObject = generate$6('alloy-fake-before-tabstop');
17055
    const afterObject = generate$6('alloy-fake-after-tabstop');
17056
    const craftWithClasses = classes => {
17057
      return {
17058
        dom: {
17059
          tag: 'div',
17060
          styles: {
17061
            width: '1px',
17062
            height: '1px',
17063
            outline: 'none'
17064
          },
17065
          attributes: { tabindex: '0' },
17066
          classes
17067
        },
17068
        behaviours: derive$1([
17069
          Focusing.config({ ignore: true }),
17070
          Tabstopping.config({})
17071
        ])
17072
      };
17073
    };
17074
    const craft = (containerClasses, spec) => {
17075
      return {
17076
        dom: {
17077
          tag: 'div',
17078
          classes: [
17079
            'tox-navobj',
17080
            ...containerClasses.getOr([])
17081
          ]
17082
        },
17083
        components: [
17084
          craftWithClasses([beforeObject]),
17085
          spec,
17086
          craftWithClasses([afterObject])
17087
        ],
17088
        behaviours: derive$1([ComposingConfigs.childAt(1)])
17089
      };
17090
    };
17091
    const triggerTab = (placeholder, shiftKey) => {
17092
      emitWith(placeholder, keydown(), {
17093
        raw: {
17094
          which: 9,
17095
          shiftKey
17096
        }
17097
      });
17098
    };
17099
    const onFocus = (container, targetComp) => {
17100
      const target = targetComp.element;
17101
      if (has(target, beforeObject)) {
17102
        triggerTab(container, true);
17103
      } else if (has(target, afterObject)) {
17104
        triggerTab(container, false);
17105
      }
17106
    };
17107
    const isPseudoStop = element => {
17108
      return closest(element, [
17109
        '.' + beforeObject,
17110
        '.' + afterObject
17111
      ].join(','), never);
17112
    };
17113
 
17114
    const dialogChannel = generate$6('update-dialog');
17115
    const titleChannel = generate$6('update-title');
17116
    const bodyChannel = generate$6('update-body');
17117
    const footerChannel = generate$6('update-footer');
17118
    const bodySendMessageChannel = generate$6('body-send-message');
17119
    const dialogFocusShiftedChannel = generate$6('dialog-focus-shifted');
17120
 
1441 ariadna 17121
    const browser = detect$1().browser;
1 efrain 17122
    const isSafari = browser.isSafari();
17123
    const isFirefox = browser.isFirefox();
17124
    const isSafariOrFirefox = isSafari || isFirefox;
17125
    const isChromium = browser.isChromium();
17126
    const isElementScrollAtBottom = ({scrollTop, scrollHeight, clientHeight}) => Math.ceil(scrollTop) + clientHeight >= scrollHeight;
17127
    const scrollToY = (win, y) => win.scrollTo(0, y === 'bottom' ? 99999999 : y);
17128
    const getScrollingElement = (doc, html) => {
17129
      const body = doc.body;
17130
      return Optional.from(!/^<!DOCTYPE (html|HTML)/.test(html) && (!isChromium && !isSafari || isNonNullable(body) && (body.scrollTop !== 0 || Math.abs(body.scrollHeight - body.clientHeight) > 1)) ? body : doc.documentElement);
17131
    };
17132
    const writeValue = (iframeElement, html, fallbackFn) => {
17133
      const iframe = iframeElement.dom;
17134
      Optional.from(iframe.contentDocument).fold(fallbackFn, doc => {
17135
        let lastScrollTop = 0;
17136
        const isScrollAtBottom = getScrollingElement(doc, html).map(el => {
17137
          lastScrollTop = el.scrollTop;
17138
          return el;
17139
        }).forall(isElementScrollAtBottom);
17140
        const scrollAfterWrite = () => {
17141
          const win = iframe.contentWindow;
17142
          if (isNonNullable(win)) {
17143
            if (isScrollAtBottom) {
17144
              scrollToY(win, 'bottom');
17145
            } else if (!isScrollAtBottom && isSafariOrFirefox && lastScrollTop !== 0) {
17146
              scrollToY(win, lastScrollTop);
17147
            }
17148
          }
17149
        };
17150
        if (isSafari) {
17151
          iframe.addEventListener('load', scrollAfterWrite, { once: true });
17152
        }
17153
        doc.open();
17154
        doc.write(html);
17155
        doc.close();
17156
        if (!isSafari) {
17157
          scrollAfterWrite();
17158
        }
17159
      });
17160
    };
17161
    const throttleInterval = someIf(isSafariOrFirefox, isSafari ? 500 : 200);
17162
    const writeValueThrottler = throttleInterval.map(interval => adaptable(writeValue, interval));
17163
    const getDynamicSource = (initialData, stream) => {
17164
      const cachedValue = Cell(initialData.getOr(''));
17165
      return {
17166
        getValue: _frameComponent => cachedValue.get(),
17167
        setValue: (frameComponent, html) => {
17168
          if (cachedValue.get() !== html) {
17169
            const iframeElement = frameComponent.element;
17170
            const setSrcdocValue = () => set$9(iframeElement, 'srcdoc', html);
17171
            if (stream) {
17172
              writeValueThrottler.fold(constant$1(writeValue), throttler => throttler.throttle)(iframeElement, html, setSrcdocValue);
17173
            } else {
17174
              setSrcdocValue();
17175
            }
17176
          }
17177
          cachedValue.set(html);
17178
        }
17179
      };
17180
    };
17181
    const renderIFrame = (spec, providersBackstage, initialData) => {
17182
      const baseClass = 'tox-dialog__iframe';
17183
      const opaqueClass = spec.transparent ? [] : [`${ baseClass }--opaque`];
17184
      const containerBorderedClass = spec.border ? [`tox-navobj-bordered`] : [];
17185
      const attributes = {
17186
        ...spec.label.map(title => ({ title })).getOr({}),
17187
        ...initialData.map(html => ({ srcdoc: html })).getOr({}),
17188
        ...spec.sandboxed ? { sandbox: 'allow-scripts allow-same-origin' } : {}
17189
      };
17190
      const sourcing = getDynamicSource(initialData, spec.streamContent);
17191
      const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
17192
      const factory = newSpec => craft(Optional.from(containerBorderedClass), {
17193
        uid: newSpec.uid,
17194
        dom: {
17195
          tag: 'iframe',
17196
          attributes,
17197
          classes: [
17198
            baseClass,
17199
            ...opaqueClass
17200
          ]
17201
        },
17202
        behaviours: derive$1([
17203
          Tabstopping.config({}),
17204
          Focusing.config({}),
17205
          withComp(initialData, sourcing.getValue, sourcing.setValue),
17206
          Receiving.config({
17207
            channels: {
17208
              [dialogFocusShiftedChannel]: {
17209
                onReceive: (comp, message) => {
17210
                  message.newFocus.each(newFocus => {
17211
                    parentElement(comp.element).each(parent => {
1441 ariadna 17212
                      const f = eq(comp.element, newFocus) ? add$2 : remove$3;
1 efrain 17213
                      f(parent, 'tox-navobj-bordered-focus');
17214
                    });
17215
                  });
17216
                }
17217
              }
17218
            }
17219
          })
17220
        ])
17221
      });
17222
      const pField = FormField.parts.field({ factory: { sketch: factory } });
17223
      return renderFormFieldWith(pLabel, pField, ['tox-form__group--stretched'], []);
17224
    };
17225
 
17226
    const image = image => new Promise((resolve, reject) => {
17227
      const loaded = () => {
17228
        destroy();
17229
        resolve(image);
17230
      };
17231
      const listeners = [
17232
        bind(image, 'load', loaded),
17233
        bind(image, 'error', () => {
17234
          destroy();
17235
          reject('Unable to load data from image: ' + image.dom.src);
17236
        })
17237
      ];
17238
      const destroy = () => each$1(listeners, l => l.unbind());
17239
      if (image.dom.complete) {
17240
        loaded();
17241
      }
17242
    });
17243
 
17244
    const calculateImagePosition = (panelWidth, panelHeight, imageWidth, imageHeight, zoom) => {
17245
      const width = imageWidth * zoom;
17246
      const height = imageHeight * zoom;
17247
      const left = Math.max(0, panelWidth / 2 - width / 2);
17248
      const top = Math.max(0, panelHeight / 2 - height / 2);
17249
      return {
17250
        left: left.toString() + 'px',
17251
        top: top.toString() + 'px',
17252
        width: width.toString() + 'px',
17253
        height: height.toString() + 'px'
17254
      };
17255
    };
17256
    const zoomToFit = (panel, width, height) => {
1441 ariadna 17257
      const panelW = get$d(panel);
17258
      const panelH = get$e(panel);
1 efrain 17259
      return Math.min(panelW / width, panelH / height, 1);
17260
    };
17261
    const renderImagePreview = (spec, initialData) => {
17262
      const cachedData = Cell(initialData.getOr({ url: '' }));
17263
      const memImage = record({
17264
        dom: {
17265
          tag: 'img',
17266
          classes: ['tox-imagepreview__image'],
17267
          attributes: initialData.map(data => ({ src: data.url })).getOr({})
17268
        }
17269
      });
17270
      const memContainer = record({
17271
        dom: {
17272
          tag: 'div',
17273
          classes: ['tox-imagepreview__container'],
17274
          attributes: { role: 'presentation' }
17275
        },
17276
        components: [memImage.asSpec()]
17277
      });
17278
      const setValue = (frameComponent, data) => {
17279
        const translatedData = { url: data.url };
17280
        data.zoom.each(z => translatedData.zoom = z);
17281
        data.cachedWidth.each(z => translatedData.cachedWidth = z);
17282
        data.cachedHeight.each(z => translatedData.cachedHeight = z);
17283
        cachedData.set(translatedData);
17284
        const applyFramePositioning = () => {
17285
          const {cachedWidth, cachedHeight, zoom} = translatedData;
17286
          if (!isUndefined(cachedWidth) && !isUndefined(cachedHeight)) {
17287
            if (isUndefined(zoom)) {
17288
              const z = zoomToFit(frameComponent.element, cachedWidth, cachedHeight);
17289
              translatedData.zoom = z;
17290
            }
1441 ariadna 17291
            const position = calculateImagePosition(get$d(frameComponent.element), get$e(frameComponent.element), cachedWidth, cachedHeight, translatedData.zoom);
1 efrain 17292
            memContainer.getOpt(frameComponent).each(container => {
17293
              setAll(container.element, position);
17294
            });
17295
          }
17296
        };
17297
        memImage.getOpt(frameComponent).each(imageComponent => {
17298
          const img = imageComponent.element;
1441 ariadna 17299
          if (data.url !== get$g(img, 'src')) {
1 efrain 17300
            set$9(img, 'src', data.url);
1441 ariadna 17301
            remove$3(frameComponent.element, 'tox-imagepreview__loaded');
1 efrain 17302
          }
17303
          applyFramePositioning();
17304
          image(img).then(img => {
17305
            if (frameComponent.getSystem().isConnected()) {
17306
              add$2(frameComponent.element, 'tox-imagepreview__loaded');
17307
              translatedData.cachedWidth = img.dom.naturalWidth;
17308
              translatedData.cachedHeight = img.dom.naturalHeight;
17309
              applyFramePositioning();
17310
            }
17311
          });
17312
        });
17313
      };
17314
      const styles = {};
17315
      spec.height.each(h => styles.height = h);
17316
      const fakeValidatedData = initialData.map(d => ({
17317
        url: d.url,
17318
        zoom: Optional.from(d.zoom),
17319
        cachedWidth: Optional.from(d.cachedWidth),
17320
        cachedHeight: Optional.from(d.cachedHeight)
17321
      }));
17322
      return {
17323
        dom: {
17324
          tag: 'div',
17325
          classes: ['tox-imagepreview'],
17326
          styles,
17327
          attributes: { role: 'presentation' }
17328
        },
17329
        components: [memContainer.asSpec()],
17330
        behaviours: derive$1([
17331
          ComposingConfigs.self(),
17332
          withComp(fakeValidatedData, () => cachedData.get(), setValue)
17333
        ])
17334
      };
17335
    };
17336
 
1441 ariadna 17337
    const renderLabel$2 = (spec, backstageShared, getCompByName) => {
1 efrain 17338
      const baseClass = 'tox-label';
17339
      const centerClass = spec.align === 'center' ? [`${ baseClass }--center`] : [];
17340
      const endClass = spec.align === 'end' ? [`${ baseClass }--end`] : [];
1441 ariadna 17341
      const label = record({
1 efrain 17342
        dom: {
17343
          tag: 'label',
17344
          classes: [
17345
            baseClass,
17346
            ...centerClass,
17347
            ...endClass
17348
          ]
17349
        },
17350
        components: [text$2(backstageShared.providers.translate(spec.label))]
1441 ariadna 17351
      });
1 efrain 17352
      const comps = map$2(spec.items, backstageShared.interpreter);
17353
      return {
17354
        dom: {
17355
          tag: 'div',
17356
          classes: ['tox-form__group']
17357
        },
17358
        components: [
1441 ariadna 17359
          label.asSpec(),
1 efrain 17360
          ...comps
17361
        ],
17362
        behaviours: derive$1([
17363
          ComposingConfigs.self(),
17364
          Replacing.config({}),
17365
          domHtml(Optional.none()),
1441 ariadna 17366
          Keying.config({ mode: 'acyclic' }),
17367
          config('label', [runOnAttached(comp => {
17368
              spec.for.each(name => {
17369
                getCompByName(name).each(target => {
17370
                  label.getOpt(comp).each(labelComp => {
17371
                    var _a;
17372
                    const id = (_a = get$g(target.element, 'id')) !== null && _a !== void 0 ? _a : generate$6('form-field');
17373
                    set$9(target.element, 'id', id);
17374
                    set$9(labelComp.element, 'for', id);
17375
                  });
17376
                });
17377
              });
17378
            })])
1 efrain 17379
        ])
17380
      };
17381
    };
17382
 
17383
    const internalToolbarButtonExecute = generate$6('toolbar.button.execute');
17384
    const onToolbarButtonExecute = info => runOnExecute$1((comp, _simulatedEvent) => {
17385
      runWithApi(info, comp)(itemApi => {
17386
        emitWith(comp, internalToolbarButtonExecute, { buttonApi: itemApi });
17387
        info.onAction(itemApi);
17388
      });
17389
    });
17390
    const commonButtonDisplayEvent = generate$6('common-button-display-events');
17391
    const toolbarButtonEventOrder = {
17392
      [execute$5()]: [
17393
        'disabling',
17394
        'alloy.base.behaviour',
17395
        'toggling',
1441 ariadna 17396
        'toolbar-button-events',
17397
        'tooltipping'
1 efrain 17398
      ],
17399
      [attachedToDom()]: [
17400
        'toolbar-button-events',
17401
        commonButtonDisplayEvent
17402
      ],
1441 ariadna 17403
      [detachedFromDom()]: [
17404
        'toolbar-button-events',
17405
        'dropdown-events',
17406
        'tooltipping'
17407
      ],
1 efrain 17408
      [mousedown()]: [
17409
        'focusing',
17410
        'alloy.base.behaviour',
17411
        commonButtonDisplayEvent
17412
      ]
17413
    };
17414
 
1441 ariadna 17415
    const forceInitialSize = comp => set$8(comp.element, 'width', get$f(comp.element, 'width'));
1 efrain 17416
 
17417
    const renderIcon$1 = (iconName, iconsProvider, behaviours) => render$3(iconName, {
17418
      tag: 'span',
17419
      classes: [
17420
        'tox-icon',
17421
        'tox-tbtn__icon-wrap'
17422
      ],
17423
      behaviours
17424
    }, iconsProvider);
17425
    const renderIconFromPack$1 = (iconName, iconsProvider) => renderIcon$1(iconName, iconsProvider, []);
17426
    const renderReplaceableIconFromPack = (iconName, iconsProvider) => renderIcon$1(iconName, iconsProvider, [Replacing.config({})]);
17427
    const renderLabel$1 = (text, prefix, providersBackstage) => ({
17428
      dom: {
17429
        tag: 'span',
17430
        classes: [`${ prefix }__select-label`]
17431
      },
17432
      components: [text$2(providersBackstage.translate(text))],
17433
      behaviours: derive$1([Replacing.config({})])
17434
    });
17435
 
17436
    const updateMenuText = generate$6('update-menu-text');
17437
    const updateMenuIcon = generate$6('update-menu-icon');
1441 ariadna 17438
    const renderCommonDropdown = (spec, prefix, sharedBackstage, btnName) => {
1 efrain 17439
      const editorOffCell = Cell(noop);
17440
      const optMemDisplayText = spec.text.map(text => record(renderLabel$1(text, prefix, sharedBackstage.providers)));
17441
      const optMemDisplayIcon = spec.icon.map(iconName => record(renderReplaceableIconFromPack(iconName, sharedBackstage.providers.icons)));
17442
      const onLeftOrRightInMenu = (comp, se) => {
17443
        const dropdown = Representing.getValue(comp);
17444
        Focusing.focus(dropdown);
17445
        emitWith(dropdown, 'keydown', { raw: se.event.raw });
17446
        Dropdown.close(dropdown);
17447
        return Optional.some(true);
17448
      };
17449
      const role = spec.role.fold(() => ({}), role => ({ role }));
1441 ariadna 17450
      const listRole = Optional.from(spec.listRole).map(listRole => ({ listRole })).getOr({});
17451
      const ariaLabelAttribute = spec.ariaLabel.fold(() => ({}), ariaLabel => {
17452
        const translatedAriaLabel = sharedBackstage.providers.translate(ariaLabel);
17453
        return { 'aria-label': translatedAriaLabel };
1 efrain 17454
      });
17455
      const iconSpec = render$3('chevron-down', {
17456
        tag: 'div',
17457
        classes: [`${ prefix }__select-chevron`]
17458
      }, sharedBackstage.providers.icons);
17459
      const fixWidthBehaviourName = generate$6('common-button-display-events');
1441 ariadna 17460
      const customEventsName = 'dropdown-events';
1 efrain 17461
      const memDropdown = record(Dropdown.sketch({
17462
        ...spec.uid ? { uid: spec.uid } : {},
17463
        ...role,
1441 ariadna 17464
        ...listRole,
1 efrain 17465
        dom: {
17466
          tag: 'button',
17467
          classes: [
17468
            prefix,
17469
            `${ prefix }--select`
17470
          ].concat(map$2(spec.classes, c => `${ prefix }--${ c }`)),
1441 ariadna 17471
          attributes: {
17472
            ...ariaLabelAttribute,
17473
            ...isNonNullable(btnName) ? { 'data-mce-name': btnName } : {}
17474
          }
1 efrain 17475
        },
17476
        components: componentRenderPipeline([
17477
          optMemDisplayIcon.map(mem => mem.asSpec()),
17478
          optMemDisplayText.map(mem => mem.asSpec()),
17479
          Optional.some(iconSpec)
17480
        ]),
17481
        matchWidth: true,
17482
        useMinWidth: true,
17483
        onOpen: (anchor, dropdownComp, tmenuComp) => {
17484
          if (spec.searchable) {
17485
            focusSearchField(tmenuComp);
17486
          }
17487
        },
17488
        dropdownBehaviours: derive$1([
17489
          ...spec.dropdownBehaviours,
1441 ariadna 17490
          DisablingConfigs.button(() => spec.disabled || sharedBackstage.providers.checkUiComponentContext(spec.context).shouldDisable),
17491
          toggleOnReceive(() => sharedBackstage.providers.checkUiComponentContext(spec.context)),
1 efrain 17492
          Unselecting.config({}),
17493
          Replacing.config({}),
1441 ariadna 17494
          ...spec.tooltip.map(t => Tooltipping.config(sharedBackstage.providers.tooltips.getConfig({ tooltipText: sharedBackstage.providers.translate(t) }))).toArray(),
17495
          config(customEventsName, [
1 efrain 17496
            onControlAttached(spec, editorOffCell),
17497
            onControlDetached(spec, editorOffCell)
17498
          ]),
1441 ariadna 17499
          config(fixWidthBehaviourName, [runOnAttached((comp, _se) => {
17500
              if (spec.listRole !== 'listbox') {
17501
                forceInitialSize(comp);
17502
              }
17503
            })]),
17504
          config('update-dropdown-width-variable', [run$1(windowResize(), (comp, _se) => Dropdown.close(comp))]),
1 efrain 17505
          config('menubutton-update-display-text', [
17506
            run$1(updateMenuText, (comp, se) => {
17507
              optMemDisplayText.bind(mem => mem.getOpt(comp)).each(displayText => {
17508
                Replacing.set(displayText, [text$2(sharedBackstage.providers.translate(se.event.text))]);
17509
              });
17510
            }),
17511
            run$1(updateMenuIcon, (comp, se) => {
17512
              optMemDisplayIcon.bind(mem => mem.getOpt(comp)).each(displayIcon => {
17513
                Replacing.set(displayIcon, [renderReplaceableIconFromPack(se.event.icon, sharedBackstage.providers.icons)]);
17514
              });
17515
            })
17516
          ])
17517
        ]),
17518
        eventOrder: deepMerge(toolbarButtonEventOrder, {
1441 ariadna 17519
          [mousedown()]: [
1 efrain 17520
            'focusing',
17521
            'alloy.base.behaviour',
17522
            'item-type-events',
17523
            'normal-dropdown-events'
17524
          ],
17525
          [attachedToDom()]: [
17526
            'toolbar-button-events',
1441 ariadna 17527
            Tooltipping.name(),
17528
            customEventsName,
1 efrain 17529
            fixWidthBehaviourName
17530
          ]
17531
        }),
17532
        sandboxBehaviours: derive$1([
17533
          Keying.config({
17534
            mode: 'special',
17535
            onLeft: onLeftOrRightInMenu,
17536
            onRight: onLeftOrRightInMenu
17537
          }),
17538
          config('dropdown-sandbox-events', [
17539
            run$1(refetchTriggerEvent, (originalSandboxComp, se) => {
17540
              handleRefetchTrigger(originalSandboxComp);
17541
              se.stop();
17542
            }),
17543
            run$1(redirectMenuItemInteractionEvent, (sandboxComp, se) => {
17544
              handleRedirectToMenuItem(sandboxComp, se);
17545
              se.stop();
17546
            })
17547
          ])
17548
        ]),
17549
        lazySink: sharedBackstage.getSink,
17550
        toggleClass: `${ prefix }--active`,
17551
        parts: {
17552
          menu: {
17553
            ...part(false, spec.columns, spec.presets),
17554
            fakeFocus: spec.searchable,
1441 ariadna 17555
            ...spec.listRole === 'listbox' ? {} : {
17556
              onHighlightItem: updateAriaOnHighlight,
17557
              onCollapseMenu: (tmenuComp, itemCompCausingCollapse, nowActiveMenuComp) => {
17558
                Highlighting.getHighlighted(nowActiveMenuComp).each(itemComp => {
17559
                  updateAriaOnHighlight(tmenuComp, nowActiveMenuComp, itemComp);
17560
                });
17561
              },
17562
              onDehighlightItem: updateAriaOnDehighlight
17563
            }
1 efrain 17564
          }
17565
        },
17566
        getAnchorOverrides: () => {
17567
          return {
17568
            maxHeightFunction: (element, available) => {
17569
              anchored()(element, available - 10);
17570
            }
17571
          };
17572
        },
17573
        fetch: comp => Future.nu(curry(spec.fetch, comp))
17574
      }));
17575
      return memDropdown.asSpec();
17576
    };
17577
 
17578
    const isMenuItemReference = item => isString(item);
17579
    const isSeparator$2 = item => item.type === 'separator';
17580
    const isExpandingMenuItem = item => has$2(item, 'getSubmenuItems');
17581
    const separator$2 = { type: 'separator' };
17582
    const unwrapReferences = (items, menuItems) => {
17583
      const realItems = foldl(items, (acc, item) => {
17584
        if (isMenuItemReference(item)) {
17585
          if (item === '') {
17586
            return acc;
17587
          } else if (item === '|') {
17588
            return acc.length > 0 && !isSeparator$2(acc[acc.length - 1]) ? acc.concat([separator$2]) : acc;
17589
          } else if (has$2(menuItems, item.toLowerCase())) {
17590
            return acc.concat([menuItems[item.toLowerCase()]]);
17591
          } else {
17592
            return acc;
17593
          }
17594
        } else {
17595
          return acc.concat([item]);
17596
        }
17597
      }, []);
17598
      if (realItems.length > 0 && isSeparator$2(realItems[realItems.length - 1])) {
17599
        realItems.pop();
17600
      }
17601
      return realItems;
17602
    };
17603
    const getFromExpandingItem = (item, menuItems) => {
17604
      const submenuItems = item.getSubmenuItems();
17605
      const rest = expand(submenuItems, menuItems);
17606
      const newMenus = deepMerge(rest.menus, { [item.value]: rest.items });
17607
      const newExpansions = deepMerge(rest.expansions, { [item.value]: item.value });
17608
      return {
17609
        item,
17610
        menus: newMenus,
17611
        expansions: newExpansions
17612
      };
17613
    };
17614
    const generateValueIfRequired = item => {
1441 ariadna 17615
      const itemValue = get$h(item, 'value').getOrThunk(() => generate$6('generated-menu-item'));
1 efrain 17616
      return deepMerge({ value: itemValue }, item);
17617
    };
17618
    const expand = (items, menuItems) => {
17619
      const realItems = unwrapReferences(isString(items) ? items.split(' ') : items, menuItems);
17620
      return foldr(realItems, (acc, item) => {
17621
        if (isExpandingMenuItem(item)) {
17622
          const itemWithValue = generateValueIfRequired(item);
17623
          const newData = getFromExpandingItem(itemWithValue, menuItems);
17624
          return {
17625
            menus: deepMerge(acc.menus, newData.menus),
17626
            items: [
17627
              newData.item,
17628
              ...acc.items
17629
            ],
17630
            expansions: deepMerge(acc.expansions, newData.expansions)
17631
          };
17632
        } else {
17633
          return {
17634
            ...acc,
17635
            items: [
17636
              item,
17637
              ...acc.items
17638
            ]
17639
          };
17640
        }
17641
      }, {
17642
        menus: {},
17643
        expansions: {},
17644
        items: []
17645
      });
17646
    };
17647
 
17648
    const getSearchModeForField = settings => {
17649
      return settings.search.fold(() => ({ searchMode: 'no-search' }), searchSettings => ({
17650
        searchMode: 'search-with-field',
17651
        placeholder: searchSettings.placeholder
17652
      }));
17653
    };
17654
    const getSearchModeForResults = settings => {
17655
      return settings.search.fold(() => ({ searchMode: 'no-search' }), _ => ({ searchMode: 'search-with-results' }));
17656
    };
17657
    const build = (items, itemResponse, backstage, settings) => {
17658
      const primary = generate$6('primary-menu');
17659
      const data = expand(items, backstage.shared.providers.menuItems());
17660
      if (data.items.length === 0) {
17661
        return Optional.none();
17662
      }
17663
      const mainMenuSearchMode = getSearchModeForField(settings);
17664
      const mainMenu = createPartialMenu(primary, data.items, itemResponse, backstage, settings.isHorizontalMenu, mainMenuSearchMode);
17665
      const submenuSearchMode = getSearchModeForResults(settings);
17666
      const submenus = map$1(data.menus, (menuItems, menuName) => createPartialMenu(menuName, menuItems, itemResponse, backstage, false, submenuSearchMode));
17667
      const menus = deepMerge(submenus, wrap$1(primary, mainMenu));
17668
      return Optional.from(tieredMenu.tieredData(primary, menus, data.expansions));
17669
    };
17670
 
17671
    const isSingleListItem = item => !has$2(item, 'items');
17672
    const dataAttribute = 'data-value';
1441 ariadna 17673
    const fetchItems = (dropdownComp, name, items, selectedValue, hasNestedItems) => map$2(items, item => {
1 efrain 17674
      if (!isSingleListItem(item)) {
17675
        return {
17676
          type: 'nestedmenuitem',
17677
          text: item.text,
1441 ariadna 17678
          getSubmenuItems: () => fetchItems(dropdownComp, name, item.items, selectedValue, hasNestedItems)
1 efrain 17679
        };
17680
      } else {
17681
        return {
17682
          type: 'togglemenuitem',
1441 ariadna 17683
          ...hasNestedItems ? {} : { role: 'option' },
1 efrain 17684
          text: item.text,
17685
          value: item.value,
17686
          active: item.value === selectedValue,
17687
          onAction: () => {
17688
            Representing.setValue(dropdownComp, item.value);
17689
            emitWith(dropdownComp, formChangeEvent, { name });
17690
            Focusing.focus(dropdownComp);
17691
          }
17692
        };
17693
      }
17694
    });
17695
    const findItemByValue = (items, value) => findMap(items, item => {
17696
      if (!isSingleListItem(item)) {
17697
        return findItemByValue(item.items, value);
17698
      } else {
17699
        return someIf(item.value === value, item);
17700
      }
17701
    });
17702
    const renderListBox = (spec, backstage, initialData) => {
1441 ariadna 17703
      const hasNestedItems = exists(spec.items, item => !isSingleListItem(item));
1 efrain 17704
      const providersBackstage = backstage.shared.providers;
17705
      const initialItem = initialData.bind(value => findItemByValue(spec.items, value)).orThunk(() => head(spec.items).filter(isSingleListItem));
17706
      const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
17707
      const pField = FormField.parts.field({
17708
        dom: {},
17709
        factory: {
17710
          sketch: sketchSpec => renderCommonDropdown({
1441 ariadna 17711
            context: spec.context,
1 efrain 17712
            uid: sketchSpec.uid,
17713
            text: initialItem.map(item => item.text),
17714
            icon: Optional.none(),
1441 ariadna 17715
            tooltip: Optional.none(),
17716
            role: someIf(!hasNestedItems, 'combobox'),
17717
            ...hasNestedItems ? {} : { listRole: 'listbox' },
17718
            ariaLabel: spec.label,
1 efrain 17719
            fetch: (comp, callback) => {
1441 ariadna 17720
              const items = fetchItems(comp, spec.name, spec.items, Representing.getValue(comp), hasNestedItems);
1 efrain 17721
              callback(build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
17722
                isHorizontalMenu: false,
17723
                search: Optional.none()
17724
              }));
17725
            },
17726
            onSetup: constant$1(noop),
17727
            getApi: constant$1({}),
17728
            columns: 1,
17729
            presets: 'normal',
17730
            classes: [],
17731
            dropdownBehaviours: [
17732
              Tabstopping.config({}),
1441 ariadna 17733
              withComp(initialItem.map(item => item.value), comp => get$g(comp.element, dataAttribute), (comp, data) => {
1 efrain 17734
                findItemByValue(spec.items, data).each(item => {
17735
                  set$9(comp.element, dataAttribute, item.value);
17736
                  emitWith(comp, updateMenuText, { text: item.text });
17737
                });
17738
              })
17739
            ]
17740
          }, 'tox-listbox', backstage.shared)
17741
        }
17742
      });
17743
      const listBoxWrap = {
17744
        dom: {
17745
          tag: 'div',
17746
          classes: ['tox-listboxfield']
17747
        },
17748
        components: [pField]
17749
      };
17750
      return FormField.sketch({
17751
        dom: {
17752
          tag: 'div',
17753
          classes: ['tox-form__group']
17754
        },
17755
        components: flatten([
17756
          pLabel.toArray(),
17757
          [listBoxWrap]
17758
        ]),
17759
        fieldBehaviours: derive$1([Disabling.config({
1441 ariadna 17760
            disabled: () => !spec.enabled || providersBackstage.checkUiComponentContext(spec.context).shouldDisable,
1 efrain 17761
            onDisabled: comp => {
17762
              FormField.getField(comp).each(Disabling.disable);
17763
            },
17764
            onEnabled: comp => {
17765
              FormField.getField(comp).each(Disabling.enable);
17766
            }
17767
          })])
17768
      });
17769
    };
17770
 
17771
    const renderPanel = (spec, backstage) => ({
17772
      dom: {
17773
        tag: 'div',
17774
        classes: spec.classes
17775
      },
17776
      components: map$2(spec.items, backstage.shared.interpreter)
17777
    });
17778
 
17779
    const factory$h = (detail, _spec) => {
17780
      const options = map$2(detail.options, option => ({
17781
        dom: {
17782
          tag: 'option',
17783
          value: option.value,
17784
          innerHtml: option.text
17785
        }
17786
      }));
17787
      const initialValues = detail.data.map(v => wrap$1('initialValue', v)).getOr({});
17788
      return {
17789
        uid: detail.uid,
17790
        dom: {
17791
          tag: 'select',
17792
          classes: detail.selectClasses,
17793
          attributes: detail.selectAttributes
17794
        },
17795
        components: options,
17796
        behaviours: augment(detail.selectBehaviours, [
17797
          Focusing.config({}),
17798
          Representing.config({
17799
            store: {
17800
              mode: 'manual',
17801
              getValue: select => {
1441 ariadna 17802
                return get$7(select.element);
1 efrain 17803
              },
17804
              setValue: (select, newValue) => {
17805
                const firstOption = head(detail.options);
17806
                const found = find$5(detail.options, opt => opt.value === newValue);
17807
                if (found.isSome()) {
17808
                  set$5(select.element, newValue);
17809
                } else if (select.element.dom.selectedIndex === -1 && newValue === '') {
17810
                  firstOption.each(value => set$5(select.element, value.value));
17811
                }
17812
              },
17813
              ...initialValues
17814
            }
17815
          })
17816
        ])
17817
      };
17818
    };
17819
    const HtmlSelect = single({
17820
      name: 'HtmlSelect',
17821
      configFields: [
17822
        required$1('options'),
17823
        field('selectBehaviours', [
17824
          Focusing,
17825
          Representing
17826
        ]),
17827
        defaulted('selectClasses', []),
17828
        defaulted('selectAttributes', {}),
17829
        option$3('data')
17830
      ],
17831
      factory: factory$h
17832
    });
17833
 
17834
    const renderSelectBox = (spec, providersBackstage, initialData) => {
17835
      const translatedOptions = map$2(spec.items, item => ({
17836
        text: providersBackstage.translate(item.text),
17837
        value: item.value
17838
      }));
17839
      const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
17840
      const pField = FormField.parts.field({
17841
        dom: {},
17842
        ...initialData.map(data => ({ data })).getOr({}),
17843
        selectAttributes: { size: spec.size },
17844
        options: translatedOptions,
17845
        factory: HtmlSelect,
17846
        selectBehaviours: derive$1([
1441 ariadna 17847
          Disabling.config({ disabled: () => !spec.enabled || providersBackstage.checkUiComponentContext(spec.context).shouldDisable }),
1 efrain 17848
          Tabstopping.config({}),
17849
          config('selectbox-change', [run$1(change(), (component, _) => {
17850
              emitWith(component, formChangeEvent, { name: spec.name });
17851
            })])
17852
        ])
17853
      });
17854
      const chevron = spec.size > 1 ? Optional.none() : Optional.some(render$3('chevron-down', {
17855
        tag: 'div',
17856
        classes: ['tox-selectfield__icon-js']
17857
      }, providersBackstage.icons));
17858
      const selectWrap = {
17859
        dom: {
17860
          tag: 'div',
17861
          classes: ['tox-selectfield']
17862
        },
17863
        components: flatten([
17864
          [pField],
17865
          chevron.toArray()
17866
        ])
17867
      };
17868
      return FormField.sketch({
17869
        dom: {
17870
          tag: 'div',
17871
          classes: ['tox-form__group']
17872
        },
17873
        components: flatten([
17874
          pLabel.toArray(),
17875
          [selectWrap]
17876
        ]),
17877
        fieldBehaviours: derive$1([
17878
          Disabling.config({
1441 ariadna 17879
            disabled: () => !spec.enabled || providersBackstage.checkUiComponentContext(spec.context).shouldDisable,
1 efrain 17880
            onDisabled: comp => {
17881
              FormField.getField(comp).each(Disabling.disable);
17882
            },
17883
            onEnabled: comp => {
17884
              FormField.getField(comp).each(Disabling.enable);
17885
            }
17886
          }),
1441 ariadna 17887
          toggleOnReceive(() => providersBackstage.checkUiComponentContext(spec.context))
1 efrain 17888
        ])
17889
      });
17890
    };
17891
 
17892
    const schema$h = constant$1([
17893
      defaulted('field1Name', 'field1'),
17894
      defaulted('field2Name', 'field2'),
17895
      onStrictHandler('onLockedChange'),
17896
      markers$1(['lockClass']),
17897
      defaulted('locked', false),
17898
      SketchBehaviours.field('coupledFieldBehaviours', [
17899
        Composing,
17900
        Representing
1441 ariadna 17901
      ]),
17902
      defaultedFunction('onInput', noop)
1 efrain 17903
    ]);
17904
    const getField = (comp, detail, partName) => getPart(comp, detail, partName).bind(Composing.getCurrent);
17905
    const coupledPart = (selfName, otherName) => required({
17906
      factory: FormField,
17907
      name: selfName,
17908
      overrides: detail => {
17909
        return {
17910
          fieldBehaviours: derive$1([config('coupled-input-behaviour', [run$1(input(), me => {
17911
                getField(me, detail, otherName).each(other => {
17912
                  getPart(me, detail, 'lock').each(lock => {
17913
                    if (Toggling.isOn(lock)) {
17914
                      detail.onLockedChange(me, other, lock);
17915
                    }
1441 ariadna 17916
                    detail.onInput(me);
1 efrain 17917
                  });
17918
                });
17919
              })])])
17920
        };
17921
      }
17922
    });
17923
    const parts$c = constant$1([
17924
      coupledPart('field1', 'field2'),
17925
      coupledPart('field2', 'field1'),
17926
      required({
17927
        factory: Button,
17928
        schema: [required$1('dom')],
17929
        name: 'lock',
17930
        overrides: detail => {
17931
          return {
17932
            buttonBehaviours: derive$1([Toggling.config({
17933
                selected: detail.locked,
17934
                toggleClass: detail.markers.lockClass,
17935
                aria: { mode: 'pressed' }
17936
              })])
17937
          };
17938
        }
17939
      })
17940
    ]);
17941
 
17942
    const factory$g = (detail, components, _spec, _externals) => ({
17943
      uid: detail.uid,
17944
      dom: detail.dom,
17945
      components,
17946
      behaviours: SketchBehaviours.augment(detail.coupledFieldBehaviours, [
17947
        Composing.config({ find: Optional.some }),
17948
        Representing.config({
17949
          store: {
17950
            mode: 'manual',
17951
            getValue: comp => {
17952
              const parts = getPartsOrDie(comp, detail, [
17953
                'field1',
17954
                'field2'
17955
              ]);
17956
              return {
17957
                [detail.field1Name]: Representing.getValue(parts.field1()),
17958
                [detail.field2Name]: Representing.getValue(parts.field2())
17959
              };
17960
            },
17961
            setValue: (comp, value) => {
17962
              const parts = getPartsOrDie(comp, detail, [
17963
                'field1',
17964
                'field2'
17965
              ]);
17966
              if (hasNonNullableKey(value, detail.field1Name)) {
17967
                Representing.setValue(parts.field1(), value[detail.field1Name]);
17968
              }
17969
              if (hasNonNullableKey(value, detail.field2Name)) {
17970
                Representing.setValue(parts.field2(), value[detail.field2Name]);
17971
              }
17972
            }
17973
          }
17974
        })
17975
      ]),
17976
      apis: {
17977
        getField1: component => getPart(component, detail, 'field1'),
17978
        getField2: component => getPart(component, detail, 'field2'),
17979
        getLock: component => getPart(component, detail, 'lock')
17980
      }
17981
    });
17982
    const FormCoupledInputs = composite({
17983
      name: 'FormCoupledInputs',
17984
      configFields: schema$h(),
17985
      partFields: parts$c(),
17986
      factory: factory$g,
17987
      apis: {
17988
        getField1: (apis, component) => apis.getField1(component),
17989
        getField2: (apis, component) => apis.getField2(component),
17990
        getLock: (apis, component) => apis.getLock(component)
17991
      }
17992
    });
17993
 
17994
    const formatSize = size => {
17995
      const unitDec = {
17996
        '': 0,
17997
        'px': 0,
17998
        'pt': 1,
17999
        'mm': 1,
18000
        'pc': 2,
18001
        'ex': 2,
18002
        'em': 2,
18003
        'ch': 2,
18004
        'rem': 2,
18005
        'cm': 3,
18006
        'in': 4,
18007
        '%': 4
18008
      };
18009
      const maxDecimal = unit => unit in unitDec ? unitDec[unit] : 1;
18010
      let numText = size.value.toFixed(maxDecimal(size.unit));
18011
      if (numText.indexOf('.') !== -1) {
18012
        numText = numText.replace(/\.?0*$/, '');
18013
      }
18014
      return numText + size.unit;
18015
    };
18016
    const parseSize = sizeText => {
18017
      const numPattern = /^\s*(\d+(?:\.\d+)?)\s*(|cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax|%)\s*$/;
18018
      const match = numPattern.exec(sizeText);
18019
      if (match !== null) {
18020
        const value = parseFloat(match[1]);
18021
        const unit = match[2];
18022
        return Result.value({
18023
          value,
18024
          unit
18025
        });
18026
      } else {
18027
        return Result.error(sizeText);
18028
      }
18029
    };
18030
    const convertUnit = (size, unit) => {
18031
      const inInch = {
18032
        '': 96,
18033
        'px': 96,
18034
        'pt': 72,
18035
        'cm': 2.54,
18036
        'pc': 12,
18037
        'mm': 25.4,
18038
        'in': 1
18039
      };
18040
      const supported = u => has$2(inInch, u);
18041
      if (size.unit === unit) {
18042
        return Optional.some(size.value);
18043
      } else if (supported(size.unit) && supported(unit)) {
18044
        if (inInch[size.unit] === inInch[unit]) {
18045
          return Optional.some(size.value);
18046
        } else {
18047
          return Optional.some(size.value / inInch[size.unit] * inInch[unit]);
18048
        }
18049
      } else {
18050
        return Optional.none();
18051
      }
18052
    };
18053
    const noSizeConversion = _input => Optional.none();
18054
    const ratioSizeConversion = (scale, unit) => size => convertUnit(size, unit).map(value => ({
18055
      value: value * scale,
18056
      unit
18057
    }));
18058
    const makeRatioConverter = (currentFieldText, otherFieldText) => {
18059
      const cValue = parseSize(currentFieldText).toOptional();
18060
      const oValue = parseSize(otherFieldText).toOptional();
18061
      return lift2(cValue, oValue, (cSize, oSize) => convertUnit(cSize, oSize.unit).map(val => oSize.value / val).map(r => ratioSizeConversion(r, oSize.unit)).getOr(noSizeConversion)).getOr(noSizeConversion);
18062
    };
18063
 
18064
    const renderSizeInput = (spec, providersBackstage) => {
18065
      let converter = noSizeConversion;
18066
      const ratioEvent = generate$6('ratio-event');
18067
      const makeIcon = iconName => render$3(iconName, {
18068
        tag: 'span',
18069
        classes: [
18070
          'tox-icon',
18071
          'tox-lock-icon__' + iconName
18072
        ]
18073
      }, providersBackstage.icons);
1441 ariadna 18074
      const disabled = () => !spec.enabled || providersBackstage.checkUiComponentContext(spec.context).shouldDisable;
18075
      const toggleOnReceive$1 = toggleOnReceive(() => providersBackstage.checkUiComponentContext(spec.context));
18076
      const label = spec.label.getOr('Constrain proportions');
18077
      const translatedLabel = providersBackstage.translate(label);
1 efrain 18078
      const pLock = FormCoupledInputs.parts.lock({
18079
        dom: {
18080
          tag: 'button',
18081
          classes: [
18082
            'tox-lock',
18083
            'tox-button',
18084
            'tox-button--naked',
18085
            'tox-button--icon'
18086
          ],
1441 ariadna 18087
          attributes: {
18088
            'aria-label': translatedLabel,
18089
            'data-mce-name': label
18090
          }
1 efrain 18091
        },
18092
        components: [
18093
          makeIcon('lock'),
18094
          makeIcon('unlock')
18095
        ],
18096
        buttonBehaviours: derive$1([
1441 ariadna 18097
          Disabling.config({ disabled }),
18098
          toggleOnReceive$1,
18099
          Tabstopping.config({}),
18100
          Tooltipping.config(providersBackstage.tooltips.getConfig({ tooltipText: translatedLabel }))
1 efrain 18101
        ])
18102
      });
18103
      const formGroup = components => ({
18104
        dom: {
18105
          tag: 'div',
18106
          classes: ['tox-form__group']
18107
        },
18108
        components
18109
      });
18110
      const getFieldPart = isField1 => FormField.parts.field({
18111
        factory: Input,
18112
        inputClasses: ['tox-textfield'],
18113
        inputBehaviours: derive$1([
1441 ariadna 18114
          Disabling.config({ disabled }),
18115
          toggleOnReceive$1,
1 efrain 18116
          Tabstopping.config({}),
18117
          config('size-input-events', [
18118
            run$1(focusin(), (component, _simulatedEvent) => {
18119
              emitWith(component, ratioEvent, { isField1 });
18120
            }),
18121
            run$1(change(), (component, _simulatedEvent) => {
18122
              emitWith(component, formChangeEvent, { name: spec.name });
18123
            })
18124
          ])
18125
        ]),
18126
        selectOnFocus: false
18127
      });
18128
      const getLabel = label => ({
18129
        dom: {
18130
          tag: 'label',
18131
          classes: ['tox-label']
18132
        },
18133
        components: [text$2(providersBackstage.translate(label))]
18134
      });
18135
      const widthField = FormCoupledInputs.parts.field1(formGroup([
18136
        FormField.parts.label(getLabel('Width')),
18137
        getFieldPart(true)
18138
      ]));
18139
      const heightField = FormCoupledInputs.parts.field2(formGroup([
18140
        FormField.parts.label(getLabel('Height')),
18141
        getFieldPart(false)
18142
      ]));
18143
      return FormCoupledInputs.sketch({
18144
        dom: {
18145
          tag: 'div',
18146
          classes: ['tox-form__group']
18147
        },
18148
        components: [{
18149
            dom: {
18150
              tag: 'div',
18151
              classes: ['tox-form__controls-h-stack']
18152
            },
18153
            components: [
18154
              widthField,
18155
              heightField,
18156
              formGroup([
18157
                getLabel(nbsp),
18158
                pLock
18159
              ])
18160
            ]
18161
          }],
18162
        field1Name: 'width',
18163
        field2Name: 'height',
18164
        locked: true,
18165
        markers: { lockClass: 'tox-locked' },
18166
        onLockedChange: (current, other, _lock) => {
18167
          parseSize(Representing.getValue(current)).each(size => {
18168
            converter(size).each(newSize => {
18169
              Representing.setValue(other, formatSize(newSize));
18170
            });
18171
          });
18172
        },
18173
        coupledFieldBehaviours: derive$1([
18174
          Disabling.config({
1441 ariadna 18175
            disabled,
1 efrain 18176
            onDisabled: comp => {
18177
              FormCoupledInputs.getField1(comp).bind(FormField.getField).each(Disabling.disable);
18178
              FormCoupledInputs.getField2(comp).bind(FormField.getField).each(Disabling.disable);
18179
              FormCoupledInputs.getLock(comp).each(Disabling.disable);
18180
            },
18181
            onEnabled: comp => {
18182
              FormCoupledInputs.getField1(comp).bind(FormField.getField).each(Disabling.enable);
18183
              FormCoupledInputs.getField2(comp).bind(FormField.getField).each(Disabling.enable);
18184
              FormCoupledInputs.getLock(comp).each(Disabling.enable);
18185
            }
18186
          }),
1441 ariadna 18187
          toggleOnReceive(() => providersBackstage.checkUiComponentContext('mode:design')),
1 efrain 18188
          config('size-input-events2', [run$1(ratioEvent, (component, simulatedEvent) => {
18189
              const isField1 = simulatedEvent.event.isField1;
18190
              const optCurrent = isField1 ? FormCoupledInputs.getField1(component) : FormCoupledInputs.getField2(component);
18191
              const optOther = isField1 ? FormCoupledInputs.getField2(component) : FormCoupledInputs.getField1(component);
18192
              const value1 = optCurrent.map(Representing.getValue).getOr('');
18193
              const value2 = optOther.map(Representing.getValue).getOr('');
18194
              converter = makeRatioConverter(value1, value2);
18195
            })])
18196
        ])
18197
      });
18198
    };
18199
 
18200
    const renderSlider = (spec, providerBackstage, initialData) => {
18201
      const labelPart = Slider.parts.label({
18202
        dom: {
18203
          tag: 'label',
18204
          classes: ['tox-label']
18205
        },
18206
        components: [text$2(providerBackstage.translate(spec.label))]
18207
      });
18208
      const spectrum = Slider.parts.spectrum({
18209
        dom: {
18210
          tag: 'div',
18211
          classes: ['tox-slider__rail'],
18212
          attributes: { role: 'presentation' }
18213
        }
18214
      });
18215
      const thumb = Slider.parts.thumb({
18216
        dom: {
18217
          tag: 'div',
18218
          classes: ['tox-slider__handle'],
18219
          attributes: { role: 'presentation' }
18220
        }
18221
      });
18222
      return Slider.sketch({
18223
        dom: {
18224
          tag: 'div',
18225
          classes: ['tox-slider'],
18226
          attributes: { role: 'presentation' }
18227
        },
18228
        model: {
18229
          mode: 'x',
18230
          minX: spec.min,
18231
          maxX: spec.max,
18232
          getInitialValue: constant$1(initialData.getOrThunk(() => (Math.abs(spec.max) - Math.abs(spec.min)) / 2))
18233
        },
18234
        components: [
18235
          labelPart,
18236
          spectrum,
18237
          thumb
18238
        ],
18239
        sliderBehaviours: derive$1([
18240
          ComposingConfigs.self(),
18241
          Focusing.config({})
18242
        ]),
18243
        onChoose: (component, thumb, value) => {
18244
          emitWith(component, formChangeEvent, {
18245
            name: spec.name,
18246
            value
18247
          });
1441 ariadna 18248
        },
18249
        onChange: (component, thumb, value) => {
18250
          emitWith(component, formChangeEvent, {
18251
            name: spec.name,
18252
            value
18253
          });
1 efrain 18254
        }
18255
      });
18256
    };
18257
 
18258
    const renderTable = (spec, providersBackstage) => {
18259
      const renderTh = text => ({
18260
        dom: {
18261
          tag: 'th',
18262
          innerHtml: providersBackstage.translate(text)
18263
        }
18264
      });
18265
      const renderHeader = header => ({
18266
        dom: { tag: 'thead' },
18267
        components: [{
18268
            dom: { tag: 'tr' },
18269
            components: map$2(header, renderTh)
18270
          }]
18271
      });
18272
      const renderTd = text => ({
18273
        dom: {
18274
          tag: 'td',
18275
          innerHtml: providersBackstage.translate(text)
18276
        }
18277
      });
18278
      const renderTr = row => ({
18279
        dom: { tag: 'tr' },
18280
        components: map$2(row, renderTd)
18281
      });
18282
      const renderRows = rows => ({
18283
        dom: { tag: 'tbody' },
18284
        components: map$2(rows, renderTr)
18285
      });
18286
      return {
18287
        dom: {
18288
          tag: 'table',
18289
          classes: ['tox-dialog__table']
18290
        },
18291
        components: [
18292
          renderHeader(spec.header),
18293
          renderRows(spec.cells)
18294
        ],
18295
        behaviours: derive$1([
18296
          Tabstopping.config({}),
18297
          Focusing.config({})
18298
        ])
18299
      };
18300
    };
18301
 
18302
    const renderTextField = (spec, providersBackstage) => {
18303
      const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
18304
      const baseInputBehaviours = [
1441 ariadna 18305
        Disabling.config({ disabled: () => spec.disabled || providersBackstage.checkUiComponentContext(spec.context).shouldDisable }),
18306
        toggleOnReceive(() => providersBackstage.checkUiComponentContext(spec.context)),
1 efrain 18307
        Keying.config({
18308
          mode: 'execution',
18309
          useEnter: spec.multiline !== true,
18310
          useControlEnter: spec.multiline === true,
18311
          execute: comp => {
18312
            emit(comp, formSubmitEvent);
18313
            return Optional.some(true);
18314
          }
18315
        }),
18316
        config('textfield-change', [
18317
          run$1(input(), (component, _) => {
18318
            emitWith(component, formChangeEvent, { name: spec.name });
18319
          }),
18320
          run$1(postPaste(), (component, _) => {
18321
            emitWith(component, formChangeEvent, { name: spec.name });
18322
          })
18323
        ]),
18324
        Tabstopping.config({})
18325
      ];
18326
      const validatingBehaviours = spec.validation.map(vl => Invalidating.config({
18327
        getRoot: input => {
18328
          return parentElement(input.element);
18329
        },
18330
        invalidClass: 'tox-invalid',
18331
        validator: {
18332
          validate: input => {
18333
            const v = Representing.getValue(input);
18334
            const result = vl.validator(v);
18335
            return Future.pure(result === true ? Result.value(v) : Result.error(result));
18336
          },
18337
          validateOnLoad: vl.validateOnLoad
18338
        }
18339
      })).toArray();
18340
      const placeholder = spec.placeholder.fold(constant$1({}), p => ({ placeholder: providersBackstage.translate(p) }));
18341
      const inputMode = spec.inputMode.fold(constant$1({}), mode => ({ inputmode: mode }));
18342
      const inputAttributes = {
18343
        ...placeholder,
1441 ariadna 18344
        ...inputMode,
18345
        'data-mce-name': spec.name
1 efrain 18346
      };
18347
      const pField = FormField.parts.field({
18348
        tag: spec.multiline === true ? 'textarea' : 'input',
18349
        ...spec.data.map(data => ({ data })).getOr({}),
18350
        inputAttributes,
18351
        inputClasses: [spec.classname],
18352
        inputBehaviours: derive$1(flatten([
18353
          baseInputBehaviours,
18354
          validatingBehaviours
18355
        ])),
18356
        selectOnFocus: false,
18357
        factory: Input
18358
      });
18359
      const pTextField = spec.multiline ? {
18360
        dom: {
18361
          tag: 'div',
18362
          classes: ['tox-textarea-wrap']
18363
        },
18364
        components: [pField]
18365
      } : pField;
18366
      const extraClasses = spec.flex ? ['tox-form__group--stretched'] : [];
18367
      const extraClasses2 = extraClasses.concat(spec.maximized ? ['tox-form-group--maximize'] : []);
18368
      const extraBehaviours = [
18369
        Disabling.config({
1441 ariadna 18370
          disabled: () => spec.disabled || providersBackstage.checkUiComponentContext(spec.context).shouldDisable,
1 efrain 18371
          onDisabled: comp => {
18372
            FormField.getField(comp).each(Disabling.disable);
18373
          },
18374
          onEnabled: comp => {
18375
            FormField.getField(comp).each(Disabling.enable);
18376
          }
18377
        }),
1441 ariadna 18378
        toggleOnReceive(() => providersBackstage.checkUiComponentContext(spec.context))
1 efrain 18379
      ];
18380
      return renderFormFieldWith(pLabel, pTextField, extraClasses2, extraBehaviours);
18381
    };
18382
    const renderInput = (spec, providersBackstage, initialData) => renderTextField({
18383
      name: spec.name,
18384
      multiline: false,
18385
      label: spec.label,
18386
      inputMode: spec.inputMode,
18387
      placeholder: spec.placeholder,
18388
      flex: false,
18389
      disabled: !spec.enabled,
18390
      classname: 'tox-textfield',
18391
      validation: Optional.none(),
18392
      maximized: spec.maximized,
1441 ariadna 18393
      data: initialData,
18394
      context: spec.context
1 efrain 18395
    }, providersBackstage);
18396
    const renderTextarea = (spec, providersBackstage, initialData) => renderTextField({
18397
      name: spec.name,
18398
      multiline: true,
18399
      label: spec.label,
18400
      inputMode: Optional.none(),
18401
      placeholder: spec.placeholder,
18402
      flex: true,
18403
      disabled: !spec.enabled,
18404
      classname: 'tox-textarea',
18405
      validation: Optional.none(),
18406
      maximized: spec.maximized,
1441 ariadna 18407
      data: initialData,
18408
      context: spec.context
1 efrain 18409
    }, providersBackstage);
18410
 
18411
    const getAnimationRoot = (component, slideConfig) => slideConfig.getAnimationRoot.fold(() => component.element, get => get(component));
18412
 
18413
    const getDimensionProperty = slideConfig => slideConfig.dimension.property;
18414
    const getDimension = (slideConfig, elem) => slideConfig.dimension.getDimension(elem);
18415
    const disableTransitions = (component, slideConfig) => {
18416
      const root = getAnimationRoot(component, slideConfig);
1441 ariadna 18417
      remove$2(root, [
1 efrain 18418
        slideConfig.shrinkingClass,
18419
        slideConfig.growingClass
18420
      ]);
18421
    };
18422
    const setShrunk = (component, slideConfig) => {
1441 ariadna 18423
      remove$3(component.element, slideConfig.openClass);
1 efrain 18424
      add$2(component.element, slideConfig.closedClass);
18425
      set$8(component.element, getDimensionProperty(slideConfig), '0px');
18426
      reflow(component.element);
18427
    };
18428
    const setGrown = (component, slideConfig) => {
1441 ariadna 18429
      remove$3(component.element, slideConfig.closedClass);
1 efrain 18430
      add$2(component.element, slideConfig.openClass);
1441 ariadna 18431
      remove$7(component.element, getDimensionProperty(slideConfig));
1 efrain 18432
    };
18433
    const doImmediateShrink = (component, slideConfig, slideState, _calculatedSize) => {
18434
      slideState.setCollapsed();
18435
      set$8(component.element, getDimensionProperty(slideConfig), getDimension(slideConfig, component.element));
18436
      disableTransitions(component, slideConfig);
18437
      setShrunk(component, slideConfig);
18438
      slideConfig.onStartShrink(component);
18439
      slideConfig.onShrunk(component);
18440
    };
18441
    const doStartShrink = (component, slideConfig, slideState, calculatedSize) => {
18442
      const size = calculatedSize.getOrThunk(() => getDimension(slideConfig, component.element));
18443
      slideState.setCollapsed();
18444
      set$8(component.element, getDimensionProperty(slideConfig), size);
18445
      reflow(component.element);
18446
      const root = getAnimationRoot(component, slideConfig);
1441 ariadna 18447
      remove$3(root, slideConfig.growingClass);
1 efrain 18448
      add$2(root, slideConfig.shrinkingClass);
18449
      setShrunk(component, slideConfig);
18450
      slideConfig.onStartShrink(component);
18451
    };
18452
    const doStartSmartShrink = (component, slideConfig, slideState) => {
18453
      const size = getDimension(slideConfig, component.element);
18454
      const shrinker = size === '0px' ? doImmediateShrink : doStartShrink;
18455
      shrinker(component, slideConfig, slideState, Optional.some(size));
18456
    };
18457
    const doStartGrow = (component, slideConfig, slideState) => {
18458
      const root = getAnimationRoot(component, slideConfig);
18459
      const wasShrinking = has(root, slideConfig.shrinkingClass);
18460
      const beforeSize = getDimension(slideConfig, component.element);
18461
      setGrown(component, slideConfig);
18462
      const fullSize = getDimension(slideConfig, component.element);
18463
      const startPartialGrow = () => {
18464
        set$8(component.element, getDimensionProperty(slideConfig), beforeSize);
18465
        reflow(component.element);
18466
      };
18467
      const startCompleteGrow = () => {
18468
        setShrunk(component, slideConfig);
18469
      };
18470
      const setStartSize = wasShrinking ? startPartialGrow : startCompleteGrow;
18471
      setStartSize();
1441 ariadna 18472
      remove$3(root, slideConfig.shrinkingClass);
1 efrain 18473
      add$2(root, slideConfig.growingClass);
18474
      setGrown(component, slideConfig);
18475
      set$8(component.element, getDimensionProperty(slideConfig), fullSize);
18476
      slideState.setExpanded();
18477
      slideConfig.onStartGrow(component);
18478
    };
1441 ariadna 18479
    const refresh$3 = (component, slideConfig, slideState) => {
1 efrain 18480
      if (slideState.isExpanded()) {
1441 ariadna 18481
        remove$7(component.element, getDimensionProperty(slideConfig));
1 efrain 18482
        const fullSize = getDimension(slideConfig, component.element);
18483
        set$8(component.element, getDimensionProperty(slideConfig), fullSize);
18484
      }
18485
    };
18486
    const grow = (component, slideConfig, slideState) => {
18487
      if (!slideState.isExpanded()) {
18488
        doStartGrow(component, slideConfig, slideState);
18489
      }
18490
    };
18491
    const shrink = (component, slideConfig, slideState) => {
18492
      if (slideState.isExpanded()) {
18493
        doStartSmartShrink(component, slideConfig, slideState);
18494
      }
18495
    };
18496
    const immediateShrink = (component, slideConfig, slideState) => {
18497
      if (slideState.isExpanded()) {
18498
        doImmediateShrink(component, slideConfig, slideState);
18499
      }
18500
    };
18501
    const hasGrown = (component, slideConfig, slideState) => slideState.isExpanded();
18502
    const hasShrunk = (component, slideConfig, slideState) => slideState.isCollapsed();
18503
    const isGrowing = (component, slideConfig, _slideState) => {
18504
      const root = getAnimationRoot(component, slideConfig);
18505
      return has(root, slideConfig.growingClass) === true;
18506
    };
18507
    const isShrinking = (component, slideConfig, _slideState) => {
18508
      const root = getAnimationRoot(component, slideConfig);
18509
      return has(root, slideConfig.shrinkingClass) === true;
18510
    };
18511
    const isTransitioning = (component, slideConfig, slideState) => isGrowing(component, slideConfig) || isShrinking(component, slideConfig);
18512
    const toggleGrow = (component, slideConfig, slideState) => {
18513
      const f = slideState.isExpanded() ? doStartSmartShrink : doStartGrow;
18514
      f(component, slideConfig, slideState);
18515
    };
18516
    const immediateGrow = (component, slideConfig, slideState) => {
18517
      if (!slideState.isExpanded()) {
18518
        setGrown(component, slideConfig);
18519
        set$8(component.element, getDimensionProperty(slideConfig), getDimension(slideConfig, component.element));
18520
        disableTransitions(component, slideConfig);
18521
        slideState.setExpanded();
18522
        slideConfig.onStartGrow(component);
18523
        slideConfig.onGrown(component);
18524
      }
18525
    };
18526
 
18527
    var SlidingApis = /*#__PURE__*/Object.freeze({
18528
        __proto__: null,
1441 ariadna 18529
        refresh: refresh$3,
1 efrain 18530
        grow: grow,
18531
        shrink: shrink,
18532
        immediateShrink: immediateShrink,
18533
        hasGrown: hasGrown,
18534
        hasShrunk: hasShrunk,
18535
        isGrowing: isGrowing,
18536
        isShrinking: isShrinking,
18537
        isTransitioning: isTransitioning,
18538
        toggleGrow: toggleGrow,
18539
        disableTransitions: disableTransitions,
18540
        immediateGrow: immediateGrow
18541
    });
18542
 
18543
    const exhibit = (base, slideConfig, _slideState) => {
18544
      const expanded = slideConfig.expanded;
1441 ariadna 18545
      return expanded ? nu$8({
1 efrain 18546
        classes: [slideConfig.openClass],
18547
        styles: {}
1441 ariadna 18548
      }) : nu$8({
1 efrain 18549
        classes: [slideConfig.closedClass],
18550
        styles: wrap$1(slideConfig.dimension.property, '0px')
18551
      });
18552
    };
1441 ariadna 18553
    const events$5 = (slideConfig, slideState) => derive$2([runOnSource(transitionend(), (component, simulatedEvent) => {
1 efrain 18554
        const raw = simulatedEvent.event.raw;
18555
        if (raw.propertyName === slideConfig.dimension.property) {
18556
          disableTransitions(component, slideConfig);
18557
          if (slideState.isExpanded()) {
1441 ariadna 18558
            remove$7(component.element, slideConfig.dimension.property);
1 efrain 18559
          }
18560
          const notify = slideState.isExpanded() ? slideConfig.onGrown : slideConfig.onShrunk;
18561
          notify(component);
18562
        }
18563
      })]);
18564
 
18565
    var ActiveSliding = /*#__PURE__*/Object.freeze({
18566
        __proto__: null,
18567
        exhibit: exhibit,
1441 ariadna 18568
        events: events$5
1 efrain 18569
    });
18570
 
18571
    var SlidingSchema = [
18572
      required$1('closedClass'),
18573
      required$1('openClass'),
18574
      required$1('shrinkingClass'),
18575
      required$1('growingClass'),
18576
      option$3('getAnimationRoot'),
18577
      onHandler('onShrunk'),
18578
      onHandler('onStartShrink'),
18579
      onHandler('onGrown'),
18580
      onHandler('onStartGrow'),
18581
      defaulted('expanded', false),
18582
      requiredOf('dimension', choose$1('property', {
18583
        width: [
18584
          output$1('property', 'width'),
1441 ariadna 18585
          output$1('getDimension', elem => get$d(elem) + 'px')
1 efrain 18586
        ],
18587
        height: [
18588
          output$1('property', 'height'),
1441 ariadna 18589
          output$1('getDimension', elem => get$e(elem) + 'px')
1 efrain 18590
        ]
18591
      }))
18592
    ];
18593
 
1441 ariadna 18594
    const init$8 = spec => {
1 efrain 18595
      const state = Cell(spec.expanded);
18596
      const readState = () => 'expanded: ' + state.get();
1441 ariadna 18597
      return nu$7({
1 efrain 18598
        isExpanded: () => state.get() === true,
18599
        isCollapsed: () => state.get() === false,
18600
        setCollapsed: curry(state.set, false),
18601
        setExpanded: curry(state.set, true),
18602
        readState
18603
      });
18604
    };
18605
 
18606
    var SlidingState = /*#__PURE__*/Object.freeze({
18607
        __proto__: null,
1441 ariadna 18608
        init: init$8
1 efrain 18609
    });
18610
 
18611
    const Sliding = create$4({
18612
      fields: SlidingSchema,
18613
      name: 'sliding',
18614
      active: ActiveSliding,
18615
      apis: SlidingApis,
18616
      state: SlidingState
18617
    });
18618
 
18619
    const getMenuButtonApi = component => ({
18620
      isEnabled: () => !Disabling.isDisabled(component),
18621
      setEnabled: state => Disabling.set(component, !state),
18622
      setActive: state => {
18623
        const elm = component.element;
18624
        if (state) {
18625
          add$2(elm, 'tox-tbtn--enabled');
18626
          set$9(elm, 'aria-pressed', true);
18627
        } else {
1441 ariadna 18628
          remove$3(elm, 'tox-tbtn--enabled');
18629
          remove$8(elm, 'aria-pressed');
1 efrain 18630
        }
18631
      },
18632
      isActive: () => has(component.element, 'tox-tbtn--enabled'),
18633
      setText: text => {
18634
        emitWith(component, updateMenuText, { text });
18635
      },
18636
      setIcon: icon => emitWith(component, updateMenuIcon, { icon })
18637
    });
1441 ariadna 18638
    const renderMenuButton = (spec, prefix, backstage, role, tabstopping = true, btnName) => {
1 efrain 18639
      return renderCommonDropdown({
18640
        text: spec.text,
18641
        icon: spec.icon,
18642
        tooltip: spec.tooltip,
1441 ariadna 18643
        ariaLabel: spec.tooltip,
1 efrain 18644
        searchable: spec.search.isSome(),
18645
        role,
18646
        fetch: (dropdownComp, callback) => {
18647
          const fetchContext = { pattern: spec.search.isSome() ? getSearchPattern(dropdownComp) : '' };
18648
          spec.fetch(items => {
18649
            callback(build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
18650
              isHorizontalMenu: false,
18651
              search: spec.search
18652
            }));
18653
          }, fetchContext, getMenuButtonApi(dropdownComp));
18654
        },
18655
        onSetup: spec.onSetup,
18656
        getApi: getMenuButtonApi,
18657
        columns: 1,
18658
        presets: 'normal',
18659
        classes: [],
1441 ariadna 18660
        dropdownBehaviours: [...tabstopping ? [Tabstopping.config({})] : []],
18661
        context: spec.context
18662
      }, prefix, backstage.shared, btnName);
1 efrain 18663
    };
18664
    const getFetch = (items, getButton, backstage) => {
18665
      const getMenuItemAction = item => api => {
18666
        const newValue = !api.isActive();
18667
        api.setActive(newValue);
18668
        item.storage.set(newValue);
18669
        backstage.shared.getSink().each(sink => {
18670
          getButton().getOpt(sink).each(orig => {
18671
            focus$3(orig.element);
18672
            emitWith(orig, formActionEvent, {
18673
              name: item.name,
18674
              value: item.storage.get()
18675
            });
18676
          });
18677
        });
18678
      };
18679
      const getMenuItemSetup = item => api => {
18680
        api.setActive(item.storage.get());
18681
      };
18682
      return success => {
18683
        success(map$2(items, item => {
18684
          const text = item.text.fold(() => ({}), text => ({ text }));
18685
          return {
18686
            type: item.type,
18687
            active: false,
18688
            ...text,
1441 ariadna 18689
            context: item.context,
1 efrain 18690
            onAction: getMenuItemAction(item),
18691
            onSetup: getMenuItemSetup(item)
18692
          };
18693
        }));
18694
      };
18695
    };
18696
 
18697
    const renderLabel = text => ({
18698
      dom: {
18699
        tag: 'span',
18700
        classes: ['tox-tree__label'],
1441 ariadna 18701
        attributes: { 'aria-label': text }
1 efrain 18702
      },
18703
      components: [text$2(text)]
18704
    });
1441 ariadna 18705
    const renderCustomStateIcon = (container, components, backstage) => {
18706
      container.customStateIcon.each(icon => components.push(renderIcon(icon, backstage.shared.providers.icons, container.customStateIconTooltip.fold(() => [], tooltip => [Tooltipping.config(backstage.shared.providers.tooltips.getConfig({ tooltipText: tooltip }))]), ['tox-icon-custom-state'])));
18707
    };
1 efrain 18708
    const leafLabelEventsId = generate$6('leaf-label-event-id');
18709
    const renderLeafLabel = ({leaf, onLeafAction, visible, treeId, selectedId, backstage}) => {
18710
      const internalMenuButton = leaf.menu.map(btn => renderMenuButton(btn, 'tox-mbtn', backstage, Optional.none(), visible));
18711
      const components = [renderLabel(leaf.title)];
1441 ariadna 18712
      renderCustomStateIcon(leaf, components, backstage);
1 efrain 18713
      internalMenuButton.each(btn => components.push(btn));
18714
      return Button.sketch({
18715
        dom: {
18716
          tag: 'div',
18717
          classes: [
18718
            'tox-tree--leaf__label',
18719
            'tox-trbtn'
18720
          ].concat(visible ? ['tox-tree--leaf__label--visible'] : [])
18721
        },
18722
        components,
18723
        role: 'treeitem',
18724
        action: button => {
18725
          onLeafAction(leaf.id);
18726
          button.getSystem().broadcastOn([`update-active-item-${ treeId }`], { value: leaf.id });
18727
        },
18728
        eventOrder: {
18729
          [keydown()]: [
18730
            leafLabelEventsId,
18731
            'keying'
18732
          ]
18733
        },
18734
        buttonBehaviours: derive$1([
18735
          ...visible ? [Tabstopping.config({})] : [],
18736
          Toggling.config({
18737
            toggleClass: 'tox-trbtn--enabled',
18738
            toggleOnExecute: false,
18739
            aria: { mode: 'selected' }
18740
          }),
18741
          Receiving.config({
18742
            channels: {
18743
              [`update-active-item-${ treeId }`]: {
18744
                onReceive: (comp, message) => {
18745
                  (message.value === leaf.id ? Toggling.on : Toggling.off)(comp);
18746
                }
18747
              }
18748
            }
18749
          }),
18750
          config(leafLabelEventsId, [
18751
            runOnAttached((comp, _se) => {
18752
              selectedId.each(id => {
18753
                const toggle = id === leaf.id ? Toggling.on : Toggling.off;
18754
                toggle(comp);
18755
              });
18756
            }),
18757
            run$1(keydown(), (comp, se) => {
18758
              const isLeftArrowKey = se.event.raw.code === 'ArrowLeft';
18759
              const isRightArrowKey = se.event.raw.code === 'ArrowRight';
18760
              if (isLeftArrowKey) {
18761
                ancestor(comp.element, '.tox-tree--directory').each(dirElement => {
18762
                  comp.getSystem().getByDom(dirElement).each(dirComp => {
18763
                    child(dirElement, '.tox-tree--directory__label').each(dirLabelElement => {
18764
                      dirComp.getSystem().getByDom(dirLabelElement).each(Focusing.focus);
18765
                    });
18766
                  });
18767
                });
18768
                se.stop();
18769
              } else if (isRightArrowKey) {
18770
                se.stop();
18771
              }
18772
            })
18773
          ])
18774
        ])
18775
      });
18776
    };
1441 ariadna 18777
    const renderIcon = (iconName, iconsProvider, behaviours, extraClasses, extraAttributes) => render$3(iconName, {
1 efrain 18778
      tag: 'span',
18779
      classes: [
18780
        'tox-tree__icon-wrap',
18781
        'tox-icon'
1441 ariadna 18782
      ].concat(extraClasses || []),
18783
      behaviours,
18784
      attributes: extraAttributes
1 efrain 18785
    }, iconsProvider);
18786
    const renderIconFromPack = (iconName, iconsProvider) => renderIcon(iconName, iconsProvider, []);
18787
    const directoryLabelEventsId = generate$6('directory-label-event-id');
18788
    const renderDirectoryLabel = ({directory, visible, noChildren, backstage}) => {
18789
      const internalMenuButton = directory.menu.map(btn => renderMenuButton(btn, 'tox-mbtn', backstage, Optional.none()));
18790
      const components = [
18791
        {
18792
          dom: {
18793
            tag: 'div',
18794
            classes: ['tox-chevron']
18795
          },
18796
          components: [renderIconFromPack('chevron-right', backstage.shared.providers.icons)]
18797
        },
18798
        renderLabel(directory.title)
18799
      ];
1441 ariadna 18800
      renderCustomStateIcon(directory, components, backstage);
1 efrain 18801
      internalMenuButton.each(btn => {
18802
        components.push(btn);
18803
      });
18804
      const toggleExpandChildren = button => {
18805
        ancestor(button.element, '.tox-tree--directory').each(directoryEle => {
18806
          button.getSystem().getByDom(directoryEle).each(directoryComp => {
18807
            const willExpand = !Toggling.isOn(directoryComp);
18808
            Toggling.toggle(directoryComp);
18809
            emitWith(button, 'expand-tree-node', {
18810
              expanded: willExpand,
18811
              node: directory.id
18812
            });
18813
          });
18814
        });
18815
      };
18816
      return Button.sketch({
18817
        dom: {
18818
          tag: 'div',
18819
          classes: [
18820
            'tox-tree--directory__label',
18821
            'tox-trbtn'
18822
          ].concat(visible ? ['tox-tree--directory__label--visible'] : [])
18823
        },
18824
        components,
18825
        action: toggleExpandChildren,
18826
        eventOrder: {
18827
          [keydown()]: [
18828
            directoryLabelEventsId,
18829
            'keying'
18830
          ]
18831
        },
18832
        buttonBehaviours: derive$1([
18833
          ...visible ? [Tabstopping.config({})] : [],
18834
          config(directoryLabelEventsId, [run$1(keydown(), (comp, se) => {
18835
              const isRightArrowKey = se.event.raw.code === 'ArrowRight';
18836
              const isLeftArrowKey = se.event.raw.code === 'ArrowLeft';
18837
              if (isRightArrowKey && noChildren) {
18838
                se.stop();
18839
              }
18840
              if (isRightArrowKey || isLeftArrowKey) {
18841
                ancestor(comp.element, '.tox-tree--directory').each(directoryEle => {
18842
                  comp.getSystem().getByDom(directoryEle).each(directoryComp => {
18843
                    if (!Toggling.isOn(directoryComp) && isRightArrowKey || Toggling.isOn(directoryComp) && isLeftArrowKey) {
18844
                      toggleExpandChildren(comp);
18845
                      se.stop();
18846
                    } else if (isLeftArrowKey && !Toggling.isOn(directoryComp)) {
18847
                      ancestor(directoryComp.element, '.tox-tree--directory').each(parentDirElement => {
18848
                        child(parentDirElement, '.tox-tree--directory__label').each(parentDirLabelElement => {
18849
                          directoryComp.getSystem().getByDom(parentDirLabelElement).each(Focusing.focus);
18850
                        });
18851
                      });
18852
                      se.stop();
18853
                    }
18854
                  });
18855
                });
18856
              }
18857
            })])
18858
        ])
18859
      });
18860
    };
18861
    const renderDirectoryChildren = ({children, onLeafAction, visible, treeId, expandedIds, selectedId, backstage}) => {
18862
      return {
18863
        dom: {
18864
          tag: 'div',
18865
          classes: ['tox-tree--directory__children']
18866
        },
18867
        components: children.map(item => {
18868
          return item.type === 'leaf' ? renderLeafLabel({
18869
            leaf: item,
18870
            selectedId,
18871
            onLeafAction,
18872
            visible,
18873
            treeId,
18874
            backstage
18875
          }) : renderDirectory({
18876
            directory: item,
18877
            expandedIds,
18878
            selectedId,
18879
            onLeafAction,
18880
            labelTabstopping: visible,
18881
            treeId,
18882
            backstage
18883
          });
18884
        }),
18885
        behaviours: derive$1([
18886
          Sliding.config({
18887
            dimension: { property: 'height' },
18888
            closedClass: 'tox-tree--directory__children--closed',
18889
            openClass: 'tox-tree--directory__children--open',
18890
            growingClass: 'tox-tree--directory__children--growing',
18891
            shrinkingClass: 'tox-tree--directory__children--shrinking',
18892
            expanded: visible
18893
          }),
18894
          Replacing.config({})
18895
        ])
18896
      };
18897
    };
18898
    const directoryEventsId = generate$6('directory-event-id');
18899
    const renderDirectory = ({directory, onLeafAction, labelTabstopping, treeId, backstage, expandedIds, selectedId}) => {
18900
      const {children} = directory;
18901
      const expandedIdsCell = Cell(expandedIds);
18902
      const computedChildrenComponents = visible => children.map(item => {
18903
        return item.type === 'leaf' ? renderLeafLabel({
18904
          leaf: item,
18905
          selectedId,
18906
          onLeafAction,
18907
          visible,
18908
          treeId,
18909
          backstage
18910
        }) : renderDirectory({
18911
          directory: item,
18912
          expandedIds: expandedIdsCell.get(),
18913
          selectedId,
18914
          onLeafAction,
18915
          labelTabstopping: visible,
18916
          treeId,
18917
          backstage
18918
        });
18919
      });
18920
      const childrenVisible = expandedIds.includes(directory.id);
18921
      return {
18922
        dom: {
18923
          tag: 'div',
18924
          classes: ['tox-tree--directory'],
18925
          attributes: { role: 'treeitem' }
18926
        },
18927
        components: [
18928
          renderDirectoryLabel({
18929
            directory,
18930
            visible: labelTabstopping,
18931
            noChildren: directory.children.length === 0,
18932
            backstage
18933
          }),
18934
          renderDirectoryChildren({
18935
            children,
18936
            expandedIds,
18937
            selectedId,
18938
            onLeafAction,
18939
            visible: childrenVisible,
18940
            treeId,
18941
            backstage
18942
          })
18943
        ],
18944
        behaviours: derive$1([
18945
          config(directoryEventsId, [
18946
            runOnAttached((comp, _se) => {
18947
              Toggling.set(comp, childrenVisible);
18948
            }),
18949
            run$1('expand-tree-node', (_cmp, se) => {
18950
              const {expanded, node} = se.event;
18951
              expandedIdsCell.set(expanded ? [
18952
                ...expandedIdsCell.get(),
18953
                node
18954
              ] : expandedIdsCell.get().filter(id => id !== node));
18955
            })
18956
          ]),
18957
          Toggling.config({
18958
            ...directory.children.length > 0 ? { aria: { mode: 'expanded' } } : {},
18959
            toggleClass: 'tox-tree--directory--expanded',
18960
            onToggled: (comp, childrenVisible) => {
18961
              const childrenComp = comp.components()[1];
18962
              const newChildren = computedChildrenComponents(childrenVisible);
18963
              if (childrenVisible) {
18964
                Sliding.grow(childrenComp);
18965
              } else {
18966
                Sliding.shrink(childrenComp);
18967
              }
18968
              Replacing.set(childrenComp, newChildren);
18969
            }
18970
          })
18971
        ])
18972
      };
18973
    };
18974
    const treeEventsId = generate$6('tree-event-id');
18975
    const renderTree = (spec, backstage) => {
18976
      const onLeafAction = spec.onLeafAction.getOr(noop);
18977
      const onToggleExpand = spec.onToggleExpand.getOr(noop);
18978
      const defaultExpandedIds = spec.defaultExpandedIds;
18979
      const expandedIds = Cell(defaultExpandedIds);
18980
      const selectedIdCell = Cell(spec.defaultSelectedId);
18981
      const treeId = generate$6('tree-id');
18982
      const children = (selectedId, expandedIds) => spec.items.map(item => {
18983
        return item.type === 'leaf' ? renderLeafLabel({
18984
          leaf: item,
18985
          selectedId,
18986
          onLeafAction,
18987
          visible: true,
18988
          treeId,
18989
          backstage
18990
        }) : renderDirectory({
18991
          directory: item,
18992
          selectedId,
18993
          onLeafAction,
18994
          expandedIds,
18995
          labelTabstopping: true,
18996
          treeId,
18997
          backstage
18998
        });
18999
      });
19000
      return {
19001
        dom: {
19002
          tag: 'div',
19003
          classes: ['tox-tree'],
19004
          attributes: { role: 'tree' }
19005
        },
19006
        components: children(selectedIdCell.get(), expandedIds.get()),
19007
        behaviours: derive$1([
19008
          Keying.config({
19009
            mode: 'flow',
19010
            selector: '.tox-tree--leaf__label--visible, .tox-tree--directory__label--visible',
19011
            cycles: false
19012
          }),
19013
          config(treeEventsId, [run$1('expand-tree-node', (_cmp, se) => {
19014
              const {expanded, node} = se.event;
19015
              expandedIds.set(expanded ? [
19016
                ...expandedIds.get(),
19017
                node
19018
              ] : expandedIds.get().filter(id => id !== node));
19019
              onToggleExpand(expandedIds.get(), {
19020
                expanded,
19021
                node
19022
              });
19023
            })]),
19024
          Receiving.config({
19025
            channels: {
19026
              [`update-active-item-${ treeId }`]: {
19027
                onReceive: (comp, message) => {
19028
                  selectedIdCell.set(Optional.some(message.value));
19029
                  Replacing.set(comp, children(Optional.some(message.value), expandedIds.get()));
19030
                }
19031
              }
19032
            }
19033
          }),
19034
          Replacing.config({})
19035
        ])
19036
      };
19037
    };
19038
 
1441 ariadna 19039
    const events$4 = (streamConfig, streamState) => {
1 efrain 19040
      const streams = streamConfig.stream.streams;
19041
      const processor = streams.setup(streamConfig, streamState);
19042
      return derive$2([
19043
        run$1(streamConfig.event, processor),
19044
        runOnDetached(() => streamState.cancel())
19045
      ].concat(streamConfig.cancelEvent.map(e => [run$1(e, () => streamState.cancel())]).getOr([])));
19046
    };
19047
 
19048
    var ActiveStreaming = /*#__PURE__*/Object.freeze({
19049
        __proto__: null,
1441 ariadna 19050
        events: events$4
1 efrain 19051
    });
19052
 
19053
    const throttle = _config => {
19054
      const state = Cell(null);
19055
      const readState = () => ({ timer: state.get() !== null ? 'set' : 'unset' });
19056
      const setTimer = t => {
19057
        state.set(t);
19058
      };
19059
      const cancel = () => {
19060
        const t = state.get();
19061
        if (t !== null) {
19062
          t.cancel();
19063
        }
19064
      };
1441 ariadna 19065
      return nu$7({
1 efrain 19066
        readState,
19067
        setTimer,
19068
        cancel
19069
      });
19070
    };
1441 ariadna 19071
    const init$7 = spec => spec.stream.streams.state(spec);
1 efrain 19072
 
19073
    var StreamingState = /*#__PURE__*/Object.freeze({
19074
        __proto__: null,
19075
        throttle: throttle,
1441 ariadna 19076
        init: init$7
1 efrain 19077
    });
19078
 
19079
    const setup$c = (streamInfo, streamState) => {
19080
      const sInfo = streamInfo.stream;
19081
      const throttler = last(streamInfo.onStream, sInfo.delay);
19082
      streamState.setTimer(throttler);
19083
      return (component, simulatedEvent) => {
19084
        throttler.throttle(component, simulatedEvent);
19085
        if (sInfo.stopEvent) {
19086
          simulatedEvent.stop();
19087
        }
19088
      };
19089
    };
19090
    var StreamingSchema = [
19091
      requiredOf('stream', choose$1('mode', {
19092
        throttle: [
19093
          required$1('delay'),
19094
          defaulted('stopEvent', true),
19095
          output$1('streams', {
19096
            setup: setup$c,
19097
            state: throttle
19098
          })
19099
        ]
19100
      })),
19101
      defaulted('event', 'input'),
19102
      option$3('cancelEvent'),
19103
      onStrictHandler('onStream')
19104
    ];
19105
 
19106
    const Streaming = create$4({
19107
      fields: StreamingSchema,
19108
      name: 'streaming',
19109
      active: ActiveStreaming,
19110
      state: StreamingState
19111
    });
19112
 
19113
    const setValueFromItem = (model, input, item) => {
19114
      const itemData = Representing.getValue(item);
19115
      Representing.setValue(input, itemData);
19116
      setCursorAtEnd(input);
19117
    };
19118
    const setSelectionOn = (input, f) => {
19119
      const el = input.element;
1441 ariadna 19120
      const value = get$7(el);
1 efrain 19121
      const node = el.dom;
1441 ariadna 19122
      if (get$g(el, 'type') !== 'number') {
1 efrain 19123
        f(node, value);
19124
      }
19125
    };
19126
    const setCursorAtEnd = input => {
19127
      setSelectionOn(input, (node, value) => node.setSelectionRange(value.length, value.length));
19128
    };
19129
    const setSelectionToEnd = (input, startOffset) => {
19130
      setSelectionOn(input, (node, value) => node.setSelectionRange(startOffset, value.length));
19131
    };
19132
    const attemptSelectOver = (model, input, item) => {
19133
      if (!model.selectsOver) {
19134
        return Optional.none();
19135
      } else {
19136
        const currentValue = Representing.getValue(input);
19137
        const inputDisplay = model.getDisplayText(currentValue);
19138
        const itemValue = Representing.getValue(item);
19139
        const itemDisplay = model.getDisplayText(itemValue);
19140
        return itemDisplay.indexOf(inputDisplay) === 0 ? Optional.some(() => {
19141
          setValueFromItem(model, input, item);
19142
          setSelectionToEnd(input, inputDisplay.length);
19143
        }) : Optional.none();
19144
      }
19145
    };
19146
 
19147
    const itemExecute = constant$1('alloy.typeahead.itemexecute');
19148
 
19149
    const make$3 = (detail, components, spec, externals) => {
19150
      const navigateList = (comp, simulatedEvent, highlighter) => {
19151
        detail.previewing.set(false);
19152
        const sandbox = Coupling.getCoupled(comp, 'sandbox');
19153
        if (Sandboxing.isOpen(sandbox)) {
19154
          Composing.getCurrent(sandbox).each(menu => {
19155
            Highlighting.getHighlighted(menu).fold(() => {
19156
              highlighter(menu);
19157
            }, () => {
19158
              dispatchEvent(sandbox, menu.element, 'keydown', simulatedEvent);
19159
            });
19160
          });
19161
        } else {
19162
          const onOpenSync = sandbox => {
19163
            Composing.getCurrent(sandbox).each(highlighter);
19164
          };
19165
          open(detail, mapFetch(comp), comp, sandbox, externals, onOpenSync, HighlightOnOpen.HighlightMenuAndItem).get(noop);
19166
        }
19167
      };
19168
      const focusBehaviours$1 = focusBehaviours(detail);
19169
      const mapFetch = comp => tdata => tdata.map(data => {
19170
        const menus = values(data.menus);
19171
        const items = bind$3(menus, menu => filter$2(menu.items, item => item.type === 'item'));
19172
        const repState = Representing.getState(comp);
19173
        repState.update(map$2(items, item => item.data));
19174
        return data;
19175
      });
19176
      const getActiveMenu = sandboxComp => Composing.getCurrent(sandboxComp);
19177
      const typeaheadCustomEvents = 'typeaheadevents';
19178
      const behaviours = [
19179
        Focusing.config({}),
19180
        Representing.config({
19181
          onSetValue: detail.onSetValue,
19182
          store: {
19183
            mode: 'dataset',
1441 ariadna 19184
            getDataKey: comp => get$7(comp.element),
1 efrain 19185
            getFallbackEntry: itemString => ({
19186
              value: itemString,
19187
              meta: {}
19188
            }),
19189
            setValue: (comp, data) => {
19190
              set$5(comp.element, detail.model.getDisplayText(data));
19191
            },
19192
            ...detail.initialData.map(d => wrap$1('initialValue', d)).getOr({})
19193
          }
19194
        }),
19195
        Streaming.config({
19196
          stream: {
19197
            mode: 'throttle',
19198
            delay: detail.responseTime,
19199
            stopEvent: false
19200
          },
19201
          onStream: (component, _simulatedEvent) => {
19202
            const sandbox = Coupling.getCoupled(component, 'sandbox');
19203
            const focusInInput = Focusing.isFocused(component);
19204
            if (focusInInput) {
1441 ariadna 19205
              if (get$7(component.element).length >= detail.minChars) {
1 efrain 19206
                const previousValue = getActiveMenu(sandbox).bind(activeMenu => Highlighting.getHighlighted(activeMenu).map(Representing.getValue));
19207
                detail.previewing.set(true);
19208
                const onOpenSync = _sandbox => {
19209
                  getActiveMenu(sandbox).each(activeMenu => {
19210
                    previousValue.fold(() => {
19211
                      if (detail.model.selectsOver) {
19212
                        Highlighting.highlightFirst(activeMenu);
19213
                      }
19214
                    }, pv => {
19215
                      Highlighting.highlightBy(activeMenu, item => {
19216
                        const itemData = Representing.getValue(item);
19217
                        return itemData.value === pv.value;
19218
                      });
19219
                      Highlighting.getHighlighted(activeMenu).orThunk(() => {
19220
                        Highlighting.highlightFirst(activeMenu);
19221
                        return Optional.none();
19222
                      });
19223
                    });
19224
                  });
19225
                };
19226
                open(detail, mapFetch(component), component, sandbox, externals, onOpenSync, HighlightOnOpen.HighlightJustMenu).get(noop);
19227
              }
19228
            }
19229
          },
19230
          cancelEvent: typeaheadCancel()
19231
        }),
19232
        Keying.config({
19233
          mode: 'special',
19234
          onDown: (comp, simulatedEvent) => {
19235
            navigateList(comp, simulatedEvent, Highlighting.highlightFirst);
19236
            return Optional.some(true);
19237
          },
19238
          onEscape: comp => {
19239
            const sandbox = Coupling.getCoupled(comp, 'sandbox');
19240
            if (Sandboxing.isOpen(sandbox)) {
19241
              Sandboxing.close(sandbox);
19242
              return Optional.some(true);
19243
            }
19244
            return Optional.none();
19245
          },
19246
          onUp: (comp, simulatedEvent) => {
19247
            navigateList(comp, simulatedEvent, Highlighting.highlightLast);
19248
            return Optional.some(true);
19249
          },
19250
          onEnter: comp => {
19251
            const sandbox = Coupling.getCoupled(comp, 'sandbox');
19252
            const sandboxIsOpen = Sandboxing.isOpen(sandbox);
19253
            if (sandboxIsOpen && !detail.previewing.get()) {
19254
              return getActiveMenu(sandbox).bind(activeMenu => Highlighting.getHighlighted(activeMenu)).map(item => {
19255
                emitWith(comp, itemExecute(), { item });
19256
                return true;
19257
              });
19258
            } else {
19259
              const currentValue = Representing.getValue(comp);
19260
              emit(comp, typeaheadCancel());
19261
              detail.onExecute(sandbox, comp, currentValue);
19262
              if (sandboxIsOpen) {
19263
                Sandboxing.close(sandbox);
19264
              }
19265
              return Optional.some(true);
19266
            }
19267
          }
19268
        }),
19269
        Toggling.config({
19270
          toggleClass: detail.markers.openClass,
19271
          aria: { mode: 'expanded' }
19272
        }),
19273
        Coupling.config({
19274
          others: {
19275
            sandbox: hotspot => {
19276
              return makeSandbox$1(detail, hotspot, {
19277
                onOpen: () => Toggling.on(hotspot),
19278
                onClose: () => {
1441 ariadna 19279
                  detail.lazyTypeaheadComp.get().each(input => remove$8(input.element, 'aria-activedescendant'));
1 efrain 19280
                  Toggling.off(hotspot);
19281
                }
19282
              });
19283
            }
19284
          }
19285
        }),
19286
        config(typeaheadCustomEvents, [
19287
          runOnAttached(typeaheadComp => {
19288
            detail.lazyTypeaheadComp.set(Optional.some(typeaheadComp));
19289
          }),
19290
          runOnDetached(_typeaheadComp => {
19291
            detail.lazyTypeaheadComp.set(Optional.none());
19292
          }),
19293
          runOnExecute$1(comp => {
19294
            const onOpenSync = noop;
19295
            togglePopup(detail, mapFetch(comp), comp, externals, onOpenSync, HighlightOnOpen.HighlightMenuAndItem).get(noop);
19296
          }),
19297
          run$1(itemExecute(), (comp, se) => {
19298
            const sandbox = Coupling.getCoupled(comp, 'sandbox');
19299
            setValueFromItem(detail.model, comp, se.event.item);
19300
            emit(comp, typeaheadCancel());
19301
            detail.onItemExecute(comp, sandbox, se.event.item, Representing.getValue(comp));
19302
            Sandboxing.close(sandbox);
19303
            setCursorAtEnd(comp);
19304
          })
19305
        ].concat(detail.dismissOnBlur ? [run$1(postBlur(), typeahead => {
19306
            const sandbox = Coupling.getCoupled(typeahead, 'sandbox');
19307
            if (search(sandbox.element).isNone()) {
19308
              Sandboxing.close(sandbox);
19309
            }
19310
          })] : []))
19311
      ];
19312
      const eventOrder = {
19313
        [detachedFromDom()]: [
19314
          Representing.name(),
19315
          Streaming.name(),
19316
          typeaheadCustomEvents
19317
        ],
19318
        ...detail.eventOrder
19319
      };
19320
      return {
19321
        uid: detail.uid,
19322
        dom: dom(deepMerge(detail, {
19323
          inputAttributes: {
19324
            'role': 'combobox',
19325
            'aria-autocomplete': 'list',
19326
            'aria-haspopup': 'true'
19327
          }
19328
        })),
19329
        behaviours: {
19330
          ...focusBehaviours$1,
19331
          ...augment(detail.typeaheadBehaviours, behaviours)
19332
        },
19333
        eventOrder
19334
      };
19335
    };
19336
 
19337
    const schema$g = constant$1([
19338
      option$3('lazySink'),
19339
      required$1('fetch'),
19340
      defaulted('minChars', 5),
19341
      defaulted('responseTime', 1000),
19342
      onHandler('onOpen'),
19343
      defaulted('getHotspot', Optional.some),
19344
      defaulted('getAnchorOverrides', constant$1({})),
19345
      defaulted('layouts', Optional.none()),
19346
      defaulted('eventOrder', {}),
19347
      defaultedObjOf('model', {}, [
19348
        defaulted('getDisplayText', itemData => itemData.meta !== undefined && itemData.meta.text !== undefined ? itemData.meta.text : itemData.value),
19349
        defaulted('selectsOver', true),
19350
        defaulted('populateFromBrowse', true)
19351
      ]),
19352
      onHandler('onSetValue'),
19353
      onKeyboardHandler('onExecute'),
19354
      onHandler('onItemExecute'),
19355
      defaulted('inputClasses', []),
19356
      defaulted('inputAttributes', {}),
19357
      defaulted('inputStyles', {}),
19358
      defaulted('matchWidth', true),
19359
      defaulted('useMinWidth', false),
19360
      defaulted('dismissOnBlur', true),
19361
      markers$1(['openClass']),
19362
      option$3('initialData'),
1441 ariadna 19363
      option$3('listRole'),
1 efrain 19364
      field('typeaheadBehaviours', [
19365
        Focusing,
19366
        Representing,
19367
        Streaming,
19368
        Keying,
19369
        Toggling,
19370
        Coupling
19371
      ]),
19372
      customField('lazyTypeaheadComp', () => Cell(Optional.none)),
19373
      customField('previewing', () => Cell(true))
19374
    ].concat(schema$l()).concat(sandboxFields()));
19375
    const parts$b = constant$1([external({
19376
        schema: [tieredMenuMarkers()],
19377
        name: 'menu',
19378
        overrides: detail => {
19379
          return {
19380
            fakeFocus: true,
19381
            onHighlightItem: (_tmenu, menu, item) => {
19382
              if (!detail.previewing.get()) {
19383
                detail.lazyTypeaheadComp.get().each(input => {
19384
                  if (detail.model.populateFromBrowse) {
19385
                    setValueFromItem(detail.model, input, item);
19386
                  }
19387
                  getOpt(item.element, 'id').each(id => set$9(input.element, 'aria-activedescendant', id));
19388
                });
19389
              } else {
19390
                detail.lazyTypeaheadComp.get().each(input => {
19391
                  attemptSelectOver(detail.model, input, item).fold(() => {
19392
                    if (detail.model.selectsOver) {
19393
                      Highlighting.dehighlight(menu, item);
19394
                      detail.previewing.set(true);
19395
                    } else {
19396
                      detail.previewing.set(false);
19397
                    }
19398
                  }, selectOverTextInInput => {
19399
                    selectOverTextInInput();
19400
                    detail.previewing.set(false);
19401
                  });
19402
                });
19403
              }
19404
            },
19405
            onExecute: (_menu, item) => {
19406
              return detail.lazyTypeaheadComp.get().map(typeahead => {
19407
                emitWith(typeahead, itemExecute(), { item });
19408
                return true;
19409
              });
19410
            },
19411
            onHover: (menu, item) => {
19412
              detail.previewing.set(false);
19413
              detail.lazyTypeaheadComp.get().each(input => {
19414
                if (detail.model.populateFromBrowse) {
19415
                  setValueFromItem(detail.model, input, item);
19416
                }
19417
              });
19418
            }
19419
          };
19420
        }
19421
      })]);
19422
 
19423
    const Typeahead = composite({
19424
      name: 'Typeahead',
19425
      configFields: schema$g(),
19426
      partFields: parts$b(),
19427
      factory: make$3
19428
    });
19429
 
19430
    const wrap = delegate => {
19431
      const toCached = () => {
19432
        return wrap(delegate.toCached());
19433
      };
19434
      const bindFuture = f => {
19435
        return wrap(delegate.bind(resA => resA.fold(err => Future.pure(Result.error(err)), a => f(a))));
19436
      };
19437
      const bindResult = f => {
19438
        return wrap(delegate.map(resA => resA.bind(f)));
19439
      };
19440
      const mapResult = f => {
19441
        return wrap(delegate.map(resA => resA.map(f)));
19442
      };
19443
      const mapError = f => {
19444
        return wrap(delegate.map(resA => resA.mapError(f)));
19445
      };
19446
      const foldResult = (whenError, whenValue) => {
19447
        return delegate.map(res => res.fold(whenError, whenValue));
19448
      };
19449
      const withTimeout = (timeout, errorThunk) => {
19450
        return wrap(Future.nu(callback => {
19451
          let timedOut = false;
19452
          const timer = setTimeout(() => {
19453
            timedOut = true;
19454
            callback(Result.error(errorThunk()));
19455
          }, timeout);
19456
          delegate.get(result => {
19457
            if (!timedOut) {
19458
              clearTimeout(timer);
19459
              callback(result);
19460
            }
19461
          });
19462
        }));
19463
      };
19464
      return {
19465
        ...delegate,
19466
        toCached,
19467
        bindFuture,
19468
        bindResult,
19469
        mapResult,
19470
        mapError,
19471
        foldResult,
19472
        withTimeout
19473
      };
19474
    };
19475
    const nu$1 = worker => {
19476
      return wrap(Future.nu(worker));
19477
    };
19478
    const value = value => {
19479
      return wrap(Future.pure(Result.value(value)));
19480
    };
19481
    const error = error => {
19482
      return wrap(Future.pure(Result.error(error)));
19483
    };
19484
    const fromResult = result => {
19485
      return wrap(Future.pure(result));
19486
    };
19487
    const fromFuture = future => {
19488
      return wrap(future.map(Result.value));
19489
    };
19490
    const fromPromise = promise => {
19491
      return nu$1(completer => {
19492
        promise.then(value => {
19493
          completer(Result.value(value));
19494
        }, error => {
19495
          completer(Result.error(error));
19496
        });
19497
      });
19498
    };
19499
    const FutureResult = {
19500
      nu: nu$1,
19501
      wrap,
19502
      pure: value,
19503
      value,
19504
      error,
19505
      fromResult,
19506
      fromFuture,
19507
      fromPromise
19508
    };
19509
 
1441 ariadna 19510
    const renderCommonSpec = (spec, actionOpt, extraBehaviours = [], dom, components, tooltip, providersBackstage) => {
1 efrain 19511
      const action = actionOpt.fold(() => ({}), action => ({ action }));
19512
      const common = {
19513
        buttonBehaviours: derive$1([
1441 ariadna 19514
          DisablingConfigs.item(() => !spec.enabled || providersBackstage.checkUiComponentContext(spec.context).shouldDisable),
19515
          toggleOnReceive(() => providersBackstage.checkUiComponentContext(spec.context)),
1 efrain 19516
          Tabstopping.config({}),
1441 ariadna 19517
          ...tooltip.map(t => Tooltipping.config(providersBackstage.tooltips.getConfig({ tooltipText: providersBackstage.translate(t) }))).toArray(),
19518
          config('button press', [preventDefault('click')])
1 efrain 19519
        ].concat(extraBehaviours)),
19520
        eventOrder: {
19521
          click: [
19522
            'button press',
19523
            'alloy.base.behaviour'
19524
          ],
19525
          mousedown: [
19526
            'button press',
19527
            'alloy.base.behaviour'
19528
          ]
19529
        },
19530
        ...action
19531
      };
19532
      const domFinal = deepMerge(common, { dom });
19533
      return deepMerge(domFinal, { components });
19534
    };
1441 ariadna 19535
    const renderIconButtonSpec = (spec, action, providersBackstage, extraBehaviours = [], btnName) => {
19536
      const tooltipAttributes = spec.tooltip.map(tooltip => ({ 'aria-label': providersBackstage.translate(tooltip) })).getOr({});
1 efrain 19537
      const dom = {
19538
        tag: 'button',
19539
        classes: ['tox-tbtn'],
1441 ariadna 19540
        attributes: {
19541
          ...tooltipAttributes,
19542
          'data-mce-name': btnName
19543
        }
1 efrain 19544
      };
19545
      const icon = spec.icon.map(iconName => renderIconFromPack$1(iconName, providersBackstage.icons));
19546
      const components = componentRenderPipeline([icon]);
1441 ariadna 19547
      return renderCommonSpec(spec, action, extraBehaviours, dom, components, spec.tooltip, providersBackstage);
1 efrain 19548
    };
19549
    const calculateClassesFromButtonType = buttonType => {
19550
      switch (buttonType) {
19551
      case 'primary':
19552
        return ['tox-button'];
19553
      case 'toolbar':
19554
        return ['tox-tbtn'];
19555
      case 'secondary':
19556
      default:
19557
        return [
19558
          'tox-button',
19559
          'tox-button--secondary'
19560
        ];
19561
      }
19562
    };
19563
    const renderButtonSpec = (spec, action, providersBackstage, extraBehaviours = [], extraClasses = []) => {
19564
      const translatedText = providersBackstage.translate(spec.text);
19565
      const icon = spec.icon.map(iconName => renderIconFromPack$1(iconName, providersBackstage.icons));
19566
      const components = [icon.getOrThunk(() => text$2(translatedText))];
19567
      const buttonType = spec.buttonType.getOr(!spec.primary && !spec.borderless ? 'secondary' : 'primary');
19568
      const baseClasses = calculateClassesFromButtonType(buttonType);
19569
      const classes = [
19570
        ...baseClasses,
19571
        ...icon.isSome() ? ['tox-button--icon'] : [],
19572
        ...spec.borderless ? ['tox-button--naked'] : [],
19573
        ...extraClasses
19574
      ];
19575
      const dom = {
19576
        tag: 'button',
19577
        classes,
1441 ariadna 19578
        attributes: {
19579
          'aria-label': translatedText,
19580
          'data-mce-name': spec.text
19581
        }
1 efrain 19582
      };
1441 ariadna 19583
      const optTooltip = spec.icon.map(constant$1(translatedText));
19584
      return renderCommonSpec(spec, action, extraBehaviours, dom, components, optTooltip, providersBackstage);
1 efrain 19585
    };
19586
    const renderButton$1 = (spec, action, providersBackstage, extraBehaviours = [], extraClasses = []) => {
19587
      const buttonSpec = renderButtonSpec(spec, Optional.some(action), providersBackstage, extraBehaviours, extraClasses);
19588
      return Button.sketch(buttonSpec);
19589
    };
19590
    const getAction = (name, buttonType) => comp => {
19591
      if (buttonType === 'custom') {
19592
        emitWith(comp, formActionEvent, {
19593
          name,
19594
          value: {}
19595
        });
19596
      } else if (buttonType === 'submit') {
19597
        emit(comp, formSubmitEvent);
19598
      } else if (buttonType === 'cancel') {
19599
        emit(comp, formCancelEvent);
19600
      } else {
19601
        console.error('Unknown button type: ', buttonType);
19602
      }
19603
    };
19604
    const isMenuFooterButtonSpec = (spec, buttonType) => buttonType === 'menu';
19605
    const isNormalFooterButtonSpec = (spec, buttonType) => buttonType === 'custom' || buttonType === 'cancel' || buttonType === 'submit';
19606
    const isToggleButtonSpec = (spec, buttonType) => buttonType === 'togglebutton';
1441 ariadna 19607
    const renderToggleButton = (spec, providers, btnName) => {
1 efrain 19608
      var _a, _b;
19609
      const optMemIcon = spec.icon.map(memIcon => renderReplaceableIconFromPack(memIcon, providers.icons)).map(record);
19610
      const action = comp => {
19611
        emitWith(comp, formActionEvent, {
19612
          name: spec.name,
19613
          value: {
19614
            setIcon: newIcon => {
19615
              optMemIcon.map(memIcon => memIcon.getOpt(comp).each(displayIcon => {
19616
                Replacing.set(displayIcon, [renderReplaceableIconFromPack(newIcon, providers.icons)]);
19617
              }));
19618
            }
19619
          }
19620
        });
19621
      };
19622
      const buttonType = spec.buttonType.getOr(!spec.primary ? 'secondary' : 'primary');
19623
      const buttonSpec = {
19624
        ...spec,
19625
        name: (_a = spec.name) !== null && _a !== void 0 ? _a : '',
19626
        primary: buttonType === 'primary',
1441 ariadna 19627
        tooltip: spec.tooltip,
1 efrain 19628
        enabled: (_b = spec.enabled) !== null && _b !== void 0 ? _b : false,
19629
        borderless: false
19630
      };
1441 ariadna 19631
      const tooltipAttributes = buttonSpec.tooltip.or(spec.text).map(tooltip => ({ 'aria-label': providers.translate(tooltip) })).getOr({});
1 efrain 19632
      const buttonTypeClasses = calculateClassesFromButtonType(buttonType !== null && buttonType !== void 0 ? buttonType : 'secondary');
19633
      const showIconAndText = spec.icon.isSome() && spec.text.isSome();
19634
      const dom = {
19635
        tag: 'button',
19636
        classes: [
19637
          ...buttonTypeClasses.concat(spec.icon.isSome() ? ['tox-button--icon'] : []),
19638
          ...spec.active ? ['tox-button--enabled'] : [],
19639
          ...showIconAndText ? ['tox-button--icon-and-text'] : []
19640
        ],
1441 ariadna 19641
        attributes: {
19642
          ...tooltipAttributes,
19643
          ...isNonNullable(btnName) ? { 'data-mce-name': btnName } : {}
19644
        }
1 efrain 19645
      };
19646
      const extraBehaviours = [];
19647
      const translatedText = providers.translate(spec.text.getOr(''));
19648
      const translatedTextComponed = text$2(translatedText);
19649
      const iconComp = componentRenderPipeline([optMemIcon.map(memIcon => memIcon.asSpec())]);
19650
      const components = [
19651
        ...iconComp,
19652
        ...spec.text.isSome() ? [translatedTextComponed] : []
19653
      ];
1441 ariadna 19654
      const iconButtonSpec = renderCommonSpec(buttonSpec, Optional.some(action), extraBehaviours, dom, components, spec.tooltip, providers);
1 efrain 19655
      return Button.sketch(iconButtonSpec);
19656
    };
19657
    const renderFooterButton = (spec, buttonType, backstage) => {
19658
      if (isMenuFooterButtonSpec(spec, buttonType)) {
19659
        const getButton = () => memButton;
19660
        const menuButtonSpec = spec;
19661
        const fixedSpec = {
19662
          ...spec,
19663
          type: 'menubutton',
19664
          search: Optional.none(),
19665
          onSetup: api => {
19666
            api.setEnabled(spec.enabled);
19667
            return noop;
19668
          },
19669
          fetch: getFetch(menuButtonSpec.items, getButton, backstage)
19670
        };
1441 ariadna 19671
        const memButton = record(renderMenuButton(fixedSpec, 'tox-tbtn', backstage, Optional.none(), true, spec.text.or(spec.tooltip).getOrUndefined()));
1 efrain 19672
        return memButton.asSpec();
19673
      } else if (isNormalFooterButtonSpec(spec, buttonType)) {
19674
        const action = getAction(spec.name, buttonType);
19675
        const buttonSpec = {
19676
          ...spec,
1441 ariadna 19677
          context: buttonType === 'cancel' ? 'any' : spec.context,
1 efrain 19678
          borderless: false
19679
        };
19680
        return renderButton$1(buttonSpec, action, backstage.shared.providers, []);
19681
      } else if (isToggleButtonSpec(spec, buttonType)) {
1441 ariadna 19682
        return renderToggleButton(spec, backstage.shared.providers, spec.text.or(spec.tooltip).getOrUndefined());
1 efrain 19683
      } else {
19684
        console.error('Unknown footer button type: ', buttonType);
19685
        throw new Error('Unknown footer button type');
19686
      }
19687
    };
19688
    const renderDialogButton = (spec, providersBackstage) => {
19689
      const action = getAction(spec.name, 'custom');
19690
      return renderFormField(Optional.none(), FormField.parts.field({
19691
        factory: Button,
19692
        ...renderButtonSpec(spec, Optional.some(action), providersBackstage, [
19693
          memory(''),
19694
          ComposingConfigs.self()
19695
        ])
19696
      }));
19697
    };
19698
 
19699
    const separator$1 = { type: 'separator' };
19700
    const toMenuItem = target => ({
19701
      type: 'menuitem',
19702
      value: target.url,
19703
      text: target.title,
19704
      meta: { attach: target.attach },
19705
      onAction: noop
19706
    });
19707
    const staticMenuItem = (title, url) => ({
19708
      type: 'menuitem',
19709
      value: url,
19710
      text: title,
19711
      meta: { attach: undefined },
19712
      onAction: noop
19713
    });
19714
    const toMenuItems = targets => map$2(targets, toMenuItem);
19715
    const filterLinkTargets = (type, targets) => filter$2(targets, target => target.type === type);
19716
    const filteredTargets = (type, targets) => toMenuItems(filterLinkTargets(type, targets));
19717
    const headerTargets = linkInfo => filteredTargets('header', linkInfo.targets);
19718
    const anchorTargets = linkInfo => filteredTargets('anchor', linkInfo.targets);
19719
    const anchorTargetTop = linkInfo => Optional.from(linkInfo.anchorTop).map(url => staticMenuItem('<top>', url)).toArray();
19720
    const anchorTargetBottom = linkInfo => Optional.from(linkInfo.anchorBottom).map(url => staticMenuItem('<bottom>', url)).toArray();
19721
    const historyTargets = history => map$2(history, url => staticMenuItem(url, url));
19722
    const joinMenuLists = items => {
19723
      return foldl(items, (a, b) => {
19724
        const bothEmpty = a.length === 0 || b.length === 0;
19725
        return bothEmpty ? a.concat(b) : a.concat(separator$1, b);
19726
      }, []);
19727
    };
19728
    const filterByQuery = (term, menuItems) => {
19729
      const lowerCaseTerm = term.toLowerCase();
19730
      return filter$2(menuItems, item => {
19731
        var _a;
19732
        const text = item.meta !== undefined && item.meta.text !== undefined ? item.meta.text : item.text;
19733
        const value = (_a = item.value) !== null && _a !== void 0 ? _a : '';
19734
        return contains$1(text.toLowerCase(), lowerCaseTerm) || contains$1(value.toLowerCase(), lowerCaseTerm);
19735
      });
19736
    };
19737
 
19738
    const getItems = (fileType, input, urlBackstage) => {
19739
      var _a, _b;
19740
      const urlInputValue = Representing.getValue(input);
19741
      const term = (_b = (_a = urlInputValue === null || urlInputValue === void 0 ? void 0 : urlInputValue.meta) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : urlInputValue.value;
19742
      const info = urlBackstage.getLinkInformation();
19743
      return info.fold(() => [], linkInfo => {
19744
        const history = filterByQuery(term, historyTargets(urlBackstage.getHistory(fileType)));
19745
        return fileType === 'file' ? joinMenuLists([
19746
          history,
19747
          filterByQuery(term, headerTargets(linkInfo)),
19748
          filterByQuery(term, flatten([
19749
            anchorTargetTop(linkInfo),
19750
            anchorTargets(linkInfo),
19751
            anchorTargetBottom(linkInfo)
19752
          ]))
19753
        ]) : history;
19754
      });
19755
    };
19756
    const errorId = generate$6('aria-invalid');
19757
    const renderUrlInput = (spec, backstage, urlBackstage, initialData) => {
19758
      const providersBackstage = backstage.shared.providers;
19759
      const updateHistory = component => {
19760
        const urlEntry = Representing.getValue(component);
19761
        urlBackstage.addToHistory(urlEntry.value, spec.filetype);
19762
      };
19763
      const typeaheadSpec = {
19764
        ...initialData.map(initialData => ({ initialData })).getOr({}),
19765
        dismissOnBlur: true,
19766
        inputClasses: ['tox-textfield'],
19767
        sandboxClasses: ['tox-dialog__popups'],
19768
        inputAttributes: {
19769
          'aria-errormessage': errorId,
19770
          'type': 'url'
19771
        },
19772
        minChars: 0,
19773
        responseTime: 0,
19774
        fetch: input => {
19775
          const items = getItems(spec.filetype, input, urlBackstage);
19776
          const tdata = build(items, ItemResponse$1.BUBBLE_TO_SANDBOX, backstage, {
19777
            isHorizontalMenu: false,
19778
            search: Optional.none()
19779
          });
19780
          return Future.pure(tdata);
19781
        },
19782
        getHotspot: comp => memUrlBox.getOpt(comp),
19783
        onSetValue: (comp, _newValue) => {
19784
          if (comp.hasConfigured(Invalidating)) {
19785
            Invalidating.run(comp).get(noop);
19786
          }
19787
        },
19788
        typeaheadBehaviours: derive$1([
19789
          ...urlBackstage.getValidationHandler().map(handler => Invalidating.config({
19790
            getRoot: comp => parentElement(comp.element),
19791
            invalidClass: 'tox-control-wrap--status-invalid',
19792
            notify: {
19793
              onInvalid: (comp, err) => {
19794
                memInvalidIcon.getOpt(comp).each(invalidComp => {
19795
                  set$9(invalidComp.element, 'title', providersBackstage.translate(err));
19796
                });
19797
              }
19798
            },
19799
            validator: {
19800
              validate: input => {
19801
                const urlEntry = Representing.getValue(input);
19802
                return FutureResult.nu(completer => {
19803
                  handler({
19804
                    type: spec.filetype,
19805
                    url: urlEntry.value
19806
                  }, validation => {
19807
                    if (validation.status === 'invalid') {
19808
                      const err = Result.error(validation.message);
19809
                      completer(err);
19810
                    } else {
19811
                      const val = Result.value(validation.message);
19812
                      completer(val);
19813
                    }
19814
                  });
19815
                });
19816
              },
19817
              validateOnLoad: false
19818
            }
19819
          })).toArray(),
1441 ariadna 19820
          Disabling.config({ disabled: () => !spec.enabled || providersBackstage.checkUiComponentContext(spec.context).shouldDisable }),
1 efrain 19821
          Tabstopping.config({}),
19822
          config('urlinput-events', [
19823
            run$1(input(), comp => {
1441 ariadna 19824
              const currentValue = get$7(comp.element);
1 efrain 19825
              const trimmedValue = currentValue.trim();
19826
              if (trimmedValue !== currentValue) {
19827
                set$5(comp.element, trimmedValue);
19828
              }
19829
              if (spec.filetype === 'file') {
19830
                emitWith(comp, formChangeEvent, { name: spec.name });
19831
              }
19832
            }),
19833
            run$1(change(), comp => {
19834
              emitWith(comp, formChangeEvent, { name: spec.name });
19835
              updateHistory(comp);
19836
            }),
19837
            run$1(postPaste(), comp => {
19838
              emitWith(comp, formChangeEvent, { name: spec.name });
19839
              updateHistory(comp);
19840
            })
19841
          ])
19842
        ]),
19843
        eventOrder: {
19844
          [input()]: [
19845
            'streaming',
19846
            'urlinput-events',
19847
            'invalidating'
19848
          ]
19849
        },
19850
        model: {
19851
          getDisplayText: itemData => itemData.value,
19852
          selectsOver: false,
19853
          populateFromBrowse: false
19854
        },
19855
        markers: { openClass: 'tox-textfield--popup-open' },
19856
        lazySink: backstage.shared.getSink,
19857
        parts: { menu: part(false, 1, 'normal') },
19858
        onExecute: (_menu, component, _entry) => {
19859
          emitWith(component, formSubmitEvent, {});
19860
        },
19861
        onItemExecute: (typeahead, _sandbox, _item, _value) => {
19862
          updateHistory(typeahead);
19863
          emitWith(typeahead, formChangeEvent, { name: spec.name });
19864
        }
19865
      };
19866
      const pField = FormField.parts.field({
19867
        ...typeaheadSpec,
19868
        factory: Typeahead
19869
      });
19870
      const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
19871
      const makeIcon = (name, errId, icon = name, label = name) => render$3(icon, {
19872
        tag: 'div',
19873
        classes: [
19874
          'tox-icon',
19875
          'tox-control-wrap__status-icon-' + name
19876
        ],
19877
        attributes: {
19878
          'title': providersBackstage.translate(label),
19879
          'aria-live': 'polite',
19880
          ...errId.fold(() => ({}), id => ({ id }))
19881
        }
19882
      }, providersBackstage.icons);
19883
      const memInvalidIcon = record(makeIcon('invalid', Optional.some(errorId), 'warning'));
19884
      const memStatus = record({
19885
        dom: {
19886
          tag: 'div',
19887
          classes: ['tox-control-wrap__status-icon-wrap']
19888
        },
19889
        components: [memInvalidIcon.asSpec()]
19890
      });
19891
      const optUrlPicker = urlBackstage.getUrlPicker(spec.filetype);
19892
      const browseUrlEvent = generate$6('browser.url.event');
19893
      const memUrlBox = record({
19894
        dom: {
19895
          tag: 'div',
19896
          classes: ['tox-control-wrap']
19897
        },
19898
        components: [
19899
          pField,
19900
          memStatus.asSpec()
19901
        ],
1441 ariadna 19902
        behaviours: derive$1([Disabling.config({ disabled: () => !spec.enabled || providersBackstage.checkUiComponentContext(spec.context).shouldDisable })])
1 efrain 19903
      });
19904
      const memUrlPickerButton = record(renderButton$1({
1441 ariadna 19905
        context: spec.context,
1 efrain 19906
        name: spec.name,
19907
        icon: Optional.some('browse'),
19908
        text: spec.picker_text.or(spec.label).getOr(''),
19909
        enabled: spec.enabled,
19910
        primary: false,
19911
        buttonType: Optional.none(),
19912
        borderless: true
19913
      }, component => emit(component, browseUrlEvent), providersBackstage, [], ['tox-browse-url']));
19914
      const controlHWrapper = () => ({
19915
        dom: {
19916
          tag: 'div',
19917
          classes: ['tox-form__controls-h-stack']
19918
        },
19919
        components: flatten([
19920
          [memUrlBox.asSpec()],
19921
          optUrlPicker.map(() => memUrlPickerButton.asSpec()).toArray()
19922
        ])
19923
      });
19924
      const openUrlPicker = comp => {
19925
        Composing.getCurrent(comp).each(field => {
19926
          const componentData = Representing.getValue(field);
19927
          const urlData = {
19928
            fieldname: spec.name,
19929
            ...componentData
19930
          };
19931
          optUrlPicker.each(picker => {
19932
            picker(urlData).get(chosenData => {
19933
              Representing.setValue(field, chosenData);
19934
              emitWith(comp, formChangeEvent, { name: spec.name });
19935
            });
19936
          });
19937
        });
19938
      };
19939
      return FormField.sketch({
19940
        dom: renderFormFieldDom(),
19941
        components: pLabel.toArray().concat([controlHWrapper()]),
19942
        fieldBehaviours: derive$1([
19943
          Disabling.config({
1441 ariadna 19944
            disabled: () => !spec.enabled || providersBackstage.checkUiComponentContext(spec.context).shouldDisable,
1 efrain 19945
            onDisabled: comp => {
19946
              FormField.getField(comp).each(Disabling.disable);
19947
              memUrlPickerButton.getOpt(comp).each(Disabling.disable);
19948
            },
19949
            onEnabled: comp => {
19950
              FormField.getField(comp).each(Disabling.enable);
19951
              memUrlPickerButton.getOpt(comp).each(Disabling.enable);
19952
            }
19953
          }),
1441 ariadna 19954
          toggleOnReceive(() => providersBackstage.checkUiComponentContext(spec.context)),
1 efrain 19955
          config('url-input-events', [run$1(browseUrlEvent, openUrlPicker)])
19956
        ])
19957
      });
19958
    };
19959
 
19960
    const renderAlertBanner = (spec, providersBackstage) => {
1441 ariadna 19961
      const icon = get$3(spec.icon, providersBackstage.icons);
1 efrain 19962
      return Container.sketch({
19963
        dom: {
19964
          tag: 'div',
19965
          attributes: { role: 'alert' },
19966
          classes: [
19967
            'tox-notification',
19968
            'tox-notification--in',
19969
            `tox-notification--${ spec.level }`
19970
          ]
19971
        },
19972
        components: [
19973
          {
19974
            dom: {
19975
              tag: 'div',
19976
              classes: ['tox-notification__icon'],
19977
              innerHtml: !spec.url ? icon : undefined
19978
            },
19979
            components: spec.url ? [Button.sketch({
19980
                dom: {
19981
                  tag: 'button',
19982
                  classes: [
19983
                    'tox-button',
19984
                    'tox-button--naked',
19985
                    'tox-button--icon'
19986
                  ],
19987
                  innerHtml: icon,
19988
                  attributes: { title: providersBackstage.translate(spec.iconTooltip) }
19989
                },
19990
                action: comp => emitWith(comp, formActionEvent, {
19991
                  name: 'alert-banner',
19992
                  value: spec.url
19993
                }),
19994
                buttonBehaviours: derive$1([addFocusableBehaviour()])
19995
              })] : undefined
19996
          },
19997
          {
19998
            dom: {
19999
              tag: 'div',
20000
              classes: ['tox-notification__body'],
20001
              innerHtml: providersBackstage.translate(spec.text)
20002
            }
20003
          }
20004
        ]
20005
      });
20006
    };
20007
 
20008
    const set$1 = (element, status) => {
20009
      element.dom.checked = status;
20010
    };
1441 ariadna 20011
    const get$2 = element => element.dom.checked;
1 efrain 20012
 
20013
    const renderCheckbox = (spec, providerBackstage, initialData) => {
20014
      const toggleCheckboxHandler = comp => {
20015
        comp.element.dom.click();
20016
        return Optional.some(true);
20017
      };
20018
      const pField = FormField.parts.field({
20019
        factory: { sketch: identity },
20020
        dom: {
20021
          tag: 'input',
20022
          classes: ['tox-checkbox__input'],
20023
          attributes: { type: 'checkbox' }
20024
        },
20025
        behaviours: derive$1([
20026
          ComposingConfigs.self(),
20027
          Disabling.config({
1441 ariadna 20028
            disabled: () => !spec.enabled || providerBackstage.checkUiComponentContext(spec.context).shouldDisable,
1 efrain 20029
            onDisabled: component => {
20030
              parentElement(component.element).each(element => add$2(element, 'tox-checkbox--disabled'));
20031
            },
20032
            onEnabled: component => {
1441 ariadna 20033
              parentElement(component.element).each(element => remove$3(element, 'tox-checkbox--disabled'));
1 efrain 20034
            }
20035
          }),
20036
          Tabstopping.config({}),
20037
          Focusing.config({}),
1441 ariadna 20038
          withElement(initialData, get$2, set$1),
1 efrain 20039
          Keying.config({
20040
            mode: 'special',
20041
            onEnter: toggleCheckboxHandler,
20042
            onSpace: toggleCheckboxHandler,
20043
            stopSpaceKeyup: true
20044
          }),
20045
          config('checkbox-events', [run$1(change(), (component, _) => {
20046
              emitWith(component, formChangeEvent, { name: spec.name });
20047
            })])
20048
        ])
20049
      });
20050
      const pLabel = FormField.parts.label({
20051
        dom: {
20052
          tag: 'span',
20053
          classes: ['tox-checkbox__label']
20054
        },
20055
        components: [text$2(providerBackstage.translate(spec.label))],
20056
        behaviours: derive$1([Unselecting.config({})])
20057
      });
20058
      const makeIcon = className => {
20059
        const iconName = className === 'checked' ? 'selected' : 'unselected';
20060
        return render$3(iconName, {
20061
          tag: 'span',
20062
          classes: [
20063
            'tox-icon',
20064
            'tox-checkbox-icon__' + className
20065
          ]
20066
        }, providerBackstage.icons);
20067
      };
20068
      const memIcons = record({
20069
        dom: {
20070
          tag: 'div',
20071
          classes: ['tox-checkbox__icons']
20072
        },
20073
        components: [
20074
          makeIcon('checked'),
20075
          makeIcon('unchecked')
20076
        ]
20077
      });
20078
      return FormField.sketch({
20079
        dom: {
20080
          tag: 'label',
20081
          classes: ['tox-checkbox']
20082
        },
20083
        components: [
20084
          pField,
20085
          memIcons.asSpec(),
20086
          pLabel
20087
        ],
20088
        fieldBehaviours: derive$1([
1441 ariadna 20089
          Disabling.config({ disabled: () => !spec.enabled || providerBackstage.checkUiComponentContext(spec.context).shouldDisable }),
20090
          toggleOnReceive(() => providerBackstage.checkUiComponentContext(spec.context))
1 efrain 20091
        ])
20092
      });
20093
    };
20094
 
1441 ariadna 20095
    const renderHtmlPanel = (spec, providersBackstage) => {
20096
      const classes = [
20097
        'tox-form__group',
20098
        ...spec.stretched ? ['tox-form__group--stretched'] : []
20099
      ];
20100
      const init = config('htmlpanel', [runOnAttached(comp => {
20101
          spec.onInit(comp.element.dom);
20102
        })]);
1 efrain 20103
      if (spec.presets === 'presentation') {
20104
        return Container.sketch({
20105
          dom: {
20106
            tag: 'div',
1441 ariadna 20107
            classes,
1 efrain 20108
            innerHtml: spec.html
1441 ariadna 20109
          },
20110
          containerBehaviours: derive$1([
20111
            Tooltipping.config({
20112
              ...providersBackstage.tooltips.getConfig({
20113
                tooltipText: '',
20114
                onShow: comp => {
20115
                  descendant(comp.element, '[data-mce-tooltip]:hover').orThunk(() => search(comp.element)).each(current => {
20116
                    getOpt(current, 'data-mce-tooltip').each(text => {
20117
                      Tooltipping.setComponents(comp, providersBackstage.tooltips.getComponents({ tooltipText: text }));
20118
                    });
20119
                  });
20120
                }
20121
              }),
20122
              mode: 'children-normal',
20123
              anchor: comp => ({
20124
                type: 'node',
20125
                node: descendant(comp.element, '[data-mce-tooltip]:hover').orThunk(() => search(comp.element).filter(current => getOpt(current, 'data-mce-tooltip').isSome())),
20126
                root: comp.element,
20127
                layouts: {
20128
                  onLtr: constant$1([
20129
                    south$2,
20130
                    north$2,
20131
                    southeast$2,
20132
                    northeast$2,
20133
                    southwest$2,
20134
                    northwest$2
20135
                  ]),
20136
                  onRtl: constant$1([
20137
                    south$2,
20138
                    north$2,
20139
                    southeast$2,
20140
                    northeast$2,
20141
                    southwest$2,
20142
                    northwest$2
20143
                  ])
20144
                },
20145
                bubble: nu$5(0, -2, {})
20146
              })
20147
            }),
20148
            init
20149
          ])
1 efrain 20150
        });
20151
      } else {
20152
        return Container.sketch({
20153
          dom: {
20154
            tag: 'div',
1441 ariadna 20155
            classes,
1 efrain 20156
            innerHtml: spec.html,
20157
            attributes: { role: 'document' }
20158
          },
20159
          containerBehaviours: derive$1([
20160
            Tabstopping.config({}),
1441 ariadna 20161
            Focusing.config({}),
20162
            init
1 efrain 20163
          ])
20164
        });
20165
      }
20166
    };
20167
 
20168
    const make$2 = render => {
1441 ariadna 20169
      return (parts, spec, dialogData, backstage, getCompByName) => get$h(spec, 'name').fold(() => render(spec, backstage, Optional.none(), getCompByName), fieldName => parts.field(fieldName, render(spec, backstage, get$h(dialogData, fieldName), getCompByName)));
1 efrain 20170
    };
1441 ariadna 20171
    const makeIframe = render => (parts, spec, dialogData, backstage, getCompByName) => {
1 efrain 20172
      const iframeSpec = deepMerge(spec, { source: 'dynamic' });
1441 ariadna 20173
      return make$2(render)(parts, iframeSpec, dialogData, backstage, getCompByName);
1 efrain 20174
    };
20175
    const factories = {
20176
      bar: make$2((spec, backstage) => renderBar(spec, backstage.shared)),
20177
      collection: make$2((spec, backstage, data) => renderCollection(spec, backstage.shared.providers, data)),
20178
      alertbanner: make$2((spec, backstage) => renderAlertBanner(spec, backstage.shared.providers)),
20179
      input: make$2((spec, backstage, data) => renderInput(spec, backstage.shared.providers, data)),
20180
      textarea: make$2((spec, backstage, data) => renderTextarea(spec, backstage.shared.providers, data)),
1441 ariadna 20181
      label: make$2((spec, backstage, _data, getCompByName) => renderLabel$2(spec, backstage.shared, getCompByName)),
1 efrain 20182
      iframe: makeIframe((spec, backstage, data) => renderIFrame(spec, backstage.shared.providers, data)),
20183
      button: make$2((spec, backstage) => renderDialogButton(spec, backstage.shared.providers)),
20184
      checkbox: make$2((spec, backstage, data) => renderCheckbox(spec, backstage.shared.providers, data)),
20185
      colorinput: make$2((spec, backstage, data) => renderColorInput(spec, backstage.shared, backstage.colorinput, data)),
20186
      colorpicker: make$2((spec, backstage, data) => renderColorPicker(spec, backstage.shared.providers, data)),
20187
      dropzone: make$2((spec, backstage, data) => renderDropZone(spec, backstage.shared.providers, data)),
20188
      grid: make$2((spec, backstage) => renderGrid(spec, backstage.shared)),
20189
      listbox: make$2((spec, backstage, data) => renderListBox(spec, backstage, data)),
20190
      selectbox: make$2((spec, backstage, data) => renderSelectBox(spec, backstage.shared.providers, data)),
20191
      sizeinput: make$2((spec, backstage) => renderSizeInput(spec, backstage.shared.providers)),
20192
      slider: make$2((spec, backstage, data) => renderSlider(spec, backstage.shared.providers, data)),
20193
      urlinput: make$2((spec, backstage, data) => renderUrlInput(spec, backstage, backstage.urlinput, data)),
20194
      customeditor: make$2(renderCustomEditor),
1441 ariadna 20195
      htmlpanel: make$2((spec, backstage) => renderHtmlPanel(spec, backstage.shared.providers)),
1 efrain 20196
      imagepreview: make$2((spec, _, data) => renderImagePreview(spec, data)),
20197
      table: make$2((spec, backstage) => renderTable(spec, backstage.shared.providers)),
20198
      tree: make$2((spec, backstage) => renderTree(spec, backstage)),
20199
      panel: make$2((spec, backstage) => renderPanel(spec, backstage))
20200
    };
20201
    const noFormParts = {
20202
      field: (_name, spec) => spec,
20203
      record: constant$1([])
20204
    };
1441 ariadna 20205
    const interpretInForm = (parts, spec, dialogData, oldBackstage, getCompByName) => {
20206
      const newBackstage = deepMerge(oldBackstage, { shared: { interpreter: childSpec => interpretParts(parts, childSpec, dialogData, newBackstage, getCompByName) } });
20207
      return interpretParts(parts, spec, dialogData, newBackstage, getCompByName);
1 efrain 20208
    };
1441 ariadna 20209
    const interpretParts = (parts, spec, dialogData, backstage, getCompByName) => get$h(factories, spec.type).fold(() => {
1 efrain 20210
      console.error(`Unknown factory type "${ spec.type }", defaulting to container: `, spec);
20211
      return spec;
1441 ariadna 20212
    }, factory => factory(parts, spec, dialogData, backstage, getCompByName));
20213
    const interpretWithoutForm = (spec, dialogData, backstage, getCompByName) => interpretParts(noFormParts, spec, dialogData, backstage, getCompByName);
1 efrain 20214
 
20215
    const labelPrefix = 'layout-inset';
20216
    const westEdgeX = anchor => anchor.x;
20217
    const middleX = (anchor, element) => anchor.x + anchor.width / 2 - element.width / 2;
20218
    const eastEdgeX = (anchor, element) => anchor.x + anchor.width - element.width;
20219
    const northY = anchor => anchor.y;
20220
    const southY = (anchor, element) => anchor.y + anchor.height - element.height;
20221
    const centreY = (anchor, element) => anchor.y + anchor.height / 2 - element.height / 2;
20222
    const southwest = (anchor, element, bubbles) => nu$6(eastEdgeX(anchor, element), southY(anchor, element), bubbles.insetSouthwest(), northwest$3(), 'southwest', boundsRestriction(anchor, {
20223
      right: 0,
20224
      bottom: 3
20225
    }), labelPrefix);
20226
    const southeast = (anchor, element, bubbles) => nu$6(westEdgeX(anchor), southY(anchor, element), bubbles.insetSoutheast(), northeast$3(), 'southeast', boundsRestriction(anchor, {
20227
      left: 1,
20228
      bottom: 3
20229
    }), labelPrefix);
20230
    const northwest = (anchor, element, bubbles) => nu$6(eastEdgeX(anchor, element), northY(anchor), bubbles.insetNorthwest(), southwest$3(), 'northwest', boundsRestriction(anchor, {
20231
      right: 0,
20232
      top: 2
20233
    }), labelPrefix);
20234
    const northeast = (anchor, element, bubbles) => nu$6(westEdgeX(anchor), northY(anchor), bubbles.insetNortheast(), southeast$3(), 'northeast', boundsRestriction(anchor, {
20235
      left: 1,
20236
      top: 2
20237
    }), labelPrefix);
20238
    const north = (anchor, element, bubbles) => nu$6(middleX(anchor, element), northY(anchor), bubbles.insetNorth(), south$3(), 'north', boundsRestriction(anchor, { top: 2 }), labelPrefix);
20239
    const south = (anchor, element, bubbles) => nu$6(middleX(anchor, element), southY(anchor, element), bubbles.insetSouth(), north$3(), 'south', boundsRestriction(anchor, { bottom: 3 }), labelPrefix);
20240
    const east = (anchor, element, bubbles) => nu$6(eastEdgeX(anchor, element), centreY(anchor, element), bubbles.insetEast(), west$3(), 'east', boundsRestriction(anchor, { right: 0 }), labelPrefix);
20241
    const west = (anchor, element, bubbles) => nu$6(westEdgeX(anchor), centreY(anchor, element), bubbles.insetWest(), east$3(), 'west', boundsRestriction(anchor, { left: 1 }), labelPrefix);
20242
    const lookupPreserveLayout = lastPlacement => {
20243
      switch (lastPlacement) {
20244
      case 'north':
20245
        return north;
20246
      case 'northeast':
20247
        return northeast;
20248
      case 'northwest':
20249
        return northwest;
20250
      case 'south':
20251
        return south;
20252
      case 'southeast':
20253
        return southeast;
20254
      case 'southwest':
20255
        return southwest;
20256
      case 'east':
20257
        return east;
20258
      case 'west':
20259
        return west;
20260
      }
20261
    };
20262
    const preserve = (anchor, element, bubbles, placee, bounds) => {
20263
      const layout = getPlacement(placee).map(lookupPreserveLayout).getOr(north);
20264
      return layout(anchor, element, bubbles, placee, bounds);
20265
    };
20266
    const lookupFlippedLayout = lastPlacement => {
20267
      switch (lastPlacement) {
20268
      case 'north':
20269
        return south;
20270
      case 'northeast':
20271
        return southeast;
20272
      case 'northwest':
20273
        return southwest;
20274
      case 'south':
20275
        return north;
20276
      case 'southeast':
20277
        return northeast;
20278
      case 'southwest':
20279
        return northwest;
20280
      case 'east':
20281
        return west;
20282
      case 'west':
20283
        return east;
20284
      }
20285
    };
20286
    const flip = (anchor, element, bubbles, placee, bounds) => {
20287
      const layout = getPlacement(placee).map(lookupFlippedLayout).getOr(north);
20288
      return layout(anchor, element, bubbles, placee, bounds);
20289
    };
20290
 
20291
    const bubbleAlignments$2 = {
20292
      valignCentre: [],
20293
      alignCentre: [],
20294
      alignLeft: [],
20295
      alignRight: [],
20296
      right: [],
20297
      left: [],
20298
      bottom: [],
20299
      top: []
20300
    };
20301
    const getInlineDialogAnchor = (contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor) => {
20302
      const bubbleSize = 12;
20303
      const overrides = { maxHeightFunction: expandable$1() };
20304
      const editableAreaAnchor = () => ({
20305
        type: 'node',
20306
        root: getContentContainer(getRootNode(contentAreaElement())),
20307
        node: Optional.from(contentAreaElement()),
20308
        bubble: nu$5(bubbleSize, bubbleSize, bubbleAlignments$2),
20309
        layouts: {
20310
          onRtl: () => [northeast],
20311
          onLtr: () => [northwest]
20312
        },
20313
        overrides
20314
      });
20315
      const standardAnchor = () => ({
20316
        type: 'hotspot',
20317
        hotspot: lazyAnchorbar(),
20318
        bubble: nu$5(-bubbleSize, bubbleSize, bubbleAlignments$2),
20319
        layouts: {
20320
          onRtl: () => [
20321
            southeast$2,
20322
            southwest$2,
20323
            south$2
20324
          ],
20325
          onLtr: () => [
20326
            southwest$2,
20327
            southeast$2,
20328
            south$2
20329
          ]
20330
        },
20331
        overrides
20332
      });
20333
      return () => lazyUseEditableAreaAnchor() ? editableAreaAnchor() : standardAnchor();
20334
    };
20335
    const getInlineBottomDialogAnchor = (inline, contentAreaElement, lazyBottomAnchorBar, lazyUseEditableAreaAnchor) => {
20336
      const bubbleSize = 12;
20337
      const overrides = { maxHeightFunction: expandable$1() };
20338
      const editableAreaAnchor = () => ({
20339
        type: 'node',
20340
        root: getContentContainer(getRootNode(contentAreaElement())),
20341
        node: Optional.from(contentAreaElement()),
20342
        bubble: nu$5(bubbleSize, bubbleSize, bubbleAlignments$2),
20343
        layouts: {
20344
          onRtl: () => [north],
20345
          onLtr: () => [north]
20346
        },
20347
        overrides
20348
      });
20349
      const standardAnchor = () => inline ? {
20350
        type: 'node',
20351
        root: getContentContainer(getRootNode(contentAreaElement())),
20352
        node: Optional.from(contentAreaElement()),
20353
        bubble: nu$5(0, -getOuter$2(contentAreaElement()), bubbleAlignments$2),
20354
        layouts: {
20355
          onRtl: () => [north$2],
20356
          onLtr: () => [north$2]
20357
        },
20358
        overrides
20359
      } : {
20360
        type: 'hotspot',
20361
        hotspot: lazyBottomAnchorBar(),
20362
        bubble: nu$5(0, 0, bubbleAlignments$2),
20363
        layouts: {
20364
          onRtl: () => [north$2],
20365
          onLtr: () => [north$2]
20366
        },
20367
        overrides
20368
      };
20369
      return () => lazyUseEditableAreaAnchor() ? editableAreaAnchor() : standardAnchor();
20370
    };
20371
    const getBannerAnchor = (contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor) => {
20372
      const editableAreaAnchor = () => ({
20373
        type: 'node',
20374
        root: getContentContainer(getRootNode(contentAreaElement())),
20375
        node: Optional.from(contentAreaElement()),
20376
        layouts: {
20377
          onRtl: () => [north],
20378
          onLtr: () => [north]
20379
        }
20380
      });
20381
      const standardAnchor = () => ({
20382
        type: 'hotspot',
20383
        hotspot: lazyAnchorbar(),
20384
        layouts: {
20385
          onRtl: () => [south$2],
20386
          onLtr: () => [south$2]
20387
        }
20388
      });
20389
      return () => lazyUseEditableAreaAnchor() ? editableAreaAnchor() : standardAnchor();
20390
    };
20391
    const getCursorAnchor = (editor, bodyElement) => () => ({
20392
      type: 'selection',
20393
      root: bodyElement(),
20394
      getSelection: () => {
20395
        const rng = editor.selection.getRng();
20396
        const selectedCells = editor.model.table.getSelectedCells();
20397
        if (selectedCells.length > 1) {
20398
          const firstCell = selectedCells[0];
20399
          const lastCell = selectedCells[selectedCells.length - 1];
20400
          const selectionTableCellRange = {
20401
            firstCell: SugarElement.fromDom(firstCell),
20402
            lastCell: SugarElement.fromDom(lastCell)
20403
          };
20404
          return Optional.some(selectionTableCellRange);
20405
        }
20406
        return Optional.some(SimSelection.range(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
20407
      }
20408
    });
20409
    const getNodeAnchor$1 = bodyElement => element => ({
20410
      type: 'node',
20411
      root: bodyElement(),
20412
      node: element
20413
    });
20414
    const getAnchors = (editor, lazyAnchorbar, lazyBottomAnchorBar, isToolbarTop) => {
20415
      const useFixedToolbarContainer = useFixedContainer(editor);
20416
      const bodyElement = () => SugarElement.fromDom(editor.getBody());
20417
      const contentAreaElement = () => SugarElement.fromDom(editor.getContentAreaContainer());
20418
      const lazyUseEditableAreaAnchor = () => useFixedToolbarContainer || !isToolbarTop();
20419
      return {
20420
        inlineDialog: getInlineDialogAnchor(contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor),
20421
        inlineBottomDialog: getInlineBottomDialogAnchor(editor.inline, contentAreaElement, lazyBottomAnchorBar, lazyUseEditableAreaAnchor),
20422
        banner: getBannerAnchor(contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor),
20423
        cursor: getCursorAnchor(editor, bodyElement),
20424
        node: getNodeAnchor$1(bodyElement)
20425
      };
20426
    };
20427
 
20428
    const colorPicker = editor => (callback, value) => {
20429
      const dialog = colorPickerDialog(editor);
20430
      dialog(callback, value);
20431
    };
20432
    const hasCustomColors = editor => () => hasCustomColors$1(editor);
20433
    const getColors = editor => id => getColors$2(editor, id);
20434
    const getColorCols = editor => id => getColorCols$1(editor, id);
20435
    const ColorInputBackstage = editor => ({
20436
      colorPicker: colorPicker(editor),
20437
      hasCustomColors: hasCustomColors(editor),
20438
      getColors: getColors(editor),
20439
      getColorCols: getColorCols(editor)
20440
    });
20441
 
20442
    const isDraggableModal = editor => () => isDraggableModal$1(editor);
20443
    const DialogBackstage = editor => ({ isDraggableModal: isDraggableModal(editor) });
20444
 
20445
    const HeaderBackstage = editor => {
20446
      const mode = Cell(isToolbarLocationBottom(editor) ? 'bottom' : 'top');
20447
      return {
20448
        isPositionedAtTop: () => mode.get() === 'top',
20449
        getDockingMode: mode.get,
20450
        setDockingMode: mode.set
20451
      };
20452
    };
20453
 
20454
    const isNestedFormat = format => hasNonNullableKey(format, 'items');
20455
    const isFormatReference = format => hasNonNullableKey(format, 'format');
20456
    const defaultStyleFormats = [
20457
      {
20458
        title: 'Headings',
20459
        items: [
20460
          {
20461
            title: 'Heading 1',
20462
            format: 'h1'
20463
          },
20464
          {
20465
            title: 'Heading 2',
20466
            format: 'h2'
20467
          },
20468
          {
20469
            title: 'Heading 3',
20470
            format: 'h3'
20471
          },
20472
          {
20473
            title: 'Heading 4',
20474
            format: 'h4'
20475
          },
20476
          {
20477
            title: 'Heading 5',
20478
            format: 'h5'
20479
          },
20480
          {
20481
            title: 'Heading 6',
20482
            format: 'h6'
20483
          }
20484
        ]
20485
      },
20486
      {
20487
        title: 'Inline',
20488
        items: [
20489
          {
20490
            title: 'Bold',
20491
            format: 'bold'
20492
          },
20493
          {
20494
            title: 'Italic',
20495
            format: 'italic'
20496
          },
20497
          {
20498
            title: 'Underline',
20499
            format: 'underline'
20500
          },
20501
          {
20502
            title: 'Strikethrough',
20503
            format: 'strikethrough'
20504
          },
20505
          {
20506
            title: 'Superscript',
20507
            format: 'superscript'
20508
          },
20509
          {
20510
            title: 'Subscript',
20511
            format: 'subscript'
20512
          },
20513
          {
20514
            title: 'Code',
20515
            format: 'code'
20516
          }
20517
        ]
20518
      },
20519
      {
20520
        title: 'Blocks',
20521
        items: [
20522
          {
20523
            title: 'Paragraph',
20524
            format: 'p'
20525
          },
20526
          {
20527
            title: 'Blockquote',
20528
            format: 'blockquote'
20529
          },
20530
          {
20531
            title: 'Div',
20532
            format: 'div'
20533
          },
20534
          {
20535
            title: 'Pre',
20536
            format: 'pre'
20537
          }
20538
        ]
20539
      },
20540
      {
20541
        title: 'Align',
20542
        items: [
20543
          {
20544
            title: 'Left',
20545
            format: 'alignleft'
20546
          },
20547
          {
20548
            title: 'Center',
20549
            format: 'aligncenter'
20550
          },
20551
          {
20552
            title: 'Right',
20553
            format: 'alignright'
20554
          },
20555
          {
20556
            title: 'Justify',
20557
            format: 'alignjustify'
20558
          }
20559
        ]
20560
      }
20561
    ];
20562
    const isNestedFormats = format => has$2(format, 'items');
20563
    const isBlockFormat = format => has$2(format, 'block');
20564
    const isInlineFormat = format => has$2(format, 'inline');
20565
    const isSelectorFormat = format => has$2(format, 'selector');
20566
    const mapFormats = userFormats => foldl(userFormats, (acc, fmt) => {
20567
      if (isNestedFormats(fmt)) {
20568
        const result = mapFormats(fmt.items);
20569
        return {
20570
          customFormats: acc.customFormats.concat(result.customFormats),
20571
          formats: acc.formats.concat([{
20572
              title: fmt.title,
20573
              items: result.formats
20574
            }])
20575
        };
20576
      } else if (isInlineFormat(fmt) || isBlockFormat(fmt) || isSelectorFormat(fmt)) {
20577
        const formatName = isString(fmt.name) ? fmt.name : fmt.title.toLowerCase();
20578
        const formatNameWithPrefix = `custom-${ formatName }`;
20579
        return {
20580
          customFormats: acc.customFormats.concat([{
20581
              name: formatNameWithPrefix,
20582
              format: fmt
20583
            }]),
20584
          formats: acc.formats.concat([{
20585
              title: fmt.title,
20586
              format: formatNameWithPrefix,
20587
              icon: fmt.icon
20588
            }])
20589
        };
20590
      } else {
20591
        return {
20592
          ...acc,
20593
          formats: acc.formats.concat(fmt)
20594
        };
20595
      }
20596
    }, {
20597
      customFormats: [],
20598
      formats: []
20599
    });
20600
    const registerCustomFormats = (editor, userFormats) => {
20601
      const result = mapFormats(userFormats);
20602
      const registerFormats = customFormats => {
20603
        each$1(customFormats, fmt => {
20604
          if (!editor.formatter.has(fmt.name)) {
20605
            editor.formatter.register(fmt.name, fmt.format);
20606
          }
20607
        });
20608
      };
20609
      if (editor.formatter) {
20610
        registerFormats(result.customFormats);
20611
      } else {
20612
        editor.on('init', () => {
20613
          registerFormats(result.customFormats);
20614
        });
20615
      }
20616
      return result.formats;
20617
    };
20618
    const getStyleFormats = editor => getUserStyleFormats(editor).map(userFormats => {
20619
      const registeredUserFormats = registerCustomFormats(editor, userFormats);
20620
      return shouldMergeStyleFormats(editor) ? defaultStyleFormats.concat(registeredUserFormats) : registeredUserFormats;
20621
    }).getOr(defaultStyleFormats);
20622
 
20623
    const isSeparator$1 = format => {
20624
      const keys$1 = keys(format);
20625
      return keys$1.length === 1 && contains$2(keys$1, 'title');
20626
    };
20627
    const processBasic = (item, isSelectedFor, getPreviewFor) => ({
20628
      ...item,
20629
      type: 'formatter',
20630
      isSelected: isSelectedFor(item.format),
20631
      getStylePreview: getPreviewFor(item.format)
20632
    });
1441 ariadna 20633
    const register$b = (editor, formats, isSelectedFor, getPreviewFor) => {
1 efrain 20634
      const enrichSupported = item => processBasic(item, isSelectedFor, getPreviewFor);
20635
      const enrichMenu = item => {
20636
        const newItems = doEnrich(item.items);
20637
        return {
20638
          ...item,
20639
          type: 'submenu',
20640
          getStyleItems: constant$1(newItems)
20641
        };
20642
      };
20643
      const enrichCustom = item => {
20644
        const formatName = isString(item.name) ? item.name : generate$6(item.title);
20645
        const formatNameWithPrefix = `custom-${ formatName }`;
20646
        const newItem = {
20647
          ...item,
20648
          type: 'formatter',
20649
          format: formatNameWithPrefix,
20650
          isSelected: isSelectedFor(formatNameWithPrefix),
20651
          getStylePreview: getPreviewFor(formatNameWithPrefix)
20652
        };
20653
        editor.formatter.register(formatName, newItem);
20654
        return newItem;
20655
      };
20656
      const doEnrich = items => map$2(items, item => {
20657
        if (isNestedFormat(item)) {
20658
          return enrichMenu(item);
20659
        } else if (isFormatReference(item)) {
20660
          return enrichSupported(item);
20661
        } else if (isSeparator$1(item)) {
20662
          return {
20663
            ...item,
20664
            type: 'separator'
20665
          };
20666
        } else {
20667
          return enrichCustom(item);
20668
        }
20669
      });
20670
      return doEnrich(formats);
20671
    };
20672
 
1441 ariadna 20673
    const init$6 = editor => {
1 efrain 20674
      const isSelectedFor = format => () => editor.formatter.match(format);
20675
      const getPreviewFor = format => () => {
20676
        const fmt = editor.formatter.get(format);
20677
        return fmt !== undefined ? Optional.some({
20678
          tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || 'div' : 'div',
20679
          styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
20680
        }) : Optional.none();
20681
      };
20682
      const settingsFormats = Cell([]);
20683
      const eventsFormats = Cell([]);
20684
      const replaceSettings = Cell(false);
20685
      editor.on('PreInit', _e => {
20686
        const formats = getStyleFormats(editor);
1441 ariadna 20687
        const enriched = register$b(editor, formats, isSelectedFor, getPreviewFor);
1 efrain 20688
        settingsFormats.set(enriched);
20689
      });
20690
      editor.on('addStyleModifications', e => {
1441 ariadna 20691
        const modifications = register$b(editor, e.items, isSelectedFor, getPreviewFor);
1 efrain 20692
        eventsFormats.set(modifications);
20693
        replaceSettings.set(e.replace);
20694
      });
20695
      const getData = () => {
20696
        const fromSettings = replaceSettings.get() ? [] : settingsFormats.get();
20697
        const fromEvents = eventsFormats.get();
20698
        return fromSettings.concat(fromEvents);
20699
      };
20700
      return { getData };
20701
    };
20702
 
1441 ariadna 20703
    const TooltipsBackstage = getSink => {
20704
      const tooltipDelay = 300;
20705
      const intervalDelay = tooltipDelay * 0.2;
20706
      let numActiveTooltips = 0;
20707
      const alreadyShowingTooltips = () => numActiveTooltips > 0;
20708
      const getComponents = spec => {
20709
        return [{
20710
            dom: {
20711
              tag: 'div',
20712
              classes: ['tox-tooltip__body']
20713
            },
20714
            components: [text$2(spec.tooltipText)]
20715
          }];
20716
      };
20717
      const getConfig = spec => {
20718
        return {
20719
          delayForShow: () => alreadyShowingTooltips() ? intervalDelay : tooltipDelay,
20720
          delayForHide: constant$1(tooltipDelay),
20721
          exclusive: true,
20722
          lazySink: getSink,
20723
          tooltipDom: {
20724
            tag: 'div',
20725
            classes: [
20726
              'tox-tooltip',
20727
              'tox-tooltip--up'
20728
            ]
20729
          },
20730
          tooltipComponents: getComponents(spec),
20731
          onShow: (comp, tooltip) => {
20732
            numActiveTooltips++;
20733
            if (spec.onShow) {
20734
              spec.onShow(comp, tooltip);
20735
            }
20736
          },
20737
          onHide: (comp, tooltip) => {
20738
            numActiveTooltips--;
20739
            if (spec.onHide) {
20740
              spec.onHide(comp, tooltip);
20741
            }
20742
          },
20743
          onSetup: spec.onSetup
20744
        };
20745
      };
20746
      return {
20747
        getConfig,
20748
        getComponents
20749
      };
20750
    };
20751
 
1 efrain 20752
    const isElement = node => isNonNullable(node) && node.nodeType === 1;
20753
    const trim = global$1.trim;
20754
    const hasContentEditableState = value => {
20755
      return node => {
20756
        if (isElement(node)) {
20757
          if (node.contentEditable === value) {
20758
            return true;
20759
          }
20760
          if (node.getAttribute('data-mce-contenteditable') === value) {
20761
            return true;
20762
          }
20763
        }
20764
        return false;
20765
      };
20766
    };
20767
    const isContentEditableTrue = hasContentEditableState('true');
20768
    const isContentEditableFalse = hasContentEditableState('false');
20769
    const create = (type, title, url, level, attach) => ({
20770
      type,
20771
      title,
20772
      url,
20773
      level,
20774
      attach
20775
    });
20776
    const isChildOfContentEditableTrue = node => {
20777
      let tempNode = node;
20778
      while (tempNode = tempNode.parentNode) {
20779
        const value = tempNode.contentEditable;
20780
        if (value && value !== 'inherit') {
20781
          return isContentEditableTrue(tempNode);
20782
        }
20783
      }
20784
      return false;
20785
    };
20786
    const select = (selector, root) => {
20787
      return map$2(descendants(SugarElement.fromDom(root), selector), element => {
20788
        return element.dom;
20789
      });
20790
    };
20791
    const getElementText = elm => {
20792
      return elm.innerText || elm.textContent;
20793
    };
20794
    const getOrGenerateId = elm => {
20795
      return elm.id ? elm.id : generate$6('h');
20796
    };
20797
    const isAnchor = elm => {
20798
      return elm && elm.nodeName === 'A' && (elm.id || elm.name) !== undefined;
20799
    };
20800
    const isValidAnchor = elm => {
20801
      return isAnchor(elm) && isEditable(elm);
20802
    };
20803
    const isHeader = elm => {
20804
      return elm && /^(H[1-6])$/.test(elm.nodeName);
20805
    };
20806
    const isEditable = elm => {
20807
      return isChildOfContentEditableTrue(elm) && !isContentEditableFalse(elm);
20808
    };
20809
    const isValidHeader = elm => {
20810
      return isHeader(elm) && isEditable(elm);
20811
    };
20812
    const getLevel = elm => {
20813
      return isHeader(elm) ? parseInt(elm.nodeName.substr(1), 10) : 0;
20814
    };
20815
    const headerTarget = elm => {
20816
      var _a;
20817
      const headerId = getOrGenerateId(elm);
20818
      const attach = () => {
20819
        elm.id = headerId;
20820
      };
20821
      return create('header', (_a = getElementText(elm)) !== null && _a !== void 0 ? _a : '', '#' + headerId, getLevel(elm), attach);
20822
    };
20823
    const anchorTarget = elm => {
20824
      const anchorId = elm.id || elm.name;
20825
      const anchorText = getElementText(elm);
20826
      return create('anchor', anchorText ? anchorText : '#' + anchorId, '#' + anchorId, 0, noop);
20827
    };
20828
    const getHeaderTargets = elms => {
20829
      return map$2(filter$2(elms, isValidHeader), headerTarget);
20830
    };
20831
    const getAnchorTargets = elms => {
20832
      return map$2(filter$2(elms, isValidAnchor), anchorTarget);
20833
    };
20834
    const getTargetElements = elm => {
20835
      const elms = select('h1,h2,h3,h4,h5,h6,a:not([href])', elm);
20836
      return elms;
20837
    };
20838
    const hasTitle = target => {
20839
      return trim(target.title).length > 0;
20840
    };
20841
    const find = elm => {
20842
      const elms = getTargetElements(elm);
20843
      return filter$2(getHeaderTargets(elms).concat(getAnchorTargets(elms)), hasTitle);
20844
    };
20845
    const LinkTargets = { find };
20846
 
20847
    const STORAGE_KEY = 'tinymce-url-history';
20848
    const HISTORY_LENGTH = 5;
20849
    const isHttpUrl = url => isString(url) && /^https?/.test(url);
20850
    const isArrayOfUrl = a => isArray(a) && a.length <= HISTORY_LENGTH && forall(a, isHttpUrl);
20851
    const isRecordOfUrlArray = r => isObject(r) && find$4(r, value => !isArrayOfUrl(value)).isNone();
20852
    const getAllHistory = () => {
20853
      const unparsedHistory = global$4.getItem(STORAGE_KEY);
20854
      if (unparsedHistory === null) {
20855
        return {};
20856
      }
20857
      let history;
20858
      try {
20859
        history = JSON.parse(unparsedHistory);
20860
      } catch (e) {
20861
        if (e instanceof SyntaxError) {
20862
          console.log('Local storage ' + STORAGE_KEY + ' was not valid JSON', e);
20863
          return {};
20864
        }
20865
        throw e;
20866
      }
20867
      if (!isRecordOfUrlArray(history)) {
20868
        console.log('Local storage ' + STORAGE_KEY + ' was not valid format', history);
20869
        return {};
20870
      }
20871
      return history;
20872
    };
20873
    const setAllHistory = history => {
20874
      if (!isRecordOfUrlArray(history)) {
20875
        throw new Error('Bad format for history:\n' + JSON.stringify(history));
20876
      }
20877
      global$4.setItem(STORAGE_KEY, JSON.stringify(history));
20878
    };
20879
    const getHistory = fileType => {
20880
      const history = getAllHistory();
1441 ariadna 20881
      return get$h(history, fileType).getOr([]);
1 efrain 20882
    };
20883
    const addToHistory = (url, fileType) => {
20884
      if (!isHttpUrl(url)) {
20885
        return;
20886
      }
20887
      const history = getAllHistory();
1441 ariadna 20888
      const items = get$h(history, fileType).getOr([]);
1 efrain 20889
      const itemsWithoutUrl = filter$2(items, item => item !== url);
20890
      history[fileType] = [url].concat(itemsWithoutUrl).slice(0, HISTORY_LENGTH);
20891
      setAllHistory(history);
20892
    };
20893
 
20894
    const isTruthy = value => !!value;
20895
    const makeMap = value => map$1(global$1.makeMap(value, /[, ]/), isTruthy);
20896
    const getPicker = editor => Optional.from(getFilePickerCallback(editor));
20897
    const getPickerTypes = editor => {
20898
      const optFileTypes = Optional.from(getFilePickerTypes(editor)).filter(isTruthy).map(makeMap);
20899
      return getPicker(editor).fold(never, _picker => optFileTypes.fold(always, types => keys(types).length > 0 ? types : false));
20900
    };
20901
    const getPickerSetting = (editor, filetype) => {
20902
      const pickerTypes = getPickerTypes(editor);
20903
      if (isBoolean(pickerTypes)) {
20904
        return pickerTypes ? getPicker(editor) : Optional.none();
20905
      } else {
20906
        return pickerTypes[filetype] ? getPicker(editor) : Optional.none();
20907
      }
20908
    };
20909
    const getUrlPicker = (editor, filetype) => getPickerSetting(editor, filetype).map(picker => entry => Future.nu(completer => {
20910
      const handler = (value, meta) => {
20911
        if (!isString(value)) {
20912
          throw new Error('Expected value to be string');
20913
        }
20914
        if (meta !== undefined && !isObject(meta)) {
20915
          throw new Error('Expected meta to be a object');
20916
        }
20917
        const r = {
20918
          value,
20919
          meta
20920
        };
20921
        completer(r);
20922
      };
20923
      const meta = {
20924
        filetype,
20925
        fieldname: entry.fieldname,
20926
        ...Optional.from(entry.meta).getOr({})
20927
      };
20928
      picker.call(editor, handler, entry.value, meta);
20929
    }));
20930
    const getTextSetting = value => Optional.from(value).filter(isString).getOrUndefined();
20931
    const getLinkInformation = editor => {
20932
      if (!useTypeaheadUrls(editor)) {
20933
        return Optional.none();
20934
      }
20935
      return Optional.some({
20936
        targets: LinkTargets.find(editor.getBody()),
20937
        anchorTop: getTextSetting(getAnchorTop(editor)),
20938
        anchorBottom: getTextSetting(getAnchorBottom(editor))
20939
      });
20940
    };
20941
    const getValidationHandler = editor => Optional.from(getFilePickerValidatorHandler(editor));
20942
    const UrlInputBackstage = editor => ({
20943
      getHistory,
20944
      addToHistory,
20945
      getLinkInformation: () => getLinkInformation(editor),
20946
      getValidationHandler: () => getValidationHandler(editor),
20947
      getUrlPicker: filetype => getUrlPicker(editor, filetype)
20948
    });
20949
 
1441 ariadna 20950
    const init$5 = (lazySinks, editor, lazyAnchorbar, lazyBottomAnchorBar) => {
1 efrain 20951
      const contextMenuState = Cell(false);
20952
      const toolbar = HeaderBackstage(editor);
20953
      const providers = {
20954
        icons: () => editor.ui.registry.getAll().icons,
20955
        menuItems: () => editor.ui.registry.getAll().menuItems,
1441 ariadna 20956
        translate: global$5.translate,
20957
        isDisabled: () => !editor.ui.isEnabled(),
20958
        getOption: editor.options.get,
20959
        tooltips: TooltipsBackstage(lazySinks.dialog),
20960
        checkUiComponentContext: specContext => {
20961
          if (isDisabled(editor)) {
20962
            return {
20963
              contextType: 'disabled',
20964
              shouldDisable: true
20965
            };
20966
          }
20967
          const [key, value = ''] = specContext.split(':');
20968
          const contexts = editor.ui.registry.getAll().contexts;
20969
          const enabledInContext = get$h(contexts, key).fold(() => get$h(contexts, 'mode').map(pred => pred('design')).getOr(false), pred => value.charAt(0) === '!' ? !pred(value.slice(1)) : pred(value));
20970
          return {
20971
            contextType: key,
20972
            shouldDisable: !enabledInContext
20973
          };
20974
        }
1 efrain 20975
      };
20976
      const urlinput = UrlInputBackstage(editor);
1441 ariadna 20977
      const styles = init$6(editor);
1 efrain 20978
      const colorinput = ColorInputBackstage(editor);
20979
      const dialogSettings = DialogBackstage(editor);
20980
      const isContextMenuOpen = () => contextMenuState.get();
20981
      const setContextMenuState = state => contextMenuState.set(state);
20982
      const commonBackstage = {
20983
        shared: {
20984
          providers,
20985
          anchors: getAnchors(editor, lazyAnchorbar, lazyBottomAnchorBar, toolbar.isPositionedAtTop),
20986
          header: toolbar
20987
        },
20988
        urlinput,
20989
        styles,
20990
        colorinput,
20991
        dialog: dialogSettings,
20992
        isContextMenuOpen,
20993
        setContextMenuState
20994
      };
1441 ariadna 20995
      const getCompByName = _name => Optional.none();
1 efrain 20996
      const popupBackstage = {
20997
        ...commonBackstage,
20998
        shared: {
20999
          ...commonBackstage.shared,
1441 ariadna 21000
          interpreter: s => interpretWithoutForm(s, {}, popupBackstage, getCompByName),
1 efrain 21001
          getSink: lazySinks.popup
21002
        }
21003
      };
21004
      const dialogBackstage = {
21005
        ...commonBackstage,
21006
        shared: {
21007
          ...commonBackstage.shared,
1441 ariadna 21008
          interpreter: s => interpretWithoutForm(s, {}, dialogBackstage, getCompByName),
1 efrain 21009
          getSink: lazySinks.dialog
21010
        }
21011
      };
21012
      return {
21013
        popup: popupBackstage,
21014
        dialog: dialogBackstage
21015
      };
21016
    };
21017
 
21018
    const setup$b = (editor, mothership, uiMotherships) => {
21019
      const broadcastEvent = (name, evt) => {
21020
        each$1([
21021
          mothership,
21022
          ...uiMotherships
21023
        ], m => {
21024
          m.broadcastEvent(name, evt);
21025
        });
21026
      };
21027
      const broadcastOn = (channel, message) => {
21028
        each$1([
21029
          mothership,
21030
          ...uiMotherships
21031
        ], m => {
21032
          m.broadcastOn([channel], message);
21033
        });
21034
      };
21035
      const fireDismissPopups = evt => broadcastOn(dismissPopups(), { target: evt.target });
21036
      const doc = getDocument();
21037
      const onTouchstart = bind(doc, 'touchstart', fireDismissPopups);
21038
      const onTouchmove = bind(doc, 'touchmove', evt => broadcastEvent(documentTouchmove(), evt));
21039
      const onTouchend = bind(doc, 'touchend', evt => broadcastEvent(documentTouchend(), evt));
21040
      const onMousedown = bind(doc, 'mousedown', fireDismissPopups);
21041
      const onMouseup = bind(doc, 'mouseup', evt => {
21042
        if (evt.raw.button === 0) {
21043
          broadcastOn(mouseReleased(), { target: evt.target });
21044
        }
21045
      });
21046
      const onContentClick = raw => broadcastOn(dismissPopups(), { target: SugarElement.fromDom(raw.target) });
21047
      const onContentMouseup = raw => {
21048
        if (raw.button === 0) {
21049
          broadcastOn(mouseReleased(), { target: SugarElement.fromDom(raw.target) });
21050
        }
21051
      };
21052
      const onContentMousedown = () => {
21053
        each$1(editor.editorManager.get(), loopEditor => {
21054
          if (editor !== loopEditor) {
21055
            loopEditor.dispatch('DismissPopups', { relatedTarget: editor });
21056
          }
21057
        });
21058
      };
21059
      const onWindowScroll = evt => broadcastEvent(windowScroll(), fromRawEvent(evt));
21060
      const onWindowResize = evt => {
21061
        broadcastOn(repositionPopups(), {});
21062
        broadcastEvent(windowResize(), fromRawEvent(evt));
21063
      };
21064
      const dos = getRootNode(SugarElement.fromDom(editor.getElement()));
21065
      const onElementScroll = capture(dos, 'scroll', evt => {
21066
        requestAnimationFrame(() => {
21067
          const c = editor.getContainer();
21068
          if (c !== undefined && c !== null) {
21069
            const optScrollingContext = detectWhenSplitUiMode(editor, mothership.element);
21070
            const scrollers = optScrollingContext.map(sc => [
21071
              sc.element,
21072
              ...sc.others
21073
            ]).getOr([]);
21074
            if (exists(scrollers, s => eq(s, evt.target))) {
21075
              editor.dispatch('ElementScroll', { target: evt.target.dom });
21076
              broadcastEvent(externalElementScroll(), evt);
21077
            }
21078
          }
21079
        });
21080
      });
21081
      const onEditorResize = () => broadcastOn(repositionPopups(), {});
21082
      const onEditorProgress = evt => {
21083
        if (evt.state) {
21084
          broadcastOn(dismissPopups(), { target: SugarElement.fromDom(editor.getContainer()) });
21085
        }
21086
      };
21087
      const onDismissPopups = event => {
21088
        broadcastOn(dismissPopups(), { target: SugarElement.fromDom(event.relatedTarget.getContainer()) });
21089
      };
1441 ariadna 21090
      const onFocusIn = event => editor.dispatch('focusin', event);
21091
      const onFocusOut = event => editor.dispatch('focusout', event);
1 efrain 21092
      editor.on('PostRender', () => {
21093
        editor.on('click', onContentClick);
21094
        editor.on('tap', onContentClick);
21095
        editor.on('mouseup', onContentMouseup);
21096
        editor.on('mousedown', onContentMousedown);
21097
        editor.on('ScrollWindow', onWindowScroll);
21098
        editor.on('ResizeWindow', onWindowResize);
21099
        editor.on('ResizeEditor', onEditorResize);
21100
        editor.on('AfterProgressState', onEditorProgress);
21101
        editor.on('DismissPopups', onDismissPopups);
1441 ariadna 21102
        each$1([
21103
          mothership,
21104
          ...uiMotherships
21105
        ], gui => {
21106
          gui.element.dom.addEventListener('focusin', onFocusIn);
21107
          gui.element.dom.addEventListener('focusout', onFocusOut);
21108
        });
1 efrain 21109
      });
21110
      editor.on('remove', () => {
21111
        editor.off('click', onContentClick);
21112
        editor.off('tap', onContentClick);
21113
        editor.off('mouseup', onContentMouseup);
21114
        editor.off('mousedown', onContentMousedown);
21115
        editor.off('ScrollWindow', onWindowScroll);
21116
        editor.off('ResizeWindow', onWindowResize);
21117
        editor.off('ResizeEditor', onEditorResize);
21118
        editor.off('AfterProgressState', onEditorProgress);
21119
        editor.off('DismissPopups', onDismissPopups);
1441 ariadna 21120
        each$1([
21121
          mothership,
21122
          ...uiMotherships
21123
        ], gui => {
21124
          gui.element.dom.removeEventListener('focusin', onFocusIn);
21125
          gui.element.dom.removeEventListener('focusout', onFocusOut);
21126
        });
1 efrain 21127
        onMousedown.unbind();
21128
        onTouchstart.unbind();
21129
        onTouchmove.unbind();
21130
        onTouchend.unbind();
21131
        onMouseup.unbind();
21132
        onElementScroll.unbind();
21133
      });
21134
      editor.on('detach', () => {
21135
        each$1([
21136
          mothership,
21137
          ...uiMotherships
21138
        ], detachSystem);
21139
        each$1([
21140
          mothership,
21141
          ...uiMotherships
21142
        ], m => m.destroy());
21143
      });
21144
    };
21145
 
21146
    const parts$a = AlloyParts;
21147
    const partType = PartType;
21148
 
21149
    const schema$f = constant$1([
21150
      defaulted('shell', false),
21151
      required$1('makeItem'),
21152
      defaulted('setupItem', noop),
21153
      SketchBehaviours.field('listBehaviours', [Replacing])
21154
    ]);
21155
    const customListDetail = () => ({ behaviours: derive$1([Replacing.config({})]) });
21156
    const itemsPart = optional({
21157
      name: 'items',
21158
      overrides: customListDetail
21159
    });
21160
    const parts$9 = constant$1([itemsPart]);
21161
    const name = constant$1('CustomList');
21162
 
21163
    const factory$f = (detail, components, _spec, _external) => {
21164
      const setItems = (list, items) => {
21165
        getListContainer(list).fold(() => {
21166
          console.error('Custom List was defined to not be a shell, but no item container was specified in components');
21167
          throw new Error('Custom List was defined to not be a shell, but no item container was specified in components');
21168
        }, container => {
21169
          const itemComps = Replacing.contents(container);
21170
          const numListsRequired = items.length;
21171
          const numListsToAdd = numListsRequired - itemComps.length;
21172
          const itemsToAdd = numListsToAdd > 0 ? range$2(numListsToAdd, () => detail.makeItem()) : [];
21173
          const itemsToRemove = itemComps.slice(numListsRequired);
21174
          each$1(itemsToRemove, item => Replacing.remove(container, item));
21175
          each$1(itemsToAdd, item => Replacing.append(container, item));
21176
          const builtLists = Replacing.contents(container);
21177
          each$1(builtLists, (item, i) => {
21178
            detail.setupItem(list, item, items[i], i);
21179
          });
21180
        });
21181
      };
21182
      const extra = detail.shell ? {
21183
        behaviours: [Replacing.config({})],
21184
        components: []
21185
      } : {
21186
        behaviours: [],
21187
        components
21188
      };
21189
      const getListContainer = component => detail.shell ? Optional.some(component) : getPart(component, detail, 'items');
21190
      return {
21191
        uid: detail.uid,
21192
        dom: detail.dom,
21193
        components: extra.components,
21194
        behaviours: augment(detail.listBehaviours, extra.behaviours),
21195
        apis: { setItems }
21196
      };
21197
    };
21198
    const CustomList = composite({
21199
      name: name(),
21200
      configFields: schema$f(),
21201
      partFields: parts$9(),
21202
      factory: factory$f,
21203
      apis: {
21204
        setItems: (apis, list, items) => {
21205
          apis.setItems(list, items);
21206
        }
21207
      }
21208
    });
21209
 
21210
    const schema$e = constant$1([
21211
      required$1('dom'),
21212
      defaulted('shell', true),
21213
      field('toolbarBehaviours', [Replacing])
21214
    ]);
21215
    const enhanceGroups = () => ({ behaviours: derive$1([Replacing.config({})]) });
21216
    const parts$8 = constant$1([optional({
21217
        name: 'groups',
21218
        overrides: enhanceGroups
21219
      })]);
21220
 
21221
    const factory$e = (detail, components, _spec, _externals) => {
21222
      const setGroups = (toolbar, groups) => {
21223
        getGroupContainer(toolbar).fold(() => {
21224
          console.error('Toolbar was defined to not be a shell, but no groups container was specified in components');
21225
          throw new Error('Toolbar was defined to not be a shell, but no groups container was specified in components');
21226
        }, container => {
21227
          Replacing.set(container, groups);
21228
        });
21229
      };
21230
      const getGroupContainer = component => detail.shell ? Optional.some(component) : getPart(component, detail, 'groups');
21231
      const extra = detail.shell ? {
21232
        behaviours: [Replacing.config({})],
21233
        components: []
21234
      } : {
21235
        behaviours: [],
21236
        components
21237
      };
21238
      return {
21239
        uid: detail.uid,
21240
        dom: detail.dom,
21241
        components: extra.components,
21242
        behaviours: augment(detail.toolbarBehaviours, extra.behaviours),
21243
        apis: {
21244
          setGroups,
21245
          refresh: noop
21246
        },
21247
        domModification: { attributes: { role: 'group' } }
21248
      };
21249
    };
21250
    const Toolbar = composite({
21251
      name: 'Toolbar',
21252
      configFields: schema$e(),
21253
      partFields: parts$8(),
21254
      factory: factory$e,
21255
      apis: {
21256
        setGroups: (apis, toolbar, groups) => {
21257
          apis.setGroups(toolbar, groups);
21258
        }
21259
      }
21260
    });
21261
 
21262
    const setup$a = noop;
1441 ariadna 21263
    const isDocked$1 = never;
1 efrain 21264
    const getBehaviours$1 = constant$1([]);
21265
 
21266
    var StaticHeader = /*#__PURE__*/Object.freeze({
21267
        __proto__: null,
21268
        setup: setup$a,
1441 ariadna 21269
        isDocked: isDocked$1,
1 efrain 21270
        getBehaviours: getBehaviours$1
21271
    });
21272
 
21273
    const toolbarHeightChange = constant$1(generate$6('toolbar-height-change'));
21274
 
21275
    const visibility = {
21276
      fadeInClass: 'tox-editor-dock-fadein',
21277
      fadeOutClass: 'tox-editor-dock-fadeout',
21278
      transitionClass: 'tox-editor-dock-transition'
21279
    };
21280
    const editorStickyOnClass = 'tox-tinymce--toolbar-sticky-on';
21281
    const editorStickyOffClass = 'tox-tinymce--toolbar-sticky-off';
21282
    const scrollFromBehindHeader = (e, containerHeader) => {
21283
      const doc = owner$4(containerHeader);
21284
      const win = defaultView(containerHeader);
21285
      const viewHeight = win.dom.innerHeight;
1441 ariadna 21286
      const scrollPos = get$c(doc);
1 efrain 21287
      const markerElement = SugarElement.fromDom(e.elm);
21288
      const markerPos = absolute$2(markerElement);
1441 ariadna 21289
      const markerHeight = get$e(markerElement);
1 efrain 21290
      const markerTop = markerPos.y;
21291
      const markerBottom = markerTop + markerHeight;
21292
      const editorHeaderPos = absolute$3(containerHeader);
1441 ariadna 21293
      const editorHeaderHeight = get$e(containerHeader);
1 efrain 21294
      const editorHeaderTop = editorHeaderPos.top;
21295
      const editorHeaderBottom = editorHeaderTop + editorHeaderHeight;
21296
      const editorHeaderDockedAtTop = Math.abs(editorHeaderTop - scrollPos.top) < 2;
21297
      const editorHeaderDockedAtBottom = Math.abs(editorHeaderBottom - (scrollPos.top + viewHeight)) < 2;
21298
      if (editorHeaderDockedAtTop && markerTop < editorHeaderBottom) {
21299
        to(scrollPos.left, markerTop - editorHeaderHeight, doc);
21300
      } else if (editorHeaderDockedAtBottom && markerBottom > editorHeaderTop) {
21301
        const y = markerTop - viewHeight + markerHeight + editorHeaderHeight;
21302
        to(scrollPos.left, y, doc);
21303
      }
21304
    };
21305
    const isDockedMode = (header, mode) => contains$2(Docking.getModes(header), mode);
21306
    const updateIframeContentFlow = header => {
1441 ariadna 21307
      const getOccupiedHeight = elm => getOuter$2(elm) + (parseInt(get$f(elm, 'margin-top'), 10) || 0) + (parseInt(get$f(elm, 'margin-bottom'), 10) || 0);
1 efrain 21308
      const elm = header.element;
21309
      parentElement(elm).each(parentElem => {
21310
        const padding = 'padding-' + Docking.getModes(header)[0];
21311
        if (Docking.isDocked(header)) {
1441 ariadna 21312
          const parentWidth = get$d(parentElem);
1 efrain 21313
          set$8(elm, 'width', parentWidth + 'px');
21314
          set$8(parentElem, padding, getOccupiedHeight(elm) + 'px');
21315
        } else {
1441 ariadna 21316
          remove$7(elm, 'width');
21317
          remove$7(parentElem, padding);
1 efrain 21318
        }
21319
      });
21320
    };
21321
    const updateSinkVisibility = (sinkElem, visible) => {
21322
      if (visible) {
1441 ariadna 21323
        remove$3(sinkElem, visibility.fadeOutClass);
1 efrain 21324
        add$1(sinkElem, [
21325
          visibility.transitionClass,
21326
          visibility.fadeInClass
21327
        ]);
21328
      } else {
1441 ariadna 21329
        remove$3(sinkElem, visibility.fadeInClass);
1 efrain 21330
        add$1(sinkElem, [
21331
          visibility.fadeOutClass,
21332
          visibility.transitionClass
21333
        ]);
21334
      }
21335
    };
21336
    const updateEditorClasses = (editor, docked) => {
21337
      const editorContainer = SugarElement.fromDom(editor.getContainer());
21338
      if (docked) {
21339
        add$2(editorContainer, editorStickyOnClass);
1441 ariadna 21340
        remove$3(editorContainer, editorStickyOffClass);
1 efrain 21341
      } else {
21342
        add$2(editorContainer, editorStickyOffClass);
1441 ariadna 21343
        remove$3(editorContainer, editorStickyOnClass);
1 efrain 21344
      }
21345
    };
21346
    const restoreFocus = (headerElem, focusedElem) => {
21347
      const ownerDoc = owner$4(focusedElem);
21348
      active$1(ownerDoc).filter(activeElm => !eq(focusedElem, activeElm)).filter(activeElm => eq(activeElm, SugarElement.fromDom(ownerDoc.dom.body)) || contains(headerElem, activeElm)).each(() => focus$3(focusedElem));
21349
    };
21350
    const findFocusedElem = (rootElm, lazySink) => search(rootElm).orThunk(() => lazySink().toOptional().bind(sink => search(sink.element)));
21351
    const setup$9 = (editor, sharedBackstage, lazyHeader) => {
21352
      if (!editor.inline) {
21353
        if (!sharedBackstage.header.isPositionedAtTop()) {
21354
          editor.on('ResizeEditor', () => {
21355
            lazyHeader().each(Docking.reset);
21356
          });
21357
        }
21358
        editor.on('ResizeWindow ResizeEditor', () => {
21359
          lazyHeader().each(updateIframeContentFlow);
21360
        });
21361
        editor.on('SkinLoaded', () => {
21362
          lazyHeader().each(comp => {
21363
            Docking.isDocked(comp) ? Docking.reset(comp) : Docking.refresh(comp);
21364
          });
21365
        });
21366
        editor.on('FullscreenStateChanged', () => {
21367
          lazyHeader().each(Docking.reset);
21368
        });
21369
      }
21370
      editor.on('AfterScrollIntoView', e => {
21371
        lazyHeader().each(header => {
21372
          Docking.refresh(header);
21373
          const headerElem = header.element;
21374
          if (isVisible(headerElem)) {
21375
            scrollFromBehindHeader(e, headerElem);
21376
          }
21377
        });
21378
      });
21379
      editor.on('PostRender', () => {
21380
        updateEditorClasses(editor, false);
21381
      });
21382
    };
21383
    const isDocked = lazyHeader => lazyHeader().map(Docking.isDocked).getOr(false);
21384
    const getIframeBehaviours = () => [Receiving.config({ channels: { [toolbarHeightChange()]: { onReceive: updateIframeContentFlow } } })];
21385
    const getBehaviours = (editor, sharedBackstage) => {
1441 ariadna 21386
      const focusedElm = value$4();
1 efrain 21387
      const lazySink = sharedBackstage.getSink;
21388
      const runOnSinkElement = f => {
21389
        lazySink().each(sink => f(sink.element));
21390
      };
21391
      const onDockingSwitch = comp => {
21392
        if (!editor.inline) {
21393
          updateIframeContentFlow(comp);
21394
        }
21395
        updateEditorClasses(editor, Docking.isDocked(comp));
21396
        comp.getSystem().broadcastOn([repositionPopups()], {});
21397
        lazySink().each(sink => sink.getSystem().broadcastOn([repositionPopups()], {}));
21398
      };
21399
      const additionalBehaviours = editor.inline ? [] : getIframeBehaviours();
21400
      return [
21401
        Focusing.config({}),
21402
        Docking.config({
21403
          contextual: {
21404
            lazyContext: comp => {
21405
              const headerHeight = getOuter$2(comp.element);
21406
              const container = editor.inline ? editor.getContentAreaContainer() : editor.getContainer();
21407
              return Optional.from(container).map(c => {
21408
                const box = box$1(SugarElement.fromDom(c));
21409
                const optScrollingContext = detectWhenSplitUiMode(editor, comp.element);
21410
                return optScrollingContext.fold(() => {
21411
                  const boxHeight = box.height - headerHeight;
21412
                  const topBound = box.y + (isDockedMode(comp, 'top') ? 0 : headerHeight);
21413
                  return bounds(box.x, topBound, box.width, boxHeight);
21414
                }, scrollEnv => {
21415
                  const constrainedBounds = constrain(box, getBoundsFrom(scrollEnv));
21416
                  const constrainedBoundsY = isDockedMode(comp, 'top') ? constrainedBounds.y : constrainedBounds.y + headerHeight;
21417
                  return bounds(constrainedBounds.x, constrainedBoundsY, constrainedBounds.width, constrainedBounds.height - headerHeight);
21418
                });
21419
              });
21420
            },
21421
            onShow: () => {
21422
              runOnSinkElement(elem => updateSinkVisibility(elem, true));
21423
            },
21424
            onShown: comp => {
1441 ariadna 21425
              runOnSinkElement(elem => remove$2(elem, [
1 efrain 21426
                visibility.transitionClass,
21427
                visibility.fadeInClass
21428
              ]));
21429
              focusedElm.get().each(elem => {
21430
                restoreFocus(comp.element, elem);
21431
                focusedElm.clear();
21432
              });
21433
            },
21434
            onHide: comp => {
21435
              findFocusedElem(comp.element, lazySink).fold(focusedElm.clear, focusedElm.set);
21436
              runOnSinkElement(elem => updateSinkVisibility(elem, false));
21437
            },
21438
            onHidden: () => {
1441 ariadna 21439
              runOnSinkElement(elem => remove$2(elem, [visibility.transitionClass]));
1 efrain 21440
            },
21441
            ...visibility
21442
          },
21443
          lazyViewport: comp => {
21444
            const optScrollingContext = detectWhenSplitUiMode(editor, comp.element);
21445
            return optScrollingContext.fold(() => {
21446
              const boundsWithoutOffset = win();
21447
              const offset = getStickyToolbarOffset(editor);
1441 ariadna 21448
              const top = boundsWithoutOffset.y + (isDockedMode(comp, 'top') && !isFullscreen(editor) ? offset : 0);
1 efrain 21449
              const height = boundsWithoutOffset.height - (isDockedMode(comp, 'bottom') ? offset : 0);
21450
              return {
21451
                bounds: bounds(boundsWithoutOffset.x, top, boundsWithoutOffset.width, height),
21452
                optScrollEnv: Optional.none()
21453
              };
21454
            }, sc => {
21455
              const combinedBounds = getBoundsFrom(sc);
21456
              return {
21457
                bounds: combinedBounds,
21458
                optScrollEnv: Optional.some({
21459
                  currentScrollTop: sc.element.dom.scrollTop,
21460
                  scrollElmTop: absolute$3(sc.element).top
21461
                })
21462
              };
21463
            });
21464
          },
21465
          modes: [sharedBackstage.header.getDockingMode()],
21466
          onDocked: onDockingSwitch,
21467
          onUndocked: onDockingSwitch
21468
        }),
21469
        ...additionalBehaviours
21470
      ];
21471
    };
21472
 
21473
    var StickyHeader = /*#__PURE__*/Object.freeze({
21474
        __proto__: null,
21475
        setup: setup$9,
21476
        isDocked: isDocked,
21477
        getBehaviours: getBehaviours
21478
    });
21479
 
21480
    const renderHeader = spec => {
21481
      const editor = spec.editor;
21482
      const getBehaviours$2 = spec.sticky ? getBehaviours : getBehaviours$1;
21483
      return {
21484
        uid: spec.uid,
21485
        dom: spec.dom,
21486
        components: spec.components,
21487
        behaviours: derive$1(getBehaviours$2(editor, spec.sharedBackstage))
21488
      };
21489
    };
21490
 
21491
    const groupToolbarButtonSchema = objOf([
21492
      type,
21493
      requiredOf('items', oneOf([
21494
        arrOfObj([
21495
          name$1,
21496
          requiredArrayOf('items', string)
21497
        ]),
21498
        string
21499
      ]))
21500
    ].concat(baseToolbarButtonFields));
21501
    const createGroupToolbarButton = spec => asRaw('GroupToolbarButton', groupToolbarButtonSchema, spec);
21502
 
21503
    const baseMenuButtonFields = [
21504
      optionString('text'),
21505
      optionString('tooltip'),
21506
      optionString('icon'),
21507
      defaultedOf('search', false, oneOf([
21508
        boolean,
21509
        objOf([optionString('placeholder')])
21510
      ], x => {
21511
        if (isBoolean(x)) {
21512
          return x ? Optional.some({ placeholder: Optional.none() }) : Optional.none();
21513
        } else {
21514
          return Optional.some(x);
21515
        }
21516
      })),
21517
      requiredFunction('fetch'),
1441 ariadna 21518
      defaultedFunction('onSetup', () => noop),
21519
      defaultedString('context', 'mode:design')
1 efrain 21520
    ];
21521
 
21522
    const MenuButtonSchema = objOf([
21523
      type,
21524
      ...baseMenuButtonFields
21525
    ]);
21526
    const createMenuButton = spec => asRaw('menubutton', MenuButtonSchema, spec);
21527
 
21528
    const splitButtonSchema = objOf([
21529
      type,
21530
      optionalTooltip,
21531
      optionalIcon,
21532
      optionalText,
21533
      optionalSelect,
21534
      fetch$1,
21535
      onSetup,
21536
      defaultedStringEnum('presets', 'normal', [
21537
        'normal',
21538
        'color',
21539
        'listpreview'
21540
      ]),
21541
      defaultedColumns(1),
21542
      onAction,
1441 ariadna 21543
      onItemAction,
21544
      defaultedString('context', 'mode:design')
1 efrain 21545
    ]);
21546
    const createSplitButton = spec => asRaw('SplitButton', splitButtonSchema, spec);
21547
 
21548
    const factory$d = (detail, spec) => {
21549
      const setMenus = (comp, menus) => {
21550
        const newMenus = map$2(menus, m => {
21551
          const buttonSpec = {
21552
            type: 'menubutton',
21553
            text: m.text,
21554
            fetch: callback => {
21555
              callback(m.getItems());
1441 ariadna 21556
            },
21557
            context: 'any'
1 efrain 21558
          };
21559
          const internal = createMenuButton(buttonSpec).mapError(errInfo => formatError(errInfo)).getOrDie();
21560
          return renderMenuButton(internal, 'tox-mbtn', spec.backstage, Optional.some('menuitem'));
21561
        });
21562
        Replacing.set(comp, newMenus);
21563
      };
21564
      const apis = {
21565
        focus: Keying.focusIn,
21566
        setMenus
21567
      };
21568
      return {
21569
        uid: detail.uid,
21570
        dom: detail.dom,
21571
        components: [],
21572
        behaviours: derive$1([
21573
          Replacing.config({}),
21574
          config('menubar-events', [
21575
            runOnAttached(component => {
21576
              detail.onSetup(component);
21577
            }),
21578
            run$1(mouseover(), (comp, se) => {
21579
              descendant(comp.element, '.' + 'tox-mbtn--active').each(activeButton => {
21580
                closest$1(se.event.target, '.' + 'tox-mbtn').each(hoveredButton => {
21581
                  if (!eq(activeButton, hoveredButton)) {
21582
                    comp.getSystem().getByDom(activeButton).each(activeComp => {
21583
                      comp.getSystem().getByDom(hoveredButton).each(hoveredComp => {
21584
                        Dropdown.expand(hoveredComp);
21585
                        Dropdown.close(activeComp);
21586
                        Focusing.focus(hoveredComp);
21587
                      });
21588
                    });
21589
                  }
21590
                });
21591
              });
21592
            }),
21593
            run$1(focusShifted(), (comp, se) => {
21594
              se.event.prevFocus.bind(prev => comp.getSystem().getByDom(prev).toOptional()).each(prev => {
21595
                se.event.newFocus.bind(nu => comp.getSystem().getByDom(nu).toOptional()).each(nu => {
21596
                  if (Dropdown.isOpen(prev)) {
21597
                    Dropdown.expand(nu);
21598
                    Dropdown.close(prev);
21599
                  }
21600
                });
21601
              });
21602
            })
21603
          ]),
21604
          Keying.config({
21605
            mode: 'flow',
21606
            selector: '.' + 'tox-mbtn',
21607
            onEscape: comp => {
21608
              detail.onEscape(comp);
21609
              return Optional.some(true);
21610
            }
21611
          }),
21612
          Tabstopping.config({})
21613
        ]),
21614
        apis,
21615
        domModification: { attributes: { role: 'menubar' } }
21616
      };
21617
    };
21618
    var SilverMenubar = single({
21619
      factory: factory$d,
21620
      name: 'silver.Menubar',
21621
      configFields: [
21622
        required$1('dom'),
21623
        required$1('uid'),
21624
        required$1('onEscape'),
21625
        required$1('backstage'),
21626
        defaulted('onSetup', noop)
21627
      ],
21628
      apis: {
21629
        focus: (apis, comp) => {
21630
          apis.focus(comp);
21631
        },
21632
        setMenus: (apis, comp, menus) => {
21633
          apis.setMenus(comp, menus);
21634
        }
21635
      }
21636
    });
21637
 
21638
    const promotionMessage = '\u26A1\ufe0fUpgrade';
21639
    const promotionLink = 'https://www.tiny.cloud/tinymce-self-hosted-premium-features/?utm_campaign=self_hosted_upgrade_promo&utm_source=tiny&utm_medium=referral';
21640
    const renderPromotion = spec => {
21641
      return {
21642
        uid: spec.uid,
21643
        dom: spec.dom,
21644
        components: [{
21645
            dom: {
21646
              tag: 'a',
21647
              attributes: {
21648
                'href': promotionLink,
21649
                'rel': 'noopener',
21650
                'target': '_blank',
21651
                'aria-hidden': 'true'
21652
              },
21653
              classes: ['tox-promotion-link'],
21654
              innerHtml: promotionMessage
21655
            }
21656
          }]
21657
      };
21658
    };
21659
 
21660
    const owner = 'container';
21661
    const schema$d = [field('slotBehaviours', [])];
21662
    const getPartName = name => '<alloy.field.' + name + '>';
21663
    const sketch = sSpec => {
21664
      const parts = (() => {
21665
        const record = [];
21666
        const slot = (name, config) => {
21667
          record.push(name);
21668
          return generateOne$1(owner, getPartName(name), config);
21669
        };
21670
        return {
21671
          slot,
21672
          record: constant$1(record)
21673
        };
21674
      })();
21675
      const spec = sSpec(parts);
21676
      const partNames = parts.record();
21677
      const fieldParts = map$2(partNames, n => required({
21678
        name: n,
21679
        pname: getPartName(n)
21680
      }));
21681
      return composite$1(owner, schema$d, fieldParts, make$1, spec);
21682
    };
21683
    const make$1 = (detail, components) => {
21684
      const getSlotNames = _ => getAllPartNames(detail);
21685
      const getSlot = (container, key) => getPart(container, detail, key);
21686
      const onSlot = (f, def) => (container, key) => getPart(container, detail, key).map(slot => f(slot, key)).getOr(def);
21687
      const onSlots = f => (container, keys) => {
21688
        each$1(keys, key => f(container, key));
21689
      };
1441 ariadna 21690
      const doShowing = (comp, _key) => get$g(comp.element, 'aria-hidden') !== 'true';
1 efrain 21691
      const doShow = (comp, key) => {
21692
        if (!doShowing(comp)) {
21693
          const element = comp.element;
1441 ariadna 21694
          remove$7(element, 'display');
21695
          remove$8(element, 'aria-hidden');
1 efrain 21696
          emitWith(comp, slotVisibility(), {
21697
            name: key,
21698
            visible: true
21699
          });
21700
        }
21701
      };
21702
      const doHide = (comp, key) => {
21703
        if (doShowing(comp)) {
21704
          const element = comp.element;
21705
          set$8(element, 'display', 'none');
21706
          set$9(element, 'aria-hidden', 'true');
21707
          emitWith(comp, slotVisibility(), {
21708
            name: key,
21709
            visible: false
21710
          });
21711
        }
21712
      };
21713
      const isShowing = onSlot(doShowing, false);
21714
      const hideSlot = onSlot(doHide);
21715
      const hideSlots = onSlots(hideSlot);
21716
      const hideAllSlots = container => hideSlots(container, getSlotNames());
21717
      const showSlot = onSlot(doShow);
21718
      const apis = {
21719
        getSlotNames,
21720
        getSlot,
21721
        isShowing,
21722
        hideSlot,
21723
        hideAllSlots,
21724
        showSlot
21725
      };
21726
      return {
21727
        uid: detail.uid,
21728
        dom: detail.dom,
21729
        components,
1441 ariadna 21730
        behaviours: get$4(detail.slotBehaviours),
1 efrain 21731
        apis
21732
      };
21733
    };
21734
    const slotApis = map$1({
21735
      getSlotNames: (apis, c) => apis.getSlotNames(c),
21736
      getSlot: (apis, c, key) => apis.getSlot(c, key),
21737
      isShowing: (apis, c, key) => apis.isShowing(c, key),
21738
      hideSlot: (apis, c, key) => apis.hideSlot(c, key),
21739
      hideAllSlots: (apis, c) => apis.hideAllSlots(c),
21740
      showSlot: (apis, c, key) => apis.showSlot(c, key)
21741
    }, value => makeApi(value));
21742
    const SlotContainer = {
21743
      ...slotApis,
21744
      ...{ sketch }
21745
    };
21746
 
21747
    const sidebarSchema = objOf([
21748
      optionalIcon,
21749
      optionalTooltip,
21750
      defaultedFunction('onShow', noop),
21751
      defaultedFunction('onHide', noop),
21752
      onSetup
21753
    ]);
21754
    const createSidebar = spec => asRaw('sidebar', sidebarSchema, spec);
21755
 
21756
    const setup$8 = editor => {
21757
      const {sidebars} = editor.ui.registry.getAll();
21758
      each$1(keys(sidebars), name => {
21759
        const spec = sidebars[name];
21760
        const isActive = () => is$1(Optional.from(editor.queryCommandValue('ToggleSidebar')), name);
21761
        editor.ui.registry.addToggleButton(name, {
21762
          icon: spec.icon,
21763
          tooltip: spec.tooltip,
21764
          onAction: buttonApi => {
21765
            editor.execCommand('ToggleSidebar', false, name);
21766
            buttonApi.setActive(isActive());
21767
          },
21768
          onSetup: buttonApi => {
21769
            buttonApi.setActive(isActive());
21770
            const handleToggle = () => buttonApi.setActive(isActive());
21771
            editor.on('ToggleSidebar', handleToggle);
21772
            return () => {
21773
              editor.off('ToggleSidebar', handleToggle);
21774
            };
1441 ariadna 21775
          },
21776
          context: 'any'
1 efrain 21777
        });
21778
      });
21779
    };
21780
    const getApi = comp => ({ element: () => comp.element.dom });
21781
    const makePanels = (parts, panelConfigs) => {
21782
      const specs = map$2(keys(panelConfigs), name => {
21783
        const spec = panelConfigs[name];
21784
        const bridged = getOrDie(createSidebar(spec));
21785
        return {
21786
          name,
21787
          getApi,
21788
          onSetup: bridged.onSetup,
21789
          onShow: bridged.onShow,
21790
          onHide: bridged.onHide
21791
        };
21792
      });
21793
      return map$2(specs, spec => {
21794
        const editorOffCell = Cell(noop);
21795
        return parts.slot(spec.name, {
21796
          dom: {
21797
            tag: 'div',
21798
            classes: ['tox-sidebar__pane']
21799
          },
21800
          behaviours: SimpleBehaviours.unnamedEvents([
21801
            onControlAttached(spec, editorOffCell),
21802
            onControlDetached(spec, editorOffCell),
21803
            run$1(slotVisibility(), (sidepanel, se) => {
21804
              const data = se.event;
21805
              const optSidePanelSpec = find$5(specs, config => config.name === data.name);
21806
              optSidePanelSpec.each(sidePanelSpec => {
21807
                const handler = data.visible ? sidePanelSpec.onShow : sidePanelSpec.onHide;
21808
                handler(sidePanelSpec.getApi(sidepanel));
21809
              });
21810
            })
21811
          ])
21812
        });
21813
      });
21814
    };
21815
    const makeSidebar = panelConfigs => SlotContainer.sketch(parts => ({
21816
      dom: {
21817
        tag: 'div',
21818
        classes: ['tox-sidebar__pane-container']
21819
      },
21820
      components: makePanels(parts, panelConfigs),
21821
      slotBehaviours: SimpleBehaviours.unnamedEvents([runOnAttached(slotContainer => SlotContainer.hideAllSlots(slotContainer))])
21822
    }));
21823
    const setSidebar = (sidebar, panelConfigs, showSidebar) => {
21824
      const optSlider = Composing.getCurrent(sidebar);
21825
      optSlider.each(slider => {
21826
        Replacing.set(slider, [makeSidebar(panelConfigs)]);
21827
        const configKey = showSidebar === null || showSidebar === void 0 ? void 0 : showSidebar.toLowerCase();
21828
        if (isString(configKey) && has$2(panelConfigs, configKey)) {
21829
          Composing.getCurrent(slider).each(slotContainer => {
21830
            SlotContainer.showSlot(slotContainer, configKey);
21831
            Sliding.immediateGrow(slider);
1441 ariadna 21832
            remove$7(slider.element, 'width');
1 efrain 21833
            updateSidebarRoleOnToggle(sidebar.element, 'region');
21834
          });
21835
        }
21836
      });
21837
    };
21838
    const updateSidebarRoleOnToggle = (sidebar, sidebarState) => {
21839
      set$9(sidebar, 'role', sidebarState);
21840
    };
21841
    const toggleSidebar = (sidebar, name) => {
21842
      const optSlider = Composing.getCurrent(sidebar);
21843
      optSlider.each(slider => {
21844
        const optSlotContainer = Composing.getCurrent(slider);
21845
        optSlotContainer.each(slotContainer => {
21846
          if (Sliding.hasGrown(slider)) {
21847
            if (SlotContainer.isShowing(slotContainer, name)) {
21848
              Sliding.shrink(slider);
21849
              updateSidebarRoleOnToggle(sidebar.element, 'presentation');
21850
            } else {
21851
              SlotContainer.hideAllSlots(slotContainer);
21852
              SlotContainer.showSlot(slotContainer, name);
21853
              updateSidebarRoleOnToggle(sidebar.element, 'region');
21854
            }
21855
          } else {
21856
            SlotContainer.hideAllSlots(slotContainer);
21857
            SlotContainer.showSlot(slotContainer, name);
21858
            Sliding.grow(slider);
21859
            updateSidebarRoleOnToggle(sidebar.element, 'region');
21860
          }
21861
        });
21862
      });
21863
    };
21864
    const whichSidebar = sidebar => {
21865
      const optSlider = Composing.getCurrent(sidebar);
21866
      return optSlider.bind(slider => {
21867
        const sidebarOpen = Sliding.isGrowing(slider) || Sliding.hasGrown(slider);
21868
        if (sidebarOpen) {
21869
          const optSlotContainer = Composing.getCurrent(slider);
21870
          return optSlotContainer.bind(slotContainer => find$5(SlotContainer.getSlotNames(slotContainer), name => SlotContainer.isShowing(slotContainer, name)));
21871
        } else {
21872
          return Optional.none();
21873
        }
21874
      });
21875
    };
21876
    const fixSize = generate$6('FixSizeEvent');
21877
    const autoSize = generate$6('AutoSizeEvent');
21878
    const renderSidebar = spec => ({
21879
      uid: spec.uid,
21880
      dom: {
21881
        tag: 'div',
21882
        classes: ['tox-sidebar'],
21883
        attributes: { role: 'presentation' }
21884
      },
21885
      components: [{
21886
          dom: {
21887
            tag: 'div',
21888
            classes: ['tox-sidebar__slider']
21889
          },
21890
          components: [],
21891
          behaviours: derive$1([
21892
            Tabstopping.config({}),
21893
            Focusing.config({}),
21894
            Sliding.config({
21895
              dimension: { property: 'width' },
21896
              closedClass: 'tox-sidebar--sliding-closed',
21897
              openClass: 'tox-sidebar--sliding-open',
21898
              shrinkingClass: 'tox-sidebar--sliding-shrinking',
21899
              growingClass: 'tox-sidebar--sliding-growing',
21900
              onShrunk: slider => {
21901
                const optSlotContainer = Composing.getCurrent(slider);
21902
                optSlotContainer.each(SlotContainer.hideAllSlots);
21903
                emit(slider, autoSize);
21904
              },
21905
              onGrown: slider => {
21906
                emit(slider, autoSize);
21907
              },
21908
              onStartGrow: slider => {
21909
                emitWith(slider, fixSize, { width: getRaw(slider.element, 'width').getOr('') });
21910
              },
21911
              onStartShrink: slider => {
1441 ariadna 21912
                emitWith(slider, fixSize, { width: get$d(slider.element) + 'px' });
1 efrain 21913
              }
21914
            }),
21915
            Replacing.config({}),
21916
            Composing.config({
21917
              find: comp => {
21918
                const children = Replacing.contents(comp);
21919
                return head(children);
21920
              }
21921
            })
21922
          ])
21923
        }],
21924
      behaviours: derive$1([
21925
        ComposingConfigs.childAt(0),
21926
        config('sidebar-sliding-events', [
21927
          run$1(fixSize, (comp, se) => {
21928
            set$8(comp.element, 'width', se.event.width);
21929
          }),
21930
          run$1(autoSize, (comp, _se) => {
1441 ariadna 21931
            remove$7(comp.element, 'width');
1 efrain 21932
          })
21933
        ])
21934
      ])
21935
    });
21936
 
21937
    const block = (component, config, state, getBusySpec) => {
21938
      set$9(component.element, 'aria-busy', true);
21939
      const root = config.getRoot(component).getOr(component);
21940
      const blockerBehaviours = derive$1([
21941
        Keying.config({
21942
          mode: 'special',
21943
          onTab: () => Optional.some(true),
21944
          onShiftTab: () => Optional.some(true)
21945
        }),
21946
        Focusing.config({})
21947
      ]);
21948
      const blockSpec = getBusySpec(root, blockerBehaviours);
21949
      const blocker = root.getSystem().build(blockSpec);
21950
      Replacing.append(root, premade(blocker));
21951
      if (blocker.hasConfigured(Keying) && config.focus) {
21952
        Keying.focusIn(blocker);
21953
      }
21954
      if (!state.isBlocked()) {
21955
        config.onBlock(component);
21956
      }
21957
      state.blockWith(() => Replacing.remove(root, blocker));
21958
    };
21959
    const unblock = (component, config, state) => {
1441 ariadna 21960
      remove$8(component.element, 'aria-busy');
1 efrain 21961
      if (state.isBlocked()) {
21962
        config.onUnblock(component);
21963
      }
21964
      state.clear();
21965
    };
21966
    const isBlocked = (component, blockingConfig, blockingState) => blockingState.isBlocked();
21967
 
21968
    var BlockingApis = /*#__PURE__*/Object.freeze({
21969
        __proto__: null,
21970
        block: block,
21971
        unblock: unblock,
21972
        isBlocked: isBlocked
21973
    });
21974
 
21975
    var BlockingSchema = [
21976
      defaultedFunction('getRoot', Optional.none),
21977
      defaultedBoolean('focus', true),
21978
      onHandler('onBlock'),
21979
      onHandler('onUnblock')
21980
    ];
21981
 
21982
    const init$4 = () => {
21983
      const blocker = destroyable();
21984
      const blockWith = destroy => {
21985
        blocker.set({ destroy });
21986
      };
1441 ariadna 21987
      return nu$7({
1 efrain 21988
        readState: blocker.isSet,
21989
        blockWith,
21990
        clear: blocker.clear,
21991
        isBlocked: blocker.isSet
21992
      });
21993
    };
21994
 
21995
    var BlockingState = /*#__PURE__*/Object.freeze({
21996
        __proto__: null,
21997
        init: init$4
21998
    });
21999
 
22000
    const Blocking = create$4({
22001
      fields: BlockingSchema,
22002
      name: 'blocking',
22003
      apis: BlockingApis,
22004
      state: BlockingState
22005
    });
22006
 
22007
    const getBusySpec$1 = providerBackstage => (_root, _behaviours) => ({
22008
      dom: {
22009
        tag: 'div',
22010
        attributes: {
22011
          'aria-label': providerBackstage.translate('Loading...'),
22012
          'tabindex': '0'
22013
        },
22014
        classes: ['tox-throbber__busy-spinner']
22015
      },
22016
      components: [{ dom: fromHtml('<div class="tox-spinner"><div></div><div></div><div></div></div>') }]
22017
    });
22018
    const focusBusyComponent = throbber => Composing.getCurrent(throbber).each(comp => focus$3(comp.element, true));
22019
    const toggleEditorTabIndex = (editor, state) => {
22020
      const tabIndexAttr = 'tabindex';
22021
      const dataTabIndexAttr = `data-mce-${ tabIndexAttr }`;
22022
      Optional.from(editor.iframeElement).map(SugarElement.fromDom).each(iframe => {
22023
        if (state) {
22024
          getOpt(iframe, tabIndexAttr).each(tabIndex => set$9(iframe, dataTabIndexAttr, tabIndex));
22025
          set$9(iframe, tabIndexAttr, -1);
22026
        } else {
1441 ariadna 22027
          remove$8(iframe, tabIndexAttr);
1 efrain 22028
          getOpt(iframe, dataTabIndexAttr).each(tabIndex => {
22029
            set$9(iframe, tabIndexAttr, tabIndex);
1441 ariadna 22030
            remove$8(iframe, dataTabIndexAttr);
1 efrain 22031
          });
22032
        }
22033
      });
22034
    };
22035
    const toggleThrobber = (editor, comp, state, providerBackstage) => {
22036
      const element = comp.element;
22037
      toggleEditorTabIndex(editor, state);
22038
      if (state) {
22039
        Blocking.block(comp, getBusySpec$1(providerBackstage));
1441 ariadna 22040
        remove$7(element, 'display');
22041
        remove$8(element, 'aria-hidden');
1 efrain 22042
        if (editor.hasFocus()) {
22043
          focusBusyComponent(comp);
22044
        }
22045
      } else {
22046
        const throbberFocus = Composing.getCurrent(comp).exists(busyComp => hasFocus(busyComp.element));
22047
        Blocking.unblock(comp);
22048
        set$8(element, 'display', 'none');
22049
        set$9(element, 'aria-hidden', 'true');
22050
        if (throbberFocus) {
22051
          editor.focus();
22052
        }
22053
      }
22054
    };
22055
    const renderThrobber = spec => ({
22056
      uid: spec.uid,
22057
      dom: {
22058
        tag: 'div',
22059
        attributes: { 'aria-hidden': 'true' },
22060
        classes: ['tox-throbber'],
22061
        styles: { display: 'none' }
22062
      },
22063
      behaviours: derive$1([
22064
        Replacing.config({}),
22065
        Blocking.config({ focus: false }),
22066
        Composing.config({ find: comp => head(comp.components()) })
22067
      ]),
22068
      components: []
22069
    });
22070
    const isFocusEvent = event => event.type === 'focusin';
22071
    const isPasteBinTarget = event => {
22072
      if (isFocusEvent(event)) {
22073
        const node = event.composed ? head(event.composedPath()) : Optional.from(event.target);
22074
        return node.map(SugarElement.fromDom).filter(isElement$1).exists(targetElm => has(targetElm, 'mce-pastebin'));
22075
      } else {
22076
        return false;
22077
      }
22078
    };
22079
    const setup$7 = (editor, lazyThrobber, sharedBackstage) => {
22080
      const throbberState = Cell(false);
1441 ariadna 22081
      const timer = value$4();
1 efrain 22082
      const stealFocus = e => {
22083
        if (throbberState.get() && !isPasteBinTarget(e)) {
22084
          e.preventDefault();
22085
          focusBusyComponent(lazyThrobber());
22086
          editor.editorManager.setActive(editor);
22087
        }
22088
      };
22089
      if (!editor.inline) {
22090
        editor.on('PreInit', () => {
22091
          editor.dom.bind(editor.getWin(), 'focusin', stealFocus);
22092
          editor.on('BeforeExecCommand', e => {
22093
            if (e.command.toLowerCase() === 'mcefocus' && e.value !== true) {
22094
              stealFocus(e);
22095
            }
22096
          });
22097
        });
22098
      }
22099
      const toggle = state => {
22100
        if (state !== throbberState.get()) {
22101
          throbberState.set(state);
22102
          toggleThrobber(editor, lazyThrobber(), state, sharedBackstage.providers);
22103
          fireAfterProgressState(editor, state);
22104
        }
22105
      };
22106
      editor.on('ProgressState', e => {
22107
        timer.on(clearTimeout);
22108
        if (isNumber(e.time)) {
22109
          const timerId = global$9.setEditorTimeout(editor, () => toggle(e.state), e.time);
22110
          timer.set(timerId);
22111
        } else {
22112
          toggle(e.state);
22113
          timer.clear();
22114
        }
22115
      });
22116
    };
22117
 
22118
    const generate$1 = (xs, f) => {
22119
      const init = {
22120
        len: 0,
22121
        list: []
22122
      };
22123
      const r = foldl(xs, (b, a) => {
22124
        const value = f(a, b.len);
22125
        return value.fold(constant$1(b), v => ({
22126
          len: v.finish,
22127
          list: b.list.concat([v])
22128
        }));
22129
      }, init);
22130
      return r.list;
22131
    };
22132
 
22133
    const output = (within, extra, withinWidth) => ({
22134
      within,
22135
      extra,
22136
      withinWidth
22137
    });
22138
    const apportion = (units, total, len) => {
22139
      const parray = generate$1(units, (unit, current) => {
22140
        const width = len(unit);
22141
        return Optional.some({
22142
          element: unit,
22143
          start: current,
22144
          finish: current + width,
22145
          width
22146
        });
22147
      });
22148
      const within = filter$2(parray, unit => unit.finish <= total);
22149
      const withinWidth = foldr(within, (acc, el) => acc + el.width, 0);
22150
      const extra = parray.slice(within.length);
22151
      return {
22152
        within,
22153
        extra,
22154
        withinWidth
22155
      };
22156
    };
22157
    const toUnit = parray => map$2(parray, unit => unit.element);
22158
    const fitLast = (within, extra, withinWidth) => {
22159
      const fits = toUnit(within.concat(extra));
22160
      return output(fits, [], withinWidth);
22161
    };
22162
    const overflow = (within, extra, overflower, withinWidth) => {
22163
      const fits = toUnit(within).concat([overflower]);
22164
      return output(fits, toUnit(extra), withinWidth);
22165
    };
22166
    const fitAll = (within, extra, withinWidth) => output(toUnit(within), [], withinWidth);
22167
    const tryFit = (total, units, len) => {
22168
      const divide = apportion(units, total, len);
22169
      return divide.extra.length === 0 ? Optional.some(divide) : Optional.none();
22170
    };
22171
    const partition = (total, units, len, overflower) => {
22172
      const divide = tryFit(total, units, len).getOrThunk(() => apportion(units, total - len(overflower), len));
22173
      const within = divide.within;
22174
      const extra = divide.extra;
22175
      const withinWidth = divide.withinWidth;
22176
      if (extra.length === 1 && extra[0].width <= len(overflower)) {
22177
        return fitLast(within, extra, withinWidth);
22178
      } else if (extra.length >= 1) {
22179
        return overflow(within, extra, overflower, withinWidth);
22180
      } else {
22181
        return fitAll(within, extra, withinWidth);
22182
      }
22183
    };
22184
 
22185
    const setGroups$1 = (toolbar, storedGroups) => {
22186
      const bGroups = map$2(storedGroups, g => premade(g));
22187
      Toolbar.setGroups(toolbar, bGroups);
22188
    };
22189
    const findFocusedComp = comps => findMap(comps, comp => search(comp.element).bind(focusedElm => comp.getSystem().getByDom(focusedElm).toOptional()));
22190
    const refresh$2 = (toolbar, detail, setOverflow) => {
22191
      const builtGroups = detail.builtGroups.get();
22192
      if (builtGroups.length === 0) {
22193
        return;
22194
      }
22195
      const primary = getPartOrDie(toolbar, detail, 'primary');
22196
      const overflowGroup = Coupling.getCoupled(toolbar, 'overflowGroup');
22197
      set$8(primary.element, 'visibility', 'hidden');
22198
      const groups = builtGroups.concat([overflowGroup]);
22199
      const focusedComp = findFocusedComp(groups);
22200
      setOverflow([]);
22201
      setGroups$1(primary, groups);
1441 ariadna 22202
      const availableWidth = get$d(primary.element);
22203
      const overflows = partition(availableWidth, detail.builtGroups.get(), comp => Math.ceil(comp.element.dom.getBoundingClientRect().width), overflowGroup);
1 efrain 22204
      if (overflows.extra.length === 0) {
22205
        Replacing.remove(primary, overflowGroup);
22206
        setOverflow([]);
22207
      } else {
22208
        setGroups$1(primary, overflows.within);
22209
        setOverflow(overflows.extra);
22210
      }
1441 ariadna 22211
      remove$7(primary.element, 'visibility');
1 efrain 22212
      reflow(primary.element);
22213
      focusedComp.each(Focusing.focus);
22214
    };
22215
 
22216
    const schema$c = constant$1([
22217
      field('splitToolbarBehaviours', [Coupling]),
22218
      customField('builtGroups', () => Cell([]))
22219
    ]);
22220
 
22221
    const schema$b = constant$1([
22222
      markers$1(['overflowToggledClass']),
22223
      optionFunction('getOverflowBounds'),
22224
      required$1('lazySink'),
22225
      customField('overflowGroups', () => Cell([])),
22226
      onHandler('onOpened'),
22227
      onHandler('onClosed')
22228
    ].concat(schema$c()));
22229
    const parts$7 = constant$1([
22230
      required({
22231
        factory: Toolbar,
22232
        schema: schema$e(),
22233
        name: 'primary'
22234
      }),
22235
      external({
22236
        schema: schema$e(),
22237
        name: 'overflow'
22238
      }),
22239
      external({ name: 'overflow-button' }),
22240
      external({ name: 'overflow-group' })
22241
    ]);
22242
 
22243
    const expandable = constant$1((element, available) => {
22244
      setMax(element, Math.floor(available));
22245
    });
22246
 
22247
    const schema$a = constant$1([
22248
      markers$1(['toggledClass']),
22249
      required$1('lazySink'),
22250
      requiredFunction('fetch'),
22251
      optionFunction('getBounds'),
22252
      optionObjOf('fireDismissalEventInstead', [defaulted('event', dismissRequested())]),
22253
      schema$y(),
22254
      onHandler('onToggled')
22255
    ]);
22256
    const parts$6 = constant$1([
22257
      external({
22258
        name: 'button',
22259
        overrides: detail => ({
22260
          dom: { attributes: { 'aria-haspopup': 'true' } },
22261
          buttonBehaviours: derive$1([Toggling.config({
22262
              toggleClass: detail.markers.toggledClass,
22263
              aria: { mode: 'expanded' },
22264
              toggleOnExecute: false,
22265
              onToggled: detail.onToggled
22266
            })])
22267
        })
22268
      }),
22269
      external({
22270
        factory: Toolbar,
22271
        schema: schema$e(),
22272
        name: 'toolbar',
22273
        overrides: detail => {
22274
          return {
22275
            toolbarBehaviours: derive$1([Keying.config({
22276
                mode: 'cyclic',
22277
                onEscape: comp => {
22278
                  getPart(comp, detail, 'button').each(Focusing.focus);
22279
                  return Optional.none();
22280
                }
22281
              })])
22282
          };
22283
        }
22284
      })
22285
    ]);
22286
 
1441 ariadna 22287
    const shouldSkipFocus = value$4();
1 efrain 22288
    const toggleWithoutFocusing = (button, externals) => {
22289
      shouldSkipFocus.set(true);
22290
      toggle(button, externals);
22291
      shouldSkipFocus.clear();
22292
    };
22293
    const toggle = (button, externals) => {
22294
      const toolbarSandbox = Coupling.getCoupled(button, 'toolbarSandbox');
22295
      if (Sandboxing.isOpen(toolbarSandbox)) {
22296
        Sandboxing.close(toolbarSandbox);
22297
      } else {
22298
        Sandboxing.open(toolbarSandbox, externals.toolbar());
22299
      }
22300
    };
22301
    const position = (button, toolbar, detail, layouts) => {
22302
      const bounds = detail.getBounds.map(bounder => bounder());
22303
      const sink = detail.lazySink(button).getOrDie();
22304
      Positioning.positionWithinBounds(sink, toolbar, {
22305
        anchor: {
22306
          type: 'hotspot',
22307
          hotspot: button,
22308
          layouts,
22309
          overrides: { maxWidthFunction: expandable() }
22310
        }
22311
      }, bounds);
22312
    };
22313
    const setGroups = (button, toolbar, detail, layouts, groups) => {
22314
      Toolbar.setGroups(toolbar, groups);
22315
      position(button, toolbar, detail, layouts);
22316
      Toggling.on(button);
22317
    };
22318
    const makeSandbox = (button, spec, detail) => {
22319
      const ariaControls = manager();
22320
      const onOpen = (sandbox, toolbar) => {
22321
        const skipFocus = shouldSkipFocus.get().getOr(false);
22322
        detail.fetch().get(groups => {
22323
          setGroups(button, toolbar, detail, spec.layouts, groups);
22324
          ariaControls.link(button.element);
22325
          if (!skipFocus) {
22326
            Keying.focusIn(toolbar);
22327
          }
22328
        });
22329
      };
22330
      const onClose = () => {
22331
        Toggling.off(button);
22332
        if (!shouldSkipFocus.get().getOr(false)) {
22333
          Focusing.focus(button);
22334
        }
22335
        ariaControls.unlink(button.element);
22336
      };
22337
      return {
22338
        dom: {
22339
          tag: 'div',
22340
          attributes: { id: ariaControls.id }
22341
        },
22342
        behaviours: derive$1([
22343
          Keying.config({
22344
            mode: 'special',
22345
            onEscape: comp => {
22346
              Sandboxing.close(comp);
22347
              return Optional.some(true);
22348
            }
22349
          }),
22350
          Sandboxing.config({
22351
            onOpen,
22352
            onClose,
22353
            isPartOf: (container, data, queryElem) => {
22354
              return isPartOf$1(data, queryElem) || isPartOf$1(button, queryElem);
22355
            },
22356
            getAttachPoint: () => {
22357
              return detail.lazySink(button).getOrDie();
22358
            }
22359
          }),
22360
          Receiving.config({
22361
            channels: {
22362
              ...receivingChannel$1({
22363
                isExtraPart: never,
22364
                ...detail.fireDismissalEventInstead.map(fe => ({ fireEventInstead: { event: fe.event } })).getOr({})
22365
              }),
22366
              ...receivingChannel({
22367
                doReposition: () => {
22368
                  Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each(toolbar => {
22369
                    position(button, toolbar, detail, spec.layouts);
22370
                  });
22371
                }
22372
              })
22373
            }
22374
          })
22375
        ])
22376
      };
22377
    };
22378
    const factory$c = (detail, components, spec, externals) => ({
22379
      ...Button.sketch({
22380
        ...externals.button(),
22381
        action: button => {
22382
          toggle(button, externals);
22383
        },
22384
        buttonBehaviours: SketchBehaviours.augment({ dump: externals.button().buttonBehaviours }, [Coupling.config({
22385
            others: {
22386
              toolbarSandbox: button => {
22387
                return makeSandbox(button, spec, detail);
22388
              }
22389
            }
22390
          })])
22391
      }),
22392
      apis: {
22393
        setGroups: (button, groups) => {
22394
          Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each(toolbar => {
22395
            setGroups(button, toolbar, detail, spec.layouts, groups);
22396
          });
22397
        },
22398
        reposition: button => {
22399
          Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each(toolbar => {
22400
            position(button, toolbar, detail, spec.layouts);
22401
          });
22402
        },
22403
        toggle: button => {
22404
          toggle(button, externals);
22405
        },
22406
        toggleWithoutFocusing: button => {
22407
          toggleWithoutFocusing(button, externals);
22408
        },
22409
        getToolbar: button => {
22410
          return Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox'));
22411
        },
22412
        isOpen: button => {
22413
          return Sandboxing.isOpen(Coupling.getCoupled(button, 'toolbarSandbox'));
22414
        }
22415
      }
22416
    });
22417
    const FloatingToolbarButton = composite({
22418
      name: 'FloatingToolbarButton',
22419
      factory: factory$c,
22420
      configFields: schema$a(),
22421
      partFields: parts$6(),
22422
      apis: {
22423
        setGroups: (apis, button, groups) => {
22424
          apis.setGroups(button, groups);
22425
        },
22426
        reposition: (apis, button) => {
22427
          apis.reposition(button);
22428
        },
22429
        toggle: (apis, button) => {
22430
          apis.toggle(button);
22431
        },
22432
        toggleWithoutFocusing: (apis, button) => {
22433
          apis.toggleWithoutFocusing(button);
22434
        },
22435
        getToolbar: (apis, button) => apis.getToolbar(button),
22436
        isOpen: (apis, button) => apis.isOpen(button)
22437
      }
22438
    });
22439
 
22440
    const schema$9 = constant$1([
22441
      required$1('items'),
22442
      markers$1(['itemSelector']),
22443
      field('tgroupBehaviours', [Keying])
22444
    ]);
22445
    const parts$5 = constant$1([group({
22446
        name: 'items',
22447
        unit: 'item'
22448
      })]);
22449
 
22450
    const factory$b = (detail, components, _spec, _externals) => ({
22451
      uid: detail.uid,
22452
      dom: detail.dom,
22453
      components,
22454
      behaviours: augment(detail.tgroupBehaviours, [Keying.config({
22455
          mode: 'flow',
22456
          selector: detail.markers.itemSelector
22457
        })]),
22458
      domModification: { attributes: { role: 'toolbar' } }
22459
    });
22460
    const ToolbarGroup = composite({
22461
      name: 'ToolbarGroup',
22462
      configFields: schema$9(),
22463
      partFields: parts$5(),
22464
      factory: factory$b
22465
    });
22466
 
22467
    const buildGroups = comps => map$2(comps, g => premade(g));
22468
    const refresh$1 = (toolbar, memFloatingToolbarButton, detail) => {
22469
      refresh$2(toolbar, detail, overflowGroups => {
22470
        detail.overflowGroups.set(overflowGroups);
22471
        memFloatingToolbarButton.getOpt(toolbar).each(floatingToolbarButton => {
22472
          FloatingToolbarButton.setGroups(floatingToolbarButton, buildGroups(overflowGroups));
22473
        });
22474
      });
22475
    };
22476
    const factory$a = (detail, components, spec, externals) => {
22477
      const memFloatingToolbarButton = record(FloatingToolbarButton.sketch({
22478
        fetch: () => Future.nu(resolve => {
22479
          resolve(buildGroups(detail.overflowGroups.get()));
22480
        }),
22481
        layouts: {
22482
          onLtr: () => [
22483
            southwest$2,
22484
            southeast$2
22485
          ],
22486
          onRtl: () => [
22487
            southeast$2,
22488
            southwest$2
22489
          ],
22490
          onBottomLtr: () => [
22491
            northwest$2,
22492
            northeast$2
22493
          ],
22494
          onBottomRtl: () => [
22495
            northeast$2,
22496
            northwest$2
22497
          ]
22498
        },
22499
        getBounds: spec.getOverflowBounds,
22500
        lazySink: detail.lazySink,
22501
        fireDismissalEventInstead: {},
22502
        markers: { toggledClass: detail.markers.overflowToggledClass },
22503
        parts: {
22504
          button: externals['overflow-button'](),
22505
          toolbar: externals.overflow()
22506
        },
22507
        onToggled: (comp, state) => detail[state ? 'onOpened' : 'onClosed'](comp)
22508
      }));
22509
      return {
22510
        uid: detail.uid,
22511
        dom: detail.dom,
22512
        components,
22513
        behaviours: augment(detail.splitToolbarBehaviours, [Coupling.config({
22514
            others: {
22515
              overflowGroup: () => {
22516
                return ToolbarGroup.sketch({
22517
                  ...externals['overflow-group'](),
22518
                  items: [memFloatingToolbarButton.asSpec()]
22519
                });
22520
              }
22521
            }
22522
          })]),
22523
        apis: {
22524
          setGroups: (toolbar, groups) => {
22525
            detail.builtGroups.set(map$2(groups, toolbar.getSystem().build));
22526
            refresh$1(toolbar, memFloatingToolbarButton, detail);
22527
          },
22528
          refresh: toolbar => refresh$1(toolbar, memFloatingToolbarButton, detail),
22529
          toggle: toolbar => {
22530
            memFloatingToolbarButton.getOpt(toolbar).each(floatingToolbarButton => {
22531
              FloatingToolbarButton.toggle(floatingToolbarButton);
22532
            });
22533
          },
22534
          toggleWithoutFocusing: toolbar => {
22535
            memFloatingToolbarButton.getOpt(toolbar).each(FloatingToolbarButton.toggleWithoutFocusing);
22536
          },
22537
          isOpen: toolbar => memFloatingToolbarButton.getOpt(toolbar).map(FloatingToolbarButton.isOpen).getOr(false),
22538
          reposition: toolbar => {
22539
            memFloatingToolbarButton.getOpt(toolbar).each(floatingToolbarButton => {
22540
              FloatingToolbarButton.reposition(floatingToolbarButton);
22541
            });
22542
          },
22543
          getOverflow: toolbar => memFloatingToolbarButton.getOpt(toolbar).bind(FloatingToolbarButton.getToolbar)
22544
        },
22545
        domModification: { attributes: { role: 'group' } }
22546
      };
22547
    };
22548
    const SplitFloatingToolbar = composite({
22549
      name: 'SplitFloatingToolbar',
22550
      configFields: schema$b(),
22551
      partFields: parts$7(),
22552
      factory: factory$a,
22553
      apis: {
22554
        setGroups: (apis, toolbar, groups) => {
22555
          apis.setGroups(toolbar, groups);
22556
        },
22557
        refresh: (apis, toolbar) => {
22558
          apis.refresh(toolbar);
22559
        },
22560
        reposition: (apis, toolbar) => {
22561
          apis.reposition(toolbar);
22562
        },
22563
        toggle: (apis, toolbar) => {
22564
          apis.toggle(toolbar);
22565
        },
22566
        toggleWithoutFocusing: (apis, toolbar) => {
22567
          apis.toggle(toolbar);
22568
        },
22569
        isOpen: (apis, toolbar) => apis.isOpen(toolbar),
22570
        getOverflow: (apis, toolbar) => apis.getOverflow(toolbar)
22571
      }
22572
    });
22573
 
22574
    const schema$8 = constant$1([
22575
      markers$1([
22576
        'closedClass',
22577
        'openClass',
22578
        'shrinkingClass',
22579
        'growingClass',
22580
        'overflowToggledClass'
22581
      ]),
22582
      onHandler('onOpened'),
22583
      onHandler('onClosed')
22584
    ].concat(schema$c()));
22585
    const parts$4 = constant$1([
22586
      required({
22587
        factory: Toolbar,
22588
        schema: schema$e(),
22589
        name: 'primary'
22590
      }),
22591
      required({
22592
        factory: Toolbar,
22593
        schema: schema$e(),
22594
        name: 'overflow',
22595
        overrides: detail => {
22596
          return {
22597
            toolbarBehaviours: derive$1([
22598
              Sliding.config({
22599
                dimension: { property: 'height' },
22600
                closedClass: detail.markers.closedClass,
22601
                openClass: detail.markers.openClass,
22602
                shrinkingClass: detail.markers.shrinkingClass,
22603
                growingClass: detail.markers.growingClass,
22604
                onShrunk: comp => {
22605
                  getPart(comp, detail, 'overflow-button').each(button => {
22606
                    Toggling.off(button);
22607
                  });
22608
                  detail.onClosed(comp);
22609
                },
22610
                onGrown: comp => {
22611
                  detail.onOpened(comp);
22612
                },
22613
                onStartGrow: comp => {
22614
                  getPart(comp, detail, 'overflow-button').each(Toggling.on);
22615
                }
22616
              }),
22617
              Keying.config({
22618
                mode: 'acyclic',
22619
                onEscape: comp => {
22620
                  getPart(comp, detail, 'overflow-button').each(Focusing.focus);
22621
                  return Optional.some(true);
22622
                }
22623
              })
22624
            ])
22625
          };
22626
        }
22627
      }),
22628
      external({
22629
        name: 'overflow-button',
22630
        overrides: detail => ({
22631
          buttonBehaviours: derive$1([Toggling.config({
22632
              toggleClass: detail.markers.overflowToggledClass,
1441 ariadna 22633
              aria: { mode: 'expanded' },
1 efrain 22634
              toggleOnExecute: false
22635
            })])
22636
        })
22637
      }),
22638
      external({ name: 'overflow-group' })
22639
    ]);
22640
 
22641
    const isOpen = (toolbar, detail) => getPart(toolbar, detail, 'overflow').map(Sliding.hasGrown).getOr(false);
1441 ariadna 22642
    const toggleToolbar = (toolbar, detail, skipFocus) => {
22643
      getPart(toolbar, detail, 'overflow-button').each(oveflowButton => {
22644
        getPart(toolbar, detail, 'overflow').each(overf => {
22645
          refresh(toolbar, detail);
22646
          if (Sliding.hasShrunk(overf)) {
22647
            const fn = detail.onOpened;
22648
            detail.onOpened = comp => {
22649
              if (!skipFocus) {
22650
                Keying.focusIn(overf);
22651
              }
22652
              fn(comp);
22653
              detail.onOpened = fn;
22654
            };
22655
          } else {
22656
            const fn = detail.onClosed;
22657
            detail.onClosed = comp => {
22658
              if (!skipFocus) {
22659
                Focusing.focus(oveflowButton);
22660
              }
22661
              fn(comp);
22662
              detail.onClosed = fn;
22663
            };
22664
          }
22665
          Sliding.toggleGrow(overf);
22666
        });
1 efrain 22667
      });
22668
    };
22669
    const refresh = (toolbar, detail) => {
22670
      getPart(toolbar, detail, 'overflow').each(overflow => {
22671
        refresh$2(toolbar, detail, groups => {
22672
          const builtGroups = map$2(groups, g => premade(g));
22673
          Toolbar.setGroups(overflow, builtGroups);
22674
        });
22675
        getPart(toolbar, detail, 'overflow-button').each(button => {
22676
          if (Sliding.hasGrown(overflow)) {
22677
            Toggling.on(button);
22678
          }
22679
        });
22680
        Sliding.refresh(overflow);
22681
      });
22682
    };
22683
    const factory$9 = (detail, components, spec, externals) => {
22684
      const toolbarToggleEvent = 'alloy.toolbar.toggle';
22685
      const doSetGroups = (toolbar, groups) => {
22686
        const built = map$2(groups, toolbar.getSystem().build);
22687
        detail.builtGroups.set(built);
22688
      };
22689
      return {
22690
        uid: detail.uid,
22691
        dom: detail.dom,
22692
        components,
22693
        behaviours: augment(detail.splitToolbarBehaviours, [
22694
          Coupling.config({
22695
            others: {
22696
              overflowGroup: toolbar => {
22697
                return ToolbarGroup.sketch({
22698
                  ...externals['overflow-group'](),
22699
                  items: [Button.sketch({
22700
                      ...externals['overflow-button'](),
22701
                      action: _button => {
22702
                        emit(toolbar, toolbarToggleEvent);
22703
                      }
22704
                    })]
22705
                });
22706
              }
22707
            }
22708
          }),
22709
          config('toolbar-toggle-events', [run$1(toolbarToggleEvent, toolbar => {
1441 ariadna 22710
              toggleToolbar(toolbar, detail, false);
1 efrain 22711
            })])
22712
        ]),
22713
        apis: {
22714
          setGroups: (toolbar, groups) => {
22715
            doSetGroups(toolbar, groups);
22716
            refresh(toolbar, detail);
22717
          },
22718
          refresh: toolbar => refresh(toolbar, detail),
1441 ariadna 22719
          toggle: toolbar => {
22720
            toggleToolbar(toolbar, detail, false);
22721
          },
22722
          toggleWithoutFocusing: toolbar => {
22723
            toggleToolbar(toolbar, detail, true);
22724
          },
1 efrain 22725
          isOpen: toolbar => isOpen(toolbar, detail)
22726
        },
22727
        domModification: { attributes: { role: 'group' } }
22728
      };
22729
    };
22730
    const SplitSlidingToolbar = composite({
22731
      name: 'SplitSlidingToolbar',
22732
      configFields: schema$8(),
22733
      partFields: parts$4(),
22734
      factory: factory$9,
22735
      apis: {
22736
        setGroups: (apis, toolbar, groups) => {
22737
          apis.setGroups(toolbar, groups);
22738
        },
22739
        refresh: (apis, toolbar) => {
22740
          apis.refresh(toolbar);
22741
        },
22742
        toggle: (apis, toolbar) => {
22743
          apis.toggle(toolbar);
22744
        },
22745
        isOpen: (apis, toolbar) => apis.isOpen(toolbar)
22746
      }
22747
    });
22748
 
22749
    const renderToolbarGroupCommon = toolbarGroup => {
1441 ariadna 22750
      const attributes = toolbarGroup.label.isNone() ? toolbarGroup.title.fold(() => ({}), title => ({ attributes: { 'aria-label': title } })) : toolbarGroup.label.fold(() => ({}), label => ({ attributes: { 'aria-label': label } }));
1 efrain 22751
      return {
22752
        dom: {
22753
          tag: 'div',
1441 ariadna 22754
          classes: ['tox-toolbar__group'].concat(toolbarGroup.label.isSome() ? ['tox-toolbar__group_with_label'] : []),
1 efrain 22755
          ...attributes
22756
        },
1441 ariadna 22757
        components: [
22758
          ...toolbarGroup.label.map(label => {
22759
            return {
22760
              dom: {
22761
                tag: 'span',
22762
                classes: [
22763
                  'tox-label',
22764
                  'tox-label--context-toolbar'
22765
                ]
22766
              },
22767
              components: [text$2(label)]
22768
            };
22769
          }).toArray(),
22770
          ToolbarGroup.parts.items({})
22771
        ],
1 efrain 22772
        items: toolbarGroup.items,
1441 ariadna 22773
        markers: { itemSelector: '*:not(.tox-split-button) > .tox-tbtn:not([disabled]), ' + '.tox-split-button:not([disabled]), ' + '.tox-toolbar-nav-item:not([disabled]), ' + '.tox-number-input:not([disabled])' },
1 efrain 22774
        tgroupBehaviours: derive$1([
22775
          Tabstopping.config({}),
1441 ariadna 22776
          Focusing.config({ ignore: true })
1 efrain 22777
        ])
22778
      };
22779
    };
22780
    const renderToolbarGroup = toolbarGroup => ToolbarGroup.sketch(renderToolbarGroupCommon(toolbarGroup));
22781
    const getToolbarBehaviours = (toolbarSpec, modeName) => {
22782
      const onAttached = runOnAttached(component => {
22783
        const groups = map$2(toolbarSpec.initGroups, renderToolbarGroup);
22784
        Toolbar.setGroups(component, groups);
22785
      });
22786
      return derive$1([
1441 ariadna 22787
        DisablingConfigs.toolbarButton(() => toolbarSpec.providers.checkUiComponentContext('any').shouldDisable),
22788
        toggleOnReceive(() => toolbarSpec.providers.checkUiComponentContext('any')),
1 efrain 22789
        Keying.config({
22790
          mode: modeName,
22791
          onEscape: toolbarSpec.onEscape,
1441 ariadna 22792
          visibilitySelector: '.tox-toolbar__overflow',
1 efrain 22793
          selector: '.tox-toolbar__group'
22794
        }),
22795
        config('toolbar-events', [onAttached])
22796
      ]);
22797
    };
22798
    const renderMoreToolbarCommon = toolbarSpec => {
22799
      const modeName = toolbarSpec.cyclicKeying ? 'cyclic' : 'acyclic';
22800
      return {
22801
        uid: toolbarSpec.uid,
22802
        dom: {
22803
          tag: 'div',
22804
          classes: ['tox-toolbar-overlord']
22805
        },
22806
        parts: {
22807
          'overflow-group': renderToolbarGroupCommon({
22808
            title: Optional.none(),
1441 ariadna 22809
            label: Optional.none(),
1 efrain 22810
            items: []
22811
          }),
22812
          'overflow-button': renderIconButtonSpec({
1441 ariadna 22813
            context: 'any',
1 efrain 22814
            name: 'more',
22815
            icon: Optional.some('more-drawer'),
22816
            enabled: true,
22817
            tooltip: Optional.some('Reveal or hide additional toolbar items'),
22818
            primary: false,
22819
            buttonType: Optional.none(),
22820
            borderless: false
1441 ariadna 22821
          }, Optional.none(), toolbarSpec.providers, [], 'overflow-button')
1 efrain 22822
        },
22823
        splitToolbarBehaviours: getToolbarBehaviours(toolbarSpec, modeName)
22824
      };
22825
    };
22826
    const renderFloatingMoreToolbar = toolbarSpec => {
22827
      const baseSpec = renderMoreToolbarCommon(toolbarSpec);
22828
      const overflowXOffset = 4;
22829
      const primary = SplitFloatingToolbar.parts.primary({
22830
        dom: {
22831
          tag: 'div',
22832
          classes: ['tox-toolbar__primary']
22833
        }
22834
      });
22835
      return SplitFloatingToolbar.sketch({
22836
        ...baseSpec,
22837
        lazySink: toolbarSpec.getSink,
22838
        getOverflowBounds: () => {
22839
          const headerElem = toolbarSpec.moreDrawerData.lazyHeader().element;
22840
          const headerBounds = absolute$2(headerElem);
22841
          const docElem = documentElement(headerElem);
22842
          const docBounds = absolute$2(docElem);
22843
          const height = Math.max(docElem.dom.scrollHeight, docBounds.height);
22844
          return bounds(headerBounds.x + overflowXOffset, docBounds.y, headerBounds.width - overflowXOffset * 2, height);
22845
        },
22846
        parts: {
22847
          ...baseSpec.parts,
22848
          overflow: {
22849
            dom: {
22850
              tag: 'div',
22851
              classes: ['tox-toolbar__overflow'],
22852
              attributes: toolbarSpec.attributes
22853
            }
22854
          }
22855
        },
22856
        components: [primary],
22857
        markers: { overflowToggledClass: 'tox-tbtn--enabled' },
22858
        onOpened: comp => toolbarSpec.onToggled(comp, true),
22859
        onClosed: comp => toolbarSpec.onToggled(comp, false)
22860
      });
22861
    };
22862
    const renderSlidingMoreToolbar = toolbarSpec => {
22863
      const primary = SplitSlidingToolbar.parts.primary({
22864
        dom: {
22865
          tag: 'div',
22866
          classes: ['tox-toolbar__primary']
22867
        }
22868
      });
22869
      const overflow = SplitSlidingToolbar.parts.overflow({
22870
        dom: {
22871
          tag: 'div',
22872
          classes: ['tox-toolbar__overflow']
22873
        }
22874
      });
22875
      const baseSpec = renderMoreToolbarCommon(toolbarSpec);
22876
      return SplitSlidingToolbar.sketch({
22877
        ...baseSpec,
22878
        components: [
22879
          primary,
22880
          overflow
22881
        ],
22882
        markers: {
22883
          openClass: 'tox-toolbar__overflow--open',
22884
          closedClass: 'tox-toolbar__overflow--closed',
22885
          growingClass: 'tox-toolbar__overflow--growing',
22886
          shrinkingClass: 'tox-toolbar__overflow--shrinking',
22887
          overflowToggledClass: 'tox-tbtn--enabled'
22888
        },
22889
        onOpened: comp => {
22890
          comp.getSystem().broadcastOn([toolbarHeightChange()], { type: 'opened' });
22891
          toolbarSpec.onToggled(comp, true);
22892
        },
22893
        onClosed: comp => {
22894
          comp.getSystem().broadcastOn([toolbarHeightChange()], { type: 'closed' });
22895
          toolbarSpec.onToggled(comp, false);
22896
        }
22897
      });
22898
    };
22899
    const renderToolbar = toolbarSpec => {
22900
      const modeName = toolbarSpec.cyclicKeying ? 'cyclic' : 'acyclic';
22901
      return Toolbar.sketch({
22902
        uid: toolbarSpec.uid,
22903
        dom: {
22904
          tag: 'div',
22905
          classes: ['tox-toolbar'].concat(toolbarSpec.type === ToolbarMode$1.scrolling ? ['tox-toolbar--scrolling'] : [])
22906
        },
22907
        components: [Toolbar.parts.groups({})],
22908
        toolbarBehaviours: getToolbarBehaviours(toolbarSpec, modeName)
22909
      });
22910
    };
22911
 
22912
    const baseButtonFields = [
22913
      optionalText,
22914
      optionalIcon,
22915
      optionString('tooltip'),
22916
      defaultedStringEnum('buttonType', 'secondary', [
22917
        'primary',
22918
        'secondary'
22919
      ]),
22920
      defaultedBoolean('borderless', false),
1441 ariadna 22921
      requiredFunction('onAction'),
22922
      defaultedString('context', 'mode:design')
1 efrain 22923
    ];
22924
    const normalButtonFields = [
22925
      ...baseButtonFields,
22926
      text,
22927
      requiredStringEnum('type', ['button'])
22928
    ];
22929
    const toggleButtonFields = [
22930
      ...baseButtonFields,
22931
      defaultedBoolean('active', false),
22932
      requiredStringEnum('type', ['togglebutton'])
22933
    ];
22934
    const schemaWithoutGroupButton = {
22935
      button: normalButtonFields,
22936
      togglebutton: toggleButtonFields
22937
    };
22938
    const groupFields = [
22939
      requiredStringEnum('type', ['group']),
22940
      defaultedArrayOf('buttons', [], choose$1('type', schemaWithoutGroupButton))
22941
    ];
22942
    const viewButtonSchema = choose$1('type', {
22943
      ...schemaWithoutGroupButton,
22944
      group: groupFields
22945
    });
22946
 
22947
    const viewSchema = objOf([
22948
      defaultedArrayOf('buttons', [], viewButtonSchema),
22949
      requiredFunction('onShow'),
22950
      requiredFunction('onHide')
22951
    ]);
22952
    const createView = spec => asRaw('view', viewSchema, spec);
22953
 
22954
    const renderButton = (spec, providers) => {
22955
      var _a, _b;
22956
      const isToggleButton = spec.type === 'togglebutton';
22957
      const optMemIcon = spec.icon.map(memIcon => renderReplaceableIconFromPack(memIcon, providers.icons)).map(record);
22958
      const getAction = () => comp => {
22959
        const setIcon = newIcon => {
22960
          optMemIcon.map(memIcon => memIcon.getOpt(comp).each(displayIcon => {
22961
            Replacing.set(displayIcon, [renderReplaceableIconFromPack(newIcon, providers.icons)]);
22962
          }));
22963
        };
22964
        const setActive = state => {
22965
          const elm = comp.element;
22966
          if (state) {
22967
            add$2(elm, 'tox-button--enabled');
22968
            set$9(elm, 'aria-pressed', true);
22969
          } else {
1441 ariadna 22970
            remove$3(elm, 'tox-button--enabled');
22971
            remove$8(elm, 'aria-pressed');
1 efrain 22972
          }
22973
        };
22974
        const isActive = () => has(comp.element, 'tox-button--enabled');
1441 ariadna 22975
        const focus = () => focus$3(comp.element);
1 efrain 22976
        if (isToggleButton) {
22977
          return spec.onAction({
22978
            setIcon,
22979
            setActive,
1441 ariadna 22980
            isActive,
22981
            focus
1 efrain 22982
          });
22983
        }
22984
        if (spec.type === 'button') {
22985
          return spec.onAction({ setIcon });
22986
        }
22987
      };
22988
      const action = getAction();
22989
      const buttonSpec = {
22990
        ...spec,
22991
        name: isToggleButton ? spec.text.getOr(spec.icon.getOr('')) : (_a = spec.text) !== null && _a !== void 0 ? _a : spec.icon.getOr(''),
22992
        primary: spec.buttonType === 'primary',
22993
        buttonType: Optional.from(spec.buttonType),
22994
        tooltip: spec.tooltip,
22995
        icon: spec.icon,
22996
        enabled: true,
22997
        borderless: spec.borderless
22998
      };
22999
      const buttonTypeClasses = calculateClassesFromButtonType((_b = spec.buttonType) !== null && _b !== void 0 ? _b : 'secondary');
23000
      const optTranslatedText = isToggleButton ? spec.text.map(providers.translate) : Optional.some(providers.translate(spec.text));
23001
      const optTranslatedTextComponed = optTranslatedText.map(text$2);
1441 ariadna 23002
      const ariaLabelAttributes = buttonSpec.tooltip.or(optTranslatedText).map(al => ({ 'aria-label': providers.translate(al) })).getOr({});
1 efrain 23003
      const optIconSpec = optMemIcon.map(memIcon => memIcon.asSpec());
23004
      const components = componentRenderPipeline([
23005
        optIconSpec,
23006
        optTranslatedTextComponed
23007
      ]);
23008
      const hasIconAndText = spec.icon.isSome() && optTranslatedTextComponed.isSome();
23009
      const dom = {
23010
        tag: 'button',
23011
        classes: buttonTypeClasses.concat(...spec.icon.isSome() && !hasIconAndText ? ['tox-button--icon'] : []).concat(...hasIconAndText ? ['tox-button--icon-and-text'] : []).concat(...spec.borderless ? ['tox-button--naked'] : []).concat(...spec.type === 'togglebutton' && spec.active ? ['tox-button--enabled'] : []),
1441 ariadna 23012
        attributes: ariaLabelAttributes
1 efrain 23013
      };
23014
      const extraBehaviours = [];
1441 ariadna 23015
      const iconButtonSpec = renderCommonSpec(buttonSpec, Optional.some(action), extraBehaviours, dom, components, spec.tooltip, providers);
1 efrain 23016
      return Button.sketch(iconButtonSpec);
23017
    };
23018
 
23019
    const renderViewButton = (spec, providers) => renderButton(spec, providers);
23020
    const renderButtonsGroup = (spec, providers) => {
23021
      return {
23022
        dom: {
23023
          tag: 'div',
23024
          classes: ['tox-view__toolbar__group']
23025
        },
23026
        components: map$2(spec.buttons, button => renderViewButton(button, providers))
23027
      };
23028
    };
1441 ariadna 23029
    const deviceDetection = detect$1().deviceType;
1 efrain 23030
    const isPhone = deviceDetection.isPhone();
23031
    const isTablet = deviceDetection.isTablet();
23032
    const renderViewHeader = spec => {
23033
      let hasGroups = false;
23034
      const endButtons = map$2(spec.buttons, btnspec => {
23035
        if (btnspec.type === 'group') {
23036
          hasGroups = true;
23037
          return renderButtonsGroup(btnspec, spec.providers);
23038
        } else {
23039
          return renderViewButton(btnspec, spec.providers);
23040
        }
23041
      });
23042
      return {
23043
        uid: spec.uid,
23044
        dom: {
23045
          tag: 'div',
23046
          classes: [
23047
            !hasGroups ? 'tox-view__header' : 'tox-view__toolbar',
23048
            ...isPhone || isTablet ? [
23049
              'tox-view--mobile',
23050
              'tox-view--scrolling'
23051
            ] : []
23052
          ]
23053
        },
23054
        behaviours: derive$1([
23055
          Focusing.config({}),
23056
          Keying.config({
23057
            mode: 'flow',
23058
            selector: 'button, .tox-button',
23059
            focusInside: FocusInsideModes.OnEnterOrSpaceMode
23060
          })
23061
        ]),
23062
        components: hasGroups ? endButtons : [
23063
          Container.sketch({
23064
            dom: {
23065
              tag: 'div',
23066
              classes: ['tox-view__header-start']
23067
            },
23068
            components: []
23069
          }),
23070
          Container.sketch({
23071
            dom: {
23072
              tag: 'div',
23073
              classes: ['tox-view__header-end']
23074
            },
23075
            components: endButtons
23076
          })
23077
        ]
23078
      };
23079
    };
23080
    const renderViewPane = spec => {
23081
      return {
23082
        uid: spec.uid,
1441 ariadna 23083
        behaviours: derive$1([
23084
          Focusing.config({}),
23085
          Tabstopping.config({})
23086
        ]),
1 efrain 23087
        dom: {
23088
          tag: 'div',
23089
          classes: ['tox-view__pane']
23090
        }
23091
      };
23092
    };
23093
    const factory$8 = (detail, components, _spec, _externals) => {
23094
      const apis = {
23095
        getPane: comp => parts$a.getPart(comp, detail, 'pane'),
23096
        getOnShow: _comp => detail.viewConfig.onShow,
23097
        getOnHide: _comp => detail.viewConfig.onHide
23098
      };
23099
      return {
23100
        uid: detail.uid,
23101
        dom: detail.dom,
23102
        components,
1441 ariadna 23103
        behaviours: derive$1([
23104
          Focusing.config({}),
23105
          Keying.config({
23106
            mode: 'cyclic',
23107
            focusInside: FocusInsideModes.OnEnterOrSpaceMode
23108
          })
23109
        ]),
1 efrain 23110
        apis
23111
      };
23112
    };
23113
    var View = composite({
23114
      name: 'silver.View',
23115
      configFields: [required$1('viewConfig')],
23116
      partFields: [
23117
        optional({
23118
          factory: { sketch: renderViewHeader },
23119
          schema: [
23120
            required$1('buttons'),
23121
            required$1('providers')
23122
          ],
23123
          name: 'header'
23124
        }),
23125
        optional({
23126
          factory: { sketch: renderViewPane },
23127
          schema: [],
23128
          name: 'pane'
23129
        })
23130
      ],
23131
      factory: factory$8,
23132
      apis: {
23133
        getPane: (apis, comp) => apis.getPane(comp),
23134
        getOnShow: (apis, comp) => apis.getOnShow(comp),
23135
        getOnHide: (apis, comp) => apis.getOnHide(comp)
23136
      }
23137
    });
23138
 
23139
    const makeViews = (parts, viewConfigs, providers) => {
23140
      return mapToArray(viewConfigs, (config, name) => {
23141
        const internalViewConfig = getOrDie(createView(config));
23142
        return parts.slot(name, View.sketch({
23143
          dom: {
23144
            tag: 'div',
23145
            classes: ['tox-view']
23146
          },
23147
          viewConfig: internalViewConfig,
23148
          components: [
23149
            ...internalViewConfig.buttons.length > 0 ? [View.parts.header({
23150
                buttons: internalViewConfig.buttons,
23151
                providers
23152
              })] : [],
23153
            View.parts.pane({})
23154
          ]
23155
        }));
23156
      });
23157
    };
23158
    const makeSlotContainer = (viewConfigs, providers) => SlotContainer.sketch(parts => ({
23159
      dom: {
23160
        tag: 'div',
23161
        classes: ['tox-view-wrap__slot-container']
23162
      },
23163
      components: makeViews(parts, viewConfigs, providers),
23164
      slotBehaviours: SimpleBehaviours.unnamedEvents([runOnAttached(slotContainer => SlotContainer.hideAllSlots(slotContainer))])
23165
    }));
23166
    const getCurrentName = slotContainer => {
23167
      return find$5(SlotContainer.getSlotNames(slotContainer), name => SlotContainer.isShowing(slotContainer, name));
23168
    };
23169
    const hideContainer = comp => {
23170
      const element = comp.element;
23171
      set$8(element, 'display', 'none');
23172
      set$9(element, 'aria-hidden', 'true');
23173
    };
23174
    const showContainer = comp => {
23175
      const element = comp.element;
1441 ariadna 23176
      remove$7(element, 'display');
23177
      remove$8(element, 'aria-hidden');
1 efrain 23178
    };
23179
    const makeViewInstanceApi = slot => ({ getContainer: constant$1(slot) });
23180
    const runOnPaneWithInstanceApi = (slotContainer, name, get) => {
23181
      SlotContainer.getSlot(slotContainer, name).each(view => {
23182
        View.getPane(view).each(pane => {
23183
          const onCallback = get(view);
23184
          onCallback(makeViewInstanceApi(pane.element.dom));
23185
        });
23186
      });
23187
    };
23188
    const runOnShow = (slotContainer, name) => runOnPaneWithInstanceApi(slotContainer, name, View.getOnShow);
23189
    const runOnHide = (slotContainer, name) => runOnPaneWithInstanceApi(slotContainer, name, View.getOnHide);
23190
    const factory$7 = (detail, spec) => {
23191
      const setViews = (comp, viewConfigs) => {
23192
        Replacing.set(comp, [makeSlotContainer(viewConfigs, spec.backstage.shared.providers)]);
23193
      };
23194
      const whichView = comp => {
23195
        return Composing.getCurrent(comp).bind(getCurrentName);
23196
      };
23197
      const toggleView = (comp, showMainView, hideMainView, name) => {
23198
        return Composing.getCurrent(comp).exists(slotContainer => {
23199
          const optCurrentSlotName = getCurrentName(slotContainer);
23200
          const isTogglingCurrentView = optCurrentSlotName.exists(current => name === current);
23201
          const exists = SlotContainer.getSlot(slotContainer, name).isSome();
23202
          if (exists) {
23203
            SlotContainer.hideAllSlots(slotContainer);
23204
            if (!isTogglingCurrentView) {
23205
              hideMainView();
23206
              showContainer(comp);
23207
              SlotContainer.showSlot(slotContainer, name);
23208
              runOnShow(slotContainer, name);
23209
            } else {
23210
              hideContainer(comp);
23211
              showMainView();
23212
            }
23213
            optCurrentSlotName.each(prevName => runOnHide(slotContainer, prevName));
23214
          }
23215
          return exists;
23216
        });
23217
      };
23218
      const apis = {
23219
        setViews,
23220
        whichView,
23221
        toggleView
23222
      };
23223
      return {
23224
        uid: detail.uid,
23225
        dom: {
23226
          tag: 'div',
23227
          classes: ['tox-view-wrap'],
23228
          attributes: { 'aria-hidden': 'true' },
23229
          styles: { display: 'none' }
23230
        },
23231
        components: [],
23232
        behaviours: derive$1([
23233
          Replacing.config({}),
23234
          Composing.config({
23235
            find: comp => {
23236
              const children = Replacing.contents(comp);
23237
              return head(children);
23238
            }
23239
          })
23240
        ]),
23241
        apis
23242
      };
23243
    };
23244
    var ViewWrapper = single({
23245
      factory: factory$7,
23246
      name: 'silver.ViewWrapper',
23247
      configFields: [required$1('backstage')],
23248
      apis: {
23249
        setViews: (apis, comp, views) => apis.setViews(comp, views),
23250
        toggleView: (apis, comp, outerContainer, editorCont, name) => apis.toggleView(comp, outerContainer, editorCont, name),
23251
        whichView: (apis, comp) => apis.whichView(comp)
23252
      }
23253
    });
23254
 
23255
    const factory$6 = (detail, components, _spec) => {
23256
      let toolbarDrawerOpenState = false;
1441 ariadna 23257
      const toggleStatusbar = editorContainer => {
23258
        sibling(editorContainer, '.tox-statusbar').each(statusBar => {
23259
          if (get$f(statusBar, 'display') === 'none' && get$g(statusBar, 'aria-hidden') === 'true') {
23260
            remove$7(statusBar, 'display');
23261
            remove$8(statusBar, 'aria-hidden');
23262
          } else {
23263
            set$8(statusBar, 'display', 'none');
23264
            set$9(statusBar, 'aria-hidden', 'true');
23265
          }
23266
        });
23267
      };
1 efrain 23268
      const apis = {
23269
        getSocket: comp => {
23270
          return parts$a.getPart(comp, detail, 'socket');
23271
        },
23272
        setSidebar: (comp, panelConfigs, showSidebar) => {
23273
          parts$a.getPart(comp, detail, 'sidebar').each(sidebar => setSidebar(sidebar, panelConfigs, showSidebar));
23274
        },
23275
        toggleSidebar: (comp, name) => {
23276
          parts$a.getPart(comp, detail, 'sidebar').each(sidebar => toggleSidebar(sidebar, name));
23277
        },
23278
        whichSidebar: comp => {
23279
          return parts$a.getPart(comp, detail, 'sidebar').bind(whichSidebar).getOrNull();
23280
        },
23281
        getHeader: comp => {
23282
          return parts$a.getPart(comp, detail, 'header');
23283
        },
23284
        getToolbar: comp => {
23285
          return parts$a.getPart(comp, detail, 'toolbar');
23286
        },
23287
        setToolbar: (comp, groups) => {
23288
          parts$a.getPart(comp, detail, 'toolbar').each(toolbar => {
23289
            const renderedGroups = map$2(groups, renderToolbarGroup);
23290
            toolbar.getApis().setGroups(toolbar, renderedGroups);
23291
          });
23292
        },
23293
        setToolbars: (comp, toolbars) => {
23294
          parts$a.getPart(comp, detail, 'multiple-toolbar').each(mToolbar => {
23295
            const renderedToolbars = map$2(toolbars, g => map$2(g, renderToolbarGroup));
23296
            CustomList.setItems(mToolbar, renderedToolbars);
23297
          });
23298
        },
23299
        refreshToolbar: comp => {
23300
          const toolbar = parts$a.getPart(comp, detail, 'toolbar');
23301
          toolbar.each(toolbar => toolbar.getApis().refresh(toolbar));
23302
        },
23303
        toggleToolbarDrawer: comp => {
23304
          parts$a.getPart(comp, detail, 'toolbar').each(toolbar => {
23305
            mapFrom(toolbar.getApis().toggle, toggle => toggle(toolbar));
23306
          });
23307
        },
23308
        toggleToolbarDrawerWithoutFocusing: comp => {
23309
          parts$a.getPart(comp, detail, 'toolbar').each(toolbar => {
23310
            mapFrom(toolbar.getApis().toggleWithoutFocusing, toggleWithoutFocusing => toggleWithoutFocusing(toolbar));
23311
          });
23312
        },
23313
        isToolbarDrawerToggled: comp => {
23314
          return parts$a.getPart(comp, detail, 'toolbar').bind(toolbar => Optional.from(toolbar.getApis().isOpen).map(isOpen => isOpen(toolbar))).getOr(false);
23315
        },
23316
        getThrobber: comp => {
23317
          return parts$a.getPart(comp, detail, 'throbber');
23318
        },
23319
        focusToolbar: comp => {
23320
          const optToolbar = parts$a.getPart(comp, detail, 'toolbar').orThunk(() => parts$a.getPart(comp, detail, 'multiple-toolbar'));
23321
          optToolbar.each(toolbar => {
23322
            Keying.focusIn(toolbar);
23323
          });
23324
        },
23325
        setMenubar: (comp, menus) => {
23326
          parts$a.getPart(comp, detail, 'menubar').each(menubar => {
23327
            SilverMenubar.setMenus(menubar, menus);
23328
          });
23329
        },
23330
        focusMenubar: comp => {
23331
          parts$a.getPart(comp, detail, 'menubar').each(menubar => {
23332
            SilverMenubar.focus(menubar);
23333
          });
23334
        },
23335
        setViews: (comp, viewConfigs) => {
23336
          parts$a.getPart(comp, detail, 'viewWrapper').each(wrapper => {
23337
            ViewWrapper.setViews(wrapper, viewConfigs);
23338
          });
23339
        },
23340
        toggleView: (comp, name) => {
23341
          return parts$a.getPart(comp, detail, 'viewWrapper').exists(wrapper => ViewWrapper.toggleView(wrapper, () => apis.showMainView(comp), () => apis.hideMainView(comp), name));
23342
        },
23343
        whichView: comp => {
23344
          return parts$a.getPart(comp, detail, 'viewWrapper').bind(ViewWrapper.whichView).getOrNull();
23345
        },
23346
        hideMainView: comp => {
23347
          toolbarDrawerOpenState = apis.isToolbarDrawerToggled(comp);
23348
          if (toolbarDrawerOpenState) {
23349
            apis.toggleToolbarDrawer(comp);
23350
          }
23351
          parts$a.getPart(comp, detail, 'editorContainer').each(editorContainer => {
23352
            const element = editorContainer.element;
1441 ariadna 23353
            toggleStatusbar(element);
1 efrain 23354
            set$8(element, 'display', 'none');
23355
            set$9(element, 'aria-hidden', 'true');
23356
          });
23357
        },
23358
        showMainView: comp => {
23359
          if (toolbarDrawerOpenState) {
23360
            apis.toggleToolbarDrawer(comp);
23361
          }
23362
          parts$a.getPart(comp, detail, 'editorContainer').each(editorContainer => {
23363
            const element = editorContainer.element;
1441 ariadna 23364
            toggleStatusbar(element);
23365
            remove$7(element, 'display');
23366
            remove$8(element, 'aria-hidden');
1 efrain 23367
          });
23368
        }
23369
      };
23370
      return {
23371
        uid: detail.uid,
23372
        dom: detail.dom,
23373
        components,
23374
        apis,
23375
        behaviours: detail.behaviours
23376
      };
23377
    };
23378
    const partMenubar = partType.optional({
23379
      factory: SilverMenubar,
23380
      name: 'menubar',
23381
      schema: [required$1('backstage')]
23382
    });
23383
    const toolbarFactory = spec => {
23384
      if (spec.type === ToolbarMode$1.sliding) {
23385
        return renderSlidingMoreToolbar;
23386
      } else if (spec.type === ToolbarMode$1.floating) {
23387
        return renderFloatingMoreToolbar;
23388
      } else {
23389
        return renderToolbar;
23390
      }
23391
    };
23392
    const partMultipleToolbar = partType.optional({
23393
      factory: {
23394
        sketch: spec => CustomList.sketch({
23395
          uid: spec.uid,
23396
          dom: spec.dom,
23397
          listBehaviours: derive$1([Keying.config({
23398
              mode: 'acyclic',
23399
              selector: '.tox-toolbar'
23400
            })]),
23401
          makeItem: () => renderToolbar({
23402
            type: spec.type,
23403
            uid: generate$6('multiple-toolbar-item'),
23404
            cyclicKeying: false,
23405
            initGroups: [],
23406
            providers: spec.providers,
23407
            onEscape: () => {
23408
              spec.onEscape();
23409
              return Optional.some(true);
23410
            }
23411
          }),
23412
          setupItem: (_mToolbar, tc, data, _index) => {
23413
            Toolbar.setGroups(tc, data);
23414
          },
23415
          shell: true
23416
        })
23417
      },
23418
      name: 'multiple-toolbar',
23419
      schema: [
23420
        required$1('dom'),
23421
        required$1('onEscape')
23422
      ]
23423
    });
23424
    const partToolbar = partType.optional({
23425
      factory: {
23426
        sketch: spec => {
23427
          const renderer = toolbarFactory(spec);
23428
          const toolbarSpec = {
23429
            type: spec.type,
23430
            uid: spec.uid,
23431
            onEscape: () => {
23432
              spec.onEscape();
23433
              return Optional.some(true);
23434
            },
23435
            onToggled: (_comp, state) => spec.onToolbarToggled(state),
23436
            cyclicKeying: false,
23437
            initGroups: [],
23438
            getSink: spec.getSink,
23439
            providers: spec.providers,
23440
            moreDrawerData: {
23441
              lazyToolbar: spec.lazyToolbar,
23442
              lazyMoreButton: spec.lazyMoreButton,
23443
              lazyHeader: spec.lazyHeader
23444
            },
23445
            attributes: spec.attributes
23446
          };
23447
          return renderer(toolbarSpec);
23448
        }
23449
      },
23450
      name: 'toolbar',
23451
      schema: [
23452
        required$1('dom'),
23453
        required$1('onEscape'),
23454
        required$1('getSink')
23455
      ]
23456
    });
23457
    const partHeader = partType.optional({
23458
      factory: { sketch: renderHeader },
23459
      name: 'header',
23460
      schema: [required$1('dom')]
23461
    });
23462
    const partPromotion = partType.optional({
23463
      factory: { sketch: renderPromotion },
23464
      name: 'promotion',
23465
      schema: [required$1('dom')]
23466
    });
23467
    const partSocket = partType.optional({
23468
      name: 'socket',
23469
      schema: [required$1('dom')]
23470
    });
23471
    const partSidebar = partType.optional({
23472
      factory: { sketch: renderSidebar },
23473
      name: 'sidebar',
23474
      schema: [required$1('dom')]
23475
    });
23476
    const partThrobber = partType.optional({
23477
      factory: { sketch: renderThrobber },
23478
      name: 'throbber',
23479
      schema: [required$1('dom')]
23480
    });
23481
    const partViewWrapper = partType.optional({
23482
      factory: ViewWrapper,
23483
      name: 'viewWrapper',
23484
      schema: [required$1('backstage')]
23485
    });
23486
    const renderEditorContainer = spec => ({
23487
      uid: spec.uid,
23488
      dom: {
23489
        tag: 'div',
23490
        classes: ['tox-editor-container']
23491
      },
23492
      components: spec.components
23493
    });
23494
    const partEditorContainer = partType.optional({
23495
      factory: { sketch: renderEditorContainer },
23496
      name: 'editorContainer',
23497
      schema: []
23498
    });
23499
    var OuterContainer = composite({
23500
      name: 'OuterContainer',
23501
      factory: factory$6,
23502
      configFields: [
23503
        required$1('dom'),
23504
        required$1('behaviours')
23505
      ],
23506
      partFields: [
23507
        partHeader,
23508
        partMenubar,
23509
        partToolbar,
23510
        partMultipleToolbar,
23511
        partSocket,
23512
        partSidebar,
23513
        partPromotion,
23514
        partThrobber,
23515
        partViewWrapper,
23516
        partEditorContainer
23517
      ],
23518
      apis: {
23519
        getSocket: (apis, comp) => {
23520
          return apis.getSocket(comp);
23521
        },
23522
        setSidebar: (apis, comp, panelConfigs, showSidebar) => {
23523
          apis.setSidebar(comp, panelConfigs, showSidebar);
23524
        },
23525
        toggleSidebar: (apis, comp, name) => {
23526
          apis.toggleSidebar(comp, name);
23527
        },
23528
        whichSidebar: (apis, comp) => {
23529
          return apis.whichSidebar(comp);
23530
        },
23531
        getHeader: (apis, comp) => {
23532
          return apis.getHeader(comp);
23533
        },
23534
        getToolbar: (apis, comp) => {
23535
          return apis.getToolbar(comp);
23536
        },
23537
        setToolbar: (apis, comp, groups) => {
23538
          apis.setToolbar(comp, groups);
23539
        },
23540
        setToolbars: (apis, comp, toolbars) => {
23541
          apis.setToolbars(comp, toolbars);
23542
        },
23543
        refreshToolbar: (apis, comp) => {
23544
          return apis.refreshToolbar(comp);
23545
        },
23546
        toggleToolbarDrawer: (apis, comp) => {
23547
          apis.toggleToolbarDrawer(comp);
23548
        },
23549
        toggleToolbarDrawerWithoutFocusing: (apis, comp) => {
23550
          apis.toggleToolbarDrawerWithoutFocusing(comp);
23551
        },
23552
        isToolbarDrawerToggled: (apis, comp) => {
23553
          return apis.isToolbarDrawerToggled(comp);
23554
        },
23555
        getThrobber: (apis, comp) => {
23556
          return apis.getThrobber(comp);
23557
        },
23558
        setMenubar: (apis, comp, menus) => {
23559
          apis.setMenubar(comp, menus);
23560
        },
23561
        focusMenubar: (apis, comp) => {
23562
          apis.focusMenubar(comp);
23563
        },
23564
        focusToolbar: (apis, comp) => {
23565
          apis.focusToolbar(comp);
23566
        },
23567
        setViews: (apis, comp, views) => {
23568
          apis.setViews(comp, views);
23569
        },
23570
        toggleView: (apis, comp, name) => {
23571
          return apis.toggleView(comp, name);
23572
        },
23573
        whichView: (apis, comp) => {
23574
          return apis.whichView(comp);
23575
        }
23576
      }
23577
    });
23578
 
23579
    const defaultMenubar = 'file edit view insert format tools table help';
23580
    const defaultMenus = {
23581
      file: {
23582
        title: 'File',
1441 ariadna 23583
        items: 'newdocument restoredraft | preview | importword exportpdf exportword | export print | deleteallconversations'
1 efrain 23584
      },
23585
      edit: {
23586
        title: 'Edit',
23587
        items: 'undo redo | cut copy paste pastetext | selectall | searchreplace'
23588
      },
23589
      view: {
23590
        title: 'View',
1441 ariadna 23591
        items: 'code revisionhistory | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments'
1 efrain 23592
      },
23593
      insert: {
23594
        title: 'Insert',
1441 ariadna 23595
        items: 'image link media addcomment pageembed inserttemplate codesample inserttable accordion math | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents footnotes | mergetags | insertdatetime'
1 efrain 23596
      },
23597
      format: {
23598
        title: 'Format',
23599
        items: 'bold italic underline strikethrough superscript subscript codeformat | styles blocks fontfamily fontsize align lineheight | forecolor backcolor | language | removeformat'
23600
      },
23601
      tools: {
23602
        title: 'Tools',
23603
        items: 'aidialog aishortcuts | spellchecker spellcheckerlanguage | autocorrect capitalization | a11ycheck code typography wordcount addtemplate'
23604
      },
23605
      table: {
23606
        title: 'Table',
23607
        items: 'inserttable | cell row column | advtablesort | tableprops deletetable'
23608
      },
23609
      help: {
23610
        title: 'Help',
23611
        items: 'help'
23612
      }
23613
    };
23614
    const make = (menu, registry, editor) => {
23615
      const removedMenuItems = getRemovedMenuItems(editor).split(/[ ,]/);
23616
      return {
23617
        text: menu.title,
23618
        getItems: () => bind$3(menu.items, i => {
23619
          const itemName = i.toLowerCase();
23620
          if (itemName.trim().length === 0) {
23621
            return [];
23622
          } else if (exists(removedMenuItems, removedMenuItem => removedMenuItem === itemName)) {
23623
            return [];
23624
          } else if (itemName === 'separator' || itemName === '|') {
23625
            return [{ type: 'separator' }];
23626
          } else if (registry.menuItems[itemName]) {
23627
            return [registry.menuItems[itemName]];
23628
          } else {
23629
            return [];
23630
          }
23631
        })
23632
      };
23633
    };
23634
    const parseItemsString = items => {
23635
      return items.split(' ');
23636
    };
23637
    const identifyMenus = (editor, registry) => {
23638
      const rawMenuData = {
23639
        ...defaultMenus,
23640
        ...registry.menus
23641
      };
23642
      const userDefinedMenus = keys(registry.menus).length > 0;
23643
      const menubar = registry.menubar === undefined || registry.menubar === true ? parseItemsString(defaultMenubar) : parseItemsString(registry.menubar === false ? '' : registry.menubar);
23644
      const validMenus = filter$2(menubar, menuName => {
23645
        const isDefaultMenu = has$2(defaultMenus, menuName);
23646
        if (userDefinedMenus) {
1441 ariadna 23647
          return isDefaultMenu || get$h(registry.menus, menuName).exists(menu => has$2(menu, 'items'));
1 efrain 23648
        } else {
23649
          return isDefaultMenu;
23650
        }
23651
      });
23652
      const menus = map$2(validMenus, menuName => {
23653
        const menuData = rawMenuData[menuName];
23654
        return make({
23655
          title: menuData.title,
23656
          items: parseItemsString(menuData.items)
23657
        }, registry, editor);
23658
      });
23659
      return filter$2(menus, menu => {
23660
        const isNotSeparator = item => isString(item) || item.type !== 'separator';
23661
        return menu.getItems().length > 0 && exists(menu.getItems(), isNotSeparator);
23662
      });
23663
    };
23664
 
23665
    const fireSkinLoaded = editor => {
23666
      const done = () => {
23667
        editor._skinLoaded = true;
23668
        fireSkinLoaded$1(editor);
23669
      };
23670
      return () => {
23671
        if (editor.initialized) {
23672
          done();
23673
        } else {
23674
          editor.on('init', done);
23675
        }
23676
      };
23677
    };
23678
    const fireSkinLoadError = (editor, err) => () => fireSkinLoadError$1(editor, { message: err });
23679
 
1441 ariadna 23680
    const getSkinResourceIdentifier = editor => {
23681
      const skin = getSkin(editor);
23682
      if (!skin) {
23683
        return Optional.none();
23684
      } else {
23685
        return Optional.from(skin);
23686
      }
23687
    };
1 efrain 23688
    const loadStylesheet = (editor, stylesheetUrl, styleSheetLoader) => {
23689
      editor.on('remove', () => styleSheetLoader.unload(stylesheetUrl));
23690
      return styleSheetLoader.load(stylesheetUrl);
23691
    };
23692
    const loadRawCss = (editor, key, css, styleSheetLoader) => {
23693
      editor.on('remove', () => styleSheetLoader.unloadRawCss(key));
23694
      return styleSheetLoader.loadRawCss(key, css);
23695
    };
1441 ariadna 23696
    const skinIdentifierToResourceKey = (identifier, filename) => 'ui/' + identifier + '/' + filename;
23697
    const getResourceValue = resourceKey => Optional.from(tinymce.Resource.get(resourceKey)).filter(isString);
23698
    const determineCSSDecision = (editor, filenameBase, skinUrl = '') => {
23699
      const resourceKey = getSkinResourceIdentifier(editor).map(identifier => skinIdentifierToResourceKey(identifier, `${ filenameBase }.css`));
23700
      const resourceValue = resourceKey.bind(getResourceValue);
23701
      return lift2(resourceKey, resourceValue, (key, css) => {
23702
        return {
23703
          _kind: 'load-raw',
23704
          key,
23705
          css
23706
        };
23707
      }).getOrThunk(() => {
23708
        const suffix = editor.editorManager.suffix;
23709
        const skinUiCssUrl = skinUrl + `/${ filenameBase }${ suffix }.css`;
23710
        return {
23711
          _kind: 'load-stylesheet',
23712
          url: skinUiCssUrl
23713
        };
23714
      });
23715
    };
23716
    const loadUiSkins = (editor, skinUrl) => {
23717
      const loader = editor.ui.styleSheetLoader;
23718
      const decision = determineCSSDecision(editor, 'skin', skinUrl);
23719
      switch (decision._kind) {
23720
      case 'load-raw':
23721
        const {key, css} = decision;
23722
        loadRawCss(editor, key, css, loader);
23723
        return Promise.resolve();
23724
      case 'load-stylesheet':
23725
        const {url} = decision;
23726
        return loadStylesheet(editor, url, loader);
23727
      default:
23728
        return Promise.resolve();
1 efrain 23729
      }
23730
    };
1441 ariadna 23731
    const loadShadowDomUiSkins = (editor, skinUrl) => {
1 efrain 23732
      const isInShadowRoot$1 = isInShadowRoot(SugarElement.fromDom(editor.getElement()));
1441 ariadna 23733
      if (!isInShadowRoot$1) {
23734
        return Promise.resolve();
23735
      } else {
23736
        const loader = global$8.DOM.styleSheetLoader;
23737
        const decision = determineCSSDecision(editor, 'skin.shadowdom', skinUrl);
23738
        switch (decision._kind) {
23739
        case 'load-raw':
23740
          const {key, css} = decision;
23741
          loadRawCss(editor, key, css, loader);
1 efrain 23742
          return Promise.resolve();
1441 ariadna 23743
        case 'load-stylesheet':
23744
          const {url} = decision;
23745
          return loadStylesheet(editor, url, loader);
23746
        default:
23747
          return Promise.resolve();
23748
        }
23749
      }
23750
    };
23751
    const loadUiContentCSS = (editor, isInline, skinUrl) => {
23752
      const filenameBase = isInline ? 'content.inline' : 'content';
23753
      const decision = determineCSSDecision(editor, filenameBase, skinUrl);
23754
      switch (decision._kind) {
23755
      case 'load-raw':
23756
        const {key, css} = decision;
23757
        if (isInline) {
23758
          loadRawCss(editor, key, css, editor.ui.styleSheetLoader);
1 efrain 23759
        } else {
1441 ariadna 23760
          editor.on('PostRender', () => {
23761
            loadRawCss(editor, key, css, editor.dom.styleSheetLoader);
23762
          });
1 efrain 23763
        }
1441 ariadna 23764
        return Promise.resolve();
23765
      case 'load-stylesheet':
23766
        const {url} = decision;
23767
        if (skinUrl) {
23768
          editor.contentCSS.push(url);
23769
        }
23770
        return Promise.resolve();
23771
      default:
23772
        return Promise.resolve();
1 efrain 23773
      }
23774
    };
23775
    const loadUrlSkin = async (isInline, editor) => {
23776
      const skinUrl = getSkinUrl(editor);
1441 ariadna 23777
      await loadUiContentCSS(editor, isInline, skinUrl);
1 efrain 23778
      if (!isSkinDisabled(editor) && isString(skinUrl)) {
23779
        return Promise.all([
23780
          loadUiSkins(editor, skinUrl),
23781
          loadShadowDomUiSkins(editor, skinUrl)
23782
        ]).then();
23783
      }
23784
    };
23785
    const loadSkin = (isInline, editor) => {
23786
      return loadUrlSkin(isInline, editor).then(fireSkinLoaded(editor), fireSkinLoadError(editor, 'Skin could not be loaded'));
23787
    };
23788
    const iframe = curry(loadSkin, false);
23789
    const inline = curry(loadSkin, true);
23790
 
1441 ariadna 23791
    const makeTooltipText = (editor, labelWithPlaceholder, value) => isEmpty(value) ? editor.translate(labelWithPlaceholder) : editor.translate([
1 efrain 23792
      labelWithPlaceholder,
23793
      editor.translate(value)
23794
    ]);
23795
 
23796
    const generateSelectItems = (backstage, spec) => {
23797
      const generateItem = (rawItem, response, invalid, value) => {
23798
        const translatedText = backstage.shared.providers.translate(rawItem.title);
23799
        if (rawItem.type === 'separator') {
23800
          return Optional.some({
23801
            type: 'separator',
23802
            text: translatedText
23803
          });
23804
        } else if (rawItem.type === 'submenu') {
23805
          const items = bind$3(rawItem.getStyleItems(), si => validate(si, response, value));
23806
          if (response === 0 && items.length <= 0) {
23807
            return Optional.none();
23808
          } else {
23809
            return Optional.some({
23810
              type: 'nestedmenuitem',
23811
              text: translatedText,
23812
              enabled: items.length > 0,
23813
              getSubmenuItems: () => bind$3(rawItem.getStyleItems(), si => validate(si, response, value))
23814
            });
23815
          }
23816
        } else {
23817
          return Optional.some({
23818
            type: 'togglemenuitem',
23819
            text: translatedText,
23820
            icon: rawItem.icon,
23821
            active: rawItem.isSelected(value),
23822
            enabled: !invalid,
23823
            onAction: spec.onAction(rawItem),
23824
            ...rawItem.getStylePreview().fold(() => ({}), preview => ({ meta: { style: preview } }))
23825
          });
23826
        }
23827
      };
23828
      const validate = (item, response, value) => {
23829
        const invalid = item.type === 'formatter' && spec.isInvalid(item);
23830
        if (response === 0) {
23831
          return invalid ? [] : generateItem(item, response, false, value).toArray();
23832
        } else {
23833
          return generateItem(item, response, invalid, value).toArray();
23834
        }
23835
      };
23836
      const validateItems = preItems => {
23837
        const value = spec.getCurrentValue();
23838
        const response = spec.shouldHide ? 0 : 1;
23839
        return bind$3(preItems, item => validate(item, response, value));
23840
      };
23841
      const getFetch = (backstage, getStyleItems) => (comp, callback) => {
23842
        const preItems = getStyleItems();
23843
        const items = validateItems(preItems);
23844
        const menu = build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
23845
          isHorizontalMenu: false,
23846
          search: Optional.none()
23847
        });
23848
        callback(menu);
23849
      };
23850
      return {
23851
        validateItems,
23852
        getFetch
23853
      };
23854
    };
1441 ariadna 23855
    const createMenuItems = (backstage, spec) => {
1 efrain 23856
      const dataset = spec.dataset;
23857
      const getStyleItems = dataset.type === 'basic' ? () => map$2(dataset.data, d => processBasic(d, spec.isSelectedFor, spec.getPreviewFor)) : dataset.getData;
23858
      return {
23859
        items: generateSelectItems(backstage, spec),
23860
        getStyleItems
23861
      };
23862
    };
1441 ariadna 23863
    const createSelectButton = (editor, backstage, spec, getTooltip, textUpdateEventName, btnName) => {
23864
      const {items, getStyleItems} = createMenuItems(backstage, spec);
23865
      const tooltipString = Cell(spec.tooltip);
1 efrain 23866
      const getApi = comp => ({
23867
        getComponent: constant$1(comp),
23868
        setTooltip: tooltip => {
23869
          const translatedTooltip = backstage.shared.providers.translate(tooltip);
1441 ariadna 23870
          set$9(comp.element, 'aria-label', translatedTooltip);
23871
          tooltipString.set(tooltip);
1 efrain 23872
        }
23873
      });
23874
      const onSetup = api => {
1441 ariadna 23875
        const handler = e => api.setTooltip(makeTooltipText(editor, getTooltip(e.value), e.value));
1 efrain 23876
        editor.on(textUpdateEventName, handler);
23877
        return composeUnbinders(onSetupEvent(editor, 'NodeChange', api => {
23878
          const comp = api.getComponent();
23879
          spec.updateText(comp);
23880
          Disabling.set(api.getComponent(), !editor.selection.isEditable());
23881
        })(api), () => editor.off(textUpdateEventName, handler));
23882
      };
23883
      return renderCommonDropdown({
1441 ariadna 23884
        context: 'mode:design',
1 efrain 23885
        text: spec.icon.isSome() ? Optional.none() : spec.text,
23886
        icon: spec.icon,
1441 ariadna 23887
        ariaLabel: Optional.some(spec.tooltip),
23888
        tooltip: Optional.none(),
1 efrain 23889
        role: Optional.none(),
23890
        fetch: items.getFetch(backstage, getStyleItems),
23891
        onSetup,
23892
        getApi,
23893
        columns: 1,
23894
        presets: 'normal',
23895
        classes: spec.icon.isSome() ? [] : ['bespoke'],
1441 ariadna 23896
        dropdownBehaviours: [Tooltipping.config({
23897
            ...backstage.shared.providers.tooltips.getConfig({
23898
              tooltipText: backstage.shared.providers.translate(spec.tooltip),
23899
              onShow: comp => {
23900
                if (spec.tooltip !== tooltipString.get()) {
23901
                  const translatedTooltip = backstage.shared.providers.translate(tooltipString.get());
23902
                  Tooltipping.setComponents(comp, backstage.shared.providers.tooltips.getComponents({ tooltipText: translatedTooltip }));
23903
                }
23904
              }
23905
            })
23906
          })]
23907
      }, 'tox-tbtn', backstage.shared, btnName);
1 efrain 23908
    };
23909
 
23910
    const process = rawFormats => map$2(rawFormats, item => {
23911
      let title = item, format = item;
23912
      const values = item.split('=');
23913
      if (values.length > 1) {
23914
        title = values[0];
23915
        format = values[1];
23916
      }
23917
      return {
23918
        title,
23919
        format
23920
      };
23921
    });
23922
    const buildBasicStaticDataset = data => ({
23923
      type: 'basic',
23924
      data
23925
    });
23926
    var Delimiter;
23927
    (function (Delimiter) {
23928
      Delimiter[Delimiter['SemiColon'] = 0] = 'SemiColon';
23929
      Delimiter[Delimiter['Space'] = 1] = 'Space';
23930
    }(Delimiter || (Delimiter = {})));
23931
    const split = (rawFormats, delimiter) => {
23932
      if (delimiter === Delimiter.SemiColon) {
23933
        return rawFormats.replace(/;$/, '').split(';');
23934
      } else {
23935
        return rawFormats.split(' ');
23936
      }
23937
    };
23938
    const buildBasicSettingsDataset = (editor, settingName, delimiter) => {
23939
      const rawFormats = editor.options.get(settingName);
23940
      const data = process(split(rawFormats, delimiter));
23941
      return {
23942
        type: 'basic',
23943
        data
23944
      };
23945
    };
23946
 
23947
    const menuTitle$4 = 'Align';
1441 ariadna 23948
    const getTooltipPlaceholder$4 = constant$1('Alignment {0}');
1 efrain 23949
    const fallbackAlignment = 'left';
23950
    const alignMenuItems = [
23951
      {
23952
        title: 'Left',
23953
        icon: 'align-left',
23954
        format: 'alignleft',
23955
        command: 'JustifyLeft'
23956
      },
23957
      {
23958
        title: 'Center',
23959
        icon: 'align-center',
23960
        format: 'aligncenter',
23961
        command: 'JustifyCenter'
23962
      },
23963
      {
23964
        title: 'Right',
23965
        icon: 'align-right',
23966
        format: 'alignright',
23967
        command: 'JustifyRight'
23968
      },
23969
      {
23970
        title: 'Justify',
23971
        icon: 'align-justify',
23972
        format: 'alignjustify',
23973
        command: 'JustifyFull'
23974
      }
23975
    ];
23976
    const getSpec$4 = editor => {
23977
      const getMatchingValue = () => find$5(alignMenuItems, item => editor.formatter.match(item.format));
23978
      const isSelectedFor = format => () => editor.formatter.match(format);
23979
      const getPreviewFor = _format => Optional.none;
23980
      const updateSelectMenuIcon = comp => {
23981
        const match = getMatchingValue();
23982
        const alignment = match.fold(constant$1(fallbackAlignment), item => item.title.toLowerCase());
23983
        emitWith(comp, updateMenuIcon, { icon: `align-${ alignment }` });
23984
        fireAlignTextUpdate(editor, { value: alignment });
23985
      };
23986
      const dataset = buildBasicStaticDataset(alignMenuItems);
23987
      const onAction = rawItem => () => find$5(alignMenuItems, item => item.format === rawItem.format).each(item => editor.execCommand(item.command));
23988
      return {
1441 ariadna 23989
        tooltip: makeTooltipText(editor, getTooltipPlaceholder$4(), fallbackAlignment),
1 efrain 23990
        text: Optional.none(),
23991
        icon: Optional.some('align-left'),
23992
        isSelectedFor,
23993
        getCurrentValue: Optional.none,
23994
        getPreviewFor,
23995
        onAction,
23996
        updateText: updateSelectMenuIcon,
23997
        dataset,
23998
        shouldHide: false,
23999
        isInvalid: item => !editor.formatter.canApply(item.format)
24000
      };
24001
    };
1441 ariadna 24002
    const createAlignButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$4(editor), getTooltipPlaceholder$4, 'AlignTextUpdate', 'align');
1 efrain 24003
    const createAlignMenu = (editor, backstage) => {
1441 ariadna 24004
      const menuItems = createMenuItems(backstage, getSpec$4(editor));
1 efrain 24005
      editor.ui.registry.addNestedMenuItem('align', {
24006
        text: backstage.shared.providers.translate(menuTitle$4),
24007
        onSetup: onSetupEditableToggle(editor),
24008
        getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
24009
      });
24010
    };
24011
 
24012
    const findNearest = (editor, getStyles) => {
24013
      const styles = getStyles();
24014
      const formats = map$2(styles, style => style.format);
1441 ariadna 24015
      return Optional.from(editor.formatter.closest(formats)).bind(fmt => find$5(styles, data => data.format === fmt));
1 efrain 24016
    };
24017
 
24018
    const menuTitle$3 = 'Blocks';
1441 ariadna 24019
    const getTooltipPlaceholder$3 = constant$1('Block {0}');
1 efrain 24020
    const fallbackFormat = 'Paragraph';
24021
    const getSpec$3 = editor => {
24022
      const isSelectedFor = format => () => editor.formatter.match(format);
24023
      const getPreviewFor = format => () => {
24024
        const fmt = editor.formatter.get(format);
24025
        if (fmt) {
24026
          return Optional.some({
24027
            tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || 'div' : 'div',
24028
            styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
24029
          });
24030
        } else {
24031
          return Optional.none();
24032
        }
24033
      };
24034
      const updateSelectMenuText = comp => {
24035
        const detectedFormat = findNearest(editor, () => dataset.data);
24036
        const text = detectedFormat.fold(constant$1(fallbackFormat), fmt => fmt.title);
24037
        emitWith(comp, updateMenuText, { text });
24038
        fireBlocksTextUpdate(editor, { value: text });
24039
      };
24040
      const dataset = buildBasicSettingsDataset(editor, 'block_formats', Delimiter.SemiColon);
24041
      return {
1441 ariadna 24042
        tooltip: makeTooltipText(editor, getTooltipPlaceholder$3(), fallbackFormat),
1 efrain 24043
        text: Optional.some(fallbackFormat),
24044
        icon: Optional.none(),
24045
        isSelectedFor,
24046
        getCurrentValue: Optional.none,
24047
        getPreviewFor,
24048
        onAction: onActionToggleFormat$1(editor),
24049
        updateText: updateSelectMenuText,
24050
        dataset,
24051
        shouldHide: false,
24052
        isInvalid: item => !editor.formatter.canApply(item.format)
24053
      };
24054
    };
1441 ariadna 24055
    const createBlocksButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$3(editor), getTooltipPlaceholder$3, 'BlocksTextUpdate', 'blocks');
1 efrain 24056
    const createBlocksMenu = (editor, backstage) => {
1441 ariadna 24057
      const menuItems = createMenuItems(backstage, getSpec$3(editor));
1 efrain 24058
      editor.ui.registry.addNestedMenuItem('blocks', {
24059
        text: menuTitle$3,
24060
        onSetup: onSetupEditableToggle(editor),
24061
        getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
24062
      });
24063
    };
24064
 
24065
    const menuTitle$2 = 'Fonts';
1441 ariadna 24066
    const getTooltipPlaceholder$2 = constant$1('Font {0}');
1 efrain 24067
    const systemFont = 'System Font';
24068
    const systemStackFonts = [
24069
      '-apple-system',
24070
      'Segoe UI',
24071
      'Roboto',
24072
      'Helvetica Neue',
24073
      'sans-serif'
24074
    ];
24075
    const splitFonts = fontFamily => {
24076
      const fonts = fontFamily.split(/\s*,\s*/);
24077
      return map$2(fonts, font => font.replace(/^['"]+|['"]+$/g, ''));
24078
    };
24079
    const matchesStack = (fonts, stack) => stack.length > 0 && forall(stack, font => fonts.indexOf(font.toLowerCase()) > -1);
24080
    const isSystemFontStack = (fontFamily, userStack) => {
24081
      if (fontFamily.indexOf('-apple-system') === 0 || userStack.length > 0) {
24082
        const fonts = splitFonts(fontFamily.toLowerCase());
24083
        return matchesStack(fonts, systemStackFonts) || matchesStack(fonts, userStack);
24084
      } else {
24085
        return false;
24086
      }
24087
    };
24088
    const getSpec$2 = editor => {
24089
      const getMatchingValue = () => {
24090
        const getFirstFont = fontFamily => fontFamily ? splitFonts(fontFamily)[0] : '';
24091
        const fontFamily = editor.queryCommandValue('FontName');
24092
        const items = dataset.data;
24093
        const font = fontFamily ? fontFamily.toLowerCase() : '';
24094
        const userStack = getDefaultFontStack(editor);
24095
        const matchOpt = find$5(items, item => {
24096
          const format = item.format;
24097
          return format.toLowerCase() === font || getFirstFont(format).toLowerCase() === getFirstFont(font).toLowerCase();
24098
        }).orThunk(() => {
24099
          return someIf(isSystemFontStack(font, userStack), {
24100
            title: systemFont,
24101
            format: font
24102
          });
24103
        });
24104
        return {
24105
          matchOpt,
24106
          font: fontFamily
24107
        };
24108
      };
24109
      const isSelectedFor = item => valueOpt => valueOpt.exists(value => value.format === item);
24110
      const getCurrentValue = () => {
24111
        const {matchOpt} = getMatchingValue();
24112
        return matchOpt;
24113
      };
24114
      const getPreviewFor = item => () => Optional.some({
24115
        tag: 'div',
24116
        styles: item.indexOf('dings') === -1 ? { 'font-family': item } : {}
24117
      });
24118
      const onAction = rawItem => () => {
24119
        editor.undoManager.transact(() => {
24120
          editor.focus();
24121
          editor.execCommand('FontName', false, rawItem.format);
24122
        });
24123
      };
24124
      const updateSelectMenuText = comp => {
24125
        const {matchOpt, font} = getMatchingValue();
24126
        const text = matchOpt.fold(constant$1(font), item => item.title);
24127
        emitWith(comp, updateMenuText, { text });
24128
        fireFontFamilyTextUpdate(editor, { value: text });
24129
      };
24130
      const dataset = buildBasicSettingsDataset(editor, 'font_family_formats', Delimiter.SemiColon);
24131
      return {
1441 ariadna 24132
        tooltip: makeTooltipText(editor, getTooltipPlaceholder$2(), systemFont),
1 efrain 24133
        text: Optional.some(systemFont),
24134
        icon: Optional.none(),
24135
        isSelectedFor,
24136
        getCurrentValue,
24137
        getPreviewFor,
24138
        onAction,
24139
        updateText: updateSelectMenuText,
24140
        dataset,
24141
        shouldHide: false,
24142
        isInvalid: never
24143
      };
24144
    };
1441 ariadna 24145
    const createFontFamilyButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$2(editor), getTooltipPlaceholder$2, 'FontFamilyTextUpdate', 'fontfamily');
1 efrain 24146
    const createFontFamilyMenu = (editor, backstage) => {
1441 ariadna 24147
      const menuItems = createMenuItems(backstage, getSpec$2(editor));
1 efrain 24148
      editor.ui.registry.addNestedMenuItem('fontfamily', {
24149
        text: backstage.shared.providers.translate(menuTitle$2),
24150
        onSetup: onSetupEditableToggle(editor),
24151
        getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
24152
      });
24153
    };
24154
 
24155
    const units = {
24156
      unsupportedLength: [
24157
        'em',
24158
        'ex',
24159
        'cap',
24160
        'ch',
24161
        'ic',
24162
        'rem',
24163
        'lh',
24164
        'rlh',
24165
        'vw',
24166
        'vh',
24167
        'vi',
24168
        'vb',
24169
        'vmin',
24170
        'vmax',
24171
        'cm',
24172
        'mm',
24173
        'Q',
24174
        'in',
24175
        'pc',
24176
        'pt',
24177
        'px'
24178
      ],
24179
      fixed: [
24180
        'px',
24181
        'pt'
24182
      ],
24183
      relative: ['%'],
24184
      empty: ['']
24185
    };
24186
    const pattern = (() => {
24187
      const decimalDigits = '[0-9]+';
24188
      const signedInteger = '[+-]?' + decimalDigits;
24189
      const exponentPart = '[eE]' + signedInteger;
24190
      const dot = '\\.';
24191
      const opt = input => `(?:${ input })?`;
24192
      const unsignedDecimalLiteral = [
24193
        'Infinity',
24194
        decimalDigits + dot + opt(decimalDigits) + opt(exponentPart),
24195
        dot + decimalDigits + opt(exponentPart),
24196
        decimalDigits + opt(exponentPart)
24197
      ].join('|');
24198
      const float = `[+-]?(?:${ unsignedDecimalLiteral })`;
24199
      return new RegExp(`^(${ float })(.*)$`);
24200
    })();
24201
    const isUnit = (unit, accepted) => exists(accepted, acc => exists(units[acc], check => unit === check));
24202
    const parse = (input, accepted) => {
24203
      const match = Optional.from(pattern.exec(input));
24204
      return match.bind(array => {
24205
        const value = Number(array[1]);
24206
        const unitRaw = array[2];
24207
        if (isUnit(unitRaw, accepted)) {
24208
          return Optional.some({
24209
            value,
24210
            unit: unitRaw
24211
          });
24212
        } else {
24213
          return Optional.none();
24214
        }
24215
      });
24216
    };
24217
    const normalise = (input, accepted) => parse(input, accepted).map(({value, unit}) => value + unit);
24218
 
24219
    const Keys = {
24220
      tab: constant$1(9),
24221
      escape: constant$1(27),
24222
      enter: constant$1(13),
24223
      backspace: constant$1(8),
24224
      delete: constant$1(46),
24225
      left: constant$1(37),
24226
      up: constant$1(38),
24227
      right: constant$1(39),
24228
      down: constant$1(40),
24229
      space: constant$1(32),
24230
      home: constant$1(36),
24231
      end: constant$1(35),
24232
      pageUp: constant$1(33),
24233
      pageDown: constant$1(34)
24234
    };
24235
 
1441 ariadna 24236
    const createBespokeNumberInput = (editor, backstage, spec, btnName) => {
1 efrain 24237
      let currentComp = Optional.none();
24238
      const getValueFromCurrentComp = comp => comp.map(alloyComp => Representing.getValue(alloyComp)).getOr('');
1441 ariadna 24239
      const onSetup = onSetupEvent(editor, 'NodeChange SwitchMode DisabledStateChange', api => {
1 efrain 24240
        const comp = api.getComponent();
24241
        currentComp = Optional.some(comp);
24242
        spec.updateInputValue(comp);
1441 ariadna 24243
        Disabling.set(comp, !editor.selection.isEditable() || isDisabled(editor));
1 efrain 24244
      });
24245
      const getApi = comp => ({ getComponent: constant$1(comp) });
24246
      const editorOffCell = Cell(noop);
24247
      const customEvents = generate$6('custom-number-input-events');
24248
      const changeValue = (f, fromInput, focusBack) => {
24249
        const text = getValueFromCurrentComp(currentComp);
24250
        const newValue = spec.getNewValue(text, f);
24251
        const lenghtDelta = text.length - `${ newValue }`.length;
24252
        const oldStart = currentComp.map(comp => comp.element.dom.selectionStart - lenghtDelta);
24253
        const oldEnd = currentComp.map(comp => comp.element.dom.selectionEnd - lenghtDelta);
24254
        spec.onAction(newValue, focusBack);
24255
        currentComp.each(comp => {
24256
          Representing.setValue(comp, newValue);
24257
          if (fromInput) {
24258
            oldStart.each(oldStart => comp.element.dom.selectionStart = oldStart);
24259
            oldEnd.each(oldEnd => comp.element.dom.selectionEnd = oldEnd);
24260
          }
24261
        });
24262
      };
24263
      const decrease = (fromInput, focusBack) => changeValue((n, s) => n - s, fromInput, focusBack);
24264
      const increase = (fromInput, focusBack) => changeValue((n, s) => n + s, fromInput, focusBack);
24265
      const goToParent = comp => parentElement(comp.element).fold(Optional.none, parent => {
24266
        focus$3(parent);
24267
        return Optional.some(true);
24268
      });
24269
      const focusInput = comp => {
24270
        if (hasFocus(comp.element)) {
24271
          firstChild(comp.element).each(input => focus$3(input));
24272
          return Optional.some(true);
24273
        } else {
24274
          return Optional.none();
24275
        }
24276
      };
24277
      const makeStepperButton = (action, title, tooltip, classes) => {
24278
        const editorOffCellStepButton = Cell(noop);
24279
        const translatedTooltip = backstage.shared.providers.translate(tooltip);
24280
        const altExecuting = generate$6('altExecuting');
1441 ariadna 24281
        const onSetup = onSetupEvent(editor, 'NodeChange SwitchMode DisabledStateChange', api => {
24282
          Disabling.set(api.getComponent(), !editor.selection.isEditable() || isDisabled(editor));
1 efrain 24283
        });
24284
        const onClick = comp => {
24285
          if (!Disabling.isDisabled(comp)) {
24286
            action(true);
24287
          }
24288
        };
24289
        return Button.sketch({
24290
          dom: {
24291
            tag: 'button',
24292
            attributes: {
1441 ariadna 24293
              'aria-label': translatedTooltip,
24294
              'data-mce-name': title
1 efrain 24295
            },
24296
            classes: classes.concat(title)
24297
          },
24298
          components: [renderIconFromPack$1(title, backstage.shared.providers.icons)],
24299
          buttonBehaviours: derive$1([
24300
            Disabling.config({}),
1441 ariadna 24301
            Tooltipping.config(backstage.shared.providers.tooltips.getConfig({ tooltipText: translatedTooltip })),
1 efrain 24302
            config(altExecuting, [
24303
              onControlAttached({
24304
                onSetup,
24305
                getApi
24306
              }, editorOffCellStepButton),
24307
              onControlDetached({ getApi }, editorOffCellStepButton),
24308
              run$1(keydown(), (comp, se) => {
24309
                if (se.event.raw.keyCode === Keys.space() || se.event.raw.keyCode === Keys.enter()) {
24310
                  if (!Disabling.isDisabled(comp)) {
24311
                    action(false);
24312
                  }
24313
                }
24314
              }),
24315
              run$1(click(), onClick),
24316
              run$1(touchend(), onClick)
24317
            ])
24318
          ]),
24319
          eventOrder: {
24320
            [keydown()]: [
24321
              altExecuting,
24322
              'keying'
24323
            ],
24324
            [click()]: [
24325
              altExecuting,
24326
              'alloy.base.behaviour'
24327
            ],
24328
            [touchend()]: [
24329
              altExecuting,
24330
              'alloy.base.behaviour'
1441 ariadna 24331
            ],
24332
            [attachedToDom()]: [
24333
              'alloy.base.behaviour',
24334
              altExecuting,
24335
              'tooltipping'
24336
            ],
24337
            [detachedFromDom()]: [
24338
              altExecuting,
24339
              'tooltipping'
1 efrain 24340
            ]
24341
          }
24342
        });
24343
      };
24344
      const memMinus = record(makeStepperButton(focusBack => decrease(false, focusBack), 'minus', 'Decrease font size', []));
24345
      const memPlus = record(makeStepperButton(focusBack => increase(false, focusBack), 'plus', 'Increase font size', []));
24346
      const memInput = record({
24347
        dom: {
24348
          tag: 'div',
24349
          classes: ['tox-input-wrapper']
24350
        },
24351
        components: [Input.sketch({
24352
            inputBehaviours: derive$1([
24353
              Disabling.config({}),
24354
              config(customEvents, [
24355
                onControlAttached({
24356
                  onSetup,
24357
                  getApi
24358
                }, editorOffCell),
24359
                onControlDetached({ getApi }, editorOffCell)
24360
              ]),
24361
              config('input-update-display-text', [
24362
                run$1(updateMenuText, (comp, se) => {
24363
                  Representing.setValue(comp, se.event.text);
24364
                }),
24365
                run$1(focusout(), comp => {
24366
                  spec.onAction(Representing.getValue(comp));
24367
                }),
24368
                run$1(change(), comp => {
24369
                  spec.onAction(Representing.getValue(comp));
24370
                })
24371
              ]),
24372
              Keying.config({
24373
                mode: 'special',
24374
                onEnter: _comp => {
24375
                  changeValue(identity, true, true);
24376
                  return Optional.some(true);
24377
                },
24378
                onEscape: goToParent,
24379
                onUp: _comp => {
24380
                  increase(true, false);
24381
                  return Optional.some(true);
24382
                },
24383
                onDown: _comp => {
24384
                  decrease(true, false);
24385
                  return Optional.some(true);
24386
                },
24387
                onLeft: (_comp, se) => {
24388
                  se.cut();
24389
                  return Optional.none();
24390
                },
24391
                onRight: (_comp, se) => {
24392
                  se.cut();
24393
                  return Optional.none();
24394
                }
24395
              })
24396
            ])
24397
          })],
24398
        behaviours: derive$1([
24399
          Focusing.config({}),
24400
          Keying.config({
24401
            mode: 'special',
24402
            onEnter: focusInput,
24403
            onSpace: focusInput,
24404
            onEscape: goToParent
24405
          }),
24406
          config('input-wrapper-events', [run$1(mouseover(), comp => {
24407
              each$1([
24408
                memMinus,
24409
                memPlus
24410
              ], button => {
24411
                const buttonNode = SugarElement.fromDom(button.get(comp).element.dom);
24412
                if (hasFocus(buttonNode)) {
24413
                  blur$1(buttonNode);
24414
                }
24415
              });
24416
            })])
24417
        ])
24418
      });
24419
      return {
24420
        dom: {
24421
          tag: 'div',
1441 ariadna 24422
          classes: ['tox-number-input'],
24423
          attributes: { ...isNonNullable(btnName) ? { 'data-mce-name': btnName } : {} }
1 efrain 24424
        },
24425
        components: [
24426
          memMinus.asSpec(),
24427
          memInput.asSpec(),
24428
          memPlus.asSpec()
24429
        ],
24430
        behaviours: derive$1([
24431
          Focusing.config({}),
24432
          Keying.config({
24433
            mode: 'flow',
24434
            focusInside: FocusInsideModes.OnEnterOrSpaceMode,
24435
            cycles: false,
24436
            selector: 'button, .tox-input-wrapper',
24437
            onEscape: wrapperComp => {
24438
              if (hasFocus(wrapperComp.element)) {
24439
                return Optional.none();
24440
              } else {
24441
                focus$3(wrapperComp.element);
24442
                return Optional.some(true);
24443
              }
24444
            }
24445
          })
24446
        ])
24447
      };
24448
    };
24449
 
24450
    const menuTitle$1 = 'Font sizes';
1441 ariadna 24451
    const getTooltipPlaceholder$1 = constant$1('Font size {0}');
1 efrain 24452
    const fallbackFontSize = '12pt';
24453
    const legacyFontSizes = {
24454
      '8pt': '1',
24455
      '10pt': '2',
24456
      '12pt': '3',
24457
      '14pt': '4',
24458
      '18pt': '5',
24459
      '24pt': '6',
24460
      '36pt': '7'
24461
    };
24462
    const keywordFontSizes = {
24463
      'xx-small': '7pt',
24464
      'x-small': '8pt',
24465
      'small': '10pt',
24466
      'medium': '12pt',
24467
      'large': '14pt',
24468
      'x-large': '18pt',
24469
      'xx-large': '24pt'
24470
    };
24471
    const round = (number, precision) => {
24472
      const factor = Math.pow(10, precision);
24473
      return Math.round(number * factor) / factor;
24474
    };
24475
    const toPt = (fontSize, precision) => {
24476
      if (/[0-9.]+px$/.test(fontSize)) {
24477
        return round(parseInt(fontSize, 10) * 72 / 96, precision || 0) + 'pt';
24478
      } else {
1441 ariadna 24479
        return get$h(keywordFontSizes, fontSize).getOr(fontSize);
1 efrain 24480
      }
24481
    };
1441 ariadna 24482
    const toLegacy = fontSize => get$h(legacyFontSizes, fontSize).getOr('');
1 efrain 24483
    const getSpec$1 = editor => {
24484
      const getMatchingValue = () => {
24485
        let matchOpt = Optional.none();
24486
        const items = dataset.data;
24487
        const fontSize = editor.queryCommandValue('FontSize');
24488
        if (fontSize) {
24489
          for (let precision = 3; matchOpt.isNone() && precision >= 0; precision--) {
24490
            const pt = toPt(fontSize, precision);
24491
            const legacy = toLegacy(pt);
24492
            matchOpt = find$5(items, item => item.format === fontSize || item.format === pt || item.format === legacy);
24493
          }
24494
        }
24495
        return {
24496
          matchOpt,
24497
          size: fontSize
24498
        };
24499
      };
24500
      const isSelectedFor = item => valueOpt => valueOpt.exists(value => value.format === item);
24501
      const getCurrentValue = () => {
24502
        const {matchOpt} = getMatchingValue();
24503
        return matchOpt;
24504
      };
24505
      const getPreviewFor = constant$1(Optional.none);
24506
      const onAction = rawItem => () => {
24507
        editor.undoManager.transact(() => {
24508
          editor.focus();
24509
          editor.execCommand('FontSize', false, rawItem.format);
24510
        });
24511
      };
24512
      const updateSelectMenuText = comp => {
24513
        const {matchOpt, size} = getMatchingValue();
24514
        const text = matchOpt.fold(constant$1(size), match => match.title);
24515
        emitWith(comp, updateMenuText, { text });
24516
        fireFontSizeTextUpdate(editor, { value: text });
24517
      };
24518
      const dataset = buildBasicSettingsDataset(editor, 'font_size_formats', Delimiter.Space);
24519
      return {
1441 ariadna 24520
        tooltip: makeTooltipText(editor, getTooltipPlaceholder$1(), fallbackFontSize),
1 efrain 24521
        text: Optional.some(fallbackFontSize),
24522
        icon: Optional.none(),
24523
        isSelectedFor,
24524
        getPreviewFor,
24525
        getCurrentValue,
24526
        onAction,
24527
        updateText: updateSelectMenuText,
24528
        dataset,
24529
        shouldHide: false,
24530
        isInvalid: never
24531
      };
24532
    };
1441 ariadna 24533
    const createFontSizeButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$1(editor), getTooltipPlaceholder$1, 'FontSizeTextUpdate', 'fontsize');
1 efrain 24534
    const getConfigFromUnit = unit => {
24535
      var _a;
24536
      const baseConfig = { step: 1 };
24537
      const configs = {
24538
        em: { step: 0.1 },
24539
        cm: { step: 0.1 },
24540
        in: { step: 0.1 },
24541
        pc: { step: 0.1 },
24542
        ch: { step: 0.1 },
24543
        rem: { step: 0.1 }
24544
      };
24545
      return (_a = configs[unit]) !== null && _a !== void 0 ? _a : baseConfig;
24546
    };
24547
    const defaultValue = 16;
24548
    const isValidValue = value => value >= 0;
24549
    const getNumberInputSpec = editor => {
24550
      const getCurrentValue = () => editor.queryCommandValue('FontSize');
24551
      const updateInputValue = comp => emitWith(comp, updateMenuText, { text: getCurrentValue() });
24552
      return {
24553
        updateInputValue,
24554
        onAction: (format, focusBack) => editor.execCommand('FontSize', false, format, { skip_focus: !focusBack }),
24555
        getNewValue: (text, updateFunction) => {
24556
          parse(text, [
24557
            'unsupportedLength',
24558
            'empty'
24559
          ]);
24560
          const currentValue = getCurrentValue();
24561
          const parsedText = parse(text, [
24562
            'unsupportedLength',
24563
            'empty'
24564
          ]).or(parse(currentValue, [
24565
            'unsupportedLength',
24566
            'empty'
24567
          ]));
24568
          const value = parsedText.map(res => res.value).getOr(defaultValue);
24569
          const defaultUnit = getFontSizeInputDefaultUnit(editor);
24570
          const unit = parsedText.map(res => res.unit).filter(u => u !== '').getOr(defaultUnit);
24571
          const newValue = updateFunction(value, getConfigFromUnit(unit).step);
24572
          const res = `${ isValidValue(newValue) ? newValue : value }${ unit }`;
24573
          if (res !== currentValue) {
24574
            fireFontSizeInputTextUpdate(editor, { value: res });
24575
          }
24576
          return res;
24577
        }
24578
      };
24579
    };
1441 ariadna 24580
    const createFontSizeInputButton = (editor, backstage) => createBespokeNumberInput(editor, backstage, getNumberInputSpec(editor), 'fontsizeinput');
1 efrain 24581
    const createFontSizeMenu = (editor, backstage) => {
1441 ariadna 24582
      const menuItems = createMenuItems(backstage, getSpec$1(editor));
1 efrain 24583
      editor.ui.registry.addNestedMenuItem('fontsize', {
24584
        text: menuTitle$1,
24585
        onSetup: onSetupEditableToggle(editor),
24586
        getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
24587
      });
24588
    };
24589
 
24590
    const menuTitle = 'Formats';
1441 ariadna 24591
    const getTooltipPlaceholder = value => isEmpty(value) ? 'Formats' : 'Format {0}';
1 efrain 24592
    const getSpec = (editor, dataset) => {
1441 ariadna 24593
      const fallbackFormat = 'Formats';
1 efrain 24594
      const isSelectedFor = format => () => editor.formatter.match(format);
24595
      const getPreviewFor = format => () => {
24596
        const fmt = editor.formatter.get(format);
24597
        return fmt !== undefined ? Optional.some({
24598
          tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || 'div' : 'div',
24599
          styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
24600
        }) : Optional.none();
24601
      };
24602
      const updateSelectMenuText = comp => {
24603
        const getFormatItems = fmt => {
24604
          if (isNestedFormat(fmt)) {
24605
            return bind$3(fmt.items, getFormatItems);
24606
          } else if (isFormatReference(fmt)) {
24607
            return [{
24608
                title: fmt.title,
24609
                format: fmt.format
24610
              }];
24611
          } else {
24612
            return [];
24613
          }
24614
        };
24615
        const flattenedItems = bind$3(getStyleFormats(editor), getFormatItems);
24616
        const detectedFormat = findNearest(editor, constant$1(flattenedItems));
1441 ariadna 24617
        const text = detectedFormat.fold(constant$1({
24618
          title: fallbackFormat,
24619
          tooltipLabel: ''
24620
        }), fmt => ({
24621
          title: fmt.title,
24622
          tooltipLabel: fmt.title
24623
        }));
24624
        emitWith(comp, updateMenuText, { text: text.title });
24625
        fireStylesTextUpdate(editor, { value: text.tooltipLabel });
1 efrain 24626
      };
24627
      return {
1441 ariadna 24628
        tooltip: makeTooltipText(editor, getTooltipPlaceholder(''), ''),
1 efrain 24629
        text: Optional.some(fallbackFormat),
24630
        icon: Optional.none(),
24631
        isSelectedFor,
24632
        getCurrentValue: Optional.none,
24633
        getPreviewFor,
24634
        onAction: onActionToggleFormat$1(editor),
24635
        updateText: updateSelectMenuText,
24636
        shouldHide: shouldAutoHideStyleFormats(editor),
24637
        isInvalid: item => !editor.formatter.canApply(item.format),
24638
        dataset
24639
      };
24640
    };
24641
    const createStylesButton = (editor, backstage) => {
24642
      const dataset = {
24643
        type: 'advanced',
24644
        ...backstage.styles
24645
      };
1441 ariadna 24646
      return createSelectButton(editor, backstage, getSpec(editor, dataset), getTooltipPlaceholder, 'StylesTextUpdate', 'styles');
1 efrain 24647
    };
24648
    const createStylesMenu = (editor, backstage) => {
24649
      const dataset = {
24650
        type: 'advanced',
24651
        ...backstage.styles
24652
      };
1441 ariadna 24653
      const menuItems = createMenuItems(backstage, getSpec(editor, dataset));
1 efrain 24654
      editor.ui.registry.addNestedMenuItem('styles', {
24655
        text: menuTitle,
24656
        onSetup: onSetupEditableToggle(editor),
24657
        getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
24658
      });
24659
    };
24660
 
24661
    const schema$7 = constant$1([
24662
      required$1('toggleClass'),
24663
      required$1('fetch'),
24664
      onStrictHandler('onExecute'),
24665
      defaulted('getHotspot', Optional.some),
24666
      defaulted('getAnchorOverrides', constant$1({})),
24667
      schema$y(),
24668
      onStrictHandler('onItemExecute'),
24669
      option$3('lazySink'),
24670
      required$1('dom'),
24671
      onHandler('onOpen'),
24672
      field('splitDropdownBehaviours', [
24673
        Coupling,
24674
        Keying,
24675
        Focusing
24676
      ]),
24677
      defaulted('matchWidth', false),
24678
      defaulted('useMinWidth', false),
24679
      defaulted('eventOrder', {}),
1441 ariadna 24680
      option$3('role'),
24681
      option$3('listRole')
1 efrain 24682
    ].concat(sandboxFields()));
24683
    const arrowPart = required({
24684
      factory: Button,
24685
      schema: [required$1('dom')],
24686
      name: 'arrow',
24687
      defaults: () => {
24688
        return { buttonBehaviours: derive$1([Focusing.revoke()]) };
24689
      },
24690
      overrides: detail => {
24691
        return {
24692
          dom: {
24693
            tag: 'span',
24694
            attributes: { role: 'presentation' }
24695
          },
24696
          action: arrow => {
24697
            arrow.getSystem().getByUid(detail.uid).each(emitExecute);
24698
          },
24699
          buttonBehaviours: derive$1([Toggling.config({
24700
              toggleOnExecute: false,
24701
              toggleClass: detail.toggleClass
24702
            })])
24703
        };
24704
      }
24705
    });
24706
    const buttonPart = required({
24707
      factory: Button,
24708
      schema: [required$1('dom')],
24709
      name: 'button',
24710
      defaults: () => {
24711
        return { buttonBehaviours: derive$1([Focusing.revoke()]) };
24712
      },
24713
      overrides: detail => {
24714
        return {
24715
          dom: {
24716
            tag: 'span',
24717
            attributes: { role: 'presentation' }
24718
          },
24719
          action: btn => {
24720
            btn.getSystem().getByUid(detail.uid).each(splitDropdown => {
24721
              detail.onExecute(splitDropdown, btn);
24722
            });
24723
          }
24724
        };
24725
      }
24726
    });
24727
    const parts$3 = constant$1([
24728
      arrowPart,
24729
      buttonPart,
24730
      optional({
24731
        factory: {
24732
          sketch: spec => {
24733
            return {
24734
              uid: spec.uid,
24735
              dom: {
24736
                tag: 'span',
24737
                styles: { display: 'none' },
24738
                attributes: { 'aria-hidden': 'true' },
24739
                innerHtml: spec.text
24740
              }
24741
            };
24742
          }
24743
        },
24744
        schema: [required$1('text')],
24745
        name: 'aria-descriptor'
24746
      }),
24747
      external({
24748
        schema: [tieredMenuMarkers()],
24749
        name: 'menu',
24750
        defaults: detail => {
24751
          return {
24752
            onExecute: (tmenu, item) => {
24753
              tmenu.getSystem().getByUid(detail.uid).each(splitDropdown => {
24754
                detail.onItemExecute(splitDropdown, tmenu, item);
24755
              });
24756
            }
24757
          };
24758
        }
24759
      }),
24760
      partType$1()
24761
    ]);
24762
 
24763
    const factory$5 = (detail, components, spec, externals) => {
24764
      const switchToMenu = sandbox => {
24765
        Composing.getCurrent(sandbox).each(current => {
24766
          Highlighting.highlightFirst(current);
24767
          Keying.focusIn(current);
24768
        });
24769
      };
24770
      const action = component => {
24771
        const onOpenSync = switchToMenu;
24772
        togglePopup(detail, identity, component, externals, onOpenSync, HighlightOnOpen.HighlightMenuAndItem).get(noop);
24773
      };
24774
      const openMenu = comp => {
24775
        action(comp);
24776
        return Optional.some(true);
24777
      };
24778
      const executeOnButton = comp => {
24779
        const button = getPartOrDie(comp, detail, 'button');
24780
        emitExecute(button);
24781
        return Optional.some(true);
24782
      };
24783
      const buttonEvents = {
24784
        ...derive$2([runOnAttached((component, _simulatedEvent) => {
24785
            const ariaDescriptor = getPart(component, detail, 'aria-descriptor');
24786
            ariaDescriptor.each(descriptor => {
24787
              const descriptorId = generate$6('aria');
24788
              set$9(descriptor.element, 'id', descriptorId);
24789
              set$9(component.element, 'aria-describedby', descriptorId);
24790
            });
24791
          })]),
1441 ariadna 24792
        ...events$9(Optional.some(action))
1 efrain 24793
      };
24794
      const apis = {
24795
        repositionMenus: comp => {
24796
          if (Toggling.isOn(comp)) {
24797
            repositionMenus(comp);
24798
          }
24799
        }
24800
      };
24801
      return {
24802
        uid: detail.uid,
24803
        dom: detail.dom,
24804
        components,
24805
        apis,
24806
        eventOrder: {
24807
          ...detail.eventOrder,
24808
          [execute$5()]: [
24809
            'disabling',
24810
            'toggling',
24811
            'alloy.base.behaviour'
24812
          ]
24813
        },
24814
        events: buttonEvents,
24815
        behaviours: augment(detail.splitDropdownBehaviours, [
24816
          Coupling.config({
24817
            others: {
24818
              sandbox: hotspot => {
24819
                const arrow = getPartOrDie(hotspot, detail, 'arrow');
24820
                const extras = {
24821
                  onOpen: () => {
24822
                    Toggling.on(arrow);
24823
                    Toggling.on(hotspot);
24824
                  },
24825
                  onClose: () => {
24826
                    Toggling.off(arrow);
24827
                    Toggling.off(hotspot);
24828
                  }
24829
                };
24830
                return makeSandbox$1(detail, hotspot, extras);
24831
              }
24832
            }
24833
          }),
24834
          Keying.config({
24835
            mode: 'special',
24836
            onSpace: executeOnButton,
24837
            onEnter: executeOnButton,
24838
            onDown: openMenu
24839
          }),
24840
          Focusing.config({}),
24841
          Toggling.config({
24842
            toggleOnExecute: false,
24843
            aria: { mode: 'expanded' }
24844
          })
24845
        ]),
24846
        domModification: {
24847
          attributes: {
24848
            'role': detail.role.getOr('button'),
24849
            'aria-haspopup': true
24850
          }
24851
        }
24852
      };
24853
    };
24854
    const SplitDropdown = composite({
24855
      name: 'SplitDropdown',
24856
      configFields: schema$7(),
24857
      partFields: parts$3(),
24858
      factory: factory$5,
24859
      apis: { repositionMenus: (apis, comp) => apis.repositionMenus(comp) }
24860
    });
24861
 
24862
    const getButtonApi = component => ({
24863
      isEnabled: () => !Disabling.isDisabled(component),
24864
      setEnabled: state => Disabling.set(component, !state),
24865
      setText: text => emitWith(component, updateMenuText, { text }),
24866
      setIcon: icon => emitWith(component, updateMenuIcon, { icon })
24867
    });
24868
    const getToggleApi = component => ({
24869
      setActive: state => {
24870
        Toggling.set(component, state);
24871
      },
24872
      isActive: () => Toggling.isOn(component),
24873
      isEnabled: () => !Disabling.isDisabled(component),
24874
      setEnabled: state => Disabling.set(component, !state),
24875
      setText: text => emitWith(component, updateMenuText, { text }),
24876
      setIcon: icon => emitWith(component, updateMenuIcon, { icon })
24877
    });
1441 ariadna 24878
    const getTooltipAttributes = (tooltip, providersBackstage) => tooltip.map(tooltip => ({ 'aria-label': providersBackstage.translate(tooltip) })).getOr({});
1 efrain 24879
    const focusButtonEvent = generate$6('focus-button');
1441 ariadna 24880
    const renderCommonStructure = (optIcon, optText, tooltip, behaviours, providersBackstage, context, btnName) => {
1 efrain 24881
      const optMemDisplayText = optText.map(text => record(renderLabel$1(text, 'tox-tbtn', providersBackstage)));
24882
      const optMemDisplayIcon = optIcon.map(icon => record(renderReplaceableIconFromPack(icon, providersBackstage.icons)));
24883
      return {
24884
        dom: {
24885
          tag: 'button',
24886
          classes: ['tox-tbtn'].concat(optText.isSome() ? ['tox-tbtn--select'] : []),
1441 ariadna 24887
          attributes: {
24888
            ...getTooltipAttributes(tooltip, providersBackstage),
24889
            ...isNonNullable(btnName) ? { 'data-mce-name': btnName } : {}
24890
          }
1 efrain 24891
        },
24892
        components: componentRenderPipeline([
24893
          optMemDisplayIcon.map(mem => mem.asSpec()),
24894
          optMemDisplayText.map(mem => mem.asSpec())
24895
        ]),
24896
        eventOrder: {
24897
          [mousedown()]: [
24898
            'focusing',
24899
            'alloy.base.behaviour',
24900
            commonButtonDisplayEvent
24901
          ],
24902
          [attachedToDom()]: [
24903
            commonButtonDisplayEvent,
24904
            'toolbar-group-button-events'
1441 ariadna 24905
          ],
24906
          [detachedFromDom()]: [
24907
            commonButtonDisplayEvent,
24908
            'toolbar-group-button-events',
24909
            'tooltipping'
1 efrain 24910
          ]
24911
        },
24912
        buttonBehaviours: derive$1([
1441 ariadna 24913
          DisablingConfigs.toolbarButton(() => providersBackstage.checkUiComponentContext(context).shouldDisable),
24914
          toggleOnReceive(() => providersBackstage.checkUiComponentContext(context)),
1 efrain 24915
          config(commonButtonDisplayEvent, [
24916
            runOnAttached((comp, _se) => forceInitialSize(comp)),
24917
            run$1(updateMenuText, (comp, se) => {
24918
              optMemDisplayText.bind(mem => mem.getOpt(comp)).each(displayText => {
24919
                Replacing.set(displayText, [text$2(providersBackstage.translate(se.event.text))]);
24920
              });
24921
            }),
24922
            run$1(updateMenuIcon, (comp, se) => {
24923
              optMemDisplayIcon.bind(mem => mem.getOpt(comp)).each(displayIcon => {
24924
                Replacing.set(displayIcon, [renderReplaceableIconFromPack(se.event.icon, providersBackstage.icons)]);
24925
              });
24926
            }),
24927
            run$1(mousedown(), (button, se) => {
24928
              se.event.prevent();
24929
              emit(button, focusButtonEvent);
24930
            })
24931
          ])
24932
        ].concat(behaviours.getOr([])))
24933
      };
24934
    };
1441 ariadna 24935
    const renderFloatingToolbarButton = (spec, backstage, identifyButtons, attributes, btnName) => {
1 efrain 24936
      const sharedBackstage = backstage.shared;
24937
      const editorOffCell = Cell(noop);
24938
      const specialisation = {
24939
        toolbarButtonBehaviours: [],
24940
        getApi: getButtonApi,
24941
        onSetup: spec.onSetup
24942
      };
1441 ariadna 24943
      const behaviours = [
24944
        config('toolbar-group-button-events', [
1 efrain 24945
          onControlAttached(specialisation, editorOffCell),
24946
          onControlDetached(specialisation, editorOffCell)
1441 ariadna 24947
        ]),
24948
        ...spec.tooltip.map(t => Tooltipping.config(backstage.shared.providers.tooltips.getConfig({ tooltipText: backstage.shared.providers.translate(t) }))).toArray()
24949
      ];
1 efrain 24950
      return FloatingToolbarButton.sketch({
24951
        lazySink: sharedBackstage.getSink,
24952
        fetch: () => Future.nu(resolve => {
24953
          resolve(map$2(identifyButtons(spec.items), renderToolbarGroup));
24954
        }),
24955
        markers: { toggledClass: 'tox-tbtn--enabled' },
24956
        parts: {
1441 ariadna 24957
          button: renderCommonStructure(spec.icon, spec.text, spec.tooltip, Optional.some(behaviours), sharedBackstage.providers, spec.context, btnName),
1 efrain 24958
          toolbar: {
24959
            dom: {
24960
              tag: 'div',
24961
              classes: ['tox-toolbar__overflow'],
24962
              attributes
24963
            }
24964
          }
24965
        }
24966
      });
24967
    };
1441 ariadna 24968
    const renderCommonToolbarButton = (spec, specialisation, providersBackstage, btnName) => {
1 efrain 24969
      var _d;
24970
      const editorOffCell = Cell(noop);
1441 ariadna 24971
      const structure = renderCommonStructure(spec.icon, spec.text, spec.tooltip, Optional.none(), providersBackstage, spec.context, btnName);
1 efrain 24972
      return Button.sketch({
24973
        dom: structure.dom,
24974
        components: structure.components,
24975
        eventOrder: toolbarButtonEventOrder,
24976
        buttonBehaviours: {
24977
          ...derive$1([
24978
            config('toolbar-button-events', [
24979
              onToolbarButtonExecute({
24980
                onAction: spec.onAction,
24981
                getApi: specialisation.getApi
24982
              }),
24983
              onControlAttached(specialisation, editorOffCell),
24984
              onControlDetached(specialisation, editorOffCell)
24985
            ]),
1441 ariadna 24986
            ...spec.tooltip.map(t => Tooltipping.config(providersBackstage.tooltips.getConfig({ tooltipText: providersBackstage.translate(t) + spec.shortcut.map(shortcut => ` (${ convertText(shortcut) })`).getOr('') }))).toArray(),
24987
            DisablingConfigs.toolbarButton(() => !spec.enabled || providersBackstage.checkUiComponentContext(spec.context).shouldDisable),
24988
            toggleOnReceive(() => providersBackstage.checkUiComponentContext(spec.context))
1 efrain 24989
          ].concat(specialisation.toolbarButtonBehaviours)),
24990
          [commonButtonDisplayEvent]: (_d = structure.buttonBehaviours) === null || _d === void 0 ? void 0 : _d[commonButtonDisplayEvent]
24991
        }
24992
      });
24993
    };
1441 ariadna 24994
    const renderToolbarButton = (spec, providersBackstage, btnName) => renderToolbarButtonWith(spec, providersBackstage, [], btnName);
24995
    const renderToolbarButtonWith = (spec, providersBackstage, bonusEvents, btnName) => renderCommonToolbarButton(spec, {
1 efrain 24996
      toolbarButtonBehaviours: bonusEvents.length > 0 ? [config('toolbarButtonWith', bonusEvents)] : [],
24997
      getApi: getButtonApi,
24998
      onSetup: spec.onSetup
1441 ariadna 24999
    }, providersBackstage, btnName);
25000
    const renderToolbarToggleButton = (spec, providersBackstage, btnName) => renderToolbarToggleButtonWith(spec, providersBackstage, [], btnName);
25001
    const renderToolbarToggleButtonWith = (spec, providersBackstage, bonusEvents, btnName) => renderCommonToolbarButton(spec, {
1 efrain 25002
      toolbarButtonBehaviours: [
25003
        Replacing.config({}),
25004
        Toggling.config({
25005
          toggleClass: 'tox-tbtn--enabled',
25006
          aria: { mode: 'pressed' },
25007
          toggleOnExecute: false
25008
        })
25009
      ].concat(bonusEvents.length > 0 ? [config('toolbarToggleButtonWith', bonusEvents)] : []),
25010
      getApi: getToggleApi,
25011
      onSetup: spec.onSetup
1441 ariadna 25012
    }, providersBackstage, btnName);
1 efrain 25013
    const fetchChoices = (getApi, spec, providersBackstage) => comp => Future.nu(callback => spec.fetch(callback)).map(items => Optional.from(createTieredDataFrom(deepMerge(createPartialChoiceMenu(generate$6('menu-value'), items, value => {
25014
      spec.onItemAction(getApi(comp), value);
25015
    }, spec.columns, spec.presets, ItemResponse$1.CLOSE_ON_EXECUTE, spec.select.getOr(never), providersBackstage), {
25016
      movement: deriveMenuMovement(spec.columns, spec.presets),
25017
      menuBehaviours: SimpleBehaviours.unnamedEvents(spec.columns !== 'auto' ? [] : [runOnAttached((comp, _se) => {
25018
          detectSize(comp, 4, classForPreset(spec.presets)).each(({numRows, numColumns}) => {
25019
            Keying.setGridSize(comp, numRows, numColumns);
25020
          });
25021
        })])
25022
    }))));
1441 ariadna 25023
    const renderSplitButton = (spec, sharedBackstage, btnName) => {
25024
      const tooltipString = Cell(spec.tooltip.getOr(''));
1 efrain 25025
      const getApi = comp => ({
25026
        isEnabled: () => !Disabling.isDisabled(comp),
25027
        setEnabled: state => Disabling.set(comp, !state),
25028
        setIconFill: (id, value) => {
25029
          descendant(comp.element, `svg path[class="${ id }"], rect[class="${ id }"]`).each(underlinePath => {
25030
            set$9(underlinePath, 'fill', value);
25031
          });
25032
        },
25033
        setActive: state => {
25034
          set$9(comp.element, 'aria-pressed', state);
25035
          descendant(comp.element, 'span').each(button => {
25036
            comp.getSystem().getByDom(button).each(buttonComp => Toggling.set(buttonComp, state));
25037
          });
25038
        },
25039
        isActive: () => descendant(comp.element, 'span').exists(button => comp.getSystem().getByDom(button).exists(Toggling.isOn)),
25040
        setText: text => descendant(comp.element, 'span').each(button => comp.getSystem().getByDom(button).each(buttonComp => emitWith(buttonComp, updateMenuText, { text }))),
25041
        setIcon: icon => descendant(comp.element, 'span').each(button => comp.getSystem().getByDom(button).each(buttonComp => emitWith(buttonComp, updateMenuIcon, { icon }))),
25042
        setTooltip: tooltip => {
25043
          const translatedTooltip = sharedBackstage.providers.translate(tooltip);
1441 ariadna 25044
          set$9(comp.element, 'aria-label', translatedTooltip);
25045
          tooltipString.set(tooltip);
1 efrain 25046
        }
25047
      });
25048
      const editorOffCell = Cell(noop);
25049
      const specialisation = {
25050
        getApi,
25051
        onSetup: spec.onSetup
25052
      };
25053
      return SplitDropdown.sketch({
25054
        dom: {
25055
          tag: 'div',
25056
          classes: ['tox-split-button'],
25057
          attributes: {
25058
            'aria-pressed': false,
1441 ariadna 25059
            ...getTooltipAttributes(spec.tooltip, sharedBackstage.providers),
25060
            ...isNonNullable(btnName) ? { 'data-mce-name': btnName } : {}
1 efrain 25061
          }
25062
        },
25063
        onExecute: button => {
25064
          const api = getApi(button);
25065
          if (api.isEnabled()) {
25066
            spec.onAction(api);
25067
          }
25068
        },
25069
        onItemExecute: (_a, _b, _c) => {
25070
        },
25071
        splitDropdownBehaviours: derive$1([
25072
          config('split-dropdown-events', [
25073
            runOnAttached((comp, _se) => forceInitialSize(comp)),
25074
            run$1(focusButtonEvent, Focusing.focus),
25075
            onControlAttached(specialisation, editorOffCell),
25076
            onControlDetached(specialisation, editorOffCell)
25077
          ]),
1441 ariadna 25078
          DisablingConfigs.splitButton(() => sharedBackstage.providers.isDisabled() || sharedBackstage.providers.checkUiComponentContext(spec.context).shouldDisable),
25079
          toggleOnReceive(() => sharedBackstage.providers.checkUiComponentContext(spec.context)),
25080
          Unselecting.config({}),
25081
          ...spec.tooltip.map(tooltip => {
25082
            return Tooltipping.config({
25083
              ...sharedBackstage.providers.tooltips.getConfig({
25084
                tooltipText: sharedBackstage.providers.translate(tooltip),
25085
                onShow: comp => {
25086
                  if (tooltipString.get() !== tooltip) {
25087
                    const translatedTooltip = sharedBackstage.providers.translate(tooltipString.get());
25088
                    Tooltipping.setComponents(comp, sharedBackstage.providers.tooltips.getComponents({ tooltipText: translatedTooltip }));
25089
                  }
25090
                }
25091
              })
25092
            });
25093
          }).toArray()
1 efrain 25094
        ]),
25095
        eventOrder: {
25096
          [attachedToDom()]: [
25097
            'alloy.base.behaviour',
1441 ariadna 25098
            'split-dropdown-events',
25099
            'tooltipping'
25100
          ],
25101
          [detachedFromDom()]: [
25102
            'split-dropdown-events',
25103
            'tooltipping'
1 efrain 25104
          ]
25105
        },
25106
        toggleClass: 'tox-tbtn--enabled',
25107
        lazySink: sharedBackstage.getSink,
25108
        fetch: fetchChoices(getApi, spec, sharedBackstage.providers),
25109
        parts: { menu: part(false, spec.columns, spec.presets) },
25110
        components: [
1441 ariadna 25111
          SplitDropdown.parts.button(renderCommonStructure(spec.icon, spec.text, Optional.none(), Optional.some([
25112
            Toggling.config({
1 efrain 25113
              toggleClass: 'tox-tbtn--enabled',
25114
              toggleOnExecute: false
1441 ariadna 25115
            }),
25116
            DisablingConfigs.toolbarButton(never),
25117
            toggleOnReceive(constant$1({
25118
              contextType: 'any',
25119
              shouldDisable: false
25120
            }))
25121
          ]), sharedBackstage.providers, spec.context)),
1 efrain 25122
          SplitDropdown.parts.arrow({
25123
            dom: {
25124
              tag: 'button',
25125
              classes: [
25126
                'tox-tbtn',
25127
                'tox-split-button__chevron'
25128
              ],
1441 ariadna 25129
              innerHtml: get$3('chevron-down', sharedBackstage.providers.icons)
1 efrain 25130
            },
25131
            buttonBehaviours: derive$1([
1441 ariadna 25132
              DisablingConfigs.splitButton(never),
25133
              toggleOnReceive(constant$1({
25134
                contextType: 'any',
25135
                shouldDisable: false
25136
              }))
1 efrain 25137
            ])
25138
          }),
25139
          SplitDropdown.parts['aria-descriptor']({ text: sharedBackstage.providers.translate('To open the popup, press Shift+Enter') })
25140
        ]
25141
      });
25142
    };
25143
 
25144
    const defaultToolbar = [
25145
      {
25146
        name: 'history',
25147
        items: [
25148
          'undo',
25149
          'redo'
25150
        ]
25151
      },
25152
      {
25153
        name: 'ai',
25154
        items: [
25155
          'aidialog',
25156
          'aishortcuts'
25157
        ]
25158
      },
25159
      {
25160
        name: 'styles',
25161
        items: ['styles']
25162
      },
25163
      {
25164
        name: 'formatting',
25165
        items: [
25166
          'bold',
25167
          'italic'
25168
        ]
25169
      },
25170
      {
25171
        name: 'alignment',
25172
        items: [
25173
          'alignleft',
25174
          'aligncenter',
25175
          'alignright',
25176
          'alignjustify'
25177
        ]
25178
      },
25179
      {
25180
        name: 'indentation',
25181
        items: [
25182
          'outdent',
25183
          'indent'
25184
        ]
25185
      },
25186
      {
25187
        name: 'permanent pen',
25188
        items: ['permanentpen']
25189
      },
25190
      {
25191
        name: 'comments',
25192
        items: ['addcomment']
25193
      }
25194
    ];
1441 ariadna 25195
    const renderFromBridge = (bridgeBuilder, render) => (spec, backstage, editor, btnName) => {
1 efrain 25196
      const internal = bridgeBuilder(spec).mapError(errInfo => formatError(errInfo)).getOrDie();
1441 ariadna 25197
      return render(internal, backstage, editor, btnName);
1 efrain 25198
    };
25199
    const types = {
1441 ariadna 25200
      button: renderFromBridge(createToolbarButton, (s, backstage, _, btnName) => renderToolbarButton(s, backstage.shared.providers, btnName)),
25201
      togglebutton: renderFromBridge(createToggleButton, (s, backstage, _, btnName) => renderToolbarToggleButton(s, backstage.shared.providers, btnName)),
25202
      menubutton: renderFromBridge(createMenuButton, (s, backstage, _, btnName) => renderMenuButton(s, 'tox-tbtn', backstage, Optional.none(), false, btnName)),
25203
      splitbutton: renderFromBridge(createSplitButton, (s, backstage, _, btnName) => renderSplitButton(s, backstage.shared, btnName)),
25204
      grouptoolbarbutton: renderFromBridge(createGroupToolbarButton, (s, backstage, editor, btnName) => {
1 efrain 25205
        const buttons = editor.ui.registry.getAll().buttons;
25206
        const identify = toolbar => identifyButtons(editor, {
25207
          buttons,
25208
          toolbar,
25209
          allowToolbarGroups: false
25210
        }, backstage, Optional.none());
25211
        const attributes = { [Attribute]: backstage.shared.header.isPositionedAtTop() ? AttributeValue.TopToBottom : AttributeValue.BottomToTop };
25212
        switch (getToolbarMode(editor)) {
25213
        case ToolbarMode$1.floating:
1441 ariadna 25214
          return renderFloatingToolbarButton(s, backstage, identify, attributes, btnName);
1 efrain 25215
        default:
25216
          throw new Error('Toolbar groups are only supported when using floating toolbar mode');
25217
        }
25218
      })
25219
    };
1441 ariadna 25220
    const extractFrom = (spec, backstage, editor, btnName) => get$h(types, spec.type).fold(() => {
1 efrain 25221
      console.error('skipping button defined by', spec);
25222
      return Optional.none();
1441 ariadna 25223
    }, render => Optional.some(render(spec, backstage, editor, btnName)));
1 efrain 25224
    const bespokeButtons = {
25225
      styles: createStylesButton,
25226
      fontsize: createFontSizeButton,
25227
      fontsizeinput: createFontSizeInputButton,
25228
      fontfamily: createFontFamilyButton,
25229
      blocks: createBlocksButton,
25230
      align: createAlignButton
25231
    };
25232
    const removeUnusedDefaults = buttons => {
25233
      const filteredItemGroups = map$2(defaultToolbar, group => {
25234
        const items = filter$2(group.items, subItem => has$2(buttons, subItem) || has$2(bespokeButtons, subItem));
25235
        return {
25236
          name: group.name,
25237
          items
25238
        };
25239
      });
25240
      return filter$2(filteredItemGroups, group => group.items.length > 0);
25241
    };
25242
    const convertStringToolbar = strToolbar => {
25243
      const groupsStrings = strToolbar.split('|');
25244
      return map$2(groupsStrings, g => ({ items: g.trim().split(' ') }));
25245
    };
1441 ariadna 25246
    const isToolbarGroupSettingArray = toolbar => isArrayOf(toolbar, t => (has$2(t, 'name') || has$2(t, 'label')) && has$2(t, 'items'));
1 efrain 25247
    const createToolbar = toolbarConfig => {
25248
      const toolbar = toolbarConfig.toolbar;
25249
      const buttons = toolbarConfig.buttons;
25250
      if (toolbar === false) {
25251
        return [];
25252
      } else if (toolbar === undefined || toolbar === true) {
25253
        return removeUnusedDefaults(buttons);
25254
      } else if (isString(toolbar)) {
25255
        return convertStringToolbar(toolbar);
25256
      } else if (isToolbarGroupSettingArray(toolbar)) {
25257
        return toolbar;
25258
      } else {
25259
        console.error('Toolbar type should be string, string[], boolean or ToolbarGroup[]');
25260
        return [];
25261
      }
25262
    };
1441 ariadna 25263
    const lookupButton = (editor, buttons, toolbarItem, allowToolbarGroups, backstage, prefixes) => get$h(buttons, toolbarItem.toLowerCase()).orThunk(() => prefixes.bind(ps => findMap(ps, prefix => get$h(buttons, prefix + toolbarItem.toLowerCase())))).fold(() => get$h(bespokeButtons, toolbarItem.toLowerCase()).map(r => r(editor, backstage)), spec => {
1 efrain 25264
      if (spec.type === 'grouptoolbarbutton' && !allowToolbarGroups) {
25265
        console.warn(`Ignoring the '${ toolbarItem }' toolbar button. Group toolbar buttons are only supported when using floating toolbar mode and cannot be nested.`);
25266
        return Optional.none();
25267
      } else {
1441 ariadna 25268
        return extractFrom(spec, backstage, editor, toolbarItem.toLowerCase());
1 efrain 25269
      }
25270
    });
25271
    const identifyButtons = (editor, toolbarConfig, backstage, prefixes) => {
25272
      const toolbarGroups = createToolbar(toolbarConfig);
25273
      const groups = map$2(toolbarGroups, group => {
25274
        const items = bind$3(group.items, toolbarItem => {
25275
          return toolbarItem.trim().length === 0 ? [] : lookupButton(editor, toolbarConfig.buttons, toolbarItem, toolbarConfig.allowToolbarGroups, backstage, prefixes).toArray();
25276
        });
25277
        return {
25278
          title: Optional.from(editor.translate(group.name)),
1441 ariadna 25279
          label: someIf(group.label !== undefined, editor.translate(group.label)),
1 efrain 25280
          items
25281
        };
25282
      });
25283
      return filter$2(groups, group => group.items.length > 0);
25284
    };
25285
 
25286
    const setToolbar = (editor, uiRefs, rawUiConfig, backstage) => {
25287
      const outerContainer = uiRefs.mainUi.outerContainer;
25288
      const toolbarConfig = rawUiConfig.toolbar;
25289
      const toolbarButtonsConfig = rawUiConfig.buttons;
25290
      if (isArrayOf(toolbarConfig, isString)) {
25291
        const toolbars = toolbarConfig.map(t => {
25292
          const config = {
25293
            toolbar: t,
25294
            buttons: toolbarButtonsConfig,
25295
            allowToolbarGroups: rawUiConfig.allowToolbarGroups
25296
          };
25297
          return identifyButtons(editor, config, backstage, Optional.none());
25298
        });
25299
        OuterContainer.setToolbars(outerContainer, toolbars);
25300
      } else {
25301
        OuterContainer.setToolbar(outerContainer, identifyButtons(editor, rawUiConfig, backstage, Optional.none()));
25302
      }
25303
    };
25304
 
1441 ariadna 25305
    const detection = detect$1();
1 efrain 25306
    const isiOS12 = detection.os.isiOS() && detection.os.version.major <= 12;
25307
    const setupEvents$1 = (editor, uiRefs) => {
25308
      const {uiMotherships} = uiRefs;
25309
      const dom = editor.dom;
25310
      let contentWindow = editor.getWin();
25311
      const initialDocEle = editor.getDoc().documentElement;
25312
      const lastWindowDimensions = Cell(SugarPosition(contentWindow.innerWidth, contentWindow.innerHeight));
25313
      const lastDocumentDimensions = Cell(SugarPosition(initialDocEle.offsetWidth, initialDocEle.offsetHeight));
25314
      const resizeWindow = () => {
25315
        const outer = lastWindowDimensions.get();
25316
        if (outer.left !== contentWindow.innerWidth || outer.top !== contentWindow.innerHeight) {
25317
          lastWindowDimensions.set(SugarPosition(contentWindow.innerWidth, contentWindow.innerHeight));
25318
          fireResizeContent(editor);
25319
        }
25320
      };
25321
      const resizeDocument = () => {
25322
        const docEle = editor.getDoc().documentElement;
25323
        const inner = lastDocumentDimensions.get();
25324
        if (inner.left !== docEle.offsetWidth || inner.top !== docEle.offsetHeight) {
25325
          lastDocumentDimensions.set(SugarPosition(docEle.offsetWidth, docEle.offsetHeight));
25326
          fireResizeContent(editor);
25327
        }
25328
      };
25329
      const scroll = e => {
25330
        fireScrollContent(editor, e);
25331
      };
25332
      dom.bind(contentWindow, 'resize', resizeWindow);
25333
      dom.bind(contentWindow, 'scroll', scroll);
25334
      const elementLoad = capture(SugarElement.fromDom(editor.getBody()), 'load', resizeDocument);
25335
      editor.on('hide', () => {
25336
        each$1(uiMotherships, m => {
25337
          set$8(m.element, 'display', 'none');
25338
        });
25339
      });
25340
      editor.on('show', () => {
25341
        each$1(uiMotherships, m => {
1441 ariadna 25342
          remove$7(m.element, 'display');
1 efrain 25343
        });
25344
      });
25345
      editor.on('NodeChange', resizeDocument);
25346
      editor.on('remove', () => {
25347
        elementLoad.unbind();
25348
        dom.unbind(contentWindow, 'resize', resizeWindow);
25349
        dom.unbind(contentWindow, 'scroll', scroll);
25350
        contentWindow = null;
25351
      });
25352
    };
25353
    const attachUiMotherships = (editor, uiRoot, uiRefs) => {
25354
      if (isSplitUiMode(editor)) {
25355
        attachSystemAfter(uiRefs.mainUi.mothership.element, uiRefs.popupUi.mothership);
25356
      }
25357
      attachSystem(uiRoot, uiRefs.dialogUi.mothership);
25358
    };
25359
    const render$1 = (editor, uiRefs, rawUiConfig, backstage, args) => {
25360
      const {mainUi, uiMotherships} = uiRefs;
25361
      const lastToolbarWidth = Cell(0);
25362
      const outerContainer = mainUi.outerContainer;
25363
      iframe(editor);
25364
      const eTargetNode = SugarElement.fromDom(args.targetNode);
25365
      const uiRoot = getContentContainer(getRootNode(eTargetNode));
25366
      attachSystemAfter(eTargetNode, mainUi.mothership);
25367
      attachUiMotherships(editor, uiRoot, uiRefs);
1441 ariadna 25368
      editor.on('PostRender', () => {
25369
        OuterContainer.setSidebar(outerContainer, rawUiConfig.sidebar, getSidebarShow(editor));
25370
      });
1 efrain 25371
      editor.on('SkinLoaded', () => {
25372
        setToolbar(editor, uiRefs, rawUiConfig, backstage);
25373
        lastToolbarWidth.set(editor.getWin().innerWidth);
25374
        OuterContainer.setMenubar(outerContainer, identifyMenus(editor, rawUiConfig));
25375
        OuterContainer.setViews(outerContainer, rawUiConfig.views);
25376
        setupEvents$1(editor, uiRefs);
25377
      });
25378
      const socket = OuterContainer.getSocket(outerContainer).getOrDie('Could not find expected socket element');
25379
      if (isiOS12) {
25380
        setAll(socket.element, {
25381
          'overflow': 'scroll',
25382
          '-webkit-overflow-scrolling': 'touch'
25383
        });
25384
        const limit = first(() => {
25385
          editor.dispatch('ScrollContent');
25386
        }, 20);
25387
        const unbinder = bind(socket.element, 'scroll', limit.throttle);
25388
        editor.on('remove', unbinder.unbind);
25389
      }
1441 ariadna 25390
      setupEventsForUi(editor, uiRefs);
1 efrain 25391
      editor.addCommand('ToggleSidebar', (_ui, value) => {
25392
        OuterContainer.toggleSidebar(outerContainer, value);
1441 ariadna 25393
        fireToggleSidebar(editor);
1 efrain 25394
      });
25395
      editor.addQueryValueHandler('ToggleSidebar', () => {
25396
        var _a;
25397
        return (_a = OuterContainer.whichSidebar(outerContainer)) !== null && _a !== void 0 ? _a : '';
25398
      });
25399
      editor.addCommand('ToggleView', (_ui, value) => {
25400
        if (OuterContainer.toggleView(outerContainer, value)) {
25401
          const target = outerContainer.element;
25402
          mainUi.mothership.broadcastOn([dismissPopups()], { target });
25403
          each$1(uiMotherships, m => {
25404
            m.broadcastOn([dismissPopups()], { target });
25405
          });
25406
          if (isNull(OuterContainer.whichView(outerContainer))) {
25407
            editor.focus();
25408
            editor.nodeChanged();
25409
            OuterContainer.refreshToolbar(outerContainer);
25410
          }
1441 ariadna 25411
          fireToggleView(editor);
1 efrain 25412
        }
25413
      });
25414
      editor.addQueryValueHandler('ToggleView', () => {
25415
        var _a;
25416
        return (_a = OuterContainer.whichView(outerContainer)) !== null && _a !== void 0 ? _a : '';
25417
      });
25418
      const toolbarMode = getToolbarMode(editor);
25419
      const refreshDrawer = () => {
25420
        OuterContainer.refreshToolbar(uiRefs.mainUi.outerContainer);
25421
      };
25422
      if (toolbarMode === ToolbarMode$1.sliding || toolbarMode === ToolbarMode$1.floating) {
25423
        editor.on('ResizeWindow ResizeEditor ResizeContent', () => {
25424
          const width = editor.getWin().innerWidth;
25425
          if (width !== lastToolbarWidth.get()) {
25426
            refreshDrawer();
25427
            lastToolbarWidth.set(width);
25428
          }
25429
        });
25430
      }
25431
      const api = {
25432
        setEnabled: state => {
1441 ariadna 25433
          const eventType = state ? 'setEnabled' : 'setDisabled';
25434
          broadcastEvents(uiRefs, eventType);
1 efrain 25435
        },
25436
        isEnabled: () => !Disabling.isDisabled(outerContainer)
25437
      };
25438
      return {
25439
        iframeContainer: socket.element.dom,
25440
        editorContainer: outerContainer.element.dom,
25441
        api
25442
      };
25443
    };
25444
 
25445
    var Iframe = /*#__PURE__*/Object.freeze({
25446
        __proto__: null,
25447
        render: render$1
25448
    });
25449
 
25450
    const parseToInt = val => {
25451
      const re = /^[0-9\.]+(|px)$/i;
25452
      if (re.test('' + val)) {
25453
        return Optional.some(parseInt('' + val, 10));
25454
      }
25455
      return Optional.none();
25456
    };
25457
    const numToPx = val => isNumber(val) ? val + 'px' : val;
25458
    const calcCappedSize = (size, minSize, maxSize) => {
25459
      const minOverride = minSize.filter(min => size < min);
25460
      const maxOverride = maxSize.filter(max => size > max);
25461
      return minOverride.or(maxOverride).getOr(size);
25462
    };
25463
 
25464
    const getHeight = editor => {
25465
      const baseHeight = getHeightOption(editor);
25466
      const minHeight = getMinHeightOption(editor);
25467
      const maxHeight = getMaxHeightOption(editor);
25468
      return parseToInt(baseHeight).map(height => calcCappedSize(height, minHeight, maxHeight));
25469
    };
25470
    const getHeightWithFallback = editor => {
25471
      const height = getHeight(editor);
25472
      return height.getOr(getHeightOption(editor));
25473
    };
25474
    const getWidth = editor => {
25475
      const baseWidth = getWidthOption(editor);
25476
      const minWidth = getMinWidthOption(editor);
25477
      const maxWidth = getMaxWidthOption(editor);
25478
      return parseToInt(baseWidth).map(width => calcCappedSize(width, minWidth, maxWidth));
25479
    };
25480
    const getWidthWithFallback = editor => {
25481
      const width = getWidth(editor);
25482
      return width.getOr(getWidthOption(editor));
25483
    };
25484
 
25485
    const {ToolbarLocation, ToolbarMode} = Options;
25486
    const maximumDistanceToEdge = 40;
25487
    const InlineHeader = (editor, targetElm, uiRefs, backstage, floatContainer) => {
25488
      const {mainUi, uiMotherships} = uiRefs;
1441 ariadna 25489
      const DOM = global$8.DOM;
1 efrain 25490
      const useFixedToolbarContainer = useFixedContainer(editor);
25491
      const isSticky = isStickyToolbar(editor);
25492
      const editorMaxWidthOpt = getMaxWidthOption(editor).or(getWidth(editor));
25493
      const headerBackstage = backstage.shared.header;
25494
      const isPositionedAtTop = headerBackstage.isPositionedAtTop;
1441 ariadna 25495
      const minimumToolbarWidth = 150;
1 efrain 25496
      const toolbarMode = getToolbarMode(editor);
25497
      const isSplitToolbar = toolbarMode === ToolbarMode.sliding || toolbarMode === ToolbarMode.floating;
25498
      const visible = Cell(false);
25499
      const isVisible = () => visible.get() && !editor.removed;
1441 ariadna 25500
      const calcToolbarOffset = toolbar => isSplitToolbar ? toolbar.fold(constant$1(0), tbar => tbar.components().length > 1 ? get$e(tbar.components()[1].element) : 0) : 0;
1 efrain 25501
      const calcMode = container => {
25502
        switch (getToolbarLocation(editor)) {
25503
        case ToolbarLocation.auto:
25504
          const toolbar = OuterContainer.getToolbar(mainUi.outerContainer);
25505
          const offset = calcToolbarOffset(toolbar);
1441 ariadna 25506
          const toolbarHeight = get$e(container.element) - offset;
1 efrain 25507
          const targetBounds = box$1(targetElm);
25508
          const roomAtTop = targetBounds.y > toolbarHeight;
25509
          if (roomAtTop) {
25510
            return 'top';
25511
          } else {
25512
            const doc = documentElement(targetElm);
1441 ariadna 25513
            const docHeight = Math.max(doc.dom.scrollHeight, get$e(doc));
1 efrain 25514
            const roomAtBottom = targetBounds.bottom < docHeight - toolbarHeight;
25515
            if (roomAtBottom) {
25516
              return 'bottom';
25517
            } else {
25518
              const winBounds = win();
25519
              const isRoomAtBottomViewport = winBounds.bottom < targetBounds.bottom - toolbarHeight;
25520
              return isRoomAtBottomViewport ? 'bottom' : 'top';
25521
            }
25522
          }
25523
        case ToolbarLocation.bottom:
25524
          return 'bottom';
25525
        case ToolbarLocation.top:
25526
        default:
25527
          return 'top';
25528
        }
25529
      };
25530
      const setupMode = mode => {
25531
        floatContainer.on(container => {
25532
          Docking.setModes(container, [mode]);
25533
          headerBackstage.setDockingMode(mode);
25534
          const verticalDir = isPositionedAtTop() ? AttributeValue.TopToBottom : AttributeValue.BottomToTop;
25535
          set$9(container.element, Attribute, verticalDir);
25536
        });
25537
      };
25538
      const updateChromeWidth = () => {
25539
        floatContainer.on(container => {
25540
          const maxWidth = editorMaxWidthOpt.getOrThunk(() => {
1441 ariadna 25541
            return getBounds$3().width - viewport$1(targetElm).left - 10;
1 efrain 25542
          });
25543
          set$8(container.element, 'max-width', maxWidth + 'px');
25544
        });
25545
      };
1441 ariadna 25546
      const updateChromePosition = (isOuterContainerWidthRestored, prevScroll) => {
1 efrain 25547
        floatContainer.on(container => {
25548
          const toolbar = OuterContainer.getToolbar(mainUi.outerContainer);
25549
          const offset = calcToolbarOffset(toolbar);
25550
          const targetBounds = box$1(targetElm);
1441 ariadna 25551
          const offsetParent = getOffsetParent$1(editor, mainUi.outerContainer.element);
25552
          const getLeft = () => offsetParent.fold(() => targetBounds.x, offsetParent => {
25553
            const offsetBox = box$1(offsetParent);
25554
            const isOffsetParentBody = eq(offsetParent, body());
25555
            return isOffsetParentBody ? targetBounds.x : targetBounds.x - offsetBox.x;
25556
          });
25557
          const getTop = () => offsetParent.fold(() => isPositionedAtTop() ? Math.max(targetBounds.y - get$e(container.element) + offset, 0) : targetBounds.bottom, offsetParent => {
1 efrain 25558
            var _a;
25559
            const offsetBox = box$1(offsetParent);
25560
            const scrollDelta = (_a = offsetParent.dom.scrollTop) !== null && _a !== void 0 ? _a : 0;
25561
            const isOffsetParentBody = eq(offsetParent, body());
1441 ariadna 25562
            const topValue = isOffsetParentBody ? Math.max(targetBounds.y - get$e(container.element) + offset, 0) : targetBounds.y - offsetBox.y + scrollDelta - get$e(container.element) + offset;
25563
            return isPositionedAtTop() ? topValue : targetBounds.bottom;
1 efrain 25564
          });
1441 ariadna 25565
          const left = getLeft();
25566
          const widthProperties = someIf(isOuterContainerWidthRestored, Math.ceil(mainUi.outerContainer.element.dom.getBoundingClientRect().width)).filter(w => w > minimumToolbarWidth).map(toolbarWidth => {
25567
            const scroll = prevScroll.getOr(get$c());
25568
            const availableWidth = window.innerWidth - (left - scroll.left);
25569
            const width = Math.max(Math.min(toolbarWidth, availableWidth), minimumToolbarWidth);
25570
            if (availableWidth < toolbarWidth) {
25571
              set$8(mainUi.outerContainer.element, 'width', width + 'px');
25572
            }
25573
            return { width: width + 'px' };
25574
          }).getOr({ width: 'max-content' });
1 efrain 25575
          const baseProperties = {
25576
            position: 'absolute',
25577
            left: Math.round(left) + 'px',
1441 ariadna 25578
            top: getTop() + 'px'
1 efrain 25579
          };
25580
          setAll(mainUi.outerContainer.element, {
25581
            ...baseProperties,
25582
            ...widthProperties
25583
          });
25584
        });
25585
      };
25586
      const getOffsetParent$1 = (editor, element) => isSplitUiMode(editor) ? getOffsetParent(element) : Optional.none();
25587
      const repositionPopups$1 = () => {
25588
        each$1(uiMotherships, m => {
25589
          m.broadcastOn([repositionPopups()], {});
25590
        });
25591
      };
1441 ariadna 25592
      const restoreOuterContainerWidth = () => {
1 efrain 25593
        if (!useFixedToolbarContainer) {
25594
          const toolbarCurrentRightsidePosition = absolute$3(mainUi.outerContainer.element).left + getOuter$1(mainUi.outerContainer.element);
25595
          if (toolbarCurrentRightsidePosition >= window.innerWidth - maximumDistanceToEdge || getRaw(mainUi.outerContainer.element, 'width').isSome()) {
25596
            set$8(mainUi.outerContainer.element, 'position', 'absolute');
25597
            set$8(mainUi.outerContainer.element, 'left', '0px');
1441 ariadna 25598
            remove$7(mainUi.outerContainer.element, 'width');
25599
            return true;
1 efrain 25600
          }
25601
        }
1441 ariadna 25602
        return false;
1 efrain 25603
      };
25604
      const update = stickyAction => {
25605
        if (!isVisible()) {
25606
          return;
25607
        }
25608
        if (!useFixedToolbarContainer) {
25609
          updateChromeWidth();
25610
        }
1441 ariadna 25611
        const prevScroll = get$c();
25612
        const isOuterContainerWidthRestored = useFixedToolbarContainer ? false : restoreOuterContainerWidth();
1 efrain 25613
        if (isSplitToolbar) {
25614
          OuterContainer.refreshToolbar(mainUi.outerContainer);
25615
        }
25616
        if (!useFixedToolbarContainer) {
1441 ariadna 25617
          const currentScroll = get$c();
25618
          const optScroll = someIf(prevScroll.left !== currentScroll.left, prevScroll);
25619
          updateChromePosition(isOuterContainerWidthRestored, optScroll);
25620
          optScroll.each(scroll => {
25621
            to(scroll.left, currentScroll.top);
25622
          });
1 efrain 25623
        }
25624
        if (isSticky) {
25625
          floatContainer.on(stickyAction);
25626
        }
25627
        repositionPopups$1();
25628
      };
25629
      const doUpdateMode = () => {
25630
        if (useFixedToolbarContainer || !isSticky || !isVisible()) {
25631
          return false;
25632
        }
25633
        return floatContainer.get().exists(fc => {
25634
          const currentMode = headerBackstage.getDockingMode();
25635
          const newMode = calcMode(fc);
25636
          if (newMode !== currentMode) {
25637
            setupMode(newMode);
25638
            return true;
25639
          } else {
25640
            return false;
25641
          }
25642
        });
25643
      };
25644
      const show = () => {
25645
        visible.set(true);
25646
        set$8(mainUi.outerContainer.element, 'display', 'flex');
25647
        DOM.addClass(editor.getBody(), 'mce-edit-focus');
25648
        each$1(uiMotherships, m => {
1441 ariadna 25649
          remove$7(m.element, 'display');
1 efrain 25650
        });
25651
        doUpdateMode();
25652
        if (isSplitUiMode(editor)) {
25653
          update(elem => Docking.isDocked(elem) ? Docking.reset(elem) : Docking.refresh(elem));
25654
        } else {
25655
          update(Docking.refresh);
25656
        }
25657
      };
25658
      const hide = () => {
25659
        visible.set(false);
25660
        set$8(mainUi.outerContainer.element, 'display', 'none');
25661
        DOM.removeClass(editor.getBody(), 'mce-edit-focus');
25662
        each$1(uiMotherships, m => {
25663
          set$8(m.element, 'display', 'none');
25664
        });
25665
      };
25666
      const updateMode = () => {
25667
        const changedMode = doUpdateMode();
25668
        if (changedMode) {
25669
          update(Docking.reset);
25670
        }
25671
      };
25672
      return {
25673
        isVisible,
25674
        isPositionedAtTop,
25675
        show,
25676
        hide,
25677
        update,
25678
        updateMode,
25679
        repositionPopups: repositionPopups$1
25680
      };
25681
    };
25682
 
25683
    const getTargetPosAndBounds = (targetElm, isToolbarTop) => {
25684
      const bounds = box$1(targetElm);
25685
      return {
25686
        pos: isToolbarTop ? bounds.y : bounds.bottom,
25687
        bounds
25688
      };
25689
    };
25690
    const setupEvents = (editor, targetElm, ui, toolbarPersist) => {
25691
      const prevPosAndBounds = Cell(getTargetPosAndBounds(targetElm, ui.isPositionedAtTop()));
25692
      const resizeContent = e => {
25693
        const {pos, bounds} = getTargetPosAndBounds(targetElm, ui.isPositionedAtTop());
25694
        const {
25695
          pos: prevPos,
25696
          bounds: prevBounds
25697
        } = prevPosAndBounds.get();
25698
        const hasResized = bounds.height !== prevBounds.height || bounds.width !== prevBounds.width;
25699
        prevPosAndBounds.set({
25700
          pos,
25701
          bounds
25702
        });
25703
        if (hasResized) {
25704
          fireResizeContent(editor, e);
25705
        }
25706
        if (ui.isVisible()) {
25707
          if (prevPos !== pos) {
25708
            ui.update(Docking.reset);
25709
          } else if (hasResized) {
25710
            ui.updateMode();
25711
            ui.repositionPopups();
25712
          }
25713
        }
25714
      };
25715
      if (!toolbarPersist) {
25716
        editor.on('activate', ui.show);
25717
        editor.on('deactivate', ui.hide);
25718
      }
25719
      editor.on('SkinLoaded ResizeWindow', () => ui.update(Docking.reset));
25720
      editor.on('NodeChange keydown', e => {
25721
        requestAnimationFrame(() => resizeContent(e));
25722
      });
25723
      let lastScrollX = 0;
25724
      const updateUi = last(() => ui.update(Docking.refresh), 33);
25725
      editor.on('ScrollWindow', () => {
1441 ariadna 25726
        const newScrollX = get$c().left;
1 efrain 25727
        if (newScrollX !== lastScrollX) {
25728
          lastScrollX = newScrollX;
25729
          updateUi.throttle();
25730
        }
25731
        ui.updateMode();
25732
      });
25733
      if (isSplitUiMode(editor)) {
25734
        editor.on('ElementScroll', _args => {
25735
          ui.update(Docking.refresh);
25736
        });
25737
      }
25738
      const elementLoad = unbindable();
25739
      elementLoad.set(capture(SugarElement.fromDom(editor.getBody()), 'load', e => resizeContent(e.raw)));
25740
      editor.on('remove', () => {
25741
        elementLoad.clear();
25742
      });
25743
    };
25744
    const render = (editor, uiRefs, rawUiConfig, backstage, args) => {
25745
      const {mainUi} = uiRefs;
1441 ariadna 25746
      const floatContainer = value$4();
1 efrain 25747
      const targetElm = SugarElement.fromDom(args.targetNode);
25748
      const ui = InlineHeader(editor, targetElm, uiRefs, backstage, floatContainer);
25749
      const toolbarPersist = isToolbarPersist(editor);
25750
      inline(editor);
25751
      const render = () => {
25752
        if (floatContainer.isSet()) {
25753
          ui.show();
25754
          return;
25755
        }
25756
        floatContainer.set(OuterContainer.getHeader(mainUi.outerContainer).getOrDie());
25757
        const uiContainer = getUiContainer(editor);
25758
        if (isSplitUiMode(editor)) {
25759
          attachSystemAfter(targetElm, mainUi.mothership);
25760
          attachSystemAfter(targetElm, uiRefs.popupUi.mothership);
25761
        } else {
25762
          attachSystem(uiContainer, mainUi.mothership);
25763
        }
25764
        attachSystem(uiContainer, uiRefs.dialogUi.mothership);
1441 ariadna 25765
        const setup = () => {
25766
          setToolbar(editor, uiRefs, rawUiConfig, backstage);
25767
          OuterContainer.setMenubar(mainUi.outerContainer, identifyMenus(editor, rawUiConfig));
25768
          ui.show();
25769
          setupEvents(editor, targetElm, ui, toolbarPersist);
25770
          editor.nodeChanged();
25771
        };
25772
        if (toolbarPersist) {
25773
          editor.once('SkinLoaded', setup);
25774
        } else {
25775
          setup();
25776
        }
1 efrain 25777
      };
25778
      editor.on('show', render);
25779
      editor.on('hide', ui.hide);
25780
      if (!toolbarPersist) {
25781
        editor.on('focus', render);
25782
        editor.on('blur', ui.hide);
25783
      }
25784
      editor.on('init', () => {
25785
        if (editor.hasFocus() || toolbarPersist) {
25786
          render();
25787
        }
25788
      });
1441 ariadna 25789
      setupEventsForUi(editor, uiRefs);
1 efrain 25790
      const api = {
25791
        show: render,
25792
        hide: ui.hide,
25793
        setEnabled: state => {
1441 ariadna 25794
          const eventType = state ? 'setEnabled' : 'setDisabled';
25795
          broadcastEvents(uiRefs, eventType);
1 efrain 25796
        },
25797
        isEnabled: () => !Disabling.isDisabled(mainUi.outerContainer)
25798
      };
25799
      return {
25800
        editorContainer: mainUi.outerContainer.element.dom,
25801
        api
25802
      };
25803
    };
25804
 
25805
    var Inline = /*#__PURE__*/Object.freeze({
25806
        __proto__: null,
25807
        render: render
25808
    });
25809
 
25810
    const LazyUiReferences = () => {
1441 ariadna 25811
      const dialogUi = value$4();
25812
      const popupUi = value$4();
25813
      const mainUi = value$4();
1 efrain 25814
      const lazyGetInOuterOrDie = (label, f) => () => mainUi.get().bind(oc => f(oc.outerContainer)).getOrDie(`Could not find ${ label } element in OuterContainer`);
25815
      const getUiMotherships = () => {
25816
        const optDialogMothership = dialogUi.get().map(ui => ui.mothership);
25817
        const optPopupMothership = popupUi.get().map(ui => ui.mothership);
25818
        return optDialogMothership.fold(() => optPopupMothership.toArray(), dm => optPopupMothership.fold(() => [dm], pm => eq(dm.element, pm.element) ? [dm] : [
25819
          dm,
25820
          pm
25821
        ]));
25822
      };
25823
      return {
25824
        dialogUi,
25825
        popupUi,
25826
        mainUi,
25827
        getUiMotherships,
25828
        lazyGetInOuterOrDie
25829
      };
25830
    };
25831
 
25832
    const showContextToolbarEvent = 'contexttoolbar-show';
25833
    const hideContextToolbarEvent = 'contexttoolbar-hide';
25834
 
1441 ariadna 25835
    const contextFormInputSelector = '.tox-toolbar-slider__input,.tox-toolbar-textfield';
25836
    const focusIn = contextbar => {
25837
      InlineView.getContent(contextbar).each(comp => {
25838
        descendant(comp.element, contextFormInputSelector).fold(() => Keying.focusIn(comp), focus$3);
25839
      });
25840
    };
25841
    const focusParent = comp => search(comp.element).each(focus => {
25842
      ancestor(focus, '[tabindex="-1"]').each(parent => {
25843
        focus$3(parent);
25844
      });
1 efrain 25845
    });
1441 ariadna 25846
 
25847
    const forwardSlideEvent = generate$6('forward-slide');
25848
    const backSlideEvent = generate$6('backward-slide');
25849
    const changeSlideEvent = generate$6('change-slide-event');
25850
    const resizingClass = 'tox-pop--resizing';
25851
    const renderContextToolbar = spec => {
25852
      const stack = Cell([]);
25853
      return InlineView.sketch({
25854
        dom: {
25855
          tag: 'div',
25856
          classes: ['tox-pop']
25857
        },
25858
        fireDismissalEventInstead: { event: 'doNotDismissYet' },
25859
        onShow: comp => {
25860
          stack.set([]);
25861
          InlineView.getContent(comp).each(c => {
25862
            remove$7(c.element, 'visibility');
25863
          });
25864
          remove$3(comp.element, resizingClass);
25865
          remove$7(comp.element, 'width');
25866
        },
25867
        onHide: () => {
25868
          spec.onHide();
25869
        },
25870
        inlineBehaviours: derive$1([
25871
          config('context-toolbar-events', [
25872
            runOnSource(transitionend(), (comp, se) => {
25873
              if (se.event.raw.propertyName === 'width') {
25874
                remove$3(comp.element, resizingClass);
25875
                remove$7(comp.element, 'width');
25876
              }
25877
            }),
25878
            run$1(changeSlideEvent, (comp, se) => {
25879
              const elem = comp.element;
25880
              remove$7(elem, 'width');
25881
              const currentWidth = get$d(elem);
25882
              remove$7(elem, 'left');
25883
              remove$7(elem, 'right');
25884
              remove$7(elem, 'max-width');
25885
              InlineView.setContent(comp, se.event.contents);
25886
              add$2(elem, resizingClass);
25887
              const newWidth = get$d(elem);
25888
              set$8(elem, 'transition', 'none');
25889
              InlineView.reposition(comp);
25890
              remove$7(elem, 'transition');
25891
              set$8(elem, 'width', currentWidth + 'px');
25892
              se.event.focus.fold(() => focusIn(comp), f => {
25893
                focus$3(f);
25894
                if (search(elem).isNone()) {
25895
                  focusIn(comp);
25896
                }
25897
              });
25898
              setTimeout(() => {
25899
                set$8(comp.element, 'width', newWidth + 'px');
25900
              }, 0);
25901
            }),
25902
            run$1(forwardSlideEvent, (comp, se) => {
25903
              InlineView.getContent(comp).each(oldContents => {
25904
                stack.set(stack.get().concat([{
25905
                    bar: oldContents,
25906
                    focus: active$1(getRootNode(comp.element))
25907
                  }]));
25908
              });
25909
              emitWith(comp, changeSlideEvent, {
25910
                contents: se.event.forwardContents,
25911
                focus: Optional.none()
25912
              });
25913
            }),
25914
            run$1(backSlideEvent, (comp, _se) => {
25915
              spec.onBack();
25916
              last$1(stack.get()).each(last => {
25917
                stack.set(stack.get().slice(0, stack.get().length - 1));
25918
                emitWith(comp, changeSlideEvent, {
25919
                  contents: premade(last.bar),
25920
                  focus: last.focus
25921
                });
25922
              });
25923
            })
25924
          ]),
25925
          Keying.config({
25926
            mode: 'special',
25927
            onEscape: comp => last$1(stack.get()).fold(() => spec.onEscape(), _ => {
25928
              emit(comp, backSlideEvent);
25929
              return Optional.some(true);
25930
            })
25931
          })
25932
        ]),
25933
        lazySink: () => Result.value(spec.sink)
25934
      });
25935
    };
25936
 
25937
    const getFormApi = (input, focusfallbackElement) => {
25938
      const valueState = value$4();
25939
      return {
25940
        setInputEnabled: state => {
25941
          if (!state && focusfallbackElement) {
25942
            focus$3(focusfallbackElement);
25943
          }
25944
          Disabling.set(input, !state);
25945
        },
25946
        isInputEnabled: () => !Disabling.isDisabled(input),
25947
        hide: () => {
25948
          if (!valueState.isSet()) {
25949
            valueState.set(Representing.getValue(input));
25950
          }
25951
          emit(input, sandboxClose());
25952
        },
25953
        back: () => {
25954
          if (!valueState.isSet()) {
25955
            valueState.set(Representing.getValue(input));
25956
          }
25957
          emit(input, backSlideEvent);
25958
        },
25959
        getValue: () => {
25960
          return valueState.get().getOrThunk(() => Representing.getValue(input));
25961
        },
25962
        setValue: value => {
25963
          if (valueState.isSet()) {
25964
            valueState.set(value);
25965
          } else {
25966
            Representing.setValue(input, value);
25967
          }
25968
        }
25969
      };
25970
    };
25971
 
1 efrain 25972
    const runOnExecute = (memInput, original) => run$1(internalToolbarButtonExecute, (comp, se) => {
25973
      const input = memInput.get(comp);
1441 ariadna 25974
      const formApi = getFormApi(input, comp.element);
1 efrain 25975
      original.onAction(formApi, se.event.buttonApi);
25976
    });
25977
    const renderContextButton = (memInput, button, providers) => {
25978
      const {primary, ...rest} = button.original;
25979
      const bridged = getOrDie(createToolbarButton({
25980
        ...rest,
25981
        type: 'button',
25982
        onAction: noop
25983
      }));
25984
      return renderToolbarButtonWith(bridged, providers, [runOnExecute(memInput, button)]);
25985
    };
25986
    const renderContextToggleButton = (memInput, button, providers) => {
25987
      const {primary, ...rest} = button.original;
25988
      const bridged = getOrDie(createToggleButton({
25989
        ...rest,
25990
        type: 'togglebutton',
25991
        onAction: noop
25992
      }));
25993
      return renderToolbarToggleButtonWith(bridged, providers, [runOnExecute(memInput, button)]);
25994
    };
25995
    const isToggleButton = button => button.type === 'contextformtogglebutton';
25996
    const generateOne = (memInput, button, providersBackstage) => {
25997
      if (isToggleButton(button)) {
25998
        return renderContextToggleButton(memInput, button, providersBackstage);
25999
      } else {
26000
        return renderContextButton(memInput, button, providersBackstage);
26001
      }
26002
    };
26003
    const generate = (memInput, buttons, providersBackstage) => {
26004
      const mementos = map$2(buttons, button => record(generateOne(memInput, button, providersBackstage)));
26005
      const asSpecs = () => map$2(mementos, mem => mem.asSpec());
26006
      const findPrimary = compInSystem => findMap(buttons, (button, i) => {
26007
        if (button.primary) {
26008
          return Optional.from(mementos[i]).bind(mem => mem.getOpt(compInSystem)).filter(not(Disabling.isDisabled));
26009
        } else {
26010
          return Optional.none();
26011
        }
26012
      });
26013
      return {
26014
        asSpecs,
26015
        findPrimary
26016
      };
26017
    };
26018
 
1441 ariadna 26019
    const renderContextFormSizeInput = (ctx, providersBackstage, onEnter) => {
26020
      const {width, height} = ctx.initValue();
26021
      let converter = noSizeConversion;
26022
      const enabled = true;
26023
      const ratioEvent = generate$6('ratio-event');
26024
      const getApi = getFormApi;
26025
      const makeIcon = iconName => render$3(iconName, {
26026
        tag: 'span',
26027
        classes: [
26028
          'tox-icon',
26029
          'tox-lock-icon__' + iconName
26030
        ]
26031
      }, providersBackstage.icons);
26032
      const disabled = () => !enabled;
26033
      const label = ctx.label.getOr('Constrain proportions');
26034
      const translatedLabel = providersBackstage.translate(label);
26035
      const pLock = FormCoupledInputs.parts.lock({
26036
        dom: {
26037
          tag: 'button',
26038
          classes: [
26039
            'tox-lock',
26040
            'tox-button',
26041
            'tox-button--naked',
26042
            'tox-button--icon'
26043
          ],
26044
          attributes: {
26045
            'aria-label': translatedLabel,
26046
            'data-mce-name': label
26047
          }
26048
        },
26049
        components: [
26050
          makeIcon('lock'),
26051
          makeIcon('unlock')
26052
        ],
26053
        buttonBehaviours: derive$1([
26054
          Disabling.config({ disabled }),
26055
          Tabstopping.config({}),
26056
          Tooltipping.config(providersBackstage.tooltips.getConfig({ tooltipText: translatedLabel }))
26057
        ])
26058
      });
26059
      const formGroup = components => ({
26060
        dom: {
26061
          tag: 'div',
26062
          classes: ['tox-context-form__group']
26063
        },
26064
        components
26065
      });
26066
      const goToParent = comp => {
26067
        const focussableWrapperOpt = ancestor(comp.element, 'div.tox-focusable-wrapper');
26068
        return focussableWrapperOpt.fold(Optional.none, focussableWrapper => {
26069
          focus$3(focussableWrapper);
26070
          return Optional.some(true);
26071
        });
26072
      };
26073
      const getFieldPart = isField1 => FormField.parts.field({
26074
        factory: Input,
1 efrain 26075
        inputClasses: [
1441 ariadna 26076
          'tox-textfield',
1 efrain 26077
          'tox-toolbar-textfield',
1441 ariadna 26078
          'tox-textfield-size'
1 efrain 26079
        ],
1441 ariadna 26080
        data: isField1 ? width : height,
26081
        inputBehaviours: derive$1([
26082
          Disabling.config({ disabled }),
26083
          Tabstopping.config({}),
26084
          config('size-input-toolbar-events', [run$1(focusin(), (component, _simulatedEvent) => {
26085
              emitWith(component, ratioEvent, { isField1 });
26086
            })]),
26087
          Keying.config({
26088
            mode: 'special',
26089
            onEnter,
26090
            onEscape: goToParent
26091
          })
26092
        ]),
26093
        selectOnFocus: false
26094
      });
26095
      const getLabel = label => ({
26096
        dom: {
26097
          tag: 'label',
26098
          classes: ['tox-label']
26099
        },
26100
        components: [text$2(providersBackstage.translate(label))]
26101
      });
26102
      const focusableWrapper = field => ({
26103
        dom: {
26104
          tag: 'div',
26105
          classes: [
26106
            'tox-focusable-wrapper',
26107
            'tox-toolbar-nav-item'
26108
          ]
26109
        },
26110
        components: [field],
26111
        behaviours: derive$1([
26112
          Tabstopping.config({}),
26113
          Focusing.config({}),
26114
          Keying.config({
26115
            mode: 'special',
26116
            onEnter: comp => {
26117
              const focussableInputOpt = descendant(comp.element, 'input');
26118
              return focussableInputOpt.fold(Optional.none, focussableInput => {
26119
                focus$3(focussableInput);
26120
                return Optional.some(true);
26121
              });
26122
            }
26123
          })
26124
        ])
26125
      });
26126
      const widthField = focusableWrapper(FormCoupledInputs.parts.field1(formGroup([
26127
        FormField.parts.label(getLabel('Width:')),
26128
        getFieldPart(true)
26129
      ])));
26130
      const heightField = focusableWrapper(FormCoupledInputs.parts.field2(formGroup([
26131
        FormField.parts.label(getLabel('Height:')),
26132
        getFieldPart(false)
26133
      ])));
26134
      const editorOffCell = Cell(noop);
26135
      const controlLifecycleHandlers = [
26136
        onControlAttached({
26137
          onSetup: ctx.onSetup,
26138
          getApi
26139
        }, editorOffCell),
26140
        onControlDetached({ getApi }, editorOffCell)
26141
      ];
26142
      return FormCoupledInputs.sketch({
26143
        dom: {
26144
          tag: 'div',
26145
          classes: ['tox-context-form__group']
26146
        },
26147
        components: [
26148
          widthField,
26149
          heightField,
26150
          formGroup([
26151
            getLabel(nbsp),
26152
            pLock
26153
          ])
26154
        ],
26155
        field1Name: 'width',
26156
        field2Name: 'height',
26157
        locked: true,
26158
        markers: { lockClass: 'tox-locked' },
26159
        onLockedChange: (current, other, _lock) => {
26160
          parseSize(Representing.getValue(current)).each(size => {
26161
            converter(size).each(newSize => {
26162
              Representing.setValue(other, formatSize(newSize));
26163
            });
26164
          });
26165
        },
26166
        onInput: current => emit(current, formInputEvent),
26167
        coupledFieldBehaviours: derive$1([
26168
          Focusing.config({}),
26169
          Keying.config({
26170
            mode: 'flow',
26171
            focusInside: FocusInsideModes.OnEnterOrSpaceMode,
26172
            cycles: false,
26173
            selector: 'button, .tox-focusable-wrapper'
26174
          }),
26175
          Disabling.config({
26176
            disabled,
26177
            onDisabled: comp => {
26178
              FormCoupledInputs.getField1(comp).bind(FormField.getField).each(Disabling.disable);
26179
              FormCoupledInputs.getField2(comp).bind(FormField.getField).each(Disabling.disable);
26180
              FormCoupledInputs.getLock(comp).each(Disabling.disable);
26181
            },
26182
            onEnabled: comp => {
26183
              FormCoupledInputs.getField1(comp).bind(FormField.getField).each(Disabling.enable);
26184
              FormCoupledInputs.getField2(comp).bind(FormField.getField).each(Disabling.enable);
26185
              FormCoupledInputs.getLock(comp).each(Disabling.enable);
26186
            }
26187
          }),
26188
          toggleOnReceive(() => providersBackstage.checkUiComponentContext('mode:design')),
26189
          config('size-input-toolbar-events2', [
26190
            run$1(ratioEvent, (component, simulatedEvent) => {
26191
              const isField1 = simulatedEvent.event.isField1;
26192
              const optCurrent = isField1 ? FormCoupledInputs.getField1(component) : FormCoupledInputs.getField2(component);
26193
              const optOther = isField1 ? FormCoupledInputs.getField2(component) : FormCoupledInputs.getField1(component);
26194
              const value1 = optCurrent.map(Representing.getValue).getOr('');
26195
              const value2 = optOther.map(Representing.getValue).getOr('');
26196
              converter = makeRatioConverter(value1, value2);
26197
            }),
26198
            run$1(formInputEvent, input => ctx.onInput(getFormApi(input))),
26199
            ...controlLifecycleHandlers
26200
          ])
26201
        ])
26202
      });
26203
    };
26204
 
26205
    const createContextFormFieldFromParts = (pLabel, pField, providers) => FormField.sketch({
26206
      dom: {
26207
        tag: 'div',
26208
        classes: ['tox-context-form__group']
26209
      },
26210
      components: [
26211
        ...pLabel.toArray(),
26212
        pField
26213
      ],
26214
      fieldBehaviours: derive$1([Disabling.config({
26215
          disabled: () => providers.checkUiComponentContext('mode:design').shouldDisable,
26216
          onDisabled: comp => {
26217
            focusParent(comp);
26218
            FormField.getField(comp).each(Disabling.disable);
26219
          },
26220
          onEnabled: comp => {
26221
            FormField.getField(comp).each(Disabling.enable);
26222
          }
26223
        })])
26224
    });
26225
 
26226
    const renderContextFormSliderInput = (ctx, providers, onEnter) => {
26227
      const editorOffCell = Cell(noop);
26228
      const pLabel = ctx.label.map(label => FormField.parts.label({
26229
        dom: {
26230
          tag: 'label',
26231
          classes: ['tox-label']
26232
        },
26233
        components: [text$2(providers.translate(label))]
26234
      }));
26235
      const pField = FormField.parts.field({
26236
        factory: Input,
26237
        type: 'range',
26238
        inputClasses: [
26239
          'tox-toolbar-slider__input',
26240
          'tox-toolbar-nav-item'
26241
        ],
26242
        inputAttributes: {
26243
          min: String(ctx.min()),
26244
          max: String(ctx.max())
26245
        },
26246
        data: ctx.initValue().toString(),
26247
        fromInputValue: value => toFloat(value).getOr(ctx.min()),
26248
        toInputValue: value => String(value),
26249
        inputBehaviours: derive$1([
26250
          Disabling.config({ disabled: () => providers.checkUiComponentContext('mode:design').shouldDisable }),
26251
          toggleOnReceive(() => providers.checkUiComponentContext('mode:design')),
26252
          Keying.config({
26253
            mode: 'special',
26254
            onEnter,
26255
            onLeft: (comp, se) => {
26256
              se.cut();
26257
              return Optional.none();
26258
            },
26259
            onRight: (comp, se) => {
26260
              se.cut();
26261
              return Optional.none();
26262
            }
26263
          }),
26264
          config('slider-events', [
26265
            onControlAttached({
26266
              onSetup: ctx.onSetup,
26267
              getApi: getFormApi,
26268
              onBeforeSetup: Keying.focusIn
26269
            }, editorOffCell),
26270
            onControlDetached({ getApi: getFormApi }, editorOffCell),
26271
            run$1(input(), comp => {
26272
              ctx.onInput(getFormApi(comp));
26273
            })
26274
          ])
26275
        ])
26276
      });
26277
      return createContextFormFieldFromParts(pLabel, pField, providers);
26278
    };
26279
 
26280
    const renderContextFormTextInput = (ctx, providers, onEnter) => {
26281
      const editorOffCell = Cell(noop);
26282
      const pLabel = ctx.label.map(label => FormField.parts.label({
26283
        dom: {
26284
          tag: 'label',
26285
          classes: ['tox-label']
26286
        },
26287
        components: [text$2(providers.translate(label))]
26288
      }));
26289
      const placeholder = ctx.placeholder.map(p => ({ placeholder: providers.translate(p) })).getOr({});
26290
      const inputAttributes = { ...placeholder };
26291
      const pField = FormField.parts.field({
26292
        factory: Input,
26293
        inputClasses: [
26294
          'tox-toolbar-textfield',
26295
          'tox-toolbar-nav-item'
26296
        ],
26297
        inputAttributes,
1 efrain 26298
        data: ctx.initValue(),
26299
        selectOnFocus: true,
1441 ariadna 26300
        inputBehaviours: derive$1([
26301
          Disabling.config({ disabled: () => providers.checkUiComponentContext('mode:design').shouldDisable }),
26302
          toggleOnReceive(() => providers.checkUiComponentContext('mode:design')),
26303
          Keying.config({
1 efrain 26304
            mode: 'special',
1441 ariadna 26305
            onEnter,
1 efrain 26306
            onLeft: (comp, se) => {
26307
              se.cut();
26308
              return Optional.none();
26309
            },
26310
            onRight: (comp, se) => {
26311
              se.cut();
26312
              return Optional.none();
26313
            }
1441 ariadna 26314
          }),
26315
          config('input-events', [
26316
            onControlAttached({
26317
              onSetup: ctx.onSetup,
26318
              getApi: comp => {
26319
                const closestFocussableOpt = ancestor(comp.element, '.tox-toolbar').bind(toolbar => descendant(toolbar, 'button:enabled'));
26320
                return closestFocussableOpt.fold(() => getFormApi(comp), closestFocussable => getFormApi(comp, closestFocussable));
26321
              },
26322
              onBeforeSetup: Keying.focusIn
26323
            }, editorOffCell),
26324
            onControlDetached({ getApi: getFormApi }, editorOffCell),
26325
            run$1(input(), comp => {
26326
              ctx.onInput(getFormApi(comp));
26327
            })
26328
          ])
26329
        ])
26330
      });
26331
      return createContextFormFieldFromParts(pLabel, pField, providers);
26332
    };
26333
 
26334
    const buildInitGroup = (f, ctx, providers) => {
26335
      const onEnter = input => {
26336
        return startCommands.findPrimary(input).orThunk(() => endCommands.findPrimary(input)).map(primary => {
26337
          emitExecute(primary);
26338
          return true;
26339
        });
26340
      };
26341
      const memInput = record(f(providers, onEnter));
26342
      const commandParts = partition$3(ctx.commands, command => command.align === 'start');
26343
      const startCommands = generate(memInput, commandParts.pass, providers);
26344
      const endCommands = generate(memInput, commandParts.fail, providers);
26345
      return filter$2([
1 efrain 26346
        {
26347
          title: Optional.none(),
1441 ariadna 26348
          label: Optional.none(),
26349
          items: startCommands.asSpecs()
26350
        },
26351
        {
26352
          title: Optional.none(),
26353
          label: Optional.none(),
1 efrain 26354
          items: [memInput.asSpec()]
26355
        },
26356
        {
26357
          title: Optional.none(),
1441 ariadna 26358
          label: Optional.none(),
26359
          items: endCommands.asSpecs()
1 efrain 26360
        }
1441 ariadna 26361
      ], group => group.items.length > 0);
1 efrain 26362
    };
1441 ariadna 26363
    const buildInitGroups = (ctx, providers) => {
26364
      switch (ctx.type) {
26365
      case 'contextform':
26366
        return buildInitGroup(curry(renderContextFormTextInput, ctx), ctx, providers);
26367
      case 'contextsliderform':
26368
        return buildInitGroup(curry(renderContextFormSliderInput, ctx), ctx, providers);
26369
      case 'contextsizeinputform':
26370
        return buildInitGroup(curry(renderContextFormSizeInput, ctx), ctx, providers);
26371
      }
26372
    };
1 efrain 26373
    const renderContextForm = (toolbarType, ctx, providers) => renderToolbar({
26374
      type: toolbarType,
26375
      uid: generate$6('context-toolbar'),
26376
      initGroups: buildInitGroups(ctx, providers),
26377
      onEscape: Optional.none,
26378
      cyclicKeying: true,
26379
      providers
26380
    });
26381
    const ContextForm = {
26382
      renderContextForm,
26383
      buildInitGroups
26384
    };
26385
 
26386
    const isVerticalOverlap = (a, b, threshold) => b.bottom - a.y >= threshold && a.bottom - b.y >= threshold;
26387
    const getRangeRect = rng => {
26388
      const rect = rng.getBoundingClientRect();
26389
      if (rect.height <= 0 && rect.width <= 0) {
26390
        const leaf$1 = leaf(SugarElement.fromDom(rng.startContainer), rng.startOffset).element;
26391
        const elm = isText(leaf$1) ? parent(leaf$1) : Optional.some(leaf$1);
26392
        return elm.filter(isElement$1).map(e => e.dom.getBoundingClientRect()).getOr(rect);
26393
      } else {
26394
        return rect;
26395
      }
26396
    };
26397
    const getSelectionBounds = editor => {
26398
      const rng = editor.selection.getRng();
26399
      const rect = getRangeRect(rng);
26400
      if (editor.inline) {
1441 ariadna 26401
        const scroll = get$c();
1 efrain 26402
        return bounds(scroll.left + rect.left, scroll.top + rect.top, rect.width, rect.height);
26403
      } else {
26404
        const bodyPos = absolute$2(SugarElement.fromDom(editor.getBody()));
26405
        return bounds(bodyPos.x + rect.left, bodyPos.y + rect.top, rect.width, rect.height);
26406
      }
26407
    };
26408
    const getAnchorElementBounds = (editor, lastElement) => lastElement.filter(elem => inBody(elem) && isHTMLElement(elem)).map(absolute$2).getOrThunk(() => getSelectionBounds(editor));
26409
    const getHorizontalBounds = (contentAreaBox, viewportBounds, margin) => {
26410
      const x = Math.max(contentAreaBox.x + margin, viewportBounds.x);
26411
      const right = Math.min(contentAreaBox.right - margin, viewportBounds.right);
26412
      return {
26413
        x,
26414
        width: right - x
26415
      };
26416
    };
26417
    const getVerticalBounds = (editor, contentAreaBox, viewportBounds, isToolbarLocationTop, toolbarType, margin) => {
26418
      const container = SugarElement.fromDom(editor.getContainer());
26419
      const header = descendant(container, '.tox-editor-header').getOr(container);
26420
      const headerBox = box$1(header);
26421
      const isToolbarBelowContentArea = headerBox.y >= contentAreaBox.bottom;
26422
      const isToolbarAbove = isToolbarLocationTop && !isToolbarBelowContentArea;
26423
      if (editor.inline && isToolbarAbove) {
26424
        return {
26425
          y: Math.max(headerBox.bottom + margin, viewportBounds.y),
26426
          bottom: viewportBounds.bottom
26427
        };
26428
      }
26429
      if (editor.inline && !isToolbarAbove) {
26430
        return {
26431
          y: viewportBounds.y,
26432
          bottom: Math.min(headerBox.y - margin, viewportBounds.bottom)
26433
        };
26434
      }
26435
      const containerBounds = toolbarType === 'line' ? box$1(container) : contentAreaBox;
26436
      if (isToolbarAbove) {
26437
        return {
26438
          y: Math.max(headerBox.bottom + margin, viewportBounds.y),
26439
          bottom: Math.min(containerBounds.bottom - margin, viewportBounds.bottom)
26440
        };
26441
      }
26442
      return {
26443
        y: Math.max(containerBounds.y + margin, viewportBounds.y),
26444
        bottom: Math.min(headerBox.y - margin, viewportBounds.bottom)
26445
      };
26446
    };
26447
    const getContextToolbarBounds = (editor, sharedBackstage, toolbarType, margin = 0) => {
26448
      const viewportBounds = getBounds$3(window);
26449
      const contentAreaBox = box$1(SugarElement.fromDom(editor.getContentAreaContainer()));
26450
      const toolbarOrMenubarEnabled = isMenubarEnabled(editor) || isToolbarEnabled(editor) || isMultipleToolbars(editor);
26451
      const {x, width} = getHorizontalBounds(contentAreaBox, viewportBounds, margin);
26452
      if (editor.inline && !toolbarOrMenubarEnabled) {
26453
        return bounds(x, viewportBounds.y, width, viewportBounds.height);
26454
      } else {
26455
        const isToolbarTop = sharedBackstage.header.isPositionedAtTop();
26456
        const {y, bottom} = getVerticalBounds(editor, contentAreaBox, viewportBounds, isToolbarTop, toolbarType, margin);
26457
        return bounds(x, y, width, bottom - y);
26458
      }
26459
    };
26460
 
26461
    const bubbleSize$1 = 12;
26462
    const bubbleAlignments$1 = {
26463
      valignCentre: [],
26464
      alignCentre: [],
26465
      alignLeft: ['tox-pop--align-left'],
26466
      alignRight: ['tox-pop--align-right'],
26467
      right: ['tox-pop--right'],
26468
      left: ['tox-pop--left'],
26469
      bottom: ['tox-pop--bottom'],
26470
      top: ['tox-pop--top'],
26471
      inset: ['tox-pop--inset']
26472
    };
26473
    const anchorOverrides = {
26474
      maxHeightFunction: expandable$1(),
26475
      maxWidthFunction: expandable()
26476
    };
26477
    const isEntireElementSelected = (editor, elem) => {
26478
      const rng = editor.selection.getRng();
26479
      const leaf$1 = leaf(SugarElement.fromDom(rng.startContainer), rng.startOffset);
26480
      return rng.startContainer === rng.endContainer && rng.startOffset === rng.endOffset - 1 && eq(leaf$1.element, elem);
26481
    };
26482
    const preservePosition = (elem, position, f) => {
26483
      const currentPosition = getRaw(elem, 'position');
26484
      set$8(elem, 'position', position);
26485
      const result = f(elem);
26486
      currentPosition.each(pos => set$8(elem, 'position', pos));
26487
      return result;
26488
    };
26489
    const shouldUseInsetLayouts = position => position === 'node';
26490
    const determineInsetLayout = (editor, contextbar, elem, data, bounds) => {
26491
      const selectionBounds = getSelectionBounds(editor);
26492
      const isSameAnchorElement = data.lastElement().exists(prev => eq(elem, prev));
26493
      if (isEntireElementSelected(editor, elem)) {
26494
        return isSameAnchorElement ? preserve : north;
26495
      } else if (isSameAnchorElement) {
26496
        return preservePosition(contextbar, data.getMode(), () => {
26497
          const isOverlapping = isVerticalOverlap(selectionBounds, box$1(contextbar), -20);
26498
          return isOverlapping && !data.isReposition() ? flip : preserve;
26499
        });
26500
      } else {
1441 ariadna 26501
        const yBounds = data.getMode() === 'fixed' ? bounds.y + get$c().top : bounds.y;
26502
        const contextbarHeight = get$e(contextbar) + bubbleSize$1;
1 efrain 26503
        return yBounds + contextbarHeight <= selectionBounds.y ? north : south;
26504
      }
26505
    };
26506
    const getAnchorSpec$2 = (editor, mobile, data, position) => {
26507
      const smartInsetLayout = elem => (anchor, element, bubbles, placee, bounds) => {
26508
        const layout = determineInsetLayout(editor, placee, elem, data, bounds);
26509
        const newAnchor = {
26510
          ...anchor,
26511
          y: bounds.y,
26512
          height: bounds.height
26513
        };
26514
        return {
26515
          ...layout(newAnchor, element, bubbles, placee, bounds),
26516
          alwaysFit: true
26517
        };
26518
      };
26519
      const getInsetLayouts = elem => shouldUseInsetLayouts(position) ? [smartInsetLayout(elem)] : [];
26520
      const desktopAnchorSpecLayouts = {
26521
        onLtr: elem => [
26522
          north$2,
26523
          south$2,
26524
          northeast$2,
26525
          southeast$2,
26526
          northwest$2,
26527
          southwest$2
26528
        ].concat(getInsetLayouts(elem)),
26529
        onRtl: elem => [
26530
          north$2,
26531
          south$2,
26532
          northwest$2,
26533
          southwest$2,
26534
          northeast$2,
26535
          southeast$2
26536
        ].concat(getInsetLayouts(elem))
26537
      };
26538
      const mobileAnchorSpecLayouts = {
26539
        onLtr: elem => [
26540
          south$2,
26541
          southeast$2,
26542
          southwest$2,
26543
          northeast$2,
26544
          northwest$2,
26545
          north$2
26546
        ].concat(getInsetLayouts(elem)),
26547
        onRtl: elem => [
26548
          south$2,
26549
          southwest$2,
26550
          southeast$2,
26551
          northwest$2,
26552
          northeast$2,
26553
          north$2
26554
        ].concat(getInsetLayouts(elem))
26555
      };
26556
      return mobile ? mobileAnchorSpecLayouts : desktopAnchorSpecLayouts;
26557
    };
26558
    const getAnchorLayout = (editor, position, isTouch, data) => {
26559
      if (position === 'line') {
26560
        return {
26561
          bubble: nu$5(bubbleSize$1, 0, bubbleAlignments$1),
26562
          layouts: {
26563
            onLtr: () => [east$2],
26564
            onRtl: () => [west$2]
26565
          },
26566
          overrides: anchorOverrides
26567
        };
26568
      } else {
26569
        return {
26570
          bubble: nu$5(0, bubbleSize$1, bubbleAlignments$1, 1 / bubbleSize$1),
26571
          layouts: getAnchorSpec$2(editor, isTouch, data, position),
26572
          overrides: anchorOverrides
26573
        };
26574
      }
26575
    };
26576
 
26577
    const matchTargetWith = (elem, candidates) => {
26578
      const ctxs = filter$2(candidates, toolbarApi => toolbarApi.predicate(elem.dom));
26579
      const {pass, fail} = partition$3(ctxs, t => t.type === 'contexttoolbar');
26580
      return {
26581
        contextToolbars: pass,
26582
        contextForms: fail
26583
      };
26584
    };
26585
    const filterByPositionForStartNode = toolbars => {
26586
      if (toolbars.length <= 1) {
26587
        return toolbars;
26588
      } else {
26589
        const doesPositionExist = value => exists(toolbars, t => t.position === value);
26590
        const filterToolbarsByPosition = value => filter$2(toolbars, t => t.position === value);
26591
        const hasSelectionToolbars = doesPositionExist('selection');
26592
        const hasNodeToolbars = doesPositionExist('node');
26593
        if (hasSelectionToolbars || hasNodeToolbars) {
26594
          if (hasNodeToolbars && hasSelectionToolbars) {
26595
            const nodeToolbars = filterToolbarsByPosition('node');
26596
            const selectionToolbars = map$2(filterToolbarsByPosition('selection'), t => ({
26597
              ...t,
26598
              position: 'node'
26599
            }));
26600
            return nodeToolbars.concat(selectionToolbars);
26601
          } else {
26602
            return hasSelectionToolbars ? filterToolbarsByPosition('selection') : filterToolbarsByPosition('node');
26603
          }
26604
        } else {
26605
          return filterToolbarsByPosition('line');
26606
        }
26607
      }
26608
    };
26609
    const filterByPositionForAncestorNode = toolbars => {
26610
      if (toolbars.length <= 1) {
26611
        return toolbars;
26612
      } else {
26613
        const findPosition = value => find$5(toolbars, t => t.position === value);
26614
        const basePosition = findPosition('selection').orThunk(() => findPosition('node')).orThunk(() => findPosition('line')).map(t => t.position);
26615
        return basePosition.fold(() => [], pos => filter$2(toolbars, t => t.position === pos));
26616
      }
26617
    };
26618
    const matchStartNode = (elem, nodeCandidates, editorCandidates) => {
26619
      const nodeMatches = matchTargetWith(elem, nodeCandidates);
26620
      if (nodeMatches.contextForms.length > 0) {
26621
        return Optional.some({
26622
          elem,
26623
          toolbars: [nodeMatches.contextForms[0]]
26624
        });
26625
      } else {
26626
        const editorMatches = matchTargetWith(elem, editorCandidates);
26627
        if (editorMatches.contextForms.length > 0) {
26628
          return Optional.some({
26629
            elem,
26630
            toolbars: [editorMatches.contextForms[0]]
26631
          });
26632
        } else if (nodeMatches.contextToolbars.length > 0 || editorMatches.contextToolbars.length > 0) {
26633
          const toolbars = filterByPositionForStartNode(nodeMatches.contextToolbars.concat(editorMatches.contextToolbars));
26634
          return Optional.some({
26635
            elem,
26636
            toolbars
26637
          });
26638
        } else {
26639
          return Optional.none();
26640
        }
26641
      }
26642
    };
26643
    const matchAncestor = (isRoot, startNode, scopes) => {
26644
      if (isRoot(startNode)) {
26645
        return Optional.none();
26646
      } else {
26647
        return ancestor$2(startNode, ancestorElem => {
26648
          if (isElement$1(ancestorElem)) {
26649
            const {contextToolbars, contextForms} = matchTargetWith(ancestorElem, scopes.inNodeScope);
26650
            const toolbars = contextForms.length > 0 ? contextForms : filterByPositionForAncestorNode(contextToolbars);
26651
            return toolbars.length > 0 ? Optional.some({
26652
              elem: ancestorElem,
26653
              toolbars
26654
            }) : Optional.none();
26655
          } else {
26656
            return Optional.none();
26657
          }
26658
        }, isRoot);
26659
      }
26660
    };
26661
    const lookup$1 = (scopes, editor) => {
26662
      const rootElem = SugarElement.fromDom(editor.getBody());
26663
      const isRoot = elem => eq(elem, rootElem);
26664
      const isOutsideRoot = startNode => !isRoot(startNode) && !contains(rootElem, startNode);
26665
      const startNode = SugarElement.fromDom(editor.selection.getNode());
26666
      if (isOutsideRoot(startNode)) {
26667
        return Optional.none();
26668
      }
26669
      return matchStartNode(startNode, scopes.inNodeScope, scopes.inEditorScope).orThunk(() => matchAncestor(isRoot, startNode, scopes));
26670
    };
26671
 
26672
    const categorise = (contextToolbars, navigate) => {
26673
      const forms = {};
26674
      const inNodeScope = [];
26675
      const inEditorScope = [];
26676
      const formNavigators = {};
26677
      const lookupTable = {};
26678
      const registerForm = (key, toolbarSpec) => {
26679
        const contextForm = getOrDie(createContextForm(toolbarSpec));
26680
        forms[key] = contextForm;
26681
        contextForm.launch.map(launch => {
26682
          formNavigators['form:' + key + ''] = {
26683
            ...toolbarSpec.launch,
26684
            type: launch.type === 'contextformtogglebutton' ? 'togglebutton' : 'button',
26685
            onAction: () => {
26686
              navigate(contextForm);
26687
            }
26688
          };
26689
        });
26690
        if (contextForm.scope === 'editor') {
26691
          inEditorScope.push(contextForm);
26692
        } else {
26693
          inNodeScope.push(contextForm);
26694
        }
26695
        lookupTable[key] = contextForm;
26696
      };
26697
      const registerToolbar = (key, toolbarSpec) => {
26698
        createContextToolbar(toolbarSpec).each(contextToolbar => {
26699
          if (toolbarSpec.scope === 'editor') {
26700
            inEditorScope.push(contextToolbar);
26701
          } else {
26702
            inNodeScope.push(contextToolbar);
26703
          }
26704
          lookupTable[key] = contextToolbar;
26705
        });
26706
      };
26707
      const keys$1 = keys(contextToolbars);
26708
      each$1(keys$1, key => {
26709
        const toolbarApi = contextToolbars[key];
1441 ariadna 26710
        if (toolbarApi.type === 'contextform' || toolbarApi.type === 'contextsliderform' || toolbarApi.type === 'contextsizeinputform') {
1 efrain 26711
          registerForm(key, toolbarApi);
26712
        } else if (toolbarApi.type === 'contexttoolbar') {
26713
          registerToolbar(key, toolbarApi);
26714
        }
26715
      });
26716
      return {
26717
        forms,
26718
        inNodeScope,
26719
        inEditorScope,
26720
        lookupTable,
26721
        formNavigators
26722
      };
26723
    };
26724
 
26725
    const transitionClass = 'tox-pop--transition';
1441 ariadna 26726
    const register$a = (editor, registryContextToolbars, sink, extras) => {
1 efrain 26727
      const backstage = extras.backstage;
26728
      const sharedBackstage = backstage.shared;
1441 ariadna 26729
      const isTouch = detect$1().deviceType.isTouch;
26730
      const lastElement = value$4();
26731
      const lastTrigger = value$4();
26732
      const lastContextPosition = value$4();
1 efrain 26733
      const contextbar = build$1(renderContextToolbar({
26734
        sink,
26735
        onEscape: () => {
26736
          editor.focus();
1441 ariadna 26737
          fireContextToolbarClose(editor);
1 efrain 26738
          return Optional.some(true);
1441 ariadna 26739
        },
26740
        onHide: () => {
26741
          fireContextToolbarClose(editor);
26742
        },
26743
        onBack: () => {
26744
          fireContextFormSlideBack(editor);
1 efrain 26745
        }
26746
      }));
26747
      const getBounds = () => {
26748
        const position = lastContextPosition.get().getOr('node');
26749
        const margin = shouldUseInsetLayouts(position) ? 1 : 0;
26750
        return getContextToolbarBounds(editor, sharedBackstage, position, margin);
26751
      };
26752
      const canLaunchToolbar = () => {
26753
        return !editor.removed && !(isTouch() && backstage.isContextMenuOpen());
26754
      };
26755
      const isSameLaunchElement = elem => is$1(lift2(elem, lastElement.get(), eq), true);
26756
      const shouldContextToolbarHide = () => {
26757
        if (!canLaunchToolbar()) {
26758
          return true;
26759
        } else {
26760
          const contextToolbarBounds = getBounds();
26761
          const anchorBounds = is$1(lastContextPosition.get(), 'node') ? getAnchorElementBounds(editor, lastElement.get()) : getSelectionBounds(editor);
26762
          return contextToolbarBounds.height <= 0 || !isVerticalOverlap(anchorBounds, contextToolbarBounds, 0.01);
26763
        }
26764
      };
26765
      const close = () => {
26766
        lastElement.clear();
26767
        lastTrigger.clear();
26768
        lastContextPosition.clear();
26769
        InlineView.hide(contextbar);
26770
      };
26771
      const hideOrRepositionIfNecessary = () => {
26772
        if (InlineView.isOpen(contextbar)) {
26773
          const contextBarEle = contextbar.element;
1441 ariadna 26774
          remove$7(contextBarEle, 'display');
1 efrain 26775
          if (shouldContextToolbarHide()) {
26776
            set$8(contextBarEle, 'display', 'none');
26777
          } else {
26778
            lastTrigger.set(0);
26779
            InlineView.reposition(contextbar);
26780
          }
26781
        }
26782
      };
26783
      const wrapInPopDialog = toolbarSpec => ({
26784
        dom: {
26785
          tag: 'div',
26786
          classes: ['tox-pop__dialog']
26787
        },
26788
        components: [toolbarSpec],
26789
        behaviours: derive$1([
26790
          Keying.config({ mode: 'acyclic' }),
26791
          config('pop-dialog-wrap-events', [
26792
            runOnAttached(comp => {
26793
              editor.shortcuts.add('ctrl+F9', 'focus statusbar', () => Keying.focusIn(comp));
26794
            }),
26795
            runOnDetached(_comp => {
26796
              editor.shortcuts.remove('ctrl+F9');
26797
            })
26798
          ])
26799
        ])
26800
      });
26801
      const getScopes = cached(() => categorise(registryContextToolbars, toolbarApi => {
26802
        const alloySpec = buildToolbar([toolbarApi]);
26803
        emitWith(contextbar, forwardSlideEvent, { forwardContents: wrapInPopDialog(alloySpec) });
26804
      }));
1441 ariadna 26805
      const buildContextToolbarGroups = (allButtons, ctx) => {
26806
        return identifyButtons(editor, {
26807
          buttons: allButtons,
26808
          toolbar: ctx.items,
26809
          allowToolbarGroups: false
26810
        }, extras.backstage, Optional.some(['form:']));
26811
      };
1 efrain 26812
      const buildContextFormGroups = (ctx, providers) => ContextForm.buildInitGroups(ctx, providers);
26813
      const buildToolbar = toolbars => {
26814
        const {buttons} = editor.ui.registry.getAll();
26815
        const scopes = getScopes();
26816
        const allButtons = {
26817
          ...buttons,
26818
          ...scopes.formNavigators
26819
        };
26820
        const toolbarType = getToolbarMode(editor) === ToolbarMode$1.scrolling ? ToolbarMode$1.scrolling : ToolbarMode$1.default;
1441 ariadna 26821
        const initGroups = flatten(map$2(toolbars, ctx => ctx.type === 'contexttoolbar' ? buildContextToolbarGroups(allButtons, contextToolbarToSpec(ctx)) : buildContextFormGroups(ctx, sharedBackstage.providers)));
1 efrain 26822
        return renderToolbar({
26823
          type: toolbarType,
26824
          uid: generate$6('context-toolbar'),
26825
          initGroups,
26826
          onEscape: Optional.none,
26827
          cyclicKeying: true,
26828
          providers: sharedBackstage.providers
26829
        });
26830
      };
26831
      const getAnchor = (position, element) => {
26832
        const anchorage = position === 'node' ? sharedBackstage.anchors.node(element) : sharedBackstage.anchors.cursor();
26833
        const anchorLayout = getAnchorLayout(editor, position, isTouch(), {
26834
          lastElement: lastElement.get,
26835
          isReposition: () => is$1(lastTrigger.get(), 0),
26836
          getMode: () => Positioning.getMode(sink)
26837
        });
26838
        return deepMerge(anchorage, anchorLayout);
26839
      };
26840
      const launchContext = (toolbarApi, elem) => {
26841
        launchContextToolbar.cancel();
26842
        if (!canLaunchToolbar()) {
26843
          return;
26844
        }
26845
        const toolbarSpec = buildToolbar(toolbarApi);
26846
        const position = toolbarApi[0].position;
26847
        const anchor = getAnchor(position, elem);
26848
        lastContextPosition.set(position);
26849
        lastTrigger.set(1);
26850
        const contextBarEle = contextbar.element;
1441 ariadna 26851
        remove$7(contextBarEle, 'display');
1 efrain 26852
        if (!isSameLaunchElement(elem)) {
1441 ariadna 26853
          remove$3(contextBarEle, transitionClass);
1 efrain 26854
          Positioning.reset(sink, contextbar);
26855
        }
26856
        InlineView.showWithinBounds(contextbar, wrapInPopDialog(toolbarSpec), {
26857
          anchor,
26858
          transition: {
26859
            classes: [transitionClass],
26860
            mode: 'placement'
26861
          }
26862
        }, () => Optional.some(getBounds()));
26863
        elem.fold(lastElement.clear, lastElement.set);
26864
        if (shouldContextToolbarHide()) {
26865
          set$8(contextBarEle, 'display', 'none');
26866
        }
26867
      };
26868
      let isDragging = false;
26869
      const launchContextToolbar = last(() => {
26870
        if (!editor.hasFocus() || editor.removed || isDragging) {
26871
          return;
26872
        }
26873
        if (has(contextbar.element, transitionClass)) {
26874
          launchContextToolbar.throttle();
26875
        } else {
26876
          const scopes = getScopes();
26877
          lookup$1(scopes, editor).fold(close, info => {
26878
            launchContext(info.toolbars, Optional.some(info.elem));
26879
          });
26880
        }
26881
      }, 17);
26882
      editor.on('init', () => {
26883
        editor.on('remove', close);
26884
        editor.on('ScrollContent ScrollWindow ObjectResized ResizeEditor longpress', hideOrRepositionIfNecessary);
26885
        editor.on('click keyup focus SetContent', launchContextToolbar.throttle);
26886
        editor.on(hideContextToolbarEvent, close);
26887
        editor.on(showContextToolbarEvent, e => {
26888
          const scopes = getScopes();
1441 ariadna 26889
          get$h(scopes.lookupTable, e.toolbarKey).each(ctx => {
1 efrain 26890
            launchContext([ctx], someIf(e.target !== editor, e.target));
1441 ariadna 26891
            focusIn(contextbar);
1 efrain 26892
          });
26893
        });
26894
        editor.on('focusout', _e => {
26895
          global$9.setEditorTimeout(editor, () => {
26896
            if (search(sink.element).isNone() && search(contextbar.element).isNone()) {
26897
              close();
26898
            }
26899
          }, 0);
26900
        });
26901
        editor.on('SwitchMode', () => {
26902
          if (editor.mode.isReadOnly()) {
26903
            close();
26904
          }
26905
        });
1441 ariadna 26906
        editor.on('DisabledStateChange', e => {
26907
          if (e.state) {
26908
            close();
26909
          }
26910
        });
26911
        editor.on('ExecCommand', ({command}) => {
26912
          if (command.toLowerCase() === 'toggleview') {
26913
            close();
26914
          }
26915
        });
1 efrain 26916
        editor.on('AfterProgressState', event => {
26917
          if (event.state) {
26918
            close();
26919
          } else if (editor.hasFocus()) {
26920
            launchContextToolbar.throttle();
26921
          }
26922
        });
26923
        editor.on('dragstart', () => {
26924
          isDragging = true;
26925
        });
26926
        editor.on('dragend drop', () => {
26927
          isDragging = false;
26928
        });
26929
        editor.on('NodeChange', _e => {
26930
          search(contextbar.element).fold(launchContextToolbar.throttle, noop);
26931
        });
26932
      });
26933
    };
26934
 
1441 ariadna 26935
    const register$9 = editor => {
1 efrain 26936
      const alignToolbarButtons = [
26937
        {
26938
          name: 'alignleft',
26939
          text: 'Align left',
26940
          cmd: 'JustifyLeft',
26941
          icon: 'align-left'
26942
        },
26943
        {
26944
          name: 'aligncenter',
26945
          text: 'Align center',
26946
          cmd: 'JustifyCenter',
26947
          icon: 'align-center'
26948
        },
26949
        {
26950
          name: 'alignright',
26951
          text: 'Align right',
26952
          cmd: 'JustifyRight',
26953
          icon: 'align-right'
26954
        },
26955
        {
26956
          name: 'alignjustify',
26957
          text: 'Justify',
26958
          cmd: 'JustifyFull',
26959
          icon: 'align-justify'
26960
        }
26961
      ];
26962
      each$1(alignToolbarButtons, item => {
26963
        editor.ui.registry.addToggleButton(item.name, {
26964
          tooltip: item.text,
26965
          icon: item.icon,
26966
          onAction: onActionExecCommand(editor, item.cmd),
26967
          onSetup: onSetupStateToggle(editor, item.name)
26968
        });
26969
      });
26970
      editor.ui.registry.addButton('alignnone', {
26971
        tooltip: 'No alignment',
26972
        icon: 'align-none',
26973
        onSetup: onSetupEditableToggle(editor),
26974
        onAction: onActionExecCommand(editor, 'JustifyNone')
26975
      });
26976
    };
26977
 
26978
    const registerController = (editor, spec) => {
26979
      const getMenuItems = () => {
26980
        const options = spec.getOptions(editor);
26981
        const initial = spec.getCurrent(editor).map(spec.hash);
1441 ariadna 26982
        const current = value$4();
1 efrain 26983
        return map$2(options, value => ({
26984
          type: 'togglemenuitem',
26985
          text: spec.display(value),
26986
          onSetup: api => {
26987
            const setActive = active => {
26988
              if (active) {
26989
                current.on(oldApi => oldApi.setActive(false));
26990
                current.set(api);
26991
              }
26992
              api.setActive(active);
26993
            };
26994
            setActive(is$1(initial, spec.hash(value)));
26995
            const unbindWatcher = spec.watcher(editor, value, setActive);
26996
            return () => {
26997
              current.clear();
26998
              unbindWatcher();
26999
            };
27000
          },
27001
          onAction: () => spec.setCurrent(editor, value)
27002
        }));
27003
      };
27004
      editor.ui.registry.addMenuButton(spec.name, {
27005
        tooltip: spec.text,
27006
        icon: spec.icon,
27007
        fetch: callback => callback(getMenuItems()),
27008
        onSetup: spec.onToolbarSetup
27009
      });
27010
      editor.ui.registry.addNestedMenuItem(spec.name, {
27011
        type: 'nestedmenuitem',
27012
        text: spec.text,
27013
        getSubmenuItems: getMenuItems,
27014
        onSetup: spec.onMenuSetup
27015
      });
27016
    };
27017
    const lineHeightSpec = editor => ({
27018
      name: 'lineheight',
27019
      text: 'Line height',
27020
      icon: 'line-height',
27021
      getOptions: getLineHeightFormats,
27022
      hash: input => normalise(input, [
27023
        'fixed',
27024
        'relative',
27025
        'empty'
27026
      ]).getOr(input),
27027
      display: identity,
27028
      watcher: (editor, value, callback) => editor.formatter.formatChanged('lineheight', callback, false, { value }).unbind,
27029
      getCurrent: editor => Optional.from(editor.queryCommandValue('LineHeight')),
27030
      setCurrent: (editor, value) => editor.execCommand('LineHeight', false, value),
27031
      onToolbarSetup: onSetupEditableToggle(editor),
27032
      onMenuSetup: onSetupEditableToggle(editor)
27033
    });
27034
    const languageSpec = editor => {
27035
      const settingsOpt = Optional.from(getContentLanguages(editor));
27036
      return settingsOpt.map(settings => ({
27037
        name: 'language',
27038
        text: 'Language',
27039
        icon: 'language',
27040
        getOptions: constant$1(settings),
27041
        hash: input => isUndefined(input.customCode) ? input.code : `${ input.code }/${ input.customCode }`,
27042
        display: input => input.title,
27043
        watcher: (editor, value, callback) => {
27044
          var _a;
27045
          return editor.formatter.formatChanged('lang', callback, false, {
27046
            value: value.code,
27047
            customValue: (_a = value.customCode) !== null && _a !== void 0 ? _a : null
27048
          }).unbind;
27049
        },
27050
        getCurrent: editor => {
27051
          const node = SugarElement.fromDom(editor.selection.getNode());
27052
          return closest$4(node, n => Optional.some(n).filter(isElement$1).bind(ele => {
27053
            const codeOpt = getOpt(ele, 'lang');
27054
            return codeOpt.map(code => {
27055
              const customCode = getOpt(ele, 'data-mce-lang').getOrUndefined();
27056
              return {
27057
                code,
27058
                customCode,
27059
                title: ''
27060
              };
27061
            });
27062
          }));
27063
        },
27064
        setCurrent: (editor, lang) => editor.execCommand('Lang', false, lang),
27065
        onToolbarSetup: api => {
27066
          const unbinder = unbindable();
27067
          api.setActive(editor.formatter.match('lang', {}, undefined, true));
27068
          unbinder.set(editor.formatter.formatChanged('lang', api.setActive, true));
27069
          return composeUnbinders(unbinder.clear, onSetupEditableToggle(editor)(api));
27070
        },
27071
        onMenuSetup: onSetupEditableToggle(editor)
27072
      }));
27073
    };
1441 ariadna 27074
    const register$8 = editor => {
1 efrain 27075
      registerController(editor, lineHeightSpec(editor));
27076
      languageSpec(editor).each(spec => registerController(editor, spec));
27077
    };
27078
 
1441 ariadna 27079
    const register$7 = (editor, backstage) => {
1 efrain 27080
      createAlignMenu(editor, backstage);
27081
      createFontFamilyMenu(editor, backstage);
27082
      createStylesMenu(editor, backstage);
27083
      createBlocksMenu(editor, backstage);
27084
      createFontSizeMenu(editor, backstage);
27085
    };
27086
 
1441 ariadna 27087
    const register$6 = editor => {
27088
      editor.ui.registry.addContext('editable', () => {
27089
        return editor.selection.isEditable();
27090
      });
27091
      editor.ui.registry.addContext('mode', mode => {
27092
        return editor.mode.get() === mode;
27093
      });
27094
      editor.ui.registry.addContext('any', always);
27095
      editor.ui.registry.addContext('formatting', format => {
27096
        return editor.formatter.canApply(format);
27097
      });
27098
      editor.ui.registry.addContext('insert', child => {
27099
        return editor.schema.isValidChild(editor.selection.getNode().tagName, child);
27100
      });
27101
    };
27102
 
1 efrain 27103
    const onSetupOutdentState = editor => onSetupEvent(editor, 'NodeChange', api => {
27104
      api.setEnabled(editor.queryCommandState('outdent') && editor.selection.isEditable());
27105
    });
27106
    const registerButtons$2 = editor => {
27107
      editor.ui.registry.addButton('outdent', {
27108
        tooltip: 'Decrease indent',
27109
        icon: 'outdent',
27110
        onSetup: onSetupOutdentState(editor),
27111
        onAction: onActionExecCommand(editor, 'outdent')
27112
      });
27113
      editor.ui.registry.addButton('indent', {
27114
        tooltip: 'Increase indent',
27115
        icon: 'indent',
27116
        onSetup: onSetupEditableToggle(editor),
27117
        onAction: onActionExecCommand(editor, 'indent')
27118
      });
27119
    };
27120
    const register$5 = editor => {
27121
      registerButtons$2(editor);
27122
    };
27123
 
27124
    const makeSetupHandler = (editor, pasteAsText) => api => {
27125
      api.setActive(pasteAsText.get());
27126
      const pastePlainTextToggleHandler = e => {
27127
        pasteAsText.set(e.state);
27128
        api.setActive(e.state);
27129
      };
27130
      editor.on('PastePlainTextToggle', pastePlainTextToggleHandler);
27131
      return composeUnbinders(() => editor.off('PastePlainTextToggle', pastePlainTextToggleHandler), onSetupEditableToggle(editor)(api));
27132
    };
27133
    const register$4 = editor => {
27134
      const pasteAsText = Cell(getPasteAsText(editor));
27135
      const onAction = () => editor.execCommand('mceTogglePlainTextPaste');
27136
      editor.ui.registry.addToggleButton('pastetext', {
27137
        active: false,
27138
        icon: 'paste-text',
27139
        tooltip: 'Paste as text',
27140
        onAction,
27141
        onSetup: makeSetupHandler(editor, pasteAsText)
27142
      });
27143
      editor.ui.registry.addToggleMenuItem('pastetext', {
27144
        text: 'Paste as text',
27145
        icon: 'paste-text',
27146
        onAction,
27147
        onSetup: makeSetupHandler(editor, pasteAsText)
27148
      });
27149
    };
27150
 
27151
    const onActionToggleFormat = (editor, fmt) => () => {
27152
      editor.execCommand('mceToggleFormat', false, fmt);
27153
    };
27154
    const registerFormatButtons = editor => {
27155
      global$1.each([
27156
        {
27157
          name: 'bold',
27158
          text: 'Bold',
1441 ariadna 27159
          icon: 'bold',
27160
          shortcut: 'Meta+B'
1 efrain 27161
        },
27162
        {
27163
          name: 'italic',
27164
          text: 'Italic',
1441 ariadna 27165
          icon: 'italic',
27166
          shortcut: 'Meta+I'
1 efrain 27167
        },
27168
        {
27169
          name: 'underline',
27170
          text: 'Underline',
1441 ariadna 27171
          icon: 'underline',
27172
          shortcut: 'Meta+U'
1 efrain 27173
        },
27174
        {
27175
          name: 'strikethrough',
27176
          text: 'Strikethrough',
27177
          icon: 'strike-through'
27178
        },
27179
        {
27180
          name: 'subscript',
27181
          text: 'Subscript',
27182
          icon: 'subscript'
27183
        },
27184
        {
27185
          name: 'superscript',
27186
          text: 'Superscript',
27187
          icon: 'superscript'
27188
        }
27189
      ], (btn, _idx) => {
27190
        editor.ui.registry.addToggleButton(btn.name, {
27191
          tooltip: btn.text,
27192
          icon: btn.icon,
27193
          onSetup: onSetupStateToggle(editor, btn.name),
1441 ariadna 27194
          onAction: onActionToggleFormat(editor, btn.name),
27195
          shortcut: btn.shortcut
1 efrain 27196
        });
27197
      });
27198
      for (let i = 1; i <= 6; i++) {
27199
        const name = 'h' + i;
1441 ariadna 27200
        const shortcut = `Access+${ i }`;
1 efrain 27201
        editor.ui.registry.addToggleButton(name, {
27202
          text: name.toUpperCase(),
27203
          tooltip: 'Heading ' + i,
27204
          onSetup: onSetupStateToggle(editor, name),
1441 ariadna 27205
          onAction: onActionToggleFormat(editor, name),
27206
          shortcut
1 efrain 27207
        });
27208
      }
27209
    };
27210
    const registerCommandButtons = editor => {
27211
      global$1.each([
27212
        {
27213
          name: 'copy',
27214
          text: 'Copy',
27215
          action: 'Copy',
1441 ariadna 27216
          icon: 'copy',
27217
          context: 'any'
1 efrain 27218
        },
27219
        {
27220
          name: 'help',
27221
          text: 'Help',
27222
          action: 'mceHelp',
1441 ariadna 27223
          icon: 'help',
27224
          shortcut: 'Alt+0',
27225
          context: 'any'
1 efrain 27226
        },
27227
        {
27228
          name: 'selectall',
27229
          text: 'Select all',
27230
          action: 'SelectAll',
1441 ariadna 27231
          icon: 'select-all',
27232
          shortcut: 'Meta+A',
27233
          context: 'any'
1 efrain 27234
        },
27235
        {
27236
          name: 'newdocument',
27237
          text: 'New document',
27238
          action: 'mceNewDocument',
27239
          icon: 'new-document'
27240
        },
27241
        {
27242
          name: 'print',
27243
          text: 'Print',
27244
          action: 'mcePrint',
1441 ariadna 27245
          icon: 'print',
27246
          shortcut: 'Meta+P',
27247
          context: 'any'
1 efrain 27248
        }
27249
      ], btn => {
27250
        editor.ui.registry.addButton(btn.name, {
27251
          tooltip: btn.text,
27252
          icon: btn.icon,
1441 ariadna 27253
          onAction: onActionExecCommand(editor, btn.action),
27254
          shortcut: btn.shortcut,
27255
          context: btn.context
1 efrain 27256
        });
27257
      });
27258
      global$1.each([
27259
        {
27260
          name: 'cut',
27261
          text: 'Cut',
27262
          action: 'Cut',
27263
          icon: 'cut'
27264
        },
27265
        {
27266
          name: 'paste',
27267
          text: 'Paste',
27268
          action: 'Paste',
27269
          icon: 'paste'
27270
        },
27271
        {
27272
          name: 'removeformat',
27273
          text: 'Clear formatting',
27274
          action: 'RemoveFormat',
27275
          icon: 'remove-formatting'
27276
        },
27277
        {
27278
          name: 'remove',
27279
          text: 'Remove',
27280
          action: 'Delete',
27281
          icon: 'remove'
27282
        },
27283
        {
27284
          name: 'hr',
27285
          text: 'Horizontal line',
27286
          action: 'InsertHorizontalRule',
27287
          icon: 'horizontal-rule'
27288
        }
27289
      ], btn => {
27290
        editor.ui.registry.addButton(btn.name, {
27291
          tooltip: btn.text,
27292
          icon: btn.icon,
27293
          onSetup: onSetupEditableToggle(editor),
27294
          onAction: onActionExecCommand(editor, btn.action)
27295
        });
27296
      });
27297
    };
27298
    const registerCommandToggleButtons = editor => {
27299
      global$1.each([{
27300
          name: 'blockquote',
27301
          text: 'Blockquote',
27302
          action: 'mceBlockQuote',
27303
          icon: 'quote'
27304
        }], btn => {
27305
        editor.ui.registry.addToggleButton(btn.name, {
27306
          tooltip: btn.text,
27307
          icon: btn.icon,
27308
          onAction: onActionExecCommand(editor, btn.action),
27309
          onSetup: onSetupStateToggle(editor, btn.name)
27310
        });
27311
      });
27312
    };
27313
    const registerButtons$1 = editor => {
27314
      registerFormatButtons(editor);
27315
      registerCommandButtons(editor);
27316
      registerCommandToggleButtons(editor);
27317
    };
27318
    const registerMenuItems$2 = editor => {
27319
      global$1.each([
27320
        {
27321
          name: 'newdocument',
27322
          text: 'New document',
27323
          action: 'mceNewDocument',
27324
          icon: 'new-document'
27325
        },
27326
        {
27327
          name: 'copy',
27328
          text: 'Copy',
27329
          action: 'Copy',
27330
          icon: 'copy',
1441 ariadna 27331
          shortcut: 'Meta+C',
27332
          context: 'any'
1 efrain 27333
        },
27334
        {
27335
          name: 'selectall',
27336
          text: 'Select all',
27337
          action: 'SelectAll',
27338
          icon: 'select-all',
1441 ariadna 27339
          shortcut: 'Meta+A',
27340
          context: 'any'
1 efrain 27341
        },
27342
        {
27343
          name: 'print',
27344
          text: 'Print...',
27345
          action: 'mcePrint',
27346
          icon: 'print',
1441 ariadna 27347
          shortcut: 'Meta+P',
27348
          context: 'any'
1 efrain 27349
        }
27350
      ], menuitem => {
27351
        editor.ui.registry.addMenuItem(menuitem.name, {
27352
          text: menuitem.text,
27353
          icon: menuitem.icon,
27354
          shortcut: menuitem.shortcut,
1441 ariadna 27355
          onAction: onActionExecCommand(editor, menuitem.action),
27356
          context: menuitem.context
1 efrain 27357
        });
27358
      });
27359
      global$1.each([
27360
        {
27361
          name: 'bold',
27362
          text: 'Bold',
27363
          action: 'Bold',
27364
          icon: 'bold',
27365
          shortcut: 'Meta+B'
27366
        },
27367
        {
27368
          name: 'italic',
27369
          text: 'Italic',
27370
          action: 'Italic',
27371
          icon: 'italic',
27372
          shortcut: 'Meta+I'
27373
        },
27374
        {
27375
          name: 'underline',
27376
          text: 'Underline',
27377
          action: 'Underline',
27378
          icon: 'underline',
27379
          shortcut: 'Meta+U'
27380
        },
27381
        {
27382
          name: 'strikethrough',
27383
          text: 'Strikethrough',
27384
          action: 'Strikethrough',
27385
          icon: 'strike-through'
27386
        },
27387
        {
27388
          name: 'subscript',
27389
          text: 'Subscript',
27390
          action: 'Subscript',
27391
          icon: 'subscript'
27392
        },
27393
        {
27394
          name: 'superscript',
27395
          text: 'Superscript',
27396
          action: 'Superscript',
27397
          icon: 'superscript'
27398
        },
27399
        {
27400
          name: 'removeformat',
27401
          text: 'Clear formatting',
27402
          action: 'RemoveFormat',
27403
          icon: 'remove-formatting'
27404
        },
27405
        {
27406
          name: 'cut',
27407
          text: 'Cut',
27408
          action: 'Cut',
27409
          icon: 'cut',
27410
          shortcut: 'Meta+X'
27411
        },
27412
        {
27413
          name: 'paste',
27414
          text: 'Paste',
27415
          action: 'Paste',
27416
          icon: 'paste',
27417
          shortcut: 'Meta+V'
27418
        },
27419
        {
27420
          name: 'hr',
27421
          text: 'Horizontal line',
27422
          action: 'InsertHorizontalRule',
27423
          icon: 'horizontal-rule'
27424
        }
27425
      ], menuitem => {
27426
        editor.ui.registry.addMenuItem(menuitem.name, {
27427
          text: menuitem.text,
27428
          icon: menuitem.icon,
27429
          shortcut: menuitem.shortcut,
27430
          onSetup: onSetupEditableToggle(editor),
27431
          onAction: onActionExecCommand(editor, menuitem.action)
27432
        });
27433
      });
27434
      editor.ui.registry.addMenuItem('codeformat', {
27435
        text: 'Code',
27436
        icon: 'sourcecode',
27437
        onSetup: onSetupEditableToggle(editor),
27438
        onAction: onActionToggleFormat(editor, 'code')
27439
      });
27440
    };
27441
    const register$3 = editor => {
27442
      registerButtons$1(editor);
27443
      registerMenuItems$2(editor);
27444
    };
27445
 
27446
    const onSetupUndoRedoState = (editor, type) => onSetupEvent(editor, 'Undo Redo AddUndo TypingUndo ClearUndos SwitchMode', api => {
27447
      api.setEnabled(!editor.mode.isReadOnly() && editor.undoManager[type]());
27448
    });
27449
    const registerMenuItems$1 = editor => {
27450
      editor.ui.registry.addMenuItem('undo', {
27451
        text: 'Undo',
27452
        icon: 'undo',
27453
        shortcut: 'Meta+Z',
27454
        onSetup: onSetupUndoRedoState(editor, 'hasUndo'),
27455
        onAction: onActionExecCommand(editor, 'undo')
27456
      });
27457
      editor.ui.registry.addMenuItem('redo', {
27458
        text: 'Redo',
27459
        icon: 'redo',
27460
        shortcut: 'Meta+Y',
27461
        onSetup: onSetupUndoRedoState(editor, 'hasRedo'),
27462
        onAction: onActionExecCommand(editor, 'redo')
27463
      });
27464
    };
27465
    const registerButtons = editor => {
27466
      editor.ui.registry.addButton('undo', {
27467
        tooltip: 'Undo',
27468
        icon: 'undo',
27469
        enabled: false,
27470
        onSetup: onSetupUndoRedoState(editor, 'hasUndo'),
1441 ariadna 27471
        onAction: onActionExecCommand(editor, 'undo'),
27472
        shortcut: 'Meta+Z'
1 efrain 27473
      });
27474
      editor.ui.registry.addButton('redo', {
27475
        tooltip: 'Redo',
27476
        icon: 'redo',
27477
        enabled: false,
27478
        onSetup: onSetupUndoRedoState(editor, 'hasRedo'),
1441 ariadna 27479
        onAction: onActionExecCommand(editor, 'redo'),
27480
        shortcut: 'Meta+Y'
1 efrain 27481
      });
27482
    };
27483
    const register$2 = editor => {
27484
      registerMenuItems$1(editor);
27485
      registerButtons(editor);
27486
    };
27487
 
27488
    const onSetupVisualAidState = editor => onSetupEvent(editor, 'VisualAid', api => {
27489
      api.setActive(editor.hasVisual);
27490
    });
27491
    const registerMenuItems = editor => {
27492
      editor.ui.registry.addToggleMenuItem('visualaid', {
27493
        text: 'Visual aids',
27494
        onSetup: onSetupVisualAidState(editor),
1441 ariadna 27495
        onAction: onActionExecCommand(editor, 'mceToggleVisualAid'),
27496
        context: 'any'
1 efrain 27497
      });
27498
    };
27499
    const registerToolbarButton = editor => {
27500
      editor.ui.registry.addButton('visualaid', {
27501
        tooltip: 'Visual aids',
27502
        text: 'Visual aids',
1441 ariadna 27503
        onAction: onActionExecCommand(editor, 'mceToggleVisualAid'),
27504
        context: 'any'
1 efrain 27505
      });
27506
    };
27507
    const register$1 = editor => {
27508
      registerToolbarButton(editor);
27509
      registerMenuItems(editor);
27510
    };
27511
 
27512
    const setup$6 = (editor, backstage) => {
1441 ariadna 27513
      register$9(editor);
1 efrain 27514
      register$3(editor);
1441 ariadna 27515
      register$7(editor, backstage);
1 efrain 27516
      register$2(editor);
1441 ariadna 27517
      register$d(editor);
1 efrain 27518
      register$1(editor);
27519
      register$5(editor);
1441 ariadna 27520
      register$8(editor);
1 efrain 27521
      register$4(editor);
1441 ariadna 27522
      register$6(editor);
1 efrain 27523
    };
27524
 
27525
    const patchPipeConfig = config => isString(config) ? config.split(/[ ,]/) : config;
27526
    const option = name => editor => editor.options.get(name);
27527
    const register = editor => {
27528
      const registerOption = editor.options.register;
27529
      registerOption('contextmenu_avoid_overlap', {
27530
        processor: 'string',
27531
        default: ''
27532
      });
27533
      registerOption('contextmenu_never_use_native', {
27534
        processor: 'boolean',
27535
        default: false
27536
      });
27537
      registerOption('contextmenu', {
27538
        processor: value => {
27539
          if (value === false) {
27540
            return {
27541
              value: [],
27542
              valid: true
27543
            };
27544
          } else if (isString(value) || isArrayOf(value, isString)) {
27545
            return {
27546
              value: patchPipeConfig(value),
27547
              valid: true
27548
            };
27549
          } else {
27550
            return {
27551
              valid: false,
27552
              message: 'Must be false or a string.'
27553
            };
27554
          }
27555
        },
27556
        default: 'link linkchecker image editimage table spellchecker configurepermanentpen'
27557
      });
27558
    };
27559
    const shouldNeverUseNative = option('contextmenu_never_use_native');
27560
    const getAvoidOverlapSelector = option('contextmenu_avoid_overlap');
27561
    const isContextMenuDisabled = editor => getContextMenu(editor).length === 0;
27562
    const getContextMenu = editor => {
27563
      const contextMenus = editor.ui.registry.getAll().contextMenus;
27564
      const contextMenu = editor.options.get('contextmenu');
27565
      if (editor.options.isSet('contextmenu')) {
27566
        return contextMenu;
27567
      } else {
27568
        return filter$2(contextMenu, item => has$2(contextMenus, item));
27569
      }
27570
    };
27571
 
27572
    const nu = (x, y) => ({
27573
      type: 'makeshift',
27574
      x,
27575
      y
27576
    });
27577
    const transpose = (pos, dx, dy) => {
27578
      return nu(pos.x + dx, pos.y + dy);
27579
    };
27580
    const isTouchEvent$1 = e => e.type === 'longpress' || e.type.indexOf('touch') === 0;
27581
    const fromPageXY = e => {
27582
      if (isTouchEvent$1(e)) {
27583
        const touch = e.touches[0];
27584
        return nu(touch.pageX, touch.pageY);
27585
      } else {
27586
        return nu(e.pageX, e.pageY);
27587
      }
27588
    };
27589
    const fromClientXY = e => {
27590
      if (isTouchEvent$1(e)) {
27591
        const touch = e.touches[0];
27592
        return nu(touch.clientX, touch.clientY);
27593
      } else {
27594
        return nu(e.clientX, e.clientY);
27595
      }
27596
    };
27597
    const transposeContentAreaContainer = (element, pos) => {
1441 ariadna 27598
      const containerPos = global$8.DOM.getPos(element);
1 efrain 27599
      return transpose(pos, containerPos.x, containerPos.y);
27600
    };
27601
    const getPointAnchor = (editor, e) => {
27602
      if (e.type === 'contextmenu' || e.type === 'longpress') {
27603
        if (editor.inline) {
27604
          return fromPageXY(e);
27605
        } else {
27606
          return transposeContentAreaContainer(editor.getContentAreaContainer(), fromClientXY(e));
27607
        }
27608
      } else {
27609
        return getSelectionAnchor(editor);
27610
      }
27611
    };
27612
    const getSelectionAnchor = editor => {
27613
      return {
27614
        type: 'selection',
27615
        root: SugarElement.fromDom(editor.selection.getNode())
27616
      };
27617
    };
27618
    const getNodeAnchor = editor => ({
27619
      type: 'node',
27620
      node: Optional.some(SugarElement.fromDom(editor.selection.getNode())),
27621
      root: SugarElement.fromDom(editor.getBody())
27622
    });
27623
    const getAnchorSpec$1 = (editor, e, anchorType) => {
27624
      switch (anchorType) {
27625
      case 'node':
27626
        return getNodeAnchor(editor);
27627
      case 'point':
27628
        return getPointAnchor(editor, e);
27629
      case 'selection':
27630
        return getSelectionAnchor(editor);
27631
      }
27632
    };
27633
 
27634
    const initAndShow$1 = (editor, e, buildMenu, backstage, contextmenu, anchorType) => {
27635
      const items = buildMenu();
27636
      const anchorSpec = getAnchorSpec$1(editor, e, anchorType);
27637
      build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
27638
        isHorizontalMenu: false,
27639
        search: Optional.none()
27640
      }).map(menuData => {
27641
        e.preventDefault();
27642
        InlineView.showMenuAt(contextmenu, { anchor: anchorSpec }, {
27643
          menu: { markers: markers('normal') },
27644
          data: menuData
27645
        });
27646
      });
27647
    };
27648
 
27649
    const layouts = {
27650
      onLtr: () => [
27651
        south$2,
27652
        southeast$2,
27653
        southwest$2,
27654
        northeast$2,
27655
        northwest$2,
27656
        north$2,
27657
        north,
27658
        south,
27659
        northeast,
27660
        southeast,
27661
        northwest,
27662
        southwest
27663
      ],
27664
      onRtl: () => [
27665
        south$2,
27666
        southwest$2,
27667
        southeast$2,
27668
        northwest$2,
27669
        northeast$2,
27670
        north$2,
27671
        north,
27672
        south,
27673
        northwest,
27674
        southwest,
27675
        northeast,
27676
        southeast
27677
      ]
27678
    };
27679
    const bubbleSize = 12;
27680
    const bubbleAlignments = {
27681
      valignCentre: [],
27682
      alignCentre: [],
27683
      alignLeft: ['tox-pop--align-left'],
27684
      alignRight: ['tox-pop--align-right'],
27685
      right: ['tox-pop--right'],
27686
      left: ['tox-pop--left'],
27687
      bottom: ['tox-pop--bottom'],
27688
      top: ['tox-pop--top']
27689
    };
27690
    const isTouchWithinSelection = (editor, e) => {
27691
      const selection = editor.selection;
27692
      if (selection.isCollapsed() || e.touches.length < 1) {
27693
        return false;
27694
      } else {
27695
        const touch = e.touches[0];
27696
        const rng = selection.getRng();
27697
        const rngRectOpt = getFirstRect(editor.getWin(), SimSelection.domRange(rng));
27698
        return rngRectOpt.exists(rngRect => rngRect.left <= touch.clientX && rngRect.right >= touch.clientX && rngRect.top <= touch.clientY && rngRect.bottom >= touch.clientY);
27699
      }
27700
    };
27701
    const setupiOSOverrides = editor => {
27702
      const originalSelection = editor.selection.getRng();
27703
      const selectionReset = () => {
27704
        global$9.setEditorTimeout(editor, () => {
27705
          editor.selection.setRng(originalSelection);
27706
        }, 10);
27707
        unbindEventListeners();
27708
      };
27709
      editor.once('touchend', selectionReset);
27710
      const preventMousedown = e => {
27711
        e.preventDefault();
27712
        e.stopImmediatePropagation();
27713
      };
27714
      editor.on('mousedown', preventMousedown, true);
27715
      const clearSelectionReset = () => unbindEventListeners();
27716
      editor.once('longpresscancel', clearSelectionReset);
27717
      const unbindEventListeners = () => {
27718
        editor.off('touchend', selectionReset);
27719
        editor.off('longpresscancel', clearSelectionReset);
27720
        editor.off('mousedown', preventMousedown);
27721
      };
27722
    };
27723
    const getAnchorSpec = (editor, e, anchorType) => {
27724
      const anchorSpec = getAnchorSpec$1(editor, e, anchorType);
27725
      const bubbleYOffset = anchorType === 'point' ? bubbleSize : 0;
27726
      return {
27727
        bubble: nu$5(0, bubbleYOffset, bubbleAlignments),
27728
        layouts,
27729
        overrides: {
27730
          maxWidthFunction: expandable(),
27731
          maxHeightFunction: expandable$1()
27732
        },
27733
        ...anchorSpec
27734
      };
27735
    };
27736
    const show = (editor, e, items, backstage, contextmenu, anchorType, highlightImmediately) => {
27737
      const anchorSpec = getAnchorSpec(editor, e, anchorType);
27738
      build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
27739
        isHorizontalMenu: true,
27740
        search: Optional.none()
27741
      }).map(menuData => {
27742
        e.preventDefault();
27743
        const highlightOnOpen = highlightImmediately ? HighlightOnOpen.HighlightMenuAndItem : HighlightOnOpen.HighlightNone;
27744
        InlineView.showMenuWithinBounds(contextmenu, { anchor: anchorSpec }, {
27745
          menu: {
27746
            markers: markers('normal'),
27747
            highlightOnOpen
27748
          },
27749
          data: menuData,
27750
          type: 'horizontal'
27751
        }, () => Optional.some(getContextToolbarBounds(editor, backstage.shared, anchorType === 'node' ? 'node' : 'selection')));
27752
        editor.dispatch(hideContextToolbarEvent);
27753
      });
27754
    };
27755
    const initAndShow = (editor, e, buildMenu, backstage, contextmenu, anchorType) => {
1441 ariadna 27756
      const detection = detect$1();
1 efrain 27757
      const isiOS = detection.os.isiOS();
27758
      const isMacOS = detection.os.isMacOS();
27759
      const isAndroid = detection.os.isAndroid();
27760
      const isTouch = detection.deviceType.isTouch();
27761
      const shouldHighlightImmediately = () => !(isAndroid || isiOS || isMacOS && isTouch);
27762
      const open = () => {
27763
        const items = buildMenu();
27764
        show(editor, e, items, backstage, contextmenu, anchorType, shouldHighlightImmediately());
27765
      };
27766
      if ((isMacOS || isiOS) && anchorType !== 'node') {
27767
        const openiOS = () => {
27768
          setupiOSOverrides(editor);
27769
          open();
27770
        };
27771
        if (isTouchWithinSelection(editor, e)) {
27772
          openiOS();
27773
        } else {
27774
          editor.once('selectionchange', openiOS);
27775
          editor.once('touchend', () => editor.off('selectionchange', openiOS));
27776
        }
27777
      } else {
27778
        open();
27779
      }
27780
    };
27781
 
27782
    const isSeparator = item => isString(item) ? item === '|' : item.type === 'separator';
27783
    const separator = { type: 'separator' };
27784
    const makeContextItem = item => {
27785
      const commonMenuItem = item => ({
27786
        text: item.text,
27787
        icon: item.icon,
27788
        enabled: item.enabled,
27789
        shortcut: item.shortcut
27790
      });
27791
      if (isString(item)) {
27792
        return item;
27793
      } else {
27794
        switch (item.type) {
27795
        case 'separator':
27796
          return separator;
27797
        case 'submenu':
27798
          return {
27799
            type: 'nestedmenuitem',
27800
            ...commonMenuItem(item),
27801
            getSubmenuItems: () => {
27802
              const items = item.getSubmenuItems();
27803
              if (isString(items)) {
27804
                return items;
27805
              } else {
27806
                return map$2(items, makeContextItem);
27807
              }
27808
            }
27809
          };
27810
        default:
27811
          const commonItem = item;
27812
          return {
27813
            type: 'menuitem',
27814
            ...commonMenuItem(commonItem),
27815
            onAction: noarg(commonItem.onAction)
27816
          };
27817
        }
27818
      }
27819
    };
27820
    const addContextMenuGroup = (xs, groupItems) => {
27821
      if (groupItems.length === 0) {
27822
        return xs;
27823
      }
27824
      const lastMenuItem = last$1(xs).filter(item => !isSeparator(item));
27825
      const before = lastMenuItem.fold(() => [], _ => [separator]);
27826
      return xs.concat(before).concat(groupItems).concat([separator]);
27827
    };
27828
    const generateContextMenu = (contextMenus, menuConfig, selectedElement) => {
27829
      const sections = foldl(menuConfig, (acc, name) => {
1441 ariadna 27830
        return get$h(contextMenus, name.toLowerCase()).map(menu => {
1 efrain 27831
          const items = menu.update(selectedElement);
27832
          if (isString(items) && isNotEmpty(trim$1(items))) {
27833
            return addContextMenuGroup(acc, items.split(' '));
27834
          } else if (isArray(items) && items.length > 0) {
27835
            const allItems = map$2(items, makeContextItem);
27836
            return addContextMenuGroup(acc, allItems);
27837
          } else {
27838
            return acc;
27839
          }
27840
        }).getOrThunk(() => acc.concat([name]));
27841
      }, []);
27842
      if (sections.length > 0 && isSeparator(sections[sections.length - 1])) {
27843
        sections.pop();
27844
      }
27845
      return sections;
27846
    };
27847
    const isNativeOverrideKeyEvent = (editor, e) => e.ctrlKey && !shouldNeverUseNative(editor);
27848
    const isTouchEvent = e => e.type === 'longpress' || has$2(e, 'touches');
27849
    const isTriggeredByKeyboard = (editor, e) => !isTouchEvent(e) && (e.button !== 2 || e.target === editor.getBody() && e.pointerType === '');
27850
    const getSelectedElement = (editor, e) => isTriggeredByKeyboard(editor, e) ? editor.selection.getStart(true) : e.target;
27851
    const getAnchorType = (editor, e) => {
27852
      const selector = getAvoidOverlapSelector(editor);
27853
      const anchorType = isTriggeredByKeyboard(editor, e) ? 'selection' : 'point';
27854
      if (isNotEmpty(selector)) {
27855
        const target = getSelectedElement(editor, e);
27856
        const selectorExists = closest(SugarElement.fromDom(target), selector);
27857
        return selectorExists ? 'node' : anchorType;
27858
      } else {
27859
        return anchorType;
27860
      }
27861
    };
27862
    const setup$5 = (editor, lazySink, backstage) => {
1441 ariadna 27863
      const detection = detect$1();
1 efrain 27864
      const isTouch = detection.deviceType.isTouch;
27865
      const contextmenu = build$1(InlineView.sketch({
27866
        dom: { tag: 'div' },
27867
        lazySink,
27868
        onEscape: () => editor.focus(),
27869
        onShow: () => backstage.setContextMenuState(true),
27870
        onHide: () => backstage.setContextMenuState(false),
27871
        fireDismissalEventInstead: {},
27872
        inlineBehaviours: derive$1([config('dismissContextMenu', [run$1(dismissRequested(), (comp, _se) => {
27873
              Sandboxing.close(comp);
27874
              editor.focus();
27875
            })])])
27876
      }));
27877
      const hideContextMenu = () => InlineView.hide(contextmenu);
27878
      const showContextMenu = e => {
27879
        if (shouldNeverUseNative(editor)) {
27880
          e.preventDefault();
27881
        }
27882
        if (isNativeOverrideKeyEvent(editor, e) || isContextMenuDisabled(editor)) {
27883
          return;
27884
        }
27885
        const anchorType = getAnchorType(editor, e);
27886
        const buildMenu = () => {
27887
          const selectedElement = getSelectedElement(editor, e);
27888
          const registry = editor.ui.registry.getAll();
27889
          const menuConfig = getContextMenu(editor);
27890
          return generateContextMenu(registry.contextMenus, menuConfig, selectedElement);
27891
        };
27892
        const initAndShow$2 = isTouch() ? initAndShow : initAndShow$1;
27893
        initAndShow$2(editor, e, buildMenu, backstage, contextmenu, anchorType);
27894
      };
27895
      editor.on('init', () => {
27896
        const hideEvents = 'ResizeEditor ScrollContent ScrollWindow longpresscancel' + (isTouch() ? '' : ' ResizeWindow');
27897
        editor.on(hideEvents, hideContextMenu);
27898
        editor.on('longpress contextmenu', showContextMenu);
27899
      });
27900
    };
27901
 
27902
    const adt = Adt.generate([
27903
      {
27904
        offset: [
27905
          'x',
27906
          'y'
27907
        ]
27908
      },
27909
      {
27910
        absolute: [
27911
          'x',
27912
          'y'
27913
        ]
27914
      },
27915
      {
27916
        fixed: [
27917
          'x',
27918
          'y'
27919
        ]
27920
      }
27921
    ]);
27922
    const subtract = change => point => point.translate(-change.left, -change.top);
27923
    const add = change => point => point.translate(change.left, change.top);
27924
    const transform = changes => (x, y) => foldl(changes, (rest, f) => f(rest), SugarPosition(x, y));
27925
    const asFixed = (coord, scroll, origin) => coord.fold(transform([
27926
      add(origin),
27927
      subtract(scroll)
27928
    ]), transform([subtract(scroll)]), transform([]));
27929
    const asAbsolute = (coord, scroll, origin) => coord.fold(transform([add(origin)]), transform([]), transform([add(scroll)]));
27930
    const asOffset = (coord, scroll, origin) => coord.fold(transform([]), transform([subtract(origin)]), transform([
27931
      add(scroll),
27932
      subtract(origin)
27933
    ]));
27934
    const withinRange = (coord1, coord2, xRange, yRange, scroll, origin) => {
27935
      const a1 = asAbsolute(coord1, scroll, origin);
27936
      const a2 = asAbsolute(coord2, scroll, origin);
27937
      return Math.abs(a1.left - a2.left) <= xRange && Math.abs(a1.top - a2.top) <= yRange;
27938
    };
27939
    const getDeltas = (coord1, coord2, xRange, yRange, scroll, origin) => {
27940
      const a1 = asAbsolute(coord1, scroll, origin);
27941
      const a2 = asAbsolute(coord2, scroll, origin);
27942
      const left = Math.abs(a1.left - a2.left);
27943
      const top = Math.abs(a1.top - a2.top);
27944
      return SugarPosition(left, top);
27945
    };
27946
    const toStyles = (coord, scroll, origin) => {
27947
      const stylesOpt = coord.fold((x, y) => ({
27948
        position: Optional.some('absolute'),
27949
        left: Optional.some(x + 'px'),
27950
        top: Optional.some(y + 'px')
27951
      }), (x, y) => ({
27952
        position: Optional.some('absolute'),
27953
        left: Optional.some(x - origin.left + 'px'),
27954
        top: Optional.some(y - origin.top + 'px')
27955
      }), (x, y) => ({
27956
        position: Optional.some('fixed'),
27957
        left: Optional.some(x + 'px'),
27958
        top: Optional.some(y + 'px')
27959
      }));
27960
      return {
27961
        right: Optional.none(),
27962
        bottom: Optional.none(),
27963
        ...stylesOpt
27964
      };
27965
    };
27966
    const translate = (coord, deltaX, deltaY) => coord.fold((x, y) => offset(x + deltaX, y + deltaY), (x, y) => absolute(x + deltaX, y + deltaY), (x, y) => fixed(x + deltaX, y + deltaY));
27967
    const absorb = (partialCoord, originalCoord, scroll, origin) => {
27968
      const absorbOne = (stencil, nu) => (optX, optY) => {
27969
        const original = stencil(originalCoord, scroll, origin);
27970
        return nu(optX.getOr(original.left), optY.getOr(original.top));
27971
      };
27972
      return partialCoord.fold(absorbOne(asOffset, offset), absorbOne(asAbsolute, absolute), absorbOne(asFixed, fixed));
27973
    };
27974
    const offset = adt.offset;
27975
    const absolute = adt.absolute;
27976
    const fixed = adt.fixed;
27977
 
27978
    const parseAttrToInt = (element, name) => {
1441 ariadna 27979
      const value = get$g(element, name);
1 efrain 27980
      return isUndefined(value) ? NaN : parseInt(value, 10);
27981
    };
1441 ariadna 27982
    const get$1 = (component, snapsInfo) => {
1 efrain 27983
      const element = component.element;
27984
      const x = parseAttrToInt(element, snapsInfo.leftAttr);
27985
      const y = parseAttrToInt(element, snapsInfo.topAttr);
27986
      return isNaN(x) || isNaN(y) ? Optional.none() : Optional.some(SugarPosition(x, y));
27987
    };
27988
    const set = (component, snapsInfo, pt) => {
27989
      const element = component.element;
27990
      set$9(element, snapsInfo.leftAttr, pt.left + 'px');
27991
      set$9(element, snapsInfo.topAttr, pt.top + 'px');
27992
    };
27993
    const clear = (component, snapsInfo) => {
27994
      const element = component.element;
1441 ariadna 27995
      remove$8(element, snapsInfo.leftAttr);
27996
      remove$8(element, snapsInfo.topAttr);
1 efrain 27997
    };
27998
 
1441 ariadna 27999
    const getCoords = (component, snapInfo, coord, delta) => get$1(component, snapInfo).fold(() => coord, fixed$1 => fixed(fixed$1.left + delta.left, fixed$1.top + delta.top));
1 efrain 28000
    const moveOrSnap = (component, snapInfo, coord, delta, scroll, origin) => {
28001
      const newCoord = getCoords(component, snapInfo, coord, delta);
28002
      const snap = snapInfo.mustSnap ? findClosestSnap(component, snapInfo, newCoord, scroll, origin) : findSnap(component, snapInfo, newCoord, scroll, origin);
28003
      const fixedCoord = asFixed(newCoord, scroll, origin);
28004
      set(component, snapInfo, fixedCoord);
28005
      return snap.fold(() => ({
28006
        coord: fixed(fixedCoord.left, fixedCoord.top),
28007
        extra: Optional.none()
28008
      }), spanned => ({
28009
        coord: spanned.output,
28010
        extra: spanned.extra
28011
      }));
28012
    };
28013
    const stopDrag = (component, snapInfo) => {
28014
      clear(component, snapInfo);
28015
    };
28016
    const findMatchingSnap = (snaps, newCoord, scroll, origin) => findMap(snaps, snap => {
28017
      const sensor = snap.sensor;
28018
      const inRange = withinRange(newCoord, sensor, snap.range.left, snap.range.top, scroll, origin);
28019
      return inRange ? Optional.some({
28020
        output: absorb(snap.output, newCoord, scroll, origin),
28021
        extra: snap.extra
28022
      }) : Optional.none();
28023
    });
28024
    const findClosestSnap = (component, snapInfo, newCoord, scroll, origin) => {
28025
      const snaps = snapInfo.getSnapPoints(component);
28026
      const matchSnap = findMatchingSnap(snaps, newCoord, scroll, origin);
28027
      return matchSnap.orThunk(() => {
28028
        const bestSnap = foldl(snaps, (acc, snap) => {
28029
          const sensor = snap.sensor;
28030
          const deltas = getDeltas(newCoord, sensor, snap.range.left, snap.range.top, scroll, origin);
28031
          return acc.deltas.fold(() => ({
28032
            deltas: Optional.some(deltas),
28033
            snap: Optional.some(snap)
28034
          }), bestDeltas => {
28035
            const currAvg = (deltas.left + deltas.top) / 2;
28036
            const bestAvg = (bestDeltas.left + bestDeltas.top) / 2;
28037
            if (currAvg <= bestAvg) {
28038
              return {
28039
                deltas: Optional.some(deltas),
28040
                snap: Optional.some(snap)
28041
              };
28042
            } else {
28043
              return acc;
28044
            }
28045
          });
28046
        }, {
28047
          deltas: Optional.none(),
28048
          snap: Optional.none()
28049
        });
28050
        return bestSnap.snap.map(snap => ({
28051
          output: absorb(snap.output, newCoord, scroll, origin),
28052
          extra: snap.extra
28053
        }));
28054
      });
28055
    };
28056
    const findSnap = (component, snapInfo, newCoord, scroll, origin) => {
28057
      const snaps = snapInfo.getSnapPoints(component);
28058
      return findMatchingSnap(snaps, newCoord, scroll, origin);
28059
    };
28060
    const snapTo$1 = (snap, scroll, origin) => ({
28061
      coord: absorb(snap.output, snap.output, scroll, origin),
28062
      extra: snap.extra
28063
    });
28064
 
28065
    const snapTo = (component, dragConfig, _state, snap) => {
28066
      const target = dragConfig.getTarget(component.element);
28067
      if (dragConfig.repositionTarget) {
28068
        const doc = owner$4(component.element);
1441 ariadna 28069
        const scroll = get$c(doc);
1 efrain 28070
        const origin = getOrigin(target);
28071
        const snapPin = snapTo$1(snap, scroll, origin);
28072
        const styles = toStyles(snapPin.coord, scroll, origin);
28073
        setOptions(target, styles);
28074
      }
28075
    };
28076
 
28077
    var DraggingApis = /*#__PURE__*/Object.freeze({
28078
        __proto__: null,
28079
        snapTo: snapTo
28080
    });
28081
 
28082
    const initialAttribute = 'data-initial-z-index';
28083
    const resetZIndex = blocker => {
28084
      parent(blocker.element).filter(isElement$1).each(root => {
1441 ariadna 28085
        getOpt(root, initialAttribute).fold(() => remove$7(root, 'z-index'), zIndex => set$8(root, 'z-index', zIndex));
28086
        remove$8(root, initialAttribute);
1 efrain 28087
      });
28088
    };
28089
    const changeZIndex = blocker => {
28090
      parent(blocker.element).filter(isElement$1).each(root => {
28091
        getRaw(root, 'z-index').each(zindex => {
28092
          set$9(root, initialAttribute, zindex);
28093
        });
1441 ariadna 28094
        set$8(root, 'z-index', get$f(blocker.element, 'z-index'));
1 efrain 28095
      });
28096
    };
28097
    const instigate = (anyComponent, blocker) => {
28098
      anyComponent.getSystem().addToGui(blocker);
28099
      changeZIndex(blocker);
28100
    };
28101
    const discard = blocker => {
28102
      resetZIndex(blocker);
28103
      blocker.getSystem().removeFromGui(blocker);
28104
    };
28105
    const createComponent = (component, blockerClass, blockerEvents) => component.getSystem().build(Container.sketch({
28106
      dom: {
28107
        styles: {
28108
          'left': '0px',
28109
          'top': '0px',
28110
          'width': '100%',
28111
          'height': '100%',
28112
          'position': 'fixed',
28113
          'z-index': '1000000000000000'
28114
        },
28115
        classes: [blockerClass]
28116
      },
28117
      events: blockerEvents
28118
    }));
28119
 
28120
    var SnapSchema = optionObjOf('snaps', [
28121
      required$1('getSnapPoints'),
28122
      onHandler('onSensor'),
28123
      required$1('leftAttr'),
28124
      required$1('topAttr'),
28125
      defaulted('lazyViewport', win),
28126
      defaulted('mustSnap', false)
28127
    ]);
28128
 
28129
    const schema$6 = [
28130
      defaulted('useFixed', never),
28131
      required$1('blockerClass'),
28132
      defaulted('getTarget', identity),
28133
      defaulted('onDrag', noop),
28134
      defaulted('repositionTarget', true),
28135
      defaulted('onDrop', noop),
28136
      defaultedFunction('getBounds', win),
28137
      SnapSchema
28138
    ];
28139
 
28140
    const getCurrentCoord = target => lift3(getRaw(target, 'left'), getRaw(target, 'top'), getRaw(target, 'position'), (left, top, position) => {
28141
      const nu = position === 'fixed' ? fixed : offset;
28142
      return nu(parseInt(left, 10), parseInt(top, 10));
28143
    }).getOrThunk(() => {
28144
      const location = absolute$3(target);
28145
      return absolute(location.left, location.top);
28146
    });
28147
    const clampCoords = (component, coords, scroll, origin, startData) => {
28148
      const bounds = startData.bounds;
28149
      const absoluteCoord = asAbsolute(coords, scroll, origin);
28150
      const newX = clamp(absoluteCoord.left, bounds.x, bounds.x + bounds.width - startData.width);
28151
      const newY = clamp(absoluteCoord.top, bounds.y, bounds.y + bounds.height - startData.height);
28152
      const newCoords = absolute(newX, newY);
28153
      return coords.fold(() => {
28154
        const offset$1 = asOffset(newCoords, scroll, origin);
28155
        return offset(offset$1.left, offset$1.top);
28156
      }, constant$1(newCoords), () => {
28157
        const fixed$1 = asFixed(newCoords, scroll, origin);
28158
        return fixed(fixed$1.left, fixed$1.top);
28159
      });
28160
    };
28161
    const calcNewCoord = (component, optSnaps, currentCoord, scroll, origin, delta, startData) => {
28162
      const newCoord = optSnaps.fold(() => {
28163
        const translated = translate(currentCoord, delta.left, delta.top);
28164
        const fixedCoord = asFixed(translated, scroll, origin);
28165
        return fixed(fixedCoord.left, fixedCoord.top);
28166
      }, snapInfo => {
28167
        const snapping = moveOrSnap(component, snapInfo, currentCoord, delta, scroll, origin);
28168
        snapping.extra.each(extra => {
28169
          snapInfo.onSensor(component, extra);
28170
        });
28171
        return snapping.coord;
28172
      });
28173
      return clampCoords(component, newCoord, scroll, origin, startData);
28174
    };
28175
    const dragBy = (component, dragConfig, startData, delta) => {
28176
      const target = dragConfig.getTarget(component.element);
28177
      if (dragConfig.repositionTarget) {
28178
        const doc = owner$4(component.element);
1441 ariadna 28179
        const scroll = get$c(doc);
1 efrain 28180
        const origin = getOrigin(target);
28181
        const currentCoord = getCurrentCoord(target);
28182
        const newCoord = calcNewCoord(component, dragConfig.snaps, currentCoord, scroll, origin, delta, startData);
28183
        const styles = toStyles(newCoord, scroll, origin);
28184
        setOptions(target, styles);
28185
      }
28186
      dragConfig.onDrag(component, target, delta);
28187
    };
28188
 
28189
    const calcStartData = (dragConfig, comp) => ({
28190
      bounds: dragConfig.getBounds(),
28191
      height: getOuter$2(comp.element),
28192
      width: getOuter$1(comp.element)
28193
    });
28194
    const move = (component, dragConfig, dragState, dragMode, event) => {
28195
      const delta = dragState.update(dragMode, event);
28196
      const dragStartData = dragState.getStartData().getOrThunk(() => calcStartData(dragConfig, component));
28197
      delta.each(dlt => {
28198
        dragBy(component, dragConfig, dragStartData, dlt);
28199
      });
28200
    };
28201
    const stop = (component, blocker, dragConfig, dragState) => {
28202
      blocker.each(discard);
28203
      dragConfig.snaps.each(snapInfo => {
28204
        stopDrag(component, snapInfo);
28205
      });
28206
      const target = dragConfig.getTarget(component.element);
28207
      dragState.reset();
28208
      dragConfig.onDrop(component, target);
28209
    };
28210
    const handlers = events => (dragConfig, dragState) => {
28211
      const updateStartState = comp => {
28212
        dragState.setStartData(calcStartData(dragConfig, comp));
28213
      };
28214
      return derive$2([
28215
        run$1(windowScroll(), comp => {
28216
          dragState.getStartData().each(() => updateStartState(comp));
28217
        }),
28218
        ...events(dragConfig, dragState, updateStartState)
28219
      ]);
28220
    };
28221
 
28222
    const init$3 = dragApi => derive$2([
28223
      run$1(mousedown(), dragApi.forceDrop),
28224
      run$1(mouseup(), dragApi.drop),
28225
      run$1(mousemove(), (comp, simulatedEvent) => {
28226
        dragApi.move(simulatedEvent.event);
28227
      }),
28228
      run$1(mouseout(), dragApi.delayDrop)
28229
    ]);
28230
 
28231
    const getData$1 = event => Optional.from(SugarPosition(event.x, event.y));
28232
    const getDelta$1 = (old, nu) => SugarPosition(nu.left - old.left, nu.top - old.top);
28233
 
28234
    var MouseData = /*#__PURE__*/Object.freeze({
28235
        __proto__: null,
28236
        getData: getData$1,
28237
        getDelta: getDelta$1
28238
    });
28239
 
28240
    const events$3 = (dragConfig, dragState, updateStartState) => [run$1(mousedown(), (component, simulatedEvent) => {
28241
        const raw = simulatedEvent.event.raw;
28242
        if (raw.button !== 0) {
28243
          return;
28244
        }
28245
        simulatedEvent.stop();
28246
        const stop$1 = () => stop(component, Optional.some(blocker), dragConfig, dragState);
28247
        const delayDrop = DelayedFunction(stop$1, 200);
28248
        const dragApi = {
28249
          drop: stop$1,
28250
          delayDrop: delayDrop.schedule,
28251
          forceDrop: stop$1,
28252
          move: event => {
28253
            delayDrop.cancel();
28254
            move(component, dragConfig, dragState, MouseData, event);
28255
          }
28256
        };
28257
        const blocker = createComponent(component, dragConfig.blockerClass, init$3(dragApi));
28258
        const start = () => {
28259
          updateStartState(component);
28260
          instigate(component, blocker);
28261
        };
28262
        start();
28263
      })];
28264
    const schema$5 = [
28265
      ...schema$6,
28266
      output$1('dragger', { handlers: handlers(events$3) })
28267
    ];
28268
 
28269
    const init$2 = dragApi => derive$2([
28270
      run$1(touchstart(), dragApi.forceDrop),
28271
      run$1(touchend(), dragApi.drop),
28272
      run$1(touchcancel(), dragApi.drop),
28273
      run$1(touchmove(), (comp, simulatedEvent) => {
28274
        dragApi.move(simulatedEvent.event);
28275
      })
28276
    ]);
28277
 
28278
    const getDataFrom = touches => {
28279
      const touch = touches[0];
28280
      return Optional.some(SugarPosition(touch.clientX, touch.clientY));
28281
    };
28282
    const getData = event => {
28283
      const raw = event.raw;
28284
      const touches = raw.touches;
28285
      return touches.length === 1 ? getDataFrom(touches) : Optional.none();
28286
    };
28287
    const getDelta = (old, nu) => SugarPosition(nu.left - old.left, nu.top - old.top);
28288
 
28289
    var TouchData = /*#__PURE__*/Object.freeze({
28290
        __proto__: null,
28291
        getData: getData,
28292
        getDelta: getDelta
28293
    });
28294
 
28295
    const events$2 = (dragConfig, dragState, updateStartState) => {
1441 ariadna 28296
      const blockerSingleton = value$4();
1 efrain 28297
      const stopBlocking = component => {
28298
        stop(component, blockerSingleton.get(), dragConfig, dragState);
28299
        blockerSingleton.clear();
28300
      };
28301
      return [
28302
        run$1(touchstart(), (component, simulatedEvent) => {
28303
          simulatedEvent.stop();
28304
          const stop = () => stopBlocking(component);
28305
          const dragApi = {
28306
            drop: stop,
28307
            delayDrop: noop,
28308
            forceDrop: stop,
28309
            move: event => {
28310
              move(component, dragConfig, dragState, TouchData, event);
28311
            }
28312
          };
28313
          const blocker = createComponent(component, dragConfig.blockerClass, init$2(dragApi));
28314
          blockerSingleton.set(blocker);
28315
          const start = () => {
28316
            updateStartState(component);
28317
            instigate(component, blocker);
28318
          };
28319
          start();
28320
        }),
28321
        run$1(touchmove(), (component, simulatedEvent) => {
28322
          simulatedEvent.stop();
28323
          move(component, dragConfig, dragState, TouchData, simulatedEvent.event);
28324
        }),
28325
        run$1(touchend(), (component, simulatedEvent) => {
28326
          simulatedEvent.stop();
28327
          stopBlocking(component);
28328
        }),
28329
        run$1(touchcancel(), stopBlocking)
28330
      ];
28331
    };
28332
    const schema$4 = [
28333
      ...schema$6,
28334
      output$1('dragger', { handlers: handlers(events$2) })
28335
    ];
28336
 
28337
    const events$1 = (dragConfig, dragState, updateStartState) => [
28338
      ...events$3(dragConfig, dragState, updateStartState),
28339
      ...events$2(dragConfig, dragState, updateStartState)
28340
    ];
28341
    const schema$3 = [
28342
      ...schema$6,
28343
      output$1('dragger', { handlers: handlers(events$1) })
28344
    ];
28345
 
28346
    const mouse = schema$5;
28347
    const touch = schema$4;
28348
    const mouseOrTouch = schema$3;
28349
 
28350
    var DraggingBranches = /*#__PURE__*/Object.freeze({
28351
        __proto__: null,
28352
        mouse: mouse,
28353
        touch: touch,
28354
        mouseOrTouch: mouseOrTouch
28355
    });
28356
 
28357
    const init$1 = () => {
28358
      let previous = Optional.none();
28359
      let startData = Optional.none();
28360
      const reset = () => {
28361
        previous = Optional.none();
28362
        startData = Optional.none();
28363
      };
28364
      const calculateDelta = (mode, nu) => {
28365
        const result = previous.map(old => mode.getDelta(old, nu));
28366
        previous = Optional.some(nu);
28367
        return result;
28368
      };
28369
      const update = (mode, dragEvent) => mode.getData(dragEvent).bind(nuData => calculateDelta(mode, nuData));
28370
      const setStartData = data => {
28371
        startData = Optional.some(data);
28372
      };
28373
      const getStartData = () => startData;
28374
      const readState = constant$1({});
1441 ariadna 28375
      return nu$7({
1 efrain 28376
        readState,
28377
        reset,
28378
        update,
28379
        getStartData,
28380
        setStartData
28381
      });
28382
    };
28383
 
28384
    var DragState = /*#__PURE__*/Object.freeze({
28385
        __proto__: null,
28386
        init: init$1
28387
    });
28388
 
28389
    const Dragging = createModes({
28390
      branchKey: 'mode',
28391
      branches: DraggingBranches,
28392
      name: 'dragging',
28393
      active: {
28394
        events: (dragConfig, dragState) => {
28395
          const dragger = dragConfig.dragger;
28396
          return dragger.handlers(dragConfig, dragState);
28397
        }
28398
      },
28399
      extra: {
28400
        snap: sConfig => ({
28401
          sensor: sConfig.sensor,
28402
          range: sConfig.range,
28403
          output: sConfig.output,
28404
          extra: Optional.from(sConfig.extra)
28405
        })
28406
      },
28407
      state: DragState,
28408
      apis: DraggingApis
28409
    });
28410
 
28411
    const snapWidth = 40;
28412
    const snapOffset = snapWidth / 2;
28413
    const calcSnap = (selectorOpt, td, x, y, width, height) => selectorOpt.fold(() => Dragging.snap({
28414
      sensor: absolute(x - snapOffset, y - snapOffset),
28415
      range: SugarPosition(width, height),
28416
      output: absolute(Optional.some(x), Optional.some(y)),
28417
      extra: { td }
28418
    }), selectorHandle => {
28419
      const sensorLeft = x - snapOffset;
28420
      const sensorTop = y - snapOffset;
28421
      const sensorWidth = snapWidth;
28422
      const sensorHeight = snapWidth;
28423
      const rect = selectorHandle.element.dom.getBoundingClientRect();
28424
      return Dragging.snap({
28425
        sensor: absolute(sensorLeft, sensorTop),
28426
        range: SugarPosition(sensorWidth, sensorHeight),
28427
        output: absolute(Optional.some(x - rect.width / 2), Optional.some(y - rect.height / 2)),
28428
        extra: { td }
28429
      });
28430
    });
28431
    const getSnapsConfig = (getSnapPoints, cell, onChange) => {
28432
      const isSameCell = (cellOpt, td) => cellOpt.exists(currentTd => eq(currentTd, td));
28433
      return {
28434
        getSnapPoints,
28435
        leftAttr: 'data-drag-left',
28436
        topAttr: 'data-drag-top',
28437
        onSensor: (component, extra) => {
28438
          const td = extra.td;
28439
          if (!isSameCell(cell.get(), td)) {
28440
            cell.set(td);
28441
            onChange(td);
28442
          }
28443
        },
28444
        mustSnap: true
28445
      };
28446
    };
28447
    const createSelector = snaps => record(Button.sketch({
28448
      dom: {
28449
        tag: 'div',
28450
        classes: ['tox-selector']
28451
      },
28452
      buttonBehaviours: derive$1([
28453
        Dragging.config({
28454
          mode: 'mouseOrTouch',
28455
          blockerClass: 'blocker',
28456
          snaps
28457
        }),
28458
        Unselecting.config({})
28459
      ]),
28460
      eventOrder: {
28461
        mousedown: [
28462
          'dragging',
28463
          'alloy.base.behaviour'
28464
        ],
28465
        touchstart: [
28466
          'dragging',
28467
          'alloy.base.behaviour'
28468
        ]
28469
      }
28470
    }));
28471
    const setup$4 = (editor, sink) => {
28472
      const tlTds = Cell([]);
28473
      const brTds = Cell([]);
28474
      const isVisible = Cell(false);
1441 ariadna 28475
      const startCell = value$4();
28476
      const finishCell = value$4();
1 efrain 28477
      const getTopLeftSnap = td => {
28478
        const box = absolute$2(td);
28479
        return calcSnap(memTopLeft.getOpt(sink), td, box.x, box.y, box.width, box.height);
28480
      };
28481
      const getTopLeftSnaps = () => map$2(tlTds.get(), td => getTopLeftSnap(td));
28482
      const getBottomRightSnap = td => {
28483
        const box = absolute$2(td);
28484
        return calcSnap(memBottomRight.getOpt(sink), td, box.right, box.bottom, box.width, box.height);
28485
      };
28486
      const getBottomRightSnaps = () => map$2(brTds.get(), td => getBottomRightSnap(td));
28487
      const topLeftSnaps = getSnapsConfig(getTopLeftSnaps, startCell, start => {
28488
        finishCell.get().each(finish => {
28489
          editor.dispatch('TableSelectorChange', {
28490
            start,
28491
            finish
28492
          });
28493
        });
28494
      });
28495
      const bottomRightSnaps = getSnapsConfig(getBottomRightSnaps, finishCell, finish => {
28496
        startCell.get().each(start => {
28497
          editor.dispatch('TableSelectorChange', {
28498
            start,
28499
            finish
28500
          });
28501
        });
28502
      });
28503
      const memTopLeft = createSelector(topLeftSnaps);
28504
      const memBottomRight = createSelector(bottomRightSnaps);
28505
      const topLeft = build$1(memTopLeft.asSpec());
28506
      const bottomRight = build$1(memBottomRight.asSpec());
28507
      const showOrHideHandle = (selector, cell, isAbove, isBelow) => {
28508
        const cellRect = cell.dom.getBoundingClientRect();
1441 ariadna 28509
        remove$7(selector.element, 'display');
1 efrain 28510
        const viewportHeight = defaultView(SugarElement.fromDom(editor.getBody())).dom.innerHeight;
28511
        const aboveViewport = isAbove(cellRect);
28512
        const belowViewport = isBelow(cellRect, viewportHeight);
28513
        if (aboveViewport || belowViewport) {
28514
          set$8(selector.element, 'display', 'none');
28515
        }
28516
      };
28517
      const snapTo = (selector, cell, getSnapConfig, pos) => {
28518
        const snap = getSnapConfig(cell);
28519
        Dragging.snapTo(selector, snap);
28520
        const isAbove = rect => rect[pos] < 0;
28521
        const isBelow = (rect, viewportHeight) => rect[pos] > viewportHeight;
28522
        showOrHideHandle(selector, cell, isAbove, isBelow);
28523
      };
28524
      const snapTopLeft = cell => snapTo(topLeft, cell, getTopLeftSnap, 'top');
28525
      const snapLastTopLeft = () => startCell.get().each(snapTopLeft);
28526
      const snapBottomRight = cell => snapTo(bottomRight, cell, getBottomRightSnap, 'bottom');
28527
      const snapLastBottomRight = () => finishCell.get().each(snapBottomRight);
1441 ariadna 28528
      if (detect$1().deviceType.isTouch()) {
28529
        const domToSugar = arr => map$2(arr, SugarElement.fromDom);
1 efrain 28530
        editor.on('TableSelectionChange', e => {
28531
          if (!isVisible.get()) {
28532
            attach(sink, topLeft);
28533
            attach(sink, bottomRight);
28534
            isVisible.set(true);
28535
          }
1441 ariadna 28536
          const start = SugarElement.fromDom(e.start);
28537
          const finish = SugarElement.fromDom(e.finish);
28538
          startCell.set(start);
28539
          finishCell.set(finish);
28540
          Optional.from(e.otherCells).each(otherCells => {
28541
            tlTds.set(domToSugar(otherCells.upOrLeftCells));
28542
            brTds.set(domToSugar(otherCells.downOrRightCells));
28543
            snapTopLeft(start);
28544
            snapBottomRight(finish);
1 efrain 28545
          });
28546
        });
28547
        editor.on('ResizeEditor ResizeWindow ScrollContent', () => {
28548
          snapLastTopLeft();
28549
          snapLastBottomRight();
28550
        });
28551
        editor.on('TableSelectionClear', () => {
28552
          if (isVisible.get()) {
28553
            detach(topLeft);
28554
            detach(bottomRight);
28555
            isVisible.set(false);
28556
          }
28557
          startCell.clear();
28558
          finishCell.clear();
28559
        });
28560
      }
28561
    };
28562
 
1441 ariadna 28563
    var Logo = "<svg height=\"16\" viewBox=\"0 0 80 16\" width=\"80\" xmlns=\"http://www.w3.org/2000/svg\"><g opacity=\".8\"><path d=\"m80 3.537v-2.202h-7.976v11.585h7.976v-2.25h-5.474v-2.621h4.812v-2.069h-4.812v-2.443zm-10.647 6.929c-.493.217-1.13.337-1.864.337s-1.276-.156-1.805-.47a3.732 3.732 0 0 1 -1.3-1.298c-.324-.554-.48-1.191-.48-1.877s.156-1.335.48-1.877a3.635 3.635 0 0 1 1.3-1.299 3.466 3.466 0 0 1 1.805-.481c.65 0 .914.06 1.263.18.36.12.698.277.986.47.289.192.578.384.842.6l.12.085v-2.586l-.023-.024c-.385-.35-.855-.614-1.384-.818-.53-.205-1.155-.313-1.877-.313-.721 0-1.6.144-2.333.445a5.773 5.773 0 0 0 -1.937 1.251 5.929 5.929 0 0 0 -1.324 1.9c-.324.735-.48 1.565-.48 2.455s.156 1.72.48 2.454c.325.734.758 1.383 1.324 1.913.553.53 1.215.938 1.937 1.25a6.286 6.286 0 0 0 2.333.434c.819 0 1.384-.108 1.961-.313.59-.216 1.083-.505 1.468-.866l.024-.024v-2.49l-.12.096c-.41.337-.878.626-1.396.866zm-14.869-4.15-4.8-5.04-.024-.025h-.902v11.67h2.502v-6.847l2.827 3.08.385.409.397-.41 2.791-3.067v6.845h2.502v-11.679h-.902l-4.788 5.052z\"/><path clip-rule=\"evenodd\" d=\"m15.543 5.137c0-3.032-2.466-5.113-4.957-5.137-.36 0-.745.024-1.094.096-.157.024-3.85.758-3.85.758-3.032.602-4.62 2.466-4.704 4.788-.024.89-.024 4.27-.024 4.27.036 3.165 2.406 5.138 5.017 5.126.337 0 1.119-.109 1.287-.145.144-.024.385-.084.746-.144.661-.12 1.684-.325 3.067-.602 2.37-.409 4.103-2.009 4.44-4.33.156-1.023.084-4.692.084-4.692zm-3.213 3.308-2.346.457v2.31l-5.859 1.143v-5.75l2.346-.458v3.441l3.513-.686v-3.44l-3.513.685v-2.297l5.859-1.143v5.75zm20.09-3.296-.083-1.023h-2.13v8.794h2.346v-4.884c0-1.107.95-1.985 2.057-1.997 1.095 0 1.901.89 1.901 1.997v4.884h2.346v-5.245c-.012-2.105-1.588-3.777-3.67-3.765a3.764 3.764 0 0 0 -2.778 1.25l.012-.011zm-6.014-4.102 2.346-.458v2.298l-2.346.457z\" fill-rule=\"evenodd\"/><path d=\"m28.752 4.126h-2.346v8.794h2.346z\"/><path clip-rule=\"evenodd\" d=\"m43.777 15.483 4.043-11.357h-2.418l-1.54 4.355-.445 1.324-.36-1.324-1.54-4.355h-2.418l3.151 8.794-1.083 3.08zm-21.028-5.51c0 .722.541 1.034.878 1.034s.638-.048.95-.144l.518 1.708c-.217.145-.879.518-2.13.518a2.565 2.565 0 0 1 -2.562-2.587c-.024-1.082-.024-2.49 0-4.21h-1.54v-2.142h1.54v-1.912l2.346-.458v2.37h2.201v2.142h-2.2v3.693-.012z\" fill-rule=\"evenodd\"/></g></svg>\n";
1 efrain 28564
 
1441 ariadna 28565
    const describedBy = (describedElement, describeElement) => {
28566
      const describeId = Optional.from(get$g(describedElement, 'id')).getOrThunk(() => {
28567
        const id = generate$6('aria');
28568
        set$9(describeElement, 'id', id);
28569
        return id;
28570
      });
28571
      set$9(describedElement, 'aria-describedby', describeId);
28572
    };
28573
    const remove = describedElement => {
28574
      remove$8(describedElement, 'aria-describedby');
28575
    };
28576
 
1 efrain 28577
    const isHidden = elm => elm.nodeName === 'BR' || !!elm.getAttribute('data-mce-bogus') || elm.getAttribute('data-mce-type') === 'bookmark';
28578
    const renderElementPath = (editor, settings, providersBackstage) => {
28579
      var _a;
28580
      const delimiter = (_a = settings.delimiter) !== null && _a !== void 0 ? _a : '\u203A';
28581
      const renderElement = (name, element, index) => Button.sketch({
28582
        dom: {
28583
          tag: 'div',
28584
          classes: ['tox-statusbar__path-item'],
1441 ariadna 28585
          attributes: { 'data-index': index }
1 efrain 28586
        },
28587
        components: [text$2(name)],
28588
        action: _btn => {
28589
          editor.focus();
28590
          editor.selection.select(element);
28591
          editor.nodeChanged();
28592
        },
28593
        buttonBehaviours: derive$1([
1441 ariadna 28594
          Tooltipping.config({
28595
            ...providersBackstage.tooltips.getConfig({
28596
              tooltipText: providersBackstage.translate([
28597
                'Select the {0} element',
28598
                element.nodeName.toLowerCase()
28599
              ]),
28600
              onShow: (comp, tooltip) => {
28601
                describedBy(comp.element, tooltip.element);
28602
              },
28603
              onHide: comp => {
28604
                remove(comp.element);
28605
              }
28606
            })
28607
          }),
1 efrain 28608
          DisablingConfigs.button(providersBackstage.isDisabled),
1441 ariadna 28609
          toggleOnReceive(() => providersBackstage.checkUiComponentContext('any'))
1 efrain 28610
        ])
28611
      });
28612
      const renderDivider = () => ({
28613
        dom: {
28614
          tag: 'div',
28615
          classes: ['tox-statusbar__path-divider'],
28616
          attributes: { 'aria-hidden': true }
28617
        },
28618
        components: [text$2(` ${ delimiter } `)]
28619
      });
28620
      const renderPathData = data => foldl(data, (acc, path, index) => {
28621
        const element = renderElement(path.name, path.element, index);
28622
        if (index === 0) {
28623
          return acc.concat([element]);
28624
        } else {
28625
          return acc.concat([
28626
            renderDivider(),
28627
            element
28628
          ]);
28629
        }
28630
      }, []);
28631
      const updatePath = parents => {
28632
        const newPath = [];
28633
        let i = parents.length;
28634
        while (i-- > 0) {
28635
          const parent = parents[i];
28636
          if (parent.nodeType === 1 && !isHidden(parent)) {
28637
            const args = fireResolveName(editor, parent);
28638
            if (!args.isDefaultPrevented()) {
28639
              newPath.push({
28640
                name: args.name,
28641
                element: parent
28642
              });
28643
            }
28644
            if (args.isPropagationStopped()) {
28645
              break;
28646
            }
28647
          }
28648
        }
28649
        return newPath;
28650
      };
28651
      return {
28652
        dom: {
28653
          tag: 'div',
28654
          classes: ['tox-statusbar__path'],
28655
          attributes: { role: 'navigation' }
28656
        },
28657
        behaviours: derive$1([
28658
          Keying.config({
28659
            mode: 'flow',
28660
            selector: 'div[role=button]'
28661
          }),
28662
          Disabling.config({ disabled: providersBackstage.isDisabled }),
1441 ariadna 28663
          toggleOnReceive(() => providersBackstage.checkUiComponentContext('any')),
1 efrain 28664
          Tabstopping.config({}),
28665
          Replacing.config({}),
28666
          config('elementPathEvents', [runOnAttached((comp, _e) => {
28667
              editor.shortcuts.add('alt+F11', 'focus statusbar elementpath', () => Keying.focusIn(comp));
28668
              editor.on('NodeChange', e => {
28669
                const newPath = updatePath(e.parents);
28670
                const newChildren = newPath.length > 0 ? renderPathData(newPath) : [];
28671
                Replacing.set(comp, newChildren);
28672
              });
28673
            })])
28674
        ]),
28675
        components: []
28676
      };
28677
    };
28678
 
28679
    var ResizeTypes;
28680
    (function (ResizeTypes) {
28681
      ResizeTypes[ResizeTypes['None'] = 0] = 'None';
28682
      ResizeTypes[ResizeTypes['Both'] = 1] = 'Both';
28683
      ResizeTypes[ResizeTypes['Vertical'] = 2] = 'Vertical';
28684
    }(ResizeTypes || (ResizeTypes = {})));
28685
    const getDimensions = (editor, deltas, resizeType, originalHeight, originalWidth) => {
28686
      const dimensions = { height: calcCappedSize(originalHeight + deltas.top, getMinHeightOption(editor), getMaxHeightOption(editor)) };
28687
      if (resizeType === ResizeTypes.Both) {
28688
        dimensions.width = calcCappedSize(originalWidth + deltas.left, getMinWidthOption(editor), getMaxWidthOption(editor));
28689
      }
28690
      return dimensions;
28691
    };
28692
    const resize = (editor, deltas, resizeType) => {
28693
      const container = SugarElement.fromDom(editor.getContainer());
1441 ariadna 28694
      const dimensions = getDimensions(editor, deltas, resizeType, get$e(container), get$d(container));
1 efrain 28695
      each(dimensions, (val, dim) => {
28696
        if (isNumber(val)) {
28697
          set$8(container, dim, numToPx(val));
28698
        }
28699
      });
28700
      fireResizeEditor(editor);
28701
    };
28702
 
28703
    const getResizeType = editor => {
28704
      const resize = getResize(editor);
28705
      if (resize === false) {
28706
        return ResizeTypes.None;
28707
      } else if (resize === 'both') {
28708
        return ResizeTypes.Both;
28709
      } else {
28710
        return ResizeTypes.Vertical;
28711
      }
28712
    };
28713
    const keyboardHandler = (editor, resizeType, x, y) => {
28714
      const scale = 20;
28715
      const delta = SugarPosition(x * scale, y * scale);
28716
      resize(editor, delta, resizeType);
28717
      return Optional.some(true);
28718
    };
28719
    const renderResizeHandler = (editor, providersBackstage) => {
28720
      const resizeType = getResizeType(editor);
28721
      if (resizeType === ResizeTypes.None) {
28722
        return Optional.none();
28723
      }
28724
      const resizeLabel = resizeType === ResizeTypes.Both ? 'Press the arrow keys to resize the editor.' : 'Press the Up and Down arrow keys to resize the editor.';
28725
      return Optional.some(render$3('resize-handle', {
28726
        tag: 'div',
28727
        classes: ['tox-statusbar__resize-handle'],
28728
        attributes: {
1441 ariadna 28729
          'aria-label': providersBackstage.translate(resizeLabel),
28730
          'data-mce-name': 'resize-handle'
1 efrain 28731
        },
28732
        behaviours: [
28733
          Dragging.config({
28734
            mode: 'mouse',
28735
            repositionTarget: false,
28736
            onDrag: (_comp, _target, delta) => resize(editor, delta, resizeType),
28737
            blockerClass: 'tox-blocker'
28738
          }),
28739
          Keying.config({
28740
            mode: 'special',
28741
            onLeft: () => keyboardHandler(editor, resizeType, -1, 0),
28742
            onRight: () => keyboardHandler(editor, resizeType, 1, 0),
28743
            onUp: () => keyboardHandler(editor, resizeType, 0, -1),
28744
            onDown: () => keyboardHandler(editor, resizeType, 0, 1)
28745
          }),
28746
          Tabstopping.config({}),
1441 ariadna 28747
          Focusing.config({}),
28748
          Tooltipping.config(providersBackstage.tooltips.getConfig({ tooltipText: providersBackstage.translate('Resize') }))
1 efrain 28749
        ]
28750
      }, providersBackstage.icons));
28751
    };
28752
 
28753
    const renderWordCount = (editor, providersBackstage) => {
28754
      const replaceCountText = (comp, count, mode) => Replacing.set(comp, [text$2(providersBackstage.translate([
28755
          '{0} ' + mode,
28756
          count[mode]
28757
        ]))]);
28758
      return Button.sketch({
28759
        dom: {
28760
          tag: 'button',
28761
          classes: ['tox-statusbar__wordcount']
28762
        },
28763
        components: [],
28764
        buttonBehaviours: derive$1([
28765
          DisablingConfigs.button(providersBackstage.isDisabled),
1441 ariadna 28766
          toggleOnReceive(() => providersBackstage.checkUiComponentContext('any')),
1 efrain 28767
          Tabstopping.config({}),
28768
          Replacing.config({}),
28769
          Representing.config({
28770
            store: {
28771
              mode: 'memory',
28772
              initialValue: {
28773
                mode: 'words',
28774
                count: {
28775
                  words: 0,
28776
                  characters: 0
28777
                }
28778
              }
28779
            }
28780
          }),
28781
          config('wordcount-events', [
28782
            runOnExecute$1(comp => {
28783
              const currentVal = Representing.getValue(comp);
28784
              const newMode = currentVal.mode === 'words' ? 'characters' : 'words';
28785
              Representing.setValue(comp, {
28786
                mode: newMode,
28787
                count: currentVal.count
28788
              });
28789
              replaceCountText(comp, currentVal.count, newMode);
28790
            }),
28791
            runOnAttached(comp => {
28792
              editor.on('wordCountUpdate', e => {
28793
                const {mode} = Representing.getValue(comp);
28794
                Representing.setValue(comp, {
28795
                  mode,
28796
                  count: e.wordCount
28797
                });
28798
                replaceCountText(comp, e.wordCount, mode);
28799
              });
28800
            })
28801
          ])
28802
        ]),
28803
        eventOrder: {
28804
          [execute$5()]: [
28805
            'disabling',
28806
            'alloy.base.behaviour',
28807
            'wordcount-events'
28808
          ]
28809
        }
28810
      });
28811
    };
28812
 
28813
    const renderStatusbar = (editor, providersBackstage) => {
28814
      const renderBranding = () => {
28815
        return {
28816
          dom: {
28817
            tag: 'span',
28818
            classes: ['tox-statusbar__branding']
28819
          },
28820
          components: [{
28821
              dom: {
28822
                tag: 'a',
28823
                attributes: {
1441 ariadna 28824
                  'href': 'https://www.tiny.cloud/powered-by-tiny?utm_campaign=poweredby&utm_source=tiny&utm_medium=referral&utm_content=v7',
1 efrain 28825
                  'rel': 'noopener',
28826
                  'target': '_blank',
1441 ariadna 28827
                  'aria-label': editor.translate([
28828
                    'Build with {0}',
28829
                    'TinyMCE'
1 efrain 28830
                  ])
28831
                },
1441 ariadna 28832
                innerHtml: editor.translate([
28833
                  'Build with {0}',
28834
                  Logo.trim()
28835
                ])
1 efrain 28836
              },
28837
              behaviours: derive$1([Focusing.config({})])
28838
            }]
28839
        };
28840
      };
28841
      const renderHelpAccessibility = () => {
28842
        const shortcutText = convertText('Alt+0');
28843
        const text = `Press {0} for help`;
28844
        return {
28845
          dom: {
28846
            tag: 'div',
28847
            classes: ['tox-statusbar__help-text']
28848
          },
1441 ariadna 28849
          components: [text$2(global$5.translate([
1 efrain 28850
              text,
28851
              shortcutText
28852
            ]))]
28853
        };
28854
      };
28855
      const renderRightContainer = () => {
28856
        const components = [];
28857
        if (editor.hasPlugin('wordcount')) {
28858
          components.push(renderWordCount(editor, providersBackstage));
28859
        }
28860
        if (useBranding(editor)) {
28861
          components.push(renderBranding());
28862
        }
28863
        return {
28864
          dom: {
28865
            tag: 'div',
28866
            classes: ['tox-statusbar__right-container']
28867
          },
28868
          components
28869
        };
28870
      };
28871
      const getTextComponents = () => {
28872
        const components = [];
28873
        const shouldRenderHelp = useHelpAccessibility(editor);
28874
        const shouldRenderElementPath = useElementPath(editor);
28875
        const shouldRenderRightContainer = useBranding(editor) || editor.hasPlugin('wordcount');
28876
        const getTextComponentClasses = () => {
28877
          const flexStart = 'tox-statusbar__text-container--flex-start';
28878
          const flexEnd = 'tox-statusbar__text-container--flex-end';
28879
          const spaceAround = 'tox-statusbar__text-container--space-around';
28880
          if (shouldRenderHelp) {
28881
            const container3Columns = 'tox-statusbar__text-container-3-cols';
28882
            if (!shouldRenderRightContainer && !shouldRenderElementPath) {
28883
              return [
28884
                container3Columns,
28885
                spaceAround
28886
              ];
28887
            }
28888
            if (shouldRenderRightContainer && !shouldRenderElementPath) {
28889
              return [
28890
                container3Columns,
28891
                flexEnd
28892
              ];
28893
            }
28894
            return [
28895
              container3Columns,
28896
              flexStart
28897
            ];
28898
          }
28899
          return [shouldRenderRightContainer && !shouldRenderElementPath ? flexEnd : flexStart];
28900
        };
28901
        if (shouldRenderElementPath) {
28902
          components.push(renderElementPath(editor, {}, providersBackstage));
28903
        }
28904
        if (shouldRenderHelp) {
28905
          components.push(renderHelpAccessibility());
28906
        }
28907
        if (shouldRenderRightContainer) {
28908
          components.push(renderRightContainer());
28909
        }
28910
        if (components.length > 0) {
28911
          return [{
28912
              dom: {
28913
                tag: 'div',
28914
                classes: [
28915
                  'tox-statusbar__text-container',
28916
                  ...getTextComponentClasses()
28917
                ]
28918
              },
28919
              components
28920
            }];
28921
        }
28922
        return [];
28923
      };
28924
      const getComponents = () => {
28925
        const components = getTextComponents();
28926
        const resizeHandler = renderResizeHandler(editor, providersBackstage);
28927
        return components.concat(resizeHandler.toArray());
28928
      };
28929
      return {
28930
        dom: {
28931
          tag: 'div',
28932
          classes: ['tox-statusbar']
28933
        },
28934
        components: getComponents()
28935
      };
28936
    };
28937
 
28938
    const getLazyMothership = (label, singleton) => singleton.get().getOrDie(`UI for ${ label } has not been rendered`);
28939
    const setup$3 = (editor, setupForTheme) => {
28940
      const isInline = editor.inline;
28941
      const mode = isInline ? Inline : Iframe;
28942
      const header = isStickyToolbar(editor) ? StickyHeader : StaticHeader;
28943
      const lazyUiRefs = LazyUiReferences();
1441 ariadna 28944
      const lazyMothership = value$4();
28945
      const lazyDialogMothership = value$4();
28946
      const lazyPopupMothership = value$4();
28947
      const platform = detect$1();
1 efrain 28948
      const isTouch = platform.deviceType.isTouch();
28949
      const touchPlatformClass = 'tox-platform-touch';
28950
      const deviceClasses = isTouch ? [touchPlatformClass] : [];
28951
      const isToolbarBottom = isToolbarLocationBottom(editor);
28952
      const toolbarMode = getToolbarMode(editor);
28953
      const memAnchorBar = record({
28954
        dom: {
28955
          tag: 'div',
28956
          classes: ['tox-anchorbar']
28957
        }
28958
      });
28959
      const memBottomAnchorBar = record({
28960
        dom: {
28961
          tag: 'div',
28962
          classes: ['tox-bottom-anchorbar']
28963
        }
28964
      });
28965
      const lazyHeader = () => lazyUiRefs.mainUi.get().map(ui => ui.outerContainer).bind(OuterContainer.getHeader);
28966
      const lazyDialogSinkResult = () => Result.fromOption(lazyUiRefs.dialogUi.get().map(ui => ui.sink), 'UI has not been rendered');
28967
      const lazyPopupSinkResult = () => Result.fromOption(lazyUiRefs.popupUi.get().map(ui => ui.sink), '(popup) UI has not been rendered');
28968
      const lazyAnchorBar = lazyUiRefs.lazyGetInOuterOrDie('anchor bar', memAnchorBar.getOpt);
28969
      const lazyBottomAnchorBar = lazyUiRefs.lazyGetInOuterOrDie('bottom anchor bar', memBottomAnchorBar.getOpt);
28970
      const lazyToolbar = lazyUiRefs.lazyGetInOuterOrDie('toolbar', OuterContainer.getToolbar);
28971
      const lazyThrobber = lazyUiRefs.lazyGetInOuterOrDie('throbber', OuterContainer.getThrobber);
1441 ariadna 28972
      const backstages = init$5({
1 efrain 28973
        popup: lazyPopupSinkResult,
28974
        dialog: lazyDialogSinkResult
28975
      }, editor, lazyAnchorBar, lazyBottomAnchorBar);
28976
      const makeHeaderPart = () => {
28977
        const verticalDirAttributes = { attributes: { [Attribute]: isToolbarBottom ? AttributeValue.BottomToTop : AttributeValue.TopToBottom } };
28978
        const partMenubar = OuterContainer.parts.menubar({
28979
          dom: {
28980
            tag: 'div',
28981
            classes: ['tox-menubar']
28982
          },
28983
          backstage: backstages.popup,
28984
          onEscape: () => {
28985
            editor.focus();
28986
          }
28987
        });
28988
        const partToolbar = OuterContainer.parts.toolbar({
28989
          dom: {
28990
            tag: 'div',
28991
            classes: ['tox-toolbar']
28992
          },
28993
          getSink: backstages.popup.shared.getSink,
28994
          providers: backstages.popup.shared.providers,
28995
          onEscape: () => {
28996
            editor.focus();
28997
          },
28998
          onToolbarToggled: state => {
28999
            fireToggleToolbarDrawer(editor, state);
29000
          },
29001
          type: toolbarMode,
29002
          lazyToolbar,
29003
          lazyHeader: () => lazyHeader().getOrDie('Could not find header element'),
29004
          ...verticalDirAttributes
29005
        });
29006
        const partMultipleToolbar = OuterContainer.parts['multiple-toolbar']({
29007
          dom: {
29008
            tag: 'div',
29009
            classes: ['tox-toolbar-overlord']
29010
          },
29011
          providers: backstages.popup.shared.providers,
29012
          onEscape: () => {
29013
            editor.focus();
29014
          },
29015
          type: toolbarMode
29016
        });
29017
        const hasMultipleToolbar = isMultipleToolbars(editor);
29018
        const hasToolbar = isToolbarEnabled(editor);
29019
        const hasMenubar = isMenubarEnabled(editor);
29020
        const shouldHavePromotion = promotionEnabled(editor);
29021
        const partPromotion = makePromotion();
29022
        const hasAnyContents = hasMultipleToolbar || hasToolbar || hasMenubar;
29023
        const getPartToolbar = () => {
29024
          if (hasMultipleToolbar) {
29025
            return [partMultipleToolbar];
29026
          } else if (hasToolbar) {
29027
            return [partToolbar];
29028
          } else {
29029
            return [];
29030
          }
29031
        };
29032
        const menubarCollection = shouldHavePromotion ? [
29033
          partPromotion,
29034
          partMenubar
29035
        ] : [partMenubar];
29036
        return OuterContainer.parts.header({
29037
          dom: {
29038
            tag: 'div',
29039
            classes: ['tox-editor-header'].concat(hasAnyContents ? [] : ['tox-editor-header--empty']),
29040
            ...verticalDirAttributes
29041
          },
29042
          components: flatten([
29043
            hasMenubar ? menubarCollection : [],
29044
            getPartToolbar(),
29045
            useFixedContainer(editor) ? [] : [memAnchorBar.asSpec()]
29046
          ]),
29047
          sticky: isStickyToolbar(editor),
29048
          editor,
29049
          sharedBackstage: backstages.popup.shared
29050
        });
29051
      };
29052
      const makePromotion = () => {
29053
        return OuterContainer.parts.promotion({
29054
          dom: {
29055
            tag: 'div',
29056
            classes: ['tox-promotion']
29057
          }
29058
        });
29059
      };
29060
      const makeSidebarDefinition = () => {
29061
        const partSocket = OuterContainer.parts.socket({
29062
          dom: {
29063
            tag: 'div',
29064
            classes: ['tox-edit-area']
29065
          }
29066
        });
29067
        const partSidebar = OuterContainer.parts.sidebar({
29068
          dom: {
29069
            tag: 'div',
29070
            classes: ['tox-sidebar']
29071
          }
29072
        });
29073
        return {
29074
          dom: {
29075
            tag: 'div',
29076
            classes: ['tox-sidebar-wrap']
29077
          },
29078
          components: [
29079
            partSocket,
29080
            partSidebar
29081
          ]
29082
        };
29083
      };
29084
      const renderDialogUi = () => {
29085
        const uiContainer = getUiContainer(editor);
1441 ariadna 29086
        const isGridUiContainer = eq(body(), uiContainer) && get$f(uiContainer, 'display') === 'grid';
1 efrain 29087
        const sinkSpec = {
29088
          dom: {
29089
            tag: 'div',
29090
            classes: [
29091
              'tox',
29092
              'tox-silver-sink',
29093
              'tox-tinymce-aux'
29094
            ].concat(deviceClasses),
1441 ariadna 29095
            attributes: { ...global$5.isRtl() ? { dir: 'rtl' } : {} }
1 efrain 29096
          },
29097
          behaviours: derive$1([Positioning.config({ useFixed: () => header.isDocked(lazyHeader) })])
29098
        };
29099
        const reactiveWidthSpec = {
29100
          dom: { styles: { width: document.body.clientWidth + 'px' } },
29101
          events: derive$2([run$1(windowResize(), comp => {
29102
              set$8(comp.element, 'width', document.body.clientWidth + 'px');
29103
            })])
29104
        };
29105
        const sink = build$1(deepMerge(sinkSpec, isGridUiContainer ? reactiveWidthSpec : {}));
29106
        const uiMothership = takeover(sink);
29107
        lazyDialogMothership.set(uiMothership);
29108
        return {
29109
          sink,
29110
          mothership: uiMothership
29111
        };
29112
      };
29113
      const renderPopupUi = () => {
29114
        const sinkSpec = {
29115
          dom: {
29116
            tag: 'div',
29117
            classes: [
29118
              'tox',
29119
              'tox-silver-sink',
29120
              'tox-silver-popup-sink',
29121
              'tox-tinymce-aux'
29122
            ].concat(deviceClasses),
1441 ariadna 29123
            attributes: { ...global$5.isRtl() ? { dir: 'rtl' } : {} }
1 efrain 29124
          },
29125
          behaviours: derive$1([Positioning.config({
29126
              useFixed: () => header.isDocked(lazyHeader),
29127
              getBounds: () => setupForTheme.getPopupSinkBounds()
29128
            })])
29129
        };
29130
        const sink = build$1(sinkSpec);
29131
        const uiMothership = takeover(sink);
29132
        lazyPopupMothership.set(uiMothership);
29133
        return {
29134
          sink,
29135
          mothership: uiMothership
29136
        };
29137
      };
29138
      const renderMainUi = () => {
29139
        const partHeader = makeHeaderPart();
29140
        const sidebarContainer = makeSidebarDefinition();
29141
        const partThrobber = OuterContainer.parts.throbber({
29142
          dom: {
29143
            tag: 'div',
29144
            classes: ['tox-throbber']
29145
          },
29146
          backstage: backstages.popup
29147
        });
29148
        const partViewWrapper = OuterContainer.parts.viewWrapper({ backstage: backstages.popup });
29149
        const statusbar = useStatusBar(editor) && !isInline ? Optional.some(renderStatusbar(editor, backstages.popup.shared.providers)) : Optional.none();
29150
        const editorComponents = flatten([
29151
          isToolbarBottom ? [] : [partHeader],
29152
          isInline ? [] : [sidebarContainer],
29153
          isToolbarBottom ? [partHeader] : []
29154
        ]);
29155
        const editorContainer = OuterContainer.parts.editorContainer({
29156
          components: flatten([
29157
            editorComponents,
1441 ariadna 29158
            isInline ? [] : [memBottomAnchorBar.asSpec()]
1 efrain 29159
          ])
29160
        });
29161
        const isHidden = isDistractionFree(editor);
29162
        const attributes = {
29163
          role: 'application',
1441 ariadna 29164
          ...global$5.isRtl() ? { dir: 'rtl' } : {},
1 efrain 29165
          ...isHidden ? { 'aria-hidden': 'true' } : {}
29166
        };
29167
        const outerContainer = build$1(OuterContainer.sketch({
29168
          dom: {
29169
            tag: 'div',
29170
            classes: [
29171
              'tox',
29172
              'tox-tinymce'
29173
            ].concat(isInline ? ['tox-tinymce-inline'] : []).concat(isToolbarBottom ? ['tox-tinymce--toolbar-bottom'] : []).concat(deviceClasses),
29174
            styles: {
29175
              visibility: 'hidden',
29176
              ...isHidden ? {
29177
                opacity: '0',
29178
                border: '0'
29179
              } : {}
29180
            },
29181
            attributes
29182
          },
29183
          components: [
29184
            editorContainer,
1441 ariadna 29185
            ...isInline ? [] : [
29186
              partViewWrapper,
29187
              ...statusbar.toArray()
29188
            ],
1 efrain 29189
            partThrobber
29190
          ],
29191
          behaviours: derive$1([
1441 ariadna 29192
            toggleOnReceive(() => backstages.popup.shared.providers.checkUiComponentContext('any')),
1 efrain 29193
            Disabling.config({ disableClass: 'tox-tinymce--disabled' }),
29194
            Keying.config({
29195
              mode: 'cyclic',
29196
              selector: '.tox-menubar, .tox-toolbar, .tox-toolbar__primary, .tox-toolbar__overflow--open, .tox-sidebar__overflow--open, .tox-statusbar__path, .tox-statusbar__wordcount, .tox-statusbar__branding a, .tox-statusbar__resize-handle'
29197
            })
29198
          ])
29199
        }));
29200
        const mothership = takeover(outerContainer);
29201
        lazyMothership.set(mothership);
29202
        return {
29203
          mothership,
29204
          outerContainer
29205
        };
29206
      };
29207
      const setEditorSize = outerContainer => {
29208
        const parsedHeight = numToPx(getHeightWithFallback(editor));
29209
        const parsedWidth = numToPx(getWidthWithFallback(editor));
29210
        if (!editor.inline) {
29211
          if (isValidValue$1('div', 'width', parsedWidth)) {
29212
            set$8(outerContainer.element, 'width', parsedWidth);
29213
          }
29214
          if (isValidValue$1('div', 'height', parsedHeight)) {
29215
            set$8(outerContainer.element, 'height', parsedHeight);
29216
          } else {
29217
            set$8(outerContainer.element, 'height', '400px');
29218
          }
29219
        }
29220
        return parsedHeight;
29221
      };
29222
      const setupShortcutsAndCommands = outerContainer => {
29223
        editor.addShortcut('alt+F9', 'focus menubar', () => {
29224
          OuterContainer.focusMenubar(outerContainer);
29225
        });
29226
        editor.addShortcut('alt+F10', 'focus toolbar', () => {
29227
          OuterContainer.focusToolbar(outerContainer);
29228
        });
29229
        editor.addCommand('ToggleToolbarDrawer', (_ui, options) => {
29230
          if (options === null || options === void 0 ? void 0 : options.skipFocus) {
29231
            OuterContainer.toggleToolbarDrawerWithoutFocusing(outerContainer);
29232
          } else {
29233
            OuterContainer.toggleToolbarDrawer(outerContainer);
29234
          }
29235
        });
29236
        editor.addQueryStateHandler('ToggleToolbarDrawer', () => OuterContainer.isToolbarDrawerToggled(outerContainer));
29237
      };
29238
      const renderUIWithRefs = uiRefs => {
29239
        const {mainUi, popupUi, uiMotherships} = uiRefs;
29240
        map$1(getToolbarGroups(editor), (toolbarGroupButtonConfig, name) => {
29241
          editor.ui.registry.addGroupToolbarButton(name, toolbarGroupButtonConfig);
29242
        });
29243
        const {buttons, menuItems, contextToolbars, sidebars, views} = editor.ui.registry.getAll();
29244
        const toolbarOpt = getMultipleToolbarsOption(editor);
29245
        const rawUiConfig = {
29246
          menuItems,
29247
          menus: getMenus(editor),
29248
          menubar: getMenubar(editor),
29249
          toolbar: toolbarOpt.getOrThunk(() => getToolbar(editor)),
29250
          allowToolbarGroups: toolbarMode === ToolbarMode$1.floating,
29251
          buttons,
29252
          sidebar: sidebars,
29253
          views
29254
        };
29255
        setupShortcutsAndCommands(mainUi.outerContainer);
29256
        setup$b(editor, mainUi.mothership, uiMotherships);
29257
        header.setup(editor, backstages.popup.shared, lazyHeader);
29258
        setup$6(editor, backstages.popup);
29259
        setup$5(editor, backstages.popup.shared.getSink, backstages.popup);
29260
        setup$8(editor);
29261
        setup$7(editor, lazyThrobber, backstages.popup.shared);
1441 ariadna 29262
        register$a(editor, contextToolbars, popupUi.sink, { backstage: backstages.popup });
1 efrain 29263
        setup$4(editor, popupUi.sink);
29264
        const elm = editor.getElement();
29265
        const height = setEditorSize(mainUi.outerContainer);
29266
        const args = {
29267
          targetNode: elm,
29268
          height
29269
        };
29270
        return mode.render(editor, uiRefs, rawUiConfig, backstages.popup, args);
29271
      };
29272
      const reuseDialogUiForPopuUi = dialogUi => {
29273
        lazyPopupMothership.set(dialogUi.mothership);
29274
        return dialogUi;
29275
      };
29276
      const renderUI = () => {
29277
        const mainUi = renderMainUi();
29278
        const dialogUi = renderDialogUi();
29279
        const popupUi = isSplitUiMode(editor) ? renderPopupUi() : reuseDialogUiForPopuUi(dialogUi);
29280
        lazyUiRefs.dialogUi.set(dialogUi);
29281
        lazyUiRefs.popupUi.set(popupUi);
29282
        lazyUiRefs.mainUi.set(mainUi);
29283
        const uiRefs = {
29284
          popupUi,
29285
          dialogUi,
29286
          mainUi,
29287
          uiMotherships: lazyUiRefs.getUiMotherships()
29288
        };
29289
        return renderUIWithRefs(uiRefs);
29290
      };
29291
      return {
29292
        popups: {
29293
          backstage: backstages.popup,
29294
          getMothership: () => getLazyMothership('popups', lazyPopupMothership)
29295
        },
29296
        dialogs: {
29297
          backstage: backstages.dialog,
29298
          getMothership: () => getLazyMothership('dialogs', lazyDialogMothership)
29299
        },
29300
        renderUI
29301
      };
29302
    };
29303
 
1441 ariadna 29304
    const get = element => element.dom.textContent;
29305
 
1 efrain 29306
    const labelledBy = (labelledElement, labelElement) => {
29307
      const labelId = getOpt(labelledElement, 'id').fold(() => {
29308
        const id = generate$6('dialog-label');
29309
        set$9(labelElement, 'id', id);
29310
        return id;
29311
      }, identity);
29312
      set$9(labelledElement, 'aria-labelledby', labelId);
29313
    };
29314
 
29315
    const schema$2 = constant$1([
29316
      required$1('lazySink'),
29317
      option$3('dragBlockClass'),
29318
      defaultedFunction('getBounds', win),
29319
      defaulted('useTabstopAt', always),
29320
      defaulted('firstTabstop', 0),
29321
      defaulted('eventOrder', {}),
29322
      field('modalBehaviours', [Keying]),
29323
      onKeyboardHandler('onExecute'),
29324
      onStrictKeyboardHandler('onEscape')
29325
    ]);
29326
    const basic = { sketch: identity };
29327
    const parts$2 = constant$1([
29328
      optional({
29329
        name: 'draghandle',
29330
        overrides: (detail, spec) => {
29331
          return {
29332
            behaviours: derive$1([Dragging.config({
29333
                mode: 'mouse',
29334
                getTarget: handle => {
29335
                  return ancestor(handle, '[role="dialog"]').getOr(handle);
29336
                },
29337
                blockerClass: detail.dragBlockClass.getOrDie(new Error('The drag blocker class was not specified for a dialog with a drag handle: \n' + JSON.stringify(spec, null, 2)).message),
29338
                getBounds: detail.getDragBounds
29339
              })])
29340
          };
29341
        }
29342
      }),
29343
      required({
29344
        schema: [required$1('dom')],
29345
        name: 'title'
29346
      }),
29347
      required({
29348
        factory: basic,
29349
        schema: [required$1('dom')],
29350
        name: 'close'
29351
      }),
29352
      required({
29353
        factory: basic,
29354
        schema: [required$1('dom')],
29355
        name: 'body'
29356
      }),
29357
      optional({
29358
        factory: basic,
29359
        schema: [required$1('dom')],
29360
        name: 'footer'
29361
      }),
29362
      external({
29363
        factory: {
29364
          sketch: (spec, detail) => ({
29365
            ...spec,
29366
            dom: detail.dom,
29367
            components: detail.components
29368
          })
29369
        },
29370
        schema: [
29371
          defaulted('dom', {
29372
            tag: 'div',
29373
            styles: {
29374
              position: 'fixed',
29375
              left: '0px',
29376
              top: '0px',
29377
              right: '0px',
29378
              bottom: '0px'
29379
            }
29380
          }),
29381
          defaulted('components', [])
29382
        ],
29383
        name: 'blocker'
29384
      })
29385
    ]);
29386
 
29387
    const factory$4 = (detail, components, spec, externals) => {
1441 ariadna 29388
      const dialogComp = value$4();
1 efrain 29389
      const showDialog = dialog => {
29390
        dialogComp.set(dialog);
29391
        const sink = detail.lazySink(dialog).getOrDie();
29392
        const externalBlocker = externals.blocker();
29393
        const blocker = sink.getSystem().build({
29394
          ...externalBlocker,
29395
          components: externalBlocker.components.concat([premade(dialog)]),
29396
          behaviours: derive$1([
29397
            Focusing.config({}),
29398
            config('dialog-blocker-events', [runOnSource(focusin(), () => {
29399
                Blocking.isBlocked(dialog) ? noop() : Keying.focusIn(dialog);
29400
              })])
29401
          ])
29402
        });
29403
        attach(sink, blocker);
29404
        Keying.focusIn(dialog);
29405
      };
29406
      const hideDialog = dialog => {
29407
        dialogComp.clear();
29408
        parent(dialog.element).each(blockerDom => {
29409
          dialog.getSystem().getByDom(blockerDom).each(blocker => {
29410
            detach(blocker);
29411
          });
29412
        });
29413
      };
29414
      const getDialogBody = dialog => getPartOrDie(dialog, detail, 'body');
29415
      const getDialogFooter = dialog => getPart(dialog, detail, 'footer');
29416
      const setBusy = (dialog, getBusySpec) => {
29417
        Blocking.block(dialog, getBusySpec);
29418
      };
29419
      const setIdle = dialog => {
29420
        Blocking.unblock(dialog);
29421
      };
29422
      const modalEventsId = generate$6('modal-events');
29423
      const eventOrder = {
29424
        ...detail.eventOrder,
29425
        [attachedToDom()]: [modalEventsId].concat(detail.eventOrder['alloy.system.attached'] || [])
29426
      };
1441 ariadna 29427
      const browser = detect$1();
1 efrain 29428
      return {
29429
        uid: detail.uid,
29430
        dom: detail.dom,
29431
        components,
29432
        apis: {
29433
          show: showDialog,
29434
          hide: hideDialog,
29435
          getBody: getDialogBody,
29436
          getFooter: getDialogFooter,
29437
          setIdle,
29438
          setBusy
29439
        },
29440
        eventOrder,
29441
        domModification: {
29442
          attributes: {
29443
            'role': 'dialog',
29444
            'aria-modal': 'true'
29445
          }
29446
        },
29447
        behaviours: augment(detail.modalBehaviours, [
29448
          Replacing.config({}),
29449
          Keying.config({
29450
            mode: 'cyclic',
29451
            onEnter: detail.onExecute,
29452
            onEscape: detail.onEscape,
29453
            useTabstopAt: detail.useTabstopAt,
29454
            firstTabstop: detail.firstTabstop
29455
          }),
29456
          Blocking.config({ getRoot: dialogComp.get }),
29457
          config(modalEventsId, [runOnAttached(c => {
1441 ariadna 29458
              const titleElm = getPartOrDie(c, detail, 'title').element;
29459
              const title = get(titleElm);
29460
              if (browser.os.isMacOS() && isNonNullable(title)) {
29461
                set$9(c.element, 'aria-label', title);
29462
              } else {
29463
                labelledBy(c.element, titleElm);
29464
              }
1 efrain 29465
            })])
29466
        ])
29467
      };
29468
    };
29469
    const ModalDialog = composite({
29470
      name: 'ModalDialog',
29471
      configFields: schema$2(),
29472
      partFields: parts$2(),
29473
      factory: factory$4,
29474
      apis: {
29475
        show: (apis, dialog) => {
29476
          apis.show(dialog);
29477
        },
29478
        hide: (apis, dialog) => {
29479
          apis.hide(dialog);
29480
        },
29481
        getBody: (apis, dialog) => apis.getBody(dialog),
29482
        getFooter: (apis, dialog) => apis.getFooter(dialog),
29483
        setBusy: (apis, dialog, getBusySpec) => {
29484
          apis.setBusy(dialog, getBusySpec);
29485
        },
29486
        setIdle: (apis, dialog) => {
29487
          apis.setIdle(dialog);
29488
        }
29489
      }
29490
    });
29491
 
29492
    const dialogToggleMenuItemSchema = objOf([
29493
      type,
29494
      name$1
29495
    ].concat(commonMenuItemFields));
29496
    const dialogToggleMenuItemDataProcessor = boolean;
29497
 
29498
    const baseFooterButtonFields = [
29499
      generatedName('button'),
29500
      optionalIcon,
29501
      defaultedStringEnum('align', 'end', [
29502
        'start',
29503
        'end'
29504
      ]),
29505
      primary,
29506
      enabled,
29507
      optionStringEnum('buttonType', [
29508
        'primary',
29509
        'secondary'
1441 ariadna 29510
      ]),
29511
      defaultedString('context', 'mode:design')
1 efrain 29512
    ];
29513
    const dialogFooterButtonFields = [
29514
      ...baseFooterButtonFields,
29515
      text
29516
    ];
29517
    const normalFooterButtonFields = [
29518
      requiredStringEnum('type', [
29519
        'submit',
29520
        'cancel',
29521
        'custom'
29522
      ]),
29523
      ...dialogFooterButtonFields
29524
    ];
29525
    const menuFooterButtonFields = [
29526
      requiredStringEnum('type', ['menu']),
29527
      optionalText,
29528
      optionalTooltip,
29529
      optionalIcon,
29530
      requiredArrayOf('items', dialogToggleMenuItemSchema),
29531
      ...baseFooterButtonFields
29532
    ];
29533
    const toggleButtonSpecFields = [
29534
      ...baseFooterButtonFields,
29535
      requiredStringEnum('type', ['togglebutton']),
1441 ariadna 29536
      optionalTooltip,
1 efrain 29537
      optionalIcon,
29538
      optionalText,
29539
      defaultedBoolean('active', false)
29540
    ];
29541
    const dialogFooterButtonSchema = choose$1('type', {
29542
      submit: normalFooterButtonFields,
29543
      cancel: normalFooterButtonFields,
29544
      custom: normalFooterButtonFields,
29545
      menu: menuFooterButtonFields,
29546
      togglebutton: toggleButtonSpecFields
29547
    });
29548
 
29549
    const alertBannerFields = [
29550
      type,
29551
      text,
29552
      requiredStringEnum('level', [
29553
        'info',
29554
        'warn',
29555
        'error',
29556
        'success'
29557
      ]),
29558
      icon,
29559
      defaulted('url', '')
29560
    ];
29561
    const alertBannerSchema = objOf(alertBannerFields);
29562
 
29563
    const createBarFields = itemsField => [
29564
      type,
29565
      itemsField
29566
    ];
29567
 
29568
    const buttonFields = [
29569
      type,
29570
      text,
29571
      enabled,
29572
      generatedName('button'),
29573
      optionalIcon,
29574
      borderless,
29575
      optionStringEnum('buttonType', [
29576
        'primary',
29577
        'secondary',
29578
        'toolbar'
29579
      ]),
1441 ariadna 29580
      primary,
29581
      defaultedString('context', 'mode:design')
1 efrain 29582
    ];
29583
    const buttonSchema = objOf(buttonFields);
29584
 
29585
    const formComponentFields = [
29586
      type,
29587
      name$1
29588
    ];
29589
    const formComponentWithLabelFields = formComponentFields.concat([optionalLabel]);
29590
 
29591
    const checkboxFields = formComponentFields.concat([
29592
      label,
1441 ariadna 29593
      enabled,
29594
      defaultedString('context', 'mode:design')
1 efrain 29595
    ]);
29596
    const checkboxSchema = objOf(checkboxFields);
29597
    const checkboxDataProcessor = boolean;
29598
 
1441 ariadna 29599
    const collectionFields = formComponentWithLabelFields.concat([
29600
      defaultedColumns('auto'),
29601
      defaultedString('context', 'mode:design')
29602
    ]);
1 efrain 29603
    const collectionSchema = objOf(collectionFields);
29604
    const collectionDataProcessor = arrOfObj([
29605
      value$1,
29606
      text,
29607
      icon
29608
    ]);
29609
 
1441 ariadna 29610
    const colorInputFields = formComponentWithLabelFields.concat([
29611
      defaultedString('storageKey', 'default'),
29612
      defaultedString('context', 'mode:design')
29613
    ]);
1 efrain 29614
    const colorInputSchema = objOf(colorInputFields);
29615
    const colorInputDataProcessor = string;
29616
 
29617
    const colorPickerFields = formComponentWithLabelFields;
29618
    const colorPickerSchema = objOf(colorPickerFields);
29619
    const colorPickerDataProcessor = string;
29620
 
29621
    const customEditorFields = formComponentFields.concat([
29622
      defaultedString('tag', 'textarea'),
29623
      requiredString('scriptId'),
29624
      requiredString('scriptUrl'),
1441 ariadna 29625
      optionFunction('onFocus'),
1 efrain 29626
      defaultedPostMsg('settings', undefined)
29627
    ]);
29628
    const customEditorFieldsOld = formComponentFields.concat([
29629
      defaultedString('tag', 'textarea'),
29630
      requiredFunction('init')
29631
    ]);
29632
    const customEditorSchema = valueOf(v => asRaw('customeditor.old', objOfOnly(customEditorFieldsOld), v).orThunk(() => asRaw('customeditor.new', objOfOnly(customEditorFields), v)));
29633
    const customEditorDataProcessor = string;
29634
 
1441 ariadna 29635
    const dropZoneFields = formComponentWithLabelFields.concat([defaultedString('context', 'mode:design')]);
1 efrain 29636
    const dropZoneSchema = objOf(dropZoneFields);
29637
    const dropZoneDataProcessor = arrOfVal();
29638
 
29639
    const createGridFields = itemsField => [
29640
      type,
29641
      requiredNumber('columns'),
29642
      itemsField
29643
    ];
29644
 
29645
    const htmlPanelFields = [
29646
      type,
29647
      requiredString('html'),
29648
      defaultedStringEnum('presets', 'presentation', [
29649
        'presentation',
29650
        'document'
1441 ariadna 29651
      ]),
29652
      defaultedFunction('onInit', noop),
29653
      defaultedBoolean('stretched', false)
1 efrain 29654
    ];
29655
    const htmlPanelSchema = objOf(htmlPanelFields);
29656
 
29657
    const iframeFields = formComponentWithLabelFields.concat([
29658
      defaultedBoolean('border', false),
29659
      defaultedBoolean('sandboxed', true),
29660
      defaultedBoolean('streamContent', false),
29661
      defaultedBoolean('transparent', true)
29662
    ]);
29663
    const iframeSchema = objOf(iframeFields);
29664
    const iframeDataProcessor = string;
29665
 
29666
    const imagePreviewSchema = objOf(formComponentFields.concat([optionString('height')]));
29667
    const imagePreviewDataProcessor = objOf([
29668
      requiredString('url'),
29669
      optionNumber('zoom'),
29670
      optionNumber('cachedWidth'),
29671
      optionNumber('cachedHeight')
29672
    ]);
29673
 
29674
    const inputFields = formComponentWithLabelFields.concat([
29675
      optionString('inputMode'),
29676
      optionString('placeholder'),
29677
      defaultedBoolean('maximized', false),
1441 ariadna 29678
      enabled,
29679
      defaultedString('context', 'mode:design')
1 efrain 29680
    ]);
29681
    const inputSchema = objOf(inputFields);
29682
    const inputDataProcessor = string;
29683
 
29684
    const createLabelFields = itemsField => [
29685
      type,
29686
      label,
29687
      itemsField,
29688
      defaultedStringEnum('align', 'start', [
29689
        'start',
29690
        'center',
29691
        'end'
1441 ariadna 29692
      ]),
29693
      optionString('for')
1 efrain 29694
    ];
29695
 
29696
    const listBoxSingleItemFields = [
29697
      text,
29698
      value$1
29699
    ];
29700
    const listBoxNestedItemFields = [
29701
      text,
29702
      requiredArrayOf('items', thunkOf('items', () => listBoxItemSchema))
29703
    ];
29704
    const listBoxItemSchema = oneOf([
29705
      objOf(listBoxSingleItemFields),
29706
      objOf(listBoxNestedItemFields)
29707
    ]);
29708
    const listBoxFields = formComponentWithLabelFields.concat([
29709
      requiredArrayOf('items', listBoxItemSchema),
1441 ariadna 29710
      enabled,
29711
      defaultedString('context', 'mode:design')
1 efrain 29712
    ]);
29713
    const listBoxSchema = objOf(listBoxFields);
29714
    const listBoxDataProcessor = string;
29715
 
29716
    const selectBoxFields = formComponentWithLabelFields.concat([
29717
      requiredArrayOfObj('items', [
29718
        text,
29719
        value$1
29720
      ]),
29721
      defaultedNumber('size', 1),
1441 ariadna 29722
      enabled,
29723
      defaultedString('context', 'mode:design')
1 efrain 29724
    ]);
29725
    const selectBoxSchema = objOf(selectBoxFields);
29726
    const selectBoxDataProcessor = string;
29727
 
29728
    const sizeInputFields = formComponentWithLabelFields.concat([
29729
      defaultedBoolean('constrain', true),
1441 ariadna 29730
      enabled,
29731
      defaultedString('context', 'mode:design')
1 efrain 29732
    ]);
29733
    const sizeInputSchema = objOf(sizeInputFields);
29734
    const sizeInputDataProcessor = objOf([
29735
      requiredString('width'),
29736
      requiredString('height')
29737
    ]);
29738
 
29739
    const sliderFields = formComponentFields.concat([
29740
      label,
29741
      defaultedNumber('min', 0),
29742
      defaultedNumber('max', 0)
29743
    ]);
29744
    const sliderSchema = objOf(sliderFields);
29745
    const sliderInputDataProcessor = number;
29746
 
29747
    const tableFields = [
29748
      type,
29749
      requiredArrayOf('header', string),
29750
      requiredArrayOf('cells', arrOf(string))
29751
    ];
29752
    const tableSchema = objOf(tableFields);
29753
 
29754
    const textAreaFields = formComponentWithLabelFields.concat([
29755
      optionString('placeholder'),
29756
      defaultedBoolean('maximized', false),
1441 ariadna 29757
      enabled,
29758
      defaultedString('context', 'mode:design')
1 efrain 29759
    ]);
29760
    const textAreaSchema = objOf(textAreaFields);
29761
    const textAreaDataProcessor = string;
29762
 
29763
    const baseTreeItemFields = [
29764
      requiredStringEnum('type', [
29765
        'directory',
29766
        'leaf'
29767
      ]),
29768
      title,
29769
      requiredString('id'),
1441 ariadna 29770
      optionOf('menu', MenuButtonSchema),
29771
      optionString('customStateIcon'),
29772
      optionString('customStateIconTooltip')
1 efrain 29773
    ];
29774
    const treeItemLeafFields = baseTreeItemFields;
29775
    const treeItemLeafSchema = objOf(treeItemLeafFields);
29776
    const treeItemDirectoryFields = baseTreeItemFields.concat([requiredArrayOf('children', thunkOf('children', () => {
29777
        return choose$2('type', {
29778
          directory: treeItemDirectorySchema,
29779
          leaf: treeItemLeafSchema
29780
        });
29781
      }))]);
29782
    const treeItemDirectorySchema = objOf(treeItemDirectoryFields);
29783
    const treeItemSchema = choose$2('type', {
29784
      directory: treeItemDirectorySchema,
29785
      leaf: treeItemLeafSchema
29786
    });
29787
    const treeFields = [
29788
      type,
29789
      requiredArrayOf('items', treeItemSchema),
29790
      optionFunction('onLeafAction'),
29791
      optionFunction('onToggleExpand'),
29792
      defaultedArrayOf('defaultExpandedIds', [], string),
29793
      optionString('defaultSelectedId')
29794
    ];
29795
    const treeSchema = objOf(treeFields);
29796
 
29797
    const urlInputFields = formComponentWithLabelFields.concat([
29798
      defaultedStringEnum('filetype', 'file', [
29799
        'image',
29800
        'media',
29801
        'file'
29802
      ]),
29803
      enabled,
1441 ariadna 29804
      optionString('picker_text'),
29805
      defaultedString('context', 'mode:design')
1 efrain 29806
    ]);
29807
    const urlInputSchema = objOf(urlInputFields);
29808
    const urlInputDataProcessor = objOf([
29809
      value$1,
29810
      defaultedMeta
29811
    ]);
29812
 
29813
    const createItemsField = name => field$1('items', 'items', required$2(), arrOf(valueOf(v => asRaw(`Checking item of ${ name }`, itemSchema, v).fold(sErr => Result.error(formatError(sErr)), passValue => Result.value(passValue)))));
29814
    const itemSchema = valueThunk(() => choose$2('type', {
29815
      alertbanner: alertBannerSchema,
29816
      bar: objOf(createBarFields(createItemsField('bar'))),
29817
      button: buttonSchema,
29818
      checkbox: checkboxSchema,
29819
      colorinput: colorInputSchema,
29820
      colorpicker: colorPickerSchema,
29821
      dropzone: dropZoneSchema,
29822
      grid: objOf(createGridFields(createItemsField('grid'))),
29823
      iframe: iframeSchema,
29824
      input: inputSchema,
29825
      listbox: listBoxSchema,
29826
      selectbox: selectBoxSchema,
29827
      sizeinput: sizeInputSchema,
29828
      slider: sliderSchema,
29829
      textarea: textAreaSchema,
29830
      urlinput: urlInputSchema,
29831
      customeditor: customEditorSchema,
29832
      htmlpanel: htmlPanelSchema,
29833
      imagepreview: imagePreviewSchema,
29834
      collection: collectionSchema,
29835
      label: objOf(createLabelFields(createItemsField('label'))),
29836
      table: tableSchema,
29837
      tree: treeSchema,
29838
      panel: panelSchema
29839
    }));
29840
    const panelFields = [
29841
      type,
29842
      defaulted('classes', []),
29843
      requiredArrayOf('items', itemSchema)
29844
    ];
29845
    const panelSchema = objOf(panelFields);
29846
 
29847
    const tabFields = [
29848
      generatedName('tab'),
29849
      title,
29850
      requiredArrayOf('items', itemSchema)
29851
    ];
29852
    const tabPanelFields = [
29853
      type,
29854
      requiredArrayOfObj('tabs', tabFields)
29855
    ];
29856
    const tabPanelSchema = objOf(tabPanelFields);
29857
 
29858
    const dialogButtonFields = dialogFooterButtonFields;
29859
    const dialogButtonSchema = dialogFooterButtonSchema;
29860
    const dialogSchema = objOf([
29861
      requiredString('title'),
29862
      requiredOf('body', choose$2('type', {
29863
        panel: panelSchema,
29864
        tabpanel: tabPanelSchema
29865
      })),
29866
      defaultedString('size', 'normal'),
29867
      defaultedArrayOf('buttons', [], dialogButtonSchema),
29868
      defaulted('initialData', {}),
29869
      defaultedFunction('onAction', noop),
29870
      defaultedFunction('onChange', noop),
29871
      defaultedFunction('onSubmit', noop),
29872
      defaultedFunction('onClose', noop),
29873
      defaultedFunction('onCancel', noop),
29874
      defaultedFunction('onTabChange', noop)
29875
    ]);
29876
    const createDialog = spec => asRaw('dialog', dialogSchema, spec);
29877
 
29878
    const urlDialogButtonSchema = objOf([
29879
      requiredStringEnum('type', [
29880
        'cancel',
29881
        'custom'
29882
      ]),
29883
      ...dialogButtonFields
29884
    ]);
29885
    const urlDialogSchema = objOf([
29886
      requiredString('title'),
29887
      requiredString('url'),
29888
      optionNumber('height'),
29889
      optionNumber('width'),
29890
      optionArrayOf('buttons', urlDialogButtonSchema),
29891
      defaultedFunction('onAction', noop),
29892
      defaultedFunction('onCancel', noop),
29893
      defaultedFunction('onClose', noop),
29894
      defaultedFunction('onMessage', noop)
29895
    ]);
29896
    const createUrlDialog = spec => asRaw('dialog', urlDialogSchema, spec);
29897
 
29898
    const getAllObjects = obj => {
29899
      if (isObject(obj)) {
29900
        return [obj].concat(bind$3(values(obj), getAllObjects));
29901
      } else if (isArray(obj)) {
29902
        return bind$3(obj, getAllObjects);
29903
      } else {
29904
        return [];
29905
      }
29906
    };
29907
 
29908
    const isNamedItem = obj => isString(obj.type) && isString(obj.name);
29909
    const dataProcessors = {
29910
      checkbox: checkboxDataProcessor,
29911
      colorinput: colorInputDataProcessor,
29912
      colorpicker: colorPickerDataProcessor,
29913
      dropzone: dropZoneDataProcessor,
29914
      input: inputDataProcessor,
29915
      iframe: iframeDataProcessor,
29916
      imagepreview: imagePreviewDataProcessor,
29917
      selectbox: selectBoxDataProcessor,
29918
      sizeinput: sizeInputDataProcessor,
29919
      slider: sliderInputDataProcessor,
29920
      listbox: listBoxDataProcessor,
29921
      size: sizeInputDataProcessor,
29922
      textarea: textAreaDataProcessor,
29923
      urlinput: urlInputDataProcessor,
29924
      customeditor: customEditorDataProcessor,
29925
      collection: collectionDataProcessor,
29926
      togglemenuitem: dialogToggleMenuItemDataProcessor
29927
    };
29928
    const getDataProcessor = item => Optional.from(dataProcessors[item.type]);
29929
    const getNamedItems = structure => filter$2(getAllObjects(structure), isNamedItem);
29930
 
29931
    const createDataValidator = structure => {
29932
      const namedItems = getNamedItems(structure);
29933
      const fields = bind$3(namedItems, item => getDataProcessor(item).fold(() => [], schema => [requiredOf(item.name, schema)]));
29934
      return objOf(fields);
29935
    };
29936
 
29937
    const extract = structure => {
29938
      var _a;
29939
      const internalDialog = getOrDie(createDialog(structure));
29940
      const dataValidator = createDataValidator(structure);
29941
      const initialData = (_a = structure.initialData) !== null && _a !== void 0 ? _a : {};
29942
      return {
29943
        internalDialog,
29944
        dataValidator,
29945
        initialData
29946
      };
29947
    };
29948
    const DialogManager = {
29949
      open: (factory, structure) => {
29950
        const extraction = extract(structure);
29951
        return factory(extraction.internalDialog, extraction.initialData, extraction.dataValidator);
29952
      },
29953
      openUrl: (factory, structure) => {
29954
        const internalDialog = getOrDie(createUrlDialog(structure));
29955
        return factory(internalDialog);
29956
      },
29957
      redial: structure => extract(structure)
29958
    };
29959
 
29960
    const events = (reflectingConfig, reflectingState) => {
29961
      const update = (component, data) => {
29962
        reflectingConfig.updateState.each(updateState => {
29963
          const newState = updateState(component, data);
29964
          reflectingState.set(newState);
29965
        });
29966
        reflectingConfig.renderComponents.each(renderComponents => {
29967
          const newComponents = renderComponents(data, reflectingState.get());
29968
          const replacer = reflectingConfig.reuseDom ? withReuse : withoutReuse;
29969
          replacer(component, newComponents);
29970
        });
29971
      };
29972
      return derive$2([
29973
        run$1(receive(), (component, message) => {
29974
          const receivingData = message;
29975
          if (!receivingData.universal) {
29976
            const channel = reflectingConfig.channel;
29977
            if (contains$2(receivingData.channels, channel)) {
29978
              update(component, receivingData.data);
29979
            }
29980
          }
29981
        }),
29982
        runOnAttached((comp, _se) => {
29983
          reflectingConfig.initialData.each(rawData => {
29984
            update(comp, rawData);
29985
          });
29986
        })
29987
      ]);
29988
    };
29989
 
29990
    var ActiveReflecting = /*#__PURE__*/Object.freeze({
29991
        __proto__: null,
29992
        events: events
29993
    });
29994
 
29995
    const getState = (component, replaceConfig, reflectState) => reflectState;
29996
 
29997
    var ReflectingApis = /*#__PURE__*/Object.freeze({
29998
        __proto__: null,
29999
        getState: getState
30000
    });
30001
 
30002
    var ReflectingSchema = [
30003
      required$1('channel'),
30004
      option$3('renderComponents'),
30005
      option$3('updateState'),
30006
      option$3('initialData'),
30007
      defaultedBoolean('reuseDom', true)
30008
    ];
30009
 
30010
    const init = () => {
30011
      const cell = Cell(Optional.none());
30012
      const clear = () => cell.set(Optional.none());
30013
      const readState = () => cell.get().getOr('none');
30014
      return {
30015
        readState,
30016
        get: cell.get,
30017
        set: cell.set,
30018
        clear
30019
      };
30020
    };
30021
 
30022
    var ReflectingState = /*#__PURE__*/Object.freeze({
30023
        __proto__: null,
30024
        init: init
30025
    });
30026
 
30027
    const Reflecting = create$4({
30028
      fields: ReflectingSchema,
30029
      name: 'reflecting',
30030
      active: ActiveReflecting,
30031
      apis: ReflectingApis,
30032
      state: ReflectingState
30033
    });
30034
 
30035
    const toValidValues = values => {
30036
      const errors = [];
30037
      const result = {};
30038
      each(values, (value, name) => {
30039
        value.fold(() => {
30040
          errors.push(name);
30041
        }, v => {
30042
          result[name] = v;
30043
        });
30044
      });
30045
      return errors.length > 0 ? Result.error(errors) : Result.value(result);
30046
    };
30047
 
1441 ariadna 30048
    const renderBodyPanel = (spec, dialogData, backstage, getCompByName) => {
1 efrain 30049
      const memForm = record(Form.sketch(parts => ({
30050
        dom: {
30051
          tag: 'div',
30052
          classes: ['tox-form'].concat(spec.classes)
30053
        },
1441 ariadna 30054
        components: map$2(spec.items, item => interpretInForm(parts, item, dialogData, backstage, getCompByName))
1 efrain 30055
      })));
30056
      return {
30057
        dom: {
30058
          tag: 'div',
30059
          classes: ['tox-dialog__body']
30060
        },
30061
        components: [{
30062
            dom: {
30063
              tag: 'div',
30064
              classes: ['tox-dialog__body-content']
30065
            },
30066
            components: [memForm.asSpec()]
30067
          }],
30068
        behaviours: derive$1([
30069
          Keying.config({
30070
            mode: 'acyclic',
30071
            useTabstopAt: not(isPseudoStop)
30072
          }),
30073
          ComposingConfigs.memento(memForm),
30074
          memento(memForm, {
30075
            postprocess: formValue => toValidValues(formValue).fold(err => {
30076
              console.error(err);
30077
              return {};
30078
            }, identity)
30079
          }),
30080
          config('dialog-body-panel', [run$1(focusin(), (comp, se) => {
30081
              comp.getSystem().broadcastOn([dialogFocusShiftedChannel], { newFocus: Optional.some(se.event.target) });
30082
            })])
30083
        ])
30084
      };
30085
    };
30086
 
30087
    const factory$3 = (detail, _spec) => ({
30088
      uid: detail.uid,
30089
      dom: detail.dom,
30090
      components: detail.components,
1441 ariadna 30091
      events: events$9(detail.action),
1 efrain 30092
      behaviours: augment(detail.tabButtonBehaviours, [
30093
        Focusing.config({}),
30094
        Keying.config({
30095
          mode: 'execution',
30096
          useSpace: true,
30097
          useEnter: true
30098
        }),
30099
        Representing.config({
30100
          store: {
30101
            mode: 'memory',
30102
            initialValue: detail.value
30103
          }
30104
        })
30105
      ]),
30106
      domModification: detail.domModification
30107
    });
30108
    const TabButton = single({
30109
      name: 'TabButton',
30110
      configFields: [
30111
        defaulted('uid', undefined),
30112
        required$1('value'),
30113
        field$1('dom', 'dom', mergeWithThunk(() => ({
30114
          attributes: {
30115
            'role': 'tab',
30116
            'id': generate$6('aria'),
30117
            'aria-selected': 'false'
30118
          }
30119
        })), anyValue()),
30120
        option$3('action'),
30121
        defaulted('domModification', {}),
30122
        field('tabButtonBehaviours', [
30123
          Focusing,
30124
          Keying,
30125
          Representing
30126
        ]),
30127
        required$1('view')
30128
      ],
30129
      factory: factory$3
30130
    });
30131
 
30132
    const schema$1 = constant$1([
30133
      required$1('tabs'),
30134
      required$1('dom'),
30135
      defaulted('clickToDismiss', false),
30136
      field('tabbarBehaviours', [
30137
        Highlighting,
30138
        Keying
30139
      ]),
30140
      markers$1([
30141
        'tabClass',
30142
        'selectedClass'
30143
      ])
30144
    ]);
30145
    const tabsPart = group({
30146
      factory: TabButton,
30147
      name: 'tabs',
30148
      unit: 'tab',
30149
      overrides: barDetail => {
30150
        const dismissTab$1 = (tabbar, button) => {
30151
          Highlighting.dehighlight(tabbar, button);
30152
          emitWith(tabbar, dismissTab(), {
30153
            tabbar,
30154
            button
30155
          });
30156
        };
30157
        const changeTab$1 = (tabbar, button) => {
30158
          Highlighting.highlight(tabbar, button);
30159
          emitWith(tabbar, changeTab(), {
30160
            tabbar,
30161
            button
30162
          });
30163
        };
30164
        return {
30165
          action: button => {
30166
            const tabbar = button.getSystem().getByUid(barDetail.uid).getOrDie();
30167
            const activeButton = Highlighting.isHighlighted(tabbar, button);
30168
            const response = (() => {
30169
              if (activeButton && barDetail.clickToDismiss) {
30170
                return dismissTab$1;
30171
              } else if (!activeButton) {
30172
                return changeTab$1;
30173
              } else {
30174
                return noop;
30175
              }
30176
            })();
30177
            response(tabbar, button);
30178
          },
30179
          domModification: { classes: [barDetail.markers.tabClass] }
30180
        };
30181
      }
30182
    });
30183
    const parts$1 = constant$1([tabsPart]);
30184
 
30185
    const factory$2 = (detail, components, _spec, _externals) => ({
30186
      'uid': detail.uid,
30187
      'dom': detail.dom,
30188
      components,
30189
      'debug.sketcher': 'Tabbar',
30190
      'domModification': { attributes: { role: 'tablist' } },
30191
      'behaviours': augment(detail.tabbarBehaviours, [
30192
        Highlighting.config({
30193
          highlightClass: detail.markers.selectedClass,
30194
          itemClass: detail.markers.tabClass,
30195
          onHighlight: (tabbar, tab) => {
30196
            set$9(tab.element, 'aria-selected', 'true');
30197
          },
30198
          onDehighlight: (tabbar, tab) => {
30199
            set$9(tab.element, 'aria-selected', 'false');
30200
          }
30201
        }),
30202
        Keying.config({
30203
          mode: 'flow',
30204
          getInitial: tabbar => {
30205
            return Highlighting.getHighlighted(tabbar).map(tab => tab.element);
30206
          },
30207
          selector: '.' + detail.markers.tabClass,
30208
          executeOnMove: true
30209
        })
30210
      ])
30211
    });
30212
    const Tabbar = composite({
30213
      name: 'Tabbar',
30214
      configFields: schema$1(),
30215
      partFields: parts$1(),
30216
      factory: factory$2
30217
    });
30218
 
30219
    const factory$1 = (detail, _spec) => ({
30220
      uid: detail.uid,
30221
      dom: detail.dom,
30222
      behaviours: augment(detail.tabviewBehaviours, [Replacing.config({})]),
30223
      domModification: { attributes: { role: 'tabpanel' } }
30224
    });
30225
    const Tabview = single({
30226
      name: 'Tabview',
30227
      configFields: [field('tabviewBehaviours', [Replacing])],
30228
      factory: factory$1
30229
    });
30230
 
30231
    const schema = constant$1([
30232
      defaulted('selectFirst', true),
30233
      onHandler('onChangeTab'),
30234
      onHandler('onDismissTab'),
30235
      defaulted('tabs', []),
30236
      field('tabSectionBehaviours', [])
30237
    ]);
30238
    const barPart = required({
30239
      factory: Tabbar,
30240
      schema: [
30241
        required$1('dom'),
30242
        requiredObjOf('markers', [
30243
          required$1('tabClass'),
30244
          required$1('selectedClass')
30245
        ])
30246
      ],
30247
      name: 'tabbar',
30248
      defaults: detail => {
30249
        return { tabs: detail.tabs };
30250
      }
30251
    });
30252
    const viewPart = required({
30253
      factory: Tabview,
30254
      name: 'tabview'
30255
    });
30256
    const parts = constant$1([
30257
      barPart,
30258
      viewPart
30259
    ]);
30260
 
30261
    const factory = (detail, components, _spec, _externals) => {
30262
      const changeTab$1 = button => {
30263
        const tabValue = Representing.getValue(button);
30264
        getPart(button, detail, 'tabview').each(tabview => {
30265
          const tabWithValue = find$5(detail.tabs, t => t.value === tabValue);
30266
          tabWithValue.each(tabData => {
30267
            const panel = tabData.view();
30268
            getOpt(button.element, 'id').each(id => {
30269
              set$9(tabview.element, 'aria-labelledby', id);
30270
            });
30271
            Replacing.set(tabview, panel);
30272
            detail.onChangeTab(tabview, button, panel);
30273
          });
30274
        });
30275
      };
30276
      const changeTabBy = (section, byPred) => {
30277
        getPart(section, detail, 'tabbar').each(tabbar => {
30278
          byPred(tabbar).each(emitExecute);
30279
        });
30280
      };
30281
      return {
30282
        uid: detail.uid,
30283
        dom: detail.dom,
30284
        components,
1441 ariadna 30285
        behaviours: get$4(detail.tabSectionBehaviours),
1 efrain 30286
        events: derive$2(flatten([
30287
          detail.selectFirst ? [runOnAttached((section, _simulatedEvent) => {
30288
              changeTabBy(section, Highlighting.getFirst);
30289
            })] : [],
30290
          [
30291
            run$1(changeTab(), (section, simulatedEvent) => {
30292
              const button = simulatedEvent.event.button;
30293
              changeTab$1(button);
30294
            }),
30295
            run$1(dismissTab(), (section, simulatedEvent) => {
30296
              const button = simulatedEvent.event.button;
30297
              detail.onDismissTab(section, button);
30298
            })
30299
          ]
30300
        ])),
30301
        apis: {
30302
          getViewItems: section => {
30303
            return getPart(section, detail, 'tabview').map(tabview => Replacing.contents(tabview)).getOr([]);
30304
          },
30305
          showTab: (section, tabKey) => {
30306
            const getTabIfNotActive = tabbar => {
30307
              const candidates = Highlighting.getCandidates(tabbar);
30308
              const optTab = find$5(candidates, c => Representing.getValue(c) === tabKey);
30309
              return optTab.filter(tab => !Highlighting.isHighlighted(tabbar, tab));
30310
            };
30311
            changeTabBy(section, getTabIfNotActive);
30312
          }
30313
        }
30314
      };
30315
    };
30316
    const TabSection = composite({
30317
      name: 'TabSection',
30318
      configFields: schema(),
30319
      partFields: parts(),
30320
      factory,
30321
      apis: {
30322
        getViewItems: (apis, component) => apis.getViewItems(component),
30323
        showTab: (apis, component, tabKey) => {
30324
          apis.showTab(component, tabKey);
30325
        }
30326
      }
30327
    });
30328
 
30329
    const measureHeights = (allTabs, tabview, tabviewComp) => map$2(allTabs, (_tab, i) => {
30330
      Replacing.set(tabviewComp, allTabs[i].view());
30331
      const rect = tabview.dom.getBoundingClientRect();
30332
      Replacing.set(tabviewComp, []);
30333
      return rect.height;
30334
    });
30335
    const getMaxHeight = heights => head(sort(heights, (a, b) => {
30336
      if (a > b) {
30337
        return -1;
30338
      } else if (a < b) {
30339
        return +1;
30340
      } else {
30341
        return 0;
30342
      }
30343
    }));
30344
    const getMaxTabviewHeight = (dialog, tabview, tablist) => {
30345
      const documentElement$1 = documentElement(dialog).dom;
30346
      const rootElm = ancestor(dialog, '.tox-dialog-wrap').getOr(dialog);
1441 ariadna 30347
      const isFixed = get$f(rootElm, 'position') === 'fixed';
1 efrain 30348
      let maxHeight;
30349
      if (isFixed) {
30350
        maxHeight = Math.max(documentElement$1.clientHeight, window.innerHeight);
30351
      } else {
30352
        maxHeight = Math.max(documentElement$1.offsetHeight, documentElement$1.scrollHeight);
30353
      }
1441 ariadna 30354
      const tabviewHeight = get$e(tabview);
30355
      const isTabListBeside = tabview.dom.offsetLeft >= tablist.dom.offsetLeft + get$d(tablist);
30356
      const currentTabHeight = isTabListBeside ? Math.max(get$e(tablist), tabviewHeight) : tabviewHeight;
30357
      const dialogTopMargin = parseInt(get$f(dialog, 'margin-top'), 10) || 0;
30358
      const dialogBottomMargin = parseInt(get$f(dialog, 'margin-bottom'), 10) || 0;
30359
      const dialogHeight = get$e(dialog) + dialogTopMargin + dialogBottomMargin;
1 efrain 30360
      const chromeHeight = dialogHeight - currentTabHeight;
30361
      return maxHeight - chromeHeight;
30362
    };
30363
    const showTab = (allTabs, comp) => {
30364
      head(allTabs).each(tab => TabSection.showTab(comp, tab.value));
30365
    };
30366
    const setTabviewHeight = (tabview, height) => {
30367
      set$8(tabview, 'height', height + 'px');
30368
      set$8(tabview, 'flex-basis', height + 'px');
30369
    };
30370
    const updateTabviewHeight = (dialogBody, tabview, maxTabHeight) => {
30371
      ancestor(dialogBody, '[role="dialog"]').each(dialog => {
30372
        descendant(dialog, '[role="tablist"]').each(tablist => {
30373
          maxTabHeight.get().map(height => {
30374
            set$8(tabview, 'height', '0');
30375
            set$8(tabview, 'flex-basis', '0');
30376
            return Math.min(height, getMaxTabviewHeight(dialog, tabview, tablist));
30377
          }).each(height => {
30378
            setTabviewHeight(tabview, height);
30379
          });
30380
        });
30381
      });
30382
    };
30383
    const getTabview = dialog => descendant(dialog, '[role="tabpanel"]');
30384
    const smartMode = allTabs => {
1441 ariadna 30385
      const maxTabHeight = value$4();
1 efrain 30386
      const extraEvents = [
30387
        runOnAttached(comp => {
30388
          const dialog = comp.element;
30389
          getTabview(dialog).each(tabview => {
30390
            set$8(tabview, 'visibility', 'hidden');
30391
            comp.getSystem().getByDom(tabview).toOptional().each(tabviewComp => {
30392
              const heights = measureHeights(allTabs, tabview, tabviewComp);
30393
              const maxTabHeightOpt = getMaxHeight(heights);
30394
              maxTabHeightOpt.fold(maxTabHeight.clear, maxTabHeight.set);
30395
            });
30396
            updateTabviewHeight(dialog, tabview, maxTabHeight);
1441 ariadna 30397
            remove$7(tabview, 'visibility');
1 efrain 30398
            showTab(allTabs, comp);
30399
            requestAnimationFrame(() => {
30400
              updateTabviewHeight(dialog, tabview, maxTabHeight);
30401
            });
30402
          });
30403
        }),
30404
        run$1(windowResize(), comp => {
30405
          const dialog = comp.element;
30406
          getTabview(dialog).each(tabview => {
30407
            updateTabviewHeight(dialog, tabview, maxTabHeight);
30408
          });
30409
        }),
30410
        run$1(formResizeEvent, (comp, _se) => {
30411
          const dialog = comp.element;
30412
          getTabview(dialog).each(tabview => {
30413
            const oldFocus = active$1(getRootNode(tabview));
30414
            set$8(tabview, 'visibility', 'hidden');
30415
            const oldHeight = getRaw(tabview, 'height').map(h => parseInt(h, 10));
1441 ariadna 30416
            remove$7(tabview, 'height');
30417
            remove$7(tabview, 'flex-basis');
1 efrain 30418
            const newHeight = tabview.dom.getBoundingClientRect().height;
30419
            const hasGrown = oldHeight.forall(h => newHeight > h);
30420
            if (hasGrown) {
30421
              maxTabHeight.set(newHeight);
30422
              updateTabviewHeight(dialog, tabview, maxTabHeight);
30423
            } else {
30424
              oldHeight.each(h => {
30425
                setTabviewHeight(tabview, h);
30426
              });
30427
            }
1441 ariadna 30428
            remove$7(tabview, 'visibility');
1 efrain 30429
            oldFocus.each(focus$3);
30430
          });
30431
        })
30432
      ];
30433
      const selectFirst = false;
30434
      return {
30435
        extraEvents,
30436
        selectFirst
30437
      };
30438
    };
30439
 
30440
    const SendDataToSectionChannel = 'send-data-to-section';
30441
    const SendDataToViewChannel = 'send-data-to-view';
1441 ariadna 30442
    const renderTabPanel = (spec, dialogData, backstage, getCompByName) => {
1 efrain 30443
      const storedValue = Cell({});
30444
      const updateDataWithForm = form => {
30445
        const formData = Representing.getValue(form);
30446
        const validData = toValidValues(formData).getOr({});
30447
        const currentData = storedValue.get();
30448
        const newData = deepMerge(currentData, validData);
30449
        storedValue.set(newData);
30450
      };
30451
      const setDataOnForm = form => {
30452
        const tabData = storedValue.get();
30453
        Representing.setValue(form, tabData);
30454
      };
30455
      const oldTab = Cell(null);
30456
      const allTabs = map$2(spec.tabs, tab => {
30457
        return {
30458
          value: tab.name,
30459
          dom: {
30460
            tag: 'div',
30461
            classes: ['tox-dialog__body-nav-item']
30462
          },
30463
          components: [text$2(backstage.shared.providers.translate(tab.title))],
30464
          view: () => {
30465
            return [Form.sketch(parts => ({
30466
                dom: {
30467
                  tag: 'div',
30468
                  classes: ['tox-form']
30469
                },
1441 ariadna 30470
                components: map$2(tab.items, item => interpretInForm(parts, item, dialogData, backstage, getCompByName)),
1 efrain 30471
                formBehaviours: derive$1([
30472
                  Keying.config({
30473
                    mode: 'acyclic',
30474
                    useTabstopAt: not(isPseudoStop)
30475
                  }),
30476
                  config('TabView.form.events', [
30477
                    runOnAttached(setDataOnForm),
30478
                    runOnDetached(updateDataWithForm)
30479
                  ]),
30480
                  Receiving.config({
30481
                    channels: wrapAll([
30482
                      {
30483
                        key: SendDataToSectionChannel,
30484
                        value: { onReceive: updateDataWithForm }
30485
                      },
30486
                      {
30487
                        key: SendDataToViewChannel,
30488
                        value: { onReceive: setDataOnForm }
30489
                      }
30490
                    ])
30491
                  })
30492
                ])
30493
              }))];
30494
          }
30495
        };
30496
      });
30497
      const tabMode = smartMode(allTabs);
30498
      return TabSection.sketch({
30499
        dom: {
30500
          tag: 'div',
30501
          classes: ['tox-dialog__body']
30502
        },
30503
        onChangeTab: (section, button, _viewItems) => {
30504
          const name = Representing.getValue(button);
30505
          emitWith(section, formTabChangeEvent, {
30506
            name,
30507
            oldName: oldTab.get()
30508
          });
30509
          oldTab.set(name);
30510
        },
30511
        tabs: allTabs,
30512
        components: [
30513
          TabSection.parts.tabbar({
30514
            dom: {
30515
              tag: 'div',
30516
              classes: ['tox-dialog__body-nav']
30517
            },
30518
            components: [Tabbar.parts.tabs({})],
30519
            markers: {
30520
              tabClass: 'tox-tab',
30521
              selectedClass: 'tox-dialog__body-nav-item--active'
30522
            },
30523
            tabbarBehaviours: derive$1([Tabstopping.config({})])
30524
          }),
30525
          TabSection.parts.tabview({
30526
            dom: {
30527
              tag: 'div',
30528
              classes: ['tox-dialog__body-content']
30529
            }
30530
          })
30531
        ],
30532
        selectFirst: tabMode.selectFirst,
30533
        tabSectionBehaviours: derive$1([
30534
          config('tabpanel', tabMode.extraEvents),
30535
          Keying.config({ mode: 'acyclic' }),
30536
          Composing.config({ find: comp => head(TabSection.getViewItems(comp)) }),
30537
          withComp(Optional.none(), tsection => {
30538
            tsection.getSystem().broadcastOn([SendDataToSectionChannel], {});
30539
            return storedValue.get();
30540
          }, (tsection, value) => {
30541
            storedValue.set(value);
30542
            tsection.getSystem().broadcastOn([SendDataToViewChannel], {});
30543
          })
30544
        ])
30545
      });
30546
    };
30547
 
1441 ariadna 30548
    const renderBody = (spec, dialogId, contentId, backstage, ariaAttrs, getCompByName) => {
1 efrain 30549
      const renderComponents = incoming => {
30550
        const body = incoming.body;
30551
        switch (body.type) {
30552
        case 'tabpanel': {
1441 ariadna 30553
            return [renderTabPanel(body, incoming.initialData, backstage, getCompByName)];
1 efrain 30554
          }
30555
        default: {
1441 ariadna 30556
            return [renderBodyPanel(body, incoming.initialData, backstage, getCompByName)];
1 efrain 30557
          }
30558
        }
30559
      };
30560
      const updateState = (_comp, incoming) => Optional.some({ isTabPanel: () => incoming.body.type === 'tabpanel' });
30561
      const ariaAttributes = { 'aria-live': 'polite' };
30562
      return {
30563
        dom: {
30564
          tag: 'div',
30565
          classes: ['tox-dialog__content-js'],
30566
          attributes: {
30567
            ...contentId.map(x => ({ id: x })).getOr({}),
30568
            ...ariaAttrs ? ariaAttributes : {}
30569
          }
30570
        },
30571
        components: [],
30572
        behaviours: derive$1([
30573
          ComposingConfigs.childAt(0),
30574
          Reflecting.config({
30575
            channel: `${ bodyChannel }-${ dialogId }`,
30576
            updateState,
30577
            renderComponents,
30578
            initialData: spec
30579
          })
30580
        ])
30581
      };
30582
    };
1441 ariadna 30583
    const renderInlineBody = (spec, dialogId, contentId, backstage, ariaAttrs, getCompByName) => renderBody(spec, dialogId, Optional.some(contentId), backstage, ariaAttrs, getCompByName);
30584
    const renderModalBody = (spec, dialogId, backstage, getCompByName) => {
30585
      const bodySpec = renderBody(spec, dialogId, Optional.none(), backstage, false, getCompByName);
1 efrain 30586
      return ModalDialog.parts.body(bodySpec);
30587
    };
30588
    const renderIframeBody = spec => {
30589
      const bodySpec = {
30590
        dom: {
30591
          tag: 'div',
30592
          classes: ['tox-dialog__content-js']
30593
        },
30594
        components: [{
30595
            dom: {
30596
              tag: 'div',
30597
              classes: ['tox-dialog__body-iframe']
30598
            },
30599
            components: [craft(Optional.none(), {
30600
                dom: {
30601
                  tag: 'iframe',
30602
                  attributes: { src: spec.url }
30603
                },
30604
                behaviours: derive$1([
30605
                  Tabstopping.config({}),
30606
                  Focusing.config({})
30607
                ])
30608
              })]
30609
          }],
30610
        behaviours: derive$1([Keying.config({
30611
            mode: 'acyclic',
30612
            useTabstopAt: not(isPseudoStop)
30613
          })])
30614
      };
30615
      return ModalDialog.parts.body(bodySpec);
30616
    };
30617
 
1441 ariadna 30618
    const isTouch = global$6.deviceType.isTouch();
1 efrain 30619
    const hiddenHeader = (title, close) => ({
30620
      dom: {
30621
        tag: 'div',
30622
        styles: { display: 'none' },
30623
        classes: ['tox-dialog__header']
30624
      },
30625
      components: [
30626
        title,
30627
        close
30628
      ]
30629
    });
30630
    const pClose = (onClose, providersBackstage) => ModalDialog.parts.close(Button.sketch({
30631
      dom: {
30632
        tag: 'button',
30633
        classes: [
30634
          'tox-button',
30635
          'tox-button--icon',
30636
          'tox-button--naked'
30637
        ],
30638
        attributes: {
30639
          'type': 'button',
30640
          'aria-label': providersBackstage.translate('Close')
30641
        }
30642
      },
30643
      action: onClose,
30644
      buttonBehaviours: derive$1([Tabstopping.config({})])
30645
    }));
30646
    const pUntitled = () => ModalDialog.parts.title({
30647
      dom: {
30648
        tag: 'div',
30649
        classes: ['tox-dialog__title'],
30650
        innerHtml: '',
30651
        styles: { display: 'none' }
30652
      }
30653
    });
30654
    const pBodyMessage = (message, providersBackstage) => ModalDialog.parts.body({
30655
      dom: {
30656
        tag: 'div',
30657
        classes: ['tox-dialog__body']
30658
      },
30659
      components: [{
30660
          dom: {
30661
            tag: 'div',
30662
            classes: ['tox-dialog__body-content']
30663
          },
30664
          components: [{ dom: fromHtml(`<p>${ sanitizeHtmlString(providersBackstage.translate(message)) }</p>`) }]
30665
        }]
30666
    });
30667
    const pFooter = buttons => ModalDialog.parts.footer({
30668
      dom: {
30669
        tag: 'div',
30670
        classes: ['tox-dialog__footer']
30671
      },
30672
      components: buttons
30673
    });
30674
    const pFooterGroup = (startButtons, endButtons) => [
30675
      Container.sketch({
30676
        dom: {
30677
          tag: 'div',
30678
          classes: ['tox-dialog__footer-start']
30679
        },
30680
        components: startButtons
30681
      }),
30682
      Container.sketch({
30683
        dom: {
30684
          tag: 'div',
30685
          classes: ['tox-dialog__footer-end']
30686
        },
30687
        components: endButtons
30688
      })
30689
    ];
30690
    const renderDialog$1 = spec => {
30691
      const dialogClass = 'tox-dialog';
30692
      const blockerClass = dialogClass + '-wrap';
30693
      const blockerBackdropClass = blockerClass + '__backdrop';
30694
      const scrollLockClass = dialogClass + '__disable-scroll';
30695
      return ModalDialog.sketch({
30696
        lazySink: spec.lazySink,
30697
        onEscape: comp => {
30698
          spec.onEscape(comp);
30699
          return Optional.some(true);
30700
        },
30701
        useTabstopAt: elem => !isPseudoStop(elem),
30702
        firstTabstop: spec.firstTabstop,
30703
        dom: {
30704
          tag: 'div',
30705
          classes: [dialogClass].concat(spec.extraClasses),
30706
          styles: {
30707
            position: 'relative',
30708
            ...spec.extraStyles
30709
          }
30710
        },
30711
        components: [
30712
          spec.header,
30713
          spec.body,
30714
          ...spec.footer.toArray()
30715
        ],
30716
        parts: {
30717
          blocker: {
30718
            dom: fromHtml(`<div class="${ blockerClass }"></div>`),
30719
            components: [{
30720
                dom: {
30721
                  tag: 'div',
30722
                  classes: isTouch ? [
30723
                    blockerBackdropClass,
30724
                    blockerBackdropClass + '--opaque'
30725
                  ] : [blockerBackdropClass]
30726
                }
30727
              }]
30728
          }
30729
        },
30730
        dragBlockClass: blockerClass,
30731
        modalBehaviours: derive$1([
30732
          Focusing.config({}),
30733
          config('dialog-events', spec.dialogEvents.concat([
30734
            runOnSource(focusin(), (comp, _se) => {
30735
              Blocking.isBlocked(comp) ? noop() : Keying.focusIn(comp);
30736
            }),
30737
            run$1(focusShifted(), (comp, se) => {
30738
              comp.getSystem().broadcastOn([dialogFocusShiftedChannel], { newFocus: se.event.newFocus });
30739
            })
30740
          ])),
30741
          config('scroll-lock', [
30742
            runOnAttached(() => {
30743
              add$2(body(), scrollLockClass);
30744
            }),
30745
            runOnDetached(() => {
1441 ariadna 30746
              remove$3(body(), scrollLockClass);
1 efrain 30747
            })
30748
          ]),
30749
          ...spec.extraBehaviours
30750
        ]),
30751
        eventOrder: {
30752
          [execute$5()]: ['dialog-events'],
30753
          [attachedToDom()]: [
30754
            'scroll-lock',
30755
            'dialog-events',
30756
            'alloy.base.behaviour'
30757
          ],
30758
          [detachedFromDom()]: [
30759
            'alloy.base.behaviour',
30760
            'dialog-events',
30761
            'scroll-lock'
30762
          ],
30763
          ...spec.eventOrder
30764
        }
30765
      });
30766
    };
30767
 
30768
    const renderClose = providersBackstage => Button.sketch({
30769
      dom: {
30770
        tag: 'button',
30771
        classes: [
30772
          'tox-button',
30773
          'tox-button--icon',
30774
          'tox-button--naked'
30775
        ],
30776
        attributes: {
30777
          'type': 'button',
30778
          'aria-label': providersBackstage.translate('Close'),
1441 ariadna 30779
          'data-mce-name': 'close'
1 efrain 30780
        }
30781
      },
1441 ariadna 30782
      buttonBehaviours: derive$1([
30783
        Tabstopping.config({}),
30784
        Tooltipping.config(providersBackstage.tooltips.getConfig({ tooltipText: providersBackstage.translate('Close') }))
30785
      ]),
1 efrain 30786
      components: [render$3('close', {
30787
          tag: 'span',
30788
          classes: ['tox-icon']
30789
        }, providersBackstage.icons)],
30790
      action: comp => {
30791
        emit(comp, formCancelEvent);
30792
      }
30793
    });
30794
    const renderTitle = (spec, dialogId, titleId, providersBackstage) => {
30795
      const renderComponents = data => [text$2(providersBackstage.translate(data.title))];
30796
      return {
30797
        dom: {
1441 ariadna 30798
          tag: 'h1',
1 efrain 30799
          classes: ['tox-dialog__title'],
30800
          attributes: { ...titleId.map(x => ({ id: x })).getOr({}) }
30801
        },
30802
        components: [],
30803
        behaviours: derive$1([Reflecting.config({
30804
            channel: `${ titleChannel }-${ dialogId }`,
30805
            initialData: spec,
30806
            renderComponents
30807
          })])
30808
      };
30809
    };
30810
    const renderDragHandle = () => ({ dom: fromHtml('<div class="tox-dialog__draghandle"></div>') });
30811
    const renderInlineHeader = (spec, dialogId, titleId, providersBackstage) => Container.sketch({
30812
      dom: fromHtml('<div class="tox-dialog__header"></div>'),
30813
      components: [
30814
        renderTitle(spec, dialogId, Optional.some(titleId), providersBackstage),
30815
        renderDragHandle(),
30816
        renderClose(providersBackstage)
30817
      ],
30818
      containerBehaviours: derive$1([Dragging.config({
30819
          mode: 'mouse',
30820
          blockerClass: 'blocker',
30821
          getTarget: handle => {
30822
            return closest$1(handle, '[role="dialog"]').getOrDie();
30823
          },
30824
          snaps: {
30825
            getSnapPoints: () => [],
30826
            leftAttr: 'data-drag-left',
30827
            topAttr: 'data-drag-top'
30828
          }
30829
        })])
30830
    });
30831
    const renderModalHeader = (spec, dialogId, providersBackstage) => {
30832
      const pTitle = ModalDialog.parts.title(renderTitle(spec, dialogId, Optional.none(), providersBackstage));
30833
      const pHandle = ModalDialog.parts.draghandle(renderDragHandle());
30834
      const pClose = ModalDialog.parts.close(renderClose(providersBackstage));
30835
      const components = [pTitle].concat(spec.draggable ? [pHandle] : []).concat([pClose]);
30836
      return Container.sketch({
30837
        dom: fromHtml('<div class="tox-dialog__header"></div>'),
30838
        components
30839
      });
30840
    };
30841
 
30842
    const getHeader = (title, dialogId, backstage) => renderModalHeader({
30843
      title: backstage.shared.providers.translate(title),
30844
      draggable: backstage.dialog.isDraggableModal()
30845
    }, dialogId, backstage.shared.providers);
30846
    const getBusySpec = (message, bs, providers, headerHeight) => ({
30847
      dom: {
30848
        tag: 'div',
30849
        classes: ['tox-dialog__busy-spinner'],
30850
        attributes: { 'aria-label': providers.translate(message) },
30851
        styles: {
30852
          left: '0px',
30853
          right: '0px',
30854
          bottom: '0px',
30855
          top: `${ headerHeight.getOr(0) }px`,
30856
          position: 'absolute'
30857
        }
30858
      },
30859
      behaviours: bs,
30860
      components: [{ dom: fromHtml('<div class="tox-spinner"><div></div><div></div><div></div></div>') }]
30861
    });
30862
    const getEventExtras = (lazyDialog, providers, extra) => ({
30863
      onClose: () => extra.closeWindow(),
30864
      onBlock: blockEvent => {
1441 ariadna 30865
        const headerHeight = descendant(lazyDialog().element, '.tox-dialog__header').map(header => get$e(header));
1 efrain 30866
        ModalDialog.setBusy(lazyDialog(), (_comp, bs) => getBusySpec(blockEvent.message, bs, providers, headerHeight));
30867
      },
30868
      onUnblock: () => {
30869
        ModalDialog.setIdle(lazyDialog());
30870
      }
30871
    });
30872
    const fullscreenClass = 'tox-dialog--fullscreen';
30873
    const largeDialogClass = 'tox-dialog--width-lg';
30874
    const mediumDialogClass = 'tox-dialog--width-md';
30875
    const getDialogSizeClass = size => {
30876
      switch (size) {
30877
      case 'large':
30878
        return Optional.some(largeDialogClass);
30879
      case 'medium':
30880
        return Optional.some(mediumDialogClass);
30881
      default:
30882
        return Optional.none();
30883
      }
30884
    };
30885
    const updateDialogSizeClass = (size, component) => {
30886
      const dialogBody = SugarElement.fromDom(component.element.dom);
30887
      if (!has(dialogBody, fullscreenClass)) {
1441 ariadna 30888
        remove$2(dialogBody, [
1 efrain 30889
          largeDialogClass,
30890
          mediumDialogClass
30891
        ]);
30892
        getDialogSizeClass(size).each(dialogSizeClass => add$2(dialogBody, dialogSizeClass));
30893
      }
30894
    };
30895
    const toggleFullscreen = (comp, currentSize) => {
30896
      const dialogBody = SugarElement.fromDom(comp.element.dom);
1441 ariadna 30897
      const classes = get$9(dialogBody);
1 efrain 30898
      const currentSizeClass = find$5(classes, c => c === largeDialogClass || c === mediumDialogClass).or(getDialogSizeClass(currentSize));
30899
      toggle$3(dialogBody, [
30900
        fullscreenClass,
30901
        ...currentSizeClass.toArray()
30902
      ]);
30903
    };
30904
    const renderModalDialog = (spec, dialogEvents, backstage) => build$1(renderDialog$1({
30905
      ...spec,
30906
      firstTabstop: 1,
30907
      lazySink: backstage.shared.getSink,
30908
      extraBehaviours: [
30909
        memory({}),
30910
        ...spec.extraBehaviours
30911
      ],
30912
      onEscape: comp => {
30913
        emit(comp, formCancelEvent);
30914
      },
30915
      dialogEvents,
30916
      eventOrder: {
30917
        [receive()]: [
30918
          Reflecting.name(),
30919
          Receiving.name()
30920
        ],
30921
        [attachedToDom()]: [
30922
          'scroll-lock',
30923
          Reflecting.name(),
30924
          'messages',
30925
          'dialog-events',
30926
          'alloy.base.behaviour'
30927
        ],
30928
        [detachedFromDom()]: [
30929
          'alloy.base.behaviour',
30930
          'dialog-events',
30931
          'messages',
30932
          Reflecting.name(),
30933
          'scroll-lock'
30934
        ]
30935
      }
30936
    }));
30937
    const mapMenuButtons = (buttons, menuItemStates = {}) => {
30938
      const mapItems = button => {
30939
        const items = map$2(button.items, item => {
1441 ariadna 30940
          const cell = get$h(menuItemStates, item.name).getOr(Cell(false));
1 efrain 30941
          return {
30942
            ...item,
30943
            storage: cell
30944
          };
30945
        });
30946
        return {
30947
          ...button,
30948
          items
30949
        };
30950
      };
30951
      return map$2(buttons, button => {
30952
        return button.type === 'menu' ? mapItems(button) : button;
30953
      });
30954
    };
30955
    const extractCellsToObject = buttons => foldl(buttons, (acc, button) => {
30956
      if (button.type === 'menu') {
30957
        const menuButton = button;
30958
        return foldl(menuButton.items, (innerAcc, item) => {
30959
          innerAcc[item.name] = item.storage;
30960
          return innerAcc;
30961
        }, acc);
30962
      }
30963
      return acc;
30964
    }, {});
30965
 
30966
    const initCommonEvents = (fireApiEvent, extras) => [
30967
      runWithTarget(focusin(), onFocus),
30968
      fireApiEvent(formCloseEvent, (_api, spec, _event, self) => {
1441 ariadna 30969
        if (hasFocus(self.element)) {
30970
          active$1(getRootNode(self.element)).each(blur$1);
30971
        }
1 efrain 30972
        extras.onClose();
30973
        spec.onClose();
30974
      }),
30975
      fireApiEvent(formCancelEvent, (api, spec, _event, self) => {
30976
        spec.onCancel(api);
30977
        emit(self, formCloseEvent);
30978
      }),
30979
      run$1(formUnblockEvent, (_c, _se) => extras.onUnblock()),
30980
      run$1(formBlockEvent, (_c, se) => extras.onBlock(se.event))
30981
    ];
30982
    const initUrlDialog = (getInstanceApi, extras) => {
30983
      const fireApiEvent = (eventName, f) => run$1(eventName, (c, se) => {
30984
        withSpec(c, (spec, _c) => {
30985
          f(getInstanceApi(), spec, se.event, c);
30986
        });
30987
      });
30988
      const withSpec = (c, f) => {
30989
        Reflecting.getState(c).get().each(currentDialog => {
30990
          f(currentDialog, c);
30991
        });
30992
      };
30993
      return [
30994
        ...initCommonEvents(fireApiEvent, extras),
30995
        fireApiEvent(formActionEvent, (api, spec, event) => {
30996
          spec.onAction(api, { name: event.name });
30997
        })
30998
      ];
30999
    };
31000
    const initDialog = (getInstanceApi, extras, getSink) => {
31001
      const fireApiEvent = (eventName, f) => run$1(eventName, (c, se) => {
31002
        withSpec(c, (spec, _c) => {
31003
          f(getInstanceApi(), spec, se.event, c);
31004
        });
31005
      });
31006
      const withSpec = (c, f) => {
31007
        Reflecting.getState(c).get().each(currentDialogInit => {
31008
          f(currentDialogInit.internalDialog, c);
31009
        });
31010
      };
31011
      return [
31012
        ...initCommonEvents(fireApiEvent, extras),
31013
        fireApiEvent(formSubmitEvent, (api, spec) => spec.onSubmit(api)),
31014
        fireApiEvent(formChangeEvent, (api, spec, event) => {
31015
          spec.onChange(api, { name: event.name });
31016
        }),
31017
        fireApiEvent(formActionEvent, (api, spec, event, component) => {
31018
          const focusIn = () => component.getSystem().isConnected() ? Keying.focusIn(component) : undefined;
31019
          const isDisabled = focused => has$1(focused, 'disabled') || getOpt(focused, 'aria-disabled').exists(val => val === 'true');
31020
          const rootNode = getRootNode(component.element);
31021
          const current = active$1(rootNode);
31022
          spec.onAction(api, {
31023
            name: event.name,
31024
            value: event.value
31025
          });
31026
          active$1(rootNode).fold(focusIn, focused => {
31027
            if (isDisabled(focused)) {
31028
              focusIn();
31029
            } else if (current.exists(cur => contains(focused, cur) && isDisabled(cur))) {
31030
              focusIn();
31031
            } else {
31032
              getSink().toOptional().filter(sink => !contains(sink.element, focused)).each(focusIn);
31033
            }
31034
          });
31035
        }),
31036
        fireApiEvent(formTabChangeEvent, (api, spec, event) => {
31037
          spec.onTabChange(api, {
31038
            newTabName: event.name,
31039
            oldTabName: event.oldName
31040
          });
31041
        }),
31042
        runOnDetached(component => {
31043
          const api = getInstanceApi();
31044
          Representing.setValue(component, api.getData());
31045
        })
31046
      ];
31047
    };
31048
 
31049
    const makeButton = (button, backstage) => renderFooterButton(button, button.type, backstage);
31050
    const lookup = (compInSystem, footerButtons, buttonName) => find$5(footerButtons, button => button.name === buttonName).bind(memButton => memButton.memento.getOpt(compInSystem));
31051
    const renderComponents = (_data, state) => {
31052
      const footerButtons = state.map(s => s.footerButtons).getOr([]);
31053
      const buttonGroups = partition$3(footerButtons, button => button.align === 'start');
31054
      const makeGroup = (edge, buttons) => Container.sketch({
31055
        dom: {
31056
          tag: 'div',
31057
          classes: [`tox-dialog__footer-${ edge }`]
31058
        },
31059
        components: map$2(buttons, button => button.memento.asSpec())
31060
      });
31061
      const startButtons = makeGroup('start', buttonGroups.pass);
31062
      const endButtons = makeGroup('end', buttonGroups.fail);
31063
      return [
31064
        startButtons,
31065
        endButtons
31066
      ];
31067
    };
31068
    const renderFooter = (initSpec, dialogId, backstage) => {
31069
      const updateState = (comp, data) => {
31070
        const footerButtons = map$2(data.buttons, button => {
31071
          const memButton = record(makeButton(button, backstage));
31072
          return {
31073
            name: button.name,
31074
            align: button.align,
31075
            memento: memButton
31076
          };
31077
        });
31078
        const lookupByName = buttonName => lookup(comp, footerButtons, buttonName);
31079
        return Optional.some({
31080
          lookupByName,
31081
          footerButtons
31082
        });
31083
      };
31084
      return {
31085
        dom: fromHtml('<div class="tox-dialog__footer"></div>'),
31086
        components: [],
31087
        behaviours: derive$1([Reflecting.config({
31088
            channel: `${ footerChannel }-${ dialogId }`,
31089
            initialData: initSpec,
31090
            updateState,
31091
            renderComponents
31092
          })])
31093
      };
31094
    };
31095
    const renderInlineFooter = (initSpec, dialogId, backstage) => renderFooter(initSpec, dialogId, backstage);
31096
    const renderModalFooter = (initSpec, dialogId, backstage) => ModalDialog.parts.footer(renderFooter(initSpec, dialogId, backstage));
31097
 
31098
    const getCompByName = (access, name) => {
31099
      const root = access.getRoot();
31100
      if (root.getSystem().isConnected()) {
31101
        const form = Composing.getCurrent(access.getFormWrapper()).getOr(access.getFormWrapper());
31102
        return Form.getField(form, name).orThunk(() => {
31103
          const footer = access.getFooter();
31104
          const footerState = footer.bind(f => Reflecting.getState(f).get());
31105
          return footerState.bind(f => f.lookupByName(name));
31106
        });
31107
      } else {
31108
        return Optional.none();
31109
      }
31110
    };
31111
    const validateData$1 = (access, data) => {
31112
      const root = access.getRoot();
31113
      return Reflecting.getState(root).get().map(dialogState => getOrDie(asRaw('data', dialogState.dataValidator, data))).getOr(data);
31114
    };
31115
    const getDialogApi = (access, doRedial, menuItemStates) => {
31116
      const withRoot = f => {
31117
        const root = access.getRoot();
31118
        if (root.getSystem().isConnected()) {
31119
          f(root);
31120
        }
31121
      };
31122
      const getData = () => {
31123
        const root = access.getRoot();
31124
        const valueComp = root.getSystem().isConnected() ? access.getFormWrapper() : root;
31125
        const representedValues = Representing.getValue(valueComp);
31126
        const menuItemCurrentState = map$1(menuItemStates, cell => cell.get());
31127
        return {
31128
          ...representedValues,
31129
          ...menuItemCurrentState
31130
        };
31131
      };
31132
      const setData = newData => {
31133
        withRoot(_ => {
31134
          const prevData = instanceApi.getData();
31135
          const mergedData = deepMerge(prevData, newData);
31136
          const newInternalData = validateData$1(access, mergedData);
31137
          const form = access.getFormWrapper();
31138
          Representing.setValue(form, newInternalData);
31139
          each(menuItemStates, (v, k) => {
31140
            if (has$2(mergedData, k)) {
31141
              v.set(mergedData[k]);
31142
            }
31143
          });
31144
        });
31145
      };
31146
      const setEnabled = (name, state) => {
31147
        getCompByName(access, name).each(state ? Disabling.enable : Disabling.disable);
31148
      };
31149
      const focus = name => {
31150
        getCompByName(access, name).each(Focusing.focus);
31151
      };
31152
      const block = message => {
31153
        if (!isString(message)) {
31154
          throw new Error('The dialogInstanceAPI.block function should be passed a blocking message of type string as an argument');
31155
        }
31156
        withRoot(root => {
31157
          emitWith(root, formBlockEvent, { message });
31158
        });
31159
      };
31160
      const unblock = () => {
31161
        withRoot(root => {
31162
          emit(root, formUnblockEvent);
31163
        });
31164
      };
31165
      const showTab = name => {
31166
        withRoot(_ => {
31167
          const body = access.getBody();
31168
          const bodyState = Reflecting.getState(body);
31169
          if (bodyState.get().exists(b => b.isTabPanel())) {
31170
            Composing.getCurrent(body).each(tabSection => {
31171
              TabSection.showTab(tabSection, name);
31172
            });
31173
          }
31174
        });
31175
      };
31176
      const redial = d => {
31177
        withRoot(root => {
31178
          const id = access.getId();
31179
          const dialogInit = doRedial(d);
31180
          const storedMenuButtons = mapMenuButtons(dialogInit.internalDialog.buttons, menuItemStates);
31181
          root.getSystem().broadcastOn([`${ dialogChannel }-${ id }`], dialogInit);
31182
          root.getSystem().broadcastOn([`${ titleChannel }-${ id }`], dialogInit.internalDialog);
31183
          root.getSystem().broadcastOn([`${ bodyChannel }-${ id }`], dialogInit.internalDialog);
31184
          root.getSystem().broadcastOn([`${ footerChannel }-${ id }`], {
31185
            ...dialogInit.internalDialog,
31186
            buttons: storedMenuButtons
31187
          });
31188
          instanceApi.setData(dialogInit.initialData);
31189
        });
31190
      };
31191
      const close = () => {
31192
        withRoot(root => {
31193
          emit(root, formCloseEvent);
31194
        });
31195
      };
31196
      const instanceApi = {
31197
        getData,
31198
        setData,
31199
        setEnabled,
31200
        focus,
31201
        block,
31202
        unblock,
31203
        showTab,
31204
        redial,
31205
        close,
31206
        toggleFullscreen: access.toggleFullscreen
31207
      };
31208
      return instanceApi;
31209
    };
31210
 
31211
    const renderDialog = (dialogInit, extra, backstage) => {
31212
      const dialogId = generate$6('dialog');
31213
      const internalDialog = dialogInit.internalDialog;
31214
      const header = getHeader(internalDialog.title, dialogId, backstage);
31215
      const dialogSize = Cell(internalDialog.size);
1441 ariadna 31216
      const getCompByName$1 = name => getCompByName(modalAccess, name);
1 efrain 31217
      const dialogSizeClasses = getDialogSizeClass(dialogSize.get()).toArray();
31218
      const updateState = (comp, incoming) => {
31219
        dialogSize.set(incoming.internalDialog.size);
31220
        updateDialogSizeClass(incoming.internalDialog.size, comp);
31221
        return Optional.some(incoming);
31222
      };
31223
      const body = renderModalBody({
31224
        body: internalDialog.body,
31225
        initialData: internalDialog.initialData
1441 ariadna 31226
      }, dialogId, backstage, getCompByName$1);
1 efrain 31227
      const storedMenuButtons = mapMenuButtons(internalDialog.buttons);
31228
      const objOfCells = extractCellsToObject(storedMenuButtons);
31229
      const footer = someIf(storedMenuButtons.length !== 0, renderModalFooter({ buttons: storedMenuButtons }, dialogId, backstage));
31230
      const dialogEvents = initDialog(() => instanceApi, getEventExtras(() => dialog, backstage.shared.providers, extra), backstage.shared.getSink);
31231
      const spec = {
31232
        id: dialogId,
31233
        header,
31234
        body,
31235
        footer,
31236
        extraClasses: dialogSizeClasses,
31237
        extraBehaviours: [Reflecting.config({
31238
            channel: `${ dialogChannel }-${ dialogId }`,
31239
            updateState,
31240
            initialData: dialogInit
31241
          })],
31242
        extraStyles: {}
31243
      };
31244
      const dialog = renderModalDialog(spec, dialogEvents, backstage);
31245
      const modalAccess = (() => {
31246
        const getForm = () => {
31247
          const outerForm = ModalDialog.getBody(dialog);
31248
          return Composing.getCurrent(outerForm).getOr(outerForm);
31249
        };
31250
        const toggleFullscreen$1 = () => {
31251
          toggleFullscreen(dialog, dialogSize.get());
31252
        };
31253
        return {
31254
          getId: constant$1(dialogId),
31255
          getRoot: constant$1(dialog),
31256
          getBody: () => ModalDialog.getBody(dialog),
31257
          getFooter: () => ModalDialog.getFooter(dialog),
31258
          getFormWrapper: getForm,
31259
          toggleFullscreen: toggleFullscreen$1
31260
        };
31261
      })();
31262
      const instanceApi = getDialogApi(modalAccess, extra.redial, objOfCells);
31263
      return {
31264
        dialog,
31265
        instanceApi
31266
      };
31267
    };
31268
 
31269
    const renderInlineDialog = (dialogInit, extra, backstage, ariaAttrs = false, refreshDocking) => {
31270
      const dialogId = generate$6('dialog');
31271
      const dialogLabelId = generate$6('dialog-label');
31272
      const dialogContentId = generate$6('dialog-content');
31273
      const internalDialog = dialogInit.internalDialog;
1441 ariadna 31274
      const getCompByName$1 = name => getCompByName(modalAccess, name);
1 efrain 31275
      const dialogSize = Cell(internalDialog.size);
31276
      const dialogSizeClass = getDialogSizeClass(dialogSize.get()).toArray();
31277
      const updateState = (comp, incoming) => {
31278
        dialogSize.set(incoming.internalDialog.size);
31279
        updateDialogSizeClass(incoming.internalDialog.size, comp);
31280
        refreshDocking();
31281
        return Optional.some(incoming);
31282
      };
31283
      const memHeader = record(renderInlineHeader({
31284
        title: internalDialog.title,
31285
        draggable: true
31286
      }, dialogId, dialogLabelId, backstage.shared.providers));
31287
      const memBody = record(renderInlineBody({
31288
        body: internalDialog.body,
31289
        initialData: internalDialog.initialData
1441 ariadna 31290
      }, dialogId, dialogContentId, backstage, ariaAttrs, getCompByName$1));
1 efrain 31291
      const storagedMenuButtons = mapMenuButtons(internalDialog.buttons);
31292
      const objOfCells = extractCellsToObject(storagedMenuButtons);
31293
      const optMemFooter = someIf(storagedMenuButtons.length !== 0, record(renderInlineFooter({ buttons: storagedMenuButtons }, dialogId, backstage)));
31294
      const dialogEvents = initDialog(() => instanceApi, {
31295
        onBlock: event => {
31296
          Blocking.block(dialog, (_comp, bs) => {
1441 ariadna 31297
            const headerHeight = memHeader.getOpt(dialog).map(dialog => get$e(dialog.element));
1 efrain 31298
            return getBusySpec(event.message, bs, backstage.shared.providers, headerHeight);
31299
          });
31300
        },
31301
        onUnblock: () => {
31302
          Blocking.unblock(dialog);
31303
        },
31304
        onClose: () => extra.closeWindow()
31305
      }, backstage.shared.getSink);
31306
      const inlineClass = 'tox-dialog-inline';
1441 ariadna 31307
      const os = detect$1().os;
1 efrain 31308
      const dialog = build$1({
31309
        dom: {
31310
          tag: 'div',
31311
          classes: [
31312
            'tox-dialog',
31313
            inlineClass,
31314
            ...dialogSizeClass
31315
          ],
31316
          attributes: {
31317
            role: 'dialog',
1441 ariadna 31318
            ...os.isMacOS() ? { 'aria-label': internalDialog.title } : { 'aria-labelledby': dialogLabelId }
1 efrain 31319
          }
31320
        },
31321
        eventOrder: {
31322
          [receive()]: [
31323
            Reflecting.name(),
31324
            Receiving.name()
31325
          ],
31326
          [execute$5()]: ['execute-on-form'],
31327
          [attachedToDom()]: [
31328
            'reflecting',
31329
            'execute-on-form'
31330
          ]
31331
        },
31332
        behaviours: derive$1([
31333
          Keying.config({
31334
            mode: 'cyclic',
31335
            onEscape: c => {
31336
              emit(c, formCloseEvent);
31337
              return Optional.some(true);
31338
            },
1441 ariadna 31339
            useTabstopAt: elem => !isPseudoStop(elem) && (name$3(elem) !== 'button' || get$g(elem, 'disabled') !== 'disabled'),
1 efrain 31340
            firstTabstop: 1
31341
          }),
31342
          Reflecting.config({
31343
            channel: `${ dialogChannel }-${ dialogId }`,
31344
            updateState,
31345
            initialData: dialogInit
31346
          }),
31347
          Focusing.config({}),
31348
          config('execute-on-form', dialogEvents.concat([
31349
            runOnSource(focusin(), (comp, _se) => {
31350
              Keying.focusIn(comp);
31351
            }),
31352
            run$1(focusShifted(), (comp, se) => {
31353
              comp.getSystem().broadcastOn([dialogFocusShiftedChannel], { newFocus: se.event.newFocus });
31354
            })
31355
          ])),
31356
          Blocking.config({ getRoot: () => Optional.some(dialog) }),
31357
          Replacing.config({}),
31358
          memory({})
31359
        ]),
31360
        components: [
31361
          memHeader.asSpec(),
31362
          memBody.asSpec(),
31363
          ...optMemFooter.map(memFooter => memFooter.asSpec()).toArray()
31364
        ]
31365
      });
31366
      const toggleFullscreen$1 = () => {
31367
        toggleFullscreen(dialog, dialogSize.get());
31368
      };
1441 ariadna 31369
      const modalAccess = {
1 efrain 31370
        getId: constant$1(dialogId),
31371
        getRoot: constant$1(dialog),
31372
        getFooter: () => optMemFooter.map(memFooter => memFooter.get(dialog)),
31373
        getBody: () => memBody.get(dialog),
31374
        getFormWrapper: () => {
31375
          const body = memBody.get(dialog);
31376
          return Composing.getCurrent(body).getOr(body);
31377
        },
31378
        toggleFullscreen: toggleFullscreen$1
1441 ariadna 31379
      };
31380
      const instanceApi = getDialogApi(modalAccess, extra.redial, objOfCells);
1 efrain 31381
      return {
31382
        dialog,
31383
        instanceApi
31384
      };
31385
    };
31386
 
31387
    var global = tinymce.util.Tools.resolve('tinymce.util.URI');
31388
 
31389
    const getUrlDialogApi = root => {
31390
      const withRoot = f => {
31391
        if (root.getSystem().isConnected()) {
31392
          f(root);
31393
        }
31394
      };
31395
      const block = message => {
31396
        if (!isString(message)) {
31397
          throw new Error('The urlDialogInstanceAPI.block function should be passed a blocking message of type string as an argument');
31398
        }
31399
        withRoot(root => {
31400
          emitWith(root, formBlockEvent, { message });
31401
        });
31402
      };
31403
      const unblock = () => {
31404
        withRoot(root => {
31405
          emit(root, formUnblockEvent);
31406
        });
31407
      };
31408
      const close = () => {
31409
        withRoot(root => {
31410
          emit(root, formCloseEvent);
31411
        });
31412
      };
31413
      const sendMessage = data => {
31414
        withRoot(root => {
31415
          root.getSystem().broadcastOn([bodySendMessageChannel], data);
31416
        });
31417
      };
31418
      return {
31419
        block,
31420
        unblock,
31421
        close,
31422
        sendMessage
31423
      };
31424
    };
31425
 
31426
    const SUPPORTED_MESSAGE_ACTIONS = [
31427
      'insertContent',
31428
      'setContent',
31429
      'execCommand',
31430
      'close',
31431
      'block',
31432
      'unblock'
31433
    ];
31434
    const isSupportedMessage = data => isObject(data) && SUPPORTED_MESSAGE_ACTIONS.indexOf(data.mceAction) !== -1;
31435
    const isCustomMessage = data => !isSupportedMessage(data) && isObject(data) && has$2(data, 'mceAction');
31436
    const handleMessage = (editor, api, data) => {
31437
      switch (data.mceAction) {
31438
      case 'insertContent':
31439
        editor.insertContent(data.content);
31440
        break;
31441
      case 'setContent':
31442
        editor.setContent(data.content);
31443
        break;
31444
      case 'execCommand':
31445
        const ui = isBoolean(data.ui) ? data.ui : false;
31446
        editor.execCommand(data.cmd, ui, data.value);
31447
        break;
31448
      case 'close':
31449
        api.close();
31450
        break;
31451
      case 'block':
31452
        api.block(data.message);
31453
        break;
31454
      case 'unblock':
31455
        api.unblock();
31456
        break;
31457
      }
31458
    };
31459
    const renderUrlDialog = (internalDialog, extra, editor, backstage) => {
31460
      const dialogId = generate$6('dialog');
31461
      const header = getHeader(internalDialog.title, dialogId, backstage);
31462
      const body = renderIframeBody(internalDialog);
31463
      const footer = internalDialog.buttons.bind(buttons => {
31464
        if (buttons.length === 0) {
31465
          return Optional.none();
31466
        } else {
31467
          return Optional.some(renderModalFooter({ buttons }, dialogId, backstage));
31468
        }
31469
      });
31470
      const dialogEvents = initUrlDialog(() => instanceApi, getEventExtras(() => dialog, backstage.shared.providers, extra));
31471
      const styles = {
31472
        ...internalDialog.height.fold(() => ({}), height => ({
31473
          'height': height + 'px',
31474
          'max-height': height + 'px'
31475
        })),
31476
        ...internalDialog.width.fold(() => ({}), width => ({
31477
          'width': width + 'px',
31478
          'max-width': width + 'px'
31479
        }))
31480
      };
31481
      const classes = internalDialog.width.isNone() && internalDialog.height.isNone() ? ['tox-dialog--width-lg'] : [];
31482
      const iframeUri = new global(internalDialog.url, { base_uri: new global(window.location.href) });
31483
      const iframeDomain = `${ iframeUri.protocol }://${ iframeUri.host }${ iframeUri.port ? ':' + iframeUri.port : '' }`;
31484
      const messageHandlerUnbinder = unbindable();
31485
      const updateState = (_comp, incoming) => Optional.some(incoming);
31486
      const extraBehaviours = [
31487
        Reflecting.config({
31488
          channel: `${ dialogChannel }-${ dialogId }`,
31489
          updateState,
31490
          initialData: internalDialog
31491
        }),
31492
        config('messages', [
31493
          runOnAttached(() => {
31494
            const unbind = bind(SugarElement.fromDom(window), 'message', e => {
31495
              if (iframeUri.isSameOrigin(new global(e.raw.origin))) {
31496
                const data = e.raw.data;
31497
                if (isSupportedMessage(data)) {
31498
                  handleMessage(editor, instanceApi, data);
31499
                } else if (isCustomMessage(data)) {
31500
                  internalDialog.onMessage(instanceApi, data);
31501
                }
31502
              }
31503
            });
31504
            messageHandlerUnbinder.set(unbind);
31505
          }),
31506
          runOnDetached(messageHandlerUnbinder.clear)
31507
        ]),
31508
        Receiving.config({
31509
          channels: {
31510
            [bodySendMessageChannel]: {
31511
              onReceive: (comp, data) => {
31512
                descendant(comp.element, 'iframe').each(iframeEle => {
31513
                  const iframeWin = iframeEle.dom.contentWindow;
31514
                  if (isNonNullable(iframeWin)) {
31515
                    iframeWin.postMessage(data, iframeDomain);
31516
                  }
31517
                });
31518
              }
31519
            }
31520
          }
31521
        })
31522
      ];
31523
      const spec = {
31524
        id: dialogId,
31525
        header,
31526
        body,
31527
        footer,
31528
        extraClasses: classes,
31529
        extraBehaviours,
31530
        extraStyles: styles
31531
      };
31532
      const dialog = renderModalDialog(spec, dialogEvents, backstage);
31533
      const instanceApi = getUrlDialogApi(dialog);
31534
      return {
31535
        dialog,
31536
        instanceApi
31537
      };
31538
    };
31539
 
31540
    const setup$2 = backstage => {
31541
      const sharedBackstage = backstage.shared;
31542
      const open = (message, callback) => {
31543
        const closeDialog = () => {
31544
          ModalDialog.hide(alertDialog);
31545
          callback();
31546
        };
31547
        const memFooterClose = record(renderFooterButton({
1441 ariadna 31548
          context: 'any',
1 efrain 31549
          name: 'close-alert',
31550
          text: 'OK',
31551
          primary: true,
31552
          buttonType: Optional.some('primary'),
31553
          align: 'end',
31554
          enabled: true,
31555
          icon: Optional.none()
31556
        }, 'cancel', backstage));
31557
        const titleSpec = pUntitled();
31558
        const closeSpec = pClose(closeDialog, sharedBackstage.providers);
31559
        const alertDialog = build$1(renderDialog$1({
31560
          lazySink: () => sharedBackstage.getSink(),
31561
          header: hiddenHeader(titleSpec, closeSpec),
31562
          body: pBodyMessage(message, sharedBackstage.providers),
31563
          footer: Optional.some(pFooter(pFooterGroup([], [memFooterClose.asSpec()]))),
31564
          onEscape: closeDialog,
31565
          extraClasses: ['tox-alert-dialog'],
31566
          extraBehaviours: [],
31567
          extraStyles: {},
31568
          dialogEvents: [run$1(formCancelEvent, closeDialog)],
31569
          eventOrder: {}
31570
        }));
31571
        ModalDialog.show(alertDialog);
31572
        const footerCloseButton = memFooterClose.get(alertDialog);
31573
        Focusing.focus(footerCloseButton);
31574
      };
31575
      return { open };
31576
    };
31577
 
31578
    const setup$1 = backstage => {
31579
      const sharedBackstage = backstage.shared;
31580
      const open = (message, callback) => {
31581
        const closeDialog = state => {
31582
          ModalDialog.hide(confirmDialog);
31583
          callback(state);
31584
        };
31585
        const memFooterYes = record(renderFooterButton({
1441 ariadna 31586
          context: 'any',
1 efrain 31587
          name: 'yes',
31588
          text: 'Yes',
31589
          primary: true,
31590
          buttonType: Optional.some('primary'),
31591
          align: 'end',
31592
          enabled: true,
31593
          icon: Optional.none()
31594
        }, 'submit', backstage));
31595
        const footerNo = renderFooterButton({
1441 ariadna 31596
          context: 'any',
1 efrain 31597
          name: 'no',
31598
          text: 'No',
31599
          primary: false,
31600
          buttonType: Optional.some('secondary'),
31601
          align: 'end',
31602
          enabled: true,
31603
          icon: Optional.none()
31604
        }, 'cancel', backstage);
31605
        const titleSpec = pUntitled();
31606
        const closeSpec = pClose(() => closeDialog(false), sharedBackstage.providers);
31607
        const confirmDialog = build$1(renderDialog$1({
31608
          lazySink: () => sharedBackstage.getSink(),
31609
          header: hiddenHeader(titleSpec, closeSpec),
31610
          body: pBodyMessage(message, sharedBackstage.providers),
31611
          footer: Optional.some(pFooter(pFooterGroup([], [
31612
            footerNo,
31613
            memFooterYes.asSpec()
31614
          ]))),
31615
          onEscape: () => closeDialog(false),
31616
          extraClasses: ['tox-confirm-dialog'],
31617
          extraBehaviours: [],
31618
          extraStyles: {},
31619
          dialogEvents: [
31620
            run$1(formCancelEvent, () => closeDialog(false)),
31621
            run$1(formSubmitEvent, () => closeDialog(true))
31622
          ],
31623
          eventOrder: {}
31624
        }));
31625
        ModalDialog.show(confirmDialog);
31626
        const footerYesButton = memFooterYes.get(confirmDialog);
31627
        Focusing.focus(footerYesButton);
31628
      };
31629
      return { open };
31630
    };
31631
 
31632
    const validateData = (data, validator) => getOrDie(asRaw('data', validator, data));
31633
    const isAlertOrConfirmDialog = target => closest(target, '.tox-alert-dialog') || closest(target, '.tox-confirm-dialog');
31634
    const inlineAdditionalBehaviours = (editor, isStickyToolbar, isToolbarLocationTop) => {
31635
      if (isStickyToolbar && isToolbarLocationTop) {
31636
        return [];
31637
      } else {
31638
        return [Docking.config({
31639
            contextual: {
31640
              lazyContext: () => Optional.some(box$1(SugarElement.fromDom(editor.getContentAreaContainer()))),
31641
              fadeInClass: 'tox-dialog-dock-fadein',
31642
              fadeOutClass: 'tox-dialog-dock-fadeout',
31643
              transitionClass: 'tox-dialog-dock-transition'
31644
            },
31645
            modes: ['top'],
31646
            lazyViewport: comp => {
31647
              const optScrollingContext = detectWhenSplitUiMode(editor, comp.element);
31648
              return optScrollingContext.map(sc => {
31649
                const combinedBounds = getBoundsFrom(sc);
31650
                return {
31651
                  bounds: combinedBounds,
31652
                  optScrollEnv: Optional.some({
31653
                    currentScrollTop: sc.element.dom.scrollTop,
31654
                    scrollElmTop: absolute$3(sc.element).top
31655
                  })
31656
                };
31657
              }).getOrThunk(() => ({
31658
                bounds: win(),
31659
                optScrollEnv: Optional.none()
31660
              }));
31661
            }
31662
          })];
31663
      }
31664
    };
31665
    const setup = extras => {
31666
      const editor = extras.editor;
31667
      const isStickyToolbar$1 = isStickyToolbar(editor);
31668
      const alertDialog = setup$2(extras.backstages.dialog);
31669
      const confirmDialog = setup$1(extras.backstages.dialog);
31670
      const open = (config, params, closeWindow) => {
31671
        if (!isUndefined(params)) {
31672
          if (params.inline === 'toolbar') {
31673
            return openInlineDialog(config, extras.backstages.popup.shared.anchors.inlineDialog(), closeWindow, params);
31674
          } else if (params.inline === 'bottom') {
31675
            return openBottomInlineDialog(config, extras.backstages.popup.shared.anchors.inlineBottomDialog(), closeWindow, params);
31676
          } else if (params.inline === 'cursor') {
31677
            return openInlineDialog(config, extras.backstages.popup.shared.anchors.cursor(), closeWindow, params);
31678
          }
31679
        }
31680
        return openModalDialog(config, closeWindow);
31681
      };
31682
      const openUrl = (config, closeWindow) => openModalUrlDialog(config, closeWindow);
31683
      const openModalUrlDialog = (config, closeWindow) => {
31684
        const factory = contents => {
31685
          const dialog = renderUrlDialog(contents, {
31686
            closeWindow: () => {
31687
              ModalDialog.hide(dialog.dialog);
31688
              closeWindow(dialog.instanceApi);
31689
            }
31690
          }, editor, extras.backstages.dialog);
31691
          ModalDialog.show(dialog.dialog);
31692
          return dialog.instanceApi;
31693
        };
31694
        return DialogManager.openUrl(factory, config);
31695
      };
31696
      const openModalDialog = (config, closeWindow) => {
31697
        const factory = (contents, internalInitialData, dataValidator) => {
31698
          const initialData = internalInitialData;
31699
          const dialogInit = {
31700
            dataValidator,
31701
            initialData,
31702
            internalDialog: contents
31703
          };
31704
          const dialog = renderDialog(dialogInit, {
31705
            redial: DialogManager.redial,
31706
            closeWindow: () => {
31707
              ModalDialog.hide(dialog.dialog);
31708
              closeWindow(dialog.instanceApi);
31709
            }
31710
          }, extras.backstages.dialog);
31711
          ModalDialog.show(dialog.dialog);
31712
          dialog.instanceApi.setData(initialData);
31713
          return dialog.instanceApi;
31714
        };
31715
        return DialogManager.open(factory, config);
31716
      };
31717
      const openInlineDialog = (config$1, anchor, closeWindow, windowParams) => {
31718
        const factory = (contents, internalInitialData, dataValidator) => {
31719
          const initialData = validateData(internalInitialData, dataValidator);
1441 ariadna 31720
          const inlineDialog = value$4();
1 efrain 31721
          const isToolbarLocationTop = extras.backstages.popup.shared.header.isPositionedAtTop();
31722
          const dialogInit = {
31723
            dataValidator,
31724
            initialData,
31725
            internalDialog: contents
31726
          };
31727
          const refreshDocking = () => inlineDialog.on(dialog => {
31728
            InlineView.reposition(dialog);
31729
            if (!isStickyToolbar$1 || !isToolbarLocationTop) {
31730
              Docking.refresh(dialog);
31731
            }
31732
          });
31733
          const dialogUi = renderInlineDialog(dialogInit, {
31734
            redial: DialogManager.redial,
31735
            closeWindow: () => {
31736
              inlineDialog.on(InlineView.hide);
31737
              editor.off('ResizeEditor', refreshDocking);
31738
              inlineDialog.clear();
31739
              closeWindow(dialogUi.instanceApi);
31740
            }
31741
          }, extras.backstages.popup, windowParams.ariaAttrs, refreshDocking);
31742
          const inlineDialogComp = build$1(InlineView.sketch({
31743
            lazySink: extras.backstages.popup.shared.getSink,
31744
            dom: {
31745
              tag: 'div',
31746
              classes: []
31747
            },
31748
            fireDismissalEventInstead: windowParams.persistent ? { event: 'doNotDismissYet' } : {},
31749
            ...isToolbarLocationTop ? {} : { fireRepositionEventInstead: {} },
31750
            inlineBehaviours: derive$1([
31751
              config('window-manager-inline-events', [run$1(dismissRequested(), (_comp, _se) => {
31752
                  emit(dialogUi.dialog, formCancelEvent);
31753
                })]),
31754
              ...inlineAdditionalBehaviours(editor, isStickyToolbar$1, isToolbarLocationTop)
31755
            ]),
31756
            isExtraPart: (_comp, target) => isAlertOrConfirmDialog(target)
31757
          }));
31758
          inlineDialog.set(inlineDialogComp);
31759
          const getInlineDialogBounds = () => {
31760
            const elem = editor.inline ? body() : SugarElement.fromDom(editor.getContainer());
31761
            const bounds = box$1(elem);
31762
            return Optional.some(bounds);
31763
          };
31764
          InlineView.showWithinBounds(inlineDialogComp, premade(dialogUi.dialog), { anchor }, getInlineDialogBounds);
31765
          if (!isStickyToolbar$1 || !isToolbarLocationTop) {
31766
            Docking.refresh(inlineDialogComp);
31767
            editor.on('ResizeEditor', refreshDocking);
31768
          }
31769
          dialogUi.instanceApi.setData(initialData);
31770
          Keying.focusIn(dialogUi.dialog);
31771
          return dialogUi.instanceApi;
31772
        };
31773
        return DialogManager.open(factory, config$1);
31774
      };
31775
      const openBottomInlineDialog = (config$1, anchor, closeWindow, windowParams) => {
31776
        const factory = (contents, internalInitialData, dataValidator) => {
31777
          const initialData = validateData(internalInitialData, dataValidator);
1441 ariadna 31778
          const inlineDialog = value$4();
1 efrain 31779
          const isToolbarLocationTop = extras.backstages.popup.shared.header.isPositionedAtTop();
31780
          const dialogInit = {
31781
            dataValidator,
31782
            initialData,
31783
            internalDialog: contents
31784
          };
31785
          const refreshDocking = () => inlineDialog.on(dialog => {
31786
            InlineView.reposition(dialog);
31787
            Docking.refresh(dialog);
31788
          });
31789
          const dialogUi = renderInlineDialog(dialogInit, {
31790
            redial: DialogManager.redial,
31791
            closeWindow: () => {
31792
              inlineDialog.on(InlineView.hide);
31793
              editor.off('ResizeEditor ScrollWindow ElementScroll', refreshDocking);
31794
              inlineDialog.clear();
31795
              closeWindow(dialogUi.instanceApi);
31796
            }
31797
          }, extras.backstages.popup, windowParams.ariaAttrs, refreshDocking);
31798
          const inlineDialogComp = build$1(InlineView.sketch({
31799
            lazySink: extras.backstages.popup.shared.getSink,
31800
            dom: {
31801
              tag: 'div',
31802
              classes: []
31803
            },
31804
            fireDismissalEventInstead: windowParams.persistent ? { event: 'doNotDismissYet' } : {},
31805
            ...isToolbarLocationTop ? {} : { fireRepositionEventInstead: {} },
31806
            inlineBehaviours: derive$1([
31807
              config('window-manager-inline-events', [run$1(dismissRequested(), (_comp, _se) => {
31808
                  emit(dialogUi.dialog, formCancelEvent);
31809
                })]),
31810
              Docking.config({
31811
                contextual: {
31812
                  lazyContext: () => Optional.some(box$1(SugarElement.fromDom(editor.getContentAreaContainer()))),
31813
                  fadeInClass: 'tox-dialog-dock-fadein',
31814
                  fadeOutClass: 'tox-dialog-dock-fadeout',
31815
                  transitionClass: 'tox-dialog-dock-transition'
31816
                },
31817
                modes: [
31818
                  'top',
31819
                  'bottom'
31820
                ],
31821
                lazyViewport: comp => {
31822
                  const optScrollingContext = detectWhenSplitUiMode(editor, comp.element);
31823
                  return optScrollingContext.map(sc => {
31824
                    const combinedBounds = getBoundsFrom(sc);
31825
                    return {
31826
                      bounds: combinedBounds,
31827
                      optScrollEnv: Optional.some({
31828
                        currentScrollTop: sc.element.dom.scrollTop,
31829
                        scrollElmTop: absolute$3(sc.element).top
31830
                      })
31831
                    };
31832
                  }).getOrThunk(() => ({
31833
                    bounds: win(),
31834
                    optScrollEnv: Optional.none()
31835
                  }));
31836
                }
31837
              })
31838
            ]),
31839
            isExtraPart: (_comp, target) => isAlertOrConfirmDialog(target)
31840
          }));
31841
          inlineDialog.set(inlineDialogComp);
31842
          const getInlineDialogBounds = () => {
31843
            return extras.backstages.popup.shared.getSink().toOptional().bind(s => {
31844
              const optScrollingContext = detectWhenSplitUiMode(editor, s.element);
31845
              const margin = 15;
31846
              const bounds$1 = optScrollingContext.map(sc => getBoundsFrom(sc)).getOr(win());
31847
              const contentAreaContainer = box$1(SugarElement.fromDom(editor.getContentAreaContainer()));
31848
              const constrainedBounds = constrain(contentAreaContainer, bounds$1);
31849
              return Optional.some(bounds(constrainedBounds.x, constrainedBounds.y, constrainedBounds.width, constrainedBounds.height - margin));
31850
            });
31851
          };
31852
          InlineView.showWithinBounds(inlineDialogComp, premade(dialogUi.dialog), { anchor }, getInlineDialogBounds);
31853
          Docking.refresh(inlineDialogComp);
31854
          editor.on('ResizeEditor ScrollWindow ElementScroll ResizeWindow', refreshDocking);
31855
          dialogUi.instanceApi.setData(initialData);
31856
          Keying.focusIn(dialogUi.dialog);
31857
          return dialogUi.instanceApi;
31858
        };
31859
        return DialogManager.open(factory, config$1);
31860
      };
31861
      const confirm = (message, callback) => {
31862
        confirmDialog.open(message, callback);
31863
      };
31864
      const alert = (message, callback) => {
31865
        alertDialog.open(message, callback);
31866
      };
31867
      const close = instanceApi => {
31868
        instanceApi.close();
31869
      };
31870
      return {
31871
        open,
31872
        openUrl,
31873
        alert,
31874
        close,
31875
        confirm
31876
      };
31877
    };
31878
 
31879
    const registerOptions = editor => {
1441 ariadna 31880
      register$f(editor);
1 efrain 31881
      register$e(editor);
31882
      register(editor);
31883
    };
31884
    var Theme = () => {
31885
      global$a.add('silver', editor => {
31886
        registerOptions(editor);
31887
        let popupSinkBounds = () => win();
31888
        const {
31889
          dialogs,
31890
          popups,
31891
          renderUI: renderModeUI
31892
        } = setup$3(editor, { getPopupSinkBounds: () => popupSinkBounds() });
31893
        const renderUI = () => {
31894
          const renderResult = renderModeUI();
31895
          const optScrollingContext = detectWhenSplitUiMode(editor, popups.getMothership().element);
31896
          optScrollingContext.each(sc => {
31897
            popupSinkBounds = () => {
31898
              return getBoundsFrom(sc);
31899
            };
31900
          });
31901
          return renderResult;
31902
        };
31903
        Autocompleter.register(editor, popups.backstage.shared);
31904
        const windowMgr = setup({
31905
          editor,
31906
          backstages: {
31907
            popup: popups.backstage,
31908
            dialog: dialogs.backstage
31909
          }
31910
        });
1441 ariadna 31911
        const notificationRegion = value$4();
31912
        const getNotificationManagerImpl = () => NotificationManagerImpl(editor, { backstage: popups.backstage }, popups.getMothership(), notificationRegion);
1 efrain 31913
        return {
31914
          renderUI,
31915
          getWindowManagerImpl: constant$1(windowMgr),
31916
          getNotificationManagerImpl
31917
        };
31918
      });
31919
    };
31920
 
31921
    Theme();
31922
 
31923
})();