Proyectos de Subversion Moodle

Rev

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

Rev Autor Línea Nro. Línea
1 efrain 1
/**
1441 ariadna 2
 * TinyMCE version 7.7.1 (2025-03-05)
1 efrain 3
 */
4
 
5
(function () {
6
    'use strict';
7
 
8
    var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager');
9
 
10
    const hasProto = (v, constructor, predicate) => {
11
      var _a;
12
      if (predicate(v, constructor.prototype)) {
13
        return true;
14
      } else {
15
        return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
16
      }
17
    };
18
    const typeOf = x => {
19
      const t = typeof x;
20
      if (x === null) {
21
        return 'null';
22
      } else if (t === 'object' && Array.isArray(x)) {
23
        return 'array';
24
      } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
25
        return 'string';
26
      } else {
27
        return t;
28
      }
29
    };
30
    const isType$1 = type => value => typeOf(value) === type;
31
    const isSimpleType = type => value => typeof value === type;
32
    const eq$1 = t => a => t === a;
33
    const isString = isType$1('string');
34
    const isArray = isType$1('array');
35
    const isBoolean = isSimpleType('boolean');
36
    const isUndefined = eq$1(undefined);
37
    const isNullable = a => a === null || a === undefined;
38
    const isNonNullable = a => !isNullable(a);
39
    const isFunction = isSimpleType('function');
40
    const isNumber = isSimpleType('number');
41
 
42
    const noop = () => {
43
    };
44
    const compose1 = (fbc, fab) => a => fbc(fab(a));
45
    const constant = value => {
46
      return () => {
47
        return value;
48
      };
49
    };
50
    const identity = x => {
51
      return x;
52
    };
53
    const tripleEquals = (a, b) => {
54
      return a === b;
55
    };
56
    function curry(fn, ...initialArgs) {
57
      return (...restArgs) => {
58
        const all = initialArgs.concat(restArgs);
59
        return fn.apply(null, all);
60
      };
61
    }
62
    const call = f => {
63
      f();
64
    };
65
    const never = constant(false);
66
    const always = constant(true);
67
 
68
    class Optional {
69
      constructor(tag, value) {
70
        this.tag = tag;
71
        this.value = value;
72
      }
73
      static some(value) {
74
        return new Optional(true, value);
75
      }
76
      static none() {
77
        return Optional.singletonNone;
78
      }
79
      fold(onNone, onSome) {
80
        if (this.tag) {
81
          return onSome(this.value);
82
        } else {
83
          return onNone();
84
        }
85
      }
86
      isSome() {
87
        return this.tag;
88
      }
89
      isNone() {
90
        return !this.tag;
91
      }
92
      map(mapper) {
93
        if (this.tag) {
94
          return Optional.some(mapper(this.value));
95
        } else {
96
          return Optional.none();
97
        }
98
      }
99
      bind(binder) {
100
        if (this.tag) {
101
          return binder(this.value);
102
        } else {
103
          return Optional.none();
104
        }
105
      }
106
      exists(predicate) {
107
        return this.tag && predicate(this.value);
108
      }
109
      forall(predicate) {
110
        return !this.tag || predicate(this.value);
111
      }
112
      filter(predicate) {
113
        if (!this.tag || predicate(this.value)) {
114
          return this;
115
        } else {
116
          return Optional.none();
117
        }
118
      }
119
      getOr(replacement) {
120
        return this.tag ? this.value : replacement;
121
      }
122
      or(replacement) {
123
        return this.tag ? this : replacement;
124
      }
125
      getOrThunk(thunk) {
126
        return this.tag ? this.value : thunk();
127
      }
128
      orThunk(thunk) {
129
        return this.tag ? this : thunk();
130
      }
131
      getOrDie(message) {
132
        if (!this.tag) {
133
          throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
134
        } else {
135
          return this.value;
136
        }
137
      }
138
      static from(value) {
139
        return isNonNullable(value) ? Optional.some(value) : Optional.none();
140
      }
141
      getOrNull() {
142
        return this.tag ? this.value : null;
143
      }
144
      getOrUndefined() {
145
        return this.value;
146
      }
147
      each(worker) {
148
        if (this.tag) {
149
          worker(this.value);
150
        }
151
      }
152
      toArray() {
153
        return this.tag ? [this.value] : [];
154
      }
155
      toString() {
156
        return this.tag ? `some(${ this.value })` : 'none()';
157
      }
158
    }
159
    Optional.singletonNone = new Optional(false);
160
 
161
    const keys = Object.keys;
162
    const hasOwnProperty = Object.hasOwnProperty;
163
    const each$1 = (obj, f) => {
164
      const props = keys(obj);
165
      for (let k = 0, len = props.length; k < len; k++) {
166
        const i = props[k];
167
        const x = obj[i];
168
        f(x, i);
169
      }
170
    };
171
    const objAcc = r => (x, i) => {
172
      r[i] = x;
173
    };
174
    const internalFilter = (obj, pred, onTrue, onFalse) => {
175
      each$1(obj, (x, i) => {
176
        (pred(x, i) ? onTrue : onFalse)(x, i);
177
      });
178
    };
179
    const filter$1 = (obj, pred) => {
180
      const t = {};
181
      internalFilter(obj, pred, objAcc(t), noop);
182
      return t;
183
    };
184
    const mapToArray = (obj, f) => {
185
      const r = [];
186
      each$1(obj, (value, name) => {
187
        r.push(f(value, name));
188
      });
189
      return r;
190
    };
191
    const values = obj => {
192
      return mapToArray(obj, identity);
193
    };
194
    const size = obj => {
195
      return keys(obj).length;
196
    };
197
    const get$4 = (obj, key) => {
198
      return has(obj, key) ? Optional.from(obj[key]) : Optional.none();
199
    };
200
    const has = (obj, key) => hasOwnProperty.call(obj, key);
201
    const hasNonNullableKey = (obj, key) => has(obj, key) && obj[key] !== undefined && obj[key] !== null;
202
    const isEmpty$1 = r => {
203
      for (const x in r) {
204
        if (hasOwnProperty.call(r, x)) {
205
          return false;
206
        }
207
      }
208
      return true;
209
    };
210
 
211
    const nativeIndexOf = Array.prototype.indexOf;
212
    const nativePush = Array.prototype.push;
213
    const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
214
    const contains = (xs, x) => rawIndexOf(xs, x) > -1;
215
    const exists = (xs, pred) => {
216
      for (let i = 0, len = xs.length; i < len; i++) {
217
        const x = xs[i];
218
        if (pred(x, i)) {
219
          return true;
220
        }
221
      }
222
      return false;
223
    };
224
    const range = (num, f) => {
225
      const r = [];
226
      for (let i = 0; i < num; i++) {
227
        r.push(f(i));
228
      }
229
      return r;
230
    };
231
    const map = (xs, f) => {
232
      const len = xs.length;
233
      const r = new Array(len);
234
      for (let i = 0; i < len; i++) {
235
        const x = xs[i];
236
        r[i] = f(x, i);
237
      }
238
      return r;
239
    };
240
    const each = (xs, f) => {
241
      for (let i = 0, len = xs.length; i < len; i++) {
242
        const x = xs[i];
243
        f(x, i);
244
      }
245
    };
246
    const eachr = (xs, f) => {
247
      for (let i = xs.length - 1; i >= 0; i--) {
248
        const x = xs[i];
249
        f(x, i);
250
      }
251
    };
252
    const partition = (xs, pred) => {
253
      const pass = [];
254
      const fail = [];
255
      for (let i = 0, len = xs.length; i < len; i++) {
256
        const x = xs[i];
257
        const arr = pred(x, i) ? pass : fail;
258
        arr.push(x);
259
      }
260
      return {
261
        pass,
262
        fail
263
      };
264
    };
265
    const filter = (xs, pred) => {
266
      const r = [];
267
      for (let i = 0, len = xs.length; i < len; i++) {
268
        const x = xs[i];
269
        if (pred(x, i)) {
270
          r.push(x);
271
        }
272
      }
273
      return r;
274
    };
275
    const foldr = (xs, f, acc) => {
276
      eachr(xs, (x, i) => {
277
        acc = f(acc, x, i);
278
      });
279
      return acc;
280
    };
281
    const foldl = (xs, f, acc) => {
282
      each(xs, (x, i) => {
283
        acc = f(acc, x, i);
284
      });
285
      return acc;
286
    };
287
    const findUntil = (xs, pred, until) => {
288
      for (let i = 0, len = xs.length; i < len; i++) {
289
        const x = xs[i];
290
        if (pred(x, i)) {
291
          return Optional.some(x);
292
        } else if (until(x, i)) {
293
          break;
294
        }
295
      }
296
      return Optional.none();
297
    };
298
    const find = (xs, pred) => {
299
      return findUntil(xs, pred, never);
300
    };
301
    const flatten$1 = xs => {
302
      const r = [];
303
      for (let i = 0, len = xs.length; i < len; ++i) {
304
        if (!isArray(xs[i])) {
305
          throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
306
        }
307
        nativePush.apply(r, xs[i]);
308
      }
309
      return r;
310
    };
311
    const bind = (xs, f) => flatten$1(map(xs, f));
312
    const forall = (xs, pred) => {
313
      for (let i = 0, len = xs.length; i < len; ++i) {
314
        const x = xs[i];
315
        if (pred(x, i) !== true) {
316
          return false;
317
        }
318
      }
319
      return true;
320
    };
321
    const mapToObject = (xs, f) => {
322
      const r = {};
323
      for (let i = 0, len = xs.length; i < len; i++) {
324
        const x = xs[i];
325
        r[String(x)] = f(x, i);
326
      }
327
      return r;
328
    };
329
    const get$3 = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
330
    const head = xs => get$3(xs, 0);
331
    const last = xs => get$3(xs, xs.length - 1);
332
    const findMap = (arr, f) => {
333
      for (let i = 0; i < arr.length; i++) {
334
        const r = f(arr[i], i);
335
        if (r.isSome()) {
336
          return r;
337
        }
338
      }
339
      return Optional.none();
340
    };
341
 
342
    const COMMENT = 8;
343
    const DOCUMENT = 9;
344
    const DOCUMENT_FRAGMENT = 11;
345
    const ELEMENT = 1;
346
    const TEXT = 3;
347
 
348
    const fromHtml = (html, scope) => {
349
      const doc = scope || document;
350
      const div = doc.createElement('div');
351
      div.innerHTML = html;
352
      if (!div.hasChildNodes() || div.childNodes.length > 1) {
353
        const message = 'HTML does not have a single root node';
354
        console.error(message, html);
355
        throw new Error(message);
356
      }
357
      return fromDom$1(div.childNodes[0]);
358
    };
359
    const fromTag = (tag, scope) => {
360
      const doc = scope || document;
361
      const node = doc.createElement(tag);
362
      return fromDom$1(node);
363
    };
364
    const fromText = (text, scope) => {
365
      const doc = scope || document;
366
      const node = doc.createTextNode(text);
367
      return fromDom$1(node);
368
    };
369
    const fromDom$1 = node => {
370
      if (node === null || node === undefined) {
371
        throw new Error('Node cannot be null or undefined');
372
      }
373
      return { dom: node };
374
    };
375
    const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$1);
376
    const SugarElement = {
377
      fromHtml,
378
      fromTag,
379
      fromText,
380
      fromDom: fromDom$1,
381
      fromPoint
382
    };
383
 
384
    const is$2 = (element, selector) => {
385
      const dom = element.dom;
386
      if (dom.nodeType !== ELEMENT) {
387
        return false;
388
      } else {
389
        const elem = dom;
390
        if (elem.matches !== undefined) {
391
          return elem.matches(selector);
392
        } else if (elem.msMatchesSelector !== undefined) {
393
          return elem.msMatchesSelector(selector);
394
        } else if (elem.webkitMatchesSelector !== undefined) {
395
          return elem.webkitMatchesSelector(selector);
396
        } else if (elem.mozMatchesSelector !== undefined) {
397
          return elem.mozMatchesSelector(selector);
398
        } else {
399
          throw new Error('Browser lacks native selectors');
400
        }
401
      }
402
    };
403
    const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
404
    const all$1 = (selector, scope) => {
405
      const base = scope === undefined ? document : scope.dom;
406
      return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom);
407
    };
408
    const one = (selector, scope) => {
409
      const base = scope === undefined ? document : scope.dom;
410
      return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
411
    };
412
 
413
    const eq = (e1, e2) => e1.dom === e2.dom;
414
    const is$1 = is$2;
415
 
416
    typeof window !== 'undefined' ? window : Function('return this;')();
417
 
418
    const name = element => {
419
      const r = element.dom.nodeName;
420
      return r.toLowerCase();
421
    };
422
    const type = element => element.dom.nodeType;
423
    const isType = t => element => type(element) === t;
424
    const isComment = element => type(element) === COMMENT || name(element) === '#comment';
425
    const isElement = isType(ELEMENT);
426
    const isText = isType(TEXT);
427
    const isDocument = isType(DOCUMENT);
428
    const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
429
    const isTag = tag => e => isElement(e) && name(e) === tag;
430
 
431
    const owner = element => SugarElement.fromDom(element.dom.ownerDocument);
432
    const documentOrOwner = dos => isDocument(dos) ? dos : owner(dos);
433
    const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
434
    const parents = (element, isRoot) => {
435
      const stop = isFunction(isRoot) ? isRoot : never;
436
      let dom = element.dom;
437
      const ret = [];
438
      while (dom.parentNode !== null && dom.parentNode !== undefined) {
439
        const rawParent = dom.parentNode;
440
        const p = SugarElement.fromDom(rawParent);
441
        ret.push(p);
442
        if (stop(p) === true) {
443
          break;
444
        } else {
445
          dom = rawParent;
446
        }
447
      }
448
      return ret;
449
    };
450
    const prevSibling = element => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom);
451
    const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
452
    const children$3 = element => map(element.dom.childNodes, SugarElement.fromDom);
453
    const child$3 = (element, index) => {
454
      const cs = element.dom.childNodes;
455
      return Optional.from(cs[index]).map(SugarElement.fromDom);
456
    };
457
    const firstChild = element => child$3(element, 0);
458
 
459
    const isShadowRoot = dos => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
1441 ariadna 460
    const getRootNode = e => SugarElement.fromDom(e.dom.getRootNode());
1 efrain 461
    const getShadowRoot = e => {
462
      const r = getRootNode(e);
463
      return isShadowRoot(r) ? Optional.some(r) : Optional.none();
464
    };
465
    const getShadowHost = e => SugarElement.fromDom(e.dom.host);
466
 
467
    const inBody = element => {
468
      const dom = isText(element) ? element.dom.parentNode : element.dom;
469
      if (dom === undefined || dom === null || dom.ownerDocument === null) {
470
        return false;
471
      }
472
      const doc = dom.ownerDocument;
473
      return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
474
    };
475
 
476
    var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
477
      if (is(scope, a)) {
478
        return Optional.some(scope);
479
      } else if (isFunction(isRoot) && isRoot(scope)) {
480
        return Optional.none();
481
      } else {
482
        return ancestor(scope, a, isRoot);
483
      }
484
    };
485
 
486
    const ancestor$1 = (scope, predicate, isRoot) => {
487
      let element = scope.dom;
488
      const stop = isFunction(isRoot) ? isRoot : never;
489
      while (element.parentNode) {
490
        element = element.parentNode;
491
        const el = SugarElement.fromDom(element);
492
        if (predicate(el)) {
493
          return Optional.some(el);
494
        } else if (stop(el)) {
495
          break;
496
        }
497
      }
498
      return Optional.none();
499
    };
500
    const closest$2 = (scope, predicate, isRoot) => {
501
      const is = (s, test) => test(s);
502
      return ClosestOrAncestor(is, ancestor$1, scope, predicate, isRoot);
503
    };
504
    const child$2 = (scope, predicate) => {
505
      const pred = node => predicate(SugarElement.fromDom(node));
506
      const result = find(scope.dom.childNodes, pred);
507
      return result.map(SugarElement.fromDom);
508
    };
509
 
510
    const ancestor = (scope, selector, isRoot) => ancestor$1(scope, e => is$2(e, selector), isRoot);
511
    const child$1 = (scope, selector) => child$2(scope, e => is$2(e, selector));
512
    const descendant = (scope, selector) => one(selector, scope);
513
    const closest$1 = (scope, selector, isRoot) => {
514
      const is = (element, selector) => is$2(element, selector);
515
      return ClosestOrAncestor(is, ancestor, scope, selector, isRoot);
516
    };
517
 
518
    const closest = target => closest$1(target, '[contenteditable]');
519
    const isEditable = (element, assumeEditable = false) => {
520
      if (inBody(element)) {
521
        return element.dom.isContentEditable;
522
      } else {
523
        return closest(element).fold(constant(assumeEditable), editable => getRaw$1(editable) === 'true');
524
      }
525
    };
