Bug 1569723 - Show a 'Discard' dialog when canceling or leaving the edit/create mode in about:logins. r=fluent-reviewers,jaws,flod

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Tim Nguyen 2019-08-01 03:09:00 +00:00
Родитель b09e5ab2d6
Коммит a1ea346540
6 изменённых файлов: 95 добавлений и 4 удалений

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

@ -126,7 +126,23 @@ export default class LoginItem extends HTMLElement {
break;
}
case "AboutLoginsLoginSelected": {
this.setLogin(event.detail);
let login = event.detail;
if (this.hasPendingChanges()) {
event.preventDefault();
this.showConfirmationDialog("discard-changes", () => {
// Clear any pending changes
this.setLogin(login);
window.dispatchEvent(
new CustomEvent("AboutLoginsLoginSelected", {
detail: login,
cancelable: true,
})
);
});
} else {
this.setLogin(login);
}
break;
}
case "blur": {
@ -153,7 +169,13 @@ export default class LoginItem extends HTMLElement {
if (classList.contains("cancel-button")) {
let wasExistingLogin = !!this._login.guid;
if (wasExistingLogin) {
this.setLogin(this._login);
if (this.hasPendingChanges()) {
this.showConfirmationDialog("discard-changes", () => {
this.setLogin(this._login);
});
} else {
this.setLogin(this._login);
}
} else {
window.dispatchEvent(new CustomEvent("AboutLoginsClearSelection"));
}
@ -274,6 +296,15 @@ export default class LoginItem extends HTMLElement {
message: "confirm-delete-dialog-message",
confirmButtonLabel: "confirm-delete-dialog-confirm-button",
};
break;
}
case "discard-changes": {
options = {
title: "confirm-discard-changes-dialog-title",
message: "confirm-discard-changes-dialog-message",
confirmButtonLabel: "confirm-discard-changes-dialog-confirm-button",
};
break;
}
}
let dialogPromise = dialog.show(options);
@ -297,6 +328,17 @@ export default class LoginItem extends HTMLElement {
});
}
hasPendingChanges() {
let { origin = "", username = "", password = "" } = this._login || {};
let valuesChanged = !window.AboutLoginsUtils.doLoginsMatch(
{ origin, username, password },
this._loginFromForm()
);
return this.dataset.editing && valuesChanged;
}
/**
* @param {login} login The login that should be displayed. The login object is
* a plain JS object representation of nsILoginInfo/nsILoginMetaInfo.

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

@ -118,6 +118,7 @@ export default class LoginList extends HTMLElement {
new CustomEvent("AboutLoginsLoginSelected", {
bubbles: true,
composed: true,
cancelable: true, // allow calling preventDefault() on event
detail: listItem._login,
})
);
@ -137,6 +138,7 @@ export default class LoginList extends HTMLElement {
window.dispatchEvent(
new CustomEvent("AboutLoginsLoginSelected", {
detail: this._logins[0],
cancelable: true,
})
);
break;
@ -152,7 +154,7 @@ export default class LoginList extends HTMLElement {
break;
}
case "AboutLoginsLoginSelected": {
if (this._selectedGuid == event.detail.guid) {
if (event.defaultPrevented || this._selectedGuid == event.detail.guid) {
return;
}

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

@ -64,14 +64,38 @@ add_task(async function test_login_item() {
usernameInput.value += "-undome";
passwordInput.value += "-undome";
let dialog = content.document.querySelector("confirmation-dialog");
ok(dialog.hidden, "Confirm dialog should initially be hidden");
let cancelButton = loginItem.shadowRoot.querySelector(".cancel-button");
cancelButton.click();
ok(!dialog.hidden, "Confirm dialog should be visible");
let confirmDiscardButton = dialog.shadowRoot.querySelector(
".confirm-button"
);
await content.document.l10n.translateElements([
dialog.shadowRoot.querySelector(".title"),
dialog.shadowRoot.querySelector(".message"),
confirmDiscardButton,
]);
confirmDiscardButton.click();
ok(dialog.hidden, "Confirm dialog should be hidden after confirming");
usernameInput = loginItem.shadowRoot.querySelector(
"input[name='username']"
);
passwordInput = loginItem.shadowRoot.querySelector(
"input[name='password']"
);
await ContentTaskUtils.waitForCondition(
() => usernameInput.value == login.username
);
is(
usernameInput.value,
login.username,

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

@ -59,5 +59,12 @@ Object.defineProperty(window, "AboutLoginsUtils", {
promptForMasterPassword(resolve) {
resolve(true);
},
doLoginsMatch(login1, login2) {
return (
login1.origin == login2.origin &&
login1.username == login2.username &&
login1.password == login2.password
);
},
},
});

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

@ -9,6 +9,7 @@ Test the login-item component
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="module" src="chrome://browser/content/aboutlogins/components/login-item.js"></script>
<script type="module" src="chrome://browser/content/aboutlogins/components/confirmation-dialog.js"></script>
<script src="aboutlogins_common.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
@ -25,7 +26,7 @@ Test the login-item component
<script>
/** Test the login-item component **/
let gLoginItem;
let gLoginItem, gConfirmationDialog;
const TEST_LOGIN_1 = {
guid: "123456789",
origin: "https://example.com",
@ -61,6 +62,10 @@ add_task(async function setup() {
gLoginItem = document.createElement("login-item");
displayEl.appendChild(gLoginItem);
gConfirmationDialog = document.createElement("confirmation-dialog");
gConfirmationDialog.hidden = true;
displayEl.appendChild(gConfirmationDialog);
});
add_task(async function test_empty_item() {
@ -152,6 +157,13 @@ add_task(async function test_edit_login_cancel() {
"loginItem should not be in 'isNewLogin' mode");
gLoginItem.shadowRoot.querySelector(".cancel-button").click();
gConfirmationDialog.shadowRoot.querySelector(".confirm-button").click();
await SimpleTest.promiseWaitForCondition(
() => gConfirmationDialog.hidden,
"waiting for confirmation dialog to hide"
);
ok(!gLoginItem.dataset.editing, "loginItem should not be in 'edit' mode");
ok(!gLoginItem.dataset.isNewLogin, "loginItem should not be in 'isNewLogin' mode");
});

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

@ -103,6 +103,10 @@ confirm-delete-dialog-title = Delete this login?
confirm-delete-dialog-message = This action cannot be undone.
confirm-delete-dialog-confirm-button = Delete
confirm-discard-changes-dialog-title = Discard unsaved changes?
confirm-discard-changes-dialog-message = All unsaved changes will be lost.
confirm-discard-changes-dialog-confirm-button = Discard
## Breach Alert notification
breach-alert-text = Passwords were leaked or stolen from this website since you last updated your login details. Change your password to protect your account.