Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
tianyazhichiC
algorithm-visualizer
提交
a3529a31
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看板
提交
a3529a31
编写于
6月 30, 2018
作者:
J
Jason Park
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Improve workspace performance and few other things
上级
b4801513
变更
23
隐藏空白更改
内联
并排
Showing
23 changed file
with
288 addition
and
272 deletion
+288
-272
src/backend/controllers/hierarchy.js
src/backend/controllers/hierarchy.js
+7
-9
src/backend/public/algorithms
src/backend/public/algorithms
+1
-1
src/frontend/apis/index.js
src/frontend/apis/index.js
+2
-1
src/frontend/common/config.js
src/frontend/common/config.js
+6
-1
src/frontend/components/App/index.jsx
src/frontend/components/App/index.jsx
+32
-36
src/frontend/components/App/stylesheet.scss
src/frontend/components/App/stylesheet.scss
+0
-1
src/frontend/components/CodeEditor/index.jsx
src/frontend/components/CodeEditor/index.jsx
+11
-35
src/frontend/components/DescriptionViewer/index.jsx
src/frontend/components/DescriptionViewer/index.jsx
+2
-43
src/frontend/components/Header/index.jsx
src/frontend/components/Header/index.jsx
+13
-5
src/frontend/components/MarkdownViewer/index.jsx
src/frontend/components/MarkdownViewer/index.jsx
+1
-1
src/frontend/components/Navigator/index.jsx
src/frontend/components/Navigator/index.jsx
+51
-14
src/frontend/core/tracerManager.jsx
src/frontend/core/tracerManager.jsx
+3
-4
src/frontend/workspace/components/WSSectionContainer/index.jsx
...rontend/workspace/components/WSSectionContainer/index.jsx
+5
-5
src/frontend/workspace/components/WSTabContainer/index.jsx
src/frontend/workspace/components/WSTabContainer/index.jsx
+1
-1
src/frontend/workspace/components/Workspace/index.jsx
src/frontend/workspace/components/Workspace/index.jsx
+66
-13
src/frontend/workspace/core/Child.js
src/frontend/workspace/core/Child.js
+0
-53
src/frontend/workspace/core/Parent.js
src/frontend/workspace/core/Parent.js
+44
-0
src/frontend/workspace/core/Section.js
src/frontend/workspace/core/Section.js
+32
-7
src/frontend/workspace/core/SectionContainer.js
src/frontend/workspace/core/SectionContainer.js
+3
-4
src/frontend/workspace/core/TabContainer.js
src/frontend/workspace/core/TabContainer.js
+6
-9
src/frontend/workspace/core/draggingData.js
src/frontend/workspace/core/draggingData.js
+0
-25
src/frontend/workspace/core/index.js
src/frontend/workspace/core/index.js
+2
-3
src/frontend/workspace/core/mixins/index.js
src/frontend/workspace/core/mixins/index.js
+0
-1
未找到文件。
src/backend/controllers/hierarchy.js
浏览文件 @
a3529a31
...
...
@@ -65,7 +65,7 @@ const cacheHierarchy = () => {
const
file
=
allFiles
[
fileIndex
];
if
(
file
)
{
const
cwd
=
getPath
();
exec
(
`git --no-pager log --follow --format="%H" "
${
file
.
path
}
"`
,
{
cwd
},
(
error
,
stdout
,
stderr
)
=>
{
exec
(
`git --no-pager log --follow --
no-merges --
format="%H" "
${
file
.
path
}
"`
,
{
cwd
},
(
error
,
stdout
,
stderr
)
=>
{
if
(
!
error
&&
!
stderr
)
{
const
output
=
stdout
.
toString
().
replace
(
/
\n
$/
,
''
);
const
shas
=
output
.
split
(
'
\n
'
).
reverse
();
...
...
@@ -92,24 +92,22 @@ const getHierarchy = (req, res, next) => {
res
.
json
({
hierarchy
:
cachedHierarchy
});
};
const
get
File
=
(
req
,
res
,
next
)
=>
{
const
{
categoryKey
,
algorithmKey
,
fileName
}
=
req
.
params
;
const
get
Algorithm
=
(
req
,
res
,
next
)
=>
{
const
{
categoryKey
,
algorithmKey
}
=
req
.
params
;
const
category
=
cachedHierarchy
.
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
.
name
===
fileName
);
if
(
!
file
)
return
next
(
new
NotFoundError
());
const
{
content
,
contributors
}
=
file
;
res
.
json
({
file
:
{
content
,
contributor
s
}
});
const
files
=
algorithm
.
files
.
map
(({
name
,
content
,
contributors
})
=>
({
name
,
content
,
contributors
}))
;
res
.
json
({
algorithm
:
{
...
algorithm
,
file
s
}
});
};
router
.
route
(
'
/
'
)
.
get
(
getHierarchy
);
router
.
route
(
'
/:categoryKey/:algorithmKey
/:fileName
'
)
.
get
(
get
File
);
router
.
route
(
'
/:categoryKey/:algorithmKey
'
)
.
get
(
get
Algorithm
);
export
default
router
;
\ No newline at end of file
algorithms
@
c9b0606b
比较
f17c5704
...
c9b0606b
Subproject commit
f17c57048f65f287d12e13e6f35b606034aeeb31
Subproject commit
c9b0606bd6c80e02bc12c0215722cbbd9751965e
src/frontend/apis/index.js
浏览文件 @
a3529a31
...
...
@@ -51,7 +51,7 @@ const PUT = URL => {
const
HierarchyApi
=
{
getHierarchy
:
GET
(
'
/hierarchy
'
),
get
File
:
GET
(
'
/hierarchy/:categoryKey/:algorithmKey/:fileName
'
),
get
Algorithm
:
GET
(
'
/hierarchy/:categoryKey/:algorithmKey
'
),
};
const
WikiApi
=
{
...
...
@@ -62,6 +62,7 @@ const WikiApi = {
const
GitHubApi
=
{
auth
:
token
=>
gh
=
new
GitHub
({
token
}),
getProfile
:
()
=>
gh
.
getUser
().
getProfile
(),
listGists
:
()
=>
gh
.
getUser
().
listGists
(),
};
export
{
...
...
src/frontend/common/config.js
浏览文件 @
a3529a31
const
stepLimit
=
1
e6
;
const
stepLimit
=
1
e6
;
// TODO: limit number of traces
const
CATEGORY_SCRATCH_PAPER
=
'
scratch-paper
'
;
const
ALGORITHM_NEW
=
'
new
'
;
export
{
stepLimit
,
CATEGORY_SCRATCH_PAPER
,
ALGORITHM_NEW
,
};
\ No newline at end of file
src/frontend/components/App/index.jsx
浏览文件 @
a3529a31
...
...
@@ -3,7 +3,6 @@ import { connect } from 'react-redux';
import
{
loadProgressBar
}
from
'
axios-progress-bar
'
import
{
CodeEditor
,
DescriptionViewer
,
Header
,
Navigator
,
ToastContainer
,
WikiViewer
,
}
from
'
/components
'
;
import
{
Workspace
,
WSSectionContainer
,
WSTabContainer
}
from
'
/workspace/components
'
;
import
{
Section
}
from
'
/workspace/core
'
;
import
{
actions
as
toastActions
}
from
'
/reducers/toast
'
;
import
{
actions
as
envActions
}
from
'
/reducers/env
'
;
import
{
GitHubApi
,
HierarchyApi
}
from
'
/apis
'
;
...
...
@@ -26,11 +25,21 @@ class App extends React.Component {
constructor
(
props
)
{
super
(
props
);
this
.
spawnReference
=
Workspace
.
createReference
();
this
.
navigatorReference
=
Workspace
.
createReference
();
this
.
workspaceRef
=
React
.
createRef
();
this
.
navigator
=
null
;
this
.
state
=
{
files
:
[],
codeFile
:
null
,
descFile
:
null
,
renderers
:
[],
};
}
componentDidMount
()
{
const
workspace
=
this
.
workspaceRef
.
current
;
this
.
navigator
=
workspace
.
findSectionById
(
'
navigator
'
);
this
.
updateDirectory
(
this
.
props
.
match
.
params
);
HierarchyApi
.
getHierarchy
()
...
...
@@ -45,7 +54,7 @@ class App extends React.Component {
const
{
signedIn
,
accessToken
}
=
this
.
props
.
env
;
if
(
signedIn
)
GitHubApi
.
auth
(
accessToken
);
tracerManager
.
setOnRender
(
renderers
=>
this
.
handleChangeRenderers
(
renderers
));
tracerManager
.
setOnRender
(
renderers
=>
this
.
setState
({
renderers
}
));
tracerManager
.
setOnError
(
error
=>
this
.
props
.
showErrorToast
(
error
.
message
));
}
...
...
@@ -63,51 +72,37 @@ class App extends React.Component {
updateDirectory
({
categoryKey
=
null
,
algorithmKey
=
null
})
{
if
(
categoryKey
&&
algorithmKey
)
{
this
.
props
.
setDirectory
(
categoryKey
,
algorithmKey
);
HierarchyApi
.
getAlgorithm
(
categoryKey
,
algorithmKey
)
.
then
(({
algorithm
})
=>
{
const
{
files
}
=
algorithm
;
const
codeFile
=
files
.
find
(
file
=>
file
.
name
===
'
code.js
'
)
||
null
;
const
descFile
=
files
.
find
(
file
=>
file
.
name
===
'
desc.md
'
)
||
null
;
this
.
setState
({
files
,
codeFile
,
descFile
});
})
.
catch
(()
=>
this
.
setState
({
files
:
[]
}));
}
}
handleChangeRenderers
(
renderers
)
{
const
oldSections
=
this
.
rendererSections
||
{};
const
newSections
=
{};
for
(
const
renderer
of
renderers
)
{
const
{
tracerKey
,
element
}
=
renderer
;
let
section
=
null
;
if
(
tracerKey
in
oldSections
)
{
section
=
oldSections
[
tracerKey
];
section
.
setElement
(
element
);
delete
oldSections
[
tracerKey
];
}
else
{
section
=
new
Section
(
element
);
this
.
spawnReference
.
core
.
addChild
(
section
);
}
newSections
[
tracerKey
]
=
section
;
}
Object
.
values
(
oldSections
).
forEach
(
tab
=>
tab
.
remove
());
this
.
rendererSections
=
newSections
;
}
render
()
{
const
{
hierarchy
,
categoryKey
,
algorithmKey
}
=
this
.
props
.
env
;
const
navigatorOpened
=
true
;
const
{
codeFile
,
descFile
,
renderers
}
=
this
.
state
;
return
hierarchy
&&
categoryKey
&&
algorithmKey
&&
(
return
(
<
div
className
=
{
styles
.
app
}
>
<
Workspace
className
=
{
styles
.
workspace
}
wsProps
=
{
{
horizontal
:
false
}
}
>
<
Workspace
className
=
{
styles
.
workspace
}
wsProps
=
{
{
horizontal
:
false
}
}
ref
=
{
this
.
workspaceRef
}
>
<
Header
wsProps
=
{
{
removable
:
false
,
size
:
32
,
fixed
:
true
,
resizable
:
false
,
}
}
onClickTitleBar
=
{
()
=>
this
.
navigator
Reference
.
core
.
setVisible
(
!
this
.
navigatorReference
.
core
.
visible
)
}
navigatorOpened
=
{
navigatorOpened
}
/>
onClickTitleBar
=
{
()
=>
this
.
navigator
.
setVisible
(
!
this
.
navigator
.
visible
)
}
navigatorOpened
=
{
true
/* TODO: fix */
}
/>
<
WSSectionContainer
wsProps
=
{
{
fixed
:
true
}
}
>
<
Navigator
wsProps
=
{
{
id
:
'
navigator
'
,
removable
:
false
,
size
:
240
,
minSize
:
120
,
reference
:
this
.
navigatorReference
,
fixed
:
true
,
}
}
/>
<
WSTabContainer
>
...
...
@@ -116,12 +111,13 @@ class App extends React.Component {
title
:
'
Visualization
'
,
removable
:
false
,
horizontal
:
false
,
reference
:
this
.
spawnReference
}
}
/>
}
}
>
{
renderers
}
</
WSSectionContainer
>
</
WSTabContainer
>
<
WSTabContainer
>
<
DescriptionViewer
wsProps
=
{
{
title
:
'
Description
'
}
}
/>
<
CodeEditor
wsProps
=
{
{
title
:
'
code.js
'
}
}
/>
<
DescriptionViewer
wsProps
=
{
{
title
:
'
Description
'
}
}
file
=
{
descFile
}
/>
<
CodeEditor
wsProps
=
{
{
title
:
'
code.js
'
}
}
file
=
{
codeFile
}
/>
</
WSTabContainer
>
</
WSSectionContainer
>
</
Workspace
>
...
...
src/frontend/components/App/stylesheet.scss
浏览文件 @
a3529a31
...
...
@@ -15,7 +15,6 @@ body {
user-select
:
none
;
color
:
$color-font
;
font-size
:
$font-size-normal
;
background-color
:
$theme-normal
;
}
a
{
...
...
src/frontend/components/CodeEditor/index.jsx
浏览文件 @
a3529a31
import
React
from
'
react
'
;
import
AceEditor
from
'
react-ace
'
;
import
{
connect
}
from
'
react-redux
'
;
import
'
brace/mode/javascript
'
;
import
'
brace/theme/tomorrow_night_eighties
'
;
import
'
brace/ext/searchbox
'
;
import
{
tracerManager
}
from
'
/core
'
;
import
{
classes
}
from
'
/common/util
'
;
import
styles
from
'
./stylesheet.scss
'
;
import
{
HierarchyApi
}
from
'
/apis
'
;
import
{
ContributorsViewer
}
from
'
/components
'
;
import
{
actions
as
envActions
}
from
'
/reducers/env
'
;
// TODO: code should not be reloaded when reopening tab
@
connect
(
({
env
})
=>
({
env
}),
{
...
envActions
}
)
class
CodeEditor
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
const
{
file
}
=
props
;
const
{
lineIndicator
}
=
tracerManager
;
this
.
state
=
{
lineMarker
:
this
.
createLineMarker
(
lineIndicator
),
file
:
null
,
code
:
file
&&
file
.
content
,
};
}
componentDidMount
()
{
const
{
categoryKey
,
algorithmKey
}
=
this
.
props
.
env
;
this
.
loadFile
(
categoryKey
,
algorithmKey
);
tracerManager
.
setOnUpdateLineIndicator
(
lineIndicator
=>
this
.
setState
({
lineMarker
:
this
.
createLineMarker
(
lineIndicator
)
}));
}
componentWillReceiveProps
(
nextProps
)
{
const
{
categoryKey
,
algorithmKey
}
=
nextProps
.
env
;
if
(
categoryKey
!==
this
.
props
.
env
.
categoryKey
||
algorithmKey
!==
this
.
props
.
env
.
algorithmKey
)
{
this
.
loadFile
(
categoryKey
,
algorithmKey
);
const
{
file
}
=
nextProps
;
if
(
file
!==
this
.
props
.
file
)
{
this
.
handleChangeCode
(
file
&&
file
.
content
);
}
}
...
...
@@ -48,15 +35,6 @@ class CodeEditor extends React.Component {
tracerManager
.
setOnUpdateLineIndicator
(
null
);
}
loadFile
(
categoryKey
,
algorithmKey
)
{
HierarchyApi
.
getFile
(
categoryKey
,
algorithmKey
,
'
code.js
'
)
.
then
(({
file
})
=>
{
this
.
setState
({
file
});
tracerManager
.
setCode
(
file
.
content
);
})
.
catch
(()
=>
this
.
setState
({
file
:
null
}));
}
createLineMarker
(
lineIndicator
)
{
if
(
lineIndicator
===
null
)
return
null
;
const
{
lineNumber
,
cursor
}
=
lineIndicator
;
...
...
@@ -73,14 +51,13 @@ class CodeEditor extends React.Component {
}
handleChangeCode
(
code
)
{
const
file
=
{
...
this
.
state
.
file
,
content
:
code
};
this
.
setState
({
file
});
this
.
setState
({
code
});
tracerManager
.
setCode
(
code
);
}
render
()
{
const
{
lineMarker
,
file
}
=
this
.
state
;
const
{
className
,
relativeWeight
}
=
this
.
props
;
const
{
className
,
file
}
=
this
.
props
;
const
{
lineMarker
,
code
}
=
this
.
state
;
return
file
&&
(
<
div
className
=
{
classes
(
styles
.
code_editor
,
className
)
}
>
...
...
@@ -92,10 +69,9 @@ class CodeEditor extends React.Component {
editorProps
=
{
{
$blockScrolling
:
true
}
}
onChange
=
{
code
=>
this
.
handleChangeCode
(
code
)
}
markers
=
{
lineMarker
?
[
lineMarker
]
:
[]
}
value
=
{
file
.
content
}
width
=
{
`
${
relativeWeight
}
`
}
/>
value
=
{
code
}
/>
<
ContributorsViewer
contributors
=
{
file
.
contributors
}
/>
</
div
>
// TODO:
trick to update on resize
</
div
>
// TODO:
need resizing when parent resizes
);
}
}
...
...
src/frontend/components/DescriptionViewer/index.jsx
浏览文件 @
a3529a31
import
React
from
'
react
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
actions
as
envActions
}
from
'
/reducers/env
'
;
import
{
HierarchyApi
}
from
'
/apis/index
'
;
import
{
ContributorsViewer
,
MarkdownViewer
}
from
'
/components
'
;
import
styles
from
'
./stylesheet.scss
'
;
import
{
classes
}
from
'
/common/util
'
;
@
connect
(
({
env
})
=>
({
env
}),
{
...
envActions
}
)
class
DescriptionViewer
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
file
:
null
,
};
}
componentDidMount
()
{
const
{
categoryKey
,
algorithmKey
}
=
this
.
props
.
env
;
const
href
=
`/algorithm/
${
categoryKey
}
/
${
algorithmKey
}
`
;
this
.
loadFile
(
href
);
}
componentWillReceiveProps
(
nextProps
)
{
const
{
categoryKey
,
algorithmKey
}
=
nextProps
.
env
;
if
(
categoryKey
!==
this
.
props
.
env
.
categoryKey
||
algorithmKey
!==
this
.
props
.
env
.
algorithmKey
)
{
const
href
=
`/algorithm/
${
categoryKey
}
/
${
algorithmKey
}
`
;
this
.
loadFile
(
href
);
}
}
loadFile
(
href
)
{
const
[,
,
categoryKey
,
algorithmKey
]
=
href
.
split
(
'
/
'
);
HierarchyApi
.
getFile
(
categoryKey
,
algorithmKey
,
'
desc.md
'
)
.
then
(({
file
})
=>
this
.
setState
({
file
}))
.
catch
(()
=>
this
.
setState
({
file
:
null
}));
}
render
()
{
const
{
className
}
=
this
.
props
;
const
{
file
}
=
this
.
state
;
const
{
className
,
file
}
=
this
.
props
;
return
file
&&
(
<
div
className
=
{
classes
(
styles
.
description_viewer
,
className
)
}
>
<
MarkdownViewer
className
=
{
styles
.
markdown_viewer
}
source
=
{
file
.
content
}
onClickLink
=
{
href
=>
this
.
loadFile
(
href
)
}
/>
<
MarkdownViewer
className
=
{
styles
.
markdown_viewer
}
source
=
{
file
.
content
}
/>
<
ContributorsViewer
contributors
=
{
file
.
contributors
}
/>
</
div
>
);
...
...
src/frontend/components/Header/index.jsx
浏览文件 @
a3529a31
...
...
@@ -72,15 +72,23 @@ class Header extends React.Component {
const
{
className
,
onClickTitleBar
,
navigatorOpened
}
=
this
.
props
;
const
{
hierarchy
,
categoryKey
,
algorithmKey
,
signedIn
}
=
this
.
props
.
env
;
const
category
=
hierarchy
.
find
(
category
=>
category
.
key
===
categoryKey
);
const
algorithm
=
category
.
algorithms
.
find
(
algorithm
=>
algorithm
.
key
===
algorithmKey
);
let
directory
=
[
'
Algorithm Visualizer
'
];
if
(
hierarchy
&&
categoryKey
&&
algorithmKey
)
{
const
category
=
hierarchy
.
find
(
category
=>
category
.
key
===
categoryKey
);
const
algorithm
=
category
.
algorithms
.
find
(
algorithm
=>
algorithm
.
key
===
algorithmKey
);
directory
=
[
category
.
name
,
algorithm
.
name
];
}
return
(
<
header
className
=
{
classes
(
styles
.
header
,
className
)
}
>
<
Button
className
=
{
styles
.
title_bar
}
onClick
=
{
onClickTitleBar
}
>
<
Ellipsis
>
{
category
.
name
}
</
Ellipsis
>
<
FontAwesomeIcon
className
=
{
styles
.
nav_arrow
}
fixedWidth
icon
=
{
faAngleRight
}
/>
<
Ellipsis
>
{
algorithm
.
name
}
</
Ellipsis
>
{
directory
.
map
((
path
,
i
)
=>
[
<
Ellipsis
key
=
{
`path-
${
i
}
`
}
>
{
path
}
</
Ellipsis
>,
i
<
directory
.
length
-
1
&&
<
FontAwesomeIcon
className
=
{
styles
.
nav_arrow
}
fixedWidth
icon
=
{
faAngleRight
}
key
=
{
`arrow-
${
i
}
`
}
/>
])
}
<
FontAwesomeIcon
className
=
{
styles
.
nav_caret
}
fixedWidth
icon
=
{
navigatorOpened
?
faCaretDown
:
faCaretRight
}
/>
</
Button
>
...
...
src/frontend/components/MarkdownViewer/index.jsx
浏览文件 @
a3529a31
...
...
@@ -8,7 +8,7 @@ class MarkdownViewer extends React.Component {
const
{
className
,
source
,
onClickLink
}
=
this
.
props
;
const
link
=
({
href
,
...
rest
})
=>
{
return
/^https
?
:
\/\/
/i
.
test
(
href
)
?
(
return
!
onClickLink
||
/^https
?
:
\/\/
/i
.
test
(
href
)
?
(
<
a
href
=
{
href
}
rel
=
"noopener"
target
=
"_blank"
{
...
rest
}
/>
)
:
(
<
a
onClick
=
{
()
=>
onClickLink
(
href
)
}
{
...
rest
}
/>
...
...
src/frontend/components/Navigator/index.jsx
浏览文件 @
a3529a31
...
...
@@ -8,29 +8,44 @@ import faGithub from '@fortawesome/fontawesome-free-brands/faGithub';
import
{
ExpandableListItem
,
ListItem
}
from
'
/components
'
;
import
{
classes
}
from
'
/common/util
'
;
import
{
actions
as
envActions
}
from
'
/reducers/env
'
;
import
{
actions
as
toastActions
}
from
'
/reducers/toast
'
;
import
styles
from
'
./stylesheet.scss
'
;
import
{
ALGORITHM_NEW
,
CATEGORY_SCRATCH_PAPER
}
from
'
/common/config
'
;
@
connect
(
({
env
})
=>
({
env
}),
{
...
envActions
...
envActions
,
...
toastActions
,
}
)
class
Navigator
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
const
{
categoryKey
}
=
this
.
props
.
env
;
this
.
state
=
{
categoriesOpened
:
{
[
categoryKey
]:
tru
e
,
}
,
categoriesOpened
:
{
},
scratchPaperOpened
:
fals
e
,
favoritesOpened
:
false
,
query
:
''
,
}
}
componentDidMount
()
{
const
{
categoryKey
}
=
this
.
props
.
env
;
if
(
categoryKey
)
{
this
.
toggleCategory
(
categoryKey
,
true
);
}
}
componentWillReceiveProps
(
nextProps
)
{
const
{
categoryKey
}
=
nextProps
.
env
;
if
(
categoryKey
)
{
this
.
toggleCategory
(
categoryKey
,
true
);
}
}
toggleCategory
(
key
,
categoryOpened
=
!
this
.
state
.
categoriesOpened
[
key
])
{
const
categoriesOpened
=
{
...
this
.
state
.
categoriesOpened
,
...
...
@@ -39,6 +54,14 @@ class Navigator extends React.Component {
this
.
setState
({
categoriesOpened
});
}
toggleScratchPaper
(
scratchPaperOpened
=
!
this
.
state
.
scratchPaperOpened
)
{
this
.
setState
({
scratchPaperOpened
});
}
toggleFavorites
(
favoritesOpened
=
!
this
.
state
.
favoritesOpened
)
{
this
.
setState
({
favoritesOpened
});
}
handleChangeQuery
(
e
)
{
const
{
hierarchy
}
=
this
.
props
.
env
;
const
categoriesOpened
=
{};
...
...
@@ -48,7 +71,6 @@ class Navigator extends React.Component {
categoriesOpened
[
category
.
key
]
=
true
;
}
});
this
.
setState
({
categoriesOpened
,
query
});
}
...
...
@@ -58,9 +80,9 @@ class Navigator extends React.Component {
}
render
()
{
const
{
categoriesOpened
,
query
}
=
this
.
state
;
const
{
categoriesOpened
,
scratchPaperOpened
,
favoritesOpened
,
query
}
=
this
.
state
;
const
{
className
,
style
}
=
this
.
props
;
const
{
hierarchy
,
categoryKey
:
selectedCategoryKey
,
algorithmKey
:
selectedAlgorithmKey
}
=
this
.
props
.
env
;
const
{
hierarchy
,
categoryKey
,
algorithmKey
,
signedIn
}
=
this
.
props
.
env
;
return
(
<
nav
className
=
{
classes
(
styles
.
navigator
,
className
)
}
style
=
{
style
}
>
...
...
@@ -71,7 +93,7 @@ class Navigator extends React.Component {
</
div
>
<
div
className
=
{
styles
.
algorithm_list
}
>
{
hierarchy
.
map
(
category
=>
{
hierarchy
&&
hierarchy
.
map
(
category
=>
{
const
categoryOpened
=
categoriesOpened
[
category
.
key
];
let
algorithms
=
category
.
algorithms
;
if
(
!
this
.
testQuery
(
category
.
name
))
{
...
...
@@ -84,7 +106,7 @@ class Navigator extends React.Component {
opened
=
{
categoryOpened
}
>
{
algorithms
.
map
(
algorithm
=>
{
const
selected
=
category
.
key
===
selectedCategoryKey
&&
algorithm
.
key
===
selectedA
lgorithmKey
;
const
selected
=
category
.
key
===
categoryKey
&&
algorithm
.
key
===
a
lgorithmKey
;
return
(
<
ListItem
indent
key
=
{
algorithm
.
key
}
selected
=
{
selected
}
to
=
{
`/
${
category
.
key
}
/
${
algorithm
.
key
}
`
}
label
=
{
algorithm
.
name
}
/>
...
...
@@ -97,9 +119,24 @@ class Navigator extends React.Component {
}
</
div
>
<
div
className
=
{
styles
.
footer
}
>
<
ExpandableListItem
icon
=
{
faCode
}
label
=
"Scratch Paper"
/>
<
ExpandableListItem
icon
=
{
faStar
}
label
=
"Favorites"
/>
<
ListItem
icon
=
{
faGithub
}
label
=
"Fork me on GitHub"
href
=
"https://github.com/parkjs814/AlgorithmVisualizer"
/>
{
signedIn
?
<
ExpandableListItem
icon
=
{
faCode
}
label
=
"Scratch Paper"
onClick
=
{
()
=>
this
.
toggleScratchPaper
()
}
opened
=
{
scratchPaperOpened
}
>
<
ListItem
indent
label
=
"New ..."
to
=
{
`/
${
CATEGORY_SCRATCH_PAPER
}
/
${
ALGORITHM_NEW
}
`
}
/>
</
ExpandableListItem
>
:
<
ListItem
icon
=
{
faCode
}
label
=
"Scratch Paper"
onClick
=
{
()
=>
this
.
props
.
showSuccessToast
(
'
Sign In Required
'
)
}
/>
}
{
signedIn
?
<
ExpandableListItem
icon
=
{
faStar
}
label
=
"Favorites"
onClick
=
{
()
=>
this
.
toggleFavorites
()
}
opened
=
{
favoritesOpened
}
/>
:
<
ListItem
icon
=
{
faStar
}
label
=
"Favorites"
onClick
=
{
()
=>
this
.
props
.
showSuccessToast
(
'
Sign In Required
'
)
}
/>
}
<
ListItem
icon
=
{
faGithub
}
label
=
"Fork me on GitHub"
href
=
"https://github.com/algorithm-visualizer/algorithm-visualizer"
/>
</
div
>
</
nav
>
);
...
...
src/frontend/core/tracerManager.jsx
浏览文件 @
a3529a31
...
...
@@ -103,10 +103,9 @@ class TracerManager {
}[
className
];
const
data
=
new
DataClass
(
options
);
this
.
datas
[
tracerKey
]
=
data
;
const
renderer
=
{
tracerKey
,
element
:
<
RendererClass
title
=
{
title
}
data
=
{
data
}
wsProps
=
{
{
fixed
:
true
}
}
/>
};
const
renderer
=
(
<
RendererClass
key
=
{
tracerKey
}
title
=
{
title
}
data
=
{
data
}
wsProps
=
{
{
fixed
:
true
}
}
/>
);
this
.
renderers
.
push
(
renderer
);
}
...
...
src/frontend/workspace/components/WSSectionContainer/index.jsx
浏览文件 @
a3529a31
...
...
@@ -9,7 +9,7 @@ class WSSectionContainer extends React.Component {
super
(
props
);
const
{
core
}
=
props
;
core
.
reference
.
component
=
this
;
core
.
component
=
this
;
this
.
core
=
core
;
}
...
...
@@ -57,7 +57,7 @@ class WSSectionContainer extends React.Component {
visibleChildren
.
forEach
((
child
,
visibleIndex
)
=>
{
const
index
=
children
.
indexOf
(
child
);
elements
.
push
(
<
Divider
key
=
{
`divider-
before-
${
child
.
key
}
`
}
horizontal
=
{
horizontal
}
<
Divider
key
=
{
`divider-
${
index
}
`
}
horizontal
=
{
horizontal
}
onResize
=
{
visibleIndex
>
0
&&
((
target
,
dx
,
dy
)
=>
this
.
handleResize
(
visibleIndex
,
target
,
dx
,
dy
))
}
onDropTab
=
{
tab
=>
this
.
handleDropTabToContainer
(
tab
,
index
)
}
onDropSection
=
{
section
=>
this
.
handleDropSectionToContainer
(
section
,
index
)
}
...
...
@@ -71,13 +71,13 @@ class WSSectionContainer extends React.Component {
};
if
(
children
.
length
===
1
)
{
elements
.
push
(
<
div
key
=
{
child
.
key
}
className
=
{
classes
(
styles
.
wrapper
)
}
style
=
{
style
}
>
<
div
key
=
{
child
.
id
}
className
=
{
classes
(
styles
.
wrapper
)
}
style
=
{
style
}
>
{
child
.
element
}
</
div
>
);
}
else
{
elements
.
push
(
<
div
key
=
{
child
.
key
}
className
=
{
classes
(
styles
.
wrapper
,
!
horizontal
&&
styles
.
horizontal
)
}
style
=
{
style
}
>
<
div
key
=
{
child
.
id
}
className
=
{
classes
(
styles
.
wrapper
,
!
horizontal
&&
styles
.
horizontal
)
}
style
=
{
style
}
>
{
!
child
.
fixed
&&
<
Divider
horizontal
=
{
!
horizontal
}
...
...
@@ -96,7 +96,7 @@ class WSSectionContainer extends React.Component {
}
if
(
visibleIndex
===
visibleChildren
.
length
-
1
)
{
elements
.
push
(
<
Divider
key
=
{
`divider-
after-
${
child
.
key
}
`
}
horizontal
=
{
horizontal
}
<
Divider
key
=
{
`divider-
last
`
}
horizontal
=
{
horizontal
}
onDropTab
=
{
tab
=>
this
.
handleDropTabToContainer
(
tab
,
index
+
1
)
}
onDropSection
=
{
section
=>
this
.
handleDropSectionToContainer
(
section
,
index
+
1
)
}
disableDrop
=
{
child
.
fixed
}
/>
...
...
src/frontend/workspace/components/WSTabContainer/index.jsx
浏览文件 @
a3529a31
...
...
@@ -22,7 +22,7 @@ class WSTabContainer extends React.Component {
super
(
props
);
const
{
core
}
=
props
;
core
.
reference
.
component
=
this
;
core
.
component
=
this
;
this
.
core
=
core
;
}
...
...
src/frontend/workspace/components/Workspace/index.jsx
浏览文件 @
a3529a31
import
React
from
'
react
'
;
import
{
classes
}
from
'
/common/util
'
;
import
{
WSSectionContainer
}
from
'
/workspace/components
'
;
import
{
SectionContainer
}
from
'
/workspace/core
'
;
import
{
Parent
,
SectionContainer
}
from
'
/workspace/core
'
;
import
styles
from
'
./stylesheet.scss
'
;
class
Workspace
extends
React
.
Component
{
static
createReference
()
{
return
{
core
:
null
,
component
:
null
,
};
}
constructor
(
props
)
{
super
(
props
);
const
{
className
,
children
,
wsProps
}
=
props
;
this
.
sectionContainer
=
new
SectionContainer
(
this
.
sectionContainer
=
new
SectionContainer
(
this
.
getElement
(
props
));
}
componentDidMount
()
{
this
.
handleChangeElement
(
this
.
props
);
}
componentWillReceiveProps
(
nextProps
)
{
this
.
handleChangeElement
(
nextProps
);
}
getElement
(
props
)
{
const
{
className
,
wsProps
,
...
rest
}
=
props
;
return
(
<
WSSectionContainer
className
=
{
classes
(
styles
.
workspace
,
className
)
}
wsProps
=
{
{
removable
:
false
,
...
wsProps
}
}
>
{
children
}
</
WSSectionContainer
>
wsProps
=
{
{
id
:
'
workspace
'
,
removable
:
false
,
...
wsProps
}
}
{
...
rest
}
/>
);
}
handleChangeElement
(
props
)
{
const
element
=
this
.
getElement
(
props
);
const
unmark
=
section
=>
{
section
.
updated
=
false
;
if
(
section
instanceof
Parent
)
{
section
.
children
.
forEach
(
unmark
);
}
};
unmark
(
this
.
sectionContainer
);
console
.
log
(
'
----
'
);
const
update
=
(
element
,
parentSection
)
=>
{
const
{
children
=
[],
wsProps
=
{}
}
=
element
.
props
;
const
id
=
wsProps
.
id
||
`
${
parentSection
.
id
}
-
${
element
.
key
}
`
;
if
(
id
.
startsWith
(
'
workspace-.1-.1-.1-
'
))
console
.
log
(
id
.
slice
(
'
workspace-.1-.1-.1-
'
.
length
));
let
section
=
this
.
findSectionById
(
id
);
if
(
section
)
{
section
.
setElement
(
element
);
}
else
{
section
=
parentSection
.
childify
(
React
.
cloneElement
(
element
,
{
wsProps
:
{
...
wsProps
,
id
}
}));
parentSection
.
addChild
(
section
);
}
section
.
updated
=
true
;
if
(
section
instanceof
Parent
)
{
React
.
Children
.
toArray
(
children
).
forEach
(
element
=>
update
(
element
,
section
));
}
};
update
(
element
);
const
removeUnmarked
=
section
=>
{
if
(
!
section
.
updated
)
{
section
.
remove
();
}
else
if
(
section
instanceof
Parent
)
{
section
.
children
.
forEach
(
removeUnmarked
);
}
};
removeUnmarked
(
this
.
sectionContainer
);
}
findSectionById
(
id
,
section
=
this
.
sectionContainer
)
{
if
(
section
.
id
===
id
)
return
section
;
if
(
section
instanceof
Parent
)
{
for
(
const
childSection
of
section
.
children
)
{
const
foundSection
=
this
.
findSectionById
(
id
,
childSection
);
if
(
foundSection
)
return
foundSection
;
}
}
}
render
()
{
return
this
.
sectionContainer
.
element
;
}
...
...
src/frontend/workspace/core/Child.js
已删除
100644 → 0
浏览文件 @
b4801513
import
React
from
'
react
'
;
import
uuid
from
'
uuid
'
;
import
{
Workspace
}
from
'
/workspace/components
'
;
class
Child
{
getDefaultProps
()
{
return
{
reference
:
Workspace
.
createReference
(),
removable
:
true
,
};
}
createElement
(
wsProps
)
{
return
(
<
div
wsProps
=
{
wsProps
}
/
>
);
}
constructor
(
element
)
{
if
(
!
React
.
isValidElement
(
element
))
{
element
=
this
.
createElement
(
element
);
}
const
{
wsProps
=
{}
}
=
element
.
props
;
Object
.
assign
(
this
,
this
.
getDefaultProps
(),
wsProps
);
this
.
reference
.
core
=
this
;
this
.
key
=
uuid
.
v4
();
this
.
parent
=
null
;
this
.
init
(
element
);
}
init
(
element
)
{
this
.
element
=
React
.
cloneElement
(
element
,
{
core
:
this
});
}
setParent
(
parent
)
{
if
(
this
.
parent
)
this
.
remove
(
true
);
this
.
parent
=
parent
;
}
setElement
(
element
)
{
this
.
init
(
element
);
this
.
parent
.
render
();
}
remove
(
moving
=
false
)
{
if
(
this
.
removable
||
moving
)
{
const
index
=
this
.
parent
.
findIndex
(
this
.
key
);
this
.
parent
.
removeChild
(
index
);
}
}
}
export
default
Child
;
\ No newline at end of file
src/frontend/workspace/core/
mixins/parentMixin
.js
→
src/frontend/workspace/core/
Parent
.js
浏览文件 @
a3529a31
import
React
from
'
react
'
;
import
{
Child
}
from
'
/workspace/core
'
;
import
{
Section
}
from
'
/workspace/core
'
;
c
onst
parentMixin
=
(
Base
=
Child
)
=>
class
Parent
extends
Base
{
c
lass
Parent
extends
Section
{
constructor
(
element
)
{
super
(
element
);
const
{
children
=
[]
}
=
this
.
element
.
props
;
this
.
children
=
[];
React
.
Children
.
forEach
(
children
,
element
=>
this
.
addChild
(
this
.
childify
(
element
)));
}
setElement
(
element
)
{
super
.
setElement
(
React
.
cloneElement
(
element
,
{
core
:
this
}));
}
childify
(
element
)
{
return
new
Child
(
element
);
return
new
Section
(
element
);
}
addChild
(
child
,
index
=
this
.
children
.
length
,
beforeRender
)
{
addChild
(
child
,
index
=
this
.
children
.
length
)
{
if
(
child
.
parent
===
this
)
{
const
oldIndex
=
this
.
children
.
indexOf
(
child
);
this
.
children
[
oldIndex
]
=
null
;
...
...
@@ -23,25 +25,20 @@ const parentMixin = (Base = Child) => class Parent extends Base {
this
.
children
.
splice
(
index
,
0
,
child
);
child
.
setParent
(
this
);
}
if
(
beforeRender
)
beforeRender
();
this
.
render
();
}
removeChild
(
index
,
beforeRender
)
{
removeChild
(
index
)
{
this
.
children
.
splice
(
index
,
1
);
if
(
this
.
children
.
length
===
0
)
this
.
remove
();
if
(
beforeRender
)
beforeRender
();
this
.
render
();
}
findIndex
(
key
)
{
return
this
.
children
.
findIndex
(
child
=>
child
.
key
===
key
);
findIndex
(
child
)
{
return
this
.
children
.
indexOf
(
child
);
}
render
()
{
const
{
component
}
=
this
.
reference
;
if
(
component
)
component
.
forceUpdate
();
if
(
this
.
component
)
this
.
component
.
forceUpdate
();
}
}
;
}
export
default
parentMixin
;
\ No newline at end of file
export
default
Parent
;
\ No newline at end of file
src/frontend/workspace/core/Section.js
浏览文件 @
a3529a31
import
{
Child
}
from
'
/workspace/core
'
;
import
React
from
'
react
'
;
class
Section
extends
Child
{
class
Section
{
getDefaultProps
()
{
return
{
...
super
.
getDefaultProps
(),
id
:
null
,
removable
:
true
,
visible
:
true
,
resizable
:
true
,
weight
:
1
,
...
...
@@ -17,13 +18,37 @@ class Section extends Child {
}
constructor
(
element
)
{
super
(
element
);
if
(
!
React
.
isValidElement
(
element
))
{
element
=
this
.
createElement
(
element
);
}
this
.
parent
=
null
;
Object
.
assign
(
this
,
this
.
getDefaultProps
());
this
.
setElement
(
element
);
}
createElement
(
wsProps
)
{
return
(
<
div
wsProps
=
{
wsProps
}
/
>
);
}
setElement
(
element
)
{
const
{
wsProps
=
{}
}
=
element
.
props
;
Object
.
assign
(
this
,
wsProps
);
this
.
relative
=
this
.
size
===
-
1
;
this
.
element
=
element
;
}
setParent
(
parent
)
{
if
(
this
.
parent
)
this
.
remove
(
true
);
this
.
parent
=
parent
;
}
setVisible
(
visible
)
{
this
.
visible
=
visible
;
this
.
parent
.
render
();
remove
(
moving
=
false
)
{
if
(
this
.
removable
||
moving
)
{
const
index
=
this
.
parent
.
findIndex
(
this
);
this
.
parent
.
removeChild
(
index
);
}
}
}
...
...
src/frontend/workspace/core/SectionContainer.js
浏览文件 @
a3529a31
import
React
from
'
react
'
;
import
{
Section
,
TabContainer
}
from
'
/workspace/core
'
;
import
{
parentMixin
}
from
'
/workspace/core/mixins
'
;
import
{
Parent
,
Section
,
TabContainer
}
from
'
/workspace/core
'
;
import
{
WSSectionContainer
,
WSTabContainer
}
from
'
/workspace/components
'
;
class
SectionContainer
extends
parentMixin
(
Section
)
{
class
SectionContainer
extends
Parent
{
getDefaultProps
()
{
return
{
...
super
.
getDefaultProps
(),
...
...
@@ -32,7 +31,7 @@ class SectionContainer extends parentMixin(Section) {
super
.
removeChild
(
index
);
if
(
this
.
removable
&&
this
.
children
.
length
===
1
)
{
const
[
child
]
=
this
.
children
;
const
index
=
this
.
parent
.
findIndex
(
this
.
key
);
const
index
=
this
.
parent
.
findIndex
(
this
);
this
.
parent
.
addChild
(
child
,
index
);
}
}
...
...
src/frontend/workspace/core/TabContainer.js
浏览文件 @
a3529a31
import
React
from
'
react
'
;
import
{
Section
,
Tab
}
from
'
/workspace/core
'
;
import
{
Parent
,
Tab
}
from
'
/workspace/core
'
;
import
{
WSTabContainer
}
from
'
/workspace/components
'
;
import
{
parentMixin
}
from
'
/workspace/core/mixins
'
;
class
TabContainer
extends
parentMixin
(
Section
)
{
class
TabContainer
extends
Parent
{
getDefaultProps
()
{
return
{
...
super
.
getDefaultProps
(),
...
...
@@ -22,15 +21,13 @@ class TabContainer extends parentMixin(Section) {
}
addChild
(
child
,
index
=
this
.
children
.
length
)
{
super
.
addChild
(
child
,
index
,
()
=>
{
this
.
setTabIndex
(
Math
.
min
(
index
,
this
.
children
.
length
-
1
));
});
super
.
addChild
(
child
,
index
);
this
.
setTabIndex
(
Math
.
min
(
index
,
this
.
children
.
length
-
1
));
}
removeChild
(
index
)
{
super
.
removeChild
(
index
,
()
=>
{
this
.
setTabIndex
(
Math
.
min
(
this
.
tabIndex
,
this
.
children
.
length
-
1
));
});
super
.
removeChild
(
index
);
this
.
setTabIndex
(
Math
.
min
(
this
.
tabIndex
,
this
.
children
.
length
-
1
));
}
setTabIndex
(
tabIndex
)
{
...
...
src/frontend/workspace/core/draggingData.js
已删除
100644 → 0
浏览文件 @
b4801513
import
uuid
from
'
uuid
'
;
const
key
=
'
dragging-data-id
'
;
class
DraggingData
{
constructor
()
{
this
.
id
=
null
;
this
.
data
=
null
;
}
set
(
e
,
type
,
child
)
{
this
.
id
=
uuid
.
v4
();
this
.
data
=
{
type
,
child
};
e
.
dataTransfer
.
dropEffect
=
'
move
'
;
e
.
dataTransfer
.
setData
(
key
,
this
.
id
);
}
get
(
e
)
{
const
id
=
e
.
dataTransfer
.
getData
(
key
);
if
(
id
===
this
.
id
)
return
this
.
data
;
}
}
const
draggingData
=
new
DraggingData
();
export
default
draggingData
;
\ No newline at end of file
src/frontend/workspace/core/index.js
浏览文件 @
a3529a31
export
{
default
as
Child
}
from
'
./Child
'
;
export
{
default
as
draggingData
}
from
'
./draggingData
'
;
export
{
default
as
Section
}
from
'
./Section
'
;
export
{
default
as
Parent
}
from
'
./Parent
'
;
export
{
default
as
SectionContainer
}
from
'
./SectionContainer
'
;
export
{
default
as
TabContainer
}
from
'
./TabContainer
'
;
export
{
default
as
Tab
}
from
'
./Tab
'
;
export
{
default
as
TabContainer
}
from
'
./TabContainer
'
;
\ No newline at end of file
src/frontend/workspace/core/mixins/index.js
已删除
100644 → 0
浏览文件 @
b4801513
export
{
default
as
parentMixin
}
from
'
./parentMixin
'
;
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录