Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
tianyazhichiC
algorithm-visualizer
提交
68c062f4
A
algorithm-visualizer
项目概览
tianyazhichiC
/
algorithm-visualizer
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
A
algorithm-visualizer
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
68c062f4
编写于
1月 24, 2019
作者:
J
Jason Park
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Refactor redux stores
上级
a056b266
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
192 addition
and
174 deletion
+192
-174
src/backend/tracers/js/worker.js
src/backend/tracers/js/worker.js
+1
-1
src/frontend/common/util.js
src/frontend/common/util.js
+9
-0
src/frontend/components/App/index.jsx
src/frontend/components/App/index.jsx
+14
-70
src/frontend/components/App/stylesheet.scss
src/frontend/components/App/stylesheet.scss
+0
-10
src/frontend/components/CodeEditor/index.jsx
src/frontend/components/CodeEditor/index.jsx
+11
-17
src/frontend/components/FoldableAceEditor/index.jsx
src/frontend/components/FoldableAceEditor/index.jsx
+8
-3
src/frontend/components/Header/index.jsx
src/frontend/components/Header/index.jsx
+3
-3
src/frontend/components/Player/index.jsx
src/frontend/components/Player/index.jsx
+10
-9
src/frontend/components/TabContainer/index.jsx
src/frontend/components/TabContainer/index.jsx
+34
-10
src/frontend/components/TabContainer/stylesheet.scss
src/frontend/components/TabContainer/stylesheet.scss
+12
-1
src/frontend/reducers/current.js
src/frontend/reducers/current.js
+90
-46
src/frontend/reducers/player.js
src/frontend/reducers/player.js
+0
-4
未找到文件。
src/backend/tracers/js/worker.js
浏览文件 @
68c062f4
...
...
@@ -7,7 +7,7 @@ const sandbox = code => {
eval
(
code
);
};
onmessage
=
e
=>
{
// TODO: stop after the first delay() on the initial run
onmessage
=
e
=>
{
const
lines
=
e
.
data
.
split
(
'
\n
'
).
map
((
line
,
i
)
=>
line
.
replace
(
/
(
.+
\.
*delay *
)(\(
*
\))
/g
,
`$1(
${
i
}
)`
));
const
{
code
}
=
Babel
.
transform
(
lines
.
join
(
'
\n
'
),
{
presets
:
[
'
es2015
'
]
});
sandbox
(
code
);
...
...
src/frontend/common/util.js
浏览文件 @
68c062f4
...
...
@@ -30,6 +30,14 @@ const createProjectFile = (name, content) => createFile(name, content, [{
const
createUserFile
=
(
name
,
content
)
=>
createFile
(
name
,
content
,
undefined
);
const
isSaved
=
({
titles
,
files
,
lastTitles
,
lastFiles
})
=>
{
const
serialize
=
(
titles
,
files
)
=>
JSON
.
stringify
({
titles
,
files
:
files
.
map
(({
name
,
content
})
=>
({
name
,
content
})),
});
return
serialize
(
titles
,
files
)
===
serialize
(
lastTitles
,
lastFiles
);
};
export
{
classes
,
distance
,
...
...
@@ -38,4 +46,5 @@ export {
createFile
,
createProjectFile
,
createUserFile
,
isSaved
,
};
src/frontend/components/App/index.jsx
浏览文件 @
68c062f4
...
...
@@ -3,10 +3,7 @@ import Cookies from 'js-cookie';
import
{
connect
}
from
'
react-redux
'
;
import
Promise
from
'
bluebird
'
;
import
{
Helmet
}
from
'
react-helmet
'
;
import
AutosizeInput
from
'
react-input-autosize
'
;
import
queryString
from
'
query-string
'
;
import
{
FontAwesomeIcon
}
from
'
@fortawesome/react-fontawesome
'
;
import
faPlus
from
'
@fortawesome/fontawesome-free-solid/faPlus
'
;
import
{
BaseComponent
,
CodeEditor
,
...
...
@@ -32,7 +29,6 @@ class App extends BaseComponent {
this
.
state
=
{
navigatorOpened
:
true
,
workspaceWeights
:
[
1
,
2
,
2
],
editorTabIndex
:
-
1
,
};
this
.
codeEditorRef
=
React
.
createRef
();
...
...
@@ -79,11 +75,12 @@ class App extends BaseComponent {
toggleHistoryBlock
(
enable
=
!
this
.
unblock
)
{
if
(
enable
)
{
const
{
saved
}
=
this
.
props
.
current
;
const
warningMessage
=
'
Are you sure you want to discard changes?
'
;
window
.
onbeforeunload
=
()
=>
this
.
isSaved
()
?
undefined
:
warningMessage
;
window
.
onbeforeunload
=
()
=>
saved
?
undefined
:
warningMessage
;
this
.
unblock
=
this
.
props
.
history
.
block
((
location
)
=>
{
if
(
location
.
pathname
===
this
.
props
.
location
.
pathname
)
return
;
if
(
!
this
.
isSaved
()
)
return
warningMessage
;
if
(
!
saved
)
return
warningMessage
;
});
}
else
{
window
.
onbeforeunload
=
undefined
;
...
...
@@ -189,11 +186,11 @@ class App extends BaseComponent {
selectDefaultTab
()
{
const
{
ext
}
=
this
.
props
.
env
;
const
{
files
}
=
this
.
props
.
current
;
let
editorTabIndex
=
files
.
findIndex
(
file
=>
extension
(
file
.
name
)
===
'
json
'
);
if
(
!~
editorTabIndex
)
files
.
findIndex
(
file
=>
extension
(
file
.
name
)
===
ext
);
if
(
!~
editorTabIndex
)
editorTabIndex
=
files
.
findIndex
(
file
=>
exts
.
includes
(
extension
(
file
.
name
)));
if
(
!~
editorTabIndex
)
editorTabIndex
=
Math
.
min
(
0
,
files
.
length
-
1
)
;
this
.
handleChangeEditorTabIndex
(
editorTabIndex
);
const
editingFile
=
files
.
find
(
file
=>
extension
(
file
.
name
)
===
'
json
'
)
||
files
.
find
(
file
=>
extension
(
file
.
name
)
===
ext
)
||
files
.
find
(
file
=>
exts
.
includes
(
extension
(
file
.
name
)))
||
files
[
files
.
length
-
1
]
;
this
.
props
.
setEditingFile
(
editingFile
);
}
handleChangeWorkspaceWeights
(
workspaceWeights
)
{
...
...
@@ -201,67 +198,15 @@ class App extends BaseComponent {
this
.
codeEditorRef
.
current
.
getWrappedInstance
().
handleResize
();
}
handleChangeEditorTabIndex
(
editorTabIndex
)
{
const
{
files
}
=
this
.
props
.
current
;
if
(
editorTabIndex
===
files
.
length
)
this
.
handleAddFile
();
this
.
setState
({
editorTabIndex
});
this
.
props
.
shouldBuild
();
}
handleAddFile
()
{
const
{
ext
}
=
this
.
props
.
env
;
const
{
files
}
=
this
.
props
.
current
;
const
language
=
languages
.
find
(
language
=>
language
.
ext
===
ext
);
const
file
=
{
...
language
.
skeleton
};
let
count
=
0
;
while
(
files
.
some
(
existingFile
=>
existingFile
.
name
===
file
.
name
))
file
.
name
=
`code-
${
++
count
}
.
${
ext
}
`
;
this
.
props
.
addFile
(
file
);
}
handleRenameFile
(
e
)
{
const
{
value
}
=
e
.
target
;
const
{
editorTabIndex
}
=
this
.
state
;
this
.
props
.
renameFile
(
editorTabIndex
,
value
);
}
handleDeleteFile
()
{
const
{
editorTabIndex
}
=
this
.
state
;
const
{
files
}
=
this
.
props
.
current
;
this
.
handleChangeEditorTabIndex
(
Math
.
min
(
editorTabIndex
,
files
.
length
-
2
));
this
.
props
.
deleteFile
(
editorTabIndex
);
}
toggleNavigatorOpened
(
navigatorOpened
=
!
this
.
state
.
navigatorOpened
)
{
this
.
setState
({
navigatorOpened
});
}
isSaved
()
{
const
{
titles
,
files
,
lastTitles
,
lastFiles
}
=
this
.
props
.
current
;
const
serialize
=
(
titles
,
files
)
=>
JSON
.
stringify
({
titles
,
files
:
files
.
map
(({
name
,
content
})
=>
({
name
,
content
})),
});
return
serialize
(
titles
,
files
)
===
serialize
(
lastTitles
,
lastFiles
);
}
render
()
{
const
{
navigatorOpened
,
workspaceWeights
,
editorTabIndex
}
=
this
.
state
;
const
{
navigatorOpened
,
workspaceWeights
}
=
this
.
state
;
const
{
files
,
titles
,
description
}
=
this
.
props
.
current
;
const
saved
=
this
.
isSaved
();
const
{
titles
,
description
,
saved
}
=
this
.
props
.
current
;
const
title
=
`
${
saved
?
''
:
'
(Unsaved)
'
}${
titles
.
join
(
'
-
'
)}
`
;
const
file
=
files
[
editorTabIndex
];
const
editorTitles
=
files
.
map
(
file
=>
file
.
name
);
if
(
file
)
{
editorTitles
[
editorTabIndex
]
=
(
<
AutosizeInput
className
=
{
styles
.
input_title
}
value
=
{
file
.
name
}
onClick
=
{
e
=>
e
.
stopPropagation
()
}
onChange
=
{
e
=>
this
.
handleRenameFile
(
e
)
}
/>
);
}
editorTitles
.
push
(
<
FontAwesomeIcon
fixedWidth
icon
=
{
faPlus
}
/>,
);
return
(
<
div
className
=
{
styles
.
app
}
>
...
...
@@ -269,17 +214,16 @@ class App extends BaseComponent {
<
title
>
{
title
}
</
title
>
<
meta
name
=
"description"
content
=
{
description
}
/>
</
Helmet
>
<
Header
className
=
{
styles
.
header
}
onClickTitleBar
=
{
()
=>
this
.
toggleNavigatorOpened
()
}
saved
=
{
saved
}
navigatorOpened
=
{
navigatorOpened
}
loadScratchPapers
=
{
()
=>
this
.
loadScratchPapers
()
}
file
=
{
file
}
<
Header
className
=
{
styles
.
header
}
onClickTitleBar
=
{
()
=>
this
.
toggleNavigatorOpened
()
}
navigatorOpened
=
{
navigatorOpened
}
loadScratchPapers
=
{
()
=>
this
.
loadScratchPapers
()
}
ignoreHistoryBlock
=
{
this
.
ignoreHistoryBlock
}
/>
<
ResizableContainer
className
=
{
styles
.
workspace
}
horizontal
weights
=
{
workspaceWeights
}
visibles
=
{
[
navigatorOpened
,
true
,
true
]
}
onChangeWeights
=
{
weights
=>
this
.
handleChangeWorkspaceWeights
(
weights
)
}
>
<
Navigator
/>
<
VisualizationViewer
className
=
{
styles
.
visualization_viewer
}
/>
<
TabContainer
className
=
{
styles
.
editor_tab_container
}
titles
=
{
editorTitles
}
tabIndex
=
{
editorTabIndex
}
onChangeTabIndex
=
{
tabIndex
=>
this
.
handleChangeEditorTabIndex
(
tabIndex
)
}
>
<
CodeEditor
ref
=
{
this
.
codeEditorRef
}
file
=
{
file
}
onClickDelete
=
{
()
=>
this
.
handleDeleteFile
()
}
/>
<
TabContainer
className
=
{
styles
.
editor_tab_container
}
>
<
CodeEditor
ref
=
{
this
.
codeEditorRef
}
/>
</
TabContainer
>
</
ResizableContainer
>
<
ToastContainer
className
=
{
styles
.
toast_container
}
/>
...
...
src/frontend/components/App/stylesheet.scss
浏览文件 @
68c062f4
...
...
@@ -60,16 +60,6 @@ button {
}
.editor_tab_container
{
.input_title
{
input
{
&
:hover
,
&
:focus
{
margin
:
-4px
;
padding
:
4px
;
background-color
:
$theme-normal
;
}
}
}
}
}
...
...
src/frontend/components/CodeEditor/index.jsx
浏览文件 @
68c062f4
...
...
@@ -8,7 +8,7 @@ import { languages } from '/common/config';
import
{
Button
,
Ellipsis
,
FoldableAceEditor
}
from
'
/components
'
;
import
styles
from
'
./stylesheet.scss
'
;
@
connect
(({
env
,
player
})
=>
({
env
,
player
}),
actions
,
null
,
{
withRef
:
true
})
@
connect
(({
current
,
env
,
player
})
=>
({
current
,
env
,
player
}),
actions
,
null
,
{
withRef
:
true
})
class
CodeEditor
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
...
...
@@ -16,24 +16,19 @@ class CodeEditor extends React.Component {
this
.
aceEditorRef
=
React
.
createRef
();
}
handleChangeCode
(
code
)
{
const
{
file
}
=
this
.
props
;
this
.
props
.
modifyFile
({
...
file
,
content
:
code
});
if
(
extension
(
file
.
name
)
===
'
md
'
)
this
.
props
.
shouldBuild
();
}
handleResize
()
{
this
.
aceEditorRef
.
current
.
editor
.
resize
();
}
render
()
{
const
{
className
,
file
,
onClickDelete
}
=
this
.
props
;
const
{
className
}
=
this
.
props
;
const
{
editingFile
}
=
this
.
props
.
current
;
const
{
user
}
=
this
.
props
.
env
;
const
{
lineIndicator
,
buildAt
}
=
this
.
props
.
player
;
const
{
lineIndicator
}
=
this
.
props
.
player
;
if
(
!
f
ile
)
return
null
;
if
(
!
editingF
ile
)
return
null
;
const
fileExt
=
extension
(
f
ile
.
name
);
const
fileExt
=
extension
(
editingF
ile
.
name
);
const
language
=
languages
.
find
(
language
=>
language
.
ext
===
fileExt
);
const
mode
=
language
?
language
.
mode
:
fileExt
===
'
md
'
?
'
markdown
'
:
...
...
@@ -49,7 +44,7 @@ class CodeEditor extends React.Component {
theme
=
"tomorrow_night_eighties"
name
=
"code_editor"
editorProps
=
{
{
$blockScrolling
:
true
}
}
onChange
=
{
code
=>
this
.
handleChangeCode
(
code
)
}
onChange
=
{
code
=>
this
.
props
.
modifyFile
(
editingFile
,
code
)
}
markers
=
{
lineIndicator
?
[{
startRow
:
lineIndicator
.
lineNumber
,
startCol
:
0
,
...
...
@@ -60,12 +55,11 @@ class CodeEditor extends React.Component {
inFront
:
true
,
_key
:
lineIndicator
.
cursor
,
}]
:
[]
}
foldAt
=
{
buildAt
}
value
=
{
file
.
content
}
/>
value
=
{
editingFile
.
content
}
/>
<
div
className
=
{
classes
(
styles
.
contributors_viewer
,
className
)
}
>
<
span
className
=
{
classes
(
styles
.
contributor
,
styles
.
label
)
}
>
Contributed by
</
span
>
{
(
f
ile
.
contributors
||
[
user
||
{
login
:
'
guest
'
,
avatar_url
:
faUser
}]).
map
(
contributor
=>
(
(
editingF
ile
.
contributors
||
[
user
||
{
login
:
'
guest
'
,
avatar_url
:
faUser
}]).
map
(
contributor
=>
(
<
Button
className
=
{
styles
.
contributor
}
icon
=
{
contributor
.
avatar_url
}
key
=
{
contributor
.
login
}
href
=
{
`https://github.com/
${
contributor
.
login
}
`
}
>
{
contributor
.
login
}
...
...
@@ -74,8 +68,8 @@ class CodeEditor extends React.Component {
}
<
div
className
=
{
styles
.
empty
}
>
<
div
className
=
{
styles
.
empty
}
/>
<
Button
className
=
{
styles
.
delete
}
icon
=
{
faTrashAlt
}
primary
onClick
=
{
onClickDelete
}
confirmNeeded
>
<
Button
className
=
{
styles
.
delete
}
icon
=
{
faTrashAlt
}
primary
confirmNeeded
onClick
=
{
()
=>
this
.
props
.
deleteFile
(
editingFile
)
}
>
<
Ellipsis
>
Delete File
</
Ellipsis
>
</
Button
>
</
div
>
...
...
src/frontend/components/FoldableAceEditor/index.jsx
浏览文件 @
68c062f4
import
React
from
'
react
'
;
import
{
connect
}
from
'
react-redux
'
;
import
AceEditor
from
'
react-ace
'
;
import
'
brace/mode/plain_text
'
;
import
'
brace/mode/markdown
'
;
...
...
@@ -8,19 +9,23 @@ import 'brace/mode/c_cpp';
import
'
brace/mode/java
'
;
import
'
brace/theme/tomorrow_night_eighties
'
;
import
'
brace/ext/searchbox
'
;
import
{
actions
}
from
'
/reducers
'
;
@
connect
(({
current
})
=>
({
current
}),
actions
)
class
FoldableAceEditor
extends
AceEditor
{
componentDidMount
()
{
super
.
componentDidMount
();
this
.
foldTracers
();
const
{
shouldBuild
}
=
this
.
props
.
current
;
if
(
shouldBuild
)
this
.
foldTracers
();
}
componentDidUpdate
(
prevProps
,
prevState
,
snapshot
)
{
super
.
componentDidUpdate
(
prevProps
,
prevState
,
snapshot
);
if
(
prevProps
.
foldAt
!==
this
.
props
.
foldAt
)
{
this
.
foldTracers
();
const
{
editingFile
,
shouldBuild
}
=
this
.
props
.
current
;
if
(
editingFile
!==
prevProps
.
current
.
editingFile
)
{
if
(
shouldBuild
)
this
.
foldTracers
();
}
}
...
...
src/frontend/components/Header/index.jsx
浏览文件 @
68c062f4
...
...
@@ -110,8 +110,8 @@ class Header extends BaseComponent {
}
render
()
{
const
{
className
,
onClickTitleBar
,
navigatorOpened
,
saved
,
file
}
=
this
.
props
;
const
{
scratchPaper
,
titles
}
=
this
.
props
.
current
;
const
{
className
,
onClickTitleBar
,
navigatorOpened
}
=
this
.
props
;
const
{
scratchPaper
,
titles
,
saved
}
=
this
.
props
.
current
;
const
{
ext
,
user
}
=
this
.
props
.
env
;
const
permitted
=
this
.
hasPermission
();
...
...
@@ -174,7 +174,7 @@ class Header extends BaseComponent {
</
div
>
</
Button
>
</
div
>
<
Player
className
=
{
styles
.
section
}
file
=
{
file
}
/>
<
Player
className
=
{
styles
.
section
}
/>
</
div
>
</
header
>
);
...
...
src/frontend/components/Player/index.jsx
浏览文件 @
68c062f4
...
...
@@ -13,7 +13,7 @@ import { actions } from '/reducers';
import
{
BaseComponent
,
Button
,
ProgressBar
}
from
'
/components
'
;
import
styles
from
'
./stylesheet.scss
'
;
@
connect
(({
player
})
=>
({
player
}),
actions
)
@
connect
(({
current
,
player
})
=>
({
current
,
player
}),
actions
)
class
Player
extends
BaseComponent
{
constructor
(
props
)
{
super
(
props
);
...
...
@@ -30,15 +30,14 @@ class Player extends BaseComponent {
}
componentDidMount
()
{
const
{
file
}
=
this
.
props
;
this
.
build
(
f
ile
);
const
{
editingFile
,
shouldBuild
}
=
this
.
props
.
current
;
if
(
shouldBuild
)
this
.
build
(
editingF
ile
);
}
componentWillReceiveProps
(
nextProps
)
{
const
{
file
}
=
nextProps
;
const
{
buildAt
}
=
nextProps
.
player
;
if
(
buildAt
!==
this
.
props
.
player
.
buildAt
)
{
this
.
build
(
file
);
const
{
editingFile
,
shouldBuild
}
=
nextProps
.
current
;
if
(
editingFile
!==
this
.
props
.
current
.
editingFile
)
{
if
(
shouldBuild
)
this
.
build
(
editingFile
);
}
}
...
...
@@ -145,13 +144,15 @@ class Player extends BaseComponent {
}
render
()
{
const
{
className
,
file
}
=
this
.
props
;
const
{
className
}
=
this
.
props
;
const
{
editingFile
}
=
this
.
props
.
current
;
const
{
chunks
,
cursor
}
=
this
.
props
.
player
;
const
{
speed
,
playing
,
building
}
=
this
.
state
;
return
(
<
div
className
=
{
classes
(
styles
.
player
,
className
)
}
>
<
Button
icon
=
{
faWrench
}
primary
disabled
=
{
building
}
inProgress
=
{
building
}
onClick
=
{
()
=>
this
.
build
(
file
)
}
>
<
Button
icon
=
{
faWrench
}
primary
disabled
=
{
building
}
inProgress
=
{
building
}
onClick
=
{
()
=>
this
.
build
(
editingFile
)
}
>
{
building
?
'
Building
'
:
'
Build
'
}
</
Button
>
{
...
...
src/frontend/components/TabContainer/index.jsx
浏览文件 @
68c062f4
import
React
from
'
react
'
;
import
{
connect
}
from
'
react-redux
'
;
import
AutosizeInput
from
'
react-input-autosize
'
;
import
{
FontAwesomeIcon
}
from
'
@fortawesome/react-fontawesome
'
;
import
faPlus
from
'
@fortawesome/fontawesome-free-solid/faPlus
'
;
import
{
classes
}
from
'
/common/util
'
;
import
{
actions
}
from
'
/reducers
'
;
import
{
languages
}
from
'
/common/config
'
;
import
styles
from
'
./stylesheet.scss
'
;
@
connect
(({
current
,
env
})
=>
({
current
,
env
}),
actions
)
class
TabContainer
extends
React
.
Component
{
handleAddFile
()
{
const
{
ext
}
=
this
.
props
.
env
;
const
{
files
}
=
this
.
props
.
current
;
const
language
=
languages
.
find
(
language
=>
language
.
ext
===
ext
);
const
newFile
=
{
...
language
.
skeleton
};
let
count
=
0
;
while
(
files
.
some
(
file
=>
file
.
name
===
newFile
.
name
))
newFile
.
name
=
`code-
${
++
count
}
.
${
ext
}
`
;
this
.
props
.
addFile
(
newFile
);
}
render
()
{
const
{
className
,
children
,
titles
,
tabIndex
,
onChangeTabIndex
}
=
this
.
props
;
const
{
className
,
children
}
=
this
.
props
;
const
{
editingFile
,
files
}
=
this
.
props
.
current
;
return
(
<
div
className
=
{
classes
(
styles
.
tab_container
,
className
)
}
>
<
div
className
=
{
styles
.
tab_bar
}
>
<
div
className
=
{
classes
(
styles
.
title
,
styles
.
fake
)
}
/>
{
titles
.
map
((
title
,
i
)
=>
{
const
selected
=
i
===
tabIndex
;
return
(
<
div
className
=
{
classes
(
styles
.
title
,
selected
&&
styles
.
selected
)
}
key
=
{
i
}
onClick
=
{
()
=>
onChangeTabIndex
(
i
)
}
>
{
title
}
</
div
>
);
})
files
.
map
((
file
,
i
)
=>
file
===
editingFile
?
(
<
div
className
=
{
classes
(
styles
.
title
,
styles
.
selected
)
}
key
=
{
i
}
onClick
=
{
()
=>
this
.
props
.
setEditingFile
(
file
)
}
>
<
AutosizeInput
className
=
{
styles
.
input_title
}
value
=
{
file
.
name
}
onClick
=
{
e
=>
e
.
stopPropagation
()
}
onChange
=
{
e
=>
this
.
props
.
renameFile
(
file
,
e
.
target
.
value
)
}
/>
</
div
>
)
:
(
<
div
className
=
{
styles
.
title
}
key
=
{
i
}
onClick
=
{
()
=>
this
.
props
.
setEditingFile
(
file
)
}
>
{
file
.
name
}
</
div
>
))
}
<
div
className
=
{
styles
.
title
}
onClick
=
{
()
=>
this
.
handleAddFile
()
}
>
<
FontAwesomeIcon
fixedWidth
icon
=
{
faPlus
}
/>
</
div
>
<
div
className
=
{
classes
(
styles
.
title
,
styles
.
fake
)
}
/>
</
div
>
<
div
className
=
{
styles
.
content
}
>
...
...
src/frontend/components/TabContainer/stylesheet.scss
浏览文件 @
68c062f4
...
...
@@ -25,6 +25,17 @@
margin
:
0
;
border-bottom
:
1px
solid
$theme-light
;
.input_title
{
input
{
&
:hover
,
&
:focus
{
margin
:
-4px
;
padding
:
4px
;
background-color
:
$theme-normal
;
}
}
}
&
.selected
{
border-left
:
1px
solid
$theme-light
;
border-right
:
1px
solid
$theme-light
;
...
...
@@ -56,4 +67,4 @@
background-color
:
$theme-dark
;
overflow
:
hidden
;
}
}
\ No newline at end of file
}
src/frontend/reducers/current.js
浏览文件 @
68c062f4
import
{
combineActions
,
createAction
,
handleActions
}
from
'
redux-actions
'
;
import
{
README_MD
}
from
'
/files
'
;
import
{
extension
,
isSaved
}
from
'
/common/util
'
;
const
prefix
=
'
CURRENT
'
;
const
setHome
=
createAction
(
`
${
prefix
}
/SET_HOME`
,
()
=>
defaultState
);
const
setAlgorithm
=
createAction
(
`
${
prefix
}
/SET_ALGORITHM`
,
({
categoryKey
,
categoryName
,
algorithmKey
,
algorithmName
,
files
,
description
})
=>
{
const
titles
=
[
categoryName
,
algorithmName
];
return
{
algorithm
:
{
categoryKey
,
algorithmKey
},
scratchPaper
:
undefined
,
titles
,
files
,
lastTitles
:
titles
,
lastFiles
:
files
,
description
,
};
});
const
setScratchPaper
=
createAction
(
`
${
prefix
}
/SET_SCRATCH_PAPER`
,
({
login
,
gistId
,
title
,
files
})
=>
{
const
titles
=
[
'
Scratch Paper
'
,
title
];
return
{
algorithm
:
undefined
,
scratchPaper
:
{
login
,
gistId
},
titles
,
files
,
lastTitles
:
titles
,
lastFiles
:
files
,
description
:
homeDescription
,
};
});
const
setAlgorithm
=
createAction
(
`
${
prefix
}
/SET_ALGORITHM`
,
({
categoryKey
,
categoryName
,
algorithmKey
,
algorithmName
,
files
,
description
})
=>
({
algorithm
:
{
categoryKey
,
algorithmKey
},
titles
:
[
categoryName
,
algorithmName
],
files
,
description
,
}));
const
setScratchPaper
=
createAction
(
`
${
prefix
}
/SET_SCRATCH_PAPER`
,
({
login
,
gistId
,
title
,
files
})
=>
({
scratchPaper
:
{
login
,
gistId
},
titles
:
[
'
Scratch Paper
'
,
title
],
files
,
description
:
homeDescription
,
}));
const
setEditingFile
=
createAction
(
`
${
prefix
}
/SET_EDITING_FILE`
,
file
=>
({
file
}));
const
modifyTitle
=
createAction
(
`
${
prefix
}
/MODIFY_TITLE`
,
title
=>
({
title
}));
const
addFile
=
createAction
(
`
${
prefix
}
/ADD_FILE`
,
file
=>
({
file
}));
const
modifyFile
=
createAction
(
`
${
prefix
}
/MODIFY_FILE`
,
file
=>
({
fil
e
}));
const
deleteFile
=
createAction
(
`
${
prefix
}
/DELETE_FILE`
,
index
=>
({
index
}));
const
renameFile
=
createAction
(
`
${
prefix
}
/RENAME_FILE`
,
(
index
,
name
)
=>
({
index
,
nam
e
}));
const
renameFile
=
createAction
(
`
${
prefix
}
/RENAME_FILE`
,
(
file
,
name
)
=>
({
file
,
nam
e
}));
const
modifyFile
=
createAction
(
`
${
prefix
}
/MODIFY_FILE`
,
(
file
,
content
)
=>
({
file
,
content
}));
const
deleteFile
=
createAction
(
`
${
prefix
}
/DELETE_FILE`
,
file
=>
({
fil
e
}));
export
const
actions
=
{
setHome
,
setAlgorithm
,
setScratchPaper
,
setEditingFile
,
modifyTitle
,
addFile
,
modifyFile
,
...
...
@@ -59,6 +50,9 @@ const defaultState = {
lastTitles
:
homeTitles
,
lastFiles
:
homeFiles
,
description
:
homeDescription
,
editingFile
:
undefined
,
shouldBuild
:
true
,
saved
:
true
,
};
export
default
handleActions
({
...
...
@@ -66,35 +60,85 @@ export default handleActions({
setHome
,
setAlgorithm
,
setScratchPaper
,
)]:
(
state
,
{
payload
})
=>
({
...
state
,
...
payload
,
}),
)]:
(
state
,
{
payload
})
=>
{
const
{
algorithm
,
scratchPaper
,
titles
,
files
,
description
}
=
payload
;
return
{
...
state
,
algorithm
,
scratchPaper
,
titles
,
files
,
lastTitles
:
titles
,
lastFiles
:
files
,
description
,
editingFile
:
undefined
,
shouldBuild
:
true
,
saved
:
true
,
};
},
[
setEditingFile
]:
(
state
,
{
payload
})
=>
{
const
{
file
}
=
payload
;
return
{
...
state
,
editingFile
:
file
,
shouldBuild
:
true
,
};
},
[
modifyTitle
]:
(
state
,
{
payload
})
=>
{
const
{
title
}
=
payload
;
return
{
const
newState
=
{
...
state
,
titles
:
[
state
.
titles
[
0
],
title
],
};
return
{
...
newState
,
saved
:
isSaved
(
newState
),
};
},
[
addFile
]:
(
state
,
{
payload
})
=>
{
const
{
file
}
=
payload
;
const
files
=
[...
state
.
files
,
file
];
return
{
...
state
,
files
};
const
newState
=
{
...
state
,
files
:
[...
state
.
files
,
file
],
editingFile
:
file
,
shouldBuild
:
true
,
};
return
{
...
newState
,
saved
:
isSaved
(
newState
),
};
},
[
modifyFile
]:
(
state
,
{
payload
})
=>
{
const
{
file
}
=
payload
;
const
files
=
state
.
files
.
map
(
oldFile
=>
oldFile
.
name
===
file
.
name
?
file
:
oldFile
);
return
{
...
state
,
files
};
[
combineActions
(
renameFile
,
modifyFile
,
)]:
(
state
,
{
payload
})
=>
{
const
{
file
,
...
update
}
=
payload
;
const
editingFile
=
{
...
file
,
...
update
};
const
newState
=
{
...
state
,
files
:
state
.
files
.
map
(
oldFile
=>
oldFile
===
file
?
editingFile
:
oldFile
),
editingFile
,
shouldBuild
:
extension
(
editingFile
.
name
)
===
'
md
'
,
};
return
{
...
newState
,
saved
:
isSaved
(
newState
),
};
},
[
deleteFile
]:
(
state
,
{
payload
})
=>
{
const
{
index
}
=
payload
;
const
files
=
state
.
files
.
filter
((
file
,
i
)
=>
i
!==
index
);
return
{
...
state
,
files
};
},
[
renameFile
]:
(
state
,
{
payload
})
=>
{
const
{
index
,
name
}
=
payload
;
const
files
=
state
.
files
.
map
((
file
,
i
)
=>
i
===
index
?
{
...
file
,
name
}
:
file
);
return
{
...
state
,
files
};
const
{
file
}
=
payload
;
const
index
=
state
.
files
.
indexOf
(
file
);
const
files
=
state
.
files
.
filter
(
oldFile
=>
oldFile
!==
file
);
const
editingFile
=
files
[
Math
.
min
(
index
,
files
.
length
-
1
)];
const
newState
=
{
...
state
,
files
,
editingFile
,
shouldBuild
:
true
,
};
return
{
...
newState
,
saved
:
isSaved
(
newState
),
};
},
},
defaultState
);
src/frontend/reducers/player.js
浏览文件 @
68c062f4
...
...
@@ -2,20 +2,17 @@ import { combineActions, createAction, handleActions } from 'redux-actions';
const
prefix
=
'
PLAYER
'
;
const
shouldBuild
=
createAction
(
`
${
prefix
}
/SHOULD_BUILD`
,
()
=>
({
buildAt
:
Date
.
now
()
}));
const
setChunks
=
createAction
(
`
${
prefix
}
/SET_CHUNKS`
,
chunks
=>
({
chunks
}));
const
setCursor
=
createAction
(
`
${
prefix
}
/SET_CURSOR`
,
cursor
=>
({
cursor
}));
const
setLineIndicator
=
createAction
(
`
${
prefix
}
/SET_LINE_INDICATOR`
,
lineIndicator
=>
({
lineIndicator
}));
export
const
actions
=
{
shouldBuild
,
setChunks
,
setCursor
,
setLineIndicator
,
};
const
defaultState
=
{
buildAt
:
0
,
chunks
:
[],
cursor
:
0
,
lineIndicator
:
undefined
,
...
...
@@ -23,7 +20,6 @@ const defaultState = {
export
default
handleActions
({
[
combineActions
(
shouldBuild
,
setChunks
,
setCursor
,
setLineIndicator
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录