tor-browser

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

LinkMenu.jsx (4813B)


      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 { actionCreators as ac } from "common/Actions.mjs";
      6 import { connect } from "react-redux";
      7 import { ContextMenu } from "content-src/components/ContextMenu/ContextMenu";
      8 import { LinkMenuOptions } from "content-src/lib/link-menu-options";
      9 import React from "react";
     10 
     11 const DEFAULT_SITE_MENU_OPTIONS = [
     12  "CheckPinTopSite",
     13  "EditTopSite",
     14  "Separator",
     15  "OpenInNewWindow",
     16  "OpenInPrivateWindow",
     17  "Separator",
     18  "BlockUrl",
     19 ];
     20 
     21 export class _LinkMenu extends React.PureComponent {
     22  getOptions() {
     23    const { props } = this;
     24    const {
     25      site,
     26      index,
     27      source,
     28      isPrivateBrowsingEnabled,
     29      siteInfo,
     30      platform,
     31      dispatch,
     32      options,
     33      shouldSendImpressionStats,
     34      userEvent = ac.UserEvent,
     35    } = props;
     36 
     37    // Handle special case of default site
     38    const propOptions =
     39      site.isDefault && !site.searchTopSite && !site.sponsored_position
     40        ? DEFAULT_SITE_MENU_OPTIONS
     41        : options;
     42 
     43    const linkMenuOptions = propOptions
     44      .map(o =>
     45        LinkMenuOptions[o](
     46          site,
     47          index,
     48          source,
     49          isPrivateBrowsingEnabled,
     50          siteInfo,
     51          platform
     52        )
     53      )
     54      .map(option => {
     55        const { action, impression, id, type, userEvent: eventName } = option;
     56        if (!type && id) {
     57          option.onClick = (event = {}) => {
     58            const { ctrlKey, metaKey, shiftKey, button } = event;
     59            // Only send along event info if there's something non-default to send
     60            if (ctrlKey || metaKey || shiftKey || button === 1) {
     61              action.data = Object.assign(
     62                {
     63                  event: { ctrlKey, metaKey, shiftKey, button },
     64                },
     65                action.data
     66              );
     67            }
     68            dispatch(action);
     69            if (eventName) {
     70              let value;
     71              // Bug 1958135: Pass additional info to ac.OPEN_NEW_WINDOW event
     72              if (action.type === "OPEN_NEW_WINDOW") {
     73                const {
     74                  card_type,
     75                  corpus_item_id,
     76                  event_source,
     77                  fetchTimestamp,
     78                  firstVisibleTimestamp,
     79                  format,
     80                  is_section_followed,
     81                  received_rank,
     82                  recommendation_id,
     83                  recommended_at,
     84                  scheduled_corpus_item_id,
     85                  section_position,
     86                  section,
     87                  selected_topics,
     88                  tile_id,
     89                  topic,
     90                } = action.data;
     91 
     92                value = {
     93                  card_type,
     94                  corpus_item_id,
     95                  event_source,
     96                  fetchTimestamp,
     97                  firstVisibleTimestamp,
     98                  format,
     99                  received_rank,
    100                  recommendation_id,
    101                  recommended_at,
    102                  scheduled_corpus_item_id,
    103                  ...(section
    104                    ? { is_section_followed, section_position, section }
    105                    : {}),
    106                  selected_topics: selected_topics ? selected_topics : "",
    107                  tile_id,
    108                  topic,
    109                };
    110              } else {
    111                value = { card_type: site.flight_id ? "spoc" : "organic" };
    112              }
    113              const userEventData = Object.assign(
    114                {
    115                  event: eventName,
    116                  source,
    117                  action_position: index,
    118                  value,
    119                },
    120                siteInfo
    121              );
    122              dispatch(userEvent(userEventData));
    123              if (impression && shouldSendImpressionStats) {
    124                dispatch(impression);
    125              }
    126            }
    127          };
    128        }
    129        return option;
    130      });
    131 
    132    // This is for accessibility to support making each item tabbable.
    133    // We want to know which item is the first and which item
    134    // is the last, so we can close the context menu accordingly.
    135    linkMenuOptions[0].first = true;
    136    linkMenuOptions[linkMenuOptions.length - 1].last = true;
    137    return linkMenuOptions;
    138  }
    139 
    140  render() {
    141    return (
    142      <ContextMenu
    143        onUpdate={this.props.onUpdate}
    144        onShow={this.props.onShow}
    145        options={this.getOptions()}
    146        keyboardAccess={this.props.keyboardAccess}
    147      />
    148    );
    149  }
    150 }
    151 
    152 const getState = state => ({
    153  isPrivateBrowsingEnabled: state.Prefs.values.isPrivateBrowsingEnabled,
    154  platform: state.Prefs.values.platform,
    155 });
    156 export const LinkMenu = connect(getState)(_LinkMenu);