richard pushed to branch tor-browser-115.10.0esr-13.5-1 at The Tor Project / Applications / Tor Browser

Commits:

10 changed files:

Changes:

  • browser/components/torpreferences/content/connectionPane.js
    ... ... @@ -5,7 +5,8 @@
    5 5
     
    
    6 6
     "use strict";
    
    7 7
     
    
    8
    -/* global Services, gSubDialog */
    
    8
    +/* import-globals-from /browser/components/preferences/preferences.js */
    
    9
    +/* import-globals-from /browser/components/preferences/search.js */
    
    9 10
     
    
    10 11
     const { setTimeout, clearTimeout } = ChromeUtils.import(
    
    11 12
       "resource://gre/modules/Timer.jsm"
    
    ... ... @@ -90,12 +91,6 @@ const Lox = {
    90 91
     };
    
    91 92
     */
    
    92 93
     
    
    93
    -const InternetStatus = Object.freeze({
    
    94
    -  Unknown: 0,
    
    95
    -  Online: 1,
    
    96
    -  Offline: -1,
    
    97
    -});
    
    98
    -
    
    99 94
     /**
    
    100 95
      * Make changes to TorSettings and save them.
    
    101 96
      *
    
    ... ... @@ -2283,6 +2278,168 @@ const gBridgeSettings = {
    2283 2278
       },
    
    2284 2279
     };
    
    2285 2280
     
    
    2281
    +/**
    
    2282
    + * Area to show the internet and tor network connection status.
    
    2283
    + */
    
    2284
    +const gNetworkStatus = {
    
    2285
    +  /**
    
    2286
    +   * Initialize the area.
    
    2287
    +   */
    
    2288
    +  init() {
    
    2289
    +    this._internetAreaEl = document.getElementById(
    
    2290
    +      "network-status-internet-area"
    
    2291
    +    );
    
    2292
    +    this._internetResultEl = this._internetAreaEl.querySelector(
    
    2293
    +      ".network-status-result"
    
    2294
    +    );
    
    2295
    +    this._internetTestButton = document.getElementById(
    
    2296
    +      "network-status-internet-test-button"
    
    2297
    +    );
    
    2298
    +    this._internetTestButton.addEventListener("click", () => {
    
    2299
    +      this._startInternetTest();
    
    2300
    +    });
    
    2301
    +
    
    2302
    +    this._torAreaEl = document.getElementById("network-status-tor-area");
    
    2303
    +    this._torResultEl = this._torAreaEl.querySelector(".network-status-result");
    
    2304
    +    this._torConnectButton = document.getElementById(
    
    2305
    +      "network-status-tor-connect-button"
    
    2306
    +    );
    
    2307
    +    this._torConnectButton.addEventListener("click", () => {
    
    2308
    +      TorConnect.openTorConnect({ beginBootstrap: true });
    
    2309
    +    });
    
    2310
    +
    
    2311
    +    this._updateInternetStatus("unknown");
    
    2312
    +    this._updateTorConnectionStatus();
    
    2313
    +
    
    2314
    +    Services.obs.addObserver(this, TorConnectTopics.StateChange);
    
    2315
    +  },
    
    2316
    +
    
    2317
    +  /**
    
    2318
    +   * Un-initialize the area.
    
    2319
    +   */
    
    2320
    +  deinint() {
    
    2321
    +    Services.obs.removeObserver(this, TorConnectTopics.StateChange);
    
    2322
    +  },
    
    2323
    +
    
    2324
    +  observe(subject, topic, data) {
    
    2325
    +    switch (topic) {
    
    2326
    +      // triggered when tor connect state changes and we may
    
    2327
    +      // need to update the messagebox
    
    2328
    +      case TorConnectTopics.StateChange: {
    
    2329
    +        this._updateTorConnectionStatus();
    
    2330
    +        break;
    
    2331
    +      }
    
    2332
    +    }
    
    2333
    +  },
    
    2334
    +
    
    2335
    +  /**
    
    2336
    +   * Whether the test should be disabled.
    
    2337
    +   *
    
    2338
    +   * @type {boolean}
    
    2339
    +   */
    
    2340
    +  _internetTestDisabled: false,
    
    2341
    +  /**
    
    2342
    +   * Start the internet test.
    
    2343
    +   */
    
    2344
    +  async _startInternetTest() {
    
    2345
    +    if (this._internetTestDisabled) {
    
    2346
    +      return;
    
    2347
    +    }
    
    2348
    +    this._internetTestDisabled = true;
    
    2349
    +    // We use "aria-disabled" rather than the "disabled" attribute so that the
    
    2350
    +    // button can remain focusable during the test.
    
    2351
    +    this._internetTestButton.setAttribute("aria-disabled", "true");
    
    2352
    +    this._internetTestButton.classList.add("spoof-button-disabled");
    
    2353
    +    try {
    
    2354
    +      this._updateInternetStatus("testing");
    
    2355
    +      const mrpc = new MoatRPC();
    
    2356
    +      let status = null;
    
    2357
    +      try {
    
    2358
    +        await mrpc.init();
    
    2359
    +        status = await mrpc.testInternetConnection();
    
    2360
    +      } catch (err) {
    
    2361
    +        console.log("Error while checking the Internet connection", err);
    
    2362
    +      } finally {
    
    2363
    +        mrpc.uninit();
    
    2364
    +      }
    
    2365
    +      if (status) {
    
    2366
    +        this._updateInternetStatus(status.successful ? "online" : "offline");
    
    2367
    +      } else {
    
    2368
    +        this._updateInternetStatus("unknown");
    
    2369
    +      }
    
    2370
    +    } finally {
    
    2371
    +      this._internetTestButton.removeAttribute("aria-disabled");
    
    2372
    +      this._internetTestButton.classList.remove("spoof-button-disabled");
    
    2373
    +      this._internetTestDisabled = false;
    
    2374
    +    }
    
    2375
    +  },
    
    2376
    +
    
    2377
    +  /**
    
    2378
    +   * Update the shown internet status.
    
    2379
    +   *
    
    2380
    +   * @param {string} stateName - The name of the state to show.
    
    2381
    +   */
    
    2382
    +  _updateInternetStatus(stateName) {
    
    2383
    +    let l10nId;
    
    2384
    +    switch (stateName) {
    
    2385
    +      case "testing":
    
    2386
    +        l10nId = "tor-connection-internet-status-testing";
    
    2387
    +        break;
    
    2388
    +      case "offline":
    
    2389
    +        l10nId = "tor-connection-internet-status-offline";
    
    2390
    +        break;
    
    2391
    +      case "online":
    
    2392
    +        l10nId = "tor-connection-internet-status-online";
    
    2393
    +        break;
    
    2394
    +    }
    
    2395
    +    if (l10nId) {
    
    2396
    +      this._internetResultEl.setAttribute("data-l10n-id", l10nId);
    
    2397
    +    } else {
    
    2398
    +      this._internetResultEl.removeAttribute("data-l10n-id");
    
    2399
    +      this._internetResultEl.textContent = "";
    
    2400
    +    }
    
    2401
    +
    
    2402
    +    this._internetAreaEl.classList.toggle(
    
    2403
    +      "status-loading",
    
    2404
    +      stateName === "testing"
    
    2405
    +    );
    
    2406
    +    this._internetAreaEl.classList.toggle(
    
    2407
    +      "status-offline",
    
    2408
    +      stateName === "offline"
    
    2409
    +    );
    
    2410
    +  },
    
    2411
    +
    
    2412
    +  /**
    
    2413
    +   * Update the shown Tor connection status.
    
    2414
    +   */
    
    2415
    +  _updateTorConnectionStatus() {
    
    2416
    +    const buttonHadFocus = this._torConnectButton.contains(
    
    2417
    +      document.activeElement
    
    2418
    +    );
    
    2419
    +    const isBootstrapped = TorConnect.state === TorConnectState.Bootstrapped;
    
    2420
    +    const isBlocked = !isBootstrapped && TorConnect.potentiallyBlocked;
    
    2421
    +    let l10nId;
    
    2422
    +    if (isBootstrapped) {
    
    2423
    +      l10nId = "tor-connection-network-status-connected";
    
    2424
    +    } else if (isBlocked) {
    
    2425
    +      l10nId = "tor-connection-network-status-blocked";
    
    2426
    +    } else {
    
    2427
    +      l10nId = "tor-connection-network-status-not-connected";
    
    2428
    +    }
    
    2429
    +
    
    2430
    +    document.l10n.setAttributes(this._torResultEl, l10nId);
    
    2431
    +    this._torAreaEl.classList.toggle("status-connected", isBootstrapped);
    
    2432
    +    this._torAreaEl.classList.toggle("status-blocked", isBlocked);
    
    2433
    +    if (isBootstrapped && buttonHadFocus) {
    
    2434
    +      // Button has become hidden and will loose focus. Most likely this has
    
    2435
    +      // happened because the user clicked the button to open about:torconnect.
    
    2436
    +      // Since this is near the top of the page, we move focus to the search
    
    2437
    +      // input (for when the user returns).
    
    2438
    +      gSearchResultsPane.searchInput.focus();
    
    2439
    +    }
    
    2440
    +  },
    
    2441
    +};
    
    2442
    +
    
    2286 2443
     /*
    
    2287 2444
       Connection Pane
    
    2288 2445
     
    
    ... ... @@ -2304,8 +2461,6 @@ const gConnectionPane = (function () {
    2304 2461
         // cached frequently accessed DOM elements
    
    2305 2462
         _enableQuickstartCheckbox: null,
    
    2306 2463
     
    
    2307
    -    _internetStatus: InternetStatus.Unknown,
    
    2308
    -
    
    2309 2464
         // populate xul with strings and cache the relevant elements
    
    2310 2465
         _populateXUL() {
    
    2311 2466
           // saves tor settings to disk when navigate away from about:preferences
    
    ... ... @@ -2321,80 +2476,6 @@ const gConnectionPane = (function () {
    2321 2476
             }
    
    2322 2477
           });
    
    2323 2478
     
    
    2324
    -      // Internet and Tor status
    
    2325
    -      const internetStatus = document.getElementById(
    
    2326
    -        "torPreferences-status-internet"
    
    2327
    -      );
    
    2328
    -      const internetResult = internetStatus.querySelector(
    
    2329
    -        ".torPreferences-status-result"
    
    2330
    -      );
    
    2331
    -      const internetTest = document.getElementById(
    
    2332
    -        "torPreferences-status-internet-test"
    
    2333
    -      );
    
    2334
    -      internetTest.addEventListener("click", () => {
    
    2335
    -        this.onInternetTest();
    
    2336
    -      });
    
    2337
    -
    
    2338
    -      const torConnectStatus = document.getElementById(
    
    2339
    -        "torPreferences-status-tor-connect"
    
    2340
    -      );
    
    2341
    -      const torConnectResult = torConnectStatus.querySelector(
    
    2342
    -        ".torPreferences-status-result"
    
    2343
    -      );
    
    2344
    -      const torConnectButton = document.getElementById(
    
    2345
    -        "torPreferences-status-tor-connect-button"
    
    2346
    -      );
    
    2347
    -      torConnectButton.addEventListener("click", () => {
    
    2348
    -        TorConnect.openTorConnect({ beginBootstrap: true });
    
    2349
    -      });
    
    2350
    -
    
    2351
    -      this._populateStatus = () => {
    
    2352
    -        let internetId;
    
    2353
    -        switch (this._internetStatus) {
    
    2354
    -          case InternetStatus.Online:
    
    2355
    -            internetStatus.classList.remove("offline");
    
    2356
    -            internetId = "tor-connection-internet-status-online";
    
    2357
    -            break;
    
    2358
    -          case InternetStatus.Offline:
    
    2359
    -            internetStatus.classList.add("offline");
    
    2360
    -            internetId = "tor-connection-internet-status-offline";
    
    2361
    -            break;
    
    2362
    -          case InternetStatus.Unknown:
    
    2363
    -          default:
    
    2364
    -            internetStatus.classList.remove("offline");
    
    2365
    -            break;
    
    2366
    -        }
    
    2367
    -        if (internetId) {
    
    2368
    -          document.l10n.setAttributes(internetResult, internetId);
    
    2369
    -          internetResult.hidden = false;
    
    2370
    -        } else {
    
    2371
    -          internetResult.hidden = true;
    
    2372
    -        }
    
    2373
    -
    
    2374
    -        let connectId;
    
    2375
    -        // FIXME: What about the TorConnectState.Disabled state?
    
    2376
    -        if (TorConnect.state === TorConnectState.Bootstrapped) {
    
    2377
    -          torConnectStatus.classList.add("connected");
    
    2378
    -          torConnectStatus.classList.remove("blocked");
    
    2379
    -          connectId = "tor-connection-network-status-connected";
    
    2380
    -          // NOTE: If the button is focused when we hide it, the focus may be
    
    2381
    -          // lost. But we don't have an obvious place to put the focus instead.
    
    2382
    -          torConnectButton.hidden = true;
    
    2383
    -        } else {
    
    2384
    -          torConnectStatus.classList.remove("connected");
    
    2385
    -          torConnectStatus.classList.toggle(
    
    2386
    -            "blocked",
    
    2387
    -            TorConnect.potentiallyBlocked
    
    2388
    -          );
    
    2389
    -          connectId = TorConnect.potentiallyBlocked
    
    2390
    -            ? "tor-connection-network-status-blocked"
    
    2391
    -            : "tor-connection-network-status-not-connected";
    
    2392
    -          torConnectButton.hidden = false;
    
    2393
    -        }
    
    2394
    -        document.l10n.setAttributes(torConnectResult, connectId);
    
    2395
    -      };
    
    2396
    -      this._populateStatus();
    
    2397
    -
    
    2398 2479
           // Quickstart
    
    2399 2480
           this._enableQuickstartCheckbox = document.getElementById(
    
    2400 2481
             "torPreferences-quickstart-toggle"
    
    ... ... @@ -2514,6 +2595,7 @@ const gConnectionPane = (function () {
    2514 2595
     
    
    2515 2596
         init() {
    
    2516 2597
           gBridgeSettings.init();
    
    2598
    +      gNetworkStatus.init();
    
    2517 2599
     
    
    2518 2600
           TorSettings.initializedPromise.then(() => this._populateXUL());
    
    2519 2601
     
    
    ... ... @@ -2526,6 +2608,7 @@ const gConnectionPane = (function () {
    2526 2608
     
    
    2527 2609
         uninit() {
    
    2528 2610
           gBridgeSettings.uninit();
    
    2611
    +      gNetworkStatus.uninit();
    
    2529 2612
     
    
    2530 2613
           // unregister our observer topics
    
    2531 2614
           Services.obs.removeObserver(this, TorSettingsTopics.SettingsChanged);
    
    ... ... @@ -2554,36 +2637,12 @@ const gConnectionPane = (function () {
    2554 2637
             // triggered when tor connect state changes and we may
    
    2555 2638
             // need to update the messagebox
    
    2556 2639
             case TorConnectTopics.StateChange: {
    
    2557
    -          this.onStateChange();
    
    2640
    +          this._showAutoconfiguration();
    
    2558 2641
               break;
    
    2559 2642
             }
    
    2560 2643
           }
    
    2561 2644
         },
    
    2562 2645
     
    
    2563
    -    async onInternetTest() {
    
    2564
    -      const mrpc = new MoatRPC();
    
    2565
    -      let status = null;
    
    2566
    -      try {
    
    2567
    -        await mrpc.init();
    
    2568
    -        status = await mrpc.testInternetConnection();
    
    2569
    -      } catch (err) {
    
    2570
    -        console.log("Error while checking the Internet connection", err);
    
    2571
    -      } finally {
    
    2572
    -        mrpc.uninit();
    
    2573
    -      }
    
    2574
    -      if (status) {
    
    2575
    -        this._internetStatus = status.successful
    
    2576
    -          ? InternetStatus.Online
    
    2577
    -          : InternetStatus.Offline;
    
    2578
    -        this._populateStatus();
    
    2579
    -      }
    
    2580
    -    },
    
    2581
    -
    
    2582
    -    onStateChange() {
    
    2583
    -      this._populateStatus();
    
    2584
    -      this._showAutoconfiguration();
    
    2585
    -    },
    
    2586
    -
    
    2587 2646
         onAdvancedSettings() {
    
    2588 2647
           gSubDialog.open(
    
    2589 2648
             "chrome://browser/content/torpreferences/connectionSettingsDialog.xhtml",
    

  • browser/components/torpreferences/content/connectionPane.xhtml
    ... ... @@ -5,16 +5,13 @@
    5 5
       src="chrome://browser/content/torpreferences/connectionPane.js"
    
    6 6
     />
    
    7 7
     <html:template id="template-paneConnection">
    
    8
    -  <hbox
    
    8
    +  <vbox
    
    9 9
         id="torPreferencesCategory"
    
    10 10
         class="subcategory"
    
    11 11
         data-category="paneConnection"
    
    12 12
         hidden="true"
    
    13 13
       >
    
    14 14
         <html:h1 data-l10n-id="tor-connection-settings-heading"></html:h1>
    
    15
    -  </hbox>
    
    16
    -
    
    17
    -  <groupbox data-category="paneConnection" hidden="true">
    
    18 15
         <description flex="1">
    
    19 16
           <html:span
    
    20 17
             data-l10n-id="tor-connection-overview"
    
    ... ... @@ -28,46 +25,61 @@
    28 25
             data-l10n-id="tor-connection-browser-learn-more-link"
    
    29 26
           />
    
    30 27
         </description>
    
    31
    -  </groupbox>
    
    32
    -
    
    33
    -  <groupbox
    
    34
    -    id="torPreferences-status-group"
    
    35
    -    data-category="paneConnection"
    
    36
    -    hidden="true"
    
    37
    -  >
    
    38
    -    <hbox id="torPreferences-status-box">
    
    39
    -      <hbox
    
    40
    -        id="torPreferences-status-internet"
    
    41
    -        class="torPreferences-status-grouping"
    
    28
    +    <!-- Keep within #torPreferencesCategory so this won't appear in search
    
    29
    +       - results. -->
    
    30
    +    <html:div
    
    31
    +      id="network-status-internet-area"
    
    32
    +      class="network-status-area"
    
    33
    +      role="group"
    
    34
    +      aria-labelledby="network-status-internet-area-label"
    
    35
    +    >
    
    36
    +      <html:img alt="" class="network-status-icon" />
    
    37
    +      <!-- Use an aria-live area to announce "Internet: Online" or
    
    38
    +         - "Internet: Offline". We only expect this to change when triggered by
    
    39
    +         - the user clicking the "Test" button, so shouldn't occur unexpectedly.
    
    40
    +         -->
    
    41
    +      <html:div
    
    42
    +        class="network-status-live-area"
    
    43
    +        aria-live="polite"
    
    44
    +        aria-atomic="true"
    
    42 45
           >
    
    43
    -        <image class="torPreferences-status-icon" />
    
    44 46
             <html:span
    
    45
    -          class="torPreferences-status-name"
    
    47
    +          id="network-status-internet-area-label"
    
    48
    +          class="network-status-label"
    
    46 49
               data-l10n-id="tor-connection-internet-status-label"
    
    47 50
             ></html:span>
    
    48
    -        <html:span class="torPreferences-status-result"></html:span>
    
    49
    -        <html:button
    
    50
    -          id="torPreferences-status-internet-test"
    
    51
    -          data-l10n-id="tor-connection-internet-status-test-button"
    
    52
    -        ></html:button>
    
    53
    -      </hbox>
    
    54
    -      <hbox
    
    55
    -        id="torPreferences-status-tor-connect"
    
    56
    -        class="torPreferences-status-grouping"
    
    57
    -      >
    
    58
    -        <image class="torPreferences-status-icon" />
    
    59
    -        <html:span
    
    60
    -          class="torPreferences-status-name"
    
    61
    -          data-l10n-id="tor-connection-network-status-label"
    
    62
    -        ></html:span>
    
    63
    -        <html:span class="torPreferences-status-result"></html:span>
    
    64
    -        <html:button
    
    65
    -          id="torPreferences-status-tor-connect-button"
    
    66
    -          data-l10n-id="tor-connection-network-status-connect-button"
    
    67
    -        ></html:button>
    
    68
    -      </hbox>
    
    69
    -    </hbox>
    
    70
    -  </groupbox>
    
    51
    +        <img alt="" class="network-status-loading-icon" />
    
    52
    +        <html:span class="network-status-result"></html:span>
    
    53
    +      </html:div>
    
    54
    +      <html:button
    
    55
    +        id="network-status-internet-test-button"
    
    56
    +        data-l10n-id="tor-connection-internet-status-test-button"
    
    57
    +      ></html:button>
    
    58
    +    </html:div>
    
    59
    +    <html:div
    
    60
    +      id="network-status-tor-area"
    
    61
    +      class="network-status-area"
    
    62
    +      role="group"
    
    63
    +      aria-labelledby="network-status-tor-area-label"
    
    64
    +    >
    
    65
    +      <html:img alt="" class="network-status-icon" />
    
    66
    +      <!-- NOTE: Unlike #network-status-internet-area, we do not wrap the label
    
    67
    +         - and status ("Tor network: Not connected", etc) in an aria-live area.
    
    68
    +         - This is not likely to change whilst this page has focus.
    
    69
    +         - Moreover, the status is already present in the torconnect status bar
    
    70
    +         - in the window tab bar. -->
    
    71
    +      <html:span
    
    72
    +        id="network-status-tor-area-label"
    
    73
    +        class="network-status-label"
    
    74
    +        data-l10n-id="tor-connection-network-status-label"
    
    75
    +      ></html:span>
    
    76
    +      <html:span class="network-status-result"></html:span>
    
    77
    +      <html:button
    
    78
    +        id="network-status-tor-connect-button"
    
    79
    +        data-l10n-id="tor-connection-network-status-connect-button"
    
    80
    +      ></html:button>
    
    81
    +    </html:div>
    
    82
    +  </vbox>
    
    71 83
     
    
    72 84
       <!-- Quickstart -->
    
    73 85
       <groupbox data-category="paneConnection" hidden="true">
    

  • browser/components/torpreferences/content/torPreferences.css
    ... ... @@ -5,25 +5,36 @@
    5 5
       list-style-image: url("chrome://global/content/torconnect/tor-connect.svg");
    
    6 6
     }
    
    7 7
     
    
    8
    +/* Make a button appear disabled, whilst still allowing it to keep keyboard
    
    9
    + * focus. */
    
    10
    +button.spoof-button-disabled {
    
    11
    +  /* Borrow the :disabled rule from common-shared.css */
    
    12
    +  opacity: 0.4;
    
    13
    +  /* Also ensure it does not get hover or active styling. */
    
    14
    +  pointer-events: none;
    
    15
    +}
    
    16
    +
    
    8 17
     /* Status */
    
    9 18
     
    
    10
    -#torPreferences-status-box {
    
    11
    -  display: flex;
    
    12
    -  align-items: center;
    
    13
    -  gap: 32px;
    
    19
    +#network-status-internet-area {
    
    20
    +  margin-block: 16px;
    
    21
    +}
    
    22
    +
    
    23
    +#network-status-tor-area {
    
    24
    +  margin-block: 0 32px;
    
    14 25
     }
    
    15 26
     
    
    16
    -.torPreferences-status-grouping {
    
    27
    +.network-status-area {
    
    17 28
       display: flex;
    
    18 29
       align-items: center;
    
    19 30
       white-space: nowrap;
    
    20 31
     }
    
    21 32
     
    
    22
    -.torPreferences-status-grouping > * {
    
    33
    +.network-status-area > * {
    
    23 34
       flex: 0 0 auto;
    
    24 35
     }
    
    25 36
     
    
    26
    -.torPreferences-status-icon {
    
    37
    +.network-status-icon {
    
    27 38
       width: 18px;
    
    28 39
       height: 18px;
    
    29 40
       margin-inline-end: 8px;
    
    ... ... @@ -32,42 +43,74 @@
    32 43
       stroke: currentColor;
    
    33 44
     }
    
    34 45
     
    
    35
    -#torPreferences-status-internet .torPreferences-status-icon {
    
    36
    -  list-style-image: url("chrome://browser/content/torpreferences/network.svg");
    
    46
    +#network-status-internet-area .network-status-icon {
    
    47
    +  content: url("chrome://browser/content/torpreferences/network.svg");
    
    37 48
     }
    
    38 49
     
    
    39
    -#torPreferences-status-tor-connect .torPreferences-status-icon {
    
    40
    -  list-style-image: url("chrome://global/content/torconnect/tor-connect-broken.svg");
    
    50
    +#network-status-internet-area.status-offline .network-status-icon {
    
    51
    +  content: url("chrome://browser/content/torpreferences/network-broken.svg");
    
    41 52
     }
    
    42 53
     
    
    43
    -.torPreferences-status-name {
    
    44
    -  font-weight: bold;
    
    45
    -  margin-inline-end: 0.75em;
    
    54
    +#network-status-tor-area .network-status-icon {
    
    55
    +  content: url("chrome://global/content/torconnect/tor-connect.svg");
    
    46 56
     }
    
    47 57
     
    
    48
    -.torPreferences-status-result {
    
    49
    -  margin-inline-end: 8px;
    
    58
    +#network-status-tor-area:not(.status-connected) .network-status-icon {
    
    59
    +  content: url("chrome://global/content/torconnect/tor-connect-broken.svg");
    
    50 60
     }
    
    51 61
     
    
    52
    -#torPreferences-status-internet.offline .torPreferences-status-icon {
    
    53
    -  list-style-image: url("chrome://browser/content/torpreferences/network-broken.svg");
    
    62
    +#network-status-tor-area.status-blocked .network-status-icon {
    
    63
    +  /* Same as .tor-connect-status-potentially-blocked. */
    
    64
    +  stroke: #c50042;
    
    54 65
     }
    
    55 66
     
    
    56
    -#torPreferences-status-tor-connect.connected .torPreferences-status-icon {
    
    57
    -  list-style-image: url("chrome://global/content/torconnect/tor-connect.svg");
    
    67
    +@media (prefers-color-scheme: dark) {
    
    68
    +  #network-status-tor-area.status-blocked  .network-status-icon {
    
    69
    +    stroke: #ff9aa2;
    
    70
    +  }
    
    58 71
     }
    
    59 72
     
    
    60
    -#torPreferences-status-tor-connect.blocked .torPreferences-status-icon {
    
    61
    -  /* Same as .tor-connect-status-potentially-blocked. */
    
    62
    -  stroke: #c50042;
    
    73
    +.network-status-live-area {
    
    74
    +  display: contents;
    
    75
    +}
    
    76
    +
    
    77
    +.network-status-label {
    
    78
    +  font-weight: bold;
    
    79
    +  margin-inline-end: 0.75em;
    
    80
    +}
    
    81
    +
    
    82
    +.network-status-loading-icon {
    
    83
    +  margin-inline-end: 0.5em;
    
    84
    +  width: 16px;
    
    85
    +  height: 16px;
    
    86
    +  content: image-set(
    
    87
    +    url("chrome://global/skin/icons/tor-light-loading.png"),
    
    88
    +    url("chrome://global/skin/icons/tor-light-loading@2x.png") 2x
    
    89
    +  );
    
    63 90
     }
    
    64 91
     
    
    65 92
     @media (prefers-color-scheme: dark) {
    
    66
    -  #torPreferences-status-tor-connect.blocked .torPreferences-status-icon {
    
    67
    -    stroke: #ff9aa2;
    
    93
    +  .network-status-loading-icon {
    
    94
    +    content: image-set(
    
    95
    +      url("chrome://global/skin/icons/tor-dark-loading.png"),
    
    96
    +      url("chrome://global/skin/icons/tor-dark-loading@2x.png") 2x
    
    97
    +    );
    
    68 98
       }
    
    69 99
     }
    
    70 100
     
    
    101
    +#network-status-internet-area:not(.status-loading) .network-status-loading-icon {
    
    102
    +  display: none;
    
    103
    +}
    
    104
    +
    
    105
    +.network-status-result:not(:empty) {
    
    106
    +  margin-inline-end: 0.75em;
    
    107
    +}
    
    108
    +
    
    109
    +#network-status-tor-area.status-connected #network-status-tor-connect-button {
    
    110
    +  /* Hide button when already connected. */
    
    111
    +  display: none;
    
    112
    +}
    
    113
    +
    
    71 114
     /* Bridge settings */
    
    72 115
     
    
    73 116
     .tor-focusable-heading:focus-visible {
    

  • browser/locales/en-US/browser/tor-browser.ftl
    ... ... @@ -65,6 +65,9 @@ tor-connection-internet-status-label = Internet:
    65 65
     # Here "Test" is a verb, as in "test the internet connection".
    
    66 66
     # Uses sentence case in English (US).
    
    67 67
     tor-connection-internet-status-test-button = Test
    
    68
    +# Shown when testing the internet status.
    
    69
    +# Uses sentence case in English (US).
    
    70
    +tor-connection-internet-status-testing = Testing…
    
    68 71
     # Shown when the user is connected to the internet.
    
    69 72
     # Uses sentence case in English (US).
    
    70 73
     tor-connection-internet-status-online = Online
    

  • toolkit/themes/shared/desktop-jar.inc.mn
    ... ... @@ -86,6 +86,10 @@
    86 86
       skin/classic/global/icons/link.svg                       (../../shared/icons/link.svg)
    
    87 87
       skin/classic/global/icons/loading.png                    (../../shared/icons/loading.png)
    
    88 88
       skin/classic/global/icons/loading@2x.png                 (../../shared/icons/loading@2x.png)
    
    89
    +  skin/classic/global/icons/tor-light-loading.png          (../../shared/icons/tor-light-loading.png)
    
    90
    +  skin/classic/global/icons/tor-light-loading@2x.png       (../../shared/icons/tor-light-loading@2x.png)
    
    91
    +  skin/classic/global/icons/tor-dark-loading.png           (../../shared/icons/tor-dark-loading.png)
    
    92
    +  skin/classic/global/icons/tor-dark-loading@2x.png        (../../shared/icons/tor-dark-loading@2x.png)
    
    89 93
       skin/classic/global/icons/more.svg                       (../../shared/icons/more.svg)
    
    90 94
       skin/classic/global/icons/open-in-new.svg                (../../shared/icons/open-in-new.svg)
    
    91 95
       skin/classic/global/icons/page-portrait.svg              (../../shared/icons/page-portrait.svg)
    

  • toolkit/themes/shared/icons/tor-dark-loading.png
    No preview for this file type
  • toolkit/themes/shared/icons/tor-dark-loading@2x.png
    No preview for this file type
  • toolkit/themes/shared/icons/tor-light-loading.png
    No preview for this file type
  • toolkit/themes/shared/icons/tor-light-loading@2x.png
    No preview for this file type
  • tools/torbrowser/generate_tor_loading_png.py
    1
    +"""
    
    2
    +Script to convert the loading.png and loading@2x.png blue spinners to purple
    
    3
    +spinners for Tor Browser, for both the light and dark themes.
    
    4
    +"""
    
    5
    +
    
    6
    +import argparse
    
    7
    +import colorsys
    
    8
    +import os
    
    9
    +
    
    10
    +from PIL import ExifTags, Image, ImageFilter
    
    11
    +
    
    12
    +parser = argparse.ArgumentParser(description="Convert the loading APNG to be purple.")
    
    13
    +parser.add_argument("loading_png", help="The loading png to convert")
    
    14
    +parser.add_argument(
    
    15
    +    "--light", required=True, help="The name of the light-theme purple output image"
    
    16
    +)
    
    17
    +parser.add_argument(
    
    18
    +    "--dark", required=True, help="The name of the dark-theme purple output image"
    
    19
    +)
    
    20
    +
    
    21
    +parsed_args = parser.parse_args()
    
    22
    +
    
    23
    +orig_im = Image.open(parsed_args.loading_png)
    
    24
    +
    
    25
    +
    
    26
    +def filter_to_light_theme(r, g, b):
    
    27
    +    h, s, v = colorsys.rgb_to_hsv(r, g, b)
    
    28
    +    # Convert from HSV 0.58, 1.0, 255 (start of the circle)
    
    29
    +    # to --purple-60 #8000d7 HSV 0.766, 1.0, 215
    
    30
    +    h = 0.766
    
    31
    +    v = v * 215 / 255
    
    32
    +    return colorsys.hsv_to_rgb(h, s, v)
    
    33
    +
    
    34
    +
    
    35
    +def filter_to_dark_theme(r, g, b):
    
    36
    +    h, s, v = colorsys.rgb_to_hsv(r, g, b)
    
    37
    +    # Convert from HSV 0.58, 1.0, 255 (start of the circle)
    
    38
    +    # to --purple-30 #c069ff HSV 0.766, 0.59, 255
    
    39
    +    h = 0.766
    
    40
    +    s = s * 0.59 / 1.0
    
    41
    +    return colorsys.hsv_to_rgb(h, s, v)
    
    42
    +
    
    43
    +
    
    44
    +filt_light = ImageFilter.Color3DLUT.generate(65, filter_to_light_theme)
    
    45
    +filt_dark = ImageFilter.Color3DLUT.generate(65, filter_to_dark_theme)
    
    46
    +
    
    47
    +transformed_light = []
    
    48
    +transformed_dark = []
    
    49
    +duration = orig_im.info["duration"]
    
    50
    +
    
    51
    +# Transform each APNG frame individually.
    
    52
    +for frame in range(orig_im.n_frames):
    
    53
    +    orig_im.seek(frame)
    
    54
    +    transformed_light.append(orig_im.filter(filt_light))
    
    55
    +    transformed_dark.append(orig_im.filter(filt_dark))
    
    56
    +
    
    57
    +exif = Image.Exif()
    
    58
    +exif[ExifTags.Base.ImageDescription] = f"Generated by {os.path.basename(__file__)}"
    
    59
    +
    
    60
    +transformed_light[0].save(
    
    61
    +    parsed_args.light,
    
    62
    +    save_all=True,
    
    63
    +    append_images=transformed_light[1:],
    
    64
    +    duration=duration,
    
    65
    +    exif=exif,
    
    66
    +)
    
    67
    +
    
    68
    +transformed_dark[0].save(
    
    69
    +    parsed_args.dark,
    
    70
    +    save_all=True,
    
    71
    +    append_images=transformed_dark[1:],
    
    72
    +    duration=duration,
    
    73
    +    exif=exif,
    
    74
    +)