Skip to content

Commit 6e8be4d

Browse files
committed
Fix minor bugs and do frontend code refactoring
1 parent eb89a86 commit 6e8be4d

File tree

16 files changed

+213
-201
lines changed

16 files changed

+213
-201
lines changed

src/frontend/common/config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CODE_CPP, CODE_JAVA, CODE_JS } from '/skeletons';
1+
import { CODE_CPP, CODE_JAVA, CODE_JS } from '/files';
22

33
const languages = [{
44
name: 'JavaScript',

src/frontend/common/util.js

+1-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { README_MD } from '/skeletons';
2-
31
const classes = (...arr) => arr.filter(v => v).join(' ');
42

53
const distance = (a, b) => {
@@ -20,28 +18,7 @@ const refineGist = gist => {
2018
content: file.content,
2119
contributors: [{ login, avatar_url }],
2220
}));
23-
return { gistId, title, files, gist };
24-
};
25-
26-
const getFiles = current => {
27-
const { algorithm, scratchPaper } = current;
28-
if (algorithm) return algorithm.files;
29-
if (scratchPaper) return scratchPaper.files;
30-
return [{
31-
name: 'README.md',
32-
content: README_MD,
33-
contributors: [{
34-
login: 'algorithm-visualizer',
35-
avatar_url: 'https://github.com/algorithm-visualizer.png',
36-
}],
37-
}];
38-
};
39-
40-
const getTitleArray = current => {
41-
const { algorithm, scratchPaper } = current;
42-
if (algorithm) return [algorithm.categoryName, algorithm.algorithmName];
43-
if (scratchPaper) return ['Scratch Paper', scratchPaper.title];
44-
return ['Algorithm Visualizer'];
21+
return { login, gistId, title, files };
4522
};
4623

