morgan pushed to branch tor-browser-128.5.0esr-14.5-2 at The Tor Project / Applications / Tor Browser
Commits: 46eb7528 by Henry Wilkes at 2024-12-19T11:13:03+00:00 fixup! TB 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
TB 43320: Exclude hidden elements from the settings search.
We hide elements using the `hidden` attribute instead of `display: none`, which will exclude them from the search.
We also always hide the options menu and screen reader announcement area using `data-hidden-from-search`.
- - - - - 018492cc by Henry Wilkes at 2024-12-19T11:13:15+00:00 fixup! TB 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
TB 43320: Add duplicate headings that only appear in search results.
These duplicate search headings have the same content but are one heading level higher, to preserve the heading level hierarchy in a search result.
- - - - -
3 changed files:
- browser/components/torpreferences/content/connectionPane.js - browser/components/torpreferences/content/connectionPane.xhtml - browser/components/torpreferences/content/torPreferences.css
Changes:
===================================== browser/components/torpreferences/content/connectionPane.js ===================================== @@ -346,7 +346,7 @@ const gBridgeGrid = {
Services.obs.addObserver(this, TorProviderTopics.BridgeChanged);
- this._grid.classList.add("grid-active"); + this._grid.hidden = false;
this._updateConnectedBridge(); }, @@ -363,7 +363,7 @@ const gBridgeGrid = {
this._forceCloseRowMenus();
- this._grid.classList.remove("grid-active"); + this._grid.hidden = true;
Services.obs.removeObserver(this, TorProviderTopics.BridgeChanged); }, @@ -1023,7 +1023,7 @@ const gBuiltinBridgesArea = {
Services.obs.addObserver(this, TorProviderTopics.BridgeChanged);
- this._area.classList.add("built-in-active"); + this._area.hidden = false;
this._updateBridgeIds(); this._updateConnectedBridge(); @@ -1038,7 +1038,7 @@ const gBuiltinBridgesArea = { } this._active = false;
- this._area.classList.remove("built-in-active"); + this._area.hidden = true;
Services.obs.removeObserver(this, TorProviderTopics.BridgeChanged); }, @@ -1243,11 +1243,19 @@ const gLoxStatus = { */ _detailsArea: null, /** - * The day counter for the next unlock. + * The list items showing the next unlocks. * - * @type {Element?} + * @type {?Object<string, Element>} + */ + _nextUnlockItems: null, + /** + * The day counter headings for the next unlock. + * + * One heading is shown during a search, the other is shown otherwise. + * + * @type {?Element[]} */ - _nextUnlockCounterEl: null, + _nextUnlockCounterEls: null, /** * Shows the number of remaining invites. * @@ -1266,6 +1274,12 @@ const gLoxStatus = { * @type {Element?} */ _unlockAlert: null, + /** + * The list items showing the unlocks. + * + * @type {?Object<string, Element>} + */ + _unlockItems: null, /** * The alert title. * @@ -1296,8 +1310,19 @@ const gLoxStatus = {
this._area = document.getElementById("tor-bridges-lox-status"); this._detailsArea = document.getElementById("tor-bridges-lox-details"); - this._nextUnlockCounterEl = document.getElementById( - "tor-bridges-lox-next-unlock-counter" + this._nextUnlockItems = { + gainBridges: document.getElementById( + "tor-bridges-lox-next-unlock-gain-bridges" + ), + firstInvites: document.getElementById( + "tor-bridges-lox-next-unlock-first-invites" + ), + moreInvites: document.getElementById( + "tor-bridges-lox-next-unlock-more-invites" + ), + }; + this._nextUnlockCounterEls = Array.from( + document.querySelectorAll(".tor-bridges-lox-next-unlock-counter") ); this._remainingInvitesEl = document.getElementById( "tor-bridges-lox-remaining-invites" @@ -1306,6 +1331,15 @@ const gLoxStatus = { "tor-bridges-lox-show-invites-button" ); this._unlockAlert = document.getElementById("tor-bridges-lox-unlock-alert"); + this._unlockItems = { + gainBridges: document.getElementById( + "tor-bridges-lox-unlock-alert-gain-bridges" + ), + newBridges: document.getElementById( + "tor-bridges-lox-unlock-alert-new-bridges" + ), + invites: document.getElementById("tor-bridges-lox-unlock-alert-invites"), + }; this._unlockAlertTitle = document.getElementById( "tor-bridge-unlock-alert-title" ); @@ -1404,6 +1438,7 @@ const gLoxStatus = { return; } this._loxId = loxId; + this._area.hidden = !loxId; // We unset _nextUnlock to ensure the areas no longer use the old value for // the new loxId. this._updateNextUnlock(true); @@ -1518,8 +1553,8 @@ const gLoxStatus = { // Uninitialized or no Lox source. // NOTE: This area may already be hidden by the change in Lox source, // but we clean up for the next non-empty id. - this._area.classList.remove("show-unlock-alert"); - this._area.classList.remove("show-next-unlock"); + this._unlockAlert.hidden = true; + this._detailsArea.hidden = true; return; }
@@ -1529,8 +1564,8 @@ const gLoxStatus = {
const pendingEvents = this._pendingEvents; const showAlert = !!pendingEvents.length; - this._area.classList.toggle("show-unlock-alert", showAlert); - this._area.classList.toggle("show-next-unlock", !showAlert); + this._unlockAlert.hidden = !showAlert; + this._detailsArea.hidden = showAlert;
if (showAlert) { // At level 0 and level 1, we do not have any invites. @@ -1567,6 +1602,7 @@ const gLoxStatus = { blockage = true; } } + let alertTitleId; if (levelUp && !blockage) { alertTitleId = "tor-bridges-lox-upgrade"; @@ -1585,9 +1621,9 @@ const gLoxStatus = { "lox-unlock-upgrade", levelUp && !blockage ); - this._unlockAlert.classList.toggle("lox-unlock-new-bridges", blockage); - this._unlockAlert.classList.toggle("lox-unlock-gain-bridges", bridgeGain); - this._unlockAlert.classList.toggle("lox-unlock-invites", showInvites); + this._unlockItems.gainBridges.hidden = !bridgeGain; + this._unlockItems.newBridges.hidden = !blockage; + this._unlockItems.invites.hidden = !showInvites; } else { // Show next unlock. // Number of days until the next unlock, rounded up. @@ -1598,29 +1634,42 @@ const gLoxStatus = { (24 * 60 * 60 * 1000) ) ); - document.l10n.setAttributes( - this._nextUnlockCounterEl, - "tor-bridges-lox-days-until-unlock", - { numDays } - ); + for (const counterEl of this._nextUnlockCounterEls) { + document.l10n.setAttributes( + counterEl, + "tor-bridges-lox-days-until-unlock", + { numDays } + ); + }
// Gain 2 bridges from level 0 to 1. After that gain invites. - const bridgeGain = this._nextUnlock.nextLevel === 1; - const firstInvites = this._nextUnlock.nextLevel === 2; - const moreInvites = this._nextUnlock.nextLevel > 2; - - this._detailsArea.classList.toggle("lox-next-gain-bridges", bridgeGain); - this._detailsArea.classList.toggle( - "lox-next-first-invites", - firstInvites - ); - this._detailsArea.classList.toggle("lox-next-more-invites", moreInvites); + this._nextUnlockItems.gainBridges.hidden = + this._nextUnlock.nextLevel !== 1; + this._nextUnlockItems.firstInvites.hidden = + this._nextUnlock.nextLevel !== 2; + this._nextUnlockItems.moreInvites.hidden = + this._nextUnlock.nextLevel <= 2; }
if (alertHadFocus && !showAlert) { // Alert has become hidden, move focus back up to the now revealed details // area. - this._nextUnlockCounterEl.focus(); + // NOTE: We have two headings: one shown during a search and one shown + // otherwise. We focus the heading that is currently visible. + // See tor-browser#43320. + // TODO: It might be better if we could use the # named anchor to + // re-orient the screen reader position instead of using tabIndex=-1, but + // about:preferences currently uses the anchor for showing categories + // only. See bugzilla bug 1799153. + if ( + this._nextUnlockCounterEls[0].checkVisibility({ + visibilityProperty: true, + }) + ) { + this._nextUnlockCounterEls[0].focus(); + } else { + this._nextUnlockCounterEls[1].focus(); + } } else if (detailsHadFocus && showAlert) { this._unlockAlertButton.focus(); } @@ -1642,21 +1691,21 @@ const gLoxStatus = { hasInvites = this._haveExistingInvites || !!this._remainingInvites; }
- if (!hasInvites) { - if ( - this._remainingInvitesEl.contains(document.activeElement) || - this._invitesButton.contains(document.activeElement) - ) { - // About to loose focus. - // Unexpected for the lox level to loose all invites. - // Move to the top of the details area, which should be visible if we - // just had focus. - this._nextUnlockCounterEl.focus(); - } + if ( + !hasInvites && + (this._remainingInvitesEl.contains(document.activeElement) || + this._invitesButton.contains(document.activeElement)) + ) { + // About to loose focus. + // Unexpected for the lox level to loose all invites. + // Move to the top of the details area, which should be visible if we + // just had focus. + this._nextUnlockCounterEl.focus(); } // Hide the invite elements if we have no historic invites or a way of // creating new ones. - this._detailsArea.classList.toggle("lox-has-invites", hasInvites); + this._remainingInvitesEl.hidden = !hasInvites; + this._invitesButton.hidden = !hasInvites;
if (hasInvites) { document.l10n.setAttributes( @@ -1691,17 +1740,27 @@ const gBridgeSettings = { */ _bridgesEl: null, /** - * The heading for the bridge settings. + * The area for sharing bridge addresses. * * @type {Element?} */ - _bridgesSettingsHeading: null, + _shareEl: null, + /** + * The two headings for the bridge settings. + * + * One heading is shown during a search, the other is shown otherwise. + * + * @type {?Element[]} + */ + _bridgesSettingsHeadings: null, /** - * The current bridges heading, at the start of the area. + * The two headings for the current bridges, at the start of the area. + * + * One heading is shown during a search, the other is shown otherwise. * * @type {Element?} */ - _currentBridgesHeading: null, + _currentBridgesHeadings: null, /** * The area for showing no bridges. * @@ -1709,17 +1768,25 @@ const gBridgeSettings = { */ _noBridgesEl: null, /** - * The heading element for changing bridges. + * The heading elements for changing bridges. * - * @type {Element?} + * One heading is shown during a search, the other is shown otherwise. + * + * @type {?Element[]} */ - _changeHeadingEl: null, + _changeHeadingEls: null, /** * The button for user to provide a bridge address or share code. * * @type {Element?} */ _userProvideButton: null, + /** + * A map from the bridge source to its corresponding label. + * + * @type {?Map<number, Element>} + */ + _sourceLabels: null,
/** * Initialize the bridge settings. @@ -1727,15 +1794,33 @@ const gBridgeSettings = { init() { gBridgesNotification.init();
- this._bridgesSettingsHeading = document.getElementById( - "torPreferences-bridges-header" + this._bridgesSettingsHeadings = Array.from( + document.querySelectorAll(".tor-bridges-subcategory-heading") ); - this._currentBridgesHeading = document.getElementById( - "tor-bridges-current-heading" + this._currentBridgesHeadings = Array.from( + document.querySelectorAll(".tor-bridges-current-heading") ); this._bridgesEl = document.getElementById("tor-bridges-current"); this._noBridgesEl = document.getElementById("tor-bridges-none"); this._groupEl = document.getElementById("torPreferences-bridges-group"); + + this._sourceLabels = new Map([ + [ + TorBridgeSource.BuiltIn, + document.getElementById("tor-bridges-built-in-label"), + ], + [ + TorBridgeSource.UserProvided, + document.getElementById("tor-bridges-user-label"), + ], + [ + TorBridgeSource.BridgeDB, + document.getElementById("tor-bridges-requested-label"), + ], + [TorBridgeSource.Lox, document.getElementById("tor-bridges-lox-label")], + ]); + this._shareEl = document.getElementById("tor-bridges-share"); + this._toggleButton = document.getElementById("tor-bridges-enabled-toggle"); // Initially disabled whilst TorSettings may not be initialized. this._toggleButton.disabled = true; @@ -1749,8 +1834,8 @@ const gBridgeSettings = { }); });
- this._changeHeadingEl = document.getElementById( - "tor-bridges-change-heading" + this._changeHeadingEls = Array.from( + document.querySelectorAll(".tor-bridges-change-heading") ); this._userProvideButton = document.getElementById( "tor-bridges-open-user-provide-dialog-button" @@ -1855,6 +1940,12 @@ const gBridgeSettings = { * @type {integer?} */ _bridgeSource: null, + /** + * Whether the user is encouraged to share their bridge addresses. + * + * @type {boolean} + */ + _canShare: false,
/** * Update _bridgeSource. @@ -1876,22 +1967,15 @@ const gBridgeSettings = { this._bridgesEl.contains(document.activeElement) || this._noBridgesEl.contains(document.activeElement);
- this._bridgesEl.classList.toggle( - "source-built-in", - bridgeSource === TorBridgeSource.BuiltIn - ); - this._bridgesEl.classList.toggle( - "source-user", - bridgeSource === TorBridgeSource.UserProvided - ); - this._bridgesEl.classList.toggle( - "source-requested", - bridgeSource === TorBridgeSource.BridgeDB - ); - this._bridgesEl.classList.toggle( - "source-lox", - bridgeSource === TorBridgeSource.Lox - ); + for (const [source, labelEl] of this._sourceLabels.entries()) { + labelEl.hidden = source !== bridgeSource; + } + + this._canShare = + bridgeSource === TorBridgeSource.UserProvided || + bridgeSource === TorBridgeSource.BridgeDB; + + this._shareEl.hidden = !this._canShare;
// Force the menu to close whenever the source changes. // NOTE: If the menu had focus then hadFocus will be true, and focus will be @@ -1937,15 +2021,18 @@ const gBridgeSettings = { // Add classes to show or hide the "no bridges" and "Your bridges" sections. // NOTE: Before haveBridges is set, neither class is added, so both sections // and hidden. - this._groupEl.classList.toggle("no-bridges", !haveBridges); - this._groupEl.classList.toggle("have-bridges", haveBridges); + this._groupEl.classList.add("bridges-initialized"); + this._bridgesEl.hidden = !haveBridges; + this._noBridgesEl.hidden = haveBridges;
- document.l10n.setAttributes( - this._changeHeadingEl, - haveBridges - ? "tor-bridges-replace-bridges-heading" - : "tor-bridges-add-bridges-heading" - ); + for (const headingEl of this._changeHeadingEls) { + document.l10n.setAttributes( + headingEl, + haveBridges + ? "tor-bridges-replace-bridges-heading" + : "tor-bridges-add-bridges-heading" + ); + } document.l10n.setAttributes( this._userProvideButton, haveBridges ? "tor-bridges-replace-button" : "tor-bridges-add-new-button" @@ -1964,17 +2051,27 @@ const gBridgeSettings = { }
// Make sure we have the latest value for _haveBridges. - // We also ensure that the _currentBridgesHeading element is visible before + // We also ensure that the _currentBridgesHeadings element is visible before // we focus it. this._updateHaveBridges(); - if (this._haveBridges) { - // Move focus to the start of the area, which is the heading. - // It has tabindex="-1" so should be focusable, even though it is not part - // of the usual tab navigation. - this._currentBridgesHeading.focus(); + + // Move focus to the start of the relevant section, which is a heading. + // They have tabindex="-1" so should be focusable, even though they are not + // part of the usual tab navigation. + // NOTE: We have two headings: one shown during a search and one shown + // otherwise. We focus the heading that is currently visible. + // See tor-browser#43320. + // TODO: It might be better if we could use the # named anchor to + // re-orient the screen reader position instead of using tabIndex=-1, but + // about:preferences currently uses the anchor for showing categories + // only. See bugzilla bug 1799153. + const focusHeadings = this._haveBridges + ? this._currentBridgesHeadings // The heading above the new bridges. + : this._bridgesSettingsHeadings; // The top of the bridge settings. + if (focusHeadings[0].checkVisibility({ visibilityProperty: true })) { + focusHeadings[0].focus(); } else { - // Move focus to the top of the bridge settings. - this._bridgesSettingsHeading.focus(); + focusHeadings[1].focus(); } },
@@ -2126,10 +2223,7 @@ const gBridgeSettings = { });
this._bridgesMenu.addEventListener("showing", () => { - const canShare = - this._bridgeSource === TorBridgeSource.UserProvided || - this._bridgeSource === TorBridgeSource.BridgeDB; - qrItem.hidden = !canShare || !this._canQRBridges; + qrItem.hidden = !this._canShare || !this._canQRBridges; editItem.hidden = this._bridgeSource !== TorBridgeSource.UserProvided; });
===================================== browser/components/torpreferences/content/connectionPane.xhtml ===================================== @@ -97,8 +97,8 @@ <!-- Bridges --> <hbox class="subcategory" data-category="paneConnection" hidden="true"> <html:h1 - id="torPreferences-bridges-header" - class="tor-focusable-heading" + id="tor-bridges-subcategory-heading-non-search" + class="tor-bridges-subcategory-heading tor-focusable-heading" tabindex="-1" data-l10n-id="tor-bridges-heading" ></html:h1> @@ -107,7 +107,22 @@ id="torPreferences-bridges-group" data-category="paneConnection" hidden="true" + aria-labelledby="tor-bridges-subcategory-heading-non-search"
+ <!-- Add a search-header that only appears in search results as a substitute + - for the hidden h1 element. See tor-browser#43320. + - NOTE: Usually the first xul:label will act as the accessible name for + - a xul:groubbox element *if* it is not hidden. Since the search-header + - is sometimes hidden we need an explicit aria-labelledby anyway. + - However, we keep the wrapper xul:label for styling consistency with the + - other settings. --> + <label class="search-header" hidden="true"> + <html:h2 + class="tor-bridges-subcategory-heading tor-focusable-heading" + tabindex="-1" + data-l10n-id="tor-bridges-heading" + ></html:h2> + </label> <description class="description-deemphasized" flex="1"> <html:span data-l10n-id="tor-bridges-overview"></html:span> <label @@ -164,8 +179,13 @@ - See https://github.com/WICG/proposals/issues/112 --> <!-- NOTE: This area is hidden by default, and is only shown temporarily - - when a notification is added. --> - <html:div id="tor-bridges-update-area" hidden="hidden"> + - when a notification is added. It should never match with search + - queries. --> + <html:div + id="tor-bridges-update-area" + hidden="hidden" + data-hidden-from-search="true" + > <!-- NOTE: This first span's text content will *not* be read out as part - of the notification because it does not have an aria-live - attribute. Instead it is just here to give context to the following @@ -182,18 +202,33 @@ aria-live="polite" ></html:span> </html:div> - <html:div id="tor-bridges-none"> + <html:div id="tor-bridges-none" hidden="hidden"> <html:img id="tor-bridges-none-icon" alt="" /> <html:div data-l10n-id="tor-bridges-none-added"></html:div> </html:div> - <html:div id="tor-bridges-current"> + <html:div id="tor-bridges-current" hidden="hidden"> <html:div id="tor-bridges-current-header-bar"> <html:h2 - id="tor-bridges-current-heading" - class="tor-focusable-heading" + id="tor-bridges-current-heading-non-search" + class="tor-bridges-current-heading tor-focusable-heading tor-small-heading tor-non-search-heading" tabindex="-1" data-l10n-id="tor-bridges-your-bridges" ></html:h2> + <!-- Add a duplicate search heading. + - In a search result the heading h1.tor-bridges-subcategory-heading + - will be hidden, and the h2.tor-bridges-subcategory-heading + - will be visible. + - As such, all headings below h2.tor-bridges-subcategory-heading also + - need to shift one lower in heading level to preseve the correct + - hierarchy of - heading levels. + - In this case we hide the <h2> heading and show the duplicate <h3> + - heading instead. + - See tor-browser#43320. --> + <html:h3 + class="tor-bridges-current-heading tor-focusable-heading tor-small-heading tor-search-heading" + tabindex="-1" + data-l10n-id="tor-bridges-your-bridges" + ></html:h3> <html:span id="tor-bridges-user-label" class="tor-bridges-source-label" @@ -221,7 +256,10 @@ aria-controls="tor-bridges-all-options-menu" data-l10n-id="tor-bridges-options-button" ></html:button> - <html:panel-list id="tor-bridges-all-options-menu"> + <html:panel-list + id="tor-bridges-all-options-menu" + data-hidden-from-search="true" + > <html:panel-item id="tor-bridges-options-qr-all-menu-item" data-l10n-attrs="accesskey" @@ -244,7 +282,7 @@ ></html:panel-item> </html:panel-list> </html:div> - <html:div id="tor-bridges-built-in-display"> + <html:div id="tor-bridges-built-in-display" hidden="hidden"> <html:div id="tor-bridges-built-in-type-name"></html:div> <html:div id="tor-bridges-built-in-connected" @@ -261,7 +299,8 @@ id="tor-bridges-grid-display" class="tor-bridges-grid" role="grid" - aria-labelledby="tor-bridges-current-heading" + aria-labelledby="tor-bridges-current-heading-non-search" + hidden="hidden" ></html:div> <html:template id="tor-bridges-grid-row-template"> <html:div class="tor-bridges-grid-row" role="row"> @@ -297,7 +336,10 @@ aria-expanded="false" data-l10n-id="tor-bridges-individual-bridge-options-button" ></html:button> - <html:panel-list class="tor-bridges-individual-options-menu"> + <html:panel-list + class="tor-bridges-individual-options-menu" + data-hidden-from-search="true" + > <html:panel-item class="tor-bridges-options-qr-one-menu-item" data-l10n-attrs="accesskey" @@ -318,11 +360,20 @@ </html:span> </html:div> </html:template> - <html:div id="tor-bridges-share" class="tor-bridges-details-box"> + <html:div + id="tor-bridges-share" + class="tor-bridges-details-box" + hidden="hidden" + > <html:h3 - id="tor-bridges-share-heading" + class="tor-bridges-share-heading tor-small-heading tor-non-search-heading" data-l10n-id="tor-bridges-share-heading" ></html:h3> + <!-- Add a duplicate search heading. See tor-browser#43320. --> + <html:h4 + class="tor-bridges-share-heading tor-small-heading tor-search-heading" + data-l10n-id="tor-bridges-share-heading" + ></html:h4> <html:span id="tor-bridges-share-description" data-l10n-id="tor-bridges-share-description" @@ -336,68 +387,84 @@ data-l10n-id="tor-bridges-qr-addresses-button" ></html:button> </html:div> - <html:div id="tor-bridges-lox-status"> + <html:div id="tor-bridges-lox-status" hidden="hidden"> <html:div data-l10n-id="tor-bridges-lox-description"></html:div> <html:div id="tor-bridges-lox-details" class="tor-bridges-details-box tor-bridges-lox-box" + hidden="hidden" > <html:img alt="" class="tor-bridges-lox-image-inner" /> <html:img alt="" class="tor-bridges-lox-image-outer" /> <html:h3 - id="tor-bridges-lox-next-unlock-counter" - class="tor-bridges-lox-intro tor-focusable-heading" + class="tor-bridges-lox-next-unlock-counter tor-small-heading tor-bridges-lox-intro tor-focusable-heading tor-non-search-heading" tabindex="-1" ></html:h3> + <!-- Add a duplicate search heading. See tor-browser#43320. --> + <html:h4 + class="tor-bridges-lox-next-unlock-counter tor-small-heading tor-bridges-lox-intro tor-focusable-heading tor-search-heading" + tabindex="-1" + ></html:h4> <html:ul class="tor-bridges-lox-list"> <html:li id="tor-bridges-lox-next-unlock-gain-bridges" class="tor-bridges-lox-list-item tor-bridges-lox-list-item-bridge" data-l10n-id="tor-bridges-lox-unlock-two-bridges" + hidden="hidden" ></html:li> <html:li id="tor-bridges-lox-next-unlock-first-invites" class="tor-bridges-lox-list-item tor-bridges-lox-list-item-invite" data-l10n-id="tor-bridges-lox-unlock-first-invites" + hidden="hidden" ></html:li> <html:li id="tor-bridges-lox-next-unlock-more-invites" class="tor-bridges-lox-list-item tor-bridges-lox-list-item-invite" data-l10n-id="tor-bridges-lox-unlock-more-invites" + hidden="hidden" ></html:li> </html:ul> - <html:div id="tor-bridges-lox-remaining-invites"></html:div> + <html:div + id="tor-bridges-lox-remaining-invites" + hidden="hidden" + ></html:div> <html:button id="tor-bridges-lox-show-invites-button" class="tor-bridges-lox-button" data-l10n-id="tor-bridges-lox-show-invites-button" + hidden="hidden" ></html:button> </html:div> <html:div id="tor-bridges-lox-unlock-alert" role="alert" class="tor-bridges-details-box tor-bridges-lox-box" + hidden="hidden" > <html:img alt="" class="tor-bridges-lox-image-inner" /> <html:img alt="" class="tor-bridges-lox-image-outer" /> <html:div id="tor-bridge-unlock-alert-title" - class="tor-bridges-lox-intro" + class="tor-small-heading tor-bridges-lox-intro" ></html:div> <html:ul class="tor-bridges-lox-list"> <html:li id="tor-bridges-lox-unlock-alert-gain-bridges" class="tor-bridges-lox-list-item tor-bridges-lox-list-item-bridge" data-l10n-id="tor-bridges-lox-gained-two-bridges" + hidden="hidden" ></html:li> <html:li id="tor-bridges-lox-unlock-alert-new-bridges" class="tor-bridges-lox-list-item tor-bridges-lox-list-item-bridge" data-l10n-id="tor-bridges-lox-new-bridges" + hidden="hidden" ></html:li> <html:li id="tor-bridges-lox-unlock-alert-invites" class="tor-bridges-lox-list-item tor-bridges-lox-list-item-invite" + hidden="hidden" ></html:li> </html:ul> <html:button @@ -408,7 +475,14 @@ </html:div> </html:div> </html:div> - <html:h2 id="tor-bridges-change-heading"></html:h2> + <html:h2 + class="tor-bridges-change-heading tor-medium-heading tor-non-search-heading" + ></html:h2> + <!-- Add a duplicate search heading. See tor-browser#43320. + - This has the same content, but a smaller font. --> + <html:h3 + class="tor-bridges-change-heading tor-small-heading tor-search-heading" + ></html:h3> <hbox align="center"> <description flex="1" @@ -428,9 +502,15 @@ ></html:button> </hbox> <html:h3 - id="tor-bridges-provider-heading" + class="tor-bridges-provider-heading tor-medium-heading tor-non-search-heading" data-l10n-id="tor-bridges-find-more-heading" ></html:h3> + <!-- Add a duplicate search heading. See tor-browser#43320. + - This has the same content, but a smaller font. --> + <html:h4 + class="tor-bridges-provider-heading tor-small-heading tor-search-heading" + data-l10n-id="tor-bridges-find-more-heading" + ></html:h4> <description data-l10n-id="tor-bridges-find-more-description" class="description-deemphasized" @@ -511,15 +591,29 @@
<!-- Advanced --> <hbox class="subcategory" data-category="paneConnection" hidden="true"> - <html:h1 data-l10n-id="tor-advanced-settings-heading"></html:h1> + <html:h1 + id="tor-advanced-subcategory-heading-non-search" + data-l10n-id="tor-advanced-settings-heading" + ></html:h1> </hbox> <groupbox id="torPreferences-advanced-group" data-category="paneConnection" hidden="true" + aria-labelledby="tor-advanced-subcategory-heading-non-search"
+ <!-- Add a search-header that only appears in search results as a substitute + - for the hidden h1 element. See tor-browser#43320. + - NOTE: Usually the first xul:label will act as the accessible name for + - a xul:groubbox element *if* it is not hidden. Since the search-header + - is sometimes hidden we need an explicit aria-labelledby anyway. + - However, we keep the wrapper xul:label for styling consistency with the + - other settings. --> + <label class="search-header" hidden="true"> + <html:h2 data-l10n-id="tor-advanced-settings-heading"></html:h2> + </label> <hbox align="center"> - <label data-l10n-id="tor-advanced-settings-description" flex="1" /> + <description data-l10n-id="tor-advanced-settings-description" flex="1" /> <html:button id="torPreferences-advanced-button" class="accessory-button" @@ -527,7 +621,7 @@ ></html:button> </hbox> <hbox align="center" data-subcategory="viewlogs"> - <label data-l10n-id="tor-view-log-description" flex="1" /> + <description data-l10n-id="tor-view-log-description" flex="1" /> <html:button id="torPreferences-buttonTorLogs" class="accessory-button"
===================================== browser/components/torpreferences/content/torPreferences.css ===================================== @@ -118,6 +118,48 @@ button.spoof-button-disabled {
/* Bridge settings */
+.tor-medium-heading { + /* Same font size as mozilla preferences h2. */ + font-size: var(--font-size-large); + font-weight: var(--font-weight-bold); + margin: 0; +} + +.tor-small-heading { + font-size: inherit; + font-weight: var(--font-weight-bold); + margin: 0; +} + +/* Hide the tor-search-heading elements when the group's search header is + * hidden. These only appear in search results. + * See tor-browser#43320. + * NOTE: `.search-header[hidden] ~ :is(* .tor-search-heading)` will not match + * (possibly because the `~` selector is unsure how to integrate with the + * non-compound `* .tor-search-heading` selector). So we need to duplicate the + * `.search-header[hidden]` rule. */ +#torPreferences-bridges-group :is( + .search-header[hidden] ~ * .tor-search-heading, + .search-header[hidden] ~ .tor-search-heading +) { + display: none; +} + +/* Hide the tor-non-search-heading elements when the group's search header is + * not hidden. These only appear outside of search results. + * See tor-browser#43320. */ +#torPreferences-bridges-group :is( + .search-header:not([hidden]) ~ * .tor-non-search-heading, + .search-header:not([hidden]) ~ .tor-non-search-heading +) { + display: none; +} + +.tor-focusable-heading { + /* Do not occupy more horizontal space than necessary. */ + width: fit-content; +} + .tor-focusable-heading:focus-visible { outline-offset: var(--in-content-focus-outline-offset); } @@ -182,53 +224,18 @@ button.spoof-button-disabled { clip-path: inset(50%); }
-#torPreferences-bridges-group:not(.have-bridges, .no-bridges) { +#torPreferences-bridges-group:not(.bridges-initialized) { /* Hide bridge settings whilst not initialized. */ display: none; }
-#torPreferences-bridges-group:not(.have-bridges) #tor-bridges-current { - display: none; -} - -#torPreferences-bridges-group:not(.no-bridges) #tor-bridges-none { - display: none; -} - -#tor-bridges-current:not(.source-built-in) #tor-bridges-built-in-label { - display: none; -} - -#tor-bridges-current:not(.source-user) #tor-bridges-user-label { - display: none; -} - -#tor-bridges-current:not(.source-requested) #tor-bridges-requested-label { - display: none; -} - -#tor-bridges-current:not(.source-lox) #tor-bridges-lox-label { - display: none; -} - -#tor-bridges-current:not( - .source-user, - .source-requested -) #tor-bridges-share { - display: none; -} - -#tor-bridges-current:not(.source-lox) #tor-bridges-lox-status { - display: none; -} - #tor-bridges-none, #tor-bridges-current { margin-inline: 0; margin-block: 32px; }
-#tor-bridges-none { +#tor-bridges-none:not([hidden]) { display: grid; justify-items: center; text-align: center; @@ -265,9 +272,7 @@ button.spoof-button-disabled { white-space: nowrap; }
-#tor-bridges-current-heading { - margin: 0; - font-size: inherit; +.tor-bridges-current-heading { grid-area: heading; }
@@ -282,7 +287,7 @@ button.spoof-button-disabled { grid-area: button; }
-#tor-bridges-lox-label { +#tor-bridges-lox-label:not([hidden]) { display: flex; align-items: center; gap: 6px; @@ -317,7 +322,7 @@ button.spoof-button-disabled { fill: currentColor; }
-#tor-bridges-built-in-display { +#tor-bridges-built-in-display:not([hidden]) { display: grid; grid-template: "type status" min-content @@ -327,10 +332,6 @@ button.spoof-button-disabled { margin-block-end: 16px; }
-#tor-bridges-built-in-display:not(.built-in-active) { - display: none; -} - #tor-bridges-built-in-type-name { font-weight: 700; grid-area: type; @@ -345,7 +346,7 @@ button.spoof-button-disabled { grid-area: description; }
-.tor-bridges-grid { +.tor-bridges-grid:not([hidden]) { display: grid; grid-template-columns: max-content repeat(4, max-content) 1fr; --tor-bridges-grid-column-gap: 8px; @@ -355,10 +356,6 @@ button.spoof-button-disabled { align-items: stretch; }
-#tor-bridges-grid-display:not(.grid-active) { - display: none; -} - .tor-bridges-grid-row { /* We want each row to act as a row of three items in the * .tor-bridges-grid grid layout. @@ -483,7 +480,7 @@ button.spoof-button-disabled { padding: 16px; }
-#tor-bridges-share { +#tor-bridges-share:not([hidden]) { display: grid; grid-template: "heading heading heading" min-content @@ -496,12 +493,9 @@ button.spoof-button-disabled { align-items: center; }
-#tor-bridges-share-heading { +.tor-bridges-share-heading { grid-area: heading; - font-size: inherit; - margin: 0; margin-block-end: 4px; - font-weight: 700; }
#tor-bridges-share-description { @@ -538,15 +532,7 @@ button.spoof-button-disabled { margin-block-start: 8px; }
-#tor-bridges-lox-status:not(.show-next-unlock) #tor-bridges-lox-details { - display: none; -} - -#tor-bridges-lox-status:not(.show-unlock-alert) #tor-bridges-lox-unlock-alert { - display: none; -} - -.tor-bridges-lox-box { +.tor-bridges-lox-box:not([hidden]) { display: grid; grid-template: "image intro intro" min-content @@ -601,11 +587,8 @@ button.spoof-button-disabled {
.tor-bridges-lox-intro { grid-area: intro; - font-weight: 700; - font-size: inherit; align-self: center; justify-self: start; - margin: 0; }
.tor-bridges-lox-list { @@ -619,11 +602,11 @@ button.spoof-button-disabled { gap: 8px 0; }
-.tor-bridges-lox-list-item { +.tor-bridges-lox-list-item:not([hidden]) { display: contents; }
-.tor-bridges-lox-list-item::before { +.tor-bridges-lox-list-item:not([hidden])::before { /* We use ::before rather than list-style-image to have more control. */ box-sizing: content-box; width: 18px; @@ -655,52 +638,19 @@ button.spoof-button-disabled { stroke: var(--in-content-success-icon-color); }
-#tor-bridges-lox-details:not(.lox-next-gain-bridges) #tor-bridges-lox-next-unlock-gain-bridges { - display: none; -} - -#tor-bridges-lox-details:not(.lox-next-first-invites) #tor-bridges-lox-next-unlock-first-invites { - display: none; -} - -#tor-bridges-lox-details:not(.lox-next-more-invites) #tor-bridges-lox-next-unlock-more-invites { - display: none; -} - - -#tor-bridges-lox-unlock-alert:not(.lox-unlock-gain-bridges) #tor-bridges-lox-unlock-alert-gain-bridges { - display: none; -} - -#tor-bridges-lox-unlock-alert:not(.lox-unlock-new-bridges) #tor-bridges-lox-unlock-alert-new-bridges { - display: none; -} - -#tor-bridges-lox-unlock-alert:not(.lox-unlock-invites) #tor-bridges-lox-unlock-alert-invites { - display: none; -} - #tor-bridges-lox-remaining-invites { grid-area: invites; justify-self: end; align-self: center; }
-#tor-bridges-lox-details:not(.lox-has-invites) :is( - #tor-bridges-lox-remaining-invites, - #tor-bridges-lox-show-invites-button -) { - display: none; -} - .tor-bridges-lox-button { grid-area: button; margin: 0; align-self: center; }
-#tor-bridges-provider-heading { - font-size: 1.14em; +.tor-bridges-provider-heading { margin-block: 48px 8px; }
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/87cdcd5...