only 2 explorers - browser and localhost

pull/1/head
yann300 5 years ago
parent 6ba69c9d46
commit fa33283e33
  1. 8
      assets/js/browserfs.min.js
  2. 14
      index.html
  3. 31
      src/app.js
  4. 119
      src/app/files/basicFileProvider.js
  5. 9
      src/app/files/compiler-metadata.js
  6. 39
      src/app/files/file-explorer.js
  7. 17
      src/app/files/fileManager.js
  8. 139
      src/app/files/filePovider.js
  9. 138
      src/app/files/fileProvider.js
  10. 29
      src/app/files/fileProviderBase.js
  11. 148
      src/app/files/localStorageProvider.js
  12. 18
      src/app/files/readonlyProvider.js
  13. 16
      src/app/panels/file-panel.js
  14. 13
      src/app/tabs/compile-tab.js
  15. 8
      src/app/tabs/compileTab/compileTab.js
  16. 8
      src/lib/gist-handler.js
  17. 2
      src/lib/helper.js
  18. 4
      test-browser/commands/switchFile.js
  19. 4
      test-browser/tests/libraryDeployment.js

File diff suppressed because one or more lines are too long

@ -31,6 +31,7 @@
<link rel="stylesheet" id="theme-link"/> <link rel="stylesheet" id="theme-link"/>
<link rel="stylesheet" href="assets/css/pygment_trac.css"> <link rel="stylesheet" href="assets/css/pygment_trac.css">
<link rel="icon" type="x-icon" href="icon.png"> <link rel="icon" type="x-icon" href="icon.png">
<script src="assets/js/browserfs.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
</head> </head>
<body> <body>
@ -76,9 +77,16 @@
document.head.appendChild(app) document.head.appendChild(app)
} }
window.onload = () => { window.onload = () => {
let app = document.createElement('script') BrowserFS.install(window)
app.setAttribute('src', versions[versionToLoad]) BrowserFS.configure({
document.body.appendChild(app) fs: "LocalStorage"
}, function(e) {
if (e) console.log(e)
let app = document.createElement('script')
app.setAttribute('src', versions[versionToLoad])
document.body.appendChild(app)
window.remixFileSystem = require('fs')
})
} }
</script> </script>
</body> </body>

