Bug 1569720 - Port Bug 433860 "No spelling suggestions for text inputs when contenteditable node in document" to SeaMonkey. r=frg a=frg
authorIan Neal <iann_cvs@blueyonder.co.uk>
Wed, 31 Jul 2019 21:56:04 +0200
changeset 32251 c7fc5af1cb292af8be2ed5ccabf4a05eddcf96e9
parent 32250 ee8368427e04c85bf16be5322f779daa2965d7b6
child 32252 d158f2160bd0c0bfd10ca264a3e53be4f3012d5d
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
bugs1569720, 433860
Bug 1569720 - Port Bug 433860 "No spelling suggestions for text inputs when contenteditable node in document" to SeaMonkey. r=frg a=frg
suite/base/content/nsContextMenu.js
--- a/suite/base/content/nsContextMenu.js
+++ b/suite/base/content/nsContextMenu.js
@@ -349,17 +349,17 @@ nsContextMenu.prototype = {
 
   initSpellingItems: function() {
     var canSpell = InlineSpellCheckerUI.canSpellCheck &&
                    !InlineSpellCheckerUI.initialSpellCheckPending;
     var onMisspelling = InlineSpellCheckerUI.overMisspelling;
     var showUndo = InlineSpellCheckerUI.enabled &&
                    InlineSpellCheckerUI.canUndo();
     this.showItem("spell-check-enabled", canSpell);
-    this.showItem("spell-separator", canSpell || this.possibleSpellChecking);
+    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);
 
     // suggestion list
     this.showItem("spell-add-separator", onMisspelling);
@@ -373,23 +373,26 @@ nsContextMenu.prototype = {
     }
 
     // dictionary list
     this.showItem("spell-dictionaries", 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);
     }
-
-    // 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
-    this.showItem("spell-add-dictionaries-main",
-                  !canSpell && 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
+      this.showItem("spell-add-dictionaries-main", true);
+    }
+    else
+      this.showItem("spell-add-dictionaries-main", false);
   },
 
   initClipboardItems: function() {
     // Copy depends on whether there is selected text.
     // Enabling this context menu item is now done through the global
     // command updating system
     // this.setItemAttr("context-copy", "disabled", !this.isTextSelected());
 
@@ -522,16 +525,20 @@ nsContextMenu.prototype = {
   },
 
   // Set various context menu attributes based on the state of the world.
   setTarget: function(aNode, aRangeParent, aRangeOffset) {
     // Currently "isRemote" is always false.
     //this.isRemote = gContextMenuContentData && gContextMenuContentData.isRemote;
 
     const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+    if (aNode.namespaceURI == xulNS) {
+      this.shouldDisplay = false;
+      return;
+    }
 
     // Initialize contextual info.
     this.onImage               = false;
     this.onLoadedImage         = false;
     this.onStandaloneImage     = false;
     this.onCanvas              = false;
     this.onVideo               = false;
     this.onAudio               = false;
@@ -551,50 +558,29 @@ nsContextMenu.prototype = {
     this.inFrame               = false;
     this.inSyntheticDoc        = false;
     this.hasBGImage            = false;
     this.bgImageURL            = "";
     this.popupPrincipal        = null;
     this.autoDownload          = false;
     this.isTextSelected        = false;
     this.isContentSelected     = false;
-    this.possibleSpellChecking = false;
+    this.onEditableArea        = false;
 
     // Remember the node that was clicked.
     this.target = aNode;
 
-    if (aNode.namespaceURI == xulNS) {
-      this.shouldDisplay = false;
-      return;
-    }
+    this.browser = this.target.ownerDocument.defaultView
+                              .QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIWebNavigation)
+                              .QueryInterface(Ci.nsIDocShell)
+                              .chromeEventHandler;
 
     this.autoDownload = Services.prefs.getBoolPref("browser.download.useDownloadDir");
 
-    // if the document is editable, show context menu like in text inputs
-    var win = this.target.ownerDocument.defaultView;
-    if (win) {
-      var webNav = win.QueryInterface(Ci.nsIInterfaceRequestor)
-                      .getInterface(Ci.nsIWebNavigation);
-      this.browser = webNav.QueryInterface(Ci.nsIDocShell)
-                           .chromeEventHandler;
-      var editingSession = webNav.QueryInterface(Ci.nsIInterfaceRequestor)
-                                 .getInterface(Ci.nsIEditingSession);
-      if (editingSession.windowIsEditable(win) &&
-          this.isTargetEditable() && this.target.spellcheck) {
-        this.onTextInput           = true;
-        this.possibleSpellChecking = true;
-        InlineSpellCheckerUI.init(editingSession.getEditorForWindow(win));
-        InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset);
-        var canSpell = InlineSpellCheckerUI.canSpellCheck;
-        this.showItem("spell-check-enabled", canSpell);
-        this.showItem("spell-separator", canSpell);
-        return;
-      }
-    }
-
     // Check if we are in a synthetic document (stand alone image, video, etc.).
     this.inSyntheticDoc = this.target.ownerDocument.mozSyntheticDocument;
     // First, do checks for nodes that never have children.
     if (this.target.nodeType == Node.ELEMENT_NODE) {
       // See if the user clicked on an image.
       if (this.target instanceof Ci.nsIImageLoadingContent &&
           this.target.currentURI) {
         this.onImage = true;
@@ -628,26 +614,26 @@ nsContextMenu.prototype = {
         this.onAudio = true;
         this.mediaURL = this.target.currentSrc || this.target.src;
       }
       else if (this.target instanceof HTMLInputElement) {
         this.onTextInput = this.isTargetATextBox(this.target);
         // allow spellchecking UI on all writable text boxes except passwords
         if (this.onTextInput && !this.target.readOnly &&
             this.target.mozIsTextField(true) && this.target.spellcheck) {
-          this.possibleSpellChecking = true;
+          this.onEditableArea = true;
           InlineSpellCheckerUI.init(this.target.QueryInterface(Ci.nsIDOMNSEditableElement).editor);
           InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset);
         }
         this.onKeywordField = this.isTargetAKeywordField(this.target);
       }
       else if (this.target instanceof HTMLTextAreaElement) {
         this.onTextInput = this.isTextBoxEnabled(this.target);
         if (this.onTextInput && !this.target.readOnly && this.target.spellcheck) {
-          this.possibleSpellChecking = true;
+          this.onEditableArea = true;
           InlineSpellCheckerUI.init(this.target.QueryInterface(Ci.nsIDOMNSEditableElement).editor);
           InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset);
         }
       }
       else if ( this.target instanceof HTMLHtmlElement ) {
         // pages with multiple <body>s are lame. we'll teach them a lesson.
         var bodyElt = this.target.ownerDocument.body;
         if (bodyElt) {
@@ -696,29 +682,18 @@ nsContextMenu.prototype = {
           }
         }
       }
     }
 
     // We have meta data on images.
     this.onMetaDataItem = this.onImage;
 
