9f70284e0a26f0f0e1a71e7df7e00b4c28b494f6
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / htmlarea / plugins / SpellChecker / spell-checker.js
1 /***************************************************************
2 * Copyright notice
3 *
4 * (c) 2003 dynarch.com. Authored by Mihai Bazon, sponsored by www.americanbible.org.
5 * (c) 2004-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This script is a modified version of a script published under the htmlArea License.
26 * A copy of the htmlArea License may be found in the textfile HTMLAREA_LICENSE.txt.
27 *
28 * This copyright notice MUST APPEAR in all copies of the script!
29 ***************************************************************/
30 /*
31 * Spell Checker Plugin for TYPO3 htmlArea RTE
32 *
33 * TYPO3 SVN ID: $Id$
34 */
35 HTMLArea.SpellChecker = HTMLArea.Plugin.extend({
36 constructor: function(editor, pluginName) {
37 this.base(editor, pluginName);
38 },
39 /*
40 * This function gets called by the class constructor
41 */
42 configurePlugin: function(editor) {
43 this.pageTSconfiguration = this.editorConfiguration.buttons.spellcheck;
44 this.contentISOLanguage = this.pageTSconfiguration.contentISOLanguage;
45 this.contentCharset = this.pageTSconfiguration.contentCharset;
46 this.spellCheckerMode = this.pageTSconfiguration.spellCheckerMode;
47 this.enablePersonalDicts = this.pageTSconfiguration.enablePersonalDicts;
48 this.userUid = this.editorConfiguration.userUid;
49 this.defaultDictionary = (this.pageTSconfiguration.dictionaries && this.pageTSconfiguration.dictionaries[this.contentISOLanguage] && this.pageTSconfiguration.dictionaries[this.contentISOLanguage].defaultValue) ? this.pageTSconfiguration.dictionaries[this.contentISOLanguage].defaultValue : '';
50 this.showDictionaries = (this.pageTSconfiguration.dictionaries && this.pageTSconfiguration.dictionaries.items) ? this.pageTSconfiguration.dictionaries.items : '';
51 this.restrictToDictionaries = (this.pageTSconfiguration.dictionaries && this.pageTSconfiguration.dictionaries.restrictToItems) ? this.pageTSconfiguration.dictionaries.restrictToItems : '';
52 /*
53 * Registering plugin "About" information
54 */
55 var pluginInformation = {
56 version : '3.0',
57 developer : 'Mihai Bazon & Stanislas Rolland',
58 developerUrl : 'http://www.sjbr.ca/',
59 copyrightOwner : 'Mihai Bazon & Stanislas Rolland',
60 sponsor : 'American Bible Society & SJBR',
61 sponsorUrl : 'http://www.sjbr.ca/',
62 license : 'GPL'
63 };
64 this.registerPluginInformation(pluginInformation);
65 /*
66 * Registering the button
67 */
68 var buttonId = 'SpellCheck';
69 var buttonConfiguration = {
70 id : buttonId,
71 tooltip : this.localize('SC-spell-check'),
72 iconCls : 'htmlarea-action-spell-check',
73 action : 'onButtonPress',
74 dialog : true
75 };
76 this.registerButton(buttonConfiguration);
77 },
78 /*
79 * Sets of default configuration values for dialogue form fields
80 */
81 configDefaults: {
82 combo: {
83 editable: true,
84 selectOnFocus: true,
85 typeAhead: true,
86 triggerAction: 'all',
87 forceSelection: true,
88 mode: 'local',
89 valueField: 'value',
90 displayField: 'text',
91 helpIcon: true,
92 tpl: '<tpl for="."><div ext:qtip="{value}" style="text-align:left;font-size:11px;" class="x-combo-list-item">{text}</div></tpl>'
93 }
94 },
95 /*
96 * This function gets called when the button was pressed.
97 *
98 * @param object editor: the editor instance
99 * @param string id: the button id or the key
100 *
101 * @return boolean false if action is completed
102 */
103 onButtonPress: function (editor, id, target) {
104 // Could be a button or its hotkey
105 var buttonId = this.translateHotKey(id);
106 buttonId = buttonId ? buttonId : id;
107 // Open dialogue window
108 this.openDialogue(
109 buttonId,
110 'Spell Checker',
111 this.getWindowDimensions(
112 {
113 width: 740,
114 height: 600
115 },
116 buttonId
117 )
118 );
119 return false;
120 },
121 /*
122 * Open the dialogue window
123 *
124 * @param string buttonId: the button id
125 * @param string title: the window title
126 * @param object dimensions: the opening dimensions of the window
127 *
128 * @return void
129 */
130 openDialogue: function (buttonId, title, dimensions) {
131 this.dialog = new Ext.Window({
132 title: this.localize(title),
133 cls: 'htmlarea-window',
134 bodyCssClass: 'spell-check',
135 border: false,
136 width: dimensions.width,
137 height: 'auto',
138 // As of ExtJS 3.1, JS error with IE when the window is resizable
139 resizable: !Ext.isIE,
140 iconCls: this.getButton(buttonId).iconCls,
141 listeners: {
142 afterrender: {
143 fn: this.onWindowAfterRender,
144 scope: this
145 },
146 resize: {
147 fn: this.onWindowResize
148 },
149 close: {
150 fn: this.onClose,
151 scope: this
152 }
153 },
154 items: [{
155 // The hidden form
156 xtype: 'form',
157 method: 'POST',
158 itemId: 'spell-check-form',
159 url: this.pageTSconfiguration.path,
160 hidden: true,
161 standardSubmit: true,
162 items: [{
163 xtype: 'hidden',
164 name: 'editorId',
165 value: this.editor.editorId
166 },{
167 xtype: 'hidden',
168 itemId: 'content',
169 name: 'content',
170 value: this.editor.getHTML()
171 },{
172 xtype: 'hidden',
173 itemId: 'dictionary',
174 name: 'dictionary',
175 value: this.defaultDictionary ? this.defaultDictionary : this.contentISOLanguage
176 },{
177 xtype: 'hidden',
178 name: 'pspell_charset',
179 value: this.contentCharset
180 },{
181 xtype: 'hidden',
182 name: 'pspell_mode',
183 value: this.spellCheckerMode
184 },{
185 xtype: 'hidden',
186 name: 'userUid',
187 value: this.userUid
188 },{
189 xtype: 'hidden',
190 name:'enablePersonalDicts',
191 value: this.enablePersonalDicts
192 },{
193 xtype: 'hidden',
194 name:'showDictionaries',
195 value: this.showDictionaries
196 },{
197 xtype: 'hidden',
198 name:'restrictToDictionaries',
199 value: this.restrictToDictionaries
200 }
201 ]
202 },{
203 // The iframe
204 xtype: 'box',
205 itemId: 'spell-check-iframe',
206 width: dimensions.width - 225,
207 autoEl: {
208 name: 'contentframe',
209 tag: 'iframe',
210 cls: 'contentframe',
211 src: Ext.isGecko ? 'javascript:void(0);' : HTMLArea.editorUrl + 'popups/blank.html'
212 }
213 },{
214 // The original word
215 xtype: 'fieldset',
216 title: this.localize('Original word'),
217 cls: 'controls',
218 labelWidth: 0,
219 defaults: {
220 hideLabel: true,
221 disabled: true,
222 minWidth: 160
223 },
224 items: [{
225 xtype: 'textfield',
226 itemId: 'word',
227 disabled: false
228 },
229 this.buildButtonConfig('Revert', this.onRevertClick)
230 ]
231 },{
232 // The replacement word and actions
233 xtype: 'fieldset',
234 title: this.localize('Replacement'),
235 cls: 'controls',
236 defaultType: 'button',
237 labelWidth: 0,
238 defaults: {
239 hideLabel: true,
240 disabled: true,
241 minWidth: 160
242 },
243 items: [{
244 xtype: 'textfield',
245 disabled: false,
246 width: 160,
247 itemId: 'replacement'
248 },{
249 itemId: 'replace',
250 text: this.localize('Replace'),
251 listeners: {
252 click: {
253 fn: this.onReplaceClick,
254 scope: this
255 }
256 }
257 },{
258 itemId: 'replaceAll',
259 text: this.localize('Replace all'),
260 listeners: {
261 click: {
262 fn: this.onReplaceAllClick,
263 scope: this
264 }
265 }
266 },{
267 itemId: 'ignore',
268 text: this.localize('Ignore'),
269 listeners: {
270 click: {
271 fn: this.onIgnoreClick,
272 scope: this
273 }
274 }
275 },{
276 itemId: 'ignoreAll',
277 text: this.localize('Ignore all'),
278 listeners: {
279 click: {
280 fn: this.onIgnoreAllClick,
281 scope: this
282 }
283 }
284 },{
285 itemId: 'learn',
286 text: this.localize('Learn'),
287 hidden: !this.enablePersonalDicts,
288 listeners: {
289 click: {
290 fn: this.onLearnClick,
291 scope: this
292 }
293 }
294 }
295 ]
296 },{
297 // The suggestions
298 xtype: 'fieldset',
299 title: this.localize('Suggestions'),
300 cls: 'controls',
301 labelWidth: 0,
302 defaults: {
303 hideLabel: true,
304 minWidth: 160
305 },
306 items: [
307 Ext.apply({
308 xtype: 'combo',
309 itemId: 'suggestions',
310 store: new Ext.data.ArrayStore({
311 autoDestroy: true,
312 fields: [{name: 'text'}, {name: 'value'}],
313 data: []
314 }),
315 listeners: {
316 select: {
317 fn: this.onSuggestionSelect,
318 scope: this
319 }
320 }
321 }, this.configDefaults['combo'])
322 ]
323 },{
324 // The dictionaries
325 xtype: 'fieldset',
326 title: this.localize('Dictionary'),
327 cls: 'controls',
328 defaultType: 'button',
329 labelWidth: 0,
330 defaults: {
331 hideLabel: true,
332 disabled: true,
333 minWidth: 160
334 },
335 items: [
336 Ext.apply({
337 xtype: 'combo',
338 itemId: 'dictionaries',
339 disabled: false,
340 store: new Ext.data.ArrayStore({
341 autoDestroy: true,
342 fields: [{name: 'text'}, {name: 'value'}],
343 data: []
344 }),
345 listeners: {
346 select: {
347 fn: this.onDictionarySelect,
348 scope: this
349 }
350 }
351 }, this.configDefaults['combo']),
352 {
353 itemId: 'recheck',
354 text: this.localize('Re-check'),
355 listeners: {
356 click: {
357 fn: this.onRecheckClick,
358 scope: this
359 }
360 }
361 }
362 ]
363 }
364 ],
365 bbar: new Ext.ux.StatusBar({
366 id: this.editor.editorId + '-spell-check-status',
367 defaultText: this.localize('statusBarReady'),
368 defaultIconCls: 'status-ready',
369 text: this.localize('Please wait. Calling spell checker.'),
370 iconCls: 'status-wait',
371 defaults: {
372 minWidth: 100,
373 disabled: true
374 },
375 items: [
376 this.buildButtonConfig('OK', this.onOK),
377 this.buildButtonConfig('Info', this.onInfoClick),
378 this.buildButtonConfig('Cancel', this.onCancel)
379 ]
380 })
381 });
382 this.show();
383 },
384 /*
385 * Handler invoked after the window has been rendered
386 */
387 onWindowAfterRender: function () {
388 // True when some word has been modified
389 this.modified = false;
390 // Array of words to add to the personal dictionary
391 this.addToPersonalDictionary = [];
392 // List of word pairs to add to replacement list of the personal dictionary
393 this.addToReplacementList = [];
394 // Initial submit
395 this.dialog.getComponent('spell-check-form').getForm().getEl().set({
396 target: 'contentframe',
397 'accept-charset': this.contentCharset.toUpperCase()
398 });
399 this.dialog.getComponent('spell-check-form').getForm().submit();
400 },
401 /*
402 * Handler invoked after the window is resized
403 */
404 onWindowResize: function (window, width, height) {
405 var frame = window.getComponent('spell-check-iframe').getEl();
406 if (frame) {
407 frame.setSize(width - 225, height - 75);
408 }
409 },
410 /*
411 * Handler invoked when the OK button is pressed
412 */
413 onOK: function () {
414 if (this.modified) {
415 this.editor.setHTML(this.cleanDocument(false));
416 }
417 // Post additions to the Aspell personal dictionary
418 if ((this.addToPersonalDictionary.length || this.addToReplacementList.length) && this.enablePersonalDicts) {
419 var data = {
420 cmd: 'learn',
421 enablePersonalDicts: this.enablePersonalDicts,
422 userUid: this.userUid,
423 dictionary: this.contentISOLanguage,
424 pspell_charset: this.contentCharset,
425 pspell_mode: this.spellCheckerMode
426 };
427 Ext.each(this.addToPersonalDictionary, function (word, index) {
428 data['to_p_dict[' + index + ']'] = word;
429 });
430 Ext.each(this.addToReplacementList, function (replacement, index) {
431 data['to_r_list[' + index + '][0]'] = replacement[0];
432 data['to_r_list[' + index + '][1]'] = replacement[1];
433 });
434 this.postData(this.pageTSconfiguration.path, data);
435 }
436 this.close();
437 return false;
438 },
439 /*
440 * Handler invoked when the Cancel button is pressed
441 */
442 onCancel: function () {
443 if (this.modified) {
444 TYPO3.Dialog.QuestionDialog({
445 title: this.getButton('SpellCheck').tooltip.title,
446 msg: this.localize('QUIT_CONFIRMATION'),
447 fn: function (button) {
448 if (button == 'yes') {
449 this.close();
450 }
451 },
452 scope: this
453 });
454 return false;
455 } else {
456 return this.base();
457 }
458 },
459 /*
460 * Clean away span elements from the text before leaving or re-submitting
461 *
462 * @param boolean leaveFixed: if true, span elements of corrected words will be left in the text (re-submit case)
463 *
464 * @return string cleaned-up html
465 */
466 cleanDocument: function (leaveFixed) {
467 var iframeDocument = this.dialog.getComponent('spell-check-iframe').getEl().dom.contentWindow.document;
468 Ext.each(this.misspelledWords.concat(this.correctedWords), function (element) {
469 element.onclick = null;
470 element.onmouseover = null;
471 element.onmouseout = null;
472 if (!leaveFixed || !HTMLArea._hasClass(element, 'htmlarea-spellcheck-fixed')) {
473 element.parentNode.insertBefore(element.firstChild, element);
474 element.parentNode.removeChild(element);
475 } else {
476 HTMLArea._removeClass(element, 'htmlarea-spellcheck-error');
477 HTMLArea._removeClass(element, 'htmlarea-spellcheck-same');
478 HTMLArea._removeClass(element, 'htmlarea-spellcheck-current');
479 }
480 }, this);
481 // Cleanup event handlers on links
482 Ext.each(iframeDocument.getElementsByTagName('a'), function (link) {
483 link.onclick = null;
484 }, this);
485 return HTMLArea.getHTML(iframeDocument.body, false, this.editor);
486 },
487 /*
488 * Handler invoked when the response from the server has finished loading
489 */
490 spellCheckComplete: function () {
491 var contentWindow = this.dialog.getComponent('spell-check-iframe').getEl().dom.contentWindow;
492 this.currentElement = null;
493 // Array of misspelled words
494 this.misspelledWords = [];
495 // Array of corrected words
496 this.correctedWords = [];
497 // Object containing array of occurrences of each misspelled word
498 this.allWords = {};
499 // Suggested words
500 this.suggestedWords = contentWindow.suggestedWords;
501 // Set status
502 Ext.getCmp(this.editor.editorId + '-spell-check-status').setStatus({
503 text: this.localize('statusBarReady'),
504 iconCls: 'status-ready',
505 clear: false
506 });
507 // Process all misspelled words
508 var id = 0;
509 var self = this;
510 Ext.each(contentWindow.document.getElementsByTagName('span'), function (span) {
511 if (HTMLArea._hasClass(span, 'htmlarea-spellcheck-error')) {
512 this.misspelledWords.push(span);
513 span.onclick = function (event) { self.setCurrentWord(this, false); };
514 span.onmouseover = function (event) { HTMLArea._addClass(this, 'htmlarea-spellcheck-hover'); };
515 span.onmouseout = function (event) { HTMLArea._removeClass(this, 'htmlarea-spellcheck-hover'); };
516 span.htmlareaId = id++;
517 span.htmlareaOriginalWord = span.firstChild.data;
518 span.htmlareaFixed = false;
519 if (typeof(this.allWords[span.htmlareaOriginalWord]) == 'undefined') {
520 this.allWords[span.htmlareaOriginalWord] = [];
521 }
522 this.allWords[span.htmlareaOriginalWord].push(span);
523 } else if (HTMLArea._hasClass(span, 'htmlarea-spellcheck-fixed')) {
524 this.correctedWords.push(span);
525 }
526 }, this);
527 // Do not open links in the iframe
528 Ext.each(contentWindow.document.getElementsByTagName('a'), function (link) {
529 link.onclick = function (event) { return false; };
530 }, this);
531 // Enable buttons
532 Ext.each(this.dialog.findByType('button'), function (button) {
533 button.setDisabled(false);
534 });
535 Ext.each(Ext.getCmp(this.editor.editorId + '-spell-check-status').findByType('button'), function (button) {
536 button.setDisabled(false);
537 });
538 if (this.misspelledWords.length) {
539 // Set current element to first misspelled word
540 this.currentElement = this.misspelledWords[0];
541 this.setCurrentWord(this.currentElement, true);
542 // Populate the dictionaries combo
543 var dictionaries = contentWindow.dictionaries.split(/,/);
544 if (dictionaries.length) {
545 var select = this.dialog.find('itemId', 'dictionaries')[0];
546 var store = select.getStore();
547 store.removeAll();
548 Ext.each(dictionaries, function (dictionary) {
549 store.add(new store.recordType({
550 text: dictionary,
551 value: dictionary
552 }));
553 });
554 select.setValue(contentWindow.selectedDictionary);
555 var selectedIndex = store.find('value', contentWindow.selectedDictionary);
556 select.fireEvent('select', select, store.getAt(selectedIndex), selectedIndex);
557 }
558 } else {
559 if (!this.modified) {
560 TYPO3.Dialog.InformationDialog({
561 title: this.getButton('SpellCheck').tooltip.title,
562 msg: this.localize('NO_ERRORS_CLOSING'),
563 fn: this.onOK,
564 scope: this
565 });
566 } else {
567 TYPO3.Dialog.InformationDialog({
568 title: this.getButton('SpellCheck').tooltip.title,
569 msg: this.localize('NO_ERRORS')
570 });
571 }
572 return false;
573 }
574 },
575 /*
576 * Get absolute position of an element inside the iframe
577 */
578 getAbsolutePosition: function (element) {
579 var position = {
580 x: element.offsetLeft,
581 y: element.offsetTop
582 };
583 if (element.offsetParent) {
584 var tmp = this.getAbsolutePosition(element.offsetParent);
585 position.x += tmp.x;
586 position.y += tmp.y;
587 }
588 return position;
589 },
590 /*
591 * Update current word
592 */
593 setCurrentWord: function (element, scroll) {
594 // Scroll element into view
595 if (scroll) {
596 var frame = this.dialog.getComponent('spell-check-iframe').getEl().dom;
597 var position = this.getAbsolutePosition(element);
598 var frameSize = {
599 x: frame.offsetWidth - 4,
600 y: frame.offsetHeight - 4
601 };
602 position.x -= Math.round(frameSize.x/2);
603 if (position.x < 0) {
604 position.x = 0;
605 }
606 position.y -= Math.round(frameSize.y/2);
607 if (position.y < 0) {
608 position.y = 0;
609 }
610 frame.contentWindow.scrollTo(position.x, position.y);
611 }
612 // De-highlight all occurrences of current word
613 if (this.currentElement) {
614 HTMLArea._removeClass(this.currentElement, 'htmlarea-spellcheck-current');
615 Ext.each(this.allWords[this.currentElement.htmlareaOriginalWord], function (word) {
616 HTMLArea._removeClass(word, 'htmlarea-spellcheck-same');
617 });
618 }
619 // Highlight all occurrences of new current word
620 this.currentElement = element;
621 HTMLArea._addClass(this.currentElement, 'htmlarea-spellcheck-current');
622 var occurrences = this.allWords[this.currentElement.htmlareaOriginalWord];
623 Ext.each(occurrences, function (word) {
624 if (word != this.currentElement) {
625 HTMLArea._addClass(word, 'htmlarea-spellcheck-same');
626 }
627 }, this);
628 this.dialog.find('itemId', 'replaceAll')[0].setDisabled(occurrences.length <= 1);
629 this.dialog.find('itemId', 'ignoreAll')[0].setDisabled(occurrences.length <= 1);
630 // Display status
631 var txt;
632 var txt2;
633 if (occurrences.length == 1) {
634 txt = this.localize('One occurrence');
635 txt2 = this.localize('was found.');
636 } else if (occurrences.length == 2) {
637 txt = this.localize('Two occurrences');
638 txt2 = this.localize('were found.');
639 } else {
640 txt = occurrences.length + ' ' + this.localize('occurrences');
641 txt2 = this.localize('were found.');
642 }
643 Ext.getCmp(this.editor.editorId + '-spell-check-status').setStatus({
644 text: txt + ' ' + this.localize('of the word') + ' "<b>' + this.currentElement.htmlareaOriginalWord + '</b>" ' + txt2,
645 iconCls: 'status-info',
646 clear: false
647 });
648 // Update suggestions
649 var suggestions = this.suggestedWords[this.currentElement.htmlareaOriginalWord];
650 if (suggestions) {
651 suggestions = suggestions.split(/,/);
652 } else {
653 suggestions = [];
654 }
655 var select = this.dialog.find('itemId', 'suggestions')[0];
656 var store = select.getStore();
657 store.removeAll();
658 Ext.each(suggestions, function (suggestion) {
659 store.add(new store.recordType({
660 text: suggestion,
661 value: suggestion
662 }));
663 });
664 // Update the current word
665 this.dialog.find('itemId', 'word')[0].setValue(this.currentElement.htmlareaOriginalWord);
666 if (suggestions.length > 0) {
667 select.setValue(store.getAt(0).get('value'));
668 select.fireEvent('select', select, store.getAt(0), 0);
669 } else {
670 this.dialog.find('itemId', 'replacement')[0].setValue(this.currentElement.innerHTML);
671 }
672 return false;
673 },
674 /*
675 * Handler invoked when the mouse moves over a misspelled word
676 */
677 onWordMouseOver: function (event, element) {
678 HTMLArea._addClass(element, 'htmlarea-spellcheck-hover');
679 },
680 /*
681 * Handler invoked when the mouse moves out of a misspelled word
682 */
683 onWordMouseOut: function (event, element) {
684 HTMLArea._removeClass(element, 'htmlarea-spellcheck-hover');
685 },
686 /*
687 * Handler invoked when a suggestion is selected
688 */
689 onSuggestionSelect: function (select, record, index) {
690 this.dialog.find('itemId', 'replacement')[0].setValue(record.get('value'));
691 },
692 /*
693 * Handler invoked when a dictionary is selected
694 */
695 onDictionarySelect: function (select, record, index) {
696 this.dialog.find('itemId', 'dictionary')[0].setValue(record.get('value'));
697 },
698 /*
699 * Handler invoked when the Revert button is clicked
700 */
701 onRevertClick: function () {
702 this.dialog.find('itemId', 'replacement')[0].setValue(this.currentElement.htmlareaOriginalWord);
703 this.replaceWord(this.currentElement);
704 HTMLArea._removeClass(this.currentElement, 'htmlarea-spellcheck-fixed');
705 HTMLArea._addClass(this.currentElement, 'htmlarea-spellcheck-error');
706 HTMLArea._addClass(this.currentElement, 'htmlarea-spellcheck-current');
707 return false;
708 },
709 /*
710 * Replace the word contained in the element
711 */
712 replaceWord: function (element) {
713 HTMLArea._removeClass(element, 'htmlarea-spellcheck-hover');
714 HTMLArea._addClass(element, 'htmlarea-spellcheck-fixed');
715 element.htmlareaFixed = true;
716 var replacement = this.dialog.find('itemId', 'replacement')[0].getValue();
717 if (element.innerHTML != replacement) {
718 this.addToReplacementList.push([element.innerHTML, replacement]);
719 element.innerHTML = replacement;
720 this.modified = true;
721 }
722 },
723 /*
724 * Handler invoked when the Replace button is clicked
725 */
726 onReplaceClick: function () {
727 this.replaceWord(this.currentElement);
728 var start = this.currentElement.htmlareaId;
729 var index = start;
730 do {
731 ++index;
732 if (index == this.misspelledWords.length) {
733 index = 0;
734 }
735 } while (index != start && this.misspelledWords[index].htmlareaFixed);
736 if (index == start) {
737 index = 0;
738 TYPO3.Dialog.InformationDialog({
739 title: this.getButton('SpellCheck').tooltip.title,
740 msg: this.localize('Finished list of mispelled words')
741 });
742 }
743 this.setCurrentWord(this.misspelledWords[index], true);
744 return false;
745 },
746 /*
747 * Handler invoked when the Replace all button is clicked
748 */
749 onReplaceAllClick: function () {
750 Ext.each(this.allWords[this.currentElement.htmlareaOriginalWord], function (element) {
751 if (element != this.currentElement) {
752 this.replaceWord(element);
753 }
754 }, this);
755 // Replace current element last, so that we jump to the next word
756 return this.onReplaceClick();
757 },
758 /*
759 * Handler invoked when the Ignore button is clicked
760 */
761 onIgnoreClick: function () {
762 this.dialog.find('itemId', 'replacement')[0].setValue(this.currentElement.htmlareaOriginalWord);
763 return this.onReplaceClick();
764 },
765 /*
766 * Handler invoked when the Ignore all button is clicked
767 */
768 onIgnoreAllClick: function () {
769 this.dialog.find('itemId', 'replacement')[0].setValue(this.currentElement.htmlareaOriginalWord);
770 return this.onReplaceAllClick();
771 },
772 /*
773 * Handler invoked when the Learn button is clicked
774 */
775 onLearnClick: function () {
776 this.addToPersonalDictionary.push(this.currentElement.htmlareaOriginalWord);
777 return this.onIgnoreAllClick();
778 },
779 /*
780 * Handler invoked when the Re-check button is clicked
781 */
782 onRecheckClick: function () {
783 // Disable buttons
784 Ext.each(this.dialog.findByType('button'), function (button) {
785 button.setDisabled(true);
786 });
787 Ext.each(Ext.getCmp(this.editor.editorId + '-spell-check-status').findByType('button'), function (button) {
788 button.setDisabled(true);
789 });
790 Ext.getCmp(this.editor.editorId + '-spell-check-status').setStatus({
791 text: this.localize('Please wait: changing dictionary to') + ': "' + this.dialog.find('itemId', 'dictionary')[0].getValue() + '".',
792 iconCls: 'status-wait',
793 clear: false
794 });
795 this.dialog.find('itemId', 'content')[0].setValue(this.cleanDocument(true));
796 this.dialog.getComponent('spell-check-form').getForm().submit();
797 },
798 /*
799 * Handler invoked when the Info button is clicked
800 */
801 onInfoClick: function () {
802 var info = this.dialog.getComponent('spell-check-iframe').getEl().dom.contentWindow.spellcheckInfo;
803 if (!info) {
804 TYPO3.Dialog.InformationDialog({
805 title: this.getButton('SpellCheck').tooltip.title,
806 msg: this.localize('No information available')
807 });
808 } else {
809 var txt = '';
810 Ext.iterate(info, function (key, value) {
811 txt += (txt ? '<br />' : '') + this.localize(key) + ': ' + value;
812 }, this);
813 txt += ' ' + this.localize('seconds');
814 TYPO3.Dialog.InformationDialog({
815 title: this.localize('Document information'),
816 msg: txt
817 });
818 }
819 return false;
820 }
821 });