diff --git a/src/app/compiler/compiler-imports.js b/src/app/compiler/compiler-imports.js index 21e5549a50..244d1c4f31 100644 --- a/src/app/compiler/compiler-imports.js +++ b/src/app/compiler/compiler-imports.js @@ -110,10 +110,18 @@ module.exports = class CompilerImports extends Plugin { }) } - import (url, loadingCb, cb) { + import (url, force, loadingCb, cb) { + if (typeof force !== 'boolean') { + let temp = loadingCb + loadingCb = force + cb = temp + force = false + } if (!loadingCb) loadingCb = () => {} + if (!cb) cb = () => {} var self = this + if (force) delete this.previouslyHandled[url] var imported = this.previouslyHandled[url] if (imported) { return cb(null, imported.content, imported.cleanUrl, imported.type, url) diff --git a/src/app/files/file-explorer.js b/src/app/files/file-explorer.js index 9ed63ca39a..0249ab783a 100644 --- a/src/app/files/file-explorer.js +++ b/src/app/files/file-explorer.js @@ -194,17 +194,29 @@ function fileExplorer (localRegistry, files, menuItems) { if (self.files.readonly) return if (key === self.files.type) return MENU_HANDLE && MENU_HANDLE.hide(null, true) - MENU_HANDLE = contextMenu(event, { - 'Rename': () => { + let actions = {} + const provider = self._deps.fileManager.fileProviderOf(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) }, + () => {} + ) + } + } else { + actions['Rename'] = () => { if (self.files.readonly) { 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) - }, - 'Delete': () => { - if (self.files.readonly) { 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?', () => { files.remove(key) }, () => {}) } - }) + } + actions['Delete'] = () => { + if (self.files.readonly) { 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?', () => { files.remove(key) }, () => {}) + } + MENU_HANDLE = contextMenu(event, actions) }) self.treeView.event.register('leafRightClick', function (key, data, label, event) { @@ -212,7 +224,7 @@ function fileExplorer (localRegistry, files, menuItems) { MENU_HANDLE && MENU_HANDLE.hide(null, true) let actions = {} const provider = self._deps.fileManager.fileProviderOf(key) - if (!provider.isReadOnly(key)) { + if (!provider.isExternalFolder(key)) { actions['Rename'] = () => { if (self.files.readonly) { return tooltip('cannot rename file. ' + self.files.type + ' is a read only explorer') } var name = label.querySelector('span[data-path="' + key + '"]') @@ -226,15 +238,6 @@ function fileExplorer (localRegistry, files, menuItems) { () => {} ) } - } else { - actions['Delete from remix'] = () => { - modalDialogCustom.confirm( - 'Delete from remix', - 'Are you sure you want to delete this file from remix?', - () => { files.remove(key) }, - () => {} - ) - } } MENU_HANDLE = contextMenu(event, actions) }) diff --git a/src/app/files/fileManager.js b/src/app/files/fileManager.js index e1b9a57381..ced094987b 100644 --- a/src/app/files/fileManager.js +++ b/src/app/files/fileManager.js @@ -49,7 +49,7 @@ class FileManager extends Plugin { localhostExplorer: this._components.registry.get('fileproviders/localhost').api, filesProviders: this._components.registry.get('fileproviders').api } - + this._deps.browserExplorer.event.register('fileChanged', (path) => { this.fileChangedEvent(path) }) 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.browserExplorer.event.register('fileRemoved', (path) => { this.fileRemovedEvent(path) }) @@ -58,6 +58,10 @@ class FileManager extends Plugin { this._deps.localhostExplorer.event.register('closed', (event) => { this.removeTabsOf(this._deps.localhostExplorer) }) } + fileChangedEvent (path) { + this.syncEditor(path) + } + fileRenamedEvent (oldName, newName, isFolder) { if (!isFolder) { this._deps.config.set('currentFile', '') diff --git a/src/app/files/fileProvider.js b/src/app/files/fileProvider.js index 21c5c679e2..29cc29cfd6 100644 --- a/src/app/files/fileProvider.js +++ b/src/app/files/fileProvider.js @@ -1,13 +1,59 @@ 'use strict' -var EventManager = require('../../lib/events') +const CompilerImport = require('../compiler/compiler-imports') +const EventManager = require('../../lib/events') +const modalDialogCustom = require('../ui/modal-dialog-custom') +const tooltip = require('../ui/tooltip') +const remixLib = require('remix-lib') +const Storage = remixLib.Storage class FileProvider { constructor (name) { this.event = new EventManager() this.type = name - this.normalizedNames = {} // contains the raw url associated with the displayed path - this.readonlyItems = ['browser'] + this.providerExternalsStorage = new Storage('providerExternals:') + this.externalFolders = [this.type + '/swarm', this.type + '/ipfs', this.type + '/github', this.type + '/gist', this.type + '/https'] + } + + addNormalizedName (path, url) { + this.providerExternalsStorage.set(this.type + '/' + path, url) + } + + removeNormalizedName (path) { + this.providerExternalsStorage.remove(path) + } + + normalizedNameExists (path) { + return this.providerExternalsStorage.exists(path) + } + + getNormalizedName (path) { + return this.providerExternalsStorage.get(path) + } + + isExternalFolder (path) { + return this.externalFolders.includes(path) + } + + discardChanges (path) { + this.remove(path) + const compilerImport = new CompilerImport() + this.providerExternalsStorage.keys().map(value => { + if (value.indexOf(path) === 0) { + compilerImport.import( + this.getNormalizedName(value), + true, + (loadingMsg) => { tooltip(loadingMsg) }, + (error, content, cleanUrl, type, url) => { + if (error) { + modalDialogCustom.alert(error) + } else { + this.addExternal(type + '/' + cleanUrl, content, url) + } + } + ) + } + }) } exists (path, cb) { @@ -25,7 +71,7 @@ class FileProvider { get (path, cb) { cb = cb || function () {} - if (this.normalizedNames[path]) path = this.normalizedNames[path] // ensure we actually use the normalized path from here + if (this.normalizedNameExists[path]) path = this.getNormalizedName(path) // ensure we actually use the normalized path from here var unprefixedpath = this.removePrefix(path) var exists = window.remixFileSystem.existsSync(unprefixedpath) if (!exists) return cb(null, null) @@ -36,10 +82,6 @@ class FileProvider { set (path, content, cb) { cb = cb || function () {} - if (this.isReadOnly(path)) { - cb(new Error('It is not possible to modify a readonly item')) - return false - } var unprefixedpath = this.removePrefix(path) var exists = window.remixFileSystem.existsSync(unprefixedpath) if (!exists && unprefixedpath.indexOf('/') !== -1) { @@ -70,26 +112,17 @@ class FileProvider { return true } - addReadOnly (path, content, url) { - this.readonlyItems.push(this.type + '/' + path) - if (!url) this.normalizedNames[url] = path + // this will not add a folder as readonly but keep the original url to be able to restore it later + addExternal (path, content, url) { + if (url) this.addNormalizedName(path, url) return this.set(path, content) } isReadOnly (path) { - return this.readonlyItems.includes(path) - } - - _removeFromReadonlyList (path) { - const indexToRemove = this.readonlyItems.indexOf(path) - if (indexToRemove !== -1) { - this.readonlyItems.splice(indexToRemove, 1) - } + return false } remove (path) { - this._removeFromReadonlyList(path) - var unprefixedpath = this.removePrefix(path) if (!this._exists(unprefixedpath)) { return false diff --git a/src/app/tabs/compile-tab.js b/src/app/tabs/compile-tab.js index ededb6d5f2..28aaab0a4c 100644 --- a/src/app/tabs/compile-tab.js +++ b/src/app/tabs/compile-tab.js @@ -313,7 +313,7 @@ class CompileTab extends ViewPlugin { modalDialogCustom.alert(yo`Metadata published successfully.
${result}
`) } }, (item) => { // triggered each time there's a new verified publish (means hash correspond) - this.fileProvider.addReadOnly('swarm/' + item.hash, item.content) + this.fileProvider.addExternal('swarm/' + item.hash, item.content) }) } else { publishOnIpfs(contract, this.fileManager, function (err, uploaded) { @@ -330,7 +330,7 @@ class CompileTab extends ViewPlugin { modalDialogCustom.alert(yo`Metadata published successfully.
${result}
`) } }, (item) => { // triggered each time there's a new verified publish (means hash correspond) - this.fileProvider.addReadOnly('ipfs/' + item.hash, item.content) + this.fileProvider.addExternal('ipfs/' + item.hash, item.content) }) } } diff --git a/src/app/tabs/compileTab/compileTab.js b/src/app/tabs/compileTab/compileTab.js index f2751d1d8c..e8f88da2cc 100644 --- a/src/app/tabs/compileTab/compileTab.js +++ b/src/app/tabs/compileTab/compileTab.js @@ -93,7 +93,7 @@ class CompileTab { if (error) return cb(error) if (this.fileProvider) { - this.fileProvider.addReadOnly(cleanUrl, content, url) + this.fileProvider.addExternal(cleanUrl, content, url) } cb(null, content) }) diff --git a/src/app/ui/landing-page/landing-page.js b/src/app/ui/landing-page/landing-page.js index 908a78d284..a87235cd2e 100644 --- a/src/app/ui/landing-page/landing-page.js +++ b/src/app/ui/landing-page/landing-page.js @@ -106,7 +106,7 @@ export class LandingPage extends ViewPlugin { if (error) { modalDialogCustom.alert(error) } else { - fileProviders['browser'].addReadOnly(type + '/' + cleanUrl, content, url) + fileProviders['browser'].addExternal(type + '/' + cleanUrl, content, url) this.verticalIcons.select('fileExplorers') } }