parent
cfd41cb939
commit
beccd28a56
@ -1,279 +0,0 @@ |
||||
var TxBrowser = require('./debuggerUI/TxBrowser') |
||||
var StepManagerUI = require('./debuggerUI/StepManager') |
||||
var VmDebugger = require('./debuggerUI/VmDebugger') |
||||
var toaster = require('../../ui/tooltip') |
||||
|
||||
var Debugger = require('@remix-project/remix-debug').TransactionDebugger |
||||
|
||||
var SourceHighlighter = require('../../editor/sourceHighlighter') |
||||
|
||||
var EventManager = require('../../../lib/events') |
||||
|
||||
var globalRegistry = require('../../../global/registry') |
||||
|
||||
var remixDebug = require('@remix-project/remix-debug') |
||||
|
||||
var init = remixDebug.init |
||||
|
||||
var yo = require('yo-yo') |
||||
var csjs = require('csjs-inject') |
||||
|
||||
var css = csjs` |
||||
.statusMessage { |
||||
margin-left: 15px; |
||||
} |
||||
|
||||
.debuggerConfig { |
||||
display: flex; |
||||
align-items: center; |
||||
} |
||||
|
||||
.debuggerConfig label { |
||||
margin: 0; |
||||
} |
||||
|
||||
.debuggerSection { |
||||
padding: 12px 24px 16px; |
||||
} |
||||
|
||||
.debuggerLabel { |
||||
margin-bottom: 2px; |
||||
font-size: 11px; |
||||
line-height: 12px; |
||||
text-transform: uppercase; |
||||
} |
||||
` |
||||
|
||||
class DebuggerUI { |
||||
|
||||
constructor (debuggerModule, component, fetchContractAndCompile) { |
||||
this.debuggerModule = debuggerModule |
||||
this.fetchContractAndCompile = fetchContractAndCompile |
||||
this.event = new EventManager() |
||||
|
||||
this.isActive = false |
||||
this.opt = { |
||||
debugWithGeneratedSources: false |
||||
} |
||||
this.sourceHighlighter = new SourceHighlighter() |
||||
|
||||
this.startTxBrowser() |
||||
this.stepManager = null |
||||
|
||||
this.statusMessage = '' |
||||
this.currentReceipt |
||||
|
||||
this.view |
||||
|
||||
component.appendChild(this.render()) |
||||
|
||||
this.setEditor() |
||||
} |
||||
|
||||
setEditor () { |
||||
this.editor = globalRegistry.get('editor').api |
||||
|
||||
this.editor.event.register('breakpointCleared', (fileName, row) => { |
||||
if (this.debugger) this.debugger.breakPointManager.remove({fileName: fileName, row: row}) |
||||
}) |
||||
|
||||
this.editor.event.register('breakpointAdded', (fileName, row) => { |
||||
if (this.debugger) this.debugger.breakPointManager.add({fileName: fileName, row: row}) |
||||
}) |
||||
|
||||
this.editor.event.register('contentChanged', () => { |
||||
if (this.debugger) this.debugger.unload() |
||||
}) |
||||
} |
||||
|
||||
listenToEvents () { |
||||
if (!this.debugger) return |
||||
|
||||
this.debugger.event.register('debuggerStatus', async (isActive) => { |
||||
await this.debuggerModule.call('editor', 'discardHighlight') |
||||
this.isActive = isActive |
||||
}) |
||||
|
||||
this.debugger.event.register('newSourceLocation', async (lineColumnPos, rawLocation, generatedSources) => { |
||||
if (!lineColumnPos) return |
||||
const contracts = await this.fetchContractAndCompile( |
||||
this.currentReceipt.contractAddress || this.currentReceipt.to, |
||||
this.currentReceipt) |
||||
if (contracts) { |
||||
let path = contracts.getSourceName(rawLocation.file) |
||||
if (!path) { |
||||
// check in generated sources
|
||||
for (const source of generatedSources) { |
||||
if (source.id === rawLocation.file) { |
||||
path = `browser/.debugger/generated-sources/${source.name}` |
||||
let content |
||||
try { |
||||
content = await this.debuggerModule.call('fileManager', 'getFile', path, source.contents) |
||||
} catch (e) { |
||||
console.log('unable to fetch generated sources, the file probably doesn\'t exist yet', e) |
||||
} |
||||
if (content !== source.contents) { |
||||
await this.debuggerModule.call('fileManager', 'setFile', path, source.contents) |
||||
} |
||||
break |
||||
} |
||||
} |
||||
} |
||||
if (path) { |
||||
await this.debuggerModule.call('editor', 'discardHighlight') |
||||
await this.debuggerModule.call('editor', 'highlight', lineColumnPos, path) |
||||
} |
||||
} |
||||
}) |
||||
|
||||
this.debugger.event.register('debuggerUnloaded', () => this.unLoad()) |
||||
} |
||||
|
||||
startTxBrowser () { |
||||
let txBrowser = new TxBrowser() |
||||
this.txBrowser = txBrowser |
||||
|
||||
txBrowser.event.register('requestDebug', (blockNumber, txNumber, tx) => { |
||||
if (this.debugger) this.debugger.unload() |
||||
this.startDebugging(blockNumber, txNumber, tx) |
||||
}) |
||||
|
||||
txBrowser.event.register('unloadRequested', this, (blockNumber, txIndex, tx) => { |
||||
if (this.debugger) this.debugger.unload() |
||||
}) |
||||
} |
||||
|
||||
isDebuggerActive () { |
||||
return this.isActive |
||||
} |
||||
|
||||
getDebugWeb3 () { |
||||
return new Promise((resolve, reject) => { |
||||
this.debuggerModule.blockchain.detectNetwork((error, network) => { |
||||
let web3 |
||||
if (error || !network) { |
||||
web3 = init.web3DebugNode(this.debuggerModule.blockchain.web3()) |
||||
} else { |
||||
const webDebugNode = init.web3DebugNode(network.name) |
||||
web3 = !webDebugNode ? this.debuggerModule.blockchain.web3() : webDebugNode |
||||
} |
||||
init.extendWeb3(web3) |
||||
resolve(web3) |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
async startDebugging (blockNumber, txNumber, tx) { |
||||
if (this.debugger) this.unLoad() |
||||
|
||||
let web3 = await this.getDebugWeb3() |
||||
this.currentReceipt = await web3.eth.getTransactionReceipt(txNumber) |
||||
this.debugger = new Debugger({ |
||||
web3, |
||||
offsetToLineColumnConverter: globalRegistry.get('offsettolinecolumnconverter').api, |
||||
compilationResult: async (address) => { |
||||
try { |
||||
return await this.fetchContractAndCompile(address, this.currentReceipt) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
return null |
||||
}, |
||||
debugWithGeneratedSources: this.opt.debugWithGeneratedSources |
||||
}) |
||||
|
||||
this.listenToEvents() |
||||
this.debugger.debug(blockNumber, txNumber, tx, () => { |
||||
this.stepManager = new StepManagerUI(this.debugger.step_manager) |
||||
this.vmDebugger = new VmDebugger(this.debugger.vmDebuggerLogic) |
||||
this.txBrowser.setState({ blockNumber, txNumber, debugging: true }) |
||||
this.renderDebugger() |
||||
}).catch((error) => { |
||||
toaster(error) |
||||
this.unLoad() |
||||
}) |
||||
} |
||||
|
||||
getTrace (hash) { |
||||
return new Promise(async (resolve, reject) => { |
||||
const web3 = await this.getDebugWeb3() |
||||
|
||||
this.currentReceipt = await web3.eth.getTransactionReceipt(hash) |
||||
const debug = new Debugger({ |
||||
web3, |
||||
offsetToLineColumnConverter: globalRegistry.get('offsettolinecolumnconverter').api, |
||||
compilationResult: async (address) => { |
||||
try { |
||||
return await this.fetchContractAndCompile(address, this.currentReceipt) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
return null |
||||
}, |
||||
debugWithGeneratedSources: false |
||||
}) |
||||
debug.debugger.traceManager.traceRetriever.getTrace(hash, (error, trace) => { |
||||
if (error) return reject(error) |
||||
resolve(trace) |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
debug (txHash) { |
||||
this.startDebugging(null, txHash, null) |
||||
} |
||||
|
||||
render () { |
||||
this.debuggerPanelsView = yo`<div class="px-2"></div>` |
||||
this.debuggerHeadPanelsView = yo`<div class="px-2"></div>` |
||||
this.stepManagerView = yo`<div class="px-2"></div>` |
||||
|
||||
var view = yo` |
||||
<div> |
||||
<div class="px-2"> |
||||
<div class="mt-3"> |
||||
<p class="mt-2 ${css.debuggerLabel}">Debugger Configuration</p> |
||||
<div class="mt-2 ${css.debuggerConfig} custom-control custom-checkbox"> |
||||
<input class="custom-control-input" id="debugGeneratedSourcesInput" onchange=${(event) => { this.opt.debugWithGeneratedSources = event.target.checked }} type="checkbox" title="Debug with generated sources"> |
||||
<label data-id="debugGeneratedSourcesLabel" class="form-check-label custom-control-label" for="debugGeneratedSourcesInput">Use generated sources (from Solidity v0.7.2)</label> |
||||
</div> |
||||
</div> |
||||
${this.txBrowser.render()} |
||||
${this.stepManagerView} |
||||
${this.debuggerHeadPanelsView}
|
||||
<div class="${css.statusMessage}">${this.statusMessage}</div> |
||||
${this.debuggerPanelsView} |
||||
</div> |
||||
` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
async unLoad () { |
||||
yo.update(this.debuggerHeadPanelsView, yo`<div></div>`) |
||||
yo.update(this.debuggerPanelsView, yo`<div></div>`) |
||||
yo.update(this.stepManagerView, yo`<div></div>`) |
||||
if (this.vmDebugger) this.vmDebugger.remove() |
||||
if (this.stepManager) this.stepManager.remove() |
||||
if (this.txBrowser) this.txBrowser.setState({debugging: false}) |
||||
this.vmDebugger = null |
||||
this.stepManager = null |
||||
if (this.debugger) delete this.debugger |
||||
this.event.trigger('traceUnloaded') |
||||
} |
||||
|
||||
async deleteHighlights () { |
||||
await this.debuggerModule.call('editor', 'discardHighlight') |
||||
} |
||||
|
||||
renderDebugger () { |
||||
yo.update(this.debuggerHeadPanelsView, this.vmDebugger.renderHead()) |
||||
yo.update(this.debuggerPanelsView, this.vmDebugger.render()) |
||||
yo.update(this.stepManagerView, this.stepManager.render()) |
||||
} |
||||
|
||||
} |
||||
|
||||
module.exports = DebuggerUI |
@ -1,130 +0,0 @@ |
||||
'use strict' |
||||
var EventManager = require('../../../../lib/events') |
||||
var yo = require('yo-yo') |
||||
|
||||
var csjs = require('csjs-inject') |
||||
|
||||
var css = csjs` |
||||
.buttons { |
||||
display: flex; |
||||
flex-wrap: wrap; |
||||
} |
||||
.stepButtons { |
||||
width: 100%; |
||||
display: flex; |
||||
justify-content: center; |
||||
} |
||||
.stepButton { |
||||
} |
||||
.jumpButtons { |
||||
width: 100%; |
||||
display: flex; |
||||
justify-content: center; |
||||
} |
||||
.jumpButton { |
||||
} |
||||
.navigator { |
||||
} |
||||
.navigator:hover { |
||||
} |
||||
` |
||||
|
||||
function ButtonNavigator () { |
||||
this.event = new EventManager() |
||||
this.intoBackDisabled = true |
||||
this.overBackDisabled = true |
||||
this.intoForwardDisabled = true |
||||
this.overForwardDisabled = true |
||||
this.jumpOutDisabled = true |
||||
this.jumpNextBreakpointDisabled = true |
||||
this.jumpPreviousBreakpointDisabled = true |
||||
|
||||
this.view |
||||
} |
||||
|
||||
ButtonNavigator.prototype.render = function () { |
||||
var self = this |
||||
var view = yo`<div class="${css.buttons}">
|
||||
<div class="${css.stepButtons} btn-group py-1"> |
||||
<button id='overback' class='btn btn-primary btn-sm ${css.navigator} ${css.stepButton} fas fa-reply' title='Step over back' onclick=${function () { self.event.trigger('stepOverBack') }} disabled=${this.overBackDisabled} ></button> |
||||
<button id='intoback' data-id="buttonNavigatorIntoBack" class='btn btn-primary btn-sm ${css.navigator} ${css.stepButton} fas fa-level-up-alt' title='Step back' onclick=${function () { self.event.trigger('stepIntoBack') }} disabled=${this.intoBackDisabled} ></button> |
||||
<button id='intoforward' data-id="buttonNavigatorIntoForward" class='btn btn-primary btn-sm ${css.navigator} ${css.stepButton} fas fa-level-down-alt' title='Step into' onclick=${function () { self.event.trigger('stepIntoForward') }} disabled=${this.intoForwardDisabled} ></button> |
||||
<button id='overforward' class='btn btn-primary btn-sm ${css.navigator} ${css.stepButton} fas fa-share' title='Step over forward'onclick=${function () { self.event.trigger('stepOverForward') }} disabled=${this.overForwardDisabled} ></button> |
||||
</div> |
||||
|
||||
<div class="${css.jumpButtons} btn-group py-1"> |
||||
<button class='btn btn-primary btn-sm ${css.navigator} ${css.jumpButton} fas fa-step-backward' id='jumppreviousbreakpoint' data-id="buttonNavigatorJumpPreviousBreakpoint" title='Jump to the previous breakpoint' onclick=${function () { self.event.trigger('jumpPreviousBreakpoint') }} disabled=${this.jumpPreviousBreakpointDisabled} ></button> |
||||
<button class='btn btn-primary btn-sm ${css.navigator} ${css.jumpButton} fas fa-eject' id='jumpout' title='Jump out' onclick=${function () { self.event.trigger('jumpOut') }} disabled=${this.jumpOutDisabled} ></button> |
||||
<button class='btn btn-primary btn-sm ${css.navigator} ${css.jumpButton} fas fa-step-forward' id='jumpnextbreakpoint' data-id="buttonNavigatorJumpNextBreakpoint" title='Jump to the next breakpoint' onclick=${function () { self.event.trigger('jumpNextBreakpoint') }} disabled=${this.jumpNextBreakpointDisabled} ></button> |
||||
</div> |
||||
<div id='reverted' style="display:none"> |
||||
<button class='btn btn-danger btn-sm' id='jumptoexception' title='Jump to exception' class='${css.navigator} ${css.button} fas fa-exclamation-triangle' onclick=${function () { self.event.trigger('jumpToException') }} disabled=${this.jumpOutDisabled} > |
||||
</button> |
||||
<span>State changes made during this call will be reverted.</span> |
||||
<span id='outofgas' style="display:none">This call will run out of gas.</span> |
||||
<span id='parenthasthrown' style="display:none">The parent call will throw an exception</span> |
||||
</div> |
||||
</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
ButtonNavigator.prototype.reset = function () { |
||||
this.intoBackDisabled = true |
||||
this.overBackDisabled = true |
||||
this.intoForwardDisabled = true |
||||
this.overForwardDisabled = true |
||||
this.jumpOutDisabled = true |
||||
this.jumpNextBreakpointDisabled = true |
||||
this.jumpPreviousBreakpointDisabled = true |
||||
this.resetWarning('') |
||||
} |
||||
|
||||
ButtonNavigator.prototype.stepChanged = function (stepState, jumpOutDisabled) { |
||||
if (stepState === 'invalid') { |
||||
// TODO: probably not necessary, already implicit done in the next steps
|
||||
this.reset() |
||||
this.updateAll() |
||||
return |
||||
} |
||||
|
||||
this.intoBackDisabled = (stepState === 'initial') |
||||
this.overBackDisabled = (stepState === 'initial') |
||||
this.jumpPreviousBreakpointDisabled = (stepState === 'initial') |
||||
this.jumpNextBreakpointDisabled = (stepState === 'end') |
||||
this.intoForwardDisabled = (stepState === 'end') |
||||
this.overForwardDisabled = (stepState === 'end') |
||||
this.jumpNextBreakpointDisabled = jumpOutDisabled |
||||
|
||||
this.updateAll() |
||||
} |
||||
|
||||
ButtonNavigator.prototype.updateAll = function () { |
||||
this.updateDisabled('intoback', this.intoBackDisabled) |
||||
this.updateDisabled('overback', this.overBackDisabled) |
||||
this.updateDisabled('overforward', this.overForwardDisabled) |
||||
this.updateDisabled('intoforward', this.intoForwardDisabled) |
||||
this.updateDisabled('jumpout', this.jumpOutDisabled) |
||||
this.updateDisabled('jumptoexception', this.jumpOutDisabled) |
||||
this.updateDisabled('jumpnextbreakpoint', this.jumpNextBreakpointDisabled) |
||||
this.updateDisabled('jumppreviousbreakpoint', this.jumpPreviousBreakpointDisabled) |
||||
} |
||||
|
||||
ButtonNavigator.prototype.updateDisabled = function (id, disabled) { |
||||
if (disabled) { |
||||
document.getElementById(id).setAttribute('disabled', true) |
||||
} else { |
||||
document.getElementById(id).removeAttribute('disabled') |
||||
} |
||||
} |
||||
|
||||
ButtonNavigator.prototype.resetWarning = function (revertedReason) { |
||||
if (!this.view) return |
||||
this.view.querySelector('#reverted #outofgas').style.display = (revertedReason === 'outofgas') ? 'inline' : 'none' |
||||
this.view.querySelector('#reverted #parenthasthrown').style.display = (revertedReason === 'parenthasthrown') ? 'inline' : 'none' |
||||
this.view.querySelector('#reverted').style.display = (revertedReason === '') ? 'none' : 'block' |
||||
} |
||||
|
||||
module.exports = ButtonNavigator |
@ -1,57 +0,0 @@ |
||||
'use strict' |
||||
var EventManager = require('../../../../lib/events') |
||||
var yo = require('yo-yo') |
||||
|
||||
class Slider { |
||||
constructor () { |
||||
this.event = new EventManager() |
||||
this.max |
||||
this.disabled = true |
||||
this.view |
||||
this.previousValue = null |
||||
} |
||||
|
||||
setSliderLength (length) { |
||||
if (!this.view) return |
||||
this.view.querySelector('#slider').setAttribute('max', length - 1) |
||||
this.max = length - 1 |
||||
this.disabled = (length === 0) |
||||
|
||||
if (this.disabled) { |
||||
this.view.querySelector('#slider').setAttribute('disabled', true) |
||||
} else { |
||||
this.view.querySelector('#slider').removeAttribute('disabled') |
||||
} |
||||
|
||||
this.setValue(0) |
||||
} |
||||
|
||||
onChange (event) { |
||||
if (!this.view) return |
||||
var value = parseInt(this.view.querySelector('#slider').value) |
||||
if (value === this.previousValue) return |
||||
|
||||
this.previousValue = value |
||||
this.event.trigger('sliderMoved', [value]) |
||||
} |
||||
|
||||
setValue (value) { |
||||
if (!this.view) return |
||||
this.view.querySelector('#slider').value = value |
||||
} |
||||
|
||||
render () { |
||||
var self = this |
||||
var view = yo`<div>
|
||||
<input id='slider' data-id="slider" class='w-100 my-0' type='range' min=0 max=${this.max} value=0 |
||||
onchange=${function () { self.onChange() }} oninput=${function () { self.onChange() }} disabled=${this.disabled} /> |
||||
</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
} |
||||
|
||||
module.exports = Slider |
@ -1,59 +0,0 @@ |
||||
var EventManager = require('../../../../lib/events') |
||||
var yo = require('yo-yo') |
||||
|
||||
var ButtonNavigator = require('./ButtonNavigator') |
||||
var Slider = require('./Slider') |
||||
|
||||
function StepManager (stepManager) { |
||||
this.event = new EventManager() |
||||
this.stepManager = stepManager |
||||
this.startSlider() |
||||
this.startButtonNavigator() |
||||
this.stepManager.event.register('stepChanged', this.updateStep.bind(this)) |
||||
} |
||||
|
||||
StepManager.prototype.startSlider = function () { |
||||
this.slider = new Slider() |
||||
this.slider.event.register('sliderMoved', this.stepManager.jumpTo.bind(this.stepManager)) |
||||
this.stepManager.event.register('traceLengthChanged', this.slider.setSliderLength.bind(this.slider)) |
||||
} |
||||
|
||||
StepManager.prototype.startButtonNavigator = function () { |
||||
this.buttonNavigator = new ButtonNavigator() |
||||
|
||||
this.stepManager.event.register('revertWarning', this.buttonNavigator.resetWarning.bind(this.buttonNavigator)) |
||||
|
||||
this.buttonNavigator.event.register('stepIntoBack', this.stepManager.stepIntoBack.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('stepIntoForward', this.stepManager.stepIntoForward.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('stepOverBack', this.stepManager.stepOverBack.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('stepOverForward', this.stepManager.stepOverForward.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('jumpOut', this.stepManager.jumpOut.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('jumpToException', this.stepManager.jumpToException.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('jumpNextBreakpoint', this.stepManager.jumpNextBreakpoint.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('jumpPreviousBreakpoint', this.stepManager.jumpPreviousBreakpoint.bind(this.stepManager)) |
||||
} |
||||
|
||||
StepManager.prototype.updateStep = function (step, stepState, jumpOutDisabled) { |
||||
if (!this.slider) return |
||||
this.slider.setValue(step) |
||||
this.buttonNavigator.stepChanged(stepState, jumpOutDisabled) |
||||
this.event.trigger('stepChanged', [step]) |
||||
} |
||||
|
||||
StepManager.prototype.remove = function () { |
||||
// used to stop listenning on event. bad and should be "refactored"
|
||||
this.slider.view = null |
||||
this.slider = null |
||||
this.buttonNavigator.view = null |
||||
this.buttonNavigator = null |
||||
} |
||||
|
||||
StepManager.prototype.render = function () { |
||||
return yo` |
||||
<div class="py-1"> |
||||
${this.slider.render()} |
||||
${this.buttonNavigator.render()} |
||||
</div>` |
||||
} |
||||
|
||||
module.exports = StepManager |
@ -1,137 +0,0 @@ |
||||
var EventManager = require('../../../../lib/events') |
||||
var yo = require('yo-yo') |
||||
var csjs = require('csjs-inject') |
||||
|
||||
var css = csjs` |
||||
.container { |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
||||
.txContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
||||
.txinput { |
||||
width: inherit; |
||||
font-size: small; |
||||
white-space: nowrap; |
||||
overflow: hidden; |
||||
text-overflow: ellipsis; |
||||
} |
||||
.txbutton { |
||||
width: inherit; |
||||
} |
||||
.txbutton:hover { |
||||
} |
||||
.vmargin { |
||||
margin-top: 10px; |
||||
margin-bottom: 10px; |
||||
} |
||||
` |
||||
|
||||
function TxBrowser () { |
||||
this.event = new EventManager() |
||||
|
||||
this.state = { |
||||
txNumber: undefined, |
||||
debugging: false |
||||
} |
||||
this.view |
||||
} |
||||
|
||||
TxBrowser.prototype.submit = function () { |
||||
if (this.state.debugging) { |
||||
this.unload() |
||||
} else { |
||||
this.event.trigger('requestDebug', [undefined, this.state.txNumber]) |
||||
} |
||||
yo.update(this.view, this.render()) |
||||
} |
||||
|
||||
TxBrowser.prototype.updateTxN = function (ev) { |
||||
this.state.txNumber = ev.target.value |
||||
if (this.view) { |
||||
yo.update(this.view, this.render()) |
||||
} |
||||
} |
||||
|
||||
TxBrowser.prototype.load = function (txHash, tx) { |
||||
this.state.txNumber = txHash |
||||
} |
||||
|
||||
TxBrowser.prototype.unload = function () { |
||||
this.event.trigger('unloadRequested') |
||||
} |
||||
|
||||
TxBrowser.prototype.setState = function (state) { |
||||
this.state = {...this.state, ...state} |
||||
if (this.view) { |
||||
yo.update(this.view, this.render()) |
||||
} |
||||
} |
||||
|
||||
TxBrowser.prototype.render = function () { |
||||
var self = this |
||||
this.state.txNumberInput = yo` |
||||
<input |
||||
value="${this.state.txNumber || ''}" |
||||
class="form-control m-0 ${css.txinput}" |
||||
id='txinput' |
||||
onkeyup=${function () { self.updateTxN(arguments[0]) }} |
||||
type='text' |
||||
oninput=${this.txInputChanged.bind(this)} |
||||
placeholder=${'Transaction hash, should start with 0x'} |
||||
data-id="debuggerTransactionInput" |
||||
/> |
||||
` |
||||
let txButton = yo` |
||||
<button |
||||
class='btn btn-primary btn-sm ${css.txbutton}' |
||||
id='load' |
||||
title='${this.state.debugging ? 'Stop' : 'Start'} debugging' |
||||
onclick=${function () { self.submit() }} |
||||
data-id="debuggerTransactionStartButton" |
||||
> |
||||
${this.state.debugging ? 'Stop' : 'Start'} debugging |
||||
</button> |
||||
` |
||||
var view = yo` |
||||
<div class="${css.container}"> |
||||
<div class="${css.txContainer}"> |
||||
<div class=" py-1 d-flex justify-content-center w-100 input-group"> |
||||
${this.state.txNumberInput} |
||||
</div> |
||||
<div class="d-flex justify-content-center w-100 btn-group py-1"> |
||||
${txButton} |
||||
</div> |
||||
</div> |
||||
<span id='error'></span> |
||||
</div> |
||||
` |
||||
if (this.state.debugging) { |
||||
view.querySelectorAll('input').forEach(element => { element.setAttribute('disabled', '') }) |
||||
} |
||||
if (!this.state.txNumber) { |
||||
view.querySelector("button[id='load']").setAttribute('disabled', '') |
||||
} else if (!this.state.debugging) { |
||||
this.state.txNumberInput.removeAttribute('disabled') |
||||
} |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
|
||||
return view |
||||
} |
||||
|
||||
TxBrowser.prototype.txInputChanged = function (event) { |
||||
// todo check validation of txnumber in the input element, use
|
||||
// required
|
||||
// oninvalid="setCustomValidity('Please provide a valid transaction number, must start with 0x and have length of 22')"
|
||||
// pattern="^0[x,X]+[0-9a-fA-F]{22}"
|
||||
// this.state.txNumberInput.setCustomValidity('')
|
||||
|
||||
this.state.txNumber = event.target.value |
||||
yo.update(this.view, this.render()) |
||||
} |
||||
|
||||
module.exports = TxBrowser |
@ -1,179 +0,0 @@ |
||||
'use strict' |
||||
var yo = require('yo-yo') |
||||
|
||||
var CodeListView = require('./vmDebugger/CodeListView') |
||||
var CalldataPanel = require('./vmDebugger/CalldataPanel') |
||||
var MemoryPanel = require('./vmDebugger/MemoryPanel') |
||||
var CallstackPanel = require('./vmDebugger/CallstackPanel') |
||||
var FunctionPanel = require('./vmDebugger/FunctionPanel') |
||||
var StackPanel = require('./vmDebugger/StackPanel') |
||||
var StoragePanel = require('./vmDebugger/StoragePanel') |
||||
var StepDetail = require('./vmDebugger/StepDetail') |
||||
var SolidityState = require('./vmDebugger/SolidityState') |
||||
var SolidityLocals = require('./vmDebugger/SolidityLocals') |
||||
var FullStoragesChangesPanel = require('./vmDebugger/FullStoragesChanges') |
||||
var DropdownPanel = require('./vmDebugger/DropdownPanel') |
||||
|
||||
function VmDebugger (vmDebuggerLogic) { |
||||
var self = this |
||||
this.view |
||||
|
||||
this.vmDebuggerLogic = vmDebuggerLogic |
||||
|
||||
this.asmCode = new CodeListView() |
||||
this.vmDebuggerLogic.event.register('codeManagerChanged', this.asmCode.changed.bind(this.asmCode)) |
||||
this.vmDebuggerLogic.event.register('traceUnloaded', this.asmCode.reset.bind(this.asmCode)) |
||||
|
||||
this.calldataPanel = new CalldataPanel() |
||||
this.vmDebuggerLogic.event.register('traceManagerCallDataUpdate', this.calldataPanel.update.bind(this.calldataPanel)) |
||||
|
||||
this.memoryPanel = new MemoryPanel() |
||||
this.vmDebuggerLogic.event.register('traceManagerMemoryUpdate', this.memoryPanel.update.bind(this.memoryPanel)) |
||||
|
||||
this.callstackPanel = new CallstackPanel() |
||||
this.vmDebuggerLogic.event.register('traceManagerCallStackUpdate', this.callstackPanel.update.bind(this.callstackPanel)) |
||||
|
||||
this.stackPanel = new StackPanel() |
||||
this.vmDebuggerLogic.event.register('traceManagerStackUpdate', this.stackPanel.update.bind(this.stackPanel)) |
||||
|
||||
this.functionPanel = new FunctionPanel() |
||||
this.vmDebuggerLogic.event.register('functionsStackUpdate', (stack) => { |
||||
if (stack === null || stack.length === 0) return |
||||
let functions = [] |
||||
for (let func of stack) { |
||||
functions.push(func.functionDefinition.name + '(' + func.inputs.join(', ') + ')') |
||||
} |
||||
this.functionPanel.update(functions) |
||||
}) |
||||
|
||||
this.storagePanel = new StoragePanel() |
||||
this.vmDebuggerLogic.event.register('traceManagerStorageUpdate', this.storagePanel.update.bind(this.storagePanel)) |
||||
|
||||
this.stepDetail = new StepDetail() |
||||
this.vmDebuggerLogic.event.register('traceUnloaded', this.stepDetail.reset.bind(this.stepDetail)) |
||||
this.vmDebuggerLogic.event.register('newTraceLoaded', this.stepDetail.reset.bind(this.stepDetail)) |
||||
|
||||
this.vmDebuggerLogic.event.register('traceCurrentStepUpdate', function (error, step) { |
||||
self.stepDetail.updateField('execution step', (error ? '-' : step)) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('traceMemExpandUpdate', function (error, addmem) { |
||||
self.stepDetail.updateField('add memory', (error ? '-' : addmem)) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('traceStepCostUpdate', function (error, gas) { |
||||
self.stepDetail.updateField('gas', (error ? '-' : gas)) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('traceCurrentCalledAddressAtUpdate', function (error, address) { |
||||
self.stepDetail.updateField('loaded address', (error ? '-' : address)) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('traceRemainingGasUpdate', function (error, remainingGas) { |
||||
self.stepDetail.updateField('remaining gas', (error ? '-' : remainingGas)) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('indexUpdate', function (index) { |
||||
self.stepDetail.updateField('vm trace step', index) |
||||
}) |
||||
|
||||
this.solidityState = new SolidityState() |
||||
this.vmDebuggerLogic.event.register('solidityState', this.solidityState.update.bind(this.solidityState)) |
||||
this.vmDebuggerLogic.event.register('solidityStateMessage', this.solidityState.setMessage.bind(this.solidityState)) |
||||
this.vmDebuggerLogic.event.register('solidityStateUpdating', this.solidityState.setUpdating.bind(this.solidityState)) |
||||
|
||||
this.solidityLocals = new SolidityLocals() |
||||
this.solidityLocals.event.register('solidityLocalsLoadMore', (cursor) => { |
||||
this.vmDebuggerLogic.event.trigger('solidityLocalsLoadMore', [cursor]) |
||||
}) |
||||
this.vmDebuggerLogic.event.register('solidityLocals', this.solidityLocals.update.bind(this.solidityLocals)) |
||||
this.vmDebuggerLogic.event.register('solidityLocalsMessage', this.solidityLocals.setMessage.bind(this.solidityLocals)) |
||||
this.vmDebuggerLogic.event.register('solidityLocalsUpdating', this.solidityLocals.setUpdating.bind(this.solidityLocals)) |
||||
this.vmDebuggerLogic.event.register('solidityLocalsLoadMoreCompleted', this.solidityLocals.loadMore.bind(this.solidityLocals)) |
||||
|
||||
this.returnValuesPanel = new DropdownPanel('Return Value', {json: true}) |
||||
this.returnValuesPanel.data = {} |
||||
this.vmDebuggerLogic.event.register('traceReturnValueUpdate', this.returnValuesPanel.update.bind(this.returnValuesPanel)) |
||||
|
||||
this.fullStoragesChangesPanel = new FullStoragesChangesPanel() |
||||
this.addresses = [] |
||||
|
||||
this.vmDebuggerLogic.event.register('traceAddressesUpdate', function (_addresses) { |
||||
self.fullStoragesChangesPanel.update({}) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('traceStorageUpdate', this.fullStoragesChangesPanel.update.bind(this.fullStoragesChangesPanel)) |
||||
|
||||
this.vmDebuggerLogic.event.register('newTrace', () => { |
||||
if (!self.view) return |
||||
|
||||
self.asmCode.basicPanel.show() |
||||
self.stackPanel.basicPanel.show() |
||||
self.functionPanel.basicPanel.show() |
||||
self.storagePanel.basicPanel.show() |
||||
self.memoryPanel.basicPanel.show() |
||||
self.stepDetail.basicPanel.show() |
||||
self.calldataPanel.basicPanel.show() |
||||
self.callstackPanel.basicPanel.show() |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('newCallTree', () => { |
||||
if (!self.view) return |
||||
self.functionPanel.basicPanel.show() |
||||
self.solidityLocals.basicPanel.show() |
||||
self.solidityState.basicPanel.show() |
||||
self.solidityPanel.hidden = false |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.start() |
||||
} |
||||
|
||||
VmDebugger.prototype.renderHead = function () { |
||||
this.solidityPanel = yo` |
||||
<div class="w-100" hidden> |
||||
${this.functionPanel.render()} |
||||
${this.solidityLocals.render()} |
||||
${this.solidityState.render()} |
||||
</div> |
||||
` |
||||
const headView = yo` |
||||
<div id="vmheadView" class="mt-1 px-0"> |
||||
<div class="d-flex flex-column"> |
||||
${this.solidityPanel} |
||||
<div class="w-100">${this.asmCode.render()}</div> |
||||
<div class="w-100">${this.stepDetail.render()}</div> |
||||
</div> |
||||
</div> |
||||
` |
||||
if (!this.headView) { |
||||
this.headView = headView |
||||
} |
||||
return headView |
||||
} |
||||
|
||||
VmDebugger.prototype.remove = function () { |
||||
// used to stop listenning on event. bad and should be "refactored"
|
||||
this.view = null |
||||
} |
||||
|
||||
VmDebugger.prototype.render = function () { |
||||
const view = yo` |
||||
<div id="vmdebugger" class="px-2"> |
||||
<div> |
||||
${this.stackPanel.render()} |
||||
${this.memoryPanel.render()} |
||||
${this.storagePanel.render()} |
||||
${this.callstackPanel.render()} |
||||
${this.calldataPanel.render()} |
||||
${this.returnValuesPanel.render()} |
||||
${this.fullStoragesChangesPanel.render()} |
||||
</div> |
||||
</div> |
||||
` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
module.exports = VmDebugger |
@ -1,76 +0,0 @@ |
||||
'use strict' |
||||
module.exports = { |
||||
truncate: { |
||||
'white-space': 'nowrap', |
||||
'overflow': 'hidden', |
||||
'text-overflow': 'ellipsis', |
||||
'margin-right': '5px' |
||||
}, |
||||
font: { |
||||
'font-family': 'arial,sans-serif' |
||||
}, |
||||
statusMessage: { |
||||
'margin-left': '15px' |
||||
}, |
||||
address: { |
||||
'font-style': 'italic' |
||||
}, |
||||
instructionsList: { |
||||
'width': '52%', |
||||
'overflow-y': 'scroll', |
||||
'max-height': '250px', |
||||
'margin': '0', |
||||
'margin-left': '10px', |
||||
'padding': '2px' |
||||
}, |
||||
transactionInfo: { |
||||
'margin-top': '5px' |
||||
}, |
||||
panel: { |
||||
container: { |
||||
'border': '1px solid', |
||||
'width': '70%' |
||||
}, |
||||
tableContainer: { |
||||
'height': '50%', |
||||
'overflow-y': 'auto' |
||||
}, |
||||
table: { |
||||
'padding': '5px' |
||||
}, |
||||
title: { |
||||
'padding': '5px', |
||||
'font-style': 'italic' |
||||
} |
||||
}, |
||||
hidden: { |
||||
'display': 'none' |
||||
}, |
||||
display: { |
||||
'display': 'block' |
||||
}, |
||||
inline: { |
||||
'display': 'inline-block' |
||||
}, |
||||
vmargin: { |
||||
'margin-top': '10px', |
||||
'margin-bottom': '10px' |
||||
}, |
||||
button: { |
||||
'border-color': 'transparent', |
||||
'border-radius': '3px', |
||||
'border': '.3px solid hsla(0, 0%, 40%, 1)', |
||||
'cursor': 'pointer', |
||||
'min-height': '25px', |
||||
'max-height': '25px', |
||||
'padding': '3px', |
||||
'min-width': '100px', |
||||
'font-size': '12px', |
||||
'overflow': 'hidden', |
||||
'word-break': 'normal', |
||||
'background-color': 'hsla(0, 0%, 40%, .2)', |
||||
'color': 'hsla(0, 0%, 40%, 1)', |
||||
'margin': '3px', |
||||
'text-decoration': 'none' |
||||
} |
||||
} |
@ -1,31 +0,0 @@ |
||||
'use strict' |
||||
module.exports = { |
||||
title: { |
||||
'border': '1px solid #dadada', |
||||
'background-color': 'white', |
||||
'width': '100%', |
||||
'color': '#363f47', |
||||
'margin-top': '5px', |
||||
'cursor': 'pointer' |
||||
}, |
||||
titleInner: { |
||||
'display': 'inline-block' |
||||
}, |
||||
content: { |
||||
'color': '#111111', |
||||
'width': '100%', |
||||
'min-height': '20px' |
||||
}, |
||||
inner: { |
||||
'padding': '2px', |
||||
'word-break': 'break-all' |
||||
}, |
||||
copyBtn: { |
||||
'float': 'right', |
||||
'margin-top': '3px' |
||||
}, |
||||
caret: { |
||||
'margin-left': '10px', |
||||
'margin-right': '10px' |
||||
} |
||||
} |
@ -1,6 +0,0 @@ |
||||
'use strict' |
||||
module.exports = { |
||||
rule: { |
||||
'width': '100%' |
||||
} |
||||
} |
@ -1,30 +0,0 @@ |
||||
'use strict' |
||||
module.exports = { |
||||
cssUl: { |
||||
'list-style-type': 'none', |
||||
'-webkit-margin-before': '0px', |
||||
'-webkit-margin-after': '0px', |
||||
'-webkit-margin-start': '0px', |
||||
'-webkit-margin-end': '0px', |
||||
'-webkit-padding-start': '0px' |
||||
}, |
||||
cssLi: { |
||||
'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' |
||||
}, |
||||
caret: { |
||||
'margin-top': '3px', |
||||
'width': '10px' |
||||
}, |
||||
data: { |
||||
} |
||||
} |
@ -1,17 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function CalldataPanel () { |
||||
this.basicPanel = new DropdownPanel('Call Data', {json: true}) |
||||
} |
||||
|
||||
CalldataPanel.prototype.update = function (calldata) { |
||||
this.basicPanel.update(calldata) |
||||
} |
||||
|
||||
CalldataPanel.prototype.render = function () { |
||||
return yo`<div id='calldatapanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = CalldataPanel |
@ -1,18 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function CallstackPanel () { |
||||
this.basicPanel = new DropdownPanel('Call Stack', {json: true}) |
||||
} |
||||
|
||||
CallstackPanel.prototype.update = function (calldata) { |
||||
this.basicPanel.update(calldata) |
||||
} |
||||
|
||||
CallstackPanel.prototype.render = function () { |
||||
return yo`<div id='callstackpanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = CallstackPanel |
||||
|
@ -1,75 +0,0 @@ |
||||
'use strict' |
||||
var style = require('../styles/basicStyles') |
||||
var yo = require('yo-yo') |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var EventManager = require('../../../../../lib/events') |
||||
var csjs = require('csjs-inject') |
||||
|
||||
var css = csjs` |
||||
.instructions { |
||||
overflow-y: scroll; |
||||
max-height: 130px; |
||||
} |
||||
` |
||||
function CodeListView () { |
||||
this.event = new EventManager() |
||||
this.code |
||||
this.address |
||||
this.itemSelected |
||||
this.basicPanel = new DropdownPanel('Instructions', {json: false, displayContentOnly: true}) |
||||
this.basicPanel.event.register('hide', () => { |
||||
this.event.trigger('hide', []) |
||||
}) |
||||
this.basicPanel.event.register('show', () => { |
||||
this.event.trigger('show', []) |
||||
}) |
||||
} |
||||
|
||||
CodeListView.prototype.render = function () { |
||||
this.view = yo`<div id='asmcodes' >${this.basicPanel.render({height: style.instructionsList.height})}</div>` |
||||
return this.view |
||||
} |
||||
|
||||
CodeListView.prototype.indexChanged = function (index) { |
||||
if (index < 0) return |
||||
if (this.itemSelected) { |
||||
this.itemSelected.removeAttribute('selected') |
||||
this.itemSelected.removeAttribute('style') |
||||
if (this.itemSelected.firstChild) { |
||||
this.itemSelected.firstChild.removeAttribute('style') |
||||
} |
||||
} |
||||
let codeView = this.view.querySelector('#asmitems') |
||||
this.itemSelected = codeView.children[index] |
||||
this.itemSelected.style.setProperty('border-color', 'var(--primary)') |
||||
this.itemSelected.style.setProperty('border-style', 'solid') |
||||
this.itemSelected.setAttribute('selected', 'selected') |
||||
codeView.scrollTop = this.itemSelected.offsetTop - parseInt(codeView.offsetTop) |
||||
} |
||||
|
||||
CodeListView.prototype.reset = function () { |
||||
this.changed([], '', -1) |
||||
} |
||||
|
||||
CodeListView.prototype.changed = function (code, address, index) { |
||||
if (this.address === address) { |
||||
return this.indexChanged(index) |
||||
} |
||||
this.code = code |
||||
this.address = address |
||||
this.basicPanel.setContent(this.renderAssemblyItems()) |
||||
this.indexChanged(index) |
||||
} |
||||
|
||||
CodeListView.prototype.renderAssemblyItems = function () { |
||||
if (this.code) { |
||||
var codeView = this.code.map(function (item, i) { |
||||
return yo`<div class="px-1" key=${i} value=${i}><span>${item}</span></div>` |
||||
}) |
||||
return yo`<div class="pl-2 my-1 small ${css.instructions}" id='asmitems' ref='itemsList'>
|
||||
${codeView} |
||||
</div>` |
||||
} |
||||
} |
||||
|
||||
module.exports = CodeListView |
@ -1,189 +0,0 @@ |
||||
'use strict' |
||||
const yo = require('yo-yo') |
||||
const copyToClipboard = require('../../../../ui/copy-to-clipboard') |
||||
const EventManager = require('../../../../../lib/events') |
||||
const TreeView = require('../../../../ui/TreeView') // TODO setup a direct reference to the UI components
|
||||
|
||||
const csjs = require('csjs-inject') |
||||
|
||||
const css = csjs` |
||||
.title { |
||||
display: flex; |
||||
align-items: center; |
||||
} |
||||
.name { |
||||
font-weight: bold; |
||||
} |
||||
.nameDetail { |
||||
font-weight: bold; |
||||
margin-left: 3px; |
||||
} |
||||
.icon { |
||||
margin-right: 5%; |
||||
} |
||||
.eyeButton { |
||||
margin: 3px; |
||||
} |
||||
.dropdownpanel { |
||||
width: 100%; |
||||
word-break: break-word; |
||||
} |
||||
.dropdownrawcontent { |
||||
padding: 2px; |
||||
word-break: break-word; |
||||
} |
||||
.message { |
||||
padding: 2px; |
||||
word-break: break-word; |
||||
} |
||||
.refresh { |
||||
display: none; |
||||
margin-left: 4px; |
||||
margin-top: 4px;
|
||||
animation: spin 2s linear infinite; |
||||
} |
||||
` |
||||
|
||||
function DropdownPanel (_name, _opts) { |
||||
this.event = new EventManager() |
||||
if (!_opts) { |
||||
_opts = {} |
||||
} |
||||
this.name = _name |
||||
this.header = '' |
||||
this.json = _opts.json |
||||
this.displayContentOnly = _opts.displayContentOnly |
||||
if (this.json) { |
||||
this.treeView = new TreeView(_opts) |
||||
} |
||||
this.view |
||||
} |
||||
|
||||
DropdownPanel.prototype.setMessage = function (message) { |
||||
if (!this.view) return |
||||
this.view.querySelector('.dropdownpanel .dropdownrawcontent').style.display = 'none' |
||||
this.view.querySelector('.dropdownpanel .dropdowncontent').style.display = 'none' |
||||
this.view.querySelector('.dropdownpanel > i').style.display = 'none' |
||||
this.message(message) |
||||
} |
||||
|
||||
DropdownPanel.prototype.setLoading = function () { |
||||
if (!this.view) return |
||||
this.view.querySelector('.dropdownpanel .dropdownrawcontent').style.display = 'none' |
||||
this.view.querySelector('.dropdownpanel .dropdowncontent').style.display = 'none' |
||||
this.view.querySelector('.dropdownpanel > i').style.display = 'inline-block' |
||||
this.message('') |
||||
} |
||||
|
||||
DropdownPanel.prototype.setUpdating = function () { |
||||
if (!this.view) return |
||||
} |
||||
|
||||
DropdownPanel.prototype.update = function (_data, _header) { |
||||
if (!this.view) return |
||||
this.view.querySelector('.dropdownpanel > i').style.display = 'none' |
||||
this.view.querySelector('.dropdownpanel .dropdowncontent').style.display = 'block' |
||||
this.view.querySelector('.dropdownpanel .dropdownrawcontent').innerText = JSON.stringify(_data, null, '\t') |
||||
if (!this.displayContentOnly) { |
||||
this.view.querySelector('.title i.fa-copy').style.display = 'block' |
||||
this.view.querySelector('.title span').innerText = _header || ' ' |
||||
} |
||||
this.message('') |
||||
if (this.json) { |
||||
this.treeView.update(_data) |
||||
} |
||||
} |
||||
|
||||
DropdownPanel.prototype.setContent = function (node) { |
||||
if (!this.view) return |
||||
yo.update(this.view, this.render(null, node)) |
||||
} |
||||
|
||||
DropdownPanel.prototype.copyClipboard = function () { |
||||
const content = this.view.querySelector('.dropdownpanel .dropdownrawcontent') |
||||
return content.innerText ? content.innerText : content.textContent |
||||
} |
||||
|
||||
DropdownPanel.prototype.render = function (overridestyle, node) { |
||||
var content = yo`<div>Empty</div>` |
||||
if (this.json) { |
||||
content = this.treeView.render({}) |
||||
} |
||||
overridestyle === undefined ? {} : overridestyle |
||||
var self = this |
||||
var contentNode = yo` |
||||
<div class='dropdownpanel ${css.dropdownpanel}' style='display:none'> |
||||
<i class="${css.refresh} fas fa-sync" aria-hidden="true"></i> |
||||
<div class='dropdowncontent'>${node || content}</div> |
||||
<div class='dropdownrawcontent' style='display:none'></div> |
||||
<div class='message' style='display:none'></div> |
||||
</div>` |
||||
var title = !self.displayContentOnly ? yo`<div class="${css.title} py-0 px-1 title">
|
||||
<div class="${css.icon} fas fa-caret-right" onclick=${function () { self.toggle() }} ></div> |
||||
<div class="${css.name}" onclick=${function () { self.toggle() }} >${this.name}</div><span class="${css.nameDetail}" onclick=${function () { self.toggle() }} ></span> |
||||
${copyToClipboard(() => this.copyClipboard())} |
||||
</div>` : yo`<div></div>` |
||||
|
||||
var view = yo` |
||||
<div class="border rounded px-1 mt-1 bg-light"> |
||||
<style> |
||||
@-moz-keyframes spin { |
||||
to { -moz-transform: rotate(359deg); } |
||||
} |
||||
@-webkit-keyframes spin { |
||||
to { -webkit-transform: rotate(359deg); } |
||||
} |
||||
@keyframes spin { |
||||
to {transform:rotate(359deg);} |
||||
} |
||||
</style> |
||||
${title} |
||||
${contentNode} |
||||
</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
if (self.displayContentOnly) contentNode.style.display = 'block' |
||||
return view |
||||
} |
||||
|
||||
DropdownPanel.prototype.toggle = function () { |
||||
var el = this.view.querySelector('.dropdownpanel') |
||||
var caret = this.view.querySelector('.title').firstElementChild |
||||
if (el.style.display === '') { |
||||
el.style.display = 'none' |
||||
caret.className = `${css.icon} fas fa-caret-right` |
||||
this.event.trigger('hide', []) |
||||
} else { |
||||
el.style.display = '' |
||||
caret.className = `${css.icon} fas fa-caret-down` |
||||
this.event.trigger('show', []) |
||||
} |
||||
} |
||||
|
||||
DropdownPanel.prototype.hide = function () { |
||||
if (!(this.view && !this.displayContentOnly)) return |
||||
var caret = this.view.querySelector('.title').firstElementChild |
||||
var el = this.view.querySelector('.dropdownpanel') |
||||
el.style.display = 'none' |
||||
caret.className = `${css.icon} fas fa-caret-right` |
||||
this.event.trigger('hide', []) |
||||
} |
||||
|
||||
DropdownPanel.prototype.show = function () { |
||||
if (!(this.view && !this.displayContentOnly)) return |
||||
var caret = this.view.querySelector('.title').firstElementChild |
||||
var el = this.view.querySelector('.dropdownpanel') |
||||
el.style.display = '' |
||||
caret.className = `${css.icon} fas fa-caret-down` |
||||
this.event.trigger('show', []) |
||||
} |
||||
|
||||
DropdownPanel.prototype.message = function (message) { |
||||
if (!this.view) return |
||||
var mes = this.view.querySelector('.dropdownpanel .message') |
||||
mes.innerText = message |
||||
mes.style.display = (message === '') ? 'none' : 'block' |
||||
} |
||||
|
||||
module.exports = DropdownPanel |
@ -1,21 +0,0 @@ |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function FullStoragesChanges () { |
||||
this.view |
||||
this.basicPanel = new DropdownPanel('Full Storages Changes', {json: true}) |
||||
} |
||||
|
||||
FullStoragesChanges.prototype.update = function (storageData) { |
||||
this.basicPanel.update(storageData) |
||||
} |
||||
|
||||
FullStoragesChanges.prototype.render = function () { |
||||
var view = yo`<div id='fullstorageschangespanel' >${this.basicPanel.render()}</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
module.exports = FullStoragesChanges |
@ -1,17 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function FunctionPanel () { |
||||
this.basicPanel = new DropdownPanel('Function Stack', {json: true, displayContentOnly: false}) |
||||
} |
||||
|
||||
FunctionPanel.prototype.update = function (calldata) { |
||||
this.basicPanel.update(calldata) |
||||
} |
||||
|
||||
FunctionPanel.prototype.render = function () { |
||||
return yo`<div id="FunctionPanel">${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = FunctionPanel |
@ -1,21 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function MemoryPanel () { |
||||
this.basicPanel = new DropdownPanel('Memory', { |
||||
json: true, |
||||
css: { |
||||
'font-family': 'monospace' |
||||
}}) |
||||
} |
||||
|
||||
MemoryPanel.prototype.update = function (calldata) { |
||||
this.basicPanel.update(calldata) |
||||
} |
||||
|
||||
MemoryPanel.prototype.render = function () { |
||||
return yo`<div id="memorypanel">${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = MemoryPanel |
@ -1,59 +0,0 @@ |
||||
'use strict' |
||||
var EventManager = require('../../../../../lib/events') |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var solidityTypeFormatter = require('./utils/SolidityTypeFormatter') |
||||
var yo = require('yo-yo') |
||||
|
||||
class SolidityLocals { |
||||
|
||||
constructor () { |
||||
this.event = new EventManager() |
||||
this.basicPanel = new DropdownPanel('Solidity Locals', { |
||||
json: true, |
||||
formatSelf: solidityTypeFormatter.formatSelf, |
||||
extractData: solidityTypeFormatter.extractData, |
||||
loadMore: (cursor) => { |
||||
this.event.trigger('solidityLocalsLoadMore', [cursor]) |
||||
} |
||||
}) |
||||
this.view |
||||
this._data = null |
||||
} |
||||
|
||||
update (data) { |
||||
this._data = data |
||||
this.basicPanel.update(this._data) |
||||
} |
||||
|
||||
loadMore (data) { |
||||
this._data = this.mergeLocals(data, this._data) |
||||
this.basicPanel.update(this._data) |
||||
} |
||||
|
||||
setMessage (message) { |
||||
this.basicPanel.setMessage(message) |
||||
} |
||||
|
||||
setUpdating () { |
||||
this.basicPanel.setUpdating() |
||||
} |
||||
|
||||
mergeLocals (locals1, locals2) { |
||||
Object.keys(locals2).map(item => { |
||||
if (locals2[item].cursor && (parseInt(locals2[item].cursor) < parseInt(locals1[item].cursor))) { |
||||
locals2[item] = { |
||||
...locals1[item], |
||||
value: [...locals2[item].value, ...locals1[item].value] |
||||
} |
||||
} |
||||
}) |
||||
return locals2 |
||||
} |
||||
|
||||
render () { |
||||
this.view = yo`<div id='soliditylocals' data-id="solidityLocals">${this.basicPanel.render()}</div>` |
||||
return this.view |
||||
} |
||||
} |
||||
|
||||
module.exports = SolidityLocals |
@ -1,36 +0,0 @@ |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var solidityTypeFormatter = require('./utils/SolidityTypeFormatter') |
||||
var yo = require('yo-yo') |
||||
|
||||
function SolidityState () { |
||||
this.basicPanel = new DropdownPanel('Solidity State', { |
||||
json: true, |
||||
// TODO: used by TreeView ui
|
||||
formatSelf: solidityTypeFormatter.formatSelf, |
||||
extractData: solidityTypeFormatter.extractData |
||||
}) |
||||
this.view |
||||
} |
||||
|
||||
SolidityState.prototype.update = function (data) { |
||||
this.basicPanel.update(data) |
||||
} |
||||
|
||||
SolidityState.prototype.setMessage = function (message) { |
||||
this.basicPanel.setMessage(message) |
||||
} |
||||
|
||||
SolidityState.prototype.setUpdating = function () { |
||||
this.basicPanel.setUpdating() |
||||
} |
||||
|
||||
SolidityState.prototype.render = function () { |
||||
if (this.view) return |
||||
this.view = yo` |
||||
<div id='soliditystate' > |
||||
${this.basicPanel.render()} |
||||
</div>` |
||||
return this.view |
||||
} |
||||
|
||||
module.exports = SolidityState |
@ -1,17 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function StackPanel () { |
||||
this.basicPanel = new DropdownPanel('Stack', {json: true, displayContentOnly: false}) |
||||
} |
||||
|
||||
StackPanel.prototype.update = function (calldata) { |
||||
this.basicPanel.update(calldata) |
||||
} |
||||
|
||||
StackPanel.prototype.render = function () { |
||||
return yo`<div id="stackpanel">${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = StackPanel |
@ -1,23 +0,0 @@ |
||||
var yo = require('yo-yo') |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
|
||||
function StepDetail () { |
||||
this.basicPanel = new DropdownPanel('Step details', {json: true, displayContentOnly: false}) |
||||
this.detail = { 'vm trace step': '-', 'execution step': '-', 'add memory': '', 'gas': '', 'remaining gas': '-', 'loaded address': '-' } |
||||
} |
||||
|
||||
StepDetail.prototype.reset = function () { |
||||
this.detail = { 'vm trace step': '-', 'execution step': '-', 'add memory': '', 'gas': '', 'remaining gas': '-', 'loaded address': '-' } |
||||
this.basicPanel.update(this.detail) |
||||
} |
||||
|
||||
StepDetail.prototype.updateField = function (key, value) { |
||||
this.detail[key] = value |
||||
this.basicPanel.update(this.detail) |
||||
} |
||||
|
||||
StepDetail.prototype.render = function () { |
||||
return yo`<div id='stepdetail' data-id="stepdetail">${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = StepDetail |
@ -1,17 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function StoragePanel (_parent, _traceManager) { |
||||
this.basicPanel = new DropdownPanel('Storage', {json: true}) |
||||
} |
||||
|
||||
StoragePanel.prototype.update = function (storage, header) { |
||||
this.basicPanel.update(storage, header) |
||||
} |
||||
|
||||
StoragePanel.prototype.render = function () { |
||||
return yo`<div id='storagepanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = StoragePanel |
@ -1,77 +0,0 @@ |
||||
var yo = require('yo-yo') |
||||
var BN = require('ethereumjs-util').BN |
||||
|
||||
module.exports = { |
||||
formatSelf: formatSelf, |
||||
extractData: extractData |
||||
} |
||||
|
||||
function formatSelf (key, data) { |
||||
const style = fontColor(data) |
||||
const keyStyle = data.isProperty ? 'color: var(--info)' : '' |
||||
if (data.type === 'string') { |
||||
data.self = JSON.stringify(data.self) |
||||
} |
||||
return yo `<label class="mb-0" style='${keyStyle};white-space:pre-wrap;'> ${' ' + key}:<label class="mb-0" style=${style}>${' ' + data.self}</label><label style='font-style:italic'> ${data.isProperty || !data.type ? '' : ' ' + data.type}</label></label>` |
||||
} |
||||
|
||||
function extractData (item, parent, key) { |
||||
var ret = {} |
||||
if (item.isProperty) { |
||||
return item |
||||
} |
||||
if (item.type.lastIndexOf(']') === item.type.length - 1) { |
||||
ret.children = (item.value || []).map(function (item, index) { |
||||
return {key: index, value: item} |
||||
}) |
||||
ret.children.unshift({ |
||||
key: 'length', |
||||
value: { |
||||
self: (new BN(item.length.replace('0x', ''), 16)).toString(10), |
||||
type: 'uint', |
||||
isProperty: true |
||||
} |
||||
}) |
||||
ret.isArray = true |
||||
ret.self = parent.isArray ? '' : item.type |
||||
ret.cursor = item.cursor |
||||
ret.hasNext = item.hasNext |
||||
} else if (item.type.indexOf('struct') === 0) { |
||||
ret.children = Object.keys((item.value || {})).map(function (key) { |
||||
return {key: key, value: item.value[key]} |
||||
}) |
||||
ret.self = item.type |
||||
ret.isStruct = true |
||||
} else if (item.type.indexOf('mapping') === 0) { |
||||
ret.children = Object.keys((item.value || {})).map(function (key) { |
||||
return {key: key, value: item.value[key]} |
||||
}) |
||||
ret.isMapping = true |
||||
ret.self = item.type |
||||
} else { |
||||
ret.children = null |
||||
ret.self = item.value |
||||
ret.type = item.type |
||||
} |
||||
return ret |
||||
} |
||||
|
||||
function fontColor (data) { |
||||
let color = 'var(--primary)' |
||||
if (data.isArray || data.isStruct || data.isMapping) { |
||||
color = 'var(--info)' |
||||
} else if ( |
||||
data.type.indexOf('uint') === 0 || |
||||
data.type.indexOf('int') === 0 || |
||||
data.type.indexOf('bool') === 0 || |
||||
data.type.indexOf('enum') === 0 |
||||
) { |
||||
color = 'var(--green)' |
||||
} else if (data.type === 'string') { |
||||
color = 'var(--teal)' |
||||
} else if (data.self == 0x0) { // eslint-disable-line
|
||||
color = 'var(--gray)' |
||||
} |
||||
return 'color:' + color |
||||
} |
||||
|
Loading…
Reference in new issue