Subversion Repositories oidplus

Rev

Rev 637 | Rev 759 | Go to most recent revision | 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
 *
679 daniel-mar 7
 * Version: 5.10.2 (2021-11-17)
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 hasProPlugin = function (editor) {
29
      if (editor.hasPlugin('tinymcespellchecker', true)) {
30
        if (typeof window.console !== 'undefined' && window.console.log) {
31
          window.console.log('Spell Checker Pro is incompatible with Spell Checker plugin! ' + 'Remove \'spellchecker\' from the \'plugins\' option.');
32
        }
33
        return true;
34
      } else {
35
        return false;
36
      }
37
    };
38
 
39
    var hasOwnProperty = Object.hasOwnProperty;
40
    var isEmpty = function (r) {
41
      for (var x in r) {
42
        if (hasOwnProperty.call(r, x)) {
43
          return false;
44
        }
45
      }
46
      return true;
47
    };
48
 
637 daniel-mar 49
    var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools');
597 daniel-mar 50
 
637 daniel-mar 51
    var global$1 = tinymce.util.Tools.resolve('tinymce.util.URI');
597 daniel-mar 52
 
637 daniel-mar 53
    var global = tinymce.util.Tools.resolve('tinymce.util.XHR');
597 daniel-mar 54
 
55
    var fireSpellcheckStart = function (editor) {
56
      return editor.fire('SpellcheckStart');
57
    };
58
    var fireSpellcheckEnd = function (editor) {
59
      return editor.fire('SpellcheckEnd');
60
    };
61
 
62
    var getLanguages = function (editor) {
63
      var defaultLanguages = 'English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr_FR,German=de,Italian=it,Polish=pl,Portuguese=pt_BR,Spanish=es,Swedish=sv';
64
      return editor.getParam('spellchecker_languages', defaultLanguages);
65
    };
66
    var getLanguage = function (editor) {
67
      var defaultLanguage = editor.getParam('language', 'en');
68
      return editor.getParam('spellchecker_language', defaultLanguage);
69
    };
70
    var getRpcUrl = function (editor) {
71
      return editor.getParam('spellchecker_rpc_url');
72
    };
73
    var getSpellcheckerCallback = function (editor) {
74
      return editor.getParam('spellchecker_callback');
75
    };
76
    var getSpellcheckerWordcharPattern = function (editor) {
77
      var defaultPattern = new RegExp('[^' + '\\s!"#$%&()*+,-./:;<=>?@[\\]^_{|}`' + '\xA7\xA9\xAB\xAE\xB1\xB6\xB7\xB8\xBB' + '\xBC\xBD\xBE\xBF\xD7\xF7\xA4\u201D\u201C\u201E\xA0\u2002\u2003\u2009' + ']+', 'g');
78
      return editor.getParam('spellchecker_wordchar_pattern', defaultPattern);
79
    };
80
 
81
    var isContentEditableFalse = function (node) {
82
      return node && node.nodeType === 1 && node.contentEditable === 'false';
83
    };
