Bug 1409301 - Update the site security subview to the Photon style. r=johannh

The site security subview is now implemented using the "photonpanelmultiview" element, replacing the last instance of the "panelmultiview" element. The subview features a standard Photon header, hence the connection state icon was moved to the element below it. This makes the styles more similar between the main view and the subview. The connection state styles are now applied using a class name, and the tests have been updated accordingly.

This change required some fixes in the "photonpanelmultiview" implementation to make sure the height of the subview is correct and to allow keyboard navigation back to the main view.

Since the expander button and the permission controls in the main view are not visible anymore after the subview is shown, some code related to focus and hover could be removed as well.

MozReview-Commit-ID: 4nIAPWJPV8k

--HG--
extra : rebase_source : 74d6d769421c0f8521bdfae249b4d111e630a3bd
This commit is contained in:
Paolo Amadini 2017-11-11 19:13:43 +00:00
parent fe75164c55
commit f735328150
12 changed files with 108 additions and 138 deletions

View File

@ -7326,28 +7326,13 @@ var gIdentityHandler = {
this._identityPopup.hidePopup();
},
toggleSubView(name, anchor) {
let view = this._identityPopupMultiView;
let id = `identity-popup-${name}View`;
let subView = document.getElementById(id);
showSecuritySubView() {
this._identityPopupMultiView.showSubView("identity-popup-securityView",
this._popupExpander);
// Listen for the subview showing or hiding to change
// the tooltip on the expander button.
subView.addEventListener("ViewShowing", this);
subView.addEventListener("ViewHiding", this);
if (view.showingSubView) {
view.showMainView();
} else {
view.showSubView(id, anchor);
}
// If an element is focused that's not the anchor, clear the focus.
// Elements of hidden views have -moz-user-focus:ignore but setting that
// per CSS selector doesn't blur a focused element in those hidden views.
if (Services.focus.focusedElement != anchor) {
Services.focus.clearFocus(window);
}
Services.focus.clearFocus(window);
},
disableMixedContentProtection() {
@ -7680,7 +7665,7 @@ var gIdentityHandler = {
this._identityPopupInsecureLoginFormsLearnMore
.setAttribute("href", baseURL + "insecure-password");
// The expander switches its tooltip when toggled, change it to the default.
// This is in the properties file because the expander used to switch its tooltip.
this._popupExpander.tooltipText = gNavigatorBundle.getString("identity.showDetails.tooltip");
// Determine connection security information.
@ -7910,16 +7895,6 @@ var gIdentityHandler = {
},
handleEvent(event) {
// If the subview is shown or hidden, change the tooltip on the expander button.
if (event.type == "ViewShowing") {
this._popupExpander.tooltipText = gNavigatorBundle.getString("identity.hideDetails.tooltip");
return;
}
if (event.type == "ViewHiding") {
this._popupExpander.tooltipText = gNavigatorBundle.getString("identity.showDetails.tooltip");
return;
}
let elem = document.activeElement;
let position = elem.compareDocumentPosition(this._identityPopup);

View File

@ -12,28 +12,24 @@
add_task(async function() {
await BrowserTestUtils.openNewForegroundTab(gBrowser);
await loadBadCertPage("https://expired.example.com");
checkControlPanelIcons();
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
.getService(Ci.nsICertOverrideService);
certOverrideService.clearValidityOverride("expired.example.com", -1);
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
// Check for the correct icons in the identity box and control center.
function checkControlPanelIcons() {
let { gIdentityHandler } = gBrowser.ownerGlobal;
gIdentityHandler._identityBox.click();
let promiseViewShown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "ViewShown");
document.getElementById("identity-popup-security-expander").click();
await promiseViewShown;
is_element_visible(document.getElementById("connection-icon"), "Should see connection icon");
let connectionIconImage = gBrowser.ownerGlobal
.getComputedStyle(document.getElementById("connection-icon"))
.getPropertyValue("list-style-image");
let securityViewBG = gBrowser.ownerGlobal
.getComputedStyle(document.getElementById("identity-popup-securityView"))
.getComputedStyle(document.getElementById("identity-popup-securityView")
.getElementsByClassName("identity-popup-security-content")[0])
.getPropertyValue("background-image");
let securityContentBG = gBrowser.ownerGlobal
.getComputedStyle(document.getElementById("identity-popup-security-content"))
.getComputedStyle(document.getElementById("identity-popup-mainView")
.getElementsByClassName("identity-popup-security-content")[0])
.getPropertyValue("background-image");
is(connectionIconImage,
"url(\"chrome://browser/skin/connection-mixed-passive-loaded.svg\")",
@ -46,5 +42,9 @@ function checkControlPanelIcons() {
"Using expected icon image in the Control Center subview");
gIdentityHandler._identityPopup.hidden = true;
}
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
.getService(Ci.nsICertOverrideService);
certOverrideService.clearValidityOverride("expired.example.com", -1);
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});

View File

@ -51,7 +51,8 @@ const EXPECTED_APPMENU_SUBVIEW_REFLOWS = [
* correct. Unfortunately this requires 2 sync reflows.
*
* If we add more views where this is necessary, we may need to duplicate
* these expected reflows further.
* these expected reflows further. Bug 1392340 is on file to remove the
* reflows completely when opening subviews.
*/
{
stack: [
@ -59,7 +60,16 @@ const EXPECTED_APPMENU_SUBVIEW_REFLOWS = [
"hideAllViewsExcept@resource:///modules/PanelMultiView.jsm",
],
times: 2, // This number should only ever go down - never up.
times: 1, // This number should only ever go down - never up.
},
{
stack: [
"descriptionHeightWorkaround@resource:///modules/PanelMultiView.jsm",
"_transitionViews@resource:///modules/PanelMultiView.jsm",
],
times: 3, // This number should only ever go down - never up.
},
/**

View File

@ -103,11 +103,13 @@ function nextTest() {
gPopupHidden = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popuphidden");
gIdentityHandler._identityBox.click();
info("Waiting for the Control Center to be shown");
popupShown.then(() => {
popupShown.then(async () => {
ok(!is_hidden(gIdentityHandler._identityPopup), "Control Center is visible");
// Show the subview, which is an easy way in automation to reproduce
// Bug 1207542, where the CC wouldn't close on navigation.
let promiseViewShown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "ViewShown");
gBrowser.ownerDocument.querySelector("#identity-popup-security-expander").click();
await promiseViewShown;
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, gCurrentTest.location);
});
}

View File

@ -38,6 +38,15 @@ add_task(async function test_simple() {
let { gIdentityHandler } = gBrowser.ownerGlobal;
gIdentityHandler._identityBox.click();
// Messages should be visible when the scheme is HTTP, and invisible when
// the scheme is HTTPS.
is(Array.every(document.getElementById("identity-popup-mainView")
.querySelectorAll("[when-loginforms=insecure]"),
element => !is_hidden(element)),
expectWarning,
"The relevant messages should be visible or hidden in the main view.");
let promiseViewShown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "ViewShown");
document.getElementById("identity-popup-security-expander").click();
await promiseViewShown;
@ -48,10 +57,12 @@ add_task(async function test_simple() {
.getComputedStyle(document.getElementById("connection-icon"))
.getPropertyValue("list-style-image");
let securityViewBG = gBrowser.ownerGlobal
.getComputedStyle(document.getElementById("identity-popup-securityView"))
.getComputedStyle(document.getElementById("identity-popup-securityView")
.getElementsByClassName("identity-popup-security-content")[0])
.getPropertyValue("background-image");
let securityContentBG = gBrowser.ownerGlobal
.getComputedStyle(document.getElementById("identity-popup-security-content"))
.getComputedStyle(document.getElementById("identity-popup-mainView")
.getElementsByClassName("identity-popup-security-content")[0])
.getPropertyValue("background-image");
is(connectionIconImage,
"url(\"chrome://browser/skin/connection-mixed-active-loaded.svg\")",
@ -62,17 +73,19 @@ add_task(async function test_simple() {
is(securityContentBG,
"url(\"chrome://browser/skin/controlcenter/mcb-disabled.svg\")",
"Using expected icon image in the Control Center subview");
is(Array.filter(document.querySelectorAll("[observes=identity-popup-insecure-login-forms-learn-more]"),
is(Array.filter(document.getElementById("identity-popup-securityView")
.querySelectorAll("[observes=identity-popup-insecure-login-forms-learn-more]"),
element => !is_hidden(element)).length, 1,
"The 'Learn more' link should be visible once.");
}
// Messages should be visible when the scheme is HTTP, and invisible when
// the scheme is HTTPS.
is(Array.every(document.querySelectorAll("[when-loginforms=insecure]"),
is(Array.every(document.getElementById("identity-popup-securityView")
.querySelectorAll("[when-loginforms=insecure]"),
element => !is_hidden(element)),
expectWarning,
"The relevant messages should be visible or hidden.");
"The relevant messages should be visible or hidden in the security view.");
if (gIdentityHandler._identityPopup.state != "closed") {
let hideEvent = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popuphidden");
@ -134,6 +147,12 @@ add_task(async function test_ignoring_window_opener() {
// Open the identity popup.
let { gIdentityHandler } = gBrowser.ownerGlobal;
gIdentityHandler._identityBox.click();
ok(Array.every(document.getElementById("identity-popup-mainView")
.querySelectorAll("[when-loginforms=insecure]"),
element => is_hidden(element)),
"All messages should be hidden in the main view.");
let promiseViewShown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "ViewShown");
document.getElementById("identity-popup-security-expander").click();
await promiseViewShown;
@ -146,10 +165,12 @@ add_task(async function test_ignoring_window_opener() {
.getComputedStyle(document.getElementById("connection-icon"))
.getPropertyValue("list-style-image");
let securityViewBG = gBrowser.ownerGlobal
.getComputedStyle(document.getElementById("identity-popup-securityView"))
.getComputedStyle(document.getElementById("identity-popup-securityView")
.getElementsByClassName("identity-popup-security-content")[0])
.getPropertyValue("background-image");
let securityContentBG = gBrowser.ownerGlobal
.getComputedStyle(document.getElementById("identity-popup-security-content"))
.getComputedStyle(document.getElementById("identity-popup-mainView")
.getElementsByClassName("identity-popup-security-content")[0])
.getPropertyValue("background-image");
is(connectionIconImage,
"url(\"chrome://browser/skin/connection-secure.svg\")",
@ -161,9 +182,10 @@ add_task(async function test_ignoring_window_opener() {
"url(\"chrome://browser/skin/controlcenter/connection.svg\")",
"Using expected icon image in the Control Center subview");
ok(Array.every(document.querySelectorAll("[when-loginforms=insecure]"),
ok(Array.every(document.getElementById("identity-popup-securityView")
.querySelectorAll("[when-loginforms=insecure]"),
element => is_hidden(element)),
"All messages should be hidden.");
"All messages should be hidden in the security view.");
if (gIdentityHandler._identityPopup.state != "closed") {
info("hiding popup");

View File

@ -218,11 +218,14 @@ async function assertMixedContentBlockingState(tabbrowser, states = {}) {
// Make sure the correct icon is visible in the Control Center.
// This logic is controlled with CSS, so this helps prevent regressions there.
let securityView = doc.getElementById("identity-popup-securityView");
let securityViewBG = tabbrowser.ownerGlobal.getComputedStyle(securityView).
getPropertyValue("background-image");
let securityContentBG = tabbrowser.ownerGlobal.getComputedStyle(securityView).
getPropertyValue("background-image");
let securityViewBG = tabbrowser.ownerGlobal
.getComputedStyle(document.getElementById("identity-popup-securityView")
.getElementsByClassName("identity-popup-security-content")[0])
.getPropertyValue("background-image");
let securityContentBG = tabbrowser.ownerGlobal
.getComputedStyle(document.getElementById("identity-popup-mainView")
.getElementsByClassName("identity-popup-security-content")[0])
.getPropertyValue("background-image");
if (stateInsecure) {
is(securityViewBG, "url(\"chrome://browser/skin/controlcenter/conn-not-secure.svg\")",
@ -262,7 +265,8 @@ async function assertMixedContentBlockingState(tabbrowser, states = {}) {
let promiseViewShown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "ViewShown");
doc.getElementById("identity-popup-security-expander").click();
await promiseViewShown;
is(Array.filter(doc.querySelectorAll("[observes=identity-popup-mcb-learn-more]"),
is(Array.filter(doc.getElementById("identity-popup-securityView")
.querySelectorAll("[observes=identity-popup-mcb-learn-more]"),
element => !is_hidden(element)).length, 1,
"The 'Learn more' link should be visible once.");
}

View File

@ -5,6 +5,7 @@
<panel id="identity-popup"
type="arrow"
hidden="true"
photon="true"
role="alertdialog"
onpopupshown="gIdentityHandler.onPopupShown(event);"
onpopuphidden="gIdentityHandler.onPopupHidden(event);"
@ -15,13 +16,13 @@
<broadcaster id="identity-popup-insecure-login-forms-learn-more" class="text-link plain" value="&identity.learnMore;"/>
</broadcasterset>
<panelmultiview id="identity-popup-multiView"
mainViewId="identity-popup-mainView">
<panelview id="identity-popup-mainView" flex="1"
<photonpanelmultiview id="identity-popup-multiView"
mainViewId="identity-popup-mainView">
<panelview id="identity-popup-mainView"
descriptionheightworkaround="true">
<!-- Security Section -->
<hbox id="identity-popup-security" class="identity-popup-section">
<vbox id="identity-popup-security-content" flex="1">
<vbox class="identity-popup-security-content" flex="1">
<label class="plain">
<label class="identity-popup-headline identity-popup-host"></label>
<label class="identity-popup-headline identity-popup-hostless" crop="end"/>
@ -48,7 +49,7 @@
<button id="identity-popup-security-expander"
class="identity-popup-expander"
when-connection="not-secure secure secure-ev secure-cert-user-overridden"
oncommand="gIdentityHandler.toggleSubView('security', this)"/>
oncommand="gIdentityHandler.showSecuritySubView();"/>
</hbox>
<!-- Tracking Protection Section -->
@ -98,8 +99,9 @@
<!-- Security SubView -->
<panelview id="identity-popup-securityView"
title="&identity.securityView.label;"
descriptionheightworkaround="true">
<vbox id="identity-popup-securityView-header">
<vbox class="identity-popup-security-content">
<label class="plain">
<label class="identity-popup-headline identity-popup-host"></label>
<label class="identity-popup-headline identity-popup-hostless" crop="end"/>
@ -182,5 +184,5 @@
</vbox>
</panelview>
</panelmultiview>
</photonpanelmultiview>
</panel>

View File

@ -682,6 +682,10 @@ this.PanelMultiView = class {
this._offscreenViewStack.appendChild(viewNode);
viewNode.setAttribute("in-transition", true);
// Now that the subview is visible, we can check the height of the
// description elements it contains.
this.descriptionHeightWorkaround(viewNode);
viewRect = await BrowserUtils.promiseLayoutFlushed(this.document, "layout", () => {
return this._dwu.getBoundsWithoutFlushing(viewNode);
});

View File

@ -72,7 +72,7 @@
closemenu="none"
tabindex="0"
tooltip="&backCmd.label;"
onclick="document.getBindingParent(this).panelMultiView.goBack(); this.blur()"/>
oncommand="document.getBindingParent(this).panelMultiView.goBack(); this.blur()"/>
<xul:label xbl:inherits="value=title"/>
</xul:box>
<children/>

View File

@ -732,6 +732,10 @@ you can use these alternative items. Otherwise, their values should be empty. -
<!ENTITY editBookmark.done.label "Done">
<!ENTITY editBookmark.removeBookmark.accessKey "R">
<!-- LOCALIZATION NOTE (identity.securityView.label)
This is the header of the security subview in the Site Identity panel. -->
<!ENTITY identity.securityView.label "Site Security">
<!ENTITY identity.connectionSecure "Secure Connection">
<!ENTITY identity.connectionNotSecure "Connection is Not Secure">
<!ENTITY identity.connectionFile "This page is stored on your computer.">

View File

@ -505,7 +505,6 @@ identity.icon.tooltip=Show site information
identity.extension.label=Extension (%S)
identity.extension.tooltip=Loaded by extension: %S
identity.showDetails.tooltip=Show connection details
identity.hideDetails.tooltip=Hide connection details
trackingProtection.intro.title=How Tracking Protection works
# LOCALIZATION NOTE (trackingProtection.intro.description2):

View File

@ -55,18 +55,6 @@
display: none !important;
}
#identity-popup,
#identity-popup:not([panelopen]) .panel-viewstack[viewtype="main"]:not([transitioning]) #identity-popup-mainView {
/* Tiny hack to ensure the panel shrinks back to its original
size after closing a subview that is bigger than the main view. */
max-height: 0;
}
.panel-mainview[panelid=identity-popup][viewtype=subview] > #identity-popup-mainView menulist,
.panel-mainview[panelid=identity-popup][viewtype=subview] > #identity-popup-mainView button:not([panel-multiview-anchor]) {
-moz-user-focus: ignore;
}
#identity-popup > .panel-arrowcontainer > .panel-arrowcontent {
padding: 0;
/* Set default fill for icons in the identity popup.
@ -75,8 +63,9 @@
fill-opacity: .6;
}
.panel-mainview[panelid=identity-popup] {
#identity-popup-mainView {
min-width: 30em;
max-width: 30em;
}
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack[viewtype="main"] > .panel-subviews {
@ -97,26 +86,19 @@
border-top: 1px solid var(--panel-separator-color);
}
#identity-popup-securityView,
#identity-popup-security-content,
.identity-popup-security-content,
#identity-popup-permissions-content,
#tracking-protection-content {
background-repeat: no-repeat;
background-position: 1em 1em;
background-size: 24px auto;
}
#identity-popup-security-content,
#identity-popup-permissions-content,
#tracking-protection-content {
padding: 0.5em 0 1em;
/* .identity-popup-host depends on this width */
padding-inline-start: calc(2em + 24px);
padding-inline-end: 1em;
}
#identity-popup-securityView:-moz-locale-dir(rtl),
#identity-popup-security-content:-moz-locale-dir(rtl),
.identity-popup-security-content:-moz-locale-dir(rtl),
#identity-popup-permissions-content:-moz-locale-dir(rtl),
#tracking-protection-content:-moz-locale-dir(rtl) {
background-position: calc(100% - 1em) 1em;
@ -138,29 +120,17 @@
color: inherit;
}
.identity-popup-expander[panel-multiview-anchor] {
transition: background-color 250ms ease-in;
background-color: Highlight;
background-image: url("chrome://browser/skin/arrow-left.svg");
color: HighlightText;
}
.identity-popup-expander[panel-multiview-anchor]:-moz-locale-dir(rtl),
.identity-popup-expander:not([panel-multiview-anchor]):-moz-locale-dir(ltr) {
.identity-popup-expander:-moz-locale-dir(ltr) {
transform: scaleX(-1);
}
.identity-popup-expander > .button-box {
padding: 0;
}
.identity-popup-expander:not([panel-multiview-anchor]) > .button-box {
border-right: 1px solid var(--panel-separator-color);
padding: 0;
}
.identity-popup-expander:hover {
background-color: var(--arrowpanel-dimmed);
background-image: url("chrome://browser/skin/arrow-left.svg");
}
.identity-popup-expander:hover:active {
@ -172,9 +142,8 @@
.identity-popup-permission-label,
.identity-popup-permission-state-label,
#identity-popup-security-content > description,
.identity-popup-security-content > description,
#identity-popup-security-descriptions > description,
#identity-popup-securityView-header > description,
#identity-popup-securityView-body > description,
#identity-popup-permissions-content > description,
#tracking-protection-content > description {
@ -194,7 +163,7 @@
.identity-popup-host {
word-wrap: break-word;
/* 1em + 2em + 24px is #identity-popup-security-content padding
/* 1em + 2em + 24px is .identity-popup-security-content padding
* 30em is .panel-mainview width */
max-width: calc(30rem - 3rem - 24px - @identityPopupExpanderWidth@);
}
@ -220,50 +189,38 @@
.identity-popup-connection-not-secure {
color: #d74345;
}
#identity-popup-securityView {
overflow: hidden;
}
#identity-popup-securityView,
#identity-popup-security-content {
.identity-popup-security-content {
background-image: url(chrome://browser/skin/controlcenter/conn-not-secure.svg);
}
#identity-popup[connection=chrome] #identity-popup-securityView,
#identity-popup[connection=chrome] #identity-popup-security-content {
#identity-popup[connection=chrome] .identity-popup-security-content {
background-image: url(chrome://branding/content/icon48.png);
}
#identity-popup[connection^=secure] #identity-popup-securityView,
#identity-popup[connection^=secure] #identity-popup-security-content {
#identity-popup[connection^=secure] .identity-popup-security-content {
background-image: url(chrome://browser/skin/controlcenter/connection.svg);
-moz-context-properties: fill;
fill: #12BC00;
}
/* Use [isbroken] to make sure we don't show a lock on an http page. See Bug 1192162. */
#identity-popup[ciphers=weak] #identity-popup-securityView,
#identity-popup[ciphers=weak] #identity-popup-security-content,
#identity-popup[mixedcontent~=passive-loaded][isbroken] #identity-popup-securityView,
#identity-popup[mixedcontent~=passive-loaded][isbroken] #identity-popup-security-content {
#identity-popup[ciphers=weak] .identity-popup-security-content,
#identity-popup[mixedcontent~=passive-loaded][isbroken] .identity-popup-security-content {
background-image: url(chrome://browser/skin/controlcenter/connection.svg);
-moz-context-properties: fill, fill-opacity;
}
#identity-popup[connection=secure-cert-user-overridden] #identity-popup-securityView,
#identity-popup[connection=secure-cert-user-overridden] #identity-popup-security-content {
#identity-popup[connection=secure-cert-user-overridden] .identity-popup-security-content {
background-image: url(chrome://browser/skin/connection-mixed-passive-loaded.svg);
-moz-context-properties: fill, fill-opacity;
}
#identity-popup[loginforms=insecure] #identity-popup-securityView,
#identity-popup[loginforms=insecure] #identity-popup-security-content,
#identity-popup[mixedcontent~=active-loaded][isbroken] #identity-popup-securityView,
#identity-popup[mixedcontent~=active-loaded][isbroken] #identity-popup-security-content {
#identity-popup[loginforms=insecure] .identity-popup-security-content,
#identity-popup[mixedcontent~=active-loaded][isbroken] .identity-popup-security-content {
background-image: url(chrome://browser/skin/controlcenter/mcb-disabled.svg);
-moz-context-properties: fill, fill-opacity;
}
#identity-popup[connection=extension] #identity-popup-securityView,
#identity-popup[connection=extension] #identity-popup-security-content {
#identity-popup[connection=extension] .identity-popup-security-content {
background-image: url(chrome://browser/skin/controlcenter/extension.svg);
-moz-context-properties: fill;
fill: #60bf4c;
@ -274,19 +231,10 @@
color: Graytext;
}
#identity-popup-securityView-header,
#identity-popup-securityView-body {
margin-inline-start: calc(2em + 24px);
margin-inline-end: 1em;
}
#identity-popup-securityView-header {
margin-top: 0.5em;
border-bottom: 1px solid var(--panel-separator-color);
padding-bottom: 1em;
}
#identity-popup-securityView-body {
border-top: 1px solid var(--panel-separator-color);
padding-inline-end: 1em;
}