diff --git a/src/ui/CalldataPanel.js b/src/ui/CalldataPanel.js
index f5e6aa550f..e2fef57b74 100644
--- a/src/ui/CalldataPanel.js
+++ b/src/ui/CalldataPanel.js
@@ -5,7 +5,7 @@ var yo = require('yo-yo')
function CalldataPanel (_parent, _traceManager) {
this.parent = _parent
this.traceManager = _traceManager
- this.basicPanel = new DropdownPanel('Call Data')
+ this.basicPanel = new DropdownPanel('Call Data', {json: true})
this.init()
}
diff --git a/src/ui/CallstackPanel.js b/src/ui/CallstackPanel.js
index 6ceeca026c..a9ecdbac5e 100644
--- a/src/ui/CallstackPanel.js
+++ b/src/ui/CallstackPanel.js
@@ -5,7 +5,7 @@ var yo = require('yo-yo')
function CallstackPanel (_parent, _traceManager) {
this.parent = _parent
this.traceManager = _traceManager
- this.basicPanel = new DropdownPanel('Call Stack')
+ this.basicPanel = new DropdownPanel('Call Stack', {json: true})
this.init()
}
diff --git a/src/ui/CodeListView.js b/src/ui/CodeListView.js
index d355dbb751..3dc8fe0022 100644
--- a/src/ui/CodeListView.js
+++ b/src/ui/CodeListView.js
@@ -11,7 +11,7 @@ function CodeListView (_parent, _codeManager) {
this.address
this.codeView
this.itemSelected
- this.basicPanel = new DropdownPanel('Instructions', true)
+ this.basicPanel = new DropdownPanel('Instructions', {json: false})
this.init()
}
@@ -51,8 +51,7 @@ CodeListView.prototype.changed = function (code, address, index) {
this.code = code
this.address = address
this.codeView = this.renderAssemblyItems()
- this.basicPanel.data = this.codeView
- this.basicPanel.update()
+ this.basicPanel.setContent(this.codeView)
}
this.indexChanged(index)
}
diff --git a/src/ui/DropdownPanel.js b/src/ui/DropdownPanel.js
index 1caf7ea2dc..8f36e1071d 100644
--- a/src/ui/DropdownPanel.js
+++ b/src/ui/DropdownPanel.js
@@ -3,49 +3,40 @@ var yo = require('yo-yo')
var ui = require('../helpers/ui')
var styleDropdown = require('./styles/dropdownPanel')
var basicStyles = require('./styles/basicStyles')
+var TreeView = require('./TreeView')
-function DropdownPanel (_name, _raw) {
- this.data
+function DropdownPanel (_name, _opts) {
+ if (!_opts) {
+ _opts = {}
+ }
this.name = _name
+ this.json = _opts.json
+ if (this.json) {
+ this.treeView = new TreeView(_opts)
+ }
this.view
- _raw = _raw === undefined ? false : _raw
- this.raw = _raw
}
DropdownPanel.prototype.update = function (_data) {
- if (!this.view) {
- return
- }
- if (_data) {
- this.data = _data
- }
- this.view.querySelector('.dropdownpanel div.dropdowncontent').innerHTML = ''
- if (!this.raw) {
- var data = JSON.stringify(this.data, null, '\t')
- if (!this.data || data === '[]' || data === '{}') {
- this.data = ['Empty']
- }
- var div = document.createElement('div')
- if (Array.isArray(this.data)) {
- this.data.map(function (item, i) {
- div.appendChild(yo`
${item}
`)
- })
- } else {
- for (var k in this.data) {
- var content = typeof this.data[k] === 'string' ? this.data[k] : JSON.stringify(this.data[k])
- div.appendChild(yo``)
- }
- }
- this.view.querySelector('.dropdownpanel div.dropdowncontent').appendChild(div)
+ if (this.view) {
+ this.view.querySelector('.dropdownpanel .dropdownrawcontent').innerText = JSON.stringify(_data, null, '\t')
this.view.querySelector('.dropdownpanel button.btn').style.display = 'block'
- this.view.querySelector('.dropdownpanel .dropdownrawcontent').innerText = data
- } else {
- this.view.querySelector('.dropdownpanel div.dropdowncontent').appendChild(this.data)
- this.view.querySelector('.dropdownpanel button.btn').style.display = 'none'
+ if (this.json) {
+ this.treeView.update(_data)
+ }
}
}
+DropdownPanel.prototype.setContent = function (node) {
+ var parent = this.view.querySelector('.dropdownpanel div.dropdowncontent')
+ parent.replaceChild(node, parent.firstElementChild)
+}
+
DropdownPanel.prototype.render = function (overridestyle) {
+ var content = yo`Empty
`
+ if (this.json) {
+ content = this.treeView.render({})
+ }
overridestyle === undefined ? {} : overridestyle
var self = this
var view = yo`
@@ -55,7 +46,7 @@ DropdownPanel.prototype.render = function (overridestyle) {
`
diff --git a/src/ui/FullStoragesChanges.js b/src/ui/FullStoragesChanges.js
index 641b4e8879..9c4d4c6769 100644
--- a/src/ui/FullStoragesChanges.js
+++ b/src/ui/FullStoragesChanges.js
@@ -8,7 +8,7 @@ function FullStoragesChanges (_parent, _traceManager) {
this.addresses = []
this.view
this.traceLength
- this.basicPanel = new DropdownPanel('Full Storages Changes')
+ this.basicPanel = new DropdownPanel('Full Storages Changes', {json: true})
this.init()
}
diff --git a/src/ui/MemoryPanel.js b/src/ui/MemoryPanel.js
index e80166e31c..b48b59d49b 100644
--- a/src/ui/MemoryPanel.js
+++ b/src/ui/MemoryPanel.js
@@ -6,7 +6,11 @@ var yo = require('yo-yo')
function MemoryPanel (_parent, _traceManager) {
this.parent = _parent
this.traceManager = _traceManager
- this.basicPanel = new DropdownPanel('Memory')
+ this.basicPanel = new DropdownPanel('Memory', {
+ json: true,
+ css: {
+ 'font-family': 'monospace'
+ }})
this.init()
}
diff --git a/src/ui/SolidityLocals.js b/src/ui/SolidityLocals.js
index afbca77a78..df2826f950 100644
--- a/src/ui/SolidityLocals.js
+++ b/src/ui/SolidityLocals.js
@@ -9,7 +9,7 @@ class SolidityLocals {
this.parent = _parent
this.internalTreeCall = internalTreeCall
this.traceManager = _traceManager
- this.basicPanel = new DropdownPanel('Solidity Locals')
+ this.basicPanel = new DropdownPanel('Solidity Locals', {json: true})
this.init()
}
diff --git a/src/ui/SolidityState.js b/src/ui/SolidityState.js
index bc4cc24e38..22303f8082 100644
--- a/src/ui/SolidityState.js
+++ b/src/ui/SolidityState.js
@@ -8,7 +8,7 @@ function SolidityState (_parent, _traceManager, _codeManager, _solidityProxy) {
this.traceManager = _traceManager
this.codeManager = _codeManager
this.solidityProxy = _solidityProxy
- this.basicPanel = new DropdownPanel('Solidity State')
+ this.basicPanel = new DropdownPanel('Solidity State', {json: true})
this.init()
}
diff --git a/src/ui/StackPanel.js b/src/ui/StackPanel.js
index dbf83dbb4d..0460c8a3ea 100644
--- a/src/ui/StackPanel.js
+++ b/src/ui/StackPanel.js
@@ -6,7 +6,7 @@ var yo = require('yo-yo')
function StackPanel (_parent, _traceManager) {
this.parent = _parent
this.traceManager = _traceManager
- this.basicPanel = new DropdownPanel('Stack')
+ this.basicPanel = new DropdownPanel('Stack', {json: true})
this.init()
}
diff --git a/src/ui/StepDetail.js b/src/ui/StepDetail.js
index ac752e5a51..88950e4e93 100644
--- a/src/ui/StepDetail.js
+++ b/src/ui/StepDetail.js
@@ -6,7 +6,7 @@ function StepDetail (_parent, _traceManager) {
this.parent = _parent
this.traceManager = _traceManager
- this.basicPanel = new DropdownPanel('Step detail')
+ this.basicPanel = new DropdownPanel('Step detail', {json: true})
this.detail = initDetail()
this.view
diff --git a/src/ui/StoragePanel.js b/src/ui/StoragePanel.js
index f7f0c90a05..e0dd9612c9 100644
--- a/src/ui/StoragePanel.js
+++ b/src/ui/StoragePanel.js
@@ -5,7 +5,7 @@ var yo = require('yo-yo')
function StoragePanel (_parent, _traceManager, _address) {
this.parent = _parent
this.traceManager = _traceManager
- this.basicPanel = new DropdownPanel('Storage Changes')
+ this.basicPanel = new DropdownPanel('Storage Changes', {json: true})
this.address = _address
this.init()
this.disabled = false
diff --git a/src/ui/TreeView.js b/src/ui/TreeView.js
new file mode 100644
index 0000000000..49df208ce9
--- /dev/null
+++ b/src/ui/TreeView.js
@@ -0,0 +1,70 @@
+'use strict'
+var yo = require('yo-yo')
+var style = require('./styles/treeView')
+var ui = require('../helpers/ui')
+
+class TreeView {
+
+ constructor (opts) {
+ function noop (node) {
+ }
+ this.beforeJsonNodeRendered = opts.beforeJsonNodeRendered || noop
+ this.beforeJsonValueRendered = opts.beforeJsonValueRendered || noop
+ this.view = null
+ this.cssLabel = ui.formatCss(opts.css || {}, style.label)
+ this.cssList = ui.formatCss(opts.css || {}, style.list)
+ }
+
+ render (json) {
+ var view = yo`${this.renderProperties(json, true)}
`
+ if (!this.view) {
+ this.view = view
+ }
+ return view
+ }
+
+ update (json) {
+ if (this.view) {
+ yo.update(this.view, this.render(json), {onBeforeElUpdated: (fromEl, toEl) => {
+ toEl.style.display = fromEl.style.display
+ toEl.className = fromEl.className
+ return true
+ }})
+ }
+ }
+
+ renderObject (item, key, expand) {
+ var label
+ if (item instanceof Array || item instanceof Object) {
+ var properties = this.renderProperties(item, false)
+ label = yo``
+ var list = yo`${properties}`
+ list.style.display = expand ? 'block' : 'none'
+ label.firstElementChild.className = expand ? 'fa fa-caret-down' : 'fa fa-caret-right'
+ label.onclick = function () {
+ this.firstElementChild.className = this.firstElementChild.className === 'fa fa-caret-right' ? 'fa fa-caret-down' : 'fa fa-caret-right'
+ var list = this.parentElement.querySelector('ul')
+ list.style.display = list.style.display === 'none' ? 'block' : 'none'
+ }
+ if (this.beforeJsonNodeRendered) {
+ this.beforeJsonNodeRendered(label, item, key)
+ }
+ return yo`- ${label}${list}
`
+ } else {
+ label = yo``
+ if (this.beforeJsonValueRendered) {
+ this.beforeJsonValueRendered(label, item, key)
+ }
+ return yo`- ${label}: ${item}
`
+ }
+ }
+
+ renderProperties (json, expand) {
+ var properties = Object.keys(json).map((innerkey) => {
+ return this.renderObject(json[innerkey], innerkey, expand)
+ })
+ return properties
+ }
+}
+
+module.exports = TreeView
diff --git a/src/ui/TxBrowser.js b/src/ui/TxBrowser.js
index 1de5681882..1b929807aa 100644
--- a/src/ui/TxBrowser.js
+++ b/src/ui/TxBrowser.js
@@ -14,7 +14,7 @@ function TxBrowser (_parent) {
this.txNumber
this.view
this.displayConnectionSetting = true
- this.basicPanel = new DropdownPanel('Transaction')
+ this.basicPanel = new DropdownPanel('Transaction', {json: true})
this.basicPanel.data = {}
var self = this
_parent.event.register('providerChanged', this, function (provider) {
@@ -34,8 +34,7 @@ function TxBrowser (_parent) {
TxBrowser.prototype.setDefaultValues = function () {
this.connectInfo = ''
- this.basicPanel.data = {}
- this.basicPanel.update()
+ this.basicPanel.update({})
this.basicPanel.hide()
this.updateWeb3Url(util.web3.currentProvider.host)
if (this.view) {
@@ -86,8 +85,7 @@ TxBrowser.prototype.update = function (error, tx) {
this.view.querySelector('#error').innerHTML = 'Cannot find transaction with reference. Block number: ' + this.blockNumber + '. Transaction index/hash: ' + this.txNumber
}
}
- this.basicPanel.data = info
- this.basicPanel.update()
+ this.basicPanel.update(info)
}
TxBrowser.prototype.updateWeb3Url = function (newhost) {
diff --git a/src/ui/VmDebugger.js b/src/ui/VmDebugger.js
index b4527df70a..c43abcede8 100644
--- a/src/ui/VmDebugger.js
+++ b/src/ui/VmDebugger.js
@@ -24,17 +24,16 @@ function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy, _call
this.solidityLocals = new SolidityLocals(_parent, _traceManager, _callTree)
/* Return values - */
- this.returnValuesPanel = new DropdownPanel('Return Value')
+ this.returnValuesPanel = new DropdownPanel('Return Value', {json: true})
this.returnValuesPanel.data = {}
_parent.event.register('indexChanged', this.returnValuesPanel, function (index) {
var self = this
_traceManager.getReturnValue(index, function (error, returnValue) {
if (error) {
- self.data = [error]
+ self.update([error])
} else if (_parent.currentStepIndex === index) {
- self.data = [returnValue]
+ self.update([returnValue])
}
- self.update()
})
})
/* Return values - */
diff --git a/src/ui/styles/dropdownPanel.js b/src/ui/styles/dropdownPanel.js
index b3c6ec5d87..3fe1c47c3e 100644
--- a/src/ui/styles/dropdownPanel.js
+++ b/src/ui/styles/dropdownPanel.js
@@ -13,8 +13,7 @@ module.exports = {
},
content: {
'color': '#111111',
- 'width': '100%',
- 'font-family': 'monospace'
+ 'width': '100%'
},
inner: {
'padding': '2px',
diff --git a/src/ui/styles/treeView.js b/src/ui/styles/treeView.js
new file mode 100644
index 0000000000..b4c17c9efb
--- /dev/null
+++ b/src/ui/styles/treeView.js
@@ -0,0 +1,16 @@
+'use strict'
+module.exports = {
+ list: {
+ 'list-style-type': 'none',
+ '-webkit-margin-before': '0px',
+ '-webkit-margin-after': '0px',
+ '-webkit-margin-start': '0px',
+ '-webkit-margin-end': '0px',
+ '-webkit-padding-start': '0px',
+ 'margin-left': '10px'
+ },
+ label: {
+ 'vertical-align': 'top',
+ 'font-family': 'arial,sans-serif'
+ }
+}
diff --git a/test-browser/init.js b/test-browser/init.js
index 59d837f754..456d861420 100644
--- a/test-browser/init.js
+++ b/test-browser/init.js
@@ -32,7 +32,7 @@ function extendBrowser (browser) {
}
browser.assertStepDetail = function (vmtracestepinfo, stepinfo, addmemoryinfo, gasinfo, remaininggasinfo, loadedaddressinfo) {
- assertPanel('#stepdetail', browser, ['vmtracestep' + vmtracestepinfo, 'executionstep' + stepinfo, 'addmemory' + addmemoryinfo, 'gas' + gasinfo, 'remaininggas' + remaininggasinfo, 'loadedaddress' + loadedaddressinfo])
+ assertPanel('#stepdetail', browser, ['vmtracestep:' + vmtracestepinfo, 'executionstep:' + stepinfo, 'addmemory:' + addmemoryinfo, 'gas:' + gasinfo, 'remaininggas:' + remaininggasinfo, 'loadedaddress:' + loadedaddressinfo])
return browser
}
@@ -141,8 +141,12 @@ function assertPanel (id, browser, value) {
return ret
}, [id, selector], function (returnValues) {
value.map(function (item, index) {
- var testValue = returnValues.value[index].replace(/\r\n/g, '').replace(/\t/g, '').replace(/\s/g, '')
- browser.assert.equal(testValue, value[index])
+ if (returnValues.value.length) {
+ var testValue = returnValues.value[index].replace(/\r\n/g, '').replace(/\t/g, '').replace(/\s/g, '')
+ browser.assert.equal(testValue, value[index])
+ } else {
+ browser.assert.equal(item, '')
+ }
})
})
return browser
diff --git a/test-browser/vmdebugger.js b/test-browser/vmdebugger.js
index da35da8d89..81eb29477b 100644
--- a/test-browser/vmdebugger.js
+++ b/test-browser/vmdebugger.js
@@ -63,21 +63,20 @@ function panels (browser) {
.setValue('#txinput', '0x20ef65b8b186ca942fcccd634f37074dde49b541c27994fc7596740ef44cfd51')
.click('#load')
.click('#nextcall')
- .assertStack(['0x', '0x60', '0x65', '0x38', '0x55', '0x60fe47b1'])
- .pause(5000)
- .assertStorageChanges(['0x000x38'])
- .assertCallData(['0x60fe47b10000000000000000000000000000000000000000000000000000000000000038'])
- .assertCallStack(['0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5'])
- .assertStackValue(1, '0x60')
- .assertMemoryValue(6, '0x6060606040526040516020806045833981????R??Q????E?9?')
- .assertMemoryValue(7, '0x7001604052808051906020019091905050???R??Q???????PP')
- .assertMemoryValue(8, '0x805b806001016000600050819055505b50?????????P??UP?P')
+ .assertStack(['0:0x', '1:0x60', '2:0x65', '3:0x38', '4:0x55', '5:0x60fe47b1'])
+ .assertStorageChanges(['0x00:0x38'])
+ .assertCallData(['0:0x60fe47b10000000000000000000000000000000000000000000000000000000000000038'])
+ .assertCallStack(['0:0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5'])
+ .assertStackValue(1, '1:0x60')
+ .assertMemoryValue(6, '0x60:60606040526040516020806045833981????R??Q????E?9?')
+ .assertMemoryValue(7, '0x70:01604052808051906020019091905050???R??Q???????PP')
+ .assertMemoryValue(8, '0x80:5b806001016000600050819055505b50?????????P??UP?P')
.click('#intoforward') // CREATE
- .assertStack(['Empty'])
- .assertStorageChanges(['Empty'])
- .assertMemory(['Empty'])
- .assertCallData(['0x0000000000000000000000000000000000000000000000000000000000000000000000000000006060606040526040516020806045833981016040528080519060200190919050505b806001016000600050819055'])
- .assertCallStack(['0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', '(ContractCreation-Step63)'])
+ .assertStack([''])
+ .assertStorageChanges([''])
+ .assertMemory([''])
+ .assertCallData(['0:0x0000000000000000000000000000000000000000000000000000000000000000000000000000006060606040526040516020806045833981016040528080519060200190919050505b806001016000600050819055'])
+ .assertCallStack(['0:0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', '1:(ContractCreation-Step63)'])
return browser
}