Bug 1413473 - Verify current focused input to determine whether the opening popup is for form autofill in order not to accidentally open new tab in wrong result types. r=lchang draft
authorRay Lin <ralin@mozilla.com>
Thu, 02 Nov 2017 13:42:12 +0800
changeset 691889 173551af246c1e9aff690feca3e1b14145916e4e
parent 691808 a0334f789772302ba5cfb6fd61290408842c7432
child 738621 701f8cfd809d61c59b37be7aaed758c67a8ba359
push id87351
push userbmo:ralin@mozilla.com
push dateThu, 02 Nov 2017 07:02:14 +0000
reviewerslchang
bugs1413473
milestone58.0a1
Bug 1413473 - Verify current focused input to determine whether the opening popup is for form autofill in order not to accidentally open new tab in wrong result types. r=lchang MozReview-Commit-ID: JFvSxHsKC1P
browser/extensions/formautofill/FormAutofillContent.jsm
browser/extensions/formautofill/content/FormAutofillFrameScript.js
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -103,16 +103,17 @@ AutofillProfileAutoCompleteSearch.protot
     let isAddressField = FormAutofillUtils.isAddressField(info.fieldName);
     let handler = FormAutofillContent.getFormHandler(focusedInput);
     let allFieldNames = handler.allFieldNames;
     let filledRecordGUID = isAddressField ? handler.address.filledRecordGUID : handler.creditCard.filledRecordGUID;
     let searchPermitted = isAddressField ?
                           FormAutofillUtils.isAutofillAddressesEnabled :
                           FormAutofillUtils.isAutofillCreditCardsEnabled;
 
+    ProfileAutocomplete.lastProfileAutoCompleteFocusedInput = focusedInput;
     // Fallback to form-history if ...
     //   - specified autofill feature is pref off.
     //   - no profile can fill the currently-focused input.
     //   - the current form has already been populated.
     //   - (address only) less than 3 inputs are covered by all saved fields in the storage.
     if (!searchPermitted || !savedFieldNames.has(info.fieldName) || filledRecordGUID || (isAddressField &&
         allFieldNames.filter(field => savedFieldNames.has(field)).length < FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD)) {
       if (focusedInput.autocomplete == "off") {
@@ -121,17 +122,17 @@ AutofillProfileAutoCompleteSearch.protot
         listener.onSearchResult(this, result);
         return;
       }
       let formHistory = Cc["@mozilla.org/autocomplete/search;1?name=form-history"]
                           .createInstance(Ci.nsIAutoCompleteSearch);
       formHistory.startSearch(searchString, searchParam, previousResult, {
         onSearchResult: (search, result) => {
           listener.onSearchResult(this, result);
-          ProfileAutocomplete.setProfileAutoCompleteResult(result);
+          ProfileAutocomplete.lastProfileAutoCompleteResult = result;
         },
       });
       return;
     }
 
     let infoWithoutElement = Object.assign({}, info);
     delete infoWithoutElement.elementWeakRef;
 
@@ -161,25 +162,25 @@ AutofillProfileAutoCompleteSearch.protot
 
         result = new CreditCardResult(searchString,
                                       info.fieldName,
                                       allFieldNames,
                                       adaptedRecords,
                                       {isSecure});
       }
       listener.onSearchResult(this, result);
