tor-browser

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

firefoxview.mjs (5327B)


      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 let pageList = [];
      6 let viewsDeck = null;
      7 let pageNav = null;
      8 let activeComponent = null;
      9 let searchKeyboardShortcut = null;
     10 
     11 const { topChromeWindow } = window.browsingContext;
     12 
     13 function onHashChange() {
     14  let view = document.location?.hash.substring(1);
     15  if (!view || !pageList.includes(view)) {
     16    view = "recentbrowsing";
     17  }
     18  changeView(view);
     19 }
     20 
     21 function changeView(view) {
     22  viewsDeck.selectedViewName = view;
     23  pageNav.currentView = view;
     24 }
     25 
     26 function onViewsDeckViewChange() {
     27  for (const child of viewsDeck.children) {
     28    if (child.getAttribute("name") == viewsDeck.selectedViewName) {
     29      child.enter();
     30      activeComponent = child;
     31    } else {
     32      child.exit();
     33    }
     34  }
     35 }
     36 
     37 function recordNavigationTelemetry(source, eventTarget) {
     38  let view = "recentbrowsing";
     39  if (source === "category-navigation") {
     40    view = eventTarget.parentNode.currentView;
     41  } else if (source === "view-all") {
     42    view = eventTarget.shortPageName;
     43  }
     44  // Record telemetry
     45  Glean.firefoxviewNext.changePageNavigation.record({
     46    page: view,
     47    source,
     48  });
     49 }
     50 
     51 async function updateSearchTextboxSize() {
     52  const msgs = [
     53    { id: "firefoxview-search-text-box-recentbrowsing" },
     54    { id: "firefoxview-search-text-box-opentabs" },
     55    { id: "firefoxview-search-text-box-recentlyclosed" },
     56    { id: "firefoxview-search-text-box-tabs" },
     57    { id: "firefoxview-search-text-box-history" },
     58  ];
     59  let maxLength = 30;
     60  for (const msg of await document.l10n.formatMessages(msgs)) {
     61    const placeholder = msg.attributes[0].value;
     62    maxLength = Math.max(maxLength, placeholder.length);
     63  }
     64  for (const child of viewsDeck.children) {
     65    child.searchTextboxSize = maxLength;
     66  }
     67 }
     68 
     69 async function updateSearchKeyboardShortcut() {
     70  const [message] = await topChromeWindow.document.l10n.formatMessages([
     71    { id: "find-shortcut" },
     72  ]);
     73  const key = message.attributes[0].value;
     74  searchKeyboardShortcut = key.toLocaleLowerCase();
     75 }
     76 
     77 function updateSyncVisibility() {
     78  const syncEnabled = Services.prefs.getBoolPref(
     79    "identity.fxaccounts.enabled",
     80    false
     81  );
     82  for (const el of document.querySelectorAll(".sync-ui-item")) {
     83    el.hidden = !syncEnabled;
     84  }
     85 }
     86 
     87 window.addEventListener("DOMContentLoaded", async () => {
     88  recordEnteredTelemetry();
     89 
     90  pageNav = document.querySelector("moz-page-nav");
     91  viewsDeck = document.querySelector("named-deck");
     92 
     93  for (const item of pageNav.pageNavButtons) {
     94    pageList.push(item.getAttribute("view"));
     95  }
     96  window.addEventListener("hashchange", onHashChange);
     97  window.addEventListener("change-view", function (event) {
     98    location.hash = event.target.getAttribute("view");
     99    window.scrollTo(0, 0);
    100    recordNavigationTelemetry("category-navigation", event.target);
    101  });
    102  window.addEventListener("card-container-view-all", function (event) {
    103    recordNavigationTelemetry("view-all", event.originalTarget);
    104  });
    105 
    106  viewsDeck.addEventListener("view-changed", onViewsDeckViewChange);
    107 
    108  // set the initial state
    109  onHashChange();
    110  onViewsDeckViewChange();
    111  await updateSearchTextboxSize();
    112  await updateSearchKeyboardShortcut();
    113  updateSyncVisibility();
    114 
    115  if (Cu.isInAutomation) {
    116    Services.obs.notifyObservers(null, "firefoxview-entered");
    117  }
    118 });
    119 
    120 document.addEventListener("visibilitychange", () => {
    121  if (document.visibilityState === "visible") {
    122    recordEnteredTelemetry();
    123    if (Cu.isInAutomation) {
    124      // allow all the component visibilitychange handlers to execute before notifying
    125      requestAnimationFrame(() => {
    126        Services.obs.notifyObservers(null, "firefoxview-entered");
    127      });
    128    }
    129  }
    130 });
    131 
    132 function recordEnteredTelemetry() {
    133  Glean.firefoxviewNext.enteredFirefoxview.record({
    134    page: document.location?.hash?.substring(1) || "recentbrowsing",
    135  });
    136 }
    137 
    138 document.addEventListener("keydown", e => {
    139  if (e.getModifierState("Accel") && e.key === searchKeyboardShortcut) {
    140    activeComponent.searchTextbox?.focus();
    141  }
    142 });
    143 
    144 window.addEventListener(
    145  "unload",
    146  () => {
    147    // Clear out the document so the disconnectedCallback will trigger
    148    // properly and all of the custom elements can cleanup.
    149    document.body.textContent = "";
    150    topChromeWindow.removeEventListener("command", onCommand);
    151    Services.obs.removeObserver(onLocalesChanged, "intl:app-locales-changed");
    152    Services.prefs.removeObserver(
    153      "identity.fxaccounts.enabled",
    154      updateSyncVisibility
    155    );
    156  },
    157  { once: true }
    158 );
    159 
    160 topChromeWindow.addEventListener("command", onCommand);
    161 Services.obs.addObserver(onLocalesChanged, "intl:app-locales-changed");
    162 Services.prefs.addObserver("identity.fxaccounts.enabled", updateSyncVisibility);
    163 
    164 function onCommand(e) {
    165  if (document.hidden || !e.target.closest("#contentAreaContextMenu")) {
    166    return;
    167  }
    168  const item =
    169    e.target.closest("#context-openlinkinusercontext-menu") || e.target;
    170  Glean.firefoxviewNext.browserContextMenuTabs.record({
    171    menu_action: item.id,
    172    page: location.hash?.substring(1) || "recentbrowsing",
    173  });
    174 }
    175 
    176 function onLocalesChanged() {
    177  requestIdleCallback(() => {
    178    updateSearchTextboxSize();
    179    updateSearchKeyboardShortcut();
    180  });
    181 }