summaryrefslogtreecommitdiff
path: root/httemplate/elements/fckeditor/editor/dialog/fck_spellerpages/spellerpages/spellChecker.js
blob: b5e55b74b95dc8eae4515ce1d9b66d3b2303bf0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
////////////////////////////////////////////////////
// spellChecker.js
//
// spellChecker object
//
// This file is sourced on web pages that have a textarea object to evaluate
// for spelling. It includes the implementation for the spellCheckObject.
//
////////////////////////////////////////////////////


// constructor
function spellChecker( textObject ) {

	// public properties - configurable
//	this.popUpUrl = '/speller/spellchecker.html';							// by FredCK
	this.popUpUrl = 'fck_spellerpages/spellerpages/spellchecker.html';		// by FredCK
	this.popUpName = 'spellchecker';
//	this.popUpProps = "menu=no,width=440,height=350,top=70,left=120,resizable=yes,status=yes";	// by FredCK
	this.popUpProps = null ;																	// by FredCK
//	this.spellCheckScript = '/speller/server-scripts/spellchecker.php';		// by FredCK
	//this.spellCheckScript = '/cgi-bin/spellchecker.pl';

	// values used to keep track of what happened to a word
	this.replWordFlag = "R";	// single replace
	this.ignrWordFlag = "I";	// single ignore
	this.replAllFlag = "RA";	// replace all occurances
	this.ignrAllFlag = "IA";	// ignore all occurances
	this.fromReplAll = "~RA";	// an occurance of a "replace all" word
	this.fromIgnrAll = "~IA";	// an occurance of a "ignore all" word
	// properties set at run time
	this.wordFlags = new Array();
	this.currentTextIndex = 0;
	this.currentWordIndex = 0;
	this.spellCheckerWin = null;
	this.controlWin = null;
	this.wordWin = null;
	this.textArea = textObject;	// deprecated
	this.textInputs = arguments;

	// private methods
	this._spellcheck = _spellcheck;
	this._getSuggestions = _getSuggestions;
	this._setAsIgnored = _setAsIgnored;
	this._getTotalReplaced = _getTotalReplaced;
	this._setWordText = _setWordText;
	this._getFormInputs = _getFormInputs;

	// public methods
	this.openChecker = openChecker;
	this.startCheck = startCheck;
	this.checkTextBoxes = checkTextBoxes;
	this.checkTextAreas = checkTextAreas;
	this.spellCheckAll = spellCheckAll;
	this.ignoreWord = ignoreWord;
	this.ignoreAll = ignoreAll;
	this.replaceWord = replaceWord;
	this.replaceAll = replaceAll;
	this.terminateSpell = terminateSpell;
	this.undo = undo;

	// set the current window's "speller" property to the instance of this class.
	// this object can now be referenced by child windows/frames.
	window.speller = this;
}

// call this method to check all text boxes (and only text boxes) in the HTML document
function checkTextBoxes() {
	this.textInputs = this._getFormInputs( "^text$" );
	this.openChecker();
}

// call this method to check all textareas (and only textareas ) in the HTML document
function checkTextAreas() {
	this.textInputs = this._getFormInputs( "^textarea$" );
	this.openChecker();
}

// call this method to check all text boxes and textareas in the HTML document
function spellCheckAll() {
	this.textInputs = this._getFormInputs( "^text(area)?$" );
	this.openChecker();
}

// call this method to check text boxe(s) and/or textarea(s) that were passed in to the
// object's constructor or to the textInputs property
function openChecker() {
	this.spellCheckerWin = window.open( this.popUpUrl, this.popUpName, this.popUpProps );
	if( !this.spellCheckerWin.opener ) {
		this.spellCheckerWin.opener = window;
	}
}

