提交 52963f85 编写于 作者: J Jason Park 提交者: Jason

Merge data and code parts into one

上级 fea69cee
......@@ -5,11 +5,11 @@ const getPath = (...args) => path.resolve(__dirname, '..', 'algorithm', ...args)
const readCategories = () => {
const createKey = name => name.toLowerCase().replace(/ /g, '-');
const subdirectories = dirPath => fs.readdirSync(dirPath).filter(subdir => !subdir.startsWith('.'));
const list = dirPath => fs.readdirSync(dirPath).filter(filename => !filename.startsWith('.'));
const getCategory = categoryName => {
const categoryPath = getPath(categoryName);
const categoryKey = createKey(categoryName);
const algorithms = subdirectories(categoryPath).map(algorithmName => getAlgorithm(categoryName, algorithmName));
const categoryPath = getPath(categoryName);
const algorithms = list(categoryPath).map(algorithmName => getAlgorithm(categoryName, algorithmName));
return {
key: categoryKey,
name: categoryName,
......@@ -17,29 +17,30 @@ const readCategories = () => {
};
};
const getAlgorithm = (categoryName, algorithmName) => {
const algorithmPath = getPath(categoryName, algorithmName);
const algorithmKey = createKey(algorithmName);
const files = subdirectories(algorithmPath).filter(fileName => fileName !== 'desc.json');
const algorithmPath = getPath(categoryName, algorithmName);
const files = list(algorithmPath);
return {
key: algorithmKey,
name: algorithmName,
files,
}
};
return subdirectories(getPath()).map(getCategory);
return list(getPath()).map(getCategory);
};
const categories = readCategories();
categories.forEach(category => {
console.error('===', category.name, '===');
category.algorithms.forEach(algorithm => {
algorithm.files.forEach(fileKey => {
const fileName = ['basic', 'normal'].includes(fileKey) ? algorithm.name : fileKey.split('_').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join(' ');
const oldPath = getPath(category.name, algorithm.name, fileKey);
const newPath = getPath(category.name, algorithm.name, fileName);
//fs.renameSync(oldPath, newPath);
console.log(oldPath + '->', newPath);
})
const fileName = algorithm.files.find(file => file !== 'desc.json');
const oldFilePath = getPath(category.name, algorithm.name, fileName);
const oldCodePath = getPath(category.name, algorithm.name, fileName, 'code.js');
const newCodePath = getPath(category.name, algorithm.name, 'code.js');
//console.log(oldCodePath, ' ==> ', newCodePath);
//fs.renameSync(oldCodePath, newCodePath);
//fs.rmdirSync(oldFilePath);
})
});
......
......@@ -9,7 +9,7 @@ const getPath = (...args) => path.resolve(__dirname, '..', '..', '..', 'algorith
const readCategories = () => {
const createKey = name => name.toLowerCase().replace(/ /g, '-');
const list = dirPath => fs.readdirSync(dirPath).filter(filename => !/\./.test(filename)); // visible directories only
const list = dirPath => fs.readdirSync(dirPath).filter(filename => !filename.startsWith('.'));
const getCategory = categoryName => {
const categoryKey = createKey(categoryName);
const categoryPath = getPath(categoryName);
......@@ -23,20 +23,13 @@ const readCategories = () => {
const getAlgorithm = (categoryName, algorithmName) => {
const algorithmKey = createKey(algorithmName);
const algorithmPath = getPath(categoryName, algorithmName);
const files = list(algorithmPath).map(fileName => getFile(categoryName, algorithmName, fileName));
const files = list(algorithmPath);
return {
key: algorithmKey,
name: algorithmName,
files,
}
};
const getFile = (categoryName, algorithmName, fileName) => {
const fileKey = createKey(fileName);
return {
key: fileKey,
name: fileName,
};
};
return list(getPath()).map(getCategory);
};
......@@ -47,49 +40,22 @@ const getCategories = (req, res, next) => {
};
const getFile = (req, res, next) => {
const { categoryKey, algorithmKey, fileKey } = req.params;
const category = categories.find(category => category.key === categoryKey);
if (!category) return next(new NotFoundError());
const algorithm = category.algorithms.find(algorithm => algorithm.key === algorithmKey);
if (!algorithm) return next(new NotFoundError());
const file = algorithm.files.find(file => file.key === fileKey);
if (!file) return next(new NotFoundError());
const dataPath = getPath(category.name, algorithm.name, file.name, 'data.js');
const codePath = getPath(category.name, algorithm.name, file.name, 'code.js');
fs.readFile(dataPath, 'utf8', (err, data) => {
if (err) return next(err);
fs.readFile(codePath, 'utf8', (err, code) => {
if (err) return next(err);
res.json({ data, code });
});
});
};
const getDescription = (req, res, next) => {
const { categoryKey, algorithmKey } = req.params;
const { categoryKey, algorithmKey, fileName } = req.params;
const category = categories.find(category => category.key === categoryKey);
if (!category) return next(new NotFoundError());
const algorithm = category.algorithms.find(algorithm => algorithm.key === algorithmKey);
if (!algorithm) return next(new NotFoundError());
if (!algorithm.files.includes(fileName)) return next(new NotFoundError());
const descriptionPath = getPath(category.name, algorithm.name, 'desc.json');
fs.readFile(descriptionPath, 'utf8', (err, raw) => {
if (err) return next(err);
const description = JSON.parse(raw);
res.json({ description });
});
const filePath = getPath(category.name, algorithm.name, fileName);
res.sendFile(filePath);
};
router.route('/')
.get(getCategories);
router.route('/description/:categoryKey/:algorithmKey')
.get(getDescription);
router.route('/:categoryKey/:algorithmKey/:fileKey')
router.route('/:categoryKey/:algorithmKey/:fileName')
.get(getFile);
export default router;
\ No newline at end of file
......@@ -48,8 +48,7 @@ const PUT = URL => {
const DirectoryApi = {
getCategories: GET('/directory'),
getDescription: GET('/directory/description/:categoryKey/:algorithmKey'),
getFile: GET('/directory/:categoryKey/:algorithmKey/:fileKey'),
getFile: GET('/directory/:categoryKey/:algorithmKey/:fileName'),
};
const WikiApi = {
......
......@@ -38,11 +38,10 @@ class App extends React.Component {
DirectoryApi.getCategories()
.then(({ categories }) => {
this.props.setCategories(categories);
const { categoryKey, algorithmKey, fileKey } = this.props.env;
const { categoryKey, algorithmKey } = this.props.env;
const category = categories.find(category => category.key === categoryKey) || categories[0];
const algorithm = category.algorithms.find(algorithm => algorithm.key === algorithmKey) || category.algorithms[0];
const file = algorithm.files.find(file => file.key === fileKey) || algorithm.files[0];
this.props.history.push(`/${category.key}/${algorithm.key}/${file.key}`);
this.props.history.push(`/${category.key}/${algorithm.key}`);
});
tracerManager.setOnError(error => this.props.showErrorToast(error.message));
......@@ -58,8 +57,8 @@ class App extends React.Component {
tracerManager.setOnError(null);
}
updateDirectory({ categoryKey = null, algorithmKey = null, fileKey = null }) {
this.props.setDirectory(categoryKey, algorithmKey, fileKey);
updateDirectory({ categoryKey = null, algorithmKey = null }) {
this.props.setDirectory(categoryKey, algorithmKey);
}
toggleNavigator(navigatorOpened = !this.state.navigatorOpened) {
......@@ -78,9 +77,9 @@ class App extends React.Component {
render() {
const { navigatorOpened, navigatorWidth, viewerSectionWidth } = this.state;
const { categories, categoryKey, algorithmKey, fileKey } = this.props.env;
const { categories, categoryKey, algorithmKey } = this.props.env;
return categories && categoryKey && algorithmKey && fileKey && (
return categories && categoryKey && algorithmKey && (
<div className={styles.app}>
<Header onClickTitleBar={() => this.toggleNavigator()} navigatorOpened={navigatorOpened} />
<main className={styles.main} ref={ref => this.elMain = ref}>
......
......@@ -35,8 +35,8 @@ class DescriptionViewer extends React.Component {
}
loadDescription(categoryKey, algorithmKey) {
DirectoryApi.getDescription(categoryKey, algorithmKey)
.then(({ description }) => this.setState({ description }));
DirectoryApi.getFile(categoryKey, algorithmKey, 'desc.json')
.then(description => this.setState({ description }));
}
getChild(value) {
......
......@@ -5,8 +5,8 @@ import 'brace/mode/javascript';
import 'brace/theme/tomorrow_night_eighties';
import FontAwesomeIcon from '@fortawesome/react-fontawesome'
import faInfoCircle from '@fortawesome/fontawesome-free-solid/faInfoCircle';
import { calculatePercentageHeight, classes } from '/common/util';
import { Divider, Ellipsis, TabBar } from '/components';
import { classes } from '/common/util';
import { Ellipsis, TabBar } from '/components';
import { actions as envActions } from '/reducers/env';
import { tracerManager } from '/core';
import { DirectoryApi } from '/apis';
......@@ -25,34 +25,29 @@ class EditorSection extends React.Component {
const { lineIndicator } = tracerManager;
this.state = {
dataContainerHeight: '30%',
lineMarker: this.createLineMarker(lineIndicator),
data: '',
code: '',
};
}
componentDidMount() {
tracerManager.setDataGetter(() => this.state.data);
tracerManager.setCodeGetter(() => this.state.code);
tracerManager.setOnUpdateLineIndicator(lineIndicator => this.setState({ lineMarker: this.createLineMarker(lineIndicator) }));
const { categoryKey, algorithmKey, fileKey } = this.props.env;
this.loadCodeAndData(categoryKey, algorithmKey, fileKey);
const { categoryKey, algorithmKey } = this.props.env;
this.loadCode(categoryKey, algorithmKey);
}
componentWillUnmount() {
tracerManager.setDataGetter(null);
tracerManager.setCodeGetter(null);
tracerManager.setOnUpdateLineIndicator(null);
}
componentWillReceiveProps(nextProps) {
const { categoryKey, algorithmKey, fileKey } = nextProps.env;
const { categoryKey, algorithmKey } = nextProps.env;
if (categoryKey !== this.props.env.categoryKey ||
algorithmKey !== this.props.env.algorithmKey ||
fileKey !== this.props.env.fileKey) {
this.loadCodeAndData(categoryKey, algorithmKey, fileKey);
algorithmKey !== this.props.env.algorithmKey) {
this.loadCode(categoryKey, algorithmKey);
}
}
......@@ -71,40 +66,31 @@ class EditorSection extends React.Component {
};
}
loadCodeAndData(categoryKey, algorithmKey, fileKey) {
DirectoryApi.getFile(categoryKey, algorithmKey, fileKey)
.then(({ data, code }) => {
this.setState({ data, code }, () => tracerManager.runData());
loadCode(categoryKey, algorithmKey) {
DirectoryApi.getFile(categoryKey, algorithmKey, 'code.js')
.then(code => {
this.setState({ code }, () => tracerManager.runInitial());
});
}
handleResizeDataContainer(x, y) {
const dataContainerHeight = calculatePercentageHeight(this.elContent, y);
this.setState({ dataContainerHeight });
}
handleChangeData(data) {
this.setState({ data }, () => tracerManager.runData());
}
handleChangeCode(code) {
this.setState({ code }, () => tracerManager.runData());
this.setState({ code }, () => tracerManager.runInitial());
}
render() {
const { dataContainerHeight, lineMarker, data, code } = this.state;
const { lineMarker, code } = this.state;
const { className } = this.props;
const { categories, categoryKey, algorithmKey, fileKey } = this.props.env;
const { categories, categoryKey, algorithmKey } = this.props.env;
const category = categories.find(category => category.key === categoryKey);
const algorithm = category.algorithms.find(algorithm => algorithm.key === algorithmKey);
const tabs = algorithm.files.map(file => ({
title: file.name,
const tabs = ['code.js'].map(fileName => ({
title: fileName,
props: {
to: `/${category.key}/${algorithm.key}/${file.key}`
to: `/${category.key}/${algorithm.key}`
},
}));
const tabIndex = algorithm.files.findIndex(file => file.key === fileKey);
const tabIndex = 0; // TODO
const fileInfo = ''; // TODO
return (
......@@ -114,29 +100,16 @@ class EditorSection extends React.Component {
<FontAwesomeIcon fixedWidth icon={faInfoCircle} className={styles.info_icon} />
<Ellipsis className={styles.info_text}>{fileInfo}</Ellipsis>
</div>
<div className={styles.content} ref={ref => this.elContent = ref}>
<div className={styles.data_container} style={{ height: dataContainerHeight }}>
<AceEditor
className={styles.editor}
mode="javascript"
theme="tomorrow_night_eighties"
name="data_editor"
editorProps={{ $blockScrolling: true }}
onChange={value => this.handleChangeData(value)}
value={data} />
</div>
<Divider horizontal onResize={(x, y) => this.handleResizeDataContainer(x, y)} />
<div className={styles.code_container}>
<AceEditor
className={styles.editor}
mode="javascript"
theme="tomorrow_night_eighties"
name="code_editor"
editorProps={{ $blockScrolling: true }}
onChange={value => this.handleChangeCode(value)}
markers={lineMarker ? [lineMarker] : []}
value={code} />
</div>
<div className={styles.content}>
<AceEditor
className={styles.editor}
mode="javascript"
theme="tomorrow_night_eighties"
name="code_editor"
editorProps={{ $blockScrolling: true }}
onChange={value => this.handleChangeCode(value)}
markers={lineMarker ? [lineMarker] : []}
value={code} />
</div>
</section>
);
......
......@@ -35,38 +35,25 @@
display: flex;
flex-direction: column;
.data_container {
border-bottom: 1px solid $theme-light;
}
.code_container {
flex: 1;
}
.data_container,
.code_container {
min-height: $resizeable-min;
.editor {
.editor {
width: 100% !important;
height: 100% !important;
.current_line_marker {
background: rgba(#29d, 0.4);
border: 1px solid #29d;
position: absolute;
width: 100% !important;
height: 100% !important;
.current_line_marker {
background: rgba(#29d, 0.4);
border: 1px solid #29d;
position: absolute;
width: 100% !important;
animation: line_highlight .1s;
}
animation: line_highlight .1s;
@keyframes line_highlight {
from {
background: rgba(#29d, 0.1);
}
@keyframes line_highlight {
from {
background: rgba(#29d, 0.1);
}
to {
background: rgba(#29d, 0.4);
}
to {
background: rgba(#29d, 0.4);
}
}
}
......
......@@ -91,10 +91,9 @@ class Navigator extends React.Component {
{
algorithms.map(algorithm => {
const selected = category.key === selectedCategoryKey && algorithm.key === selectedAlgorithmKey;
const [file] = algorithm.files;
return (
<ListItem indent key={algorithm.key} selected={selected}
to={`/${category.key}/${algorithm.key}/${file.key}`}>
to={`/${category.key}/${algorithm.key}`}>
<Ellipsis>{algorithm.name}</Ellipsis>
</ListItem>
)
......
......@@ -15,7 +15,7 @@ class TracerManager {
this.paused = false;
this.started = false;
this.lineIndicator = null;
this.reset(new Seed());
this.reset();
}
setOnRender(onRender) {
......@@ -34,10 +34,6 @@ class TracerManager {
this.onError = onError;
}
setDataGetter(dataGetter) {
this.dataGetter = dataGetter;
}
setCodeGetter(codeGetter) {
this.codeGetter = codeGetter;
}
......@@ -66,17 +62,12 @@ class TracerManager {
if (this.onUpdateLineIndicator) this.onUpdateLineIndicator(lineIndicator);
}
getData() {
if (this.dataGetter) return this.dataGetter();
return null;
}
getCode() {
if (this.codeGetter) return this.codeGetter();
return null;
}
reset(seed) {
reset(seed = new Seed()) {
this.traces = seed.traces;
this.resetCursor();
this.stopTimer();
......@@ -158,15 +149,13 @@ class TracerManager {
}
}
execute(data, code, callback) {
execute(callback) {
try {
const dataLines = data.split('\n');
const codeLines = code.split('\n');
const lines = [...dataLines, ...codeLines];
const newLines = lines.map((line, i) => line.replace(/(.+\. *wait *)(\( *\))/g, `$1(${i - dataLines.length})`));
const code = this.getCode();
const lines = code.split('\n').map((line, i) => line.replace(/(.+\. *wait *)(\( *\))/g, `$1(${i})`));
const seed = new Seed();
Tracer.seed = seed;
eval(Babel.transform(newLines.join('\n'), { presets: ['es2015'] }).code);
eval(Babel.transform(lines.join('\n'), { presets: ['es2015'] }).code);
this.reset(seed);
if (callback) callback();
} catch (error) {
......@@ -174,16 +163,19 @@ class TracerManager {
}
}
runData() {
const data = this.getData();
this.execute(data, '', () => this.applyTraceChunk());
runInitial() {
const error = this.execute(() => this.applyTraceChunk());
if (error) {
this.reset();
this.render();
}
}
run() {
const data = this.getData();
const code = this.getCode();
const error = this.execute(data, code, () => this.resume());
const error = this.execute(() => this.resume());
if (error) {
this.reset();
this.render();
this.handleError(error);
} else {
this.setStarted(true);
......@@ -217,7 +209,6 @@ class TracerManager {
handleError(error) {
console.error(error);
this.reset(new Seed());
if (this.onError) this.onError(error);
}
}
......
......@@ -16,7 +16,7 @@ const render = (Component) => {
<Provider store={store}>
<BrowserRouter>
<Switch>
<Route exact path="/:categoryKey/:algorithmKey/:fileKey" component={Component} />
<Route exact path="/:categoryKey/:algorithmKey" component={Component} />
<Route path="/" component={Component} />
</Switch>
</BrowserRouter>
......
......@@ -3,10 +3,9 @@ import { combineActions, createAction, handleActions } from 'redux-actions';
const prefix = 'ENV';
const setCategories = createAction(`${prefix}/SET_CATEGORIES`, categories => ({ categories }));
const setDirectory = createAction(`${prefix}/SELECT_FILE`, (categoryKey, algorithmKey, fileKey) => ({
const setDirectory = createAction(`${prefix}/SET_DIRECTORY`, (categoryKey, algorithmKey) => ({
categoryKey,
algorithmKey,
fileKey,
}));
export const actions = {
......@@ -20,7 +19,6 @@ const mutables = {
categories: null,
categoryKey: null,
algorithmKey: null,
fileKey: null,
};
export default handleActions({
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册