Subversion Repositories oidplus

Rev

Rev 1422 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
597 daniel-mar 1
/**
2
 * Copyright (c) Tiny Technologies, Inc. All rights reserved.
3
 * Licensed under the LGPL or a commercial license.
4
 * For LGPL see License.txt in the project root for license information.
5
 * For commercial licenses see https://www.tiny.cloud/
6
 *
1434 daniel-mar 7
 * Version: 5.10.9 (2023-11-15)
597 daniel-mar 8
 */
9
(function () {
10
    'use strict';
11
 
12
    var Cell = function (initial) {
13
      var value = initial;
14
      var get = function () {
15
        return value;
16
      };
17
      var set = function (v) {
18
        value = v;
19
      };
20
      return {
21
        get: get,
22
        set: set
23
      };
24
    };
25
 
637 daniel-mar 26
    var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager');
597 daniel-mar 27
 
28
    var __assign = function () {
29
      __assign = Object.assign || function __assign(t) {
30
        for (var s, i = 1, n = arguments.length; i < n; i++) {
31
          s = arguments[i];
32
          for (var p in s)
33
            if (Object.prototype.hasOwnProperty.call(s, p))
34
              t[p] = s[p];
35
        }
36
        return t;
37
      };
38
      return __assign.apply(this, arguments);
39
    };
40
 
41
    var typeOf = function (x) {
42
      var t = typeof x;
43
      if (x === null) {
44
        return 'null';
45
      } else if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
46
        return 'array';
47
      } else if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
48
        return 'string';
49
      } else {
50
        return t;
51
      }
52
    };
637 daniel-mar 53
    var isType$1 = function (type) {
597 daniel-mar 54
      return function (value) {
55
        return typeOf(value) === type;
56
      };
57
    };
58
    var isSimpleType = function (type) {
59
      return function (value) {
60
        return typeof value === type;
61
      };
62
    };
637 daniel-mar 63
    var isString = isType$1('string');
64
    var isArray = isType$1('array');
597 daniel-mar 65
    var isBoolean = isSimpleType('boolean');
66
    var isNumber = isSimpleType('number');
67
 
68
    var noop = function () {
69
    };
70
    var constant = function (value) {
71
      return function () {
72
        return value;
73
      };
74
    };
637 daniel-mar 75
    var identity = function (x) {
76
      return x;
77
    };
597 daniel-mar 78
    var never = constant(false);
79
    var always = constant(true);
80
 
81
    var punctuationStr = '[!-#%-*,-\\/:;?@\\[-\\]_{}\xA1\xAB\xB7\xBB\xBF;\xB7\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1361-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u3008\u3009\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30\u2E31\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uff3f\uFF5B\uFF5D\uFF5F-\uFF65]';
82
 
637 daniel-mar 83
    var punctuation$1 = constant(punctuationStr);
597 daniel-mar 84
 
85
    var none = function () {
86
      return NONE;
87
    };
88
    var NONE = function () {
89
      var call = function (thunk) {
90
        return thunk();
91
      };
637 daniel-mar 92
      var id = identity;
597 daniel-mar 93
      var me = {
94
        fold: function (n, _s) {
95
          return n();
96
        },
97
        isSome: never,
98
        isNone: always,
99
        getOr: id,
100
        getOrThunk: call,
101
        getOrDie: function (msg) {
102
          throw new Error(msg || 'error: getOrDie called on none.');
103
        },
104
        getOrNull: constant(null),
105
        getOrUndefined: constant(undefined),
106
        or: id,
107
        orThunk: call,
108
        map: none,
109
        each: noop,
110
        bind: none,
111
        exists: never,
112
        forall: always,
637 daniel-mar 113
        filter: function () {
114
          return none();
115
        },
597 daniel-mar 116
        toArray: function () {
117
          return [];
118
        },
119
        toString: constant('none()')
120
      };
121
      return me;
122
    }();
123
    var some = function (a) {
124
      var constant_a = constant(a);
125
      var self = function () {
126
        return me;
127
      };
128
      var bind = function (f) {
129
        return f(a);
130
      };
131
      var me = {
132
        fold: function (n, s) {
133
          return s(a);
134
        },
135
        isSome: always,
136
        isNone: never,
137
        getOr: constant_a,
138
        getOrThunk: constant_a,
139
        getOrDie: constant_a,
140
        getOrNull: constant_a,
141
        getOrUndefined: constant_a,
142
        or: self,
143
        orThunk: self,
144
        map: function (f) {
145
          return some(f(a));
146
        },
147
        each: function (f) {
148
          f(a);
149
        },
150
        bind: bind,
151
        exists: bind,
152
        forall: bind,
153
        filter: function (f) {
154
          return f(a) ? me : NONE;
155
        },
156
        toArray: function () {
157
          return [a];
158
        },
159
        toString: function () {
160
          return 'some(' + a + ')';
161
        }
162
      };
163
      return me;
164
    };
165
    var from = function (value) {
166
      return value === null || value === undefined ? NONE : some(value);
167
    };
168
    var Optional = {
169
      some: some,
170
      none: none,
171
      from: from
172
    };
173
 
