Getting ready for 1.4.0 RC1
[squirrelmail.git] / plugins / squirrelspell / js / check_me.js
... / ...
CommitLineData
1/**
2 * check_me.js
3 * ------------
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. ;))
7 *
8 * $Id$
9 *
10 * @author Konstantin Riabitsev <icon@duke.edu> ($Author$)
11 * @version $Date$
12 */
13
14var CurrentError=0;
15var CurrentLocation=0;
16
17var CurrentLine;
18var CurrentSymbol;
19var ChangesMade=false;
20
21/**
22 * This function loads spellchecking errors into the form
23 * displayed to the user.
24 *
25 * @return void
26 */
27function populateSqspellForm(){
28 CurrentWord=Word=misses[CurrentError];
29 WordLocations = locations[CurrentError].split(", ");
30 CurrentLoc = WordLocations[CurrentLocation];
31 if(CurrentLocation==WordLocations.length-1) {
32 CurrentLocation=0;
33 } else {
34 CurrentLocation++;
35 }
36
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];
42 StartWith=0;
43 NewLineValue="";
44 if (CurrentSymbol > 40){
45 StartWith=CurrentSymbol-40;
46 NewLineValue = "...";
47 }
48 EndWith=LineValue.length;
49 EndLine="";
50 if (EndWith > CurrentSymbol + 40){
51 EndWith=CurrentSymbol+40;
52 EndLine="...";
53 }
54 NewLineValue+=LineValue.substring(StartWith, CurrentSymbol) + "*" + Word + "*" + LineValue.substring(CurrentSymbol + Word.length, EndWith) + EndLine;
55 document.forms[0].sqspell_line_area.value=NewLineValue;
56
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]);
61 }
62 } else {
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();
67 }
68
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;
75}
76
77
78
79/**
80 * This function updates a line from the message with a new value,
81 * received from the user.
82 *
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
87 * @return void
88 */
89function 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;
94}
95
96/**
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 "%".
101 *
102 * @return void
103 */
104function sqspellRemember(){
105 CurrentWord = misses[CurrentError] + "%";
106 document.forms[0].words.value += CurrentWord;
107 /**
108 * Now ignore all occurances of this word.
109 */
110 sqspellIgnoreAll();
111}
112
113/**
114 * This function is called when the "Change" button is pressed.
115 *
116 * @return void
117 */
118function sqspellChange(){
119 CurrentWord = misses[CurrentError];
120 NewWord=document.forms[0].sqspell_oruse.value;
121 updateLine(CurrentLine, CurrentSymbol, CurrentWord, NewWord);
122 proceed();
123}
124
125/**
126 * This function is called when the "Change All" button is pressed.
127 *
128 * @return void
129 */
130function sqspellChangeAll(){
131 // Called when pressed the "Change All" button
132 allLoc = locations[CurrentError].split(", ");
133 if (allLoc.length==1) {
134 /**
135 * There's no need to "change all", only one occurance of this
136 * word in the whole text.
137 */
138 sqspellChange();
139 return;
140 }
141 /**
142 * Dark magic.
143 */
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);
150 /**
151 * Load it again to reflect the changes in symbol data
152 */
153 allLoc = locations[CurrentError].split(", ");
154 }
155 CurrentLocation=0;
156 proceed();
157}
158
159/**
160 * This function is only here for consistency. It is called when
161 * "Ignore" is pressed.
162 *
163 * @return void
164 */
165function sqspellIgnore(){
166 proceed();
167}
168
169/**
170 * This function is called when the "Ignore All" button is pressed.
171 *
172 * @return void
173 */
174function sqspellIgnoreAll(){
175 CurrentLocation=0;
176 proceed();
177}
178
179/**
180 * This function clears the options in a select box "sqspell_suggestions".
181 *
182 * @return void
183 */
184function clearSqspellForm(){
185 for (i=0; i<document.forms[0].sqspell_suggestion.length; i++){
186 document.forms[0].sqspell_suggestion.options[i]=null;
187 }
188
189 /**
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... ;)
196 */
197 document.forms[0].sqspell_oruse.value="";
198}
199
200/**
201 * This function goes on to the next error, or finishes nicely if
202 * no more errors are available.
203 *
204 * @return void
205 */
206function proceed(){
207 if (!CurrentLocation) CurrentError++;
208 if (misses[CurrentError]){
209 clearSqspellForm();
210 populateSqspellForm();
211 } else {
212 if (ChangesMade || document.forms[0].words.value){
213 if (confirm(ui_completed))
214 sqspellCommitChanges();
215 else self.close();
216 } else {
217 confirm (ui_nochange);
218 self.close();
219 }
220 }
221}
222
223/**
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... ;)
227 *
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.
232 * @return void
233 */
234function updateSymbol(lLine, lSymbol, difference){
235 /**
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.
238 *
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.
246 *
247 * It just looks heinous. In real life it's really nice and sane. ;)
248 */
249
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(":");
260 }
261 }
262 }
263 locations[i] = allLoc.join(", ");
264 }
265 }
266}
267
268/**
269 * This function writes the changes back into the compose form.
270 *
271 * @return void
272 */
273function sqspellCommitChanges(){
274 newSubject = sqspell_lines[0];
275 newBody = "";
276 for (i=1; i<sqspell_lines.length; i++){
277 if (i!=1) newBody+="\r\n";
278 newBody += sqspell_lines[i];
279 }
280
281 opener.document.forms[0].subject.value=newSubject;
282 opener.document.forms[0].body.value=newBody;
283
284 /**
285 * See if any words were added to the dictionary.
286 */
287 if (document.forms[0].words.value){
288 /**
289 * Yeppers.
290 */
291 document.forms[0].sqspell_line_area.value=ui_wait;
292 /**
293 * pass focus to the parent so we can do background save.
294 */
295 window.opener.focus();
296 document.forms[0].submit();
297 } else {
298 self.close();
299 }
300}