diff --git a/toolkit/components/passwordmgr/nsILoginManager.idl b/toolkit/components/passwordmgr/nsILoginManager.idl index 8f8807c8ae5d..4beee995d173 100644 --- a/toolkit/components/passwordmgr/nsILoginManager.idl +++ b/toolkit/components/passwordmgr/nsILoginManager.idl @@ -8,12 +8,12 @@ interface nsIURI; interface nsILoginInfo; interface nsIAutoCompleteResult; -interface nsIFormAutoCompleteObserver; interface nsIDOMHTMLInputElement; interface nsIDOMHTMLFormElement; interface nsIPropertyBag; -[scriptable, uuid(f441b0a3-6588-455e-baa8-2e2dbba84655)] +[scriptable, uuid(f5f2a39a-dffe-4eb9-ad28-340afd53b1a3)] + interface nsILoginManager : nsISupports { /** * This promise is resolved when initialization is complete, and is rejected @@ -210,10 +210,9 @@ interface nsILoginManager : nsISupports { * 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 nsIDOMHTMLInputElement aElement, - in nsIFormAutoCompleteObserver aListener); + nsIAutoCompleteResult autoCompleteSearch(in AString aSearchString, + in nsIAutoCompleteResult aPreviousResult, + in nsIDOMHTMLInputElement aElement); /** * Fill a form with login information if we have it. This method will fill diff --git a/toolkit/components/passwordmgr/nsLoginManager.js b/toolkit/components/passwordmgr/nsLoginManager.js index 55952bdfeb5f..9e54764049cc 100644 --- a/toolkit/components/passwordmgr/nsLoginManager.js +++ b/toolkit/components/passwordmgr/nsLoginManager.js @@ -8,7 +8,6 @@ const Ci = Components.interfaces; Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); -Components.utils.import("resource://gre/modules/Timer.jsm"); Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent", @@ -409,34 +408,32 @@ LoginManager.prototype = { return this._storage.setLoginSavingEnabled(hostname, enabled); }, + /* - * autoCompleteSearchAsync + * autoCompleteSearch * * Yuck. This is called directly by satchel: * nsFormFillController::StartSearch() - * [toolkit/components/satchel/nsFormFillController.cpp] + * [toolkit/components/satchel/src/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 : function (aSearchString, aPreviousResult, - aElement, aCallback) { + autoCompleteSearch : function (aSearchString, aPreviousResult, aElement) { // aPreviousResult & aResult are nsIAutoCompleteResult, // aElement is nsIDOMHTMLInputElement - if (!this._remember) { - setTimeout(function() { - aCallback.onSearchCompletion(new UserAutoCompleteResult(aSearchString, [])); - }, 0); - return; - } + if (!this._remember) + return null; log("AutoCompleteSearch invoked. Search is:", aSearchString); + var result = null; + if (aPreviousResult && aSearchString.substr(0, aPreviousResult.searchString.length) == aPreviousResult.searchString) { log("Using previous autocomplete result"); - let result = aPreviousResult; + result = aPreviousResult; result.wrappedJSObject.searchString = aSearchString; // We have a list of results for a shorter search string, so just @@ -455,47 +452,47 @@ LoginManager.prototype = { result.removeValueAt(i, false); } } - - setTimeout(function() { aCallback.onSearchCompletion(result); }, 0); } else { log("Creating new autocomplete search result."); - setTimeout(function() { - var doc = aElement.ownerDocument; - var origin = this._getPasswordOrigin(doc.documentURI); - var actionOrigin = this._getActionOrigin(aElement.form); + var doc = aElement.ownerDocument; + var origin = this._getPasswordOrigin(doc.documentURI); + var actionOrigin = this._getActionOrigin(aElement.form); - // This shouldn't trigger a master password prompt, because we - // don't attach to the input until after we successfully obtain - // logins for the form. - var logins = this.findLogins({}, origin, actionOrigin, null); - var matchingLogins = []; + // This shouldn't trigger a master password prompt, because we + // don't attach to the input until after we successfully obtain + // logins for the form. + var logins = this.findLogins({}, origin, actionOrigin, null); + var matchingLogins = []; - // Filter out logins that don't match the search prefix. Also - // filter logins without a username, since that's confusing to see - // in the dropdown and we can't autocomplete them anyway. - for (let i = 0; i < logins.length; i++) { - var username = logins[i].username.toLowerCase(); - log(username); - if (username && - aSearchString.length <= username.length && - aSearchString.toLowerCase() == - username.substr(0, aSearchString.length)) - { - matchingLogins.push(logins[i]); - } + // Filter out logins that don't match the search prefix. Also + // filter logins without a username, since that's confusing to see + // in the dropdown and we can't autocomplete them anyway. + for (i = 0; i < logins.length; i++) { + var username = logins[i].username.toLowerCase(); + if (username && + aSearchString.length <= username.length && + aSearchString.toLowerCase() == + username.substr(0, aSearchString.length)) + { + matchingLogins.push(logins[i]); } - log(matchingLogins.length, "autocomplete logins avail."); - aCallback.onSearchCompletion(new UserAutoCompleteResult(aSearchString, - matchingLogins)); - }.bind(this), 0); + } + log(matchingLogins.length, "autocomplete logins avail."); + result = new UserAutoCompleteResult(aSearchString, matchingLogins); } + + return result; }, + + /* ------- Internal methods / callbacks for document integration ------- */ + + /* * _getPasswordOrigin * diff --git a/toolkit/components/satchel/nsFormFillController.cpp b/toolkit/components/satchel/nsFormFillController.cpp index 777364362110..d753959acc7e 100644 --- a/toolkit/components/satchel/nsFormFillController.cpp +++ b/toolkit/components/satchel/nsFormFillController.cpp @@ -599,6 +599,7 @@ nsFormFillController::StartSearch(const nsAString &aSearchString, const nsAStrin nsIAutoCompleteResult *aPreviousResult, nsIAutoCompleteObserver *aListener) { nsresult rv; + nsCOMPtr result; // If the login manager has indicated it's responsible for this field, let it // handle the autocomplete. Otherwise, handle with form history. @@ -606,12 +607,14 @@ nsFormFillController::StartSearch(const nsAString &aSearchString, const nsAStrin if (mPwmgrInputs.Get(mFocusedInputNode, &dummy)) { // 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 = mLoginManager->AutoCompleteSearch(aSearchString, + aPreviousResult, + mFocusedInput, + getter_AddRefs(result)); NS_ENSURE_SUCCESS(rv, rv); + if (aListener) { + aListener->OnSearchResult(this, result); + } } else { mLastListener = aListener; @@ -650,42 +653,32 @@ nsFormFillController::PerformInputListAutoComplete(nsIAutoCompleteResult* aPrevi nsresult rv; nsCOMPtr result; - bool dummy; - if (!mPwmgrInputs.Get(mFocusedInputNode, &dummy)) { - nsCOMPtr inputListAutoComplete = - do_GetService("@mozilla.org/satchel/inputlist-autocomplete;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - rv = inputListAutoComplete->AutoCompleteSearch(aPreviousResult, - mLastSearchString, - mFocusedInput, - getter_AddRefs(result)); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr inputListAutoComplete = + do_GetService("@mozilla.org/satchel/inputlist-autocomplete;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = inputListAutoComplete->AutoCompleteSearch(aPreviousResult, + mLastSearchString, + mFocusedInput, + getter_AddRefs(result)); + NS_ENSURE_SUCCESS(rv, rv); - if (mFocusedInput) { - nsCOMPtr list; - mFocusedInput->GetList(getter_AddRefs(list)); + if (mFocusedInput) { + nsCOMPtr list; + mFocusedInput->GetList(getter_AddRefs(list)); - // Add a mutation observer to check for changes to the items in the - // and update the suggestions accordingly. - nsCOMPtr node = do_QueryInterface(list); - if (mListNode != node) { - if (mListNode) { - mListNode->RemoveMutationObserver(this); - mListNode = nullptr; - } - if (node) { - node->AddMutationObserverUnlessExists(this); - mListNode = node; - } + // Add a mutation observer to check for changes to the items in the + // and update the suggestions accordingly. + nsCOMPtr node = do_QueryInterface(list); + if (mListNode != node) { + if (mListNode) { + mListNode->RemoveMutationObserver(this); + mListNode = nullptr; + } + if (node) { + node->AddMutationObserverUnlessExists(this); + mListNode = node; } } - } else { - result = aPreviousResult; - - // If this is a password manager input mLastSearchResult will be a JS - // object (wrapped in an XPConnect reflector), so we need to take care not - // to hold onto it for too long. - mLastSearchResult = nullptr; } if (mLastListener) {