tor-browser

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

AdBanner.jsx (5695B)


      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 React, { useState } from "react";
      6 import { SafeAnchor } from "../SafeAnchor/SafeAnchor";
      7 import { ImpressionStats } from "../../DiscoveryStreamImpressionStats/ImpressionStats";
      8 import { actionCreators as ac } from "common/Actions.mjs";
      9 import { AdBannerContextMenu } from "../AdBannerContextMenu/AdBannerContextMenu";
     10 import { PromoCard } from "../PromoCard/PromoCard.jsx";
     11 
     12 const PREF_SECTIONS_ENABLED = "discoverystream.sections.enabled";
     13 const PREF_OHTTP_UNIFIED_ADS = "unifiedAds.ohttp.enabled";
     14 const PREF_REPORT_ADS_ENABLED = "discoverystream.reportAds.enabled";
     15 const PREF_PROMOCARD_ENABLED = "discoverystream.promoCard.enabled";
     16 const PREF_PROMOCARD_VISIBLE = "discoverystream.promoCard.visible";
     17 
     18 /**
     19 * A new banner ad that appears between rows of stories: leaderboard or billboard size.
     20 *
     21 * @param spoc
     22 * @param dispatch
     23 * @param firstVisibleTimestamp
     24 * @param row
     25 * @param type
     26 * @param prefs
     27 * @returns {Element}
     28 * @class
     29 */
     30 export const AdBanner = ({
     31  spoc,
     32  dispatch,
     33  firstVisibleTimestamp,
     34  row,
     35  type,
     36  prefs,
     37 }) => {
     38  const getDimensions = format => {
     39    switch (format) {
     40      case "leaderboard":
     41        return {
     42          width: "728",
     43          height: "90",
     44        };
     45      case "billboard":
     46        return {
     47          width: "970",
     48          height: "250",
     49        };
     50    }
     51    return {
     52      // image will still render with default values
     53      width: undefined,
     54      height: undefined,
     55    };
     56  };
     57  const promoCardEnabled =
     58    spoc.format === "billboard" &&
     59    prefs[PREF_PROMOCARD_ENABLED] &&
     60    prefs[PREF_PROMOCARD_VISIBLE];
     61 
     62  const sectionsEnabled = prefs[PREF_SECTIONS_ENABLED];
     63  const ohttpEnabled = prefs[PREF_OHTTP_UNIFIED_ADS];
     64  const showAdReporting = prefs[PREF_REPORT_ADS_ENABLED];
     65  const ohttpImagesEnabled = prefs.ohttpImagesConfig?.enabled;
     66  const [menuActive, setMenuActive] = useState(false);
     67  const adBannerWrapperClassName = `ad-banner-wrapper ${menuActive ? "active" : ""} ${promoCardEnabled ? "promo-card" : ""}`;
     68 
     69  const { width: imgWidth, height: imgHeight } = getDimensions(spoc.format);
     70 
     71  const onLinkClick = () => {
     72    dispatch(
     73      ac.DiscoveryStreamUserEvent({
     74        event: "CLICK",
     75        source: type.toUpperCase(),
     76        // Banner ads don't have a position, but a row number
     77        action_position: parseInt(row, 10),
     78        value: {
     79          card_type: "spoc",
     80          tile_id: spoc.id,
     81          ...(spoc.shim?.click ? { shim: spoc.shim.click } : {}),
     82          fetchTimestamp: spoc.fetchTimestamp,
     83          firstVisibleTimestamp,
     84          format: spoc.format,
     85          ...(sectionsEnabled
     86            ? {
     87                section: spoc.format,
     88                section_position: parseInt(row, 10),
     89              }
     90            : {}),
     91        },
     92      })
     93    );
     94  };
     95 
     96  const toggleActive = active => {
     97    setMenuActive(active);
     98  };
     99 
    100  // in the default card grid 1 would come before the 1st row of cards and 9 comes after the last row
    101  // using clamp to make sure its between valid values (1-9)
    102  const clampedRow = Math.max(1, Math.min(9, row));
    103 
    104  const secureImage = ohttpImagesEnabled && ohttpEnabled;
    105 
    106  let rawImageSrc = spoc.raw_image_src;
    107 
    108  // Wraps the image URL with the moz-cached-ohttp:// protocol.
    109  // This enables Firefox to load resources over Oblivious HTTP (OHTTP),
    110  // providing privacy-preserving resource loading.
    111  // Applied only when inferred personalization is enabled.
    112  // See: https://firefox-source-docs.mozilla.org/browser/components/mozcachedohttp/docs/index.html
    113  if (secureImage) {
    114    rawImageSrc = `moz-cached-ohttp://newtab-image/?url=${encodeURIComponent(spoc.raw_image_src)}`;
    115  }
    116 
    117  return (
    118    <aside className={adBannerWrapperClassName} style={{ gridRow: clampedRow }}>
    119      <div className={`ad-banner-inner ${spoc.format}`}>
    120        <SafeAnchor
    121          className="ad-banner-link"
    122          url={spoc.url}
    123          title={spoc.title || spoc.sponsor || spoc.alt_text}
    124          onLinkClick={onLinkClick}
    125          dispatch={dispatch}
    126          isSponsored={true}
    127        >
    128          <ImpressionStats
    129            flightId={spoc.flight_id}
    130            rows={[
    131              {
    132                id: spoc.id,
    133                card_type: "spoc",
    134                pos: row,
    135                recommended_at: spoc.recommended_at,
    136                received_rank: spoc.received_rank,
    137                format: spoc.format,
    138                ...(spoc.shim?.impression
    139                  ? { shim: spoc.shim.impression }
    140                  : {}),
    141              },
    142            ]}
    143            dispatch={dispatch}
    144            firstVisibleTimestamp={firstVisibleTimestamp}
    145          />
    146          <div className="ad-banner-content">
    147            <img
    148              src={rawImageSrc}
    149              alt={spoc.alt_text}
    150              loading="eager"
    151              width={imgWidth}
    152              height={imgHeight}
    153            />
    154          </div>
    155          <div className="ad-banner-sponsored">
    156            <span
    157              className="ad-banner-sponsored-label"
    158              data-l10n-id="newtab-label-sponsored-fixed"
    159            />
    160          </div>
    161        </SafeAnchor>
    162        <div className="ad-banner-hover-background">
    163          <AdBannerContextMenu
    164            dispatch={dispatch}
    165            spoc={spoc}
    166            position={row}
    167            type={type}
    168            showAdReporting={showAdReporting}
    169            toggleActive={toggleActive}
    170          />
    171        </div>
    172      </div>
    173      {promoCardEnabled && <PromoCard />}
    174    </aside>
    175  );
    176 };