Bug 1804728, part 4 - Make UI match mock, without pictures - r=pbz,desktop-theme-reviewers,flod,Itiel

Differential Revision: https://phabricator.services.mozilla.com/D168817
This commit is contained in:
Benjamin VanderSloot 2023-02-14 19:25:51 +00:00
Родитель 3aced29319
Коммит b723b61608
6 изменённых файлов: 273 добавлений и 124 удалений

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

@ -172,26 +172,32 @@
<popupnotificationcontent id="identity-credential-provider" orient="vertical"> <popupnotificationcontent id="identity-credential-provider" orient="vertical">
<html:div id="identity-credential-provider-selector-container"> <html:div id="identity-credential-provider-selector-container">
</html:div> </html:div>
<description class="popup-notification-description" id="credential-provider-explanation" data-l10n-id="identity-credential-description-provider-explanation"/>
<html:template id="template-credential-provider-list-item"> <html:template id="template-credential-provider-list-item">
<toolbarbutton class="credential-provider-list-item subviewbutton-nav subviewbutton" align="center" wrap="true"> <html:label class="identity-credential-list-item" align="center">
<label flex="1" class="credential-provider-list-item-label"></label> <html:input type="radio" name="credential-provider" class="identity-credential-list-item-radio"></html:input>
</toolbarbutton> <html:img class="identity-credential-list-item-icon" src="chrome://global/skin/icons/defaultFavicon.svg"></html:img>
<span class="identity-credential-list-item-label"></span>
</html:label>
</html:template> </html:template>
</popupnotificationcontent> </popupnotificationcontent>
<popupnotificationcontent id="identity-credential-policy" orient="vertical"> <popupnotificationcontent id="identity-credential-policy" orient="vertical">
<description id="identity-credential-policy-explanation"/> <description id="identity-credential-policy-explanation" data-l10n-id="identity-credential-policy-description" data-l10n-args='{"host":"", "provider":""}'>
<label class="text-link" is="text-link" data-l10n-id="identity-credential-privacy-policy" id="identity-credential-privacy-policy"></label> <label class="text-link" is="text-link" data-l10n-name="privacy-url" id="identity-credential-privacy-policy"></label>
<label class="text-link" is="text-link" data-l10n-id="identity-credential-terms-of-service" id="identity-credential-terms-of-service"></label> <label class="text-link" is="text-link" data-l10n-name="tos-url" id="identity-credential-terms-of-service"></label>
</description>
</popupnotificationcontent> </popupnotificationcontent>
<popupnotificationcontent id="identity-credential-account" orient="vertical" hidden="true"> <popupnotificationcontent id="identity-credential-account" orient="vertical" hidden="true">
<html:div id="identity-credential-account-selector-container"> <html:div id="identity-credential-account-selector-container">
</html:div> </html:div>
<description class="popup-notification-description" id="credential-account-explanation"/>
<html:template id="template-credential-account-list-item"> <html:template id="template-credential-account-list-item">
<toolbarbutton class="credential-account-list-item subviewbutton-nav subviewbutton" align="center" wrap="true"> <html:label class="identity-credential-list-item" align="center">
<label flex="1" class="credential-account-list-item-label"></label> <html:input type="radio" name="credential-account" class="identity-credential-list-item-radio"></html:input>
</toolbarbutton> <html:img class="identity-credential-list-item-icon" src="chrome://browser/skin/fxa/avatar.svg"></html:img>
<div class="identity-credential-list-item-label-stack">
<div class="identity-credential-list-item-label-name"></div>
<div class="identity-credential-list-item-label-email"></div>
</div>
</html:label>
</html:template> </html:template>
</popupnotificationcontent> </popupnotificationcontent>
</popupnotification> </popupnotification>

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