84
    var DomTextMatcher = function (node, editor) {
85
      var m, matches = [];
86
      var dom = editor.dom;
87
      var blockElementsMap = editor.schema.getBlockElements();
88
      var hiddenTextElementsMap = editor.schema.getWhiteSpaceElements();
89
      var shortEndedElementsMap = editor.schema.getShortEndedElements();
90
      var createMatch = function (m, data) {
91
        if (!m[0]) {
92
          throw new Error('findAndReplaceDOMText cannot handle zero-length matches');
93
        }
94
        return {
95
          start: m.index,
96
          end: m.index + m[0].length,
97
          text: m[0],
98
          data: data
99
        };
100
      };
101
      var getText = function (node) {
102
        if (node.nodeType === 3) {
103
          return node.data;
104
        }
105
        if (hiddenTextElementsMap[node.nodeName] && !blockElementsMap[node.nodeName]) {
106
          return '';
107
        }
108
        if (isContentEditableFalse(node)) {
109
          return '\n';
110
        }
637 daniel-mar 111
        var txt = '';
597 daniel-mar 112
        if (blockElementsMap[node.nodeName] || shortEndedElementsMap[node.nodeName]) {
113
          txt += '\n';
114
        }
115
        if (node = node.firstChild) {
116
          do {
117
            txt += getText(node);
118
          } while (node = node.nextSibling);
119
        }
120
        return txt;
121
      };
122
      var stepThroughMatches = function (node, matches, replaceFn) {
123
        var startNode, endNode, startNodeIndex, endNodeIndex, innerNodes = [], atIndex = 0, curNode = node, matchLocation, matchIndex = 0;
124
        matches = matches.slice(0);
125
        matches.sort(function (a, b) {
126
          return a.start - b.start;
127
        });
128
        matchLocation = matches.shift();
129
        out:
130
          while (true) {
131
            if (blockElementsMap[curNode.nodeName] || shortEndedElementsMap[curNode.nodeName] || isContentEditableFalse(curNode)) {
132
              atIndex++;
133
            }
134
            if (curNode.nodeType === 3) {
135
              if (!endNode && curNode.length + atIndex >= matchLocation.end) {
136
                endNode = curNode;
137
                endNodeIndex = matchLocation.end - atIndex;
138
              } else if (startNode) {
139
                innerNodes.push(curNode);
140
              }
141
              if (!startNode && curNode.length + atIndex > matchLocation.start) {
142
                startNode = curNode;
143
                startNodeIndex = matchLocation.start - atIndex;
144
              }
145
              atIndex += curNode.length;
146
            }
147
            if (startNode && endNode) {
148
              curNode = replaceFn({
149
                startNode: startNode,
150
                startNodeIndex: startNodeIndex,
151
                endNode: endNode,
152
                endNodeIndex: endNodeIndex,
153
                innerNodes: innerNodes,
154
                match: matchLocation.text,
155
                matchIndex: matchIndex
156
              });
157
              atIndex -= endNode.length - endNodeIndex;
158
              startNode = null;
159
              endNode = null;
160
              innerNodes = [];
161
              matchLocation = matches.shift();
162
              matchIndex++;
163
              if (!matchLocation) {
164
                break;
165
              }
166
            } else if ((!hiddenTextElementsMap[curNode.nodeName] || blockElementsMap[curNode.nodeName]) && curNode.firstChild) {
167
              if (!isContentEditableFalse(curNode)) {
168
                curNode = curNode.firstChild;
169
                continue;
170
              }
171
            } else if (curNode.nextSibling) {
172
              curNode = curNode.nextSibling;
173
              continue;
174
            }
175
            while (true) {
176
              if (curNode.nextSibling) {
177
                curNode = curNode.nextSibling;
178
                break;
179
              } else if (curNode.parentNode !== node) {
180
                curNode = curNode.parentNode;
181
              } else {
182
                break out;
183
              }
184
            }
185
          }
186
      };
187
      var genReplacer = function (callback) {
188
        var makeReplacementNode = function (fill, matchIndex) {
189
          var match = matches[matchIndex];
190
          if (!match.stencil) {
191
            match.stencil = callback(match);
192
          }
193
          var clone = match.stencil.cloneNode(false);
637 daniel-mar 194
          clone.setAttribute('data-mce-index', '' + matchIndex);
597 daniel-mar 195
          if (fill) {
196
            clone.appendChild(dom.doc.createTextNode(fill));
197
          }
198
          return clone;
199
        };
200
        return function (range) {
201
          var before;
202
          var after;
203
          var parentNode;
204
          var startNode = range.startNode;
205
          var endNode = range.endNode;
206
          var matchIndex = range.matchIndex;
207
          var doc = dom.doc;
208
          if (startNode === endNode) {
209
            var node_1 = startNode;
210
            parentNode = node_1.parentNode;
211
            if (range.startNodeIndex > 0) {
212
              before = doc.createTextNode(node_1.data.substring(0, range.startNodeIndex));
213
              parentNode.insertBefore(before, node_1);
214
            }
215
            var el = makeReplacementNode(range.match, matchIndex);
216
            parentNode.insertBefore(el, node_1);
217
            if (range.endNodeIndex < node_1.length) {
218
              after = doc.createTextNode(node_1.data.substring(range.endNodeIndex));
219
              parentNode.insertBefore(after, node_1);
220
            }
221
            node_1.parentNode.removeChild(node_1);
222
            return el;
223
          }
224
          before = doc.createTextNode(startNode.data.substring(0, range.startNodeIndex));
225
          after = doc.createTextNode(endNode.data.substring(range.endNodeIndex));
226
          var elA = makeReplacementNode(startNode.data.substring(range.startNodeIndex), matchIndex);
227
          for (var i = 0, l = range.innerNodes.length; i < l; ++i) {
228
            var innerNode = range.innerNodes[i];
229
            var innerEl = makeReplacementNode(innerNode.data, matchIndex);
230
            innerNode.parentNode.replaceChild(innerEl, innerNode);
231
          }
232
          var elB = makeReplacementNode(endNode.data.substring(0, range.endNodeIndex), matchIndex);
233
          parentNode = startNode.parentNode;
234
          parentNode.insertBefore(before, startNode);
235
          parentNode.insertBefore(elA, startNode);
236
          parentNode.removeChild(startNode);
237
          parentNode = endNode.parentNode;
238
          parentNode.insertBefore(elB, endNode);
239
          parentNode.insertBefore(after, endNode);
240
          parentNode.removeChild(endNode);
241
          return elB;
242
        };
243
      };
244
      var unwrapElement = function (element) {
245
        var parentNode = element.parentNode;
246
        while (element.childNodes.length > 0) {
247
          parentNode.insertBefore(element.childNodes[0], element);
248
        }
249
        parentNode.removeChild(element);
250
      };
251
      var hasClass = function (elm) {
252
        return elm.className.indexOf('mce-spellchecker-word') !== -1;
253
      };
254
      var getWrappersByIndex = function (index) {
255
        var elements = node.getElementsByTagName('*'), wrappers = [];
256
        index = typeof index === 'number' ? '' + index : null;
257
        for (var i = 0; i < elements.length; i++) {
258
          var element = elements[i], dataIndex = element.getAttribute('data-mce-index');
259
          if (dataIndex !== null && dataIndex.length && hasClass(element)) {
260
            if (dataIndex === index || index === null) {
261
              wrappers.push(element);
262
            }
263
          }
264
        }
265
        return wrappers;
266
      };
267
      var indexOf = function (match) {
268
        var i = matches.length;
269
        while (i--) {
270
          if (matches[i] === match) {
271
            return i;
272
          }
273
        }
274
        return -1;
275
      };
276
      function filter(callback) {
277
        var filteredMatches = [];
278
        each(function (match, i) {
279
          if (callback(match, i)) {
280
            filteredMatches.push(match);
281
          }
282
        });
283
        matches = filteredMatches;
284
        return this;
285
      }
286
      function each(callback) {
287
        for (var i = 0, l = matches.length; i < l; i++) {
288
          if (callback(matches[i], i) === false) {
289
            break;
290
          }
291
        }
292
        return this;
293
      }
294
      function wrap(callback) {
295
        if (matches.length) {
296
          stepThroughMatches(node, matches, genReplacer(callback));
297
        }
298
        return this;
299
      }
300
      function find(regex, data) {
301
        if (text && regex.global) {
302
          while (m = regex.exec(text)) {
303
            matches.push(createMatch(m, data));
304
          }
305
        }
306
        return this;
307
      }
308
      function unwrap(match) {
309
        var i;
310
        var elements = getWrappersByIndex(match ? indexOf(match) : null);
311
        i = elements.length;
312
        while (i--) {
313
          unwrapElement(elements[i]);
314
        }
315
        return this;
316
      }
317
      var matchFromElement = function (element) {
318
        return matches[element.getAttribute('data-mce-index')];
319
      };
320
      var elementFromMatch = function (match) {
321
        return getWrappersByIndex(indexOf(match))[0];
322
      };
323
      function add(start, length, data) {
324
        matches.push({
325
          start: start,
326
          end: start + length,
327
          text: text.substr(start, length),
328
          data: data
329
        });
330
        return this;
331
      }
332
      var rangeFromMatch = function (match) {
333
        var wrappers = getWrappersByIndex(indexOf(match));
334
        var rng = editor.dom.createRng();
335
        rng.setStartBefore(wrappers[0]);
336
        rng.setEndAfter(wrappers[wrappers.length - 1]);
337
        return rng;
338
      };
339
      var replace = function (match, text) {
340
        var rng = rangeFromMatch(match);
341
        rng.deleteContents();
342
        if (text.length > 0) {
343
          rng.insertNode(editor.dom.doc.createTextNode(text));
344
        }
345
        return rng;
346
      };
347
      function reset() {
348
        matches.splice(0, matches.length);
349
        unwrap();
350
        return this;
351
      }
352
      var text = getText(node);
353
      return {
354
        text: text,
355
        matches: matches,
356
        each: each,
357
        filter: filter,
358
        reset: reset,
359
        matchFromElement: matchFromElement,
360
        elementFromMatch: elementFromMatch,
361
        find: find,
362
        add: add,
363
        wrap: wrap,
364
        unwrap: unwrap,
365
        replace: replace,
366
        rangeFromMatch: rangeFromMatch,
367
        indexOf: indexOf
368
      };
369
    };