526
    const getRaw$1 = element => element.dom.contentEditable;
527
 
528
    const getNodeName = elm => elm.nodeName.toLowerCase();
529
    const getBody = editor => SugarElement.fromDom(editor.getBody());
530
    const getIsRoot = editor => element => eq(element, getBody(editor));
531
    const removePxSuffix = size => size ? size.replace(/px$/, '') : '';
532
    const addPxSuffix = size => /^\d+(\.\d+)?$/.test(size) ? size + 'px' : size;
533
    const getSelectionStart = editor => SugarElement.fromDom(editor.selection.getStart());
534
    const getSelectionEnd = editor => SugarElement.fromDom(editor.selection.getEnd());
535
    const isInEditableContext = cell => closest$2(cell, isTag('table')).forall(isEditable);
536
 
537
    const children$2 = (scope, predicate) => filter(children$3(scope), predicate);
538
    const descendants$1 = (scope, predicate) => {
539
      let result = [];
540
      each(children$3(scope), x => {
541
        if (predicate(x)) {
542
          result = result.concat([x]);
543
        }
544
        result = result.concat(descendants$1(x, predicate));
545
      });
546
      return result;
547
    };
548
 
549
    const children$1 = (scope, selector) => children$2(scope, e => is$2(e, selector));
550
    const descendants = (scope, selector) => all$1(selector, scope);
551
 
552
    const rawSet = (dom, key, value) => {
553
      if (isString(value) || isBoolean(value) || isNumber(value)) {
554
        dom.setAttribute(key, value + '');
555
      } else {
556
        console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
557
        throw new Error('Attribute value was not simple');
558
      }
559
    };
560
    const set$2 = (element, key, value) => {
561
      rawSet(element.dom, key, value);
562
    };
563
    const setAll = (element, attrs) => {
564
      const dom = element.dom;
565
      each$1(attrs, (v, k) => {
566
        rawSet(dom, k, v);
567
      });
568
    };
569
    const get$2 = (element, key) => {
570
      const v = element.dom.getAttribute(key);
571
      return v === null ? undefined : v;
572
    };
573
    const getOpt = (element, key) => Optional.from(get$2(element, key));
574
    const remove$2 = (element, key) => {
575
      element.dom.removeAttribute(key);
576
    };
577
    const clone = element => foldl(element.dom.attributes, (acc, attr) => {
578
      acc[attr.name] = attr.value;
579
      return acc;
580
    }, {});
581
 
582
    const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
583
    const cat = arr => {
584
      const r = [];
585
      const push = x => {
586
        r.push(x);
587
      };
588
      for (let i = 0; i < arr.length; i++) {
589
        arr[i].each(push);
590
      }
591
      return r;
592
    };
593
    const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
594
    const flatten = oot => oot.bind(identity);
595
    const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
596
 
597
    const removeFromStart = (str, numChars) => {
598
      return str.substring(numChars);
599
    };
600
 
601
    const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
602
    const removeLeading = (str, prefix) => {
603
      return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
604
    };
605
    const startsWith = (str, prefix) => {
606
      return checkRange(str, prefix, 0);
607
    };
608
    const blank = r => s => s.replace(r, '');
609
    const trim = blank(/^\s+|\s+$/g);
610
    const isNotEmpty = s => s.length > 0;
611
    const isEmpty = s => !isNotEmpty(s);
612
    const toInt = (value, radix = 10) => {
613
      const num = parseInt(value, radix);
614
      return isNaN(num) ? Optional.none() : Optional.some(num);
615
    };
616
    const toFloat = value => {
617
      const num = parseFloat(value);
618
      return isNaN(num) ? Optional.none() : Optional.some(num);
619
    };
620
 
621
    const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
622
 
623
    const internalSet = (dom, property, value) => {
624
      if (!isString(value)) {
625
        console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
626
        throw new Error('CSS value must be a string: ' + value);
627
      }
628
      if (isSupported(dom)) {
629
        dom.style.setProperty(property, value);
630
      }
631
    };
632
    const internalRemove = (dom, property) => {
633
      if (isSupported(dom)) {
634
        dom.style.removeProperty(property);
635
      }
636
    };
637
    const set$1 = (element, property, value) => {
638
      const dom = element.dom;
639
      internalSet(dom, property, value);
640
    };
641
    const get$1 = (element, property) => {
642
      const dom = element.dom;
643
      const styles = window.getComputedStyle(dom);
644
      const r = styles.getPropertyValue(property);
645
      return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
646
    };
647
    const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : '';
648
    const getRaw = (element, property) => {
649
      const dom = element.dom;
650
      const raw = getUnsafeProperty(dom, property);
651
      return Optional.from(raw).filter(r => r.length > 0);
652
    };
653
    const remove$1 = (element, property) => {
654
      const dom = element.dom;
655
      internalRemove(dom, property);
656
      if (is(getOpt(element, 'style').map(trim), '')) {
657
        remove$2(element, 'style');
658
      }
659
    };
660
 
661
    const getAttrValue = (cell, name, fallback = 0) => getOpt(cell, name).map(value => parseInt(value, 10)).getOr(fallback);
662
 
663
    const firstLayer = (scope, selector) => {
664
      return filterFirstLayer(scope, selector, always);
665
    };
666
    const filterFirstLayer = (scope, selector, predicate) => {
667
      return bind(children$3(scope), x => {
668
        if (is$2(x, selector)) {
669
          return predicate(x) ? [x] : [];
670
        } else {
671
          return filterFirstLayer(x, selector, predicate);
672
        }
673
      });
674
    };
675
 
676
    const validSectionList = [
677
      'tfoot',
678
      'thead',
679
      'tbody',
680
      'colgroup'
681
    ];
682
    const isValidSection = parentName => contains(validSectionList, parentName);
683
    const grid = (rows, columns) => ({
684
      rows,
685
      columns
686
    });
687
    const detail = (element, rowspan, colspan) => ({
688
      element,
689
      rowspan,
690
      colspan
691
    });
692
    const extended = (element, rowspan, colspan, row, column, isLocked) => ({
693
      element,
694
      rowspan,
695
      colspan,
696
      row,
697
      column,
698
      isLocked
699
    });
700
    const rowdetail = (element, cells, section) => ({
701
      element,
702
      cells,
703
      section
704
    });
705
    const bounds = (startRow, startCol, finishRow, finishCol) => ({
706
      startRow,
707
      startCol,
708
      finishRow,
709
      finishCol
710
    });
711
    const columnext = (element, colspan, column) => ({
712
      element,
713
      colspan,
714
      column
715
    });
716
    const colgroup = (element, columns) => ({
717
      element,
718
      columns
719
    });
720
 
721
    const lookup = (tags, element, isRoot = never) => {
722
      if (isRoot(element)) {
723
        return Optional.none();
724
      }
725
      if (contains(tags, name(element))) {
726
        return Optional.some(element);
727
      }
728
      const isRootOrUpperTable = elm => is$2(elm, 'table') || isRoot(elm);
729
      return ancestor(element, tags.join(','), isRootOrUpperTable);
730
    };
731
    const cell = (element, isRoot) => lookup([
732
      'td',
733
      'th'
734
    ], element, isRoot);
735
    const cells = ancestor => firstLayer(ancestor, 'th,td');
736
    const columns = ancestor => {
737
      if (is$2(ancestor, 'colgroup')) {
738
        return children$1(ancestor, 'col');
739
      } else {
740
        return bind(columnGroups(ancestor), columnGroup => children$1(columnGroup, 'col'));
741
      }
742
    };
743
    const table = (element, isRoot) => closest$1(element, 'table', isRoot);
744
    const rows = ancestor => firstLayer(ancestor, 'tr');
745
    const columnGroups = ancestor => table(ancestor).fold(constant([]), table => children$1(table, 'colgroup'));
746
 
747
    const fromRowsOrColGroups = (elems, getSection) => map(elems, row => {
748
      if (name(row) === 'colgroup') {
749
        const cells = map(columns(row), column => {
750
          const colspan = getAttrValue(column, 'span', 1);
751
          return detail(column, 1, colspan);
752
        });
753
        return rowdetail(row, cells, 'colgroup');
754
      } else {
755
        const cells$1 = map(cells(row), cell => {
756
          const rowspan = getAttrValue(cell, 'rowspan', 1);
757
          const colspan = getAttrValue(cell, 'colspan', 1);
758
          return detail(cell, rowspan, colspan);
759
        });
760
        return rowdetail(row, cells$1, getSection(row));
761
      }
762
    });
763
    const getParentSection = group => parent(group).map(parent => {
764
      const parentName = name(parent);
765
      return isValidSection(parentName) ? parentName : 'tbody';
766
    }).getOr('tbody');
767
    const fromTable$1 = table => {
768
      const rows$1 = rows(table);
769
      const columnGroups$1 = columnGroups(table);
770
      const elems = [
771
        ...columnGroups$1,
772
        ...rows$1
773
      ];
774
      return fromRowsOrColGroups(elems, getParentSection);
775
    };
776
 
777
    const LOCKED_COL_ATTR = 'data-snooker-locked-cols';
778
    const getLockedColumnsFromTable = table => getOpt(table, LOCKED_COL_ATTR).bind(lockedColStr => Optional.from(lockedColStr.match(/\d+/g))).map(lockedCols => mapToObject(lockedCols, always));
779
 
780
    const key = (row, column) => {
781
      return row + ',' + column;
782
    };
783
    const getAt = (warehouse, row, column) => Optional.from(warehouse.access[key(row, column)]);
784
    const findItem = (warehouse, item, comparator) => {
785
      const filtered = filterItems(warehouse, detail => {
786
        return comparator(item, detail.element);
787
      });
788
      return filtered.length > 0 ? Optional.some(filtered[0]) : Optional.none();
789
    };
790
    const filterItems = (warehouse, predicate) => {
791
      const all = bind(warehouse.all, r => {
792
        return r.cells;
793
      });
794
      return filter(all, predicate);
795
    };
796
    const generateColumns = rowData => {
797
      const columnsGroup = {};
798
      let index = 0;
799
      each(rowData.cells, column => {
800
        const colspan = column.colspan;
801
        range(colspan, columnIndex => {
802
          const colIndex = index + columnIndex;
803
          columnsGroup[colIndex] = columnext(column.element, colspan, colIndex);
804
        });
805
        index += colspan;
806
      });
807
      return columnsGroup;
808
    };
809
    const generate$1 = list => {
810
      const access = {};
811
      const cells = [];
812
      const tableOpt = head(list).map(rowData => rowData.element).bind(table);
813
      const lockedColumns = tableOpt.bind(getLockedColumnsFromTable).getOr({});
814
      let maxRows = 0;
815
      let maxColumns = 0;
816
      let rowCount = 0;
817
      const {
818
        pass: colgroupRows,
819
        fail: rows
820
      } = partition(list, rowData => rowData.section === 'colgroup');
821
      each(rows, rowData => {
822
        const currentRow = [];
823
        each(rowData.cells, rowCell => {
824
          let start = 0;
825
          while (access[key(rowCount, start)] !== undefined) {
826
            start++;
827
          }
828
          const isLocked = hasNonNullableKey(lockedColumns, start.toString());
829
          const current = extended(rowCell.element, rowCell.rowspan, rowCell.colspan, rowCount, start, isLocked);
830
          for (let occupiedColumnPosition = 0; occupiedColumnPosition < rowCell.colspan; occupiedColumnPosition++) {
831
            for (let occupiedRowPosition = 0; occupiedRowPosition < rowCell.rowspan; occupiedRowPosition++) {
832
              const rowPosition = rowCount + occupiedRowPosition;
833
              const columnPosition = start + occupiedColumnPosition;
834
              const newpos = key(rowPosition, columnPosition);
835
              access[newpos] = current;
836
              maxColumns = Math.max(maxColumns, columnPosition + 1);
837
            }
838
          }
839
          currentRow.push(current);
840
        });
841
        maxRows++;
842
        cells.push(rowdetail(rowData.element, currentRow, rowData.section));
843
        rowCount++;
844
      });
845
      const {columns, colgroups} = last(colgroupRows).map(rowData => {
846
        const columns = generateColumns(rowData);
847
        const colgroup$1 = colgroup(rowData.element, values(columns));
848
        return {
849
          colgroups: [colgroup$1],
850
          columns
851
        };
852
      }).getOrThunk(() => ({
853
        colgroups: [],
854
        columns: {}
855
      }));
856
      const grid$1 = grid(maxRows, maxColumns);
857
      return {
858
        grid: grid$1,
859
        access,
860
        all: cells,
861
        columns,
862
        colgroups
863
      };
864
    };
865
    const fromTable = table => {
866
      const list = fromTable$1(table);
867
      return generate$1(list);
868
    };
869
    const justCells = warehouse => bind(warehouse.all, w => w.cells);
870
    const justColumns = warehouse => values(warehouse.columns);
871
    const hasColumns = warehouse => keys(warehouse.columns).length > 0;
872
    const getColumnAt = (warehouse, columnIndex) => Optional.from(warehouse.columns[columnIndex]);
873
    const Warehouse = {
874
      fromTable,
875
      generate: generate$1,
876
      getAt,
877
      findItem,
878
      filterItems,
879
      justCells,
880
      justColumns,
881
      hasColumns,
882
      getColumnAt
883
    };
884
 
885
    var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools');
886
 
887
    const getTDTHOverallStyle = (dom, elm, name) => {
888
      const cells = dom.select('td,th', elm);
889
      let firstChildStyle;
890
      for (let i = 0; i < cells.length; i++) {
891
        const currentStyle = dom.getStyle(cells[i], name);
892
        if (isUndefined(firstChildStyle)) {
893
          firstChildStyle = currentStyle;
894
        }
895
        if (firstChildStyle !== currentStyle) {
896
          return '';
897
        }
898
      }
899
      return firstChildStyle;
900
    };
901
    const setAlign = (editor, elm, name) => {
902
      global$2.each('left center right'.split(' '), align => {
903
        if (align !== name) {
904
          editor.formatter.remove('align' + align, {}, elm);
905
        }
906
      });
907
      if (name) {
908
        editor.formatter.apply('align' + name, {}, elm);
909
      }
910
    };
911
    const setVAlign = (editor, elm, name) => {
912
      global$2.each('top middle bottom'.split(' '), align => {
913
        if (align !== name) {
914
          editor.formatter.remove('valign' + align, {}, elm);
915
        }
916
      });
917
      if (name) {
918
        editor.formatter.apply('valign' + name, {}, elm);
919
      }
920
    };
921
 
922
    const fireTableModified = (editor, table, data) => {
923
      editor.dispatch('TableModified', {
924
        ...data,
925
        table
926
      });
927
    };
928
 
929
    const toNumber = (px, fallback) => toFloat(px).getOr(fallback);
930
    const getProp = (element, name, fallback) => toNumber(get$1(element, name), fallback);
931
    const calcContentBoxSize = (element, size, upper, lower) => {
932
      const paddingUpper = getProp(element, `padding-${ upper }`, 0);
933
      const paddingLower = getProp(element, `padding-${ lower }`, 0);
934
      const borderUpper = getProp(element, `border-${ upper }-width`, 0);
935
      const borderLower = getProp(element, `border-${ lower }-width`, 0);
936
      return size - paddingUpper - paddingLower - borderUpper - borderLower;
937
    };
938
    const getCalculatedWidth = (element, boxSizing) => {
939
      const dom = element.dom;
940
      const width = dom.getBoundingClientRect().width || dom.offsetWidth;
941
      return boxSizing === 'border-box' ? width : calcContentBoxSize(element, width, 'left', 'right');
942
    };
943
    const getInnerWidth = element => getCalculatedWidth(element, 'content-box');
944
 
945
    const getInner = getInnerWidth;
946
 
947
    var global$1 = tinymce.util.Tools.resolve('tinymce.Env');
948
 
949
    const defaultTableToolbar = 'tableprops tabledelete | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol';
950
    const defaultCellBorderWidths = range(5, i => {
951
      const size = `${ i + 1 }px`;
952
      return {
953
        title: size,
954
        value: size
955
      };
956
    });
957
    const defaultCellBorderStyles = map([
958
      'Solid',
959
      'Dotted',
960
      'Dashed',
961
      'Double',
962
      'Groove',
963
      'Ridge',
964
      'Inset',
965
      'Outset',
966
      'None',
967
      'Hidden'
968
    ], type => {
969
      return {
970
        title: type,
971
        value: type.toLowerCase()
972
      };
973
    });
974
    const defaultWidth = '100%';
975
    const getPixelForcedWidth = editor => {
976
      var _a;
977
      const dom = editor.dom;
978
      const parentBlock = (_a = dom.getParent(editor.selection.getStart(), dom.isBlock)) !== null && _a !== void 0 ? _a : editor.getBody();
979
      return getInner(SugarElement.fromDom(parentBlock)) + 'px';
980
    };
