зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1549814 - Add 'New Login' button to create new saved logins. r=MattN,Pike
Differential Revision: https://phabricator.services.mozilla.com/D31713 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
eec920c32d
Коммит
4ad2b10786
|
@ -35,6 +35,7 @@ let LEGACY_ACTORS = {
|
|||
matches: ["about:logins"],
|
||||
module: "resource:///actors/AboutLoginsChild.jsm",
|
||||
events: {
|
||||
"AboutLoginsCreateLogin": {wantUntrusted: true},
|
||||
"AboutLoginsDeleteLogin": {wantUntrusted: true},
|
||||
"AboutLoginsOpenSite": {wantUntrusted: true},
|
||||
"AboutLoginsUpdateLogin": {wantUntrusted: true},
|
||||
|
@ -546,6 +547,7 @@ const listeners = {
|
|||
},
|
||||
|
||||
mm: {
|
||||
"AboutLogins:CreateLogin": ["AboutLoginsParent"],
|
||||
"AboutLogins:DeleteLogin": ["AboutLoginsParent"],
|
||||
"AboutLogins:OpenSite": ["AboutLoginsParent"],
|
||||
"AboutLogins:Subscribe": ["AboutLoginsParent"],
|
||||
|
|
|
@ -31,6 +31,10 @@ class AboutLoginsChild extends ActorChild {
|
|||
});
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsCreateLogin": {
|
||||
this.mm.sendAsyncMessage("AboutLogins:CreateLogin", {login: event.detail});
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsDeleteLogin": {
|
||||
this.mm.sendAsyncMessage("AboutLogins:DeleteLogin", {login: event.detail});
|
||||
break;
|
||||
|
|
|
@ -74,6 +74,16 @@ var AboutLoginsParent = {
|
|||
}
|
||||
|
||||
switch (message.name) {
|
||||
case "AboutLogins:CreateLogin": {
|
||||
let newLogin = message.data.login;
|
||||
Object.assign(newLogin, {
|
||||
formSubmitURL: "",
|
||||
usernameField: "",
|
||||
passwordField: "",
|
||||
});
|
||||
Services.logins.addLogin(LoginHelper.vanillaObjectToLogin(newLogin));
|
||||
break;
|
||||
}
|
||||
case "AboutLogins:DeleteLogin": {
|
||||
let login = LoginHelper.vanillaObjectToLogin(message.data.login);
|
||||
Services.logins.removeLogin(login);
|
||||
|
|
|
@ -17,6 +17,7 @@ header {
|
|||
align-items: center;
|
||||
background-color: var(--in-content-box-background);
|
||||
border-bottom: 1px solid var(--in-content-box-border-color);
|
||||
padding: 0 18px;
|
||||
}
|
||||
|
||||
login-filter {
|
||||
|
@ -26,6 +27,7 @@ login-filter {
|
|||
|
||||
login-list {
|
||||
grid-area: logins;
|
||||
overflow: hidden auto;
|
||||
}
|
||||
|
||||
login-item {
|
||||
|
@ -35,7 +37,12 @@ login-item {
|
|||
|
||||
#branding-logo {
|
||||
height: 32px;
|
||||
margin-inline-end: 18px;
|
||||
}
|
||||
|
||||
#create-login-button {
|
||||
margin-inline-start: 18px;
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
|
||||
:root:not(.official-branding) #branding-logo {
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
### need to be applied to the composed node where they can be moved to the proper
|
||||
### descendant after translation.
|
||||
|
||||
about-logins-page-title = Login Manager
|
||||
about-logins-page-title = Logins & Passwords
|
||||
|
||||
create-login-button = New Login
|
||||
|
||||
login-filter =
|
||||
.placeholder = Search Logins
|
||||
|
@ -24,20 +26,21 @@ login-list =
|
|||
|
||||
login-item =
|
||||
.cancel-button = Cancel
|
||||
.copied-password-button = ✓ Copied!
|
||||
.copied-username-button = ✓ Copied!
|
||||
.copy-password-button = Copy
|
||||
.copy-username-button = Copy
|
||||
.delete-button = Delete
|
||||
.edit-button = Edit
|
||||
.hostname-label = Website Address
|
||||
.modal-input-reveal-checkbox-hide = Hide password
|
||||
.modal-input-reveal-checkbox-show = Show password
|
||||
.copied-password-button = ✓ Copied!
|
||||
.copied-username-button = ✓ Copied!
|
||||
.copy-password-button = Copy
|
||||
.copy-username-button = Copy
|
||||
.new-login-title = New Entry
|
||||
.open-site-button = Launch
|
||||
.password-label = Password
|
||||
.save-changes-button = Save Changes
|
||||
.time-created = Created: { DATETIME($timeCreated, day: "numeric", month: "long", year: "numeric") }
|
||||
.time-changed = Last changed: { DATETIME($timeChanged, day: "numeric", month: "long", year: "numeric") }
|
||||
.time-changed = Last modified: { DATETIME($timeChanged, day: "numeric", month: "long", year: "numeric") }
|
||||
.time-used = Last used: { DATETIME($timeUsed, day: "numeric", month: "long", year: "numeric") }
|
||||
.username-label = Username
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
<img id="branding-logo" src="chrome://branding/content/aboutlogins.svg" alt=""/>
|
||||
<login-filter data-l10n-id="login-filter"
|
||||
data-l10n-attrs="placeholder"></login-filter>
|
||||
<button id="create-login-button" data-l10n-id="create-login-button"></button>
|
||||
</header>
|
||||
<login-list data-l10n-id="login-list"
|
||||
data-l10n-attrs="count"
|
||||
|
@ -41,6 +42,7 @@
|
|||
hostname-label,
|
||||
modal-input-reveal-checkbox-hide,
|
||||
modal-input-reveal-checkbox-show,
|
||||
new-login-title,
|
||||
open-site-button,
|
||||
password-label,
|
||||
save-changes-button,
|
||||
|
@ -77,7 +79,8 @@
|
|||
<div class="detail-row">
|
||||
<label>
|
||||
<span class="hostname-label field-label"></span>
|
||||
<span class="hostname"/>
|
||||
<span class="hostname-saved-value"></span>
|
||||
<input type="text" name="hostname"/>
|
||||
</label>
|
||||
<button class="open-site-button"></button>
|
||||
</div>
|
||||
|
|
|
@ -7,6 +7,12 @@ let gElements = {};
|
|||
document.addEventListener("DOMContentLoaded", () => {
|
||||
gElements.loginList = document.querySelector("login-list");
|
||||
gElements.loginItem = document.querySelector("login-item");
|
||||
gElements.newLoginButton = document.querySelector("#create-login-button");
|
||||
|
||||
gElements.newLoginButton.addEventListener("click", () => {
|
||||
gElements.loginItem.setLogin({});
|
||||
gElements.loginList.clearSelection();
|
||||
});
|
||||
|
||||
document.dispatchEvent(new CustomEvent("AboutLoginsInit", {bubbles: true}));
|
||||
}, {once: true});
|
||||
|
@ -19,6 +25,7 @@ window.addEventListener("AboutLoginsChromeToContent", event => {
|
|||
}
|
||||
case "LoginAdded": {
|
||||
gElements.loginList.loginAdded(event.detail.value);
|
||||
gElements.loginItem.loginAdded(event.detail.value);
|
||||
break;
|
||||
}
|
||||
case "LoginModified": {
|
||||
|
|
|
@ -7,6 +7,5 @@
|
|||
}
|
||||
|
||||
input {
|
||||
margin: 18px;
|
||||
flex: auto;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
padding-right: 40px;
|
||||
}
|
||||
|
||||
:host([isNewLogin]) .hostname-saved-value,
|
||||
:host([isNewLogin]) copy-to-clipboard-button,
|
||||
:host([isNewLogin]) .open-site-button,
|
||||
:host([isNewLogin]) .meta-info,
|
||||
:host(:not([isNewLogin])) input[name="hostname"],
|
||||
:host(:not([editing])) .save-changes-button,
|
||||
:host(:not([editing])) .cancel-button {
|
||||
display: none;
|
||||
|
|
|
@ -57,6 +57,7 @@ class LoginItem extends ReflectedFluentElement {
|
|||
"hostname-label",
|
||||
"modal-input-reveal-checkbox-hide",
|
||||
"modal-input-reveal-checkbox-show",
|
||||
"new-login-title",
|
||||
"open-site-button",
|
||||
"password-label",
|
||||
"save-changes-button",
|
||||
|
@ -97,6 +98,14 @@ class LoginItem extends ReflectedFluentElement {
|
|||
.setAttribute("reveal-checkbox-show", this.getAttribute(attrName));
|
||||
break;
|
||||
}
|
||||
case "new-login-title": {
|
||||
let title = this.shadowRoot.querySelector(".title");
|
||||
title.setAttribute(attrName, this.getAttribute(attrName));
|
||||
if (!this._login.title) {
|
||||
title.textContent = this.getAttribute(attrName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -110,8 +119,10 @@ class LoginItem extends ReflectedFluentElement {
|
|||
timeUsed: this._login.timeLastUsed || "",
|
||||
};
|
||||
document.l10n.setAttributes(this, "login-item", l10nArgs);
|
||||
this.shadowRoot.querySelector(".title").textContent = this._login.title || "";
|
||||
this.shadowRoot.querySelector(".hostname").textContent = this._login.hostname || "";
|
||||
|
||||
let title = this.shadowRoot.querySelector(".title");
|
||||
title.textContent = this._login.title || title.getAttribute("new-login-title");
|
||||
this.shadowRoot.querySelector(".hostname-saved-value").textContent = this._login.hostname || "";
|
||||
this.shadowRoot.querySelector("modal-input[name='username']").setAttribute("value", this._login.username || "");
|
||||
this.shadowRoot.querySelector("modal-input[name='password']").setAttribute("value", this._login.password || "");
|
||||
}
|
||||
|
@ -153,21 +164,19 @@ class LoginItem extends ReflectedFluentElement {
|
|||
return;
|
||||
}
|
||||
if (event.target.classList.contains("save-changes-button")) {
|
||||
let loginUpdates = {
|
||||
guid: this._login.guid,
|
||||
};
|
||||
let formUsername = this.shadowRoot.querySelector("modal-input[name='username']").value.trim();
|
||||
if (formUsername != this._login.username) {
|
||||
loginUpdates.username = formUsername;
|
||||
let loginUpdates = this._loginFromForm();
|
||||
if (this._login.guid) {
|
||||
loginUpdates.guid = this._login.guid;
|
||||
document.dispatchEvent(new CustomEvent("AboutLoginsUpdateLogin", {
|
||||
bubbles: true,
|
||||
detail: loginUpdates,
|
||||
}));
|
||||
} else {
|
||||
document.dispatchEvent(new CustomEvent("AboutLoginsCreateLogin", {
|
||||
bubbles: true,
|
||||
detail: loginUpdates,
|
||||
}));
|
||||
}
|
||||
let formPassword = this.shadowRoot.querySelector("modal-input[name='password']").value.trim();
|
||||
if (formPassword != this._login.password) {
|
||||
loginUpdates.password = formPassword;
|
||||
}
|
||||
document.dispatchEvent(new CustomEvent("AboutLoginsUpdateLogin", {
|
||||
bubbles: true,
|
||||
detail: loginUpdates,
|
||||
}));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -175,17 +184,29 @@ class LoginItem extends ReflectedFluentElement {
|
|||
}
|
||||
|
||||
setLogin(login) {
|
||||
this._login = login;
|
||||
this.toggleAttribute("isNewLogin", !login.guid);
|
||||
this.toggleEditing(!login.guid);
|
||||
this.render();
|
||||
}
|
||||
|
||||
loginAdded(login) {
|
||||
if (this._login.guid ||
|
||||
!window.AboutLoginsUtils.doLoginsMatch(login, this._loginFromForm())) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.toggleEditing(false);
|
||||
this._login = login;
|
||||
this.render();
|
||||
}
|
||||
|
||||
loginModified(login) {
|
||||
if (login.guid != this._login.guid) {
|
||||
if (this._login.guid != login.guid) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._login = login;
|
||||
this.toggleEditing(false);
|
||||
this.render();
|
||||
}
|
||||
|
||||
|
@ -199,10 +220,24 @@ class LoginItem extends ReflectedFluentElement {
|
|||
|
||||
toggleEditing(force) {
|
||||
let shouldEdit = force !== undefined ? force : !this.hasAttribute("editing");
|
||||
|
||||
if (!shouldEdit) {
|
||||
this.removeAttribute("isNewLogin");
|
||||
}
|
||||
|
||||
this.shadowRoot.querySelector(".edit-button").disabled = shouldEdit;
|
||||
this.shadowRoot.querySelectorAll("modal-input")
|
||||
.forEach(el => el.toggleAttribute("editing", shouldEdit));
|
||||
this.toggleAttribute("editing", shouldEdit);
|
||||
}
|
||||
|
||||
_loginFromForm() {
|
||||
return {
|
||||
username: this.shadowRoot.querySelector("modal-input[name='username']").value.trim(),
|
||||
password: this.shadowRoot.querySelector("modal-input[name='password']").value.trim(),
|
||||
hostname: this.hasAttribute("isNewLogin") ? this.shadowRoot.querySelector("input[name='hostname']").value.trim()
|
||||
: this.shadowRoot.querySelector(".hostname-saved-value").textContent,
|
||||
};
|
||||
}
|
||||
}
|
||||
customElements.define("login-item", LoginItem);
|
||||
|
|
|
@ -83,6 +83,14 @@ class LoginList extends ReflectedFluentElement {
|
|||
return this.reflectedFluentIDs;
|
||||
}
|
||||
|
||||
clearSelection() {
|
||||
if (!this._selectedItem) {
|
||||
return;
|
||||
}
|
||||
this._selectedItem.classList.remove("selected");
|
||||
this._selectedItem = null;
|
||||
}
|
||||
|
||||
setLogins(logins) {
|
||||
this._logins = logins;
|
||||
this.render();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
--reveal-button-opacity-active: 1;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:host([editing]) .locked-value,
|
||||
|
|
Загрузка…
Ссылка в новой задаче