Commit d0d13b00 authored by serapath's avatar serapath Committed by yann300

ADD terminal (first draft)

parent 01336798
......@@ -107,7 +107,7 @@ class App {
self._components.editor = new Editor({}) // @TODO: put into editorpanel
// ----------------- editor panel ----------------------
self._components.editorpanel = new EditorPanel({
api: { editor: self._components.editor }
api: { editor: self._components.editor, config: self._api.config }
})
self._components.editorpanel.event.register('resize', direction => self._adjustLayout(direction))
}
......
......@@ -8,10 +8,8 @@ var Range = ace.acequire('ace/range').Range
require('./mode-solidity.js')
var css = csjs`
.ace-editor {
font-size : 1.1em;
width : 100%;
height : 100%;
.ace-editor {
width : 100%;
}
`
document.head.appendChild(yo`
......
......@@ -2,7 +2,14 @@ var csjs = require('csjs-inject')
var yo = require('yo-yo')
var EventManager = require('ethereum-remix').lib.EventManager
var Terminal = require('./terminal')
var css = csjs`
.editorpanel {
display : flex;
flex-direction : column;
height : 100%;
}
.tabsbar {
display : flex;
overflow : hidden;
......@@ -105,17 +112,76 @@ var css = csjs`
pointer-events : none;
transition : .3s opacity ease-in;
}
.content {
position : relative;
display : flex;
flex-direction : column;
height : 100%;
width : 100%;
}
`
class EditorPanel {
constructor (opts = {}) {
var self = this
self._api = { config: opts.api.config }
self.event = new EventManager()
self.data = {
_FILE_SCROLL_DELTA: 200
_FILE_SCROLL_DELTA: 200,
_layout: {
top: {
offset: self._api.config.get('terminal-top-offset') || 500,
show: true
}
}
}
self._view = {}
self._api = { editor: opts.api.editor }
self.event = new EventManager()
self._components = {
editor: opts.api.editor, // @TODO: instantiate in eventpanel instead of passing via `opts`
terminal: new Terminal({
api: {
getPosition (event) {
var limitUp = 36
var limitDown = 20
var height = window.innerHeight
var newpos = (event.pageY < limitUp) ? limitUp : event.pageY
newpos = (newpos < height - limitDown) ? newpos : height - limitDown
return newpos
}
}
// events: { txlistener: txlistener.event, udapp: udapp.event }
})
}
self._components.terminal.event.register('resize', delta => self._adjustLayout('top', delta))
}
_adjustLayout (direction, delta) {
var limitUp = 36
var limitDown = 20
var containerHeight = window.innerHeight - limitUp // - menu bar containerHeight
var self = this
var layout = self.data._layout[direction]
if (layout) {
if (delta === undefined) {
layout.show = !layout.show
if (layout.show) delta = layout.offset
else delta = containerHeight
} else {
layout.show = true
self._api.config.set(`terminal-${direction}-offset`, delta)
layout.offset = delta
}
}
var tmp = delta - limitDown
delta = tmp > 0 ? tmp : 0
if (direction === 'top') {
var height = containerHeight - delta
height = height < 0 ? 0 : height
self._view.editor.style.height = `${delta}px`
self._view.terminal.style.height = `${height}px` // - menu bar height
self._components.editor.resize((document.querySelector('#editorWrap') || {}).checked)
self._components.terminal.scroll2bottom()
}
}
refresh () {
var self = this
......@@ -124,10 +190,22 @@ class EditorPanel {
render () {
var self = this
if (self._view.el) return self._view.el
self._view.el = [
self._renderTabsbar(),
self._api.editor.render()
]
self._view.editor = self._components.editor.render()
self._view.terminal = self._components.terminal.render()
self._view.content = yo`
<div class=${css.content}>
${self._view.editor}
${self._view.terminal}
</div>
`
self._view.el = yo`
<div class=${css.editorpanel}>
${self._renderTabsbar()}
${self._view.content}
</div>
`
// INIT
self._adjustLayout('top', self.data._layout.top.offset)
return self._view.el
}
_renderTabsbar () {
......@@ -197,8 +275,8 @@ class EditorPanel {
this.children[0].classList.toggle('fa-angle-double-left')
self.event.trigger('resize', ['right'])
}
function increase () { self._api.editor.editorFontSize(1) }
function decrease () { self._api.editor.editorFontSize(-1) }
function increase () { self._components.editor.editorFontSize(1) }
function decrease () { self._components.editor.editorFontSize(-1) }
function scrollLeft (event) {
var leftArrow = this
var rightArrow = this.nextElementSibling.nextElementSibling
......
......@@ -228,7 +228,7 @@ function filepanel (appAPI, filesProvider) {
newpos = (newpos < (rhp - limit)) ? newpos : (rhp - limit)
return newpos
}
function moveGhostbar (event) {
function moveGhostbar (event) { // @NOTE VERTICAL ghostbar
ghostbar.style.left = getPosition(event) + 'px'
}
function removeGhostbar (event) {
......
......@@ -132,7 +132,7 @@ function RighthandPanel (appAPI, events, opts) {
newpos = (newpos > (lhp + limit)) ? newpos : lhp + limit
return newpos
}
function moveGhostbar (event) {
function moveGhostbar (event) { // @NOTE VERTICAL ghostbar
ghostbar.style.left = getPosition(event) + 'px'
}
function removeGhostbar (event) {
......
var yo = require('yo-yo')
var csjs = require('csjs-inject')
var EventManager = require('ethereum-remix').lib.EventManager
var css = csjs`
.panel {
position : relative;
display : flex;
flex-direction : column;
font-size : 12px;
font-family : monospace;
color : white;
background-color : black;
margin-top : auto;
height : 100%;
min-height : 1.7em;
}
.bar {
display : flex;
justify-content : flex-end;
min-height : 1.7em;
padding : 2px;
cursor : ns-resize;
background-color : #eef;
}
.minimize {
text-align : center;
padding-top : 3px;
width : 10px;
min-height : 100%;
cursor : pointer;
color : black;
}
.hover {
color : orange;
}
.terminal {
display : flex;
flex-direction : column;
height : 100%;
padding-left : 5px;
padding-right : 5px;
padding-bottom : 3px;
overflow-y : auto;
font-family : monospace;
}
.log {
margin-top : auto;
font-family : monospace;
}
.block {
word-break : break-all;
white-space : pre-wrap;
line-height : 1ch;
min-height : 1ch;
width : 80ch;
background-color : darkblue;
}
.cli {
line-height : 1.7em;
font-family : monospace;
}
.prompt {
margin-right : 0.5em;
font-family : monospace;
}
.input {
word-break : break-all;
outline : none;
font-family : monospace;
}
.ghostbar {
position : absolute;
height : 6px;
background-color : #C6CFF7;
opacity : 0.5;
cursor : row-resize;
z-index : 9999;
left : 0;
right : 0;
}
`
var ghostbar = yo`<div class=${css.ghostbar}></div>`
class Terminal {
constructor (opts = {}) {
var self = this
self.data = {
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
******************************************************************************/
`
}
self.event = new EventManager()
self._api = opts.api
self._view = { panel: null, bar: null, input: null, term: null, log: null, cli: null }
if (opts.shell) self._shell = opts.shell
// var events = opts.events
// events.txlistener.register('newBlock', function (block) {
// self.log(block)
// })
// events.udapp.register('transactionExecuted', function (address, data, lookupOnly, txResult) {
// self.log({ address, data, lookupOnly, txResult })
// // - trans.sent and info about it once it's mined
// // - everything related to the address
// })
// ////////
// make `web3` object available in the console vm
// web3.object creates contract
// * create transaction
// * when transaction is mined
// => show all transactions, that are mined and have known addresses
}
render () {
var self = this
if (self._view.panel) return self._view.panel
self._view.log = yo`<div class=${css.log}></div>`
window.INPUT = self._view.input = yo`
<span class=${css.input} contenteditable="true" onkeydown=${change}></span>
`
self._view.cli = yo`
<div class=${css.cli} onclick=${e => self._view.input.focus()}>
<span class=${css.prompt}>${'>'}</span>
${self._view.input}
</div>
`
self._view.icon = yo`<i onmouseenter=${hover} onmouseleave=${hover} onmousedown=${minimize} class="${css.minimize} fa fa-angle-double-down"></i>`
self._view.bar = yo`
<div class=${css.bar} onmousedown=${mousedown}>
${self._view.icon}
</div>
`
self._view.term = yo`
<div class=${css.terminal}>
${self._view.log}
${self._view.cli}
</div>
`
self._view.panel = yo`
<div class=${css.panel}>
${self._view.bar}
${self._view.term}
</div>
`
self.log(self.data.banner)
// @TODO: on manual scroll, stop auto-scroll-to-bottom
// @TODO: while in stopped mode: show indicator about new lines getting logged
function hover (event) { event.currentTarget.classList.toggle(css.hover) }
function minimize (event) {
event.preventDefault()
event.stopPropagation()
var classList = self._view.icon.classList
classList.toggle('fa-angle-double-down')
classList.toggle('fa-angle-double-up')
self.event.trigger('resize', [])
}
// ----------------- resizeable ui ---------------
function mousedown (event) {
event.preventDefault()
if (event.which === 1) {
moveGhostbar(event)
document.body.appendChild(ghostbar)
document.addEventListener('mousemove', moveGhostbar)
document.addEventListener('mouseup', removeGhostbar)
document.addEventListener('keydown', cancelGhostbar)
}
}
function cancelGhostbar (event) {
if (event.keyCode === 27) {
document.body.removeChild(ghostbar)
document.removeEventListener('mousemove', moveGhostbar)
document.removeEventListener('mouseup', removeGhostbar)
document.removeEventListener('keydown', cancelGhostbar)
}
}
function moveGhostbar (event) { // @NOTE HORIZONTAL ghostbar
ghostbar.style.top = self._api.getPosition(event) + 'px'
}
function removeGhostbar (event) {
if (self._view.icon.classList.contains('fa-angle-double-up')) {
self._view.icon.classList.toggle('fa-angle-double-down')
self._view.icon.classList.toggle('fa-angle-double-up')
}
document.body.removeChild(ghostbar)
document.removeEventListener('mousemove', moveGhostbar)
document.removeEventListener('mouseup', removeGhostbar)
document.removeEventListener('keydown', cancelGhostbar)
self.event.trigger('resize', [self._api.getPosition(event)])
}
return self._view.panel
function change (event) {
if (event.which === 13) {
if (event.ctrlKey) { // <ctrl+enter>
// console.log('enter')
self._view.input.appendChild(document.createElement('br'))
self.scroll2bottom()
} else {
event.preventDefault()
}
}
console.log(event.which, event.keyCode)
// console.log('----------------')
// console.log(event.key) // Control
// console.log('-----')
// console.log(event.code) // ControlLeft
// console.log('-----------')
// console.log('event.altKey ' + event.altKey)
// console.log('event.ctrlKey ' + event.ctrlKey)
// console.log('event.metaKey ' + event.metaKey)
// console.log('event.shiftKey ' + event.shiftKey)
// console.log(event.location)
// console.log('event.location')
// console.log(event.returnValue)
// console.log('event.returnValue')
// console.log(event.type)
// console.log('event.type')
// console.log('-----')
// console.log(event)
}
}
log (obj) {
var self = this
// var entries = self._serialize(obj)
// @TODO: convert types to \n string arrays
var entries = obj.split('\n')
self.data.session.push(entries)
var block = yo`
<div class=${css.block}>
${entries.map(str => document.createTextNode(`${str}\n`))}
</div>
`
self._view.log.appendChild(block)
self.scroll2bottom()
return entries
}
scroll2bottom () {
var self = this
setTimeout(function () {
self._view.term.scrollTop = self._view.term.scrollHeight
}, 0)
}
_serialize (obj) { return JSON.stringify(obj, null, 2) }
_shell (text) { // default shell
var self = this
self.log(text)
var result = self.evaluate(text)
self.log(result)
}
}
module.exports = Terminal
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment