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
 
679 daniel-mar 12
    var global$7 = tinymce.util.Tools.resolve('tinymce.PluginManager');
597 daniel-mar 13
 
679 daniel-mar 14
    var global$6 = tinymce.util.Tools.resolve('tinymce.util.VK');
597 daniel-mar 15
 
16
    var typeOf = function (x) {
17
      var t = typeof x;
18
      if (x === null) {
19
        return 'null';
20
      } else if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
21
        return 'array';
22
      } else if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
23
        return 'string';
24
      } else {
25
        return t;
26
      }
27
    };
28
    var isType = function (type) {
29
      return function (value) {
30
        return typeOf(value) === type;
31
      };
32
    };
33
    var isSimpleType = function (type) {
34
      return function (value) {
35
        return typeof value === type;
36
      };
37
    };
38
    var eq = function (t) {
39
      return function (a) {
40
        return t === a;
41
      };
42
    };
43
    var isString = isType('string');
44
    var isArray = isType('array');
45
    var isNull = eq(null);
46
    var isBoolean = isSimpleType('boolean');
47
    var isFunction = isSimpleType('function');
48
 
49
    var noop = function () {
50
    };
51
    var constant = function (value) {
52
      return function () {
53
        return value;
54
      };
55
    };
637 daniel-mar 56
    var identity = function (x) {
57
      return x;
58
    };
59
    var tripleEquals = function (a, b) {
60
      return a === b;
61
    };
597 daniel-mar 62
    var never = constant(false);
63
    var always = constant(true);
64
 
65
    var none = function () {
66
      return NONE;
67
    };
68
    var NONE = function () {
69
      var call = function (thunk) {
70
        return thunk();
71
      };
637 daniel-mar 72
      var id = identity;
597 daniel-mar 73
      var me = {
74
        fold: function (n, _s) {
75
          return n();
76
        },
77
        isSome: never,
78
        isNone: always,
79
        getOr: id,
80
        getOrThunk: call,
81
        getOrDie: function (msg) {
82
          throw new Error(msg || 'error: getOrDie called on none.');
83
        },
84
        getOrNull: constant(null),
85
        getOrUndefined: constant(undefined),
86
        or: id,
87
        orThunk: call,
88
        map: none,
89
        each: noop,
90
        bind: none,
91
        exists: never,
92
        forall: always,
637 daniel-mar 93
        filter: function () {
94
          return none();
95
        },
597 daniel-mar 96
        toArray: function () {
97
          return [];
98
        },
99
        toString: constant('none()')
100
      };
101
      return me;
102
    }();
103
    var some = function (a) {
104
      var constant_a = constant(a);
105
      var self = function () {
106
        return me;
107
      };
108
      var bind = function (f) {
109
        return f(a);
110
      };
111
      var me = {
112
        fold: function (n, s) {
113
          return s(a);
114
        },
115
        isSome: always,
116
        isNone: never,
117
        getOr: constant_a,
118
        getOrThunk: constant_a,
119
        getOrDie: constant_a,
120
        getOrNull: constant_a,
121
        getOrUndefined: constant_a,
122
        or: self,
123
        orThunk: self,
124
        map: function (f) {
125
          return some(f(a));
126
        },
127
        each: function (f) {
128
          f(a);
129
        },
130
        bind: bind,
131
        exists: bind,
132
        forall: bind,
133
        filter: function (f) {
134
          return f(a) ? me : NONE;
135
        },
136
        toArray: function () {
137
          return [a];
138
        },
139
        toString: function () {
140
          return 'some(' + a + ')';
141
        }
142
      };
143
      return me;
144
    };
145
    var from = function (value) {
146
      return value === null || value === undefined ? NONE : some(value);
147
    };
148
    var Optional = {
149
      some: some,
150
      none: none,
151
      from: from
152
    };
153
 
154
    var nativeIndexOf = Array.prototype.indexOf;
155
    var nativePush = Array.prototype.push;
156
    var rawIndexOf = function (ts, t) {
157
      return nativeIndexOf.call(ts, t);
158
    };
159
    var contains = function (xs, x) {
160
      return rawIndexOf(xs, x) > -1;
161
    };
162
    var map = function (xs, f) {
163
      var len = xs.length;
164
      var r = new Array(len);
165
      for (var i = 0; i < len; i++) {
166
        var x = xs[i];
167
        r[i] = f(x, i);
168
      }
169
      return r;
170
    };
637 daniel-mar 171
    var each$1 = function (xs, f) {
597 daniel-mar 172
      for (var i = 0, len = xs.length; i < len; i++) {
173
        var x = xs[i];
174
        f(x, i);
175
      }
176
    };
177
    var foldl = function (xs, f, acc) {
637 daniel-mar 178
      each$1(xs, function (x, i) {
179
        acc = f(acc, x, i);
597 daniel-mar 180
      });
181
      return acc;
182
    };
183
    var flatten = function (xs) {
184
      var r = [];
185
      for (var i = 0, len = xs.length; i < len; ++i) {
186
        if (!isArray(xs[i])) {
187
          throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
188
        }
189
        nativePush.apply(r, xs[i]);
190
      }
191
      return r;
192
    };
193
    var bind = function (xs, f) {
194
      return flatten(map(xs, f));
195
    };
196
    var findMap = function (arr, f) {
197
      for (var i = 0; i < arr.length; i++) {
198
        var r = f(arr[i], i);
199
        if (r.isSome()) {
200
          return r;
201
        }
202
      }
203
      return Optional.none();
204
    };
205
 
637 daniel-mar 206
    var is = function (lhs, rhs, comparator) {
207
      if (comparator === void 0) {
208
        comparator = tripleEquals;
209
      }
210
      return lhs.exists(function (left) {
211
        return comparator(left, rhs);
212
      });
213
    };