981
    const determineDefaultStyles = (editor, defaultStyles) => {
982
      if (isResponsiveForced(editor) || !shouldStyleWithCss(editor)) {
983
        return defaultStyles;
984
      } else if (isPixelsForced(editor)) {
985
        return {
986
          ...defaultStyles,
987
          width: getPixelForcedWidth(editor)
988
        };
989
      } else {
990
        return {
991
          ...defaultStyles,
992
          width: defaultWidth
993
        };
994
      }
995
    };
996
    const determineDefaultAttributes = (editor, defaultAttributes) => {
997
      if (isResponsiveForced(editor) || shouldStyleWithCss(editor)) {
998
        return defaultAttributes;
999
      } else if (isPixelsForced(editor)) {
1000
        return {
1001
          ...defaultAttributes,
1002
          width: getPixelForcedWidth(editor)
1003
        };
1004
      } else {
1005
        return {
1006
          ...defaultAttributes,
1007
          width: defaultWidth
1008
        };
1009
      }
1010
    };
1011
    const option = name => editor => editor.options.get(name);
1012
    const register = editor => {
1013
      const registerOption = editor.options.register;
1014
      registerOption('table_border_widths', {
1015
        processor: 'object[]',
1016
        default: defaultCellBorderWidths
1017
      });
1018
      registerOption('table_border_styles', {
1019
        processor: 'object[]',
1020
        default: defaultCellBorderStyles
1021
      });
1022
      registerOption('table_cell_advtab', {
1023
        processor: 'boolean',
1024
        default: true
1025
      });
1026
      registerOption('table_row_advtab', {
1027
        processor: 'boolean',
1028
        default: true
1029
      });
1030
      registerOption('table_advtab', {
1031
        processor: 'boolean',
1032
        default: true
1033
      });
1034
      registerOption('table_appearance_options', {
1035
        processor: 'boolean',
1036
        default: true
1037
      });
1038
      registerOption('table_grid', {
1039
        processor: 'boolean',
1040
        default: !global$1.deviceType.isTouch()
1041
      });
1042
      registerOption('table_cell_class_list', {
1043
        processor: 'object[]',
1044
        default: []
1045
      });
1046
      registerOption('table_row_class_list', {
1047
        processor: 'object[]',
1048
        default: []
1049
      });
1050
      registerOption('table_class_list', {
1051
        processor: 'object[]',
1052
        default: []
1053
      });
1054
      registerOption('table_toolbar', {
1055
        processor: 'string',
1056
        default: defaultTableToolbar
1057
      });
1058
      registerOption('table_background_color_map', {
1059
        processor: 'object[]',
1060
        default: []
1061
      });
1062
      registerOption('table_border_color_map', {
1063
        processor: 'object[]',
1064
        default: []
1065
      });
1066
    };
1067
    const getTableSizingMode = option('table_sizing_mode');
1068
    const getTableBorderWidths = option('table_border_widths');
1069
    const getTableBorderStyles = option('table_border_styles');
1070
    const hasAdvancedCellTab = option('table_cell_advtab');
1071
    const hasAdvancedRowTab = option('table_row_advtab');
1072
    const hasAdvancedTableTab = option('table_advtab');
1073
    const hasAppearanceOptions = option('table_appearance_options');
1074
    const hasTableGrid = option('table_grid');
1075
    const shouldStyleWithCss = option('table_style_by_css');
1076
    const getCellClassList = option('table_cell_class_list');
1077
    const getRowClassList = option('table_row_class_list');
1078
    const getTableClassList = option('table_class_list');
1079
    const getToolbar = option('table_toolbar');
1080
    const getTableBackgroundColorMap = option('table_background_color_map');
1081
    const getTableBorderColorMap = option('table_border_color_map');
1082
    const isPixelsForced = editor => getTableSizingMode(editor) === 'fixed';
1083
    const isResponsiveForced = editor => getTableSizingMode(editor) === 'responsive';
1084
    const getDefaultStyles = editor => {
1085
      const options = editor.options;
1086
      const defaultStyles = options.get('table_default_styles');
1087
      return options.isSet('table_default_styles') ? defaultStyles : determineDefaultStyles(editor, defaultStyles);
1088
    };
1089
    const getDefaultAttributes = editor => {
1090
      const options = editor.options;
1091
      const defaultAttributes = options.get('table_default_attributes');
1092
      return options.isSet('table_default_attributes') ? defaultAttributes : determineDefaultAttributes(editor, defaultAttributes);
1093
    };
1094
 
1095
    const isWithin = (bounds, detail) => {
1096
      return detail.column >= bounds.startCol && detail.column + detail.colspan - 1 <= bounds.finishCol && detail.row >= bounds.startRow && detail.row + detail.rowspan - 1 <= bounds.finishRow;
1097
    };
1098
    const isRectangular = (warehouse, bounds) => {
1099
      let isRect = true;
1100
      const detailIsWithin = curry(isWithin, bounds);
1101
      for (let i = bounds.startRow; i <= bounds.finishRow; i++) {
1102
        for (let j = bounds.startCol; j <= bounds.finishCol; j++) {
1103
          isRect = isRect && Warehouse.getAt(warehouse, i, j).exists(detailIsWithin);
1104
        }
1105
      }
1106
      return isRect ? Optional.some(bounds) : Optional.none();
1107
    };
1108
 
1109
    const getBounds = (detailA, detailB) => {
1110
      return bounds(Math.min(detailA.row, detailB.row), Math.min(detailA.column, detailB.column), Math.max(detailA.row + detailA.rowspan - 1, detailB.row + detailB.rowspan - 1), Math.max(detailA.column + detailA.colspan - 1, detailB.column + detailB.colspan - 1));
1111
    };
1112
    const getAnyBox = (warehouse, startCell, finishCell) => {
1113
      const startCoords = Warehouse.findItem(warehouse, startCell, eq);
1114
      const finishCoords = Warehouse.findItem(warehouse, finishCell, eq);
1115
      return startCoords.bind(sc => {
1116
        return finishCoords.map(fc => {
1117
          return getBounds(sc, fc);
1118
        });
1119
      });
1120
    };
1121
    const getBox$1 = (warehouse, startCell, finishCell) => {
1122
      return getAnyBox(warehouse, startCell, finishCell).bind(bounds => {
1123
        return isRectangular(warehouse, bounds);
1124
      });
1125
    };
1126
 
1127
    const getBox = (table, first, last) => {
1128
      const warehouse = getWarehouse(table);
1129
      return getBox$1(warehouse, first, last);
1130
    };
1131
    const getWarehouse = Warehouse.fromTable;
1132
 
1133
    const before = (marker, element) => {
1134
      const parent$1 = parent(marker);
1135
      parent$1.each(v => {
1136
        v.dom.insertBefore(element.dom, marker.dom);
1137
      });
1138
    };
1139
    const after$1 = (marker, element) => {
1140
      const sibling = nextSibling(marker);
1141
      sibling.fold(() => {
1142
        const parent$1 = parent(marker);
1143
        parent$1.each(v => {
1144
          append$1(v, element);
1145
        });
1146
      }, v => {
1147
        before(v, element);
1148
      });
1149
    };
1150
    const prepend = (parent, element) => {
1151
      const firstChild$1 = firstChild(parent);
1152
      firstChild$1.fold(() => {
1153
        append$1(parent, element);
1154
      }, v => {
1155
        parent.dom.insertBefore(element.dom, v.dom);
1156
      });
1157
    };
1158
    const append$1 = (parent, element) => {
1159
      parent.dom.appendChild(element.dom);
1160
    };
1161
    const wrap = (element, wrapper) => {
1162
      before(element, wrapper);
1163
      append$1(wrapper, element);
1164
    };
1165
 
1166
    const after = (marker, elements) => {
1167
      each(elements, (x, i) => {
1168
        const e = i === 0 ? marker : elements[i - 1];
1169
        after$1(e, x);
1170
      });
1171
    };
1172
    const append = (parent, elements) => {
1173
      each(elements, x => {
1174
        append$1(parent, x);
1175
      });
1176
    };
1177
 
1178
    const remove = element => {
1179
      const dom = element.dom;
1180
      if (dom.parentNode !== null) {
1181
        dom.parentNode.removeChild(dom);
1182
      }
1183
    };
1184
    const unwrap = wrapper => {
1185
      const children = children$3(wrapper);
1186
      if (children.length > 0) {
1187
        after(wrapper, children);
1188
      }
1189
      remove(wrapper);
1190
    };
1191
 
1192
    const NodeValue = (is, name) => {
1193
      const get = element => {
1194
        if (!is(element)) {
1195
          throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
1196
        }
1197
        return getOption(element).getOr('');
1198
      };
1199
      const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
1200
      const set = (element, value) => {
1201
        if (!is(element)) {
1202
          throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
1203
        }
1204
        element.dom.nodeValue = value;
1205
      };
1206
      return {
1207
        get,
1208
        getOption,
1209
        set
1210
      };
1211
    };
1212
 
1213
    const api = NodeValue(isText, 'text');
1214
    const get = element => api.get(element);
1215
    const set = (element, value) => api.set(element, value);
1216
 
1217
    var TagBoundaries = [
1218
      'body',
1219
      'p',
1220
      'div',
1221
      'article',
1222
      'aside',
1223
      'figcaption',
1224
      'figure',
1225
      'footer',
1226
      'header',
1227
      'nav',
1228
      'section',
1229
      'ol',
1230
      'ul',
1231
      'li',
1232
      'table',
1233
      'thead',
1234
      'tbody',
1235
      'tfoot',
1236
      'caption',
1237
      'tr',
1238
      'td',
1239
      'th',
1240
      'h1',
1241
      'h2',
1242
      'h3',
1243
      'h4',
1244
      'h5',
1245
      'h6',
1246
      'blockquote',
1247
      'pre',
1248
      'address'
1249
    ];
1250
 
1251
    var DomUniverse = () => {
1252
      const clone$1 = element => {
1253
        return SugarElement.fromDom(element.dom.cloneNode(false));
1254
      };
1255
      const document = element => documentOrOwner(element).dom;
1256
      const isBoundary = element => {
1257
        if (!isElement(element)) {
1258
          return false;
1259
        }
1260
        if (name(element) === 'body') {
1261
          return true;
1262
        }
1263
        return contains(TagBoundaries, name(element));
1264
      };
1265
      const isEmptyTag = element => {
1266
        if (!isElement(element)) {
1267
          return false;
1268
        }
1269
        return contains([
1270
          'br',
1271
          'img',
1272
          'hr',
1273
          'input'
1274
        ], name(element));
1275
      };
1276
      const isNonEditable = element => isElement(element) && get$2(element, 'contenteditable') === 'false';
1277
      const comparePosition = (element, other) => {
1278
        return element.dom.compareDocumentPosition(other.dom);
1279
      };
1280
      const copyAttributesTo = (source, destination) => {
1281
        const as = clone(source);
1282
        setAll(destination, as);
1283
      };
1284
      const isSpecial = element => {
1285
        const tag = name(element);
1286
        return contains([
1287
          'script',
1288
          'noscript',
1289
          'iframe',
1290
          'noframes',
1291
          'noembed',
1292
          'title',
1293
          'style',
1294
          'textarea',
1295
          'xmp'
1296
        ], tag);
1297
      };
1298
      const getLanguage = element => isElement(element) ? getOpt(element, 'lang') : Optional.none();
1299
      return {
1300
        up: constant({
1301
          selector: ancestor,
1302
          closest: closest$1,
1303
          predicate: ancestor$1,
1304
          all: parents
1305
        }),
1306
        down: constant({
1307
          selector: descendants,
1308
          predicate: descendants$1
1309
        }),
1310
        styles: constant({
1311
          get: get$1,
1312
          getRaw: getRaw,
1313
          set: set$1,
1314
          remove: remove$1
1315
        }),
1316
        attrs: constant({
1317
          get: get$2,
1318
          set: set$2,
1319
          remove: remove$2,
1320
          copyTo: copyAttributesTo
1321
        }),
1322
        insert: constant({
1323
          before: before,
1324
          after: after$1,
1325
          afterAll: after,
1326
          append: append$1,
1327
          appendAll: append,
1328
          prepend: prepend,
1329
          wrap: wrap
1330
        }),
1331
        remove: constant({
1332
          unwrap: unwrap,
1333
          remove: remove
1334
        }),
1335
        create: constant({
1336
          nu: SugarElement.fromTag,
1337
          clone: clone$1,
1338
          text: SugarElement.fromText
1339
        }),
1340
        query: constant({
1341
          comparePosition,
1342
          prevSibling: prevSibling,
1343
          nextSibling: nextSibling
1344
        }),
1345
        property: constant({
1346
          children: children$3,
1347
          name: name,
1348
          parent: parent,
1349
          document,
1350
          isText: isText,
1351
          isComment: isComment,
1352
          isElement: isElement,
1353
          isSpecial,
1354
          getLanguage,
1355
          getText: get,
1356
          setText: set,
1357
          isBoundary,
1358
          isEmptyTag,
1359
          isNonEditable
1360
        }),
1361
        eq: eq,
1362
        is: is$1
1363
      };
1364
    };
1365
 
1366
    const all = (universe, look, elements, f) => {
1367
      const head = elements[0];
1368
      const tail = elements.slice(1);
1369
      return f(universe, look, head, tail);
1370
    };
1371
    const oneAll = (universe, look, elements) => {
1372
      return elements.length > 0 ? all(universe, look, elements, unsafeOne) : Optional.none();
1373
    };
1374
    const unsafeOne = (universe, look, head, tail) => {
1375
      const start = look(universe, head);
1376
      return foldr(tail, (b, a) => {
1377
        const current = look(universe, a);
1378
        return commonElement(universe, b, current);
1379
      }, start);
1380
    };
1381
    const commonElement = (universe, start, end) => {
1382
      return start.bind(s => {
1383
        return end.filter(curry(universe.eq, s));
1384
      });
1385
    };
1386
 
1387
    const sharedOne$1 = oneAll;
1388
 
1389
    const universe = DomUniverse();
1390
    const sharedOne = (look, elements) => {
1391
      return sharedOne$1(universe, (_universe, element) => {
1392
        return look(element);
1393
      }, elements);
1394
    };
1395
 
1396
    const lookupTable = container => {
1397
      return ancestor(container, 'table');
1398
    };
1399
    const retrieve$1 = (container, selector) => {
1400
      const sels = descendants(container, selector);
1401
      return sels.length > 0 ? Optional.some(sels) : Optional.none();
1402
    };
1403
    const getEdges = (container, firstSelectedSelector, lastSelectedSelector) => {
1404
      return descendant(container, firstSelectedSelector).bind(first => {
1405
        return descendant(container, lastSelectedSelector).bind(last => {
1406
          return sharedOne(lookupTable, [
1407
            first,
1408
            last
1409
          ]).map(table => {
1410
            return {
1411
              first,
1412
              last,
1413
              table
1414
            };
1415
          });
1416
        });
1417
      });
1418
    };
1419
 
1420
    const retrieve = (container, selector) => {
1421
      return retrieve$1(container, selector);
1422
    };
1423
    const retrieveBox = (container, firstSelectedSelector, lastSelectedSelector) => {
1424
      return getEdges(container, firstSelectedSelector, lastSelectedSelector).bind(edges => {
1425
        const isRoot = ancestor => {
1426
          return eq(container, ancestor);
1427
        };
1428
        const sectionSelector = 'thead,tfoot,tbody,table';
1429
        const firstAncestor = ancestor(edges.first, sectionSelector, isRoot);
1430
        const lastAncestor = ancestor(edges.last, sectionSelector, isRoot);
1431
        return firstAncestor.bind(fA => {
1432
          return lastAncestor.bind(lA => {
1433
            return eq(fA, lA) ? getBox(edges.table, edges.first, edges.last) : Optional.none();
1434
          });
1435
        });
1436
      });
1437
    };
1438
 
1439
    const fromDom = nodes => map(nodes, SugarElement.fromDom);
1440
 
1441
    const strSelected = 'data-mce-selected';
1442
    const strSelectedSelector = 'td[' + strSelected + '],th[' + strSelected + ']';
1443
    const strFirstSelected = 'data-mce-first-selected';
1444
    const strFirstSelectedSelector = 'td[' + strFirstSelected + '],th[' + strFirstSelected + ']';
1445
    const strLastSelected = 'data-mce-last-selected';
1446
    const strLastSelectedSelector = 'td[' + strLastSelected + '],th[' + strLastSelected + ']';
1447
    const ephemera = {
1448
      selected: strSelected,
1449
      selectedSelector: strSelectedSelector,
1450
      firstSelected: strFirstSelected,
1451
      firstSelectedSelector: strFirstSelectedSelector,
1452
      lastSelected: strLastSelected,
1453
      lastSelectedSelector: strLastSelectedSelector
1454
    };
