Bug 1530029 - Pressing enter on the autocomplete footer should open the password manager dialog. r=MattN

Differential Revision: https://phabricator.services.mozilla.com/D21603

--HG--
extra : moz-landing-system : lando
This commit is contained in:
prathiksha 2019-03-12 00:21:13 +00:00
Родитель 8a746eed7d
Коммит e0ac67769b
6 изменённых файлов: 114 добавлений и 17 удалений

Просмотреть файл

@ -539,6 +539,7 @@ const listeners = {
"PasswordManager:autoCompleteLogins": ["LoginManagerParent"],
"PasswordManager:removeLogin": ["LoginManagerParent"],
"PasswordManager:insecureLoginFormPresent": ["LoginManagerParent"],
"PasswordManager:OpenPreferences": ["LoginManagerParent"],
// PLEASE KEEP THIS LIST IN SYNC WITH THE MOBILE LISTENERS IN BrowserCLH.js
"rtcpeer:CancelRequest": ["webrtcUI"],
"rtcpeer:Request": ["webrtcUI"],

Просмотреть файл

@ -51,7 +51,7 @@ function LoginAutoCompleteResult(aSearchString, matchingLogins, {isSecure, messa
}
this._showInsecureFieldWarning = (!isSecure && LoginHelper.showInsecureFieldWarning) ? 1 : 0;
this._showAutoCompleteFooter = LoginHelper.showAutoCompleteFooter ? 1 : 0;
this._showAutoCompleteFooter = (LoginHelper.showAutoCompleteFooter && LoginHelper.enabled) ? 1 : 0;
this.searchString = aSearchString;
this.logins = matchingLogins.sort(loginSort);
this.matchCount = matchingLogins.length + this._showInsecureFieldWarning + this._showAutoCompleteFooter;

Просмотреть файл

@ -31,6 +31,7 @@ var LoginHelper = {
schemeUpgrades: null,
insecureAutofill: null,
privateBrowsingCaptureEnabled: null,
showAutoCompleteFooter: null,
init() {
// Watch for pref changes to update cached pref values.
@ -49,8 +50,8 @@ var LoginHelper = {
Services.prefs.getBoolPref("signon.privateBrowsingCapture.enabled");
this.schemeUpgrades = Services.prefs.getBoolPref("signon.schemeUpgrades");
this.storeWhenAutocompleteOff = Services.prefs.getBoolPref("signon.storeWhenAutocompleteOff");
this.showAutoCompleteFooter = Services.prefs.getBoolPref("signon.showAutoCompleteFooter");
this.storeWhenAutocompleteOff = Services.prefs.getBoolPref("signon.storeWhenAutocompleteOff");
},
createLogger(aLogPrefix) {

Просмотреть файл

@ -178,6 +178,9 @@ var LoginManagerContent = {
// Number of outstanding requests to each manager.
_managers: new Map(),
// Input element on which enter keydown event was fired.
_keyDownEnterForInput: null,
_takeRequest(msg) {
let data = msg.data;
let request = this._requests.get(data.requestId);
@ -221,6 +224,27 @@ var LoginManagerContent = {
return deferred.promise;
},
_onKeyDown(event) {
let focusedElement = LoginManagerContent._formFillService.focusedInput;
if (event.keyCode != event.DOM_VK_RETURN || focusedElement != event.target) {
this._keyDownEnterForInput = null;
return;
}
LoginManagerContent._keyDownEnterForInput = focusedElement;
},
_onPopupClosed(selectedRowStyle, mm) {
let focusedElement = LoginManagerContent._formFillService.focusedInput;
let eventTarget = LoginManagerContent._keyDownEnterForInput;
if (!eventTarget || eventTarget !== focusedElement ||
selectedRowStyle != "loginsFooter") {
this._keyDownEnterForInput = null;
return;
}
let hostname = eventTarget.ownerDocument.documentURIObject.host;
mm.sendAsyncMessage("PasswordManager:OpenPreferences", {hostname});
},
receiveMessage(msg, topWindow) {
if (msg.name == "PasswordManager:fillForm") {
this.fillForm({
@ -233,10 +257,10 @@ var LoginManagerContent = {
return;
}
let request = this._takeRequest(msg);
switch (msg.name) {
case "PasswordManager:loginsFound": {
let loginsFound = LoginHelper.vanillaObjectsToLogins(msg.data.logins);
let request = this._takeRequest(msg);
request.promise.resolve({
form: request.form,
loginsFound,
@ -248,9 +272,25 @@ var LoginManagerContent = {
case "PasswordManager:loginsAutoCompleted": {
let loginsFound = LoginHelper.vanillaObjectsToLogins(msg.data.logins);
let messageManager = msg.target;
let request = this._takeRequest(msg);
request.promise.resolve({ logins: loginsFound, messageManager });
break;
}
case "FormAutoComplete:PopupOpened": {
let {chromeEventHandler} = msg.target.docShell;
chromeEventHandler.addEventListener("keydown", this._onKeyDown,
true);
break;
}
case "FormAutoComplete:PopupClosed": {
this._onPopupClosed(msg.data.selectedRowStyle, msg.target);
let {chromeEventHandler} = msg.target.docShell;
chromeEventHandler.removeEventListener("keydown", this._onKeyDown,
true);
break;
}
}
},
@ -310,6 +350,11 @@ var LoginManagerContent = {
isPasswordField: aElement.type == "password",
};
if (LoginHelper.showAutoCompleteFooter) {
messageManager.addMessageListener("FormAutoComplete:PopupOpened", this);
messageManager.addMessageListener("FormAutoComplete:PopupClosed", this);
}
return this._sendRequest(messageManager, requestData,
"PasswordManager:autoCompleteLogins",
messageData);

Просмотреть файл

@ -115,6 +115,11 @@ var LoginManagerParent = {
AutoCompletePopup.removeLogin(login);
break;
}
case "PasswordManager:OpenPreferences": {
LoginHelper.openPasswordManager(msg.target.ownerGlobal, msg.data.hostname);
break;
}
}
return undefined;

Просмотреть файл

@ -21,6 +21,24 @@ function loginList() {
];
}
function openPopup(popup, browser) {
return new Promise(async (resolve) => {
let promiseShown = BrowserTestUtils.waitForEvent(popup, "popupshown");
await SimpleTest.promiseFocus(browser);
info("content window focused");
// Focus the username field to open the popup.
await ContentTask.spawn(browser, null, function openAutocomplete() {
content.document.getElementById("form-basic-username").focus();
});
let shown = await promiseShown;
ok(shown, "autocomplete popup shown");
resolve(shown);
});
}
/**
* Initialize logins and set prefs needed for the test.
*/
@ -35,27 +53,16 @@ add_task(async function test_initialize() {
}
});
add_task(async function test_autocomplete_footer() {
add_task(async function test_autocomplete_footer_onclick() {
let url = TEST_HOSTNAME + BASIC_FORM_PAGE_PATH;
await BrowserTestUtils.withNewTab({
gBrowser,
url,
}, async function(browser) {
}, async function footer_onclick(browser) {
let popup = document.getElementById("PopupAutoComplete");
ok(popup, "Got popup");
let promiseShown = BrowserTestUtils.waitForEvent(popup, "popupshown");
await SimpleTest.promiseFocus(browser);
info("content window focused");
// Focus the username field to open the popup.
await ContentTask.spawn(browser, null, function openAutocomplete() {
content.document.getElementById("form-basic-username").focus();
});
await promiseShown;
ok(promiseShown, "autocomplete shown");
await openPopup(popup, browser);
let footer = popup.querySelector(`[originaltype="loginsFooter"]`);
ok(footer, "Got footer richlistitem");
@ -79,3 +86,41 @@ add_task(async function test_autocomplete_footer() {
popup.hidePopup();
});
});
add_task(async function test_autocomplete_footer_keydown() {
let url = TEST_HOSTNAME + BASIC_FORM_PAGE_PATH;
await BrowserTestUtils.withNewTab({
gBrowser,
url,
}, async function footer_enter_keydown(browser) {
let popup = document.getElementById("PopupAutoComplete");
ok(popup, "Got popup");
await openPopup(popup, browser);
let footer = popup.querySelector(`[originaltype="loginsFooter"]`);
ok(footer, "Got footer richlistitem");
await TestUtils.waitForCondition(() => {
return !EventUtils.isHidden(footer);
}, "Waiting for footer to become visible");
await EventUtils.synthesizeKey("KEY_ArrowDown");
await EventUtils.synthesizeKey("KEY_ArrowDown");
await EventUtils.synthesizeKey("KEY_ArrowDown");
await EventUtils.synthesizeKey("KEY_Enter");
await TestUtils.waitForCondition(() => {
return Services.wm.getMostRecentWindow("Toolkit:PasswordManager") !== null;
}, "Waiting for the password manager dialog to open");
info("Login dialog was opened");
let window = Services.wm.getMostRecentWindow("Toolkit:PasswordManager");
await TestUtils.waitForCondition(() => {
return window.document.getElementById("filter").value == "example.com";
}, "Waiting for the search string to filter logins");
window.close();
popup.hidePopup();
});
});