597 daniel-mar 214
    var cat = function (arr) {
215
      var r = [];
216
      var push = function (x) {
217
        r.push(x);
218
      };
219
      for (var i = 0; i < arr.length; i++) {
220
        arr[i].each(push);
221
      }
222
      return r;
223
    };
224
    var someIf = function (b, a) {
225
      return b ? Optional.some(a) : Optional.none();
226
    };
227
 
637 daniel-mar 228
    var assumeExternalTargets = function (editor) {
229
      var externalTargets = editor.getParam('link_assume_external_targets', false);
230
      if (isBoolean(externalTargets) && externalTargets) {
231
        return 1;
232
      } else if (isString(externalTargets) && (externalTargets === 'http' || externalTargets === 'https')) {
233
        return externalTargets;
234
      }
235
      return 0;
236
    };
237
    var hasContextToolbar = function (editor) {
238
      return editor.getParam('link_context_toolbar', false, 'boolean');
239
    };
240
    var getLinkList = function (editor) {
241
      return editor.getParam('link_list');
242
    };
243
    var getDefaultLinkTarget = function (editor) {
244
      return editor.getParam('default_link_target');
245
    };
246
    var getTargetList = function (editor) {
247
      return editor.getParam('target_list', true);
248
    };
249
    var getRelList = function (editor) {
250
      return editor.getParam('rel_list', [], 'array');
251
    };
252
    var getLinkClassList = function (editor) {
253
      return editor.getParam('link_class_list', [], 'array');
254
    };
255
    var shouldShowLinkTitle = function (editor) {
256
      return editor.getParam('link_title', true, 'boolean');
257
    };
258
    var allowUnsafeLinkTarget = function (editor) {
259
      return editor.getParam('allow_unsafe_link_target', false, 'boolean');
260
    };
261
    var useQuickLink = function (editor) {
262
      return editor.getParam('link_quicklink', false, 'boolean');
263
    };
264
    var getDefaultLinkProtocol = function (editor) {
265
      return editor.getParam('link_default_protocol', 'http', 'string');
266
    };
597 daniel-mar 267
 
679 daniel-mar 268
    var global$5 = tinymce.util.Tools.resolve('tinymce.util.Tools');
637 daniel-mar 269
 
597 daniel-mar 270
    var getValue = function (item) {
271
      return isString(item.value) ? item.value : '';
272
    };
273
    var getText = function (item) {
274
      if (isString(item.text)) {
275
        return item.text;
276
      } else if (isString(item.title)) {
277
        return item.title;
278
      } else {
279
        return '';
280
      }
281
    };
282
    var sanitizeList = function (list, extractValue) {
283
      var out = [];
679 daniel-mar 284
      global$5.each(list, function (item) {
597 daniel-mar 285
        var text = getText(item);
286
        if (item.menu !== undefined) {
287
          var items = sanitizeList(item.menu, extractValue);
288
          out.push({
289
            text: text,
290
            items: items
291
          });
292
        } else {
293
          var value = extractValue(item);
294
          out.push({
295
            text: text,
296
            value: value
297
          });
298
        }
299
      });
300
      return out;
301
    };
302
    var sanitizeWith = function (extracter) {
303
      if (extracter === void 0) {
304
        extracter = getValue;
305
      }
306
      return function (list) {
307
        return Optional.from(list).map(function (list) {
308
          return sanitizeList(list, extracter);
309
        });
310
      };
311
    };
312
    var sanitize = function (list) {
313
      return sanitizeWith(getValue)(list);
314
    };
315
    var createUi = function (name, label) {
316
      return function (items) {
317
        return {
318
          name: name,
319
          type: 'listbox',
320
          label: label,
321
          items: items
322
        };
323
      };
324
    };
325
    var ListOptions = {
326
      sanitize: sanitize,
327
      sanitizeWith: sanitizeWith,
328
      createUi: createUi,
329
      getValue: getValue
330
    };
331
 
332
    var __assign = function () {
333
      __assign = Object.assign || function __assign(t) {
334
        for (var s, i = 1, n = arguments.length; i < n; i++) {
335
          s = arguments[i];
336
          for (var p in s)
337
            if (Object.prototype.hasOwnProperty.call(s, p))
338
              t[p] = s[p];
339
        }
340
        return t;
341
      };
342
      return __assign.apply(this, arguments);
343
    };
344
 
345
    var keys = Object.keys;
346
    var hasOwnProperty = Object.hasOwnProperty;
637 daniel-mar 347
    var each = function (obj, f) {
597 daniel-mar 348
      var props = keys(obj);
349
      for (var k = 0, len = props.length; k < len; k++) {
350
        var i = props[k];
351
        var x = obj[i];
352
        f(x, i);
353
      }
354
    };
355
    var objAcc = function (r) {
356
      return function (x, i) {
357
        r[i] = x;
358
      };
359
    };
360
    var internalFilter = function (obj, pred, onTrue, onFalse) {
361
      var r = {};
637 daniel-mar 362
      each(obj, function (x, i) {
597 daniel-mar 363
        (pred(x, i) ? onTrue : onFalse)(x, i);
364
      });
365
      return r;
366
    };
367
    var filter = function (obj, pred) {
368
      var t = {};
369
      internalFilter(obj, pred, objAcc(t), noop);
370
      return t;
371
    };
372
    var has = function (obj, key) {
373
      return hasOwnProperty.call(obj, key);
374
    };
375
    var hasNonNullableKey = function (obj, key) {
376
      return has(obj, key) && obj[key] !== undefined && obj[key] !== null;
377
    };
378
 
679 daniel-mar 379
    var global$4 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
597 daniel-mar 380
 
679 daniel-mar 381
    var global$3 = tinymce.util.Tools.resolve('tinymce.util.URI');
382
 
597 daniel-mar 383
    var isAnchor = function (elm) {
384
      return elm && elm.nodeName.toLowerCase() === 'a';
385
    };
386
    var isLink = function (elm) {
387
      return isAnchor(elm) && !!getHref(elm);
388
    };
