tor-browser

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

aboutTabCrashed.js (7315B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 var AboutTabCrashed = {
      6  /**
      7   * This can be set to true once this page receives a message from the
      8   * parent saying whether or not a crash report is available.
      9   */
     10  hasReport: false,
     11 
     12  /**
     13   * The messages that we might receive from the parent.
     14   */
     15  MESSAGES: ["SetCrashReportAvailable", "CrashReportSent", "UpdateCount"],
     16 
     17  /**
     18   * Items for which we will listen for click events.
     19   */
     20  CLICK_TARGETS: ["closeTab", "restoreTab", "restoreAll", "sendReport"],
     21 
     22  /**
     23   * Returns information about this crashed tab.
     24   *
     25   * @return (Object) An object with the following properties:
     26   *           title (String):
     27   *             The title of the page that crashed.
     28   *           URL (String):
     29   *             The URL of the page that crashed.
     30   */
     31  get pageData() {
     32    delete this.pageData;
     33 
     34    let URL = document.documentURI;
     35    let queryString = URL.replace(/^about:tabcrashed?e=tabcrashed/, "");
     36 
     37    let titleMatch = queryString.match(/d=([^&]*)/);
     38    let URLMatch = queryString.match(/u=([^&]*)/);
     39 
     40    return (this.pageData = {
     41      title:
     42        titleMatch && titleMatch[1] ? decodeURIComponent(titleMatch[1]) : "",
     43      URL: URLMatch && URLMatch[1] ? decodeURIComponent(URLMatch[1]) : "",
     44    });
     45  },
     46 
     47  init() {
     48    addEventListener("DOMContentLoaded", this);
     49 
     50    document.title = this.pageData.title;
     51  },
     52 
     53  receiveMessage(message) {
     54    switch (message.name) {
     55      case "UpdateCount": {
     56        this.setMultiple(message.data.count > 1);
     57        break;
     58      }
     59      case "SetCrashReportAvailable": {
     60        this.onSetCrashReportAvailable(message);
     61        break;
     62      }
     63      case "CrashReportSent": {
     64        this.onCrashReportSent();
     65        break;
     66      }
     67    }
     68  },
     69 
     70  handleEvent(event) {
     71    switch (event.type) {
     72      case "DOMContentLoaded": {
     73        this.onDOMContentLoaded();
     74        break;
     75      }
     76      case "click": {
     77        this.onClick(event);
     78        break;
     79      }
     80    }
     81  },
     82 
     83  onDOMContentLoaded() {
     84    this.MESSAGES.forEach(msg =>
     85      RPMAddMessageListener(msg, this.receiveMessage.bind(this))
     86    );
     87 
     88    this.CLICK_TARGETS.forEach(targetID => {
     89      let el = document.getElementById(targetID);
     90      el.addEventListener("click", this);
     91    });
     92 
     93    // Error pages are loaded as LOAD_BACKGROUND, so they don't get load events.
     94    let event = new CustomEvent("AboutTabCrashedLoad", { bubbles: true });
     95    document.dispatchEvent(event);
     96 
     97    RPMSendAsyncMessage("Load");
     98  },
     99 
    100  onClick(event) {
    101    switch (event.target.id) {
    102      case "closeTab": {
    103        this.sendMessage("closeTab");
    104        break;
    105      }
    106 
    107      case "restoreTab": {
    108        this.sendMessage("restoreTab");
    109        break;
    110      }
    111 
    112      case "restoreAll": {
    113        this.sendMessage("restoreAll");
    114        break;
    115      }
    116 
    117      case "sendReport": {
    118        this.showCrashReportUI(event.target.checked);
    119        break;
    120      }
    121    }
    122  },
    123 
    124  /**
    125   * After this page tells the parent that it has loaded, the parent
    126   * will respond with whether or not a crash report is available. This
    127   * method handles that message.
    128   *
    129   * @param message
    130   *        The message from the parent, which should contain a data
    131   *        Object property with the following properties:
    132   *
    133   *        hasReport (bool):
    134   *          Whether or not there is a crash report.
    135   *
    136   *        sendReport (bool):
    137   *          Whether or not the the user prefers to send the report
    138   *          by default.
    139   *
    140   *        includeURL (bool):
    141   *          Whether or not the user prefers to send the URL of
    142   *          the tab that crashed.
    143   *
    144   *        requestAutoSubmit (bool):
    145   *          Whether or not we should ask the user to automatically
    146   *          submit backlogged crash reports.
    147   */
    148  onSetCrashReportAvailable(message) {
    149    let data = message.data;
    150 
    151    if (data.hasReport) {
    152      this.hasReport = true;
    153      document.documentElement.classList.add("crashDumpAvailable");
    154 
    155      document.getElementById("sendReport").checked = data.sendReport;
    156      document.getElementById("includeURL").checked = data.includeURL;
    157 
    158      this.showCrashReportUI(data.sendReport);
    159    } else {
    160      this.showCrashReportUI(false);
    161    }
    162 
    163    if (data.requestAutoSubmit) {
    164      document.getElementById("requestAutoSubmit").hidden = false;
    165    }
    166 
    167    let event = new CustomEvent("AboutTabCrashedReady", { bubbles: true });
    168    document.dispatchEvent(event);
    169  },
    170 
    171  /**
    172   * Handler for when the parent reports that the crash report associated
    173   * with this about:tabcrashed page has been sent.
    174   */
    175  onCrashReportSent() {
    176    document.documentElement.classList.remove("crashDumpAvailable");
    177    document.documentElement.classList.add("crashDumpSubmitted");
    178  },
    179 
    180  /**
    181   * Toggles the display of the crash report form.
    182   *
    183   * @param shouldShow (bool)
    184   *        True if the crash report form should be shown
    185   */
    186  showCrashReportUI(shouldShow) {
    187    let options = document.getElementById("options");
    188    options.hidden = !shouldShow;
    189  },
    190 
    191  /**
    192   * Toggles whether or not the page is one of several visible pages
    193   * showing the crash reporter. This controls some of the language
    194   * on the page, along with what the "primary" button is.
    195   *
    196   * @param hasMultiple (bool)
    197   *        True if there are multiple crash report pages being shown.
    198   */
    199  setMultiple(hasMultiple) {
    200    let main = document.getElementById("main");
    201    main.setAttribute("multiple", hasMultiple);
    202 
    203    let restoreTab = document.getElementById("restoreTab");
    204 
    205    // The "Restore All" button has the "primary" class by default, so
    206    // we only need to modify the "Restore Tab" button.
    207    if (hasMultiple) {
    208      restoreTab.classList.remove("primary");
    209    } else {
    210      restoreTab.classList.add("primary");
    211    }
    212  },
    213 
    214  /**
    215   * Sends a message to the parent in response to the user choosing
    216   * one of the actions available on the page. This might also send up
    217   * crash report information if the user has chosen to submit a crash
    218   * report.
    219   *
    220   * @param messageName (String)
    221   *        The message to send to the parent
    222   */
    223  sendMessage(messageName) {
    224    let comments = "";
    225    let URL = "";
    226    let sendReport = false;
    227    let includeURL = false;
    228    let autoSubmit = false;
    229 
    230    if (this.hasReport) {
    231      sendReport = document.getElementById("sendReport").checked;
    232      if (sendReport) {
    233        comments = document.getElementById("comments").value.trim();
    234 
    235        includeURL = document.getElementById("includeURL").checked;
    236        if (includeURL) {
    237          URL = this.pageData.URL.trim();
    238        }
    239      }
    240    }
    241 
    242    let requestAutoSubmit = document.getElementById("requestAutoSubmit");
    243    if (requestAutoSubmit.hidden) {
    244      // The checkbox is hidden if the user has already opted in to sending
    245      // backlogged crash reports.
    246      autoSubmit = true;
    247    } else {
    248      autoSubmit = document.getElementById("autoSubmit").checked;
    249    }
    250 
    251    RPMSendAsyncMessage(messageName, {
    252      sendReport,
    253      comments,
    254      includeURL,
    255      URL,
    256      autoSubmit,
    257      hasReport: this.hasReport,
    258    });
    259  },
    260 };
    261 
    262 AboutTabCrashed.init();