Skip to content

Commit 68c062f

Browse files
committed
Refactor redux stores
1 parent a056b26 commit 68c062f

File tree

12 files changed

+192
-174
lines changed

12 files changed

+192
-174
lines changed

src/backend/tracers/js/worker.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const sandbox = code => {
77
eval(code);
88
};
99

10-
onmessage = e => { // TODO: stop after the first delay() on the initial run
10+
onmessage = e => {
1111
const lines = e.data.split('\n').map((line, i) => line.replace(/(.+\. *delay *)(\( *\))/g, `$1(${i})`));
1212
const { code } = Babel.transform(lines.join('\n'), { presets: ['es2015'] });
1313
sandbox(code);

src/frontend/common/util.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ const createProjectFile = (name, content) => createFile(name, content, [{
3030

3131
const createUserFile = (name, content) => createFile(name, content, undefined);
3232

33+
const isSaved = ({ titles, files, lastTitles, lastFiles }) => {
34+
const serialize = (titles, files) => JSON.stringify({
35+
titles,
36+
files: files.map(({ name, content }) => ({ name, content })),
37+
});
38+
return serialize(titles, files) === serialize(lastTitles, lastFiles);
39+
};
40+
3341
export {
3442
classes,
3543
distance,
@@ -38,4 +46,5 @@ export {
3846
createFile,
3947
createProjectFile,
4048
createUserFile,
49+
isSaved,
4150
};

src/frontend/components/App/index.jsx

Lines changed: 14 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ import Cookies from 'js-cookie';
33
import { connect } from 'react-redux';
44
import Promise from 'bluebird';
55
import { Helmet } from 'react-helmet';
6-
import AutosizeInput from 'react-input-autosize';
76
import queryString from 'query-string';
8-
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
9-
import faPlus from '@fortawesome/fontawesome-free-solid/faPlus';
107
import {
118
BaseComponent,
129
CodeEditor,
@@ -32,7 +29,6 @@ class App extends BaseComponent {
3229
this.state = {
3330
navigatorOpened: true,
3431
workspaceWeights: [1, 2, 2],
35-
editorTabIndex: -1,
3632
};
3733

3834
this.codeEditorRef = React.createRef();
@@ -79,11 +75,12 @@ class App extends BaseComponent {
7975

8076
toggleHistoryBlock(enable = !this.unblock) {
8177
if (enable) {
78+
const { saved } = this.props.current;
8279
const warningMessage = 'Are you sure you want to discard changes?';
83-
window.onbeforeunload = () => this.isSaved() ? undefined : warningMessage;
80+
window.onbeforeunload = () => saved ? undefined : warningMessage;
8481
this.unblock = this.props.history.block((location) => {
8582
if (location.pathname === this.props.location.pathname) return;
86-
if (!this.isSaved()) return warningMessage;
83+
if (!saved) return warningMessage;
8784
});
8885
} else {
8986
window.onbeforeunload = undefined;
@@ -189,97 +186,44 @@ class App extends BaseComponent {
189186
selectDefaultTab() {
190187
const { ext } = this.props.env;
191188
const { files } = this.props.current;
192-
let editorTabIndex = files.findIndex(file => extension(file.name) === 'json');
193-
if (!~editorTabIndex) files.findIndex(file => extension(file.name) === ext);
194-
if (!~editorTabIndex) editorTabIndex = files.findIndex(file => exts.includes(extension(file.name)));
195-
if (!~editorTabIndex) editorTabIndex = Math.min(0, files.length - 1);
196-
this.handleChangeEditorTabIndex(editorTabIndex);
189+
const editingFile = files.find(file => extension(file.name) === 'json') ||
190+
files.find(file => extension(file.name) === ext) ||
191+
files.find(file => exts.includes(extension(file.name))) ||
192+
files[files.length - 1];
193+
this.props.setEditingFile(editingFile);
197194
}
198195

199196
handleChangeWorkspaceWeights(workspaceWeights) {
200197
this.setState({ workspaceWeights });
201198
this.codeEditorRef.current.getWrappedInstance().handleResize();
202199
}
203200

204-
handleChangeEditorTabIndex(editorTabIndex) {
205-
const { files } = this.props.current;
206-
if (editorTabIndex === files.length) this.handleAddFile();
207-
this.setState({ editorTabIndex });
208-
this.props.shouldBuild();
209-
}
210-
211-
handleAddFile() {
212-
const { ext } = this.props.env;
213-
const { files } = this.props.current;
214-
const language = languages.find(language => language.ext === ext);
215-
const file = { ...language.skeleton };
216-
let count = 0;
217-
while (files.some(existingFile => existingFile.name === file.name)) file.name = `code-${++count}.${ext}`;
218-
this.props.addFile(file);
219-
}
220-
221-
handleRenameFile(e) {
222-
const { value } = e.target;
223-
const { editorTabIndex } = this.state;
224-
this.props.renameFile(editorTabIndex, value);
225-
}
226-
227-
handleDeleteFile() {
228-
const { editorTabIndex } = this.state;
229-
const { files } = this.props.current;
230-
this.handleChangeEditorTabIndex(Math.min(editorTabIndex, files.length - 2));
231-
this.props.deleteFile(editorTabIndex);
232-
}
233-
234201
toggleNavigatorOpened(navigatorOpened = !this.state.navigatorOpened) {
235202
this.setState({ navigatorOpened });
236203
}
237204

238-
isSaved() {
239-
const { titles, files, lastTitles, lastFiles } = this.props.current;
240-
const serialize = (titles, files) => JSON.stringify({
241-
titles,
242-
files: files.map(({ name, content }) => ({ name, content })),
243-
});
244-
return serialize(titles, files) === serialize(lastTitles, lastFiles);
245-
}
246-
247205
render() {
248-
const { navigatorOpened, workspaceWeights, editorTabIndex } = this.state;
206+
const { navigatorOpened, workspaceWeights } = this.state;
249207

250-
const { files, titles, description } = this.props.current;
251-
const saved = this.isSaved();
208+
const { titles, description, saved } = this.props.current;
252209
const title = `${saved ? '' : '(Unsaved) '}${titles.join(' - ')}`;
253-
const file = files[editorTabIndex];
254-
255-
const editorTitles = files.map(file => file.name);
256-
if (file) {
257-
editorTitles[editorTabIndex] = (
258-
<AutosizeInput className={styles.input_title} value={file.name}
259-
onClick={e => e.stopPropagation()} onChange={e => this.handleRenameFile(e)} />
260-
);
261-
}
262-
editorTitles.push(
263-
<FontAwesomeIcon fixedWidth icon={faPlus} />,
264-
);
265210

266211
return (
267212
<div className={styles.app}>
268213
<Helmet>
269214
<title>{title}</title>
270215
<meta name="description" content={description} />
271216
</Helmet>
272-
<Header className={styles.header} onClickTitleBar={() => this.toggleNavigatorOpened()} saved={saved}
273-
navigatorOpened={navigatorOpened} loadScratchPapers={() => this.loadScratchPapers()} file={file}
217+
<Header className={styles.header} onClickTitleBar={() => this.toggleNavigatorOpened()}
218+
navigatorOpened={navigatorOpened} loadScratchPapers={() => this.loadScratchPapers()}
274219
ignoreHistoryBlock={this.ignoreHistoryBlock} />
275220
<ResizableContainer className={styles.workspace} horizontal weights={workspaceWeights}
276221
visibles={[navigatorOpened, true, true]}
277222
onChangeWeights={weights => this.handleChangeWorkspaceWeights(weights)}>
278223
<Navigator />
279224
<VisualizationViewer className={styles.visualization_viewer} />
280-
<TabContainer className={styles.editor_tab_container} titles={editorTitles} tabIndex={editorTabIndex}
281-
onChangeTabIndex={tabIndex => this.handleChangeEditorTabIndex(tabIndex)}>
282-
<CodeEditor ref={this.codeEditorRef} file={file} onClickDelete={() => this.handleDeleteFile()} />
225+
<TabContainer className={styles.editor_tab_container}>
226+
<CodeEditor ref={this.codeEditorRef} />
283227
</TabContainer>
284228
</ResizableContainer>
285229
<ToastContainer className={styles.toast_container} />

src/frontend/components/App/stylesheet.scss

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,6 @@ button {
6060
}
6161

6262
.editor_tab_container {
63-
.input_title {
64-
input {
65-
&:hover,
66-
&:focus {
67-
margin: -4px;
68-
padding: 4px;
69-
background-color: $theme-normal;
70-
}
71-
}
72-
}
7363
}
7464
}
7565

src/frontend/components/CodeEditor/index.jsx

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,27 @@ import { languages } from '/common/config';
88
import { Button, Ellipsis, FoldableAceEditor } from '/components';
99
import styles from './stylesheet.scss';
1010

11-
@connect(({ env, player }) => ({ env, player }), actions, null, { withRef: true })
11+
@connect(({ current, env, player }) => ({ current, env, player }), actions, null, { withRef: true })
1212
class CodeEditor extends React.Component {
1313
constructor(props) {
1414
super(props);
1515

1616
this.aceEditorRef = React.createRef();
1717
}
1818

19-
handleChangeCode(code) {
20-
const { file } = this.props;
21-
this.props.modifyFile({ ...file, content: code });
22-
if (extension(file.name) === 'md') this.props.shouldBuild();
23-
}
24-
2519
handleResize() {
2620
this.aceEditorRef.current.editor.resize();
2721
}
2822

2923
render() {
30-
const { className, file, onClickDelete } = this.props;
24+
const { className } = this.props;
25+
const { editingFile } = this.props.current;
3126
const { user } = this.props.env;
32-
const { lineIndicator, buildAt } = this.props.player;
27+
const { lineIndicator } = this.props.player;
3328

34-
if (!file) return null;
29+
if (!editingFile) return null;
3530

36-
const fileExt = extension(file.name);
31+
const fileExt = extension(editingFile.name);
3732
const language = languages.find(language => language.ext === fileExt);
3833
const mode = language ? language.mode :
3934
fileExt === 'md' ? 'markdown' :
@@ -49,7 +44,7 @@ class CodeEditor extends React.Component {
4944
theme="tomorrow_night_eighties"
5045
name="code_editor"
5146
editorProps={{ $blockScrolling: true }}
52-
onChange={code => this.handleChangeCode(code)}
47+
onChange={code => this.props.modifyFile(editingFile, code)}
5348
markers={lineIndicator ? [{
5449
startRow: lineIndicator.lineNumber,
5550
startCol: 0,
@@ -60,12 +55,11 @@ class CodeEditor extends React.Component {
6055
inFront: true,
6156
_key: lineIndicator.cursor,
6257
}] : []}
63-
foldAt={buildAt}
64-
value={file.content} />
58+
value={editingFile.content} />
6559
<div className={classes(styles.contributors_viewer, className)}>
6660
<span className={classes(styles.contributor, styles.label)}>Contributed by</span>
6761
{
68-
(file.contributors || [user || { login: 'guest', avatar_url: faUser }]).map(contributor => (
62+
(editingFile.contributors || [user || { login: 'guest', avatar_url: faUser }]).map(contributor => (
6963
<Button className={styles.contributor} icon={contributor.avatar_url} key={contributor.login}
7064
href={`https://github.com/${contributor.login}`}>
7165
{contributor.login}
@@ -74,8 +68,8 @@ class CodeEditor extends React.Component {
7468
}
7569
<div className={styles.empty}>
7670
<div className={styles.empty} />
77-
<Button className={styles.delete} icon={faTrashAlt} primary onClick={onClickDelete}
78-
confirmNeeded>
71+
<Button className={styles.delete} icon={faTrashAlt} primary confirmNeeded
72+
onClick={() => this.props.deleteFile(editingFile)}>
7973
<Ellipsis>Delete File</Ellipsis>
8074
</Button>
8175
</div>

src/frontend/components/FoldableAceEditor/index.jsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from 'react';
2+
import { connect } from 'react-redux';
23
import AceEditor from 'react-ace';
34
import 'brace/mode/plain_text';
45
import 'brace/mode/markdown';
@@ -8,19 +9,23 @@ import 'brace/mode/c_cpp';
89
import 'brace/mode/java';
910
import 'brace/theme/tomorrow_night_eighties';
1011
import 'brace/ext/searchbox';
12+
import { actions } from '/reducers';
1113

14+
@connect(({ current }) => ({ current }), actions)
1215
class FoldableAceEditor extends AceEditor {
1316
componentDidMount() {
1417
super.componentDidMount();
1518

16-
this.foldTracers();
19+
const { shouldBuild } = this.props.current;
20+
if (shouldBuild) this.foldTracers();
1721
}
1822

1923
componentDidUpdate(prevProps, prevState, snapshot) {
2024
super.componentDidUpdate(prevProps, prevState, snapshot);
2125

22-
if (prevProps.foldAt !== this.props.foldAt) {
23-
this.foldTracers();
26+
const { editingFile, shouldBuild } = this.props.current;
27+
if (editingFile !== prevProps.current.editingFile) {
28+
if (shouldBuild) this.foldTracers();
2429
}
2530
}
2631

src/frontend/components/Header/index.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ class Header extends BaseComponent {
110110
}
111111

112112
render() {
113-
const { className, onClickTitleBar, navigatorOpened, saved, file } = this.props;
114-
const { scratchPaper, titles } = this.props.current;
113+
const { className, onClickTitleBar, navigatorOpened } = this.props;
114+
const { scratchPaper, titles, saved } = this.props.current;
115115
const { ext, user } = this.props.env;
116116

117117
const permitted = this.hasPermission();
@@ -174,7 +174,7 @@ class Header extends BaseComponent {
174174
</div>
175175
</Button>
176176
</div>
177-
<Player className={styles.section} file={file} />
177+
<Player className={styles.section} />
178178
</div>
179179
</header>
180180
);

src/frontend/components/Player/index.jsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { actions } from '/reducers';
1313
import { BaseComponent, Button, ProgressBar } from '/components';
1414
import styles from './stylesheet.scss';
1515

16-
@connect(({ player }) => ({ player }), actions)
16+
@connect(({ current, player }) => ({ current, player }), actions)
1717
class Player extends BaseComponent {
1818
constructor(props) {
1919
super(props);
@@ -30,15 +30,14 @@ class Player extends BaseComponent {
3030
}
3131

3232
componentDidMount() {
33-
const { file } = this.props;
34-
this.build(file);
33+
const { editingFile, shouldBuild } = this.props.current;
34+
if (shouldBuild) this.build(editingFile);
3535
}
3636

3737
componentWillReceiveProps(nextProps) {
38-
const { file } = nextProps;
39-
const { buildAt } = nextProps.player;
40-
if (buildAt !== this.props.player.buildAt) {
41-
this.build(file);
38+
const { editingFile, shouldBuild } = nextProps.current;
39+
if (editingFile !== this.props.current.editingFile) {
40+
if (shouldBuild) this.build(editingFile);
4241
}
4342
}
4443

@@ -145,13 +144,15 @@ class Player extends BaseComponent {
145144
}
146145

147146
render() {
148-
const { className, file } = this.props;
147+
const { className } = this.props;
148+
const { editingFile } = this.props.current;
149149
const { chunks, cursor } = this.props.player;
150150
const { speed, playing, building } = this.state;
151151

152152
return (
153153
<div className={classes(styles.player, className)}>
154-
<Button icon={faWrench} primary disabled={building} inProgress={building} onClick={() => this.build(file)}>
154+
<Button icon={faWrench} primary disabled={building} inProgress={building}
155+
onClick={() => this.build(editingFile)}>
155156
{building ? 'Building' : 'Build'}
156157
</Button>
157158
{

0 commit comments

Comments
 (0)