389
    var collectNodesInRange = function (rng, predicate) {
390
      if (rng.collapsed) {
391
        return [];
392
      } else {
393
        var contents = rng.cloneContents();
679 daniel-mar 394
        var walker = new global$4(contents.firstChild, contents);
597 daniel-mar 395
        var elements = [];
396
        var current = contents.firstChild;
397
        do {
398
          if (predicate(current)) {
399
            elements.push(current);
400
          }
401
        } while (current = walker.next());
402
        return elements;
403
      }
404
    };
405
    var hasProtocol = function (url) {
406
      return /^\w+:/i.test(url);
407
    };
408
    var getHref = function (elm) {
409
      var href = elm.getAttribute('data-mce-href');
410
      return href ? href : elm.getAttribute('href');
411
    };
412
    var applyRelTargetRules = function (rel, isUnsafe) {
413
      var rules = ['noopener'];
414
      var rels = rel ? rel.split(/\s+/) : [];
415
      var toString = function (rels) {
679 daniel-mar 416
        return global$5.trim(rels.sort().join(' '));
597 daniel-mar 417
      };
418
      var addTargetRules = function (rels) {
419
        rels = removeTargetRules(rels);
420
        return rels.length > 0 ? rels.concat(rules) : rules;
421
      };
422
      var removeTargetRules = function (rels) {
423
        return rels.filter(function (val) {
679 daniel-mar 424
          return global$5.inArray(rules, val) === -1;
597 daniel-mar 425
        });
426
      };
427
      var newRels = isUnsafe ? addTargetRules(rels) : removeTargetRules(rels);
428
      return newRels.length > 0 ? toString(newRels) : '';
429
    };
430
    var trimCaretContainers = function (text) {
431
      return text.replace(/\uFEFF/g, '');
432
    };
433
    var getAnchorElement = function (editor, selectedElm) {
434
      selectedElm = selectedElm || editor.selection.getNode();
435
      if (isImageFigure(selectedElm)) {
436
        return editor.dom.select('a[href]', selectedElm)[0];
437
      } else {
438
        return editor.dom.getParent(selectedElm, 'a[href]');
439
      }
440
    };
441
    var getAnchorText = function (selection, anchorElm) {
442
      var text = anchorElm ? anchorElm.innerText || anchorElm.textContent : selection.getContent({ format: 'text' });
443
      return trimCaretContainers(text);
444
    };
445
    var hasLinks = function (elements) {
679 daniel-mar 446
      return global$5.grep(elements, isLink).length > 0;
597 daniel-mar 447
    };
448
    var hasLinksInSelection = function (rng) {
449
      return collectNodesInRange(rng, isLink).length > 0;
450
    };
451
    var isOnlyTextSelected = function (editor) {
452
      var inlineTextElements = editor.schema.getTextInlineElements();
453
      var isElement = function (elm) {
454
        return elm.nodeType === 1 && !isAnchor(elm) && !has(inlineTextElements, elm.nodeName.toLowerCase());
455
      };
456
      var elements = collectNodesInRange(editor.selection.getRng(), isElement);
457
      return elements.length === 0;
458
    };
459
    var isImageFigure = function (elm) {
460
      return elm && elm.nodeName === 'FIGURE' && /\bimage\b/i.test(elm.className);
461
    };
462
    var getLinkAttrs = function (data) {
637 daniel-mar 463
      var attrs = [
597 daniel-mar 464
        'title',
465
        'rel',
466
        'class',
467
        'target'
637 daniel-mar 468
      ];
469
      return foldl(attrs, function (acc, key) {
597 daniel-mar 470
        data[key].each(function (value) {
471
          acc[key] = value.length > 0 ? value : null;
472
        });
473
        return acc;
474
      }, { href: data.href });
475
    };
476
    var handleExternalTargets = function (href, assumeExternalTargets) {
477
      if ((assumeExternalTargets === 'http' || assumeExternalTargets === 'https') && !hasProtocol(href)) {
478
        return assumeExternalTargets + '://' + href;
479
      }
480
      return href;
481
    };
482
    var applyLinkOverrides = function (editor, linkAttrs) {
483
      var newLinkAttrs = __assign({}, linkAttrs);
484
      if (!(getRelList(editor).length > 0) && allowUnsafeLinkTarget(editor) === false) {
485
        var newRel = applyRelTargetRules(newLinkAttrs.rel, newLinkAttrs.target === '_blank');
486
        newLinkAttrs.rel = newRel ? newRel : null;
487
      }
488
      if (Optional.from(newLinkAttrs.target).isNone() && getTargetList(editor) === false) {
489
        newLinkAttrs.target = getDefaultLinkTarget(editor);
490
      }
491
      newLinkAttrs.href = handleExternalTargets(newLinkAttrs.href, assumeExternalTargets(editor));
492
      return newLinkAttrs;
493
    };
494
    var updateLink = function (editor, anchorElm, text, linkAttrs) {
495
      text.each(function (text) {
637 daniel-mar 496
        if (has(anchorElm, 'innerText')) {
597 daniel-mar 497
          anchorElm.innerText = text;
498
        } else {
499
          anchorElm.textContent = text;
500
        }
501
      });
502
      editor.dom.setAttribs(anchorElm, linkAttrs);
503
      editor.selection.select(anchorElm);
504
    };
505
    var createLink = function (editor, selectedElm, text, linkAttrs) {
506
      if (isImageFigure(selectedElm)) {
507
        linkImageFigure(editor, selectedElm, linkAttrs);
508
      } else {
509
        text.fold(function () {
510
          editor.execCommand('mceInsertLink', false, linkAttrs);
511
        }, function (text) {
512
          editor.insertContent(editor.dom.createHTML('a', linkAttrs, editor.dom.encode(text)));
513
        });
514
      }
515
    };
