add minimal API for plugin

pull/1/head
yann300 6 years ago
parent 2accb9b10a
commit 33da4e0d8a
  1. 1
      package.json
  2. 81
      src/app.js
  3. 35
      src/app/components/plugin-manager-component.js
  4. 2
      src/app/components/swap-panel-api.js
  5. 2
      src/app/components/vertical-icons-api.js
  6. 35
      src/app/editor/SourceHighlighters.js
  7. 3
      src/app/editor/editor.js
  8. 7
      src/app/files/browser-files-tree.js
  9. 49
      src/app/files/fileManager.js
  10. 48
      src/app/panels/editor-panel.js
  11. 5
      src/app/tabs/compile-tab.js
  12. 36
      src/universal-dapp.js

@ -22,6 +22,7 @@
"csslint": "^1.0.2",
"deep-equal": "^1.0.1",
"ethereumjs-util": "^5.1.2",
"events": "^3.0.0",
"execr": "^1.0.1",
"exorcist": "^0.4.0",
"fast-async": "6.3.1",

@ -6,6 +6,7 @@ var async = require('async')
var request = require('request')
var remixLib = require('remix-lib')
var EventManager = require('./lib/events')
var EventEmitter = require('events')
var registry = require('./global/registry')
var UniversalDApp = require('./universal-dapp.js')
@ -203,6 +204,13 @@ class App {
var self = this
run.apply(self)
}
profile () {
return {
type: 'app',
methods: ['getExecutionContextProvider', 'getProviderEndpoint', 'detectNetWork', 'addProvider', 'removeProvider']
}
}
render () {
var self = this
@ -283,6 +291,34 @@ class App {
if (callback) callback(error)
})
}
getExecutionContextProvider (cb) {
cb(null, executionContext.getProvider())
}
getProviderEndpoint (cb) {
if (executionContext.getProvider() === 'web3') {
cb(null, executionContext.web3().currentProvider.host)
} else {
cb('no endpoint: current provider is either injected or vm')
}
}
detectNetWork (cb) {
executionContext.detectNetwork((error, network) => {
cb(error, network)
})
}
addProvider (name, url, cb) {
executionContext.addProvider({ name, url })
cb()
}
removeProvider (name, cb) {
executionContext.removeProvider(name)
cb()
}
}
module.exports = App
@ -359,33 +395,60 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
})
registry.put({api: eventsDecoder, name: 'eventsdecoder'})
/*
that proxy is used by appManager to broadcast new transaction event
*/
const txListenerModuleProxy = {
event: new EventEmitter(),
profile() {
return {
type: 'txListener',
events: ['newTransaction']
}
}
}
txlistener.event.register('newTransaction', (tx) => {
txListenerModule.event.emit('newTransaction', tx)
})
txlistener.startListening()
// TODO: There are still a lot of dep between editorpanel and filemanager
// ----------------- editor panel ----------------------
self._components.editorpanel = new EditorPanel()
registry.put({ api: self._components.editorpanel, name: 'editorpanel' })
// ----------------- file manager ----------------------------
self._components.fileManager = new FileManager()
var fileManager = self._components.fileManager
registry.put({api: fileManager, name: 'filemanager'})
// ----------------- editor panel ----------------------
self._components.editorpanel = new EditorPanel()
registry.put({ api: self._components.editorpanel, name: 'editorpanel' })
// ----------------- Renderer -----------------
var renderer = new Renderer()
registry.put({api: renderer, name: 'renderer'})
// ----------------- app manager ----------------------------
const PluginManagerProfile = {
type: 'pluginManager',
methods: []
}
/*
TODOs:
- for each activated plugin,
an internal module (associated only with the plugin) should be created for accessing specific part of the UI. detail to be discussed
- the current API is not optimal. For instance methods of `app` only refers to `executionContext`, wich does not make really sense.
*/
const appManager = new AppManager({modules: [],plugins : []})
const swapPanelComponent = new SwapPanelComponent()
const pluginManagerComponent = new PluginManagerComponent()
const pluginManagerComponent = new PluginManagerComponent(
{
app: this,
udapp: udapp,
fileManager: fileManager,
sourceHighlighters: registry.get('editor').api.sourceHighlighters,
config: self._components.filesProviders['config'],
txListener: txListenerModuleProxy
})
registry.put({api: pluginManagerComponent.proxy(), name: 'pluginmanager'})
self._components.editorpanel.init()