-    // See if the user clicked on MathML
+    // Bubble out, looking for items of interest
     const NS_MathML = "http://www.w3.org/1998/Math/MathML";
-    if ((this.target.nodeType == Node.TEXT_NODE &&
-         this.target.parentNode.namespaceURI == NS_MathML) ||
-        (this.target.namespaceURI == NS_MathML))
-      this.onMathML = true;
-
-    // See if the user clicked in a frame.
-    var docDefaultView = this.target.ownerDocument.defaultView;
-    if (docDefaultView != docDefaultView.top)
-      this.inFrame = true;
-
-    // Bubble out, looking for items of interest
     const XMLNS = "http://www.w3.org/XML/1998/namespace";
     var elem = this.target;
     while (elem) {
       if (elem.nodeType == Node.ELEMENT_NODE) {
         // Link?
         if (!this.onLink &&
             ((elem instanceof HTMLAnchorElement && elem.href) ||
              (elem instanceof HTMLAreaElement && elem.href) ||
@@ -766,16 +741,54 @@ nsContextMenu.prototype = {
           if (bgImgUrl) {
             this.hasBGImage = true;
             this.bgImageURL = makeURLAbsolute(elem.baseURI, bgImgUrl);
           }
         }
       }
       elem = elem.parentNode;
     }
+
+    // See if the user clicked on MathML
+    if ((this.target.nodeType == Node.TEXT_NODE &&
+         this.target.parentNode.namespaceURI == NS_MathML) ||
+        (this.target.namespaceURI == NS_MathML))
+      this.onMathML = true;
+
+    // See if the user clicked in a frame.
+    var docDefaultView = this.target.ownerDocument.defaultView;
+    if (docDefaultView != docDefaultView.top)
+      this.inFrame = true;
+
+    // if the document is editable, show context menu like in text inputs
+    if (!this.onEditableArea) {
+      var win = this.target.ownerDocument.defaultView;
+      if (win) {
+        var editingSession = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                                .getInterface(Ci.nsIWebNavigation)
+                                .QueryInterface(Ci.nsIInterfaceRequestor)
+                                .getInterface(Ci.nsIEditingSession);
+        if (editingSession.windowIsEditable(win) &&
+            this.isTargetEditable() && this.target.spellcheck) {
+          this.onTextInput       = true;
+          this.onKeywordField    = false;
+          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;
+          this.showItem("spell-check-enabled", canSpell);
+          this.showItem("spell-separator", canSpell);
+        }
+      }
+    }
   },
 
   initPopupPrincipal: function() {
     // quick check: if no opener, it can't be a popup
     if (!window.content.opener)
       return;
     try {
       var show = false;