516
    var linkDomMutation = function (editor, attachState, data) {
517
      var selectedElm = editor.selection.getNode();
518
      var anchorElm = getAnchorElement(editor, selectedElm);
519
      var linkAttrs = applyLinkOverrides(editor, getLinkAttrs(data));
520
      editor.undoManager.transact(function () {
521
        if (data.href === attachState.href) {
522
          attachState.attach();
523
        }
524
        if (anchorElm) {
525
          editor.focus();
526
          updateLink(editor, anchorElm, data.text, linkAttrs);
527
        } else {
528
          createLink(editor, selectedElm, data.text, linkAttrs);
529
        }
530
      });
531
    };
532
    var unlinkSelection = function (editor) {
533
      var dom = editor.dom, selection = editor.selection;
534
      var bookmark = selection.getBookmark();
535
      var rng = selection.getRng().cloneRange();
536
      var startAnchorElm = dom.getParent(rng.startContainer, 'a[href]', editor.getBody());
537
      var endAnchorElm = dom.getParent(rng.endContainer, 'a[href]', editor.getBody());
538
      if (startAnchorElm) {
539
        rng.setStartBefore(startAnchorElm);
540
      }
541
      if (endAnchorElm) {
542
        rng.setEndAfter(endAnchorElm);
543
      }
544
      selection.setRng(rng);
545
      editor.execCommand('unlink');
546
      selection.moveToBookmark(bookmark);
547
    };
548
    var unlinkDomMutation = function (editor) {
549
      editor.undoManager.transact(function () {
550
        var node = editor.selection.getNode();
551
        if (isImageFigure(node)) {
552
          unlinkImageFigure(editor, node);
553
        } else {
554
          unlinkSelection(editor);
555
        }
556
        editor.focus();
557
      });
558
    };
559
    var unwrapOptions = function (data) {
560
      var cls = data.class, href = data.href, rel = data.rel, target = data.target, text = data.text, title = data.title;
561
      return filter({
562
        class: cls.getOrNull(),
563
        href: href,
564
        rel: rel.getOrNull(),
565
        target: target.getOrNull(),
566
        text: text.getOrNull(),
567
        title: title.getOrNull()
568
      }, function (v, _k) {
569
        return isNull(v) === false;
570
      });
571
    };
679 daniel-mar 572
    var sanitizeData = function (editor, data) {
573
      var href = data.href;
574
      return __assign(__assign({}, data), { href: global$3.isDomSafe(href, 'a', editor.settings) ? href : '' });
575
    };
597 daniel-mar 576
    var link = function (editor, attachState, data) {
679 daniel-mar 577
      var sanitizedData = sanitizeData(editor, data);
578
      editor.hasPlugin('rtc', true) ? editor.execCommand('createlink', false, unwrapOptions(sanitizedData)) : linkDomMutation(editor, attachState, sanitizedData);
597 daniel-mar 579
    };
580
    var unlink = function (editor) {
581
      editor.hasPlugin('rtc', true) ? editor.execCommand('unlink') : unlinkDomMutation(editor);
582
    };
583
    var unlinkImageFigure = function (editor, fig) {
584
      var img = editor.dom.select('img', fig)[0];
585
      if (img) {
586
        var a = editor.dom.getParents(img, 'a[href]', fig)[0];
587
        if (a) {
588
          a.parentNode.insertBefore(img, a);
589
          editor.dom.remove(a);
590
        }
591
      }
592
    };
593
    var linkImageFigure = function (editor, fig, attrs) {
594
      var img = editor.dom.select('img', fig)[0];
595
      if (img) {
596
        var a = editor.dom.create('a', attrs);
597
        img.parentNode.insertBefore(a, img);
598
        a.appendChild(img);
599
      }
600
    };
601
 
602
    var isListGroup = function (item) {
603
      return hasNonNullableKey(item, 'items');
604
    };
605
    var findTextByValue = function (value, catalog) {
606
      return findMap(catalog, function (item) {
607
        if (isListGroup(item)) {
608
          return findTextByValue(value, item.items);
609
        } else {
610
          return someIf(item.value === value, item);
611
        }
612
      });
613
    };
614
    var getDelta = function (persistentText, fieldName, catalog, data) {
615
      var value = data[fieldName];
616
      var hasPersistentText = persistentText.length > 0;
617
      return value !== undefined ? findTextByValue(value, catalog).map(function (i) {
618
        return {
619
          url: {
620
            value: i.value,
621
            meta: {
622
              text: hasPersistentText ? persistentText : i.text,
623
              attach: noop
624
            }
625
          },
626
          text: hasPersistentText ? persistentText : i.text
627
        };
628
      }) : Optional.none();
629
    };
630
    var findCatalog = function (catalogs, fieldName) {
631
      if (fieldName === 'link') {
632
        return catalogs.link;
633
      } else if (fieldName === 'anchor') {
634
        return catalogs.anchor;
635
      } else {
636
        return Optional.none();
637
      }
638
    };
639
    var init = function (initialData, linkCatalog) {
640
      var persistentData = {
641
        text: initialData.text,
642
        title: initialData.title
643
      };
644
      var getTitleFromUrlChange = function (url) {
645
        return someIf(persistentData.title.length <= 0, Optional.from(url.meta.title).getOr(''));
646
      };
647
      var getTextFromUrlChange = function (url) {
648
        return someIf(persistentData.text.length <= 0, Optional.from(url.meta.text).getOr(url.value));
649
      };
650
      var onUrlChange = function (data) {
651
        var text = getTextFromUrlChange(data.url);
652
        var title = getTitleFromUrlChange(data.url);
653
        if (text.isSome() || title.isSome()) {
654
          return Optional.some(__assign(__assign({}, text.map(function (text) {
655
            return { text: text };
656
          }).getOr({})), title.map(function (title) {
657
            return { title: title };
658
          }).getOr({})));
659
        } else {
660
          return Optional.none();
661
        }
662
      };
663
      var onCatalogChange = function (data, change) {
664
        var catalog = findCatalog(linkCatalog, change.name).getOr([]);
665
        return getDelta(persistentData.text, change.name, catalog, data);
666
      };
667
      var onChange = function (getData, change) {
668
        var name = change.name;
669
        if (name === 'url') {
670
          return onUrlChange(getData());
671
        } else if (contains([
672
            'anchor',
673
            'link'
674
          ], name)) {
675
          return onCatalogChange(getData(), change);
676
        } else if (name === 'text' || name === 'title') {
677
          persistentData[name] = getData()[name];
678
          return Optional.none();
679
        } else {
680
          return Optional.none();
681
        }
682
      };
683
      return { onChange: onChange };
684
    };