4724
const handleError = function (error) {
@@ -54,7 +31,5 @@ export {
5431
distance,
5532
extension,
5633
refineGist,
57-
getFiles,
58-
getTitleArray,
5934
handleError,
6035
};

src/frontend/components/App/index.jsx

+54-77
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ import {
1919
} from '/components';
2020
import { AlgorithmApi, GitHubApi } from '/apis';
2121
import { actions } from '/reducers';
22-
import { extension, getFiles, getTitleArray, handleError, refineGist } from '/common/util';
22+
import { extension, handleError, refineGist } from '/common/util';
2323
import { exts, languages } from '/common/config';
24-
import { SCRATCH_PAPER_MD } from '/skeletons';
24+
import { SCRATCH_PAPER_MD } from '/files';
2525
import styles from './stylesheet.scss';
2626

2727
loadProgressBar();
@@ -53,7 +53,9 @@ class App extends React.Component {
5353
.then(({ categories }) => this.props.setCategories(categories))
5454
.catch(handleError.bind(this));
5555

56-
window.onbeforeunload = () => this.isGistSaved() ? undefined : 'Changes you made will not be saved.';
56+
this.props.history.block(() => {
57+
if (!this.isSaved()) return 'Are you sure want to discard changes?';
58+
});
5759
}
5860

5961
componentWillUnmount() {
@@ -65,26 +67,12 @@ class App extends React.Component {
6567

6668
componentWillReceiveProps(nextProps) {
6769
const { params } = nextProps.match;
68-
const { algorithm, scratchPaper } = nextProps.current;
69-
70-
const categoryKey = algorithm && algorithm.categoryKey;
71-
const algorithmKey = algorithm && algorithm.algorithmKey;
72-
const gistId = scratchPaper && scratchPaper.gistId;
73-
74-
if (params.categoryKey !== categoryKey ||
75-
params.algorithmKey !== algorithmKey ||
76-
params.gistId !== gistId) {
77-
if (nextProps.location.pathname !== this.props.location.pathname) {
78-
this.loadAlgorithm(params);
79-
} else {
80-
if (categoryKey && algorithmKey) {
81-
this.props.history.push(`/${categoryKey}/${algorithmKey}`);
82-
} else if (gistId) {
83-
this.props.history.push(`/scratch-paper/${gistId}`);
84-
} else {
85-
this.props.history.push('/');
86-
}
87-
}
70+
if (params !== this.props.match.params) {
71+
const { categoryKey, algorithmKey, gistId } = params;
72+
const { algorithm, scratchPaper } = nextProps.current;
73+
if (algorithm && algorithm.categoryKey === categoryKey && algorithm.algorithmKey === algorithmKey) return;
74+
if (scratchPaper && scratchPaper.gistId === gistId) return;
75+
this.loadAlgorithm(params);
8876
}
8977
}
9078

@@ -95,7 +83,6 @@ class App extends React.Component {
9583
.then(user => {
9684
const { login, avatar_url } = user;
9785
this.props.setUser({ login, avatar_url });
98-
Cookies.set('login', login);
9986
})
10087
.then(() => this.loadScratchPapers())
10188
.catch(() => this.signOut());
@@ -106,7 +93,6 @@ class App extends React.Component {
10693
GitHubApi.auth(undefined)
10794
.then(() => {
10895
this.props.setUser(undefined);
109-
Cookies.remove('login');
11096
})
11197
.then(() => this.props.setScratchPapers([]));
11298
}
@@ -134,44 +120,37 @@ class App extends React.Component {
134120
.catch(handleError.bind(this));
135121
}
136122

137-
loadAlgorithm({ categoryKey, algorithmKey, gistId }, forceLoad = false) {
138-
if (!forceLoad && !this.isGistSaved() && !window.confirm('Are you sure want to discard changes?')) return;
139-
123+
loadAlgorithm({ categoryKey, algorithmKey, gistId }) {
140124
const { ext } = this.props.env;
141-
let fetchPromise = null;
142-
if (categoryKey && algorithmKey) {
143-
fetchPromise = AlgorithmApi.getAlgorithm(categoryKey, algorithmKey)
144-
.then(({ algorithm }) => this.props.setAlgorithm(algorithm));
145-
} else if (['new', 'forked'].includes(gistId)) {
146-
gistId = 'new';
147-
const language = languages.find(language => language.ext === ext);
148-
fetchPromise = Promise.resolve(this.props.setScratchPaper({
149-
gistId,
150-
title: 'Untitled',
151-
files: [{
152-
name: 'README.md',
153-
content: SCRATCH_PAPER_MD,
154-
contributors: undefined,
155-
}, {
156-
name: `code.${ext}`,
157-
content: language.skeleton,
158-
contributors: undefined,
159-
}],
160-
}));
161-
} else if (gistId) {
162-
fetchPromise = GitHubApi.getGist(gistId, { timestamp: Date.now() })
163-
.then(refineGist)
164-
.then(this.props.setScratchPaper);
165-
} else {
166-
fetchPromise = Promise.reject(new Error());
167-
}
168-
fetchPromise
125+
const fetch = () => {
126+
if (categoryKey && algorithmKey) {
127+
return AlgorithmApi.getAlgorithm(categoryKey, algorithmKey)
128+
.then(({ algorithm }) => this.props.setAlgorithm(algorithm));
129+
} else if (gistId === 'new') {
130+
const language = languages.find(language => language.ext === ext);
131+
this.props.setScratchPaper({
132+
login: undefined,
133+
gistId,
134+
title: 'Untitled',
135+
files: [SCRATCH_PAPER_MD, language.skeleton],
136+
});
137+
return Promise.resolve();
138+
} else if (gistId) {
139+
return GitHubApi.getGist(gistId, { timestamp: Date.now() })
140+
.then(refineGist)
141+
.then(this.props.setScratchPaper);
142+
} else {
143+
this.props.setHome();
144+
return Promise.resolve();
145+
}
146+
};
147+
fetch()
169148
.catch(error => {
170-
if (error.message) handleError.bind(this)(error);
149+
handleError.bind(this)(error);
171150
this.props.setHome();
172151
})
173152
.finally(() => {
174-
const files = getFiles(this.props.current);
153+
const { files } = this.props.current;
175154
let editorTabIndex = files.findIndex(file => extension(file.name) === ext);
176155
if (!~editorTabIndex) editorTabIndex = files.findIndex(file => exts.includes(extension(file.name)));
177156
if (!~editorTabIndex) editorTabIndex = Math.min(0, files.length - 1);
@@ -185,15 +164,15 @@ class App extends React.Component {
185164
}
186165

187166
handleChangeEditorTabIndex(editorTabIndex) {
188-
const files = getFiles(this.props.current);
167+
const { files } = this.props.current;
189168
if (editorTabIndex === files.length) this.handleAddFile();
190169
this.setState({ editorTabIndex });
191170
this.props.shouldBuild();
192171
}
193172

194173
handleAddFile() {
195174
const { ext } = this.props.env;
196-
const files = getFiles(this.props.current);
175+
const { files } = this.props.current;
197176
let name = `code.${ext}`;
198177
let count = 0;
199178
while (files.some(file => file.name === name)) name = `code-${++count}.${ext}`;
@@ -213,7 +192,7 @@ class App extends React.Component {
213192

214193
handleDeleteFile() {
215194
const { editorTabIndex } = this.state;
216-
const files = getFiles(this.props.current);
195+
const { files } = this.props.current;
217196
this.handleChangeEditorTabIndex(Math.min(editorTabIndex, files.length - 2));
218197
this.props.deleteFile(editorTabIndex);
219198
}
@@ -222,16 +201,17 @@ class App extends React.Component {
222201
this.setState({ navigatorOpened });
223202
}
224203

225-
isGistSaved() {
226-
const { scratchPaper } = this.props.current;
227-
if (!scratchPaper) return true;
228-
const { title, files, lastTitle, lastFiles } = scratchPaper;
229-
const serializeFiles = files => JSON.stringify(files.map(({ name, content }) => ({ name, content })));
230-
return title === lastTitle && serializeFiles(files) === serializeFiles(lastFiles);
204+
isSaved() {
205+
const { titles, files, lastTitles, lastFiles } = this.props.current;
206+
const serialize = (titles, files) => JSON.stringify({
207+
titles,
208+
files: files.map(({ name, content }) => ({ name, content })),
209+
});
210+
return serialize(titles, files) === serialize(lastTitles, lastFiles);
231211
}
232212

233213
getDescription() {
234-
const files = getFiles(this.props.current);
214+
const { files } = this.props.current;
235215
const readmeFile = files.find(file => file.name === 'README.md');
236216
if (!readmeFile) return '';
237217
const groups = /^\s*# .*\n+([^\n]+)/.exec(readmeFile.content);
@@ -241,10 +221,9 @@ class App extends React.Component {
241221
render() {
242222
const { navigatorOpened, workspaceWeights, editorTabIndex } = this.state;
243223

244-
const files = getFiles(this.props.current);
245-
const titleArray = getTitleArray(this.props.current);
246-
const gistSaved = this.isGistSaved();
247-
const title = `${gistSaved ? '' : '(Unsaved) '}${titleArray.join(' - ')}`;
224+
const { files, titles } = this.props.current;
225+
const saved = this.isSaved();
226+
const title = `${saved ? '' : '(Unsaved) '}${titles.join(' - ')}`;
248227
const description = this.getDescription();
249228
const file = files[editorTabIndex];
250229

@@ -265,14 +244,12 @@ class App extends React.Component {
265244
<title>{title}</title>
266245
<meta name="description" content={description} />
267246
</Helmet>
268-
<Header className={styles.header} onClickTitleBar={() => this.toggleNavigatorOpened()}
269-
navigatorOpened={navigatorOpened} loadScratchPapers={() => this.loadScratchPapers()}
270-
loadAlgorithm={this.loadAlgorithm.bind(this)} gistSaved={gistSaved}
271-
file={file} />
247+
<Header className={styles.header} onClickTitleBar={() => this.toggleNavigatorOpened()} saved={saved}
248+
navigatorOpened={navigatorOpened} loadScratchPapers={() => this.loadScratchPapers()} file={file} />
272249
<ResizableContainer className={styles.workspace} horizontal weights={workspaceWeights}
273250
visibles={[navigatorOpened, true, true]}
274251
onChangeWeights={weights => this.handleChangeWorkspaceWeights(weights)}>
275-
<Navigator loadAlgorithm={this.loadAlgorithm.bind(this)} />
252+
<Navigator />
276253
<VisualizationViewer className={styles.visualization_viewer} />
277254
<TabContainer className={styles.editor_tab_container} titles={editorTitles} tabIndex={editorTabIndex}
278255
onChangeTabIndex={tabIndex => this.handleChangeEditorTabIndex(tabIndex)}>

src/frontend/components/CodeEditor/index.jsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import 'brace/mode/markdown';
55
import 'brace/mode/javascript';
66
import 'brace/mode/c_cpp';
77
import 'brace/mode/java';
8-
import 'brace/mode/python';
98
import 'brace/theme/tomorrow_night_eighties';
109
import 'brace/ext/searchbox';
1110
import faTrashAlt from '@fortawesome/fontawesome-free-solid/faTrashAlt';
@@ -17,7 +16,7 @@ import { languages } from '/common/config';
1716
import { Button, Ellipsis } from '/components';
1817
import styles from './stylesheet.scss';
1918

20-
@connect(({ current, env, player }) => ({ current, env, player }), actions, null, { withRef: true })
19+
@connect(({ env, player }) => ({ env, player }), actions, null, { withRef: true })
2120
class CodeEditor extends React.Component {
2221
constructor(props) {
2322
super(props);

0 commit comments

Comments
 (0)