637 daniel-mar 174
    var punctuation = punctuation$1;
597 daniel-mar 175
 
679 daniel-mar 176
    var global$2 = tinymce.util.Tools.resolve('tinymce.Env');
597 daniel-mar 177
 
679 daniel-mar 178
    var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
179
 
597 daniel-mar 180
    var nativeSlice = Array.prototype.slice;
181
    var nativePush = Array.prototype.push;
182
    var map = function (xs, f) {
183
      var len = xs.length;
184
      var r = new Array(len);
185
      for (var i = 0; i < len; i++) {
186
        var x = xs[i];
187
        r[i] = f(x, i);
188
      }
189
      return r;
190
    };
191
    var each = function (xs, f) {
192
      for (var i = 0, len = xs.length; i < len; i++) {
193
        var x = xs[i];
194
        f(x, i);
195
      }
196
    };
197
    var eachr = function (xs, f) {
198
      for (var i = xs.length - 1; i >= 0; i--) {
199
        var x = xs[i];
200
        f(x, i);
201
      }
202
    };
203
    var groupBy = function (xs, f) {
204
      if (xs.length === 0) {
205
        return [];
206
      } else {
207
        var wasType = f(xs[0]);
208
        var r = [];
209
        var group = [];
210
        for (var i = 0, len = xs.length; i < len; i++) {
211
          var x = xs[i];
212
          var type = f(x);
213
          if (type !== wasType) {
214
            r.push(group);
215
            group = [];
216
          }
217
          wasType = type;
218
          group.push(x);
219
        }
220
        if (group.length !== 0) {
221
          r.push(group);
222
        }
223
        return r;
224
      }
225
    };
226
    var foldl = function (xs, f, acc) {
637 daniel-mar 227
      each(xs, function (x, i) {
228
        acc = f(acc, x, i);
597 daniel-mar 229
      });
230
      return acc;
231
    };
232
    var flatten = function (xs) {
233
      var r = [];
234
      for (var i = 0, len = xs.length; i < len; ++i) {
235
        if (!isArray(xs[i])) {
236
          throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
237
        }
238
        nativePush.apply(r, xs[i]);
239
      }
240
      return r;
241
    };
242
    var bind = function (xs, f) {
243
      return flatten(map(xs, f));
244
    };
245
    var sort = function (xs, comparator) {
246
      var copy = nativeSlice.call(xs, 0);
247
      copy.sort(comparator);
248
      return copy;
249
    };
250
 
251
    var hasOwnProperty = Object.hasOwnProperty;
252
    var has = function (obj, key) {
253
      return hasOwnProperty.call(obj, key);
254
    };
255
 
637 daniel-mar 256
    typeof window !== 'undefined' ? window : Function('return this;')();
597 daniel-mar 257
 
258
    var DOCUMENT = 9;
259
    var DOCUMENT_FRAGMENT = 11;
260
    var ELEMENT = 1;
261
    var TEXT = 3;
262
 
263
    var type = function (element) {
264
      return element.dom.nodeType;
265
    };
637 daniel-mar 266
    var isType = function (t) {
597 daniel-mar 267
      return function (element) {
268
        return type(element) === t;
269
      };
270
    };
637 daniel-mar 271
    var isText$1 = isType(TEXT);
597 daniel-mar 272
 
273
    var rawSet = function (dom, key, value) {
274
      if (isString(value) || isBoolean(value) || isNumber(value)) {
275
        dom.setAttribute(key, value + '');
276
      } else {
277
        console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
278
        throw new Error('Attribute value was not simple');
279
      }
280
    };
281
    var set = function (element, key, value) {
282
      rawSet(element.dom, key, value);
283
    };
284
 
285
    var compareDocumentPosition = function (a, b, match) {
286
      return (a.compareDocumentPosition(b) & match) !== 0;
287
    };
288
    var documentPositionPreceding = function (a, b) {
289
      return compareDocumentPosition(a, b, Node.DOCUMENT_POSITION_PRECEDING);
290
    };
291
 
292
    var fromHtml = function (html, scope) {
293
      var doc = scope || document;
294
      var div = doc.createElement('div');
295
      div.innerHTML = html;
296
      if (!div.hasChildNodes() || div.childNodes.length > 1) {
297
        console.error('HTML does not have a single root node', html);
298
        throw new Error('HTML must have a single root node');
299
      }
300
      return fromDom(div.childNodes[0]);
301
    };
302
    var fromTag = function (tag, scope) {
303
      var doc = scope || document;
304
      var node = doc.createElement(tag);
305
      return fromDom(node);
306
    };
307
    var fromText = function (text, scope) {
308
      var doc = scope || document;
309
      var node = doc.createTextNode(text);
310
      return fromDom(node);
311
    };
312
    var fromDom = function (node) {
313
      if (node === null || node === undefined) {
314
        throw new Error('Node cannot be null or undefined');
315
      }
316
      return { dom: node };
317
    };
318
    var fromPoint = function (docElm, x, y) {
319
      return Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
320
    };
321
    var SugarElement = {
322
      fromHtml: fromHtml,
323
      fromTag: fromTag,
324
      fromText: fromText,
325
      fromDom: fromDom,
326
      fromPoint: fromPoint
327
    };
