mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	This patch adds the following messages to the autocomplete item: 1. For address and credit card autofill, use the `FormAutofill:FillForm` message. 2. For login autofill, use the `PasswordManager:OnFieldAutoComplete` message. 3. For generated password autofill, use the `PasswordManager:FillGeneratedPassword` message. After adding the above three messages, every autocomplete item that performs an action upon being clicked has a corresponding `fillMessageName`. Here is how the new architecture works: 1. Whenever a user selects an autocomplete entry, the `AutoCompleteChild` sends the `AutoComplete:SelectEntry` message to the parent process. 2. `AutoCompleteParent` extracts `fillMessageName` from the message and uses the prefix of the message name to determine which actor should process this message. 3. The `OnFieldAutoCompleteEntrySelected` method of the actor is called. The actor in the parent process determines what action to take. Differential Revision: https://phabricator.services.mozilla.com/D209353
		
			
				
	
	
		
			184 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			184 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
 | 
						|
 | 
						|
const lazy = {};
 | 
						|
 | 
						|
ChromeUtils.defineESModuleGetters(lazy, {
 | 
						|
  FirefoxRelay: "resource://gre/modules/FirefoxRelay.sys.mjs",
 | 
						|
  FormHistory: "resource://gre/modules/FormHistory.sys.mjs",
 | 
						|
  LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs",
 | 
						|
});
 | 
						|
 | 
						|
XPCOMUtils.defineLazyPreferenceGetter(
 | 
						|
  lazy,
 | 
						|
  "PREFERENCE_PREFIX_WEIGHT",
 | 
						|
  "browser.formfill.prefixWeight"
 | 
						|
);
 | 
						|
 | 
						|
XPCOMUtils.defineLazyPreferenceGetter(
 | 
						|
  lazy,
 | 
						|
  "PREFERENCE_BOUNDARY_WEIGHT",
 | 
						|
  "browser.formfill.boundaryWeight"
 | 
						|
);
 | 
						|
 | 
						|
