Bug 1340468 - Notify formautofill add-on of which item is being selected. r=MattN draft
authorRay Lin <ralin@mozilla.com>
Fri, 24 Feb 2017 10:15:55 +0800
changeset 495132 45f771d4928d1d509e2d93e361b7e04921bd0fab
parent 495131 cb65f94ce82ed3038dd85e1041156583298eb454
child 548297 a6a0a6773f5a0882b6b8f04be2fdeeaad00a94ee
push id48247
push userbmo:ralin@mozilla.com
push dateWed, 08 Mar 2017 10:18:27 +0000
reviewersMattN
bugs1340468
milestone55.0a1
Bug 1340468 - Notify formautofill add-on of which item is being selected. r=MattN MozReview-Commit-ID: 3YfW35Zon1Q
browser/extensions/formautofill/FormAutofillContent.jsm
browser/extensions/formautofill/FormAutofillHandler.jsm
browser/extensions/formautofill/content/FormAutofillFrameScript.js
browser/extensions/formautofill/content/formautofill.xml
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -232,16 +232,50 @@ let ProfileAutocomplete = {
       return;
     }
 
     let profile = JSON.parse(this._lastAutoCompleteResult.getCommentAt(selectedIndex));
     let formHandler = FormAutofillContent.getFormHandler(focusedInput);
 
     formHandler.autofillFormFields(profile, focusedInput);
   },
+
+  _previewFromAutocompleteRow(doc) {
+    let mm = this._frameMMFromWindow(doc.ownerGlobal);
+    let selectedIndexResult = mm.sendSyncMessage("FormAutoComplete:GetSelectedIndex", {});
+    if (selectedIndexResult.length != 1 || !Number.isInteger(selectedIndexResult[0])) {
+      throw new Error("Invalid autocomplete selectedIndex");
+    }
+
+    let selectedIndex = selectedIndexResult[0];
+    if (selectedIndex == -1) {
+      // Clear exisiting preview feilds
+      [...doc.getElementsByTagName("form")]
+        .map(form => FormAutofillContent._formsDetails.get(form))
+        .filter(fh => !!fh)
+        .forEach(fh => fh.clearPreviewedFormFields());
+      return;
+    }
+
+    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") {
+      return;
+    }
+
+    let profile = JSON.parse(this._lastAutoCompleteResult.getCommentAt(selectedIndex));
+    let formHandler = FormAutofillContent.getFormHandler(focusedInput);
+
+    formHandler.previewFormFields(profile);
+  },
 };
 
 /**
  * Handles content's interactions for the process.
  *
  * NOTE: Declares it by "var" to make it accessible in unit tests.
  */
 var FormAutofillContent = {
@@ -352,12 +386,16 @@ var FormAutofillContent = {
       this.log.debug("Adding form handler to _formsDetails:", formHandler);
       formHandler.fieldDetails.forEach(detail => this._markAsAutofillField(detail.element));
     });
   },
 
   _markAsAutofillField(field) {
     formFillController.markAsAutofillField(field);
   },
+
+  _previewProfile(doc) {
+    ProfileAutocomplete._previewFromAutocompleteRow(doc);
+  },
 };
 
 
 FormAutofillContent.init();
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -124,9 +124,46 @@ FormAutofillHandler.prototype = {
       }
 
       let value = profile[fieldDetail.fieldName];
       if (value) {
         fieldDetail.element.setUserInput(value);
       }
     }
   },
+
+  /**
+   * Populates result to the preview layers with given profile.
+   *
+   * @param {Object} profile
+   *        A profile to be previewed with
+   */
+  previewFormFields(profile) {
+    log.debug("preview profile in autofillFormFields:", profile);
+    for (let fieldDetail of this.fieldDetails) {
+      let value = profile[fieldDetail.fieldName] || "";
+
+      // Skip the fields that already has text entered
+      if (fieldDetail.element.value) {
+        continue;
+      }
+
+      // fieldDetail.element.highlight = !!value;
+      // fieldDetail.element.setUserInputPreview = value;
+
+      // TODO: Remove these once DOM preview API is ready
+      fieldDetail.element.style.backgroundColor = value ? "rgba(36,138,235,.1)" : "transparent";
+      fieldDetail.element.placeholder = value;
+    }
+  },
+
+  clearPreviewedFormFields() {
+    log.debug("clear previewed fields in:", this.form);
+    for (let fieldDetail of this.fieldDetails) {
+      // fieldDetail.element.setUserInputPreview("");
+      // fieldDetail.element.highlight = false;
+
+      // TODO: Remove these once DOM preview API is ready
+      fieldDetail.element.style.backgroundColor = "transparent";
+      fieldDetail.element.placeholder = "";
+    }
+  },
 };
--- a/browser/extensions/formautofill/content/FormAutofillFrameScript.js
+++ b/browser/extensions/formautofill/content/FormAutofillFrameScript.js
@@ -17,16 +17,19 @@ Cu.import("resource://formautofill/FormA
 /**
  * Handles content's interactions for the frame.
  *
  * NOTE: Declares it by "var" to make it accessible in unit tests.
  */
 var FormAutofillFrameScript = {
   init() {
     addEventListener("DOMContentLoaded", this);
+    addMessageListener("FormAutofill:PreviewProfile", this);
+    addMessageListener("FormAutoComplete:PopupClosed", this);
+    addMessageListener("FormAutoComplete:SetSelectedIndex", this);
   },
 
   handleEvent(evt) {
     if (!evt.isTrusted) {
       return;
     }
 
     if (!Services.prefs.getBoolPref("browser.formautofill.enabled")) {
@@ -39,11 +42,25 @@ var FormAutofillFrameScript = {
         if (!(doc instanceof Ci.nsIDOMHTMLDocument)) {
           return;
         }
         FormAutofillContent.identifyAutofillFields(doc);
         break;
       }
     }
   },
+
+  receiveMessage(aMessage) {
+    if (!Services.prefs.getBoolPref("browser.formautofill.enabled")) {
+      return;
+    }
+
+    switch (aMessage.name) {
+      case "FormAutofill:PreviewProfile":
+      case "FormAutoComplete:PopupClosed":
+      case "FormAutoComplete:SetSelectedIndex":
+        FormAutofillContent._previewProfile(content.document);
+        break;
+    }
+  },
 };
 
 FormAutofillFrameScript.init();
--- a/browser/extensions/formautofill/content/formautofill.xml
+++ b/browser/extensions/formautofill/content/formautofill.xml
@@ -33,29 +33,48 @@
             this, "anonid", "profile-item-box"
           );
           this._label = document.getAnonymousElementByAttribute(
             this, "anonid", "profile-label"
           );
           this._comment = document.getAnonymousElementByAttribute(
             this, "anonid", "profile-comment"
           );
+          this.mm = document.ownerGlobal.gBrowser.selectedBrowser.messageManager;
 
           this._adjustAcItem();
         ]]>
       </constructor>
 
+      <property name="selected" onget="return this.getAttribute('selected') == 'true';">
+        <setter><![CDATA[
+          if (val) {
+            this.setAttribute("selected", "true");
+          } else {
+            this.removeAttribute("selected");
+          }
+
+          this.mm.sendAsyncMessage("FormAutofill:PreviewProfile");
+
+          return val;
+        ]]></setter>
+      </property>
+
       <method name="_cleanup">
         <body>
         <![CDATA[
             this._itemBox.removeAttribute("size");
         ]]>
         </body>
       </method>
 
+      <method name="_onChanged">
+        <body></body>
+      </method>
+
       <method name="_onOverflow">
         <body></body>
       </method>
 
       <method name="_onUnderflow">
         <body></body>
       </method>