370
 
371
    var getTextMatcher = function (editor, textMatcherState) {
372
      if (!textMatcherState.get()) {
373
        var textMatcher = DomTextMatcher(editor.getBody(), editor);
374
        textMatcherState.set(textMatcher);
375
      }
376
      return textMatcherState.get();
377
    };
378
    var defaultSpellcheckCallback = function (editor, pluginUrl, currentLanguageState) {
379
      return function (method, text, doneCallback, errorCallback) {
380
        var data = {
381
          method: method,
382
          lang: currentLanguageState.get()
383
        };
384
        var postData = '';
385
        data[method === 'addToDictionary' ? 'word' : 'text'] = text;
637 daniel-mar 386
        global$2.each(data, function (value, key) {
597 daniel-mar 387
          if (postData) {
388
            postData += '&';
389
          }
390
          postData += key + '=' + encodeURIComponent(value);
391
        });
637 daniel-mar 392
        global.send({
393
          url: new global$1(pluginUrl).toAbsolute(getRpcUrl(editor)),
597 daniel-mar 394
          type: 'post',
395
          content_type: 'application/x-www-form-urlencoded',
396
          data: postData,
397
          success: function (result) {
398
            var parseResult = JSON.parse(result);
399
            if (!parseResult) {
400
              var message = editor.translate('Server response wasn\'t proper JSON.');
401
              errorCallback(message);
402
            } else if (parseResult.error) {
403
              errorCallback(parseResult.error);
404
            } else {
405
              doneCallback(parseResult);
406
            }
407
          },
408
          error: function () {
409
            var message = editor.translate('The spelling service was not found: (') + getRpcUrl(editor) + editor.translate(')');
410
            errorCallback(message);
411
          }
412
        });
413
      };
414
    };