328
 
329
    var bypassSelector = function (dom) {
330
      return dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
331
    };
332
    var all = function (selector, scope) {
333
      var base = scope === undefined ? document : scope.dom;
334
      return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom);
335
    };
336
 
337
    var parent = function (element) {
338
      return Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
339
    };
340
    var children = function (element) {
341
      return map(element.dom.childNodes, SugarElement.fromDom);
342
    };
343
    var spot = function (element, offset) {
344
      return {
345
        element: element,
346
        offset: offset
347
      };
348
    };
349
    var leaf = function (element, offset) {
350
      var cs = children(element);
351
      return cs.length > 0 && offset < cs.length ? spot(cs[offset], 0) : spot(element, offset);
352
    };
353
 
354
    var before = function (marker, element) {
355
      var parent$1 = parent(marker);
356
      parent$1.each(function (v) {
357
        v.dom.insertBefore(element.dom, marker.dom);
358
      });
359
    };
360
    var append = function (parent, element) {
361
      parent.dom.appendChild(element.dom);
362
    };
363
    var wrap = function (element, wrapper) {
364
      before(element, wrapper);
365
      append(wrapper, element);
366
    };
367
 
368
    var NodeValue = function (is, name) {
369
      var get = function (element) {
370
        if (!is(element)) {
371
          throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
372
        }
373
        return getOption(element).getOr('');
374
      };
375
      var getOption = function (element) {
376
        return is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
377
      };
378
      var set = function (element, value) {
379
        if (!is(element)) {
380
          throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
381
        }
382
        element.dom.nodeValue = value;
383
      };
384
      return {
385
        get: get,
386
        getOption: getOption,
387
        set: set
388
      };
389
    };
390
 
637 daniel-mar 391
    var api = NodeValue(isText$1, 'text');
392
    var get$1 = function (element) {
597 daniel-mar 393
      return api.get(element);
394
    };
395
 
396
    var descendants = function (scope, selector) {
397
      return all(selector, scope);
398
    };
399
 
679 daniel-mar 400
    var global = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
597 daniel-mar 401
 
402
    var isSimpleBoundary = function (dom, node) {
403
      return dom.isBlock(node) || has(dom.schema.getShortEndedElements(), node.nodeName);
404
    };
405
    var isContentEditableFalse = function (dom, node) {
406
      return dom.getContentEditable(node) === 'false';
407
    };
408
    var isContentEditableTrueInCef = function (dom, node) {
409
      return dom.getContentEditable(node) === 'true' && dom.getContentEditableParent(node.parentNode) === 'false';
410
    };
411
    var isHidden = function (dom, node) {
412
      return !dom.isBlock(node) && has(dom.schema.getWhiteSpaceElements(), node.nodeName);
413
    };
414
    var isBoundary = function (dom, node) {
415
      return isSimpleBoundary(dom, node) || isContentEditableFalse(dom, node) || isHidden(dom, node) || isContentEditableTrueInCef(dom, node);
416
    };
637 daniel-mar 417
    var isText = function (node) {
597 daniel-mar 418
      return node.nodeType === 3;
419
    };
420
    var nuSection = function () {
421
      return {
422
        sOffset: 0,
423
        fOffset: 0,
424
        elements: []
425
      };
426
    };
427
    var toLeaf = function (node, offset) {
428
      return leaf(SugarElement.fromDom(node), offset);
429
    };
430
    var walk = function (dom, walkerFn, startNode, callbacks, endNode, skipStart) {
431
      if (skipStart === void 0) {
432
        skipStart = true;
433
      }
434
      var next = skipStart ? walkerFn(false) : startNode;
435
      while (next) {
436
        var isCefNode = isContentEditableFalse(dom, next);
437
        if (isCefNode || isHidden(dom, next)) {
438
          var stopWalking = isCefNode ? callbacks.cef(next) : callbacks.boundary(next);
439
          if (stopWalking) {
440
            break;
441
          } else {
442
            next = walkerFn(true);
443
            continue;
444
          }
445
        } else if (isSimpleBoundary(dom, next)) {
446
          if (callbacks.boundary(next)) {
447
            break;
448
          }
637 daniel-mar 449
        } else if (isText(next)) {
597 daniel-mar 450
          callbacks.text(next);
451
        }
452
        if (next === endNode) {
453
          break;
454
        } else {
455
          next = walkerFn(false);
456
        }
457
      }
458
    };
459
    var collectTextToBoundary = function (dom, section, node, rootNode, forwards) {
460
      if (isBoundary(dom, node)) {
461
        return;
462
      }
463
      var rootBlock = dom.getParent(rootNode, dom.isBlock);
679 daniel-mar 464
      var walker = new global(node, rootBlock);
597 daniel-mar 465
      var walkerFn = forwards ? walker.next.bind(walker) : walker.prev.bind(walker);
466
      walk(dom, walkerFn, node, {
467
        boundary: always,
468
        cef: always,
469
        text: function (next) {
470
          if (forwards) {
471
            section.fOffset += next.length;
472
          } else {
473
            section.sOffset += next.length;
474
          }
475
          section.elements.push(SugarElement.fromDom(next));
476
        }
477
      });
478
    };
