mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			127 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			127 lines
		
	
	
	
		
			3.6 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/. */
 | 
						|
 | 
						|
/**
 | 
						|
 * Form Autofill content process module.
 | 
						|
 */
 | 
						|
 | 
						|
import { sendFillRequestToParent } from "resource://gre/modules/FillHelpers.sys.mjs";
 | 
						|
 | 
						|
/* eslint-disable no-use-before-define */
 | 
						|
 | 
						|
const lazy = {};
 | 
						|
 | 
						|
ChromeUtils.defineESModuleGetters(lazy, {
 | 
						|
  FormAutofill: "resource://autofill/FormAutofill.sys.mjs",
 | 
						|
  FormAutofillContent: "resource://autofill/FormAutofillContent.sys.mjs",
 | 
						|
});
 | 
						|
 | 
						|
const autocompleteController = Cc[
 | 
						|
  "@mozilla.org/autocomplete/controller;1"
 | 
						|
].getService(Ci.nsIAutoCompleteController);
 | 
						|
 | 
						|
function getActorFromWindow(contentWindow, name = "FormAutofill") {
 | 
						|
  // In unit tests, contentWindow isn't a real window.
 | 
						|
  if (!contentWindow) {
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  return contentWindow.windowGlobalChild
 | 
						|
    ? contentWindow.windowGlobalChild.getActor(name)
 | 
						|
    : null;
 | 
						|
}
 | 
						|
 | 
						|
export const ProfileAutocomplete = {
 | 
						|
  QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
 | 
						|
 | 
						|
  _registered: false,
 | 
						|
 | 
						|
  ensureRegistered() {
 | 
						|
    if (this._registered) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    this.log = lazy.FormAutofill.defineLogGetter(this, "ProfileAutocomplete");
 | 
						|
    this.debug("ensureRegistered");
 | 
						|
    this._registered = true;
 | 
						|
 | 
						|
    Services.obs.addObserver(this, "autocomplete-will-enter-text");
 | 
						|
 | 
						|
    this.debug(
 | 
						|
      "ensureRegistered. Finished with _registered:",
 | 
						|
      this._registered
 | 
						|
    );
 | 
						|
  },
 | 
						|
 | 
						|
  ensureUnregistered() {
 | 
						|
    if (!this._registered) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    this.debug("ensureUnregistered");
 | 
						|
    this._registered = false;
 | 
						|
 | 
						|
    Services.obs.removeObserver(this, "autocomplete-will-enter-text");
 | 
						|
  },
 | 
						|
 | 
						|
  async observe(_subject, topic, _data) {
 | 
						|
    switch (topic) {
 | 
						|
      case "autocomplete-will-enter-text": {
 | 
						|
        if (!lazy.FormAutofillContent.activeInput) {
 | 
						|
          // The observer notification is for autocomplete in a different process.
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        await this._fillFromAutocompleteRow(
 | 
						|
          lazy.FormAutofillContent.activeInput
 | 
						|
        );
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  async _fillFromAutocompleteRow(focusedInput) {
 | 
						|
    this.debug("_fillFromAutocompleteRow:", focusedInput);
 | 
						|
    let formDetails = lazy.FormAutofillContent.activeFormDetails;
 | 
						|
    if (!formDetails) {
 | 
						|
      // The observer notification is for a different frame.
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    const actor = getActorFromWindow(focusedInput.ownerGlobal, "AutoComplete");
 | 
						|
    if (!actor) {
 | 
						|
      throw new Error("Invalid autocomplete selectedIndex");
 | 
						|
    }
 | 
						|
 | 
						|
    const selectedIndex = actor.selectedIndex;
 | 
						|
    const lastProfileAutoCompleteResult = actor.lastProfileAutoCompleteResult;
 | 
						|
    const validIndex =
 | 
						|
      selectedIndex >= 0 &&
 | 
						|
      selectedIndex < lastProfileAutoCompleteResult?.matchCount;
 | 
						|
    const comment = validIndex
 | 
						|
      ? lastProfileAutoCompleteResult.getCommentAt(selectedIndex)
 | 
						|
      : null;
 | 
						|
 | 
						|
    let parsedComment = JSON.parse(comment);
 | 
						|
    if (
 | 
						|
      selectedIndex == -1 ||
 | 
						|
      lastProfileAutoCompleteResult?.getStyleAt(selectedIndex) != "autofill"
 | 
						|
    ) {
 | 
						|
      if (
 | 
						|
        focusedInput &&
 | 
						|
        focusedInput == autocompleteController?.input.focusedInput
 | 
						|
      ) {
 | 
						|
        if (parsedComment?.fillMessageName == "FormAutofill:ClearForm") {
 | 
						|
          // The child can do this directly.
 | 
						|
          getActorFromWindow(focusedInput.ownerGlobal)?.clearForm();
 | 
						|
        } else {
 | 
						|
          // Pass focusedInput as both input arguments.
 | 
						|
          await sendFillRequestToParent(
 | 
						|
            "FormAutofill",
 | 
						|
            autocompleteController.input,
 | 
						|
            comment
 | 
						|
          );
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  },
 | 
						|
};
 |