[tbb-commits] [tor-browser] 03/03: fixup! Bug 40925: Implemented the Security Level component
gitolite role
git at cupani.torproject.org
Tue Dec 6 11:43:38 UTC 2022
This is an automated email from the git hooks/post-receive script.
pierov pushed a commit to branch tor-browser-102.5.0esr-12.5-1
in repository tor-browser.
commit 1add8d34c1bb91f299d0419aab2cac4edbe142aa
Author: Henry Wilkes <henry at torproject.org>
AuthorDate: Mon Nov 21 16:35:34 2022 +0000
fixup! Bug 40925: Implemented the Security Level component
Make the security level panel and button more accessible:
+ We use semantic elements if possible and otherwise set aria attributes. In
particular, we give the panel a dialog role.
+ We set the "Restore Defaults" button as default if it is shown since
it is the recommended action.
+ We focus the default button when showing the popup.
+ We handle the case where the security level button is in the overflow
menu by closing the overflow menu first. Before this key navigation in
the sub-panel could disrupt the position in the parent panel.
We also simplify the code in general and use HTML for the main content
of the panel.
---
.../securitylevel/content/securityLevel.js | 293 +++++++++------------
.../content/securityLevelButton.inc.xhtml | 6 +-
.../securitylevel/content/securityLevelPanel.css | 70 +++--
.../content/securityLevelPanel.inc.xhtml | 58 ++--
4 files changed, 182 insertions(+), 245 deletions(-)
diff --git a/browser/components/securitylevel/content/securityLevel.js b/browser/components/securitylevel/content/securityLevel.js
index 4df65fe5452b..e823ac993812 100644
--- a/browser/components/securitylevel/content/securityLevel.js
+++ b/browser/components/securitylevel/content/securityLevel.js
@@ -2,10 +2,6 @@
/* global AppConstants, Services, openPreferences, XPCOMUtils */
-XPCOMUtils.defineLazyModuleGetters(this, {
- PanelMultiView: "resource:///modules/PanelMultiView.jsm",
-});
-
XPCOMUtils.defineLazyGetter(this, "SecurityLevelStrings", () => {
let strings = {
// Generic terms
@@ -111,58 +107,92 @@ var SecurityLevelPrefs = {
var SecurityLevelButton = {
_securityPrefsBranch: null,
+ /**
+ * Whether we have added popup listeners to the panel.
+ *
+ * @type {boolean}
+ */
+ _panelPopupListenersSetup: false,
+ /**
+ * The toolbar button element.
+ *
+ * @type {Element}
+ */
+ _button: null,
+ /**
+ * The button that the panel should point to. Either the toolbar button or the
+ * overflow button.
+ *
+ * @type {Element}
+ */
+ _anchorButton: null,
_configUIFromPrefs() {
- const securityLevelButton = this.button;
- if (securityLevelButton != null) {
- const level = SecurityLevelPrefs.securityLevel;
- if (!level) {
- return;
- }
- const customStr = SecurityLevelPrefs.securityCustom ? "_custom" : "";
- securityLevelButton.setAttribute("level", `${level}${customStr}`);
- securityLevelButton.setAttribute(
- "tooltiptext",
- SecurityLevelStrings[`security_level_tooltip_${level}`]
- );
+ const level = SecurityLevelPrefs.securityLevel;
+ if (!level) {
+ return;
}
+ const customStr = SecurityLevelPrefs.securityCustom ? "_custom" : "";
+ this._button.setAttribute("level", `${level}${customStr}`);
+ this._button.setAttribute(
+ "tooltiptext",
+ SecurityLevelStrings[`security_level_tooltip_${level}`]
+ );
},
/**
- * The node for this button.
- *
- * Note, the returned element may be part of the DOM or may live in the
- * toolbox palette, where it may be added later to the DOM through
- * customization.
- *
- * @type {MozToolbarbutton}
+ * Open the panel popup for the button.
*/
- get button() {
- // We first search in the DOM for the security level button. If it does not
- // exist it may be in the toolbox palette. We still want to return the
- // button in the latter case to allow it to be initialized or adjusted in
- // case it is added back through customization.
- return (
- document.getElementById("security-level-button") ||
- window.gNavToolbox.palette.querySelector("#security-level-button")
- );
- },
+ openPopup() {
+ let anchorNode;
+ const overflowPanel = document.getElementById("widget-overflow");
+ if (overflowPanel.contains(this._button)) {
+ // We are in the overflow panel.
+ // We first close the overflow panel, otherwise focus will not return to
+ // the nav-bar-overflow-button if the security level panel is closed with
+ // "Escape" (the navigation toolbar does not track focus when a panel is
+ // opened whilst another is already open).
+ // NOTE: In principle, using PanelMultiView would allow us to open panels
+ // from within another panel. However, when using panelmultiview for the
+ // security level panel, tab navigation was broken within the security
+ // level panel. PanelMultiView may be set up to work with a menu-like
+ // panel rather than our dialog-like panel.
+ overflowPanel.hidePopup();
+ this._anchorButton = document.getElementById("nav-bar-overflow-button");
+ anchorNode = this._anchorButton.icon;
+ } else {
+ this._anchorButton = this._button;
+ anchorNode = this._button.badgeStack;
+ }
- get anchor() {
- let button = this.button;
- let anchor = button?.icon;
- if (!anchor) {
- return null;
+ const panel = SecurityLevelPanel.panel;
+ if (!this._panelPopupListenersSetup) {
+ this._panelPopupListenersSetup = true;
+ // NOTE: We expect the _anchorButton to not change whilst the popup is
+ // open.
+ panel.addEventListener("popupshown", () => {
+ this._anchorButton.setAttribute("open", "true");
+ });
+ panel.addEventListener("popuphidden", () => {
+ this._anchorButton.removeAttribute("open");
+ });
}
- anchor.setAttribute("consumeanchor", button.id);
- return anchor;
+ panel.openPopup(anchorNode, "bottomcenter topright", 0, 0, false);
},
init() {
+ // We first search in the DOM for the security level button. If it does not
+ // exist it may be in the toolbox palette. We still want to return the
+ // button in the latter case to allow it to be initialized or adjusted in
+ // case it is added back through customization.
+ this._button =
+ document.getElementById("security-level-button") ||
+ window.gNavToolbox.palette.querySelector("#security-level-button");
// Set a label to be be used as the accessible name, and to be shown in the
// overflow menu and during customization.
- this.button?.setAttribute("label", SecurityLevelStrings.security_level);
+ this._button.setAttribute("label", SecurityLevelStrings.security_level);
+ this._button.addEventListener("command", () => this.openPopup());
// set the initial class based off of the current pref
this._configUIFromPrefs();
@@ -190,32 +220,6 @@ var SecurityLevelButton = {
break;
}
},
-
- // for when the toolbar button needs to be activated and displays the Security Level panel
- //
- // In the toolbarbutton xul you'll notice we register this callback for both onkeypress and
- // onmousedown. We do this to match the behavior of other panel spawning buttons such as Downloads,
- // Library, and the Hamburger menus. Using oncommand alone would result in only getting fired
- // after onclick, which is mousedown followed by mouseup.
- onCommand(aEvent) {
- // snippet borrowed from /browser/components/downloads/content/indicator.js DownloadsIndicatorView.onCommand(evt)
- if (
- // On Mac, ctrl-click will send a context menu event from the widget, so
- // we don't want to bring up the panel when ctrl key is pressed.
- (aEvent.type == "mousedown" &&
- (aEvent.button != 0 ||
- (AppConstants.platform == "macosx" && aEvent.ctrlKey))) ||
- (aEvent.type == "keypress" && aEvent.key != " " && aEvent.key != "Enter")
- ) {
- return;
- }
-
- // we need to set this attribute for the button to be shaded correctly to look like it is pressed
- // while the security level panel is open
- this.button.setAttribute("open", "true");
- SecurityLevelPanel.show();
- aEvent.stopPropagation();
- },
}; /* SecurityLevelButton */
/*
@@ -226,66 +230,49 @@ var SecurityLevelButton = {
var SecurityLevelPanel = {
_securityPrefsBranch: null,
- _panel: null,
- _anchor: null,
_populated: false,
- _selectors: Object.freeze({
- panel: "panel#securityLevel-panel",
- icon: "vbox#securityLevel-vbox>vbox",
- labelLevel: "label#securityLevel-level",
- labelCustom: "label#securityLevel-custom",
- summary: "description#securityLevel-summary",
- restoreDefaults: "button#securityLevel-restoreDefaults",
- advancedSecuritySettings: "button#securityLevel-advancedSecuritySettings",
- // Selectors used only for l10n - remove them when switching to Fluent
- header: "#securityLevel-header",
- learnMore: "#securityLevel-panel .learnMore",
- }),
-
_populateXUL() {
- let selectors = this._selectors;
-
this._elements = {
- panel: document.querySelector(selectors.panel),
- icon: document.querySelector(selectors.icon),
- labelLevel: document.querySelector(selectors.labelLevel),
- labelCustom: document.querySelector(selectors.labelCustom),
- summaryDescription: document.querySelector(selectors.summary),
- restoreDefaultsButton: document.querySelector(selectors.restoreDefaults),
- advancedSecuritySettings: document.querySelector(
- selectors.advancedSecuritySettings
+ panel: document.getElementById("securityLevel-panel"),
+ background: document.getElementById("securityLevel-background"),
+ levelName: document.getElementById("securityLevel-level"),
+ customName: document.getElementById("securityLevel-custom"),
+ summary: document.getElementById("securityLevel-summary"),
+ restoreDefaultsButton: document.getElementById(
+ "securityLevel-restoreDefaults"
),
- header: document.querySelector(selectors.header),
- learnMore: document.querySelector(selectors.learnMore),
+ settingsButton: document.getElementById("securityLevel-settings"),
};
- this._elements.header.textContent = SecurityLevelStrings.security_level;
- this._elements.labelCustom.setAttribute(
- "value",
- SecurityLevelStrings.security_level_custom
- );
- this._elements.learnMore.setAttribute(
- "value",
- SecurityLevelStrings.security_level_learn_more
- );
+ document.getElementById("securityLevel-header").textContent =
+ SecurityLevelStrings.security_level;
+ this._elements.customName.textContent =
+ SecurityLevelStrings.security_level_custom;
+ const learnMoreEl = document.getElementById("securityLevel-learnMore");
+ learnMoreEl.textContent = SecurityLevelStrings.security_level_learn_more;
+ learnMoreEl.addEventListener("click", event => {
+ window.openTrustedLinkIn(learnMoreEl.href, "tab");
+ this.hide();
+ event.preventDefault();
+ });
this._elements.restoreDefaultsButton.textContent =
SecurityLevelStrings.security_level_restore;
- this._elements.advancedSecuritySettings.textContent =
+ this._elements.settingsButton.textContent =
SecurityLevelStrings.security_level_change;
- this._elements.panel.addEventListener("onpopupshown", e => {
- this.onPopupShown(e);
- });
- this._elements.panel.addEventListener("onpopuphidden", e => {
- this.onPopupHidden(e);
- });
this._elements.restoreDefaultsButton.addEventListener("command", () => {
this.restoreDefaults();
});
- this._elements.advancedSecuritySettings.addEventListener("command", () => {
- this.openAdvancedSecuritySettings();
+ this._elements.settingsButton.addEventListener("command", () => {
+ this.openSecuritySettings();
+ });
+
+ this._elements.panel.addEventListener("popupshown", () => {
+ // Bring focus into the panel by focusing the default button.
+ this._elements.panel.querySelector('button[default="true"]').focus();
});
+
this._populated = true;
this._configUIFromPrefs();
},
@@ -301,26 +288,35 @@ var SecurityLevelPanel = {
const custom = SecurityLevelPrefs.securityCustom;
// only visible when user is using custom settings
- let labelCustomWarning = this._elements.labelCustom;
- labelCustomWarning.hidden = !custom;
- let buttonRestoreDefaults = this._elements.restoreDefaultsButton;
- buttonRestoreDefaults.hidden = !custom;
+ this._elements.customName.hidden = !custom;
+ this._elements.restoreDefaultsButton.hidden = !custom;
+ if (custom) {
+ this._elements.settingsButton.removeAttribute("default");
+ this._elements.restoreDefaultsButton.setAttribute("default", "true");
+ } else {
+ this._elements.settingsButton.setAttribute("default", "true");
+ this._elements.restoreDefaultsButton.removeAttribute("default");
+ }
- const summary = this._elements.summaryDescription;
// Descriptions change based on security level
- if (level) {
- this._elements.icon.setAttribute("level", level);
- this._elements.labelLevel.setAttribute(
- "value",
- SecurityLevelStrings[`security_level_${level}`]
- );
- summary.textContent =
- SecurityLevelStrings[`security_level_${level}_summary`];
- }
- // override the summary text with custom warning
- if (custom) {
- summary.textContent = SecurityLevelStrings.security_level_custom_summary;
+ this._elements.background.setAttribute("level", level);
+ this._elements.levelName.textContent =
+ SecurityLevelStrings[`security_level_${level}`];
+ this._elements.summary.textContent = custom
+ ? SecurityLevelStrings.security_level_custom_summary
+ : SecurityLevelStrings[`security_level_${level}_summary`];
+ },
+
+ /**
+ * The popup element.
+ *
+ * @type {MozPanel}
+ */
+ get panel() {
+ if (!this._populated) {
+ this._populateXUL();
}
+ return this._elements.panel;
},
init() {
@@ -335,37 +331,18 @@ var SecurityLevelPanel = {
this._securityPrefsBranch = null;
},
- show() {
- // we have to defer this until after the browser has finished init'ing
- // before we can populate the panel
- if (!this._populated) {
- this._populateXUL();
- }
-
- this._elements.panel.hidden = false;
- PanelMultiView.openPopup(
- this._elements.panel,
- SecurityLevelButton.anchor,
- "bottomcenter topright",
- 0,
- 0,
- false,
- null
- ).catch(Cu.reportError);
- },
-
hide() {
- PanelMultiView.hidePopup(this._elements.panel);
+ this._elements.panel.hidePopup();
},
restoreDefaults() {
SecurityLevelPrefs.securityCustom = false;
- // hide and reshow so that layout re-renders properly
- this.hide();
- this.show(this._anchor);
+ // Move focus to the settings button since restore defaults button will
+ // become hidden.
+ this._elements.settingsButton.focus();
},
- openAdvancedSecuritySettings() {
+ openSecuritySettings() {
openPreferences("privacy-securitylevel");
this.hide();
},
@@ -380,16 +357,6 @@ var SecurityLevelPanel = {
break;
}
},
-
- // callback when the panel is displayed
- onPopupShown(event) {
- SecurityLevelButton.button.setAttribute("open", "true");
- },
-
- // callback when the panel is hidden
- onPopupHidden(event) {
- SecurityLevelButton.button.removeAttribute("open");
- },
}; /* SecurityLevelPanel */
/*
diff --git a/browser/components/securitylevel/content/securityLevelButton.inc.xhtml b/browser/components/securitylevel/content/securityLevelButton.inc.xhtml
index 96ee1ec0ca49..1737d27914c3 100644
--- a/browser/components/securitylevel/content/securityLevelButton.inc.xhtml
+++ b/browser/components/securitylevel/content/securityLevelButton.inc.xhtml
@@ -1,7 +1,5 @@
-<toolbarbutton id="security-level-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+<toolbarbutton id="security-level-button"
+ class="toolbarbutton-1 chromeclass-toolbar-additional"
badged="true"
removable="true"
- onmousedown="SecurityLevelButton.onCommand(event);"
- onkeypress="SecurityLevelButton.onCommand(event);"
- closemenu="none"
cui-areatype="toolbar"/>
diff --git a/browser/components/securitylevel/content/securityLevelPanel.css b/browser/components/securitylevel/content/securityLevelPanel.css
index c50acf0ae76c..5a13852be015 100644
--- a/browser/components/securitylevel/content/securityLevelPanel.css
+++ b/browser/components/securitylevel/content/securityLevelPanel.css
@@ -1,71 +1,61 @@
/* Security Level CSS */
-panelview#securityLevel-panelview {
- width: 25em;
-}
-
-vbox#securityLevel-vbox > vbox {
+#securityLevel-background {
+ /* xul:vbox with display: block will be correctly measured in size by the
+ * parent xul:panel, with line-wrapping taken into account, and allocated the
+ * required space. */
+ display: block;
+ min-height: 10em;
+ padding-inline: 16px;
background-repeat: no-repeat;
- /* icon center-line should be in-line with right margin */
- /* -margin + panelWidth - imageWidth/2 */
- background-position: calc(-16px + 25em - 4.5em) 0.4em;
+ background-position-y: top 0.4em;
+ /* Icon center should be in-line with end padding.
+ * We set the right-to-left position here, and the left-to-right position
+ * below. */
+ --background-inline-offset: calc(16px - 4.5em);
+ background-position-x: left var(--background-inline-offset);
background-size: 9em 9em;
-moz-context-properties: fill, fill-opacity;
fill-opacity: 1;
fill: var(--button-bgcolor);
- min-height: 10em;
}
-vbox#securityLevel-vbox > vbox[level="standard"] {
+/* NOTE: Use ":dir" instead of ":-moz-locale-dir" when panel switches to HTML. */
+#securityLevel-background:-moz-locale-dir(ltr) {
+ background-position-x: right var(--background-inline-offset);
+}
+
+#securityLevel-background[level="standard"] {
background-image: url("chrome://browser/content/securitylevel/securityLevelIcon.svg#standard");
}
-vbox#securityLevel-vbox > vbox[level="safer"] {
+
+#securityLevel-background[level="safer"] {
background-image: url("chrome://browser/content/securitylevel/securityLevelIcon.svg#safer");
}
-vbox#securityLevel-vbox > vbox[level="safest"] {
+
+#securityLevel-background[level="safest"] {
background-image: url("chrome://browser/content/securitylevel/securityLevelIcon.svg#safest");
}
-vbox#securityLevel-vbox > toolbarseparator {
+/* Override margin in panelUI-shared.css */
+#securityLevel-panel toolbarseparator#securityLevel-separator {
margin-inline: 16px;
}
-vbox#securityLevel-vbox > vbox {
- margin-inline: 0;
- padding-inline: 16px;
-}
-
-vbox#securityLevel-vbox > vbox * {
- margin-inline: 0;
-}
-
-label#securityLevel-level {
+#securityLevel-level {
font-size: 1.25em;
font-weight: 600;
- padding-top: 0.15em;
}
-label#securityLevel-custom {
+#securityLevel-custom {
border-radius: 4px;
background-color: var(--yellow-50);
color: black;
- font-size: 1em;
- height: 1.6em;
- line-height: 1.0em;
padding: 0.4em 0.5em;
- margin-inline-start: 1em !important;
+ margin-inline-start: 1em;
}
-description#securityLevel-summary {
- margin-top: 1em;
+#securityLevel-summary {
padding-inline-end: 5em;
-}
-
-vbox#securityLevel-vbox > hbox.panel-footer {
- display: flex;
-}
-
-
-button#securityLevel-advancedSecuritySettings {
- margin-block: 0;
+ max-width: 20em;
}
diff --git a/browser/components/securitylevel/content/securityLevelPanel.inc.xhtml b/browser/components/securitylevel/content/securityLevelPanel.inc.xhtml
index c485f819aba9..d330042f7311 100644
--- a/browser/components/securitylevel/content/securityLevelPanel.inc.xhtml
+++ b/browser/components/securitylevel/content/securityLevelPanel.inc.xhtml
@@ -1,44 +1,26 @@
<panel id="securityLevel-panel"
- role="group"
+ role="dialog"
+ aria-labelledby="securityLevel-header"
+ aria-describedby="securityLevel-subheading securityLevel-summary"
type="arrow"
orient="vertical"
level="top"
- hidden="true"
class="panel-no-padding">
- <panelmultiview mainViewId="securityLevel-panelview">
- <panelview id="securityLevel-panelview" descriptionheightworkaround="true">
- <vbox id="securityLevel-vbox">
- <box class="panel-header">
- <html:h1 id="securityLevel-header"/>
- </box>
- <toolbarseparator></toolbarseparator>
- <vbox>
- <hbox>
- <label id="securityLevel-level"/>
- <vbox>
- <spacer flex="1"/>
- <label id="securityLevel-custom"/>
- <spacer flex="1"/>
- </vbox>
- <spacer flex="1"/>
- </hbox>
- <description id="securityLevel-summary"/>
- <hbox>
- <label
- class="learnMore text-link"
- href="about:manual#security-settings"
- useoriginprincipal="true"
- onclick="SecurityLevelPanel.hide();"
- is="text-link"/>
- <spacer/>
- </hbox>
- </vbox>
- <hbox class="panel-footer">
- <button id="securityLevel-restoreDefaults"/>
- <button id="securityLevel-advancedSecuritySettings"
- default="true"/>
- </hbox>
- </vbox>
- </panelview>
- </panelmultiview>
+ <box class="panel-header">
+ <html:h1 id="securityLevel-header"></html:h1>
+ </box>
+ <toolbarseparator id="securityLevel-separator"></toolbarseparator>
+ <vbox id="securityLevel-background" class="panel-subview-body">
+ <html:p id="securityLevel-subheading">
+ <html:span id="securityLevel-level"></html:span>
+ <html:span id="securityLevel-custom"></html:span>
+ </html:p>
+ <html:p id="securityLevel-summary"></html:p>
+ <html:a id="securityLevel-learnMore" href="about:manual#security-settings">
+ </html:a>
+ </vbox>
+ <hbox class="panel-footer">
+ <button id="securityLevel-settings"/>
+ <button id="securityLevel-restoreDefaults"/>
+ </hbox>
</panel>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the tbb-commits
mailing list