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 | }()); |