479
    var collect = function (dom, rootNode, startNode, endNode, callbacks, skipStart) {
480
      if (skipStart === void 0) {
481
        skipStart = true;
482
      }
679 daniel-mar 483
      var walker = new global(startNode, rootNode);
597 daniel-mar 484
      var sections = [];
485
      var current = nuSection();
486
      collectTextToBoundary(dom, current, startNode, rootNode, false);
487
      var finishSection = function () {
488
        if (current.elements.length > 0) {
489
          sections.push(current);
490
          current = nuSection();
491
        }
492
        return false;
493
      };
494
      walk(dom, walker.next.bind(walker), startNode, {
495
        boundary: finishSection,
496
        cef: function (node) {
497
          finishSection();
498
          if (callbacks) {
499
            sections.push.apply(sections, callbacks.cef(node));
500
          }
501
          return false;
502
        },
503
        text: function (next) {
504
          current.elements.push(SugarElement.fromDom(next));
505
          if (callbacks) {
506
            callbacks.text(next, current);
507
          }
508
        }
509
      }, endNode, skipStart);
510
      if (endNode) {
511
        collectTextToBoundary(dom, current, endNode, rootNode, true);
512
      }
513
      finishSection();
514
      return sections;
515
    };
516
    var collectRangeSections = function (dom, rng) {
517
      var start = toLeaf(rng.startContainer, rng.startOffset);
518
      var startNode = start.element.dom;
519
      var end = toLeaf(rng.endContainer, rng.endOffset);
520
      var endNode = end.element.dom;
521
      return collect(dom, rng.commonAncestorContainer, startNode, endNode, {
522
        text: function (node, section) {
523
          if (node === endNode) {
524
            section.fOffset += node.length - end.offset;
525
          } else if (node === startNode) {
526
            section.sOffset += start.offset;
527
          }
528
        },
529
        cef: function (node) {
530
          var sections = bind(descendants(SugarElement.fromDom(node), '*[contenteditable=true]'), function (e) {
531
            var ceTrueNode = e.dom;
532
            return collect(dom, ceTrueNode, ceTrueNode);
533
          });
534
          return sort(sections, function (a, b) {
535
            return documentPositionPreceding(a.elements[0].dom, b.elements[0].dom) ? 1 : -1;
536
          });
537
        }
538
      }, false);
539
    };
540
    var fromRng = function (dom, rng) {
541
      return rng.collapsed ? [] : collectRangeSections(dom, rng);
542
    };
543
    var fromNode = function (dom, node) {
544
      var rng = dom.createRng();
545
      rng.selectNode(node);
546
      return fromRng(dom, rng);
547
    };
548
    var fromNodes = function (dom, nodes) {
549
      return bind(nodes, function (node) {
550
        return fromNode(dom, node);
551
      });
552
    };
553
 
637 daniel-mar 554
    var find$2 = function (text, pattern, start, finish) {
597 daniel-mar 555
      if (start === void 0) {
556
        start = 0;
557
      }
558
      if (finish === void 0) {
559
        finish = text.length;
560
      }
561
      var regex = pattern.regex;
562
      regex.lastIndex = start;
563
      var results = [];
564
      var match;
565
      while (match = regex.exec(text)) {
566
        var matchedText = match[pattern.matchIndex];
567
        var matchStart = match.index + match[0].indexOf(matchedText);
568
        var matchFinish = matchStart + matchedText.length;
569
        if (matchFinish > finish) {
570
          break;
571
        }
572
        results.push({
573
          start: matchStart,
574
          finish: matchFinish
575
        });
576
        regex.lastIndex = matchFinish;
577
      }
578
      return results;
579
    };
580
    var extract = function (elements, matches) {
581
      var nodePositions = foldl(elements, function (acc, element) {
637 daniel-mar 582
        var content = get$1(element);
597 daniel-mar 583
        var start = acc.last;
584
        var finish = start + content.length;
585
        var positions = bind(matches, function (match, matchIdx) {
586
          if (match.start < finish && match.finish > start) {
587
            return [{
588
                element: element,
589
                start: Math.max(start, match.start) - start,
590
                finish: Math.min(finish, match.finish) - start,
591
                matchId: matchIdx
592
              }];
593
          } else {
594
            return [];
595
          }
596
        });
597
        return {
598
          results: acc.results.concat(positions),
599
          last: finish
600
        };
601
      }, {
602
        results: [],
603
        last: 0
604
      }).results;
605
      return groupBy(nodePositions, function (position) {
606
        return position.matchId;
607
      });
608
    };
609
 
610
    var find$1 = function (pattern, sections) {
611
      return bind(sections, function (section) {
612
        var elements = section.elements;
637 daniel-mar 613
        var content = map(elements, get$1).join('');
614
        var positions = find$2(content, pattern, section.sOffset, content.length - section.fOffset);
597 daniel-mar 615
        return extract(elements, positions);
616
      });
617
    };
