4 * This JavaScript app is the driving power of the SquirrelSpell's
5 * main spellchecker window. Hope you have as much pain figuring
6 * it out as it took to write. ;))
10 * @author Konstantin Riabitsev <icon@duke.edu> ($Author$)
15 var CurrentLocation
=0;
19 var ChangesMade
=false;
22 * This function loads spellchecking errors into the form
23 * displayed to the user.
27 function populateSqspellForm(){
28 CurrentWord
=Word
=misses
[CurrentError
];
29 WordLocations
= locations
[CurrentError
].split(", ");
30 CurrentLoc
= WordLocations
[CurrentLocation
];
31 if(CurrentLocation
==WordLocations
.length
-1) {
37 tmp
= CurrentLoc
.split(":");
38 CurrentLine
=parseInt(tmp
[0]);
39 CurrentSymbol
=parseInt(tmp
[1]);
40 document
.forms
[0].sqspell_error
.value
=Word
;
41 LineValue
=sqspell_lines
[CurrentLine
];
44 if (CurrentSymbol
> 40){
45 StartWith
=CurrentSymbol
-40;
48 EndWith
=LineValue
.length
;
50 if (EndWith
> CurrentSymbol
+ 40){
51 EndWith
=CurrentSymbol
+40;
54 NewLineValue
+=LineValue
.substring(StartWith
, CurrentSymbol
) + "*" + Word
+ "*" + LineValue
.substring(CurrentSymbol
+ Word
.length
, EndWith
) + EndLine
;
55 document
.forms
[0].sqspell_line_area
.value
=NewLineValue
;
57 if (suggestions
[CurrentError
]){
58 WordSuggestions
= suggestions
[CurrentError
].split(", ");
59 for (i
=0; i
<WordSuggestions
.length
; i
++){
60 document
.forms
[0].sqspell_suggestion
.options
[i
] = new Option(WordSuggestions
[i
], WordSuggestions
[i
]);
63 document
.forms
[0].sqspell_suggestion
.options
[0] = new Option("No Suggestions", "_NONE");
64 document
.forms
[0].sqspell_oruse
.value
=Word
;
65 document
.forms
[0].sqspell_oruse
.focus();
66 document
.forms
[0].sqspell_oruse
.select();
69 document
.forms
[0].sqspell_suggestion
.selectedIndex
=0;
70 if (!document
.forms
[0].sqspell_oruse
.value
)
71 document
.forms
[0].sqspell_oruse
.value
=document
.forms
[0].sqspell_suggestion
.options
[document
.forms
[0].sqspell_suggestion
.selectedIndex
].value
;
72 occursTimes
= WordLocations
.length
;
73 if (CurrentLocation
) occursTimes
+= CurrentLocation
-1;
74 document
.forms
[0].sqspell_likethis
.value
=occursTimes
;
80 * This function updates a line from the message with a new value,
81 * received from the user.
83 * @param lLine line number.
84 * @param lSymbol symbol at which the misspelled word starts.
85 * @param lWord misspelled word
86 * @param lNewWord corrected word
89 function updateLine(lLine
, lSymbol
, lWord
, lNewWord
){
90 sqspell_lines
[lLine
] = sqspell_lines
[lLine
].substring(0, lSymbol
) + lNewWord
+ sqspell_lines
[lLine
].substring(lSymbol
+lWord
.length
, sqspell_lines
[lLine
].length
);
91 if (lWord
.length
!= lNewWord
.length
)
92 updateSymbol(lLine
, lSymbol
, lNewWord
.length
-lWord
.length
);
93 if (!ChangesMade
) ChangesMade
=true;
97 * This function is used to add a word user wishes to place in his/her
98 * user dictionary to the form field for later submission. Since there
99 * is no sane way to pass arrays between javascript and PHP, all words
100 * are concatenated into one strings and separated with a "%".
104 function sqspellRemember(){
105 CurrentWord
= misses
[CurrentError
] + "%";
106 document
.forms
[0].words
.value
+= CurrentWord
;
108 * Now ignore all occurances of this word.
114 * This function is called when the "Change" button is pressed.
118 function sqspellChange(){
119 CurrentWord
= misses
[CurrentError
];
120 NewWord
=document
.forms
[0].sqspell_oruse
.value
;
121 updateLine(CurrentLine
, CurrentSymbol
, CurrentWord
, NewWord
);
126 * This function is called when the "Change All" button is pressed.
130 function sqspellChangeAll(){
131 // Called when pressed the "Change All" button
132 allLoc
= locations
[CurrentError
].split(", ");
133 if (allLoc
.length
==1) {
135 * There's no need to "change all", only one occurance of this
136 * word in the whole text.
144 NewWord
=document
.forms
[0].sqspell_oruse
.value
;
145 CurrentWord
= misses
[CurrentError
];
146 for (z
=CurrentLocation
-1; z
<allLoc
.length
; z
++){
147 tmp
= allLoc
[z
].split(":");
148 lLine
= parseInt(tmp
[0]); lSymbol
= parseInt(tmp
[1]);
149 updateLine(lLine
, lSymbol
, CurrentWord
, NewWord
);
151 * Load it again to reflect the changes in symbol data
153 allLoc
= locations
[CurrentError
].split(", ");
160 * This function is only here for consistency. It is called when
161 * "Ignore" is pressed.
165 function sqspellIgnore(){
170 * This function is called when the "Ignore All" button is pressed.
174 function sqspellIgnoreAll(){
180 * This function clears the options in a select box "sqspell_suggestions".
184 function clearSqspellForm(){
185 for (i
=0; i
<document
.forms
[0].sqspell_suggestion
.length
; i
++){
186 document
.forms
[0].sqspell_suggestion
.options
[i
]=null;
190 * Now, I've been instructed by the Netscape Developer docs to call
191 * history.go(0) to refresh the page after I've changed the options.
192 * However, that brings so many pains with it that I just decided not
193 * to do it. It works like it is in Netscape 4.x. If there are problems
194 * in earlier versions of Netscape, then oh well. I'm not THAT anxious
195 * to have it working on all browsers... ;)
197 document
.forms
[0].sqspell_oruse
.value
="";
201 * This function goes on to the next error, or finishes nicely if
202 * no more errors are available.
207 if (!CurrentLocation
) CurrentError
++;
208 if (misses
[CurrentError
]){
210 populateSqspellForm();
212 if (ChangesMade
|| document
.forms
[0].words
.value
){
213 if (confirm(ui_completed
))
214 sqspellCommitChanges();
217 confirm (ui_nochange
);
224 * This function updates the symbol locations after there have been
225 * word length changes in the lines. Otherwise SquirrelSpell barfs all
226 * over your message... ;)
228 * @param lLine line number on which the error occurs
229 * @param lSymbol symbol number at which error occurs
230 * @param difference the difference in length between the old word
231 * and the new word. Can be negative or positive.
234 function updateSymbol(lLine
, lSymbol
, difference
){
236 * Now, I will admit that this is not the best way to do stuff,
237 * However that's the solution I've come up with.
239 * If you are wondering why I didn't use two-dimensional arrays instead,
240 * well, sometimes there will be a long line with an error close to the
241 * end of it, so the coordinates would be something like 2,98 and
242 * some Javascript implementations will create 98 empty members of an
243 * array just to have a filled number 98. This is too resource-wasteful
244 * and I have decided to go with the below solution instead. It takes
245 * a little more processing, but it saves a lot on memory.
247 * It just looks heinous. In real life it's really nice and sane. ;)
250 for (i
=0; i
<misses
.length
; i
++){
251 if(locations
[i
].indexOf(lLine
+ ":") >= 0){
252 allLoc
= locations
[i
].split(", ");
253 for (j
=0; j
<allLoc
.length
; j
++){
254 if (allLoc
[j
].indexOf(lLine
+":")==0){
255 tmp
= allLoc
[j
].split(":");
256 tmp
[0] = parseInt(tmp
[0]); tmp
[1] = parseInt(tmp
[1]);
257 if (tmp
[1] > lSymbol
){
258 tmp
[1] = tmp
[1] + difference
;
259 allLoc
[j
] = tmp
.join(":");
263 locations
[i
] = allLoc
.join(", ");
269 * This function writes the changes back into the compose form.
273 function sqspellCommitChanges(){
274 newSubject
= sqspell_lines
[0];
276 for (i
=1; i
<sqspell_lines
.length
; i
++){
277 if (i
!=1) newBody
+="\r\n";
278 newBody
+= sqspell_lines
[i
];
281 opener
.document
.forms
[0].subject
.value
=newSubject
;
282 opener
.document
.forms
[0].body
.value
=newBody
;
285 * See if any words were added to the dictionary.
287 if (document
.forms
[0].words
.value
){
291 document
.forms
[0].sqspell_line_area
.value
=ui_wait
;
293 * pass focus to the parent so we can do background save.
295 window
.opener
.focus();
296 document
.forms
[0].submit();