415
    var sendRpcCall = function (editor, pluginUrl, currentLanguageState, name, data, successCallback, errorCallback) {
416
      var userSpellcheckCallback = getSpellcheckerCallback(editor);
417
      var spellCheckCallback = userSpellcheckCallback ? userSpellcheckCallback : defaultSpellcheckCallback(editor, pluginUrl, currentLanguageState);
418
      spellCheckCallback.call(editor.plugins.spellchecker, name, data, successCallback, errorCallback);
419
    };
420
    var spellcheck = function (editor, pluginUrl, startedState, textMatcherState, lastSuggestionsState, currentLanguageState) {
421
      if (finish(editor, startedState, textMatcherState)) {
422
        return;
423
      }
424
      var errorCallback = function (message) {
425
        editor.notificationManager.open({
426
          text: message,
427
          type: 'error'
428
        });
429
        editor.setProgressState(false);
430
        finish(editor, startedState, textMatcherState);
431
      };
432
      var successCallback = function (data) {
433
        markErrors(editor, startedState, textMatcherState, lastSuggestionsState, data);
434
      };
435
      editor.setProgressState(true);
436
      sendRpcCall(editor, pluginUrl, currentLanguageState, 'spellcheck', getTextMatcher(editor, textMatcherState).text, successCallback, errorCallback);
437
      editor.focus();
438
    };
