// Spell Checker Plugin for HTMLArea-3.0 // Sponsored by www.americanbible.org // Implementation by Mihai Bazon, http://dynarch.com/mishoo/ // // (c) dynarch.com 2003. // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). // // internationalization file was already loaded in parent ;-) var SpellChecker = window.opener.SpellChecker; var i18n = SpellChecker.I18N; var HTMLArea = window.opener.HTMLArea; var is_ie = HTMLArea.is_ie; var editor = SpellChecker.editor; var frame = null; var currentElement = null; var wrongWords = null; var modified = false; var allWords = {}; var fixedWords = []; var suggested_words = {}; function makeCleanDoc(leaveFixed) { // document.getElementById("status").innerHTML = 'Please wait: rendering valid HTML'; var words = wrongWords.concat(fixedWords); for (var i = words.length; --i >= 0;) { var el = words[i]; if (!(leaveFixed && /HA-spellcheck-fixed/.test(el.className))) { el.parentNode.insertBefore(el.firstChild, el); el.parentNode.removeChild(el); } else el.className = "HA-spellcheck-fixed"; } // we should use innerHTML here, but IE6's implementation fucks up the // HTML to such extent that our poor Perl parser doesn't understand it // anymore. return window.opener.HTMLArea.getHTML(frame.contentWindow.document.body, false, editor); }; function recheckClicked() { document.getElementById("status").innerHTML = i18n["Please wait: changing dictionary to"] + ': "' + document.getElementById("f_dictionary").value + '".'; var field = document.getElementById("f_content"); field.value = makeCleanDoc(true); field.form.submit(); }; function saveClicked() { if (modified) { editor.setHTML(makeCleanDoc(false)); } window.close(); return false; }; function cancelClicked() { var ok = true; if (modified) { ok = confirm(i18n["QUIT_CONFIRMATION"]); } if (ok) { window.close(); } return false; }; function replaceWord(el) { var replacement = document.getElementById("v_replacement").value; var this_word_modified = (el.innerHTML != replacement); if (this_word_modified) modified = true; if (el) { el.className = el.className.replace(/\s*HA-spellcheck-(hover|fixed)\s*/g, " "); } el.className += " HA-spellcheck-fixed"; el.__msh_fixed = true; if (!this_word_modified) { return false; } el.innerHTML = replacement; }; function replaceClicked() { replaceWord(currentElement); var start = currentElement.__msh_id; var index = start; do { ++index; if (index == wrongWords.length) { index = 0; } } while ((index != start) && wrongWords[index].__msh_fixed); if (index == start) { index = 0; alert(i18n["Finished list of mispelled words"]); } wrongWords[index].__msh_wordClicked(true); return false; }; function revertClicked() { document.getElementById("v_replacement").value = currentElement.__msh_origWord; replaceWord(currentElement); currentElement.className = "HA-spellcheck-error HA-spellcheck-current"; return false; }; function replaceAllClicked() { var replacement = document.getElementById("v_replacement").value; var ok = true; var spans = allWords[currentElement.__msh_origWord]; if (spans.length == 0) { alert("An impossible condition just happened. Call FBI. ;-)"); } else if (spans.length == 1) { replaceClicked(); return false; } /* var message = "The word \"" + currentElement.__msh_origWord + "\" occurs " + spans.length + " times.\n"; if (replacement == currentElement.__msh_origWord) { ok = confirm(message + "Ignore all occurrences?"); } else { ok = confirm(message + "Replace all occurrences with \"" + replacement + "\"?"); } */ if (ok) { for (var i in spans) { if (spans[i] != currentElement) { replaceWord(spans[i]); } } // replace current element the last, so that we jump to the next word ;-) replaceClicked(); } return false; }; function ignoreClicked() { document.getElementById("v_replacement").value = currentElement.__msh_origWord; replaceClicked(); return false; }; function ignoreAllClicked() { document.getElementById("v_replacement").value = currentElement.__msh_origWord; replaceAllClicked(); return false; }; function learnClicked() { alert("Not [yet] implemented"); return false; }; function internationalizeWindow() { var types = ["div", "span", "button"]; for (var i in types) { var tag = types[i]; var els = document.getElementsByTagName(tag); for (var j = els.length; --j >= 0;) { var el = els[j]; if (el.childNodes.length == 1 && /\S/.test(el.innerHTML)) { var txt = el.innerHTML; if (typeof i18n[txt] != "undefined") { el.innerHTML = i18n[txt]; } } } } }; function initDocument() { internationalizeWindow(); modified = false; frame = document.getElementById("i_framecontent"); var field = document.getElementById("f_content"); field.value = HTMLArea.getHTML(editor._doc.body, false, editor); field.form.submit(); document.getElementById("f_init").value = "0"; // assign some global event handlers var select = document.getElementById("v_suggestions"); select.onchange = function() { document.getElementById("v_replacement").value = this.value; }; if (is_ie) { select.attachEvent("ondblclick", replaceClicked); } else { select.addEventListener("dblclick", replaceClicked, true); } document.getElementById("b_replace").onclick = replaceClicked; // document.getElementById("b_learn").onclick = learnClicked; document.getElementById("b_replall").onclick = replaceAllClicked; document.getElementById("b_ignore").onclick = ignoreClicked; document.getElementById("b_ignall").onclick = ignoreAllClicked; document.getElementById("b_recheck").onclick = recheckClicked; document.getElementById("b_revert").onclick = revertClicked; document.getElementById("b_info").onclick = displayInfo; document.getElementById("b_ok").onclick = saveClicked; document.getElementById("b_cancel").onclick = cancelClicked; select = document.getElementById("v_dictionaries"); select.onchange = function() { document.getElementById("f_dictionary").value = this.value; }; }; function getAbsolutePos(el) { var r = { x: el.offsetLeft, y: el.offsetTop }; if (el.offsetParent) { var tmp = getAbsolutePos(el.offsetParent); r.x += tmp.x; r.y += tmp.y; } return r; }; function wordClicked(scroll) { var self = this; if (scroll) (function() { var pos = getAbsolutePos(self); var ws = { x: frame.offsetWidth - 4, y: frame.offsetHeight - 4 }; var wp = { x: frame.contentWindow.document.body.scrollLeft, y: frame.contentWindow.document.body.scrollTop }; pos.x -= Math.round(ws.x/2); if (pos.x < 0) pos.x = 0; pos.y -= Math.round(ws.y/2); if (pos.y < 0) pos.y = 0; frame.contentWindow.scrollTo(pos.x, pos.y); })(); if (currentElement) { var a = allWords[currentElement.__msh_origWord]; currentElement.className = currentElement.className.replace(/\s*HA-spellcheck-current\s*/g, " "); for (var i in a) { var el = a[i]; if (el != currentElement) { el.className = el.className.replace(/\s*HA-spellcheck-same\s*/g, " "); } } } currentElement = this; this.className += " HA-spellcheck-current"; var a = allWords[currentElement.__msh_origWord]; for (var i in a) { var el = a[i]; if (el != currentElement) { el.className += " HA-spellcheck-same"; } } // document.getElementById("b_replall").disabled = (a.length <= 1); // document.getElementById("b_ignall").disabled = (a.length <= 1); var txt; if (a.length == 1) { txt = "one occurrence"; } else if (a.length == 2) { txt = "two occurrences"; } else { txt = a.length + " occurrences"; } var suggestions = suggested_words[this.__msh_origWord]; if (suggestions) suggestions = suggestions.split(/,/); else suggestions = []; var select = document.getElementById("v_suggestions"); document.getElementById("statusbar").innerHTML = "Found " + txt + ' for word "' + currentElement.__msh_origWord + '"'; for (var i = select.length; --i >= 0;) { select.remove(i); } for (var i = 0; i < suggestions.length; ++i) { var txt = suggestions[i]; var option = document.createElement("option"); option.value = txt; option.appendChild(document.createTextNode(txt)); select.appendChild(option); } document.getElementById("v_currentWord").innerHTML = this.__msh_origWord; if (suggestions.length > 0) { select.selectedIndex = 0; select.onchange(); } else { document.getElementById("v_replacement").value = this.innerHTML; } select.style.display = "none"; select.style.display = "block"; return false; }; function wordMouseOver() { this.className += " HA-spellcheck-hover"; }; function wordMouseOut() { this.className = this.className.replace(/\s*HA-spellcheck-hover\s*/g, " "); }; function displayInfo() { var info = frame.contentWindow.spellcheck_info; if (!info) alert("No information available"); else { var txt = "** Document information **"; for (var i in info) { txt += "\n" + i + " : " + info[i]; } alert(txt); } return false; }; function finishedSpellChecking() { // initialization of global variables currentElement = null; wrongWords = null; allWords = {}; fixedWords = []; suggested_words = frame.contentWindow.suggested_words; document.getElementById("status").innerHTML = "HTMLArea Spell Checker (info)"; var doc = frame.contentWindow.document; var spans = doc.getElementsByTagName("span"); var sps = []; var id = 0; for (var i = 0; i < spans.length; ++i) { var el = spans[i]; if (/HA-spellcheck-error/.test(el.className)) { sps.push(el); el.__msh_wordClicked = wordClicked; el.onclick = function(ev) { ev || (ev = window.event); ev && HTMLArea._stopEvent(ev); return this.__msh_wordClicked(false); }; el.onmouseover = wordMouseOver; el.onmouseout = wordMouseOut; el.__msh_id = id++; var txt = (el.__msh_origWord = el.firstChild.data); el.__msh_fixed = false; if (typeof allWords[txt] == "undefined") { allWords[txt] = [el]; } else { allWords[txt].push(el); } } else if (/HA-spellcheck-fixed/.test(el.className)) { fixedWords.push(el); } } wrongWords = sps; if (sps.length == 0) { if (!modified) { alert(i18n["NO_ERRORS_CLOSING"]); window.close(); } else { alert(i18n["NO_ERRORS"]); } return false; } (currentElement = sps[0]).__msh_wordClicked(true); var as = doc.getElementsByTagName("a"); for (var i = as.length; --i >= 0;) { var a = as[i]; a.onclick = function() { if (confirm(i18n["CONFIRM_LINK_CLICK"] + ":\n" + this.href + "\n" + i18n["I will open it in a new page."])) { window.open(this.href); } return false; }; } var dicts = doc.getElementById("HA-spellcheck-dictionaries"); if (dicts) { dicts.parentNode.removeChild(dicts); dicts = dicts.innerHTML.split(/,/); var select = document.getElementById("v_dictionaries"); for (var i = select.length; --i >= 0;) { select.remove(i); } for (var i = 0; i < dicts.length; ++i) { var txt = dicts[i]; var option = document.createElement("option"); if (/^@(.*)$/.test(txt)) { txt = RegExp.$1; option.selected = true; } option.value = txt; option.appendChild(document.createTextNode(txt)); select.appendChild(option); } } };