1455
 
1456
    const getSelectionCellFallback = element => table(element).bind(table => retrieve(table, ephemera.firstSelectedSelector)).fold(constant(element), cells => cells[0]);
1457
    const getSelectionFromSelector = selector => (initCell, isRoot) => {
1458
      const cellName = name(initCell);
1459
      const cell = cellName === 'col' || cellName === 'colgroup' ? getSelectionCellFallback(initCell) : initCell;
1460
      return closest$1(cell, selector, isRoot);
1461
    };
1462
    const getSelectionCellOrCaption = getSelectionFromSelector('th,td,caption');
1463
    const getSelectionCell = getSelectionFromSelector('th,td');
1464
    const getCellsFromSelection = editor => fromDom(editor.model.table.getSelectedCells());
1465
    const getRowsFromSelection = (selected, selector) => {
1466
      const cellOpt = getSelectionCell(selected);
1467
      const rowsOpt = cellOpt.bind(cell => table(cell)).map(table => rows(table));
1468
      return lift2(cellOpt, rowsOpt, (cell, rows) => filter(rows, row => exists(fromDom(row.dom.cells), rowCell => get$2(rowCell, selector) === '1' || eq(rowCell, cell)))).getOr([]);
1469
    };
1470
 
1471
    const verticalAlignValues = [
1472
      {
1473
        text: 'None',
1474
        value: ''
1475
      },
1476
      {
1477
        text: 'Top',
1478
        value: 'top'
1479
      },
1480
      {
1481
        text: 'Middle',
1482
        value: 'middle'
1483
      },
1484
      {
1485
        text: 'Bottom',
1486
        value: 'bottom'
1487
      }
1488
    ];
1489
 
1490
    const hexColour = value => ({ value: normalizeHex(value) });
1491
    const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
1492
    const longformRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
1493
    const isHexString = hex => shorthandRegex.test(hex) || longformRegex.test(hex);
1494
    const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();
1495
    const fromString$1 = hex => isHexString(hex) ? Optional.some({ value: normalizeHex(hex) }) : Optional.none();
1496
    const toHex = component => {
1497
      const hex = component.toString(16);
1498
      return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
1499
    };
1500
    const fromRgba = rgbaColour => {
1501
      const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
1502
      return hexColour(value);
1503
    };
1504
 
1441 ariadna 1505
    const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*\)\s*$/i;
1506
    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 1507
    const rgbaColour = (red, green, blue, alpha) => ({
1508
      red,
1509
      green,
1510
      blue,
1511
      alpha
1512
    });
1513
    const fromStringValues = (red, green, blue, alpha) => {
1514
      const r = parseInt(red, 10);
1515
      const g = parseInt(green, 10);
1516
      const b = parseInt(blue, 10);
1517
      const a = parseFloat(alpha);
1518
      return rgbaColour(r, g, b, a);
1519
    };
1520
    const fromString = rgbaString => {
1521
      const rgbMatch = rgbRegex.exec(rgbaString);
1522
      if (rgbMatch !== null) {
1523
        return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
1524
      }
1525
      const rgbaMatch = rgbaRegex.exec(rgbaString);
1526
      if (rgbaMatch !== null) {
1527
        return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
1528
      }
1529
      return Optional.none();
1530
    };
1531
 
1532
    const anyToHex = color => fromString$1(color).orThunk(() => fromString(color).map(fromRgba)).getOrThunk(() => {
1533
      const canvas = document.createElement('canvas');
1534
      canvas.height = 1;
1535
      canvas.width = 1;
1536
      const canvasContext = canvas.getContext('2d');
1537
      canvasContext.clearRect(0, 0, canvas.width, canvas.height);
1538
      canvasContext.fillStyle = '#FFFFFF';
1539
      canvasContext.fillStyle = color;
1540
      canvasContext.fillRect(0, 0, 1, 1);
1541
      const rgba = canvasContext.getImageData(0, 0, 1, 1).data;
1542
      const r = rgba[0];
1543
      const g = rgba[1];
1544
      const b = rgba[2];
1545
      const a = rgba[3];
1546
      return fromRgba(rgbaColour(r, g, b, a));
1547
    });
1548
    const rgbaToHexString = color => fromString(color).map(fromRgba).map(h => '#' + h.value).getOr(color);
1549
 
1550
    const Cell = initial => {
1551
      let value = initial;
1552
      const get = () => {
1553
        return value;
1554
      };
1555
      const set = v => {
1556
        value = v;
1557
      };
1558
      return {
1559
        get,
1560
        set
1561
      };
1562
    };
1563
 
1564
    const singleton = doRevoke => {
1565
      const subject = Cell(Optional.none());
1566
      const revoke = () => subject.get().each(doRevoke);
1567
      const clear = () => {
1568
        revoke();
1569
        subject.set(Optional.none());
1570
      };
1571
      const isSet = () => subject.get().isSome();
1572
      const get = () => subject.get();
1573
      const set = s => {
1574
        revoke();
1575
        subject.set(Optional.some(s));
1576
      };
1577
      return {
1578
        clear,
1579
        isSet,
1580
        get,
1581
        set
1582
      };
1583
    };
1584
    const unbindable = () => singleton(s => s.unbind());
1585
 
1586
    const onSetupToggle = (editor, formatName, formatValue) => {
1587
      return api => {
1588
        const boundCallback = unbindable();
1589
        const isNone = isEmpty(formatValue);
1590
        const init = () => {
1591
          const selectedCells = getCellsFromSelection(editor);
1592
          const checkNode = cell => editor.formatter.match(formatName, { value: formatValue }, cell.dom, isNone);
1593
          if (isNone) {
1594
            api.setActive(!exists(selectedCells, checkNode));
1595
            boundCallback.set(editor.formatter.formatChanged(formatName, match => api.setActive(!match), true));
1596
          } else {
1597
            api.setActive(forall(selectedCells, checkNode));
1598
            boundCallback.set(editor.formatter.formatChanged(formatName, api.setActive, false, { value: formatValue }));
1599
          }
1600
        };
1601
        editor.initialized ? init() : editor.on('init', init);
1602
        return boundCallback.clear;
1603
      };
1604
    };
1605
    const isListGroup = item => hasNonNullableKey(item, 'menu');
1606
    const buildListItems = items => map(items, item => {
1607
      const text = item.text || item.title || '';
1608
      if (isListGroup(item)) {
1609
        return {
1610
          text,
1611
          items: buildListItems(item.menu)
1612
        };
1613
      } else {
1614
        return {
1615
          text,
1616
          value: item.value
1617
        };
1618
      }
1619
    });
1441 ariadna 1620
    const buildClassList = classList => {
1621
      if (!classList.length) {
1622
        return Optional.none();
1623
      }
1624
      return Optional.some(buildListItems([
1625
        {
1626
          text: 'Select...',
1627
          value: 'mce-no-match'
1628
        },
1629
        ...classList
1630
      ]));
1631
    };
1 efrain 1632
    const buildMenuItems = (editor, items, format, onAction) => map(items, item => {
1633
      const text = item.text || item.title;
1634
      if (isListGroup(item)) {
1635
        return {
1636
          type: 'nestedmenuitem',
1637
          text,
1638
          getSubmenuItems: () => buildMenuItems(editor, item.menu, format, onAction)
1639
        };
1640
      } else {
1641
        return {
1642
          text,
1643
          type: 'togglemenuitem',
1644
          onAction: () => onAction(item.value),
1645
          onSetup: onSetupToggle(editor, format, item.value)
1646
        };
1647
      }
1648
    });
1649
    const applyTableCellStyle = (editor, style) => value => {
1650
      editor.execCommand('mceTableApplyCellStyle', false, { [style]: value });
1651
    };
1652
    const filterNoneItem = list => bind(list, item => {
1653
      if (isListGroup(item)) {
1654
        return [{
1655
            ...item,
1656
            menu: filterNoneItem(item.menu)
1657
          }];
1658
      } else {
1659
        return isNotEmpty(item.value) ? [item] : [];
1660
      }
1661
    });
1662
    const generateMenuItemsCallback = (editor, items, format, onAction) => callback => callback(buildMenuItems(editor, items, format, onAction));
1663
    const buildColorMenu = (editor, colorList, style) => {
1664
      const colorMap = map(colorList, entry => ({
1665
        text: entry.title,
1666
        value: '#' + anyToHex(entry.value).value,
1667
        type: 'choiceitem'
1668
      }));
1669
      return [{
1670
          type: 'fancymenuitem',
1671
          fancytype: 'colorswatch',
1672
          initData: {
1673
            colors: colorMap.length > 0 ? colorMap : undefined,
1674
            allowCustomColors: false
1675
          },
1676
          onAction: data => {
1677
            const value = data.value === 'remove' ? '' : data.value;
1678
            editor.execCommand('mceTableApplyCellStyle', false, { [style]: value });
1679
          }
1680
        }];
1681
    };
1682
    const changeRowHeader = editor => () => {
1683
      const currentType = editor.queryCommandValue('mceTableRowType');
1684
      const newType = currentType === 'header' ? 'body' : 'header';
1685
      editor.execCommand('mceTableRowType', false, { type: newType });
1686
    };
1687
    const changeColumnHeader = editor => () => {
1688
      const currentType = editor.queryCommandValue('mceTableColType');
1689
      const newType = currentType === 'th' ? 'td' : 'th';
1690
      editor.execCommand('mceTableColType', false, { type: newType });
1691
    };
1692
 
1441 ariadna 1693
    const getClassList$1 = editor => buildClassList(getCellClassList(editor)).map(items => ({
1694
      name: 'class',
1695
      type: 'listbox',
1696
      label: 'Class',
1697
      items
1698
    }));
1 efrain 1699
    const children = [
1700
      {
1701
        name: 'width',
1702
        type: 'input',
1703
        label: 'Width'
1704
      },
1705
      {
1706
        name: 'celltype',
1707
        type: 'listbox',
1708
        label: 'Cell type',
1709
        items: [
1710
          {
1711
            text: 'Cell',
1712
            value: 'td'
1713
          },
1714
          {
1715
            text: 'Header cell',
1716
            value: 'th'
1717
          }
1718
        ]
1719
      },
1720
      {
1721
        name: 'scope',
1722
        type: 'listbox',
1723
        label: 'Scope',
1724
        items: [
1725
          {
1726
            text: 'None',
1727
            value: ''
1728
          },
1729
          {
1730
            text: 'Row',
1731
            value: 'row'
1732
          },
1733
          {
1734
            text: 'Column',
1735
            value: 'col'
1736
          },
1737
          {
1738
            text: 'Row group',
1739
            value: 'rowgroup'
1740
          },
1741
          {
1742
            text: 'Column group',
1743
            value: 'colgroup'
1744
          }
1745
        ]
1746
      },
1747
      {
1748
        name: 'halign',
1749
        type: 'listbox',
1750
        label: 'Horizontal align',
1751
        items: [
1752
          {
1753
            text: 'None',
1754
            value: ''
1755
          },
1756
          {
1757
            text: 'Left',
1758
            value: 'left'
1759
          },
1760
          {
1761
            text: 'Center',
1762
            value: 'center'
1763
          },
1764
          {
1765
            text: 'Right',
1766
            value: 'right'
1767
          }
1768
        ]
1769
      },
1770
      {
1771
        name: 'valign',
1772
        type: 'listbox',
1773
        label: 'Vertical align',
1774
        items: verticalAlignValues
1775
      }
1776
    ];
1777
    const getItems$2 = editor => children.concat(getClassList$1(editor).toArray());
1778
 
1779
    const getAdvancedTab = (editor, dialogName) => {
1780
      const emptyBorderStyle = [{
1781
          text: 'Select...',
1782
          value: ''
1783
        }];
1784
      const advTabItems = [
1785
        {
1786
          name: 'borderstyle',
1787
          type: 'listbox',
1788
          label: 'Border style',
1789
          items: emptyBorderStyle.concat(buildListItems(getTableBorderStyles(editor)))
1790
        },
1791
        {
1792
          name: 'bordercolor',
1793
          type: 'colorinput',
1794
          label: 'Border color'
1795
        },
1796
        {
1797
          name: 'backgroundcolor',
1798
          type: 'colorinput',
1799
          label: 'Background color'
1800
        }
1801
      ];
1802
      const borderWidth = {
1803
        name: 'borderwidth',
1804
        type: 'input',
1805
        label: 'Border width'
1806
      };
1807
      const items = dialogName === 'cell' ? [borderWidth].concat(advTabItems) : advTabItems;
1808
      return {
1809
        title: 'Advanced',
1810
        name: 'advanced',
1811
        items
1812
      };
1813
    };
1814
 
1815
    const normal = (editor, element) => {
1816
      const dom = editor.dom;
1817
      const setAttrib = (attr, value) => {
1818
        dom.setAttrib(element, attr, value);
1819
      };
1820
      const setStyle = (prop, value) => {
1821
        dom.setStyle(element, prop, value);
1822
      };
1823
      const setFormat = (formatName, value) => {
1824
        if (value === '') {
1825
          editor.formatter.remove(formatName, { value: null }, element, true);
1826
        } else {
1827
          editor.formatter.apply(formatName, { value }, element);
1828
        }
1829
      };
1830
      return {
1831
        setAttrib,
1832
        setStyle,
1833
        setFormat
1834
      };
1835
    };
1836
    const DomModifier = { normal };
1837
 
1838
    const isHeaderCell = isTag('th');
1839
    const getRowHeaderType = (isHeaderRow, isHeaderCells) => {
1840
      if (isHeaderRow && isHeaderCells) {
1841
        return 'sectionCells';
1842
      } else if (isHeaderRow) {
1843
        return 'section';
1844
      } else {
1845
        return 'cells';
1846
      }
1847
    };
1848
    const getRowType$1 = row => {
1849
      const isHeaderRow = row.section === 'thead';
1850
      const isHeaderCells = is(findCommonCellType(row.cells), 'th');
1851
      if (row.section === 'tfoot') {
1852
        return { type: 'footer' };
1853
      } else if (isHeaderRow || isHeaderCells) {
1854
        return {
1855
          type: 'header',
1856
          subType: getRowHeaderType(isHeaderRow, isHeaderCells)
1857
        };
1858
      } else {
1859
        return { type: 'body' };
1860
      }
1861
    };
1862
    const findCommonCellType = cells => {
1863
      const headerCells = filter(cells, cell => isHeaderCell(cell.element));
1864
      if (headerCells.length === 0) {
1865
        return Optional.some('td');
1866
      } else if (headerCells.length === cells.length) {
1867
        return Optional.some('th');
1868
      } else {
1869
        return Optional.none();
1870
      }
1871
    };
1872
    const findCommonRowType = rows => {
1873
      const rowTypes = map(rows, row => getRowType$1(row).type);
1874
      const hasHeader = contains(rowTypes, 'header');
1875
      const hasFooter = contains(rowTypes, 'footer');
1876
      if (!hasHeader && !hasFooter) {
1877
        return Optional.some('body');
1878
      } else {
1879
        const hasBody = contains(rowTypes, 'body');
1880
        if (hasHeader && !hasBody && !hasFooter) {
1881
          return Optional.some('header');
1882
        } else if (!hasHeader && !hasBody && hasFooter) {
1883
          return Optional.some('footer');
1884
        } else {
1885
          return Optional.none();
1886
        }
1887
      }
1888
    };
1889
 
1890
    const cached = f => {
1891
      let called = false;
1892
      let r;
1893
      return (...args) => {
1894
        if (!called) {
1895
          called = true;
1896
          r = f.apply(null, args);
1897
        }
1898
        return r;
1899
      };
1900
    };
1901
 
1902
    const findInWarehouse = (warehouse, element) => findMap(warehouse.all, r => find(r.cells, e => eq(element, e.element)));
1903
    const extractCells = (warehouse, target, predicate) => {
1904
      const details = map(target.selection, cell$1 => {
1905
        return cell(cell$1).bind(lc => findInWarehouse(warehouse, lc)).filter(predicate);
1906
      });
1907
      const cells = cat(details);
1908
      return someIf(cells.length > 0, cells);
1909
    };
1910
    const onMergable = (_warehouse, target) => target.mergable;
1911
    const onUnmergable = (_warehouse, target) => target.unmergable;
1912
    const onCells = (warehouse, target) => extractCells(warehouse, target, always);
1913
    const isUnlockedTableCell = (warehouse, cell) => findInWarehouse(warehouse, cell).exists(detail => !detail.isLocked);
1914
    const allUnlocked = (warehouse, cells) => forall(cells, cell => isUnlockedTableCell(warehouse, cell));
1915
    const onUnlockedMergable = (warehouse, target) => onMergable(warehouse, target).filter(mergeable => allUnlocked(warehouse, mergeable.cells));