618
    var mark = function (matches, replacementNode) {
619
      eachr(matches, function (match, idx) {
620
        eachr(match, function (pos) {
621
          var wrapper = SugarElement.fromDom(replacementNode.cloneNode(false));
622
          set(wrapper, 'data-mce-index', idx);
623
          var textNode = pos.element.dom;
624
          if (textNode.length === pos.finish && pos.start === 0) {
625
            wrap(pos.element, wrapper);
626
          } else {
627
            if (textNode.length !== pos.finish) {
628
              textNode.splitText(pos.finish);
629
            }
630
            var matchNode = textNode.splitText(pos.start);
631
            wrap(SugarElement.fromDom(matchNode), wrapper);
632
          }
633
        });
634
      });
635
    };
636
    var findAndMark = function (dom, pattern, node, replacementNode) {
637
      var textSections = fromNode(dom, node);
638
      var matches = find$1(pattern, textSections);
639
      mark(matches, replacementNode);
640
      return matches.length;
641
    };
642
    var findAndMarkInSelection = function (dom, pattern, selection, replacementNode) {
643
      var bookmark = selection.getBookmark();
644
      var nodes = dom.select('td[data-mce-selected],th[data-mce-selected]');
645
      var textSections = nodes.length > 0 ? fromNodes(dom, nodes) : fromRng(dom, selection.getRng());
646
      var matches = find$1(pattern, textSections);
647
      mark(matches, replacementNode);
648
      selection.moveToBookmark(bookmark);
649
      return matches.length;
650
    };
651
 
652
    var getElmIndex = function (elm) {
653
      var value = elm.getAttribute('data-mce-index');
654
      if (typeof value === 'number') {
655
        return '' + value;
656
      }
657
      return value;
658
    };
659
    var markAllMatches = function (editor, currentSearchState, pattern, inSelection) {
660
      var marker = editor.dom.create('span', { 'data-mce-bogus': 1 });
661
      marker.className = 'mce-match-marker';
662
      var node = editor.getBody();
663
      done(editor, currentSearchState, false);
664
      if (inSelection) {
665
        return findAndMarkInSelection(editor.dom, pattern, editor.selection, marker);
666
      } else {
667
        return findAndMark(editor.dom, pattern, node, marker);
668
      }
669
    };
670
    var unwrap = function (node) {
671
      var parentNode = node.parentNode;
672
      if (node.firstChild) {
673
        parentNode.insertBefore(node.firstChild, node);
674
      }
675
      node.parentNode.removeChild(node);
676
    };
677
    var findSpansByIndex = function (editor, index) {
678
      var spans = [];
679 daniel-mar 679
      var nodes = global$1.toArray(editor.getBody().getElementsByTagName('span'));
597 daniel-mar 680
      if (nodes.length) {
681
        for (var i = 0; i < nodes.length; i++) {
682
          var nodeIndex = getElmIndex(nodes[i]);
683
          if (nodeIndex === null || !nodeIndex.length) {
684
            continue;
685
          }
686
          if (nodeIndex === index.toString()) {
687
            spans.push(nodes[i]);
688
          }
689
        }
690
      }
691
      return spans;
692
    };
693
    var moveSelection = function (editor, currentSearchState, forward) {
694
      var searchState = currentSearchState.get();
695
      var testIndex = searchState.index;
696
      var dom = editor.dom;
697
      forward = forward !== false;
698
      if (forward) {
699
        if (testIndex + 1 === searchState.count) {
700
          testIndex = 0;
701
        } else {
702
          testIndex++;
703
        }
704
      } else {
705
        if (testIndex - 1 === -1) {
706
          testIndex = searchState.count - 1;
707
        } else {
708
          testIndex--;
709
        }
710
      }
711
      dom.removeClass(findSpansByIndex(editor, searchState.index), 'mce-match-marker-selected');
712
      var spans = findSpansByIndex(editor, testIndex);
713
      if (spans.length) {
714
        dom.addClass(findSpansByIndex(editor, testIndex), 'mce-match-marker-selected');
715
        editor.selection.scrollIntoView(spans[0]);
716
        return testIndex;
717
      }
718
      return -1;
719
    };
720
    var removeNode = function (dom, node) {
721
      var parent = node.parentNode;
722
      dom.remove(node);
723
      if (dom.isEmpty(parent)) {
724
        dom.remove(parent);
725
      }
726
    };
727
    var escapeSearchText = function (text, wholeWord) {
728
      var escapedText = text.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&').replace(/\s/g, '[^\\S\\r\\n\\uFEFF]');
729
      var wordRegex = '(' + escapedText + ')';
637 daniel-mar 730
      return wholeWord ? '(?:^|\\s|' + punctuation() + ')' + wordRegex + ('(?=$|\\s|' + punctuation() + ')') : wordRegex;
597 daniel-mar 731
    };