439
    var checkIfFinished = function (editor, startedState, textMatcherState) {
440
      if (!editor.dom.select('span.mce-spellchecker-word').length) {
441
        finish(editor, startedState, textMatcherState);
442
      }
443
    };
444
    var addToDictionary = function (editor, pluginUrl, startedState, textMatcherState, currentLanguageState, word, spans) {
445
      editor.setProgressState(true);
446
      sendRpcCall(editor, pluginUrl, currentLanguageState, 'addToDictionary', word, function () {
447
        editor.setProgressState(false);
448
        editor.dom.remove(spans, true);
449
        checkIfFinished(editor, startedState, textMatcherState);
450
      }, function (message) {
451
        editor.notificationManager.open({
452
          text: message,
453
          type: 'error'
454
        });
455
        editor.setProgressState(false);
456
      });
457
    };
458
    var ignoreWord = function (editor, startedState, textMatcherState, word, spans, all) {
459
      editor.selection.collapse();
460
      if (all) {
637 daniel-mar 461
        global$2.each(editor.dom.select('span.mce-spellchecker-word'), function (span) {
597 daniel-mar 462
          if (span.getAttribute('data-mce-word') === word) {
463
            editor.dom.remove(span, true);
464
          }
465
        });
466
      } else {
467
        editor.dom.remove(spans, true);
468
      }
469
      checkIfFinished(editor, startedState, textMatcherState);
470
    };
471
    var finish = function (editor, startedState, textMatcherState) {
472
      var bookmark = editor.selection.getBookmark();
473
      getTextMatcher(editor, textMatcherState).reset();
474
      editor.selection.moveToBookmark(bookmark);
475
      textMatcherState.set(null);
476
      if (startedState.get()) {
477
        startedState.set(false);
478
        fireSpellcheckEnd(editor);
479
        return true;
480
      }
481
    };
482
    var getElmIndex = function (elm) {
483
      var value = elm.getAttribute('data-mce-index');
484
      if (typeof value === 'number') {
485
        return '' + value;
486
      }
487
      return value;
488
    };
489
    var findSpansByIndex = function (editor, index) {
490
      var spans = [];
637 daniel-mar 491
      var nodes = global$2.toArray(editor.getBody().getElementsByTagName('span'));
597 daniel-mar 492
      if (nodes.length) {
493
        for (var i = 0; i < nodes.length; i++) {
494
          var nodeIndex = getElmIndex(nodes[i]);
495
          if (nodeIndex === null || !nodeIndex.length) {
496
            continue;
497
          }
498
          if (nodeIndex === index.toString()) {
499
            spans.push(nodes[i]);
500
          }
501
        }
502
      }
503
      return spans;
504
    };
505
    var markErrors = function (editor, startedState, textMatcherState, lastSuggestionsState, data) {
506
      var hasDictionarySupport = !!data.dictionary;
507
      var suggestions = data.words;
508
      editor.setProgressState(false);
509
      if (isEmpty(suggestions)) {
510
        var message = editor.translate('No misspellings found.');
511
        editor.notificationManager.open({
512
          text: message,
513
          type: 'info'
514
        });
515
        startedState.set(false);
516
        return;
517
      }
518
      lastSuggestionsState.set({
519
        suggestions: suggestions,
520
        hasDictionarySupport: hasDictionarySupport
521
      });
522
      var bookmark = editor.selection.getBookmark();
523
      getTextMatcher(editor, textMatcherState).find(getSpellcheckerWordcharPattern(editor)).filter(function (match) {
524
        return !!suggestions[match.text];
525
      }).wrap(function (match) {
526
        return editor.dom.create('span', {
527
          'class': 'mce-spellchecker-word',
528
          'aria-invalid': 'spelling',
529
          'data-mce-bogus': 1,
530
          'data-mce-word': match.text
531
        });
532
      });
533
      editor.selection.moveToBookmark(bookmark);
534
      startedState.set(true);
535
      fireSpellcheckStart(editor);
536
    };
