morgan pushed to branch tor-browser-128.4.0esr-14.5-1 at The Tor Project / Applications / Tor Browser
Commits: a83dddb9 by Henry Wilkes at 2024-11-13T19:54:08+00:00 fixup! Bug 30237: Add v3 onion services client authentication prompt
Bug 43263: Add some alert semantics for onion site keys.
Also use `spoof-button-disabled` to better manage focus for temporarily disabled buttons.
- - - - - 2073c1fa by Henry Wilkes at 2024-11-13T19:54:08+00:00 fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
Bug 43263: Update `spoof-button-disabled` buttons to use tabIndex=-1.
Also remove aria-live="assertive" from role="alert" since it should already be implied by default.
- - - - -
10 changed files:
- browser/components/onionservices/content/authPopup.inc.xhtml - browser/components/onionservices/content/authPreferences.css - browser/components/onionservices/content/authPrompt.js - browser/components/onionservices/content/savedKeysDialog.js - browser/components/onionservices/content/savedKeysDialog.xhtml - browser/components/torpreferences/content/connectionPane.js - browser/components/torpreferences/content/loxInviteDialog.js - browser/components/torpreferences/content/provideBridgeDialog.js - browser/components/torpreferences/content/provideBridgeDialog.xhtml - browser/components/torpreferences/content/torPreferences.css
Changes:
===================================== browser/components/onionservices/content/authPopup.inc.xhtml ===================================== @@ -11,12 +11,27 @@ data-l10n-id="onion-site-authentication-prompt-learn-more" /> html:div + <!-- NOTE: Orca 46.2 will not say "invalid" for "type=password". See + - https://gitlab.gnome.org/GNOME/orca/-/issues/550 + - Moreover, it will ignore the aria-errormessage relation when we are + - not in a document context. See related bugzilla bug 1820765. --> <html:input id="tor-clientauth-notification-key" type="password" data-l10n-id="onion-site-authentication-prompt-key-input" + aria-errormessage="tor-clientauth-warning" /> - <html:div id="tor-clientauth-warning"></html:div> + <html:div + id="tor-clientauth-warning" + role="alert" + aria-labelledby="tor-clientauth-warning-text" + > + <!-- NOTE: Orca 46.2 treats this notification as non-document context. + - As such it seems to only read out the alert content if it contains + - a <xul:label>, <html:label> or if it has an accessible name. + - We use aria-labelledby here. --> + <html:span id="tor-clientauth-warning-text"></html:span> + </html:div> <checkbox id="tor-clientauth-persistkey-checkbox" data-l10n-id="onion-site-authentication-prompt-remember-checkbox"
===================================== browser/components/onionservices/content/authPreferences.css ===================================== @@ -23,3 +23,15 @@ -moz-context-properties: fill; fill: var(--in-content-warning-icon-color); } + +/* Make a button appear disabled, whilst still allowing it to keep keyboard + * focus. + * Duplicate of rule in torPreferences.css. + * TODO: Replace with moz-button when it handles this for us. See + * tor-browser#43275. */ +button.spoof-button-disabled { + /* Borrow the :disabled rule from common-shared.css */ + opacity: 0.4; + /* Also ensure it does not get hover or active styling. */ + pointer-events: none; +}
===================================== browser/components/onionservices/content/authPrompt.js ===================================== @@ -32,6 +32,8 @@ var OnionAuthPrompt = {
/** * The currently shown details in the prompt. + * + * @type {?PromptDetails} */ _shownDetails: null,
@@ -264,16 +266,18 @@ var OnionAuthPrompt = { */ _showWarning(warningMessageId) { this._logger.debug(`Showing warning: ${warningMessageId}`); + if (warningMessageId) { - document.l10n.setAttributes(this._warningEl, warningMessageId); + document.l10n.setAttributes(this._warningTextEl, warningMessageId); this._warningEl.removeAttribute("hidden"); this._keyInput.classList.add("invalid"); + this._keyInput.setAttribute("aria-invalid", "true"); } else { - // Clean up. - this._warningEl.removeAttribute("data-l10n-id"); - this._warningEl.textContent = ""; + this._warningTextEl.removeAttribute("data-l10n-id"); + this._warningTextEl.textContent = ""; this._warningEl.setAttribute("hidden", "true"); this._keyInput.classList.remove("invalid"); + this._keyInput.removeAttribute("aria-invalid"); } },
@@ -344,6 +348,9 @@ var OnionAuthPrompt = { "tor-clientauth-persistkey-checkbox" ); this._warningEl = document.getElementById("tor-clientauth-warning"); + this._warningTextEl = document.getElementById( + "tor-clientauth-warning-text" + ); this._descriptionEl = document.getElementById( "tor-clientauth-notification-desc" );
===================================== browser/components/onionservices/content/savedKeysDialog.js ===================================== @@ -14,6 +14,20 @@ var gOnionServicesSavedKeysDialog = { return this._busyCount > 0; },
+ /** + * Whether the "remove selected" button is disabled. + * + * @type {boolean} + */ + _removeSelectedDisabled: true, + + /** + * Whether the "remove all" button is disabled. + * + * @type {boolean} + */ + _removeAllDisabled: true, + async _deleteSelectedKeys() { this._showError(null); this._withBusy(async () => { @@ -36,6 +50,15 @@ var gOnionServicesSavedKeysDialog = { for (let i = indexesToDelete.length - 1; i >= 0; --i) { await this._deleteOneKey(provider, indexesToDelete[i]); } + // If successful and the user focus is still on the buttons move focus + // to the table with the updated state. We do this before calling + // _updateButtonState and potentially making the buttons disabled. + if ( + this._removeButton.contains(document.activeElement) || + this._removeAllButton.contains(document.activeElement) + ) { + this._tree.focus(); + } } catch (e) { console.error("Removing a saved key failed", e); this._showError( @@ -51,10 +74,37 @@ var gOnionServicesSavedKeysDialog = { await this._deleteSelectedKeys(); },
+ /** + * Show the given button as being disabled or enabled. + * + * @param {Button} button - The button to change. + * @param {boolean} disable - Whether to show the button as disabled or + * enabled. + */ + _disableButton(button, disable) { + // If we are disabled we show the button as disabled, and we also remove it + // from the tab focus cycle using `tabIndex = -1`. + // This is similar to using the `disabled` attribute, except that + // `tabIndex = -1` still allows the button to be focusable. I.e. not part of + // the focus cycle but can *keep* existing focus when the button becomes + // disabled to avoid loosing focus to the top of the dialog. + // TODO: Replace with moz-button when it handles this for us. See + // tor-browser#43275. + button.classList.toggle("spoof-button-disabled", disable); + button.tabIndex = disable ? -1 : 0; + if (disable) { + this._removeButton.setAttribute("aria-disabled", "true"); + } else { + this._removeButton.removeAttribute("aria-disabled"); + } + }, + _updateButtonsState() { const haveSelection = this._tree.view.selection.getRangeCount() > 0; - this._removeButton.disabled = this._isBusy || !haveSelection; - this._removeAllButton.disabled = this._isBusy || this.rowCount === 0; + this._removeSelectedDisabled = this._isBusy || !haveSelection; + this._removeAllDisabled = this._isBusy || this.rowCount === 0; + this._disableButton(this._removeButton, this._removeSelectedDisabled); + this._disableButton(this._removeAllButton, this._removeAllDisabled); },
// Private functions. @@ -79,12 +129,18 @@ var gOnionServicesSavedKeysDialog = { "onionservices-savedkeys-remove" ); this._removeButton.addEventListener("click", () => { + if (this._removeSelectedDisabled) { + return; + } this._deleteSelectedKeys(); }); this._removeAllButton = document.getElementById( "onionservices-savedkeys-removeall" ); this._removeAllButton.addEventListener("click", () => { + if (this._removeAllDisabled) { + return; + } this._deleteAllKeys(); });
===================================== browser/components/onionservices/content/savedKeysDialog.xhtml ===================================== @@ -49,7 +49,11 @@ </treecols> <treechildren /> </tree> - <hbox id="onionservices-savedkeys-errorContainer" align="center"> + <hbox + id="onionservices-savedkeys-errorContainer" + align="center" + role="alert" + > <image id="onionservices-savedkeys-errorIcon" /> <description id="onionservices-savedkeys-errorMessage" flex="1" /> </hbox> @@ -57,7 +61,6 @@ <hbox id="onionservices-savedkeys-buttons"> <html:button id="onionservices-savedkeys-remove" - disabled="true" data-l10n-id="onion-site-saved-keys-dialog-remove-button" ></html:button> <html:button
===================================== browser/components/torpreferences/content/connectionPane.js ===================================== @@ -2354,8 +2354,11 @@ const gNetworkStatus = { this._internetTestDisabled = true; // We use "aria-disabled" rather than the "disabled" attribute so that the // button can remain focusable during the test. + // TODO: Replace with moz-button when it handles this for us. See + // tor-browser#43275. this._internetTestButton.setAttribute("aria-disabled", "true"); this._internetTestButton.classList.add("spoof-button-disabled"); + this._internetTestButton.tabIndex = -1; try { this._updateInternetStatus("testing"); const mrpc = new MoatRPC(); @@ -2376,6 +2379,7 @@ const gNetworkStatus = { } finally { this._internetTestButton.removeAttribute("aria-disabled"); this._internetTestButton.classList.remove("spoof-button-disabled"); + this._internetTestButton.tabIndex = 0; this._internetTestDisabled = false; } },
===================================== browser/components/torpreferences/content/loxInviteDialog.js ===================================== @@ -255,15 +255,11 @@ const gLoxInvites = { // When generating we use "aria-disabled" rather than the "disabled" // attribute so that the button can remain focusable whilst we generate // invites. - // NOTE: When we generate the invite the focus will move to the invite list, - // so it should be safe to make the button non-focusable in this case. - const spoofDisabled = this._generating; - this._generateButton.disabled = disabled && !spoofDisabled; - this._generateButton.classList.toggle( - "spoof-button-disabled", - spoofDisabled - ); - if (spoofDisabled) { + // TODO: Replace with moz-button when it handles this for us. See + // tor-browser#43275. + this._generateButton.classList.toggle("spoof-button-disabled", disabled); + this._generateButton.tabIndex = disabled ? -1 : 0; + if (disabled) { this._generateButton.setAttribute("aria-disabled", "true"); } else { this._generateButton.removeAttribute("aria-disabled");
===================================== browser/components/torpreferences/content/provideBridgeDialog.js ===================================== @@ -215,7 +215,10 @@ const gProvideBridgeDialog = { this._acceptDisabled = disabled; // Spoof the button to look and act as if it is disabled, but still allow // keyboard focus so the user can sit on this button whilst we are loading. + // TODO: Replace with moz-button when it handles this for us. See + // tor-browser#43275. this._acceptButton.classList.toggle("spoof-button-disabled", disabled); + this._acceptButton.tabIndex = disabled ? -1 : 0; if (disabled) { this._acceptButton.setAttribute("aria-disabled", "true"); } else {
===================================== browser/components/torpreferences/content/provideBridgeDialog.xhtml ===================================== @@ -55,7 +55,6 @@ <html:span id="user-provide-bridge-error-message" role="alert" - aria-live="assertive" ></html:span> <img id="user-provide-bridge-loading-icon"
===================================== browser/components/torpreferences/content/torPreferences.css ===================================== @@ -6,7 +6,9 @@ }
/* Make a button appear disabled, whilst still allowing it to keep keyboard - * focus. */ + * focus. + * TODO: Replace with moz-button when it handles this for us. See + * tor-browser#43275. */ button.spoof-button-disabled { /* Borrow the :disabled rule from common-shared.css */ opacity: 0.4;
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/b66037f...