637 daniel-mar 732
    var find = function (editor, currentSearchState, text, matchCase, wholeWord, inSelection) {
679 daniel-mar 733
      var selection = editor.selection;
597 daniel-mar 734
      var escapedText = escapeSearchText(text, wholeWord);
679 daniel-mar 735
      var isForwardSelection = selection.isForward();
597 daniel-mar 736
      var pattern = {
737
        regex: new RegExp(escapedText, matchCase ? 'g' : 'gi'),
738
        matchIndex: 1
739
      };
740
      var count = markAllMatches(editor, currentSearchState, pattern, inSelection);
679 daniel-mar 741
      if (global$2.browser.isSafari()) {
742
        selection.setRng(selection.getRng(), isForwardSelection);
743
      }
597 daniel-mar 744
      if (count) {
745
        var newIndex = moveSelection(editor, currentSearchState, true);
746
        currentSearchState.set({
747
          index: newIndex,
748
          count: count,
749
          text: text,
750
          matchCase: matchCase,
751
          wholeWord: wholeWord,
752
          inSelection: inSelection
753
        });
754
      }
755
      return count;
756
    };
757
    var next = function (editor, currentSearchState) {
758
      var index = moveSelection(editor, currentSearchState, true);
759
      currentSearchState.set(__assign(__assign({}, currentSearchState.get()), { index: index }));
760
    };
761
    var prev = function (editor, currentSearchState) {
762
      var index = moveSelection(editor, currentSearchState, false);
763
      currentSearchState.set(__assign(__assign({}, currentSearchState.get()), { index: index }));
764
    };
765
    var isMatchSpan = function (node) {
766
      var matchIndex = getElmIndex(node);
767
      return matchIndex !== null && matchIndex.length > 0;
768
    };
769
    var replace = function (editor, currentSearchState, text, forward, all) {
770
      var searchState = currentSearchState.get();
771
      var currentIndex = searchState.index;
772
      var currentMatchIndex, nextIndex = currentIndex;
773
      forward = forward !== false;
774
      var node = editor.getBody();
679 daniel-mar 775
      var nodes = global$1.grep(global$1.toArray(node.getElementsByTagName('span')), isMatchSpan);
597 daniel-mar 776
      for (var i = 0; i < nodes.length; i++) {
777
        var nodeIndex = getElmIndex(nodes[i]);
778
        var matchIndex = currentMatchIndex = parseInt(nodeIndex, 10);
779
        if (all || matchIndex === searchState.index) {
780
          if (text.length) {
781
            nodes[i].firstChild.nodeValue = text;
782
            unwrap(nodes[i]);
783
          } else {
784
            removeNode(editor.dom, nodes[i]);
785
          }
786
          while (nodes[++i]) {
787
            matchIndex = parseInt(getElmIndex(nodes[i]), 10);
788
            if (matchIndex === currentMatchIndex) {
789
              removeNode(editor.dom, nodes[i]);
790
            } else {
791
              i--;
792
              break;
793
            }
794
          }
795
          if (forward) {
796
            nextIndex--;
797
          }
798
        } else if (currentMatchIndex > currentIndex) {
799
          nodes[i].setAttribute('data-mce-index', String(currentMatchIndex - 1));
800
        }
801
      }
802
      currentSearchState.set(__assign(__assign({}, searchState), {
803
        count: all ? 0 : searchState.count - 1,
804
        index: nextIndex
805
      }));
806
      if (forward) {
807
        next(editor, currentSearchState);
808
      } else {
809
        prev(editor, currentSearchState);
810
      }
811
      return !all && currentSearchState.get().count > 0;
812
    };
813
    var done = function (editor, currentSearchState, keepEditorSelection) {
637 daniel-mar 814
      var startContainer, endContainer;
597 daniel-mar 815
      var searchState = currentSearchState.get();
679 daniel-mar 816
      var nodes = global$1.toArray(editor.getBody().getElementsByTagName('span'));
637 daniel-mar 817
      for (var i = 0; i < nodes.length; i++) {
597 daniel-mar 818
        var nodeIndex = getElmIndex(nodes[i]);
819
        if (nodeIndex !== null && nodeIndex.length) {
820
          if (nodeIndex === searchState.index.toString()) {
821
            if (!startContainer) {
822
              startContainer = nodes[i].firstChild;
823
            }
824
            endContainer = nodes[i].firstChild;
825
          }
826
          unwrap(nodes[i]);
827
        }
828
      }
829
      currentSearchState.set(__assign(__assign({}, searchState), {
830
        index: -1,
831
        count: 0,
832
        text: ''
833
      }));
834
      if (startContainer && endContainer) {
835
        var rng = editor.dom.createRng();
836
        rng.setStart(startContainer, 0);
837
        rng.setEnd(endContainer, endContainer.data.length);
838
        if (keepEditorSelection !== false) {
839
          editor.selection.setRng(rng);
840
        }
841
        return rng;
842
      }
843
    };
844
    var hasNext = function (editor, currentSearchState) {
845
      return currentSearchState.get().count > 1;
846
    };
847
    var hasPrev = function (editor, currentSearchState) {
848
      return currentSearchState.get().count > 1;
849
    };
850
 
