mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-03 17:58:55 +02:00
Currently, clicking "confirm" buttons on modals in the profile backup settings menu will always close the modals regardless of whether the operation succeeded or failed. In the case of errors, users don't know that something went wrong. It's better to keep the modals open and display an error so that the user knows what to do next and can try to fix the issue, if applicable. Differential Revision: https://phabricator.services.mozilla.com/D218358
214 lines
6.6 KiB
JavaScript
214 lines
6.6 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
import { html } from "chrome://global/content/vendor/lit.all.mjs";
|
|
import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
|
|
|
|
// eslint-disable-next-line import/no-unassigned-import
|
|
import "chrome://browser/content/backup/password-rules-tooltip.mjs";
|
|
|
|
/**
|
|
* The widget for enabling password protection if the backup is not yet
|
|
* encrypted.
|
|
*/
|
|
export default class PasswordValidationInputs extends MozLitElement {
|
|
static properties = {
|
|
_hasCommon: { type: Boolean, state: true },
|
|
_hasEmail: { type: Boolean, state: true },
|
|
_passwordsMatch: { type: Boolean, state: true },
|
|
_passwordsValid: { type: Boolean, state: true },
|
|
_showRules: { type: Boolean, state: true },
|
|
_tooShort: { type: Boolean, state: true },
|
|
/**
|
|
* If, by chance, there is focus on a focusable element in the tooltip,
|
|
* track the focus state so that we can keep the tooltip open.
|
|
*/
|
|
_tooltipFocus: { type: Boolean, state: true },
|
|
supportBaseLink: { type: String },
|
|
};
|
|
|
|
static get queries() {
|
|
return {
|
|
formEl: "#password-inputs-form",
|
|
inputNewPasswordEl: "#new-password-input",
|
|
inputRepeatPasswordEl: "#repeat-password-input",
|
|
passwordRulesEl: "#password-rules",
|
|
};
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
this.supportBaseLink = "";
|
|
this._tooShort = true;
|
|
this._hasCommon = false;
|
|
this._hasEmail = false;
|
|
this._passwordsMatch = false;
|
|
this._passwordsValid = false;
|
|
this._tooltipFocus = false;
|
|
}
|
|
|
|
reset() {
|
|
this.formEl.reset();
|
|
this._showRules = false;
|
|
this._hasCommon = false;
|
|
this._hasEmail = false;
|
|
this._tooShort = true;
|
|
this._passwordsMatch = false;
|
|
this._passwordsValid = false;
|
|
this._tooltipFocus = false;
|
|
}
|
|
|
|
handleFocusNewPassword() {
|
|
this._showRules = true;
|
|
}
|
|
|
|
handleBlurNewPassword(event) {
|
|
this._showRules = !event.target.checkValidity();
|
|
}
|
|
|
|
handleChangeNewPassword() {
|
|
this.updatePasswordValidity();
|
|
}
|
|
|
|
handleChangeRepeatPassword() {
|
|
this.updatePasswordValidity();
|
|
}
|
|
|
|
updatePasswordValidity() {
|
|
const emailRegex = /^[\w!#$%&'*+/=?^`{|}~.-]+@[A-Z0-9-]+\.[A-Z0-9.-]+$/i;
|
|
this._hasEmail = emailRegex.test(this.inputNewPasswordEl.value);
|
|
if (this._hasEmail) {
|
|
// TODO: we need a localized string for this error (bug 1909983)
|
|
this.inputNewPasswordEl.setCustomValidity("TODO: no emails");
|
|
} else {
|
|
this.inputNewPasswordEl.setCustomValidity("");
|
|
}
|
|
|
|
const newPassValidity = this.inputNewPasswordEl.validity;
|
|
this._tooShort = newPassValidity?.valueMissing || newPassValidity?.tooShort;
|
|
|
|
this._passwordsMatch =
|
|
this.inputNewPasswordEl.value == this.inputRepeatPasswordEl.value;
|
|
if (!this._passwordsMatch) {
|
|
// TODO: we need a localized string for this error (bug 1909983)
|
|
this.inputRepeatPasswordEl.setCustomValidity("TODO: not matching");
|
|
} else {
|
|
this.inputRepeatPasswordEl.setCustomValidity("");
|
|
}
|
|
|
|
const repeatPassValidity = this.inputRepeatPasswordEl.validity;
|
|
this._passwordsValid =
|
|
newPassValidity?.valid &&
|
|
repeatPassValidity?.valid &&
|
|
this._passwordsMatch;
|
|
|
|
/**
|
|
* This step may involve async validation with BackupService. For instance, we have to
|
|
* check against a list of common passwords (bug 1905140) and display an error message if an
|
|
* issue occurs (bug 1905145).
|
|
*/
|
|
}
|
|
|
|
handleTooltipFocus() {
|
|
this._tooltipFocus = true;
|
|
}
|
|
|
|
handleTooltipBlur() {
|
|
this._tooltipFocus = false;
|
|
}
|
|
|
|
/**
|
|
* Dispatches a custom event whenever validity changes.
|
|
*
|
|
* @param {Map<string, any>} changedProperties a Map of recently changed properties and their new values
|
|
*/
|
|
updated(changedProperties) {
|
|
if (!changedProperties.has("_passwordsValid")) {
|
|
return;
|
|
}
|
|
|
|
if (this._passwordsValid) {
|
|
this.dispatchEvent(
|
|
new CustomEvent("ValidPasswordsDetected", {
|
|
bubbles: true,
|
|
composed: true,
|
|
detail: {
|
|
password: this.inputNewPasswordEl.value,
|
|
},
|
|
})
|
|
);
|
|
} else {
|
|
this.dispatchEvent(
|
|
new CustomEvent("InvalidPasswordsDetected", {
|
|
bubbles: true,
|
|
composed: true,
|
|
})
|
|
);
|
|
}
|
|
}
|
|
|
|
contentTemplate() {
|
|
return html`
|
|
<div id="password-inputs-wrapper" aria-live="polite">
|
|
<form id="password-inputs-form">
|
|
<!--TODO: (bug 1909983) change first input field label for the "change-password" dialog-->
|
|
<label id="new-password-label" for="new-password-input">
|
|
<div id="new-password-label-wrapper-span-input">
|
|
<span
|
|
id="new-password-span"
|
|
data-l10n-id="enable-backup-encryption-create-password-label"
|
|
></span>
|
|
<input
|
|
type="password"
|
|
id="new-password-input"
|
|
minlength="8"
|
|
required
|
|
@input=${this.handleChangeNewPassword}
|
|
@focus=${this.handleFocusNewPassword}
|
|
@blur=${this.handleBlurNewPassword}
|
|
/>
|
|
<!--TODO: (bug 1909984) improve how we read out the first input field for screen readers-->
|
|
</div>
|
|
</label>
|
|
<!--TODO: (bug 1909984) look into how the tooltip vs dialog behaves when pressing the ESC key-->
|
|
<password-rules-tooltip
|
|
id="password-rules"
|
|
class=${!this._showRules && !this._tooltipFocus ? "hidden" : ""}
|
|
.hasCommon=${this._hasCommon}
|
|
.hasEmail=${this._hasEmail}
|
|
.tooShort=${this._tooShort}
|
|
.supportBaseLink=${this.supportBaseLink}
|
|
@focus=${this.handleTooltipFocus}
|
|
@blur=${this.handleTooltipBlur}
|
|
></password-rules-tooltip>
|
|
<label id="repeat-password-label" for="repeat-password-input">
|
|
<span
|
|
id="repeat-password-span"
|
|
data-l10n-id="enable-backup-encryption-repeat-password-label"
|
|
></span>
|
|
<input
|
|
type="password"
|
|
id="repeat-password-input"
|
|
minlength="8"
|
|
required
|
|
@input=${this.handleChangeRepeatPassword}
|
|
/>
|
|
</label>
|
|
</form>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
render() {
|
|
return html`
|
|
<link
|
|
rel="stylesheet"
|
|
href="chrome://browser/content/backup/password-validation-inputs.css"
|
|
/>
|
|
${this.contentTemplate()}
|
|
`;
|
|
}
|
|
}
|
|
|
|
customElements.define("password-validation-inputs", PasswordValidationInputs);
|