Bug 337155 SeaMonkey missing spellcheck language selector in mail compose window and preferences also backporting enhancements to Thunderbird

p=me r=mnyromyr(SM)/mscott(TB) sr=neil


git-svn-id: svn://10.0.0.236/trunk@201311 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
bugzilla%arlen.demon.co.uk
2006-06-29 23:10:04 +00:00
parent a41f1f4455
commit 526b5a512a
15 changed files with 612 additions and 258 deletions

View File

@@ -44,12 +44,14 @@ var gAllowSelectWord = true;
var gPreviousReplaceWord = "";
var gFirstTime = true;
var gLastSelectedLang = null;
var gDictCount = 0;
function Startup()
{
var sendMailMessageMode = false;
if (!GetCurrentEditor())
var editor = GetCurrentEditor();
if (!editor)
{
window.close();
return;
@@ -78,11 +80,8 @@ function Startup()
filterContractId = "@mozilla.org/editor/txtsrvfilter;1";
gSpellChecker.setFilter(Components.classes[filterContractId].createInstance(Components.interfaces.nsITextServicesFilter));
gSpellChecker.InitSpellChecker(GetCurrentEditor(), enableSelectionChecking);
gSpellChecker.InitSpellChecker(editor, enableSelectionChecking);
// XXX: We need to read in a pref here so we can set the
// default language for the spellchecker!
// gSpellChecker.SetCurrentDictionary();
}
catch(ex) {
dump("*** Exception error: InitSpellChecker\n");
@@ -146,7 +145,7 @@ function Startup()
gFirstTime = false;
}
function InitLanguageMenu(curLang)
function InitLanguageMenu(aCurLang)
{
var o1 = {};
@@ -155,9 +154,12 @@ function InitLanguageMenu(curLang)
// Get the list of dictionaries from
// the spellchecker.
try {
try
{
gSpellChecker.GetDictionaryList(o1, o2);
} catch(ex) {
}
catch(ex)
{
dump("Failed to get DictionaryList!\n");
return;
}
@@ -165,65 +167,84 @@ function InitLanguageMenu(curLang)
var dictList = o1.value;
var count = o2.value;
// If we're not just starting up and dictionary count
// hasn't changed then no need to update the menu.
if (gDictCount == count)
return;
// Store current dictionary count.
gDictCount = count;
// Load the string bundles that will help us map
// RFC 1766 strings to UI strings.
// Load the language string bundle.
var languageBundle = document.getElementById("languageBundle");
var regionBundle;
var regionBundle = null;
// If we have a language string bundle, load the region string bundle.
if (languageBundle)
regionBundle = document.getElementById("regionBundle");
var menuStr2;
var isoStrArray;
var defaultItem = null;
var langId;
var langLabel;
var i;
for (i = 0; i < dictList.length; i++)
for (i = 0; i < count; i++)
{
try {
try
{
langId = dictList[i];
isoStrArray = dictList[i].split("-");
dictList[i] = new Array(2); // first subarray element - pretty name
dictList[i][1] = langId; // second subarray element - language ID
if (languageBundle && isoStrArray[0])
dictList[i][0] = languageBundle.getString(isoStrArray[0].toLowerCase());
langLabel = languageBundle.getString(isoStrArray[0].toLowerCase());
if (regionBundle && dictList[i][0] && isoStrArray.length > 1 && isoStrArray[1])
if (regionBundle && langLabel && isoStrArray.length > 1 && isoStrArray[1])
{
menuStr2 = regionBundle.getString(isoStrArray[1].toLowerCase());
if (menuStr2)
dictList[i][0] = dictList[i][0] + "/" + menuStr2;
langLabel += "/" + menuStr2;
}
if (!dictList[i][0])
dictList[i][0] = dictList[i][1];
} catch (ex) {
// GetString throws an exception when
// a key is not found in the bundle. In that
// case, just use the original dictList string.
dictList[i][0] = dictList[i][1];
if (!langLabel)
langLabel = langId;
}
catch (ex)
{
// getString throws an exception when a key is not found in the
// bundle. In that case, just use the original dictList string.
langLabel = langId;
}
dictList[i] = [langLabel, langId];
}
// note this is not locale-aware collation, just simple ASCII-based sorting
// we really need to add loacel-aware JS collation, see bug XXXXX
dictList.sort();
// sort by locale-aware collation
dictList.sort(
function compareFn(a, b)
{
return a[0].localeCompare(b[0]);
}
);
for (i = 0; i < dictList.length; i++)
// Remove any languages from the list.
var languageMenuPopup = gDialog.LanguageMenulist.firstChild;
while (languageMenuPopup.firstChild.localName != "menuseparator")
languageMenuPopup.removeChild(languageMenuPopup.firstChild);
var defaultItem = null;
for (i = 0; i < count; i++)
{
var item = gDialog.LanguageMenulist.appendItem(dictList[i][0], dictList[i][1]);
if (curLang && dictList[i][1] == curLang)
var item = gDialog.LanguageMenulist.insertItemAt(i, dictList[i][0], dictList[i][1]);
if (aCurLang && dictList[i][1] == aCurLang)
defaultItem = item;
}
// Now make sure the correct item in the menu list is selected.
if (defaultItem) {
if (defaultItem)
{
gDialog.LanguageMenulist.selectedItem = defaultItem;
gLastSelectedLang = defaultItem;
}
@@ -448,7 +469,6 @@ function Recheck()
//TODO: Should we bother to add a "Recheck" method to interface?
try {
var curLang = gSpellChecker.GetCurrentDictionary();
gSpellChecker.UninitSpellChecker();
gSpellChecker.InitSpellChecker(GetCurrentEditor(), false);
gSpellChecker.SetCurrentDictionary(curLang);
@@ -535,14 +555,34 @@ function doDefault()
return false;
}
function CancelSpellCheck()
function ExitSpellChecker()
{
if (gSpellChecker)
{
try {
try
{
var curLang = gSpellChecker.GetCurrentDictionary();
gSpellChecker.UninitSpellChecker();
} finally { gSpellChecker = null; }
if ("@mozilla.org/spellchecker;1" in Components.classes) {
var spellChecker = Components.classes["@mozilla.org/spellchecker/myspell;1"]
.getService(Components.interfaces.mozISpellCheckingEngine);
spellChecker.dictionary = curLang;
}
// now check the document over again with the new dictionary
if ("inlineSpellChecker" in window.opener.InlineSpellChecker)
if (window.opener.InlineSpellChecker.inlineSpellChecker.enableRealTimeSpell)
window.opener.InlineSpellChecker.checkDocument(window.opener.content.document);
}
finally
{
gSpellChecker = null;
}
}
}
function CancelSpellCheck()
{
ExitSpellChecker();
// Signal to calling window that we canceled
window.opener.cancelSendMessage = true;
@@ -551,12 +591,8 @@ function CancelSpellCheck()
function onClose()
{
if (gSpellChecker)
{
try {
gSpellChecker.UninitSpellChecker();
} finally { gSpellChecker = null; }
}
ExitSpellChecker();
window.opener.cancelSendMessage = false;
window.close();
}

View File

@@ -127,10 +127,10 @@
accesskey="&languagePopup.accessKey;"/>
<row>
<menulist id="LanguageMenulist" oncommand="SelectLanguage()">
<menupopup>
<menuitem value="more-cmd" label="&moreDictionaries.label;"/>
<menuseparator/>
<menupopup onpopupshowing="InitLanguageMenu(gDialog.LanguageMenulist.selectedItem.value);">
<!-- dynamic content populated by JS -->
<menuseparator/>
<menuitem value="more-cmd" label="&moreDictionaries.label;"/>
</menupopup>
</menulist>
<hbox flex="1">

View File

@@ -56,7 +56,7 @@
<!ENTITY stopButton.label "Stop">
<!ENTITY stopButton.accessKey "t">
<!ENTITY userDictionary.label "Personal Dictionary:">
<!ENTITY moreDictionaries.label "Download More">
<!ENTITY moreDictionaries.label "Download more dictionaries...">
<!ENTITY addToUserDictionaryButton.label "Add Word">
<!ENTITY addToUserDictionaryButton.accessKey "d">
<!ENTITY editUserDictionaryButton.label "Edit...">

View File

@@ -4559,12 +4559,6 @@ to filter unwanted mail.</p>
<li><strong>Forward Messages</strong>: Choose how you want forwarded
message text to appear: as an attachment or <em>inline</em> (in the body
of your message).</li>
<li><strong>Check spelling before sending</strong>: Select this option to
have Mail &amp; Newsgroups always check the spelling of your message before
you send it.</li>
<li><strong>Check spelling as you type</strong>: Select this option to have
Mail &amp; Newsgroups always check the spelling of your message as you type
it.</li>
<li><strong>Automatically save the message every ___ minutes</strong>: Choose
this option if you want Mail &amp; Newsgroups to save the message you are
currently composing automatically at the given interval. After a computer
@@ -4577,6 +4571,15 @@ to filter unwanted mail.</p>
keyboard shortcut by mistake when composing a message.</li>
<li><strong>Wrap plain text messages at ___ characters</strong>: Enter a
number to set the right margin for text in the message area.</li>
<li><strong>Check spelling before sending</strong>: Select this option to
have Mail &amp; Newsgroups always check the spelling of your message before
you send it.</li>
<li><strong>Check spelling as you type</strong>: Select this option to have
Mail &amp; Newsgroups always check the spelling of your message as you type
it.</li>
<li><strong>Language</strong>: Use the drop-down list to select the language
you want to use to check the spelling in your messages or to download more
dictionaries.</li>
<li><strong>Defaults for HTML Messages</strong>: Here you can define what the
defaults are for font, size, text and background color if you choose to
send mails in HTML format.</li>

View File

@@ -44,12 +44,14 @@ var gAllowSelectWord = true;
var gPreviousReplaceWord = "";
var gFirstTime = true;
var gLastSelectedLang = null;
var gDictCount = 0;
function Startup()
{
var sendMailMessageMode = false;
if (!GetCurrentEditor())
var editor = GetCurrentEditor();
if (!editor)
{
window.close();
return;
@@ -78,11 +80,8 @@ function Startup()
filterContractId = "@mozilla.org/editor/txtsrvfilter;1";
gSpellChecker.setFilter(Components.classes[filterContractId].createInstance(Components.interfaces.nsITextServicesFilter));
gSpellChecker.InitSpellChecker(GetCurrentEditor(), enableSelectionChecking);
gSpellChecker.InitSpellChecker(editor, enableSelectionChecking);
// XXX: We need to read in a pref here so we can set the
// default language for the spellchecker!
// gSpellChecker.SetCurrentDictionary();
}
catch(ex) {
dump("*** Exception error: InitSpellChecker\n");
@@ -146,7 +145,7 @@ function Startup()
gFirstTime = false;
}
function InitLanguageMenu(curLang)
function InitLanguageMenu(aCurLang)
{
var o1 = {};
@@ -155,9 +154,12 @@ function InitLanguageMenu(curLang)
// Get the list of dictionaries from
// the spellchecker.
try {
try
{
gSpellChecker.GetDictionaryList(o1, o2);
} catch(ex) {
}
catch(ex)
{
dump("Failed to get DictionaryList!\n");
return;
}
@@ -165,65 +167,83 @@ function InitLanguageMenu(curLang)
var dictList = o1.value;
var count = o2.value;
// If dictionary count hasn't changed then no need to update the menu.
if (gDictCount == count)
return;
// Store current dictionary count.
gDictCount = count;
// Load the string bundles that will help us map
// RFC 1766 strings to UI strings.
// Load the language string bundle.
var languageBundle = document.getElementById("languageBundle");
var regionBundle;
var regionBundle = null;
// If we have a language string bundle, load the region string bundle.
if (languageBundle)
regionBundle = document.getElementById("regionBundle");
var menuStr2;
var isoStrArray;
var defaultItem = null;
var langId;
var langLabel;
var i;
for (i = 0; i < dictList.length; i++)
for (i = 0; i < count; i++)
{
try {
try
{
langId = dictList[i];
isoStrArray = dictList[i].split("-");
dictList[i] = new Array(2); // first subarray element - pretty name
dictList[i][1] = langId; // second subarray element - language ID
if (languageBundle && isoStrArray[0])
dictList[i][0] = languageBundle.getString(isoStrArray[0].toLowerCase());
langLabel = languageBundle.getString(isoStrArray[0].toLowerCase());
if (regionBundle && dictList[i][0] && isoStrArray.length > 1 && isoStrArray[1])
if (regionBundle && langLabel && isoStrArray.length > 1 && isoStrArray[1])
{
menuStr2 = regionBundle.getString(isoStrArray[1].toLowerCase());
if (menuStr2)
dictList[i][0] = dictList[i][0] + "/" + menuStr2;
langLabel += "/" + menuStr2;
}
if (!dictList[i][0])
dictList[i][0] = dictList[i][1];
} catch (ex) {
// GetString throws an exception when
// a key is not found in the bundle. In that
// case, just use the original dictList string.
dictList[i][0] = dictList[i][1];
if (!langLabel)
langLabel = langId;
}
catch (ex)
{
// getString throws an exception when a key is not found in the
// bundle. In that case, just use the original dictList string.
langLabel = langId;
}
dictList[i] = [langLabel, langId];
}
// note this is not locale-aware collation, just simple ASCII-based sorting
// we really need to add loacel-aware JS collation, see bug XXXXX
dictList.sort();
// sort by locale-aware collation
dictList.sort(
function compareFn(a, b)
{
return a[0].localeCompare(b[0]);
}
);
for (i = 0; i < dictList.length; i++)
// Remove any languages from the list.
var languageMenuPopup = gDialog.LanguageMenulist.firstChild;
while (languageMenuPopup.firstChild.localName != "menuseparator")
languageMenuPopup.removeChild(languageMenuPopup.firstChild);
var defaultItem = null;
for (i = 0; i < count; i++)
{
var item = gDialog.LanguageMenulist.appendItem(dictList[i][0], dictList[i][1]);
if (curLang && dictList[i][1] == curLang)
var item = gDialog.LanguageMenulist.insertItemAt(i, dictList[i][0], dictList[i][1]);
if (aCurLang && dictList[i][1] == aCurLang)
defaultItem = item;
}
// Now make sure the correct item in the menu list is selected.
if (defaultItem) {
if (defaultItem)
{
gDialog.LanguageMenulist.selectedItem = defaultItem;
gLastSelectedLang = defaultItem;
}
@@ -452,7 +472,6 @@ function Recheck()
//TODO: Should we bother to add a "Recheck" method to interface?
try {
var curLang = gSpellChecker.GetCurrentDictionary();
gSpellChecker.UninitSpellChecker();
gSpellChecker.InitSpellChecker(GetCurrentEditor(), false);
gSpellChecker.SetCurrentDictionary(curLang);
@@ -539,14 +558,34 @@ function doDefault()
return false;
}
function CancelSpellCheck()
function ExitSpellChecker()
{
if (gSpellChecker)
{
try {
try
{
var curLang = gSpellChecker.GetCurrentDictionary();
gSpellChecker.UninitSpellChecker();
} finally { gSpellChecker = null; }
if ("@mozilla.org/spellchecker;1" in Components.classes) {
var spellChecker = Components.classes["@mozilla.org/spellchecker/myspell;1"]
.getService(Components.interfaces.mozISpellCheckingEngine);
spellChecker.dictionary = curLang;
}
// now check the document over again with the new dictionary
if ("inlineSpellChecker" in window.opener.InlineSpellChecker)
if (window.opener.InlineSpellChecker.inlineSpellChecker.enableRealTimeSpell)
window.opener.InlineSpellChecker.checkDocument(window.opener.content.document);
}
finally
{
gSpellChecker = null;
}
}
}
function CancelSpellCheck()
{
ExitSpellChecker();
// Signal to calling window that we canceled
window.opener.cancelSendMessage = true;
@@ -555,12 +594,8 @@ function CancelSpellCheck()
function onClose()
{
if (gSpellChecker)
{
try {
gSpellChecker.UninitSpellChecker();
} finally { gSpellChecker = null; }
}
ExitSpellChecker();
window.opener.cancelSendMessage = false;
window.close();
}

View File

@@ -39,14 +39,15 @@
/**
* interfaces
*/
var nsIMsgCompDeliverMode = Components.interfaces.nsIMsgCompDeliverMode;
var nsIMsgCompSendFormat = Components.interfaces.nsIMsgCompSendFormat;
var nsIMsgCompConvertible = Components.interfaces.nsIMsgCompConvertible;
var nsIMsgCompType = Components.interfaces.nsIMsgCompType;
var nsIMsgCompFormat = Components.interfaces.nsIMsgCompFormat;
var nsIAbPreferMailFormat = Components.interfaces.nsIAbPreferMailFormat;
var nsIPlaintextEditorMail = Components.interfaces.nsIPlaintextEditor;
const nsIMsgCompDeliverMode = Components.interfaces.nsIMsgCompDeliverMode;
const nsIMsgCompSendFormat = Components.interfaces.nsIMsgCompSendFormat;
const nsIMsgCompConvertible = Components.interfaces.nsIMsgCompConvertible;
const nsIMsgCompType = Components.interfaces.nsIMsgCompType;
const nsIMsgCompFormat = Components.interfaces.nsIMsgCompFormat;
const nsIAbPreferMailFormat = Components.interfaces.nsIAbPreferMailFormat;
const nsIPlaintextEditorMail = Components.interfaces.nsIPlaintextEditor;
const nsISupportsString = Components.interfaces.nsISupportsString;
const mozISpellCheckingEngine = Components.interfaces.mozISpellCheckingEngine;
/**
* In order to distinguish clearly globals that are initialized once when js load (static globals) and those that need to be
@@ -66,6 +67,7 @@ var sOther_headers = "";
var sAccountManagerDataSource = null;
var sRDF = null;
var sNameProperty = null;
var sDictCount = 0;
/* Create message window object. This is use by mail-offline.js and therefore should not be renamed. We need to avoid doing
this kind of cross file global stuff in the future and instead pass this object as parameter when needed by function
@@ -1361,7 +1363,6 @@ function ComposeStartup(recycled, aParams)
// Do setup common to Message Composer and Web Composer
EditorSharedStartup();
initLanguageMenu();
}
var msgCompFields = gMsgCompose.compFields;
@@ -2188,12 +2189,14 @@ function ToggleInlineSpellChecker(target)
}
}
function initLanguageMenu()
function InitLanguageMenu()
{
var languageMenuList = document.getElementById('LanguageMenulist');
if (!languageMenuList) return;
var languageMenuList = document.getElementById('languageMenuList');
if (!languageMenuList)
return;
var spellChecker = Components.classes['@mozilla.org/spellchecker/myspell;1'].getService(Components.interfaces.mozISpellCheckingEngine);
var spellChecker = Components.classes['@mozilla.org/spellchecker/myspell;1']
.getService(mozISpellCheckingEngine);
var o1 = {};
var o2 = {};
@@ -2205,87 +2208,100 @@ function initLanguageMenu()
var dictList = o1.value;
var count = o2.value;
// Load the string bundles that will help us map
// RFC 1766 strings to UI strings.
// If dictionary count hasn't changed then no need to update the menu.
if (sDictCount == count)
return;
// Load the language string bundle.
// Store current dictionary count.
sDictCount = count;
// Load the string bundle that will help us map
// RFC 1766 strings to UI strings.
var languageBundle = document.getElementById("languageBundle");
var isoStrArray;
var langId;
var langLabel;
var i;
for (i = 0; i < dictList.length; i++)
for (i = 0; i < count; i++)
{
try {
try
{
langId = dictList[i];
isoStrArray = dictList[i].split("-");
dictList[i] = new Array(2); // first subarray element - pretty name
dictList[i][1] = langId; // second subarray element - language ID
if (languageBundle && isoStrArray[0])
dictList[i][0] = languageBundle.getString(isoStrArray[0].toLowerCase());
langLabel = languageBundle.getString(isoStrArray[0].toLowerCase());
// the user needs to be able to distinguish between the UK English dictionary
// and say the United States English Dictionary. If we have a isoStr value then
// wrap it in parentheses and append it to the menu item string. i.e.
// English (US) and English (UK)
if (!dictList[i][0])
dictList[i][0] = dictList[i][1];
if (!langLabel)
langLabel = langId;
else if (isoStrArray.length > 1 && isoStrArray[1]) // if we have a language ID like US or UK, append it to the menu item
dictList[i][0] += ' (' + isoStrArray[1] + ')';
} catch (ex) {
// GetString throws an exception when
// a key is not found in the bundle. In that
// case, just use the original dictList string.
dictList[i][0] = dictList[i][1];
langLabel += ' (' + isoStrArray[1] + ')';
}
catch (ex)
{
// getString throws an exception when a key is not found in the
// bundle. In that case, just use the original dictList string.
langLabel = langId;
}
dictList[i] = [langLabel, langId];
}
// note this is not locale-aware collation, just simple ASCII-based sorting
// we really need to add locale-aware JS collation
dictList.sort();
// sort by locale-aware collation
dictList.sort(
function compareFn(a, b)
{
return a[0].localeCompare(b[0]);
}
);
// now select the dictionary we are currently using
for (i = 0; i < dictList.length; i++)
// Remove any languages from the list.
while (languageMenuList.hasChildNodes())
languageMenuList.removeChild(languageMenuList.firstChild);
for (i = 0; i < count; i++)
{
var item = document.createElement("menuitem");
item.setAttribute("label", dictList[i][0]);
item.setAttribute("value", dictList[i][1]);
item.setAttribute('type', 'radio');
item.setAttribute('oncommand', "changeLanguage(event)");
languageMenuList.appendChild(item);
}
}
function onShowDictionaryMenu()
function OnShowDictionaryMenu(aTarget)
{
var curLang = sPrefs.getComplexValue("spellchecker.dictionary", Components.interfaces.nsISupportsString).data;
var languageMenuList = document.getElementById('LanguageMenulist');
var languages = languageMenuList.getElementsByAttribute('value', curLang);
languages[0].setAttribute('checked', true);
InitLanguageMenu();
var curLang = sPrefs.getComplexValue("spellchecker.dictionary", nsISupportsString).data;
var languages = aTarget.getElementsByAttribute("value", curLang);
if (languages.length > 0)
languages[0].setAttribute("checked", true);
}
function changeLanguage(event)
function ChangeLanguage(event)
{
// We need to change the dictionary language and if we are using inline spell check,
// recheck the message
var spellChecker = Components.classes['@mozilla.org/spellchecker/myspell;1'].getService(Components.interfaces.mozISpellCheckingEngine);
var spellChecker = Components.classes['@mozilla.org/spellchecker/myspell;1']
.getService(mozISpellCheckingEngine);
if (spellChecker.dictionary != event.target.value)
{
spellChecker.dictionary = event.target.value;
var str = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
.createInstance(nsISupportsString);
str.data = event.target.value;
sPrefs.setComplexValue("spellchecker.dictionary", Components.interfaces.nsISupportsString, str);
sPrefs.setComplexValue("spellchecker.dictionary", nsISupportsString, str);
// now check the document over again with the new dictionary
InlineSpellChecker.checkDocument(window.content.document);
if (InlineSpellChecker.inlineSpellChecker)
if (InlineSpellChecker.inlineSpellChecker.enableRealTimeSpell)
InlineSpellChecker.checkDocument(window.content.document);
}
event.stopPropagation();
}

View File

@@ -610,9 +610,9 @@
<toolbarbutton class="toolbarbutton-1" type="menu-button"
id="spellingButton" label="&spellingButton.label;"
command="cmd_spelling">
<menupopup id="LanguageMenulist" onpopupshowing="onShowDictionaryMenu();">
<!-- this popup gets dynamically generated -->
</menupopup>
<!-- this popup gets dynamically generated -->
<menupopup id="languageMenuList" oncommand="ChangeLanguage(event);"
onpopupshowing="OnShowDictionaryMenu(event.target);"/>
</toolbarbutton>
<toolbarbutton class="toolbarbutton-1" type="menu-button"

View File

@@ -45,6 +45,7 @@ var gComposePane = {
mDirectories: null,
mLDAPPrefsService: null,
mSpellChecker: null,
mDictCount : 0,
init: function ()
{
@@ -299,7 +300,6 @@ var gComposePane = {
this.mSpellChecker = Components.classes['@mozilla.org/spellchecker/myspell;1'].getService(Components.interfaces.mozISpellCheckingEngine);
var o1 = {};
var o2 = {};
var languageMenuList = document.getElementById('LanguageMenulist');
// Get the list of dictionaries from
// the spellchecker.
@@ -309,60 +309,73 @@ var gComposePane = {
var dictList = o1.value;
var count = o2.value;
// If dictionary count hasn't changed then no need to update the menu.
if (this.mDictCount == count)
return;
// Store current dictionary count.
this.mDictCount = count;
// Load the string bundles that will help us map
// RFC 1766 strings to UI strings.
// Load the language string bundle.
var languageBundle = document.getElementById("languageBundle");
var regionBundle;
var regionBundle = null;
// If we have a language string bundle, load the region string bundle.
if (languageBundle)
regionBundle = document.getElementById("regionBundle");
var menuStr2;
var isoStrArray;
var defaultItem = null;
var langId;
var langLabel;
var i;
for (i = 0; i < dictList.length; i++)
for (i = 0; i < count; i++)
{
try {
langId = dictList[i];
isoStrArray = dictList[i].split("-");
dictList[i] = new Array(2); // first subarray element - pretty name
dictList[i][1] = langId; // second subarray element - language ID
if (languageBundle && isoStrArray[0])
dictList[i][0] = languageBundle.getString(isoStrArray[0].toLowerCase());
langLabel = languageBundle.getString(isoStrArray[0].toLowerCase());
if (regionBundle && dictList[i][0] && isoStrArray.length > 1 && isoStrArray[1])
if (regionBundle && langLabel && isoStrArray.length > 1 && isoStrArray[1])
{
menuStr2 = regionBundle.getString(isoStrArray[1].toLowerCase());
if (menuStr2)
dictList[i][0] = dictList[i][0] + "/" + menuStr2;
langLabel += "/" + menuStr2;
}
if (!dictList[i][0])
dictList[i][0] = dictList[i][1];
if (!langLabel)
langLabel = langId;
} catch (ex) {
// GetString throws an exception when
// a key is not found in the bundle. In that
// case, just use the original dictList string.
dictList[i][0] = dictList[i][1];
// getString throws an exception when a key is not found in the
// bundle. In that case, just use the original dictList string.
langLabel = langId;
}
dictList[i] = [langLabel, langId];
}
// note this is not locale-aware collation, just simple ASCII-based sorting
// we really need to add loacel-aware JS collation, see bug XXXXX
dictList.sort();
// sort by locale-aware collation
dictList.sort(
function compareFn(a, b)
{
return a[0].localeCompare(b[0]);
}
);
var languageMenuList = document.getElementById("languageMenuList");
// Remove any languages from the list.
var languageMenuPopup = languageMenuList.firstChild;
while (languageMenuPopup.hasChildNodes())
languageMenuPopup.removeChild(languageMenuPopup.firstChild);
var curLang = languageMenuList.value;
var defaultItem = null;
// now select the dictionary we are currently using
for (i = 0; i < dictList.length; i++)
for (i = 0; i < count; i++)
{
var item = languageMenuList.appendItem(dictList[i][0], dictList[i][1]);
if (curLang && dictList[i][1] == curLang)

View File

@@ -192,9 +192,9 @@
<separator class="thin"/>
<hbox align="center" pack="start">
<label value ="&languagePopup.label;" control="LanguageMenulist" accesskey="&languagePopup.accessKey;"/>
<menulist id="LanguageMenulist" preference="spellchecker.dictionary">
<menupopup>
<label value ="&languagePopup.label;" control="languageMenuList" accesskey="&languagePopup.accessKey;"/>
<menulist id="languageMenuList" preference="spellchecker.dictionary">
<menupopup onpopupshowing="gComposePane.initLanguageMenu();">
<!-- dynamic content populated by JS -->
</menupopup>
</menulist>

View File

@@ -0,0 +1,140 @@
var gAutoSaveInterval;
var gLastSelectedLang;
var gDictCount = 0;
function Startup() {
if ("@mozilla.org/spellchecker;1" in Components.classes)
InitLanguageMenu();
else
document.getElementById("spellingGroup").hidden = true;
gAutoSaveInterval = document.getElementById("autoSaveInterval");
EnableTextbox(document.getElementById("autoSave"), gAutoSaveInterval, true);
}
function EnableTextbox(aCheckbox, aTextbox, aStartingUp) {
aTextbox.disabled = (!aCheckbox.checked ||
parent.hPrefWindow.getPrefIsLocked(aTextbox.getAttribute("prefstring")));
if (!aTextbox.disabled && !aStartingUp)
aTextbox.focus();
}
function PopulateFonts() {
var fontsList = document.getElementById("fontSelect");
try {
var enumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"]
.getService(Components.interfaces.nsIFontEnumerator);
var localFontCount = { value: 0 }
var localFonts = enumerator.EnumerateAllFonts(localFontCount);
for (var i = 0; i < localFonts.length; ++i) {
if (localFonts[i] != "") {
fontsList.appendItem(localFonts[i], localFonts[i]);
}
}
} catch (ex) { }
}
function InitLanguageMenu() {
var spellChecker = Components.classes["@mozilla.org/spellchecker/myspell;1"]
.getService(Components.interfaces.mozISpellCheckingEngine);
var o1 = {};
var o2 = {};
// Get the list of dictionaries from the spellchecker.
spellChecker.getDictionaryList(o1, o2);
var dictList = o1.value;
var count = o2.value;
// If dictionary count hasn't changed then no need to update the menu.
if (gDictCount == count)
return;
// Store current dictionary count.
gDictCount = count;
// Load the string bundles that will help us map
// RFC 1766 strings to UI strings.
// Load the language string bundle.
var languageBundle = document.getElementById("languageBundle");
var regionBundle = null;
// If we have a language string bundle, load the region string bundle.
if (languageBundle)
regionBundle = document.getElementById("regionBundle");
var menuStr2;
var isoStrArray;
var langId;
var langLabel;
var i;
for (i = 0; i < count; i++) {
try {
langId = dictList[i];
isoStrArray = dictList[i].split("-");
if (languageBundle && isoStrArray[0])
langLabel = languageBundle.getString(isoStrArray[0].toLowerCase());
if (regionBundle && langLabel && isoStrArray.length > 1 && isoStrArray[1]) {
menuStr2 = regionBundle.getString(isoStrArray[1].toLowerCase());
if (menuStr2)
langLabel += "/" + menuStr2;
}
if (!langLabel)
langLabel = langId;
} catch (ex) {
// getString throws an exception when a key is not found in the
// bundle. In that case, just use the original dictList string.
langLabel = langId;
}
dictList[i] = [langLabel, langId];
}
// sort by locale-aware collation
dictList.sort(
function compareFn(a, b) {
return a[0].localeCompare(b[0]);
}
);
var languageMenuList = document.getElementById("languageMenuList");
// Remove any languages from the list.
var languageMenuPopup = languageMenuList.firstChild;
while (languageMenuPopup.firstChild.localName != "menuseparator")
languageMenuPopup.removeChild(languageMenuPopup.firstChild);
var curLang = languageMenuList.value;
var defaultItem = null;
for (i = 0; i < count; i++) {
var item = languageMenuList.insertItemAt(i, dictList[i][0], dictList[i][1]);
if (curLang && dictList[i][1] == curLang)
defaultItem = item;
}
// Now make sure the correct item in the menu list is selected.
if (defaultItem) {
languageMenuList.selectedItem = defaultItem;
gLastSelectedLang = defaultItem;
}
}
function SelectLanguage(aTarget) {
try {
if (aTarget.value != "more-cmd")
gLastSelectedLang = aTarget;
else {
window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no",
xlateURL('urn:clienturl:composer:spellcheckers'));
if (gLastSelectedLang)
document.getElementById("languageMenuList").selectedItem = gLastSelectedLang;
}
} catch (ex) {
dump(ex);
}
}

View File

@@ -2,6 +2,8 @@
<?xml-stylesheet href="chrome://communicator/skin/" type="text/css"?>
<?xul-overlay href="chrome://communicator/content/utilityOverlay.xul"?>
<!DOCTYPE page [
<!ENTITY % pref-composing_messagesDTD SYSTEM "chrome://messenger/locale/messengercompose/pref-composing_messages.dtd" >
%pref-composing_messagesDTD;
@@ -10,56 +12,25 @@
]>
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="populateFonts();parent.initPanel('chrome://messenger/content/messengercompose/pref-composing_messages.xul');"
onload="PopulateFonts();parent.initPanel('chrome://messenger/content/messengercompose/pref-composing_messages.xul');"
headertitle="&pref.composing.messages.title;">
<stringbundle id="languageBundle" src="chrome://global/locale/languageNames.properties"/>
<stringbundle id="regionBundle" src="chrome://global/locale/regionNames.properties"/>
<script type="application/x-javascript" src="chrome://messenger/content/messengercompose/pref-composing_messages.js"/>
<script type="application/x-javascript">
<![CDATA[
var _elementIDs = ["forwardMessageMode", "autoSave",
"autoSaveInterval","spellCheckBeforeSend", "inlineSpellCheck",
"mailWarnOnSendAccelKey", "wrapLength", "FontSelect",
var _elementIDs = ["forwardMessageMode", "autoSave", "autoSaveInterval",
"spellCheckBeforeSend", "inlineSpellCheck", "languageMenuList",
"mailWarnOnSendAccelKey", "wrapLength", "fontSelect",
"fontSizeSelect", "textColor", "backgroundColor"];
var gAutoSaveInterval;
function Startup()
{
var hideSpellCheck = !("@mozilla.org/spellchecker;1" in Components.classes);
document.getElementById("spellCheckBeforeSend").hidden = hideSpellCheck;
document.getElementById("inlineSpellCheck").hidden = hideSpellCheck;
gAutoSaveInterval = document.getElementById("autoSaveInterval");
enableTextbox(document.getElementById("autoSave"), gAutoSaveInterval, true);
}
function enableTextbox(checkbox, textbox, startingUp) {
textbox.disabled = (!checkbox.checked ||
parent.hPrefWindow.getPrefIsLocked(textbox.getAttribute("prefstring")));
if (!textbox.disabled && !startingUp)
textbox.focus();
}
function populateFonts() {
var fontsList = document.getElementById("FontSelect");
try {
var enumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"]
.getService(Components.interfaces.nsIFontEnumerator);
var localFontCount = { value: 0 }
var localFonts = enumerator.EnumerateAllFonts(localFontCount);
for (var i = 0; i < localFonts.length; ++i) {
if (localFonts[i] != "") {
fontsList.appendItem(localFonts[i], localFonts[i]);
}
}
}
catch(e) { }
}
]]>
</script>
<groupbox>
<caption label="&forwardReply.label;"/>
<caption label="&generalComposing.label;"/>
<radiogroup id="forwardMessageMode" orient="horizontal" align="center"
prefstring="mail.forward_message_mode">
<label value="&forwardMsg.label;"/>
@@ -67,28 +38,14 @@
<radio value="0" label="&asAttachment.label;"
accesskey="&asAttachment.accesskey;"/>
</radiogroup>
</groupbox>
<!-- Composing Mail -->
<groupbox align="start">
<caption label="&sendingMessagesHeader.label;"/>
<vbox align="start">
<checkbox id="spellCheckBeforeSend" label="&spellCheck.label;"
prefstring="mail.SpellCheckBeforeSend"
accesskey="&spellCheck.accesskey;"/>
<checkbox id="inlineSpellCheck" label="&spellCheckInline.label;"
prefstring="mail.spellcheck.inline"
accesskey="&spellCheckInline.accesskey;"/>
</vbox>
<hbox align="center">
<checkbox id="autoSave" label="&autoSave.label;"
prefstring="mail.compose.autosave"
accesskey="&autoSave.accesskey;"
oncommand="enableTextbox(this, gAutoSaveInterval, false);"/>
<textbox id="autoSaveInterval" size="2" preftype="int"
prefstring="mail.compose.autosaveinterval"/>
oncommand="EnableTextbox(this, gAutoSaveInterval, false);"/>
<textbox id="autoSaveInterval" size="2" preftype="int"
prefstring="mail.compose.autosaveinterval"/>
<label value="&autoSaveEnd.label;"/>
</hbox>
@@ -102,15 +59,44 @@
prefstring="mailnews.wraplength" prefattribute="value"/>
<label value="&char.label;"/>
</hbox>
</groupbox>
<!-- Composing Mail -->
<groupbox id="spellingGroup" align="start">
<caption label="&spellingHeader.label;"/>
<vbox align="start">
<checkbox id="spellCheckBeforeSend" label="&spellCheck.label;"
prefstring="mail.SpellCheckBeforeSend"
accesskey="&spellCheck.accesskey;"/>
<checkbox id="inlineSpellCheck" label="&spellCheckInline.label;"
prefstring="mail.spellcheck.inline"
accesskey="&spellCheckInline.accesskey;"/>
</vbox>
<separator class="thin"/>
<hbox align="center" pack="start">
<label value="&languagePopup.label;" control="languageMenuList"
accesskey="&languagePopup.accessKey;"/>
<menulist id="languageMenuList" oncommand="SelectLanguage(event.target)"
preftype="localizedstring" prefstring="spellchecker.dictionary">
<menupopup onpopupshowing="InitLanguageMenu();">
<!-- dynamic content populated by JS -->
<menuseparator/>
<menuitem value="more-cmd" label="&moreDictionaries.label;"/>
</menupopup>
</menulist>
<spring flex="1"/>
</hbox>
</groupbox>
<groupbox align="start">
<caption label="&defaultMessagesHeader.label;"/>
<caption label="&defaultMessagesHeader.label;"/>
<vbox>
<hbox align="center">
<label control="FontSelect" value="&font.label;" accesskey="&font.accesskey;"/>
<menulist id="FontSelect" preftype="string" prefstring="msgcompose.font_face">
<label control="fontSelect" value="&font.label;" accesskey="&font.accesskey;"/>
<menulist id="fontSelect" preftype="string" prefstring="msgcompose.font_face">
<menupopup>
<menuitem value="" label="&fontVarWidth.label;"/>
<menuitem value="tt" label="&fontFixedWidth.label;"/>
@@ -120,7 +106,7 @@
<menuitem value="Courier New, Courier, monospace" label="&fontCourier.label;"/>
<menuseparator/>
</menupopup>
</menulist>
</menulist>
</hbox>
<hbox align="center">
<label control="fontSizeSelect" value="&size.label;" accesskey="&size.accesskey;"/>
@@ -136,10 +122,10 @@
</menulist>
<label control="textColor" value="&fontColor.label;" accesskey="&fontColor.accesskey;"/>
<colorpicker type="button" id="textColor" prefstring="msgcompose.text_color"/>
<label control="backgroundColor" value="&bgColor.label;" accesskey="&bgColor.accesskey;"/>
<label control="backgroundColor" value="&bgColor.label;" accesskey="&bgColor.accesskey;"/>
<colorpicker type="button" id="backgroundColor" prefstring="msgcompose.background_color"/>
</hbox>
</vbox>
</vbox>
</groupbox>
</page>

View File

@@ -37,7 +37,7 @@
***** END LICENSE BLOCK ***** -->
<!ENTITY pref.composing.messages.title "Composition">
<!ENTITY forwardReply.label "Forwarding Messages">
<!ENTITY generalComposing.label "General">
<!ENTITY forwardMsg.label "Forward messages:">
<!ENTITY inline.label "Inline">
<!ENTITY inline.accesskey "n">
@@ -46,22 +46,25 @@
<!ENTITY warnOnSendAccelKey.label "Confirm when using keyboard shortcut to send message">
<!ENTITY warnOnSendAccelKey.accesskey "k">
<!ENTITY sendingMessagesHeader.label "Composing Messages">
<!-- LOCALIZATION NOTE (autoSave.label): This will concatenate with
"xxx minutes", using a number and (autoSaveEnd.label). -->
<!ENTITY autoSave.label "Automatically save the message every">
<!ENTITY autoSave.accesskey "u">
<!ENTITY autoSaveEnd.label "minutes">
<!ENTITY spellCheck.label "Check spelling before sending">
<!ENTITY spellCheck.accesskey "C">
<!ENTITY spellCheckInline.label "Check spelling as you type">
<!ENTITY spellCheckInline.accesskey "e">
<!-- LOCALIZATION NOTE (wrapOutMsg.label): This will concatenate with "xxx characters", using a number and (char.label). -->
<!ENTITY wrapOutMsg.label "Wrap plain text messages at">
<!ENTITY wrapOutMsg.accesskey "W">
<!ENTITY char.label "characters">
<!ENTITY spellingHeader.label "Spelling">
<!ENTITY spellCheck.label "Check spelling before sending">
<!ENTITY spellCheck.accesskey "C">
<!ENTITY spellCheckInline.label "Check spelling as you type">
<!ENTITY spellCheckInline.accesskey "e">
<!ENTITY languagePopup.label "Language:">
<!ENTITY languagePopup.accessKey "g">
<!ENTITY moreDictionaries.label "Download more dictionaries...">
<!ENTITY defaultMessagesHeader.label "Defaults for HTML Messages">
<!ENTITY font.label "Font:">
<!ENTITY font.accesskey "F">

View File

@@ -40,14 +40,15 @@
/**
* interfaces
*/
var nsIMsgCompDeliverMode = Components.interfaces.nsIMsgCompDeliverMode;
var nsIMsgCompSendFormat = Components.interfaces.nsIMsgCompSendFormat;
var nsIMsgCompConvertible = Components.interfaces.nsIMsgCompConvertible;
var nsIMsgCompType = Components.interfaces.nsIMsgCompType;
var nsIMsgCompFormat = Components.interfaces.nsIMsgCompFormat;
var nsIAbPreferMailFormat = Components.interfaces.nsIAbPreferMailFormat;
var nsIPlaintextEditorMail = Components.interfaces.nsIPlaintextEditor;
const nsIMsgCompDeliverMode = Components.interfaces.nsIMsgCompDeliverMode;
const nsIMsgCompSendFormat = Components.interfaces.nsIMsgCompSendFormat;
const nsIMsgCompConvertible = Components.interfaces.nsIMsgCompConvertible;
const nsIMsgCompType = Components.interfaces.nsIMsgCompType;
const nsIMsgCompFormat = Components.interfaces.nsIMsgCompFormat;
const nsIAbPreferMailFormat = Components.interfaces.nsIAbPreferMailFormat;
const nsIPlaintextEditorMail = Components.interfaces.nsIPlaintextEditor;
const nsISupportsString = Components.interfaces.nsISupportsString;
const mozISpellCheckingEngine = Components.interfaces.mozISpellCheckingEngine;
/**
* In order to distinguish clearly globals that are initialized once when js load (static globals) and those that need to be
@@ -67,6 +68,7 @@ var sOther_headers = "";
var sAccountManagerDataSource = null;
var sRDF = null;
var sNameProperty = null;
var sDictCount = 0;
/* Create message window object. This is use by mail-offline.js and therefore should not be renamed. We need to avoid doing
this kind of cross file global stuff in the future and instead pass this object as parameter when needed by function
@@ -2114,6 +2116,120 @@ function ToggleInlineSpellChecker(target)
}
}
function InitLanguageMenu()
{
var languageMenuList = document.getElementById("languageMenuList");
if (!languageMenuList)
return;
var spellChecker = Components.classes["@mozilla.org/spellchecker/myspell;1"]
.getService(mozISpellCheckingEngine);
var o1 = {};
var o2 = {};
// Get the list of dictionaries from the spellchecker.
spellChecker.getDictionaryList(o1, o2);
var dictList = o1.value;
var count = o2.value;
// If dictionary count hasn't changed then no need to update the menu.
if (sDictCount == count)
return;
// Store current dictionary count.
sDictCount = count;
// Load the language string bundle that will help us map
// RFC 1766 strings to UI strings.
var languageBundle = document.getElementById("languageBundle");
var isoStrArray;
var langId;
var langLabel;
var i;
for (i = 0; i < count; i++)
{
try
{
langId = dictList[i];
isoStrArray = dictList[i].split("-");
if (languageBundle && isoStrArray[0])
langLabel = languageBundle.getString(isoStrArray[0].toLowerCase());
// the user needs to be able to distinguish between the UK English dictionary
// and say the United States English Dictionary. If we have a isoStr value then
// wrap it in parentheses and append it to the menu item string. i.e.
// English (US) and English (UK)
if (!langLabel)
langLabel = langId;
else if (isoStrArray.length > 1 && isoStrArray[1]) // if we have a language ID like US or UK, append it to the menu item
langLabel += ' (' + isoStrArray[1] + ')';
}
catch (ex)
{
// getString throws an exception when a key is not found in the
// bundle. In that case, just use the original dictList string.
langLabel = langId;
}
dictList[i] = [langLabel, langId];
}
// sort by locale-aware collation
dictList.sort(
function compareFn(a, b)
{
return a[0].localeCompare(b[0]);
}
);
// Remove any languages from the list.
while (languageMenuList.hasChildNodes())
languageMenuList.removeChild(languageMenuList.firstChild);
for (i = 0; i < count; i++)
{
var item = document.createElement("menuitem");
item.setAttribute("label", dictList[i][0]);
item.setAttribute("value", dictList[i][1]);
item.setAttribute("type", "radio");
languageMenuList.appendChild(item);
}
}
function OnShowDictionaryMenu(aTarget)
{
InitLanguageMenu();
var curLang = sPrefs.getComplexValue("spellchecker.dictionary", nsISupportsString).data;
var languages = aTarget.getElementsByAttribute("value", curLang);
if (languages.length > 0)
languages[0].setAttribute("checked", true);
}
function ChangeLanguage(event)
{
// We need to change the dictionary language and if we are using inline spell check,
// recheck the message
var spellChecker = Components.classes["@mozilla.org/spellchecker/myspell;1"]
.getService(mozISpellCheckingEngine);
if (spellChecker.dictionary != event.target.value)
{
spellChecker.dictionary = event.target.value;
var str = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(nsISupportsString);
str.data = event.target.value;
sPrefs.setComplexValue("spellchecker.dictionary", nsISupportsString, str);
// now check the document over again with the new dictionary
if (InlineSpellChecker.inlineSpellChecker)
if (InlineSpellChecker.inlineSpellChecker.enableRealTimeSpell)
InlineSpellChecker.checkDocument(window.content.document);
}
event.stopPropagation();
}
function ToggleReturnReceipt(target)
{
var msgCompFields = gMsgCompose.compFields;

View File

@@ -85,6 +85,7 @@
<stringbundle id="bundle_composeMsgs" src="chrome://messenger/locale/messengercompose/composeMsgs.properties"/>
<stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
<stringbundle id="bundle_offlinePrompts" src="chrome://messenger/locale/offline.properties"/>
<stringbundle id="languageBundle" src="chrome://global/locale/languageNames.properties"/>
</stringbundleset>
<script type="application/x-javascript" src="chrome://communicator/content/contentAreaDD.js"/>
@@ -457,9 +458,13 @@
<menuitem type="checkbox" label="&attachVCardCmd.label;" accesskey="&attachVCardCmd.accesskey;" command="cmd_attachVCard"/>
</menupopup>
</toolbarbutton>
<toolbarbutton class="toolbarbutton-1"
<toolbarbutton class="toolbarbutton-1" type="menu-button"
id="spellingButton" label="&spellingButton.label;"
command="cmd_spelling"/>
command="cmd_spelling">
<!-- this popup gets dynamically generated -->
<menupopup id="languageMenuList" oncommand="ChangeLanguage(event);"
onpopupshowing="OnShowDictionaryMenu(event.target);"/>
</toolbarbutton>
<toolbarseparator id="saveSeparator" class="toolbarseparator-primary"/>
<toolbarbutton class="toolbarbutton-1" type="menu-button"
id="button-save" label="&saveButton.label;"

View File

@@ -167,6 +167,7 @@ messenger.jar:
content/messenger/junkLog.xul (base/resources/content/junkLog.xul)
content/messenger/junkLog.js (base/resources/content/junkLog.js)
content/messenger/messengercompose/pref-composing_messages.xul (compose/prefs/resources/content/pref-composing_messages.xul)
content/messenger/messengercompose/pref-composing_messages.js (compose/prefs/resources/content/pref-composing_messages.js)
content/messenger/messengercompose/pref-formatting.xul (compose/prefs/resources/content/pref-formatting.xul)
content/messenger/messengercompose/pref-formatting.js (compose/prefs/resources/content/pref-formatting.js)
content/messenger/messengercompose/messengercompose.xul (compose/resources/content/messengercompose.xul)