637 daniel-mar 851
    var get = function (editor, currentState) {
597 daniel-mar 852
      var done$1 = function (keepEditorSelection) {
853
        return done(editor, currentState, keepEditorSelection);
854
      };
637 daniel-mar 855
      var find$1 = function (text, matchCase, wholeWord, inSelection) {
597 daniel-mar 856
        if (inSelection === void 0) {
857
          inSelection = false;
858
        }
637 daniel-mar 859
        return find(editor, currentState, text, matchCase, wholeWord, inSelection);
597 daniel-mar 860
      };
861
      var next$1 = function () {
862
        return next(editor, currentState);
863
      };
864
      var prev$1 = function () {
865
        return prev(editor, currentState);
866
      };
867
      var replace$1 = function (text, forward, all) {
868
        return replace(editor, currentState, text, forward, all);
869
      };
870
      return {
871
        done: done$1,
637 daniel-mar 872
        find: find$1,
597 daniel-mar 873
        next: next$1,
874
        prev: prev$1,
875
        replace: replace$1
876
      };
877
    };
878
 
637 daniel-mar 879
    var singleton = function (doRevoke) {
597 daniel-mar 880
      var subject = Cell(Optional.none());
637 daniel-mar 881
      var revoke = function () {
882
        return subject.get().each(doRevoke);
883
      };
597 daniel-mar 884
      var clear = function () {
637 daniel-mar 885
        revoke();
886
        subject.set(Optional.none());
597 daniel-mar 887
      };
888
      var isSet = function () {
889
        return subject.get().isSome();
890
      };
637 daniel-mar 891
      var get = function () {
892
        return subject.get();
597 daniel-mar 893
      };
637 daniel-mar 894
      var set = function (s) {
895
        revoke();
896
        subject.set(Optional.some(s));
897
      };
597 daniel-mar 898
      return {
899
        clear: clear,
900
        isSet: isSet,
637 daniel-mar 901
        get: get,
902
        set: set
597 daniel-mar 903
      };
904
    };
637 daniel-mar 905
    var value = function () {
906
      var subject = singleton(noop);
907
      var on = function (f) {
908
        return subject.get().each(f);
909
      };
910
      return __assign(__assign({}, subject), { on: on });
911
    };
597 daniel-mar 912
 