-      ProfileAutocomplete.setProfileAutoCompleteResult(result);
+      ProfileAutocomplete.lastProfileAutoCompleteResult = result;
     });
   },
 
   /**
    * Stops an asynchronous search that is in progress
    */
   stopSearch() {
-    ProfileAutocomplete.setProfileAutoCompleteResult(null);
+    ProfileAutocomplete.lastProfileAutoCompleteResult = null;
     this.forceStop = true;
   },
 
   /**
    * Get the records from parent process for AutoComplete result.
    *
    * @private
    * @param  {Object} data
@@ -206,18 +207,18 @@ AutofillProfileAutoCompleteSearch.protot
   },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AutofillProfileAutoCompleteSearch]);
 
 let ProfileAutocomplete = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
-  _lastAutoCompleteResult: null,
-  _lastAutoCompleteFocusedInput: null,
+  lastProfileAutoCompleteResult: null,
+  lastProfileAutoCompleteFocusedInput: null,
   _registered: false,
   _factory: null,
 
   ensureRegistered() {
     if (this._registered) {
       return;
     }
 
@@ -239,25 +240,16 @@ let ProfileAutocomplete = {
     this._factory.unregister();
     this._factory = null;
     this._registered = false;
     this._lastAutoCompleteResult = null;
 
     Services.obs.removeObserver(this, "autocomplete-will-enter-text");
   },
 
-  getProfileAutoCompleteResult() {
-    return this._lastAutoCompleteResult;
-  },
-
-  setProfileAutoCompleteResult(result) {
-    this._lastAutoCompleteResult = result;
-    this._lastAutoCompleteFocusedInput = formFillController.focusedInput;
-  },
-
   observe(subject, topic, data) {
     switch (topic) {
       case "autocomplete-will-enter-text": {
         if (!formFillController.focusedInput) {
           // The observer notification is for autocomplete in a different process.
           break;
         }
         this._fillFromAutocompleteRow(formFillController.focusedInput);
@@ -288,51 +280,51 @@ let ProfileAutocomplete = {
     let formDetails = FormAutofillContent.getFormDetails(focusedInput);
     if (!formDetails) {
       // The observer notification is for a different frame.
       return;
     }
 
     let selectedIndex = this._getSelectedIndex(focusedInput.ownerGlobal);
     if (selectedIndex == -1 ||
-        !this._lastAutoCompleteResult ||
-        this._lastAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile") {
+        !this.lastProfileAutoCompleteResult ||
+        this.lastProfileAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile") {
       return;
     }
 
-    let profile = JSON.parse(this._lastAutoCompleteResult.getCommentAt(selectedIndex));
+    let profile = JSON.parse(this.lastProfileAutoCompleteResult.getCommentAt(selectedIndex));
     let formHandler = FormAutofillContent.getFormHandler(focusedInput);
 
     formHandler.autofillFormFields(profile, focusedInput);
   },
 
   _clearProfilePreview() {
-    let focusedInput = formFillController.focusedInput || this._lastAutoCompleteFocusedInput;
+    let focusedInput = formFillController.focusedInput || this.lastProfileAutoCompleteFocusedInput;
     if (!focusedInput || !FormAutofillContent.getFormDetails(focusedInput)) {
       return;
     }
 
     let formHandler = FormAutofillContent.getFormHandler(focusedInput);
 
     formHandler.clearPreviewedFormFields(focusedInput);
   },
 
   _previewSelectedProfile(selectedIndex) {
     let focusedInput = formFillController.focusedInput;
     if (!focusedInput || !FormAutofillContent.getFormDetails(focusedInput)) {
       // The observer notification is for a different process/frame.
       return;
     }
 
-    if (!this._lastAutoCompleteResult ||
-        this._lastAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile") {
+    if (!this.lastProfileAutoCompleteResult ||
+        this.lastProfileAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile") {
       return;
     }
 
-    let profile = JSON.parse(this._lastAutoCompleteResult.getCommentAt(selectedIndex));
+    let profile = JSON.parse(this.lastProfileAutoCompleteResult.getCommentAt(selectedIndex));
     let formHandler = FormAutofillContent.getFormHandler(focusedInput);
 
     formHandler.previewFormFields(profile, focusedInput);
   },
 };
 
 /**
  * Handles content's interactions for the process.
@@ -517,17 +509,17 @@ var FormAutofillContent = {
     validDetails.forEach(detail =>
       this._markAsAutofillField(detail.elementWeakRef.get())
     );
   },
 
   previewProfile(doc) {
     let docWin = doc.ownerGlobal;
     let selectedIndex = ProfileAutocomplete._getSelectedIndex(docWin);
-    let lastAutoCompleteResult = ProfileAutocomplete.getProfileAutoCompleteResult();
+    let lastAutoCompleteResult = ProfileAutocomplete.lastProfileAutoCompleteResult;
     let focusedInput = formFillController.focusedInput;
     let mm = this._messageManagerFromWindow(docWin);
 
     if (selectedIndex === -1 ||
         !focusedInput ||
         !lastAutoCompleteResult ||
         lastAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile") {
       mm.sendAsyncMessage("FormAutofill:UpdateWarningMessage", {});
@@ -545,16 +537,21 @@ var FormAutofillContent = {
         focusedCategory,
         categories,
       });
 
       ProfileAutocomplete._previewSelectedProfile(selectedIndex);
     }
   },
 
+  onPopupClosed() {
+    ProfileAutocomplete._clearProfilePreview();
+    ProfileAutocomplete.lastProfileAutoCompleteResult = null;
+  },
+
   _markAsAutofillField(field) {
     // Since Form Autofill popup is only for input element, any non-Input
     // element should be excluded here.
     if (!field || !(field instanceof Ci.nsIDOMHTMLInputElement)) {
       return;
     }
 
     formFillController.markAsAutofillField(field);
@@ -564,20 +561,21 @@ var FormAutofillContent = {
     return win.QueryInterface(Ci.nsIInterfaceRequestor)
               .getInterface(Ci.nsIWebNavigation)
               .QueryInterface(Ci.nsIDocShell)
               .QueryInterface(Ci.nsIInterfaceRequestor)
               .getInterface(Ci.nsIContentFrameMessageManager);
   },
 
   _onKeyDown(e) {
-    let lastAutoCompleteResult = ProfileAutocomplete.getProfileAutoCompleteResult();
+    let lastAutoCompleteResult = ProfileAutocomplete.lastProfileAutoCompleteResult;
     let focusedInput = formFillController.focusedInput;
 
-    if (e.keyCode != Ci.nsIDOMKeyEvent.DOM_VK_RETURN || !lastAutoCompleteResult || !focusedInput) {
+    if (e.keyCode != Ci.nsIDOMKeyEvent.DOM_VK_RETURN || !lastAutoCompleteResult ||
+        !focusedInput || focusedInput != ProfileAutocomplete.lastProfileAutoCompleteFocusedInput) {
       return;
     }
 
     let selectedIndex = ProfileAutocomplete._getSelectedIndex(e.target.ownerGlobal);
     let selectedRowStyle = lastAutoCompleteResult.getStyleAt(selectedIndex);
     if (selectedRowStyle == "autofill-footer") {
       focusedInput.addEventListener("DOMAutoComplete", () => {
         Services.cpmm.sendAsyncMessage("FormAutofill:OpenPreferences");
--- a/browser/extensions/formautofill/content/FormAutofillFrameScript.js
+++ b/browser/extensions/formautofill/content/FormAutofillFrameScript.js
@@ -84,17 +84,17 @@ var FormAutofillFrameScript = {
     const {chromeEventHandler} = doc.ownerGlobal.getInterface(Ci.nsIDocShell);
 
     switch (message.name) {
       case "FormAutofill:PreviewProfile": {
         FormAutofillContent.previewProfile(doc);
         break;
       }
       case "FormAutoComplete:PopupClosed": {
-        FormAutofillContent.previewProfile(doc);
+        FormAutofillContent.onPopupClosed();
         chromeEventHandler.removeEventListener("keydown", FormAutofillContent._onKeyDown,
                                                {capturing: true});
         break;
       }
       case "FormAutoComplete:PopupOpened": {
         chromeEventHandler.addEventListener("keydown", FormAutofillContent._onKeyDown,
                                             {capturing: true});
       }