Bug 352037 - Add an "Undo add to dictionary" item to spell checker's context menu item; r=ehsan

This commit is contained in:
Quentin Headen 2011-12-29 16:06:56 -05:00
parent c8de934380
commit 6236efde57
10 changed files with 170 additions and 8 deletions

View File

@ -46,6 +46,10 @@
label="&spellAddToDictionary.label;"
accesskey="&spellAddToDictionary.accesskey;"
oncommand="InlineSpellCheckerUI.addToDictionary();"/>
<menuitem id="spell-undo-add-to-dictionary"
label="&spellUndoAddToDictionary.label;"
accesskey="&spellUndoAddToDictionary.accesskey;"
oncommand="InlineSpellCheckerUI.undoAddToDictionary();" />
<menuseparator id="spell-suggestions-separator"/>
<menuitem id="context-openlinkincurrent"
label="&openLinkCmdInCurrent.label;"

View File

@ -337,6 +337,7 @@ nsContextMenu.prototype = {
.setAttribute("checked", canSpell && InlineSpellCheckerUI.enabled);
this.showItem("spell-add-to-dictionary", onMisspelling);
this.showItem("spell-undo-add-to-dictionary", InlineSpellCheckerUI.canUndo());
// suggestion list
this.showItem("spell-suggestions-separator", onMisspelling);

View File

@ -19,6 +19,7 @@ Browser context menu tests.
/** Test for Login Manager: multiple login autocomplete. **/
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
const Cc = Components.classes;
const Ci = Components.interfaces;
@ -514,12 +515,36 @@ function runTest(testNum) {
"---", null,
"spell-add-dictionaries", true], null,
].concat(inspectItems));
contextMenu.ownerDocument.getElementById("spell-add-to-dictionary").doCommand(); // Add to dictionary
closeContextMenu();
openContextMenuFor(contenteditable); // Invoke context menu for next test.
openContextMenuFor(textarea, false, true); // Invoke context menu for next test.
break;
case 15:
// Context menu for textarea after a word has been added
// to the dictionary
checkContextMenu(["spell-undo-add-to-dictionary", true,
"context-undo", false,
"---", null,
"context-cut", false,
"context-copy", false,
"context-paste", null, // ignore clipboard state
"context-delete", false,
"---", null,
"context-selectall", true,
"---", null,
"spell-check-enabled", true,
"spell-dictionaries", true,
["spell-check-dictionary-en-US", true,
"---", null,
"spell-add-dictionaries", true], null,
].concat(inspectItems));
contextMenu.ownerDocument.getElementById("spell-undo-add-to-dictionary").doCommand(); // Undo add to dictionary
closeContextMenu();
openContextMenuFor(contenteditable);
break;
case 15:
case 16:
// Context menu for contenteditable
checkContextMenu(["spell-no-suggestions", false,
"spell-add-to-dictionary", true,
@ -544,7 +569,7 @@ function runTest(testNum) {
openContextMenuFor(inputspell); // Invoke context menu for next test.
break;
case 16:
case 17:
// Context menu for spell-check input
checkContextMenu(["*prodigality", true, // spelling suggestion
"spell-add-to-dictionary", true,
@ -569,13 +594,13 @@ function runTest(testNum) {
openContextMenuFor(link); // Invoke context menu for next test.
break;
case 17:
case 18:
executeCopyCommand("cmd_copyLink", "http://mozilla.com/");
closeContextMenu();
openContextMenuFor(pagemenu); // Invoke context menu for next test.
break;
case 18:
case 19:
// Context menu for element with assigned content context menu
checkContextMenu(["+Plain item", {type: "", icon: "", checked: false, disabled: false},
"+Disabled item", {type: "", icon: "", checked: false, disabled: true},
@ -618,7 +643,7 @@ function runTest(testNum) {
openContextMenuFor(pagemenu, true); // Invoke context menu for next test.
break;
case 19:
case 20:
// Context menu for element with assigned content context menu
// The shift key should bypass content context menu processing
checkContextMenu(["context-back", false,

View File

@ -43,7 +43,7 @@ interface nsISelection;
interface nsIEditor;
interface nsIEditorSpellCheck;
[scriptable, uuid(f456dda1-965d-470c-8c55-e51b38e45212)]
[scriptable, uuid(df635540-d073-47b8-8678-18776130691d)]
interface nsIInlineSpellChecker : nsISupports
{
@ -68,6 +68,7 @@ interface nsIInlineSpellChecker : nsISupports
nsIDOMRange getMisspelledWord(in nsIDOMNode aNode, in long aOffset);
void replaceWord(in nsIDOMNode aNode, in long aOffset, in AString aNewword);
void addWordToDictionary(in AString aWord);
void removeWordFromDictionary(in AString aWord);
void ignoreWord(in AString aWord);
void ignoreWords([array, size_is(aCount)] in wstring aWordsToIgnore, in unsigned long aCount);

View File

@ -869,6 +869,24 @@ mozInlineSpellChecker::AddWordToDictionary(const nsAString &word)
return ScheduleSpellCheck(status);
}
// mozInlineSpellChecker::RemoveWordFromDictionary
NS_IMETHODIMP
mozInlineSpellChecker::RemoveWordFromDictionary(const nsAString &word)
{
NS_ENSURE_TRUE(mSpellCheck, NS_ERROR_NOT_INITIALIZED);
nsAutoString wordstr(word);
nsresult rv = mSpellCheck->RemoveWordFromDictionary(wordstr.get());
NS_ENSURE_SUCCESS(rv, rv);
mozInlineSpellStatus status(this);
nsCOMPtr<nsIRange> range = do_QueryInterface(NULL); // Check everything
rv = status.InitForRange(range);
NS_ENSURE_SUCCESS(rv, rv);
return ScheduleSpellCheck(status);
}
// mozInlineSpellChecker::IgnoreWord
NS_IMETHODIMP

View File

@ -38,9 +38,11 @@
var EXPORTED_SYMBOLS = [ "InlineSpellChecker" ];
var gLanguageBundle;
var gRegionBundle;
const MAX_UNDO_STACK_DEPTH = 1;
function InlineSpellChecker(aEditor) {
this.init(aEditor);
this.mAddedWordStack = []; // We init this here to preserve it between init/uninit calls
}
InlineSpellChecker.prototype = {
@ -284,8 +286,27 @@ InlineSpellChecker.prototype = {
// callback for adding the current misspelling to the user-defined dictionary
addToDictionary: function()
{
// Prevent the undo stack from growing over the max depth
if (this.mAddedWordStack.length == MAX_UNDO_STACK_DEPTH)
this.mAddedWordStack.shift();
this.mAddedWordStack.push(this.mMisspelling);
this.mInlineSpellChecker.addWordToDictionary(this.mMisspelling);
},
// callback for removing the last added word to the dictionary LIFO fashion
undoAddToDictionary: function()
{
if (this.mAddedWordStack.length > 0)
{
var word = this.mAddedWordStack.pop();
this.mInlineSpellChecker.removeWordFromDictionary(word);
}
},
canUndo : function()
{
// Return true if we have words on the stack
return (this.mAddedWordStack.length > 0);
},
ignoreWord: function()
{
this.mInlineSpellChecker.ignoreWord(this.mMisspelling);

View File

@ -144,6 +144,7 @@ _TEST_FILES += \
test_textbox_emptytext.xul \
test_textbox_number.xul \
test_textbox_search.xul \
test_textbox_dictionary.xul\
test_toolbar.xul \
xul_selectcontrol.js \
test_popupincontent.xul \

View File

@ -0,0 +1,85 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<!--
XUL Widget Test for textbox with placeholder
-->
<window title="Textbox Add and Undo Add Dictionary Test" width="500" height="600"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<hbox>
<textbox id="t1" value="Hellop" oncontextmenu="runContextMenuTest()" spellcheck="true"/>
</hbox>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
SimpleTest.waitForExplicitFinish();
var textbox;
var testNum;
function bringUpContextMenu(element)
{
synthesizeMouseAtCenter(element, { type: "contextmenu", button: 2});
}
function leftClickElement(element)
{
synthesizeMouseAtCenter(element, { button: 0 });
}
function startTests()
{
textbox = document.getElementById("t1");
textbox.focus();
testNum = 0;
SimpleTest.executeSoon( function() { bringUpContextMenu(textbox); });
}
function runContextMenuTest()
{
SimpleTest.executeSoon( function() {
// The textbox has its children in an hbox XUL element, so get that first
var hbox = document.getAnonymousNodes(textbox).item(0);
var contextMenu = document.getAnonymousElementByAttribute(hbox, "anonid", "input-box-contextmenu");
switch(testNum)
{
case 0: // "Add to Dictionary" button
var addToDict = contextMenu.querySelector("[anonid=spell-add-to-dictionary]");
is(!addToDict.hidden, true, "Is Add to Dictionary visible?");
addToDict.doCommand();
contextMenu.hidePopup();
testNum++;
SimpleTest.executeSoon( function() {bringUpContextMenu(textbox); }); // Bring up the menu again to invoke the next test
break;
case 1: // "Undo Add to Dictionary" button
var undoAddDict = contextMenu.querySelector("[anonid=spell-undo-add-to-dictionary]");
is(!undoAddDict.hidden, true, "Is Undo Add to Dictioanry visible?");
undoAddDict.doCommand();
contextMenu.hidePopup();
SimpleTest.finish();
break;
}
});
}
SimpleTest.waitForFocus(startTests);
]]></script>
</window>

View File

@ -515,6 +515,8 @@
<xul:menuitem label="&spellNoSuggestions.label;" anonid="spell-no-suggestions" disabled="true"/>
<xul:menuitem label="&spellAddToDictionary.label;" accesskey="&spellAddToDictionary.accesskey;" anonid="spell-add-to-dictionary"
oncommand="this.parentNode.parentNode.spellCheckerUI.addToDictionary();"/>
<xul:menuitem label="&spellUndoAddToDictionary.label;" accesskey="&spellUndoAddToDictionary.accesskey;" anonid="spell-undo-add-to-dictionary"
oncommand="this.parentNode.parentNode.spellCheckerUI.undoAddToDictionary();"/>
<xul:menuseparator anonid="spell-suggestions-separator"/>
<xul:menuitem label="&undoCmd.label;" accesskey="&undoCmd.accesskey;" cmd="cmd_undo"/>
<xul:menuseparator/>
@ -580,6 +582,7 @@
this._setMenuItemVisibility("spell-check-enabled", false);
this._setMenuItemVisibility("spell-check-separator", false);
this._setMenuItemVisibility("spell-add-to-dictionary", false);
this._setMenuItemVisibility("spell-undo-add-to-dictionary", false);
this._setMenuItemVisibility("spell-suggestions-separator", false);
this._setMenuItemVisibility("spell-dictionaries", false);
return;
@ -593,6 +596,7 @@
var overMisspelling = spellui.overMisspelling;
this._setMenuItemVisibility("spell-add-to-dictionary", overMisspelling);
this._setMenuItemVisibility("spell-undo-add-to-dictionary", spellui.canUndo());
this._setMenuItemVisibility("spell-suggestions-separator", overMisspelling);
// suggestion list

View File

@ -13,6 +13,8 @@
<!ENTITY spellAddToDictionary.label "Add to Dictionary">
<!ENTITY spellAddToDictionary.accesskey "o">
<!ENTITY spellUndoAddToDictionary.label "Undo Add To Dictionary">
<!ENTITY spellUndoAddToDictionary.accesskey "n">
<!ENTITY spellCheckEnable.label "Check Spelling">
<!ENTITY spellCheckEnable.accesskey "S">
<!ENTITY spellNoSuggestions.label "(No Spelling Suggestions)">