1916
    const onUnlockedUnmergable = (warehouse, target) => onUnmergable(warehouse, target).filter(cells => allUnlocked(warehouse, cells));
1917
 
1918
    const generate = cases => {
1919
      if (!isArray(cases)) {
1920
        throw new Error('cases must be an array');
1921
      }
1922
      if (cases.length === 0) {
1923
        throw new Error('there must be at least one case');
1924
      }
1925
      const constructors = [];
1926
      const adt = {};
1927
      each(cases, (acase, count) => {
1928
        const keys$1 = keys(acase);
1929
        if (keys$1.length !== 1) {
1930
          throw new Error('one and only one name per case');
1931
        }
1932
        const key = keys$1[0];
1933
        const value = acase[key];
1934
        if (adt[key] !== undefined) {
1935
          throw new Error('duplicate key detected:' + key);
1936
        } else if (key === 'cata') {
1937
          throw new Error('cannot have a case named cata (sorry)');
1938
        } else if (!isArray(value)) {
1939
          throw new Error('case arguments must be an array');
1940
        }
1941
        constructors.push(key);
1942
        adt[key] = (...args) => {
1943
          const argLength = args.length;
1944
          if (argLength !== value.length) {
1945
            throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
1946
          }
1947
          const match = branches => {
1948
            const branchKeys = keys(branches);
1949
            if (constructors.length !== branchKeys.length) {
1950
              throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
1951
            }
1952
            const allReqd = forall(constructors, reqKey => {
1953
              return contains(branchKeys, reqKey);
1954
            });
1955
            if (!allReqd) {
1956
              throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
1957
            }
1958
            return branches[key].apply(null, args);
1959
          };
1960
          return {
1961
            fold: (...foldArgs) => {
1962
              if (foldArgs.length !== cases.length) {
1963
                throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
1964
              }
1965
              const target = foldArgs[count];
1966
              return target.apply(null, args);
1967
            },
1968
            match,
1969
            log: label => {
1970
              console.log(label, {
1971
                constructors,
1972
                constructor: key,
1973
                params: args
1974
              });
1975
            }
1976
          };
1977
        };
1978
      });
1979
      return adt;
1980
    };
1981
    const Adt = { generate };
1982
 
1983
    const adt = Adt.generate([
1984
      { none: [] },
1985
      { only: ['index'] },
1986
      {
1987
        left: [
1988
          'index',
1989
          'next'
1990
        ]
1991
      },
1992
      {
1993
        middle: [
1994
          'prev',
1995
          'index',
1996
          'next'
1997
        ]
1998
      },
1999
      {
2000
        right: [
2001
          'prev',
2002
          'index'
2003
        ]
2004
      }
2005
    ]);
2006
    ({ ...adt });
2007
 
2008
    const opGetRowsType = (table, target) => {
2009
      const house = Warehouse.fromTable(table);
2010
      const details = onCells(house, target);
2011
      return details.bind(selectedCells => {
2012
        const lastSelectedCell = selectedCells[selectedCells.length - 1];
2013
        const minRowRange = selectedCells[0].row;
2014
        const maxRowRange = lastSelectedCell.row + lastSelectedCell.rowspan;
2015
        const selectedRows = house.all.slice(minRowRange, maxRowRange);
2016
        return findCommonRowType(selectedRows);
2017
      }).getOr('');
2018
    };
2019
    const getRowsType = opGetRowsType;
2020
 
2021
    const rgbToHex = value => startsWith(value, 'rgb') ? rgbaToHexString(value) : value;
2022
    const extractAdvancedStyles = elm => {
2023
      const element = SugarElement.fromDom(elm);
2024
      return {
2025
        borderwidth: getRaw(element, 'border-width').getOr(''),
2026
        borderstyle: getRaw(element, 'border-style').getOr(''),
2027
        bordercolor: getRaw(element, 'border-color').map(rgbToHex).getOr(''),
2028
        backgroundcolor: getRaw(element, 'background-color').map(rgbToHex).getOr('')
2029
      };
2030
    };
2031
    const getSharedValues = data => {
2032
      const baseData = data[0];
2033
      const comparisonData = data.slice(1);
2034
      each(comparisonData, items => {
2035
        each(keys(baseData), key => {
2036
          each$1(items, (itemValue, itemKey) => {
2037
            const comparisonValue = baseData[key];
2038
            if (comparisonValue !== '' && key === itemKey) {
2039
              if (comparisonValue !== itemValue) {
1441 ariadna 2040
                baseData[key] = key === 'class' ? 'mce-no-match' : '';
1 efrain 2041
              }
2042
            }
2043
          });
2044
        });
2045
      });
2046
      return baseData;
2047
    };
2048
    const getAlignment = (formats, formatName, editor, elm) => find(formats, name => !isUndefined(editor.formatter.matchNode(elm, formatName + name))).getOr('');
2049
    const getHAlignment = curry(getAlignment, [
2050
      'left',
2051
      'center',
2052
      'right'
2053
    ], 'align');
2054
    const getVAlignment = curry(getAlignment, [
2055
      'top',
2056
      'middle',
2057
      'bottom'
2058
    ], 'valign');
2059
    const extractDataFromSettings = (editor, hasAdvTableTab) => {
2060
      const style = getDefaultStyles(editor);
2061
      const attrs = getDefaultAttributes(editor);
2062
      const extractAdvancedStyleData = () => ({
2063
        borderstyle: get$4(style, 'border-style').getOr(''),
2064
        bordercolor: rgbToHex(get$4(style, 'border-color').getOr('')),
2065
        backgroundcolor: rgbToHex(get$4(style, 'background-color').getOr(''))
2066
      });
2067
      const defaultData = {
2068
        height: '',
2069
        width: '100%',
2070
        cellspacing: '',
2071
        cellpadding: '',
2072
        caption: false,
2073
        class: '',
2074
        align: '',
2075
        border: ''
2076
      };
2077
      const getBorder = () => {
2078
        const borderWidth = style['border-width'];
2079
        if (shouldStyleWithCss(editor) && borderWidth) {
2080
          return { border: borderWidth };
2081
        }
2082
        return get$4(attrs, 'border').fold(() => ({}), border => ({ border }));
2083
      };
2084
      const advStyle = hasAdvTableTab ? extractAdvancedStyleData() : {};
2085
      const getCellPaddingCellSpacing = () => {
2086
        const spacing = get$4(style, 'border-spacing').or(get$4(attrs, 'cellspacing')).fold(() => ({}), cellspacing => ({ cellspacing }));
2087
        const padding = get$4(style, 'border-padding').or(get$4(attrs, 'cellpadding')).fold(() => ({}), cellpadding => ({ cellpadding }));
2088
        return {
2089
          ...spacing,
2090
          ...padding
2091
        };
2092
      };
2093
      const data = {
2094
        ...defaultData,
2095
        ...style,
2096
        ...attrs,
2097
        ...advStyle,
2098
        ...getBorder(),
2099
        ...getCellPaddingCellSpacing()
2100
      };
2101
      return data;
2102
    };
2103
    const getRowType = elm => table(SugarElement.fromDom(elm)).map(table => {
2104
      const target = { selection: fromDom(elm.cells) };
2105
      return getRowsType(table, target);
2106
    }).getOr('');
2107
    const extractDataFromTableElement = (editor, elm, hasAdvTableTab) => {
2108
      const getBorder = (dom, elm) => {
2109
        const optBorderWidth = getRaw(SugarElement.fromDom(elm), 'border-width');
2110
        if (shouldStyleWithCss(editor) && optBorderWidth.isSome()) {
2111
          return optBorderWidth.getOr('');
2112
        }
2113
        return dom.getAttrib(elm, 'border') || getTDTHOverallStyle(editor.dom, elm, 'border-width') || getTDTHOverallStyle(editor.dom, elm, 'border') || '';
2114
      };
2115
      const dom = editor.dom;
2116
      const cellspacing = shouldStyleWithCss(editor) ? dom.getStyle(elm, 'border-spacing') || dom.getAttrib(elm, 'cellspacing') : dom.getAttrib(elm, 'cellspacing') || dom.getStyle(elm, 'border-spacing');
2117
      const cellpadding = shouldStyleWithCss(editor) ? getTDTHOverallStyle(dom, elm, 'padding') || dom.getAttrib(elm, 'cellpadding') : dom.getAttrib(elm, 'cellpadding') || getTDTHOverallStyle(dom, elm, 'padding');
2118
      return {
2119
        width: dom.getStyle(elm, 'width') || dom.getAttrib(elm, 'width'),
2120
        height: dom.getStyle(elm, 'height') || dom.getAttrib(elm, 'height'),
2121
        cellspacing: cellspacing !== null && cellspacing !== void 0 ? cellspacing : '',
2122
        cellpadding: cellpadding !== null && cellpadding !== void 0 ? cellpadding : '',
2123
        border: getBorder(dom, elm),
2124
        caption: !!dom.select('caption', elm)[0],
2125
        class: dom.getAttrib(elm, 'class', ''),
2126
        align: getHAlignment(editor, elm),
2127
        ...hasAdvTableTab ? extractAdvancedStyles(elm) : {}
2128
      };
2129
    };
2130
    const extractDataFromRowElement = (editor, elm, hasAdvancedRowTab) => {
2131
      const dom = editor.dom;
2132
      return {
2133
        height: dom.getStyle(elm, 'height') || dom.getAttrib(elm, 'height'),
2134
        class: dom.getAttrib(elm, 'class', ''),
2135
        type: getRowType(elm),
2136
        align: getHAlignment(editor, elm),
2137
        ...hasAdvancedRowTab ? extractAdvancedStyles(elm) : {}
2138
      };
2139
    };
2140
    const extractDataFromCellElement = (editor, cell, hasAdvancedCellTab, column) => {
2141
      const dom = editor.dom;
2142
      const colElm = column.getOr(cell);
2143
      const getStyle = (element, style) => dom.getStyle(element, style) || dom.getAttrib(element, style);
2144
      return {
2145
        width: getStyle(colElm, 'width'),
2146
        scope: dom.getAttrib(cell, 'scope'),
2147
        celltype: getNodeName(cell),
2148
        class: dom.getAttrib(cell, 'class', ''),
2149
        halign: getHAlignment(editor, cell),
2150
        valign: getVAlignment(editor, cell),
2151
        ...hasAdvancedCellTab ? extractAdvancedStyles(cell) : {}
2152
      };
2153
    };
2154
 
2155
    const getSelectedCells = (table, cells) => {
2156
      const warehouse = Warehouse.fromTable(table);
2157
      const allCells = Warehouse.justCells(warehouse);
2158
      const filtered = filter(allCells, cellA => exists(cells, cellB => eq(cellA.element, cellB)));
2159
      return map(filtered, cell => ({
2160
        element: cell.element.dom,
2161
        column: Warehouse.getColumnAt(warehouse, cell.column).map(col => col.element.dom)
2162
      }));
2163
    };
2164
    const updateSimpleProps$1 = (modifier, colModifier, data, shouldUpdate) => {
2165
      if (shouldUpdate('scope')) {
2166
        modifier.setAttrib('scope', data.scope);
2167
      }
1441 ariadna 2168
      if (shouldUpdate('class') && data.class !== 'mce-no-match') {
1 efrain 2169
        modifier.setAttrib('class', data.class);
2170
      }
2171
      if (shouldUpdate('width')) {
2172
        colModifier.setStyle('width', addPxSuffix(data.width));
2173
      }
2174
    };
2175
    const updateAdvancedProps$1 = (modifier, data, shouldUpdate) => {
2176
      if (shouldUpdate('backgroundcolor')) {
2177
        modifier.setFormat('tablecellbackgroundcolor', data.backgroundcolor);
2178
      }
2179
      if (shouldUpdate('bordercolor')) {
2180
        modifier.setFormat('tablecellbordercolor', data.bordercolor);
2181
      }
2182
      if (shouldUpdate('borderstyle')) {
2183
        modifier.setFormat('tablecellborderstyle', data.borderstyle);
2184
      }
2185
      if (shouldUpdate('borderwidth')) {
2186
        modifier.setFormat('tablecellborderwidth', addPxSuffix(data.borderwidth));
2187
      }
2188
    };
2189
    const applyStyleData$1 = (editor, cells, data, wasChanged) => {
2190
      const isSingleCell = cells.length === 1;
2191
      each(cells, item => {
2192
        const cellElm = item.element;
2193
        const shouldOverrideCurrentValue = isSingleCell ? always : wasChanged;
2194
        const modifier = DomModifier.normal(editor, cellElm);
2195
        const colModifier = item.column.map(col => DomModifier.normal(editor, col)).getOr(modifier);
2196
        updateSimpleProps$1(modifier, colModifier, data, shouldOverrideCurrentValue);
2197
        if (hasAdvancedCellTab(editor)) {
2198
          updateAdvancedProps$1(modifier, data, shouldOverrideCurrentValue);
2199
        }
2200
        if (wasChanged('halign')) {
2201
          setAlign(editor, cellElm, data.halign);
2202
        }
2203
        if (wasChanged('valign')) {
2204
          setVAlign(editor, cellElm, data.valign);
2205
        }
2206
      });
2207
    };
2208
    const applyStructureData$1 = (editor, data) => {
2209
      editor.execCommand('mceTableCellType', false, {
2210
        type: data.celltype,
2211
        no_events: true
2212
      });
2213
    };
2214
    const applyCellData = (editor, cells, oldData, data) => {
2215
      const modifiedData = filter$1(data, (value, key) => oldData[key] !== value);
2216
      if (size(modifiedData) > 0 && cells.length >= 1) {
2217
        table(cells[0]).each(table => {
2218
          const selectedCells = getSelectedCells(table, cells);
2219
          const styleModified = size(filter$1(modifiedData, (_value, key) => key !== 'scope' && key !== 'celltype')) > 0;
2220
          const structureModified = has(modifiedData, 'celltype');
2221
          if (styleModified || has(modifiedData, 'scope')) {
2222
            applyStyleData$1(editor, selectedCells, data, curry(has, modifiedData));
2223
          }
2224
          if (structureModified) {
2225
            applyStructureData$1(editor, data);
2226
          }
2227
          fireTableModified(editor, table.dom, {
2228
            structure: structureModified,
2229
            style: styleModified
2230
          });
2231
        });
2232
      }
2233
    };
2234
    const onSubmitCellForm = (editor, cells, oldData, api) => {
2235
      const data = api.getData();
2236
      api.close();
2237
      editor.undoManager.transact(() => {
2238
        applyCellData(editor, cells, oldData, data);
2239
        editor.focus();
2240
      });
2241
    };
2242
    const getData$1 = (editor, cells) => {
2243
      const cellsData = table(cells[0]).map(table => map(getSelectedCells(table, cells), item => extractDataFromCellElement(editor, item.element, hasAdvancedCellTab(editor), item.column)));
2244
      return getSharedValues(cellsData.getOrDie());
2245
    };
2246
    const open$2 = editor => {
2247
      const cells = getCellsFromSelection(editor);
2248
      if (cells.length === 0) {
2249
        return;
2250
      }
2251
      const data = getData$1(editor, cells);
2252
      const dialogTabPanel = {
2253
        type: 'tabpanel',
2254
        tabs: [
2255
          {
2256
            title: 'General',
2257
            name: 'general',
2258
            items: getItems$2(editor)
2259
          },
2260
          getAdvancedTab(editor, 'cell')
2261
        ]
2262
      };
2263
      const dialogPanel = {
2264
        type: 'panel',
2265
        items: [{
2266
            type: 'grid',
2267
            columns: 2,
2268
            items: getItems$2(editor)
2269
          }]
2270
      };
2271
      editor.windowManager.open({
2272
        title: 'Cell Properties',
2273
        size: 'normal',
2274
        body: hasAdvancedCellTab(editor) ? dialogTabPanel : dialogPanel,
2275
        buttons: [
2276
          {
2277
            type: 'cancel',
2278
            name: 'cancel',
2279
            text: 'Cancel'
2280
          },
2281
          {
2282
            type: 'submit',
2283
            name: 'save',
2284
            text: 'Save',
2285
            primary: true
2286
          }
2287
        ],
2288
        initialData: data,
2289
        onSubmit: curry(onSubmitCellForm, editor, cells, data)
2290
      });
2291
    };
2292
 
1441 ariadna 2293
    const getClassList = editor => buildClassList(getRowClassList(editor)).map(items => ({
2294
      name: 'class',
2295
      type: 'listbox',
2296
      label: 'Class',
2297
      items
2298
    }));