@ -6,20 +6,16 @@
## $host (String): the hostname of the site that is being displayed. ## $host (String): the hostname of the site that is being displayed.
## $provider (String): the hostname of another website you are using to log in to the site being displayed ## $provider (String): the hostname of another website you are using to log in to the site being displayed
identity-credential-header-providers = Sign in to { $host } identity-credential-header-providers = Sign in with a login provider
identity-credential-header-accounts = Pick a { $host } account identity-credential-header-accounts = Sign in with { $provider }
# Identity providers are websites you use to log into another website, for example: Google when you Log in with Google. # Identity providers are websites you use to log into another website, for example: Google when you Log in with Google.
identity-credential-description-provider-explanation = These are the identity providers that would like to help you log in.
identity-credential-description-account-explanation = Picking an account here shares that identity with { $host }.
identity-credential-urlbar-anchor = identity-credential-urlbar-anchor =
.tooltiptext = Open federated login panel .tooltiptext = Open login panel
identity-credential-cancel-button = identity-credential-cancel-button =
.label = Cancel .label = Cancel
.accesskey = C .accesskey = n
identity-credential-accept-button = identity-credential-accept-button =
.label = Okay .label = Continue
.accesskey = O .accesskey = C
identity-credential-policy-title = Legal information identity-credential-policy-title = Use { $provider } as a login provider
identity-credential-policy-description = Logging into { $host } with an account from { $provider } is controlled by these legal policies. This is optional and you can cancel this and try to log in again using another method. identity-credential-policy-description = Logging in to { $host } with a { $provider } account is subject to { $provider }s <label data-l10n-name="privacy-url">Privacy Policy</label> and <label data-l10n-name="tos-url">Terms of Service</label>.
identity-credential-privacy-policy = Privacy Policy
identity-credential-terms-of-service = Terms of Service

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

@ -1106,7 +1106,6 @@ panelview .toolbarbutton-1,
} }
#protections-popup-mainView .subviewbutton-nav:not(.notFound)::after, #protections-popup-mainView .subviewbutton-nav:not(.notFound)::after,
#identity-credential-notification .subviewbutton-nav::after,
.widget-overflow-list .subviewbutton-nav::after, .widget-overflow-list .subviewbutton-nav::after,
.PanelUI-subView .subviewbutton-nav::after { .PanelUI-subView .subviewbutton-nav::after {
-moz-context-properties: fill, fill-opacity; -moz-context-properties: fill, fill-opacity;
@ -1117,7 +1116,6 @@ panelview .toolbarbutton-1,
} }
#protections-popup-mainView .subviewbutton-nav:not(.notFound):-moz-locale-dir(rtl)::after, #protections-popup-mainView .subviewbutton-nav:not(.notFound):-moz-locale-dir(rtl)::after,
#identity-credential-notification .subviewbutton-nav:-moz-locale-dir(rtl)::after,
.widget-overflow-list .subviewbutton-nav:-moz-locale-dir(rtl)::after, .widget-overflow-list .subviewbutton-nav:-moz-locale-dir(rtl)::after,
.PanelUI-subView .subviewbutton-nav:-moz-locale-dir(rtl)::after { .PanelUI-subView .subviewbutton-nav:-moz-locale-dir(rtl)::after {
content: url(chrome://global/skin/icons/arrow-left.svg); content: url(chrome://global/skin/icons/arrow-left.svg);

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

@ -2,12 +2,103 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#identity-credential-notification .subviewbutton { #identity-credential-notification {
width: 100%; --list-item-border: color-mix(in srgb, currentColor 10%, transparent);
margin-inline: 0; --list-item-checked-bgcolor: color-mix(in srgb, var(--button-primary-bgcolor) 6%, transparent);
--list-item-checked-border: color-mix(in srgb, var(--button-primary-bgcolor) 20%, transparent);
} }
#credential-provider-explanation, @media (prefers-contrast) {
#credential-account-explanation { #identity-credential-notification {
margin-top: 1em; --list-item-border: ThreeDShadow;
--list-item-checked-bgcolor: transparent;
--list-item-checked-border: AccentColor;
}
}
#identity-credential-provider-selector-container,
#identity-credential-account-selector-container {
display: flex;
flex-direction: column;
gap: 12px;
}
.identity-credential-list-item {
display: flex;
gap: 10px;
padding-block: max(calc(var(--arrowpanel-menuitem-padding-block) * 2), 4px);
padding-inline: calc(var(--arrowpanel-menuitem-padding-inline) * 2);
border: 2px solid var(--list-item-border);
border-radius: 4px;
}
.identity-credential-list-item.checked {
background-color: var(--list-item-checked-bgcolor);
border-color: var(--list-item-checked-border);
}
.identity-credential-list-item > .identity-credential-list-item-radio {
appearance: none;
background-color: var(--checkbox-unchecked-bgcolor);
background-image: url("chrome://global/skin/icons/radio.svg");
border: 1px solid var(--checkbox-border-color);
border-radius: 100%;
align-self: center;
outline: none;
-moz-context-properties: fill;
fill: transparent;
}
.identity-credential-list-item > .identity-credential-list-item-radio:focus-visible {
outline-offset: var(--focus-outline-offset);
}
.identity-credential-list-item > .identity-credential-list-item-radio:hover {
background-color: var(--checkbox-unchecked-hover-bgcolor);
}
.identity-credential-list-item > .identity-credential-list-item-radio:hover:active {
background-color: var(--checkbox-unchecked-active-bgcolor);
}
.identity-credential-list-item > .identity-credential-list-item-radio:checked {
fill: var(--checkbox-checked-color);
background-color: var(--checkbox-checked-bgcolor);
border-color: var(--checkbox-checked-border-color);
}
.identity-credential-list-item > .identity-credential-list-item-radio:checked:hover {
background-color: var(--checkbox-checked-hover-bgcolor);
}
.identity-credential-list-item > .identity-credential-list-item-radio:checked:hover:active {
background-color: var(--checkbox-checked-active-bgcolor);
}
.identity-credential-list-item-icon {
-moz-context-properties: fill, fill-opacity;
fill: currentColor;
fill-opacity: 0.6;
clip-path: circle(50%);
width: 32px;
height: 32px;
}
.identity-credential-list-item > .identity-credential-list-item-label {
align-self: center;
font-weight: 600;
}
.identity-credential-list-item-label-stack > .identity-credential-list-item-label-name {
font-weight: 600;
}
.identity-credential-list-item-label-stack > .identity-credential-list-item-label-email {
font-size: 80%;
}
.identity-credential-list-item > .identity-credential-list-item-label-stack {
display: flex;
flex-direction: column;
gap: 4px;
} }

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

