| 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-2020 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 | } |