Bug 1573606 - Prompt for confirmation when exiting edit mode with unsaved changes via 'New login' button. r=MattN

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Tim Nguyen 2019-08-14 02:32:07 +00:00
Родитель bf94f57431
Коммит 62bc42ce67
3 изменённых файлов: 83 добавлений и 65 удалений

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

@ -146,27 +146,11 @@ export default class LoginItem extends HTMLElement {
break;
}
case "AboutLoginsLoginSelected": {
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);
}
this.confirmPendingChangesOnEvent(event, event.detail);
break;
}
case "AboutLoginsShowBlankLogin": {
this.setLogin({});
this.confirmPendingChangesOnEvent(event, {});
break;
}
case "blur": {
@ -322,6 +306,31 @@ export default class LoginItem extends HTMLElement {
}
}
/**
* Helper to show the "Discard changes" confirmation dialog and delay the
* received event after confirmation.
* @param {object} event The event to be delayed.
* @param {object} login The login to be shown on confirmation.
*/
confirmPendingChangesOnEvent(event, login) {
if (this.hasPendingChanges()) {
event.preventDefault();
this.showConfirmationDialog("discard-changes", () => {
// Clear any pending changes
this.setLogin(login);
window.dispatchEvent(
new CustomEvent(event.type, {
detail: login,
cancelable: false,
})
);
});
} else {
this.setLogin(login);
}
}
/**
* Shows a confirmation dialog.
* @param {string} type The type of confirmation dialog to display.

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

@ -123,7 +123,11 @@ export default class LoginList extends HTMLElement {
switch (event.type) {
case "click": {
if (event.originalTarget == this._createLoginButton) {
window.dispatchEvent(new CustomEvent("AboutLoginsShowBlankLogin"));
window.dispatchEvent(
new CustomEvent("AboutLoginsShowBlankLogin", {
cancelable: true,
})
);
recordTelemetryEvent({ object: "new_login", method: "new" });
return;
}
@ -192,8 +196,10 @@ export default class LoginList extends HTMLElement {
break;
}
case "AboutLoginsShowBlankLogin": {
this._selectedGuid = null;
this._setListItemAsSelected(this._blankLoginListItem);
if (!event.defaultPrevented) {
this._selectedGuid = null;
this._setListItemAsSelected(this._blankLoginListItem);
}
break;
}
case "keydown": {

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

@ -60,54 +60,57 @@ add_task(async function test_login_item() {
);
let editButton = loginItem.shadowRoot.querySelector(".edit-button");
editButton.click();
await Promise.resolve();
usernameInput.value += "-undome";
passwordInput.value += "-undome";
async function test_discard_dialog(exitPoint) {
editButton.click();
await Promise.resolve();
let dialog = content.document.querySelector("confirmation-dialog");
ok(dialog.hidden, "Confirm dialog should initially be hidden");
usernameInput.value += "-undome";
passwordInput.value += "-undome";
let dialog = content.document.querySelector("confirmation-dialog");
ok(dialog.hidden, "Confirm dialog should initially be hidden");
exitPoint.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");
await Promise.resolve();
loginListItem.click();
await ContentTaskUtils.waitForCondition(
() => usernameInput.value == login.username
);
is(
usernameInput.value,
login.username,
"Username change should be reverted"
);
is(
passwordInput.value,
login.password,
"Password change should be reverted"
);
}
await test_discard_dialog(loginList._createLoginButton);
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,
"Username change should be reverted"
);
is(
passwordInput.value,
login.password,
"Password change should be reverted"
);
await test_discard_dialog(cancelButton);
editButton.click();
await Promise.resolve();