@ -199,7 +199,7 @@
} }
#identity-credential-notification-icon { #identity-credential-notification-icon {
list-style-image: url(chrome://browser/skin/fingerprint.svg); list-style-image: url(chrome://browser/skin/login.svg);
} }
#permission-popup-menulist { #permission-popup-menulist {

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

@ -68,17 +68,17 @@ export class IdentityCredentialPromptService {
true true
); );
let headerMessage = localization.formatValueSync( let headerMessage = localization.formatValueSync(
"identity-credential-header-providers", "identity-credential-header-providers"
{
host: "<>",
}
); );
let [cancel] = localization.formatMessagesSync([ let [accept, cancel] = localization.formatMessagesSync([
{ id: "identity-credential-accept-button" },
{ id: "identity-credential-cancel-button" }, { id: "identity-credential-cancel-button" },
]); ]);
let cancelLabel = cancel.attributes.find(x => x.name == "label").value; let cancelLabel = cancel.attributes.find(x => x.name == "label").value;
let cancelKey = cancel.attributes.find(x => x.name == "accesskey").value; let cancelKey = cancel.attributes.find(x => x.name == "accesskey").value;
let acceptLabel = accept.attributes.find(x => x.name == "label").value;
let acceptKey = accept.attributes.find(x => x.name == "accesskey").value;
// Build the choices into the panel // Build the choices into the panel
let listBox = browser.ownerDocument.getElementById( let listBox = browser.ownerDocument.getElementById(
@ -91,39 +91,62 @@ export class IdentityCredentialPromptService {
"template-credential-provider-list-item" "template-credential-provider-list-item"
); );
for (const [providerIndex, provider] of identityProviders.entries()) { for (const [providerIndex, provider] of identityProviders.entries()) {
let providerURI = new URL(provider.configURL); let providerURL = new URL(provider.configURL);
let displayDomain = lazy.IDNService.convertToDisplayIDN( let displayDomain = lazy.IDNService.convertToDisplayIDN(
providerURI.host, providerURL.host,
{} {}
); );
let newItem = itemTemplate.content.firstElementChild.cloneNode(true); let newItem = itemTemplate.content.firstElementChild.cloneNode(true);
newItem.firstElementChild.textContent = displayDomain; let newRadio = newItem.getElementsByClassName(
newItem.setAttribute("oncommand", `this.callback(event)`); "identity-credential-list-item-radio"
newItem.callback = function(event) { )[0];
let notification = browser.ownerGlobal.PopupNotifications.getNotification( newRadio.value = providerIndex;
"identity-credential", newRadio.addEventListener("change", function(event) {
browser for (let item of listBox.children) {
); item.classList.remove("checked");
browser.ownerGlobal.PopupNotifications.remove(notification); }
resolve(providerIndex); if (event.target.checked) {
event.stopPropagation(); event.target.parentElement.classList.add("checked");
}; }
});
if (providerIndex == 0) {
newRadio.checked = true;
newItem.classList.add("checked");
}
newItem.getElementsByClassName(
"identity-credential-list-item-label"
)[0].textContent = displayDomain;
listBox.append(newItem); listBox.append(newItem);
} }
// Construct the necessary arguments for notification behavior // Construct the necessary arguments for notification behavior
let currentOrigin =
browsingContext.currentWindowContext.documentPrincipal.originNoSuffix;
let options = { let options = {
name: currentOrigin, hideClose: true,
}; eventCallback: (topic, nextRemovalReason, isCancel) => {
let mainAction = { if (topic == "removed" && isCancel) {
label: cancelLabel, reject();
accessKey: cancelKey, }
callback(event) {
reject();
}, },
}; };
let mainAction = {
label: acceptLabel,
accessKey: acceptKey,
callback(event) {
let result = listBox.querySelector(
".identity-credential-list-item-radio:checked"
).value;
resolve(parseInt(result));
},
};
let secondaryActions = [
{
label: cancelLabel,
accessKey: cancelKey,
callback(event) {
reject();
},
},
];
// Show the popup // Show the popup
browser.ownerDocument.getElementById( browser.ownerDocument.getElementById(
@ -141,7 +164,7 @@ export class IdentityCredentialPromptService {
headerMessage, headerMessage,
"identity-credential-notification-icon", "identity-credential-notification-icon",
mainAction, mainAction,
null, secondaryActions,
options options
); );
}); });
@ -167,8 +190,8 @@ export class IdentityCredentialPromptService {
} }
if ( if (
!identityCredentialMetadata || !identityCredentialMetadata ||
(!identityCredentialMetadata.privacy_policy_url && !identityCredentialMetadata.privacy_policy_url ||
!identityCredentialMetadata.terms_of_service_url) !identityCredentialMetadata.terms_of_service_url
) { ) {
return Promise.resolve(true); return Promise.resolve(true);
} }
@ -179,9 +202,9 @@ export class IdentityCredentialPromptService {
return; return;
} }
let providerURI = new URL(identityProvider.configURL); let providerURL = new URL(identityProvider.configURL);
let providerDisplayDomain = lazy.IDNService.convertToDisplayIDN( let providerDisplayDomain = lazy.IDNService.convertToDisplayIDN(
providerURI.host, providerURL.host,
{} {}
); );
let currentBaseDomain = let currentBaseDomain =
@ -192,13 +215,6 @@ export class IdentityCredentialPromptService {
["preview/identityCredentialNotification.ftl"], ["preview/identityCredentialNotification.ftl"],
true true
); );
let descriptionMessage = localization.formatValueSync(
"identity-credential-policy-description",
{
host: currentBaseDomain,
provider: providerDisplayDomain,
}
);
let [accept, cancel] = localization.formatMessagesSync([ let [accept, cancel] = localization.formatMessagesSync([
{ id: "identity-credential-accept-button" }, { id: "identity-credential-accept-button" },
{ id: "identity-credential-cancel-button" }, { id: "identity-credential-cancel-button" },
@ -208,36 +224,53 @@ export class IdentityCredentialPromptService {
let cancelKey = cancel.attributes.find(x => x.name == "accesskey").value; let cancelKey = cancel.attributes.find(x => x.name == "accesskey").value;
let acceptLabel = accept.attributes.find(x => x.name == "label").value; let acceptLabel = accept.attributes.find(x => x.name == "label").value;
let acceptKey = accept.attributes.find(x => x.name == "accesskey").value; let acceptKey = accept.attributes.find(x => x.name == "accesskey").value;
let title = localization.formatValueSync( let title = localization.formatValueSync(
"identity-credential-policy-title" "identity-credential-policy-title",
{
provider: providerDisplayDomain,
}
); );
let privacyPolicyAnchor = browser.ownerDocument.getElementById(
"identity-credential-privacy-policy"
);
privacyPolicyAnchor.href = identityCredentialMetadata.privacy_policy_url;
let termsOfServiceAnchor = browser.ownerDocument.getElementById(
"identity-credential-terms-of-service"
);
termsOfServiceAnchor.href =
identityCredentialMetadata.terms_of_service_url;
// Populate the content of the policy panel // Populate the content of the policy panel
let description = browser.ownerDocument.getElementById( let description = browser.ownerDocument.getElementById(
"identity-credential-policy-explanation" "identity-credential-policy-explanation"
); );
description.textContent = descriptionMessage; description.setAttribute(
let privacyPolicyAnchor = browser.ownerDocument.getElementById( "data-l10n-args",
"identity-credential-privacy-policy" JSON.stringify({
host: currentBaseDomain,
provider: providerDisplayDomain,
})
); );
privacyPolicyAnchor.hidden = true; browser.ownerDocument.l10n.setAttributes(
if (identityCredentialMetadata.privacy_policy_url) { description,
privacyPolicyAnchor.href = "identity-credential-policy-description",
identityCredentialMetadata.privacy_policy_url; {
privacyPolicyAnchor.hidden = false; host: currentBaseDomain,
} provider: providerDisplayDomain,
let termsOfServiceAnchor = browser.ownerDocument.getElementById( }
"identity-credential-terms-of-service"
); );
termsOfServiceAnchor.hidden = true;
if (identityCredentialMetadata.terms_of_service_url) {
termsOfServiceAnchor.href =
identityCredentialMetadata.terms_of_service_url;
termsOfServiceAnchor.hidden = false;
}
// Construct the necessary arguments for notification behavior // Construct the necessary arguments for notification behavior
let options = {}; let options = {
hideClose: true,
eventCallback: (topic, nextRemovalReason, isCancel) => {
if (topic == "removed" && isCancel) {
reject();
}
},
};
let mainAction = { let mainAction = {
label: acceptLabel, label: acceptLabel,
accessKey: acceptKey, accessKey: acceptKey,
@ -257,6 +290,7 @@ export class IdentityCredentialPromptService {
// Show the popup // Show the popup
let ownerDocument = browser.ownerDocument; let ownerDocument = browser.ownerDocument;
ownerDocument.l10n.translateFragment(description);
ownerDocument.getElementById( ownerDocument.getElementById(
"identity-credential-provider" "identity-credential-provider"
).hidden = true; ).hidden = true;
@ -298,8 +332,6 @@ export class IdentityCredentialPromptService {
reject(); reject();
return; return;
} }
let currentOrigin =
browsingContext.currentWindowContext.documentPrincipal.originNoSuffix;
// Localize all strings to be used // Localize all strings to be used
// Bug 1797154 - Convert localization calls to use the async formatValues. // Bug 1797154 - Convert localization calls to use the async formatValues.
@ -307,29 +339,26 @@ export class IdentityCredentialPromptService {
["preview/identityCredentialNotification.ftl"], ["preview/identityCredentialNotification.ftl"],
true true
); );
let providerURL = new URL(provider.configURL);
let displayDomain = lazy.IDNService.convertToDisplayIDN(
providerURL.host,
{}
);
let headerMessage = localization.formatValueSync( let headerMessage = localization.formatValueSync(
"identity-credential-header-accounts", "identity-credential-header-accounts",
{ {
host: "<>", provider: displayDomain,
} }
); );
let descriptionMessage = localization.formatValueSync( let [accept, cancel] = localization.formatMessagesSync([
"identity-credential-description-account-explanation", { id: "identity-credential-accept-button" },
{
host: currentOrigin,
}
);
let [cancel] = localization.formatMessagesSync([
{ id: "identity-credential-cancel-button" }, { id: "identity-credential-cancel-button" },
]); ]);
let cancelLabel = cancel.attributes.find(x => x.name == "label").value; let cancelLabel = cancel.attributes.find(x => x.name == "label").value;
let cancelKey = cancel.attributes.find(x => x.name == "accesskey").value; let cancelKey = cancel.attributes.find(x => x.name == "accesskey").value;
let acceptLabel = accept.attributes.find(x => x.name == "label").value;
// Add the description text let acceptKey = accept.attributes.find(x => x.name == "accesskey").value;
browser.ownerDocument.getElementById(
"credential-account-explanation"
).textContent = descriptionMessage;
// Build the choices into the panel // Build the choices into the panel
let listBox = browser.ownerDocument.getElementById( let listBox = browser.ownerDocument.getElementById(
@ -343,30 +372,59 @@ export class IdentityCredentialPromptService {
); );
for (const [accountIndex, account] of accountList.accounts.entries()) { for (const [accountIndex, account] of accountList.accounts.entries()) {
let newItem = itemTemplate.content.firstElementChild.cloneNode(true); let newItem = itemTemplate.content.firstElementChild.cloneNode(true);
newItem.firstElementChild.textContent = account.email; let newRadio = newItem.getElementsByClassName(
newItem.setAttribute("oncommand", "this.callback()"); "identity-credential-list-item-radio"
newItem.callback = function() { )[0];
let notification = browser.ownerGlobal.PopupNotifications.getNotification( newRadio.value = accountIndex;
"identity-credential", newRadio.addEventListener("change", function(event) {
browser for (let item of listBox.children) {
); item.classList.remove("checked");
browser.ownerGlobal.PopupNotifications.remove(notification); }
resolve(accountIndex); if (event.target.checked) {
}; event.target.parentElement.classList.add("checked");
}
});
if (accountIndex == 0) {
newRadio.checked = true;
newItem.classList.add("checked");
}
newItem.getElementsByClassName(
"identity-credential-list-item-label-name"
)[0].textContent = account.name;
newItem.getElementsByClassName(
"identity-credential-list-item-label-email"
)[0].textContent = account.email;
listBox.append(newItem); listBox.append(newItem);
} }
// Construct the necessary arguments for notification behavior // Construct the necessary arguments for notification behavior
let options = { let options = {
name: currentOrigin, hideClose: true,
}; eventCallback: (topic, nextRemovalReason, isCancel) => {
let mainAction = { if (topic == "removed" && isCancel) {
label: cancelLabel, reject();
accessKey: cancelKey, }
callback(event) {
reject();
}, },
}; };
let mainAction = {
label: acceptLabel,
accessKey: acceptKey,
callback(event) {
let result = listBox.querySelector(
".identity-credential-list-item-radio:checked"
).value;
resolve(parseInt(result));
},
};
let secondaryActions = [
{
label: cancelLabel,
accessKey: cancelKey,
callback(event) {
reject();
},
},
];
// Show the popup // Show the popup
browser.ownerDocument.getElementById( browser.ownerDocument.getElementById(
@ -384,7 +442,7 @@ export class IdentityCredentialPromptService {
headerMessage, headerMessage,
"identity-credential-notification-icon", "identity-credential-notification-icon",
mainAction, mainAction,
null, secondaryActions,
options options
); );
}); });
@ -405,7 +463,7 @@ export class IdentityCredentialPromptService {
browser browser
); );
if (notification) { if (notification) {
browser.ownerGlobal.PopupNotifications.remove(notification); browser.ownerGlobal.PopupNotifications.remove(notification, true);
} }
} }
} }