@ -21,11 +21,20 @@ const EventEmitter = require ('events')
class PluginManagerComponent {
constructor () {
constructor ({ app, udapp, fileManager, sourceHighlighters, config, txListener }) {
this.event = new EventEmitter()
this.modulesDefinition = {
'FilePanel': { name: 'FilePanel', Type: FilePanel, icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDUwIDUwIiBoZWlnaHQ9IjUwcHgiIGlkPSJMYXllcl8xIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MCA1MCIgd2lkdGg9IjUwcHgiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxyZWN0IGZpbGw9Im5vbmUiIGhlaWdodD0iNTAiIHdpZHRoPSI1MCIvPjxwb2x5bGluZSBmaWxsPSJub25lIiBwb2ludHM9IjQ0LDIxIDQ0LDQ5IDYsNDkgICA2LDIxICIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLXdpZHRoPSIyIi8+PHBvbHlsaW5lIGZpbGw9Im5vbmUiIHBvaW50cz0iMTksNDkgMTksMjggMzEsMjggICAzMSw0OSAiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iMiIvPjxwb2x5Z29uIHBvaW50cz0iMzUsNSAzNSw4LjAxNiAzNywxMC4wOTQgMzcsNyAzOSw3IDM5LDEyLjIwMyA0MSwxNC4yNjYgNDEsNSAiLz48cG9seWxpbmUgZmlsbD0ibm9uZSIgcG9pbnRzPSIgIDEuMTEsMjUuOTQyIDI1LDEuMDUzIDQ4Ljg5LDI1Ljk0MyAiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iMiIvPjwvc3ZnPg==' },
// service module. They can be seen as daemon
// they usually don't have UI and only represent the minimal API a plugins can access.
'App': { name: 'App', target: app },
'Udapp': { name: 'Udapp', target: udapp },
'FileManager': { name: 'FileManager', target: fileManager },
'SourceHighlighters': { name: 'SourceHighlighters', target: sourceHighlighters },
'Config': { name: 'Config', target: config },
'TxListener': { name: 'TxListener', target: txListener },
// internal components. They are mostly views, they don't provide external API for plugins
'Solidity Compile': { name: 'Solidity Compile', class: 'evm-compiler', Type: CompileTab, icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDUwIDUwIiBoZWlnaHQ9IjUwcHgiIGlkPSJMYXllcl8xIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MCA1MCIgd2lkdGg9IjUwcHgiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxyZWN0IGZpbGw9Im5vbmUiIGhlaWdodD0iNTAiIHdpZHRoPSI1MCIvPjxwYXRoIGQ9Ik00NiwxNXYtNCAgYzAtMS4xMDQtMC44OTYtMi0yLTJjMCwwLTI0LjY0OCwwLTI2LDBjLTEuNDY5LDAtMi40ODQtNC00LTRIM0MxLjg5Niw1LDEsNS44OTYsMSw3djR2Mjl2NGMwLDEuMTA0LDAuODk2LDIsMiwyaDM5ICBjMS4xMDQsMCwyLTAuODk2LDItMiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLXdpZHRoPSIyIi8+PHBhdGggZD0iTTEsNDRsNS0yNyAgYzAtMS4xMDQsMC44OTYtMiwyLTJoMzljMS4xMDQsMCwyLDAuODk2LDIsMmwtNSwyNyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLXdpZHRoPSIyIi8+PC9zdmc+' },
'FilePanel': { name: 'FilePanel', Type: FilePanel, icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDUwIDUwIiBoZWlnaHQ9IjUwcHgiIGlkPSJMYXllcl8xIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MCA1MCIgd2lkdGg9IjUwcHgiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxyZWN0IGZpbGw9Im5vbmUiIGhlaWdodD0iNTAiIHdpZHRoPSI1MCIvPjxwb2x5bGluZSBmaWxsPSJub25lIiBwb2ludHM9IjQ0LDIxIDQ0LDQ5IDYsNDkgICA2LDIxICIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLXdpZHRoPSIyIi8+PHBvbHlsaW5lIGZpbGw9Im5vbmUiIHBvaW50cz0iMTksNDkgMTksMjggMzEsMjggICAzMSw0OSAiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iMiIvPjxwb2x5Z29uIHBvaW50cz0iMzUsNSAzNSw4LjAxNiAzNywxMC4wOTQgMzcsNyAzOSw3IDM5LDEyLjIwMyA0MSwxNC4yNjYgNDEsNSAiLz48cG9seWxpbmUgZmlsbD0ibm9uZSIgcG9pbnRzPSIgIDEuMTEsMjUuOTQyIDI1LDEuMDUzIDQ4Ljg5LDI1Ljk0MyAiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iMiIvPjwvc3ZnPg==' },
'Test': { name: 'Test', dep: 'Solidity Compile', Type: TestTab, icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDUwIDUwIiBoZWlnaHQ9IjUwcHgiIGlkPSJMYXllcl8xIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MCA1MCIgd2lkdGg9IjUwcHgiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxyZWN0IGZpbGw9Im5vbmUiIGhlaWdodD0iNTAiIHdpZHRoPSI1MCIvPjxwYXRoIGQ9Ik00OSw0djI1YzAsMC01LjI3MywzLTEyLDMgIGMtMTEuOTI5LDAtMTUuODY5LTQtMjQtNFMxLDMwLDEsMzBWM2MwLDAsMi4wODUtMiwxMi0yczE0LjA0Nyw2LDI0LDZDNDMuMjgxLDcsNDguMTMsNC40NzEsNDksNHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iMiIvPjxsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iMiIgeDE9IjEiIHgyPSIxIiB5MT0iMyIgeTI9IjQ5Ii8+PC9zdmc+' },
'Run': { name: 'Run', Type: RunTab, icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDUwIDUwIiBoZWlnaHQ9IjUwcHgiIGlkPSJMYXllcl8xIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MCA1MCIgd2lkdGg9IjUwcHgiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxyZWN0IGZpbGw9Im5vbmUiIGhlaWdodD0iNTAiIHdpZHRoPSI1MCIvPjxwYXRoIGQ9Ik00My43MzQsMjFjLTMuNjMxLDAtMTUuMDkyLDAtMTUuMDkyLDAgIFMxNi4yNSw1LjE4OCwxNi4wNDcsNC45MzhzLTAuNDIyLTAuNTk0LTEuMTI1LTAuNjcyYy0wLjg1OS0wLjA5NS0xLjk2OS0wLjIwMy0yLjMyOC0wLjIzNGMtMC40MDYtMC4wMzUtMC43MTksMC4xNDEtMC40OTYsMC43MzQgIEMxMi4zODgsNS41MzksMTguNzQ4LDIxLDE4Ljc0OCwyMUg2LjAzNGMwLDAtMi40NTgtNC43MjItMi44NzgtNS41MzFDMi45NjUsMTUuMTAxLDIuNTU3LDE1LjAxNCwyLDE1SDEuMjk3ICBjLTAuMTI1LDAtMC4zMTIsMC0wLjI4MSwwLjM0NEMxLjA1OCwxNS44MTEsMywyNSwzLDI1cy0xLjg4OCw5LjE5Ny0xLjk4NCw5LjY1NkMwLjk1MywzNC45NTMsMS4xNzIsMzUsMS4yOTcsMzVIMiAgYzAuOTY2LTAuMDA5LDAuOTU0LTAuMDc5LDEuMTU2LTAuNDY5QzMuNTc2LDMzLjcyMiw2LjAzNCwyOSw2LjAzNCwyOWgxMi43MTRjMCwwLTYuMzYsMTUuNDYxLTYuNjUsMTYuMjM0ICBjLTAuMjIzLDAuNTk0LDAuMDksMC43NywwLjQ5NiwwLjczNGMwLjM1OS0wLjAzMSwxLjQ2OS0wLjEzOSwyLjMyOC0wLjIzNGMwLjcwMy0wLjA3OCwwLjkyMi0wLjQyMiwxLjEyNS0wLjY3MlMyOC42NDMsMjksMjguNjQzLDI5ICBzMTEuNDYxLDAsMTUuMDkyLDBjMy43NjYsMCw1LjI2NC0zLjAzMSw1LjI2NC00UzQ3LjQ4NCwyMSw0My43MzQsMjF6IiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLXdpZHRoPSIyIi8+PC9zdmc+' },
'Solidity Static Analysis': { name: 'Solidity Static Analysis', Type: AnalysisTab, icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDUwIDUwIiBoZWlnaHQ9IjUwcHgiIGlkPSJMYXllcl8xIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MCA1MCIgd2lkdGg9IjUwcHgiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxyZWN0IGZpbGw9Im5vbmUiIGhlaWdodD0iNTAiIHdpZHRoPSI1MCIvPjxjaXJjbGUgY3g9IjIiIGN5PSIyNSIgcj0iMiIvPjxjaXJjbGUgY3g9IjE1IiBjeT0iMTkiIHI9IjIiLz48Y2lyY2xlIGN4PSIyNSIgY3k9IjExIiByPSIyIi8+PGNpcmNsZSBjeD0iMzUiIGN5PSIxNyIgcj0iMiIvPjxjaXJjbGUgY3g9IjQ4IiBjeT0iNSIgcj0iMiIvPjxjaXJjbGUgY3g9IjIiIGN5PSIzOSIgcj0iMiIvPjxjaXJjbGUgY3g9IjE1IiBjeT0iNDEiIHI9IjIiLz48Y2lyY2xlIGN4PSIyNSIgY3k9IjMzIiByPSIyIi8+PGNpcmNsZSBjeD0iMzUiIGN5PSI0MyIgcj0iMiIvPjxjaXJjbGUgY3g9IjQ4IiBjeT0iMzEiIHI9IjIiLz48cG9seWxpbmUgZmlsbD0ibm9uZSIgcG9pbnRzPSIyLDI1IDE1LDE5IDI1LDExICAgMzUsMTcgNDgsNSAiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iMiIvPjxwb2x5bGluZSBmaWxsPSJub25lIiBwb2ludHM9IjIsMzkgMTUsNDEgMjUsMzMgICAzNSw0MyA0OCwzMSAiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iMiIvPjwvc3ZnPg==' },
@ -45,6 +54,13 @@ class PluginManagerComponent {
}
initDefault () {
this.activateInternal('App')
this.activateInternal('Udapp')
this.activateInternal('FileManager')
this.activateInternal('SourceHighlighters')
this.activateInternal('Config')
this.activateInternal('TxListener')
this.activateInternal('FilePanel')
this.activateInternal('Solidity Compile')
this.activateInternal('Run')
@ -63,13 +79,12 @@ class PluginManagerComponent {
`
}
activatePlugin (name, api) {
let profile = { json: Plugin1Profile, api: pluginManagerApi }
activatePlugin (jsonProfile, api) {
let profile = { json: jsonProfile, api }
let plugin = new Plugin(profile, api)
this.appManager.addPlugin(plugin)
// Plugin1Profile.location
// mainpanel or swappanel or bottom-bar
// plugin.render() // plugin.create()
this.event.emit('displayableModuleActivated', jsonProfile, plugin.render())
this.activated[jsonProfile.name] = plugin
}
activateInternal (name) {
@ -78,12 +93,14 @@ class PluginManagerComponent {
if (mod.dep) dep = this.activateInternal(mod.dep)
let instance = mod.target
if (!instance && mod.Type) instance = new mod.Type(registry, dep)
if (!instance) return console.log('PluginManagerComponent: no Type or instance to add')
if (!instance) return console.log(`PluginManagerComponent: no Type or instance to add: ${JSON.stringify(mod)}`)
registry.put({api: instance, name: mod.name.toLocaleLowerCase()})
if (instance.profile && typeof instance.profile === 'function') {
this.event.emit('requestActivation', instance.profile(), instance)
}
this.event.emit('internalActivated', mod, instance.render())
if (mod.icon && instance.render && typeof instance.render === 'function') {
this.event.emit('requestContainer', mod, instance.render())
}
// if of type evm-compiler, we forward to the internal components
if (mod.class === 'evm-compiler') {
this.data.proxy.register(mod, instance)

@ -13,7 +13,7 @@ class SwapPanelApi {
verticalIconsComponent.event.on('showContent', (moduleName) => {
this.component.showContent(moduleName)
})
pluginManagerComponent.event.on('internalActivated', (mod, content) => {
pluginManagerComponent.event.on('requestContainer', (mod, content) => {
this.add(mod.name, content)
})
}

@ -10,7 +10,7 @@ class VerticalIconsApi {
constructor(verticalIconsComponent, pluginManagerComponent) {
this.component = verticalIconsComponent
pluginManagerComponent.event.on('internalActivated', (mod, content) => verticalIconsComponent.addIcon(mod) )
pluginManagerComponent.event.on('requestContainer', (mod, content) => verticalIconsComponent.addIcon(mod) )
}
}
module.exports = VerticalIconsApi

@ -0,0 +1,35 @@
'use strict'
var SourceHighlighter = require('./sourceHighlighter')
module.exports = class SourceHighlighters {
constructor () {
this.highlighters = {}
}
profile () {
return {
type: 'sourcehighlighter',
methods: ['highlight', 'discardHighlight']
}
}
// TODO what to do with mod?
highlight (mod, lineColumnPos, filePath, hexColor, cb) {
var position
try {
position = JSON.parse(lineColumnPos)
} catch (e) {
return cb(e.message)
}
if (!highlighters[mod]) highlighters[mod] = new SourceHighlighter()
highlighters[mod].currentSourceLocation(null)
highlighters[mod].currentSourceLocationFromfileName(position, filePath, hexColor)
cb()
}
discardHighlight (mod, cb) {
if (highlighters[mod]) highlighters[mod].currentSourceLocation(null)
cb()
}
}

@ -7,6 +7,7 @@ var ace = require('brace')
require('brace/theme/tomorrow_night_blue')
var globalRegistry = require('../../global/registry')
const SourceHighlighters = require('./SourceHighlighters')
var Range = ace.acequire('ace/range').Range
require('brace/ext/language_tools')
@ -317,6 +318,8 @@ function Editor (opts = {}, localRegistry) {
editor.commands.bindKeys({ 'ctrl-t': null })
editor.setShowPrintMargin(false)
editor.resize(true)
this.sourceHighlighters = new SourceHighlighters()
}
function editorOnChange (self) {

@ -130,6 +130,13 @@ function FilesTree (name, storage) {
if (path[0] === '/') return path.substring(1)
return path
}
this.profile = function () {
return {
type: this.type,
methods: ['get', 'set', 'remove']
}
}
}
module.exports = FilesTree

@ -2,6 +2,7 @@
var $ = require('jquery')
var yo = require('yo-yo')
var EventEmitter = require ('events')
var EventManager = require('../../lib/events')
var globalRegistry = require('../../global/registry')
var CompilerImport = require('../compiler/compiler-imports')
@ -15,6 +16,7 @@ class FileManager {
constructor (localRegistry) {
this.tabbedFiles = {}
this.event = new EventManager()
this.nodeEvent = new EventEmitter()
this._components = {}
this._components.compilerImport = new CompilerImport()
this._components.registry = localRegistry || globalRegistry
@ -42,6 +44,18 @@ class FileManager {
self._deps.gistExplorer.event.register('fileRemoved', (path) => { this.fileRemovedEvent(path) })
self._deps.localhostExplorer.event.register('errored', (event) => { this.removeTabsOf(self._deps.localhostExplorer) })
self._deps.localhostExplorer.event.register('closed', (event) => { this.removeTabsOf(self._deps.localhostExplorer) })
self.event.register('currentFileChanged', (file, provider) => {
this.nodeEvent.emit('currentFileChanged', file)
})
}
profile () {
return {
type: 'fileManager',
methods: ['getFilesFromPath', 'getCurrentFile', 'getFile', 'setFile'],
events: ['currentFileChanged']
}
}
fileRenamedEvent (oldName, newName, isFolder) {
@ -94,6 +108,41 @@ class FileManager {
return path ? path[1] : null
}
getCurrentFile (cb) {
var path = this.currentFile()
if (!path) {
cb('no file selected')
} else {
cb(null, path)
}
}
getFile (path, cb) {
var provider = this.fileProviderOf(path)
if (provider) {
// TODO add approval to user for external plugin to get the content of the given `path`
provider.get(path, (error, content) => {
cb(error, content)
})
} else {
cb(path + ' not available')
}
}
setFile (path, content, cb) {
var provider = this.fileProviderOf(path)
if (provider) {
// TODO add approval to user for external plugin to set the content of the given `path`
provider.set(path, content, (error) => {
if (error) return cb(error)
this.syncEditor(path)
cb()
})
} else {
cb(path + ' not available')
}
}
removeTabsOf (provider) {
for (var tab in this.tabbedFiles) {
if (this.fileProviderOf(tab).type === provider.type) {

@ -15,9 +15,11 @@ var css = styles.css
class EditorPanel {
constructor (localRegistry) {
var self = this
self.event = new EventManager()
self._components = {}
self._components.registry = localRegistry || globalRegistry
self.event = new EventManager()
self._components.editor = new Editor({})
self._components.registry.put({api: self._components.editor, name: 'editor'})
}
init () {
var self = this
@ -38,32 +40,26 @@ class EditorPanel {
}
}
self._view = {}
var editor = new Editor({})
self._components.registry.put({api: editor, name: 'editor'})
var contextualListener = new ContextualListener({editor, pluginManager: self._deps.pluginManager})
var contextView = new ContextView({contextualListener, editor})
var contextualListener = new ContextualListener({editor: self._components.editor, pluginManager: self._deps.pluginManager})
var contextView = new ContextView({contextualListener, editor: self._components.editor})
self._components = {
editor: editor,
contextualListener: contextualListener,
contextView: contextView,
// TODO list of compilers is always empty; should find a path to add plugin compiler here
terminal: new Terminal({
udapp: self._deps.udapp,
compilers: {}
},
{
getPosition: (event) => {
var limitUp = 36
var limitDown = 20
var height = window.innerHeight
var newpos = (event.pageY < limitUp) ? limitUp : event.pageY
newpos = (newpos < height - limitDown) ? newpos : height - limitDown
return newpos
}
})
}
self._components.contextualListener = contextualListener
self._components.contextView = contextView
self._components.terminal = new Terminal({
udapp: self._deps.udapp,
compilers: {}
},
{
getPosition: (event) => {
var limitUp = 36
var limitDown = 20
var height = window.innerHeight
var newpos = (event.pageY < limitUp) ? limitUp : event.pageY
newpos = (newpos < height - limitDown) ? newpos : height - limitDown
return newpos
}
})
self._components.terminal.event.register('filterChanged', (type, value) => {
this.event.trigger('terminalFilterChanged', [type, value])

@ -182,10 +182,13 @@ module.exports = class CompileTab {
}
})
}
getCompilationResult (cb) {
cb(null, self._components.compiler.lastCompilationResult)
}
profile () {
return {
type: 'solidityCompile',
methods: {},
methods: ['getCompilationResult'],
events: ['compilationFinished']
}
}

@ -51,6 +51,13 @@ function UniversalDApp (opts, localRegistry) {
self.resetEnvironment()
}
UniversalDApp.prototype.profile = function () {
return {
type: 'udapp',
methods: ['runTestTx', 'getAccounts', 'createVMAccount']
}
}
UniversalDApp.prototype.resetEnvironment = function () {
this.accounts = {}
if (executionContext.isVM()) {
@ -77,6 +84,7 @@ UniversalDApp.prototype.resetAPI = function (transactionContextAPI) {
}
UniversalDApp.prototype.createVMAccount = function (privateKey, balance, cb) {
if (executionContext.getProvider() !== 'vm') return cb('plugin API does not allow creating a new account through web3 connection. Only vm mode is allowed')
this._addAccount(privateKey, balance)
executionContext.vm().stateManager.cache.flush(function () {})
privateKey = Buffer.from(privateKey, 'hex')
@ -286,6 +294,34 @@ UniversalDApp.prototype.getInputs = function (funABI) {
return txHelper.inputParametersDeclarationToString(funABI.inputs)
}
/**
* This function send a tx only to javascript VM or testnet, will return an error for the mainnet
* SHOULD BE TAKEN CAREFULLY!
*
* @param {Object} tx - transaction.
* @param {Function} callback - callback.
*/
UniversalDApp.prototype.runTestTx = function (tx, cb) {
executionContext.detectNetwork((error, network) => {
if (error) return cb(error)
if (network.name === 'Main' && network.id === '1') {
return cb('It is not allowed to make this action against mainnet')
}
udapp.silentRunTx(tx, (error, result) => {
if (error) return cb(error)
cb(null, {
transactionHash: result.transactionHash,
status: result.result.status,
gasUsed: '0x' + result.result.gasUsed.toString('hex'),
error: result.result.vm.exceptionError,
return: result.result.vm.return ? '0x' + result.result.vm.return.toString('hex') : '0x',
createdAddress: result.result.createdAddress ? '0x' + result.result.createdAddress.toString('hex') : undefined
})
})
})
}
/**
* This function send a tx without alerting the user (if mainnet or if gas estimation too high).
* SHOULD BE TAKEN CAREFULLY!

Loading…
Cancel
Save