spellcheck.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. // These are variables the popup is going to want to access...
  2. var spell_formname, spell_fieldname;
  3. // Spell check the specified field in the specified form.
  4. function spellCheck(formName, fieldName)
  5. {
  6. // Grab the (hidden) spell checking form.
  7. var spellform = document.forms.spell_form;
  8. // Register the name of the editing form for future reference.
  9. spell_formname = formName;
  10. spell_fieldname = fieldName;
  11. // This should match a word (most of the time).
  12. var regexpWordMatch = /(?:<[^>]+>)|(?:\[[^ ][^\]]*\])|(?:&[^; ]+;)|(?:[^0-9\s\]\[{};:"\\|,<.>\/?`~!@#$%^&*()_+=]+)/g;
  13. // These characters can appear within words.
  14. var aWordCharacters = ['-', '\''];
  15. var aWords = new Array(), aResult = new Array();
  16. var sText = document.forms[formName][fieldName].value;
  17. var bInCode = false;
  18. var iOffset1, iOffset2;
  19. // Loop through all words.
  20. while ((aResult = regexpWordMatch.exec(sText)) && typeof(aResult) != 'undefined')
  21. {
  22. iOffset1 = 0;
  23. iOffset2 = aResult[0].length - 1;
  24. // Strip the dashes and hyphens from the begin of the word.
  25. while (in_array(aResult[0].charAt(iOffset1), aWordCharacters) && iOffset1 < iOffset2)
  26. iOffset1++;
  27. // Strip the dashes and hyphens from the end of the word.
  28. while (in_array(aResult[0].charAt(iOffset2), aWordCharacters) && iOffset1 < iOffset2)
  29. iOffset2--;
  30. // I guess there's only dashes and hyphens in this word...
  31. if (iOffset1 == iOffset2)
  32. continue;
  33. // Ignore code blocks.
  34. if (aResult[0].substr(0, 5).toLowerCase() == '[code')
  35. bInCode = true;
  36. // Glad we're out of that code block!
  37. else if (bInCode && aResult[0].substr(0, 7).toLowerCase() == '[/code]')
  38. bInCode = false;
  39. // Now let's get to business.
  40. else if (!bInCode && !in_array(aResult[0].charAt(0), ['[', '<']) && aResult[0].toUpperCase() != aResult[0])
  41. aWords[aWords.length] = aResult[0].substr(iOffset1, iOffset2 - iOffset1 + 1) + '|' + (iOffset1 + sText.substr(0, aResult.index).length) + '|' + (iOffset2 + sText.substr(0, aResult.index).length);
  42. }
  43. // Open the window...
  44. openSpellWin(640, 480);
  45. // Pass the data to a form...
  46. spellform.spellstring.value = aWords.join('\n');
  47. // and go!
  48. spellform.submit();
  49. return true;
  50. }
  51. // Private functions -------------------------------
  52. // Globals...
  53. var wordindex = -1, offsetindex = 0;
  54. var ignoredWords = [];
  55. // A "misspelled word" object.
  56. function misp(word, start, end, suggestions)
  57. {
  58. // The word, start index, end index, and array of suggestions.
  59. this.word = word;
  60. this.start = start;
  61. this.end = end;
  62. this.suggestions = suggestions;
  63. }
  64. // Replace the word in the misps array at the "wordindex" index. The
  65. // misps array is generated by a PHP script after the string to be spell
  66. // checked is evaluated with pspell.
  67. function replaceWord()
  68. {
  69. var strstart = "";
  70. var strend;
  71. // If this isn't the beginning of the string then get all of the string
  72. // that is before the word we are replacing.
  73. if (misps[wordindex].start != 0)
  74. strstart = mispstr.slice(0, misps[wordindex].start + offsetindex);
  75. // Get the end of the string after the word we are replacing.
  76. strend = mispstr.slice(misps[wordindex].end + 1 + offsetindex);
  77. // Rebuild the string with the new word.
  78. mispstr = strstart + document.forms.spellingForm.changeto.value + strend;
  79. // Update offsetindex to compensate for replacing a word with a word
  80. // of a different length.
  81. offsetindex += document.forms.spellingForm.changeto.value.length - misps[wordindex].word.length;
  82. // Update the word so future replaceAll calls don't change it.
  83. misps[wordindex].word = document.forms.spellingForm.changeto.value;
  84. nextWord(false);
  85. }
  86. // Replaces all instances of currently selected word with contents chosen by user.
  87. // Note: currently only replaces words after highlighted word. I think we can re-index
  88. // all words at replacement or ignore time to have it wrap to the beginning if we want
  89. // to.
  90. function replaceAll()
  91. {
  92. var strend;
  93. var idx;
  94. var origword;
  95. var localoffsetindex = offsetindex;
  96. origword = misps[wordindex].word;
  97. // Re-index everything past the current word.
  98. for (idx = wordindex; idx < misps.length; idx++)
  99. {
  100. misps[idx].start += localoffsetindex;
  101. misps[idx].end += localoffsetindex;
  102. }
  103. localoffsetindex = 0;
  104. for (idx = 0; idx < misps.length; idx++)
  105. {
  106. if (misps[idx].word == origword)
  107. {
  108. var strstart = "";
  109. if (misps[idx].start != 0)
  110. strstart = mispstr.slice(0, misps[idx].start + localoffsetindex);
  111. // Get the end of the string after the word we are replacing.
  112. strend = mispstr.slice(misps[idx].end + 1 + localoffsetindex);
  113. // Rebuild the string with the new word.
  114. mispstr = strstart + document.forms.spellingForm.changeto.value + strend;
  115. // Update offsetindex to compensate for replacing a word with a word
  116. // of a different length.
  117. localoffsetindex += document.forms.spellingForm.changeto.value.length - misps[idx].word.length;
  118. }
  119. // We have to re-index everything after replacements.
  120. misps[idx].start += localoffsetindex;
  121. misps[idx].end += localoffsetindex;
  122. }
  123. // Add the word to the ignore array.
  124. ignoredWords[origword] = true;
  125. // Reset offsetindex since we re-indexed.
  126. offsetindex = 0;
  127. nextWord(false);
  128. }
  129. // Highlight the word that was selected using the nextWord function.
  130. function highlightWord()
  131. {
  132. var strstart = "";
  133. var strend;
  134. // If this isn't the beginning of the string then get all of the string
  135. // that is before the word we are replacing.
  136. if (misps[wordindex].start != 0)
  137. strstart = mispstr.slice(0, misps[wordindex].start + offsetindex);
  138. // Get the end of the string after the word we are replacing.
  139. strend = mispstr.slice(misps[wordindex].end + 1 + offsetindex);
  140. // Rebuild the string with a span wrapped around the misspelled word
  141. // so we can highlight it in the div the user is viewing the string in.
  142. var divptr, newValue;
  143. divptr = document.getElementById("spellview");
  144. newValue = htmlspecialchars(strstart) + '<span class="highlight" id="h1">' + misps[wordindex].word + '</span>' + htmlspecialchars(strend);
  145. setInnerHTML(divptr, newValue.replace(/_\|_/g, '<br />'));
  146. // We could use scrollIntoView, but it's just not that great anyway.
  147. var spellview_height = typeof(document.getElementById("spellview").currentStyle) != "undefined" ? parseInt(document.getElementById("spellview").currentStyle.height) : document.getElementById("spellview").offsetHeight;
  148. var word_position = document.getElementById("h1").offsetTop;
  149. var current_position = document.getElementById("spellview").scrollTop;
  150. // The spellview is not tall enough! Scroll down!
  151. if (spellview_height <= (word_position + current_position))
  152. document.getElementById("spellview").scrollTop = word_position + current_position - spellview_height + 32;
  153. }
  154. // Display the next misspelled word to the user and populate the suggested spellings box.
  155. function nextWord(ignoreall)
  156. {
  157. // Push ignored word onto ignoredWords array.
  158. if (ignoreall)
  159. ignoredWords[misps[wordindex].word] = true;
  160. // Update the index of all words we have processed...
  161. // This must be done to accomodate the replaceAll function.
  162. if (wordindex >= 0)
  163. {
  164. misps[wordindex].start += offsetindex;
  165. misps[wordindex].end += offsetindex;
  166. }
  167. // Increment the counter for the array of misspelled words.
  168. wordindex++;
  169. // Draw it and quit if there are no more misspelled words to evaluate.
  170. if (misps.length <= wordindex)
  171. {
  172. var divptr;
  173. divptr = document.getElementById("spellview");
  174. setInnerHTML(divptr, htmlspecialchars(mispstr).replace(/_\|_/g, "<br />"));
  175. while (document.forms.spellingForm.suggestions.options.length > 0)
  176. document.forms.spellingForm.suggestions.options[0] = null;
  177. alert(txt['done']);
  178. document.forms.spellingForm.change.disabled = true;
  179. document.forms.spellingForm.changeall.disabled = true;
  180. document.forms.spellingForm.ignore.disabled = true;
  181. document.forms.spellingForm.ignoreall.disabled = true;
  182. // Put line feeds back...
  183. mispstr = mispstr.replace(/_\|_/g, "\n");
  184. // Get a handle to the field we need to re-populate.
  185. window.opener.document.forms[spell_formname][spell_fieldname].value = mispstr;
  186. if (!window.opener.spellCheckDone)
  187. window.opener.document.forms[spell_formname][spell_fieldname].focus();
  188. else
  189. window.opener.spellCheckDone();
  190. window.close();
  191. return true;
  192. }
  193. // Check to see if word is supposed to be ignored.
  194. if (typeof(ignoredWords[misps[wordindex].word]) != "undefined")
  195. {
  196. nextWord(false);
  197. return false;
  198. }
  199. // Clear out the suggestions box!
  200. while (document.forms.spellingForm.suggestions.options.length > 0)
  201. document.forms.spellingForm.suggestions.options[0] = null;
  202. // Re-populate the suggestions box if there are any suggested spellings for the word.
  203. if (misps[wordindex].suggestions.length)
  204. {
  205. for (var sugidx = 0; sugidx < misps[wordindex].suggestions.length; sugidx++)
  206. {
  207. var newopt = new Option(misps[wordindex].suggestions[sugidx], misps[wordindex].suggestions[sugidx]);
  208. document.forms.spellingForm.suggestions.options[sugidx] = newopt;
  209. if (sugidx == 0)
  210. {
  211. newopt.selected = true;
  212. document.forms.spellingForm.changeto.value = newopt.value;
  213. document.forms.spellingForm.changeto.select();
  214. }
  215. }
  216. }
  217. if (document.forms.spellingForm.suggestions.options.length == 0)
  218. document.forms.spellingForm.changeto.value = "";
  219. highlightWord();
  220. return false;
  221. }
  222. function htmlspecialchars(thetext)
  223. {
  224. thetext = thetext.replace(/\</g, "&lt;");
  225. thetext = thetext.replace(/\>/g, "&gt;");
  226. thetext = thetext.replace(/\n/g, "<br />");
  227. thetext = thetext.replace(/\ \ /g, " &nbsp;");
  228. return thetext;
  229. }
  230. function openSpellWin(width, height)
  231. {
  232. window.open("", "spellWindow", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=no,width=" + width + ",height=" + height);
  233. }