function startCheck( wordWindowObj, controlWindowObj ) {

	// set properties from args
	this.wordWin = wordWindowObj;
	this.controlWin = controlWindowObj;

	// reset properties
	this.wordWin.resetForm();
	this.controlWin.resetForm();
	this.currentTextIndex = 0;
	this.currentWordIndex = 0;
	// initialize the flags to an array - one element for each text input
	this.wordFlags = new Array( this.wordWin.textInputs.length );
	// each element will be an array that keeps track of each word in the text
	for( var i=0; i<this.wordFlags.length; i++ ) {
		this.wordFlags[i] = [];
	}

	// start
	this._spellcheck();

	return true;
}

function ignoreWord() {
	var wi = this.currentWordIndex;
	var ti = this.currentTextIndex;
	if( !this.wordWin ) {
		alert( 'Error: Word frame not available.' );
		return false;
	}
	if( !this.wordWin.getTextVal( ti, wi )) {
		alert( 'Error: "Not in dictionary" text is missing.' );
		return false;
	}
	// set as ignored
	if( this._setAsIgnored( ti, wi, this.ignrWordFlag )) {
		this.currentWordIndex++;
		this._spellcheck();
	}
	return true;
}

function ignoreAll() {
	var wi = this.currentWordIndex;
	var ti = this.currentTextIndex;
	if( !this.wordWin ) {
		alert( 'Error: Word frame not available.' );
		return false;
	}
	// get the word that is currently being evaluated.
	var s_word_to_repl = this.wordWin.getTextVal( ti, wi );
	if( !s_word_to_repl ) {
		alert( 'Error: "Not in dictionary" text is missing' );
		return false;
	}

	// set this word as an "ignore all" word.
	this._setAsIgnored( ti, wi, this.ignrAllFlag );

	// loop through all the words after this word
	for( var i = ti; i < this.wordWin.textInputs.length; i++ ) {
		for( var j = 0; j < this.wordWin.totalWords( i ); j++ ) {
			if(( i == ti && j > wi ) || i > ti ) {
				// future word: set as "from ignore all" if
				// 1) do not already have a flag and
				// 2) have the same value as current word
				if(( this.wordWin.getTextVal( i, j ) == s_word_to_repl )
				&& ( !this.wordFlags[i][j] )) {
					this._setAsIgnored( i, j, this.fromIgnrAll );
				}
			}
		}
	}

	// finally, move on
	this.currentWordIndex++;
	this._spellcheck();
	return true;
}

function replaceWord() {
	var wi = this.currentWordIndex;
	var ti = this.currentTextIndex;
	if( !this.wordWin ) {
		alert( 'Error: Word frame not available.' );
		return false;
	}
	if( !this.wordWin.getTextVal( ti, wi )) {
		alert( 'Error: "Not in dictionary" text is missing' );
		return false;
	}
	if( !this.controlWin.replacementText ) {
		return false ;
	}
	var txt = this.controlWin.replacementText;
	if( txt.value ) {
		var newspell = new String( txt.value );
		if( this._setWordText( ti, wi, newspell, this.replWordFlag )) {
			this.currentWordIndex++;
			this._spellcheck();
		}
	}
	return true;
}

function replaceAll() {
	var ti = this.currentTextIndex;
	var wi = this.currentWordIndex;
	if( !this.wordWin ) {
		alert( 'Error: Word frame not available.' );
		return false;
	}
	var s_word_to_repl = this.wordWin.getTextVal( ti, wi );
	if( !s_word_to_repl ) {
		alert( 'Error: "Not in dictionary" text is missing' );
		return false;
	}
	var txt = this.controlWin.replacementText;
	if( !txt.value ) return false;
	var newspell = new String( txt.value );

	// set this word as a "replace all" word.
	this._setWordText( ti, wi, newspell, this.replAllFlag );

	// loop through all the words after this word
	for( var i = ti; i < this.wordWin.textInputs.length; i++ ) {
		for( var j = 0; j < this.wordWin.totalWords( i ); j++ ) {
			if(( i == ti && j > wi ) || i > ti ) {
				// future word: set word text to s_word_to_repl if
				// 1) do not already have a flag and
				// 2) have the same value as s_word_to_repl
				if(( this.wordWin.getTextVal( i, j ) == s_word_to_repl )
				&& ( !this.wordFlags[i][j] )) {
					this._setWordText( i, j, newspell, this.fromReplAll );
				}
			}
		}
	}

	// finally, move on
	this.currentWordIndex++;
	this._spellcheck();
	return true;
}

