/[drupal]/contributions/modules/ajax_spellcheck/spellcheck.js
ViewVC logotype

Contents of /contributions/modules/ajax_spellcheck/spellcheck.js

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.3 - (show annotations) (download) (as text)
Mon Dec 12 16:15:51 2005 UTC (3 years, 11 months ago) by thox
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +2 -2 lines
File MIME type: text/javascript
- Patch #40832 by amanuel: update for HEAD (3rd time lucky)
1 // $Id: spellcheck.js,v 1.2 2005-12-12 10:50:54 thox Exp $
2
3 if (isJsEnabled()) {
4 addLoadEvent(spellcheckerAutoAttach);
5 }
6
7 /**
8 * Attach spellchecking to all textareas on the current page
9 */
10 function spellcheckerAutoAttach() {
11 var textAreas = document.getElementsByTagName('textarea');
12 for (i = 0; i < textAreas.length; i++) {
13 temp = new spellchecker;
14 temp.setup(textAreas[i]);
15 }
16
17 if (document.onclick) {
18 var oldOnclick = document.onclick;
19 document.onclick = function(e) {
20 spellcheckerHandleClick(e);
21 oldOnclick(e);
22 }
23 } else {
24 document.onclick = spellcheckerHandleClick;
25 }
26 }
27
28 /**
29 * Handles onclick events on the page to hide the suggestions popup
30 */
31 function spellcheckerHandleClick(e) {
32 var node = window.event ? window.event.srcElement : e.target;
33 switch (node.className) {
34 case 'spellcheck-correction':
35 case 'spellcheck-mistake':
36 break;
37 default:
38 removeNode(document.getElementById('spellcheck-suggestions'));
39 }
40 }
41
42 /**
43 * spellchecker object
44 */
45 spellchecker = function () {
46 /* Intentionally empty */
47 }
48
49
50 /**
51 * Initialises a spellchecker object
52 */
53 spellchecker.prototype.setup = function (textArea) {
54 this.highlighted = false;
55 this.textArea = textArea;
56 this.corrections = [];
57
58 var sc = this;
59 this.para = document.createElement('p');
60 this.para.className = 'spellcheck-trigger';
61 this.trigger = document.createElement('a');
62 this.trigger.href = '#';
63 this.trigger.innerHTML = 'Check spelling';
64 this.trigger.onclick = function() { sc.check(); return false; };
65 this.para.appendChild(this.trigger);
66 this.textArea.parentNode.insertBefore(this.para, this.textArea.nextSibling);
67 }
68
69 /**
70 * Performs the actual spelling check, sending results to spellchecker.callback
71 */
72 spellchecker.prototype.check = function () {
73 if (this.textArea.value.length == 0) {
74 return this.statusMessage('Nothing to check');
75 }
76 this.trigger.innerHTML = 'Checking...';
77 this.trigger.onclick = function() { return false; };
78 var base_url = document.getElementsByTagName('base')[0].href;
79 HTTPPost(base_url + '?q=spellcheck', this.callback, this, this.textArea.value);
80 }
81
82 /**
83 * Converts the spellchecking DIV back to a textarea
84 */
85 spellchecker.prototype.resume = function () {
86 var sc = this;
87 this.trigger.innerHTML = "Check spelling";
88 this.trigger.onclick = function() { sc.check(); return false; };
89
90 if (this.corrections.length > 0) {
91 var correctedString = '';
92 var offset = 0;
93 var words = this.div.getElementsByTagName('a');
94 for (i = 0; correction = words[i]; i++) {
95 correction = this.corrections[i];
96 correctedString += this.textArea.value.substr(offset, correction.stringStart - offset);
97 correctedString += words[i].innerHTML;
98 offset = correction.stringStart + correction.stringLength;
99 }
100 if (offset < this.textArea.value.length) {
101 correctedString += this.textArea.value.substr(offset);
102 }
103 this.textArea.value = correctedString;
104 removeNode(this.div);
105 this.div = null;
106 this.textArea.style.display = 'block';
107 this.corrections = [];
108 }
109 }
110
111 /**
112 * Handles HTTP errors and sends XML to spellchecker.parseResponse
113 */
114 spellchecker.prototype.callback = function (html, http, spellcheckerInstance) {
115 if (http.status != 200) {
116 spellcheckerInstance.statusMessage('An HTTP error occured');
117 spellcheckerInstance.resume();
118 return;
119 }
120 spellcheckerInstance.parseResponse(http.responseXML);
121 }
122
123 /**
124 * Displays a status message on the page for 2 seconds
125 */
126 spellchecker.prototype.statusMessage = function (statusString) {
127 if (!this.statusElement || !this.statusElement.parentNode) {
128 this.statusElement = document.createElement('span');
129 this.statusElement.className = 'spellcheck-status';
130 this.para.appendChild(this.statusElement);
131 }
132 this.statusElement.innerHTML = ' - ' + statusString;
133 var temp = this.statusElement;
134 setTimeout(function() { removeNode(temp); }, 2000);
135 }
136
137 /**
138 * Parses the XML response from Google
139 */
140 spellchecker.prototype.parseResponse = function (xml) {
141 if (!xml || !xml.documentElement) {
142 return this.statusMessage('An XML error occured');
143 }
144
145 var correctionNodes = xml.documentElement.getElementsByTagName('c');
146 var sc = this;
147
148 if (correctionNodes.length > 0) {
149 this.trigger.innerHTML = "Resume editing";
150 this.trigger.onclick = function() { sc.resume(); return false; };
151
152 var i = 0;
153 for (i = 0; i < correctionNodes.length; i++) {
154 this.corrections[i] = {
155 'stringStart' : parseInt(correctionNodes[i].getAttribute('o')),
156 'stringLength' : parseInt(correctionNodes[i].getAttribute('l')),
157 'suggestions' : correctionNodes[i].hasChildNodes() ? correctionNodes[i].firstChild.nodeValue.split('\t') : []
158 };
159 }
160 this.statusMessage('Found ' + correctionNodes.length + ' possible mistakes');
161 this.displayCorrectionDiv();
162 }
163 else {
164 this.statusMessage('No mistakes found');
165 this.corrections = [];
166 this.resume();
167 }
168 return this.corrections;
169 }
170
171 /**
172 * Converts the current textarea into an interactive spell checking DIV
173 */
174 spellchecker.prototype.displayCorrectionDiv = function () {
175 this.div = document.createElement('div');
176 this.div.id = 'spellcheck';
177 this.div.style.overflow = 'auto';
178 this.div.style.height = this.textArea.offsetHeight + 'px';
179 this.div.style.width = this.textArea.offsetWidth + 'px';
180
181 var offset = 0;
182 var sc = this;
183
184 for (var i = 0; correction = this.corrections[i]; i++) {
185 span = document.createElement('span');
186 span.innerHTML = this.checkPlain(this.textArea.value.substr(offset, correction.stringStart - offset));
187 this.div.appendChild(span);
188
189 wordLink = document.createElement('a');
190 wordLink.href = '#';
191 wordLink.innerHTML = this.textArea.value.substr(correction.stringStart, correction.stringLength);
192 wordLink.className = 'spellcheck-mistake';
193 wordLink.onclick = function() { sc.clickWord(this); return false; };
194 wordLink.suggestions = correction.suggestions;
195 wordLink.sc = this;
196 this.div.appendChild(wordLink);
197
198 offset = correction.stringStart + correction.stringLength;
199 }
200 if (offset < this.textArea.value.length) {
201 span = document.createElement('span');
202 span.innerHTML = this.checkPlain(this.textArea.value.substr(offset));
203 this.div.appendChild(span);
204 }
205
206 this.textArea.parentNode.insertBefore(this.div, this.textArea);
207 this.textArea.style.display = 'none';
208 }
209
210 /**
211 * Handles the user clicking on a highlighted word
212 */
213 spellchecker.prototype.clickWord = function (word) {
214 var div = document.getElementById('spellcheck-suggestions');
215 if (!div) {
216 div = document.createElement('div');
217 div.id = 'spellcheck-suggestions';
218 }
219 while (div.hasChildNodes()) {
220 removeNode(div.firstChild);
221 }
222 var ul = document.createElement('ul');
223 var sc = this;
224
225 word.suggestions.push('Edit...');
226
227 for (var i = 0; i < word.suggestions.length; i++) {
228 li = document.createElement('li');
229 li.innerHTML = word.suggestions[i];
230 li.onmousedown = function() { sc.clickSuggestion(this, word); };
231 li.onmouseover = function() { sc.highlight(this, word); };
232 li.onmouseout = function() { sc.unhighlight(this, word); };
233 if (word.suggestions[i] == 'Edit...') {
234 li.className = 'spellcheck-edit';
235 }
236 ul.appendChild(li);
237 }
238
239 word.suggestions.pop();
240
241 var pos = absolutePosition(word);
242 div.style.top = (pos.y + word.offsetHeight) +'px';
243 div.style.left = pos.x +'px';
244
245 div.appendChild(ul);
246 document.getElementsByTagName('body')[0].appendChild(div);
247 }
248
249 /**
250 * Handles highlighting of a word suggestion
251 */
252 spellchecker.prototype.highlight = function (node) {
253 removeClass(this.highlighted, 'selected');
254 addClass(node, 'selected');
255 this.highlighted = node;
256 }
257
258 /**
259 * Removes highlighting of suggestions
260 */
261 spellchecker.prototype.unhighlight = function (node) {
262 removeClass(node, 'selected');
263 this.highlighted = false;
264 }
265
266 /**
267 * Handles clicking of spellcheck suggestions
268 */
269 spellchecker.prototype.clickSuggestion = function(suggestion, word) {
270 if (suggestion.innerHTML == 'Edit...') {
271 var input = document.createElement('input');
272 input.value = word.innerHTML;
273 input.style.width = (word.offsetWidth + 10) + 'px';
274 input.onchange = function () { word.innerHTML = this.value; };
275 word.parentNode.insertBefore(input, word);
276 word.style.display = 'none';
277 }
278 else {
279 word.innerHTML = suggestion.innerHTML;
280 word.className = 'spellcheck-correction';
281 }
282 removeNode(document.getElementById('spellcheck-suggestions'));
283 }
284
285 /**
286 * Converts some characters to HTML
287 */
288 spellchecker.prototype.checkPlain = function (string) {
289 string = eregReplace("&", "&amp;", string);
290 string = eregReplace(">", "&gt;", string);
291 string = eregReplace("<", "&lt;", string);
292 string = eregReplace("\n", "<br />", string);
293 if (string == ' ') {
294 string = '&nbsp;';
295 }
296 return string;
297 }

  ViewVC Help
Powered by ViewVC 1.1.2