015309d73494cbd88f4a98c6297a3d4798a8ecbf
[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 Ext.MessageBox.confirm('', this.localize('QUIT_CONFIRMATION'), function (button) {
445 if (button == 'yes') {
446 this.close();
447 }
448 }, this);
449 return false;
450 } else {
451 return this.base();
452 }
453 },
454 /*
455 * Clean away span elements from the text before leaving or re-submitting
456 *
457 * @param boolean leaveFixed: if true, span elements of corrected words will be left in the text (re-submit case)
458 *
459 * @return string cleaned-up html
460 */
461 cleanDocument: function (leaveFixed) {
462 var iframeDocument = this.dialog.getComponent('spell-check-iframe').getEl().dom.contentWindow.document;
463 Ext.each(this.misspelledWords.concat(this.correctedWords), function (element) {
464 element.onclick = null;
465 element.onmouseover = null;
466 element.onmouseout = null;
467 if (!leaveFixed || !HTMLArea._hasClass(element, 'htmlarea-spellcheck-fixed')) {
468 element.parentNode.insertBefore(element.firstChild, element);
469 element.parentNode.removeChild(element);
470 } else {
471 HTMLArea._removeClass(element, 'htmlarea-spellcheck-error');
472 HTMLArea._removeClass(element, 'htmlarea-spellcheck-same');
473 HTMLArea._removeClass(element, 'htmlarea-spellcheck-current');
474 }
475 }, this);
476 // Cleanup event handlers on links
477 Ext.each(iframeDocument.getElementsByTagName('a'), function (link) {
478 link.onclick = null;
479 }, this);
480 return HTMLArea.getHTML(iframeDocument.body, false, this.editor);
481 },
482 /*
483 * Handler invoked when the response from the server has finished loading
484 */
485 spellCheckComplete: function () {
486 var contentWindow = this.dialog.getComponent('spell-check-iframe').getEl().dom.contentWindow;
487 this.currentElement = null;
488 // Array of misspelled words
489 this.misspelledWords = [];
490 // Array of corrected words
491 this.correctedWords = [];
492 // Object containing array of occurrences of each misspelled word
493 this.allWords = {};
494 // Suggested words
495 this.suggestedWords = contentWindow.suggestedWords;
496 // Set status
497 Ext.getCmp(this.editor.editorId + '-spell-check-status').setStatus({
498 text: this.localize('statusBarReady'),
499 iconCls: 'status-ready',
500 clear: false
501 });
502 // Process all misspelled words
503 var id = 0;
504 var self = this;
505 Ext.each(contentWindow.document.getElementsByTagName('span'), function (span) {
506 if (HTMLArea._hasClass(span, 'htmlarea-spellcheck-error')) {
507 this.misspelledWords.push(span);
508 span.onclick = function (event) { self.setCurrentWord(this, false); };
509 span.onmouseover = function (event) { HTMLArea._addClass(this, 'htmlarea-spellcheck-hover'); };
510 span.onmouseout = function (event) { HTMLArea._removeClass(this, 'htmlarea-spellcheck-hover'); };
511 span.htmlareaId = id++;
512 span.htmlareaOriginalWord = span.firstChild.data;
513 span.htmlareaFixed = false;
514 if (typeof(this.allWords[span.htmlareaOriginalWord]) == 'undefined') {
515 this.allWords[span.htmlareaOriginalWord] = [];
516 }
517 this.allWords[span.htmlareaOriginalWord].push(span);
518 } else if (HTMLArea._hasClass(span, 'htmlarea-spellcheck-fixed')) {
519 this.correctedWords.push(span);
520 }
521 }, this);
522 // Do not open links in the iframe
523 Ext.each(contentWindow.document.getElementsByTagName('a'), function (link) {
524 link.onclick = function (event) { return false; };
525 }, this);
526 // Enable buttons
527 Ext.each(this.dialog.findByType('button'), function (button) {
528 button.setDisabled(false);
529 });
530 Ext.each(Ext.getCmp(this.editor.editorId + '-spell-check-status').findByType('button'), function (button) {
531 button.setDisabled(false);
532 });
533 if (this.misspelledWords.length) {
534 // Set current element to first misspelled word
535 this.currentElement = this.misspelledWords[0];
536 this.setCurrentWord(this.currentElement, true);
537 // Populate the dictionaries combo
538 var dictionaries = contentWindow.dictionaries.split(/,/);
539 if (dictionaries.length) {
540 var select = this.dialog.find('itemId', 'dictionaries')[0];
541 var store = select.getStore();
542 store.removeAll();
543 Ext.each(dictionaries, function (dictionary) {
544 store.add(new store.recordType({
545 text: dictionary,
546 value: dictionary
547 }));
548 });
549 select.setValue(contentWindow.selectedDictionary);
550 var selectedIndex = store.find('value', contentWindow.selectedDictionary);
551 select.fireEvent('select', select, store.getAt(selectedIndex), selectedIndex);
552 }
553 } else {
554 if (!this.modified) {
555 Ext.MessageBox.alert('', this.localize('NO_ERRORS_CLOSING'));
556 this.onOK();
557 } else {
558 Ext.MessageBox.alert('', this.localize('NO_ERRORS'));
559 }
560 return false;
561 }
562 },
563 /*
564 * Get absolute position of an element inside the iframe
565 */
566 getAbsolutePosition: function (element) {
567 var position = {
568 x: element.offsetLeft,
569 y: element.offsetTop
570 };
571 if (element.offsetParent) {
572 var tmp = this.getAbsolutePosition(element.offsetParent);
573 position.x += tmp.x;
574 position.y += tmp.y;
575 }
576 return position;
577 },
578 /*
579 * Update current word
580 */
581 setCurrentWord: function (element, scroll) {
582 // Scroll element into view
583 if (scroll) {
584 var frame = this.dialog.getComponent('spell-check-iframe').getEl().dom;
585 var position = this.getAbsolutePosition(element);
586 var frameSize = {
587 x: frame.offsetWidth - 4,
588 y: frame.offsetHeight - 4
589 };
590 position.x -= Math.round(frameSize.x/2);
591 if (position.x < 0) {
592 position.x = 0;
593 }
594 position.y -= Math.round(frameSize.y/2);
595 if (position.y < 0) {
596 position.y = 0;
597 }
598 frame.contentWindow.scrollTo(position.x, position.y);
599 }
600 // De-highlight all occurrences of current word
601 if (this.currentElement) {
602 HTMLArea._removeClass(this.currentElement, 'htmlarea-spellcheck-current');
603 Ext.each(this.allWords[this.currentElement.htmlareaOriginalWord], function (word) {
604 HTMLArea._removeClass(word, 'htmlarea-spellcheck-same');
605 });
606 }
607 // Highlight all occurrences of new current word
608 this.currentElement = element;
609 HTMLArea._addClass(this.currentElement, 'htmlarea-spellcheck-current');
610 var occurrences = this.allWords[this.currentElement.htmlareaOriginalWord];
611 Ext.each(occurrences, function (word) {
612 if (word != this.currentElement) {
613 HTMLArea._addClass(word, 'htmlarea-spellcheck-same');
614 }
615 }, this);
616 this.dialog.find('itemId', 'replaceAll')[0].setDisabled(occurrences.length <= 1);
617 this.dialog.find('itemId', 'ignoreAll')[0].setDisabled(occurrences.length <= 1);
618 // Display status
619 var txt;
620 var txt2;
621 if (occurrences.length == 1) {
622 txt = this.localize('One occurrence');
623 txt2 = this.localize('was found.');
624 } else if (occurrences.length == 2) {
625 txt = this.localize('Two occurrences');
626 txt2 = this.localize('were found.');
627 } else {
628 txt = occurrences.length + ' ' + this.localize('occurrences');
629 txt2 = this.localize('were found.');
630 }
631 Ext.getCmp(this.editor.editorId + '-spell-check-status').setStatus({
632 text: txt + ' ' + this.localize('of the word') + ' "<b>' + this.currentElement.htmlareaOriginalWord + '</b>" ' + txt2,
633 iconCls: 'status-info',
634 clear: false
635 });
636 // Update suggestions
637 var suggestions = this.suggestedWords[this.currentElement.htmlareaOriginalWord];
638 if (suggestions) {
639 suggestions = suggestions.split(/,/);
640 } else {
641 suggestions = [];
642 }
643 var select = this.dialog.find('itemId', 'suggestions')[0];
644 var store = select.getStore();
645 store.removeAll();
646 Ext.each(suggestions, function (suggestion) {
647 store.add(new store.recordType({
648 text: suggestion,
649 value: suggestion
650 }));
651 });
652 // Update the current word
653 this.dialog.find('itemId', 'word')[0].setValue(this.currentElement.htmlareaOriginalWord);
654 if (suggestions.length > 0) {
655 select.setValue(store.getAt(0).get('value'));
656 select.fireEvent('select', select, store.getAt(0), 0);
657 } else {
658 this.dialog.find('itemId', 'replacement')[0].setValue(this.currentElement.innerHTML);
659 }
660 return false;
661 },
662 /*
663 * Handler invoked when the mouse moves over a misspelled word
664 */
665 onWordMouseOver: function (event, element) {
666 HTMLArea._addClass(element, 'htmlarea-spellcheck-hover');
667 },
668 /*
669 * Handler invoked when the mouse moves out of a misspelled word
670 */
671 onWordMouseOut: function (event, element) {
672 HTMLArea._removeClass(element, 'htmlarea-spellcheck-hover');
673 },
674 /*
675 * Handler invoked when a suggestion is selected
676 */
677 onSuggestionSelect: function (select, record, index) {
678 this.dialog.find('itemId', 'replacement')[0].setValue(record.get('value'));
679 },
680 /*
681 * Handler invoked when a dictionary is selected
682 */
683 onDictionarySelect: function (select, record, index) {
684 this.dialog.find('itemId', 'dictionary')[0].setValue(record.get('value'));
685 },
686 /*
687 * Handler invoked when the Revert button is clicked
688 */
689 onRevertClick: function () {
690 this.dialog.find('itemId', 'replacement')[0].setValue(this.currentElement.htmlareaOriginalWord);
691 this.replaceWord(this.currentElement);
692 HTMLArea._removeClass(this.currentElement, 'htmlarea-spellcheck-fixed');
693 HTMLArea._addClass(this.currentElement, 'htmlarea-spellcheck-error');
694 HTMLArea._addClass(this.currentElement, 'htmlarea-spellcheck-current');
695 return false;
696 },
697 /*
698 * Replace the word contained in the element
699 */
700 replaceWord: function (element) {
701 HTMLArea._removeClass(element, 'htmlarea-spellcheck-hover');
702 HTMLArea._addClass(element, 'htmlarea-spellcheck-fixed');
703 element.htmlareaFixed = true;
704 var replacement = this.dialog.find('itemId', 'replacement')[0].getValue();
705 if (element.innerHTML != replacement) {
706 this.addToReplacementList.push([element.innerHTML, replacement]);
707 element.innerHTML = replacement;
708 this.modified = true;
709 }
710 },
711 /*
712 * Handler invoked when the Replace button is clicked
713 */
714 onReplaceClick: function () {
715 this.replaceWord(this.currentElement);
716 var start = this.currentElement.htmlareaId;
717 var index = start;
718 do {
719 ++index;
720 if (index == this.misspelledWords.length) {
721 index = 0;
722 }
723 } while (index != start && this.misspelledWords[index].htmlareaFixed);
724 if (index == start) {
725 index = 0;
726 Ext.MessageBox.alert('', this.localize('Finished list of mispelled words'));
727 }
728 this.setCurrentWord(this.misspelledWords[index], true);
729 return false;
730 },
731 /*
732 * Handler invoked when the Replace all button is clicked
733 */
734 onReplaceAllClick: function () {
735 Ext.each(this.allWords[this.currentElement.htmlareaOriginalWord], function (element) {
736 if (element != this.currentElement) {
737 this.replaceWord(element);
738 }
739 }, this);
740 // Replace current element last, so that we jump to the next word
741 return this.onReplaceClick();
742 },
743 /*
744 * Handler invoked when the Ignore button is clicked
745 */
746 onIgnoreClick: function () {
747 this.dialog.find('itemId', 'replacement')[0].setValue(this.currentElement.htmlareaOriginalWord);
748 return this.onReplaceClick();
749 },
750 /*
751 * Handler invoked when the Ignore all button is clicked
752 */
753 onIgnoreAllClick: function () {
754 this.dialog.find('itemId', 'replacement')[0].setValue(this.currentElement.htmlareaOriginalWord);
755 return this.onReplaceAllClick();
756 },
757 /*
758 * Handler invoked when the Learn button is clicked
759 */
760 onLearnClick: function () {
761 this.addToPersonalDictionary.push(this.currentElement.htmlareaOriginalWord);
762 return this.onIgnoreAllClick();
763 },
764 /*
765 * Handler invoked when the Re-check button is clicked
766 */
767 onRecheckClick: function () {
768 // Disable buttons
769 Ext.each(this.dialog.findByType('button'), function (button) {
770 button.setDisabled(true);
771 });
772 Ext.each(Ext.getCmp(this.editor.editorId + '-spell-check-status').findByType('button'), function (button) {
773 button.setDisabled(true);
774 });
775 Ext.getCmp(this.editor.editorId + '-spell-check-status').setStatus({
776 text: this.localize('Please wait: changing dictionary to') + ': "' + this.dialog.find('itemId', 'dictionary')[0].getValue() + '".',
777 iconCls: 'status-wait',
778 clear: false
779 });
780 this.dialog.find('itemId', 'content')[0].setValue(this.cleanDocument(true));
781 this.dialog.getComponent('spell-check-form').getForm().submit();
782 },
783 /*
784 * Handler invoked when the Info button is clicked
785 */
786 onInfoClick: function () {
787 var info = this.dialog.getComponent('spell-check-iframe').getEl().dom.contentWindow.spellcheckInfo;
788 if (!info) {
789 Ext.MessageBox.alert('', this.localize('No information available'));
790 } else {
791 var txt = this.localize('Document information') + '<br />';
792 Ext.iterate(info, function (key, value) {
793 txt += '<br />' + this.localize(key) + ': ' + value;
794 }, this);
795 txt += ' ' + this.localize('seconds');
796 Ext.MessageBox.alert('', txt);
797 }
798 return false;
799 }
800 });