function terminateSpell() {
	// called when we have reached the end of the spell checking.
	var msg = "";		// by FredCK
	var numrepl = this._getTotalReplaced();
	if( numrepl == 0 ) {
		// see if there were no misspellings to begin with
		if( !this.wordWin ) {
			msg = "";
		} else {
			if( this.wordWin.totalMisspellings() ) {
//				msg += "No words changed.";			// by FredCK
				msg += FCKLang.DlgSpellNoChanges ;	// by FredCK
			} else {
//				msg += "No misspellings found.";	// by FredCK
				msg += FCKLang.DlgSpellNoMispell ;	// by FredCK
			}
		}
	} else if( numrepl == 1 ) {
//		msg += "One word changed.";			// by FredCK
		msg += FCKLang.DlgSpellOneChange ;	// by FredCK
	} else {
//		msg += numrepl + " words changed.";	// by FredCK
		msg += FCKLang.DlgSpellManyChanges.replace( /%1/g, numrepl ) ;
	}
	if( msg ) {
//		msg += "\n";	// by FredCK
		alert( msg );
	}

	if( numrepl > 0 ) {
		// update the text field(s) on the opener window
		for( var i = 0; i < this.textInputs.length; i++ ) {
			// this.textArea.value = this.wordWin.text;
			if( this.wordWin ) {
				if( this.wordWin.textInputs[i] ) {
					this.textInputs[i].value = this.wordWin.textInputs[i];
				}
			}
		}
	}

	// return back to the calling window
//	this.spellCheckerWin.close();					// by FredCK
	if ( typeof( this.OnFinished ) == 'function' )	// by FredCK
		this.OnFinished(numrepl) ;					// by FredCK

	return true;
}

function undo() {
	// skip if this is the first word!
	var ti = this.currentTextIndex;
	var wi = this.currentWordIndex;

	if( this.wordWin.totalPreviousWords( ti, wi ) > 0 ) {
		this.wordWin.removeFocus( ti, wi );

		// go back to the last word index that was acted upon
		do {
			// if the current word index is zero then reset the seed
			if( this.currentWordIndex == 0 && this.currentTextIndex > 0 ) {
				this.currentTextIndex--;
				this.currentWordIndex = this.wordWin.totalWords( this.currentTextIndex )-1;
				if( this.currentWordIndex < 0 ) this.currentWordIndex = 0;
			} else {
				if( this.currentWordIndex > 0 ) {
					this.currentWordIndex--;
				}
			}
		} while (
			this.wordWin.totalWords( this.currentTextIndex ) == 0
			|| this.wordFlags[this.currentTextIndex][this.currentWordIndex] == this.fromIgnrAll
			|| this.wordFlags[this.currentTextIndex][this.currentWordIndex] == this.fromReplAll
		);

		var text_idx = this.currentTextIndex;
		var idx = this.currentWordIndex;
		var preReplSpell = this.wordWin.originalSpellings[text_idx][idx];

		// if we got back to the first word then set the Undo button back to disabled
		if( this.wordWin.totalPreviousWords( text_idx, idx ) == 0 ) {
			this.controlWin.disableUndo();
		}

		var i, j, origSpell ;
		// examine what happened to this current word.
		switch( this.wordFlags[text_idx][idx] ) {
			// replace all: go through this and all the future occurances of the word
			// and revert them all to the original spelling and clear their flags
			case this.replAllFlag :
				for( i = text_idx; i < this.wordWin.textInputs.length; i++ ) {
					for( j = 0; j < this.wordWin.totalWords( i ); j++ ) {
						if(( i == text_idx && j >= idx ) || i > text_idx ) {
							origSpell = this.wordWin.originalSpellings[i][j];
							if( origSpell == preReplSpell ) {
								this._setWordText ( i, j, origSpell, undefined );
							}
						}
					}
				}
				break;

			// ignore all: go through all the future occurances of the word
			// and clear their flags
			case this.ignrAllFlag :
				for( i = text_idx; i < this.wordWin.textInputs.length; i++ ) {
					for( j = 0; j < this.wordWin.totalWords( i ); j++ ) {
						if(( i == text_idx && j >= idx ) || i > text_idx ) {
							origSpell = this.wordWin.originalSpellings[i][j];
							if( origSpell == preReplSpell ) {
								this.wordFlags[i][j] = undefined;
							}
						}
					}
				}
				break;

			// replace: revert the word to its original spelling
			case this.replWordFlag :
				this._setWordText ( text_idx, idx, preReplSpell, undefined );
				break;
		}

		// For all four cases, clear the wordFlag of this word. re-start the process
		this.wordFlags[text_idx][idx] = undefined;
		this._spellcheck();
	}
}

