tor-browser

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

opentabs-splitview.mjs (4574B)


      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 import { html } from "chrome://global/content/vendor/lit.all.mjs";
      6 import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
      7 
      8 const lazy = {};
      9 const BROWSER_NEW_TAB_URL = "about:newtab";
     10 const BROWSER_OPEN_TABS_URL = "about:opentabs";
     11 
     12 ChromeUtils.defineESModuleGetters(lazy, {
     13  OpenTabsController: "resource:///modules/OpenTabsController.sys.mjs",
     14  NonPrivateTabs: "resource:///modules/OpenTabs.sys.mjs",
     15  getTabsTargetForWindow: "resource:///modules/OpenTabs.sys.mjs",
     16  PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
     17 });
     18 
     19 /**
     20 * A collection of open, unpinned, unsplit tabs for the current by window.
     21 */
     22 class OpenTabsInSplitView extends MozLitElement {
     23  currentWindow = null;
     24  openTabsTarget = null;
     25 
     26  constructor() {
     27    super();
     28    this.currentWindow =
     29      this.ownerGlobal.top.browsingContext.embedderWindowGlobal.browsingContext.window;
     30    if (lazy.PrivateBrowsingUtils.isWindowPrivate(this.currentWindow)) {
     31      this.openTabsTarget = lazy.getTabsTargetForWindow(this.currentWindow);
     32    } else {
     33      this.openTabsTarget = lazy.NonPrivateTabs;
     34    }
     35    this.controller = new lazy.OpenTabsController(this, {
     36      component: "splitview",
     37    });
     38    this.listenersAdded = false;
     39  }
     40 
     41  static queries = {
     42    sidebarTabList: "sidebar-tab-list",
     43  };
     44 
     45  connectedCallback() {
     46    super.connectedCallback();
     47    this.addListeners(true);
     48    this.currentWindow.addEventListener("TabSelect", this);
     49  }
     50 
     51  disconnectedCallback() {
     52    super.disconnectedCallback();
     53    this.removeListeners();
     54    this.currentWindow.removeEventListener("TabSelect", this);
     55  }
     56 
     57  addListeners(skipUpdate) {
     58    if (!this.listenersAdded) {
     59      this.openTabsTarget.addEventListener("TabChange", this);
     60      if (!skipUpdate) {
     61        this.requestUpdate();
     62      }
     63      this.listenersAdded = true;
     64    }
     65  }
     66 
     67  removeListeners() {
     68    if (this.listenersAdded) {
     69      this.openTabsTarget.removeEventListener("TabChange", this);
     70      this.listenersAdded = false;
     71    }
     72  }
     73 
     74  handleEvent(e) {
     75    switch (e.type) {
     76      case "TabChange":
     77        this.requestUpdate();
     78        break;
     79      case "TabSelect":
     80        if (this.currentSplitView) {
     81          this.addListeners();
     82          this.requestUpdate();
     83        } else {
     84          this.removeListeners();
     85        }
     86        break;
     87    }
     88  }
     89 
     90  getWindow() {
     91    return window.browsingContext.embedderWindowGlobal.browsingContext.window;
     92  }
     93 
     94  get currentSplitView() {
     95    const { gBrowser } = this.getWindow();
     96    return gBrowser.selectedTab.splitview;
     97  }
     98 
     99  onTabListRowClick(event) {
    100    const { gBrowser } = this.getWindow();
    101    const tab = event.originalTarget.tabElement;
    102    if (this.currentSplitView) {
    103      this.currentSplitView.replaceTab(gBrowser.selectedTab, tab);
    104    }
    105  }
    106 
    107  get nonSplitViewUnpinnedTabs() {
    108    const { gBrowser } = this.getWindow();
    109    return gBrowser.tabs.filter(tab => {
    110      return (
    111        !tab.hidden &&
    112        !tab.pinned &&
    113        !tab.splitview &&
    114        tab?.linkedBrowser?.currentURI?.spec !== BROWSER_OPEN_TABS_URL
    115      );
    116    });
    117  }
    118 
    119  render() {
    120    const { gBrowser } = this.getWindow();
    121    let tabs = this.nonSplitViewUnpinnedTabs;
    122    if (
    123      !tabs.length ||
    124      (gBrowser.selectedTab.linkedBrowser.currentURI.spec ===
    125        BROWSER_OPEN_TABS_URL &&
    126        !this.currentSplitView)
    127    ) {
    128      // If there are no unpinned, unsplit tabs to display or about:opentabs
    129      // is opened outside of a split view, open about:newtab instead
    130      this.getWindow().openTrustedLinkIn(BROWSER_NEW_TAB_URL, "current");
    131    }
    132    return html`
    133      <link
    134        rel="stylesheet"
    135        href="chrome://browser/content/tabbrowser/opentabs-splitview.css"
    136      />
    137      <link
    138        rel="stylesheet"
    139        href="chrome://browser/content/firefoxview/firefoxview.css"
    140      />
    141      <moz-card>
    142        <sidebar-tab-list
    143          maxTabsLength="-1"
    144          .tabItems=${this.controller.getTabListItems(tabs)}
    145          @fxview-tab-list-primary-action=${this.onTabListRowClick}
    146        >
    147        </sidebar-tab-list>
    148      </moz-card>
    149    `;
    150  }
    151 }
    152 customElements.define("splitview-opentabs", OpenTabsInSplitView);
    153 
    154 window.addEventListener(
    155  "unload",
    156  () => {
    157    // Clear out the document so the disconnectedCallback will trigger
    158    // properly
    159    document.body.textContent = "";
    160  },
    161  { once: true }
    162 );