Subversion Repositories oidplus

Rev

Rev 1042 | Go to most recent revision | View as "text/javascript" | Blame | Compare with Previous | Last modification | View Log | RSS feed

  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.  *
  7.  * Version: 5.10.8 (2023-10-19)
  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.  
  26.     var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager');
  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.  
  49.     var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools');
  50.  
  51.     var global$1 = tinymce.util.Tools.resolve('tinymce.util.URI');
  52.  
  53.     var global = tinymce.util.Tools.resolve('tinymce.util.XHR');
  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.         }
  111.         var txt = '';
  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);
  194.           clone.setAttribute('data-mce-index', '' + matchIndex);
  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;
  386.         global$2.each(data, function (value, key) {
  387.           if (postData) {
  388.             postData += '&';
  389.           }
  390.           postData += key + '=' + encodeURIComponent(value);
  391.         });
  392.         global.send({
  393.           url: new global$1(pluginUrl).toAbsolute(getRpcUrl(editor)),
  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) {
  461.         global$2.each(editor.dom.select('span.mce-spellchecker-word'), function (span) {
  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 = [];
  491.       var nodes = global$2.toArray(editor.getBody().getElementsByTagName('span'));
  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.  
  538.     var get = function (editor, startedState, lastSuggestionsState, textMatcherState, currentLanguageState) {
  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.  
  553.     var register$1 = function (editor, pluginUrl, startedState, textMatcherState, lastSuggestionsState, currentLanguageState) {
  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 = [];
  575.       global$2.each(languageValues, function (languageValue) {
  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) {
  585.       return global$2.map(getLanguages(editor).split(','), function (langPair) {
  586.         var langPairs = langPair.split('=');
  587.         return {
  588.           name: langPairs[0],
  589.           value: langPairs[1]
  590.         };
  591.       });
  592.     };
  593.     var register = function (editor, pluginUrl, startedState, textMatcherState, currentLanguageState, lastSuggestionsState) {
  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) {
  618.           var items = global$2.map(languageMenuItems, function (languageItem) {
  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];
  657.       global$2.each(suggestions, function (suggestion) {
  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 () {
  714.       global$3.add('spellchecker', function (editor, pluginUrl) {
  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);
  720.           register(editor, pluginUrl, startedState, textMatcherState, currentLanguageState, lastSuggestionsState);
  721.           setup(editor, pluginUrl, lastSuggestionsState, startedState, textMatcherState, currentLanguageState);
  722.           register$1(editor, pluginUrl, startedState, textMatcherState, lastSuggestionsState, currentLanguageState);
  723.           return get(editor, startedState, lastSuggestionsState, textMatcherState, currentLanguageState);
  724.         }
  725.       });
  726.     }
  727.  
  728.     Plugin();
  729.  
  730. }());
  731.