537
 
637 daniel-mar 538
    var get = function (editor, startedState, lastSuggestionsState, textMatcherState, currentLanguageState) {
597 daniel-mar 539
      var getWordCharPattern = function () {
540
        return getSpellcheckerWordcharPattern(editor);
541
      };
542
      var markErrors$1 = function (data) {
543
        markErrors(editor, startedState, textMatcherState, lastSuggestionsState, data);
544
      };
545
      return {
546
        getTextMatcher: textMatcherState.get,
547
        getWordCharPattern: getWordCharPattern,
548
        markErrors: markErrors$1,
549
        getLanguage: currentLanguageState.get
550
      };
551
    };
552
 
637 daniel-mar 553
    var register$1 = function (editor, pluginUrl, startedState, textMatcherState, lastSuggestionsState, currentLanguageState) {
597 daniel-mar 554
      editor.addCommand('mceSpellCheck', function () {
555
        spellcheck(editor, pluginUrl, startedState, textMatcherState, lastSuggestionsState, currentLanguageState);
556
      });
557
    };
558
 
559
    var __assign = function () {
560
      __assign = Object.assign || function __assign(t) {
561
        for (var s, i = 1, n = arguments.length; i < n; i++) {
562
          s = arguments[i];
563
          for (var p in s)
564
            if (Object.prototype.hasOwnProperty.call(s, p))
565
              t[p] = s[p];
566
        }
567
        return t;
568
      };
569
      return __assign.apply(this, arguments);
570
    };
571
 
572
    var spellcheckerEvents = 'SpellcheckStart SpellcheckEnd';
573
    var buildMenuItems = function (listName, languageValues) {
574
      var items = [];
637 daniel-mar 575
      global$2.each(languageValues, function (languageValue) {
597 daniel-mar 576
        items.push({
577
          selectable: true,
578
          text: languageValue.name,
579
          data: languageValue.value
580
        });
581
      });
582
      return items;
583
    };
584
    var getItems = function (editor) {
637 daniel-mar 585
      return global$2.map(getLanguages(editor).split(','), function (langPair) {
597 daniel-mar 586
        var langPairs = langPair.split('=');
587
        return {
588
          name: langPairs[0],
589
          value: langPairs[1]
590
        };
591
      });
592
    };
637 daniel-mar 593
    var register = function (editor, pluginUrl, startedState, textMatcherState, currentLanguageState, lastSuggestionsState) {
597 daniel-mar 594
      var languageMenuItems = buildMenuItems('Language', getItems(editor));
595
      var startSpellchecking = function () {
596
        spellcheck(editor, pluginUrl, startedState, textMatcherState, lastSuggestionsState, currentLanguageState);
597
      };
598
      var buttonArgs = {
599
        tooltip: 'Spellcheck',
600
        onAction: startSpellchecking,
601
        icon: 'spell-check',
602
        onSetup: function (buttonApi) {
603
          var setButtonState = function () {
604
            buttonApi.setActive(startedState.get());
605
          };
606
          editor.on(spellcheckerEvents, setButtonState);
607
          return function () {
608
            editor.off(spellcheckerEvents, setButtonState);
609
          };
610
        }
611
      };
612
      var splitButtonArgs = __assign(__assign({}, buttonArgs), {
613
        type: 'splitbutton',
614
        select: function (value) {
615
          return value === currentLanguageState.get();
616
        },
617
        fetch: function (callback) {
637 daniel-mar 618
          var items = global$2.map(languageMenuItems, function (languageItem) {
597 daniel-mar 619
            return {
620
              type: 'choiceitem',
621
              value: languageItem.data,
622
              text: languageItem.text
623
            };
624
          });
625
          callback(items);
626
        },
627
        onItemAction: function (splitButtonApi, value) {
628
          currentLanguageState.set(value);
629
        }
630
      });
631
      if (languageMenuItems.length > 1) {
632
        editor.ui.registry.addSplitButton('spellchecker', splitButtonArgs);
633
      } else {
634
        editor.ui.registry.addToggleButton('spellchecker', buttonArgs);
635
      }
636
      editor.ui.registry.addToggleMenuItem('spellchecker', {
637
        text: 'Spellcheck',
638
        icon: 'spell-check',
639
        onSetup: function (menuApi) {
640
          menuApi.setActive(startedState.get());
641
          var setMenuItemCheck = function () {
642
            menuApi.setActive(startedState.get());
643
          };
644
          editor.on(spellcheckerEvents, setMenuItemCheck);
645
          return function () {
646
            editor.off(spellcheckerEvents, setMenuItemCheck);
647
          };
648
        },
649
        onAction: startSpellchecking
650
      });
651
    };