685
    var DialogChanges = {
686
      init: init,
687
      getDelta: getDelta
688
    };
689
 
637 daniel-mar 690
    var global$2 = tinymce.util.Tools.resolve('tinymce.util.Delay');
597 daniel-mar 691
 
637 daniel-mar 692
    var global$1 = tinymce.util.Tools.resolve('tinymce.util.Promise');
597 daniel-mar 693
 
694
    var delayedConfirm = function (editor, message, callback) {
695
      var rng = editor.selection.getRng();
637 daniel-mar 696
      global$2.setEditorTimeout(editor, function () {
597 daniel-mar 697
        editor.windowManager.confirm(message, function (state) {
698
          editor.selection.setRng(rng);
699
          callback(state);
700
        });
701
      });
702
    };
703
    var tryEmailTransform = function (data) {
704
      var url = data.href;
705
      var suggestMailTo = url.indexOf('@') > 0 && url.indexOf('/') === -1 && url.indexOf('mailto:') === -1;
706
      return suggestMailTo ? Optional.some({
707
        message: 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?',
708
        preprocess: function (oldData) {
709
          return __assign(__assign({}, oldData), { href: 'mailto:' + url });
710
        }
711
      }) : Optional.none();
712
    };
713
    var tryProtocolTransform = function (assumeExternalTargets, defaultLinkProtocol) {
714
      return function (data) {
715
        var url = data.href;
716
        var suggestProtocol = assumeExternalTargets === 1 && !hasProtocol(url) || assumeExternalTargets === 0 && /^\s*www(\.|\d\.)/i.test(url);
717
        return suggestProtocol ? Optional.some({
718
          message: 'The URL you entered seems to be an external link. Do you want to add the required ' + defaultLinkProtocol + ':// prefix?',
719
          preprocess: function (oldData) {
720
            return __assign(__assign({}, oldData), { href: defaultLinkProtocol + '://' + url });
721
          }
722
        }) : Optional.none();
723
      };
724
    };
725
    var preprocess = function (editor, data) {
726
      return findMap([
727
        tryEmailTransform,
728
        tryProtocolTransform(assumeExternalTargets(editor), getDefaultLinkProtocol(editor))
729
      ], function (f) {
730
        return f(data);
731
      }).fold(function () {
637 daniel-mar 732
        return global$1.resolve(data);
597 daniel-mar 733
      }, function (transform) {
637 daniel-mar 734
        return new global$1(function (callback) {
597 daniel-mar 735
          delayedConfirm(editor, transform.message, function (state) {
736
            callback(state ? transform.preprocess(data) : data);
737
          });
738
        });
739
      });
740
    };
741
    var DialogConfirms = { preprocess: preprocess };
742
 
743
    var getAnchors = function (editor) {
744
      var anchorNodes = editor.dom.select('a:not([href])');
745
      var anchors = bind(anchorNodes, function (anchor) {
746
        var id = anchor.name || anchor.id;
747
        return id ? [{
748
            text: id,
749
            value: '#' + id
750
          }] : [];
751
      });
752
      return anchors.length > 0 ? Optional.some([{
753
          text: 'None',
754
          value: ''
755
        }].concat(anchors)) : Optional.none();
756
    };
757
    var AnchorListOptions = { getAnchors: getAnchors };
758
 
759
    var getClasses = function (editor) {
760
      var list = getLinkClassList(editor);
761
      if (list.length > 0) {
762
        return ListOptions.sanitize(list);
763
      }
764
      return Optional.none();
765
    };
766
    var ClassListOptions = { getClasses: getClasses };
767
 
637 daniel-mar 768
    var global = tinymce.util.Tools.resolve('tinymce.util.XHR');
597 daniel-mar 769
 
770
    var parseJson = function (text) {
771
      try {
772
        return Optional.some(JSON.parse(text));
773
      } catch (err) {
774
        return Optional.none();
775
      }
776
    };
777
    var getLinks = function (editor) {
778
      var extractor = function (item) {
779
        return editor.convertURL(item.value || item.url, 'href');
780
      };
781
      var linkList = getLinkList(editor);
637 daniel-mar 782
      return new global$1(function (callback) {
597 daniel-mar 783
        if (isString(linkList)) {
637 daniel-mar 784
          global.send({
597 daniel-mar 785
            url: linkList,
786
            success: function (text) {
787
              return callback(parseJson(text));
788
            },
789
            error: function (_) {
790
              return callback(Optional.none());
791
            }
792
          });
793
        } else if (isFunction(linkList)) {
794
          linkList(function (output) {
795
            return callback(Optional.some(output));
796
          });
797
        } else {
798
          callback(Optional.from(linkList));
799
        }
800
      }).then(function (optItems) {
801
        return optItems.bind(ListOptions.sanitizeWith(extractor)).map(function (items) {
802
          if (items.length > 0) {
803
            var noneItem = [{
804
                text: 'None',
805
                value: ''
806
              }];
807
            return noneItem.concat(items);
808
          } else {
809
            return items;
810
          }
811
        });
812
      });
813
    };
814
    var LinkListOptions = { getLinks: getLinks };
815
 
