зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1334012 - Move Login AutoComplete to its own interface. r=jaws
Differential Revision: https://phabricator.services.mozilla.com/D29694 --HG-- rename : toolkit/components/passwordmgr/nsILoginManager.idl => toolkit/components/passwordmgr/nsILoginAutoCompleteSearch.idl extra : moz-landing-system : lando
This commit is contained in:
Родитель
a918978a29
Коммит
8aad4d375a
|
@ -13,8 +13,16 @@ var EXPORTED_SYMBOLS = ["LoginAutoCompleteResult"];
|
|||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "BrowserUtils",
|
||||
"resource://gre/modules/BrowserUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "InsecurePasswordUtils",
|
||||
"resource://gre/modules/InsecurePasswordUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "LoginFormFactory",
|
||||
"resource://gre/modules/LoginFormFactory.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "LoginHelper",
|
||||
"resource://gre/modules/LoginHelper.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "LoginManagerContent",
|
||||
"resource://gre/modules/LoginManagerContent.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "formFillController",
|
||||
"@mozilla.org/satchel/form-fill-controller;1",
|
||||
|
@ -24,6 +32,7 @@ XPCOMUtils.defineLazyGetter(this, "log", () => {
|
|||
return LoginHelper.createLogger("LoginAutoCompleteResult");
|
||||
});
|
||||
|
||||
|
||||
// nsIAutoCompleteResult implementation
|
||||
function LoginAutoCompleteResult(aSearchString, matchingLogins, {isSecure, messageManager, isPasswordField, hostname}) {
|
||||
function loginSort(a, b) {
|
||||
|
@ -236,3 +245,108 @@ LoginAutoCompleteResult.prototype = {
|
|||
}
|
||||
},
|
||||
};
|
||||
|
||||
function LoginAutoComplete() {}
|
||||
LoginAutoComplete.prototype = {
|
||||
classID: Components.ID("{2bdac17c-53f1-4896-a521-682ccdeef3a8}"),
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsILoginAutoCompleteSearch]),
|
||||
|
||||
_autoCompleteLookupPromise: null,
|
||||
|
||||
/**
|
||||
* Yuck. This is called directly by satchel:
|
||||
* nsFormFillController::StartSearch()
|
||||
* [toolkit/components/satchel/nsFormFillController.cpp]
|
||||
*
|
||||
* We really ought to have a simple way for code to register an
|
||||
* auto-complete provider, and not have satchel calling pwmgr directly.
|
||||
*
|
||||
* @param {string} aSearchString The value typed in the field.
|
||||
* @param {nsIAutoCompleteResult} aPreviousResult
|
||||
* @param {HTMLInputElement} aElement
|
||||
* @param {nsIFormAutoCompleteObserver} aCallback
|
||||
*/
|
||||
startSearch(aSearchString, aPreviousResult, aElement, aCallback) {
|
||||
let {isNullPrincipal} = aElement.nodePrincipal;
|
||||
// Show the insecure login warning in the passwords field on null principal documents.
|
||||
let isSecure = !isNullPrincipal;
|
||||
// Avoid loading InsecurePasswordUtils.jsm in a sandboxed document (e.g. an ad. frame) if we
|
||||
// already know it has a null principal and will therefore get the insecure autocomplete
|
||||
// treatment.
|
||||
// InsecurePasswordUtils doesn't handle the null principal case as not secure because we don't
|
||||
// want the same treatment:
|
||||
// * The web console warnings will be confusing (as they're primarily about http:) and not very
|
||||
// useful if the developer intentionally sandboxed the document.
|
||||
// * The site identity insecure field warning would require LoginManagerContent being loaded and
|
||||
// listening to some of the DOM events we're ignoring in null principal documents. For memory
|
||||
// reasons it's better to not load LMC at all for these sandboxed frames. Also, if the top-
|
||||
// document is sandboxing a document, it probably doesn't want that sandboxed document to be
|
||||
// able to affect the identity icon in the address bar by adding a password field.
|
||||
if (isSecure) {
|
||||
let form = LoginFormFactory.createFromField(aElement);
|
||||
isSecure = InsecurePasswordUtils.isFormSecure(form);
|
||||
}
|
||||
let isPasswordField = aElement.type == "password";
|
||||
let hostname = aElement.ownerDocument.documentURIObject.host;
|
||||
|
||||
let completeSearch = (autoCompleteLookupPromise, { logins, messageManager }) => {
|
||||
// If the search was canceled before we got our
|
||||
// results, don't bother reporting them.
|
||||
if (this._autoCompleteLookupPromise !== autoCompleteLookupPromise) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._autoCompleteLookupPromise = null;
|
||||
let results = new LoginAutoCompleteResult(aSearchString, logins, {
|
||||
messageManager,
|
||||
isSecure,
|
||||
isPasswordField,
|
||||
hostname,
|
||||
});
|
||||
aCallback.onSearchCompletion(results);
|
||||
};
|
||||
|
||||
if (isNullPrincipal) {
|
||||
// Don't search login storage when the field has a null principal as we don't want to fill
|
||||
// logins for the `location` in this case.
|
||||
let acLookupPromise = this._autoCompleteLookupPromise = Promise.resolve({ logins: [] });
|
||||
acLookupPromise.then(completeSearch.bind(this, acLookupPromise));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPasswordField && aSearchString) {
|
||||
// Return empty result on password fields with password already filled.
|
||||
let acLookupPromise = this._autoCompleteLookupPromise = Promise.resolve({ logins: [] });
|
||||
acLookupPromise.then(completeSearch.bind(this, acLookupPromise));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LoginHelper.enabled) {
|
||||
let acLookupPromise = this._autoCompleteLookupPromise = Promise.resolve({ logins: [] });
|
||||
acLookupPromise.then(completeSearch.bind(this, acLookupPromise));
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("AutoCompleteSearch invoked. Search is:", aSearchString);
|
||||
|
||||
let previousResult;
|
||||
if (aPreviousResult) {
|
||||
previousResult = {
|
||||
searchString: aPreviousResult.searchString,
|
||||
logins: aPreviousResult.wrappedJSObject.logins,
|
||||
};
|
||||
} else {
|
||||
previousResult = null;
|
||||
}
|
||||
|
||||
let rect = BrowserUtils.getElementBoundingScreenRect(aElement);
|
||||
let acLookupPromise = this._autoCompleteLookupPromise =
|
||||
LoginManagerContent._autoCompleteSearchAsync(aSearchString, previousResult,
|
||||
aElement, rect);
|
||||
acLookupPromise.then(completeSearch.bind(this, acLookupPromise)).catch(log.error);
|
||||
},
|
||||
|
||||
stopSearch() {
|
||||
this._autoCompleteLookupPromise = null;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -9,16 +9,12 @@ const PERMISSION_SAVE_LOGINS = "login-saving";
|
|||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "BrowserUtils",
|
||||
"resource://gre/modules/BrowserUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "LoginHelper",
|
||||
"resource://gre/modules/LoginHelper.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "LoginFormFactory",
|
||||
"resource://gre/modules/LoginFormFactory.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "LoginManagerContent",
|
||||
"resource://gre/modules/LoginManagerContent.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "LoginAutoCompleteResult",
|
||||
"resource://gre/modules/LoginAutoCompleteResult.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "InsecurePasswordUtils",
|
||||
"resource://gre/modules/InsecurePasswordUtils.jsm");
|
||||
|
||||
|
@ -29,6 +25,11 @@ XPCOMUtils.defineLazyGetter(this, "log", () => {
|
|||
|
||||
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
||||
|
||||
if (Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT) {
|
||||
throw new Error("LoginManager.jsm should only run in the parent process");
|
||||
}
|
||||
|
||||
|
||||
function LoginManager() {
|
||||
this.init();
|
||||
}
|
||||
|
@ -56,8 +57,6 @@ LoginManager.prototype = {
|
|||
|
||||
/* ---------- private members ---------- */
|
||||
|
||||
|
||||
|
||||
_storage: null, // Storage component which contains the saved logins
|
||||
|
||||
|
||||
|
@ -65,24 +64,17 @@ LoginManager.prototype = {
|
|||
* Initialize the Login Manager. Automatically called when service
|
||||
* is created.
|
||||
*
|
||||
* Note: Service created in /browser/base/content/browser.js,
|
||||
* delayedStartup()
|
||||
* Note: Service created in BrowserGlue#_scheduleStartupIdleTasks()
|
||||
*/
|
||||
init() {
|
||||
// Cache references to current |this| in utility objects
|
||||
this._observer._pwmgr = this;
|
||||
this._autoCompleteLookupPromise = null;
|
||||
|
||||
// Form submit observer checks forms for new logins and pw changes.
|
||||
Services.obs.addObserver(this._observer, "xpcom-shutdown");
|
||||
Services.obs.addObserver(this._observer, "passwordmgr-storage-replace");
|
||||
|
||||
if (Services.appinfo.processType ===
|
||||
Services.appinfo.PROCESS_TYPE_DEFAULT) {
|
||||
Services.obs.addObserver(this._observer, "passwordmgr-storage-replace");
|
||||
|
||||
// Initialize storage so that asynchronous data loading can start.
|
||||
this._initStorage();
|
||||
}
|
||||
// Initialize storage so that asynchronous data loading can start.
|
||||
this._initStorage();
|
||||
|
||||
Services.obs.addObserver(this._observer, "gather-telemetry");
|
||||
},
|
||||
|
@ -464,101 +456,6 @@ LoginManager.prototype = {
|
|||
log.debug("Login saving for", origin, "now enabled?", enabled);
|
||||
LoginHelper.notifyStorageChanged(enabled ? "hostSavingEnabled" : "hostSavingDisabled", origin);
|
||||
},
|
||||
|
||||
/**
|
||||
* Yuck. This is called directly by satchel:
|
||||
* nsFormFillController::StartSearch()
|
||||
* [toolkit/components/satchel/nsFormFillController.cpp]
|
||||
*
|
||||
* We really ought to have a simple way for code to register an
|
||||
* auto-complete provider, and not have satchel calling pwmgr directly.
|
||||
*/
|
||||
autoCompleteSearchAsync(aSearchString, aPreviousResult,
|
||||
aElement, aCallback) {
|
||||
// aPreviousResult is an nsIAutoCompleteResult, aElement is
|
||||
// HTMLInputElement
|
||||
|
||||
let {isNullPrincipal} = aElement.nodePrincipal;
|
||||
// Show the insecure login warning in the passwords field on null principal documents.
|
||||
let isSecure = !isNullPrincipal;
|
||||
// Avoid loading InsecurePasswordUtils.jsm in a sandboxed document (e.g. an ad. frame) if we
|
||||
// already know it has a null principal and will therefore get the insecure autocomplete
|
||||
// treatment.
|
||||
// InsecurePasswordUtils doesn't handle the null principal case as not secure because we don't
|
||||
// want the same treatment:
|
||||
// * The web console warnings will be confusing (as they're primarily about http:) and not very
|
||||
// useful if the developer intentionally sandboxed the document.
|
||||
// * The site identity insecure field warning would require LoginManagerContent being loaded and
|
||||
// listening to some of the DOM events we're ignoring in null principal documents. For memory
|
||||
// reasons it's better to not load LMC at all for these sandboxed frames. Also, if the top-
|
||||
// document is sandboxing a document, it probably doesn't want that sandboxed document to be
|
||||
// able to affect the identity icon in the address bar by adding a password field.
|
||||
if (isSecure) {
|
||||
let form = LoginFormFactory.createFromField(aElement);
|
||||
isSecure = InsecurePasswordUtils.isFormSecure(form);
|
||||
}
|
||||
let isPasswordField = aElement.type == "password";
|
||||
let hostname = aElement.ownerDocument.documentURIObject.host;
|
||||
|
||||
let completeSearch = (autoCompleteLookupPromise, { logins, messageManager }) => {
|
||||
// If the search was canceled before we got our
|
||||
// results, don't bother reporting them.
|
||||
if (this._autoCompleteLookupPromise !== autoCompleteLookupPromise) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._autoCompleteLookupPromise = null;
|
||||
let results = new LoginAutoCompleteResult(aSearchString, logins, {
|
||||
messageManager,
|
||||
isSecure,
|
||||
isPasswordField,
|
||||
hostname,
|
||||
});
|
||||
aCallback.onSearchCompletion(results);
|
||||
};
|
||||
|
||||
if (isNullPrincipal) {
|
||||
// Don't search login storage when the field has a null principal as we don't want to fill
|
||||
// logins for the `location` in this case.
|
||||
let acLookupPromise = this._autoCompleteLookupPromise = Promise.resolve({ logins: [] });
|
||||
acLookupPromise.then(completeSearch.bind(this, acLookupPromise));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPasswordField && aSearchString) {
|
||||
// Return empty result on password fields with password already filled.
|
||||
let acLookupPromise = this._autoCompleteLookupPromise = Promise.resolve({ logins: [] });
|
||||
acLookupPromise.then(completeSearch.bind(this, acLookupPromise));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LoginHelper.enabled) {
|
||||
let acLookupPromise = this._autoCompleteLookupPromise = Promise.resolve({ logins: [] });
|
||||
acLookupPromise.then(completeSearch.bind(this, acLookupPromise));
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("AutoCompleteSearch invoked. Search is:", aSearchString);
|
||||
|
||||
let previousResult;
|
||||
if (aPreviousResult) {
|
||||
previousResult = { searchString: aPreviousResult.searchString,
|
||||
logins: aPreviousResult.wrappedJSObject.logins };
|
||||
} else {
|
||||
previousResult = null;
|
||||
}
|
||||
|
||||
let rect = BrowserUtils.getElementBoundingScreenRect(aElement);
|
||||
let acLookupPromise = this._autoCompleteLookupPromise =
|
||||
LoginManagerContent._autoCompleteSearchAsync(aSearchString, previousResult,
|
||||
aElement, rect);
|
||||
acLookupPromise.then(completeSearch.bind(this, acLookupPromise))
|
||||
.catch(Cu.reportError);
|
||||
},
|
||||
|
||||
stopSearch() {
|
||||
this._autoCompleteLookupPromise = null;
|
||||
},
|
||||
}; // end of LoginManager implementation
|
||||
|
||||
var EXPORTED_SYMBOLS = ["LoginManager"];
|
||||
|
|
|
@ -17,6 +17,12 @@ Classes = [
|
|||
'jsm': 'resource://gre/modules/LoginManagerPrompter.jsm',
|
||||
'constructor': 'LoginManagerPromptFactory',
|
||||
},
|
||||
{
|
||||
'cid': '{2bdac17c-53f1-4896-a521-682ccdeef3a8}',
|
||||
'contract_ids': ['@mozilla.org/passwordmanager/autocompletesearch;1'],
|
||||
'jsm': 'resource://gre/modules/LoginAutoCompleteResult.jsm',
|
||||
'constructor': 'LoginAutoComplete',
|
||||
},
|
||||
{
|
||||
'cid': '{8aa66d77-1bbb-45a6-991e-b8f47751c291}',
|
||||
'contract_ids': ['@mozilla.org/login-manager/prompter;1'],
|
||||
|
|
|
@ -18,6 +18,7 @@ TESTING_JS_MODULES += [
|
|||
]
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsILoginAutoCompleteSearch.idl',
|
||||
'nsILoginInfo.idl',
|
||||
'nsILoginManager.idl',
|
||||
'nsILoginManagerCrypto.idl',
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIAutoCompleteResult;
|
||||
interface nsIFormAutoCompleteObserver;
|
||||
|
||||
webidl HTMLInputElement;
|
||||
|
||||
[scriptable, uuid(2bdac17c-53f1-4896-a521-682ccdeef3a8)]
|
||||
interface nsILoginAutoCompleteSearch : nsISupports {
|
||||
/**
|
||||
* Generate results for a login field autocomplete menu.
|
||||
*
|
||||
* NOTE: This interface is provided for use only by the FormFillController,
|
||||
* which calls it directly. This isn't really ideal, it should
|
||||
* probably be callback registered through the FFC.
|
||||
* NOTE: This API is different than nsIAutoCompleteSearch.
|
||||
*/
|
||||
void startSearch(in AString aSearchString,
|
||||
in nsIAutoCompleteResult aPreviousResult,
|
||||
in HTMLInputElement aElement,
|
||||
in nsIFormAutoCompleteObserver aListener);
|
||||
|
||||
/**
|
||||
* Stop a previously-started search.
|
||||
*/
|
||||
void stopSearch();
|
||||
};
|
|
@ -2,17 +2,11 @@
|
|||
* 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/. */
|
||||
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIURI;
|
||||
interface nsILoginInfo;
|
||||
interface nsIAutoCompleteResult;
|
||||
interface nsIFormAutoCompleteObserver;
|
||||
interface nsIPropertyBag;
|
||||
|
||||
webidl HTMLInputElement;
|
||||
|
||||
[scriptable, uuid(38c7f6af-7df9-49c7-b558-2776b24e6cc1)]
|
||||
interface nsILoginManager : nsISupports {
|
||||
/**
|
||||
|
@ -217,24 +211,6 @@ interface nsILoginManager : nsISupports {
|
|||
unsigned long countLogins(in AString aHostname, in AString aActionURL,
|
||||
in AString aHttpRealm);
|
||||
|
||||
|
||||
/**
|
||||
* Generate results for a userfield autocomplete menu.
|
||||
*
|
||||
* NOTE: This interface is provided for use only by the FormFillController,
|
||||
* which calls it directly. This isn't really ideal, it should
|
||||
* probably be callback registered through the FFC.
|
||||
*/
|
||||
void autoCompleteSearchAsync(in AString aSearchString,
|
||||
in nsIAutoCompleteResult aPreviousResult,
|
||||
in HTMLInputElement aElement,
|
||||
in nsIFormAutoCompleteObserver aListener);
|
||||
|
||||
/**
|
||||
* Stop a previously-started async search.
|
||||
*/
|
||||
void stopSearch();
|
||||
|
||||
/**
|
||||
* Search for logins in the login manager. An array is always returned;
|
||||
* if there are no logins the array is empty.
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "nsIContentViewer.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsILoginManager.h"
|
||||
#include "nsILoginAutoCompleteSearch.h"
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsEmbedCID.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
@ -65,7 +65,7 @@ static nsIFormAutoComplete* GetFormAutoComplete() {
|
|||
return sInstance;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(nsFormFillController, mController, mLoginManager,
|
||||
NS_IMPL_CYCLE_COLLECTION(nsFormFillController, mController, mLoginManagerAC,
|
||||
mLoginReputationService, mFocusedPopup, mDocShells,
|
||||
mPopups, mLastListener, mLastFormAutoComplete)
|
||||
|
||||
|
@ -298,8 +298,8 @@ nsFormFillController::MarkAsLoginManagerField(HTMLInputElement* aInput) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!mLoginManager) {
|
||||
mLoginManager = do_GetService("@mozilla.org/login-manager;1");
|
||||
if (!mLoginManagerAC) {
|
||||
mLoginManagerAC = do_GetService("@mozilla.org/passwordmanager/autocompletesearch;1");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -707,19 +707,18 @@ nsFormFillController::StartSearch(const nsAString& aSearchString,
|
|||
// Handle the case where a password field is focused but
|
||||
// MarkAsLoginManagerField wasn't called because password manager is
|
||||
// disabled.
|
||||
if (!mLoginManager) {
|
||||
mLoginManager = do_GetService("@mozilla.org/login-manager;1");
|
||||
if (!mLoginManagerAC) {
|
||||
mLoginManagerAC = do_GetService("@mozilla.org/passwordmanger/autocompletesearch;1");
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mLoginManager)) {
|
||||
if (NS_WARN_IF(!mLoginManagerAC)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// XXX aPreviousResult shouldn't ever be a historyResult type, since we're
|
||||
// not letting satchel manage the field?
|
||||
mLastListener = aListener;
|
||||
rv = mLoginManager->AutoCompleteSearchAsync(aSearchString, aPreviousResult,
|
||||
mFocusedInput, this);
|
||||
rv = mLoginManagerAC->StartSearch(aSearchString, aPreviousResult, mFocusedInput, this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
MOZ_LOG(sLogger, LogLevel::Debug, ("StartSearch: non-login field"));
|
||||
|
@ -800,8 +799,8 @@ nsFormFillController::StopSearch() {
|
|||
if (mLastFormAutoComplete) {
|
||||
mLastFormAutoComplete->StopAutoCompleteSearch();
|
||||
mLastFormAutoComplete = nullptr;
|
||||
} else if (mLoginManager) {
|
||||
mLoginManager->StopSearch();
|
||||
} else if (mLoginManagerAC) {
|
||||
mLoginManagerAC->StopSearch();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsILoginManager.h"
|
||||
#include "nsILoginAutoCompleteSearch.h"
|
||||
#include "nsIMutationObserver.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
@ -110,7 +110,7 @@ class nsFormFillController final : public nsIFormFillController,
|
|||
// members //////////////////////////////////////////
|
||||
|
||||
nsCOMPtr<nsIAutoCompleteController> mController;
|
||||
nsCOMPtr<nsILoginManager> mLoginManager;
|
||||
nsCOMPtr<nsILoginAutoCompleteSearch> mLoginManagerAC;
|
||||
nsCOMPtr<nsILoginReputationService> mLoginReputationService;
|
||||
mozilla::dom::HTMLInputElement* mFocusedInput;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче