remix-debugger
Version:
Ethereum IDE and tools for the web
187 lines (168 loc) • 5.06 kB
JavaScript
'use strict'
var yo = require('yo-yo')
var csjs = require('csjs-inject')
var css = csjs`
.li_tv {
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;
}
.ul_tv {
list-style-type: none;
-webkit-margin-before: 0px;
-webkit-margin-after: 0px;
-webkit-margin-start: 0px;
-webkit-margin-end: 0px;
-webkit-padding-start: 0px;
}
.caret_tv {
width: 10px;
}
.label_tv {
display: flex;
align-items: center;
}
`
var remixLib = require('remix-lib')
var EventManager = remixLib.EventManager
/**
* TreeView
* - extendable by specifying custom `extractData` and `formatSelf` function
* - trigger `nodeClick` and `leafClick`
*/
class TreeView {
constructor (opts) {
this.event = new EventManager()
this.extractData = opts.extractData || this.extractDataDefault
this.formatSelf = opts.formatSelf || this.formatSelfDefault
this.view = null
}
render (json, expand) {
var view = this.renderProperties(json, expand)
if (!this.view) {
this.view = view
}
return view
}
update (json) {
if (this.view) {
yo.update(this.view, this.render(json))
}
}
renderObject (item, parent, key, expand, keyPath) {
var data = this.extractData(item, parent, key)
var children = (data.children || []).map((child, index) => {
return this.renderObject(child.value, data, child.key, expand, keyPath + '/' + child.key)
})
return this.formatData(key, data, children, expand, keyPath)
}
renderProperties (json, expand, key) {
key = key || ''
var children = Object.keys(json).map((innerkey) => {
return this.renderObject(json[innerkey], json, innerkey, expand, innerkey)
})
return yo`<ul key=${key} class="${css.ul_tv}">${children}</ul>`
}
formatData (key, data, children, expand, keyPath) {
var self = this
var li = yo`<li key=${keyPath} class=${css.li_tv}></li>`
var caret = yo`<div class="fa fa-caret-right caret ${css.caret_tv}"></div>`
var label = yo`
<div key=${keyPath} class=${css.label_tv}>
${caret}
<span>${self.formatSelf(key, data, li)}</span>
</div>`
li.appendChild(label)
if (data.children) {
var list = yo`<ul key=${keyPath} class=${css.ul_tv}>${children}</ul>`
list.style.display = 'none'
caret.className = list.style.display === 'none' ? `fa fa-caret-right caret ${css.caret_tv}` : `fa fa-caret-down caret ${css.caret_tv}`
label.onclick = function () {
self.expand(keyPath)
}
label.oncontextmenu = function (event) {
self.event.trigger('nodeRightClick', [keyPath, data, label, event])
}
li.appendChild(list)
} else {
caret.style.visibility = 'hidden'
label.oncontextmenu = function (event) {
self.event.trigger('leafRightClick', [keyPath, data, label, event])
}
label.onclick = function (event) {
self.event.trigger('leafClick', [keyPath, data, label, event])
}
}
return li
}
isExpanded (path) {
var current = this.nodeAt(path)
if (current) {
return current.style.display !== 'none'
}
return false
}
expand (path) {
var caret = this.caretAt(path)
var node = this.nodeAt(path)
if (node) {
node.style.display = node.style.display === 'none' ? 'block' : 'none'
caret.className = node.style.display === 'none' ? `fa fa-caret-right caret ${css.caret_tv}` : `fa fa-caret-down caret ${css.caret_tv}`
this.event.trigger('nodeClick', [path, node])
}
}
caretAt (path) {
var label = this.labelAt(path)
if (label) {
return label.querySelector('.caret')
}
}
itemAt (path) {
return this.view.querySelector(`li[key="${path}"]`)
}
labelAt (path) {
return this.view.querySelector(`div[key="${path}"]`)
}
nodeAt (path) {
return this.view.querySelector(`ul[key="${path}"]`)
}
updateNodeFromJSON (path, jsonTree, expand) {
var newTree = this.renderProperties(jsonTree, expand, path)
var current = this.nodeAt(path)
if (current && current.parentElement) {
current.parentElement.replaceChild(newTree, current)
}
}
formatSelfDefault (key, data) {
return yo`<label>${key}: ${data.self}</label>`
}
extractDataDefault (item, parent, key) {
var ret = {}
if (item instanceof Array) {
ret.children = item.map((item, index) => {
return {key: index, value: item}
})
ret.self = 'Array'
ret.isNode = true
ret.isLeaf = false
} else if (item instanceof Object) {
ret.children = Object.keys(item).map((key) => {
return {key: key, value: item[key]}
})
ret.self = 'Object'
ret.isNode = true
ret.isLeaf = false
} else {
ret.self = item
ret.children = null
ret.isNode = false
ret.isLeaf = true
}
return ret
}
}
module.exports = TreeView