816
    var getRels = function (editor, initialTarget) {
817
      var list = getRelList(editor);
818
      if (list.length > 0) {
637 daniel-mar 819
        var isTargetBlank_1 = is(initialTarget, '_blank');
597 daniel-mar 820
        var enforceSafe = allowUnsafeLinkTarget(editor) === false;
821
        var safeRelExtractor = function (item) {
822
          return applyRelTargetRules(ListOptions.getValue(item), isTargetBlank_1);
823
        };
824
        var sanitizer = enforceSafe ? ListOptions.sanitizeWith(safeRelExtractor) : ListOptions.sanitize;
825
        return sanitizer(list);
826
      }
827
      return Optional.none();
828
    };
829
    var RelOptions = { getRels: getRels };
830
 
831
    var fallbacks = [
832
      {
833
        text: 'Current window',
834
        value: ''
835
      },
836
      {
837
        text: 'New window',
838
        value: '_blank'
839
      }
840
    ];
841
    var getTargets = function (editor) {
842
      var list = getTargetList(editor);
843
      if (isArray(list)) {
844
        return ListOptions.sanitize(list).orThunk(function () {
845
          return Optional.some(fallbacks);
846
        });
847
      } else if (list === false) {
848
        return Optional.none();
849
      }
850
      return Optional.some(fallbacks);
851
    };
852
    var TargetOptions = { getTargets: getTargets };
853
 
854
    var nonEmptyAttr = function (dom, elem, name) {
855
      var val = dom.getAttrib(elem, name);
856
      return val !== null && val.length > 0 ? Optional.some(val) : Optional.none();
857
    };
858
    var extractFromAnchor = function (editor, anchor) {
859
      var dom = editor.dom;
860
      var onlyText = isOnlyTextSelected(editor);
861
      var text = onlyText ? Optional.some(getAnchorText(editor.selection, anchor)) : Optional.none();
862
      var url = anchor ? Optional.some(dom.getAttrib(anchor, 'href')) : Optional.none();
863
      var target = anchor ? Optional.from(dom.getAttrib(anchor, 'target')) : Optional.none();
864
      var rel = nonEmptyAttr(dom, anchor, 'rel');
865
      var linkClass = nonEmptyAttr(dom, anchor, 'class');
866
      var title = nonEmptyAttr(dom, anchor, 'title');
867
      return {
868
        url: url,
869
        text: text,
870
        title: title,
871
        target: target,
872
        rel: rel,
873
        linkClass: linkClass
874
      };
875
    };
876
    var collect = function (editor, linkNode) {
877
      return LinkListOptions.getLinks(editor).then(function (links) {
878
        var anchor = extractFromAnchor(editor, linkNode);
879
        return {
880
          anchor: anchor,
881
          catalogs: {
882
            targets: TargetOptions.getTargets(editor),
883
            rels: RelOptions.getRels(editor, anchor.target),
884
            classes: ClassListOptions.getClasses(editor),
885
            anchor: AnchorListOptions.getAnchors(editor),
886
            link: links
887
          },
888
          optNode: Optional.from(linkNode),
889
          flags: { titleEnabled: shouldShowLinkTitle(editor) }
890
        };
891
      });
892
    };
893
    var DialogInfo = { collect: collect };
894
 
895
    var handleSubmit = function (editor, info) {
896
      return function (api) {
897
        var data = api.getData();
898
        if (!data.url.value) {
899
          unlink(editor);
900
          api.close();
901
          return;
902
        }
903
        var getChangedValue = function (key) {
904
          return Optional.from(data[key]).filter(function (value) {
637 daniel-mar 905
            return !is(info.anchor[key], value);
597 daniel-mar 906
          });
907
        };
908
        var changedData = {
909
          href: data.url.value,
910
          text: getChangedValue('text'),
911
          target: getChangedValue('target'),
912
          rel: getChangedValue('rel'),
913
          class: getChangedValue('linkClass'),
914
          title: getChangedValue('title')
915
        };
916
        var attachState = {
917
          href: data.url.value,
918
          attach: data.url.meta !== undefined && data.url.meta.attach ? data.url.meta.attach : noop
919
        };
920
        DialogConfirms.preprocess(editor, changedData).then(function (pData) {
921
          link(editor, attachState, pData);
922
        });
923
        api.close();
924
      };
925
    };
926
    var collectData = function (editor) {
927
      var anchorNode = getAnchorElement(editor);
928
      return DialogInfo.collect(editor, anchorNode);
929
    };
930
    var getInitialData = function (info, defaultTarget) {
931
      var anchor = info.anchor;
932
      var url = anchor.url.getOr('');
933
      return {
934
        url: {
935
          value: url,
936
          meta: { original: { value: url } }
937
        },
938
        text: anchor.text.getOr(''),
939
        title: anchor.title.getOr(''),
940
        anchor: url,
941
        link: url,
942
        rel: anchor.rel.getOr(''),
943
        target: anchor.target.or(defaultTarget).getOr(''),
944
        linkClass: anchor.linkClass.getOr('')
945
      };
946
    };
