diff --git a/src/app.js b/src/app.js index 88cb513937..ba5d97e589 100644 --- a/src/app.js +++ b/src/app.js @@ -117,54 +117,60 @@ var css = csjs` class App { constructor (api = {}, events = {}, opts = {}) { var self = this - self._api = {} + self._components = {} registry.put({api: self, name: 'app'}) + var fileStorage = new Storage('sol:') registry.put({api: fileStorage, name: 'fileStorage'}) var configStorage = new Storage('config:') registry.put({api: configStorage, name: 'configStorage'}) - self._api.config = new Config(fileStorage) - registry.put({api: self._api.config, name: 'config'}) + self._components.config = new Config(fileStorage) + registry.put({api: self._components.config, name: 'config'}) - executionContext.init(self._api.config) + executionContext.init(self._components.config) executionContext.listenOnLastBlock() - self._api.filesProviders = {} - self._api.filesProviders['browser'] = new Browserfiles(fileStorage) - self._api.filesProviders['config'] = new BrowserfilesTree('config', configStorage) - self._api.filesProviders['config'].init() - registry.put({api: self._api.filesProviders['browser'], name: 'fileproviders/browser'}) - registry.put({api: self._api.filesProviders['config'], name: 'fileproviders/config'}) + + self._components.compilerImport = new CompilerImport() + registry.put({api: self._components.compilerImport, name: 'compilerimport'}) + self._components.gistHandler = new GistHandler() + + self._components.filesProviders = {} + self._components.filesProviders['browser'] = new Browserfiles(fileStorage) + self._components.filesProviders['config'] = new BrowserfilesTree('config', configStorage) + self._components.filesProviders['config'].init() + registry.put({api: self._components.filesProviders['browser'], name: 'fileproviders/browser'}) + registry.put({api: self._components.filesProviders['config'], name: 'fileproviders/config'}) + var remixd = new Remixd() - registry.put({api: remixd, name: 'remixd/config'}) + registry.put({api: remixd, name: 'remixd'}) remixd.event.register('system', (message) => { if (message.error) toolTip(message.error) }) - self._api.filesProviders['localhost'] = new SharedFolder(remixd) - self._api.filesProviders['swarm'] = new BasicReadOnlyExplorer('swarm') - self._api.filesProviders['github'] = new BasicReadOnlyExplorer('github') - self._api.filesProviders['gist'] = new NotPersistedExplorer('gist') - self._api.filesProviders['ipfs'] = new BasicReadOnlyExplorer('ipfs') - registry.put({api: self._api.filesProviders['localhost'], name: 'fileproviders/localhost'}) - registry.put({api: self._api.filesProviders['swarm'], name: 'fileproviders/swarm'}) - registry.put({api: self._api.filesProviders['github'], name: 'fileproviders/github'}) - registry.put({api: self._api.filesProviders['gist'], name: 'fileproviders/gist'}) - registry.put({api: self._api.filesProviders['ipfs'], name: 'fileproviders/ipfs'}) - registry.put({api: self._api.filesProviders, name: 'fileproviders'}) + + self._components.filesProviders['localhost'] = new SharedFolder(remixd) + self._components.filesProviders['swarm'] = new BasicReadOnlyExplorer('swarm') + self._components.filesProviders['github'] = new BasicReadOnlyExplorer('github') + self._components.filesProviders['gist'] = new NotPersistedExplorer('gist') + self._components.filesProviders['ipfs'] = new BasicReadOnlyExplorer('ipfs') + 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'}) + self._view = {} - self._components = {} - self._components.compilerImport = new CompilerImport() - registry.put({api: self._components.compilerImport, name: 'compilerimport'}) - self._components.gistHandler = new GistHandler() + self.data = { _layout: { right: { - offset: self._api.config.get('right-offset') || 400, + offset: self._components.config.get('right-offset') || 400, show: true }, // @TODO: adapt sizes proportionally to browser window size left: { - offset: self._api.config.get('left-offset') || 200, + offset: self._components.config.get('left-offset') || 200, show: true } } @@ -179,7 +185,7 @@ class App { if (layout.show) delta = layout.offset else delta = 0 } else { - self._api.config.set(`${direction}-offset`, delta) + self._components.config.set(`${direction}-offset`, delta) layout.offset = delta } } @@ -232,7 +238,7 @@ class App { self._components.fileManager.saveCurrentFile() self._components.editor.clearAnnotations() - var currentFile = self._api.config.get('currentFile') + var currentFile = self._components.config.get('currentFile') if (currentFile) { if (/.(.sol)$/.exec(currentFile)) { // only compile *.sol file. @@ -259,9 +265,9 @@ class App { self.event.trigger('debuggingRequested', []) self._view.transactionDebugger.debug(txHash) } - loadFromGist (gistId) { + loadFromGist (params) { const self = this - return self._components.gistHandler.handleLoad(gistId, function (gistId) { + return self._components.gistHandler.handleLoad(params, function (gistId) { request.get({ url: `https://api.github.com/gists/${gistId}`, json: true @@ -271,7 +277,7 @@ class App { return } self.loadFiles(data.files, 'gist', (errorLoadingFile) => { - if (!errorLoadingFile) self._api.filesProviders['gist'].id = gistId + if (!errorLoadingFile) self._components.filesProviders['gist'].id = gistId }) }) }) @@ -281,14 +287,14 @@ class App { if (!fileProvider) fileProvider = 'browser' async.each(Object.keys(filesSet), (file, callback) => { - helper.createNonClashingName(file, self._api.filesProviders[fileProvider], + helper.createNonClashingName(file, self._components.filesProviders[fileProvider], (error, name) => { if (error) { modalDialogCustom.alert('Unexpected error loading the file ' + error) } else if (helper.checkSpecialChars(name)) { modalDialogCustom.alert('Special characters are not allowed') } else { - self._api.filesProviders[fileProvider].set(name, filesSet[file].content) + self._components.filesProviders[fileProvider].set(name, filesSet[file].content) } callback() }) @@ -305,8 +311,8 @@ class App { }, (error, content, cleanUrl, type, url) => { if (!error) { - if (self._api.filesProviders[type]) { - self._api.filesProviders[type].addReadOnly(cleanUrl, content, url) + if (self._components.filesProviders[type]) { + self._components.filesProviders[type].addReadOnly(cleanUrl, content, url) } cb(null, content) } else { @@ -476,12 +482,9 @@ Please make a backup of your contracts and start using http://remix.ethereum.org this module basically listen on user input (from terminal && editor) and interpret them as commands */ - var cmdInterpreter = new CommandInterpreter() + var cmdInterpreter = new CommandInterpreter() // @TODO: put into editorpanel registry.put({api: cmdInterpreter, name: 'cmdinterpreter'}) - var config = self._api.config - var filesProviders = self._api.filesProviders - // ----------------- file manager ---------------------------- self._components.fileManager = new FileManager() @@ -503,8 +506,6 @@ Please make a backup of your contracts and start using http://remix.ethereum.org this._view.centerpanel.appendChild(this._components.editorpanel.render()) - var queryParams = new QueryParams() - // The event listener needs to be registered as early as possible, because the // parent will send the message upon the "load" event. var filesToLoad = null @@ -528,47 +529,11 @@ Please make a backup of your contracts and start using http://remix.ethereum.org self.loadFiles(filesToLoad) } - var loadingFromGist = self.loadFromGist(queryParams.get()) - - // insert ballot contract if there are no files available - if (!loadingFromGist) { - filesProviders['browser'].resolveDirectory('browser', (error, filesList) => { - if (error) console.error(error) - if (Object.keys(filesList).length === 0) { - if (!filesProviders['browser'].set(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.') - } else { - filesProviders['browser'].set(examples.ballot_test.name, examples.ballot_test.content) - } - } - }) - } - - window.syncStorage = chromeCloudStorageSync - chromeCloudStorageSync() - // ---------------- FilePanel -------------------- var filePanel = new FilePanel() - - // TODO this should happen inside file-panel.js - var filepanelContainer = document.querySelector('#filepanel') - filepanelContainer.appendChild(filePanel.render()) - + self._view.leftpanel.appendChild(filePanel.render()) filePanel.event.register('resize', delta => self._adjustLayout('left', delta)) - var previouslyOpenedFile = config.get('currentFile') - if (previouslyOpenedFile) { - filesProviders['browser'].get(previouslyOpenedFile, (error, content) => { - if (!error && content) { - fileManager.switchFile(previouslyOpenedFile) - } else { - fileManager.switchFile() - } - }) - } else { - fileManager.switchFile() - } - // ----------------- Renderer ----------------- var renderer = new Renderer() registry.put({api: renderer, name: 'renderer'}) @@ -586,35 +551,19 @@ Please make a backup of your contracts and start using http://remix.ethereum.org var node = document.getElementById('staticanalysisView') node.insertBefore(staticanalysis.render(), node.childNodes[0]) - // ----------------- editor resize --------------- - - function onResize () { - editor.resize(document.querySelector('#editorWrap').checked) - } - onResize() - - self._view.el.addEventListener('change', onResize) - document.querySelector('#editorWrap').addEventListener('change', onResize) - // ----------------- Debugger ----------------- - var sourceHighlighter = new SourceHighlighter() - self._view.transactionDebugger = new Debugger('#debugger', sourceHighlighter) + self._view.transactionDebugger = new Debugger('#debugger', new SourceHighlighter()) self._view.transactionDebugger.addProvider('vm', executionContext.vm()) self._view.transactionDebugger.addProvider('injected', executionContext.internalWeb3()) self._view.transactionDebugger.addProvider('web3', executionContext.internalWeb3()) self._view.transactionDebugger.switchProvider(executionContext.getProvider()) - var txLogger = new TxLogger() - - txLogger.event.register('debugRequested', (hash) => { - self.startdebugging(hash) - }) + var txLogger = new TxLogger() // eslint-disable-line var previousInput = '' var saveTimeout = null - function editorOnChange () { - var currentFile = config.get('currentFile') + var currentFile = self._components.config.get('currentFile') if (!currentFile) { return } @@ -638,18 +587,23 @@ Please make a backup of your contracts and start using http://remix.ethereum.org }, 5000) } + // auto save the file when content changed editor.event.register('contentChanged', editorOnChange) - // in order to save the file when switching + // save the file when switching editor.event.register('sessionSwitched', editorOnChange) executionContext.event.register('contextChanged', this, function (context) { self.runCompiler() }) + // rerun the compiler when the environement changed executionContext.event.register('web3EndpointChanged', this, function (context) { self.runCompiler() }) + var queryParams = new QueryParams() + + // check init query parameters from the URL once the compiler is loaded compiler.event.register('compilerLoaded', this, function (version) { previousInput = '' self.runCompiler() @@ -677,4 +631,37 @@ Please make a backup of your contracts and start using http://remix.ethereum.org self.startdebugging(queryParams.get().debugtx) } }) + + // chrome app + window.syncStorage = chromeCloudStorageSync + chromeCloudStorageSync() + + var loadingFromGist = self.loadFromGist(queryParams.get()) + if (!loadingFromGist) { + // insert ballot contract if there are no files to show + self._components.filesProviders['browser'].resolveDirectory('browser', (error, filesList) => { + if (error) console.error(error) + if (Object.keys(filesList).length === 0) { + if (!self._components.filesProviders['browser'].set(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.') + } else { + self._components.filesProviders['browser'].set(examples.ballot_test.name, examples.ballot_test.content) + } + } + }) + } + + // Open last opened file + var previouslyOpenedFile = self._components.config.get('currentFile') + if (previouslyOpenedFile) { + self._components.filesProviders['browser'].get(previouslyOpenedFile, (error, content) => { + if (!error && content) { + fileManager.switchFile(previouslyOpenedFile) + } else { + fileManager.switchFile() + } + }) + } else { + fileManager.switchFile() + } } diff --git a/src/app/execution/txLogger.js b/src/app/execution/txLogger.js index 73fe26a5df..a6320cdc88 100644 --- a/src/app/execution/txLogger.js +++ b/src/app/execution/txLogger.js @@ -120,7 +120,6 @@ var css = csjs` }` /** * This just export a function that register to `newTransaction` and forward them to the logger. - * Emit debugRequested * */ class TxLogger { @@ -141,7 +140,8 @@ class TxLogger { editorPanel: this._components.registry.get('editorpanel').api, txListener: this._components.registry.get('txlistener').api, eventsDecoder: this._components.registry.get('eventsdecoder').api, - compiler: this._components.registry.get('compiler').api + compiler: this._components.registry.get('compiler').api, + app: this._components.registry.get('app').api } this.logKnownTX = this._deps.editorPanel.registerCommand('knownTransaction', (args, cmds, append) => { @@ -205,7 +205,7 @@ function debug (e, data, self) { if (data.tx.isCall && data.tx.envMode !== 'vm') { modalDialog.alert('Cannot debug this call. Debugging calls is only possible in JavaScript VM mode.') } else { - self.event.trigger('debugRequested', [data.tx.hash]) + self._deps.app.startdebugging(data.tx.hash) } } diff --git a/src/app/files/fileManager.js b/src/app/files/fileManager.js index 559cf5d7ce..80a0df3bc1 100644 --- a/src/app/files/fileManager.js +++ b/src/app/files/fileManager.js @@ -85,6 +85,7 @@ class FileManager { self._deps.editor.discardCurrentSession() delete this.tabbedFiles[path] this.refreshTabs() + this.switchFile() } // Display files that have already been selected diff --git a/src/app/tabs/compile-tab.js b/src/app/tabs/compile-tab.js index a888263a51..d86e8b4680 100644 --- a/src/app/tabs/compile-tab.js +++ b/src/app/tabs/compile-tab.js @@ -127,7 +127,7 @@ module.exports = class CompileTab { var error = false if (data['error']) { error = true - self._deps.renderer.error(data['error'].formattedMessage, self._view.errorContainer, {type: data['error'].severity}) + self._deps.renderer.error(data['error'].formattedMessage, self._view.errorContainer, {type: data['error'].severity || 'error'}) } if (data.errors && data.errors.length) { error = true diff --git a/src/app/tabs/settings-tab.js b/src/app/tabs/settings-tab.js index 8721e78063..f86a009220 100644 --- a/src/app/tabs/settings-tab.js +++ b/src/app/tabs/settings-tab.js @@ -111,7 +111,7 @@ module.exports = class SettingsTab { Always use Ethereum VM at Load