849bdf42 |
1 | /** |
d112ed5a |
2 | * check_me.js |
145dc7aa |
3 | * |
d112ed5a |
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 | * |
c0d96801 |
8 | * @copyright 1999-2012 The SquirrelMail Project Team |
4b4abf93 |
9 | * @license http://opensource.org/licenses/gpl-license.php GNU Public License |
10 | * @version $Id$ |
d112ed5a |
11 | */ |
849bdf42 |
12 | |
13 | var CurrentError=0; |
14 | var CurrentLocation=0; |
15 | |
16 | var CurrentLine; |
17 | var CurrentSymbol; |
18 | var ChangesMade=false; |
19 | |
d112ed5a |
20 | /** |
21 | * This function loads spellchecking errors into the form |
22 | * displayed to the user. |
23 | * |
24 | * @return void |
25 | */ |
849bdf42 |
26 | function populateSqspellForm(){ |
849bdf42 |
27 | CurrentWord=Word=misses[CurrentError]; |
28 | WordLocations = locations[CurrentError].split(", "); |
29 | CurrentLoc = WordLocations[CurrentLocation]; |
30 | if(CurrentLocation==WordLocations.length-1) { |
31 | CurrentLocation=0; |
32 | } else { |
33 | CurrentLocation++; |
34 | } |
e50f5ac2 |
35 | |
849bdf42 |
36 | tmp = CurrentLoc.split(":"); |
37 | CurrentLine=parseInt(tmp[0]); |
38 | CurrentSymbol=parseInt(tmp[1]); |
39 | document.forms[0].sqspell_error.value=Word; |
40 | LineValue=sqspell_lines[CurrentLine]; |
41 | StartWith=0; |
42 | NewLineValue=""; |
43 | if (CurrentSymbol > 40){ |
44 | StartWith=CurrentSymbol-40; |
45 | NewLineValue = "..."; |
46 | } |
47 | EndWith=LineValue.length; |
48 | EndLine=""; |
49 | if (EndWith > CurrentSymbol + 40){ |
50 | EndWith=CurrentSymbol+40; |
51 | EndLine="..."; |
52 | } |
53 | NewLineValue+=LineValue.substring(StartWith, CurrentSymbol) + "*" + Word + "*" + LineValue.substring(CurrentSymbol + Word.length, EndWith) + EndLine; |
54 | document.forms[0].sqspell_line_area.value=NewLineValue; |
e50f5ac2 |
55 | |
849bdf42 |
56 | if (suggestions[CurrentError]){ |
57 | WordSuggestions = suggestions[CurrentError].split(", "); |
58 | for (i=0; i<WordSuggestions.length; i++){ |
59 | document.forms[0].sqspell_suggestion.options[i] = new Option(WordSuggestions[i], WordSuggestions[i]); |
60 | } |
61 | } else { |
62 | document.forms[0].sqspell_suggestion.options[0] = new Option("No Suggestions", "_NONE"); |
63 | document.forms[0].sqspell_oruse.value=Word; |
64 | document.forms[0].sqspell_oruse.focus(); |
65 | document.forms[0].sqspell_oruse.select(); |
66 | } |
e50f5ac2 |
67 | |
849bdf42 |
68 | document.forms[0].sqspell_suggestion.selectedIndex=0; |
69 | if (!document.forms[0].sqspell_oruse.value) |
70 | document.forms[0].sqspell_oruse.value=document.forms[0].sqspell_suggestion.options[document.forms[0].sqspell_suggestion.selectedIndex].value; |
71 | occursTimes = WordLocations.length; |
72 | if (CurrentLocation) occursTimes += CurrentLocation-1; |
73 | document.forms[0].sqspell_likethis.value=occursTimes; |
74 | } |
75 | |
d112ed5a |
76 | |
77 | |
78 | /** |
79 | * This function updates a line from the message with a new value, |
80 | * received from the user. |
81 | * |
82 | * @param lLine line number. |
83 | * @param lSymbol symbol at which the misspelled word starts. |
84 | * @param lWord misspelled word |
85 | * @param lNewWord corrected word |
86 | * @return void |
87 | */ |
849bdf42 |
88 | function updateLine(lLine, lSymbol, lWord, lNewWord){ |
849bdf42 |
89 | sqspell_lines[lLine] = sqspell_lines[lLine].substring(0, lSymbol) + lNewWord + sqspell_lines[lLine].substring(lSymbol+lWord.length, sqspell_lines[lLine].length); |
90 | if (lWord.length != lNewWord.length) |
91 | updateSymbol(lLine, lSymbol, lNewWord.length-lWord.length); |
92 | if (!ChangesMade) ChangesMade=true; |
93 | } |
d112ed5a |
94 | |
95 | /** |
96 | * This function is used to add a word user wishes to place in his/her |
97 | * user dictionary to the form field for later submission. Since there |
98 | * is no sane way to pass arrays between javascript and PHP, all words |
99 | * are concatenated into one strings and separated with a "%". |
100 | * |
101 | * @return void |
102 | */ |
849bdf42 |
103 | function sqspellRemember(){ |
849bdf42 |
104 | CurrentWord = misses[CurrentError] + "%"; |
105 | document.forms[0].words.value += CurrentWord; |
d112ed5a |
106 | /** |
107 | * Now ignore all occurances of this word. |
108 | */ |
849bdf42 |
109 | sqspellIgnoreAll(); |
110 | } |
111 | |
d112ed5a |
112 | /** |
113 | * This function is called when the "Change" button is pressed. |
114 | * |
115 | * @return void |
116 | */ |
849bdf42 |
117 | function sqspellChange(){ |
849bdf42 |
118 | CurrentWord = misses[CurrentError]; |
119 | NewWord=document.forms[0].sqspell_oruse.value; |
120 | updateLine(CurrentLine, CurrentSymbol, CurrentWord, NewWord); |
121 | proceed(); |
122 | } |
123 | |
d112ed5a |
124 | /** |
125 | * This function is called when the "Change All" button is pressed. |
126 | * |
127 | * @return void |
128 | */ |
849bdf42 |
129 | function sqspellChangeAll(){ |
130 | // Called when pressed the "Change All" button |
131 | allLoc = locations[CurrentError].split(", "); |
132 | if (allLoc.length==1) { |
d112ed5a |
133 | /** |
134 | * There's no need to "change all", only one occurance of this |
135 | * word in the whole text. |
136 | */ |
849bdf42 |
137 | sqspellChange(); |
138 | return; |
139 | } |
d112ed5a |
140 | /** |
141 | * Dark magic. |
142 | */ |
849bdf42 |
143 | NewWord=document.forms[0].sqspell_oruse.value; |
144 | CurrentWord = misses[CurrentError]; |
145 | for (z=CurrentLocation-1; z<allLoc.length; z++){ |
146 | tmp = allLoc[z].split(":"); |
147 | lLine = parseInt(tmp[0]); lSymbol = parseInt(tmp[1]); |
148 | updateLine(lLine, lSymbol, CurrentWord, NewWord); |
d112ed5a |
149 | /** |
150 | * Load it again to reflect the changes in symbol data |
151 | */ |
849bdf42 |
152 | allLoc = locations[CurrentError].split(", "); |
e50f5ac2 |
153 | } |
849bdf42 |
154 | CurrentLocation=0; |
155 | proceed(); |
156 | } |
157 | |
d112ed5a |
158 | /** |
159 | * This function is only here for consistency. It is called when |
160 | * "Ignore" is pressed. |
161 | * |
162 | * @return void |
163 | */ |
849bdf42 |
164 | function sqspellIgnore(){ |
849bdf42 |
165 | proceed(); |
166 | } |
167 | |
d112ed5a |
168 | /** |
169 | * This function is called when the "Ignore All" button is pressed. |
e50f5ac2 |
170 | * |
d112ed5a |
171 | * @return void |
172 | */ |
849bdf42 |
173 | function sqspellIgnoreAll(){ |
849bdf42 |
174 | CurrentLocation=0; |
175 | proceed(); |
176 | } |
177 | |
d112ed5a |
178 | /** |
179 | * This function clears the options in a select box "sqspell_suggestions". |
180 | * |
181 | * @return void |
182 | */ |
849bdf42 |
183 | function clearSqspellForm(){ |
849bdf42 |
184 | for (i=0; i<document.forms[0].sqspell_suggestion.length; i++){ |
185 | document.forms[0].sqspell_suggestion.options[i]=null; |
186 | } |
e50f5ac2 |
187 | |
d112ed5a |
188 | /** |
189 | * Now, I've been instructed by the Netscape Developer docs to call |
190 | * history.go(0) to refresh the page after I've changed the options. |
191 | * However, that brings so many pains with it that I just decided not |
192 | * to do it. It works like it is in Netscape 4.x. If there are problems |
193 | * in earlier versions of Netscape, then oh well. I'm not THAT anxious |
194 | * to have it working on all browsers... ;) |
195 | */ |
849bdf42 |
196 | document.forms[0].sqspell_oruse.value=""; |
197 | } |
198 | |
d112ed5a |
199 | /** |
200 | * This function goes on to the next error, or finishes nicely if |
201 | * no more errors are available. |
202 | * |
203 | * @return void |
204 | */ |
849bdf42 |
205 | function proceed(){ |
849bdf42 |
206 | if (!CurrentLocation) CurrentError++; |
207 | if (misses[CurrentError]){ |
208 | clearSqspellForm(); |
209 | populateSqspellForm(); |
210 | } else { |
211 | if (ChangesMade || document.forms[0].words.value){ |
d112ed5a |
212 | if (confirm(ui_completed)) |
e50f5ac2 |
213 | sqspellCommitChanges(); |
d112ed5a |
214 | else self.close(); |
849bdf42 |
215 | } else { |
d112ed5a |
216 | confirm (ui_nochange); |
849bdf42 |
217 | self.close(); |
218 | } |
219 | } |
220 | } |
221 | |
d112ed5a |
222 | /** |
223 | * This function updates the symbol locations after there have been |
224 | * word length changes in the lines. Otherwise SquirrelSpell barfs all |
225 | * over your message... ;) |
226 | * |
227 | * @param lLine line number on which the error occurs |
228 | * @param lSymbol symbol number at which error occurs |
229 | * @param difference the difference in length between the old word |
230 | * and the new word. Can be negative or positive. |
231 | * @return void |
232 | */ |
849bdf42 |
233 | function updateSymbol(lLine, lSymbol, difference){ |
e50f5ac2 |
234 | /** |
d112ed5a |
235 | * Now, I will admit that this is not the best way to do stuff, |
236 | * However that's the solution I've come up with. |
237 | * |
238 | * If you are wondering why I didn't use two-dimensional arrays instead, |
239 | * well, sometimes there will be a long line with an error close to the |
e50f5ac2 |
240 | * end of it, so the coordinates would be something like 2,98 and |
241 | * some Javascript implementations will create 98 empty members of an |
242 | * array just to have a filled number 98. This is too resource-wasteful |
243 | * and I have decided to go with the below solution instead. It takes |
d112ed5a |
244 | * a little more processing, but it saves a lot on memory. |
245 | * |
246 | * It just looks heinous. In real life it's really nice and sane. ;) |
247 | */ |
e50f5ac2 |
248 | |
849bdf42 |
249 | for (i=0; i<misses.length; i++){ |
250 | if(locations[i].indexOf(lLine + ":") >= 0){ |
251 | allLoc = locations[i].split(", "); |
252 | for (j=0; j<allLoc.length; j++){ |
e50f5ac2 |
253 | if (allLoc[j].indexOf(lLine+":")==0){ |
254 | tmp = allLoc[j].split(":"); |
255 | tmp[0] = parseInt(tmp[0]); tmp[1] = parseInt(tmp[1]); |
256 | if (tmp[1] > lSymbol){ |
257 | tmp[1] = tmp[1] + difference; |
258 | allLoc[j] = tmp.join(":"); |
259 | } |
260 | } |
849bdf42 |
261 | } |
262 | locations[i] = allLoc.join(", "); |
263 | } |
264 | } |
265 | } |
266 | |
d112ed5a |
267 | /** |
268 | * This function writes the changes back into the compose form. |
269 | * |
270 | * @return void |
271 | */ |
849bdf42 |
272 | function sqspellCommitChanges(){ |
d112ed5a |
273 | newSubject = sqspell_lines[0]; |
274 | newBody = ""; |
275 | for (i=1; i<sqspell_lines.length; i++){ |
276 | if (i!=1) newBody+="\r\n"; |
277 | newBody += sqspell_lines[i]; |
849bdf42 |
278 | } |
e50f5ac2 |
279 | |
145dc7aa |
280 | opener.document.compose.subject.value=newSubject; |
281 | opener.document.compose.body.value=newBody; |
e50f5ac2 |
282 | |
d112ed5a |
283 | /** |
284 | * See if any words were added to the dictionary. |
285 | */ |
849bdf42 |
286 | if (document.forms[0].words.value){ |
d112ed5a |
287 | /** |
288 | * Yeppers. |
289 | */ |
290 | document.forms[0].sqspell_line_area.value=ui_wait; |
291 | /** |
292 | * pass focus to the parent so we can do background save. |
293 | */ |
849bdf42 |
294 | window.opener.focus(); |
295 | document.forms[0].submit(); |
296 | } else { |
d112ed5a |
297 | self.close(); |
849bdf42 |
298 | } |
4b4abf93 |
299 | } |