1 efrain 2299
    const formChildren = [
2300
      {
2301
        type: 'listbox',
2302
        name: 'type',
2303
        label: 'Row type',
2304
        items: [
2305
          {
2306
            text: 'Header',
2307
            value: 'header'
2308
          },
2309
          {
2310
            text: 'Body',
2311
            value: 'body'
2312
          },
2313
          {
2314
            text: 'Footer',
2315
            value: 'footer'
2316
          }
2317
        ]
2318
      },
2319
      {
2320
        type: 'listbox',
2321
        name: 'align',
2322
        label: 'Alignment',
2323
        items: [
2324
          {
2325
            text: 'None',
2326
            value: ''
2327
          },
2328
          {
2329
            text: 'Left',
2330
            value: 'left'
2331
          },
2332
          {
2333
            text: 'Center',
2334
            value: 'center'
2335
          },
2336
          {
2337
            text: 'Right',
2338
            value: 'right'
2339
          }
2340
        ]
2341
      },
2342
      {
2343
        label: 'Height',
2344
        name: 'height',
2345
        type: 'input'
2346
      }
2347
    ];
2348
    const getItems$1 = editor => formChildren.concat(getClassList(editor).toArray());
2349
 
2350
    const updateSimpleProps = (modifier, data, shouldUpdate) => {
1441 ariadna 2351
      if (shouldUpdate('class') && data.class !== 'mce-no-match') {
1 efrain 2352
        modifier.setAttrib('class', data.class);
2353
      }
2354
      if (shouldUpdate('height')) {
2355
        modifier.setStyle('height', addPxSuffix(data.height));
2356
      }
2357
    };
2358
    const updateAdvancedProps = (modifier, data, shouldUpdate) => {
2359
      if (shouldUpdate('backgroundcolor')) {
2360
        modifier.setStyle('background-color', data.backgroundcolor);
2361
      }
2362
      if (shouldUpdate('bordercolor')) {
2363
        modifier.setStyle('border-color', data.bordercolor);
2364
      }
2365
      if (shouldUpdate('borderstyle')) {
2366
        modifier.setStyle('border-style', data.borderstyle);
2367
      }
2368
    };
2369
    const applyStyleData = (editor, rows, data, wasChanged) => {
2370
      const isSingleRow = rows.length === 1;
2371
      const shouldOverrideCurrentValue = isSingleRow ? always : wasChanged;
2372
      each(rows, rowElm => {
1441 ariadna 2373
        const rowCells = children$1(SugarElement.fromDom(rowElm), 'td,th');
1 efrain 2374
        const modifier = DomModifier.normal(editor, rowElm);
2375
        updateSimpleProps(modifier, data, shouldOverrideCurrentValue);
2376
        if (hasAdvancedRowTab(editor)) {
2377
          updateAdvancedProps(modifier, data, shouldOverrideCurrentValue);
2378
        }
1441 ariadna 2379
        if (wasChanged('height')) {
2380
          each(rowCells, cell => {
2381
            editor.dom.setStyle(cell.dom, 'height', null);
2382
          });
2383
        }
1 efrain 2384
        if (wasChanged('align')) {
2385
          setAlign(editor, rowElm, data.align);
2386
        }
2387
      });
2388
    };
2389
    const applyStructureData = (editor, data) => {
2390
      editor.execCommand('mceTableRowType', false, {
2391
        type: data.type,
2392
        no_events: true
2393
      });
2394
    };
2395
    const applyRowData = (editor, rows, oldData, data) => {
2396
      const modifiedData = filter$1(data, (value, key) => oldData[key] !== value);
2397
      if (size(modifiedData) > 0) {
2398
        const typeModified = has(modifiedData, 'type');
2399
        const styleModified = typeModified ? size(modifiedData) > 1 : true;
2400
        if (styleModified) {
2401
          applyStyleData(editor, rows, data, curry(has, modifiedData));
2402
        }
2403
        if (typeModified) {
2404
          applyStructureData(editor, data);
2405
        }
2406
        table(SugarElement.fromDom(rows[0])).each(table => fireTableModified(editor, table.dom, {
2407
          structure: typeModified,
2408
          style: styleModified
2409
        }));
2410
      }
2411
    };
2412
    const onSubmitRowForm = (editor, rows, oldData, api) => {
2413
      const data = api.getData();
2414
      api.close();
2415
      editor.undoManager.transact(() => {
2416
        applyRowData(editor, rows, oldData, data);
2417
        editor.focus();
2418
      });
2419
    };
2420
    const open$1 = editor => {
2421
      const rows = getRowsFromSelection(getSelectionStart(editor), ephemera.selected);
2422
      if (rows.length === 0) {
2423
        return;
2424
      }
2425
      const rowsData = map(rows, rowElm => extractDataFromRowElement(editor, rowElm.dom, hasAdvancedRowTab(editor)));
2426
      const data = getSharedValues(rowsData);
2427
      const dialogTabPanel = {
2428
        type: 'tabpanel',
2429
        tabs: [
2430
          {
2431
            title: 'General',
2432
            name: 'general',
2433
            items: getItems$1(editor)
2434
          },
2435
          getAdvancedTab(editor, 'row')
2436
        ]
2437
      };
2438
      const dialogPanel = {
2439
        type: 'panel',
2440
        items: [{
2441
            type: 'grid',
2442
            columns: 2,
2443
            items: getItems$1(editor)
2444
          }]
2445
      };
2446
      editor.windowManager.open({
2447
        title: 'Row Properties',
2448
        size: 'normal',
2449
        body: hasAdvancedRowTab(editor) ? dialogTabPanel : dialogPanel,
2450
        buttons: [
2451
          {
2452
            type: 'cancel',
2453
            name: 'cancel',
2454
            text: 'Cancel'
2455
          },
2456
          {
2457
            type: 'submit',
2458
            name: 'save',
2459
            text: 'Save',
2460
            primary: true
2461
          }
2462
        ],
2463
        initialData: data,
2464
        onSubmit: curry(onSubmitRowForm, editor, map(rows, r => r.dom), data)
2465
      });
2466
    };
2467
 
2468
    const getItems = (editor, classes, insertNewTable) => {
2469
      const rowColCountItems = !insertNewTable ? [] : [
2470
        {
2471
          type: 'input',
2472
          name: 'cols',
2473
          label: 'Cols',
2474
          inputMode: 'numeric'
2475
        },
2476
        {
2477
          type: 'input',
2478
          name: 'rows',
2479
          label: 'Rows',
2480
          inputMode: 'numeric'
2481
        }
2482
      ];
2483
      const alwaysItems = [
2484
        {
2485
          type: 'input',
2486
          name: 'width',
2487
          label: 'Width'
2488
        },
2489
        {
2490
          type: 'input',
2491
          name: 'height',
2492
          label: 'Height'
2493
        }
2494
      ];
2495
      const appearanceItems = hasAppearanceOptions(editor) ? [
2496
        {
2497
          type: 'input',
2498
          name: 'cellspacing',
2499
          label: 'Cell spacing',
2500
          inputMode: 'numeric'
2501
        },
2502
        {
2503
          type: 'input',
2504
          name: 'cellpadding',
2505
          label: 'Cell padding',
2506
          inputMode: 'numeric'
2507
        },
2508
        {
2509
          type: 'input',
2510
          name: 'border',
2511
          label: 'Border width'
2512
        },
2513
        {
2514
          type: 'label',
2515
          label: 'Caption',
2516
          items: [{
2517
              type: 'checkbox',
2518
              name: 'caption',
2519
              label: 'Show caption'
2520
            }]
2521
        }
2522
      ] : [];
2523
      const alignmentItem = [{
2524
          type: 'listbox',
2525
          name: 'align',
2526
          label: 'Alignment',
2527
          items: [
2528
            {
2529
              text: 'None',
2530
              value: ''
2531
            },
2532
            {
2533
              text: 'Left',
2534
              value: 'left'
2535
            },
2536
            {
2537
              text: 'Center',
2538
              value: 'center'
2539
            },
2540
            {
2541
              text: 'Right',
2542
              value: 'right'
2543
            }
2544
          ]
2545
        }];
2546
      const classListItem = classes.length > 0 ? [{
1441 ariadna 2547
          name: 'class',
1 efrain 2548
          type: 'listbox',
2549
          label: 'Class',
2550
          items: classes
2551
        }] : [];
2552
      return rowColCountItems.concat(alwaysItems).concat(appearanceItems).concat(alignmentItem).concat(classListItem);
2553
    };
2554
 
2555
    const styleTDTH = (dom, elm, name, value) => {
2556
      if (elm.tagName === 'TD' || elm.tagName === 'TH') {
2557
        if (isString(name) && isNonNullable(value)) {
2558
          dom.setStyle(elm, name, value);
2559
        } else {
2560
          dom.setStyles(elm, name);
2561
        }
2562
      } else {
2563
        if (elm.children) {
2564
          for (let i = 0; i < elm.children.length; i++) {
2565
            styleTDTH(dom, elm.children[i], name, value);
2566
          }
2567
        }
2568
      }
2569
    };
2570
    const applyDataToElement = (editor, tableElm, data, shouldApplyOnCell) => {
2571
      const dom = editor.dom;
2572
      const attrs = {};
2573
      const styles = {};
2574
      const shouldStyleWithCss$1 = shouldStyleWithCss(editor);
2575
      const hasAdvancedTableTab$1 = hasAdvancedTableTab(editor);
1441 ariadna 2576
      const borderIsZero = parseFloat(data.border) === 0;
2577
      if (!isUndefined(data.class) && data.class !== 'mce-no-match') {
1 efrain 2578
        attrs.class = data.class;
2579
      }
2580
      styles.height = addPxSuffix(data.height);
2581
      if (shouldStyleWithCss$1) {
2582
        styles.width = addPxSuffix(data.width);
2583
      } else if (dom.getAttrib(tableElm, 'width')) {
2584
        attrs.width = removePxSuffix(data.width);
2585
      }
2586
      if (shouldStyleWithCss$1) {
1441 ariadna 2587
        if (borderIsZero) {
2588
          attrs.border = 0;
2589
          styles['border-width'] = '';
2590
        } else {
2591
          styles['border-width'] = addPxSuffix(data.border);
2592
          attrs.border = 1;
2593
        }
1 efrain 2594
        styles['border-spacing'] = addPxSuffix(data.cellspacing);
2595
      } else {
1441 ariadna 2596
        attrs.border = borderIsZero ? 0 : data.border;
1 efrain 2597
        attrs.cellpadding = data.cellpadding;
2598
        attrs.cellspacing = data.cellspacing;
2599
      }
2600
      if (shouldStyleWithCss$1 && tableElm.children) {
2601
        const cellStyles = {};
1441 ariadna 2602
        if (borderIsZero) {
2603
          cellStyles['border-width'] = '';
2604
        } else if (shouldApplyOnCell.border) {
1 efrain 2605
          cellStyles['border-width'] = addPxSuffix(data.border);
2606
        }
2607
        if (shouldApplyOnCell.cellpadding) {
2608
          cellStyles.padding = addPxSuffix(data.cellpadding);
2609
        }
2610
        if (hasAdvancedTableTab$1 && shouldApplyOnCell.bordercolor) {
2611
          cellStyles['border-color'] = data.bordercolor;
2612
        }
2613
        if (!isEmpty$1(cellStyles)) {
2614
          for (let i = 0; i < tableElm.children.length; i++) {
2615
            styleTDTH(dom, tableElm.children[i], cellStyles);
2616
          }
2617
        }
2618
      }
2619
      if (hasAdvancedTableTab$1) {
2620
        const advData = data;
2621
        styles['background-color'] = advData.backgroundcolor;
2622
        styles['border-color'] = advData.bordercolor;
2623
        styles['border-style'] = advData.borderstyle;
2624
      }
2625
      dom.setStyles(tableElm, {
2626
        ...getDefaultStyles(editor),
2627
        ...styles
2628
      });
2629
      dom.setAttribs(tableElm, {
2630
        ...getDefaultAttributes(editor),
2631
        ...attrs
2632
      });
2633
    };
2634
    const onSubmitTableForm = (editor, tableElm, oldData, api) => {
2635
      const dom = editor.dom;
2636
      const data = api.getData();
2637
      const modifiedData = filter$1(data, (value, key) => oldData[key] !== value);
2638
      api.close();
2639
      editor.undoManager.transact(() => {
2640
        if (!tableElm) {
2641
          const cols = toInt(data.cols).getOr(1);
2642
          const rows = toInt(data.rows).getOr(1);
2643
          editor.execCommand('mceInsertTable', false, {
2644
            rows,
2645
            columns: cols
2646
          });
2647
          tableElm = getSelectionCell(getSelectionStart(editor), getIsRoot(editor)).bind(cell => table(cell, getIsRoot(editor))).map(table => table.dom).getOrDie();
2648
        }
2649
        if (size(modifiedData) > 0) {
2650
          const applicableCellProperties = {
2651
            border: has(modifiedData, 'border'),
2652
            bordercolor: has(modifiedData, 'bordercolor'),
2653
            cellpadding: has(modifiedData, 'cellpadding')
2654
          };
2655
          applyDataToElement(editor, tableElm, data, applicableCellProperties);
2656
          const captionElm = dom.select('caption', tableElm)[0];
2657
          if (captionElm && !data.caption || !captionElm && data.caption) {
2658
            editor.execCommand('mceTableToggleCaption');
2659
          }
2660
          setAlign(editor, tableElm, data.align);
2661
        }
2662
        editor.focus();
2663
        editor.addVisual();
2664
        if (size(modifiedData) > 0) {
2665
          const captionModified = has(modifiedData, 'caption');
2666
          const styleModified = captionModified ? size(modifiedData) > 1 : true;
2667
          fireTableModified(editor, tableElm, {
2668
            structure: captionModified,
2669
            style: styleModified
2670
          });
2671
        }
2672
      });
2673
    };
2674
    const open = (editor, insertNewTable) => {
2675
      const dom = editor.dom;
2676
      let tableElm;
2677
      let data = extractDataFromSettings(editor, hasAdvancedTableTab(editor));
2678
      if (insertNewTable) {
2679
        data.cols = '1';
2680
        data.rows = '1';
2681
        if (hasAdvancedTableTab(editor)) {
2682
          data.borderstyle = '';
2683
          data.bordercolor = '';
2684
          data.backgroundcolor = '';
2685
        }
2686
      } else {
2687
        tableElm = dom.getParent(editor.selection.getStart(), 'table', editor.getBody());
2688
        if (tableElm) {
2689
          data = extractDataFromTableElement(editor, tableElm, hasAdvancedTableTab(editor));
2690
        } else {
2691
          if (hasAdvancedTableTab(editor)) {
2692
            data.borderstyle = '';
2693
            data.bordercolor = '';
2694
            data.backgroundcolor = '';
2695
          }
2696
        }
2697
      }
1441 ariadna 2698
      const classes = buildClassList(getTableClassList(editor));
2699
      if (classes.isSome()) {
1 efrain 2700
        if (data.class) {
2701
          data.class = data.class.replace(/\s*mce\-item\-table\s*/g, '');
2702
        }
2703
      }
2704
      const generalPanel = {
2705
        type: 'grid',
2706
        columns: 2,
1441 ariadna 2707
        items: getItems(editor, classes.getOr([]), insertNewTable)
1 efrain 2708
      };
2709
      const nonAdvancedForm = () => ({
2710
        type: 'panel',
2711
        items: [generalPanel]
2712
      });
2713
      const advancedForm = () => ({
2714
        type: 'tabpanel',
2715
        tabs: [
2716
          {
2717
            title: 'General',
2718
            name: 'general',
2719
            items: [generalPanel]
2720
          },
2721
          getAdvancedTab(editor, 'table')
2722
        ]
2723
      });
2724
      const dialogBody = hasAdvancedTableTab(editor) ? advancedForm() : nonAdvancedForm();
2725
      editor.windowManager.open({
2726
        title: 'Table Properties',
2727
        size: 'normal',
2728
        body: dialogBody,
2729
        onSubmit: curry(onSubmitTableForm, editor, tableElm, data),
2730
        buttons: [
2731
          {
2732
            type: 'cancel',
2733
            name: 'cancel',
2734
            text: 'Cancel'
2735
          },
2736
          {
2737
            type: 'submit',
2738
            name: 'save',
2739
            text: 'Save',
2740
            primary: true
2741
          }
2742
        ],
2743
        initialData: data
2744
      });
2745
    };
2746
 
2747
    const registerCommands = editor => {
2748
      const runAction = f => {
2749
        if (isInEditableContext(getSelectionStart(editor))) {
2750
          f();
2751
        }
2752
      };
2753
      each$1({
2754
        mceTableProps: curry(open, editor, false),
2755
        mceTableRowProps: curry(open$1, editor),
2756
        mceTableCellProps: curry(open$2, editor),
2757
        mceInsertTableDialog: curry(open, editor, true)
2758
      }, (func, name) => editor.addCommand(name, () => runAction(func)));
2759
    };
2760
 
2761
    const child = (scope, selector) => child$1(scope, selector).isSome();
