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
-
2073c1fa
by Henry Wilkes at 2024-11-13T19:54:08+00:00
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:
| ... | ... | @@ -11,12 +11,27 @@ |
| 11 | 11 | data-l10n-id="onion-site-authentication-prompt-learn-more"
|
| 12 | 12 | />
|
| 13 | 13 | <html:div>
|
| 14 | + <!-- NOTE: Orca 46.2 will not say "invalid" for "type=password". See
|
|
| 15 | + - https://gitlab.gnome.org/GNOME/orca/-/issues/550
|
|
| 16 | + - Moreover, it will ignore the aria-errormessage relation when we are
|
|
| 17 | + - not in a document context. See related bugzilla bug 1820765. -->
|
|
| 14 | 18 | <html:input
|
| 15 | 19 | id="tor-clientauth-notification-key"
|
| 16 | 20 | type="password"
|
| 17 | 21 | data-l10n-id="onion-site-authentication-prompt-key-input"
|
| 22 | + aria-errormessage="tor-clientauth-warning"
|
|
| 18 | 23 | />
|
| 19 | - <html:div id="tor-clientauth-warning"></html:div>
|
|
| 24 | + <html:div
|
|
| 25 | + id="tor-clientauth-warning"
|
|
| 26 | + role="alert"
|
|
| 27 | + aria-labelledby="tor-clientauth-warning-text"
|
|
| 28 | + >
|
|
| 29 | + <!-- NOTE: Orca 46.2 treats this notification as non-document context.
|
|
| 30 | + - As such it seems to only read out the alert content if it contains
|
|
| 31 | + - a <xul:label>, <html:label> or if it has an accessible name.
|
|
| 32 | + - We use aria-labelledby here. -->
|
|
| 33 | + <html:span id="tor-clientauth-warning-text"></html:span>
|
|
| 34 | + </html:div>
|
|
| 20 | 35 | <checkbox
|
| 21 | 36 | id="tor-clientauth-persistkey-checkbox"
|
| 22 | 37 | data-l10n-id="onion-site-authentication-prompt-remember-checkbox"
|
| ... | ... | @@ -23,3 +23,15 @@ |
| 23 | 23 | -moz-context-properties: fill;
|
| 24 | 24 | fill: var(--in-content-warning-icon-color);
|
| 25 | 25 | }
|
| 26 | + |
|
| 27 | +/* Make a button appear disabled, whilst still allowing it to keep keyboard
|
|
| 28 | + * focus.
|
|
| 29 | + * Duplicate of rule in torPreferences.css.
|
|
| 30 | + * TODO: Replace with moz-button when it handles this for us. See
|
|
| 31 | + * tor-browser#43275. */
|
|
| 32 | +button.spoof-button-disabled {
|
|
| 33 | + /* Borrow the :disabled rule from common-shared.css */
|
|
| 34 | + opacity: 0.4;
|
|
| 35 | + /* Also ensure it does not get hover or active styling. */
|
|
| 36 | + pointer-events: none;
|
|
| 37 | +} |
| ... | ... | @@ -32,6 +32,8 @@ var OnionAuthPrompt = { |
| 32 | 32 | |
| 33 | 33 | /**
|
| 34 | 34 | * The currently shown details in the prompt.
|
| 35 | + *
|
|
| 36 | + * @type {?PromptDetails}
|
|
| 35 | 37 | */
|
| 36 | 38 | _shownDetails: null,
|
| 37 | 39 | |
| ... | ... | @@ -264,16 +266,18 @@ var OnionAuthPrompt = { |
| 264 | 266 | */
|
| 265 | 267 | _showWarning(warningMessageId) {
|
| 266 | 268 | this._logger.debug(`Showing warning: ${warningMessageId}`);
|
| 269 | + |
|
| 267 | 270 | if (warningMessageId) {
|
| 268 | - document.l10n.setAttributes(this._warningEl, warningMessageId);
|
|
| 271 | + document.l10n.setAttributes(this._warningTextEl, warningMessageId);
|
|
| 269 | 272 | this._warningEl.removeAttribute("hidden");
|
| 270 | 273 | this._keyInput.classList.add("invalid");
|
| 274 | + this._keyInput.setAttribute("aria-invalid", "true");
|
|
| 271 | 275 | } else {
|
| 272 | - // Clean up.
|
|
| 273 | - this._warningEl.removeAttribute("data-l10n-id");
|
|
| 274 | - this._warningEl.textContent = "";
|
|
| 276 | + this._warningTextEl.removeAttribute("data-l10n-id");
|
|
| 277 | + this._warningTextEl.textContent = "";
|
|
| 275 | 278 | this._warningEl.setAttribute("hidden", "true");
|
| 276 | 279 | this._keyInput.classList.remove("invalid");
|
| 280 | + this._keyInput.removeAttribute("aria-invalid");
|
|
| 277 | 281 | }
|
| 278 | 282 | },
|
| 279 | 283 | |
| ... | ... | @@ -344,6 +348,9 @@ var OnionAuthPrompt = { |
| 344 | 348 | "tor-clientauth-persistkey-checkbox"
|
| 345 | 349 | );
|
| 346 | 350 | this._warningEl = document.getElementById("tor-clientauth-warning");
|
| 351 | + this._warningTextEl = document.getElementById(
|
|
| 352 | + "tor-clientauth-warning-text"
|
|
| 353 | + );
|
|
| 347 | 354 | this._descriptionEl = document.getElementById(
|
| 348 | 355 | "tor-clientauth-notification-desc"
|
| 349 | 356 | );
|
| ... | ... | @@ -14,6 +14,20 @@ var gOnionServicesSavedKeysDialog = { |
| 14 | 14 | return this._busyCount > 0;
|
| 15 | 15 | },
|
| 16 | 16 | |
| 17 | + /**
|
|
| 18 | + * Whether the "remove selected" button is disabled.
|
|
| 19 | + *
|
|
| 20 | + * @type {boolean}
|
|
| 21 | + */
|
|
| 22 | + _removeSelectedDisabled: true,
|
|
| 23 | + |
|
| 24 | + /**
|
|
| 25 | + * Whether the "remove all" button is disabled.
|
|
| 26 | + *
|
|
| 27 | + * @type {boolean}
|
|
| 28 | + */
|
|
| 29 | + _removeAllDisabled: true,
|
|
| 30 | + |
|
| 17 | 31 | async _deleteSelectedKeys() {
|
| 18 | 32 | this._showError(null);
|
| 19 | 33 | this._withBusy(async () => {
|
| ... | ... | @@ -36,6 +50,15 @@ var gOnionServicesSavedKeysDialog = { |
| 36 | 50 | for (let i = indexesToDelete.length - 1; i >= 0; --i) {
|
| 37 | 51 | await this._deleteOneKey(provider, indexesToDelete[i]);
|
| 38 | 52 | }
|
| 53 | + // If successful and the user focus is still on the buttons move focus
|
|
| 54 | + // to the table with the updated state. We do this before calling
|
|
| 55 | + // _updateButtonState and potentially making the buttons disabled.
|
|
| 56 | + if (
|
|
| 57 | + this._removeButton.contains(document.activeElement) ||
|
|
| 58 | + this._removeAllButton.contains(document.activeElement)
|
|
| 59 | + ) {
|
|
| 60 | + this._tree.focus();
|
|
| 61 | + }
|
|
| 39 | 62 | } catch (e) {
|
| 40 | 63 | console.error("Removing a saved key failed", e);
|
| 41 | 64 | this._showError(
|
| ... | ... | @@ -51,10 +74,37 @@ var gOnionServicesSavedKeysDialog = { |
| 51 | 74 | await this._deleteSelectedKeys();
|
| 52 | 75 | },
|
| 53 | 76 | |
| 77 | + /**
|
|
| 78 | + * Show the given button as being disabled or enabled.
|
|
| 79 | + *
|
|
| 80 | + * @param {Button} button - The button to change.
|
|
| 81 | + * @param {boolean} disable - Whether to show the button as disabled or
|
|
| 82 | + * enabled.
|
|
| 83 | + */
|
|
| 84 | + _disableButton(button, disable) {
|
|
| 85 | + // If we are disabled we show the button as disabled, and we also remove it
|
|
| 86 | + // from the tab focus cycle using `tabIndex = -1`.
|
|
| 87 | + // This is similar to using the `disabled` attribute, except that
|
|
| 88 | + // `tabIndex = -1` still allows the button to be focusable. I.e. not part of
|
|
| 89 | + // the focus cycle but can *keep* existing focus when the button becomes
|
|
| 90 | + // disabled to avoid loosing focus to the top of the dialog.
|
|
| 91 | + // TODO: Replace with moz-button when it handles this for us. See
|
|
| 92 | + // tor-browser#43275.
|
|
| 93 | + button.classList.toggle("spoof-button-disabled", disable);
|
|
| 94 | + button.tabIndex = disable ? -1 : 0;
|
|
| 95 | + if (disable) {
|
|
| 96 | + this._removeButton.setAttribute("aria-disabled", "true");
|
|
| 97 | + } else {
|
|
| 98 | + this._removeButton.removeAttribute("aria-disabled");
|
|
| 99 | + }
|
|
| 100 | + },
|
|
| 101 | + |
|
| 54 | 102 | _updateButtonsState() {
|
| 55 | 103 | const haveSelection = this._tree.view.selection.getRangeCount() > 0;
|
| 56 | - this._removeButton.disabled = this._isBusy || !haveSelection;
|
|
| 57 | - this._removeAllButton.disabled = this._isBusy || this.rowCount === 0;
|
|
| 104 | + this._removeSelectedDisabled = this._isBusy || !haveSelection;
|
|
| 105 | + this._removeAllDisabled = this._isBusy || this.rowCount === 0;
|
|
| 106 | + this._disableButton(this._removeButton, this._removeSelectedDisabled);
|
|
| 107 | + this._disableButton(this._removeAllButton, this._removeAllDisabled);
|
|
| 58 | 108 | },
|
| 59 | 109 | |
| 60 | 110 | // Private functions.
|
| ... | ... | @@ -79,12 +129,18 @@ var gOnionServicesSavedKeysDialog = { |
| 79 | 129 | "onionservices-savedkeys-remove"
|
| 80 | 130 | );
|
| 81 | 131 | this._removeButton.addEventListener("click", () => {
|
| 132 | + if (this._removeSelectedDisabled) {
|
|
| 133 | + return;
|
|
| 134 | + }
|
|
| 82 | 135 | this._deleteSelectedKeys();
|
| 83 | 136 | });
|
| 84 | 137 | this._removeAllButton = document.getElementById(
|
| 85 | 138 | "onionservices-savedkeys-removeall"
|
| 86 | 139 | );
|
| 87 | 140 | this._removeAllButton.addEventListener("click", () => {
|
| 141 | + if (this._removeAllDisabled) {
|
|
| 142 | + return;
|
|
| 143 | + }
|
|
| 88 | 144 | this._deleteAllKeys();
|
| 89 | 145 | });
|
| 90 | 146 |
| ... | ... | @@ -49,7 +49,11 @@ |
| 49 | 49 | </treecols>
|
| 50 | 50 | <treechildren />
|
| 51 | 51 | </tree>
|
| 52 | - <hbox id="onionservices-savedkeys-errorContainer" align="center">
|
|
| 52 | + <hbox
|
|
| 53 | + id="onionservices-savedkeys-errorContainer"
|
|
| 54 | + align="center"
|
|
| 55 | + role="alert"
|
|
| 56 | + >
|
|
| 53 | 57 | <image id="onionservices-savedkeys-errorIcon" />
|
| 54 | 58 | <description id="onionservices-savedkeys-errorMessage" flex="1" />
|
| 55 | 59 | </hbox>
|
| ... | ... | @@ -57,7 +61,6 @@ |
| 57 | 61 | <hbox id="onionservices-savedkeys-buttons">
|
| 58 | 62 | <html:button
|
| 59 | 63 | id="onionservices-savedkeys-remove"
|
| 60 | - disabled="true"
|
|
| 61 | 64 | data-l10n-id="onion-site-saved-keys-dialog-remove-button"
|
| 62 | 65 | ></html:button>
|
| 63 | 66 | <html:button
|
| ... | ... | @@ -2354,8 +2354,11 @@ const gNetworkStatus = { |
| 2354 | 2354 | this._internetTestDisabled = true;
|
| 2355 | 2355 | // We use "aria-disabled" rather than the "disabled" attribute so that the
|
| 2356 | 2356 | // button can remain focusable during the test.
|
| 2357 | + // TODO: Replace with moz-button when it handles this for us. See
|
|
| 2358 | + // tor-browser#43275.
|
|
| 2357 | 2359 | this._internetTestButton.setAttribute("aria-disabled", "true");
|
| 2358 | 2360 | this._internetTestButton.classList.add("spoof-button-disabled");
|
| 2361 | + this._internetTestButton.tabIndex = -1;
|
|
| 2359 | 2362 | try {
|
| 2360 | 2363 | this._updateInternetStatus("testing");
|
| 2361 | 2364 | const mrpc = new MoatRPC();
|
| ... | ... | @@ -2376,6 +2379,7 @@ const gNetworkStatus = { |
| 2376 | 2379 | } finally {
|
| 2377 | 2380 | this._internetTestButton.removeAttribute("aria-disabled");
|
| 2378 | 2381 | this._internetTestButton.classList.remove("spoof-button-disabled");
|
| 2382 | + this._internetTestButton.tabIndex = 0;
|
|
| 2379 | 2383 | this._internetTestDisabled = false;
|
| 2380 | 2384 | }
|
| 2381 | 2385 | },
|
| ... | ... | @@ -255,15 +255,11 @@ const gLoxInvites = { |
| 255 | 255 | // When generating we use "aria-disabled" rather than the "disabled"
|
| 256 | 256 | // attribute so that the button can remain focusable whilst we generate
|
| 257 | 257 | // invites.
|
| 258 | - // NOTE: When we generate the invite the focus will move to the invite list,
|
|
| 259 | - // so it should be safe to make the button non-focusable in this case.
|
|
| 260 | - const spoofDisabled = this._generating;
|
|
| 261 | - this._generateButton.disabled = disabled && !spoofDisabled;
|
|
| 262 | - this._generateButton.classList.toggle(
|
|
| 263 | - "spoof-button-disabled",
|
|
| 264 | - spoofDisabled
|
|
| 265 | - );
|
|
| 266 | - if (spoofDisabled) {
|
|
| 258 | + // TODO: Replace with moz-button when it handles this for us. See
|
|
| 259 | + // tor-browser#43275.
|
|
| 260 | + this._generateButton.classList.toggle("spoof-button-disabled", disabled);
|
|
| 261 | + this._generateButton.tabIndex = disabled ? -1 : 0;
|
|
| 262 | + if (disabled) {
|
|
| 267 | 263 | this._generateButton.setAttribute("aria-disabled", "true");
|
| 268 | 264 | } else {
|
| 269 | 265 | this._generateButton.removeAttribute("aria-disabled");
|
| ... | ... | @@ -215,7 +215,10 @@ const gProvideBridgeDialog = { |
| 215 | 215 | this._acceptDisabled = disabled;
|
| 216 | 216 | // Spoof the button to look and act as if it is disabled, but still allow
|
| 217 | 217 | // keyboard focus so the user can sit on this button whilst we are loading.
|
| 218 | + // TODO: Replace with moz-button when it handles this for us. See
|
|
| 219 | + // tor-browser#43275.
|
|
| 218 | 220 | this._acceptButton.classList.toggle("spoof-button-disabled", disabled);
|
| 221 | + this._acceptButton.tabIndex = disabled ? -1 : 0;
|
|
| 219 | 222 | if (disabled) {
|
| 220 | 223 | this._acceptButton.setAttribute("aria-disabled", "true");
|
| 221 | 224 | } else {
|
| ... | ... | @@ -55,7 +55,6 @@ |
| 55 | 55 | <html:span
|
| 56 | 56 | id="user-provide-bridge-error-message"
|
| 57 | 57 | role="alert"
|
| 58 | - aria-live="assertive"
|
|
| 59 | 58 | ></html:span>
|
| 60 | 59 | <img
|
| 61 | 60 | id="user-provide-bridge-loading-icon"
|
| ... | ... | @@ -6,7 +6,9 @@ |
| 6 | 6 | }
|
| 7 | 7 | |
| 8 | 8 | /* Make a button appear disabled, whilst still allowing it to keep keyboard
|
| 9 | - * focus. */
|
|
| 9 | + * focus.
|
|
| 10 | + * TODO: Replace with moz-button when it handles this for us. See
|
|
| 11 | + * tor-browser#43275. */
|
|
| 10 | 12 | button.spoof-button-disabled {
|
| 11 | 13 | /* Borrow the :disabled rule from common-shared.css */
|
| 12 | 14 | opacity: 0.4;
|