tor-browser

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

sidebar-page.mjs (6292B)


      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 const lazy = {};
      6 
      7 import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
      8 import { html } from "chrome://global/content/vendor/lit.all.mjs";
      9 // eslint-disable-next-line mozilla/reject-import-system-module-from-non-system
     10 import { PlacesUtils } from "resource://gre/modules/PlacesUtils.sys.mjs";
     11 // eslint-disable-next-line import/no-unassigned-import
     12 import "chrome://browser/content/sidebar/sidebar-panel-header.mjs";
     13 
     14 ChromeUtils.defineESModuleGetters(lazy, {
     15  BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs",
     16  PlacesUIUtils: "moz-src:///browser/components/places/PlacesUIUtils.sys.mjs",
     17 });
     18 
     19 export class SidebarPage extends MozLitElement {
     20  constructor() {
     21    super();
     22    this.clearDocument = this.clearDocument.bind(this);
     23  }
     24 
     25  connectedCallback() {
     26    super.connectedCallback();
     27    this.ownerGlobal.addEventListener("beforeunload", this.clearDocument);
     28    this.ownerGlobal.addEventListener("unload", this.clearDocument);
     29 
     30    this._contextMenu = this.topWindow.SidebarController.currentContextMenu;
     31  }
     32 
     33  disconnectedCallback() {
     34    super.disconnectedCallback();
     35    this.ownerGlobal.removeEventListener("beforeunload", this.clearDocument);
     36    this.ownerGlobal.removeEventListener("unload", this.clearDocument);
     37  }
     38 
     39  get topWindow() {
     40    return this.ownerGlobal.top;
     41  }
     42 
     43  get sidebarController() {
     44    return this.topWindow.SidebarController;
     45  }
     46 
     47  addContextMenuListeners() {
     48    this.addEventListener("contextmenu", this);
     49    this._contextMenu.addEventListener("command", this);
     50    this._contextMenu.addEventListener(
     51      "popupshowing",
     52      this.placesContextShowing
     53    );
     54    this._contextMenu.addEventListener("popuphiding", this.placesContextHiding);
     55  }
     56 
     57  removeContextMenuListeners() {
     58    this.removeEventListener("contextmenu", this);
     59    this._contextMenu.removeEventListener("command", this);
     60    this._contextMenu.removeEventListener(
     61      "popupshowing",
     62      this.placesContextShowing
     63    );
     64    this._contextMenu.removeEventListener(
     65      "popuphiding",
     66      this.placesContextHiding
     67    );
     68  }
     69 
     70  addSidebarFocusedListeners() {
     71    this.topWindow.addEventListener("SidebarFocused", this);
     72  }
     73 
     74  removeSidebarFocusedListeners() {
     75    this.topWindow.removeEventListener("SidebarFocused", this);
     76  }
     77 
     78  handleEvent(e) {
     79    switch (e.type) {
     80      case "contextmenu":
     81        this.handleContextMenuEvent?.(e);
     82        break;
     83      case "command":
     84        this.handleCommandEvent?.(e);
     85        break;
     86      case "SidebarFocused":
     87        this.handleSidebarFocusedEvent?.(e);
     88        break;
     89    }
     90  }
     91 
     92  placesContextShowing(e) {
     93    lazy.PlacesUIUtils.placesContextShowing(e);
     94  }
     95 
     96  placesContextHiding(e) {
     97    lazy.PlacesUIUtils.placesContextHiding(e);
     98  }
     99 
    100  /**
    101   * Check if this event comes from an element of the specified type. If it
    102   * does, return that element.
    103   *
    104   * @param {Event} e
    105   *   The event to check.
    106   * @param {string} localName
    107   *   The name of the element to match.
    108   * @returns {Element | null}
    109   *   The matching element, or `null` if no match is found.
    110   */
    111  findTriggerNode(e, localName) {
    112    let elements = [
    113      e.explicitOriginalTarget,
    114      e.originalTarget.flattenedTreeParentNode,
    115      // Event might be in shadow DOM, check the host element.
    116      e.explicitOriginalTarget.flattenedTreeParentNode.getRootNode().host,
    117      e.originalTarget.flattenedTreeParentNode.getRootNode().host,
    118    ];
    119    for (let el of elements) {
    120      if (el?.localName == localName) {
    121        return el;
    122      }
    123    }
    124    return null;
    125  }
    126 
    127  /**
    128   * Handle a command if it is a common one that is used in multiple pages.
    129   * Commands specific to a page should be handled in a subclass.
    130   *
    131   * @param {Event} e
    132   *   The event to handle.
    133   */
    134  handleCommandEvent(e) {
    135    switch (e.target.id) {
    136      case "sidebar-history-context-open-in-tab":
    137        this.topWindow.openTrustedLinkIn(this.triggerNode.url, "tab");
    138        break;
    139      case "sidebar-history-context-forget-site":
    140        this.forgetAboutThisSite().catch(console.error);
    141        break;
    142      case "sidebar-history-context-open-in-window":
    143      case "sidebar-synced-tabs-context-open-in-window":
    144        this.topWindow.openTrustedLinkIn(this.triggerNode.url, "window", {
    145          private: false,
    146        });
    147        break;
    148      case "sidebar-history-context-open-in-private-window":
    149      case "sidebar-synced-tabs-context-open-in-private-window":
    150        this.topWindow.openTrustedLinkIn(this.triggerNode.url, "window", {
    151          private: true,
    152        });
    153        break;
    154      case "sidebar-history-context-copy-link":
    155      case "sidebar-synced-tabs-context-copy-link":
    156        lazy.BrowserUtils.copyLink(
    157          this.triggerNode.url,
    158          this.triggerNode.title
    159        );
    160        break;
    161      case "sidebar-synced-tabs-context-bookmark-tab":
    162      case "sidebar-history-context-bookmark-page":
    163        this.topWindow.PlacesCommandHook.bookmarkLink(
    164          this.triggerNode.url,
    165          this.triggerNode.title
    166        );
    167        break;
    168    }
    169  }
    170 
    171  async forgetAboutThisSite() {
    172    let host;
    173    if (PlacesUtils.nodeIsHost(this.triggerNode)) {
    174      host = this.triggerNode.query.domain;
    175    } else {
    176      host = Services.io.newURI(this.triggerNode.url).host;
    177    }
    178    let baseDomain;
    179    try {
    180      baseDomain = Services.eTLD.getBaseDomainFromHost(host);
    181    } catch (e) {
    182      // If there is no baseDomain we fall back to host
    183    }
    184    await this.topWindow.gDialogBox.open(
    185      "chrome://browser/content/places/clearDataForSite.xhtml",
    186      { host, hostOrBaseDomain: baseDomain ?? host }
    187    );
    188  }
    189 
    190  /**
    191   * Clear out the document so the disconnectedCallback() will trigger properly
    192   * and all of the custom elements can cleanup.
    193   */
    194  clearDocument() {
    195    this.ownerGlobal.document.body.textContent = "";
    196  }
    197 
    198  /**
    199   * The common stylesheet for all sidebar pages.
    200   *
    201   * @returns {TemplateResult}
    202   */
    203  stylesheet() {
    204    return html`
    205      <link
    206        rel="stylesheet"
    207        href="chrome://browser/content/sidebar/sidebar.css"
    208      />
    209    `;
    210  }
    211 }