Skip to content
This repository was archived by the owner on Jan 11, 2023. It is now read-only.

Commit 9e8566a

Browse files
bomsyjasonLaster
authored andcommitted
Refactor tabs (#5133)
1 parent 01f5123 commit 9e8566a

File tree

6 files changed

+338
-355
lines changed

6 files changed

+338
-355
lines changed

src/actions/tabs.js

Whitespace-only changes.

src/components/Editor/Tab.js

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
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+
// @flow
6+
7+
import React, { PureComponent } from "react";
8+
import { connect } from "react-redux";
9+
import { bindActionCreators } from "redux";
10+
11+
import { showMenu, buildMenu } from "devtools-contextmenu";
12+
13+
import CloseButton from "../shared/Button/Close";
14+
15+
import type { List } from "immutable";
16+
import type { SourceRecord } from "../../reducers/sources";
17+
18+
import actions from "../../actions";
19+
20+
import { getFilename, getFileURL, isPretty } from "../../utils/source";
21+
import { copyToTheClipboard } from "../../utils/clipboard";
22+
import { getSourceAnnotation } from "../../utils/tabs";
23+
24+
import {
25+
getSelectedSource,
26+
getSourceMetaData,
27+
getActiveSearch,
28+
getSourcesForTabs
29+
} from "../../selectors";
30+
31+
import classnames from "classnames";
32+
33+
type SourcesList = List<SourceRecord>;
34+
35+
type Props = {
36+
tabSources: SourcesList,
37+
selectSource: Object => void,
38+
selectedSource: SourceRecord,
39+
closeTab: string => void,
40+
closeTabs: (List<string>) => void,
41+
togglePrettyPrint: string => void,
42+
showSource: string => void,
43+
source: SourceRecord,
44+
activeSearch: string,
45+
getMetaData: string => any
46+
};
47+
48+
class Tab extends PureComponent<Props> {
49+
onTabContextMenu = (event, tab: string) => {
50+
event.preventDefault();
51+
this.showContextMenu(event, tab);
52+
};
53+
54+
showContextMenu(e, tab: string) {
55+
const {
56+
closeTab,
57+
closeTabs,
58+
tabSources,
59+
showSource,
60+
togglePrettyPrint
61+
} = this.props;
62+
63+
const closeTabLabel = L10N.getStr("sourceTabs.closeTab");
64+
const closeOtherTabsLabel = L10N.getStr("sourceTabs.closeOtherTabs");
65+
const closeTabsToEndLabel = L10N.getStr("sourceTabs.closeTabsToEnd");
66+
const closeAllTabsLabel = L10N.getStr("sourceTabs.closeAllTabs");
67+
const revealInTreeLabel = L10N.getStr("sourceTabs.revealInTree");
68+
const copyLinkLabel = L10N.getStr("copySourceUri2");
69+
const prettyPrintLabel = L10N.getStr("sourceTabs.prettyPrint");
70+
71+
const closeTabKey = L10N.getStr("sourceTabs.closeTab.accesskey");
72+
const closeOtherTabsKey = L10N.getStr(
73+
"sourceTabs.closeOtherTabs.accesskey"
74+
);
75+
const closeTabsToEndKey = L10N.getStr(
76+
"sourceTabs.closeTabsToEnd.accesskey"
77+
);
78+
const closeAllTabsKey = L10N.getStr("sourceTabs.closeAllTabs.accesskey");
79+
const revealInTreeKey = L10N.getStr("sourceTabs.revealInTree.accesskey");
80+
const copyLinkKey = L10N.getStr("copySourceUri2.accesskey");
81+
const prettyPrintKey = L10N.getStr("sourceTabs.prettyPrint.accesskey");
82+
83+
const otherTabs = tabSources.filter(t => t.get("id") !== tab);
84+
const sourceTab = tabSources.find(t => t.get("id") == tab);
85+
const tabURLs = tabSources.map(t => t.get("url"));
86+
const otherTabURLs = otherTabs.map(t => t.get("url"));
87+
88+
if (!sourceTab) {
89+
return;
90+
}
91+
92+
const isPrettySource = isPretty(sourceTab);
93+
94+
const closeTabMenuItem = {
95+
id: "node-menu-close-tab",
96+
label: closeTabLabel,
97+
accesskey: closeTabKey,
98+
disabled: false,
99+
click: () => closeTab(sourceTab.get("url"))
100+
};
101+
102+
const closeOtherTabsMenuItem = {
103+
id: "node-menu-close-other-tabs",
104+
label: closeOtherTabsLabel,
105+
accesskey: closeOtherTabsKey,
106+
disabled: false,
107+
click: () => closeTabs(otherTabURLs)
108+
};
109+
110+
const closeTabsToEndMenuItem = {
111+
id: "node-menu-close-tabs-to-end",
112+
label: closeTabsToEndLabel,
113+
accesskey: closeTabsToEndKey,
114+
disabled: false,
115+
click: () => {
116+
const tabIndex = tabSources.findIndex(t => t == tab);
117+
closeTabs(tabURLs.filter((t, i) => i > tabIndex));
118+
}
119+
};
120+
121+
const closeAllTabsMenuItem = {
122+
id: "node-menu-close-all-tabs",
123+
label: closeAllTabsLabel,
124+
accesskey: closeAllTabsKey,
125+
disabled: false,
126+
click: () => closeTabs(tabURLs)
127+
};
128+
129+
const showSourceMenuItem = {
130+
id: "node-menu-show-source",
131+
label: revealInTreeLabel,
132+
accesskey: revealInTreeKey,
133+
disabled: false,
134+
click: () => showSource(sourceTab)
135+
};
136+
137+
const copySourceUri2 = {
138+
id: "node-menu-copy-source-url",
139+
label: copyLinkLabel,
140+
accesskey: copyLinkKey,
141+
disabled: false,
142+
click: () => copyToTheClipboard(sourceTab.get("url"))
143+
};
144+
145+
const prettyPrint = {
146+
id: "node-menu-pretty-print",
147+
label: prettyPrintLabel,
148+
accesskey: prettyPrintKey,
149+
disabled: false,
150+
click: () => togglePrettyPrint(sourceTab.get("id"))
151+
};
152+
153+
const items = [
154+
{ item: closeTabMenuItem },
155+
{ item: closeOtherTabsMenuItem, hidden: () => tabSources.size === 1 },
156+
{
157+
item: closeTabsToEndMenuItem,
158+
hidden: () =>
159+
tabSources.some((t, i) => t === tab && tabSources.size - 1 === i)
160+
},
161+
{ item: closeAllTabsMenuItem },
162+
{ item: { type: "separator" } },
163+
{ item: copySourceUri2 }
164+
];
165+
166+
if (!isPrettySource) {
167+
items.push({ item: showSourceMenuItem });
168+
items.push({ item: prettyPrint });
169+
}
170+
171+
showMenu(e, buildMenu(items));
172+
}
173+
174+
isProjectSearchEnabled() {
175+
return this.props.activeSearch === "project";
176+
}
177+
178+
isSourceSearchEnabled() {
179+
return this.props.activeSearch === "source";
180+
}
181+
182+
render() {
183+
const {
184+
selectedSource,
185+
selectSource,
186+
closeTab,
187+
source,
188+
getMetaData
189+
} = this.props;
190+
const src = source.toJS();
191+
const filename = getFilename(src);
192+
const sourceId = source.get("id");
193+
const active =
194+
selectedSource &&
195+
sourceId == selectedSource.get("id") &&
196+
(!this.isProjectSearchEnabled() && !this.isSourceSearchEnabled());
197+
const isPrettyCode = isPretty(source);
198+
const sourceAnnotation = getSourceAnnotation(source, getMetaData);
199+
200+
function onClickClose(ev) {
201+
ev.stopPropagation();
202+
closeTab(source.get("url"));
203+
}
204+
205+
const className = classnames("source-tab", {
206+
active,
207+
pretty: isPrettyCode
208+
});
209+
210+
return (
211+
<div
212+
className={className}
213+
key={sourceId}
214+
onClick={() => selectSource(sourceId)}
215+
onContextMenu={e => this.onTabContextMenu(e, sourceId)}
216+
title={getFileURL(src)}
217+
>
218+
{sourceAnnotation}
219+
<div className="filename">{filename}</div>
220+
<CloseButton
221+
handleClick={onClickClose}
222+
tooltip={L10N.getStr("sourceTabs.closeTabButtonTooltip")}
223+
/>
224+
</div>
225+
);
226+
}
227+
}
228+
229+
export default connect(
230+
state => {
231+
return {
232+
tabSources: getSourcesForTabs(state),
233+
selectedSource: getSelectedSource(state),
234+
getMetaData: sourceId => getSourceMetaData(state, sourceId),
235+
activeSearch: getActiveSearch(state)
236+
};
237+
},
238+
dispatch => bindActionCreators(actions, dispatch)
239+
)(Tab);

0 commit comments

Comments
 (0)