export class FormHistoryParent extends JSWindowActorParent {
 | 
						|
  receiveMessage({ name, data }) {
 | 
						|
    switch (name) {
 | 
						|
      case "FormHistory:FormSubmitEntries":
 | 
						|
        this.#onFormSubmitEntries(data);
 | 
						|
        break;
 | 
						|
 | 
						|
      case "FormHistory:AutoCompleteSearchAsync":
 | 
						|
        return this.#onAutoCompleteSearch(data);
 | 
						|
 | 
						|
      case "FormHistory:RemoveEntry":
 | 
						|
        this.#onRemoveEntry(data);
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    return undefined;
 | 
						|
  }
 | 
						|
 | 
						|
  #onFormSubmitEntries(entries) {
 | 
						|
    const changes = entries.map(entry => ({
 | 
						|
      op: "bump",
 | 
						|
      fieldname: entry.name,
 | 
						|
      value: entry.value,
 | 
						|
    }));
 | 
						|
 | 
						|
    lazy.FormHistory.update(changes);
 | 
						|
  }
 | 
						|
 | 
						|
  get formOrigin() {
 | 
						|
    return lazy.LoginHelper.getLoginOrigin(
 | 
						|
      this.manager.documentPrincipal?.originNoSuffix
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  async #onAutoCompleteSearch({ searchString, params, scenarioName }) {
 | 
						|
    searchString = searchString.trim().toLowerCase();
 | 
						|
 | 
						|
    let formHistoryPromise;
 | 
						|
    if (
 | 
						|
      FormHistoryParent.canSearchIncrementally(
 | 
						|
        searchString,
 | 
						|
        this.previousSearchString
 | 
						|
      )
 | 
						|
    ) {
 | 
						|
      formHistoryPromise = Promise.resolve(
 | 
						|
        FormHistoryParent.incrementalSearch(
 | 
						|
          searchString,
 | 
						|
          this.previousSearchString,
 | 
						|
          this.previousSearchResult
 | 
						|
        )
 | 
						|
      );
 | 
						|
    } else {
 | 
						|
      formHistoryPromise = lazy.FormHistory.getAutoCompleteResults(
 | 
						|
        searchString,
 | 
						|
        params
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    const relayPromise = lazy.FirefoxRelay.autocompleteItemsAsync({
 | 
						|
      formOrigin: this.formOrigin,
 | 
						|
      scenarioName,
 | 
						|
      hasInput: !!searchString.length,
 | 
						|
    });
 | 
						|
    const [formHistoryEntries, externalEntries] = await Promise.all([
 | 
						|
      formHistoryPromise,
 | 
						|
      relayPromise,
 | 
						|
    ]);
 | 
						|
 | 
						|
    this.previousSearchString = searchString;
 | 
						|
    this.previousSearchResult = formHistoryEntries;
 | 
						|
 | 
						|
    return { formHistoryEntries, externalEntries };
 | 
						|
  }
 | 
						|
 | 
						|
  #onRemoveEntry({ inputName, value, guid }) {
 | 
						|
    lazy.FormHistory.update({
 | 
						|
      op: "remove",
 | 
						|
      fieldname: inputName,
 | 
						|
      value,
 | 
						|
      guid,
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  async searchAutoCompleteEntries(searchString, data) {
 | 
						|
    const { inputName, scenarioName } = data;
 | 
						|
    const params = {
 | 
						|
      fieldname: inputName,
 | 
						|
    };
 | 
						|
    return this.#onAutoCompleteSearch({ searchString, params, scenarioName });
 | 
						|
  }
 | 
						|
 | 
						|
  static canSearchIncrementally(searchString, previousSearchString) {
 | 
						|
    previousSearchString ||= "";
 | 
						|
    return (
 | 
						|
      previousSearchString.length > 1 &&
 | 
						|
      searchString.includes(previousSearchString)
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  static incrementalSearch(
 | 
						|
    searchString,
 | 
						|
    previousSearchString,
 | 
						|
    previousSearchResult
 | 
						|
  ) {
 | 
						|
    const searchTokens = searchString.split(/\s+/);
 | 
						|
    // We have a list of results for a shorter search string, so just
 | 
						|
    // filter them further based on the new search string and add to a new array.
 | 
						|
    let filteredEntries = [];
 | 
						|
    for (const entry of previousSearchResult) {
 | 
						|
      // Remove results that do not contain the token
 | 
						|
      // XXX bug 394604 -- .toLowerCase can be wrong for some intl chars
 | 
						|
      if (searchTokens.some(tok => !entry.textLowerCase.includes(tok))) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      FormHistoryParent.calculateScore(entry, searchString, searchTokens);
 | 
						|
      filteredEntries.push(entry);
 | 
						|
    }
 | 
						|
    filteredEntries.sort((a, b) => b.totalScore - a.totalScore);
 | 
						|
    return filteredEntries;
 | 
						|
  }
 | 
						|
 | 
						|
  /*
 | 
						|
   * calculateScore
 | 
						|
   *
 | 
						|
   * entry    -- an nsIAutoCompleteResult entry
 | 
						|
   * searchString -- current value of the input (lowercase)
 | 
						|
   * searchTokens -- array of tokens of the search string
 | 
						|
   *
 | 
						|
   * Returns: an int
 | 
						|
   */
 | 
						|
  static calculateScore(entry, searchString, searchTokens) {
 | 
						|
    let boundaryCalc = 0;
 | 
						|
    // for each word, calculate word boundary weights
 | 
						|
    for (const token of searchTokens) {
 | 
						|
      if (entry.textLowerCase.startsWith(token)) {
 | 
						|
        boundaryCalc++;
 | 
						|
      }
 | 
						|
      if (entry.textLowerCase.includes(" " + token)) {
 | 
						|
        boundaryCalc++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    boundaryCalc = boundaryCalc * lazy.PREFERENCE_BOUNDARY_WEIGHT;
 | 
						|
    // now add more weight if we have a traditional prefix match and
 | 
						|
    // multiply boundary bonuses by boundary weight
 | 
						|
    if (entry.textLowerCase.startsWith(searchString)) {
 | 
						|
      boundaryCalc += lazy.PREFERENCE_PREFIX_WEIGHT;
 | 
						|
    }
 | 
						|
    entry.totalScore = Math.round(entry.frecency * Math.max(1, boundaryCalc));
 | 
						|
  }
 | 
						|
 | 
						|
  previewFields(_result) {
 | 
						|
    // Not implemented
 | 
						|
  }
 | 
						|
 | 
						|
  autofillFields(_result) {
 | 
						|
    // Not implemented
 | 
						|
  }
 | 
						|
}
 |