diff --git a/src/app/files/file-explorer.js b/src/app/files/file-explorer.js index b46dc6a439..c172d0e421 100644 --- a/src/app/files/file-explorer.js +++ b/src/app/files/file-explorer.js @@ -158,7 +158,6 @@ function fileExplorer (localRegistry, files, menuItems) { var isFile = false Object.keys(value).filter(function keep (x) { if (x === '/content') isFile = true - // if (x === '/readOnly') isReadOnly = true if (x[0] !== '/') return true }).forEach(function (x) { newValue[x] = value[x] }) return { @@ -208,17 +207,35 @@ function fileExplorer (localRegistry, files, menuItems) { MENU_HANDLE && MENU_HANDLE.hide(null, true) let actions = {} const provider = self._deps.fileManager.fileProviderOf(key) + actions['Create File'] = () => self.createNewFile(key) + actions['Create Folder'] = () => self.createNewFolder(key) if (provider.isExternalFolder(key)) { actions['Discard changes'] = () => { modalDialogCustom.confirm( 'Discard changes', 'Are you sure you want to discard all your changes?', - () => { files.discardChanges(key) }, + () => { self.files.discardChanges(key) }, () => {} ) } } else { const folderPath = extractExternalFolder(key) + actions['Rename'] = () => { + if (self.files.isReadOnly(key)) { return tooltip('cannot rename folder. ' + self.files.type + ' is a read only explorer') } + var name = label.querySelector('span[data-path="' + key + '"]') + if (name) editModeOn(name) + } + actions['Delete'] = () => { + if (self.files.isReadOnly(key)) { return tooltip('cannot delete folder. ' + self.files.type + ' is a read only explorer') } + modalDialogCustom.confirm('Confirm to delete a folder', 'Are you sure you want to delete this folder?', + () => { + if (!files.remove(key)) { + tooltip(`failed to remove ${key}. Make sure the directory is empty before removing it.`) + } else { + self.updatePath('browser') + } + }, () => {}) + } if (folderPath === 'browser/gists') { actions['Push changes to gist'] = () => { const id = key.substr(key.lastIndexOf('/') + 1, key.length - 1) @@ -230,21 +247,6 @@ function fileExplorer (localRegistry, files, menuItems) { ) } } - actions['Create File'] = () => self.createNewFile(key) - actions['Create Folder'] = () => self.createNewFolder(key) - - actions['Rename'] = () => { - if (self.files.isReadOnly(key)) { return tooltip('cannot rename folder. ' + self.files.type + ' is a read only explorer') } - var name = label.querySelector('span[data-path="' + key + '"]') - if (name) editModeOn(name) - } - } - actions['Delete'] = () => { - if (self.files.isReadOnly(key)) { return tooltip('cannot delete folder. ' + self.files.type + ' is a read only explorer') } - modalDialogCustom.confirm('Confirm to delete a folder', 'Are you sure you want to delete this folder?', - () => { - if (!files.remove(key)) tooltip(`failed to remove ${key}. Make sure the directory is empty before removing it.`) - }, () => {}) } MENU_HANDLE = contextMenu(event, actions) }) @@ -265,7 +267,10 @@ function fileExplorer (localRegistry, files, menuItems) { if (self.files.isReadOnly(key)) { return tooltip('cannot delete file. ' + self.files.type + ' is a read only explorer') } modalDialogCustom.confirm( 'Delete a file', 'Are you sure you want to delete this file?', - () => { files.remove(key) }, + () => { + files.remove(key) + self.updatePath('browser') + }, () => {} ) } @@ -579,16 +584,15 @@ fileExplorer.prototype.copyFiles = function () { } } -fileExplorer.prototype.createNewFile = function (parentFolder) { +fileExplorer.prototype.createNewFile = function (parentFolder = 'browser') { let self = this modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { - helper.createNonClashingName(input, self.files, (error, newName) => { - if (error) return modalDialogCustom.alert('Failed to create file ' + newName + ' ' + error) - const currentPath = !parentFolder ? self._deps.fileManager.currentPath() : parentFolder - newName = currentPath ? currentPath + '/' + newName : self.files.type + '/' + newName + if (!input) input = 'New file' + helper.createNonClashingName(parentFolder + '/' + input, self.files, (error, newName) => { + if (error) return tooltip('Failed to create file ' + newName + ' ' + error) if (!self.files.set(newName, '')) { - modalDialogCustom.alert('Failed to create file ' + newName) + tooltip('Failed to create file ' + newName) } else { self._deps.fileManager.switchFile(newName) if (newName.includes('_test.sol')) { @@ -601,14 +605,23 @@ fileExplorer.prototype.createNewFile = function (parentFolder) { fileExplorer.prototype.createNewFolder = function (parentFolder) { let self = this - modalDialogCustom.prompt('Create new folder', '', '', (input) => { + modalDialogCustom.prompt('Create new folder', '', 'New folder', (input) => { + if (!input) { + return tooltip('Failed to create folder. The name can not be empty') + } + const currentPath = !parentFolder ? self._deps.fileManager.currentPath() : parentFolder let newName = currentPath ? currentPath + '/' + input : self.files.type + '/' + input newName = newName + '/' - if (!self.files.set(newName, '')) { - modalDialogCustom.alert('Failed to create folder ' + newName) - } + self.files.exists(newName, (error, exist) => { + if (error) return tooltip('Unexpected error while creating folder: ' + error) + if (!exist) { + self.files.set(newName, '') + } else { + tooltip('Folder already exists.', () => {}) + } + }) }, null, true) } diff --git a/src/app/files/fileProvider.js b/src/app/files/fileProvider.js index 9d288f3223..ce1605c142 100644 --- a/src/app/files/fileProvider.js +++ b/src/app/files/fileProvider.js @@ -64,6 +64,8 @@ class FileProvider { } exists (path, cb) { + // todo check the type (directory/file) as well #2386 + // currently it is not possible to have a file and folder with same path cb(null, this._exists(path)) } @@ -131,24 +133,43 @@ class FileProvider { return false } + /** + * Removes the folder recursively + * @param {*} path is the folder to be removed + */ 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) + path = this.removePrefix(path) + if (window.remixFileSystem.existsSync(path)) { + const stat = window.remixFileSystem.statSync(path) + try { + if (!stat.isDirectory()) { + window.remixFileSystem.unlinkSync(path, console.log) + this.event.trigger('fileRemoved', [this._normalizePath(path)]) + return true + } else { + const items = window.remixFileSystem.readdirSync(path) + if (items.length !== 0) { + items.forEach((item, index) => { + const curPath = `${path}/${item}` + if (window.remixFileSystem.statSync(curPath).isDirectory()) { // delete folder + this.remove(curPath) + } else { // delete file + window.remixFileSystem.unlinkSync(curPath, console.log) + this.event.trigger('fileRemoved', [this._normalizePath(path)]) + } + }) + if (window.remixFileSystem.readdirSync(path).length === 0) window.remixFileSystem.rmdirSync(path, console.log) + } else { + // folder is empty + window.remixFileSystem.rmdirSync(path, console.log) + } + } + } catch (e) { + console.log(e) + return false } - this.event.trigger('fileRemoved', [this._normalizePath(unprefixedpath)]) - return true - } catch (e) { - console.log(e) - return false } + return true } rename (oldPath, newPath, isFolder) { diff --git a/src/app/panels/tab-proxy.js b/src/app/panels/tab-proxy.js index 7240e05f16..47f2988553 100644 --- a/src/app/panels/tab-proxy.js +++ b/src/app/panels/tab-proxy.js @@ -132,7 +132,7 @@ export class TabProxy { id: name, title, icon, - tooltip: title + tooltip: name }) this._handlers[name] = { switchTo, close } } diff --git a/src/lib/helper.js b/src/lib/helper.js index b72c3aa3a0..8628418f5e 100644 --- a/src/lib/helper.js +++ b/src/lib/helper.js @@ -12,6 +12,7 @@ module.exports = { return data.slice(0, 5) + '...' + data.slice(len - 5, len) }, createNonClashingNameWithPrefix (name, fileProvider, prefix, cb) { + if (!name) name = 'Undefined' var counter = '' var ext = 'sol' var reg = /(.*)\.([^.]+)/g