Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
B
baas-ide
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
guxukai
baas-ide
Commits
134245e0
Unverified
Commit
134245e0
authored
Feb 08, 2018
by
yann300
Committed by
GitHub
Feb 08, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1016 from ethereum/file-exlorer
Fix file explorer update events
parents
f9e518ac
0b394f74
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
182 additions
and
410 deletions
+182
-410
.travis.yml
.travis.yml
+1
-1
browser_tests.sh
ci/browser_tests.sh
+1
-8
contract1.sol
contracts/contract1.sol
+2
-0
contract2.sol
contracts/contract2.sol
+2
-0
contract1.sol
contracts/folder1/contract1.sol
+2
-0
contract2.sol
contracts/folder1/contract2.sol
+2
-0
contract_chrome.sol
contracts/folder1/contract_chrome.sol
+2
-0
contract_firefox.sol
contracts/folder1/contract_firefox.sol
+2
-0
package.json
package.json
+2
-1
app.js
src/app.js
+2
-4
basicReadOnlyExplorer.js
src/app/files/basicReadOnlyExplorer.js
+22
-41
browser-files.js
src/app/files/browser-files.js
+5
-31
file-explorer.js
src/app/files/file-explorer.js
+89
-266
fileManager.js
src/app/files/fileManager.js
+18
-35
shared-folder.js
src/app/files/shared-folder.js
+1
-14
file-panel.js
src/app/panels/file-panel.js
+28
-8
file-panel-styles.js
src/app/panels/styles/file-panel-styles.js
+1
-1
No files found.
.travis.yml
View file @
134245e0
...
...
@@ -2,7 +2,7 @@ language: node_js
node_js
:
-
"
7"
script
:
-
npm run lint && npm run test && npm run downloadsolc && npm run make-mock-compiler && npm run build
-
npm run lint && npm run test && npm run downloadsolc && npm run make-mock-compiler && npm run
setupremix && npm run
build
-
./ci/browser_tests.sh
deploy
:
-
provider
:
script
...
...
ci/browser_tests.sh
View file @
134245e0
...
...
@@ -4,14 +4,7 @@ set -e
setupRemixd
()
{
mkdir
remixdSharedfolder
cd
remixdSharedfolder
echo
"contract test1 { function get () returns (uint) { return 8; }}"
>
contract1.sol
echo
"contract test2 { function get () returns (uint) { return 9; }}"
>
contract2.sol
mkdir
folder1
cd
folder1
echo
"contract test1 { function get () returns (uint) { return 10; }}"
>
contract1.sol
echo
"contract test2 { function get () returns (uint) { return 11; }}"
>
contract2.sol
cd
..
cd
contracts
echo
'sharing folder: '
echo
$PWD
node ../node_modules/remixd/src/main.js
-s
$PWD
&
...
...
contracts/contract1.sol
0 → 100644
View file @
134245e0
contract test1 { function get () returns (uint) { return 8; }}
\ No newline at end of file
contracts/contract2.sol
0 → 100644
View file @
134245e0
contract test2 { function get () returns (uint) { return 9; }}
\ No newline at end of file
contracts/folder1/contract1.sol
0 → 100644
View file @
134245e0
contract test1 { function get () returns (uint) { return 10; }}
\ No newline at end of file
contracts/folder1/contract2.sol
0 → 100644
View file @
134245e0
contract test2 { function get () returns (uint) { return 11; }}
\ No newline at end of file
contracts/folder1/contract_chrome.sol
0 → 100644
View file @
134245e0
contract test2 { function get () returns (uint) { return 11; }}
\ No newline at end of file
contracts/folder1/contract_firefox.sol
0 → 100644
View file @
134245e0
contract test2 { function get () returns (uint) { return 11; }}
\ No newline at end of file
package.json
View file @
134245e0
...
...
@@ -139,7 +139,8 @@
]
},
"scripts"
:
{
"pullremix"
:
"mkdir remix; git clone https://github.com/ethereum/remix; cd .."
,
"setupremix"
:
"npm run pullremix && npm run linkremixcore && npm run linkremixlib && npm run linkremixsolidity && npm run linkremixdebugger;"
,
"pullremix"
:
"git clone https://github.com/ethereum/remix"
,
"linkremixcore"
:
"cd node_modules && rm -rf remix-core && ln -s ../remix/remix-core remix-core && cd .."
,
"linkremixlib"
:
"cd node_modules && rm -rf remix-lib && ln -s ../remix/remix-lib remix-lib && cd .."
,
"linkremixsolidity"
:
"cd node_modules && rm -rf remix-solidity && ln -s ../remix/remix-solidity remix-solidity && cd .."
,
...
...
src/app.js
View file @
134245e0
...
...
@@ -497,10 +497,8 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
switchFile
:
function
(
path
)
{
fileManager
.
switchFile
(
path
)
},
event
:
this
.
event
,
currentFile
:
function
()
{
return
config
.
get
(
'currentFile'
)
},
event
:
fileManager
.
event
,
config
:
config
,
currentContent
:
function
()
{
return
editor
.
get
(
config
.
get
(
'currentFile'
))
},
...
...
src/app/files/basicReadOnlyExplorer.js
View file @
134245e0
...
...
@@ -5,7 +5,9 @@ class BasicReadOnlyExplorer {
constructor
(
type
)
{
this
.
event
=
new
EventManager
()
this
.
files
=
{}
this
.
paths
=
{}
this
.
normalizedNames
=
{}
// contains the raw url associated with the displayed path
this
.
paths
[
type
]
=
{}
this
.
type
=
type
this
.
readonly
=
true
}
...
...
@@ -36,19 +38,32 @@ class BasicReadOnlyExplorer {
}
set
(
path
,
content
,
cb
)
{
this
.
addReadOnly
(
path
,
content
)
var
unprefixedPath
=
this
.
removePrefix
(
path
)
this
.
addReadOnly
(
unprefixedPath
,
content
)
if
(
cb
)
cb
()
return
true
}
addReadOnly
(
path
,
content
,
rawPath
)
{
var
unprefixedPath
=
this
.
removePrefix
(
path
)
try
{
// lazy try to format JSON
content
=
JSON
.
stringify
(
JSON
.
parse
(
content
),
null
,
'
\
t'
)
}
catch
(
e
)
{}
this
.
files
[
this
.
type
+
'/'
+
unprefixedPath
]
=
content
// splitting off the path in a tree structure, the json tree is used in `resolveDirectory`
var
split
=
path
var
folder
=
false
while
(
split
.
lastIndexOf
(
'/'
)
!==
-
1
)
{
var
subitem
=
split
.
substring
(
split
.
lastIndexOf
(
'/'
))
split
=
split
.
substring
(
0
,
split
.
lastIndexOf
(
'/'
))
if
(
!
this
.
paths
[
this
.
type
+
'/'
+
split
])
{
this
.
paths
[
this
.
type
+
'/'
+
split
]
=
{}
}
this
.
paths
[
this
.
type
+
'/'
+
split
][
split
+
subitem
]
=
{
isDirectory
:
folder
}
folder
=
true
}
this
.
paths
[
this
.
type
][
split
]
=
{
isDirectory
:
folder
}
this
.
files
[
path
]
=
content
this
.
normalizedNames
[
rawPath
]
=
path
this
.
event
.
trigger
(
'fileAdded'
,
[
this
.
type
+
'/'
+
unprefixedP
ath
,
true
])
this
.
event
.
trigger
(
'fileAdded'
,
[
p
ath
,
true
])
return
true
}
...
...
@@ -68,46 +83,12 @@ class BasicReadOnlyExplorer {
return
this
.
files
}
//
// Tree model for files
// {
// 'a': { }, // empty directory 'a'
// 'b': {
// 'c': {}, // empty directory 'b/c'
// 'd': { '/readonly': true, '/content': 'Hello World' } // files 'b/c/d'
// 'e': { '/readonly': false, '/path': 'b/c/d' } // symlink to 'b/c/d'
// 'f': { '/readonly': false, '/content': '<executable>', '/mode': 0755 }
// }
// }
//
resolveDirectory
(
path
,
callback
/* (error, filesList) => { } */
)
{
resolveDirectory
(
path
,
callback
)
{
var
self
=
this
if
(
path
[
0
]
===
'/'
)
path
=
path
.
substring
(
1
)
if
(
!
path
)
return
callback
(
null
,
{
[
self
.
type
]:
{
}
})
var
tree
=
{}
// This does not include '.remix.config', because it is filtered
// inside list().
Object
.
keys
(
this
.
list
()).
forEach
(
function
(
path
)
{
hashmapize
(
tree
,
path
,
{
'/readonly'
:
self
.
isReadOnly
(
path
),
'/content'
:
self
.
get
(
path
)
})
})
return
callback
(
null
,
tree
[
path
]
||
{})
function
hashmapize
(
obj
,
path
,
val
)
{
var
nodes
=
path
.
split
(
'/'
)
var
i
=
0
for
(;
i
<
nodes
.
length
-
1
;
i
++
)
{
var
node
=
nodes
[
i
]
if
(
obj
[
node
]
===
undefined
)
{
obj
[
node
]
=
{}
}
obj
=
obj
[
node
]
}
obj
[
nodes
[
i
]]
=
val
}
// we just return the json tree populated by `addReadOnly`
callback
(
null
,
this
.
paths
[
path
])
}
removePrefix
(
path
)
{
...
...
src/app/files/browser-files.js
View file @
134245e0
...
...
@@ -103,55 +103,29 @@ function Files (storage) {
return
false
}
//
// Tree model for files
// {
// 'a': { }, // empty directory 'a'
// 'b': {
// 'c': {}, // empty directory 'b/c'
// 'd': { '/readonly': true, '/content': 'Hello World' } // files 'b/c/d'
// 'e': { '/readonly': false, '/path': 'b/c/d' } // symlink to 'b/c/d'
// 'f': { '/readonly': false, '/content': '<executable>', '/mode': 0755 }
// }
// }
//
this
.
resolveDirectory
=
function
(
path
,
callback
)
{
var
self
=
this
if
(
path
[
0
]
===
'/'
)
path
=
path
.
substring
(
1
)
if
(
!
path
)
return
callback
(
null
,
{
[
self
.
type
]:
{
}
})
path
=
self
.
removePrefix
(
path
)
var
filesList
=
{}
var
tree
=
{}
// add r/w filesList to the list
storage
.
keys
().
forEach
((
path
)
=>
{
// NOTE: as a temporary measure do not show the config file
if
(
path
!==
'.remix.config'
)
{
filesList
[
self
.
type
+
'/'
+
path
]
=
false
filesList
[
path
]
=
false
}
})
// add r/o files to the list
Object
.
keys
(
readonly
).
forEach
((
path
)
=>
{
filesList
[
self
.
type
+
'/'
+
path
]
=
true
filesList
[
path
]
=
true
})
Object
.
keys
(
filesList
).
forEach
(
function
(
path
)
{
hashmapize
(
tree
,
path
,
{
'/readonly'
:
self
.
isReadOnly
(
path
),
'/content'
:
self
.
get
(
path
)
tree
[
path
]
=
{
isDirectory
:
false
}
})
})
return
callback
(
null
,
tree
[
path
]
||
{})
function
hashmapize
(
obj
,
path
,
val
)
{
var
nodes
=
path
.
split
(
'/'
)
var
i
=
0
for
(;
i
<
nodes
.
length
-
1
;
i
++
)
{
var
node
=
nodes
[
i
]
if
(
obj
[
node
]
===
undefined
)
{
obj
[
node
]
=
{}
}
obj
=
obj
[
node
]
}
obj
[
nodes
[
i
]]
=
val
}
return
callback
(
null
,
tree
)
}
this
.
removePrefix
=
function
(
path
)
{
...
...
src/app/files/file-explorer.js
View file @
134245e0
/* global FileReader */
var
yo
=
require
(
'yo-yo'
)
var
csjs
=
require
(
'csjs-inject'
)
var
Treeview
=
require
(
'remix-debugger'
).
ui
.
TreeView
...
...
@@ -55,14 +54,21 @@ module.exports = fileExplorer
function
fileExplorer
(
appAPI
,
files
)
{
var
self
=
this
this
.
events
=
new
EventManager
()
// file provider backend
this
.
files
=
files
// element currently focused on
this
.
focusElement
=
null
// path currently focused on
this
.
focusPath
=
null
// warn if file changed outside of Remix
function
remixdDialog
()
{
return
yo
`<div>This file has been changed outside of Remix IDE.</div>`
}
this
.
files
.
event
.
register
(
'fileExternallyChanged'
,
(
path
,
content
)
=>
{
if
(
appAPI
.
c
urrentFile
()
===
path
&&
appAPI
.
currentContent
()
!==
content
)
{
this
.
files
.
event
.
register
(
'fileExternallyChanged'
,
(
path
,
file
)
=>
{
if
(
appAPI
.
c
onfig
.
get
(
'currentFile'
)
===
path
&&
appAPI
.
currentContent
()
!==
file
.
content
)
{
modalDialog
(
path
+
' changed'
,
remixdDialog
(),
{
label
:
'Keep the content displayed in Remix'
,
...
...
@@ -71,15 +77,58 @@ function fileExplorer (appAPI, files) {
{
label
:
'Replace by the new content'
,
fn
:
()
=>
{
appAPI
.
setText
(
content
)
appAPI
.
setText
(
file
.
content
)
}
}
)
}
})
var
fileEvents
=
files
.
event
// register to event of the file provider
files
.
event
.
register
(
'fileRemoved'
,
fileRemoved
)
files
.
event
.
register
(
'fileRenamed'
,
fileRenamed
)
files
.
event
.
register
(
'fileRenamedError'
,
fileRenamedError
)
files
.
event
.
register
(
'fileAdded'
,
fileAdded
)
function
fileRenamedError
(
error
)
{
modalDialogCustom
.
alert
(
error
)
}
function
fileAdded
(
filepath
)
{
self
.
ensureRoot
(()
=>
{
var
folderpath
=
filepath
.
split
(
'/'
).
slice
(
0
,
-
1
).
join
(
'/'
)
var
currentTree
=
self
.
treeView
.
nodeAt
(
folderpath
)
if
(
currentTree
&&
self
.
treeView
.
isExpanded
(
folderpath
))
{
self
.
files
.
resolveDirectory
(
folderpath
,
(
error
,
fileTree
)
=>
{
if
(
error
)
console
.
error
(
error
)
if
(
!
fileTree
)
return
fileTree
=
normalize
(
folderpath
,
fileTree
)
self
.
treeView
.
updateNodeFromJSON
(
folderpath
,
fileTree
,
true
)
self
.
focusElement
=
self
.
treeView
.
labelAt
(
self
.
focusPath
)
// TODO: here we update the selected file (it applicable)
// cause we are refreshing the interface of the whole directory when there's a new file.
if
(
self
.
focusElement
&&
!
self
.
focusElement
.
classList
.
contains
(
css
.
hasFocus
))
{
self
.
focusElement
.
classList
.
add
(
css
.
hasFocus
)
}
})
}
})
}
function
fileRemoved
(
filepath
)
{
var
label
=
this
.
treeView
.
labelAt
(
filepath
)
if
(
label
&&
label
.
parentElement
)
{
label
.
parentElement
.
removeChild
(
label
)
}
}
function
fileRenamed
(
oldName
,
newName
,
isFolder
)
{
fileRemoved
(
oldName
)
fileAdded
(
newName
)
}
// make interface and register to nodeClick, leafClick
self
.
treeView
=
new
Treeview
({
extractData
:
function
extractData
(
value
,
tree
,
key
)
{
var
newValue
=
{}
...
...
@@ -101,12 +150,10 @@ function fileExplorer (appAPI, files) {
}
},
formatSelf
:
function
formatSelf
(
key
,
data
,
li
)
{
var
isRoot
=
data
.
path
.
indexOf
(
'/'
)
===
-
1
var
isRoot
=
data
.
path
===
self
.
files
.
type
return
yo
`<label class="
${
data
.
children
?
css
.
folder
:
css
.
file
}
"
data-path="
${
data
.
path
}
"
style="
${
isRoot
?
'font-weight:bold;'
:
''
}
"
onload=
${
function
(
el
)
{
adaptEnvironment
(
el
,
focus
,
hover
,
li
)
}
}
onunload=
${
function
(
el
)
{
unadaptEnvironment
(
el
,
focus
,
hover
,
li
)
}
}
onclick=
${
editModeOn
}
onkeydown=
${
editModeOff
}
onblur=
${
editModeOff
}
...
...
@@ -114,18 +161,30 @@ function fileExplorer (appAPI, files) {
}
})
self
.
treeView
.
event
.
register
(
'leafClick'
,
function
(
key
,
data
,
label
)
{
if
(
self
.
focusElement
)
{
self
.
focusElement
.
classList
.
remove
(
css
.
hasFocus
)
self
.
focusElement
=
null
self
.
focusPath
=
null
}
self
.
focusElement
=
self
.
treeView
.
labelAt
(
key
)
if
(
self
.
focusElement
)
{
self
.
focusElement
.
classList
.
add
(
css
.
hasFocus
)
self
.
focusPath
=
key
self
.
events
.
trigger
(
'focus'
,
[
key
])
appAPI
.
config
.
set
(
'currentFile'
,
key
)
}
})
self
.
treeView
.
event
.
register
(
'nodeClick'
,
function
(
path
,
childrenContainer
)
{
if
(
!
childrenContainer
)
return
if
(
childrenContainer
.
style
.
display
===
'none'
)
{
childrenContainer
.
innerHTML
=
''
return
}
if
(
childrenContainer
.
style
.
display
===
'none'
)
return
files
.
resolveDirectory
(
path
,
(
error
,
fileTree
)
=>
{
if
(
error
)
console
.
error
(
error
)
if
(
!
fileTree
)
return
var
newTree
=
normalize
(
path
,
fileTree
)
var
tree
=
self
.
treeView
.
renderProperties
(
newTree
,
false
)
childrenContainer
.
appendChild
(
tree
)
self
.
treeView
.
updateNodeFromJSON
(
path
,
newTree
,
true
)
})
})
...
...
@@ -138,111 +197,22 @@ function fileExplorer (appAPI, files) {
return
newList
}
var
deleteButton
=
yo
`
<span class=
${
css
.
remove
}
onclick=
${
deletePath
}
>
<i class="fa fa-trash" aria-hidden="true"></i>
</span>
`
// register to main app, trigger when the current file in the editor changed
appAPI
.
event
.
register
(
'currentFileChanged'
,
(
newFile
,
explorer
)
=>
{
if
(
explorer
===
files
)
{
fileFocus
(
newFile
)
}
else
{
unfocus
(
focusElement
)
if
(
self
.
focusElement
&&
explorer
.
type
!==
files
.
type
&&
self
.
focusPath
!==
newFile
)
{
self
.
focusElement
.
classList
.
remove
(
css
.
hasFocus
)
self
.
focusElement
=
null
self
.
focusPath
=
null
}
})
fileEvents
.
register
(
'fileRemoved'
,
fileRemoved
)
fileEvents
.
register
(
'fileRenamed'
,
fileRenamed
)
fileEvents
.
register
(
'fileRenamedError'
,
fileRenamedError
)
fileEvents
.
register
(
'fileAdded'
,
fileAdded
)
var
filepath
=
null
var
focusElement
=
null
var
textUnderEdit
=
null
var
textInRename
=
false
self
.
events
=
new
EventManager
()
self
.
api
=
{}
self
.
api
.
addFile
=
function
addFile
(
file
)
{
function
loadFile
()
{
var
fileReader
=
new
FileReader
()
fileReader
.
onload
=
function
(
event
)
{
if
(
helper
.
checkSpecialChars
(
file
.
name
))
{
modalDialogCustom
.
alert
(
'Special characters are not allowed'
)
return
}
var
success
=
files
.
set
(
name
,
event
.
target
.
result
)
if
(
!
success
)
modalDialogCustom
.
alert
(
'Failed to create file '
+
name
)
else
self
.
events
.
trigger
(
'focus'
,
[
name
])
}
fileReader
.
readAsText
(
file
)
}
var
name
=
files
.
type
+
'/'
+
file
.
name
if
(
!
files
.
exists
(
name
))
{
loadFile
()
}
else
{
modalDialogCustom
.
confirm
(
null
,
`The file
${
name
}
already exists! Would you like to overwrite it?`
,
()
=>
{
loadFile
()
})
}
}
function
focus
(
event
)
{
event
.
cancelBubble
=
true
var
li
=
this
if
(
focusElement
===
li
)
return
unfocus
(
focusElement
)
focusElement
=
li
focusElement
.
classList
.
toggle
(
css
.
hasFocus
)
var
label
=
getLabelFrom
(
li
)
var
filepath
=
label
.
dataset
.
path
var
isFile
=
label
.
className
.
indexOf
(
'file'
)
===
0
if
(
isFile
)
self
.
events
.
trigger
(
'focus'
,
[
filepath
])
}
function
unfocus
(
el
)
{
if
(
focusElement
)
focusElement
.
classList
.
toggle
(
css
.
hasFocus
)
focusElement
=
null
}
function
hover
(
event
)
{
var
path
=
this
.
querySelector
(
'label'
).
dataset
.
path
if
(
path
===
self
.
files
.
type
)
return
// can't delete the root node
if
(
event
.
type
===
'mouseout'
)
{
var
exitedTo
=
event
.
toElement
||
event
.
relatedTarget
if
(
this
.
contains
(
exitedTo
))
return
this
.
style
.
backgroundColor
=
''
this
.
style
.
paddingRight
=
'19px'
return
this
.
removeChild
(
deleteButton
)
}
this
.
style
.
backgroundColor
=
styles
.
leftPanel
.
backgroundColor_FileExplorer
this
.
style
.
paddingRight
=
'0px'
this
.
appendChild
(
deleteButton
)
}
function
getElement
(
path
)
{
var
label
=
self
.
element
.
querySelector
(
`label[data-path="
${
path
}
"]`
)
if
(
label
)
return
getLiFrom
(
label
)
}
function
deletePath
(
event
)
{
event
.
cancelBubble
=
true
var
span
=
this
var
li
=
span
.
parentElement
.
parentElement
var
label
=
getLabelFrom
(
li
)
var
path
=
label
.
dataset
.
path
var
isFolder
=
!!~
label
.
className
.
indexOf
(
'folder'
)
if
(
isFolder
)
path
+=
'/'
modalDialogCustom
.
confirm
(
null
,
`Do you really want to delete "
${
path
}
" ?`
,
()
=>
{
li
.
parentElement
.
removeChild
(
li
)
removeSubtree
(
files
,
path
,
isFolder
)
})
}
function
editModeOn
(
event
)
{
if
(
self
.
files
.
readonly
)
return
var
label
=
this
var
li
=
getLiFrom
(
label
)
var
li
=
label
.
parentElement
.
parentElement
.
parentElement
var
classes
=
li
.
className
if
(
~
classes
.
indexOf
(
'hasFocus'
)
&&
!
label
.
getAttribute
(
'contenteditable'
)
&&
label
.
getAttribute
(
'data-path'
)
!==
self
.
files
.
type
)
{
textUnderEdit
=
label
.
innerText
...
...
@@ -273,185 +243,38 @@ function fileExplorer (appAPI, files) {
}
}
function
cancelRename
()
{
label
.
innerText
=
textUnderEdit
}
if
(
event
.
which
===
13
)
event
.
preventDefault
()
if
(
!
textInRename
&&
(
event
.
type
===
'blur'
||
event
.
which
===
27
||
event
.
which
===
13
)
&&
label
.
getAttribute
(
'contenteditable'
))
{
textInRename
=
true
var
isFolder
=
label
.
className
.
indexOf
(
'folder'
)
!==
-
1
var
save
=
textUnderEdit
!==
label
.
innerText
if
(
save
)
{
modalDialogCustom
.
confirm
(
null
,
'Do you want to rename?'
,
()
=>
{
rename
()
},
()
=>
{
cancelRename
()
})
modalDialogCustom
.
confirm
(
null
,
'Do you want to rename?'
,
()
=>
{
rename
()
},
()
=>
{
label
.
innerText
=
textUnderEdit
})
}
label
.
removeAttribute
(
'contenteditable'
)
label
.
classList
.
remove
(
css
.
rename
)
textInRename
=
false
}
}
function
renameSubtree
(
label
,
dontcheck
)
{
var
oldPath
=
label
.
dataset
.
path
var
newPath
=
oldPath
newPath
=
newPath
.
split
(
'/'
)
newPath
[
newPath
.
length
-
1
]
=
label
.
innerText
newPath
=
newPath
.
join
(
'/'
)
if
(
!
dontcheck
)
{
var
allPaths
=
Object
.
keys
(
files
.
list
())
for
(
var
i
=
0
,
len
=
allPaths
.
length
,
path
,
err
;
i
<
len
;
i
++
)
{
path
=
allPaths
[
i
]
if
(
files
.
isReadOnly
(
path
))
{
err
=
'path contains readonly elements'
break
}
else
if
(
path
.
indexOf
(
newPath
)
===
0
)
{
err
=
'new path is conflicting with another existing path'
break
}
}
}
if
(
err
)
{
modalDialogCustom
.
alert
(
`could not rename -
${
err
}
`
)
label
.
innerText
=
textUnderEdit
}
else
{
textUnderEdit
=
label
.
innerText
updateAllLabels
([
getElement
(
oldPath
)],
oldPath
,
newPath
)
}
}
function
updateAllLabels
(
lis
,
oldPath
,
newPath
)
{
lis
.
forEach
(
function
(
li
)
{
var
label
=
getLabelFrom
(
li
)
var
path
=
label
.
dataset
.
path
var
newName
=
path
.
replace
(
oldPath
,
newPath
)
label
.
dataset
.
path
=
newName
var
ul
=
li
.
lastChild
if
(
ul
.
tagName
===
'UL'
)
{
updateAllLabels
([...
ul
.
children
],
oldPath
,
newPath
)
}
})
}
function
fileFocus
(
path
)
{
if
(
filepath
===
path
)
return
filepath
=
path
var
el
=
getElement
(
filepath
)
expandPathTo
(
el
)
setTimeout
(
function
focusNode
()
{
el
.
click
()
},
0
)
}
function
fileRemoved
(
filepath
)
{
// @TODO: only important if currently visible in TreeView
var
li
=
getElement
(
filepath
)
if
(
li
)
li
.
parentElement
.
removeChild
(
li
)
}
function
fileRenamed
(
oldName
,
newName
,
isFolder
)
{
// @TODO: only important if currently visible in TreeView
var
li
=
getElement
(
oldName
)
if
(
li
)
{
oldName
=
oldName
.
split
(
'/'
)
newName
=
newName
.
split
(
'/'
)
var
index
=
oldName
.
reduce
(
function
(
idx
,
key
,
i
)
{
return
oldName
[
i
]
!==
newName
[
i
]
?
i
:
idx
},
undefined
)
var
newKey
=
newName
[
index
]
var
oldPath
=
oldName
.
slice
(
0
,
index
+
1
).
join
(
'/'
)
li
=
getElement
(
oldPath
)
var
label
=
getLabelFrom
(
li
)
label
.
innerText
=
newKey
renameSubtree
(
label
,
true
)
}
}
function
fileRenamedError
(
error
)
{
modalDialogCustom
.
alert
(
error
)
}
function
fileAdded
(
filepath
)
{
// @TODO: only important if currently visible in TreeView
self
.
files
.
resolveDirectory
(
'./'
,
(
error
,
files
)
=>
{
if
(
error
)
console
.
error
(
error
)
var
element
=
self
.
treeView
.
render
(
files
)
element
.
className
=
css
.
fileexplorer
self
.
element
.
parentElement
.
replaceChild
(
element
,
self
.
element
)
self
.
element
=
element
})
}
}
/*
HELPER FUNCTIONS
*/
function
adaptEnvironment
(
label
,
focus
,
hover
)
{
var
li
=
getLiFrom
(
label
)
// @TODO: maybe this gets refactored?
li
.
style
.
position
=
'relative'
var
span
=
li
.
firstChild
// add focus
li
.
addEventListener
(
'click'
,
focus
)
// add hover
span
.
classList
.
add
(
css
.
activeMode
)
span
.
addEventListener
(
'mouseover'
,
hover
)
span
.
addEventListener
(
'mouseout'
,
hover
)
}
function
unadaptEnvironment
(
label
,
focus
,
hover
)
{
var
li
=
getLiFrom
(
label
)
// @TODO: maybe this gets refactored?
var
span
=
li
.
firstChild
li
.
style
.
position
=
undefined
// remove focus
li
.
removeEventListener
(
'click'
,
focus
)
// remove hover
span
.
classList
.
remove
(
css
.
activeMode
)
span
.
removeEventListener
(
'mouseover'
,
hover
)
span
.
removeEventListener
(
'mouseout'
,
hover
)
}
function
getLiFrom
(
label
)
{
return
label
.
parentElement
.
parentElement
.
parentElement
}
function
getLabelFrom
(
li
)
{
return
li
.
children
[
0
].
children
[
1
].
children
[
0
]
}
function
removeSubtree
(
files
,
path
,
isFolder
)
{
var
parts
=
path
.
split
(
'/'
)
var
isFile
=
parts
[
parts
.
length
-
1
].
length
var
removePaths
=
isFile
?
[
path
]
:
Object
.
keys
(
files
.
list
()).
filter
(
keep
)
function
keep
(
p
)
{
return
~
p
.
indexOf
(
path
)
}
removePaths
.
forEach
(
function
(
path
)
{
[...
window
.
files
.
querySelectorAll
(
'.file .name'
)].
forEach
(
function
(
span
)
{
if
(
span
.
innerText
===
path
)
{
var
li
=
span
.
parentElement
li
.
parentElement
.
removeChild
(
li
)
// delete tab
}
})
files
.
remove
(
path
)
})
if
(
isFolder
)
files
.
remove
(
path
)
}
function
expandPathTo
(
li
)
{
while
((
li
=
li
.
parentElement
.
parentElement
)
&&
li
.
tagName
===
'LI'
)
{
var
caret
=
li
.
firstChild
.
firstChild
if
(
caret
.
classList
.
contains
(
'fa-caret-right'
))
caret
.
click
()
// expand
}
fileExplorer
.
prototype
.
init
=
function
()
{
this
.
container
=
yo
`<div></div>`
return
this
.
container
}
fileExplorer
.
prototype
.
init
=
function
(
)
{
fileExplorer
.
prototype
.
ensureRoot
=
function
(
cb
)
{
var
self
=
this
if
(
self
.
element
&&
cb
)
return
cb
()
self
.
files
.
resolveDirectory
(
'/'
,
(
error
,
files
)
=>
{
if
(
error
)
console
.
error
(
error
)
var
element
=
self
.
treeView
.
render
(
files
)
var
element
=
self
.
treeView
.
render
(
files
,
false
)
element
.
className
=
css
.
fileexplorer
element
.
events
=
self
.
events
element
.
api
=
self
.
api
setTimeout
(
function
()
{
self
.
element
.
parentElement
.
replaceChild
(
element
,
self
.
element
)
self
.
container
.
appendChild
(
element
)
self
.
element
=
element
},
0
)
if
(
cb
)
cb
(
)
})
self
.
element
=
yo
`<div></div>`
return
self
.
element
}
src/app/files/fileManager.js
View file @
134245e0
...
...
@@ -47,6 +47,7 @@ class FileManager {
self
.
switchFile
(
Object
.
keys
(
self
.
tabbedFiles
)[
0
])
}
else
{
opt
.
editor
.
displayEmptyReadOnlySession
()
self
.
opt
.
config
.
set
(
'currentFile'
,
''
)
}
return
false
})
...
...
@@ -98,7 +99,6 @@ class FileManager {
// Display files that have already been selected
refreshTabs
(
newfile
)
{
var
self
=
this
if
(
newfile
)
{
this
.
tabbedFiles
[
newfile
]
=
newfile
}
...
...
@@ -109,29 +109,32 @@ class FileManager {
for
(
var
file
in
this
.
tabbedFiles
)
{
$filesEl
.
append
(
yo
`<li class="file"><span class="name">
${
file
}
</span><span class="remove"><i class="fa fa-close"></i></span></li>`
)
}
var
currentFileOpen
=
!!
this
.
opt
.
config
.
get
(
'currentFile'
)
if
(
currentFileOpen
)
{
var
active
=
$
(
'#files .file'
).
filter
(
function
()
{
return
$
(
this
).
find
(
'.name'
).
text
()
===
self
.
opt
.
config
.
get
(
'currentFile'
)
})
active
.
addClass
(
'active'
)
}
$
(
'#input'
).
toggle
(
currentFileOpen
)
$
(
'#output'
).
toggle
(
currentFileOpen
)
var
active
=
$
(
'#files .file'
).
filter
(
function
()
{
return
$
(
this
).
find
(
'.name'
).
text
()
===
newfile
})
if
(
active
.
length
)
active
.
addClass
(
'active'
)
else
this
.
switchFile
()
// $('#input').toggle(active)
$
(
'#output'
).
toggle
(
active
)
}
switchFile
(
file
)
{
var
self
=
this
if
(
!
file
)
{
self
.
opt
.
filesProviders
[
'browser'
].
resolveDirectory
(
'/'
,
(
error
,
filesTree
)
=>
{
if
(
file
)
return
_switchFile
(
file
)
else
{
var
browserProvider
=
self
.
opt
.
filesProviders
[
'browser'
]
browserProvider
.
resolveDirectory
(
'browser'
,
(
error
,
filesTree
)
=>
{
if
(
error
)
console
.
error
(
error
)
var
fileList
=
Object
.
keys
(
f
latten
(
filesTree
)
)
var
fileList
=
Object
.
keys
(
f
ilesTree
)
if
(
fileList
.
length
)
{
file
=
fileList
[
0
]
if
(
file
)
_switchFile
(
file
)
_switchFile
(
browserProvider
.
type
+
'/'
+
fileList
[
0
])
}
else
{
self
.
event
.
trigger
(
'currentFileChanged'
,
[])
}
})
}
else
_switchFile
(
file
)
function
_switchFile
()
{
}
function
_switchFile
(
file
)
{
self
.
saveCurrentFile
()
self
.
opt
.
config
.
set
(
'currentFile'
,
file
)
self
.
refreshTabs
(
file
)
...
...
@@ -179,23 +182,3 @@ class FileManager {
}
module
.
exports
=
FileManager
function
flatten
(
tree
)
{
var
flat
=
{}
var
names
=
Object
.
keys
(
tree
||
{})
if
(
!
names
.
length
)
return
else
{
names
.
forEach
(
name
=>
{
if
(
'/content'
in
tree
[
name
])
flat
[
name
]
=
false
else
{
var
subflat
=
flatten
(
tree
[
name
])
if
(
!
subflat
)
{
// empty folder
}
else
{
Object
.
keys
(
subflat
).
forEach
(
path
=>
{
flat
[
name
+
'/'
+
path
]
=
false
})
}
}
})
return
flat
}
}
src/app/files/shared-folder.js
View file @
134245e0
...
...
@@ -137,19 +137,6 @@ module.exports = class SharedFolder {
return
true
}
//
// Tree model for files
// {
// 'a': { }, // empty directory 'a'
// 'b': {
// 'c': {}, // empty directory 'b/c'
// 'd': { '/readonly': true, '/content': 'Hello World' } // files 'b/c/d'
// 'e': { '/readonly': false, '/path': 'b/c/d' } // symlink to 'b/c/d'
// 'f': { '/readonly': false, '/content': '<executable>', '/mode': 0755 }
// }
// }
//
removePrefix
(
path
)
{
path
=
path
.
indexOf
(
this
.
type
)
===
0
?
path
.
replace
(
this
.
type
,
''
)
:
path
if
(
path
[
0
]
===
'/'
)
return
path
.
substring
(
1
)
...
...
@@ -160,7 +147,7 @@ module.exports = class SharedFolder {
var
self
=
this
if
(
path
[
0
]
===
'/'
)
path
=
path
.
substring
(
1
)
if
(
!
path
)
return
callback
(
null
,
{
[
self
.
type
]:
{
}
})
path
=
self
.
removePrefix
(
''
+
(
path
||
''
)
)
path
=
self
.
removePrefix
(
path
)
self
.
remixd
.
dir
(
path
,
callback
)
}
}
...
...
src/app/panels/file-panel.js
View file @
134245e0
/* global FileReader */
var
async
=
require
(
'async'
)
var
$
=
require
(
'jquery'
)
var
yo
=
require
(
'yo-yo'
)
...
...
@@ -73,7 +74,7 @@ function filepanel (appAPI, filesProvider) {
</div>
<div class=
${
css
.
treeviews
}
>
<div class=
${
css
.
treeview
}
>
${
fileExplorer
.
init
()}
</div>
<div class="filesystemexplorer
${
css
.
treeview
}
"></div>
<div class="filesystemexplorer
${
css
.
treeview
}
">
${
fileSystemExplorer
.
init
()}
</div>
<div class="swarmexplorer
${
css
.
treeview
}
">
${
swarmExplorer
.
init
()}
</div>
<div class="githubexplorer
${
css
.
treeview
}
">
${
githubExplorer
.
init
()}
</div>
<div class="gistexplorer
${
css
.
treeview
}
">
${
gistExplorer
.
init
()}
</div>
...
...
@@ -87,7 +88,7 @@ function filepanel (appAPI, filesProvider) {
var
event
=
new
EventManager
()
self
.
event
=
event
var
element
=
template
()
fileExplorer
.
ensureRoot
()
var
containerFileSystem
=
element
.
querySelector
(
'.filesystemexplorer'
)
var
websocketconn
=
element
.
querySelector
(
'.websocketconn'
)
filesProvider
[
'localhost'
].
remixd
.
event
.
register
(
'connecting'
,
(
event
)
=>
{
...
...
@@ -143,7 +144,30 @@ function filepanel (appAPI, filesProvider) {
// the files module. Please ask the user here if they want to overwrite
// a file and then just use `files.add`. The file explorer will
// pick that up via the 'fileAdded' event from the files module.
;[...
this
.
files
].
forEach
(
fileExplorer
.
api
.
addFile
)
;[...
this
.
files
].
forEach
((
file
)
=>
{
var
files
=
fileExplorer
.
files
function
loadFile
()
{
var
fileReader
=
new
FileReader
()
fileReader
.
onload
=
function
(
event
)
{
if
(
helper
.
checkSpecialChars
(
file
.
name
))
{
modalDialogCustom
.
alert
(
'Special characters are not allowed'
)
return
}
var
success
=
files
.
set
(
name
,
event
.
target
.
result
)
if
(
!
success
)
modalDialogCustom
.
alert
(
'Failed to create file '
+
name
)
else
self
.
events
.
trigger
(
'focus'
,
[
name
])
}
fileReader
.
readAsText
(
file
)
}
var
name
=
files
.
type
+
'/'
+
file
.
name
if
(
!
files
.
exists
(
name
))
{
loadFile
()
}
else
{
modalDialogCustom
.
confirm
(
null
,
`The file
${
name
}
already exists! Would you like to overwrite it?`
,
()
=>
{
loadFile
()
})
}
})
}
// ----------------- resizeable ui ---------------
...
...
@@ -200,7 +224,6 @@ function filepanel (appAPI, filesProvider) {
* @param {String} txHash - hash of the transaction
*/
function
connectToLocalhost
()
{
var
container
=
document
.
querySelector
(
'.filesystemexplorer'
)
if
(
filesProvider
[
'localhost'
].
isConnected
())
{
filesProvider
[
'localhost'
].
close
((
error
)
=>
{
if
(
error
)
console
.
log
(
error
)
...
...
@@ -213,10 +236,7 @@ function filepanel (appAPI, filesProvider) {
if
(
error
)
{
console
.
log
(
error
)
}
else
{
if
(
fileSystemExplorer
.
element
&&
container
.
children
.
length
>
0
)
{
container
.
removeChild
(
fileSystemExplorer
.
element
)
}
container
.
appendChild
(
fileSystemExplorer
.
init
())
fileSystemExplorer
.
ensureRoot
()
}
})
}})
...
...
src/app/panels/styles/file-panel-styles.js
View file @
134245e0
...
...
@@ -77,7 +77,7 @@ var css = csjs`
}
.dragbar {
position : absolute;
top :
37
px;
top :
29
px;
width : 0.5em;
right : 0;
bottom : 0;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment