Commit 00e009df authored by henry's avatar henry
Browse files

fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in...

fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection

Bug 42457: Add a loading icon for Lox invites.

Also reduce the amount of focus-jumping by keeping the focus on the
disabled button.

Also change the focus of the last provideBridgeDialog page to be the
table of bridges. NVDA did not announce the focus when it was set to the
dialog itself.
parent b12ce2e6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@
          class="network-status-label"
          data-l10n-id="tor-connection-internet-status-label"
        ></html:span>
        <img alt="" class="network-status-loading-icon" />
        <img alt="" class="network-status-loading-icon tor-loading-icon" />
        <html:span class="network-status-result"></html:span>
      </html:div>
      <html:button
+37 −19
Original line number Diff line number Diff line
@@ -62,12 +62,12 @@ const gLoxInvites = {
    this._remainingInvitesEl = document.getElementById(
      "lox-invite-dialog-remaining"
    );
    this._generateArea = document.getElementById(
      "lox-invite-dialog-generate-area"
    );
    this._generateButton = document.getElementById(
      "lox-invite-dialog-generate-button"
    );
    this._connectingEl = document.getElementById(
      "lox-invite-dialog-connecting"
    );
    this._errorEl = document.getElementById("lox-invite-dialog-error-message");
    this._inviteListEl = document.getElementById("lox-invite-dialog-list");

@@ -237,20 +237,46 @@ const gLoxInvites = {
  _setGenerating(isGenerating) {
    this._generating = isGenerating;
    this._updateGenerateButtonState();
    this._connectingEl.classList.toggle("show-connecting", isGenerating);
    this._generateArea.classList.toggle("show-connecting", isGenerating);
  },

  /**
   * Whether the generate button is disabled.
   *
   * @type {boolean}
   */
  _generateDisabled: false,
  /**
   * Update the state of the generate button.
   */
  _updateGenerateButtonState() {
    this._generateButton.disabled = this._generating || !this._remainingInvites;
    const disabled = this._generating || !this._remainingInvites;
    this._generateDisabled = disabled;
    // 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) {
      this._generateButton.setAttribute("aria-disabled", "true");
    } else {
      this._generateButton.removeAttribute("aria-disabled");
    }
  },

  /**
   * Start generating a new invite.
   */
  _generateNewInvite() {
    if (this._generateDisabled) {
      return;
    }
    if (this._generating) {
      console.error("Already generating an invite");
      return;
@@ -258,15 +284,13 @@ const gLoxInvites = {
    this._setGenerating(true);
    // Clear the previous error.
    this._updateGenerateError(null);
    // Move focus from the button to the connecting element, since button is
    // now disabled.
    this._connectingEl.focus();

    let lostFocus = false;
    let moveFocus = false;
    Lox.generateInvite(this._loxId)
      .finally(() => {
        // Fetch whether the connecting label still has focus before we hide it.
        lostFocus = this._connectingEl.contains(document.activeElement);
        // Fetch whether the generate button has focus before we potentially
        // disable it.
        moveFocus = this._generateButton.contains(document.activeElement);
        this._setGenerating(false);
      })
      .then(
@@ -279,7 +303,7 @@ const gLoxInvites = {
            this._inviteListEl.selectedIndex = 0;
          }

          if (lostFocus) {
          if (moveFocus) {
            // Move focus to the new invite before we hide the "Connecting"
            // message.
            this._inviteListEl.focus();
@@ -295,12 +319,6 @@ const gLoxInvites = {
              this._updateGenerateError("generic");
              break;
          }

          if (lostFocus) {
            // Move focus back to the button before we hide the "Connecting"
            // message.
            this._generateButton.focus();
          }
        }
      );
  },
@@ -315,7 +333,7 @@ const gLoxInvites = {
    // First clear the existing error.
    this._errorEl.removeAttribute("data-l10n-id");
    this._errorEl.textContent = "";
    this._errorEl.classList.toggle("show-error", !!type);
    this._generateArea.classList.toggle("show-error", !!type);

    if (!type) {
      return;
+5 −1
Original line number Diff line number Diff line
@@ -40,10 +40,14 @@
          id="lox-invite-dialog-error-message"
          role="alert"
        ></html:span>
        <img
          id="lox-invite-dialog-loading-icon"
          class="tor-loading-icon"
          alt=""
        />
        <html:span
          id="lox-invite-dialog-connecting"
          role="alert"
          tabindex="0"
          data-l10n-id="lox-invite-dialog-connecting"
        ></html:span>
      </html:div>
+43 −25
Original line number Diff line number Diff line
@@ -84,13 +84,19 @@ const gProvideBridgeDialog = {

    this._dialog = document.getElementById("user-provide-bridge-dialog");
    this._acceptButton = this._dialog.getButton("accept");

    // Inject our stylesheet into the shadow root so that the accept button can
    // take the spoof-button-disabled styling.
    const styleLink = document.createElement("link");
    styleLink.rel = "stylesheet";
    styleLink.href =
      "chrome://browser/content/torpreferences/torPreferences.css";
    this._dialog.shadowRoot.append(styleLink);

    this._textarea = document.getElementById("user-provide-bridge-textarea");
    this._errorEl = document.getElementById(
      "user-provide-bridge-error-message"
    );
    this._connectingEl = document.getElementById(
      "user-provide-bridge-connecting"
    );
    this._resultDescription = document.getElementById(
      "user-provide-result-description"
    );
@@ -152,13 +158,16 @@ const gProvideBridgeDialog = {
   * Reset focus position in the dialog.
   */
  takeFocus() {
    if (this._page === "entry") {
    switch (this._page) {
      case "entry":
        this._textarea.focus();
    } else {
      // Move focus to the <xul:window> element.
        break;
      case "result":
        // Move focus to the table.
        // In particular, we do not want to keep the focus on the (same) accept
        // button (with now different text).
      document.documentElement.focus();
        this._bridgeGrid.focus();
        break;
    }
  },

@@ -193,12 +202,27 @@ const gProvideBridgeDialog = {
    }
  },

  /**
   * Whether the dialog accept button is disabled.
   *
   * @type {boolean}
   */
  _acceptDisabled: false,
  /**
   * Callback for whenever the accept button's might need to be disabled.
   */
  updateAcceptDisabled() {
    this._acceptButton.disabled =
    const disabled =
      this._page === "entry" && (this.isEmpty() || this._loxLoading);
    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.
    this._acceptButton.classList.toggle("spoof-button-disabled", disabled);
    if (disabled) {
      this._acceptButton.setAttribute("aria-disabled", "true");
    } else {
      this._acceptButton.removeAttribute("aria-disabled");
    }
  },

  /**
@@ -217,16 +241,7 @@ const gProvideBridgeDialog = {
  setLoxLoading(isLoading) {
    this._loxLoading = isLoading;
    this._textarea.readOnly = isLoading;
    this._connectingEl.classList.toggle("show-connecting", isLoading);
    if (
      isLoading &&
      this._acceptButton.contains(
        this._acceptButton.getRootNode().activeElement
      )
    ) {
      // Move focus to the alert before we disable the button.
      this._connectingEl.focus();
    }
    this._dialog.classList.toggle("show-connecting", isLoading);
    this.updateAcceptDisabled();
  },

@@ -236,6 +251,12 @@ const gProvideBridgeDialog = {
   * @param {Event} event - The dialogaccept event.
   */
  onDialogAccept(event) {
    if (this._acceptDisabled) {
      // Prevent closing.
      event.preventDefault();
      return;
    }

    if (this._page === "result") {
      this._result.accepted = true;
      // Continue to close the dialog.
@@ -313,14 +334,11 @@ const gProvideBridgeDialog = {
    this._errorEl.textContent = "";
    if (error) {
      this._textarea.setAttribute("aria-invalid", "true");
      // Move focus back to the text area, likely away from the Next button or
      // the "Connecting..." alert.
      this._textarea.focus();
    } else {
      this._textarea.removeAttribute("aria-invalid");
    }
    this._textarea.classList.toggle("invalid-input", !!error);
    this._errorEl.classList.toggle("show-error", !!error);
    this._dialog.classList.toggle("show-error", !!error);

    if (!error) {
      return;
+7 −1
Original line number Diff line number Diff line
@@ -51,10 +51,14 @@
          role="alert"
          aria-live="assertive"
        ></html:span>
        <img
          id="user-provide-bridge-loading-icon"
          class="tor-loading-icon"
          alt=""
        />
        <html:span
          id="user-provide-bridge-connecting"
          role="alert"
          tabindex="0"
          data-l10n-id="user-provide-bridge-dialog-connecting"
        ></html:span>
      </html:div>
@@ -70,6 +74,8 @@
        id="user-provide-bridge-grid-display"
        class="tor-bridges-grid"
        role="table"
        tabindex="0"
        aria-labelledby="user-provide-result-description"
      ></html:div>
      <html:template id="user-provide-bridge-row-template">
        <html:div class="tor-bridges-grid-row" role="row">
Loading