summaryrefslogtreecommitdiffstats
path: root/browser/components/newtab/content-src/components/LinkMenu/LinkMenu.jsx
blob: 650a03eb95112c9a074852b717558d6d2f6ed241 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/* 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/. */

import { actionCreators as ac } from "common/Actions.sys.mjs";
import { connect } from "react-redux";
import { ContextMenu } from "content-src/components/ContextMenu/ContextMenu";
import { LinkMenuOptions } from "content-src/lib/link-menu-options";
import React from "react";

const DEFAULT_SITE_MENU_OPTIONS = [
  "CheckPinTopSite",
  "EditTopSite",
  "Separator",
  "OpenInNewWindow",
  "OpenInPrivateWindow",
  "Separator",
  "BlockUrl",
];

export class _LinkMenu extends React.PureComponent {
  getOptions() {
    const { props } = this;
    const {
      site,
      index,
      source,
      isPrivateBrowsingEnabled,
      siteInfo,
      platform,
      userEvent = ac.UserEvent,
    } = props;

    // Handle special case of default site
    const propOptions =
      site.isDefault && !site.searchTopSite && !site.sponsored_position
        ? DEFAULT_SITE_MENU_OPTIONS
        : props.options;

    const options = propOptions
      .map(o =>
        LinkMenuOptions[o](
          site,
          index,
          source,
          isPrivateBrowsingEnabled,
          siteInfo,
          platform
        )
      )
      .map(option => {
        const { action, impression, id, type, userEvent: eventName } = option;
        if (!type && id) {
          option.onClick = (event = {}) => {
            const { ctrlKey, metaKey, shiftKey, button } = event;
            // Only send along event info if there's something non-default to send
            if (ctrlKey || metaKey || shiftKey || button === 1) {
              action.data = Object.assign(
                {
                  event: { ctrlKey, metaKey, shiftKey, button },
                },
                action.data
              );
            }
            props.dispatch(action);
            if (eventName) {
              const userEventData = Object.assign(
                {
                  event: eventName,
                  source,
                  action_position: index,
                  value: { card_type: site.flight_id ? "spoc" : "organic" },
                },
                siteInfo
              );
              props.dispatch(userEvent(userEventData));
            }
            if (impression && props.shouldSendImpressionStats) {
              props.dispatch(impression);
            }
          };
        }
        return option;
      });

    // This is for accessibility to support making each item tabbable.
    // We want to know which item is the first and which item
    // is the last, so we can close the context menu accordingly.
    options[0].first = true;
    options[options.length - 1].last = true;
    return options;
  }

  render() {
    return (
      <ContextMenu
        onUpdate={this.props.onUpdate}
        onShow={this.props.onShow}
        options={this.getOptions()}
        keyboardAccess={this.props.keyboardAccess}
      />
    );
  }
}

const getState = state => ({
  isPrivateBrowsingEnabled: state.Prefs.values.isPrivateBrowsingEnabled,
  platform: state.Prefs.values.platform,
});
export const LinkMenu = connect(getState)(_LinkMenu);