|
|
|
@ -1,4 +1,4 @@ |
|
|
|
|
/* global Node */ |
|
|
|
|
/* global Node, requestAnimationFrame */ |
|
|
|
|
var yo = require('yo-yo') |
|
|
|
|
var csjs = require('csjs-inject') |
|
|
|
|
var javascriptserialize = require('javascript-serialize') |
|
|
|
@ -9,6 +9,7 @@ var EventManager = require('ethereum-remix').lib.EventManager |
|
|
|
|
var Web3 = require('web3') |
|
|
|
|
|
|
|
|
|
var executionContext = require('../../execution-context') |
|
|
|
|
var Dropdown = require('../ui/dropdown') |
|
|
|
|
|
|
|
|
|
var css = csjs` |
|
|
|
|
.panel { |
|
|
|
@ -27,17 +28,29 @@ var css = csjs` |
|
|
|
|
|
|
|
|
|
.bar { |
|
|
|
|
display : flex; |
|
|
|
|
justify-content : flex-end; |
|
|
|
|
min-height : 1.7em; |
|
|
|
|
padding : 2px; |
|
|
|
|
cursor : ns-resize; |
|
|
|
|
background-color : #eef; |
|
|
|
|
z-index : 3; |
|
|
|
|
} |
|
|
|
|
.menu { |
|
|
|
|
position : relative; |
|
|
|
|
display : flex; |
|
|
|
|
align-items : center; |
|
|
|
|
width : 100%; |
|
|
|
|
} |
|
|
|
|
.title { |
|
|
|
|
margin-right : 15px; |
|
|
|
|
} |
|
|
|
|
.minimize { |
|
|
|
|
text-align : center; |
|
|
|
|
padding-top : 3px; |
|
|
|
|
margin-left : auto; |
|
|
|
|
width : 10px; |
|
|
|
|
min-height : 100%; |
|
|
|
|
cursor : pointer; |
|
|
|
|
color : black; |
|
|
|
|
} |
|
|
|
|
.clear { |
|
|
|
|
margin-right : 5px; |
|
|
|
|
font-size : 15px; |
|
|
|
|
cursor : pointer; |
|
|
|
|
color : black; |
|
|
|
|
} |
|
|
|
@ -78,17 +91,7 @@ var css = csjs` |
|
|
|
|
outline : none; |
|
|
|
|
font-family : monospace; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.error { |
|
|
|
|
color : red; |
|
|
|
|
} |
|
|
|
|
.info { |
|
|
|
|
color : blue; |
|
|
|
|
} |
|
|
|
|
.log { |
|
|
|
|
color : black; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.dragbarHorizontal { |
|
|
|
|
position : absolute; |
|
|
|
|
top : 0; |
|
|
|
@ -120,63 +123,49 @@ var ghostbar = yo`<div class=${css.ghostbar}></div>` |
|
|
|
|
class Terminal { |
|
|
|
|
constructor (opts = { auto: true }) { |
|
|
|
|
var self = this |
|
|
|
|
self.event = new EventManager() |
|
|
|
|
self._api = opts.api |
|
|
|
|
self.data = { |
|
|
|
|
lineLength: opts.lineLength || 80, |
|
|
|
|
session: [], |
|
|
|
|
banner: opts.banner || ` |
|
|
|
|
/****************************************************************************** |
|
|
|
|
|
|
|
|
|
........................................... |
|
|
|
|
.....................:..................... |
|
|
|
|
....................o:;.................... |
|
|
|
|
...................oo:;;................... |
|
|
|
|
..................ooo:;;;.................. |
|
|
|
|
.................oooo:;;;;................. |
|
|
|
|
................ooooo:;;;;;................ |
|
|
|
|
...............oooooo:;;;;;;............... |
|
|
|
|
..............ooooooo:;;;;;;;.............. |
|
|
|
|
.............ooooooo;:';;;;;;;............. |
|
|
|
|
............ooooo;;;;:'''';;;;;............ |
|
|
|
|
...........oo;;;;;;;;:'''''''';;........... |
|
|
|
|
..........;;;;;;;;;;;:'''''''''''.......... |
|
|
|
|
..............;;;;;;;:'''''''.............. |
|
|
|
|
...........oo...;;;;;:'''''...;;........... |
|
|
|
|
............oooo...;;:''...;;;;............ |
|
|
|
|
..............oooo...:...;;;;.............. |
|
|
|
|
...............oooooo:;;;;;;............... |
|
|
|
|
................ooooo:;;;;;................ |
|
|
|
|
.................oooo:;;;;................. |
|
|
|
|
..................ooo:;;;.................. |
|
|
|
|
...................oo:;;................... |
|
|
|
|
....................o:;.................... |
|
|
|
|
.....................:..................... |
|
|
|
|
........................................... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
######## ######## ## ## #### ## ##
|
|
|
|
|
## ## ## ### ### ## ## ##
|
|
|
|
|
## ## ## #### #### ## ## ##
|
|
|
|
|
######## ###### ## ### ## ## ###
|
|
|
|
|
## ## ## ## ## ## ## ##
|
|
|
|
|
## ## ## ## ## ## ## ##
|
|
|
|
|
## ## ######## ## ## #### ## ##
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
welcome to browser solidity |
|
|
|
|
|
|
|
|
|
new features: |
|
|
|
|
- dom terminal v0.0.1-alpha |
|
|
|
|
|
|
|
|
|
******************************************************************************/ |
|
|
|
|
` |
|
|
|
|
banner: opts.banner, |
|
|
|
|
activeFilters: { commands: {}, input: '' } |
|
|
|
|
} |
|
|
|
|
self.event = new EventManager() |
|
|
|
|
self._api = opts.api |
|
|
|
|
self._view = { el: null, bar: null, input: null, term: null, journal: null, cli: null } |
|
|
|
|
self._templates = {} |
|
|
|
|
self.logger = {} |
|
|
|
|
;['log', 'info', 'error'].forEach(typename => { |
|
|
|
|
self.registerType(typename, self._blocksRenderer(typename)) |
|
|
|
|
self._components = {} |
|
|
|
|
self._components.dropdown = new Dropdown({ |
|
|
|
|
options: [ |
|
|
|
|
'knownTransaction', |
|
|
|
|
'unknownTransaction', |
|
|
|
|
'script' |
|
|
|
|
], |
|
|
|
|
defaults: ['knownTransaction', 'script'] |
|
|
|
|
}) |
|
|
|
|
self._components.dropdown.event.register('deselect', function (label) { |
|
|
|
|
self.updateJournal({ type: 'deselect', value: label }) |
|
|
|
|
}) |
|
|
|
|
self._components.dropdown.event.register('select', function (label) { |
|
|
|
|
self.updateJournal({ type: 'select', value: label }) |
|
|
|
|
}) |
|
|
|
|
self._commands = {} |
|
|
|
|
self.commands = {} |
|
|
|
|
self._JOURNAL = [] |
|
|
|
|
self._jobs = [] |
|
|
|
|
self._INDEX = {} |
|
|
|
|
self._INDEX.all = [] |
|
|
|
|
self._INDEX.allMain = [] |
|
|
|
|
self._INDEX.commands = {} |
|
|
|
|
self._INDEX.commandsMain = {} |
|
|
|
|
self.registerCommand('log', self._blocksRenderer('log')) |
|
|
|
|
self.registerCommand('info', self._blocksRenderer('info')) |
|
|
|
|
self.registerCommand('error', self._blocksRenderer('error')) |
|
|
|
|
self.registerCommand('script', function execute (args, scopedCommands, append) { |
|
|
|
|
var script = String(args[0]) |
|
|
|
|
scopedCommands.log(`> ${script}`) |
|
|
|
|
self._shell(script, scopedCommands, function (error, output) { |
|
|
|
|
if (error) scopedCommands.error(error) |
|
|
|
|
else scopedCommands.log(output) |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
self._jsSandboxContext = {} |
|
|
|
|
self._jsSandbox = vm.createContext(self._jsSandboxContext) |
|
|
|
@ -198,14 +187,23 @@ class Terminal { |
|
|
|
|
` |
|
|
|
|
self._view.icon = yo`<i onmouseenter=${hover} onmouseleave=${hover} onmousedown=${minimize} class="${css.minimize} fa fa-angle-double-down"></i>` |
|
|
|
|
self._view.dragbar = yo`<div onmousedown=${mousedown} class=${css.dragbarHorizontal}></div>` |
|
|
|
|
self._view.dropdown = self._components.dropdown.render() |
|
|
|
|
self._view.bar = yo` |
|
|
|
|
<div class=${css.bar}> |
|
|
|
|
${self._view.dragbar} |
|
|
|
|
${self._view.icon} |
|
|
|
|
<div class=${css.menu}> |
|
|
|
|
<div class=${css.title}>Remix Terminal</div> |
|
|
|
|
<div class=${css.clear} onclick=${clear}> |
|
|
|
|
<i class="fa fa-ban" aria-hidden="true" onmouseenter=${hover} onmouseleave=${hover}></i> |
|
|
|
|
</div> |
|
|
|
|
${self._view.dropdown} |
|
|
|
|
<input type="text" class=${css.filter} onkeyup=${filter}></div> |
|
|
|
|
${self._view.icon} |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
` |
|
|
|
|
self._view.term = yo` |
|
|
|
|
<div class=${css.terminal} onscroll=${throttle(reattach, 50)} onclick=${focusinput}> |
|
|
|
|
<div class=${css.terminal} onscroll=${throttle(reattach, 10)} onclick=${focusinput}> |
|
|
|
|
${self._view.journal} |
|
|
|
|
${self._view.cli} |
|
|
|
|
</div> |
|
|
|
@ -216,18 +214,17 @@ class Terminal { |
|
|
|
|
${self._view.term} |
|
|
|
|
</div> |
|
|
|
|
` |
|
|
|
|
self._output(self.data.banner) |
|
|
|
|
if (self.data.banner) self.commands.log(self.data.banner) |
|
|
|
|
|
|
|
|
|
function focusinput (event) { |
|
|
|
|
if (self._view.journal.offsetHeight - (self._view.term.scrollTop + self._view.term.offsetHeight) < 50) { |
|
|
|
|
refocus() |
|
|
|
|
function throttle (fn, wait) { |
|
|
|
|
var time = Date.now() |
|
|
|
|
return function debounce () { |
|
|
|
|
if ((time + wait - Date.now()) < 0) { |
|
|
|
|
fn.apply(this, arguments) |
|
|
|
|
time = Date.now() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
function refocus () { |
|
|
|
|
self._view.input.focus() |
|
|
|
|
reattach({ currentTarget: self._view.term }) |
|
|
|
|
self.scroll2bottom() |
|
|
|
|
} |
|
|
|
|
var css2 = csjs` |
|
|
|
|
.anchor { |
|
|
|
|
position : static; |
|
|
|
@ -264,18 +261,20 @@ class Terminal { |
|
|
|
|
var placeholder = yo`<div class=${css2.anchor}>${background}${text}</div>` |
|
|
|
|
var inserted = false |
|
|
|
|
|
|
|
|
|
function throttle (fn, wait) { |
|
|
|
|
var time = Date.now() |
|
|
|
|
return function () { |
|
|
|
|
if ((time + wait - Date.now()) < 0) { |
|
|
|
|
fn.apply(this, arguments) |
|
|
|
|
time = Date.now() |
|
|
|
|
} |
|
|
|
|
function focusinput (event) { |
|
|
|
|
if (self._view.journal.offsetHeight - (self._view.term.scrollTop + self._view.term.offsetHeight) < 50) { |
|
|
|
|
refocus() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
function refocus () { |
|
|
|
|
self._view.input.focus() |
|
|
|
|
reattach({ currentTarget: self._view.term }) |
|
|
|
|
delete self.scroll2bottom |
|
|
|
|
self.scroll2bottom() |
|
|
|
|
} |
|
|
|
|
function reattach (event) { |
|
|
|
|
var el = event.currentTarget |
|
|
|
|
var isBottomed = el.scrollHeight - el.scrollTop < el.clientHeight + 30 |
|
|
|
|
var isBottomed = el.scrollHeight - el.scrollTop - el.clientHeight < 30 |
|
|
|
|
if (isBottomed) { |
|
|
|
|
if (inserted) { |
|
|
|
|
text.innerText = '' |
|
|
|
@ -320,11 +319,11 @@ class Terminal { |
|
|
|
|
background.style.height = (self._view.journal.offsetHeight - (placeholder.offsetTop + placeholder.offsetHeight)) + 'px' |
|
|
|
|
background.onclick = undefined |
|
|
|
|
background.style.cursor = 'default' |
|
|
|
|
background.style.pointerEvents = 'none' |
|
|
|
|
} else { |
|
|
|
|
background.style = '' |
|
|
|
|
text.style = '' |
|
|
|
|
background.onclick = function (event) { |
|
|
|
|
console.error('background click') |
|
|
|
|
placeholder.scrollIntoView() |
|
|
|
|
check() |
|
|
|
|
} |
|
|
|
@ -341,6 +340,14 @@ class Terminal { |
|
|
|
|
self.event.trigger('resize', []) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
function filter (event) { |
|
|
|
|
var input = event.currentTarget |
|
|
|
|
self.updateJournal({ type: 'search', value: input.value }) |
|
|
|
|
} |
|
|
|
|
function clear (event) { |
|
|
|
|
refocus() |
|
|
|
|
self._view.journal.innerHTML = '' |
|
|
|
|
} |
|
|
|
|
// ----------------- resizeable ui ---------------
|
|
|
|
|
function mousedown (event) { |
|
|
|
|
event.preventDefault() |
|
|
|
@ -385,7 +392,7 @@ class Terminal { |
|
|
|
|
putCursor2End(self._view.input) |
|
|
|
|
} else { // <enter>
|
|
|
|
|
event.preventDefault() |
|
|
|
|
self.execute(self._view.input.innerText) |
|
|
|
|
self.commands.script(self._view.input.innerText) |
|
|
|
|
self._view.input.innerHTML = '' |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -418,12 +425,78 @@ class Terminal { |
|
|
|
|
editable.focus() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
updateJournal (filterEvent) { |
|
|
|
|
var self = this |
|
|
|
|
var commands = self.data.activeFilters.commands |
|
|
|
|
var value = filterEvent.value |
|
|
|
|
if (filterEvent.type === 'select') { |
|
|
|
|
commands[value] = true |
|
|
|
|
if (!self._INDEX.commandsMain[value]) return |
|
|
|
|
self._INDEX.commandsMain[value].forEach(item => { |
|
|
|
|
item.root.steps.forEach(item => { self._JOURNAL[item.gidx] = item }) |
|
|
|
|
self._JOURNAL[item.gidx] = item |
|
|
|
|
}) |
|
|
|
|
} else if (filterEvent.type === 'deselect') { |
|
|
|
|
commands[value] = false |
|
|
|
|
if (!self._INDEX.commandsMain[value]) return |
|
|
|
|
self._INDEX.commandsMain[value].forEach(item => { |
|
|
|
|
item.root.steps.forEach(item => { self._JOURNAL[item.gidx] = undefined }) |
|
|
|
|
self._JOURNAL[item.gidx] = undefined |
|
|
|
|
}) |
|
|
|
|
} else if (filterEvent.type === 'search') { |
|
|
|
|
if (value !== self.data.activeFilters.input) { |
|
|
|
|
var query = self.data.activeFilters.input = value |
|
|
|
|
var items = self._JOURNAL |
|
|
|
|
for (var gidx = 0, len = items.length; gidx < len; gidx++) { |
|
|
|
|
var item = items[gidx] |
|
|
|
|
if (item) { |
|
|
|
|
var show = query.length ? match(item.args, query) : true |
|
|
|
|
item.hide = !show |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
var df = document.createDocumentFragment() |
|
|
|
|
self._JOURNAL.forEach(item => { |
|
|
|
|
if (item && item.el && !item.hide) df.appendChild(item.el) |
|
|
|
|
}) |
|
|
|
|
requestAnimationFrame(function updateDOM () { |
|
|
|
|
self._view.journal.innerHTML = '' |
|
|
|
|
self._view.journal.appendChild(df) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
_shouldAdd (item) { |
|
|
|
|
var self = this |
|
|
|
|
if (self.data.activeFilters.commands[item.root.cmd]) { |
|
|
|
|
var query = self.data.activeFilters.input |
|
|
|
|
var args = item.args |
|
|
|
|
return query.length ? match(args, query) : true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
_appendItem (item) { |
|
|
|
|
var self = this |
|
|
|
|
var { el, gidx } = item |
|
|
|
|
self._JOURNAL[gidx] = item |
|
|
|
|
if (!self._jobs.length) { |
|
|
|
|
requestAnimationFrame(function updateTerminal () { |
|
|
|
|
self._jobs.forEach(el => self._view.journal.appendChild(el)) |
|
|
|
|
self.scroll2bottom() |
|
|
|
|
self._jobs = [] |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
self._jobs.push(el) |
|
|
|
|
} |
|
|
|
|
scroll2bottom () { |
|
|
|
|
var self = this |
|
|
|
|
setTimeout(function () { |
|
|
|
|
self._view.term.scrollTop = self._view.term.scrollHeight |
|
|
|
|
}, 0) |
|
|
|
|
} |
|
|
|
|
_blocksRenderer (mode) { |
|
|
|
|
var self = this |
|
|
|
|
var modes = { log: true, info: true, error: true } |
|
|
|
|
if (modes[mode]) { |
|
|
|
|
return function render () { |
|
|
|
|
var args = [].slice.call(arguments) |
|
|
|
|
mode = { log: 'black', info: 'blue', error: 'red' }[mode] // defaults
|
|
|
|
|
if (mode) { |
|
|
|
|
return function logger (args, scopedCommands, append) { |
|
|
|
|
var types = args.map(type) |
|
|
|
|
var values = javascriptserialize.apply(null, args).map(function (val, idx) { |
|
|
|
|
if (typeof args[idx] === 'string') val = args[idx] |
|
|
|
@ -432,69 +505,71 @@ class Terminal { |
|
|
|
|
var lines = val.match(new RegExp(pattern, 'g')) |
|
|
|
|
return lines.map(str => document.createTextNode(`${str}\n`)) |
|
|
|
|
}) |
|
|
|
|
return values |
|
|
|
|
append(yo`<span style="color: ${mode};">${values}</span>`) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
throw new Error('mode is not supported') |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
execute (script) { |
|
|
|
|
_scopeCommands (append) { |
|
|
|
|
var self = this |
|
|
|
|
script = String(script) |
|
|
|
|
self._output({ type: 'log', value: `> ${script}` }) |
|
|
|
|
self._shell(script, function (error, output) { |
|
|
|
|
if (error) { |
|
|
|
|
self._output({ type: 'error', value: error }) |
|
|
|
|
return error |
|
|
|
|
} else { |
|
|
|
|
self._output({ type: 'log', value: output }) |
|
|
|
|
return output |
|
|
|
|
var scopedCommands = {} |
|
|
|
|
Object.keys(self.commands).forEach(function makeScopedCommand (cmd) { |
|
|
|
|
var command = self._commands[cmd] |
|
|
|
|
scopedCommands[cmd] = function _command () { |
|
|
|
|
var args = [...arguments] |
|
|
|
|
command(args, scopedCommands, el => append(cmd, args, blockify(el))) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
return scopedCommands |
|
|
|
|
} |
|
|
|
|
registerType (typename, template) { |
|
|
|
|
registerCommand (name, command) { |
|
|
|
|
var self = this |
|
|
|
|
if (typeof template !== 'function') throw new Error('invalid template') |
|
|
|
|
self._templates[typename] = template |
|
|
|
|
self.logger[typename] = function () { |
|
|
|
|
var args = [...arguments].map(x => ({ type: typename, value: x })) |
|
|
|
|
self._output.apply(self, args) |
|
|
|
|
name = String(name) |
|
|
|
|
if (self._commands[name]) throw new Error(`command "${name}" exists already`) |
|
|
|
|
if (typeof command !== 'function') throw new Error(`invalid command: ${command}`) |
|
|
|
|
self._commands[name] = command |
|
|
|
|
self._INDEX.commands[name] = [] |
|
|
|
|
self._INDEX.commandsMain[name] = [] |
|
|
|
|
self.commands[name] = function _command () { |
|
|
|
|
var args = [...arguments] |
|
|
|
|
var steps = [] |
|
|
|
|
var root = { steps, cmd: name } |
|
|
|
|
var ITEM = { root, cmd: name } |
|
|
|
|
root.gidx = self._INDEX.allMain.push(ITEM) - 1 |
|
|
|
|
root.idx = self._INDEX.commandsMain[name].push(ITEM) - 1 |
|
|
|
|
function append (cmd, params, el) { |
|
|
|
|
var item |
|
|
|
|
if (cmd) { // subcommand
|
|
|
|
|
item = { el, cmd, root } |
|
|
|
|
} else { // command
|
|
|
|
|
item = ITEM |
|
|
|
|
item.el = el |
|
|
|
|
cmd = name |
|
|
|
|
} |
|
|
|
|
item.gidx = self._INDEX.all.push(item) - 1 |
|
|
|
|
item.idx = self._INDEX.commands[cmd].push(item) - 1 |
|
|
|
|
item.step = steps.push(item) - 1 |
|
|
|
|
item.args = params |
|
|
|
|
if (self._shouldAdd(item)) self._appendItem(item) |
|
|
|
|
} |
|
|
|
|
var scopedCommands = self._scopeCommands(append) |
|
|
|
|
command(args, scopedCommands, el => append(null, args, blockify(el))) |
|
|
|
|
} |
|
|
|
|
var help = typeof command.help === 'string' ? command.help : [ |
|
|
|
|
`// no help available for:`, |
|
|
|
|
`terminal.commands.${name}(...)` |
|
|
|
|
].join('\n') |
|
|
|
|
self.commands[name].toString = _ => { return help } |
|
|
|
|
self.commands[name].help = help |
|
|
|
|
return self.commands[name] |
|
|
|
|
} |
|
|
|
|
log () { |
|
|
|
|
// @TODO: temporary to not break stuff that uses the old API
|
|
|
|
|
this._output.apply(this, arguments) |
|
|
|
|
} |
|
|
|
|
_output () { |
|
|
|
|
var self = this |
|
|
|
|
var args = [...arguments] |
|
|
|
|
self.data.session.push(args) |
|
|
|
|
args.forEach(function (data) { |
|
|
|
|
if (!data || !data.type) data = { type: 'log', value: data } |
|
|
|
|
var render = self._templates[data.type] |
|
|
|
|
var blocks = render(data.value) |
|
|
|
|
blocks = [].concat(blocks) |
|
|
|
|
blocks.forEach(function (block) { |
|
|
|
|
self._view.journal.appendChild(yo` |
|
|
|
|
<div class="${css.block} ${css[data.type] || data.type}"> |
|
|
|
|
${block} |
|
|
|
|
</div> |
|
|
|
|
`)
|
|
|
|
|
self.scroll2bottom() |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
scroll2bottom () { |
|
|
|
|
var self = this |
|
|
|
|
setTimeout(function () { |
|
|
|
|
self._view.term.scrollTop = self._view.term.scrollHeight |
|
|
|
|
}, 0) |
|
|
|
|
} |
|
|
|
|
_shell (script, done) { // default shell
|
|
|
|
|
_shell (script, scopedCommands, done) { // default shell
|
|
|
|
|
var self = this |
|
|
|
|
var context = domTerminalFeatures(self, scopedCommands) |
|
|
|
|
try { |
|
|
|
|
var context = vm.createContext(Object.assign(self._jsSandboxContext, domTerminalFeatures(self))) |
|
|
|
|
var result = vm.runInContext(script, context) |
|
|
|
|
var cmds = vm.createContext(Object.assign(self._jsSandboxContext, context)) |
|
|
|
|
var result = vm.runInContext(script, cmds) |
|
|
|
|
self._jsSandboxContext = Object.assign({}, context) |
|
|
|
|
done(null, result) |
|
|
|
|
} catch (error) { |
|
|
|
@ -503,14 +578,40 @@ class Terminal { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function domTerminalFeatures (self) { |
|
|
|
|
// @TODO add all the `console` functions
|
|
|
|
|
function domTerminalFeatures (self, scopedCommands) { |
|
|
|
|
return { |
|
|
|
|
web3: executionContext.getProvider() !== 'vm' ? new Web3(executionContext.web3().currentProvider) : null, |
|
|
|
|
console: { |
|
|
|
|
log: function () { self._output.apply(self, arguments) } |
|
|
|
|
log: function () { scopedCommands.log.apply(scopedCommands, arguments) }, |
|
|
|
|
info: function () { scopedCommands.info.apply(scopedCommands, arguments) }, |
|
|
|
|
error: function () { scopedCommands.error.apply(scopedCommands, arguments) } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function findDeep (object, fn, found = { break: false, value: undefined }) { |
|
|
|
|
if (typeof object !== 'object' || object === null) return |
|
|
|
|
for (var i in object) { |
|
|
|
|
if (found.break) break |
|
|
|
|
var el = object[i] |
|
|
|
|
if (!fn(el, i, object)) findDeep(el, fn, found) |
|
|
|
|
else if (found.break = true) return found.value = el // eslint-disable-line
|
|
|
|
|
} |
|
|
|
|
return found.value |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function match (args, query) { |
|
|
|
|
query = query.trim() |
|
|
|
|
var isMatch = !!findDeep(args, function check (value, key) { |
|
|
|
|
if (value === undefined || value === null) return false |
|
|
|
|
if (typeof value === 'function') return false |
|
|
|
|
if (typeof value === 'object') return false |
|
|
|
|
var contains = String(value).indexOf(query.trim()) !== -1 |
|
|
|
|
return contains |
|
|
|
|
}) |
|
|
|
|
return isMatch |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function blockify (el) { return yo`<div class=${css.block}>${el}</div>` } |
|
|
|
|
|
|
|
|
|
module.exports = Terminal |
|
|
|
|