Bug 1311301 - making login fields show autocomplete on autofocused inputs r?MattN draft
authorJonathan Kingston <jkt@mozilla.com>
Fri, 21 Oct 2016 13:20:23 +0100
changeset 428054 f50dd84e452574231b707b6c1da6e1c58ead6bf1
parent 427573 d942a3d0b0917b9f91d710fa3adf89b2329904bc
child 534648 aca99b95088b3ded3ff9aa079a109bbf1c2c4b96
push id33218
push userjkingston@mozilla.com
push dateFri, 21 Oct 2016 14:04:38 +0000
reviewersMattN
bugs1311301
milestone52.0a1
Bug 1311301 - making login fields show autocomplete on autofocused inputs r?MattN MozReview-Commit-ID: H4DJvfsgA6v
browser/base/content/content.js
toolkit/components/passwordmgr/LoginManagerContent.jsm
toolkit/components/satchel/nsFormFillController.cpp
toolkit/components/satchel/nsIFormFillController.idl
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -33,16 +33,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FormSubmitObserver",
   "resource:///modules/FormSubmitObserver.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PageMetadata",
   "resource://gre/modules/PageMetadata.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils",
   "resource:///modules/PlacesUIUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AutoCompletePopup",
+                                  "resource://gre/modules/AutoCompletePopup.jsm");
 XPCOMUtils.defineLazyGetter(this, "PageMenuChild", function() {
   let tmp = {};
   Cu.import("resource://gre/modules/PageMenu.jsm", tmp);
   return new tmp.PageMenuChild();
 });
 XPCOMUtils.defineLazyModuleGetter(this, "Feeds",
   "resource:///modules/Feeds.jsm");
 
@@ -79,16 +81,20 @@ addEventListener("pageshow", function(ev
 addEventListener("DOMAutoComplete", function(event) {
   LoginManagerContent.onUsernameInput(event);
 });
 addEventListener("blur", function(event) {
   LoginManagerContent.onUsernameInput(event);
 });
 
 var handleContentContextMenu = function (event) {
+  if (event.target instanceof Ci.nsIDOMHTMLInputElement) {
+    AutoCompletePopup.closePopup();
+  }
+
   let defaultPrevented = event.defaultPrevented;
   if (!Services.prefs.getBoolPref("dom.event.contextmenu.enabled")) {
     let plugin = null;
     try {
       plugin = event.target.QueryInterface(Ci.nsIObjectLoadingContent);
     } catch (e) {}
     if (plugin && plugin.displayedType == Ci.nsIObjectLoadingContent.TYPE_PLUGIN) {
       // Don't open a context menu for plugins.
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -1009,17 +1009,17 @@ var LoginManagerContent = {
         recordAutofillResult(AUTOFILL_RESULT.NO_LOGINS_FIT);
         return;
       }
 
       // Attach autocomplete stuff to the username field, if we have
       // one. This is normally used to select from multiple accounts,
       // but even with one account we should refill if the user edits.
       if (usernameField)
-        this._formFillService.markAsLoginManagerField(usernameField);
+        this._formFillService.markAsLoginManagerField(usernameField, userTriggered);
 
       // Don't clobber an existing password.
       if (passwordField.value && !clobberPassword) {
         log("form not filled, the password field was already filled");
         recordAutofillResult(AUTOFILL_RESULT.EXISTING_PASSWORD);
         return;
       }
 
--- a/toolkit/components/satchel/nsFormFillController.cpp
+++ b/toolkit/components/satchel/nsFormFillController.cpp
@@ -34,16 +34,17 @@
 #include "mozilla/ModuleUtils.h"
 #include "nsToolkitCompsCID.h"
 #include "nsEmbedCID.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsContentUtils.h"
 #include "nsILoadContext.h"
 #include "nsIFrame.h"
 #include "nsIScriptSecurityManager.h"
+#include "nsFocusManager.h"
 
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION(nsFormFillController,
                          mController, mLoginManager, mFocusedPopup, mDocShells,
                          mPopups, mLastListener, mLastFormAutoComplete)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFormFillController)
@@ -254,30 +255,42 @@ nsFormFillController::DetachFromBrowser(
   mDocShells.RemoveElementAt(index);
   mPopups.RemoveElementAt(index);
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
-nsFormFillController::MarkAsLoginManagerField(nsIDOMHTMLInputElement *aInput)
+nsFormFillController::MarkAsLoginManagerField(nsIDOMHTMLInputElement *aInput, bool aUserTriggered)
 {
   /*
    * The Login Manager can supply autocomplete results for username fields,
    * when a user has multiple logins stored for a site. It uses this
    * interface to indicate that the form manager shouldn't handle the
    * autocomplete. The form manager also checks for this tag when saving
    * form history (so it doesn't save usernames).
    */
   nsCOMPtr<nsINode> node = do_QueryInterface(aInput);
   NS_ENSURE_STATE(node);
   mPwmgrInputs.Put(node, true);
   node->AddMutationObserverUnlessExists(this);
 
+  // Check if the element has already been focused prior to form fill being attached
+  if (!aUserTriggered) {
+    nsFocusManager *fm = nsFocusManager::GetFocusManager();
+    if (fm) {
+      nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent();
+      if (SameCOMIdentity(focusedContent, node)) {
+        nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(node);
+        ShowPopup();
+      }
+    }
+  }
+
   if (!mLoginManager)
     mLoginManager = do_GetService("@mozilla.org/login-manager;1");
 
   return NS_OK;
 }
 
 
 ////////////////////////////////////////////////////////////////////////
--- a/toolkit/components/satchel/nsIFormFillController.idl
+++ b/toolkit/components/satchel/nsIFormFillController.idl
@@ -36,11 +36,12 @@ interface nsIFormFillController : nsISup
   void detachFromBrowser(in nsIDocShell docShell);
 
   /*
    * Mark the specified <input> element as being managed by password manager.
    * Autocomplete requests will be handed off to the password manager, and will
    * not be stored in form history.
    *
    * @param aInput - The HTML <input> element to tag
+   * @param aUserTriggered - a bool if the user tiggered the filling
    */
-  void markAsLoginManagerField(in nsIDOMHTMLInputElement aInput);
+  void markAsLoginManagerField(in nsIDOMHTMLInputElement aInput, in bool aUserTriggered);
 };