2762
 
2763
    const selection = identity;
2764
    const unmergable = selectedCells => {
2765
      const hasSpan = (elem, type) => getOpt(elem, type).exists(span => parseInt(span, 10) > 1);
2766
      const hasRowOrColSpan = elem => hasSpan(elem, 'rowspan') || hasSpan(elem, 'colspan');
2767
      return selectedCells.length > 0 && forall(selectedCells, hasRowOrColSpan) ? Optional.some(selectedCells) : Optional.none();
2768
    };
2769
    const mergable = (table, selectedCells, ephemera) => {
2770
      if (selectedCells.length <= 1) {
2771
        return Optional.none();
2772
      } else {
2773
        return retrieveBox(table, ephemera.firstSelectedSelector, ephemera.lastSelectedSelector).map(bounds => ({
2774
          bounds,
2775
          cells: selectedCells
2776
        }));
2777
      }
2778
    };
2779
 
2780
    const noMenu = cell => ({
2781
      element: cell,
2782
      mergable: Optional.none(),
2783
      unmergable: Optional.none(),
2784
      selection: [cell]
2785
    });
2786
    const forMenu = (selectedCells, table, cell) => ({
2787
      element: cell,
2788
      mergable: mergable(table, selectedCells, ephemera),
2789
      unmergable: unmergable(selectedCells),
2790
      selection: selection(selectedCells)
2791
    });
2792
 
2793
    const getSelectionTargets = editor => {
2794
      const targets = Cell(Optional.none());
2795
      const changeHandlers = Cell([]);
2796
      let selectionDetails = Optional.none();
2797
      const isCaption = isTag('caption');
2798
      const isDisabledForSelection = key => selectionDetails.forall(details => !details[key]);
2799
      const getStart = () => getSelectionCellOrCaption(getSelectionStart(editor), getIsRoot(editor));
2800
      const getEnd = () => getSelectionCellOrCaption(getSelectionEnd(editor), getIsRoot(editor));
2801
      const findTargets = () => getStart().bind(startCellOrCaption => flatten(lift2(table(startCellOrCaption), getEnd().bind(table), (startTable, endTable) => {
2802
        if (eq(startTable, endTable)) {
2803
          if (isCaption(startCellOrCaption)) {
2804
            return Optional.some(noMenu(startCellOrCaption));
2805
          } else {
2806
            return Optional.some(forMenu(getCellsFromSelection(editor), startTable, startCellOrCaption));
2807
          }
2808
        }
2809
        return Optional.none();
2810
      })));
2811
      const getExtractedDetails = targets => {
2812
        const tableOpt = table(targets.element);
2813
        return tableOpt.map(table => {
2814
          const warehouse = Warehouse.fromTable(table);
2815
          const selectedCells = onCells(warehouse, targets).getOr([]);
2816
          const locked = foldl(selectedCells, (acc, cell) => {
2817
            if (cell.isLocked) {
2818
              acc.onAny = true;
2819
              if (cell.column === 0) {
2820
                acc.onFirst = true;
2821
              } else if (cell.column + cell.colspan >= warehouse.grid.columns) {
2822
                acc.onLast = true;
2823
              }
2824
            }
2825
            return acc;
2826
          }, {
2827
            onAny: false,
2828
            onFirst: false,
2829
            onLast: false
2830
          });
2831
          return {
2832
            mergeable: onUnlockedMergable(warehouse, targets).isSome(),
2833
            unmergeable: onUnlockedUnmergable(warehouse, targets).isSome(),
2834
            locked
2835
          };
2836
        });
2837
      };
2838
      const resetTargets = () => {
2839
        targets.set(cached(findTargets)());
2840
        selectionDetails = targets.get().bind(getExtractedDetails);
2841
        each(changeHandlers.get(), call);
2842
      };
2843
      const setupHandler = handler => {
2844
        handler();
2845
        changeHandlers.set(changeHandlers.get().concat([handler]));
2846
        return () => {
2847
          changeHandlers.set(filter(changeHandlers.get(), h => h !== handler));
2848
        };
2849
      };
2850
      const onSetup = (api, isDisabled) => setupHandler(() => targets.get().fold(() => {
2851
        api.setEnabled(false);
2852
      }, targets => {
2853
        api.setEnabled(!isDisabled(targets) && editor.selection.isEditable());
2854
      }));
2855
      const onSetupWithToggle = (api, isDisabled, isActive) => setupHandler(() => targets.get().fold(() => {
2856
        api.setEnabled(false);
2857
        api.setActive(false);
2858
      }, targets => {
2859
        api.setEnabled(!isDisabled(targets) && editor.selection.isEditable());
2860
        api.setActive(isActive(targets));
2861
      }));
2862
      const isDisabledFromLocked = lockedDisable => selectionDetails.exists(details => details.locked[lockedDisable]);
2863
      const onSetupTable = api => onSetup(api, _ => false);
2864
      const onSetupCellOrRow = api => onSetup(api, targets => isCaption(targets.element));
2865
      const onSetupColumn = lockedDisable => api => onSetup(api, targets => isCaption(targets.element) || isDisabledFromLocked(lockedDisable));
2866
      const onSetupPasteable = getClipboardData => api => onSetup(api, targets => isCaption(targets.element) || getClipboardData().isNone());
2867
      const onSetupPasteableColumn = (getClipboardData, lockedDisable) => api => onSetup(api, targets => isCaption(targets.element) || getClipboardData().isNone() || isDisabledFromLocked(lockedDisable));
2868
      const onSetupMergeable = api => onSetup(api, _targets => isDisabledForSelection('mergeable'));
2869
      const onSetupUnmergeable = api => onSetup(api, _targets => isDisabledForSelection('unmergeable'));
2870
      const onSetupTableWithCaption = api => {
2871
        return onSetupWithToggle(api, never, targets => {
2872
          const tableOpt = table(targets.element, getIsRoot(editor));
2873
          return tableOpt.exists(table => child(table, 'caption'));
2874
        });
2875
      };
2876
      const onSetupTableHeaders = (command, headerType) => api => {
2877
        return onSetupWithToggle(api, targets => isCaption(targets.element), () => editor.queryCommandValue(command) === headerType);
2878
      };
2879
      const onSetupTableRowHeaders = onSetupTableHeaders('mceTableRowType', 'header');
2880
      const onSetupTableColumnHeaders = onSetupTableHeaders('mceTableColType', 'th');
2881
      editor.on('NodeChange ExecCommand TableSelectorChange', resetTargets);
2882
      return {
2883
        onSetupTable,
2884
        onSetupCellOrRow,
2885
        onSetupColumn,
2886
        onSetupPasteable,
2887
        onSetupPasteableColumn,
2888
        onSetupMergeable,
2889
        onSetupUnmergeable,
2890
        resetTargets,
2891
        onSetupTableWithCaption,
2892
        onSetupTableRowHeaders,
2893
        onSetupTableColumnHeaders,
2894
        targets: targets.get
2895
      };
2896
    };
2897
 
2898
    var global = tinymce.util.Tools.resolve('tinymce.FakeClipboard');
2899
 
2900
    const tableTypeBase = 'x-tinymce/dom-table-';
2901
    const tableTypeRow = tableTypeBase + 'rows';
2902
    const tableTypeColumn = tableTypeBase + 'columns';
2903
    const getData = type => {
2904
      var _a;
2905
      const items = (_a = global.read()) !== null && _a !== void 0 ? _a : [];
2906
      return findMap(items, item => Optional.from(item.getType(type)));
2907
    };
2908
    const getRows = () => getData(tableTypeRow);
2909
    const getColumns = () => getData(tableTypeColumn);
2910
 
2911
    const onSetupEditable$1 = editor => api => {
2912
      const nodeChanged = () => {
2913
        api.setEnabled(editor.selection.isEditable());
2914
      };
2915
      editor.on('NodeChange', nodeChanged);
2916
      nodeChanged();
2917
      return () => {
2918
        editor.off('NodeChange', nodeChanged);
2919
      };
2920
    };
2921
    const addButtons = (editor, selectionTargets) => {
2922
      editor.ui.registry.addMenuButton('table', {
2923
        tooltip: 'Table',
2924
        icon: 'table',
2925
        onSetup: onSetupEditable$1(editor),
2926
        fetch: callback => callback('inserttable | cell row column | advtablesort | tableprops deletetable')
2927
      });
2928
      const cmd = command => () => editor.execCommand(command);
2929
      const addButtonIfRegistered = (name, spec) => {
2930
        if (editor.queryCommandSupported(spec.command)) {
2931
          editor.ui.registry.addButton(name, {
2932
            ...spec,
2933
            onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)
2934
          });
2935
        }
2936
      };
2937
      const addToggleButtonIfRegistered = (name, spec) => {
2938
        if (editor.queryCommandSupported(spec.command)) {
2939
          editor.ui.registry.addToggleButton(name, {
2940
            ...spec,
2941
            onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)
2942
          });
2943
        }
2944
      };
2945
      addButtonIfRegistered('tableprops', {
2946
        tooltip: 'Table properties',
2947
        command: 'mceTableProps',
2948
        icon: 'table',
2949
        onSetup: selectionTargets.onSetupTable
2950
      });
2951
      addButtonIfRegistered('tabledelete', {
2952
        tooltip: 'Delete table',
2953
        command: 'mceTableDelete',
2954
        icon: 'table-delete-table',
2955
        onSetup: selectionTargets.onSetupTable
2956
      });
2957
      addButtonIfRegistered('tablecellprops', {
2958
        tooltip: 'Cell properties',
2959
        command: 'mceTableCellProps',
2960
        icon: 'table-cell-properties',
2961
        onSetup: selectionTargets.onSetupCellOrRow
2962
      });
2963
      addButtonIfRegistered('tablemergecells', {
2964
        tooltip: 'Merge cells',
2965
        command: 'mceTableMergeCells',
2966
        icon: 'table-merge-cells',
2967
        onSetup: selectionTargets.onSetupMergeable
2968
      });
2969
      addButtonIfRegistered('tablesplitcells', {
2970
        tooltip: 'Split cell',
2971
        command: 'mceTableSplitCells',
2972
        icon: 'table-split-cells',
2973
        onSetup: selectionTargets.onSetupUnmergeable
2974
      });
2975
      addButtonIfRegistered('tableinsertrowbefore', {
2976
        tooltip: 'Insert row before',
2977
        command: 'mceTableInsertRowBefore',
2978
        icon: 'table-insert-row-above',
2979
        onSetup: selectionTargets.onSetupCellOrRow
2980
      });
2981
      addButtonIfRegistered('tableinsertrowafter', {
2982
        tooltip: 'Insert row after',
2983
        command: 'mceTableInsertRowAfter',
2984
        icon: 'table-insert-row-after',
2985
        onSetup: selectionTargets.onSetupCellOrRow
2986
      });
2987
      addButtonIfRegistered('tabledeleterow', {
2988
        tooltip: 'Delete row',
2989
        command: 'mceTableDeleteRow',
2990
        icon: 'table-delete-row',
2991
        onSetup: selectionTargets.onSetupCellOrRow
2992
      });
2993
      addButtonIfRegistered('tablerowprops', {
2994
        tooltip: 'Row properties',
2995
        command: 'mceTableRowProps',
2996
        icon: 'table-row-properties',
2997
        onSetup: selectionTargets.onSetupCellOrRow
2998
      });
2999
      addButtonIfRegistered('tableinsertcolbefore', {
3000
        tooltip: 'Insert column before',
3001
        command: 'mceTableInsertColBefore',
3002
        icon: 'table-insert-column-before',
3003
        onSetup: selectionTargets.onSetupColumn('onFirst')
3004
      });
3005
      addButtonIfRegistered('tableinsertcolafter', {
3006
        tooltip: 'Insert column after',
3007
        command: 'mceTableInsertColAfter',
3008
        icon: 'table-insert-column-after',
3009
        onSetup: selectionTargets.onSetupColumn('onLast')
3010
      });
3011
      addButtonIfRegistered('tabledeletecol', {
3012
        tooltip: 'Delete column',
3013
        command: 'mceTableDeleteCol',
3014
        icon: 'table-delete-column',
3015
        onSetup: selectionTargets.onSetupColumn('onAny')
3016
      });
3017
      addButtonIfRegistered('tablecutrow', {
3018
        tooltip: 'Cut row',
3019
        command: 'mceTableCutRow',
3020
        icon: 'cut-row',
3021
        onSetup: selectionTargets.onSetupCellOrRow
3022
      });
3023
      addButtonIfRegistered('tablecopyrow', {
3024
        tooltip: 'Copy row',
3025
        command: 'mceTableCopyRow',
3026
        icon: 'duplicate-row',
3027
        onSetup: selectionTargets.onSetupCellOrRow
3028
      });
3029
      addButtonIfRegistered('tablepasterowbefore', {
3030
        tooltip: 'Paste row before',
3031
        command: 'mceTablePasteRowBefore',
3032
        icon: 'paste-row-before',
3033
        onSetup: selectionTargets.onSetupPasteable(getRows)
3034
      });
3035
      addButtonIfRegistered('tablepasterowafter', {
3036
        tooltip: 'Paste row after',
3037
        command: 'mceTablePasteRowAfter',
3038
        icon: 'paste-row-after',
3039
        onSetup: selectionTargets.onSetupPasteable(getRows)
3040
      });
3041
      addButtonIfRegistered('tablecutcol', {
3042
        tooltip: 'Cut column',
3043
        command: 'mceTableCutCol',
3044
        icon: 'cut-column',
3045
        onSetup: selectionTargets.onSetupColumn('onAny')
3046
      });
3047
      addButtonIfRegistered('tablecopycol', {
3048
        tooltip: 'Copy column',
3049
        command: 'mceTableCopyCol',
3050
        icon: 'duplicate-column',
3051
        onSetup: selectionTargets.onSetupColumn('onAny')
3052
      });
3053
      addButtonIfRegistered('tablepastecolbefore', {
3054
        tooltip: 'Paste column before',
3055
        command: 'mceTablePasteColBefore',
3056
        icon: 'paste-column-before',
3057
        onSetup: selectionTargets.onSetupPasteableColumn(getColumns, 'onFirst')
3058
      });
3059
      addButtonIfRegistered('tablepastecolafter', {
3060
        tooltip: 'Paste column after',
3061
        command: 'mceTablePasteColAfter',
3062
        icon: 'paste-column-after',
3063
        onSetup: selectionTargets.onSetupPasteableColumn(getColumns, 'onLast')
3064
      });
3065
      addButtonIfRegistered('tableinsertdialog', {
3066
        tooltip: 'Insert table',
3067
        command: 'mceInsertTableDialog',
3068
        icon: 'table',
3069
        onSetup: onSetupEditable$1(editor)
3070
      });
3071
      const tableClassList = filterNoneItem(getTableClassList(editor));
3072
      if (tableClassList.length !== 0 && editor.queryCommandSupported('mceTableToggleClass')) {
3073
        editor.ui.registry.addMenuButton('tableclass', {
3074
          icon: 'table-classes',
3075
          tooltip: 'Table styles',
3076
          fetch: generateMenuItemsCallback(editor, tableClassList, 'tableclass', value => editor.execCommand('mceTableToggleClass', false, value)),
3077
          onSetup: selectionTargets.onSetupTable
3078
        });
3079
      }
3080
      const tableCellClassList = filterNoneItem(getCellClassList(editor));
3081
      if (tableCellClassList.length !== 0 && editor.queryCommandSupported('mceTableCellToggleClass')) {
3082
        editor.ui.registry.addMenuButton('tablecellclass', {
3083
          icon: 'table-cell-classes',
3084
          tooltip: 'Cell styles',
3085
          fetch: generateMenuItemsCallback(editor, tableCellClassList, 'tablecellclass', value => editor.execCommand('mceTableCellToggleClass', false, value)),
3086
          onSetup: selectionTargets.onSetupCellOrRow
3087
        });
3088
      }
