Bug 1569749 - Update spellcheck context menu. Port Bug 905176 "Don't show the Check Spelling menu item for spellcheck=false contenteditable elements". r=frg a=frg
authorIan Neal <iann_cvs@blueyonder.co.uk>
Wed, 31 Jul 2019 21:56:04 +0200
changeset 32253 6809d06a5b834fe052308762dca91a275816ae8d
parent 32252 d158f2160bd0c0bfd10ca264a3e53be4f3012d5d
child 32254 a73b3a81a817f34e124aed51433f7f4a98664574
push id208
push userfrgrahl@gmx.net
push dateWed, 31 Jul 2019 19:58:37 +0000
treeherdercomm-esr60@2375c07411d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfrg, frg
bugs1569749, 905176
Bug 1569749 - Update spellcheck context menu. Port Bug 905176 "Don't show the Check Spelling menu item for spellcheck=false contenteditable elements". r=frg a=frg
suite/base/content/nsContextMenu.js
--- a/suite/base/content/nsContextMenu.js
+++ b/suite/base/content/nsContextMenu.js
@@ -344,20 +344,20 @@ nsContextMenu.prototype = {
     this.showItem("context-bidi-text-direction-toggle",
                   this.onTextInput && gShowBiDi);
     this.showItem("context-bidi-page-direction-toggle",
                   !this.onTextInput && gShowBiDi);
   },
 
   initSpellingItems: function() {
     var canSpell = InlineSpellCheckerUI.canSpellCheck &&
-                   !InlineSpellCheckerUI.initialSpellCheckPending;
+                   !InlineSpellCheckerUI.initialSpellCheckPending &&
+                   this.canSpellCheck;
     var onMisspelling = InlineSpellCheckerUI.overMisspelling;
-    var showUndo = InlineSpellCheckerUI.enabled &&
-                   InlineSpellCheckerUI.canUndo();
+    var showUndo = canSpell && InlineSpellCheckerUI.canUndo();
     this.showItem("spell-check-enabled", canSpell);
     this.showItem("spell-separator", canSpell || this.onEditableArea);
     if (canSpell)
       this.setItemAttr("spell-check-enabled", "checked", InlineSpellCheckerUI.enabled);
     this.showItem("spell-add-to-dictionary", onMisspelling);
     this.showItem("spell-undo-add-to-dictionary", showUndo);
     this.showItem("spell-ignore-word", onMisspelling);
 
@@ -368,17 +368,17 @@ nsContextMenu.prototype = {
       var suggestionsSeparator = document.getElementById("spell-add-separator");
       var numsug = InlineSpellCheckerUI.addSuggestionsToMenu(suggestionsSeparator.parentNode, suggestionsSeparator, 5);
       this.showItem("spell-no-suggestions", numsug == 0);
     } else {
       this.showItem("spell-no-suggestions", false);
     }
 
     // dictionary list
-    this.showItem("spell-dictionaries", InlineSpellCheckerUI.enabled);
+    this.showItem("spell-dictionaries", canSpell && InlineSpellCheckerUI.enabled);
     var dictMenu = document.getElementById("spell-dictionaries-menu");
     if (canSpell && dictMenu) {
       var dictSep = document.getElementById("spell-language-separator");
       InlineSpellCheckerUI.addDictionaryListToMenu(dictMenu, dictSep);
       this.showItem("spell-add-dictionaries-main", false);
     }
     else if (this.onEditableArea) {
       // when there is no spellchecker but we might be able to spellcheck
@@ -559,16 +559,17 @@ nsContextMenu.prototype = {
     this.inSyntheticDoc        = false;
     this.hasBGImage            = false;
     this.bgImageURL            = "";
     this.popupPrincipal        = null;
     this.autoDownload          = false;
     this.isTextSelected        = false;
     this.isContentSelected     = false;
     this.onEditableArea        = false;
+    this.canSpellCheck         = false;
 
     // Remember the node that was clicked.
     this.target = aNode;
 
     this.browser = this.target.ownerDocument.defaultView
                               .QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIWebNavigation)
                               .QueryInterface(Ci.nsIDocShell)
@@ -677,16 +678,23 @@ nsContextMenu.prototype = {
             // If element is a directory, then you can't save it.
             this.onSaveableLink = root.getAttribute("container") != "true";
           }
           else {
             root = root.parentNode;
           }
         }
       }
+
+      this.canSpellCheck = this._isSpellCheckEnabled(this.target);
+    }
+    else if (this.target.nodeType == Node.TEXT_NODE) {
+      // For text nodes, look at the parent node to determine the spellcheck attribute.
+      this.canSpellCheck = this.target.parentNode &&
+                           this._isSpellCheckEnabled(this.target);
     }
 
     // We have meta data on images.
     this.onMetaDataItem = this.onImage;
 
     // Bubble out, looking for items of interest
     const NS_MathML = "http://www.w3.org/1998/Math/MathML";
     const XMLNS = "http://www.w3.org/XML/1998/namespace";
@@ -773,17 +781,17 @@ nsContextMenu.prototype = {
           this.onImage           = false;
           this.onLoadedImage     = false;
           this.onMathML          = false;
           this.inFrame           = false;
           this.hasBGImage        = false;
           this.onEditableArea    = true;
           InlineSpellCheckerUI.init(editingSession.getEditorForWindow(win));
           InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset);
-          var canSpell = InlineSpellCheckerUI.canSpellCheck;
+          var canSpell = InlineSpellCheckerUI.canSpellCheck && this.canSpellCheck;
           this.showItem("spell-check-enabled", canSpell);
           this.showItem("spell-separator", canSpell);
         }
       }
     }
   },
 
   initPopupPrincipal: function() {
@@ -808,16 +816,33 @@ nsContextMenu.prototype = {
       if (show) {
         // initialize popupPrincipal
         this.popupPrincipal = window.content.opener.document.nodePrincipal;
       }
     } catch(e) {
     }
   },
 
+  _isSpellCheckEnabled: function(aNode) {
+    // We can always force-enable spellchecking on textboxes
+    if (this.isTargetATextBox(aNode)) {
+      return true;
+    }
+    // We can never spell check something which is not content editable
+    var editable = aNode.isContentEditable;
+    if (!editable && aNode.ownerDocument) {
+      editable = aNode.ownerDocument.designMode == "on";
+    }
+    if (!editable) {
+      return false;
+    }
+    // Otherwise make sure that nothing in the parent chain disables spellchecking
+    return aNode.spellcheck;
+  },
+
   // Returns the computed style attribute for the given element.
   getComputedStyle: function(aElem, aProp) {
     return aElem.ownerDocument
                 .defaultView
                 .getComputedStyle(aElem, "").getPropertyValue(aProp);
   },
 
   // Returns a "url"-type computed style attribute value, with the url() stripped.