tor-browser

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

link-menu-options.mjs (15305B)


      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 {
      6  actionCreators as ac,
      7  actionTypes as at,
      8 } from "../../common/Actions.mjs";
      9 
     10 const _OpenInPrivateWindow = site => ({
     11  id: "newtab-menu-open-new-private-window",
     12  icon: "new-window-private",
     13  action: ac.OnlyToMain({
     14    type: at.OPEN_PRIVATE_WINDOW,
     15    data: {
     16      url: site.url,
     17      referrer: site.referrer,
     18      event_source: "CONTEXT_MENU",
     19    },
     20  }),
     21  userEvent: "OPEN_PRIVATE_WINDOW",
     22 });
     23 
     24 /**
     25 * List of functions that return items that can be included as menu options in a
     26 * LinkMenu. All functions take the site as the first parameter, and optionally
     27 * the index of the site.
     28 */
     29 export const LinkMenuOptions = {
     30  Separator: () => ({ type: "separator" }),
     31  EmptyItem: () => ({ type: "empty" }),
     32  ShowPrivacyInfo: () => ({
     33    id: "newtab-menu-show-privacy-info",
     34    icon: "info",
     35    action: {
     36      type: at.SHOW_PRIVACY_INFO,
     37    },
     38    userEvent: "SHOW_PRIVACY_INFO",
     39  }),
     40  AboutSponsored: site => ({
     41    id: "newtab-menu-show-privacy-info",
     42    icon: "info",
     43    action: ac.AlsoToMain({
     44      type: at.ABOUT_SPONSORED_TOP_SITES,
     45      data: {
     46        advertiser_name: (site.label || site.hostname).toLocaleLowerCase(),
     47        position: site.sponsored_position,
     48        tile_id: site.sponsored_tile_id,
     49        block_key: site.block_key,
     50      },
     51    }),
     52    userEvent: "TOPSITE_SPONSOR_INFO",
     53  }),
     54  RemoveBookmark: site => ({
     55    id: "newtab-menu-remove-bookmark",
     56    icon: "bookmark-added",
     57    action: ac.AlsoToMain({
     58      type: at.DELETE_BOOKMARK_BY_ID,
     59      data: site.bookmarkGuid,
     60    }),
     61    userEvent: "BOOKMARK_DELETE",
     62  }),
     63  AddBookmark: site => ({
     64    id: "newtab-menu-bookmark",
     65    icon: "bookmark-hollow",
     66    action: ac.AlsoToMain({
     67      type: at.BOOKMARK_URL,
     68      data: { url: site.url, title: site.title, type: site.type },
     69    }),
     70    userEvent: "BOOKMARK_ADD",
     71  }),
     72  OpenInNewWindow: site => ({
     73    id: "newtab-menu-open-new-window",
     74    icon: "new-window",
     75    action: ac.AlsoToMain({
     76      type: at.OPEN_NEW_WINDOW,
     77      data: {
     78        card_type: site.card_type,
     79        referrer: site.referrer,
     80        typedBonus: site.typedBonus,
     81        url: site.url,
     82        is_sponsored: !!site.sponsored_tile_id,
     83        event_source: "CONTEXT_MENU",
     84        topic: site.topic,
     85        firstVisibleTimestamp: site.firstVisibleTimestamp,
     86        tile_id: site.tile_id,
     87        recommendation_id: site.recommendation_id,
     88        scheduled_corpus_item_id: site.scheduled_corpus_item_id,
     89        corpus_item_id: site.corpus_item_id,
     90        received_rank: site.received_rank,
     91        recommended_at: site.recommended_at,
     92        format: site.format,
     93        ...(site.flight_id ? { flight_id: site.flight_id } : {}),
     94        is_pocket_card: site.type === "CardGrid",
     95        ...(site.section
     96          ? {
     97              section: site.section,
     98              section_position: site.section_position,
     99              is_section_followed: site.is_section_followed,
    100            }
    101          : {}),
    102      },
    103    }),
    104    userEvent: "OPEN_NEW_WINDOW",
    105  }),
    106 
    107  // This blocks the url for regular stories,
    108  // but also sends a message to DiscoveryStream with flight_id.
    109  // If DiscoveryStream sees this message for a flight_id
    110  // it also blocks it on the flight_id.
    111  BlockUrl: (site, index, eventSource) => {
    112    return LinkMenuOptions.BlockUrls([site], index, eventSource);
    113  },
    114  // Same as BlockUrl, except can work on an array of sites.
    115  BlockUrls: (tiles, pos, eventSource) => ({
    116    id: "newtab-menu-dismiss",
    117    icon: "dismiss",
    118    action: ac.AlsoToMain({
    119      type: at.BLOCK_URL,
    120      source: eventSource,
    121      data: tiles.map(site => ({
    122        url: site.original_url || site.open_url || site.url,
    123        // pocket_id is only for pocket stories being in highlights, and then dismissed.
    124        pocket_id: site.pocket_id,
    125        tile_id: site.tile_id,
    126        ...(site.block_key ? { block_key: site.block_key } : {}),
    127        recommendation_id: site.recommendation_id,
    128        scheduled_corpus_item_id: site.scheduled_corpus_item_id,
    129        corpus_item_id: site.corpus_item_id,
    130        received_rank: site.received_rank,
    131        recommended_at: site.recommended_at,
    132        // used by PlacesFeed and TopSitesFeed for sponsored top sites blocking.
    133        isSponsoredTopSite: site.sponsored_position,
    134        type: site.type,
    135        card_type: site.card_type,
    136        ...(site.shim && site.shim.delete ? { shim: site.shim.delete } : {}),
    137        ...(site.flight_id ? { flight_id: site.flight_id } : {}),
    138        // If not sponsored, hostname could be anything (Cat3 Data!).
    139        // So only put in advertiser_name for sponsored topsites.
    140        ...(site.sponsored_position
    141          ? {
    142              advertiser_name: (
    143                site.label || site.hostname
    144              )?.toLocaleLowerCase(),
    145            }
    146          : {}),
    147        position: pos,
    148        ...(site.sponsored_tile_id ? { tile_id: site.sponsored_tile_id } : {}),
    149        is_pocket_card: site.type === "CardGrid",
    150        ...(site.format ? { format: site.format } : {}),
    151        ...(site.section
    152          ? {
    153              section: site.section,
    154              section_position: site.section_position,
    155              is_section_followed: site.is_section_followed,
    156            }
    157          : {}),
    158      })),
    159    }),
    160    impression: ac.ImpressionStats({
    161      source: eventSource,
    162      block: 0,
    163      tiles: tiles.map((site, index) => ({
    164        id: site.guid,
    165        pos: pos + index,
    166        ...(site.shim && site.shim.delete ? { shim: site.shim.delete } : {}),
    167      })),
    168    }),
    169    userEvent: "BLOCK",
    170  }),
    171 
    172  // This is the "Dismiss" action for leaderboard/billboard ads.
    173  BlockAdUrl: (site, pos, eventSource) => ({
    174    id: "newtab-menu-dismiss",
    175    icon: "dismiss",
    176    action: ac.AlsoToMain({
    177      type: at.BLOCK_URL,
    178      data: [site],
    179    }),
    180    impression: ac.ImpressionStats({
    181      source: eventSource,
    182      block: 0,
    183      tiles: [
    184        {
    185          id: site.guid,
    186          pos,
    187          ...(site.shim && site.shim.save ? { shim: site.shim.save } : {}),
    188        },
    189      ],
    190    }),
    191    userEvent: "BLOCK",
    192  }),
    193 
    194  // This is an option for web extentions which will result in remove items from
    195  // memory and notify the web extenion, rather than using the built-in block list.
    196  WebExtDismiss: (site, index, eventSource) => ({
    197    id: "menu_action_webext_dismiss",
    198    string_id: "newtab-menu-dismiss",
    199    icon: "dismiss",
    200    action: ac.WebExtEvent(at.WEBEXT_DISMISS, {
    201      source: eventSource,
    202      url: site.url,
    203      action_position: index,
    204    }),
    205  }),
    206  DeleteUrl: (site, index, eventSource, isEnabled, siteInfo) => ({
    207    id: "newtab-menu-delete-history",
    208    icon: "delete",
    209    action: {
    210      type: at.DIALOG_OPEN,
    211      data: {
    212        onConfirm: [
    213          ac.AlsoToMain({
    214            type: at.DELETE_HISTORY_URL,
    215            data: {
    216              url: site.url,
    217              pocket_id: site.pocket_id,
    218              forceBlock: site.bookmarkGuid,
    219            },
    220          }),
    221          ac.UserEvent(
    222            Object.assign(
    223              { event: "DELETE", source: eventSource, action_position: index },
    224              siteInfo
    225            )
    226          ),
    227          // Also broadcast that this url has been deleted so that
    228          // the confirmation dialog knows it needs to disappear now.
    229          ac.AlsoToMain({
    230            type: at.DIALOG_CLOSE,
    231          }),
    232        ],
    233        eventSource,
    234        body_string_id: [
    235          "newtab-confirm-delete-history-p1",
    236          "newtab-confirm-delete-history-p2",
    237        ],
    238        confirm_button_string_id: "newtab-topsites-delete-history-button",
    239        cancel_button_string_id: "newtab-topsites-cancel-button",
    240        icon: "modal-delete",
    241      },
    242    },
    243    userEvent: "DIALOG_OPEN",
    244  }),
    245  ShowFile: site => ({
    246    id: "newtab-menu-show-file",
    247    icon: "search",
    248    action: ac.OnlyToMain({
    249      type: at.SHOW_DOWNLOAD_FILE,
    250      data: { url: site.url },
    251    }),
    252  }),
    253  OpenFile: site => ({
    254    id: "newtab-menu-open-file",
    255    icon: "open-file",
    256    action: ac.OnlyToMain({
    257      type: at.OPEN_DOWNLOAD_FILE,
    258      data: { url: site.url },
    259    }),
    260  }),
    261  CopyDownloadLink: site => ({
    262    id: "newtab-menu-copy-download-link",
    263    icon: "copy",
    264    action: ac.OnlyToMain({
    265      type: at.COPY_DOWNLOAD_LINK,
    266      data: { url: site.url },
    267    }),
    268  }),
    269  GoToDownloadPage: site => ({
    270    id: "newtab-menu-go-to-download-page",
    271    icon: "download",
    272    action: ac.OnlyToMain({
    273      type: at.OPEN_LINK,
    274      data: { url: site.referrer },
    275    }),
    276    disabled: !site.referrer,
    277  }),
    278  RemoveDownload: site => ({
    279    id: "newtab-menu-remove-download",
    280    icon: "delete",
    281    action: ac.OnlyToMain({
    282      type: at.REMOVE_DOWNLOAD_FILE,
    283      data: { url: site.url },
    284    }),
    285  }),
    286  PinTopSite: (site, index) => ({
    287    id: "newtab-menu-pin",
    288    icon: "pin",
    289    action: ac.AlsoToMain({
    290      type: at.TOP_SITES_PIN,
    291      data: {
    292        site,
    293        index,
    294      },
    295    }),
    296    userEvent: "PIN",
    297  }),
    298  UnpinTopSite: site => ({
    299    id: "newtab-menu-unpin",
    300    icon: "unpin",
    301    action: ac.AlsoToMain({
    302      type: at.TOP_SITES_UNPIN,
    303      data: { site: { url: site.url } },
    304    }),
    305    userEvent: "UNPIN",
    306  }),
    307  EditTopSite: (site, index) => ({
    308    id: "newtab-menu-edit-topsites",
    309    icon: "edit",
    310    action: {
    311      type: at.TOP_SITES_EDIT,
    312      data: { index },
    313    },
    314  }),
    315  CheckBookmark: site =>
    316    site.bookmarkGuid
    317      ? LinkMenuOptions.RemoveBookmark(site)
    318      : LinkMenuOptions.AddBookmark(site),
    319  CheckPinTopSite: (site, index) =>
    320    site.isPinned
    321      ? LinkMenuOptions.UnpinTopSite(site)
    322      : LinkMenuOptions.PinTopSite(site, index),
    323  OpenInPrivateWindow: (site, index, eventSource, isEnabled) =>
    324    isEnabled ? _OpenInPrivateWindow(site) : LinkMenuOptions.EmptyItem(),
    325  ChangeWeatherLocation: () => ({
    326    id: "newtab-weather-menu-change-location",
    327    action: ac.BroadcastToContent({
    328      type: at.WEATHER_SEARCH_ACTIVE,
    329      data: true,
    330    }),
    331  }),
    332  DetectLocation: () => ({
    333    id: "newtab-weather-menu-detect-my-location",
    334    action: ac.AlsoToMain({
    335      type: at.WEATHER_USER_OPT_IN_LOCATION,
    336    }),
    337    userEvent: "WEATHER_DETECT_LOCATION",
    338  }),
    339  ChangeWeatherDisplaySimple: () => ({
    340    id: "newtab-weather-menu-change-weather-display-simple",
    341    action: ac.OnlyToMain({
    342      type: at.SET_PREF,
    343      data: {
    344        name: "weather.display",
    345        value: "simple",
    346      },
    347    }),
    348  }),
    349  ChangeWeatherDisplayDetailed: () => ({
    350    id: "newtab-weather-menu-change-weather-display-detailed",
    351    action: ac.OnlyToMain({
    352      type: at.SET_PREF,
    353      data: {
    354        name: "weather.display",
    355        value: "detailed",
    356      },
    357    }),
    358  }),
    359  ChangeTempUnitFahrenheit: () => ({
    360    id: "newtab-weather-menu-change-temperature-units-fahrenheit",
    361    action: ac.OnlyToMain({
    362      type: at.SET_PREF,
    363      data: {
    364        name: "weather.temperatureUnits",
    365        value: "f",
    366      },
    367    }),
    368  }),
    369  ChangeTempUnitCelsius: () => ({
    370    id: "newtab-weather-menu-change-temperature-units-celsius",
    371    action: ac.OnlyToMain({
    372      type: at.SET_PREF,
    373      data: {
    374        name: "weather.temperatureUnits",
    375        value: "c",
    376      },
    377    }),
    378  }),
    379  HideWeather: () => ({
    380    id: "newtab-weather-menu-hide-weather",
    381    action: ac.OnlyToMain({
    382      type: at.SET_PREF,
    383      data: {
    384        name: "showWeather",
    385        value: false,
    386      },
    387    }),
    388  }),
    389  OpenLearnMoreURL: site => ({
    390    id: "newtab-weather-menu-learn-more",
    391    action: ac.OnlyToMain({
    392      type: at.OPEN_LINK,
    393      data: { url: site.url },
    394    }),
    395  }),
    396  SectionBlock: ({
    397    sectionPersonalization,
    398    sectionKey,
    399    sectionPosition,
    400    title,
    401  }) => ({
    402    id: "newtab-menu-section-block",
    403    icon: "delete",
    404    action: {
    405      // Open the confirmation dialog to block a section.
    406      type: at.DIALOG_OPEN,
    407      data: {
    408        onConfirm: [
    409          // Once the user confirmed their intention to block this section,
    410          // update their preferences.
    411          ac.AlsoToMain({
    412            type: at.SECTION_PERSONALIZATION_SET,
    413            data: {
    414              ...sectionPersonalization,
    415              [sectionKey]: {
    416                isBlocked: true,
    417                isFollowed: false,
    418              },
    419            },
    420          }),
    421          // Telemetry
    422          ac.OnlyToMain({
    423            type: at.BLOCK_SECTION,
    424            data: {
    425              section: sectionKey,
    426              section_position: sectionPosition,
    427              event_source: "CONTEXT_MENU",
    428            },
    429          }),
    430          // Also broadcast that this section has been blocked so that
    431          // the confirmation dialog knows it needs to disappear now.
    432          ac.AlsoToMain({
    433            type: at.DIALOG_CLOSE,
    434          }),
    435        ],
    436        // Pass Fluent strings to ConfirmDialog component for the copy
    437        // of the prompt to block sections.
    438        body_string_id: [
    439          "newtab-section-confirm-block-topic-p1",
    440          "newtab-section-confirm-block-topic-p2",
    441        ],
    442        confirm_button_string_id: "newtab-section-block-topic-button",
    443        confirm_button_string_args: { topic: title },
    444        cancel_button_string_id: "newtab-section-cancel-button",
    445      },
    446    },
    447    userEvent: "DIALOG_OPEN",
    448  }),
    449  SectionUnfollow: ({
    450    sectionPersonalization,
    451    sectionKey,
    452    sectionPosition,
    453  }) => ({
    454    id: "newtab-menu-section-unfollow",
    455    action: ac.AlsoToMain({
    456      type: at.SECTION_PERSONALIZATION_SET,
    457      data: (({ [sectionKey]: _sectionKey, ...remaining }) => remaining)(
    458        sectionPersonalization
    459      ),
    460    }),
    461    impression: ac.OnlyToMain({
    462      type: at.UNFOLLOW_SECTION,
    463      data: {
    464        section: sectionKey,
    465        section_position: sectionPosition,
    466        event_source: "CONTEXT_MENU",
    467      },
    468    }),
    469  }),
    470  ManageSponsoredContent: () => ({
    471    id: "newtab-menu-manage-sponsored-content",
    472    action: ac.OnlyToMain({ type: at.SETTINGS_OPEN }),
    473    userEvent: "OPEN_NEWTAB_PREFS",
    474  }),
    475  OurSponsorsAndYourPrivacy: () => ({
    476    id: "newtab-menu-our-sponsors-and-your-privacy",
    477    action: ac.OnlyToMain({
    478      type: at.OPEN_LINK,
    479      data: {
    480        url: "https://support.mozilla.org/kb/pocket-sponsored-stories-new-tabs",
    481      },
    482    }),
    483    userEvent: "CLICK_PRIVACY_INFO",
    484  }),
    485  ReportAd: site => {
    486    return {
    487      id: "newtab-menu-report-this-ad",
    488      action: ac.AlsoToMain({
    489        type: at.REPORT_AD_OPEN,
    490        data: {
    491          card_type: site.card_type,
    492          position: site.position,
    493          reporting_url: site.shim.report,
    494          url: site.url,
    495        },
    496      }),
    497    };
    498  },
    499 
    500  ReportContent: site => {
    501    return {
    502      id: "newtab-menu-report",
    503      action: ac.AlsoToMain({
    504        type: at.REPORT_CONTENT_OPEN,
    505        data: {
    506          card_type: site.card_type,
    507          corpus_item_id: site.corpus_item_id,
    508          scheduled_corpus_item_id: site.scheduled_corpus_item_id,
    509          section_position: site.section_position,
    510          section: site.section,
    511          title: site.title,
    512          topic: site.topic,
    513          url: site.url,
    514        },
    515      }),
    516    };
    517  },
    518 };