tor-browser

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

moreFromMozilla.js (9460B)


      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 file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /* import-globals-from preferences.js */
      6 
      7 var gMoreFromMozillaPane = {
      8  initialized: false,
      9 
     10  /**
     11   * "default" is whatever template is the default, as defined by the code
     12   * in this file (currently in `getTemplateName`).  Setting option to an
     13   * invalid value will leave it unchanged.
     14   */
     15  _option: "default",
     16  set option(value) {
     17    if (!value) {
     18      this._option = "default";
     19      return;
     20    }
     21 
     22    if (value === "default" || value === "simple") {
     23      this._option = value;
     24    }
     25  },
     26 
     27  get option() {
     28    return this._option;
     29  },
     30 
     31  getTemplateName() {
     32    if (!this._option || this._option == "default") {
     33      return "simple";
     34    }
     35    return this._option;
     36  },
     37 
     38  getURL(url, region, option, hasEmail) {
     39    const URL_PARAMS = {
     40      utm_source: "about-prefs",
     41      utm_campaign: "morefrommozilla",
     42      utm_medium: "firefox-desktop",
     43    };
     44    // UTM content param used in analytics to record
     45    // UI template used to open URL
     46    const utm_content = {
     47      default: "default",
     48      simple: "fxvt-113-a",
     49    };
     50 
     51    const experiment_params = {
     52      entrypoint_experiment: "morefrommozilla-experiment-1846",
     53    };
     54 
     55    let pageUrl = new URL(url);
     56    for (let [key, val] of Object.entries(URL_PARAMS)) {
     57      pageUrl.searchParams.append(key, val);
     58    }
     59 
     60    // Append region by product to utm_content and also
     61    // append '-email' when URL is opened
     62    // from send email link in QRCode box
     63    if (option) {
     64      pageUrl.searchParams.set(
     65        "utm_content",
     66        `${utm_content[option]}-${region}${hasEmail ? "-email" : ""}`
     67      );
     68    }
     69 
     70    // Add experiments params when user is shown an experimental UI
     71    // with template value as 'simple' set via Nimbus
     72    if (option !== "default") {
     73      pageUrl.searchParams.set(
     74        "entrypoint_experiment",
     75        experiment_params.entrypoint_experiment
     76      );
     77      pageUrl.searchParams.set("entrypoint_variation", `treatment-${option}`);
     78    }
     79    return pageUrl.toString();
     80  },
     81 
     82  renderProducts() {
     83    const isRegionUS = Region.home.toLowerCase() === "us";
     84    let products = [
     85      {
     86        id: "firefox-mobile",
     87        title_string_id: "more-from-moz-firefox-mobile-title",
     88        description_string_id: "more-from-moz-firefox-mobile-description",
     89        region: "global",
     90        button: {
     91          id: "fxMobile",
     92          type: "link",
     93          label_string_id: "more-from-moz-learn-more-link",
     94          actionURL: BrowserUtils.isChinaRepack()
     95            ? "https://www.firefox.com.cn/browsers/mobile/"
     96            : "https://www.mozilla.org/firefox/browsers/mobile/",
     97        },
     98        qrcode: {
     99          title: {
    100            string_id: "more-from-moz-qr-code-box-firefox-mobile-title",
    101          },
    102          image_src_prefix:
    103            "chrome://browser/content/preferences/more-from-mozilla-qr-code",
    104          button: {
    105            id: "qr-code-send-email",
    106            label: {
    107              string_id: "more-from-moz-qr-code-box-firefox-mobile-button",
    108            },
    109            actionURL: BrowserUtils.isChinaRepack()
    110              ? "https://www.firefox.com.cn/mobile/get-app/"
    111              : "https://www.mozilla.org/firefox/mobile/get-app/?v=mfm",
    112          },
    113        },
    114      },
    115      {
    116        id: "mozilla-monitor",
    117        title_string_id: "more-from-moz-mozilla-monitor-title",
    118        description_string_id:
    119          "more-from-moz-mozilla-monitor-global-description",
    120        region: isRegionUS ? "us" : "global",
    121        button: {
    122          id: "mozillaMonitor",
    123          label_string_id: "more-from-moz-mozilla-monitor-button",
    124          actionURL: "https://monitor.mozilla.org/",
    125        },
    126      },
    127    ];
    128 
    129    if (BrowserUtils.shouldShowVPNPromo()) {
    130      const vpn = {
    131        id: "mozilla-vpn",
    132        title_string_id: "more-from-moz-mozilla-vpn-title",
    133        description_string_id: "more-from-moz-mozilla-vpn-description",
    134        region: "global",
    135        button: {
    136          id: "mozillaVPN",
    137          label_string_id: "more-from-moz-button-mozilla-vpn-2",
    138          actionURL: "https://www.mozilla.org/products/vpn/",
    139        },
    140      };
    141      products.push(vpn);
    142    }
    143 
    144    if (BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.RELAY)) {
    145      const relay = {
    146        id: "firefox-relay",
    147        title_string_id: "more-from-moz-firefox-relay-title",
    148        description_string_id: "more-from-moz-firefox-relay-description",
    149        region: "global",
    150        button: {
    151          id: "firefoxRelay",
    152          label_string_id: "more-from-moz-firefox-relay-button",
    153          actionURL: "https://relay.firefox.com/",
    154        },
    155      };
    156      products.push(relay);
    157    }
    158 
    159    products.push({
    160      id: "solo-ai",
    161      title_string_id: "more-from-moz-solo-title-2",
    162      description_string_id: "more-from-moz-solo-description",
    163      region: "global",
    164      button: {
    165        id: "soloAI",
    166        label_string_id: "more-from-moz-solo-button",
    167        actionURL: "https://soloist.ai/?utm_type=more_from_mozilla",
    168      },
    169    });
    170 
    171    products.push({
    172      id: "mdn",
    173      title_string_id: "more-from-moz-mdn-title",
    174      description_string_id: "more-from-moz-mdn-description",
    175      region: "global",
    176      button: {
    177        id: "mdn",
    178        label_string_id: "more-from-moz-mdn-button",
    179        actionURL: "https://developer.mozilla.org/docs/Learn_web_development",
    180      },
    181    });
    182 
    183    this._productsContainer = document.getElementById(
    184      "moreFromMozillaCategory"
    185    );
    186    let frag = document.createDocumentFragment();
    187    this._template = document.getElementById(this.getTemplateName());
    188 
    189    // Exit when internal data is incomplete
    190    if (!this._template) {
    191      return;
    192    }
    193 
    194    for (let product of products) {
    195      let template = this._template.content.cloneNode(true);
    196      let title = template.querySelector(".product-title");
    197      let desc = template.querySelector(".description");
    198 
    199      document.l10n.setAttributes(title, product.title_string_id);
    200      title.id = product.id;
    201 
    202      document.l10n.setAttributes(desc, product.description_string_id);
    203 
    204      let isLink = product.button.type === "link";
    205      let actionElement = template.querySelector(
    206        isLink ? ".text-link" : ".small-button"
    207      );
    208 
    209      if (actionElement) {
    210        actionElement.hidden = false;
    211        actionElement.id = `${this.option}-${product.button.id}`;
    212        document.l10n.setAttributes(
    213          actionElement,
    214          product.button.label_string_id
    215        );
    216 
    217        if (isLink) {
    218          actionElement.setAttribute(
    219            "href",
    220            this.getURL(product.button.actionURL, product.region, this.option)
    221          );
    222        } else {
    223          actionElement.addEventListener("click", function () {
    224            let mainWindow = window.windowRoot.ownerGlobal;
    225            mainWindow.openTrustedLinkIn(
    226              gMoreFromMozillaPane.getURL(
    227                product.button.actionURL,
    228                product.region,
    229                gMoreFromMozillaPane.option
    230              ),
    231              "tab"
    232            );
    233          });
    234        }
    235      }
    236 
    237      if (product.qrcode) {
    238        let qrcode = template.querySelector(".qr-code-box");
    239        qrcode.setAttribute("hidden", "false");
    240 
    241        let qrcode_title = template.querySelector(".qr-code-box-title");
    242        document.l10n.setAttributes(
    243          qrcode_title,
    244          product.qrcode.title.string_id
    245        );
    246 
    247        let img = template.querySelector(".qr-code-box-image");
    248        // Append QRCode image source by template. For CN region
    249        // simple template, we want a CN specific QRCode
    250        img.src =
    251          product.qrcode.image_src_prefix +
    252          "-" +
    253          this.getTemplateName() +
    254          `${
    255            BrowserUtils.isChinaRepack() &&
    256            this.getTemplateName().includes("simple")
    257              ? "-cn"
    258              : ""
    259          }` +
    260          ".svg";
    261        // Add image a11y attributes
    262        document.l10n.setAttributes(
    263          img,
    264          "more-from-moz-qr-code-firefox-mobile-img"
    265        );
    266 
    267        let qrc_link = template.querySelector(".qr-code-link");
    268 
    269        // So the telemetry includes info about which option is being used
    270        qrc_link.id = `${this.option}-${product.qrcode.button.id}`;
    271 
    272        // For supported locales, this link allows users to send themselves a
    273        // download link by email. It should be hidden for unsupported locales.
    274        if (BrowserUtils.sendToDeviceEmailsSupported()) {
    275          document.l10n.setAttributes(
    276            qrc_link,
    277            product.qrcode.button.label.string_id
    278          );
    279          qrc_link.href = this.getURL(
    280            product.qrcode.button.actionURL,
    281            product.region,
    282            this.option,
    283            true
    284          );
    285          qrc_link.hidden = false;
    286        }
    287      }
    288 
    289      frag.appendChild(template);
    290    }
    291    this._productsContainer.appendChild(frag);
    292  },
    293 
    294  async init() {
    295    if (this.initialized) {
    296      return;
    297    }
    298    this.initialized = true;
    299    document
    300      .getElementById("moreFromMozillaCategory")
    301      .removeAttribute("data-hidden-from-search");
    302    document
    303      .getElementById("moreFromMozillaCategory-header")
    304      .removeAttribute("data-hidden-from-search");
    305 
    306    this.renderProducts();
    307  },
    308 };