196482df39353f0af9513b0a55e6026df99d2b1e
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / htmlarea / plugins / SpellChecker / spell-check-ui.js
1 /***************************************************************
2 * Copyright notice
3 *
4 * (c) 2003 dynarch.com. Authored by Mihai Bazon, sponsored by www.americanbible.org.
5 * (c) 2004-2008 Stanislas Rolland <typo3(arobas)sjbr.ca>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This script is a modified version of a script published under the htmlArea License.
26 * A copy of the htmlArea License may be found in the textfile HTMLAREA_LICENSE.txt.
27 *
28 * This copyright notice MUST APPEAR in all copies of the script!
29 ***************************************************************/
30 /*
31 * Spell Checker Plugin for TYPO3 htmlArea RTE
32 *
33 * TYPO3 SVN ID: $Id$
34 */
35 var dialog = window.opener.HTMLArea.Dialog.SpellChecker;
36 var frame = null;
37 var currentElement = null;
38 var wrongWords = null;
39 var modified = false;
40 var allWords = {};
41 var fixedWords = [];
42 var suggested_words = {};
43
44 var to_p_dict = []; // List of words to add to personal dictionary
45 var to_r_list = []; // List of words to add to replacement list
46
47 function makeCleanDoc(leaveFixed) {
48 // document.getElementById("status").innerHTML = 'Please wait: rendering valid HTML';
49 var words = wrongWords.concat(fixedWords);
50 for (var i = words.length; --i >= 0;) {
51 var el = words[i];
52 if (!(leaveFixed && /HA-spellcheck-fixed/.test(el.className))) {
53 el.parentNode.insertBefore(el.firstChild, el);
54 el.parentNode.removeChild(el);
55 } else
56 el.className = "HA-spellcheck-fixed";
57 }
58 return window.opener.HTMLArea.getHTML(frame.contentWindow.document.body, false, dialog.plugin.editor);
59 };
60
61 function recheckClicked() {
62 document.getElementById("status").innerHTML = dialog.plugin.localize("Please wait: changing dictionary to") + ': "' + document.getElementById("f_dictionary").value + '".';
63 var field = document.getElementById("f_content");
64 field.value = makeCleanDoc(true);
65 field.form.submit();
66 };
67
68 function saveClicked() {
69 if (modified) {
70 dialog.plugin.editor.setHTML(makeCleanDoc(false));
71 }
72 if ((to_p_dict.length || to_r_list.length) && dialog.plugin.enablePersonalDicts) {
73 var data = {};
74 for (var i = 0;i < to_p_dict.length;i++) {
75 data['to_p_dict[' + i + ']'] = to_p_dict[i];
76 }
77 for (var i = 0;i < to_r_list.length;i++) {
78 data['to_r_list[' + i + '][0]'] = to_r_list[i][0];
79 data['to_r_list[' + i + '][1]'] = to_r_list[i][1];
80 }
81 data['cmd'] = 'learn';
82 data['enablePersonalDicts'] = dialog.plugin.enablePersonalDicts;
83 data['userUid'] = dialog.plugin.userUid;
84 data['dictionary'] = dialog.plugin.contentISOLanguage;
85 data['pspell_charset'] = dialog.plugin.contentCharset;
86 data['pspell_mode'] = dialog.plugin.spellCheckerMode;
87 window.opener.HTMLArea._postback('plugins/SpellChecker/spell-check-logic.php', data);
88 }
89 window.close();
90 return false;
91 };
92
93 function cancelClicked() {
94 var ok = true;
95 if (modified) {
96 ok = confirm(dialog.plugin.localize("QUIT_CONFIRMATION"));
97 }
98 if (ok) {
99 dialog.close();
100 }
101 return false;
102 };
103
104 function replaceWord(el) {
105 var replacement = document.getElementById("v_replacement").value;
106 var this_word_modified = (el.innerHTML != replacement);
107 if (this_word_modified)
108 modified = true;
109 if (el) {
110 el.className = el.className.replace(/\s*HA-spellcheck-(hover|fixed)\s*/g, " ");
111 }
112 el.className += " HA-spellcheck-fixed";
113 el.__msh_fixed = true;
114 if (!this_word_modified) {
115 return false;
116 }
117 to_r_list.push([el.innerHTML, replacement]);
118 el.innerHTML = replacement;
119 };
120
121 function replaceClicked() {
122 replaceWord(currentElement);
123 var start = currentElement.__msh_id;
124 var index = start;
125 do {
126 ++index;
127 if (index == wrongWords.length) index = 0;
128 } while((index != start) && wrongWords[index].__msh_fixed);
129 if (index == start) {
130 index = 0;
131 alert(dialog.plugin.localize("Finished list of mispelled words"));
132 }
133 wrongWords[index].__msh_wordClicked(true);
134 return false;
135 };
136
137 function revertClicked() {
138 document.getElementById("v_replacement").value = currentElement.__msh_origWord;
139 replaceWord(currentElement);
140 currentElement.className = "HA-spellcheck-error HA-spellcheck-current";
141 return false;
142 };
143
144 function replaceAllClicked() {
145 var replacement = document.getElementById("v_replacement").value;
146 var ok = true;
147 var spans = allWords[currentElement.__msh_origWord];
148 if (spans.length == 0) {
149 alert("An impossible condition just happened. Call FBI. ;-)");
150 } else if (spans.length == 1) {
151 replaceClicked();
152 return false;
153 }
154 /*
155 var message = "The word \"" + currentElement.__msh_origWord + "\" occurs " + spans.length + " times.\n";
156 if (replacement == currentElement.__msh_origWord) {
157 ok = confirm(message + "Ignore all occurrences?");
158 } else {
159 ok = confirm(message + "Replace all occurrences with \"" + replacement + "\"?");
160 }
161 */
162 if (ok) {
163 for (var i = 0; i < spans.length; ++i) {
164 if (spans[i] != currentElement) {
165 replaceWord(spans[i]);
166 }
167 }
168 // replace current element the last, so that we jump to the next word ;-)
169 replaceClicked();
170 }
171 return false;
172 };
173
174 function ignoreClicked() {
175 document.getElementById("v_replacement").value = currentElement.__msh_origWord;
176 replaceClicked();
177 return false;
178 };
179
180 function ignoreAllClicked() {
181 document.getElementById("v_replacement").value = currentElement.__msh_origWord;
182 replaceAllClicked();
183 return false;
184 };
185
186 function learnClicked() {
187 to_p_dict.push(currentElement.__msh_origWord);
188 return ignoreAllClicked();
189 };
190
191 function initDocument() {
192 dialog.initialize();
193 var plugin = dialog.plugin;
194 var editor = plugin.editor;
195
196 modified = false;
197 document.title = dialog.plugin.localize("Spell Checker");
198 frame = document.getElementById("i_framecontent");
199 var field = document.getElementById("f_content");
200 field.value = HTMLArea.getHTML(editor._doc.body, false, editor);
201 document.getElementById("f_init").value = "0";
202 document.getElementById("f_dictionary").value = plugin.contentISOLanguage;
203 document.getElementById("f_charset").value = plugin.contentCharset;
204 document.getElementById("f_pspell_mode").value = plugin.spellCheckerMode;
205 document.getElementById("f_user_uid").value = plugin.userUid;
206 document.getElementById("f_personal_dicts").value = plugin.enablePersonalDicts;
207 field.form.submit();
208 // assign some global event handlers
209 var select = document.getElementById("v_suggestions");
210 select.onchange = function() {
211 document.getElementById("v_replacement").value = this.value;
212 };
213 HTMLArea._addEvent(select, "dblclick", replaceClicked);
214
215 document.getElementById("b_replace").onclick = replaceClicked;
216 if (plugin.enablePersonalDicts) document.getElementById("b_learn").onclick = learnClicked;
217 else document.getElementById("b_learn").style.display = 'none';
218 document.getElementById("b_replall").onclick = replaceAllClicked;
219 document.getElementById("b_ignore").onclick = ignoreClicked;
220 document.getElementById("b_ignall").onclick = ignoreAllClicked;
221 document.getElementById("b_recheck").onclick = recheckClicked;
222 document.getElementById("b_revert").onclick = revertClicked;
223 document.getElementById("b_info").onclick = displayInfo;
224
225 document.getElementById("b_ok").onclick = saveClicked;
226 document.getElementById("b_cancel").onclick = cancelClicked;
227
228 select = document.getElementById("v_dictionaries");
229 select.onchange = function() {
230 document.getElementById("f_dictionary").value = this.value;
231 };
232 };
233
234 function getAbsolutePos(el) {
235 var r = { x: el.offsetLeft, y: el.offsetTop };
236 if (el.offsetParent) {
237 var tmp = getAbsolutePos(el.offsetParent);
238 r.x += tmp.x;
239 r.y += tmp.y;
240 }
241 return r;
242 };
243
244 function wordClicked(scroll) {
245 var self = this;
246 if (scroll) (function() {
247 var pos = getAbsolutePos(self);
248 var ws = { x: frame.offsetWidth - 4,
249 y: frame.offsetHeight - 4 };
250 var wp = { x: frame.contentWindow.document.body.scrollLeft,
251 y: frame.contentWindow.document.body.scrollTop };
252 pos.x -= Math.round(ws.x/2);
253 if (pos.x < 0) pos.x = 0;
254 pos.y -= Math.round(ws.y/2);
255 if (pos.y < 0) pos.y = 0;
256 frame.contentWindow.scrollTo(pos.x, pos.y);
257 })();
258 if (currentElement) {
259 var a = allWords[currentElement.__msh_origWord];
260 currentElement.className = currentElement.className.replace(/\s*HA-spellcheck-current\s*/g, " ");
261 for (var i = 0; i < a.length; ++i) {
262 var el = a[i];
263 if (el != currentElement) {
264 el.className = el.className.replace(/\s*HA-spellcheck-same\s*/g, " ");
265 }
266 }
267 }
268 currentElement = this;
269 this.className += " HA-spellcheck-current";
270 var a = allWords[currentElement.__msh_origWord];
271 for (var i = 0; i < a.length; ++i) {
272 var el = a[i];
273 if (el != currentElement) {
274 el.className += " HA-spellcheck-same";
275 }
276 }
277 // document.getElementById("b_replall").disabled = (a.length <= 1);
278 // document.getElementById("b_ignall").disabled = (a.length <= 1);
279 var txt;
280 var txt2;
281 if (a.length == 1) {
282 txt = dialog.plugin.localize("One occurrence");
283 txt2 = dialog.plugin.localize("was found.");
284 } else if (a.length == 2) {
285 txt = dialog.plugin.localize("Two occurrences");
286 txt2 = dialog.plugin.localize("were found.");
287 } else {
288 txt = a.length + " " + dialog.plugin.localize("occurrences");
289 txt2 = dialog.plugin.localize("were found.");
290 }
291 var suggestions = suggested_words[this.__msh_origWord];
292 if (suggestions) suggestions = suggestions.split(/,/);
293 else suggestions = [];
294 var select = document.getElementById("v_suggestions");
295 document.getElementById("statusbar").innerHTML = txt + " " + dialog.plugin.localize("of the word") +
296 ' "<b>' + currentElement.__msh_origWord + '</b>"' + " " + txt2;
297 for (var i = select.length; --i >= 0;) {
298 select.remove(i);
299 }
300 for (var i = 0; i < suggestions.length; ++i) {
301 var txt = suggestions[i];
302 var option = document.createElement("option");
303 option.value = txt;
304 option.appendChild(document.createTextNode(txt));
305 select.appendChild(option);
306 }
307 document.getElementById("v_currentWord").innerHTML = this.__msh_origWord;
308 if (suggestions.length > 0) {
309 select.selectedIndex = 0;
310 select.onchange();
311 } else {
312 document.getElementById("v_replacement").value = this.innerHTML;
313 }
314 select.style.display = "none";
315 select.style.display = "inline";
316 return false;
317 };
318
319 function wordMouseOver() {
320 this.className += " HA-spellcheck-hover";
321 };
322
323 function wordMouseOut() {
324 this.className = this.className.replace(/\s*HA-spellcheck-hover\s*/g, " ");
325 };
326
327 function displayInfo() {
328 var info = frame.contentWindow.spellcheck_info;
329 if (!info)
330 alert(dialog.plugin.localize("No information available"));
331 else {
332 var txt = dialog.plugin.localize("Document information") + "\n" ;
333 for (var i in info) {
334 txt += "\n" + dialog.plugin.localize(i) + " : " + info[i];
335 }
336 txt += " " + dialog.plugin.localize("seconds");
337 alert(txt);
338 }
339 return false;
340 };
341
342 function finishedSpellChecking() {
343 // initialization of global variables
344 currentElement = null;
345 wrongWords = null;
346 allWords = {};
347 fixedWords = [];
348 suggested_words = frame.contentWindow.suggested_words;
349
350 document.getElementById("status").innerHTML = dialog.plugin.localize("HTMLArea Spell Checker");
351 var doc = frame.contentWindow.document;
352 var spans = doc.getElementsByTagName("span");
353 var sps = [];
354 var id = 0;
355 for (var i = 0; i < spans.length; ++i) {
356 var el = spans[i];
357 if (/HA-spellcheck-error/.test(el.className)) {
358 sps.push(el);
359 el.__msh_wordClicked = wordClicked;
360 el.onclick = function(ev) {
361 ev || (ev = window.event);
362 ev && HTMLArea._stopEvent(ev);
363 return this.__msh_wordClicked(false);
364 };
365 el.onmouseover = wordMouseOver;
366 el.onmouseout = wordMouseOut;
367 el.__msh_id = id++;
368 var txt = (el.__msh_origWord = el.firstChild.data);
369 el.__msh_fixed = false;
370 if (typeof allWords[txt] == "undefined") {
371 allWords[txt] = [el];
372 } else {
373 allWords[txt].push(el);
374 }
375 } else if (/HA-spellcheck-fixed/.test(el.className)) {
376 fixedWords.push(el);
377 }
378 }
379 wrongWords = sps;
380 if (sps.length == 0) {
381 if (!modified) {
382 alert(dialog.plugin.localize("NO_ERRORS_CLOSING"));
383 window.close();
384 } else {
385 alert(dialog.plugin.localize("NO_ERRORS"));
386 }
387 return false;
388 }
389 (currentElement = sps[0]).__msh_wordClicked(true);
390 var as = doc.getElementsByTagName("a");
391 for (var i = as.length; --i >= 0;) {
392 var a = as[i];
393 a.onclick = function() {
394 if (confirm(dialog.plugin.localize("CONFIRM_LINK_CLICK") + ":\n" +
395 this.href + "\n" + dialog.plugin.localize("I will open it in a new page."))) {
396 window.open(this.href);
397 }
398 return false;
399 };
400 }
401 var dicts = doc.getElementById("HA-spellcheck-dictionaries");
402 if (dicts) {
403 dicts.parentNode.removeChild(dicts);
404 dicts = dicts.innerHTML.split(/,/);
405 var select = document.getElementById("v_dictionaries");
406 for (var i = select.length; --i >= 0;) {
407 select.remove(i);
408 }
409 var selectedOptionIndex = 0;
410 for (var i = 0; i < dicts.length; ++i) {
411 var txt = dicts[i];
412 var option = document.createElement("option");
413 if (/^@(.*)$/.test(txt)) {
414 txt = RegExp.$1;
415 selectedOptionIndex = i;
416 if (HTMLArea.is_ie) option.selected = true;
417 document.getElementById("f_dictionary").value = txt;
418 }
419 option.value = txt;
420 option.appendChild(document.createTextNode(txt));
421 select.appendChild(option);
422 }
423 select.selectedIndex = selectedOptionIndex;
424 }
425 };
426