@ -12,15 +12,13 @@ var { OffsetToLineColumnConverter } = require('./lib/offsetToLineColumnConverter
var QueryParams = require('./lib/query-params') var QueryParams = require('./lib/query-params')
var GistHandler = require('./lib/gist-handler') var GistHandler = require('./lib/gist-handler')
var Storage = remixLib.Storage var Storage = remixLib.Storage
var LocalStorageProvider = require('./app/files/localStorageProvider')
var RemixDProvider = require('./app/files/remixDProvider') var RemixDProvider = require('./app/files/remixDProvider')
var Config = require('./config') var Config = require('./config')
var Renderer = require('./app/ui/renderer') var Renderer = require('./app/ui/renderer')
var examples = require('./app/editor/example-contracts') var examples = require('./app/editor/example-contracts')
var modalDialogCustom = require('./app/ui/modal-dialog-custom') var modalDialogCustom = require('./app/ui/modal-dialog-custom')
var FileManager = require('./app/files/fileManager') var FileManager = require('./app/files/fileManager')
var ReadonlyProvider = require('./app/files/readonlyProvider') var FileProvider = require('./app/files/fileProvider')
var BasicFileProvider = require('./app/files/basicFileProvider')
var toolTip = require('./app/ui/tooltip') var toolTip = require('./app/ui/tooltip')
var CompilerMetadata = require('./app/files/compiler-metadata') var CompilerMetadata = require('./app/files/compiler-metadata')
var CompilerImport = require('./app/compiler/compiler-imports') var CompilerImport = require('./app/compiler/compiler-imports')
@ -113,7 +111,7 @@ class App {
// load file system // load file system
self._components.filesProviders = {} self._components.filesProviders = {}
self._components.filesProviders['browser'] = new LocalStorageProvider(fileStorage) self._components.filesProviders['browser'] = new FileProvider('browser', fileStorage)
registry.put({api: self._components.filesProviders['browser'], name: 'fileproviders/browser'}) registry.put({api: self._components.filesProviders['browser'], name: 'fileproviders/browser'})
var remixd = new Remixd(65520) var remixd = new Remixd(65520)
@ -123,17 +121,7 @@ class App {
}) })
self._components.filesProviders['localhost'] = new RemixDProvider(remixd) self._components.filesProviders['localhost'] = new RemixDProvider(remixd)
self._components.filesProviders['swarm'] = new ReadonlyProvider('swarm')
self._components.filesProviders['github'] = new ReadonlyProvider('github')
self._components.filesProviders['gist'] = new BasicFileProvider('gist')
self._components.filesProviders['ipfs'] = new ReadonlyProvider('ipfs')
self._components.filesProviders['https'] = new ReadonlyProvider('https')
self._components.filesProviders['http'] = new ReadonlyProvider('http')
registry.put({api: self._components.filesProviders['localhost'], name: 'fileproviders/localhost'}) registry.put({api: self._components.filesProviders['localhost'], name: 'fileproviders/localhost'})
registry.put({api: self._components.filesProviders['swarm'], name: 'fileproviders/swarm'})
registry.put({api: self._components.filesProviders['github'], name: 'fileproviders/github'})
registry.put({api: self._components.filesProviders['gist'], name: 'fileproviders/gist'})
registry.put({api: self._components.filesProviders['ipfs'], name: 'fileproviders/ipfs'})
registry.put({api: self._components.filesProviders, name: 'fileproviders'}) registry.put({api: self._components.filesProviders, name: 'fileproviders'})
self._view = {} self._view = {}
@ -297,10 +285,8 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
editor, editor,
registry.get('config').api, registry.get('config').api,
new Renderer(), new Renderer(),
registry.get('fileproviders/swarm').api, registry.get('fileproviders/browser').api,
registry.get('fileproviders/ipfs').api, registry.get('filemanager').api
registry.get('filemanager').api,
registry.get('fileproviders').api,
) )
const run = new RunTab( const run = new RunTab(
udapp, udapp,
@ -352,14 +338,11 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
const loadedFromGist = gistHandler.loadFromGist(queryParams.get(), fileManager) const loadedFromGist = gistHandler.loadFromGist(queryParams.get(), fileManager)
if (!loadedFromGist) { if (!loadedFromGist) {
// insert ballot contract if there are no files to show // insert ballot contract if there are no files to show
self._components.filesProviders['browser'].resolveDirectory('browser', (error, filesList) => { self._components.filesProviders['browser'].resolveDirectory('/', (error, filesList) => {
if (error) console.error(error) if (error) console.error(error)
if (Object.keys(filesList).length === 0) { if (Object.keys(filesList).length === 0) {
if (!self._components.filesProviders['browser'].set(examples.ballot.name, examples.ballot.content)) { fileManager.setFile(examples.ballot.name, examples.ballot.content)
modalDialogCustom.alert('Failed to store example contract in browser. Remix will not work properly. Please ensure Remix has access to LocalStorage. Safari in Private mode is known not to work.') fileManager.setFile(examples.ballot_test.name, examples.ballot_test.content)
} else {
self._components.filesProviders['browser'].set(examples.ballot_test.name, examples.ballot_test.content)
}
} }
}) })
} }

@ -1,119 +0,0 @@
'use strict'
const EventManager = require('../../lib/events')
const toolTip = require('../ui/tooltip')
class BasicFileProvider {
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
}
close (cb) {
this.files = {}
cb()
}
init (cb) {
this.files = {}
}
exists (path, cb) {
if (!this.files) return cb(null, false)
var unprefixedPath = this.removePrefix(path)
cb(null, this.files[unprefixedPath] !== undefined)
}
get (path, cb) {
if (this.normalizedNames[path]) path = this.normalizedNames[path] // ensure we actually use the normalized path from here
var unprefixedPath = this.removePrefix(path)
var content = this.files[unprefixedPath]
if (!content) {
content = this.files[this.type + '/' + this.normalizedNames[path]]
}
if (cb) {
cb(null, content)
}
return content
}
set (path, content, cb) {
this.addReadOnly(path, content)
if (cb) cb()
return true
}
addReadOnly (path, content, rawPath) {
path = this.removePrefix(path)
try { // lazy try to format JSON
content = JSON.stringify(JSON.parse(content), null, '\t')
} catch (e) {}
if (!rawPath) rawPath = path
// 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 + '/' + path, true])
return true
}
remove (path) {
var unprefixedPath = this.removePrefix(path)
var folderPath = path.substring(0, path.lastIndexOf('/'))
if (this.paths[folderPath]) {
delete this.paths[folderPath][unprefixedPath]
delete this.files[path]
}
this.event.trigger('fileRemoved', [this.type + '/' + unprefixedPath])
return true
}
rename (oldPath, newPath, isFolder) {
if (isFolder) { return toolTip('folder renaming is not handled by this explorer') }
var unprefixedoldPath = this.removePrefix(oldPath)
var unprefixednewPath = this.removePrefix(newPath)
this.get(oldPath, (error, content) => {
if (error) return console.log(error)
this.remove(oldPath)
this.set(newPath, content)
this.event.trigger('fileRenamed', [this.type + '/' + unprefixedoldPath, this.type + '/' + unprefixednewPath, isFolder])
})
}
isReadOnly (path) {
return false
}
list () {
return this.files
}
resolveDirectory (path, callback) {
var self = this
if (path[0] === '/') path = path.substring(1)
if (!path) return callback(null, { [self.type]: { } })
// we just return the json tree populated by `addReadOnly`
callback(null, this.paths[path])
}
removePrefix (path) {
return path.indexOf(this.type + '/') === 0 ? path.replace(this.type + '/', '') : path
}
}
module.exports = BasicFileProvider

@ -18,6 +18,11 @@ class CompilerMetadata extends Plugin {
self.fileManager = fileManager self.fileManager = fileManager
self.config = config self.config = config
self.networks = ['VM:-', 'main:1', 'ropsten:3', 'rinkeby:4', 'kovan:42', 'görli:5', 'Custom'] self.networks = ['VM:-', 'main:1', 'ropsten:3', 'rinkeby:4', 'kovan:42', 'görli:5', 'Custom']
self.innerPath = 'artifacts'
}
_JSONFileName (path, contractName) {
return path + '/' + this.innerPath + '/' + contractName + '.json'
} }
onActivation () { onActivation () {
@ -31,7 +36,7 @@ class CompilerMetadata extends Plugin {
compiler.visitContracts((contract) => { compiler.visitContracts((contract) => {
if (contract.file !== source.target) return if (contract.file !== source.target) return
var fileName = path + '/' + contract.name + '.json' var fileName = self._JSONFileName(path, contract.name)
provider.get(fileName, (error, content) => { provider.get(fileName, (error, content) => {
if (!error) { if (!error) {
content = content || '{}' content = content || '{}'
@ -96,7 +101,7 @@ class CompilerMetadata extends Plugin {
if (err) { if (err) {
console.log(err) console.log(err)
} else { } else {
var fileName = path + '/' + contractName + '.json' var fileName = self._JSONFileName(path, contractName)
provider.get(fileName, (error, content) => { provider.get(fileName, (error, content) => {
if (error) return reject(error) if (error) return reject(error)
if (!content) return resolve() if (!content) return resolve()

@ -97,6 +97,7 @@ function fileExplorer (localRegistry, files, menuItems) {
files.event.register('fileRenamed', fileRenamed) files.event.register('fileRenamed', fileRenamed)
files.event.register('fileRenamedError', fileRenamedError) files.event.register('fileRenamedError', fileRenamedError)
files.event.register('fileAdded', fileAdded) files.event.register('fileAdded', fileAdded)
files.event.register('folderAdded', folderAdded)
function fileRenamedError (error) { function fileRenamedError (error) {
modalDialogCustom.alert(error) modalDialogCustom.alert(error)
@ -124,6 +125,18 @@ function fileExplorer (localRegistry, files, menuItems) {
}) })
} }
function folderAdded (folderpath) {
self.ensureRoot(() => {
folderpath = folderpath.split('/').slice(0, -1).join('/')
self.files.resolveDirectory(folderpath, (error, fileTree) => {
if (error) console.error(error)
if (!fileTree) return
fileTree = normalize(folderpath, fileTree)
self.treeView.updateNodeFromJSON(folderpath, fileTree, true)
})
})
}
function fileRemoved (filepath) { function fileRemoved (filepath) {
var label = self.treeView.labelAt(filepath) var label = self.treeView.labelAt(filepath)
if (label && label.parentElement) { if (label && label.parentElement) {
@ -462,7 +475,7 @@ fileExplorer.prototype.toGist = function (id) {
// return all the files, except the temporary/readonly ones.. // return all the files, except the temporary/readonly ones..
fileExplorer.prototype.packageFiles = function (filesProvider, callback) { fileExplorer.prototype.packageFiles = function (filesProvider, callback) {
var ret = {} var ret = {}
filesProvider.resolveDirectory(filesProvider.type, (error, files) => { filesProvider.resolveDirectory('/', (error, files) => {
if (error) callback(error) if (error) callback(error)
else { else {
async.eachSeries(Object.keys(files), (path, cb) => { async.eachSeries(Object.keys(files), (path, cb) => {
@ -525,7 +538,7 @@ fileExplorer.prototype.updateGist = function () {
fileExplorer.prototype.createNewFile = function () { fileExplorer.prototype.createNewFile = function () {
let self = this let self = this
modalDialogCustom.prompt('Create new file', 'File Name', 'Untitled.sol', (input) => { modalDialogCustom.prompt('Create new file', 'File Path (Untitled.sol, Folder1/Untitled.sol)', 'Untitled.sol', (input) => {
helper.createNonClashingName(input, self.files, (error, newName) => { helper.createNonClashingName(input, self.files, (error, newName) => {
if (error) return modalDialogCustom.alert('Failed to create file ' + newName + ' ' + error) if (error) return modalDialogCustom.alert('Failed to create file ' + newName + ' ' + error)
if (!self.files.set(newName, '')) { if (!self.files.set(newName, '')) {
@ -568,18 +581,16 @@ fileExplorer.prototype.ensureRoot = function (cb) {
cb = cb || (() => {}) cb = cb || (() => {})
var self = this var self = this
if (self.element) return cb() if (self.element) return cb()
const root = {}
self.files.resolveDirectory('/', (error, files) => { root[this.files.type] = {}
if (error) console.error(error) var element = self.treeView.render(root, false)
var element = self.treeView.render(files, false) element.classList.add(css.fileexplorer)
element.classList.add(css.fileexplorer) element.events = self.events
element.events = self.events element.api = self.api
element.api = self.api self.container.appendChild(element)
self.container.appendChild(element) self.element = element
self.element = element if (cb) cb()
if (cb) cb() self.treeView.expand(self.files.type)
self.treeView.expand(self.files.type)
})
} }
function normalize (path, filesList) { function normalize (path, filesList) {

@ -47,16 +47,13 @@ class FileManager extends Plugin {
config: this._components.registry.get('config').api, config: this._components.registry.get('config').api,
browserExplorer: this._components.registry.get('fileproviders/browser').api, browserExplorer: this._components.registry.get('fileproviders/browser').api,
localhostExplorer: this._components.registry.get('fileproviders/localhost').api, localhostExplorer: this._components.registry.get('fileproviders/localhost').api,
gistExplorer: this._components.registry.get('fileproviders/gist').api,
filesProviders: this._components.registry.get('fileproviders').api filesProviders: this._components.registry.get('fileproviders').api
} }
this._deps.browserExplorer.event.register('fileRenamed', (oldName, newName, isFolder) => { this.fileRenamedEvent(oldName, newName, isFolder) }) this._deps.browserExplorer.event.register('fileRenamed', (oldName, newName, isFolder) => { this.fileRenamedEvent(oldName, newName, isFolder) })
this._deps.localhostExplorer.event.register('fileRenamed', (oldName, newName, isFolder) => { this.fileRenamedEvent(oldName, newName, isFolder) }) this._deps.localhostExplorer.event.register('fileRenamed', (oldName, newName, isFolder) => { this.fileRenamedEvent(oldName, newName, isFolder) })
this._deps.gistExplorer.event.register('fileRenamed', (oldName, newName, isFolder) => { this.fileRenamedEvent(oldName, newName, isFolder) })
this._deps.browserExplorer.event.register('fileRemoved', (path) => { this.fileRemovedEvent(path) }) this._deps.browserExplorer.event.register('fileRemoved', (path) => { this.fileRemovedEvent(path) })
this._deps.localhostExplorer.event.register('fileRemoved', (path) => { this.fileRemovedEvent(path) }) this._deps.localhostExplorer.event.register('fileRemoved', (path) => { this.fileRemovedEvent(path) })
this._deps.gistExplorer.event.register('fileRemoved', (path) => { this.fileRemovedEvent(path) })
this._deps.localhostExplorer.event.register('errored', (event) => { this.removeTabsOf(this._deps.localhostExplorer) }) this._deps.localhostExplorer.event.register('errored', (event) => { this.removeTabsOf(this._deps.localhostExplorer) })
this._deps.localhostExplorer.event.register('closed', (event) => { this.removeTabsOf(this._deps.localhostExplorer) }) this._deps.localhostExplorer.event.register('closed', (event) => { this.removeTabsOf(this._deps.localhostExplorer) })
} }
@ -309,18 +306,10 @@ class FileManager extends Plugin {
} }
fileProviderOf (file) { fileProviderOf (file) {
if (!file) return null if (file.indexOf('localhost') === 0) {
var provider = file.match(/[^/]*/) return this._deps.filesProviders['localhost']
if (provider !== null && this._deps.filesProviders[provider[0]]) {
return this._deps.filesProviders[provider[0]]
} else {
for (var handler of this._components.compilerImport.handlers()) {
if (handler.match.exec(file)) {
return this._deps.filesProviders[handler.type]
}
}
} }
return null return this._deps.filesProviders['browser']
} }
saveCurrentFile () { saveCurrentFile () {

@ -1,139 +0,0 @@
'use strict'
var EventManager = require('../../lib/events')
class FileProvider {
constructor (name, storage) {
this.event = new EventManager()
this.storage = storage
this.type = name
this.structFile = '.' + name + '.tree'
this.tree = {}
}
exists (path, cb) {
cb(null, this._exists(path))
}
updateRefs (path, type) {
var split = path.split('/') // this should be unprefixed path
var crawlpath = this.tree
var intermediatePath = ''
split.forEach((pathPart, index) => {
intermediatePath += pathPart
if (!crawlpath[pathPart]) crawlpath[intermediatePath] = {}
if (index < split.length - 1) {
crawlpath = crawlpath[intermediatePath]
intermediatePath += '/'
} else if (type === 'add') {
crawlpath[intermediatePath] = path
} else if (type === 'remove' && crawlpath[intermediatePath]) {
delete crawlpath[intermediatePath]
}
})
this.storage.set(this.structFile, JSON.stringify(this.tree))
}
_exists (path) {
var unprefixedpath = this.removePrefix(path)
return this.storage.exists(unprefixedpath)
}
init (cb) {
var tree = this.storage.get(this.structFile)
this.tree = tree ? JSON.parse(tree) : {}
if (cb) cb()
}
get (path, cb) {
var unprefixedpath = this.removePrefix(path)
var content = this.storage.get(unprefixedpath)
if (cb) {
cb(null, content)
}
return content
}
set (path, content, cb) {
var unprefixedpath = this.removePrefix(path)
this.updateRefs(unprefixedpath, 'add')
var exists = this.storage.exists(unprefixedpath)
if (!this.storage.set(unprefixedpath, content)) {
if (cb) cb('error updating ' + path)
return false
}
if (!exists) {
this.event.trigger('fileAdded', [this.type + '/' + unprefixedpath, false])
} else {
this.event.trigger('fileChanged', [this.type + '/' + unprefixedpath])
}
if (cb) cb()
return true
}
addReadOnly (path, content) {
return this.set(path, content)
}
isReadOnly (path) {
return false
}
remove (path) {
var unprefixedpath = this.removePrefix(path)
this.updateRefs(unprefixedpath, 'remove')
if (!this._exists(unprefixedpath)) {
return false
}
if (!this.storage.remove(unprefixedpath)) {
return false
}
this.event.trigger('fileRemoved', [this.type + '/' + unprefixedpath])
return true
}
rename (oldPath, newPath, isFolder) {
var unprefixedoldPath = this.removePrefix(oldPath)
var unprefixednewPath = this.removePrefix(newPath)
this.updateRefs(unprefixedoldPath, 'remove')
this.updateRefs(unprefixednewPath, 'add')
if (this.storage.exists(unprefixedoldPath)) {
if (!this.storage.rename(unprefixedoldPath, unprefixednewPath)) {
return false
}
this.event.trigger('fileRenamed', [
this.type + '/' + unprefixedoldPath,
this.type + '/' + unprefixednewPath,
isFolder
])
return true
}
return false
}
resolveDirectory (path, callback) {
if (path[0] === '/') path = path.substring(1)
if (!path) return callback(null, { [this.type]: {} })
var tree = {}
path = this.removePrefix(path)
var split = path.split('/') // this should be unprefixed path
var crawlpath = this.tree
split.forEach((pathPart, index) => {
if (crawlpath[pathPart]) crawlpath = crawlpath[pathPart]
})
for (var item in crawlpath) {
tree[item] = { isDirectory: typeof crawlpath[item] !== 'string' }
}
callback(null, tree)
}
removePrefix (path) {
path = path.indexOf(this.type) === 0 ? path.replace(this.type, '') : path
if (path[0] === '/') return path.substring(1)
return path
}
}
module.exports = FileProvider

@ -0,0 +1,138 @@
'use strict'
var EventManager = require('../../lib/events')
class FileProvider {
constructor (name) {
this.event = new EventManager()
this.type = name
}
exists (path, cb) {
cb(null, this._exists(path))
}
_exists (path) {
var unprefixedpath = this.removePrefix(path)
return window.remixFileSystem.existsSync(unprefixedpath)
}
init (cb) {
cb()
}
get (path, cb) {
cb = cb || function () {}
var unprefixedpath = this.removePrefix(path)
var exists = window.remixFileSystem.existsSync(unprefixedpath)
if (!exists) return cb(null, null)
window.remixFileSystem.readFile(unprefixedpath, 'utf8', (err, content) => {
cb(err, content)
})
}
set (path, content, cb) {
cb = cb || function () {}
var unprefixedpath = this.removePrefix(path)
var exists = window.remixFileSystem.existsSync(unprefixedpath)
if (!exists && unprefixedpath.indexOf('/') !== -1) {
const paths = unprefixedpath.split('/')
paths.pop() // last element should the filename
if (paths.length && paths[0] === '') paths.shift()
let currentCheck = ''
paths.forEach((value) => {
currentCheck = currentCheck + '/' + value
if (!window.remixFileSystem.existsSync(currentCheck)) {
window.remixFileSystem.mkdirSync(currentCheck)
this.event.trigger('folderAdded', [this._normalizePath(currentCheck)])
}
})
}
try {
window.remixFileSystem.writeFileSync(unprefixedpath, content)
} catch (e) {
cb(e)
return false
}
if (!exists) {
this.event.trigger('fileAdded', [this._normalizePath(unprefixedpath), false])
} else {
this.event.trigger('fileChanged', [this._normalizePath(unprefixedpath)])
}
cb()
return true
}
addReadOnly (path, content) {
return this.set(path, content)
}
isReadOnly (path) {
return false
}
remove (path) {
var unprefixedpath = this.removePrefix(path)
if (!this._exists(unprefixedpath)) {
return false
}
const stat = window.remixFileSystem.statSync(unprefixedpath)
try {
if (stat.isDirectory()) {
window.remixFileSystem.rmdirSync(unprefixedpath, console.log)
} else {
window.remixFileSystem.unlinkSync(unprefixedpath, console.log)
}
this.event.trigger('fileRemoved', [this._normalizePath(unprefixedpath)])
return true
} catch (e) {
console.log(e)
return false
}
}
rename (oldPath, newPath, isFolder) {
var unprefixedoldPath = this.removePrefix(oldPath)
var unprefixednewPath = this.removePrefix(newPath)
if (this._exists(unprefixedoldPath)) {
window.remixFileSystem.renameSync(unprefixedoldPath, unprefixednewPath)
this.event.trigger('fileRenamed', [
this._normalizePath(unprefixedoldPath),
this._normalizePath(unprefixednewPath),
isFolder
])
return true
}
return false
}
resolveDirectory (path, callback) {
if (!path) return callback(null, { [this.type]: {} })
path = this.removePrefix(path)
if (path.indexOf('/') !== 0) path = '/' + path
window.remixFileSystem.readdir(path, (error, files) => {
var ret = {}
if (files) {
files.forEach(element => {
const absPath = (path === '/' ? '' : path) + '/' + element
ret[absPath.indexOf('/') === 0 ? absPath.replace('/', '') : absPath] = { isDirectory: window.remixFileSystem.statSync(absPath).isDirectory() }
// ^ ret does not accept path starting with '/'
})
}
callback(error, ret)
})
}
removePrefix (path) {
path = path.indexOf(this.type) === 0 ? path.replace(this.type, '') : path
return path
}
_normalizePath (path) {
if (path.indexOf('/') !== 0) path = '/' + path
return this.type + path
}
}
module.exports = FileProvider

@ -1,29 +0,0 @@
'use strict'
class FileProvider {
exists (path, cb) { throw new Error(this.name + ' function is not implemented for ' + this.constructor.name + ' class') }
init (cb) { throw new Error(this.name + ' function is not implemented for ' + this.constructor.name + ' class') }
get (path, cb) { throw new Error(this.name + ' function is not implemented for ' + this.constructor.name + ' class') }
set (path, content, cb) { throw new Error(this.name + ' function is not implemented for ' + this.constructor.name + ' class') }
addReadOnly (path, content) { throw new Error(this.name + ' function is not implemented for ' + this.constructor.name + ' class') }
isReadOnly (path) { throw new Error(this.name + ' function is not implemented for ' + this.constructor.name + ' class') }
remove (path) { throw new Error(this.name + ' function is not implemented for ' + this.constructor.name + ' class') }
rename (oldPath, newPath, isFolder) { throw new Error(this.name + ' function is not implemented for ' + this.constructor.name + ' class') }
resolveDirectory (path, callback) { throw new Error(this.name + ' function is not implemented for ' + this.constructor.name + ' class') }
removePrefix (path) { throw new Error(this.name + ' function is not implemented for ' + this.constructor.name + ' class') }
updateRefs (path, type) { throw new Error(this.name + ' function is not implemented for ' + this.constructor.name + ' class') }
}
module.exports = FileProvider

@ -1,148 +0,0 @@
'use strict'
var EventManager = require('../../lib/events')
function LocalStorageProvider (storage) {
var event = new EventManager()
this.event = event
var readonly = {}
this.type = 'browser'
this.exists = function (path, cb) {
cb(null, this._exists(path))
}
this._exists = function (path) {
var unprefixedpath = this.removePrefix(path)
// NOTE: ignore the config file
if (path === '.remix.config') return false
return this.isReadOnly(unprefixedpath) || storage.exists(unprefixedpath)
}
this.init = function (cb) {
cb()
}
this.get = function (path, cb) {
var unprefixedpath = this.removePrefix(path)
// NOTE: ignore the config file
if (path === '.remix.config') {
return null
}
var content = readonly[unprefixedpath] || storage.get(unprefixedpath)
if (cb) {
cb(null, content)
}
return content
}
this.set = function (path, content, cb) {
var unprefixedpath = this.removePrefix(path)
// NOTE: ignore the config file
if (path === '.remix.config') {
if (cb) cb('change not allowed')
return false
}
if (!this.isReadOnly(unprefixedpath)) {
var exists = storage.exists(unprefixedpath)
if (!storage.set(unprefixedpath, content)) {
if (cb) cb('error updating ' + path)
return false
}
if (!exists) {
event.trigger('fileAdded', [this.type + '/' + unprefixedpath, false])
} else {
event.trigger('fileChanged', [this.type + '/' + unprefixedpath])
}
if (cb) cb()
return true
}
if (cb) cb('is read only')
return false
}
this.addReadOnly = function (path, content) {
var unprefixedpath = this.removePrefix(path)
if (!storage.exists(unprefixedpath)) {
readonly[unprefixedpath] = content
event.trigger('fileAdded', [this.type + '/' + unprefixedpath, true])
return true
}
return false
}
this.isReadOnly = function (path) {
path = this.removePrefix(path)
return readonly[path] !== undefined
}
this.remove = function (path) {
var unprefixedpath = this.removePrefix(path)
if (!this._exists(unprefixedpath)) {
return false
}
if (this.isReadOnly(unprefixedpath)) {
readonly[unprefixedpath] = undefined
} else {
if (!storage.remove(unprefixedpath)) {
return false
}
}
event.trigger('fileRemoved', [this.type + '/' + unprefixedpath])
return true
}
this.rename = function (oldPath, newPath, isFolder) {
var unprefixedoldPath = this.removePrefix(oldPath)
var unprefixednewPath = this.removePrefix(newPath)
if (!this.isReadOnly(unprefixedoldPath) && storage.exists(unprefixedoldPath)) {
if (!storage.rename(unprefixedoldPath, unprefixednewPath)) {
return false
}
event.trigger('fileRenamed', [this.type + '/' + unprefixedoldPath, this.type + '/' + unprefixednewPath, isFolder])
return true
}
return false
}
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[path] = false
}
})
// add r/o files to the list
Object.keys(readonly).forEach((path) => {
filesList[path] = true
})
Object.keys(filesList).forEach(function (path) {
tree[path] = { isDirectory: false }
})
return callback(null, tree)
}
this.removePrefix = function (path) {
return path.indexOf(this.type + '/') === 0 ? path.replace(this.type + '/', '') : path
}
// rename .browser-solidity.json to .remix.config
if (this._exists('.browser-solidity.json')) {
this.rename('.browser-solidity.json', '.remix.config')
}
}
module.exports = LocalStorageProvider

@ -1,18 +0,0 @@
'use strict'
let BasicFileProvider = require('./basicFileProvider')
class ReadonlyProvider extends BasicFileProvider {
remove (path) {
return false
}
rename (oldPath, newPath, isFolder) {
return false
}
isReadOnly (path) {
return true
}
}
module.exports = ReadonlyProvider

@ -52,21 +52,13 @@ module.exports = class Filepanel extends ViewPlugin {
fileManager: self._components.registry.get('filemanager').api, fileManager: self._components.registry.get('filemanager').api,
config: self._components.registry.get('config').api config: self._components.registry.get('config').api
} }
var fileExplorer = new FileExplorer(self._components.registry, self._deps.fileProviders['browser'],
['createNewFile', 'publishToGist', 'copyFiles', canUpload ? 'uploadFile' : '']
)
function createProvider (key, menuItems) { function createProvider (key, menuItems) {
return new FileExplorer(self._components.registry, self._deps.fileProviders[key], menuItems) return new FileExplorer(self._components.registry, self._deps.fileProviders[key], menuItems)
} }
var fileExplorer = createProvider('browser', ['createNewFile', 'publishToGist', 'copyFiles', canUpload ? 'uploadFile' : ''])
var fileSystemExplorer = createProvider('localhost') var fileSystemExplorer = createProvider('localhost')
var swarmExplorer = createProvider('swarm')
var githubExplorer = createProvider('github')
var gistExplorer = createProvider('gist', ['updateGist'])
var httpExplorer = createProvider('http')
var httpsExplorer = createProvider('https')
var ipfsExplorer = createProvider('ipfs')
self.remixdHandle = new RemixdHandle(fileSystemExplorer, self._deps.fileProviders['localhost'], appManager) self.remixdHandle = new RemixdHandle(fileSystemExplorer, self._deps.fileProviders['localhost'], appManager)
@ -74,12 +66,6 @@ module.exports = class Filepanel extends ViewPlugin {
<div> <div>
<div class=${css.treeview}>${fileExplorer.init()}</div> <div class=${css.treeview}>${fileExplorer.init()}</div>
<div class="filesystemexplorer ${css.treeview}">${fileSystemExplorer.init()}</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>
<div class="httpexplorer ${css.treeview}">${httpExplorer.init()}</div>
<div class="httpsexplorer ${css.treeview}">${httpsExplorer.init()}</div>
<div class="ipfsexplorer ${css.treeview}">${ipfsExplorer.init()}</div>
</div> </div>
` `

@ -42,7 +42,7 @@ const profile = {
class CompileTab extends ViewPlugin { class CompileTab extends ViewPlugin {
constructor (editor, config, renderer, swarmfileProvider, ipfsfileProvider, fileManager, fileProviders) { constructor (editor, config, renderer, fileProvider, fileManager) {
super(profile) super(profile)
this.events = new EventEmitter() this.events = new EventEmitter()
this._view = { this._view = {
@ -52,15 +52,12 @@ class CompileTab extends ViewPlugin {
contractEl: null contractEl: null
} }
this.queryParams = new QueryParams() this.queryParams = new QueryParams()
this.fileProvider = fileProvider
// dependencies // dependencies
this.editor = editor this.editor = editor
this.config = config this.config = config
this.renderer = renderer this.renderer = renderer
this.swarmfileProvider = swarmfileProvider
this.ipfsfileProvider = ipfsfileProvider
this.fileManager = fileManager this.fileManager = fileManager
this.fileProviders = fileProviders
this.data = { this.data = {
contractsDetails: {} contractsDetails: {}
@ -68,7 +65,7 @@ class CompileTab extends ViewPlugin {
} }
onActivationInternal () { onActivationInternal () {
this.compileTabLogic = new CompileTabLogic(this.queryParams, this.fileManager, this.editor, this.config, this.fileProviders) this.compileTabLogic = new CompileTabLogic(this.queryParams, this.fileManager, this.editor, this.config, this.fileProvider)
this.compiler = this.compileTabLogic.compiler this.compiler = this.compileTabLogic.compiler
this.compileTabLogic.init() this.compileTabLogic.init()
@ -311,7 +308,7 @@ class CompileTab extends ViewPlugin {
modalDialogCustom.alert(yo`<span>Metadata published successfully.<br> <pre>${result}</pre> </span>`) modalDialogCustom.alert(yo`<span>Metadata published successfully.<br> <pre>${result}</pre> </span>`)
} }
}, (item) => { // triggered each time there's a new verified publish (means hash correspond) }, (item) => { // triggered each time there's a new verified publish (means hash correspond)
this.swarmfileProvider.addReadOnly('swarm/' + item.hash, item.content) this.fileProvider.addReadOnly('swarm/' + item.hash, item.content)
}) })
} else { } else {
publishOnIpfs(contract, this.fileManager, function (err, uploaded) { publishOnIpfs(contract, this.fileManager, function (err, uploaded) {
@ -328,7 +325,7 @@ class CompileTab extends ViewPlugin {
modalDialogCustom.alert(yo`<span>Metadata published successfully.<br> <pre>${result}</pre> </span>`) modalDialogCustom.alert(yo`<span>Metadata published successfully.<br> <pre>${result}</pre> </span>`)
} }
}, (item) => { // triggered each time there's a new verified publish (means hash correspond) }, (item) => { // triggered each time there's a new verified publish (means hash correspond)
this.ipfsfileProvider.addReadOnly('ipfs/' + item.hash, item.content) this.fileProvider.addReadOnly('ipfs/' + item.hash, item.content)
}) })
} }
} }

@ -9,7 +9,7 @@ const addTooltip = require('../../ui/tooltip')
class CompileTab { class CompileTab {
constructor (queryParams, fileManager, editor, config, fileProviders) { constructor (queryParams, fileManager, editor, config, fileProvider) {
this.event = new EventEmitter() this.event = new EventEmitter()
this.queryParams = queryParams this.queryParams = queryParams
this.compilerImport = new CompilerImport() this.compilerImport = new CompilerImport()
@ -17,7 +17,7 @@ class CompileTab {
this.fileManager = fileManager this.fileManager = fileManager
this.editor = editor this.editor = editor
this.config = config this.config = config
this.fileProviders = fileProviders this.fileProvider = fileProvider
} }
init () { init () {
@ -92,8 +92,8 @@ class CompileTab {
(error, content, cleanUrl, type, url) => { (error, content, cleanUrl, type, url) => {
if (error) return cb(error) if (error) return cb(error)
if (this.fileProviders[type]) { if (this.fileProvider) {
this.fileProviders[type].addReadOnly(cleanUrl, content, url) this.fileProvider.addReadOnly(cleanUrl, content, url)
} }
cb(null, content) cb(null, content)
}) })

@ -42,7 +42,7 @@ function GistHandler (_window) {
} }
this.loadFromGist = (params, fileManager) => { this.loadFromGist = (params, fileManager) => {
const gistProvider = fileManager.fileProviderOf('gist') const gistProvider = fileManager.fileProviderOf('browser')
const self = this const self = this
return self.handleLoad(params, function (gistId) { return self.handleLoad(params, function (gistId) {
request.get({ request.get({
@ -53,7 +53,11 @@ function GistHandler (_window) {
modalDialogCustom.alert(`Gist load error: ${error || data.message}`) modalDialogCustom.alert(`Gist load error: ${error || data.message}`)
return return
} }
fileManager.setBatchFiles(data.files, 'gist', (errorLoadingFile) => { let obj = {}
Object.keys(data.files).forEach((element) => {
obj['/gists/' + gistId + '/' + element] = data.files[element]
})
fileManager.setBatchFiles(obj, 'browser', (errorLoadingFile) => {
if (!errorLoadingFile) { if (!errorLoadingFile) {
gistProvider.id = gistId gistProvider.id = gistId
gistProvider.origGistFiles = data.files gistProvider.origGistFiles = data.files

@ -41,7 +41,7 @@ module.exports = {
this.createNonClashingNameWithPrefix(name, fileProvider, '', cb) this.createNonClashingNameWithPrefix(name, fileProvider, '', cb)
}, },
checkSpecialChars (name) { checkSpecialChars (name) {
return name.match(/[/:*?"<>\\'|]/) != null return name.match(/[:*?"<>\\'|]/) != null
}, },
find: find find: find
} }

@ -1,9 +1,9 @@
const EventEmitter = require('events') const EventEmitter = require('events')
class SwitchFile extends EventEmitter { class SwitchFile extends EventEmitter {
command (contractName) { command (name) {
this.api.perform((done) => { this.api.perform((done) => {
switchFile(this.api, contractName, () => { switchFile(this.api, name, () => {
done() done()
this.emit('complete') this.emit('complete')
}) })

@ -56,7 +56,7 @@ module.exports = {
function checkDeployShouldFail (browser, callback) { function checkDeployShouldFail (browser, callback) {
let config let config
browser.switchFile('browser/test.json') browser.switchFile('browser/artifacts').switchFile('browser/artifacts/test.json')
.getEditorValue((content) => { .getEditorValue((content) => {
config = JSON.parse(content) config = JSON.parse(content)
config.deploy['VM:-'].autoDeployLib = false config.deploy['VM:-'].autoDeployLib = false
@ -74,7 +74,7 @@ function checkDeployShouldFail (browser, callback) {
function checkDeployShouldSucceed (browser, address, callback) { function checkDeployShouldSucceed (browser, address, callback) {
let addressRef let addressRef
let config let config
browser.switchFile('browser/test.json') browser.switchFile('browser/artifacts').switchFile('browser/artifacts/test.json')
.getEditorValue((content) => { .getEditorValue((content) => {
config = JSON.parse(content) config = JSON.parse(content)
config.deploy['VM:-'].autoDeployLib = false config.deploy['VM:-'].autoDeployLib = false

Loading…
Cancel
Save