3089
      if (editor.queryCommandSupported('mceTableApplyCellStyle')) {
3090
        editor.ui.registry.addMenuButton('tablecellvalign', {
3091
          icon: 'vertical-align',
3092
          tooltip: 'Vertical align',
3093
          fetch: generateMenuItemsCallback(editor, verticalAlignValues, 'tablecellverticalalign', applyTableCellStyle(editor, 'vertical-align')),
3094
          onSetup: selectionTargets.onSetupCellOrRow
3095
        });
3096
        editor.ui.registry.addMenuButton('tablecellborderwidth', {
3097
          icon: 'border-width',
3098
          tooltip: 'Border width',
3099
          fetch: generateMenuItemsCallback(editor, getTableBorderWidths(editor), 'tablecellborderwidth', applyTableCellStyle(editor, 'border-width')),
3100
          onSetup: selectionTargets.onSetupCellOrRow
3101
        });
3102
        editor.ui.registry.addMenuButton('tablecellborderstyle', {
3103
          icon: 'border-style',
3104
          tooltip: 'Border style',
3105
          fetch: generateMenuItemsCallback(editor, getTableBorderStyles(editor), 'tablecellborderstyle', applyTableCellStyle(editor, 'border-style')),
3106
          onSetup: selectionTargets.onSetupCellOrRow
3107
        });
3108
        editor.ui.registry.addMenuButton('tablecellbackgroundcolor', {
3109
          icon: 'cell-background-color',
3110
          tooltip: 'Background color',
3111
          fetch: callback => callback(buildColorMenu(editor, getTableBackgroundColorMap(editor), 'background-color')),
3112
          onSetup: selectionTargets.onSetupCellOrRow
3113
        });
3114
        editor.ui.registry.addMenuButton('tablecellbordercolor', {
3115
          icon: 'cell-border-color',
3116
          tooltip: 'Border color',
3117
          fetch: callback => callback(buildColorMenu(editor, getTableBorderColorMap(editor), 'border-color')),
3118
          onSetup: selectionTargets.onSetupCellOrRow
3119
        });
3120
      }
3121
      addToggleButtonIfRegistered('tablecaption', {
3122
        tooltip: 'Table caption',
3123
        icon: 'table-caption',
3124
        command: 'mceTableToggleCaption',
3125
        onSetup: selectionTargets.onSetupTableWithCaption
3126
      });
3127
      addToggleButtonIfRegistered('tablerowheader', {
3128
        tooltip: 'Row header',
3129
        icon: 'table-top-header',
3130
        command: 'mceTableRowType',
3131
        onAction: changeRowHeader(editor),
3132
        onSetup: selectionTargets.onSetupTableRowHeaders
3133
      });
3134
      addToggleButtonIfRegistered('tablecolheader', {
3135
        tooltip: 'Column header',
3136
        icon: 'table-left-header',
3137
        command: 'mceTableColType',
3138
        onAction: changeColumnHeader(editor),
3139
        onSetup: selectionTargets.onSetupTableColumnHeaders
3140
      });
3141
    };
3142
    const addToolbars = editor => {
3143
      const isEditableTable = table => editor.dom.is(table, 'table') && editor.getBody().contains(table) && editor.dom.isEditable(table.parentNode);
3144
      const toolbar = getToolbar(editor);
3145
      if (toolbar.length > 0) {
3146
        editor.ui.registry.addContextToolbar('table', {
3147
          predicate: isEditableTable,
3148
          items: toolbar,
3149
          scope: 'node',
3150
          position: 'node'
3151
        });
3152
      }
3153
    };
3154
 
3155
    const onSetupEditable = editor => api => {
3156
      const nodeChanged = () => {
3157
        api.setEnabled(editor.selection.isEditable());
3158
      };
3159
      editor.on('NodeChange', nodeChanged);
3160
      nodeChanged();
3161
      return () => {
3162
        editor.off('NodeChange', nodeChanged);
3163
      };
3164
    };
3165
    const addMenuItems = (editor, selectionTargets) => {
3166
      const cmd = command => () => editor.execCommand(command);
3167
      const addMenuIfRegistered = (name, spec) => {
3168
        if (editor.queryCommandSupported(spec.command)) {
3169
          editor.ui.registry.addMenuItem(name, {
3170
            ...spec,
3171
            onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)
3172
          });
3173
          return true;
3174
        } else {
3175
          return false;
3176
        }
3177
      };
3178
      const addToggleMenuIfRegistered = (name, spec) => {
3179
        if (editor.queryCommandSupported(spec.command)) {
3180
          editor.ui.registry.addToggleMenuItem(name, {
3181
            ...spec,
3182
            onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)
3183
          });
3184
        }
3185
      };
3186
      const insertTableAction = data => {
3187
        editor.execCommand('mceInsertTable', false, {
3188
          rows: data.numRows,
3189
          columns: data.numColumns
3190
        });
3191
      };
3192
      const hasRowMenuItems = [
3193
        addMenuIfRegistered('tableinsertrowbefore', {
3194
          text: 'Insert row before',
3195
          icon: 'table-insert-row-above',
3196
          command: 'mceTableInsertRowBefore',
3197
          onSetup: selectionTargets.onSetupCellOrRow
3198
        }),
3199
        addMenuIfRegistered('tableinsertrowafter', {
3200
          text: 'Insert row after',
3201
          icon: 'table-insert-row-after',
3202
          command: 'mceTableInsertRowAfter',
3203
          onSetup: selectionTargets.onSetupCellOrRow
3204
        }),
3205
        addMenuIfRegistered('tabledeleterow', {
3206
          text: 'Delete row',
3207
          icon: 'table-delete-row',
3208
          command: 'mceTableDeleteRow',
3209
          onSetup: selectionTargets.onSetupCellOrRow
3210
        }),
3211
        addMenuIfRegistered('tablerowprops', {
3212
          text: 'Row properties',
3213
          icon: 'table-row-properties',
3214
          command: 'mceTableRowProps',
3215
          onSetup: selectionTargets.onSetupCellOrRow
3216
        }),
3217
        addMenuIfRegistered('tablecutrow', {
3218
          text: 'Cut row',
3219
          icon: 'cut-row',
3220
          command: 'mceTableCutRow',
3221
          onSetup: selectionTargets.onSetupCellOrRow
3222
        }),
3223
        addMenuIfRegistered('tablecopyrow', {
3224
          text: 'Copy row',
3225
          icon: 'duplicate-row',
3226
          command: 'mceTableCopyRow',
3227
          onSetup: selectionTargets.onSetupCellOrRow
3228
        }),
3229
        addMenuIfRegistered('tablepasterowbefore', {
3230
          text: 'Paste row before',
3231
          icon: 'paste-row-before',
3232
          command: 'mceTablePasteRowBefore',
3233
          onSetup: selectionTargets.onSetupPasteable(getRows)
3234
        }),
3235
        addMenuIfRegistered('tablepasterowafter', {
3236
          text: 'Paste row after',
3237
          icon: 'paste-row-after',
3238
          command: 'mceTablePasteRowAfter',
3239
          onSetup: selectionTargets.onSetupPasteable(getRows)
3240
        })
3241
      ];
3242
      const hasColumnMenuItems = [
3243
        addMenuIfRegistered('tableinsertcolumnbefore', {
3244
          text: 'Insert column before',
3245
          icon: 'table-insert-column-before',
3246
          command: 'mceTableInsertColBefore',
3247
          onSetup: selectionTargets.onSetupColumn('onFirst')
3248
        }),
3249
        addMenuIfRegistered('tableinsertcolumnafter', {
3250
          text: 'Insert column after',
3251
          icon: 'table-insert-column-after',
3252
          command: 'mceTableInsertColAfter',
3253
          onSetup: selectionTargets.onSetupColumn('onLast')
3254
        }),
3255
        addMenuIfRegistered('tabledeletecolumn', {
3256
          text: 'Delete column',
3257
          icon: 'table-delete-column',
3258
          command: 'mceTableDeleteCol',
3259
          onSetup: selectionTargets.onSetupColumn('onAny')
3260
        }),
3261
        addMenuIfRegistered('tablecutcolumn', {
3262
          text: 'Cut column',
3263
          icon: 'cut-column',
3264
          command: 'mceTableCutCol',
3265
          onSetup: selectionTargets.onSetupColumn('onAny')
3266
        }),
3267
        addMenuIfRegistered('tablecopycolumn', {
3268
          text: 'Copy column',
3269
          icon: 'duplicate-column',
3270
          command: 'mceTableCopyCol',
3271
          onSetup: selectionTargets.onSetupColumn('onAny')
3272
        }),
3273
        addMenuIfRegistered('tablepastecolumnbefore', {
3274
          text: 'Paste column before',
3275
          icon: 'paste-column-before',
3276
          command: 'mceTablePasteColBefore',
3277
          onSetup: selectionTargets.onSetupPasteableColumn(getColumns, 'onFirst')
3278
        }),
3279
        addMenuIfRegistered('tablepastecolumnafter', {
3280
          text: 'Paste column after',
3281
          icon: 'paste-column-after',
3282
          command: 'mceTablePasteColAfter',
3283
          onSetup: selectionTargets.onSetupPasteableColumn(getColumns, 'onLast')
3284
        })
3285
      ];
3286
      const hasCellMenuItems = [
3287
        addMenuIfRegistered('tablecellprops', {
3288
          text: 'Cell properties',
3289
          icon: 'table-cell-properties',
3290
          command: 'mceTableCellProps',
3291
          onSetup: selectionTargets.onSetupCellOrRow
3292
        }),
3293
        addMenuIfRegistered('tablemergecells', {
3294
          text: 'Merge cells',
3295
          icon: 'table-merge-cells',
3296
          command: 'mceTableMergeCells',
3297
          onSetup: selectionTargets.onSetupMergeable
3298
        }),
3299
        addMenuIfRegistered('tablesplitcells', {
3300
          text: 'Split cell',
3301
          icon: 'table-split-cells',
3302
          command: 'mceTableSplitCells',
3303
          onSetup: selectionTargets.onSetupUnmergeable
3304
        })
3305
      ];
3306
      if (!hasTableGrid(editor)) {
3307
        editor.ui.registry.addMenuItem('inserttable', {
3308
          text: 'Table',
3309
          icon: 'table',
3310
          onAction: cmd('mceInsertTableDialog'),
3311
          onSetup: onSetupEditable(editor)
3312
        });
3313
      } else {
3314
        editor.ui.registry.addNestedMenuItem('inserttable', {
3315
          text: 'Table',
3316
          icon: 'table',
3317
          getSubmenuItems: () => [{
3318
              type: 'fancymenuitem',
3319
              fancytype: 'inserttable',
3320
              onAction: insertTableAction
3321
            }],
3322
          onSetup: onSetupEditable(editor)
3323
        });
3324
      }
3325
      editor.ui.registry.addMenuItem('inserttabledialog', {
3326
        text: 'Insert table',
3327
        icon: 'table',
3328
        onAction: cmd('mceInsertTableDialog'),
3329
        onSetup: onSetupEditable(editor)
3330
      });
3331
      addMenuIfRegistered('tableprops', {
3332
        text: 'Table properties',
3333
        onSetup: selectionTargets.onSetupTable,
3334
        command: 'mceTableProps'
3335
      });
3336
      addMenuIfRegistered('deletetable', {
3337
        text: 'Delete table',
3338
        icon: 'table-delete-table',
3339
        onSetup: selectionTargets.onSetupTable,
3340
        command: 'mceTableDelete'
3341
      });
3342
      if (contains(hasRowMenuItems, true)) {
3343
        editor.ui.registry.addNestedMenuItem('row', {
3344
          type: 'nestedmenuitem',
3345
          text: 'Row',
3346
          getSubmenuItems: constant('tableinsertrowbefore tableinsertrowafter tabledeleterow tablerowprops | tablecutrow tablecopyrow tablepasterowbefore tablepasterowafter')
3347
        });
3348
      }
3349
      if (contains(hasColumnMenuItems, true)) {
3350
        editor.ui.registry.addNestedMenuItem('column', {
3351
          type: 'nestedmenuitem',
3352
          text: 'Column',
3353
          getSubmenuItems: constant('tableinsertcolumnbefore tableinsertcolumnafter tabledeletecolumn | tablecutcolumn tablecopycolumn tablepastecolumnbefore tablepastecolumnafter')
3354
        });
3355
      }
3356
      if (contains(hasCellMenuItems, true)) {
3357
        editor.ui.registry.addNestedMenuItem('cell', {
3358
          type: 'nestedmenuitem',
3359
          text: 'Cell',
3360
          getSubmenuItems: constant('tablecellprops tablemergecells tablesplitcells')
3361
        });
3362
      }
3363
      editor.ui.registry.addContextMenu('table', {
3364
        update: () => {
3365
          selectionTargets.resetTargets();
3366
          return selectionTargets.targets().fold(constant(''), targets => {
3367
            if (name(targets.element) === 'caption') {
3368
              return 'tableprops deletetable';
3369
            } else {
3370
              return 'cell row column | advtablesort | tableprops deletetable';
3371
            }
3372
          });
3373
        }
3374
      });
3375
      const tableClassList = filterNoneItem(getTableClassList(editor));
3376
      if (tableClassList.length !== 0 && editor.queryCommandSupported('mceTableToggleClass')) {
3377
        editor.ui.registry.addNestedMenuItem('tableclass', {
3378
          icon: 'table-classes',
3379
          text: 'Table styles',
3380
          getSubmenuItems: () => buildMenuItems(editor, tableClassList, 'tableclass', value => editor.execCommand('mceTableToggleClass', false, value)),
3381
          onSetup: selectionTargets.onSetupTable
3382
        });
3383
      }
3384
      const tableCellClassList = filterNoneItem(getCellClassList(editor));
3385
      if (tableCellClassList.length !== 0 && editor.queryCommandSupported('mceTableCellToggleClass')) {
3386
        editor.ui.registry.addNestedMenuItem('tablecellclass', {
3387
          icon: 'table-cell-classes',
3388
          text: 'Cell styles',
3389
          getSubmenuItems: () => buildMenuItems(editor, tableCellClassList, 'tablecellclass', value => editor.execCommand('mceTableCellToggleClass', false, value)),
3390
          onSetup: selectionTargets.onSetupCellOrRow
3391
        });
3392
      }
3393
      if (editor.queryCommandSupported('mceTableApplyCellStyle')) {
3394
        editor.ui.registry.addNestedMenuItem('tablecellvalign', {
3395
          icon: 'vertical-align',
3396
          text: 'Vertical align',
3397
          getSubmenuItems: () => buildMenuItems(editor, verticalAlignValues, 'tablecellverticalalign', applyTableCellStyle(editor, 'vertical-align')),
3398
          onSetup: selectionTargets.onSetupCellOrRow
3399
        });
3400
        editor.ui.registry.addNestedMenuItem('tablecellborderwidth', {
3401
          icon: 'border-width',
3402
          text: 'Border width',
3403
          getSubmenuItems: () => buildMenuItems(editor, getTableBorderWidths(editor), 'tablecellborderwidth', applyTableCellStyle(editor, 'border-width')),
3404
          onSetup: selectionTargets.onSetupCellOrRow
3405
        });
3406
        editor.ui.registry.addNestedMenuItem('tablecellborderstyle', {
3407
          icon: 'border-style',
3408
          text: 'Border style',
3409
          getSubmenuItems: () => buildMenuItems(editor, getTableBorderStyles(editor), 'tablecellborderstyle', applyTableCellStyle(editor, 'border-style')),
3410
          onSetup: selectionTargets.onSetupCellOrRow
3411
        });
3412
        editor.ui.registry.addNestedMenuItem('tablecellbackgroundcolor', {
3413
          icon: 'cell-background-color',
3414
          text: 'Background color',
3415
          getSubmenuItems: () => buildColorMenu(editor, getTableBackgroundColorMap(editor), 'background-color'),
3416
          onSetup: selectionTargets.onSetupCellOrRow
3417
        });
3418
        editor.ui.registry.addNestedMenuItem('tablecellbordercolor', {
3419
          icon: 'cell-border-color',
3420
          text: 'Border color',
3421
          getSubmenuItems: () => buildColorMenu(editor, getTableBorderColorMap(editor), 'border-color'),
3422
          onSetup: selectionTargets.onSetupCellOrRow
3423
        });
3424
      }
3425
      addToggleMenuIfRegistered('tablecaption', {
3426
        icon: 'table-caption',
3427
        text: 'Table caption',
3428
        command: 'mceTableToggleCaption',
3429
        onSetup: selectionTargets.onSetupTableWithCaption
3430
      });
3431
      addToggleMenuIfRegistered('tablerowheader', {
3432
        text: 'Row header',
3433
        icon: 'table-top-header',
3434
        command: 'mceTableRowType',
3435
        onAction: changeRowHeader(editor),
3436
        onSetup: selectionTargets.onSetupTableRowHeaders
3437
      });
3438
      addToggleMenuIfRegistered('tablecolheader', {
3439
        text: 'Column header',
3440
        icon: 'table-left-header',
3441
        command: 'mceTableColType',
3442
        onAction: changeColumnHeader(editor),
3443
        onSetup: selectionTargets.onSetupTableRowHeaders
3444
      });
3445
    };
3446
 
3447
    const Plugin = editor => {
3448
      const selectionTargets = getSelectionTargets(editor);
3449
      register(editor);
3450
      registerCommands(editor);
3451
      addMenuItems(editor, selectionTargets);
3452
      addButtons(editor, selectionTargets);
3453
      addToolbars(editor);
3454
    };
3455
    var Plugin$1 = () => {
3456
      global$3.add('table', Plugin);
3457
    };
3458
 
3459
    Plugin$1();
3460
 
3461
})();