function _spellcheck() {
	var ww = this.wordWin;

	// check if this is the last word in the current text element
	if( this.currentWordIndex == ww.totalWords( this.currentTextIndex) ) {
		this.currentTextIndex++;
		this.currentWordIndex = 0;
		// keep going if we're not yet past the last text element
		if( this.currentTextIndex < this.wordWin.textInputs.length ) {
			this._spellcheck();
			return;
		} else {
			this.terminateSpell();
			return;
		}
	}

	// if this is after the first one make sure the Undo button is enabled
	if( this.currentWordIndex > 0 ) {
		this.controlWin.enableUndo();
	}

	// skip the current word if it has already been worked on
	if( this.wordFlags[this.currentTextIndex][this.currentWordIndex] ) {
		// increment the global current word index and move on.
		this.currentWordIndex++;
		this._spellcheck();
	} else {
		var evalText = ww.getTextVal( this.currentTextIndex, this.currentWordIndex );
		if( evalText ) {
			this.controlWin.evaluatedText.value = evalText;
			ww.setFocus( this.currentTextIndex, this.currentWordIndex );
			this._getSuggestions( this.currentTextIndex, this.currentWordIndex );
		}
	}
}

function _getSuggestions( text_num, word_num ) {
	this.controlWin.clearSuggestions();
	// add suggestion in list for each suggested word.
	// get the array of suggested words out of the
	// three-dimensional array containing all suggestions.
	var a_suggests = this.wordWin.suggestions[text_num][word_num];
	if( a_suggests ) {
		// got an array of suggestions.
		for( var ii = 0; ii < a_suggests.length; ii++ ) {
			this.controlWin.addSuggestion( a_suggests[ii] );
		}
	}
	this.controlWin.selectDefaultSuggestion();
}

function _setAsIgnored( text_num, word_num, flag ) {
	// set the UI
	this.wordWin.removeFocus( text_num, word_num );
	// do the bookkeeping
	this.wordFlags[text_num][word_num] = flag;
	return true;
}

function _getTotalReplaced() {
	var i_replaced = 0;
	for( var i = 0; i < this.wordFlags.length; i++ ) {
		for( var j = 0; j < this.wordFlags[i].length; j++ ) {
			if(( this.wordFlags[i][j] == this.replWordFlag )
			|| ( this.wordFlags[i][j] == this.replAllFlag )
			|| ( this.wordFlags[i][j] == this.fromReplAll )) {
				i_replaced++;
			}
		}
	}
	return i_replaced;
}

function _setWordText( text_num, word_num, newText, flag ) {
	// set the UI and form inputs
	this.wordWin.setText( text_num, word_num, newText );
	// keep track of what happened to this word:
	this.wordFlags[text_num][word_num] = flag;
	return true;
}

function _getFormInputs( inputPattern ) {
	var inputs = new Array();
	for( var i = 0; i < document.forms.length; i++ ) {
		for( var j = 0; j < document.forms[i].elements.length; j++ ) {
			if( document.forms[i].elements[j].type.match( inputPattern )) {
				inputs[inputs.length] = document.forms[i].elements[j];
			}
		}
	}
	return inputs;
}