summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/compose/content/dialogs/EdSpellCheck.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/compose/content/dialogs/EdSpellCheck.js')
-rw-r--r--comm/mail/components/compose/content/dialogs/EdSpellCheck.js496
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();
+}