947
    var makeDialog = function (settings, onSubmit, editor) {
948
      var urlInput = [{
949
          name: 'url',
950
          type: 'urlinput',
951
          filetype: 'file',
952
          label: 'URL'
953
        }];
954
      var displayText = settings.anchor.text.map(function () {
955
        return {
956
          name: 'text',
957
          type: 'input',
958
          label: 'Text to display'
959
        };
960
      }).toArray();
961
      var titleText = settings.flags.titleEnabled ? [{
962
          name: 'title',
963
          type: 'input',
964
          label: 'Title'
965
        }] : [];
966
      var defaultTarget = Optional.from(getDefaultLinkTarget(editor));
967
      var initialData = getInitialData(settings, defaultTarget);
968
      var catalogs = settings.catalogs;
969
      var dialogDelta = DialogChanges.init(initialData, catalogs);
970
      var body = {
971
        type: 'panel',
972
        items: flatten([
973
          urlInput,
974
          displayText,
975
          titleText,
976
          cat([
977
            catalogs.anchor.map(ListOptions.createUi('anchor', 'Anchors')),
978
            catalogs.rels.map(ListOptions.createUi('rel', 'Rel')),
979
            catalogs.targets.map(ListOptions.createUi('target', 'Open link in...')),
980
            catalogs.link.map(ListOptions.createUi('link', 'Link list')),
981
            catalogs.classes.map(ListOptions.createUi('linkClass', 'Class'))
982
          ])
983
        ])
984
      };
985
      return {
986
        title: 'Insert/Edit Link',
987
        size: 'normal',
988
        body: body,
989
        buttons: [
990
          {
991
            type: 'cancel',
992
            name: 'cancel',
993
            text: 'Cancel'
994
          },
995
          {
996
            type: 'submit',
997
            name: 'save',
998
            text: 'Save',
999
            primary: true
1000
          }
1001
        ],
1002
        initialData: initialData,
1003
        onChange: function (api, _a) {
1004
          var name = _a.name;
1005
          dialogDelta.onChange(api.getData, { name: name }).each(function (newData) {
1006
            api.setData(newData);
1007
          });
1008
        },
1009
        onSubmit: onSubmit
1010
      };
1011
    };
637 daniel-mar 1012
    var open$1 = function (editor) {
597 daniel-mar 1013
      var data = collectData(editor);
1014
      data.then(function (info) {
1015
        var onSubmit = handleSubmit(editor, info);
1016
        return makeDialog(info, onSubmit, editor);
1017
      }).then(function (spec) {
1018
        editor.windowManager.open(spec);
1019
      });
1020
    };
1021
 
1022
    var appendClickRemove = function (link, evt) {
1023
      document.body.appendChild(link);
1024
      link.dispatchEvent(evt);
1025
      document.body.removeChild(link);
1026
    };
637 daniel-mar 1027
    var open = function (url) {
597 daniel-mar 1028
      var link = document.createElement('a');
1029
      link.target = '_blank';
1030
      link.href = url;
1031
      link.rel = 'noreferrer noopener';
1032
      var evt = document.createEvent('MouseEvents');
1033
      evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
1034
      appendClickRemove(link, evt);
1035
    };
1036
 
1037
    var getLink = function (editor, elm) {
1038
      return editor.dom.getParent(elm, 'a[href]');
1039
    };
1040
    var getSelectedLink = function (editor) {
1041
      return getLink(editor, editor.selection.getStart());
1042
    };
1043
    var hasOnlyAltModifier = function (e) {
1044
      return e.altKey === true && e.shiftKey === false && e.ctrlKey === false && e.metaKey === false;
1045
    };
1046
    var gotoLink = function (editor, a) {
1047
      if (a) {
1048
        var href = getHref(a);
1049
        if (/^#/.test(href)) {
1050
          var targetEl = editor.$(href);
1051
          if (targetEl.length) {
1052
            editor.selection.scrollIntoView(targetEl[0], true);
1053
          }
1054
        } else {
637 daniel-mar 1055
          open(a.href);
597 daniel-mar 1056
        }
1057
      }
1058
    };
1059
    var openDialog = function (editor) {
1060
      return function () {
637 daniel-mar 1061
        open$1(editor);
597 daniel-mar 1062
      };
1063
    };
1064
    var gotoSelectedLink = function (editor) {
1065
      return function () {
1066
        gotoLink(editor, getSelectedLink(editor));
1067
      };
1068
    };
1069
    var setupGotoLinks = function (editor) {
1070
      editor.on('click', function (e) {
1071
        var link = getLink(editor, e.target);
679 daniel-mar 1072
        if (link && global$6.metaKeyPressed(e)) {
597 daniel-mar 1073
          e.preventDefault();
1074
          gotoLink(editor, link);
1075
        }
1076
      });
1077
      editor.on('keydown', function (e) {
1078
        var link = getSelectedLink(editor);
1079
        if (link && e.keyCode === 13 && hasOnlyAltModifier(e)) {
1080
          e.preventDefault();
1081
          gotoLink(editor, link);
1082
        }
1083
      });
1084
    };
1085
    var toggleState = function (editor, toggler) {
1086
      editor.on('NodeChange', toggler);
1087
      return function () {
1088
        return editor.off('NodeChange', toggler);
1089
      };
1090
    };
1091
    var toggleActiveState = function (editor) {
1092
      return function (api) {
637 daniel-mar 1093
        var updateState = function () {
1094
          return api.setActive(!editor.mode.isReadOnly() && getAnchorElement(editor, editor.selection.getNode()) !== null);
1095
        };
1096
        updateState();
1097
        return toggleState(editor, updateState);
597 daniel-mar 1098
      };
1099
    };
1100
    var toggleEnabledState = function (editor) {
1101
      return function (api) {
1102
        var updateState = function () {
1103
          return api.setDisabled(getAnchorElement(editor, editor.selection.getNode()) === null);
1104
        };
1105
        updateState();
1106
        return toggleState(editor, updateState);
1107
      };
1108
    };
1109
    var toggleUnlinkState = function (editor) {
1110
      return function (api) {
1111
        var hasLinks$1 = function (parents) {
1112
          return hasLinks(parents) || hasLinksInSelection(editor.selection.getRng());
1113
        };
1114
        var parents = editor.dom.getParents(editor.selection.getStart());
1115
        api.setDisabled(!hasLinks$1(parents));
1116
        return toggleState(editor, function (e) {
1117
          return api.setDisabled(!hasLinks$1(e.parents));
1118
        });
1119
      };
1120
    };
1121
 
1122
    var register = function (editor) {
1123
      editor.addCommand('mceLink', function () {
1124
        if (useQuickLink(editor)) {
1125
          editor.fire('contexttoolbar-show', { toolbarKey: 'quicklink' });
1126
        } else {
1127
          openDialog(editor)();
1128
        }
1129
      });
1130
    };
