summaryrefslogtreecommitdiffstats
path: root/browser/components/newtab/content-src/components/LinkMenu/LinkMenu.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/newtab/content-src/components/LinkMenu/LinkMenu.jsx')
-rw-r--r--browser/components/newtab/content-src/components/LinkMenu/LinkMenu.jsx110
1 files changed, 110 insertions, 0 deletions
diff --git a/browser/components/newtab/content-src/components/LinkMenu/LinkMenu.jsx b/browser/components/newtab/content-src/components/LinkMenu/LinkMenu.jsx
new file mode 100644
index 0000000000..650a03eb95
--- /dev/null
+++ b/browser/components/newtab/content-src/components/LinkMenu/LinkMenu.jsx
@@ -0,0 +1,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);