913
    var open = function (editor, currentSearchState) {
914
      var dialogApi = value();
915
      editor.undoManager.add();
679 daniel-mar 916
      var selectedText = global$1.trim(editor.selection.getContent({ format: 'text' }));
597 daniel-mar 917
      var updateButtonStates = function (api) {
918
        var updateNext = hasNext(editor, currentSearchState) ? api.enable : api.disable;
919
        updateNext('next');
920
        var updatePrev = hasPrev(editor, currentSearchState) ? api.enable : api.disable;
921
        updatePrev('prev');
922
      };
923
      var updateSearchState = function (api) {
924
        var data = api.getData();
925
        var current = currentSearchState.get();
926
        currentSearchState.set(__assign(__assign({}, current), {
927
          matchCase: data.matchcase,
928
          wholeWord: data.wholewords,
929
          inSelection: data.inselection
930
        }));
931
      };
932
      var disableAll = function (api, disable) {
933
        var buttons = [
934
          'replace',
935
          'replaceall',
936
          'prev',
937
          'next'
938
        ];
939
        var toggle = disable ? api.disable : api.enable;
940
        each(buttons, toggle);
941
      };
942
      var notFoundAlert = function (api) {
943
        editor.windowManager.alert('Could not find the specified string.', function () {
944
          api.focus('findtext');
945
        });
946
      };
947
      var focusButtonIfRequired = function (api, name) {
679 daniel-mar 948
        if (global$2.browser.isSafari() && global$2.deviceType.isTouch() && (name === 'find' || name === 'replace' || name === 'replaceall')) {
597 daniel-mar 949
          api.focus(name);
950
        }
951
      };
952
      var reset = function (api) {
953
        done(editor, currentSearchState, false);
954
        disableAll(api, true);
955
        updateButtonStates(api);
956
      };
957
      var doFind = function (api) {
958
        var data = api.getData();
959
        var last = currentSearchState.get();
960
        if (!data.findtext.length) {
961
          reset(api);
962
          return;
963
        }
964
        if (last.text === data.findtext && last.matchCase === data.matchcase && last.wholeWord === data.wholewords) {
965
          next(editor, currentSearchState);
966
        } else {
637 daniel-mar 967
          var count = find(editor, currentSearchState, data.findtext, data.matchcase, data.wholewords, data.inselection);
597 daniel-mar 968
          if (count <= 0) {
969
            notFoundAlert(api);
970
          }
971
          disableAll(api, count === 0);
972
        }
973
        updateButtonStates(api);
974
      };
975
      var initialState = currentSearchState.get();
976
      var initialData = {
977
        findtext: selectedText,
978
        replacetext: '',
979
        wholewords: initialState.wholeWord,
980
        matchcase: initialState.matchCase,
981
        inselection: initialState.inSelection
982
      };
983
      var spec = {
984
        title: 'Find and Replace',
985
        size: 'normal',
986
        body: {
987
          type: 'panel',
988
          items: [
989
            {
990
              type: 'bar',
991
              items: [
992
                {
993
                  type: 'input',
994
                  name: 'findtext',
995
                  placeholder: 'Find',
996
                  maximized: true,
997
                  inputMode: 'search'
998
                },
999
                {
1000
                  type: 'button',
1001
                  name: 'prev',
1002
                  text: 'Previous',
1003
                  icon: 'action-prev',
1004
                  disabled: true,
1005
                  borderless: true
1006
                },
1007
                {
1008
                  type: 'button',
1009
                  name: 'next',
1010
                  text: 'Next',
1011
                  icon: 'action-next',
1012
                  disabled: true,
1013
                  borderless: true
1014
                }
1015
              ]
1016
            },
1017
            {
1018
              type: 'input',
1019
              name: 'replacetext',
1020
              placeholder: 'Replace with',
1021
              inputMode: 'search'
1022
            }
1023
          ]
1024
        },
1025
        buttons: [
1026
          {
1027
            type: 'menu',
1028
            name: 'options',
1029
            icon: 'preferences',
1030
            tooltip: 'Preferences',
1031
            align: 'start',
1032
            items: [
1033
              {
1034
                type: 'togglemenuitem',
1035
                name: 'matchcase',
1036
                text: 'Match case'
1037
              },
1038
              {
1039
                type: 'togglemenuitem',
1040
                name: 'wholewords',
1041
                text: 'Find whole words only'
1042
              },
1043
              {
1044
                type: 'togglemenuitem',
1045
                name: 'inselection',
1046
                text: 'Find in selection'
1047
              }
1048
            ]
1049
          },
1050
          {
1051
            type: 'custom',
1052
            name: 'find',
1053
            text: 'Find',
1054
            primary: true
1055
          },
1056
          {
1057
            type: 'custom',
1058
            name: 'replace',
1059
            text: 'Replace',
1060
            disabled: true
1061
          },
1062
          {
1063
            type: 'custom',
1064
            name: 'replaceall',
1065
            text: 'Replace all',
1066
            disabled: true
1067
          }
1068
        ],
1069
        initialData: initialData,
1070
        onChange: function (api, details) {
1071
          if (details.name === 'findtext' && currentSearchState.get().count > 0) {
1072
            reset(api);
1073
          }
1074
        },
1075
        onAction: function (api, details) {
1076
          var data = api.getData();
1077
          switch (details.name) {
1078
          case 'find':
1079
            doFind(api);
1080
            break;
1081
          case 'replace':
1082
            if (!replace(editor, currentSearchState, data.replacetext)) {
1083
              reset(api);
1084
            } else {
1085
              updateButtonStates(api);
1086
            }
1087
            break;
1088
          case 'replaceall':
1089
            replace(editor, currentSearchState, data.replacetext, true, true);
1090
            reset(api);
1091
            break;
1092
          case 'prev':
1093
            prev(editor, currentSearchState);
1094
            updateButtonStates(api);
1095
            break;
1096
          case 'next':
1097
            next(editor, currentSearchState);
1098
            updateButtonStates(api);
1099
            break;
1100
          case 'matchcase':
1101
          case 'wholewords':
1102
          case 'inselection':
1103
            updateSearchState(api);
1104
            reset(api);
1105
            break;
1106
          }
1107
          focusButtonIfRequired(api, details.name);
1108
        },
1109
        onSubmit: function (api) {
1110
          doFind(api);
1111
          focusButtonIfRequired(api, 'find');
1112
        },
1113
        onClose: function () {
1114
          editor.focus();
1115
          done(editor, currentSearchState);
1116
          editor.undoManager.add();
1117
        }
1118
      };
1119
      dialogApi.set(editor.windowManager.open(spec, { inline: 'toolbar' }));
1120
    };
1121
 
637 daniel-mar 1122
    var register$1 = function (editor, currentSearchState) {
597 daniel-mar 1123
      editor.addCommand('SearchReplace', function () {
1124
        open(editor, currentSearchState);
1125
      });
1126
    };
1127
 
1128
    var showDialog = function (editor, currentSearchState) {
1129
      return function () {
1130
        open(editor, currentSearchState);
1131
      };
1132
    };
637 daniel-mar 1133
    var register = function (editor, currentSearchState) {
597 daniel-mar 1134
      editor.ui.registry.addMenuItem('searchreplace', {
1135
        text: 'Find and replace...',
1136
        shortcut: 'Meta+F',
1137
        onAction: showDialog(editor, currentSearchState),
1138
        icon: 'search'
1139
      });
1140
      editor.ui.registry.addButton('searchreplace', {
1141
        tooltip: 'Find and replace',
1142
        onAction: showDialog(editor, currentSearchState),
1143
        icon: 'search'
1144
      });
1145
      editor.shortcuts.add('Meta+F', '', showDialog(editor, currentSearchState));
1146
    };
1147
 
1148
    function Plugin () {
637 daniel-mar 1149
      global$3.add('searchreplace', function (editor) {
597 daniel-mar 1150
        var currentSearchState = Cell({
1151
          index: -1,
1152
          count: 0,
1153
          text: '',
1154
          matchCase: false,
1155
          wholeWord: false,
1156
          inSelection: false
1157
        });
637 daniel-mar 1158
        register$1(editor, currentSearchState);
597 daniel-mar 1159
        register(editor, currentSearchState);
637 daniel-mar 1160
        return get(editor, currentSearchState);
597 daniel-mar 1161
      });
1162
    }
1163
 
1164
    Plugin();
1165
 
1166
}());