1131
 
1132
    var setup = function (editor) {
1133
      editor.addShortcut('Meta+K', '', function () {
1134
        editor.execCommand('mceLink');
1135
      });
1136
    };
1137
 
1138
    var setupButtons = function (editor) {
1139
      editor.ui.registry.addToggleButton('link', {
1140
        icon: 'link',
1141
        tooltip: 'Insert/edit link',
1142
        onAction: openDialog(editor),
1143
        onSetup: toggleActiveState(editor)
1144
      });
1145
      editor.ui.registry.addButton('openlink', {
1146
        icon: 'new-tab',
1147
        tooltip: 'Open link',
1148
        onAction: gotoSelectedLink(editor),
1149
        onSetup: toggleEnabledState(editor)
1150
      });
1151
      editor.ui.registry.addButton('unlink', {
1152
        icon: 'unlink',
1153
        tooltip: 'Remove link',
1154
        onAction: function () {
1155
          return unlink(editor);
1156
        },
1157
        onSetup: toggleUnlinkState(editor)
1158
      });
1159
    };
1160
    var setupMenuItems = function (editor) {
1161
      editor.ui.registry.addMenuItem('openlink', {
1162
        text: 'Open link',
1163
        icon: 'new-tab',
1164
        onAction: gotoSelectedLink(editor),
1165
        onSetup: toggleEnabledState(editor)
1166
      });
1167
      editor.ui.registry.addMenuItem('link', {
1168
        icon: 'link',
1169
        text: 'Link...',
1170
        shortcut: 'Meta+K',
1171
        onAction: openDialog(editor)
1172
      });
1173
      editor.ui.registry.addMenuItem('unlink', {
1174
        icon: 'unlink',
1175
        text: 'Remove link',
1176
        onAction: function () {
1177
          return unlink(editor);
1178
        },
1179
        onSetup: toggleUnlinkState(editor)
1180
      });
1181
    };
1182
    var setupContextMenu = function (editor) {
1183
      var inLink = 'link unlink openlink';
1184
      var noLink = 'link';
1185
      editor.ui.registry.addContextMenu('link', {
1186
        update: function (element) {
1187
          return hasLinks(editor.dom.getParents(element, 'a')) ? inLink : noLink;
1188
        }
1189
      });
1190
    };
1191
    var setupContextToolbars = function (editor) {
1192
      var collapseSelectionToEnd = function (editor) {
1193
        editor.selection.collapse(false);
1194
      };
1195
      var onSetupLink = function (buttonApi) {
1196
        var node = editor.selection.getNode();
1197
        buttonApi.setDisabled(!getAnchorElement(editor, node));
1198
        return noop;
1199
      };
637 daniel-mar 1200
      var getLinkText = function (value) {
1201
        var anchor = getAnchorElement(editor);
1202
        var onlyText = isOnlyTextSelected(editor);
1203
        if (!anchor && onlyText) {
1204
          var text = getAnchorText(editor.selection, anchor);
1205
          return Optional.some(text.length > 0 ? text : value);
1206
        } else {
1207
          return Optional.none();
1208
        }
1209
      };
597 daniel-mar 1210
      editor.ui.registry.addContextForm('quicklink', {
1211
        launch: {
1212
          type: 'contextformtogglebutton',
1213
          icon: 'link',
1214
          tooltip: 'Link',
1215
          onSetup: toggleActiveState(editor)
1216
        },
1217
        label: 'Link',
1218
        predicate: function (node) {
1219
          return !!getAnchorElement(editor, node) && hasContextToolbar(editor);
1220
        },
1221
        initValue: function () {
1222
          var elm = getAnchorElement(editor);
1223
          return !!elm ? getHref(elm) : '';
1224
        },
1225
        commands: [
1226
          {
1227
            type: 'contextformtogglebutton',
1228
            icon: 'link',
1229
            tooltip: 'Link',
1230
            primary: true,
1231
            onSetup: function (buttonApi) {
1232
              var node = editor.selection.getNode();
1233
              buttonApi.setActive(!!getAnchorElement(editor, node));
1234
              return toggleActiveState(editor)(buttonApi);
1235
            },
1236
            onAction: function (formApi) {
1237
              var value = formApi.getValue();
637 daniel-mar 1238
              var text = getLinkText(value);
1239
              var attachState = {
1240
                href: value,
1241
                attach: noop
1242
              };
1243
              link(editor, attachState, {
1244
                href: value,
1245
                text: text,
1246
                title: Optional.none(),
1247
                rel: Optional.none(),
1248
                target: Optional.none(),
1249
                class: Optional.none()
1250
              });
1251
              collapseSelectionToEnd(editor);
1252
              formApi.hide();
597 daniel-mar 1253
            }
1254
          },
1255
          {
1256
            type: 'contextformbutton',
1257
            icon: 'unlink',
1258
            tooltip: 'Remove link',
1259
            onSetup: onSetupLink,
1260
            onAction: function (formApi) {
1261
              unlink(editor);
1262
              formApi.hide();
1263
            }
1264
          },
1265
          {
1266
            type: 'contextformbutton',
1267
            icon: 'new-tab',
1268
            tooltip: 'Open link',
1269
            onSetup: onSetupLink,
1270
            onAction: function (formApi) {
1271
              gotoSelectedLink(editor)();
1272
              formApi.hide();
1273
            }
1274
          }
1275
        ]
1276
      });
1277
    };
1278
 
1279
    function Plugin () {
679 daniel-mar 1280
      global$7.add('link', function (editor) {
597 daniel-mar 1281
        setupButtons(editor);
1282
        setupMenuItems(editor);
1283
        setupContextMenu(editor);
1284
        setupContextToolbars(editor);
1285
        setupGotoLinks(editor);
1286
        register(editor);
1287
        setup(editor);
1288
      });
1289
    }
1290
 
1291
    Plugin();
1292
 
1293
}());