652
 
653
    var ignoreAll = true;
654
    var getSuggestions = function (editor, pluginUrl, lastSuggestionsState, startedState, textMatcherState, currentLanguageState, word, spans) {
655
      var items = [];
656
      var suggestions = lastSuggestionsState.get().suggestions[word];
637 daniel-mar 657
      global$2.each(suggestions, function (suggestion) {
597 daniel-mar 658
        items.push({
659
          text: suggestion,
660
          onAction: function () {
661
            editor.insertContent(editor.dom.encode(suggestion));
662
            editor.dom.remove(spans);
663
            checkIfFinished(editor, startedState, textMatcherState);
664
          }
665
        });
666
      });
667
      var hasDictionarySupport = lastSuggestionsState.get().hasDictionarySupport;
668
      if (hasDictionarySupport) {
669
        items.push({ type: 'separator' });
670
        items.push({
671
          text: 'Add to dictionary',
672
          onAction: function () {
673
            addToDictionary(editor, pluginUrl, startedState, textMatcherState, currentLanguageState, word, spans);
674
          }
675
        });
676
      }
677
      items.push.apply(items, [
678
        { type: 'separator' },
679
        {
680
          text: 'Ignore',
681
          onAction: function () {
682
            ignoreWord(editor, startedState, textMatcherState, word, spans);
683
          }
684
        },
685
        {
686
          text: 'Ignore all',
687
          onAction: function () {
688
            ignoreWord(editor, startedState, textMatcherState, word, spans, ignoreAll);
689
          }
690
        }
691
      ]);
692
      return items;
693
    };
694
    var setup = function (editor, pluginUrl, lastSuggestionsState, startedState, textMatcherState, currentLanguageState) {
695
      var update = function (element) {
696
        var target = element;
697
        if (target.className === 'mce-spellchecker-word') {
698
          var spans = findSpansByIndex(editor, getElmIndex(target));
699
          if (spans.length > 0) {
700
            var rng = editor.dom.createRng();
701
            rng.setStartBefore(spans[0]);
702
            rng.setEndAfter(spans[spans.length - 1]);
703
            editor.selection.setRng(rng);
704
            return getSuggestions(editor, pluginUrl, lastSuggestionsState, startedState, textMatcherState, currentLanguageState, target.getAttribute('data-mce-word'), spans);
705
          }
706
        } else {
707
          return [];
708
        }
709
      };
710
      editor.ui.registry.addContextMenu('spellchecker', { update: update });
711
    };
712
 
713
    function Plugin () {
637 daniel-mar 714
      global$3.add('spellchecker', function (editor, pluginUrl) {
597 daniel-mar 715
        if (hasProPlugin(editor) === false) {
716
          var startedState = Cell(false);
717
          var currentLanguageState = Cell(getLanguage(editor));
718
          var textMatcherState = Cell(null);
719
          var lastSuggestionsState = Cell(null);
637 daniel-mar 720
          register(editor, pluginUrl, startedState, textMatcherState, currentLanguageState, lastSuggestionsState);
597 daniel-mar 721
          setup(editor, pluginUrl, lastSuggestionsState, startedState, textMatcherState, currentLanguageState);
637 daniel-mar 722
          register$1(editor, pluginUrl, startedState, textMatcherState, lastSuggestionsState, currentLanguageState);
597 daniel-mar 723
          return get(editor, startedState, lastSuggestionsState, textMatcherState, currentLanguageState);
724
        }
725
      });
726
    }
727
 
728
    Plugin();
729
 
730
}());