forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			343 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			343 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
/* eslint-env mozilla/frame-script */
 | 
						|
 | 
						|
/**
 | 
						|
 * Determines whether a given value is a fluent id or plain text and adds it to an element
 | 
						|
 * @param {Array<[HTMLElement, string]>} items An array of [element, value] where value is
 | 
						|
 *                                       a fluent id starting with "fluent:" or plain text
 | 
						|
 */
 | 
						|
async function translateElements(container, items) {
 | 
						|
  // We need to wait for fluent to initialize
 | 
						|
  await document.l10n.ready;
 | 
						|
 | 
						|
  items.forEach(([element, value]) => {
 | 
						|
    // Skip empty text or elements
 | 
						|
    if (!element || !value) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    const fluentId = value.replace(/^fluent:/, "");
 | 
						|
    if (fluentId !== value) {
 | 
						|
      document.l10n.setAttributes(element, fluentId);
 | 
						|
    } else {
 | 
						|
      element.textContent = value;
 | 
						|
      element.removeAttribute("data-l10n-id");
 | 
						|
    }
 | 
						|
  });
 | 
						|
 | 
						|
  document.l10n.translateFragment(container);
 | 
						|
}
 | 
						|
 | 
						|
async function renderInfo({
 | 
						|
  infoEnabled,
 | 
						|
  infoTitle,
 | 
						|
  infoTitleEnabled,
 | 
						|
  infoBody,
 | 
						|
  infoLinkText,
 | 
						|
  infoLinkUrl,
 | 
						|
  infoIcon,
 | 
						|
}) {
 | 
						|
  const container = document.querySelector(".info");
 | 
						|
  if (infoEnabled === false) {
 | 
						|
    container.remove();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  const titleEl = document.getElementById("info-title");
 | 
						|
  const bodyEl = document.getElementById("info-body");
 | 
						|
  const linkEl = document.getElementById("private-browsing-myths");
 | 
						|
 | 
						|
  if (infoIcon) {
 | 
						|
    container.style.backgroundImage = `url(${infoIcon})`;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!infoTitleEnabled) {
 | 
						|
    titleEl.remove();
 | 
						|
  }
 | 
						|
 | 
						|
  await translateElements(container, [
 | 
						|
    [titleEl, infoTitle],
 | 
						|
    [bodyEl, infoBody],
 | 
						|
    [linkEl, infoLinkText],
 | 
						|
  ]);
 | 
						|
 | 
						|
  linkEl.setAttribute(
 | 
						|
    "href",
 | 
						|
    infoLinkUrl ||
 | 
						|
      RPMGetFormatURLPref("app.support.baseURL") + "private-browsing-myths"
 | 
						|
  );
 | 
						|
 | 
						|
  linkEl.addEventListener("click", () => {
 | 
						|
    window.PrivateBrowsingRecordClick("info_link");
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
async function renderPromo({
 | 
						|
  promoEnabled,
 | 
						|
  promoTitle,
 | 
						|
  promoTitleEnabled,
 | 
						|
  promoLinkText,
 | 
						|
  promoLinkUrl,
 | 
						|
  promoLinkType,
 | 
						|
  promoSectionStyle,
 | 
						|
  promoHeader,
 | 
						|
  promoImageLarge,
 | 
						|
  promoImageSmall,
 | 
						|
}) {
 | 
						|
  const container = document.querySelector(".promo");
 | 
						|
  if (promoEnabled === false) {
 | 
						|
    container.remove();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Check the current geo and remove if we're in the wrong one.
 | 
						|
  RPMSendQuery("ShouldShowVPNPromo", {}).then(shouldShow => {
 | 
						|
    if (!shouldShow) {
 | 
						|
      container.remove();
 | 
						|
    }
 | 
						|
  });
 | 
						|
 | 
						|
  const titleEl = document.getElementById("private-browsing-vpn-text");
 | 
						|
  let linkEl = document.getElementById("private-browsing-vpn-link");
 | 
						|
  const promoHeaderEl = document.getElementById("promo-header");
 | 
						|
  const infoContainerEl = document.querySelector(".info");
 | 
						|
  const promoImageLargeEl = document.querySelector(".promo-image-large img");
 | 
						|
  const promoImageSmallEl = document.querySelector(".promo-image-small img");
 | 
						|
 | 
						|
  // Setup the private browsing VPN link.
 | 
						|
  const vpnPromoUrl =
 | 
						|
    promoLinkUrl || RPMGetFormatURLPref("browser.privatebrowsing.vpnpromourl");
 | 
						|
 | 
						|
  if (promoLinkType === "button") {
 | 
						|
    linkEl.classList.add("button");
 | 
						|
  }
 | 
						|
 | 
						|
  if (vpnPromoUrl) {
 | 
						|
    linkEl.setAttribute("href", vpnPromoUrl);
 | 
						|
    linkEl.addEventListener("click", () => {
 | 
						|
      window.PrivateBrowsingRecordClick("promo_link");
 | 
						|
    });
 | 
						|
  } else {
 | 
						|
    // If the link is undefined, remove the promo completely
 | 
						|
    container.remove();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (promoSectionStyle) {
 | 
						|
    container.classList.add(promoSectionStyle);
 | 
						|
 | 
						|
    switch (promoSectionStyle) {
 | 
						|
      case "below-search":
 | 
						|
        container.remove();
 | 
						|
        infoContainerEl?.insertAdjacentElement("beforebegin", container);
 | 
						|
        break;
 | 
						|
      case "top":
 | 
						|
        container.remove();
 | 
						|
        document.body.insertAdjacentElement("afterbegin", container);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (promoImageLarge) {
 | 
						|
    promoImageLargeEl.src = promoImageLarge;
 | 
						|
  } else {
 | 
						|
    promoImageLargeEl.parentNode.remove();
 | 
						|
  }
 | 
						|
 | 
						|
  if (promoImageSmall) {
 | 
						|
    promoImageSmallEl.src = promoImageSmall;
 | 
						|
  } else {
 | 
						|
    promoImageSmallEl.parentNode.remove();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!promoTitleEnabled) {
 | 
						|
    titleEl.remove();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!promoHeader) {
 | 
						|
    promoHeaderEl.remove();
 | 
						|
  }
 | 
						|
 | 
						|
  await translateElements(container, [
 | 
						|
    [titleEl, promoTitle],
 | 
						|
    [linkEl, promoLinkText],
 | 
						|
    [promoHeaderEl, promoHeader],
 | 
						|
  ]);
 | 
						|
}
 | 
						|
 | 
						|
const DEFAULT_PRIVATE_BROWSING_CONTENT = {
 | 
						|
  promoEnabled: true,
 | 
						|
  infoEnabled: true,
 | 
						|
  infoIcon: "",
 | 
						|
  infoTitle: "",
 | 
						|
  infoBody: "fluent:about-private-browsing-info-description-private-window",
 | 
						|
  infoLinkText: "fluent:about-private-browsing-learn-more-link",
 | 
						|
  infoTitleEnabled: false,
 | 
						|
  promoLinkType: "button",
 | 
						|
  promoLinkText: "fluent:about-private-browsing-prominent-cta",
 | 
						|
  promoSectionStyle: "below-search",
 | 
						|
  promoHeader: "fluent:about-private-browsing-get-privacy",
 | 
						|
  promoTitle: "fluent:about-private-browsing-hide-activity-1",
 | 
						|
  promoTitleEnabled: true,
 | 
						|
  promoImageLarge: "chrome://browser/content/assets/moz-vpn.svg",
 | 
						|
};
 | 
						|
 | 
						|
async function setupFeatureConfig() {
 | 
						|
  // Setup experiment data
 | 
						|
  let config = {};
 | 
						|
  try {
 | 
						|
    config = window.PrivateBrowsingFeatureConfig(
 | 
						|
      DEFAULT_PRIVATE_BROWSING_CONTENT
 | 
						|
    );
 | 
						|
  } catch (e) {}
 | 
						|
 | 
						|
  await renderInfo(config);
 | 
						|
  await renderPromo(config);
 | 
						|
 | 
						|
  // For tests
 | 
						|
  document.documentElement.setAttribute("PrivateBrowsingRenderComplete", true);
 | 
						|
}
 | 
						|
 | 
						|
document.addEventListener("DOMContentLoaded", function() {
 | 
						|
  setupFeatureConfig();
 | 
						|
 | 
						|
  if (!RPMIsWindowPrivate()) {
 | 
						|
    document.documentElement.classList.remove("private");
 | 
						|
    document.documentElement.classList.add("normal");
 | 
						|
    document
 | 
						|
      .getElementById("startPrivateBrowsing")
 | 
						|
      .addEventListener("click", function() {
 | 
						|
        RPMSendAsyncMessage("OpenPrivateWindow");
 | 
						|
      });
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Set up the private search banner.
 | 
						|
  const privateSearchBanner = document.getElementById("search-banner");
 | 
						|
 | 
						|
  RPMSendQuery("ShouldShowSearchBanner", {}).then(engineName => {
 | 
						|
    if (engineName) {
 | 
						|
      document.l10n.setAttributes(
 | 
						|
        document.getElementById("about-private-browsing-search-banner-title"),
 | 
						|
        "about-private-browsing-search-banner-title",
 | 
						|
        { engineName }
 | 
						|
      );
 | 
						|
      privateSearchBanner.removeAttribute("hidden");
 | 
						|
      document.body.classList.add("showBanner");
 | 
						|
    }
 | 
						|
 | 
						|
    // We set this attribute so that tests know when we are done.
 | 
						|
    document.documentElement.setAttribute("SearchBannerInitialized", true);
 | 
						|
  });
 | 
						|
 | 
						|
  function hideSearchBanner() {
 | 
						|
    privateSearchBanner.hidden = true;
 | 
						|
    document.body.classList.remove("showBanner");
 | 
						|
    RPMSendAsyncMessage("SearchBannerDismissed");
 | 
						|
  }
 | 
						|
 | 
						|
  document
 | 
						|
    .getElementById("search-banner-close-button")
 | 
						|
    .addEventListener("click", () => {
 | 
						|
      hideSearchBanner();
 | 
						|
    });
 | 
						|
 | 
						|
  let openSearchOptions = document.getElementById(
 | 
						|
    "about-private-browsing-search-banner-description"
 | 
						|
  );
 | 
						|
  let openSearchOptionsEvtHandler = evt => {
 | 
						|
    if (
 | 
						|
      evt.target.id == "open-search-options-link" &&
 | 
						|
      (evt.keyCode == evt.DOM_VK_RETURN || evt.type == "click")
 | 
						|
    ) {
 | 
						|
      RPMSendAsyncMessage("OpenSearchPreferences");
 | 
						|
      hideSearchBanner();
 | 
						|
    }
 | 
						|
  };
 | 
						|
  openSearchOptions.addEventListener("click", openSearchOptionsEvtHandler);
 | 
						|
  openSearchOptions.addEventListener("keypress", openSearchOptionsEvtHandler);
 | 
						|
 | 
						|
  // Setup the search hand-off box.
 | 
						|
  let btn = document.getElementById("search-handoff-button");
 | 
						|
  RPMSendQuery("ShouldShowSearch", {}).then(
 | 
						|
    ([engineName, shouldHandOffToSearchMode]) => {
 | 
						|
      let input = document.querySelector(".fake-textbox");
 | 
						|
      if (shouldHandOffToSearchMode) {
 | 
						|
        document.l10n.setAttributes(btn, "about-private-browsing-search-btn");
 | 
						|
        document.l10n.setAttributes(
 | 
						|
          input,
 | 
						|
          "about-private-browsing-search-placeholder"
 | 
						|
        );
 | 
						|
      } else if (engineName) {
 | 
						|
        document.l10n.setAttributes(btn, "about-private-browsing-handoff", {
 | 
						|
          engine: engineName,
 | 
						|
        });
 | 
						|
        document.l10n.setAttributes(
 | 
						|
          input,
 | 
						|
          "about-private-browsing-handoff-text",
 | 
						|
          {
 | 
						|
            engine: engineName,
 | 
						|
          }
 | 
						|
        );
 | 
						|
      } else {
 | 
						|
        document.l10n.setAttributes(
 | 
						|
          btn,
 | 
						|
          "about-private-browsing-handoff-no-engine"
 | 
						|
        );
 | 
						|
        document.l10n.setAttributes(
 | 
						|
          input,
 | 
						|
          "about-private-browsing-handoff-text-no-engine"
 | 
						|
        );
 | 
						|
      }
 | 
						|
    }
 | 
						|
  );
 | 
						|
 | 
						|
  let editable = document.getElementById("fake-editable");
 | 
						|
  let DISABLE_SEARCH_TOPIC = "DisableSearch";
 | 
						|
  let SHOW_SEARCH_TOPIC = "ShowSearch";
 | 
						|
  let SEARCH_HANDOFF_TOPIC = "SearchHandoff";
 | 
						|
 | 
						|
  function showSearch() {
 | 
						|
    btn.classList.remove("focused");
 | 
						|
    btn.classList.remove("disabled");
 | 
						|
    RPMRemoveMessageListener(SHOW_SEARCH_TOPIC, showSearch);
 | 
						|
  }
 | 
						|
 | 
						|
  function disableSearch() {
 | 
						|
    btn.classList.add("disabled");
 | 
						|
  }
 | 
						|
 | 
						|
  function handoffSearch(text) {
 | 
						|
    RPMSendAsyncMessage(SEARCH_HANDOFF_TOPIC, { text });
 | 
						|
    RPMAddMessageListener(SHOW_SEARCH_TOPIC, showSearch);
 | 
						|
    if (text) {
 | 
						|
      disableSearch();
 | 
						|
    } else {
 | 
						|
      btn.classList.add("focused");
 | 
						|
      RPMAddMessageListener(DISABLE_SEARCH_TOPIC, disableSearch);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  btn.addEventListener("focus", function() {
 | 
						|
    handoffSearch();
 | 
						|
  });
 | 
						|
  btn.addEventListener("click", function() {
 | 
						|
    handoffSearch();
 | 
						|
  });
 | 
						|
 | 
						|
  // Hand-off any text that gets dropped or pasted
 | 
						|
  editable.addEventListener("drop", function(ev) {
 | 
						|
    ev.preventDefault();
 | 
						|
    let text = ev.dataTransfer.getData("text");
 | 
						|
    if (text) {
 | 
						|
      handoffSearch(text);
 | 
						|
    }
 | 
						|
  });
 | 
						|
  editable.addEventListener("paste", function(ev) {
 | 
						|
    ev.preventDefault();
 | 
						|
    handoffSearch(ev.clipboardData.getData("Text"));
 | 
						|
  });
 | 
						|
 | 
						|
  // Load contentSearchUI so it sets the search engine icon and name for us.
 | 
						|
  new window.ContentSearchHandoffUIController();
 | 
						|
});
 |