add support for large file hierarchies to file explorer

pull/1/head
serapath 7 years ago
parent 968f2bbaa0
commit 8b0702fab7
  1. 2
      src/app.js
  2. 26
      src/app/files/basicReadOnlyExplorer.js
  3. 34
      src/app/files/browser-files.js
  4. 51
      src/app/files/file-explorer.js
  5. 2
      src/app/files/fileManager.js
  6. 67
      src/app/files/shared-folder.js

@ -454,7 +454,7 @@ function run () {
// insert ballot contract if there are no files available
if (!loadingFromGist) {
filesProviders['browser'].resolveDirectory('', (error, filesList) => {
filesProviders['browser'].resolveDirectory('/', (error, filesList) => {
if (error) console.error(error)
if (Object.keys(filesList).length === 0) {
if (!filesProviders['browser'].set(examples.ballot.name, examples.ballot.content)) {

@ -81,7 +81,18 @@ class BasicReadOnlyExplorer {
// }
//
resolveDirectory (path, callback /* (error, filesList) => { } */) {
// path = '' + (path || '')
var self = this
if (path[0] === '/') path = path.substring(1)
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
@ -96,19 +107,6 @@ class BasicReadOnlyExplorer {
obj[nodes[i]] = val
}
var tree = {}
var self = this
// 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)
})
})
callback(null, tree)
}
removePrefix (path) {

@ -117,20 +117,10 @@ function Files (storage) {
//
this.resolveDirectory = function (path, callback) {
var self = this
// path = '' + (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
}
if (path[0] === '/') path = path.substring(1)
if (!path) return callback(null, { [self.type]: { } })
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
@ -142,16 +132,26 @@ function Files (storage) {
Object.keys(readonly).forEach((path) => {
filesList[self.type + '/' + path] = true
})
var tree = {}
// This does not include '.remix.config', because it is filtered
// inside list().
Object.keys(filesList).forEach(function (path) {
hashmapize(tree, path, {
'/readonly': self.isReadOnly(path),
'/content': self.get(path)
})
})
callback(null, tree)
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
}
}
this.removePrefix = function (path) {

@ -79,8 +79,9 @@ function fileExplorer (appAPI, files) {
})
var fileEvents = files.event
var treeView = new Treeview({
extractData: function (value, tree, key) {
self.treeView = new Treeview({
extractData: function extractData (value, tree, key) {
var newValue = {}
// var isReadOnly = false
var isFile = false
@ -99,8 +100,9 @@ function fileExplorer (appAPI, files) {
})) : undefined
}
},
formatSelf: function (key, data, li) {
var isRoot = data.path.indexOf('/') === -1
formatSelf: function formatSelf (key, data, li) {
var isRoot = !data.path.indexOf('browser') && data.path.length === 'browser'.length
isRoot = isRoot || !data.path.indexOf('localhost') && data.path.length === 'localhost'.length
return yo`<label class="${data.children ? css.folder : css.file}"
data-path="${data.path}"
style="${isRoot ? 'font-weight:bold;' : ''}"
@ -109,11 +111,33 @@ function fileExplorer (appAPI, files) {
onclick=${editModeOn}
onkeydown=${editModeOff}
onblur=${editModeOff}
>${key}</label>`
>${key.split('/').pop()}</label>`
}
})
self.treeView.event.register('nodeClick', function (path, childrenContainer) {
if (!childrenContainer) return
if (childrenContainer.style.display === 'none') {
childrenContainer.innerHTML = ''
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)
})
})
this.treeView = treeView
function normalize (path, filesList) {
var prefix = path.split('/')[0]
var newList = {}
Object.keys(filesList).forEach(key => {
newList[prefix + '/' + key] = filesList[key].isDirectory ? {} : { '/content': true }
})
return newList
}
var deleteButton = yo`
<span class=${css.remove} onclick=${deletePath}>
@ -138,10 +162,9 @@ function fileExplorer (appAPI, files) {
var textUnderEdit = null
var textInRename = false
var events = new EventManager()
this.events = events
var api = {}
api.addFile = function addFile (file) {
self.events = new EventManager()
self.api = {}
self.api.addFile = function addFile (file) {
function loadFile () {
var fileReader = new FileReader()
fileReader.onload = function (event) {
@ -151,7 +174,7 @@ function fileExplorer (appAPI, files) {
}
var success = files.set(name, event.target.result)
if (!success) modalDialogCustom.alert('Failed to create file ' + name)
else events.trigger('focus', [name])
else self.events.trigger('focus', [name])
}
fileReader.readAsText(file)
}
@ -163,7 +186,6 @@ function fileExplorer (appAPI, files) {
modalDialogCustom.confirm(null, `The file ${name} already exists! Would you like to overwrite it?`, () => { loadFile() })
}
}
this.api = api
function focus (event) {
event.cancelBubble = true
@ -175,7 +197,7 @@ function fileExplorer (appAPI, files) {
var label = getLabelFrom(li)
var filepath = label.dataset.path
var isFile = label.className.indexOf('file') === 0
if (isFile) events.trigger('focus', [filepath])
if (isFile) self.events.trigger('focus', [filepath])
}
function unfocus (el) {
@ -320,11 +342,13 @@ function fileExplorer (appAPI, files) {
}
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('/')
@ -346,6 +370,7 @@ function fileExplorer (appAPI, files) {
}
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)

@ -122,7 +122,7 @@ class FileManager {
switchFile (file) {
var self = this
if (!file) {
self.opt.filesProviders['browser'].resolveDirectory('', (error, filesTree) => {
self.opt.filesProviders['browser'].resolveDirectory('/', (error, filesTree) => {
if (error) console.error(error)
var fileList = Object.keys(flatten(filesTree))
if (fileList.length) {

@ -2,52 +2,6 @@
var EventManager = require('remix-lib').EventManager
var pathtool = require('path')
function buildList (self, path = '', callback) {
path = '' + (path || '')
self.remixd.dir(path, (error, filesList) => {
if (error) console.error(error)
var list = Object.keys(filesList)
var counter = list.length
var fileTree = {}
if (!counter) callback(null, fileTree)
for (var i = 0, name, len = counter; i < len; i++) {
name = list[i]
self.files[path] = path
if (filesList[name].isDirectory) {
setFolder(self, path, name, fileTree, finish)
} else {
setFileContent(self, path, name, fileTree, finish)
}
}
function finish (error) {
if (error) console.error(error)
counter--
if (!counter) callback(null, fileTree)
}
})
}
function setFolder (self, path, name, fileTree, done) {
buildList(self, name, (error, subFileTree) => {
if (error) console.error(error)
name = name.replace(path, '')
if (name[0] === '/') name = name.substring(1)
fileTree[name] = subFileTree
done(null)
})
}
function setFileContent (self, path, name, fileTree, done) {
self.remixd.read(name, (error, result) => {
if (error) console.error(error)
name = name.replace(path, '')
if (name[0] === '/') name = name.substring(1)
fileTree[name] = {
'/content': result.content,
'/readonly': result.readonly
}
done(null)
})
}
module.exports = class SharedFolder {
constructor (remixd) {
this.event = new EventManager()
@ -195,18 +149,19 @@ module.exports = class SharedFolder {
// }
// }
//
resolveDirectory (path, callback) {
var self = this
path = '' + (path || '')
path = pathtool.join('./', path)
buildList(self, path, (error, fileTree) => {
if (error) return callback(error)
callback(null, { [self.type]: fileTree })
})
}
removePrefix (path) {
return path.indexOf(this.type + '/') === 0 ? path.replace(this.type + '/', '') : path
path = path.indexOf(this.type) === 0 ? path.replace(this.type, '') : path
if (path[0] === '/') return path.substring(1)
return path
}
resolveDirectory (path, callback) {
var self = this
if (path[0] === '/') path = path.substring(1)
if (!path) return callback(null, { [self.type]: { } })
path = self.removePrefix('' + (path || ''))
self.remixd.dir(path, callback)
}
}

Loading…
Cancel
Save