mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-04 13:07:52 +00:00
Bug 439365 – need a notification to fire when a form is available to be filled in. r=dolske
This commit is contained in:
parent
ce4913a634
commit
1a1ab238f9
@ -43,7 +43,7 @@ interface nsIAutoCompleteResult;
|
||||
interface nsIDOMHTMLInputElement;
|
||||
interface nsIDOMHTMLFormElement;
|
||||
|
||||
[scriptable, uuid(5247f630-38a5-11dd-ae16-0800200c9a66)]
|
||||
[scriptable, uuid(04dbfa30-4238-11dd-ae16-0800200c9a66)]
|
||||
|
||||
interface nsILoginManager : nsISupports {
|
||||
|
||||
@ -219,8 +219,9 @@ interface nsILoginManager : nsISupports {
|
||||
*
|
||||
* @param aForm
|
||||
* The form to fill
|
||||
* @return Success of attempt fill form
|
||||
*/
|
||||
void fillForm(in nsIDOMHTMLFormElement aForm);
|
||||
boolean fillForm(in nsIDOMHTMLFormElement aForm);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
@ -84,6 +84,15 @@ LoginManager.prototype = {
|
||||
},
|
||||
|
||||
|
||||
__observerService : null, // Observer Service, for notifications
|
||||
get _observerService() {
|
||||
if (!this.__observerService)
|
||||
this.__observerService = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
return this.__observerService;
|
||||
},
|
||||
|
||||
|
||||
__storage : null, // Storage component which contains the saved logins
|
||||
get _storage() {
|
||||
if (!this.__storage) {
|
||||
@ -155,10 +164,8 @@ LoginManager.prototype = {
|
||||
|
||||
|
||||
// Form submit observer checks forms for new logins and pw changes.
|
||||
var observerService = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
observerService.addObserver(this._observer, "earlyformsubmit", false);
|
||||
observerService.addObserver(this._observer, "xpcom-shutdown", false);
|
||||
this._observerService.addObserver(this._observer, "earlyformsubmit", false);
|
||||
this._observerService.addObserver(this._observer, "xpcom-shutdown", false);
|
||||
|
||||
// WebProgressListener for getting notification of new doc loads.
|
||||
var progress = Cc["@mozilla.org/docloaderservice;1"].
|
||||
@ -966,7 +973,7 @@ LoginManager.prototype = {
|
||||
previousActionOrigin = actionOrigin;
|
||||
}
|
||||
this.log("_fillDocument processing form[" + i + "]");
|
||||
foundLogins = this._fillForm(form, autofillForm, foundLogins);
|
||||
foundLogins = this._fillForm(form, autofillForm, false, foundLogins)[1];
|
||||
} // foreach form
|
||||
},
|
||||
|
||||
@ -976,10 +983,14 @@ LoginManager.prototype = {
|
||||
*
|
||||
* Fill the form with login information if we can find it. This will find
|
||||
* an array of logins if not given any, otherwise it will use the logins
|
||||
* passed in. The logins are returned so they can be reused for
|
||||
* optimization.
|
||||
* passed in. The logins are returned so they can be reused for
|
||||
* optimization. Success of action is also returned in format
|
||||
* [success, foundLogins]. autofillForm denotes if we should fill the form
|
||||
* in automatically, ignoreAutocomplete denotes if we should ignore
|
||||
* autocomplete=off attributes, and foundLogins is an array of nsILoginInfo
|
||||
* for optimization
|
||||
*/
|
||||
_fillForm : function (form, autofillForm, foundLogins) {
|
||||
_fillForm : function (form, autofillForm, ignoreAutocomplete, foundLogins) {
|
||||
// Heuristically determine what the user/pass fields are
|
||||
// We do this before checking to see if logins are stored,
|
||||
// so that the user isn't prompted for a master password
|
||||
@ -989,7 +1000,7 @@ LoginManager.prototype = {
|
||||
|
||||
// Need a valid password field to do anything.
|
||||
if (passwordField == null)
|
||||
return foundLogins;
|
||||
return [false, foundLogins];
|
||||
|
||||
// Need to get a list of logins if we weren't given them
|
||||
if (foundLogins == null) {
|
||||
@ -1027,7 +1038,7 @@ LoginManager.prototype = {
|
||||
|
||||
// Nothing to do if we have no matching logins available.
|
||||
if (logins.length == 0)
|
||||
return foundLogins;
|
||||
return [false, foundLogins];
|
||||
|
||||
|
||||
// Attach autocomplete stuff to the username field, if we have
|
||||
@ -1041,55 +1052,72 @@ LoginManager.prototype = {
|
||||
// the autocomplete stuff to the username field, so the user can
|
||||
// still manually select a login to be filled in.
|
||||
var isFormDisabled = false;
|
||||
if (this._isAutocompleteDisabled(form) ||
|
||||
this._isAutocompleteDisabled(usernameField) ||
|
||||
this._isAutocompleteDisabled(passwordField)) {
|
||||
if (!ignoreAutocomplete &&
|
||||
(this._isAutocompleteDisabled(form) ||
|
||||
this._isAutocompleteDisabled(usernameField) ||
|
||||
this._isAutocompleteDisabled(passwordField))) {
|
||||
|
||||
isFormDisabled = true;
|
||||
this.log("form not filled, has autocomplete=off");
|
||||
}
|
||||
|
||||
if (autofillForm && !isFormDisabled) {
|
||||
// Variable such that we reduce code duplication and can be sure we
|
||||
// should be firing notifications if and only if we can fill the form.
|
||||
var selectedLogin = null;
|
||||
|
||||
if (usernameField && usernameField.value) {
|
||||
// If username was specified in the form, only fill in the
|
||||
// password if we find a matching login.
|
||||
if (usernameField && usernameField.value) {
|
||||
// If username was specified in the form, only fill in the
|
||||
// password if we find a matching login.
|
||||
|
||||
var username = usernameField.value;
|
||||
var username = usernameField.value;
|
||||
|
||||
var matchingLogin;
|
||||
var found = logins.some(function(l) {
|
||||
matchingLogin = l;
|
||||
return (l.username == username);
|
||||
});
|
||||
if (found)
|
||||
passwordField.value = matchingLogin.password;
|
||||
else
|
||||
this.log("Password not filled. None of the stored " +
|
||||
"logins match the username already present.");
|
||||
var matchingLogin;
|
||||
var found = logins.some(function(l) {
|
||||
matchingLogin = l;
|
||||
return (l.username == username);
|
||||
});
|
||||
if (found)
|
||||
selectedLogin = matchingLogin;
|
||||
else
|
||||
this.log("Password not filled. None of the stored " +
|
||||
"logins match the username already present.");
|
||||
|
||||
} else if (usernameField && logins.length == 2) {
|
||||
// Special case, for sites which have a normal user+pass
|
||||
// login *and* a password-only login (eg, a PIN)...
|
||||
// When we have a username field and 1 of 2 available
|
||||
// logins is password-only, go ahead and prefill the
|
||||
// one with a username.
|
||||
if (!logins[0].username && logins[1].username) {
|
||||
usernameField.value = logins[1].username;
|
||||
passwordField.value = logins[1].password;
|
||||
} else if (!logins[1].username && logins[0].username) {
|
||||
usernameField.value = logins[0].username;
|
||||
passwordField.value = logins[0].password;
|
||||
}
|
||||
} else if (logins.length == 1) {
|
||||
if (usernameField)
|
||||
usernameField.value = logins[0].username;
|
||||
passwordField.value = logins[0].password;
|
||||
} else {
|
||||
this.log("Multiple logins for form, so not filling any.");
|
||||
}
|
||||
} else if (usernameField && logins.length == 2) {
|
||||
// Special case, for sites which have a normal user+pass
|
||||
// login *and* a password-only login (eg, a PIN)...
|
||||
// When we have a username field and 1 of 2 available
|
||||
// logins is password-only, go ahead and prefill the
|
||||
// one with a username.
|
||||
if (!logins[0].username && logins[1].username)
|
||||
selectedLogin = logins[1];
|
||||
else if (!logins[1].username && logins[0].username)
|
||||
selectedLogin = logins[0];
|
||||
} else if (logins.length == 1) {
|
||||
selectedLogin = logins[0];
|
||||
} else {
|
||||
this.log("Multiple logins for form, so not filling any.");
|
||||
}
|
||||
return foundLogins;
|
||||
|
||||
var didFillForm = false;
|
||||
if (selectedLogin && autofillForm && !isFormDisabled) {
|
||||
// Fill the form
|
||||
if (usernameField)
|
||||
usernameField.value = selectedLogin.username;
|
||||
passwordField.value = selectedLogin.password;
|
||||
didFillForm = true;
|
||||
} else if (selectedLogin && !autofillForm) {
|
||||
// For when autofillForm is false, but we still have the information
|
||||
// to fill a form, we notify observers.
|
||||
this._observerService.notifyObservers(form, "passwordmgr-found-form", "noAutofillForms");
|
||||
this.log("autofillForms=false but form can be filled; notified observers");
|
||||
} else if (selectedLogin && isFormDisabled) {
|
||||
// For when autocomplete is off, but we still have the information
|
||||
// to fill a form, we notify observers.
|
||||
this._observerService.notifyObservers(form, "passwordmgr-found-form", "autocompleteOff");
|
||||
this.log("autocomplete=off but form can be filled; notified observers");
|
||||
}
|
||||
|
||||
return [didFillForm, foundLogins];
|
||||
},
|
||||
|
||||
|
||||
@ -1100,7 +1128,7 @@ LoginManager.prototype = {
|
||||
*/
|
||||
fillForm : function (form) {
|
||||
this.log("fillForm processing form[id=" + form.id + "]");
|
||||
this._fillForm(form, true, null)
|
||||
return this._fillForm(form, true, true, null)[0];
|
||||
},
|
||||
|
||||
|
||||
|
@ -57,6 +57,8 @@ MOCHI_TESTS = \
|
||||
test_basic_form_2pw_2.html \
|
||||
test_basic_form_3pw_1.html \
|
||||
test_basic_form_autocomplete.html \
|
||||
test_basic_form_observer_autofillForms.html \
|
||||
test_basic_form_observer_autocomplete.html \
|
||||
test_basic_form_pwonly.html \
|
||||
test_bug_227640.html \
|
||||
test_bug_242956.html \
|
||||
|
@ -45,8 +45,9 @@ function startTest(){
|
||||
is($_(1, "uname").value, "", "Checking for blank username");
|
||||
is($_(1, "pword").value, "", "Checking for blank password");
|
||||
|
||||
// Call the public method
|
||||
pwmgr.fillForm(document.getElementById("form1"));
|
||||
// Call the public method, check return value
|
||||
is(pwmgr.fillForm(document.getElementById("form1")), true,
|
||||
"Checking return value of fillForm");
|
||||
|
||||
// Check that the form was filled
|
||||
is($_(1, "uname").value, "testuser", "Checking for filled username");
|
||||
|
@ -0,0 +1,107 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Login Manager</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="pwmgr_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
Login Manager test: simple form with autocomplete off and notifying observers & normal form
|
||||
<p id="display"></p>
|
||||
|
||||
<div id="content" style="display: block">
|
||||
|
||||
<form id="form1" action="formtest.js" autocomplete="off">
|
||||
<p>This is form 1.</p>
|
||||
<input type="text" name="uname">
|
||||
<input type="password" name="pword">
|
||||
|
||||
<button type="submit">Submit</button>
|
||||
<button type="reset"> Reset </button>
|
||||
</form>
|
||||
|
||||
<form id="form2" action="formtest.js">
|
||||
<p>This is form 2.</p>
|
||||
<input type="text" name="uname">
|
||||
<input type="password" name="pword">
|
||||
|
||||
<button type="submit">Submit</button>
|
||||
<button type="reset"> Reset </button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Login Manager: simple form with autocomplete off and notifying observers & normal form **/
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
var TestObserver = {
|
||||
receivedNotification1 : false,
|
||||
receivedNotification2 : false,
|
||||
data1 : "",
|
||||
data2 : "",
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
|
||||
observe : function (subject, topic, data) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var pwmgr = Cc["@mozilla.org/login-manager;1"].
|
||||
getService(Ci.nsILoginManager);
|
||||
if (topic == "passwordmgr-found-form") {
|
||||
if (subject.id == "form1") {
|
||||
this.receivedNotification1 = true;
|
||||
this.data1 = data;
|
||||
} else if (subject.id == "form2") {
|
||||
this.receivedNotification2 = true;
|
||||
this.data2 = data;
|
||||
}
|
||||
// Now fill the form
|
||||
pwmgr.fillForm(subject);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Add the observer
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(TestObserver, "passwordmgr-found-form", false);
|
||||
|
||||
function startTest(){
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
// Test that observer is notified & got correct data
|
||||
is(TestObserver.receivedNotification1, true, "Checking observer was notified");
|
||||
is(TestObserver.data1, "autocompleteOff", "Checking observer got correct data");
|
||||
|
||||
// Check that form1 was filled
|
||||
is($_(1, "uname").value, "testuser", "Checking for filled username 1");
|
||||
is($_(1, "pword").value, "testpass", "Checking for filled password 1");
|
||||
|
||||
// Test that observer wasn't notified & didn't get data
|
||||
is(TestObserver.receivedNotification2, false, "Checking observer was not notified");
|
||||
is(TestObserver.data2, "", "Checking observer didn't get data");
|
||||
|
||||
// Check that form2 was filled
|
||||
is($_(2, "uname").value, "testuser", "Checking for filled username 2");
|
||||
is($_(2, "pword").value, "testpass", "Checking for filled password 2");
|
||||
|
||||
// Remove the observer
|
||||
os.removeObserver(TestObserver, "passwordmgr-found-form");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
window.onload = startTest;
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,92 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Login Manager</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="pwmgr_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
Login Manager test: simple form with autofillForms disabled and notifying observers
|
||||
<p id="display"></p>
|
||||
|
||||
<div id="content" style="display: block">
|
||||
|
||||
<form id="form1" action="formtest.js">
|
||||
<p>This is form 1.</p>
|
||||
<input type="text" name="uname">
|
||||
<input type="password" name="pword">
|
||||
|
||||
<button type="submit">Submit</button>
|
||||
<button type="reset"> Reset </button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Login Manager: simple form with autofillForms disabled and notifying observers **/
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService);
|
||||
prefs = prefs.getBranch("signon.");
|
||||
// Assume that the pref starts out true, so set to false
|
||||
prefs.setBoolPref("autofillForms", false);
|
||||
|
||||
var TestObserver = {
|
||||
receivedNotification : false,
|
||||
data : "",
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
|
||||
observe : function (subject, topic, data) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var pwmgr = Cc["@mozilla.org/login-manager;1"].
|
||||
getService(Ci.nsILoginManager);
|
||||
if (topic == "passwordmgr-found-form") {
|
||||
this.receivedNotification = true;
|
||||
this.data = data;
|
||||
// Now fill the form
|
||||
pwmgr.fillForm(subject);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Add the observer
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(TestObserver, "passwordmgr-found-form", false);
|
||||
|
||||
function startTest(){
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
// Test that observer is notified & got correct data
|
||||
is(TestObserver.receivedNotification, true, "Checking observer was notified");
|
||||
is(TestObserver.data, "noAutofillForms", "Checking observer got correct data");
|
||||
|
||||
// Check that form1 was filled
|
||||
is($_(1, "uname").value, "testuser", "Checking for filled username");
|
||||
is($_(1, "pword").value, "testpass", "Checking for filled password");
|
||||
|
||||
// Reset pref (since we assumed it was true to start)
|
||||
prefs.setBoolPref("autofillForms", true);
|
||||
|
||||
// Remove the observer
|
||||
os.removeObserver(TestObserver, "passwordmgr-found-form");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
window.onload = startTest;
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user