Happy 2017
[squirrelmail.git] / plugins / squirrelspell / js / check_me.js
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 * @copyright 1999-2017 The SquirrelMail Project Team
9 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
10 * @version $Id$
11 */
12
13 var CurrentError=0;
14 var CurrentLocation=0;
15
16 var CurrentLine;
17 var CurrentSymbol;
18 var ChangesMade=false;
19
20 /**
21 * This function loads spellchecking errors into the form
22 * displayed to the user.
23 *
24 * @return void
25 */
26 function populateSqspellForm(){
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 }
35
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;
55
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 }
67
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
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 */
88 function updateLine(lLine, lSymbol, lWord, lNewWord){
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 }
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 */
103 function sqspellRemember(){
104 CurrentWord = misses[CurrentError] + "%";
105 document.forms[0].words.value += CurrentWord;
106 /**
107 * Now ignore all occurances of this word.
108 */
109 sqspellIgnoreAll();
110 }
111
112 /**
113 * This function is called when the "Change" button is pressed.
114 *
115 * @return void
116 */
117 function sqspellChange(){
118 CurrentWord = misses[CurrentError];
119 NewWord=document.forms[0].sqspell_oruse.value;
120 updateLine(CurrentLine, CurrentSymbol, CurrentWord, NewWord);
121 proceed();
122 }
123
124 /**
125 * This function is called when the "Change All" button is pressed.
126 *
127 * @return void
128 */
129 function sqspellChangeAll(){
130 // Called when pressed the "Change All" button
131 allLoc = locations[CurrentError].split(", ");
132 if (allLoc.length==1) {
133 /**
134 * There's no need to "change all", only one occurance of this
135 * word in the whole text.
136 */
137 sqspellChange();
138 return;
139 }
140 /**
141 * Dark magic.
142 */
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);
149 /**
150 * Load it again to reflect the changes in symbol data
151 */
152 allLoc = locations[CurrentError].split(", ");
153 }
154 CurrentLocation=0;
155 proceed();
156 }
157
158 /**
159 * This function is only here for consistency. It is called when
160 * "Ignore" is pressed.
161 *
162 * @return void
163 */
164 function sqspellIgnore(){
165 proceed();
166 }
167
168 /**
169 * This function is called when the "Ignore All" button is pressed.
170 *
171 * @return void
172 */
173 function sqspellIgnoreAll(){
174 CurrentLocation=0;
175 proceed();
176 }
177
178 /**
179 * This function clears the options in a select box "sqspell_suggestions".
180 *
181 * @return void
182 */
183 function clearSqspellForm(){
184 for (i=0; i<document.forms[0].sqspell_suggestion.length; i++){
185 document.forms[0].sqspell_suggestion.options[i]=null;
186 }
187
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 */
196 document.forms[0].sqspell_oruse.value="";
197 }
198
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 */
205 function proceed(){
206 if (!CurrentLocation) CurrentError++;
207 if (misses[CurrentError]){
208 clearSqspellForm();
209 populateSqspellForm();
210 } else {
211 if (ChangesMade || document.forms[0].words.value){
212 if (confirm(ui_completed))
213 sqspellCommitChanges();
214 else self.close();
215 } else {
216 confirm (ui_nochange);
217 self.close();
218 }
219 }
220 }
221
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 */
233 function updateSymbol(lLine, lSymbol, difference){
234 /**
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
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
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 */
248
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++){
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 }
261 }
262 locations[i] = allLoc.join(", ");
263 }
264 }
265 }
266
267 /**
268 * This function writes the changes back into the compose form.
269 *
270 * @return void
271 */
272 function sqspellCommitChanges(){
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];
278 }
279
280 opener.document.compose.subject.value=newSubject;
281 opener.document.compose.body.value=newBody;
282
283 /**
284 * See if any words were added to the dictionary.
285 */
286 if (document.forms[0].words.value){
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 */
294 window.opener.focus();
295 document.forms[0].submit();
296 } else {
297 self.close();
298 }
299 }