/* 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 . */ // @flow import React, { PureComponent } from "react"; import { connect } from "../../utils/connect"; import { showMenu, buildMenu } from "devtools-contextmenu"; import SourceIcon from "../shared/SourceIcon"; import { CloseButton } from "../shared/Button"; import type { List } from "immutable"; import type { Source, Context } from "../../types"; import actions from "../../actions"; import { getDisplayPath, getFileURL, getRawSourceURL, getSourceQueryString, getTruncatedFileName, isPretty, shouldBlackbox } from "../../utils/source"; import { copyToTheClipboard } from "../../utils/clipboard"; import { getTabMenuItems } from "../../utils/tabs"; import { getSelectedSource, getActiveSearch, getSourcesForTabs, getHasSiblingOfSameName, getContext } from "../../selectors"; import type { ActiveSearchType } from "../../selectors"; import classnames from "classnames"; type SourcesList = List; type Props = { cx: Context, tabSources: SourcesList, selectedSource: Source, source: Source, activeSearch: ActiveSearchType, hasSiblingOfSameName: boolean, selectSource: typeof actions.selectSource, closeTab: typeof actions.closeTab, closeTabs: typeof actions.closeTabs, togglePrettyPrint: typeof actions.togglePrettyPrint, showSource: typeof actions.showSource, toggleBlackBox: typeof actions.toggleBlackBox }; class Tab extends PureComponent { onTabContextMenu = (event, tab: string) => { event.preventDefault(); this.showContextMenu(event, tab); }; showContextMenu(e, tab: string) { const { cx, closeTab, closeTabs, tabSources, showSource, toggleBlackBox, togglePrettyPrint, selectedSource, source } = this.props; const tabCount = tabSources.length; const otherTabs = tabSources.filter(t => t.id !== tab); const sourceTab = tabSources.find(t => t.id == tab); const tabURLs = tabSources.map(t => t.url); const otherTabURLs = otherTabs.map(t => t.url); if (!sourceTab) { return; } const tabMenuItems = getTabMenuItems(); const items = [ { item: { ...tabMenuItems.closeTab, click: () => closeTab(cx, sourceTab) } }, { item: { ...tabMenuItems.closeOtherTabs, click: () => closeTabs(cx, otherTabURLs), disabled: otherTabURLs.length === 0 } }, { item: { ...tabMenuItems.closeTabsToEnd, click: () => { const tabIndex = tabSources.findIndex(t => t.id == tab); closeTabs(cx, tabURLs.filter((t, i) => i > tabIndex)); }, disabled: tabCount === 1 || tabSources.some((t, i) => t === tab && tabCount - 1 === i) } }, { item: { ...tabMenuItems.closeAllTabs, click: () => closeTabs(cx, tabURLs) } }, { item: { type: "separator" } }, { item: { ...tabMenuItems.copyToClipboard, disabled: selectedSource.id !== tab, click: () => copyToTheClipboard(sourceTab.text) } }, { item: { ...tabMenuItems.copySourceUri2, disabled: !selectedSource.url, click: () => copyToTheClipboard(getRawSourceURL(sourceTab.url)) } }, { item: { ...tabMenuItems.showSource, disabled: !selectedSource.url, click: () => showSource(cx, tab) } }, { item: { ...tabMenuItems.toggleBlackBox, label: source.isBlackBoxed ? L10N.getStr("sourceFooter.unblackbox") : L10N.getStr("sourceFooter.blackbox"), disabled: !shouldBlackbox(source), click: () => toggleBlackBox(cx, source) } }, { item: { ...tabMenuItems.prettyPrint, click: () => togglePrettyPrint(cx, tab), disabled: isPretty(sourceTab) } } ]; showMenu(e, buildMenu(items)); } isProjectSearchEnabled() { return this.props.activeSearch === "project"; } isSourceSearchEnabled() { return this.props.activeSearch === "source"; } render() { const { cx, selectedSource, selectSource, closeTab, source, tabSources, hasSiblingOfSameName } = this.props; const sourceId = source.id; const active = selectedSource && sourceId == selectedSource.id && (!this.isProjectSearchEnabled() && !this.isSourceSearchEnabled()); const isPrettyCode = isPretty(source); function onClickClose(e) { e.stopPropagation(); closeTab(cx, source); } function handleTabClick(e) { e.preventDefault(); e.stopPropagation(); return selectSource(cx, sourceId); } const className = classnames("source-tab", { active, pretty: isPrettyCode }); const path = getDisplayPath(source, tabSources); const query = hasSiblingOfSameName ? getSourceQueryString(source) : ""; return (
e.button === 1 && closeTab(cx, source)} onContextMenu={e => this.onTabContextMenu(e, sourceId)} title={getFileURL(source, false)} > ["file", "javascript"].includes(icon)} />
{getTruncatedFileName(source, query)} {path && {`../${path}/..`}}
); } } const mapStateToProps = (state, { source }) => { const selectedSource = getSelectedSource(state); return { cx: getContext(state), tabSources: getSourcesForTabs(state), selectedSource: selectedSource, activeSearch: getActiveSearch(state), hasSiblingOfSameName: getHasSiblingOfSameName(state, source) }; }; export default connect( mapStateToProps, { selectSource: actions.selectSource, closeTab: actions.closeTab, closeTabs: actions.closeTabs, togglePrettyPrint: actions.togglePrettyPrint, showSource: actions.showSource, toggleBlackBox: actions.toggleBlackBox } )(Tab);