fune/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js

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();
});