Tab.js (3818B)
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 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 import React, { PureComponent } from "devtools/client/shared/vendor/react"; 6 import { div, span } from "devtools/client/shared/vendor/react-dom-factories"; 7 import PropTypes from "devtools/client/shared/vendor/react-prop-types"; 8 import { connect } from "devtools/client/shared/vendor/react-redux"; 9 10 import SourceIcon from "../shared/SourceIcon"; 11 import { CloseButton } from "../shared/Button/index"; 12 13 import actions from "../../actions/index"; 14 15 import { 16 getDisplayPath, 17 getFileURL, 18 getTruncatedFileName, 19 } from "../../utils/source"; 20 import { createLocation } from "../../utils/location"; 21 22 import { 23 getSelectedLocation, 24 isSourceBlackBoxed, 25 getOpenedSources, 26 } from "../../selectors/index"; 27 28 const classnames = require("resource://devtools/client/shared/classnames.js"); 29 30 class Tab extends PureComponent { 31 static get propTypes() { 32 return { 33 closeTabForSource: PropTypes.func.isRequired, 34 onDragEnd: PropTypes.func.isRequired, 35 onDragOver: PropTypes.func.isRequired, 36 onDragStart: PropTypes.func.isRequired, 37 selectSource: PropTypes.func.isRequired, 38 source: PropTypes.object.isRequired, 39 isBlackBoxed: PropTypes.bool.isRequired, 40 }; 41 } 42 43 onContextMenu = event => { 44 event.preventDefault(); 45 this.props.showTabContextMenu(event, this.props.source); 46 }; 47 48 isSourceSearchEnabled() { 49 return this.props.activeSearch === "source"; 50 } 51 52 render() { 53 const { 54 selectSource, 55 closeTabForSource, 56 source, 57 onDragOver, 58 onDragStart, 59 onDragEnd, 60 index, 61 isActive, 62 } = this.props; 63 64 function onClickClose(e) { 65 e.stopPropagation(); 66 closeTabForSource(source); 67 } 68 69 function handleTabClick(e) { 70 e.preventDefault(); 71 e.stopPropagation(); 72 return selectSource(source); 73 } 74 75 const className = classnames("source-tab", { 76 active: isActive, 77 blackboxed: this.props.isBlackBoxed, 78 }); 79 80 const path = getDisplayPath(source, this.props.openedSources); 81 return div( 82 { 83 draggable: true, 84 onDragOver, 85 onDragStart, 86 onDragEnd, 87 className, 88 "data-index": index, 89 "data-source-id": source.id, 90 onClick: handleTabClick, 91 // Accommodate middle click to close tab 92 onMouseUp: e => e.button === 1 && closeTabForSource(source), 93 onContextMenu: this.onContextMenu, 94 title: getFileURL(source, false), 95 }, 96 React.createElement(SourceIcon, { 97 location: createLocation({ 98 source, 99 }), 100 }), 101 div( 102 { 103 className: "filename", 104 }, 105 getTruncatedFileName(source), 106 path && span(null, `../${path}/..`) 107 ), 108 React.createElement(CloseButton, { 109 handleClick: onClickClose, 110 tooltip: L10N.getStr("sourceTabs.closeTabButtonTooltip"), 111 }) 112 ); 113 } 114 } 115 116 const mapStateToProps = (state, { source }) => { 117 const selectedSource = getSelectedLocation(state)?.source; 118 // When a pretty printed source is selected, we should check if the related minimized/generated source is opened in a tab. 119 const isActive = selectedSource?.isPrettyPrinted 120 ? selectedSource.generatedSource == source 121 : selectedSource == source; 122 return { 123 isBlackBoxed: isSourceBlackBoxed(state, source), 124 isActive, 125 openedSources: getOpenedSources(state), 126 }; 127 }; 128 129 export default connect( 130 mapStateToProps, 131 { 132 selectSource: actions.selectSource, 133 closeTabForSource: actions.closeTabForSource, 134 showTabContextMenu: actions.showTabContextMenu, 135 }, 136 null, 137 { 138 withRef: true, 139 } 140 )(Tab);