Bug 1370391 - integrate heuristics into results. r=mattn draft
authorJonathan Guillotte-Blouin <jguillotteblouin@mozilla.com>
Tue, 06 Jun 2017 11:24:51 -0700
changeset 605551 5cf2f0162367b2257023c540a0882c03faf3947c
parent 605550 7299984d5b74c3517337d812d2a698a96a316e43
child 636530 ab65f2d7d5b7123ca34b74f7d22b509b9939970c
push id67450
push userbmo:jguillotteblouin@mozilla.com
push dateFri, 07 Jul 2017 23:26:08 +0000
reviewersmattn
bugs1370391
milestone56.0a1
Bug 1370391 - integrate heuristics into results. r=mattn MozReview-Commit-ID: Jy7mKOz2Hce
browser/extensions/formautofill/FormAutofillContent.jsm
toolkit/components/satchel/FormHistoryStartup.js
toolkit/components/satchel/nsFormAutoComplete.js
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -92,17 +92,18 @@ AutofillProfileAutoCompleteSearch.protot
     this.log.debug("startSearch: for", searchString, "with input", formFillController.focusedInput);
     let focusedInput = formFillController.focusedInput;
     this.forceStop = false;
     let info = FormAutofillContent.getInputDetails(focusedInput);
 
     if (!FormAutofillContent.savedFieldNames.has(info.fieldName) ||
         FormAutofillContent.getFormHandler(focusedInput).filledProfileGUID) {
       let formHistory = Cc["@mozilla.org/autocomplete/search;1?name=form-history"]
-                          .createInstance(Ci.nsIAutoCompleteSearch);
+                          .getService(Ci.nsIAutoCompleteSearch);
+
       formHistory.startSearch(searchString, searchParam, previousResult, {
         onSearchResult: (search, result) => {
           listener.onSearchResult(this, result);
           ProfileAutocomplete.setProfileAutoCompleteResult(result);
         },
       });
       return;
     }
@@ -399,16 +400,20 @@ var FormAutofillContent = {
    *
    * @param {HTMLInputElement} element Focused input which triggered profile searching
    * @returns {Object|null}
    *          Return target input's information that cloned from content cache
    *          (or return null if the information is not found in the cache).
    */
   getInputDetails(element) {
     let formDetails = this.getFormDetails(element);
+    if (!formDetails) {
+      return null;
+    }
+
     for (let detail of formDetails) {
       let detailElement = detail.elementWeakRef.get();
       if (detailElement && element == detailElement) {
         return detail;
       }
     }
     return null;
   },
--- a/toolkit/components/satchel/FormHistoryStartup.js
+++ b/toolkit/components/satchel/FormHistoryStartup.js
@@ -127,19 +127,25 @@ FormHistoryStartup.prototype = {
             // query might have been canceled shortly before completing, in
             // that case we don't want to call the callback anymore.
             if (query === this.pendingQuery) {
               this.pendingQuery = null;
               if (aReason) {
                 return;
               }
 
-              // for now we only query autofill storage for @type=email
-              if (params.fieldtype == "email") {
-                let autofillValues = this.getAutofillValues("email", searchString);
+              // for now we only query autofill storage for type=email
+              const ALLOWED_FIELDTYPES = ["email"];
+              let index = ALLOWED_FIELDTYPES.indexOf(params.heuristicsFieldType);
+              if (index == -1) { // heuristics fieldType is not good, try the input type itself
+                index = ALLOWED_FIELDTYPES.indexOf(params.fieldtype);
+              }
+              if (index != -1) { // one of heuristics or input type works, use it w/ autofill
+                const fieldType = ALLOWED_FIELDTYPES[index];
+                let autofillValues = this.getAutofillValues(fieldType, searchString);
                 results = this.dedupeAutofillAndHistory(autofillValues, results);
               }
 
               // compute frecency and remove metadata of deduped results
               for (let result of results) {
                 result.frecency = FormHistory.computeFrecency(params, result.metadata);
                 delete result.metadata;
               }
--- a/toolkit/components/satchel/nsFormAutoComplete.js
+++ b/toolkit/components/satchel/nsFormAutoComplete.js
@@ -6,16 +6,30 @@
 "use strict";
 
 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils", "resource://gre/modules/BrowserUtils.jsm");
+// Gracefully handle if the Form Autofill System Add-on isn't installed in this locale or for this user.
+// defineLazyModuleGetter would report to the console.
+XPCOMUtils.defineLazyGetter(this, "FormAutofillContent", () => {
+  let _formAutofillContent;
+
+  try {
+    _formAutofillContent = Cu.import("resource://formautofill/FormAutofillContent.jsm", {})
+                             .FormAutofillContent;
+  } catch (e) {
+    _formAutofillContent = null;
+  }
+
+  return _formAutofillContent;
+});
 
 function isAutocompleteDisabled(aField) {
   if (aField.autocomplete !== "") {
     return aField.autocomplete === "off";
   }
 
   return aField.form && aField.form.autocomplete === "off";
 }
@@ -500,26 +514,30 @@ FormAutoComplete.prototype = {
    * @param {string} searchString
    *                 string to search for
    * @param {function} callback
    *                 called when the values are available. Passed an array of objects,
    *                 containing properties for each result. The callback is only called
    *                 when successful.
    */
   getAutoCompleteValues(client, field, inputName, searchString, callback) {
+    let heuristics = field && FormAutofillContent ?
+                       FormAutofillContent.getInputDetails(field) :
+                       null;
     let params = {
       agedWeight:         this._agedWeight,
       bucketSize:         this._bucketSize,
       expiryDate:         1000 * (Date.now() - this._expireDays * 24 * 60 * 60 * 1000),
       fieldname:          inputName,
       fieldtype:          field ? field.type : null,
       maxTimeGroupings:   this._maxTimeGroupings,
       timeGroupingSize:   this._timeGroupingSize,
       prefixWeight:       this._prefixWeight,
       boundaryWeight:     this._boundaryWeight,
+      heuristicsFieldType: heuristics ? heuristics.fieldName : null,
     };
 
     this.stopAutoCompleteSearch();
     client.requestAutoCompleteResults(searchString, params, (entries) => {
       this._pendingClient = null;
       callback(entries);
     });
     this._pendingClient = client;