morgan pushed to branch tor-browser-128.7.0esr-14.5-1 at The Tor Project / Applications / Tor Browser

Commits:

5 changed files:

Changes:

  • browser/components/torpreferences/content/torLogDialog.js
    ... ... @@ -4,20 +4,18 @@ const { setTimeout, clearTimeout } = ChromeUtils.importESModule(
    4 4
       "resource://gre/modules/Timer.sys.mjs"
    
    5 5
     );
    
    6 6
     
    
    7
    -const { TorProviderBuilder } = ChromeUtils.importESModule(
    
    7
    +const { TorProviderBuilder, TorProviderTopics } = ChromeUtils.importESModule(
    
    8 8
       "resource://gre/modules/TorProviderBuilder.sys.mjs"
    
    9 9
     );
    
    10 10
     
    
    11
    -window.addEventListener(
    
    12
    -  "DOMContentLoaded",
    
    13
    -  () => {
    
    11
    +const gTorLogDialog = {
    
    12
    +  init() {
    
    14 13
         const dialog = document.getElementById("torPreferences-torLog-dialog");
    
    15 14
         const copyLogButton = dialog.getButton("extra1");
    
    16 15
         copyLogButton.setAttribute("data-l10n-id", "tor-log-dialog-copy-button");
    
    17 16
     
    
    18
    -    const logText = document.getElementById(
    
    19
    -      "torPreferences-torDialog-textarea"
    
    20
    -    );
    
    17
    +    this._logTable = document.getElementById("tor-log-table");
    
    18
    +    this._logBody = document.getElementById("tor-log-body");
    
    21 19
     
    
    22 20
         let restoreButtonTimeout = null;
    
    23 21
         copyLogButton.addEventListener("command", () => {
    
    ... ... @@ -25,7 +23,14 @@ window.addEventListener(
    25 23
           let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(
    
    26 24
             Ci.nsIClipboardHelper
    
    27 25
           );
    
    28
    -      clipboard.copyString(logText.value);
    
    26
    +      // The copied text should match the text content the user would get if
    
    27
    +      // they hand-selected the entire table.
    
    28
    +      clipboard.copyString(
    
    29
    +        Array.from(
    
    30
    +          this._logTable.querySelectorAll("td"),
    
    31
    +          el => el.textContent
    
    32
    +        ).join("\n")
    
    33
    +      );
    
    29 34
     
    
    30 35
           copyLogButton.setAttribute(
    
    31 36
             "data-l10n-id",
    
    ... ... @@ -47,13 +52,79 @@ window.addEventListener(
    47 52
           }, RESTORE_TIME);
    
    48 53
         });
    
    49 54
     
    
    55
    +    // Intercept the copy event.
    
    56
    +    // NOTE: We attach this to the window rather than the _logTable because if
    
    57
    +    // the whole table is selected it will not receive the "copy" event.
    
    58
    +    window.addEventListener("copy", event => {
    
    59
    +      event.preventDefault();
    
    60
    +      event.clipboardData.setData(
    
    61
    +        "text",
    
    62
    +        // By default the selected text will insert "\n\t" between the <td>
    
    63
    +        // elements, which separates the timestamp from the message column.
    
    64
    +        // We drop this "\t" character, to just keep the "\n".
    
    65
    +        window.getSelection().toString().replace(/^\t/gm, "")
    
    66
    +      );
    
    67
    +    });
    
    68
    +
    
    50 69
         // A waiting state should not be needed at this point.
    
    51 70
         // Also, we probably cannot even arrive here if the provider failed to
    
    52 71
         // initialize, otherwise we could use a try/catch, and write the exception
    
    53 72
         // text in the logs, instead.
    
    54
    -    TorProviderBuilder.build().then(
    
    55
    -      provider => (logText.value = provider.getLog())
    
    56
    -    );
    
    73
    +    TorProviderBuilder.build().then(provider => {
    
    74
    +      Services.obs.addObserver(this, TorProviderTopics.TorLog);
    
    75
    +      window.addEventListener(
    
    76
    +        "unload",
    
    77
    +        () => {
    
    78
    +          Services.obs.removeObserver(this, TorProviderTopics.TorLog);
    
    79
    +        },
    
    80
    +        { once: true }
    
    81
    +      );
    
    82
    +
    
    83
    +      for (const logEntry of provider.getLog()) {
    
    84
    +        this.addLogEntry(logEntry, true);
    
    85
    +      }
    
    86
    +      // Set the initial scroll to the bottom.
    
    87
    +      this._logTable.scrollTo({
    
    88
    +        top: this._logTable.scrollTopMax,
    
    89
    +        behaviour: "instant",
    
    90
    +      });
    
    91
    +    });
    
    92
    +  },
    
    93
    +
    
    94
    +  observe(subject, topic) {
    
    95
    +    if (topic === TorProviderTopics.TorLog) {
    
    96
    +      this.addLogEntry(subject.wrappedJSObject, false);
    
    97
    +    }
    
    98
    +  },
    
    99
    +
    
    100
    +  addLogEntry(logEntry, initial) {
    
    101
    +    const timeEl = document.createElement("td");
    
    102
    +    timeEl.textContent = logEntry.timestamp;
    
    103
    +    timeEl.classList.add("time");
    
    104
    +    const messageEl = document.createElement("td");
    
    105
    +    messageEl.textContent = `[${logEntry.type}] ${logEntry.msg}`;
    
    106
    +    messageEl.classList.add("message");
    
    107
    +
    
    108
    +    const row = document.createElement("tr");
    
    109
    +    row.append(timeEl, messageEl);
    
    110
    +
    
    111
    +    // If this is a new entry, and we are currently scrolled to the bottom (with
    
    112
    +    // a 6px allowance) we keep the scroll position at the bottom to "follow"
    
    113
    +    // the updates.
    
    114
    +    const scrollToBottom =
    
    115
    +      !initial && this._logTable.scrollTop >= this._logTable.scrollTopMax - 6;
    
    116
    +
    
    117
    +    this._logBody.append(row);
    
    118
    +    if (scrollToBottom) {
    
    119
    +      this._logTable.scrollTo({ top: this._logTable.scrollTopMax });
    
    120
    +    }
    
    121
    +  },
    
    122
    +};
    
    123
    +
    
    124
    +window.addEventListener(
    
    125
    +  "DOMContentLoaded",
    
    126
    +  () => {
    
    127
    +    gTorLogDialog.init();
    
    57 128
       },
    
    58 129
       { once: true }
    
    59 130
     );

  • browser/components/torpreferences/content/torLogDialog.xhtml
    ... ... @@ -23,10 +23,33 @@
    23 23
     
    
    24 24
         <script src="chrome://browser/content/torpreferences/torLogDialog.js" />
    
    25 25
     
    
    26
    -    <html:textarea
    
    27
    -      id="torPreferences-torDialog-textarea"
    
    28
    -      multiline="true"
    
    29
    -      readonly="true"
    
    30
    -    />
    
    26
    +    <!-- We use a <table> element rather than a <ol>. A table structure allows
    
    27
    +       - screen reader users to navigate within one column so they can avoid the
    
    28
    +       - readback of the timestamp on every row. See tor-browser#43328.
    
    29
    +       - NOTE: We add the explicit role="table". Whilst this should not be
    
    30
    +       - neccessary, nor is it recommended, some screen readers (Orca 46) do not
    
    31
    +       - read out the default table role if the CSS `display` is not `table`.
    
    32
    +       - NOTE: Even though this table is updated with live information, we do
    
    33
    +       - not want to make this an aria-live area or use a "log updated"
    
    34
    +       - notification because the log messages are potentially busy.
    
    35
    +       - Moreover, the live updates is a convience so that the log doesn't need
    
    36
    +       - to be manually refreshed, rather than important information.
    
    37
    +       - NOTE: We add a tabindex=0 to make this element focusable with or
    
    38
    +       - without the overflow. This also makes the table the the initial focus
    
    39
    +       - of the dialog.
    
    40
    +       - NOTE: We add lang="en" and dir="ltr" to the <tbody> since the content
    
    41
    +       - of the log is in English. We do not add this to the <table> element
    
    42
    +       - since its aria-label is localised and we want the scrollbar to match
    
    43
    +       - the locale direction.
    
    44
    +       - NOTE: We avoid any whitespace between the <table> and <tbody> to ensure
    
    45
    +       - it does not contribute to the text content when the top of the table is
    
    46
    +       - manually copied. -->
    
    47
    +    <html:table
    
    48
    +      id="tor-log-table"
    
    49
    +      role="table"
    
    50
    +      data-l10n-id="tor-log-dialog-table"
    
    51
    +      tabindex="0"
    
    52
    +      ><html:tbody id="tor-log-body" lang="en" dir="ltr"></html:tbody
    
    53
    +    ></html:table>
    
    31 54
       </dialog>
    
    32 55
     </window>

  • browser/components/torpreferences/content/torPreferences.css
    ... ... @@ -1058,12 +1058,39 @@ groupbox#torPreferences-bridges-group textarea {
    1058 1058
     }
    
    1059 1059
     
    
    1060 1060
     /* Tor logs dialog */
    
    1061
    -textarea#torPreferences-torDialog-textarea {
    
    1061
    +#tor-log-table {
    
    1062 1062
       flex: 1 0 auto;
    
    1063
    -  font-family: monospace;
    
    1064
    -  font-size: 0.8em;
    
    1065
    -  white-space: pre;
    
    1066 1063
       overflow: auto;
    
    1067
    -  /* 10 lines */
    
    1068 1064
       min-height: 20em;
    
    1065
    +  height: 20em;
    
    1066
    +  display: flex;
    
    1067
    +  flex-direction: column;
    
    1068
    +  padding: var(--space-small);
    
    1069
    +  margin-block-end: 4px;
    
    1070
    +  border: 1px solid var(--in-content-box-border-color);
    
    1071
    +  border-radius: var(--border-radius-small);
    
    1072
    +  font-size: var(--font-size-small);
    
    1073
    +}
    
    1074
    +
    
    1075
    +#tor-log-body,
    
    1076
    +#tor-log-table tr {
    
    1077
    +  display: contents;
    
    1078
    +}
    
    1079
    +
    
    1080
    +#tor-log-table td {
    
    1081
    +  flex: 0 0 auto;
    
    1082
    +  padding: 0;
    
    1083
    +}
    
    1084
    +
    
    1085
    +#tor-log-table td.time {
    
    1086
    +  color: var(--text-color-deemphasized);
    
    1087
    +  margin-block-end: var(--space-xsmall);
    
    1088
    +}
    
    1089
    +
    
    1090
    +#tor-log-table td.message {
    
    1091
    +  overflow-wrap: anywhere;
    
    1092
    +}
    
    1093
    +
    
    1094
    +#tor-log-table tr:not(:last-of-type) td.message {
    
    1095
    +  margin-block-end: var(--space-medium);
    
    1069 1096
     }

  • toolkit/components/tor-launcher/TorProvider.sys.mjs
    ... ... @@ -512,14 +512,12 @@ export class TorProvider {
    512 512
       }
    
    513 513
     
    
    514 514
       /**
    
    515
    -   * Returns captured log message as a text string (one message per line).
    
    515
    +   * Returns captured log messages.
    
    516 516
        *
    
    517
    -   * @returns {string} The logs we collected from the tor daemon so far
    
    517
    +   * @returns {LogEntry[]} The logs we collected from the tor daemon so far.
    
    518 518
        */
    
    519 519
       getLog() {
    
    520
    -    return this.#logs
    
    521
    -      .map(logObj => `${logObj.timestamp} [${logObj.type}] ${logObj.msg}`)
    
    522
    -      .join(TorLauncherUtil.isWindows ? "\r\n" : "\n");
    
    520
    +    return structuredClone(this.#logs);
    
    523 521
       }
    
    524 522
     
    
    525 523
       /**
    

  • toolkit/locales/en-US/toolkit/global/tor-browser.ftl
    ... ... @@ -423,6 +423,9 @@ tor-view-log-button = View log…
    423 423
     # "log" is a noun, referring to the recorded text output of the Tor process.
    
    424 424
     tor-log-dialog-title =
    
    425 425
         .title = Tor log
    
    426
    +# The screen-reader name for the Tor log table. Should match the dialog title.
    
    427
    +tor-log-dialog-table =
    
    428
    +    .aria-label = { tor-log-dialog-title.title }
    
    426 429
     # "log" is a noun, referring to the recorded text output of the Tor process.
    
    427 430
     tor-log-dialog-copy-button =
    
    428 431
         .label = Copy Tor log to clipboard