From d52ae1cb31dbfd54ad41e4de06372082ba8ee158 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 1 Jun 2010 14:08:38 -0400 Subject: [PATCH] Bug 433860 - No spelling suggestions for text inputs when contenteditable node in document; r=gavin --- browser/base/content/nsContextMenu.js | 76 ++++++------- .../base/content/test/subtst_contextmenu.html | 3 + .../base/content/test/test_contextmenu.html | 104 ++++++++++++++++-- toolkit/content/InlineSpellChecker.jsm | 3 +- 4 files changed, 140 insertions(+), 46 deletions(-) diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 0b241ac491a9..56737bb01ef0 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -87,7 +87,7 @@ function nsContextMenu(aXulMenu, aBrowser) { this.isContentSelected = false; this.shouldDisplay = true; this.isDesignMode = false; - this.possibleSpellChecking = false; + this.onEditableArea = false; this.ellipsis = "\u2026"; try { this.ellipsis = gPrefService.getComplexValue("intl.ellipsis", @@ -367,7 +367,7 @@ nsContextMenu.prototype = { var canSpell = InlineSpellCheckerUI.canSpellCheck; var onMisspelling = InlineSpellCheckerUI.overMisspelling; this.showItem("spell-check-enabled", canSpell); - this.showItem("spell-separator", canSpell || this.possibleSpellChecking); + this.showItem("spell-separator", canSpell || this.onEditableArea); if (canSpell) { document.getElementById("spell-check-enabled") .setAttribute("checked", InlineSpellCheckerUI.enabled); @@ -395,7 +395,7 @@ nsContextMenu.prototype = { InlineSpellCheckerUI.addDictionaryListToMenu(dictMenu, dictSep); this.showItem("spell-add-dictionaries-main", false); } - else if (this.possibleSpellChecking) { + else if (this.onEditableArea) { // when there is no spellchecker but we might be able to spellcheck // add the add to dictionaries item. This will ensure that people // with no dictionaries will be able to download them @@ -503,7 +503,7 @@ nsContextMenu.prototype = { this.inFrame = false; this.hasBGImage = false; this.bgImageURL = ""; - this.possibleSpellChecking = false; + this.onEditableArea = false; // Clear any old spellchecking items from the menu, this used to // be in the menu hiding code but wasn't getting called in all @@ -552,7 +552,7 @@ nsContextMenu.prototype = { // allow spellchecking UI on all writable text boxes except passwords if (this.onTextInput && ! this.target.readOnly && this.target.type != "password") { - this.possibleSpellChecking = true; + this.onEditableArea = true; InlineSpellCheckerUI.init(this.target.QueryInterface(Ci.nsIDOMNSEditableElement).editor); InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset); } @@ -561,7 +561,7 @@ nsContextMenu.prototype = { else if (this.target instanceof HTMLTextAreaElement) { this.onTextInput = true; if (!this.target.readOnly) { - this.possibleSpellChecking = true; + this.onEditableArea = true; InlineSpellCheckerUI.init(this.target.QueryInterface(Ci.nsIDOMNSEditableElement).editor); InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset); } @@ -662,39 +662,41 @@ nsContextMenu.prototype = { this.inFrame = true; // if the document is editable, show context menu like in text inputs - var win = this.target.ownerDocument.defaultView; - if (win) { - var isEditable = false; - try { - var editingSession = win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIEditingSession); - if (editingSession.windowIsEditable(win) && - this.getComputedStyle(this.target, "-moz-user-modify") == "read-write") { - isEditable = true; + if (!this.onEditableArea) { + var win = this.target.ownerDocument.defaultView; + if (win) { + var isEditable = false; + try { + var editingSession = win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIEditingSession); + if (editingSession.windowIsEditable(win) && + this.getComputedStyle(this.target, "-moz-user-modify") == "read-write") { + isEditable = true; + } + } + catch(ex) { + // If someone built with composer disabled, we can't get an editing session. } - } - catch(ex) { - // If someone built with composer disabled, we can't get an editing session. - } - if (isEditable) { - this.onTextInput = true; - this.onKeywordField = false; - this.onImage = false; - this.onLoadedImage = false; - this.onCompletedImage = false; - this.onMathML = false; - this.inFrame = false; - this.hasBGImage = false; - this.isDesignMode = true; - this.possibleSpellChecking = true; - InlineSpellCheckerUI.init(editingSession.getEditorForWindow(win)); - var canSpell = InlineSpellCheckerUI.canSpellCheck; - InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset); - this.showItem("spell-check-enabled", canSpell); - this.showItem("spell-separator", canSpell); + if (isEditable) { + this.onTextInput = true; + this.onKeywordField = false; + this.onImage = false; + this.onLoadedImage = false; + this.onCompletedImage = false; + this.onMathML = false; + this.inFrame = false; + this.hasBGImage = false; + this.isDesignMode = true; + this.onEditableArea = true; + InlineSpellCheckerUI.init(editingSession.getEditorForWindow(win)); + var canSpell = InlineSpellCheckerUI.canSpellCheck; + InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset); + this.showItem("spell-check-enabled", canSpell); + this.showItem("spell-separator", canSpell); + } } } }, diff --git a/browser/base/content/test/subtst_contextmenu.html b/browser/base/content/test/subtst_contextmenu.html index 5a487cd1a29d..caaf143dff0f 100644 --- a/browser/base/content/test/subtst_contextmenu.html +++ b/browser/base/content/test/subtst_contextmenu.html @@ -18,6 +18,9 @@ Browser context menu subtest. + +
chssseefsbbbie
+ diff --git a/browser/base/content/test/test_contextmenu.html b/browser/base/content/test/test_contextmenu.html index 38e64551b944..f95d9eab65d4 100644 --- a/browser/base/content/test/test_contextmenu.html +++ b/browser/base/content/test/test_contextmenu.html @@ -49,14 +49,27 @@ function getVisibleMenuItems(aMenu) { key = key.toLowerCase(); if (item.nodeName == "menuitem") { - ok(item.id, "child menuitem #" + i + " has an ID"); + var isSpellSuggestion = item.className == "spell-suggestion"; + if (isSpellSuggestion) { + is(item.id, "", "child menuitem #" + i + " is a spelling suggestion"); + } else { + ok(item.id, "child menuitem #" + i + " has an ID"); + } ok(item.label.length, "menuitem " + item.id + " has a label"); - ok(key, "menuitem " + item.id + " has an access key"); - if (accessKeys[key]) - ok(false, "menuitem " + item.id + " has same accesskey as " + accessKeys[key]); - else - accessKeys[key] = item.id; - items.push(item.id); + if (isSpellSuggestion) { + is(key, "", "Spell suggestions shouldn't have an access key"); + items.push("*" + item.label); + } else if (item.id.indexOf("spell-check-dictionary-") != 0 && + item.id != "spell-no-suggestions") { + ok(key, "menuitem " + item.id + " has an access key"); + if (accessKeys[key]) + ok(false, "menuitem " + item.id + " has same accesskey as " + accessKeys[key]); + else + accessKeys[key] = item.id; + } + if (!isSpellSuggestion) { + items.push(item.id); + } items.push(!item.disabled); } else if (item.nodeName == "menuseparator") { ok(true, "--- seperator id is " + item.id); @@ -306,7 +319,78 @@ function runTest(testNum) { "context-viewsource", true, "context-viewinfo", true]); closeContextMenu(); + openContextMenuFor(textarea); // Invoke context menu for next test. + break; + case 12: + // Context menu for textarea + checkContextMenu(["*chubbiness", true, // spelling suggestion + "spell-add-to-dictionary", true, + "---", null, + "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]); + + closeContextMenu(); + openContextMenuFor(contenteditable); // Invoke context menu for next test. + break; + + case 13: + // Context menu for contenteditable + checkContextMenu(["spell-no-suggestions", false, + "spell-add-to-dictionary", true, + "---", null, + "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]); + + closeContextMenu(); + openContextMenuFor(inputspell); // Invoke context menu for next test. + break; + + case 14: + // Context menu for spell-check input + checkContextMenu(["*prodigality", true, // spelling suggestion + "spell-add-to-dictionary", true, + "---", null, + "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]); + + closeContextMenu(); subwindow.close(); SimpleTest.finish(); return; @@ -331,7 +415,8 @@ function runTest(testNum) { var testNum = 1; var subwindow, chromeWin, contextMenu; -var text, link, mailto, input, img, canvas, video, iframe; +var text, link, mailto, input, img, canvas, video, iframe, + textarea, contenteditable, inputspell; function startTest() { netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); @@ -356,6 +441,9 @@ function startTest() { video_bad = subwindow.document.getElementById("test-video-bad"); video_bad2 = subwindow.document.getElementById("test-video-bad2"); iframe = subwindow.document.getElementById("test-iframe"); + textarea = subwindow.document.getElementById("test-textarea"); + contenteditable = subwindow.document.getElementById("test-contenteditable"); + inputspell = subwindow.document.getElementById("test-input-spellcheck"); contextMenu.addEventListener("popupshown", function() { runTest(++testNum); }, false); runTest(1); diff --git a/toolkit/content/InlineSpellChecker.jsm b/toolkit/content/InlineSpellChecker.jsm index 0727e5762e59..369d9d490ad0 100644 --- a/toolkit/content/InlineSpellChecker.jsm +++ b/toolkit/content/InlineSpellChecker.jsm @@ -218,7 +218,8 @@ InlineSpellChecker.prototype = { this.mDictionaryNames.push(list[i]); var item = menu.ownerDocument.createElement("menuitem"); - item.setAttribute("label", displayName); + item.setAttribute("id", "spell-check-dictionary-" + list[i]); + item.label = displayName; item.setAttribute("type", "checkbox"); this.mDictionaryItems.push(item); if (curlang == list[i]) {