tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

torLogDialog.js (3921B)


      1 "use strict";
      2 
      3 const { setTimeout, clearTimeout } = ChromeUtils.importESModule(
      4  "resource://gre/modules/Timer.sys.mjs"
      5 );
      6 
      7 const { TorProviderBuilder, TorProviderTopics } = ChromeUtils.importESModule(
      8  "resource://gre/modules/TorProviderBuilder.sys.mjs"
      9 );
     10 
     11 const gTorLogDialog = {
     12  init() {
     13    const dialog = document.getElementById("torPreferences-torLog-dialog");
     14    const copyLogButton = dialog.getButton("extra1");
     15    copyLogButton.setAttribute("data-l10n-id", "tor-log-dialog-copy-button");
     16 
     17    this._logTable = document.getElementById("tor-log-table");
     18    this._logBody = document.getElementById("tor-log-body");
     19 
     20    let restoreButtonTimeout = null;
     21    copyLogButton.addEventListener("command", () => {
     22      // Copy tor log messages to the system clipboard.
     23      let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(
     24        Ci.nsIClipboardHelper
     25      );
     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      );
     34 
     35      copyLogButton.setAttribute(
     36        "data-l10n-id",
     37        "tor-log-dialog-copy-button-copied"
     38      );
     39      copyLogButton.classList.add("primary");
     40 
     41      const RESTORE_TIME = 1200;
     42      if (restoreButtonTimeout !== null) {
     43        clearTimeout(restoreButtonTimeout);
     44      }
     45      restoreButtonTimeout = setTimeout(() => {
     46        copyLogButton.setAttribute(
     47          "data-l10n-id",
     48          "tor-log-dialog-copy-button"
     49        );
     50        copyLogButton.classList.remove("primary");
     51        restoreButtonTimeout = null;
     52      }, RESTORE_TIME);
     53    });
     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 
     69    Services.obs.addObserver(this, TorProviderTopics.TorLog);
     70    window.addEventListener(
     71      "unload",
     72      () => {
     73        Services.obs.removeObserver(this, TorProviderTopics.TorLog);
     74      },
     75      { once: true }
     76    );
     77 
     78    for (const logEntry of TorProviderBuilder.getLog()) {
     79      this.addLogEntry(logEntry, true);
     80    }
     81    // Set the initial scroll to the bottom.
     82    this._logTable.scrollTo({
     83      top: this._logTable.scrollTopMax,
     84      behaviour: "instant",
     85    });
     86  },
     87 
     88  observe(subject, topic) {
     89    if (topic === TorProviderTopics.TorLog) {
     90      this.addLogEntry(subject.wrappedJSObject, false);
     91    }
     92  },
     93 
     94  addLogEntry(logEntry, initial) {
     95    const timeEl = document.createElement("td");
     96    timeEl.textContent = logEntry.timestamp;
     97    timeEl.classList.add("time");
     98    const messageEl = document.createElement("td");
     99    messageEl.textContent = `[${logEntry.type}] ${logEntry.msg}`;
    100    messageEl.classList.add("message");
    101 
    102    const row = document.createElement("tr");
    103    row.append(timeEl, messageEl);
    104 
    105    // If this is a new entry, and we are currently scrolled to the bottom (with
    106    // a 6px allowance) we keep the scroll position at the bottom to "follow"
    107    // the updates.
    108    const scrollToBottom =
    109      !initial && this._logTable.scrollTop >= this._logTable.scrollTopMax - 6;
    110 
    111    this._logBody.append(row);
    112    if (scrollToBottom) {
    113      this._logTable.scrollTo({ top: this._logTable.scrollTopMax });
    114    }
    115  },
    116 };
    117 
    118 window.addEventListener(
    119  "DOMContentLoaded",
    120  () => {
    121    gTorLogDialog.init();
    122  },
    123  { once: true }
    124 );