diff options
Diffstat (limited to '')
-rw-r--r-- | comm/mail/components/compose/content/dialogs/EdSpellCheck.js | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/comm/mail/components/compose/content/dialogs/EdSpellCheck.js b/comm/mail/components/compose/content/dialogs/EdSpellCheck.js new file mode 100644 index 0000000000..5b54205bc3 --- /dev/null +++ b/comm/mail/components/compose/content/dialogs/EdSpellCheck.js @@ -0,0 +1,496 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* import-globals-from ../../../../base/content/utilityOverlay.js */ +/* import-globals-from ../editorUtilities.js */ +/* import-globals-from EdDialogCommon.js */ + +var { InlineSpellChecker } = ChromeUtils.importESModule( + "resource://gre/modules/InlineSpellChecker.sys.mjs" +); + +var gMisspelledWord; +var gSpellChecker = null; +var gAllowSelectWord = true; +var gPreviousReplaceWord = ""; +var gFirstTime = true; +var gDictCount = 0; + +document.addEventListener("dialogaccept", doDefault); +document.addEventListener("dialogcancel", CancelSpellCheck); + +function Startup() { + var editor = GetCurrentEditor(); + if (!editor) { + window.close(); + return; + } + + // Get the spellChecker shell + gSpellChecker = Cu.createSpellChecker(); + if (!gSpellChecker) { + dump("SpellChecker not found!!!\n"); + window.close(); + return; + } + + // Start the spell checker module. + try { + var skipBlockQuotes = window.arguments[1]; + var enableSelectionChecking = window.arguments[2]; + + gSpellChecker.setFilterType( + skipBlockQuotes + ? Ci.nsIEditorSpellCheck.FILTERTYPE_MAIL + : Ci.nsIEditorSpellCheck.FILTERTYPE_NORMAL + ); + gSpellChecker.InitSpellChecker( + editor, + enableSelectionChecking, + spellCheckStarted + ); + } catch (ex) { + dump("*** Exception error: InitSpellChecker\n"); + window.close(); + } +} + +function spellCheckStarted() { + gDialog.MisspelledWordLabel = document.getElementById("MisspelledWordLabel"); + gDialog.MisspelledWord = document.getElementById("MisspelledWord"); + gDialog.ReplaceButton = document.getElementById("Replace"); + gDialog.IgnoreButton = document.getElementById("Ignore"); + gDialog.StopButton = document.getElementById("Stop"); + gDialog.CloseButton = document.getElementById("Close"); + gDialog.ReplaceWordInput = document.getElementById("ReplaceWordInput"); + gDialog.SuggestedList = document.getElementById("SuggestedList"); + gDialog.LanguageMenulist = document.getElementById("LanguageMenulist"); + + // Fill in the language menulist and sync it up + // with the spellchecker's current language. + + var curLangs; + + try { + curLangs = new Set(gSpellChecker.getCurrentDictionaries()); + } catch (ex) { + curLangs = new Set(); + } + + InitLanguageMenu(curLangs); + + // Get the first misspelled word and setup all UI + NextWord(); + + // When startup param is true, setup different UI when spell checking + // just before sending mail message + if (window.arguments[0]) { + // If no misspelled words found, simply close dialog and send message + if (!gMisspelledWord) { + onClose(); + return; + } + + // Hide "Close" button and use "Send" instead + gDialog.CloseButton.hidden = true; + gDialog.CloseButton = document.getElementById("Send"); + gDialog.CloseButton.hidden = false; + } else { + // Normal spell checking - hide the "Stop" button + // (Note that this button is the "Cancel" button for + // Esc keybinding and related window close actions) + gDialog.StopButton.hidden = true; + } + + // Clear flag that determines message when + // no misspelled word is found + // (different message when used for the first time) + gFirstTime = false; + + window.sizeToContent(); +} + +/** + * Populate the dictionary language selector menu. + * + * @param {Set<string>} activeDictionaries - Currently active dictionaries. + */ +function InitLanguageMenu(activeDictionaries) { + // Get the list of dictionaries from + // the spellchecker. + + var dictList; + try { + dictList = gSpellChecker.GetDictionaryList(); + } catch (ex) { + dump("Failed to get DictionaryList!\n"); + return; + } + + // If we're not just starting up and dictionary count + // hasn't changed then no need to update the menu. + if (gDictCount == dictList.length) { + return; + } + + // Store current dictionary count. + gDictCount = dictList.length; + + var inlineSpellChecker = new InlineSpellChecker(); + var sortedList = inlineSpellChecker.sortDictionaryList(dictList); + + // Remove any languages from the list. + let list = document.getElementById("dictionary-list"); + let template = document.getElementById("language-item"); + + list.replaceChildren( + ...sortedList.map(({ displayName, localeCode }) => { + let item = template.content.cloneNode(true); + item.querySelector(".checkbox-label").textContent = displayName; + let input = item.querySelector("input"); + input.addEventListener("input", () => { + SelectLanguage(localeCode); + }); + input.checked = activeDictionaries.has(localeCode); + return item; + }) + ); +} + +function DoEnabling() { + if (!gMisspelledWord) { + // No more misspelled words + gDialog.MisspelledWord.setAttribute( + "value", + GetString(gFirstTime ? "NoMisspelledWord" : "CheckSpellingDone") + ); + + gDialog.ReplaceButton.removeAttribute("default"); + gDialog.IgnoreButton.removeAttribute("default"); + + gDialog.CloseButton.setAttribute("default", "true"); + // Shouldn't have to do this if "default" is true? + gDialog.CloseButton.focus(); + + SetElementEnabledById("MisspelledWordLabel", false); + SetElementEnabledById("ReplaceWordLabel", false); + SetElementEnabledById("ReplaceWordInput", false); + SetElementEnabledById("CheckWord", false); + SetElementEnabledById("SuggestedListLabel", false); + SetElementEnabledById("SuggestedList", false); + SetElementEnabledById("Ignore", false); + SetElementEnabledById("IgnoreAll", false); + SetElementEnabledById("Replace", false); + SetElementEnabledById("ReplaceAll", false); + SetElementEnabledById("AddToDictionary", false); + } else { + SetElementEnabledById("MisspelledWordLabel", true); + SetElementEnabledById("ReplaceWordLabel", true); + SetElementEnabledById("ReplaceWordInput", true); + SetElementEnabledById("CheckWord", true); + SetElementEnabledById("SuggestedListLabel", true); + SetElementEnabledById("SuggestedList", true); + SetElementEnabledById("Ignore", true); + SetElementEnabledById("IgnoreAll", true); + SetElementEnabledById("AddToDictionary", true); + + gDialog.CloseButton.removeAttribute("default"); + SetReplaceEnable(); + } +} + +function NextWord() { + gMisspelledWord = gSpellChecker.GetNextMisspelledWord(); + SetWidgetsForMisspelledWord(); +} + +function SetWidgetsForMisspelledWord() { + gDialog.MisspelledWord.setAttribute("value", gMisspelledWord); + + // Initial replace word is misspelled word + gDialog.ReplaceWordInput.value = gMisspelledWord; + gPreviousReplaceWord = gMisspelledWord; + + // This sets gDialog.ReplaceWordInput to first suggested word in list + FillSuggestedList(gMisspelledWord); + + DoEnabling(); + + if (gMisspelledWord) { + SetTextboxFocus(gDialog.ReplaceWordInput); + } +} + +function CheckWord() { + var word = gDialog.ReplaceWordInput.value; + if (word) { + if (gSpellChecker.CheckCurrentWord(word)) { + FillSuggestedList(word); + SetReplaceEnable(); + } else { + ClearListbox(gDialog.SuggestedList); + var item = gDialog.SuggestedList.appendItem( + GetString("CorrectSpelling"), + "" + ); + if (item) { + item.setAttribute("disabled", "true"); + } + // Suppress being able to select the message text + gAllowSelectWord = false; + } + } +} + +function SelectSuggestedWord() { + if (gAllowSelectWord) { + if (gDialog.SuggestedList.selectedItem) { + var selValue = gDialog.SuggestedList.selectedItem.label; + gDialog.ReplaceWordInput.value = selValue; + gPreviousReplaceWord = selValue; + } else { + gDialog.ReplaceWordInput.value = gPreviousReplaceWord; + } + SetReplaceEnable(); + } +} + +function ChangeReplaceWord() { + // Calling this triggers SelectSuggestedWord(), + // so temporarily suppress the effect of that + var saveAllow = gAllowSelectWord; + gAllowSelectWord = false; + + // Select matching word in list + var newSelectedItem; + var replaceWord = TrimString(gDialog.ReplaceWordInput.value); + if (replaceWord) { + for (var i = 0; i < gDialog.SuggestedList.getRowCount(); i++) { + var item = gDialog.SuggestedList.getItemAtIndex(i); + if (item.label == replaceWord) { + newSelectedItem = item; + break; + } + } + } + gDialog.SuggestedList.selectedItem = newSelectedItem; + + gAllowSelectWord = saveAllow; + + // Remember the new word + gPreviousReplaceWord = gDialog.ReplaceWordInput.value; + + SetReplaceEnable(); +} + +function Ignore() { + NextWord(); +} + +function IgnoreAll() { + if (gMisspelledWord) { + gSpellChecker.IgnoreWordAllOccurrences(gMisspelledWord); + } + NextWord(); +} + +function Replace(newWord) { + if (!newWord) { + return; + } + + if (gMisspelledWord && gMisspelledWord != newWord) { + var editor = GetCurrentEditor(); + editor.beginTransaction(); + try { + gSpellChecker.ReplaceWord(gMisspelledWord, newWord, false); + } catch (e) {} + editor.endTransaction(); + } + NextWord(); +} + +function ReplaceAll() { + var newWord = gDialog.ReplaceWordInput.value; + if (gMisspelledWord && gMisspelledWord != newWord) { + var editor = GetCurrentEditor(); + editor.beginTransaction(); + try { + gSpellChecker.ReplaceWord(gMisspelledWord, newWord, true); + } catch (e) {} + editor.endTransaction(); + } + NextWord(); +} + +function AddToDictionary() { + if (gMisspelledWord) { + gSpellChecker.AddWordToDictionary(gMisspelledWord); + } + NextWord(); +} + +function EditDictionary() { + window.openDialog( + "chrome://messenger/content/messengercompose/EdDictionary.xhtml", + "_blank", + "chrome,close,titlebar,modal", + "", + gMisspelledWord + ); +} + +/** + * Change the selection state of the given dictionary language. + * + * @param {string} language + */ +function SelectLanguage(language) { + let activeDictionaries = new Set(gSpellChecker.getCurrentDictionaries()); + if (activeDictionaries.has(language)) { + activeDictionaries.delete(language); + } else { + activeDictionaries.add(language); + } + let activeDictionariesArray = Array.from(activeDictionaries); + gSpellChecker.setCurrentDictionaries(activeDictionariesArray); + // For compose windows we need to set the "lang" attribute so the + // core editor uses the correct dictionary for the inline spell check. + if (window.arguments[1]) { + if ("ComposeChangeLanguage" in window.opener) { + // We came here from a compose window. + window.opener.ComposeChangeLanguage(activeDictionariesArray); + } else if (activeDictionaries.size === 1) { + window.opener.document.documentElement.setAttribute( + "lang", + activeDictionariesArray[0] + ); + } else { + window.opener.document.documentElement.setAttribute("lang", ""); + } + } +} + +function Recheck() { + var recheckLanguages; + + function finishRecheck() { + gSpellChecker.setCurrentDictionaries(recheckLanguages); + gMisspelledWord = gSpellChecker.GetNextMisspelledWord(); + SetWidgetsForMisspelledWord(); + } + + // TODO: Should we bother to add a "Recheck" method to interface? + try { + recheckLanguages = gSpellChecker.getCurrentDictionaries(); + gSpellChecker.UninitSpellChecker(); + // Clear the ignore all list. + Cc["@mozilla.org/spellchecker/personaldictionary;1"] + .getService(Ci.mozIPersonalDictionary) + .endSession(); + gSpellChecker.InitSpellChecker(GetCurrentEditor(), false, finishRecheck); + } catch (ex) { + console.error(ex); + } +} + +function FillSuggestedList(misspelledWord) { + var list = gDialog.SuggestedList; + + // Clear the current contents of the list + gAllowSelectWord = false; + ClearListbox(list); + var item; + + if (misspelledWord.length > 0) { + // Get suggested words until an empty string is returned + var count = 0; + do { + var word = gSpellChecker.GetSuggestedWord(); + if (word.length > 0) { + list.appendItem(word, ""); + count++; + } + } while (word.length > 0); + + if (count == 0) { + // No suggestions - show a message but don't let user select it + item = list.appendItem(GetString("NoSuggestedWords")); + if (item) { + item.setAttribute("disabled", "true"); + } + gAllowSelectWord = false; + } else { + gAllowSelectWord = true; + // Initialize with first suggested list by selecting it + gDialog.SuggestedList.selectedIndex = 0; + } + } else { + item = list.appendItem("", ""); + if (item) { + item.setAttribute("disabled", "true"); + } + } +} + +function SetReplaceEnable() { + // Enable "Change..." buttons only if new word is different than misspelled + var newWord = gDialog.ReplaceWordInput.value; + var enable = newWord.length > 0 && newWord != gMisspelledWord; + SetElementEnabledById("Replace", enable); + SetElementEnabledById("ReplaceAll", enable); + if (enable) { + gDialog.ReplaceButton.setAttribute("default", "true"); + gDialog.IgnoreButton.removeAttribute("default"); + } else { + gDialog.IgnoreButton.setAttribute("default", "true"); + gDialog.ReplaceButton.removeAttribute("default"); + } +} + +function doDefault(event) { + if (gDialog.ReplaceButton.getAttribute("default") == "true") { + Replace(gDialog.ReplaceWordInput.value); + } else if (gDialog.IgnoreButton.getAttribute("default") == "true") { + Ignore(); + } else if (gDialog.CloseButton.getAttribute("default") == "true") { + onClose(); + } + + event.preventDefault(); +} + +function ExitSpellChecker() { + if (gSpellChecker) { + try { + gSpellChecker.UninitSpellChecker(); + // now check the document over again with the new dictionary + // if we have an inline spellchecker + if ( + "InlineSpellCheckerUI" in window.opener && + window.opener.InlineSpellCheckerUI.enabled + ) { + window.opener.InlineSpellCheckerUI.mInlineSpellChecker.spellCheckRange( + null + ); + } + } finally { + gSpellChecker = null; + } + } +} + +function CancelSpellCheck() { + ExitSpellChecker(); + + // Signal to calling window that we canceled + window.opener.cancelSendMessage = true; +} + +function onClose() { + ExitSpellChecker(); + + window.opener.cancelSendMessage = false; + window.close(); +} |