mirror of https://github.com/ethereum/go-ethereum
commit
a77dcd1041
@ -0,0 +1,236 @@ |
|||||||
|
// Main Ethereum library
|
||||||
|
window.eth = { |
||||||
|
prototype: Object(), |
||||||
|
|
||||||
|
// Retrieve block
|
||||||
|
//
|
||||||
|
// Either supply a number or a string. Type is determent for the lookup method
|
||||||
|
// string - Retrieves the block by looking up the hash
|
||||||
|
// number - Retrieves the block by looking up the block number
|
||||||
|
getBlock: function(numberOrHash, cb) { |
||||||
|
var func; |
||||||
|
if(typeof numberOrHash == "string") { |
||||||
|
func = "getBlockByHash"; |
||||||
|
} else { |
||||||
|
func = "getBlockByNumber"; |
||||||
|
} |
||||||
|
postData({call: func, args: [numberOrHash]}, cb); |
||||||
|
}, |
||||||
|
|
||||||
|
// Create transaction
|
||||||
|
//
|
||||||
|
// Transact between two state objects
|
||||||
|
transact: function(sec, recipient, value, gas, gasPrice, data, cb) { |
||||||
|
postData({call: "transact", args: [sec, recipient, value, gas, gasPrice, data]}, cb); |
||||||
|
}, |
||||||
|
|
||||||
|
create: function(sec, value, gas, gasPrice, init, body, cb) { |
||||||
|
postData({call: "create", args: [sec, value, gas, gasPrice, init, body]}, cb); |
||||||
|
}, |
||||||
|
|
||||||
|
getStorageAt: function(address, storageAddress, cb) { |
||||||
|
postData({call: "getStorage", args: [address, storageAddress]}, cb); |
||||||
|
}, |
||||||
|
|
||||||
|
getKey: function(cb) { |
||||||
|
postData({call: "getKey"}, cb); |
||||||
|
}, |
||||||
|
|
||||||
|
getBalanceAt: function(address, cb) { |
||||||
|
postData({call: "getBalance", args: [address]}, cb); |
||||||
|
}, |
||||||
|
|
||||||
|
getSecretToAddress: function(sec, cb) { |
||||||
|
postData({call: "getSecretToAddress", args: [sec]}, cb); |
||||||
|
}, |
||||||
|
|
||||||
|
watch: function(address, storageAddrOrCb, cb) { |
||||||
|
var ev; |
||||||
|
if(cb === undefined) { |
||||||
|
cb = storageAddrOrCb; |
||||||
|
storageAddrOrCb = ""; |
||||||
|
ev = "object:"+address; |
||||||
|
} else { |
||||||
|
ev = "storage:"+address+":"+storageAddrOrCb; |
||||||
|
} |
||||||
|
|
||||||
|
eth.on(ev, cb) |
||||||
|
|
||||||
|
postData({call: "watch", args: [address, storageAddrOrCb]}); |
||||||
|
}, |
||||||
|
|
||||||
|
disconnect: function(address, storageAddrOrCb, cb) { |
||||||
|
var ev; |
||||||
|
if(cb === undefined) { |
||||||
|
cb = storageAddrOrCb; |
||||||
|
storageAddrOrCb = ""; |
||||||
|
ev = "object:"+address; |
||||||
|
} else { |
||||||
|
ev = "storage:"+address+":"+storageAddrOrCb; |
||||||
|
} |
||||||
|
|
||||||
|
eth.off(ev, cb) |
||||||
|
|
||||||
|
postData({call: "disconnect", args: [address, storageAddrOrCb]}); |
||||||
|
}, |
||||||
|
|
||||||
|
set: function(props) { |
||||||
|
postData({call: "set", args: props}); |
||||||
|
}, |
||||||
|
|
||||||
|
on: function(event, cb) { |
||||||
|
if(eth._onCallbacks[event] === undefined) { |
||||||
|
eth._onCallbacks[event] = []; |
||||||
|
} |
||||||
|
|
||||||
|
eth._onCallbacks[event].push(cb); |
||||||
|
|
||||||
|
return this |
||||||
|
}, |
||||||
|
|
||||||
|
off: function(event, cb) { |
||||||
|
if(eth._onCallbacks[event] !== undefined) { |
||||||
|
var callbacks = eth._onCallbacks[event]; |
||||||
|
for(var i = 0; i < callbacks.length; i++) { |
||||||
|
if(callbacks[i] === cb) { |
||||||
|
delete callbacks[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return this |
||||||
|
}, |
||||||
|
|
||||||
|
trigger: function(event, data) { |
||||||
|
var callbacks = eth._onCallbacks[event]; |
||||||
|
if(callbacks !== undefined) { |
||||||
|
for(var i = 0; i < callbacks.length; i++) { |
||||||
|
// Figure out whether the returned data was an array
|
||||||
|
// array means multiple return arguments (multiple params)
|
||||||
|
if(data instanceof Array) { |
||||||
|
callbacks[i].apply(this, data); |
||||||
|
} else { |
||||||
|
callbacks[i].call(this, data); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
} |
||||||
|
window.eth._callbacks = {} |
||||||
|
window.eth._onCallbacks = {} |
||||||
|
|
||||||
|
function hello() { |
||||||
|
debug("hello") |
||||||
|
window.dataTest = true; |
||||||
|
} |
||||||
|
|
||||||
|
function debug(/**/) { |
||||||
|
var args = arguments; |
||||||
|
var msg = "" |
||||||
|
for(var i = 0; i < args.length; i++){ |
||||||
|
if(typeof args[i] === "object") { |
||||||
|
msg += " " + JSON.stringify(args[i]) |
||||||
|
} else { |
||||||
|
msg += args[i] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
postData({call:"debug", args:[msg]}) |
||||||
|
document.getElementById("debug").innerHTML += "<br>" + msg |
||||||
|
} |
||||||
|
|
||||||
|
// Helper function for generating pseudo callbacks and sending data to the QML part of the application
|
||||||
|
function postData(data, cb) { |
||||||
|
data._seed = Math.floor(Math.random() * 1000000) |
||||||
|
if(cb) { |
||||||
|
eth._callbacks[data._seed] = cb; |
||||||
|
} |
||||||
|
|
||||||
|
if(data.args === undefined) { |
||||||
|
data.args = []; |
||||||
|
} |
||||||
|
|
||||||
|
navigator.qt.postMessage(JSON.stringify(data)); |
||||||
|
} |
||||||
|
|
||||||
|
navigator.qt.onmessage = function(ev) { |
||||||
|
var data = JSON.parse(ev.data) |
||||||
|
|
||||||
|
if(data._event !== undefined) { |
||||||
|
eth.trigger(data._event, data.data); |
||||||
|
} else { |
||||||
|
if(data._seed) { |
||||||
|
var cb = eth._callbacks[data._seed]; |
||||||
|
if(cb) { |
||||||
|
// Figure out whether the returned data was an array
|
||||||
|
// array means multiple return arguments (multiple params)
|
||||||
|
if(data.data instanceof Array) { |
||||||
|
cb.apply(this, data.data) |
||||||
|
} else { |
||||||
|
cb.call(this, data.data) |
||||||
|
} |
||||||
|
|
||||||
|
// Remove the "trigger" callback
|
||||||
|
delete eth._callbacks[ev._seed]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
window.eth._0 = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" |
||||||
|
String.prototype.pad = function(len) { |
||||||
|
var bin = this.bin(); |
||||||
|
var l = bin.length; |
||||||
|
if(l < 32) { |
||||||
|
return eth._0.substr(0, 32 - bin.length) + bin; |
||||||
|
} |
||||||
|
|
||||||
|
return bin; |
||||||
|
} |
||||||
|
|
||||||
|
String.prototype.unpad = function() { |
||||||
|
var i, l; |
||||||
|
for(i = 0, l = this.length; i < l; i++) { |
||||||
|
if(this[i] != "\0") { |
||||||
|
return this.substr(i, this.length); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return this.substr(i, this.length); |
||||||
|
} |
||||||
|
|
||||||
|
String.prototype.bin = function() { |
||||||
|
if(this.substr(0, 2) == "0x") { |
||||||
|
return this.hex2bin(); |
||||||
|
} else if(/^\d+$/.test(this)) { |
||||||
|
return this.num2bin() |
||||||
|
} |
||||||
|
|
||||||
|
// Otherwise we'll return the "String" object instead of an actual string
|
||||||
|
return this.substr(0, this.length) |
||||||
|
} |
||||||
|
|
||||||
|
String.prototype.unbin = function() { |
||||||
|
var i, l, o = ''; |
||||||
|
for(i = 0, l = this.length; i < l; i++) { |
||||||
|
var n = this.charCodeAt(i).toString(16); |
||||||
|
o += n.length < 2 ? '0' + n : n; |
||||||
|
} |
||||||
|
|
||||||
|
return "0x" + o; |
||||||
|
} |
||||||
|
|
||||||
|
String.prototype.hex2bin = function() { |
||||||
|
bytes = [] |
||||||
|
|
||||||
|
for(var i=2; i< this.length-1; i+=2) { |
||||||
|
bytes.push(parseInt(this.substr(i, 2), 16)); |
||||||
|
} |
||||||
|
|
||||||
|
return String.fromCharCode.apply(String, bytes); |
||||||
|
} |
||||||
|
|
||||||
|
String.prototype.num2bin = function() { |
||||||
|
return ("0x"+parseInt(this).toString(16)).bin() |
||||||
|
} |
||||||
|
|
@ -0,0 +1,272 @@ |
|||||||
|
/* BASICS */ |
||||||
|
|
||||||
|
.CodeMirror { |
||||||
|
/* Set height, width, borders, and global font properties here */ |
||||||
|
font-family: monospace; |
||||||
|
height: 300px; |
||||||
|
} |
||||||
|
.CodeMirror-scroll { |
||||||
|
/* Set scrolling behaviour here */ |
||||||
|
overflow: auto; |
||||||
|
} |
||||||
|
|
||||||
|
/* PADDING */ |
||||||
|
|
||||||
|
.CodeMirror-lines { |
||||||
|
padding: 4px 0; /* Vertical padding around content */ |
||||||
|
} |
||||||
|
.CodeMirror pre { |
||||||
|
padding: 0 4px; /* Horizontal padding of content */ |
||||||
|
} |
||||||
|
|
||||||
|
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { |
||||||
|
background-color: white; /* The little square between H and V scrollbars */ |
||||||
|
} |
||||||
|
|
||||||
|
/* GUTTER */ |
||||||
|
|
||||||
|
.CodeMirror-gutters { |
||||||
|
border-right: 1px solid #ddd; |
||||||
|
background-color: #f7f7f7; |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
.CodeMirror-linenumbers {} |
||||||
|
.CodeMirror-linenumber { |
||||||
|
padding: 0 3px 0 5px; |
||||||
|
min-width: 20px; |
||||||
|
text-align: right; |
||||||
|
color: #999; |
||||||
|
-moz-box-sizing: content-box; |
||||||
|
box-sizing: content-box; |
||||||
|
} |
||||||
|
|
||||||
|
/* CURSOR */ |
||||||
|
|
||||||
|
.CodeMirror div.CodeMirror-cursor { |
||||||
|
border-left: 1px solid black; |
||||||
|
} |
||||||
|
/* Shown when moving in bi-directional text */ |
||||||
|
.CodeMirror div.CodeMirror-secondarycursor { |
||||||
|
border-left: 1px solid silver; |
||||||
|
} |
||||||
|
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor { |
||||||
|
width: auto; |
||||||
|
border: 0; |
||||||
|
background: #7e7; |
||||||
|
} |
||||||
|
/* Can style cursor different in overwrite (non-insert) mode */ |
||||||
|
div.CodeMirror-overwrite div.CodeMirror-cursor {} |
||||||
|
|
||||||
|
.cm-tab { display: inline-block; } |
||||||
|
|
||||||
|
.CodeMirror-ruler { |
||||||
|
border-left: 1px solid #ccc; |
||||||
|
position: absolute; |
||||||
|
} |
||||||
|
|
||||||
|
/* DEFAULT THEME */ |
||||||
|
|
||||||
|
.cm-s-default .cm-keyword {color: #708;} |
||||||
|
.cm-s-default .cm-atom {color: #219;} |
||||||
|
.cm-s-default .cm-number {color: #164;} |
||||||
|
.cm-s-default .cm-def {color: #00f;} |
||||||
|
.cm-s-default .cm-variable, |
||||||
|
.cm-s-default .cm-punctuation, |
||||||
|
.cm-s-default .cm-property, |
||||||
|
.cm-s-default .cm-operator {} |
||||||
|
.cm-s-default .cm-variable-2 {color: #05a;} |
||||||
|
.cm-s-default .cm-variable-3 {color: #085;} |
||||||
|
.cm-s-default .cm-comment {color: #a50;} |
||||||
|
.cm-s-default .cm-string {color: #a11;} |
||||||
|
.cm-s-default .cm-string-2 {color: #f50;} |
||||||
|
.cm-s-default .cm-meta {color: #555;} |
||||||
|
.cm-s-default .cm-qualifier {color: #555;} |
||||||
|
.cm-s-default .cm-builtin {color: #30a;} |
||||||
|
.cm-s-default .cm-bracket {color: #997;} |
||||||
|
.cm-s-default .cm-tag {color: #170;} |
||||||
|
.cm-s-default .cm-attribute {color: #00c;} |
||||||
|
.cm-s-default .cm-header {color: blue;} |
||||||
|
.cm-s-default .cm-quote {color: #090;} |
||||||
|
.cm-s-default .cm-hr {color: #999;} |
||||||
|
.cm-s-default .cm-link {color: #00c;} |
||||||
|
|
||||||
|
.cm-negative {color: #d44;} |
||||||
|
.cm-positive {color: #292;} |
||||||
|
.cm-header, .cm-strong {font-weight: bold;} |
||||||
|
.cm-em {font-style: italic;} |
||||||
|
.cm-link {text-decoration: underline;} |
||||||
|
|
||||||
|
.cm-s-default .cm-error {color: #f00;} |
||||||
|
.cm-invalidchar {color: #f00;} |
||||||
|
|
||||||
|
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} |
||||||
|
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} |
||||||
|
.CodeMirror-activeline-background {background: #e8f2ff;} |
||||||
|
|
||||||
|
/* STOP */ |
||||||
|
|
||||||
|
/* The rest of this file contains styles related to the mechanics of |
||||||
|
the editor. You probably shouldn't touch them. */ |
||||||
|
|
||||||
|
.CodeMirror { |
||||||
|
line-height: 1; |
||||||
|
position: relative; |
||||||
|
overflow: hidden; |
||||||
|
background: white; |
||||||
|
color: black; |
||||||
|
} |
||||||
|
|
||||||
|
.CodeMirror-scroll { |
||||||
|
/* 30px is the magic margin used to hide the element's real scrollbars */ |
||||||
|
/* See overflow: hidden in .CodeMirror */ |
||||||
|
margin-bottom: -30px; margin-right: -30px; |
||||||
|
padding-bottom: 30px; |
||||||
|
height: 100%; |
||||||
|
outline: none; /* Prevent dragging from highlighting the element */ |
||||||
|
position: relative; |
||||||
|
-moz-box-sizing: content-box; |
||||||
|
box-sizing: content-box; |
||||||
|
} |
||||||
|
.CodeMirror-sizer { |
||||||
|
position: relative; |
||||||
|
border-right: 30px solid transparent; |
||||||
|
-moz-box-sizing: content-box; |
||||||
|
box-sizing: content-box; |
||||||
|
} |
||||||
|
|
||||||
|
/* The fake, visible scrollbars. Used to force redraw during scrolling |
||||||
|
before actuall scrolling happens, thus preventing shaking and |
||||||
|
flickering artifacts. */ |
||||||
|
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { |
||||||
|
position: absolute; |
||||||
|
z-index: 6; |
||||||
|
display: none; |
||||||
|
} |
||||||
|
.CodeMirror-vscrollbar { |
||||||
|
right: 0; top: 0; |
||||||
|
overflow-x: hidden; |
||||||
|
overflow-y: scroll; |
||||||
|
} |
||||||
|
.CodeMirror-hscrollbar { |
||||||
|
bottom: 0; left: 0; |
||||||
|
overflow-y: hidden; |
||||||
|
overflow-x: scroll; |
||||||
|
} |
||||||
|
.CodeMirror-scrollbar-filler { |
||||||
|
right: 0; bottom: 0; |
||||||
|
} |
||||||
|
.CodeMirror-gutter-filler { |
||||||
|
left: 0; bottom: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.CodeMirror-gutters { |
||||||
|
position: absolute; left: 0; top: 0; |
||||||
|
padding-bottom: 30px; |
||||||
|
z-index: 3; |
||||||
|
} |
||||||
|
.CodeMirror-gutter { |
||||||
|
white-space: normal; |
||||||
|
height: 100%; |
||||||
|
-moz-box-sizing: content-box; |
||||||
|
box-sizing: content-box; |
||||||
|
padding-bottom: 30px; |
||||||
|
margin-bottom: -32px; |
||||||
|
display: inline-block; |
||||||
|
/* Hack to make IE7 behave */ |
||||||
|
*zoom:1; |
||||||
|
*display:inline; |
||||||
|
} |
||||||
|
.CodeMirror-gutter-elt { |
||||||
|
position: absolute; |
||||||
|
cursor: default; |
||||||
|
z-index: 4; |
||||||
|
} |
||||||
|
|
||||||
|
.CodeMirror-lines { |
||||||
|
cursor: text; |
||||||
|
} |
||||||
|
.CodeMirror pre { |
||||||
|
/* Reset some styles that the rest of the page might have set */ |
||||||
|
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; |
||||||
|
border-width: 0; |
||||||
|
background: transparent; |
||||||
|
font-family: inherit; |
||||||
|
font-size: inherit; |
||||||
|
margin: 0; |
||||||
|
white-space: pre; |
||||||
|
word-wrap: normal; |
||||||
|
line-height: inherit; |
||||||
|
color: inherit; |
||||||
|
z-index: 2; |
||||||
|
position: relative; |
||||||
|
overflow: visible; |
||||||
|
} |
||||||
|
.CodeMirror-wrap pre { |
||||||
|
word-wrap: break-word; |
||||||
|
white-space: pre-wrap; |
||||||
|
word-break: normal; |
||||||
|
} |
||||||
|
|
||||||
|
.CodeMirror-linebackground { |
||||||
|
position: absolute; |
||||||
|
left: 0; right: 0; top: 0; bottom: 0; |
||||||
|
z-index: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.CodeMirror-linewidget { |
||||||
|
position: relative; |
||||||
|
z-index: 2; |
||||||
|
overflow: auto; |
||||||
|
} |
||||||
|
|
||||||
|
.CodeMirror-widget {} |
||||||
|
|
||||||
|
.CodeMirror-wrap .CodeMirror-scroll { |
||||||
|
overflow-x: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
.CodeMirror-measure { |
||||||
|
position: absolute; |
||||||
|
width: 100%; |
||||||
|
height: 0; |
||||||
|
overflow: hidden; |
||||||
|
visibility: hidden; |
||||||
|
} |
||||||
|
.CodeMirror-measure pre { position: static; } |
||||||
|
|
||||||
|
.CodeMirror div.CodeMirror-cursor { |
||||||
|
position: absolute; |
||||||
|
border-right: none; |
||||||
|
width: 0; |
||||||
|
} |
||||||
|
|
||||||
|
div.CodeMirror-cursors { |
||||||
|
visibility: hidden; |
||||||
|
position: relative; |
||||||
|
z-index: 1; |
||||||
|
} |
||||||
|
.CodeMirror-focused div.CodeMirror-cursors { |
||||||
|
visibility: visible; |
||||||
|
} |
||||||
|
|
||||||
|
.CodeMirror-selected { background: #d9d9d9; } |
||||||
|
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } |
||||||
|
.CodeMirror-crosshair { cursor: crosshair; } |
||||||
|
|
||||||
|
.cm-searching { |
||||||
|
background: #ffa; |
||||||
|
background: rgba(255, 255, 0, .4); |
||||||
|
} |
||||||
|
|
||||||
|
/* IE7 hack to prevent it from returning funny offsetTops on the spans */ |
||||||
|
.CodeMirror span { *vertical-align: text-bottom; } |
||||||
|
|
||||||
|
/* Used to force a border model for a node */ |
||||||
|
.cm-force-border { padding-right: .1px; } |
||||||
|
|
||||||
|
@media print { |
||||||
|
/* Hide the cursor when printing */ |
||||||
|
.CodeMirror div.CodeMirror-cursors { |
||||||
|
visibility: hidden; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
<!doctype> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<style type="text/css"> |
||||||
|
html, body { |
||||||
|
margin: 0; padding: 0; |
||||||
|
min-height: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
#debugger { |
||||||
|
height: 100%; |
||||||
|
font-family: "Monaco" |
||||||
|
} |
||||||
|
#debugger .line { |
||||||
|
overflow: none; |
||||||
|
} |
||||||
|
#debugger .col1, #debugger .col2 { |
||||||
|
float: left; |
||||||
|
padding: 3px; |
||||||
|
} |
||||||
|
#debugger .col1 { |
||||||
|
width: 10px; |
||||||
|
padding-left: 10px |
||||||
|
-webkit-touch-callout: none; |
||||||
|
-webkit-user-select: none; |
||||||
|
-khtml-user-select: none; |
||||||
|
-moz-user-select: none; |
||||||
|
-ms-user-select: none; |
||||||
|
user-select: none; |
||||||
|
} |
||||||
|
#debugger .col2 { |
||||||
|
width: 90%; |
||||||
|
} |
||||||
|
.prompt { |
||||||
|
color: "#5089D4"; |
||||||
|
} |
||||||
|
</style> |
||||||
|
|
||||||
|
</head> |
||||||
|
|
||||||
|
<body> |
||||||
|
<div id="debugger"> |
||||||
|
<div class="line"> |
||||||
|
<div class="col1 prompt"> |
||||||
|
> |
||||||
|
</div> |
||||||
|
<div class="col2" contenteditable> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,23 @@ |
|||||||
|
.cm-s-eclipse span.cm-meta {color: #FF1717;} |
||||||
|
.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; } |
||||||
|
.cm-s-eclipse span.cm-atom {color: #219;} |
||||||
|
.cm-s-eclipse span.cm-number {color: #164;} |
||||||
|
.cm-s-eclipse span.cm-def {color: #00f;} |
||||||
|
.cm-s-eclipse span.cm-variable {color: black;} |
||||||
|
.cm-s-eclipse span.cm-variable-2 {color: #0000C0;} |
||||||
|
.cm-s-eclipse span.cm-variable-3 {color: #0000C0;} |
||||||
|
.cm-s-eclipse span.cm-property {color: black;} |
||||||
|
.cm-s-eclipse span.cm-operator {color: black;} |
||||||
|
.cm-s-eclipse span.cm-comment {color: #3F7F5F;} |
||||||
|
.cm-s-eclipse span.cm-string {color: #2A00FF;} |
||||||
|
.cm-s-eclipse span.cm-string-2 {color: #f50;} |
||||||
|
.cm-s-eclipse span.cm-qualifier {color: #555;} |
||||||
|
.cm-s-eclipse span.cm-builtin {color: #30a;} |
||||||
|
.cm-s-eclipse span.cm-bracket {color: #cc7;} |
||||||
|
.cm-s-eclipse span.cm-tag {color: #170;} |
||||||
|
.cm-s-eclipse span.cm-attribute {color: #00c;} |
||||||
|
.cm-s-eclipse span.cm-link {color: #219;} |
||||||
|
.cm-s-eclipse span.cm-error {color: #f00;} |
||||||
|
|
||||||
|
.cm-s-eclipse .CodeMirror-activeline-background {background: #e8f2ff !important;} |
||||||
|
.cm-s-eclipse .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;} |
@ -0,0 +1,80 @@ |
|||||||
|
<!doctype> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<title>Mutan Editor</title> |
||||||
|
<link rel="stylesheet" href="codemirror.css"> |
||||||
|
<link rel="stylesheet" href="eclipse.css"> |
||||||
|
<script src="lib/codemirror.js"></script> |
||||||
|
<script src="lib/matchbrackets.js"></script> |
||||||
|
<script src="lib/go.js"></script> |
||||||
|
<script src="muted.js"></script> |
||||||
|
|
||||||
|
<style type="text/css"> |
||||||
|
html, body { |
||||||
|
margin: 0; padding: 0; |
||||||
|
min-height: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
#debugger { |
||||||
|
height: 30%; |
||||||
|
font-family: "Monaco"; |
||||||
|
border-top: 5px solid grey; |
||||||
|
} |
||||||
|
#debugger .line { |
||||||
|
overflow: none; |
||||||
|
} |
||||||
|
#debugger .col1, #debugger .col2 { |
||||||
|
float: left; |
||||||
|
padding: 3px; |
||||||
|
} |
||||||
|
#debugger .col1 { |
||||||
|
width: 10px; |
||||||
|
padding-left: 10px |
||||||
|
-webkit-touch-callout: none; |
||||||
|
-webkit-user-select: none; |
||||||
|
-khtml-user-select: none; |
||||||
|
-moz-user-select: none; |
||||||
|
-ms-user-select: none; |
||||||
|
user-select: none; |
||||||
|
} |
||||||
|
#debugger .col2 { |
||||||
|
width: 90%; |
||||||
|
} |
||||||
|
.prompt { |
||||||
|
color: "#5089D4"; |
||||||
|
} |
||||||
|
|
||||||
|
.CodeMirror { |
||||||
|
height: 70%; |
||||||
|
font-size: 14pt; |
||||||
|
} |
||||||
|
</style> |
||||||
|
</head> |
||||||
|
|
||||||
|
<body> |
||||||
|
<textarea id="editor"></textarea> |
||||||
|
|
||||||
|
<div id="debugger"> |
||||||
|
<div class="line"> |
||||||
|
<div class="col1 prompt"> |
||||||
|
> |
||||||
|
</div> |
||||||
|
<div class="col2" contenteditable> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<script> |
||||||
|
var textArea = document.querySelector("#editor") |
||||||
|
var editor = CodeMirror.fromTextArea(textArea, { |
||||||
|
theme: "eclipse", |
||||||
|
mode: "text/html", |
||||||
|
lineNumbers: true, |
||||||
|
mode: "text/x-go", |
||||||
|
indentUnit: 8, |
||||||
|
tabSize: 8, |
||||||
|
indentWithTabs: true, |
||||||
|
}); |
||||||
|
</script> |
||||||
|
</body> |
||||||
|
</html> |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,182 @@ |
|||||||
|
(function(mod) { |
||||||
|
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||||
|
mod(require("../../lib/codemirror")); |
||||||
|
else if (typeof define == "function" && define.amd) // AMD
|
||||||
|
define(["../../lib/codemirror"], mod); |
||||||
|
else // Plain browser env
|
||||||
|
mod(CodeMirror); |
||||||
|
})(function(CodeMirror) { |
||||||
|
"use strict"; |
||||||
|
|
||||||
|
CodeMirror.defineMode("go", function(config) { |
||||||
|
var indentUnit = config.indentUnit; |
||||||
|
|
||||||
|
var keywords = { |
||||||
|
"break":true, "case":true, "chan":true, "const":true, "continue":true, |
||||||
|
"default":true, "defer":true, "else":true, "fallthrough":true, "for":true, |
||||||
|
"func":true, "go":true, "goto":true, "if":true, "import":true, |
||||||
|
"interface":true, "map":true, "package":true, "range":true, "return":true, |
||||||
|
"select":true, "struct":true, "switch":true, "type":true, "var":true, |
||||||
|
"bool":true, "byte":true, "complex64":true, "complex128":true, |
||||||
|
"float32":true, "float64":true, "int8":true, "int16":true, "int32":true, |
||||||
|
"int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true, |
||||||
|
"uint64":true, "int":true, "uint":true, "uintptr":true, "big": true, |
||||||
|
"main": true, "init": true, "this":true |
||||||
|
}; |
||||||
|
|
||||||
|
var atoms = { |
||||||
|
"true":true, "false":true, "iota":true, "nil":true, "append":true, |
||||||
|
"cap":true, "close":true, "complex":true, "copy":true, "imag":true, |
||||||
|
"len":true, "make":true, "new":true, "panic":true, "print":true, |
||||||
|
"println":true, "real":true, "recover":true,
|
||||||
|
}; |
||||||
|
|
||||||
|
var isOperatorChar = /[+\-*&^%:=<>!|\/]/; |
||||||
|
|
||||||
|
var curPunc; |
||||||
|
|
||||||
|
function tokenBase(stream, state) { |
||||||
|
var ch = stream.next(); |
||||||
|
if (ch == '"' || ch == "'" || ch == "`") { |
||||||
|
state.tokenize = tokenString(ch); |
||||||
|
return state.tokenize(stream, state); |
||||||
|
} |
||||||
|
if (/[\d\.]/.test(ch)) { |
||||||
|
if (ch == ".") { |
||||||
|
stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/); |
||||||
|
} else if (ch == "0") { |
||||||
|
stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/); |
||||||
|
} else { |
||||||
|
stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/); |
||||||
|
} |
||||||
|
return "number"; |
||||||
|
} |
||||||
|
if (/[\[\]{}\(\),;\:\.]/.test(ch)) { |
||||||
|
curPunc = ch; |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (ch == "/") { |
||||||
|
if (stream.eat("*")) { |
||||||
|
state.tokenize = tokenComment; |
||||||
|
return tokenComment(stream, state); |
||||||
|
} |
||||||
|
if (stream.eat("/")) { |
||||||
|
stream.skipToEnd(); |
||||||
|
return "comment"; |
||||||
|
} |
||||||
|
} |
||||||
|
if (isOperatorChar.test(ch)) { |
||||||
|
stream.eatWhile(isOperatorChar); |
||||||
|
return "operator"; |
||||||
|
} |
||||||
|
stream.eatWhile(/[\w\$_]/); |
||||||
|
var cur = stream.current(); |
||||||
|
if (keywords.propertyIsEnumerable(cur)) { |
||||||
|
if (cur == "case" || cur == "default") curPunc = "case"; |
||||||
|
return "keyword"; |
||||||
|
} |
||||||
|
if (atoms.propertyIsEnumerable(cur)) return "atom"; |
||||||
|
return "variable"; |
||||||
|
} |
||||||
|
|
||||||
|
function tokenString(quote) { |
||||||
|
return function(stream, state) { |
||||||
|
var escaped = false, next, end = false; |
||||||
|
while ((next = stream.next()) != null) { |
||||||
|
if (next == quote && !escaped) {end = true; break;} |
||||||
|
escaped = !escaped && next == "\\"; |
||||||
|
} |
||||||
|
if (end || !(escaped || quote == "`")) |
||||||
|
state.tokenize = tokenBase; |
||||||
|
return "string"; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
function tokenComment(stream, state) { |
||||||
|
var maybeEnd = false, ch; |
||||||
|
while (ch = stream.next()) { |
||||||
|
if (ch == "/" && maybeEnd) { |
||||||
|
state.tokenize = tokenBase; |
||||||
|
break; |
||||||
|
} |
||||||
|
maybeEnd = (ch == "*"); |
||||||
|
} |
||||||
|
return "comment"; |
||||||
|
} |
||||||
|
|
||||||
|
function Context(indented, column, type, align, prev) { |
||||||
|
this.indented = indented; |
||||||
|
this.column = column; |
||||||
|
this.type = type; |
||||||
|
this.align = align; |
||||||
|
this.prev = prev; |
||||||
|
} |
||||||
|
function pushContext(state, col, type) { |
||||||
|
return state.context = new Context(state.indented, col, type, null, state.context); |
||||||
|
} |
||||||
|
function popContext(state) { |
||||||
|
var t = state.context.type; |
||||||
|
if (t == ")" || t == "]" || t == "}") |
||||||
|
state.indented = state.context.indented; |
||||||
|
return state.context = state.context.prev; |
||||||
|
} |
||||||
|
|
||||||
|
// Interface
|
||||||
|
|
||||||
|
return { |
||||||
|
startState: function(basecolumn) { |
||||||
|
return { |
||||||
|
tokenize: null, |
||||||
|
context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), |
||||||
|
indented: 0, |
||||||
|
startOfLine: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
|
||||||
|
token: function(stream, state) { |
||||||
|
var ctx = state.context; |
||||||
|
if (stream.sol()) { |
||||||
|
if (ctx.align == null) ctx.align = false; |
||||||
|
state.indented = stream.indentation(); |
||||||
|
state.startOfLine = true; |
||||||
|
if (ctx.type == "case") ctx.type = "}"; |
||||||
|
} |
||||||
|
if (stream.eatSpace()) return null; |
||||||
|
curPunc = null; |
||||||
|
var style = (state.tokenize || tokenBase)(stream, state); |
||||||
|
if (style == "comment") return style; |
||||||
|
if (ctx.align == null) ctx.align = true; |
||||||
|
|
||||||
|
if (curPunc == "{") pushContext(state, stream.column(), "}"); |
||||||
|
else if (curPunc == "[") pushContext(state, stream.column(), "]"); |
||||||
|
else if (curPunc == "(") pushContext(state, stream.column(), ")"); |
||||||
|
else if (curPunc == "case") ctx.type = "case"; |
||||||
|
else if (curPunc == "}" && ctx.type == "}") ctx = popContext(state); |
||||||
|
else if (curPunc == ctx.type) popContext(state); |
||||||
|
state.startOfLine = false; |
||||||
|
return style; |
||||||
|
}, |
||||||
|
|
||||||
|
indent: function(state, textAfter) { |
||||||
|
if (state.tokenize != tokenBase && state.tokenize != null) return 0; |
||||||
|
var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); |
||||||
|
if (ctx.type == "case" && /^(?:case|default)\b/.test(textAfter)) { |
||||||
|
state.context.type = "}"; |
||||||
|
return ctx.indented; |
||||||
|
} |
||||||
|
var closing = firstChar == ctx.type; |
||||||
|
if (ctx.align) return ctx.column + (closing ? 0 : 1); |
||||||
|
else return ctx.indented + (closing ? 0 : indentUnit); |
||||||
|
}, |
||||||
|
|
||||||
|
electricChars: "{}):", |
||||||
|
fold: "brace", |
||||||
|
blockCommentStart: "/*", |
||||||
|
blockCommentEnd: "*/", |
||||||
|
lineComment: "//" |
||||||
|
}; |
||||||
|
}); |
||||||
|
|
||||||
|
CodeMirror.defineMIME("text/x-go", "go"); |
||||||
|
|
||||||
|
}); |
@ -0,0 +1,117 @@ |
|||||||
|
(function(mod) { |
||||||
|
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||||
|
mod(require("../../lib/codemirror")); |
||||||
|
else if (typeof define == "function" && define.amd) // AMD
|
||||||
|
define(["../../lib/codemirror"], mod); |
||||||
|
else // Plain browser env
|
||||||
|
mod(CodeMirror); |
||||||
|
})(function(CodeMirror) { |
||||||
|
var ie_lt8 = /MSIE \d/.test(navigator.userAgent) && |
||||||
|
(document.documentMode == null || document.documentMode < 8); |
||||||
|
|
||||||
|
var Pos = CodeMirror.Pos; |
||||||
|
|
||||||
|
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"}; |
||||||
|
|
||||||
|
function findMatchingBracket(cm, where, strict, config) { |
||||||
|
var line = cm.getLineHandle(where.line), pos = where.ch - 1; |
||||||
|
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)]; |
||||||
|
if (!match) return null; |
||||||
|
var dir = match.charAt(1) == ">" ? 1 : -1; |
||||||
|
if (strict && (dir > 0) != (pos == where.ch)) return null; |
||||||
|
var style = cm.getTokenTypeAt(Pos(where.line, pos + 1)); |
||||||
|
|
||||||
|
var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config); |
||||||
|
if (found == null) return null; |
||||||
|
return {from: Pos(where.line, pos), to: found && found.pos, |
||||||
|
match: found && found.ch == match.charAt(0), forward: dir > 0}; |
||||||
|
} |
||||||
|
|
||||||
|
// bracketRegex is used to specify which type of bracket to scan
|
||||||
|
// should be a regexp, e.g. /[[\]]/
|
||||||
|
//
|
||||||
|
// Note: If "where" is on an open bracket, then this bracket is ignored.
|
||||||
|
//
|
||||||
|
// Returns false when no bracket was found, null when it reached
|
||||||
|
// maxScanLines and gave up
|
||||||
|
function scanForBracket(cm, where, dir, style, config) { |
||||||
|
var maxScanLen = (config && config.maxScanLineLength) || 10000; |
||||||
|
var maxScanLines = (config && config.maxScanLines) || 1000; |
||||||
|
|
||||||
|
var stack = []; |
||||||
|
var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/; |
||||||
|
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1) |
||||||
|
: Math.max(cm.firstLine() - 1, where.line - maxScanLines); |
||||||
|
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) { |
||||||
|
var line = cm.getLine(lineNo); |
||||||
|
if (!line) continue; |
||||||
|
var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1; |
||||||
|
if (line.length > maxScanLen) continue; |
||||||
|
if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0); |
||||||
|
for (; pos != end; pos += dir) { |
||||||
|
var ch = line.charAt(pos); |
||||||
|
if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) { |
||||||
|
var match = matching[ch]; |
||||||
|
if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch); |
||||||
|
else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch}; |
||||||
|
else stack.pop(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null; |
||||||
|
} |
||||||
|
|
||||||
|
function matchBrackets(cm, autoclear, config) { |
||||||
|
// Disable brace matching in long lines, since it'll cause hugely slow updates
|
||||||
|
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000; |
||||||
|
var marks = [], ranges = cm.listSelections(); |
||||||
|
for (var i = 0; i < ranges.length; i++) { |
||||||
|
var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config); |
||||||
|
if (match && cm.getLine(match.from.line).length <= maxHighlightLen) { |
||||||
|
var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; |
||||||
|
marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style})); |
||||||
|
if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen) |
||||||
|
marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style})); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (marks.length) { |
||||||
|
// Kludge to work around the IE bug from issue #1193, where text
|
||||||
|
// input stops going to the textare whever this fires.
|
||||||
|
if (ie_lt8 && cm.state.focused) cm.display.input.focus(); |
||||||
|
|
||||||
|
var clear = function() { |
||||||
|
cm.operation(function() { |
||||||
|
for (var i = 0; i < marks.length; i++) marks[i].clear(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
if (autoclear) setTimeout(clear, 800); |
||||||
|
else return clear; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
var currentlyHighlighted = null; |
||||||
|
function doMatchBrackets(cm) { |
||||||
|
cm.operation(function() { |
||||||
|
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;} |
||||||
|
currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { |
||||||
|
if (old && old != CodeMirror.Init) |
||||||
|
cm.off("cursorActivity", doMatchBrackets); |
||||||
|
if (val) { |
||||||
|
cm.state.matchBrackets = typeof val == "object" ? val : {}; |
||||||
|
cm.on("cursorActivity", doMatchBrackets); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);}); |
||||||
|
CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){ |
||||||
|
return findMatchingBracket(this, pos, strict, config); |
||||||
|
}); |
||||||
|
CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){ |
||||||
|
return scanForBracket(this, pos, dir, style, config); |
||||||
|
}); |
||||||
|
}); |
@ -0,0 +1,61 @@ |
|||||||
|
// Helper function for generating pseudo callbacks and sending data to the QML part of the application
|
||||||
|
function postData(data, cb) { |
||||||
|
data._seed = Math.floor(Math.random() * 1000000) |
||||||
|
if(cb) { |
||||||
|
Muted._callbacks[data._seed] = cb; |
||||||
|
} |
||||||
|
|
||||||
|
if(data.args === undefined) { |
||||||
|
data.args = []; |
||||||
|
} |
||||||
|
|
||||||
|
navigator.qt.postMessage(JSON.stringify(data)); |
||||||
|
} |
||||||
|
|
||||||
|
window.Muted = { |
||||||
|
prototype: Object(), |
||||||
|
} |
||||||
|
|
||||||
|
window.Muted._callbacks = {} |
||||||
|
window.Muted._onCallbacks = {} |
||||||
|
|
||||||
|
function debug(/**/) { |
||||||
|
console.log("hello world") |
||||||
|
|
||||||
|
var args = arguments; |
||||||
|
var msg = "" |
||||||
|
for(var i = 0; i < args.length; i++){ |
||||||
|
if(typeof args[i] == "object") { |
||||||
|
msg += " " + JSON.stringify(args[i]) |
||||||
|
} else { |
||||||
|
msg += args[i] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
document.querySelector("#debugger").innerHTML += "<div class='line'><div class='col1'></div><div class='col2'>"+msg+"</div></div>"; |
||||||
|
} |
||||||
|
console.log = function() { |
||||||
|
var args = [] |
||||||
|
for(var i = 0; i < arguments.length; i++) { |
||||||
|
args.push(arguments[i]); |
||||||
|
} |
||||||
|
postData({call:"log", args:args}) |
||||||
|
} |
||||||
|
|
||||||
|
navigator.qt.onmessage = function(ev) { |
||||||
|
var data = JSON.parse(ev.data) |
||||||
|
|
||||||
|
if(data._event !== undefined) { |
||||||
|
Muted.trigger(data._event, data.data); |
||||||
|
} else { |
||||||
|
if(data._seed) { |
||||||
|
var cb = Muted._callbacks[data._seed]; |
||||||
|
if(cb) { |
||||||
|
// Call the callback
|
||||||
|
cb(data.data); |
||||||
|
// Remove the "trigger" callback
|
||||||
|
delete Muted._callbacks[ev._seed]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,155 @@ |
|||||||
|
import QtQuick 2.0 |
||||||
|
import Ethereum 1.0 |
||||||
|
|
||||||
|
// Which ones do we actually need? |
||||||
|
import QtQuick.Controls 1.0; |
||||||
|
import QtQuick.Layouts 1.0; |
||||||
|
import QtQuick.Dialogs 1.0; |
||||||
|
import QtQuick.Window 2.1; |
||||||
|
import QtQuick.Controls.Styles 1.1 |
||||||
|
import QtQuick.Dialogs 1.1 |
||||||
|
|
||||||
|
ApplicationWindow { |
||||||
|
id: wizardRoot |
||||||
|
width: 500 |
||||||
|
height: 400 |
||||||
|
title: "Ethereal first run setup" |
||||||
|
|
||||||
|
Column { |
||||||
|
spacing: 5 |
||||||
|
anchors.leftMargin: 10 |
||||||
|
anchors.left: parent.left |
||||||
|
|
||||||
|
Text { |
||||||
|
visible: true |
||||||
|
text: "<h2>Ethereal setup</h2>" |
||||||
|
} |
||||||
|
|
||||||
|
Column { |
||||||
|
id: restoreColumn |
||||||
|
spacing: 5 |
||||||
|
Text { |
||||||
|
visible: true |
||||||
|
font.pointSize: 14 |
||||||
|
text: "Restore your Ethereum account" |
||||||
|
id: restoreLabel |
||||||
|
} |
||||||
|
|
||||||
|
TextField { |
||||||
|
id: txPrivKey |
||||||
|
width: 480 |
||||||
|
placeholderText: "Private key or mnemonic words" |
||||||
|
focus: true |
||||||
|
onTextChanged: { |
||||||
|
if(this.text.length == 64){ |
||||||
|
detailLabel.text = "Private (hex) key detected." |
||||||
|
actionButton.enabled = true |
||||||
|
} |
||||||
|
else if(this.text.split(" ").length == 24){ |
||||||
|
detailLabel.text = "Mnemonic key detected." |
||||||
|
actionButton.enabled = true |
||||||
|
}else{ |
||||||
|
detailLabel.text = "" |
||||||
|
actionButton.enabled = false |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
Row { |
||||||
|
spacing: 10 |
||||||
|
Button { |
||||||
|
id: actionButton |
||||||
|
text: "Restore" |
||||||
|
enabled: false |
||||||
|
onClicked: { |
||||||
|
var success = eth.importAndSetPrivKey(txPrivKey.text) |
||||||
|
if(success){ |
||||||
|
importedDetails.visible = true |
||||||
|
restoreColumn.visible = false |
||||||
|
newKey.visible = false |
||||||
|
wizardRoot.height = 120 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
Text { |
||||||
|
id: detailLabel |
||||||
|
font.pointSize: 12 |
||||||
|
anchors.topMargin: 10 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
Column { |
||||||
|
id: importedDetails |
||||||
|
visible: false |
||||||
|
Text { |
||||||
|
text: "<b>Your account has been imported. Please close the application and restart it again to let the changes take effect.</b>" |
||||||
|
wrapMode: Text.WordWrap |
||||||
|
width: 460 |
||||||
|
} |
||||||
|
} |
||||||
|
Column { |
||||||
|
spacing: 5 |
||||||
|
id: newDetailsColumn |
||||||
|
visible: false |
||||||
|
Text { |
||||||
|
font.pointSize: 14 |
||||||
|
text: "Your account details" |
||||||
|
} |
||||||
|
Label { |
||||||
|
text: "Address" |
||||||
|
} |
||||||
|
TextField { |
||||||
|
id: addressInput |
||||||
|
readOnly:true |
||||||
|
width: 480 |
||||||
|
} |
||||||
|
Label { |
||||||
|
text: "Private key" |
||||||
|
} |
||||||
|
TextField { |
||||||
|
id: privkeyInput |
||||||
|
readOnly:true |
||||||
|
width: 480 |
||||||
|
} |
||||||
|
Label { |
||||||
|
text: "Mnemonic words" |
||||||
|
} |
||||||
|
TextField { |
||||||
|
id: mnemonicInput |
||||||
|
readOnly:true |
||||||
|
width: 480 |
||||||
|
} |
||||||
|
Label { |
||||||
|
text: "<b>A new account has been created. Please take the time to write down the <i>24 words</i>. You can use those to restore your account at a later date.</b>" |
||||||
|
wrapMode: Text.WordWrap |
||||||
|
width: 480 |
||||||
|
} |
||||||
|
Label { |
||||||
|
text: "Please restart the application once you have completed the steps above." |
||||||
|
wrapMode: Text.WordWrap |
||||||
|
width: 480 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
Button { |
||||||
|
anchors.right: parent.right |
||||||
|
anchors.bottom: parent.bottom |
||||||
|
anchors.rightMargin: 10 |
||||||
|
anchors.bottomMargin: 10 |
||||||
|
id: newKey |
||||||
|
text: "I don't have an account yet" |
||||||
|
onClicked: { |
||||||
|
var res = eth.createAndSetPrivKey() |
||||||
|
mnemonicInput.text = res[0] |
||||||
|
addressInput.text = res[1] |
||||||
|
privkeyInput.text = res[2] |
||||||
|
|
||||||
|
// Hide restore |
||||||
|
restoreColumn.visible = false |
||||||
|
|
||||||
|
// Show new details |
||||||
|
newDetailsColumn.visible = true |
||||||
|
newKey.visible = false |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,74 @@ |
|||||||
|
import QtQuick 2.0 |
||||||
|
import QtWebKit 3.0 |
||||||
|
import QtWebKit.experimental 1.0 |
||||||
|
import QtQuick.Controls 1.0; |
||||||
|
import QtQuick.Layouts 1.0; |
||||||
|
import QtQuick.Window 2.1; |
||||||
|
import Ethereum 1.0 |
||||||
|
|
||||||
|
ApplicationWindow { |
||||||
|
id: window |
||||||
|
title: "muted" |
||||||
|
width: 900 |
||||||
|
height: 600 |
||||||
|
minimumHeight: 300 |
||||||
|
|
||||||
|
property alias url: webView.url |
||||||
|
property alias webView: webView |
||||||
|
|
||||||
|
|
||||||
|
Item { |
||||||
|
id: root |
||||||
|
anchors.fill: parent |
||||||
|
WebView { |
||||||
|
objectName: "webView" |
||||||
|
id: webView |
||||||
|
anchors { |
||||||
|
top: root.top |
||||||
|
right: root.right |
||||||
|
left: root.left |
||||||
|
bottom: root.bottom |
||||||
|
//bottom: sizeGrip.top |
||||||
|
} |
||||||
|
|
||||||
|
experimental.preferences.javascriptEnabled: true |
||||||
|
experimental.preferences.navigatorQtObjectEnabled: true |
||||||
|
experimental.onMessageReceived: { |
||||||
|
var data = JSON.parse(message.data) |
||||||
|
|
||||||
|
switch(data.call) { |
||||||
|
case "log": |
||||||
|
console.log.apply(this, data.args) |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
function postData(seed, data) { |
||||||
|
webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed})) |
||||||
|
} |
||||||
|
function postEvent(event, data) { |
||||||
|
webview.experimental.postMessage(JSON.stringify({data: data, _event: event})) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
Rectangle { |
||||||
|
id: sizeGrip |
||||||
|
color: "gray" |
||||||
|
height: 5 |
||||||
|
anchors { |
||||||
|
left: root.left |
||||||
|
right: root.right |
||||||
|
} |
||||||
|
y: Math.round(root.height * 2 / 3) |
||||||
|
|
||||||
|
MouseArea { |
||||||
|
anchors.fill: parent |
||||||
|
drag.target: sizeGrip |
||||||
|
drag.minimumY: 0 |
||||||
|
drag.maximumY: root.height - sizeGrip.height |
||||||
|
drag.axis: Drag.YAxis |
||||||
|
} |
||||||
|
} |
||||||
|
*/ |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,196 @@ |
|||||||
|
import QtQuick 2.0 |
||||||
|
import QtQuick.Controls 1.0; |
||||||
|
import QtQuick.Layouts 1.0; |
||||||
|
import QtQuick.Dialogs 1.0; |
||||||
|
import QtQuick.Window 2.1; |
||||||
|
import QtQuick.Controls.Styles 1.1 |
||||||
|
import Ethereum 1.0 |
||||||
|
|
||||||
|
Component { |
||||||
|
id: newContract |
||||||
|
Column { |
||||||
|
id: mainContractColumn |
||||||
|
function contractFormReady(){ |
||||||
|
if(codeView.text.length > 0 && txValue.text.length > 0 && txGas.text.length > 0 && txGasPrice.length > 0) { |
||||||
|
txButton.state = "READY" |
||||||
|
}else{ |
||||||
|
txButton.state = "NOTREADY" |
||||||
|
} |
||||||
|
} |
||||||
|
states: [ |
||||||
|
State{ |
||||||
|
name: "ERROR" |
||||||
|
PropertyChanges { target: txResult; visible:true} |
||||||
|
PropertyChanges { target: codeView; visible:true} |
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "DONE" |
||||||
|
PropertyChanges { target: txValue; visible:false} |
||||||
|
PropertyChanges { target: txGas; visible:false} |
||||||
|
PropertyChanges { target: txGasPrice; visible:false} |
||||||
|
PropertyChanges { target: codeView; visible:false} |
||||||
|
PropertyChanges { target: txButton; visible:false} |
||||||
|
PropertyChanges { target: txDataLabel; visible:false} |
||||||
|
|
||||||
|
PropertyChanges { target: txResult; visible:true} |
||||||
|
PropertyChanges { target: txOutput; visible:true} |
||||||
|
PropertyChanges { target: newTxButton; visible:true} |
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "SETUP" |
||||||
|
PropertyChanges { target: txValue; visible:true; text: ""} |
||||||
|
PropertyChanges { target: txGas; visible:true; text: ""} |
||||||
|
PropertyChanges { target: txGasPrice; visible:true; text: ""} |
||||||
|
PropertyChanges { target: codeView; visible:true; text: ""} |
||||||
|
PropertyChanges { target: txButton; visible:true} |
||||||
|
PropertyChanges { target: txDataLabel; visible:true} |
||||||
|
|
||||||
|
PropertyChanges { target: txResult; visible:false} |
||||||
|
PropertyChanges { target: txOutput; visible:false} |
||||||
|
PropertyChanges { target: newTxButton; visible:false} |
||||||
|
} |
||||||
|
] |
||||||
|
width: 400 |
||||||
|
spacing: 5 |
||||||
|
anchors.left: parent.left |
||||||
|
anchors.top: parent.top |
||||||
|
anchors.leftMargin: 5 |
||||||
|
anchors.topMargin: 5 |
||||||
|
|
||||||
|
TextField { |
||||||
|
id: txValue |
||||||
|
width: 200 |
||||||
|
placeholderText: "Amount" |
||||||
|
validator: IntValidator { } |
||||||
|
onTextChanged: { |
||||||
|
contractFormReady() |
||||||
|
} |
||||||
|
} |
||||||
|
TextField { |
||||||
|
id: txGas |
||||||
|
width: 200 |
||||||
|
validator: IntValidator { } |
||||||
|
placeholderText: "Gas" |
||||||
|
onTextChanged: { |
||||||
|
contractFormReady() |
||||||
|
} |
||||||
|
} |
||||||
|
TextField { |
||||||
|
id: txGasPrice |
||||||
|
width: 200 |
||||||
|
placeholderText: "Gas price" |
||||||
|
validator: IntValidator { } |
||||||
|
onTextChanged: { |
||||||
|
contractFormReady() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Row { |
||||||
|
id: rowContract |
||||||
|
ExclusiveGroup { id: contractTypeGroup } |
||||||
|
RadioButton { |
||||||
|
id: createContractRadio |
||||||
|
text: "Create contract" |
||||||
|
checked: true |
||||||
|
exclusiveGroup: contractTypeGroup |
||||||
|
onClicked: { |
||||||
|
txFuelRecipient.visible = false |
||||||
|
txDataLabel.text = "Contract code" |
||||||
|
} |
||||||
|
} |
||||||
|
RadioButton { |
||||||
|
id: runContractRadio |
||||||
|
text: "Run contract" |
||||||
|
exclusiveGroup: contractTypeGroup |
||||||
|
onClicked: { |
||||||
|
txFuelRecipient.visible = true |
||||||
|
txDataLabel.text = "Contract arguments" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
Label { |
||||||
|
id: txDataLabel |
||||||
|
text: "Contract code" |
||||||
|
} |
||||||
|
|
||||||
|
TextArea { |
||||||
|
id: codeView |
||||||
|
height: 300 |
||||||
|
anchors.topMargin: 5 |
||||||
|
Layout.fillWidth: true |
||||||
|
width: parent.width /2 |
||||||
|
onTextChanged: { |
||||||
|
contractFormReady() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
TextField { |
||||||
|
id: txFuelRecipient |
||||||
|
placeholderText: "Contract address" |
||||||
|
validator: RegExpValidator { regExp: /[a-f0-9]{40}/ } |
||||||
|
visible: false |
||||||
|
width: 530 |
||||||
|
} |
||||||
|
|
||||||
|
Button { |
||||||
|
id: txButton |
||||||
|
/* enabled: false */ |
||||||
|
states: [ |
||||||
|
State { |
||||||
|
name: "READY" |
||||||
|
PropertyChanges { target: txButton; /*enabled: true*/} |
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "NOTREADY" |
||||||
|
PropertyChanges { target: txButton; /*enabled:false*/} |
||||||
|
} |
||||||
|
] |
||||||
|
text: "Send" |
||||||
|
onClicked: { |
||||||
|
//this.enabled = false |
||||||
|
var res = eth.createTx(txFuelRecipient.text, txValue.text, txGas.text, txGasPrice.text, codeView.text) |
||||||
|
if(res[1]) { |
||||||
|
txResult.text = "Your contract <b>could not</b> be send over the network:\n<b>" |
||||||
|
txResult.text += res[1].error() |
||||||
|
txResult.text += "</b>" |
||||||
|
mainContractColumn.state = "ERROR" |
||||||
|
} else { |
||||||
|
txResult.text = "Your transaction has been submitted:\n" |
||||||
|
txOutput.text = res[0] |
||||||
|
mainContractColumn.state = "DONE" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
Text { |
||||||
|
id: txResult |
||||||
|
visible: false |
||||||
|
} |
||||||
|
TextField { |
||||||
|
id: txOutput |
||||||
|
visible: false |
||||||
|
width: 530 |
||||||
|
} |
||||||
|
Button { |
||||||
|
id: newTxButton |
||||||
|
visible: false |
||||||
|
text: "Create an other contract" |
||||||
|
onClicked: { |
||||||
|
this.visible = false |
||||||
|
txResult.text = "" |
||||||
|
txOutput.text = "" |
||||||
|
mainContractColumn.state = "SETUP" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Button { |
||||||
|
id: debugButton |
||||||
|
text: "Debug" |
||||||
|
onClicked: { |
||||||
|
var res = ui.debugTx("", txValue.text, txGas.text, txGasPrice.text, codeView.text) |
||||||
|
debugWindow.visible = true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,111 @@ |
|||||||
|
import QtQuick 2.0 |
||||||
|
import QtQuick.Controls 1.0; |
||||||
|
import QtQuick.Layouts 1.0; |
||||||
|
import QtQuick.Dialogs 1.0; |
||||||
|
import QtQuick.Window 2.1; |
||||||
|
import QtQuick.Controls.Styles 1.1 |
||||||
|
import Ethereum 1.0 |
||||||
|
|
||||||
|
Component { |
||||||
|
id: newTransaction |
||||||
|
Column { |
||||||
|
id: simpleSendColumn |
||||||
|
states: [ |
||||||
|
State{ |
||||||
|
name: "ERROR" |
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "DONE" |
||||||
|
PropertyChanges { target: txSimpleValue; visible:false} |
||||||
|
PropertyChanges { target: txSimpleRecipient; visible:false} |
||||||
|
PropertyChanges { target:newSimpleTxButton; visible:false} |
||||||
|
|
||||||
|
PropertyChanges { target: txSimpleResult; visible:true} |
||||||
|
PropertyChanges { target: txSimpleOutput; visible:true} |
||||||
|
PropertyChanges { target:newSimpleTxButton; visible:true} |
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "SETUP" |
||||||
|
PropertyChanges { target: txSimpleValue; visible:true; text: ""} |
||||||
|
PropertyChanges { target: txSimpleRecipient; visible:true; text: ""} |
||||||
|
PropertyChanges { target: txSimpleButton; visible:true} |
||||||
|
PropertyChanges { target:newSimpleTxButton; visible:false} |
||||||
|
} |
||||||
|
] |
||||||
|
spacing: 5 |
||||||
|
anchors.leftMargin: 5 |
||||||
|
anchors.topMargin: 5 |
||||||
|
anchors.top: parent.top |
||||||
|
anchors.left: parent.left |
||||||
|
|
||||||
|
function checkFormState(){ |
||||||
|
if(txSimpleRecipient.text.length == 40 && txSimpleValue.text.length > 0) { |
||||||
|
txSimpleButton.state = "READY" |
||||||
|
}else{ |
||||||
|
txSimpleButton.state = "NOTREADY" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
TextField { |
||||||
|
id: txSimpleRecipient |
||||||
|
placeholderText: "Recipient address" |
||||||
|
Layout.fillWidth: true |
||||||
|
validator: RegExpValidator { regExp: /[a-f0-9]{40}/ } |
||||||
|
width: 530 |
||||||
|
onTextChanged: { checkFormState() } |
||||||
|
} |
||||||
|
TextField { |
||||||
|
id: txSimpleValue |
||||||
|
placeholderText: "Amount" |
||||||
|
anchors.rightMargin: 5 |
||||||
|
validator: IntValidator { } |
||||||
|
onTextChanged: { checkFormState() } |
||||||
|
} |
||||||
|
Button { |
||||||
|
id: txSimpleButton |
||||||
|
/*enabled: false*/ |
||||||
|
states: [ |
||||||
|
State { |
||||||
|
name: "READY" |
||||||
|
PropertyChanges { target: txSimpleButton; /*enabled: true*/} |
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "NOTREADY" |
||||||
|
PropertyChanges { target: txSimpleButton; /*enabled: false*/} |
||||||
|
} |
||||||
|
] |
||||||
|
text: "Send" |
||||||
|
onClicked: { |
||||||
|
//this.enabled = false |
||||||
|
var res = eth.createTx(txSimpleRecipient.text, txSimpleValue.text,"","","") |
||||||
|
if(res[1]) { |
||||||
|
txSimpleResult.text = "There has been an error broadcasting your transaction:" + res[1].error() |
||||||
|
} else { |
||||||
|
txSimpleResult.text = "Your transaction has been broadcasted over the network.\nYour transaction id is:" |
||||||
|
txSimpleOutput.text = res[0] |
||||||
|
this.visible = false |
||||||
|
simpleSendColumn.state = "DONE" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
Text { |
||||||
|
id: txSimpleResult |
||||||
|
visible: false |
||||||
|
|
||||||
|
} |
||||||
|
TextField { |
||||||
|
id: txSimpleOutput |
||||||
|
visible: false |
||||||
|
width: 530 |
||||||
|
} |
||||||
|
Button { |
||||||
|
id: newSimpleTxButton |
||||||
|
visible: false |
||||||
|
text: "Create an other transaction" |
||||||
|
onClicked: { |
||||||
|
this.visible = false |
||||||
|
simpleSendColumn.state = "SETUP" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,184 @@ |
|||||||
|
import QtQuick 2.0 |
||||||
|
import QtWebKit 3.0 |
||||||
|
import QtWebKit.experimental 1.0 |
||||||
|
import QtQuick.Controls 1.0; |
||||||
|
import QtQuick.Layouts 1.0; |
||||||
|
import QtQuick.Window 2.1; |
||||||
|
import Ethereum 1.0 |
||||||
|
|
||||||
|
ApplicationWindow { |
||||||
|
id: window |
||||||
|
title: "Ethereum" |
||||||
|
width: 900 |
||||||
|
height: 600 |
||||||
|
minimumHeight: 300 |
||||||
|
|
||||||
|
property alias url: webview.url |
||||||
|
property alias webView: webview |
||||||
|
|
||||||
|
Item { |
||||||
|
objectName: "root" |
||||||
|
id: root |
||||||
|
anchors.fill: parent |
||||||
|
state: "inspectorShown" |
||||||
|
|
||||||
|
WebView { |
||||||
|
objectName: "webView" |
||||||
|
id: webview |
||||||
|
anchors.fill: parent |
||||||
|
/* |
||||||
|
anchors { |
||||||
|
left: parent.left |
||||||
|
right: parent.right |
||||||
|
bottom: sizeGrip.top |
||||||
|
top: parent.top |
||||||
|
} |
||||||
|
*/ |
||||||
|
|
||||||
|
onTitleChanged: { window.title = title } |
||||||
|
experimental.preferences.javascriptEnabled: true |
||||||
|
experimental.preferences.navigatorQtObjectEnabled: true |
||||||
|
experimental.preferences.developerExtrasEnabled: true |
||||||
|
experimental.userScripts: [ui.assetPath("ethereum.js")] |
||||||
|
experimental.onMessageReceived: { |
||||||
|
console.log("[onMessageReceived]: ", message.data) |
||||||
|
// TODO move to messaging.js |
||||||
|
var data = JSON.parse(message.data) |
||||||
|
|
||||||
|
try { |
||||||
|
switch(data.call) { |
||||||
|
case "getBlockByNumber": |
||||||
|
var block = eth.getBlock("b9b56cf6f907fbee21db0cd7cbc0e6fea2fe29503a3943e275c5e467d649cb06") |
||||||
|
postData(data._seed, block) |
||||||
|
break |
||||||
|
case "getBlockByHash": |
||||||
|
var block = eth.getBlock("b9b56cf6f907fbee21db0cd7cbc0e6fea2fe29503a3943e275c5e467d649cb06") |
||||||
|
postData(data._seed, block) |
||||||
|
break |
||||||
|
case "transact": |
||||||
|
require(5) |
||||||
|
|
||||||
|
var tx = eth.transact(data.args[0], data.args[1], data.args[2],data.args[3],data.args[4],data.args[5]) |
||||||
|
postData(data._seed, tx) |
||||||
|
|
||||||
|
break |
||||||
|
case "create": |
||||||
|
postData(data._seed, null) |
||||||
|
|
||||||
|
break |
||||||
|
case "getStorage": |
||||||
|
require(2); |
||||||
|
|
||||||
|
var stateObject = eth.getStateObject(data.args[0]) |
||||||
|
var storage = stateObject.getStorage(data.args[1]) |
||||||
|
postData(data._seed, storage) |
||||||
|
|
||||||
|
break |
||||||
|
case "getBalance": |
||||||
|
require(1); |
||||||
|
|
||||||
|
postData(data._seed, eth.getStateObject(data.args[0]).value()); |
||||||
|
|
||||||
|
break |
||||||
|
case "getKey": |
||||||
|
var key = eth.getKey().privateKey; |
||||||
|
|
||||||
|
postData(data._seed, key) |
||||||
|
break |
||||||
|
case "watch": |
||||||
|
require(1) |
||||||
|
eth.watch(data.args[0], data.args[1]); |
||||||
|
break |
||||||
|
case "disconnect": |
||||||
|
require(1) |
||||||
|
postData(data._seed, null) |
||||||
|
break; |
||||||
|
case "set": |
||||||
|
for(var key in data.args) { |
||||||
|
if(webview.hasOwnProperty(key)) { |
||||||
|
window[key] = data.args[key]; |
||||||
|
} |
||||||
|
} |
||||||
|
break; |
||||||
|
case "getSecretToAddress": |
||||||
|
require(1) |
||||||
|
postData(data._seed, eth.secretToAddress(data.args[0])) |
||||||
|
break; |
||||||
|
case "debug": |
||||||
|
console.log(data.args[0]); |
||||||
|
break; |
||||||
|
} |
||||||
|
} catch(e) { |
||||||
|
console.log(data.call + ": " + e) |
||||||
|
|
||||||
|
postData(data._seed, null); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function require(args, num) { |
||||||
|
if(args.length < num) { |
||||||
|
throw("required argument count of "+num+" got "+args.length); |
||||||
|
} |
||||||
|
} |
||||||
|
function postData(seed, data) { |
||||||
|
webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed})) |
||||||
|
} |
||||||
|
function postEvent(event, data) { |
||||||
|
webview.experimental.postMessage(JSON.stringify({data: data, _event: event})) |
||||||
|
} |
||||||
|
|
||||||
|
function onNewBlockCb(block) { |
||||||
|
postEvent("block:new", block) |
||||||
|
} |
||||||
|
function onObjectChangeCb(stateObject) { |
||||||
|
postEvent("object:"+stateObject.address(), stateObject) |
||||||
|
} |
||||||
|
function onStorageChangeCb(storageObject) { |
||||||
|
var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":"); |
||||||
|
postEvent(ev, [storageObject.address, storageObject.value]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Rectangle { |
||||||
|
id: sizeGrip |
||||||
|
color: "gray" |
||||||
|
visible: false |
||||||
|
height: 10 |
||||||
|
anchors { |
||||||
|
left: root.left |
||||||
|
right: root.right |
||||||
|
} |
||||||
|
y: Math.round(root.height * 2 / 3) |
||||||
|
|
||||||
|
MouseArea { |
||||||
|
anchors.fill: parent |
||||||
|
drag.target: sizeGrip |
||||||
|
drag.minimumY: 0 |
||||||
|
drag.maximumY: root.height |
||||||
|
drag.axis: Drag.YAxis |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
WebView { |
||||||
|
id: inspector |
||||||
|
visible: false |
||||||
|
url: webview.experimental.remoteInspectorUrl |
||||||
|
anchors { |
||||||
|
left: root.left |
||||||
|
right: root.right |
||||||
|
top: sizeGrip.bottom |
||||||
|
bottom: root.bottom |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
states: [ |
||||||
|
State { |
||||||
|
name: "inspectorShown" |
||||||
|
PropertyChanges { |
||||||
|
target: inspector |
||||||
|
url: webview.experimental.remoteInspectorUrl |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 85 KiB |
@ -0,0 +1,34 @@ |
|||||||
|
/* Space out content a bit */ |
||||||
|
body { |
||||||
|
padding-top: 20px; |
||||||
|
padding-bottom: 20px; |
||||||
|
} |
||||||
|
|
||||||
|
/* Everything but the jumbotron gets side spacing for mobile first |
||||||
|
* views */ |
||||||
|
.header, |
||||||
|
.marketing, |
||||||
|
.footer { |
||||||
|
padding-right: 15px; |
||||||
|
padding-left: 15px; |
||||||
|
} |
||||||
|
|
||||||
|
/* Custom page header */ |
||||||
|
.header { |
||||||
|
border-bottom: 1px solid #e5e5e5; |
||||||
|
} |
||||||
|
/* Make the masthead heading the same height as the navigation */ |
||||||
|
.header h3 { |
||||||
|
padding-bottom: 19px; |
||||||
|
margin-top: 0; |
||||||
|
margin-bottom: 0; |
||||||
|
line-height: 40px; |
||||||
|
} |
||||||
|
|
||||||
|
.jumbotron { |
||||||
|
text-align: center; |
||||||
|
border-bottom: 1px solid #e5e5e5; |
||||||
|
|
||||||
|
margin: 0 auto; |
||||||
|
width: 300px; |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
<html> |
||||||
|
<head> |
||||||
|
<title>jeffcoin</title> |
||||||
|
|
||||||
|
<link rel="stylesheet" href="bootstrap.min.css"> |
||||||
|
<link rel="stylesheet" href="bootstrap-theme.min.css"> |
||||||
|
<link rel="stylesheet" href="samplecoin.css"> |
||||||
|
<script src="promise.min.js"></script> |
||||||
|
<meta name="viewport" content="minimum-scale=1; maximum-scale=1; initial-scale=1;"> |
||||||
|
|
||||||
|
<script type="text/javascript"> |
||||||
|
|
||||||
|
var jefcoinAddr = "3dff537f51350239abc95c76a5864aa605259e7d" |
||||||
|
var mAddr = "" |
||||||
|
|
||||||
|
function createTransaction() { |
||||||
|
var addr = document.querySelector("#addr").value; |
||||||
|
var amount = document.querySelector("#amount").value; |
||||||
|
|
||||||
|
var data = (("0x"+addr).pad(32) + amount.pad(32)).unbin() |
||||||
|
eth.transact(mAddr, jefcoinAddr, 0, "10000000", "250", data, function(receipt) { |
||||||
|
debug("received tx hash:", reciept.address) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
function init() { |
||||||
|
eth.set({width: 500}); |
||||||
|
|
||||||
|
eth.getKey(function(sec) { |
||||||
|
eth.getSecretToAddress(sec, function(addr) { |
||||||
|
mAddr = addr; |
||||||
|
|
||||||
|
eth.getStorageAt(jefcoinAddr, addr, function(storage) { |
||||||
|
document.querySelector("#current-amount").innerHTML = storage; |
||||||
|
}); |
||||||
|
|
||||||
|
eth.watch(jefcoinAddr, addr, function(addr, value) { |
||||||
|
document.querySelector("#current-amount").innerHTML = value |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
</script> |
||||||
|
</head> |
||||||
|
|
||||||
|
<body onload="init();"> |
||||||
|
<div class="container"> |
||||||
|
<div class="header"> |
||||||
|
<h3 class="text-muted">JeffCoin</h3> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="jumbotron "> |
||||||
|
<img src="icon.png"> |
||||||
|
<div>Amount: <strong id="current-amount"></strong></div> |
||||||
|
|
||||||
|
<div id="transactions"> |
||||||
|
<div class="form-group"> |
||||||
|
<input id="addr" class="form-control" type="text" placeholder="Receiver address"></input><br> |
||||||
|
<input id="amount" class="form-control" type="text" placeholder="Amount"></input><br> |
||||||
|
</div> |
||||||
|
|
||||||
|
<button class="btn btn-default" onclick="createTransaction();">Send Tx</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div id="debug" style="border: 1px solid black; min-height: 30px;"></div> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
||||||
|
|
@ -0,0 +1,126 @@ |
|||||||
|
package ethui |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"github.com/ethereum/eth-go/ethchain" |
||||||
|
"github.com/ethereum/eth-go/ethpub" |
||||||
|
"github.com/ethereum/eth-go/ethutil" |
||||||
|
"github.com/go-qml/qml" |
||||||
|
) |
||||||
|
|
||||||
|
type AppContainer interface { |
||||||
|
Create() error |
||||||
|
Destroy() |
||||||
|
|
||||||
|
Window() *qml.Window |
||||||
|
Engine() *qml.Engine |
||||||
|
|
||||||
|
NewBlock(*ethchain.Block) |
||||||
|
ObjectChanged(*ethchain.StateObject) |
||||||
|
StorageChanged(*ethchain.StorageState) |
||||||
|
} |
||||||
|
|
||||||
|
type ExtApplication struct { |
||||||
|
*ethpub.PEthereum |
||||||
|
|
||||||
|
blockChan chan ethutil.React |
||||||
|
changeChan chan ethutil.React |
||||||
|
quitChan chan bool |
||||||
|
|
||||||
|
container AppContainer |
||||||
|
lib *UiLib |
||||||
|
registeredEvents []string |
||||||
|
} |
||||||
|
|
||||||
|
func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication { |
||||||
|
app := &ExtApplication{ |
||||||
|
ethpub.NewPEthereum(lib.eth.StateManager(), lib.eth.BlockChain(), lib.eth.TxPool()), |
||||||
|
make(chan ethutil.React, 1), |
||||||
|
make(chan ethutil.React, 1), |
||||||
|
make(chan bool), |
||||||
|
container, |
||||||
|
lib, |
||||||
|
nil, |
||||||
|
} |
||||||
|
|
||||||
|
return app |
||||||
|
} |
||||||
|
|
||||||
|
func (app *ExtApplication) run() { |
||||||
|
// Set the "eth" api on to the containers context
|
||||||
|
context := app.container.Engine().Context() |
||||||
|
context.SetVar("eth", app) |
||||||
|
context.SetVar("ui", app.lib) |
||||||
|
|
||||||
|
err := app.container.Create() |
||||||
|
if err != nil { |
||||||
|
fmt.Println(err) |
||||||
|
|
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Call the main loop
|
||||||
|
go app.mainLoop() |
||||||
|
|
||||||
|
// Subscribe to events
|
||||||
|
reactor := app.lib.eth.Reactor() |
||||||
|
reactor.Subscribe("newBlock", app.blockChan) |
||||||
|
|
||||||
|
win := app.container.Window() |
||||||
|
win.Show() |
||||||
|
win.Wait() |
||||||
|
|
||||||
|
app.stop() |
||||||
|
} |
||||||
|
|
||||||
|
func (app *ExtApplication) stop() { |
||||||
|
// Clean up
|
||||||
|
reactor := app.lib.eth.Reactor() |
||||||
|
reactor.Unsubscribe("newBlock", app.blockChan) |
||||||
|
for _, event := range app.registeredEvents { |
||||||
|
reactor.Unsubscribe(event, app.changeChan) |
||||||
|
} |
||||||
|
|
||||||
|
// Kill the main loop
|
||||||
|
app.quitChan <- true |
||||||
|
|
||||||
|
close(app.blockChan) |
||||||
|
close(app.quitChan) |
||||||
|
close(app.changeChan) |
||||||
|
|
||||||
|
app.container.Destroy() |
||||||
|
} |
||||||
|
|
||||||
|
func (app *ExtApplication) mainLoop() { |
||||||
|
out: |
||||||
|
for { |
||||||
|
select { |
||||||
|
case <-app.quitChan: |
||||||
|
break out |
||||||
|
case block := <-app.blockChan: |
||||||
|
if block, ok := block.Resource.(*ethchain.Block); ok { |
||||||
|
app.container.NewBlock(block) |
||||||
|
} |
||||||
|
case object := <-app.changeChan: |
||||||
|
if stateObject, ok := object.Resource.(*ethchain.StateObject); ok { |
||||||
|
app.container.ObjectChanged(stateObject) |
||||||
|
} else if storageObject, ok := object.Resource.(*ethchain.StorageState); ok { |
||||||
|
app.container.StorageChanged(storageObject) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
func (app *ExtApplication) Watch(addr, storageAddr string) { |
||||||
|
var event string |
||||||
|
if len(storageAddr) == 0 { |
||||||
|
event = "object:" + string(ethutil.FromHex(addr)) |
||||||
|
app.lib.eth.Reactor().Subscribe(event, app.changeChan) |
||||||
|
} else { |
||||||
|
event = "storage:" + string(ethutil.FromHex(addr)) + ":" + string(ethutil.FromHex(storageAddr)) |
||||||
|
app.lib.eth.Reactor().Subscribe(event, app.changeChan) |
||||||
|
} |
||||||
|
|
||||||
|
app.registeredEvents = append(app.registeredEvents, event) |
||||||
|
} |
@ -0,0 +1,73 @@ |
|||||||
|
package ethui |
||||||
|
|
||||||
|
import ( |
||||||
|
"errors" |
||||||
|
"github.com/ethereum/eth-go/ethchain" |
||||||
|
"github.com/ethereum/eth-go/ethpub" |
||||||
|
"github.com/ethereum/eth-go/ethutil" |
||||||
|
"github.com/go-qml/qml" |
||||||
|
"path/filepath" |
||||||
|
) |
||||||
|
|
||||||
|
type HtmlApplication struct { |
||||||
|
win *qml.Window |
||||||
|
webView qml.Object |
||||||
|
engine *qml.Engine |
||||||
|
lib *UiLib |
||||||
|
path string |
||||||
|
} |
||||||
|
|
||||||
|
func NewHtmlApplication(path string, lib *UiLib) *HtmlApplication { |
||||||
|
engine := qml.NewEngine() |
||||||
|
|
||||||
|
return &HtmlApplication{engine: engine, lib: lib, path: path} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
func (app *HtmlApplication) Create() error { |
||||||
|
component, err := app.engine.LoadFile(app.lib.AssetPath("qml/webapp.qml")) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
if filepath.Ext(app.path) == "eth" { |
||||||
|
return errors.New("Ethereum package not yet supported") |
||||||
|
|
||||||
|
// TODO
|
||||||
|
ethutil.OpenPackage(app.path) |
||||||
|
} |
||||||
|
|
||||||
|
win := component.CreateWindow(nil) |
||||||
|
win.Set("url", app.path) |
||||||
|
webView := win.ObjectByName("webView") |
||||||
|
|
||||||
|
app.win = win |
||||||
|
app.webView = webView |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (app *HtmlApplication) Engine() *qml.Engine { |
||||||
|
return app.engine |
||||||
|
} |
||||||
|
|
||||||
|
func (app *HtmlApplication) Window() *qml.Window { |
||||||
|
return app.win |
||||||
|
} |
||||||
|
|
||||||
|
func (app *HtmlApplication) NewBlock(block *ethchain.Block) { |
||||||
|
b := ðpub.PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())} |
||||||
|
app.webView.Call("onNewBlockCb", b) |
||||||
|
} |
||||||
|
|
||||||
|
func (app *HtmlApplication) ObjectChanged(stateObject *ethchain.StateObject) { |
||||||
|
app.webView.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject)) |
||||||
|
} |
||||||
|
|
||||||
|
func (app *HtmlApplication) StorageChanged(storageObject *ethchain.StorageState) { |
||||||
|
app.webView.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject)) |
||||||
|
} |
||||||
|
|
||||||
|
func (app *HtmlApplication) Destroy() { |
||||||
|
app.engine.Destroy() |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
package utils |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"github.com/obscuren/mutan" |
||||||
|
"strings" |
||||||
|
) |
||||||
|
|
||||||
|
// General compile function
|
||||||
|
func Compile(script string) ([]byte, error) { |
||||||
|
byteCode, errors := mutan.Compile(strings.NewReader(script), false) |
||||||
|
if len(errors) > 0 { |
||||||
|
var errs string |
||||||
|
for _, er := range errors { |
||||||
|
if er != nil { |
||||||
|
errs += er.Error() |
||||||
|
} |
||||||
|
} |
||||||
|
return nil, fmt.Errorf("%v", errs) |
||||||
|
} |
||||||
|
|
||||||
|
return byteCode, nil |
||||||
|
} |
||||||
|
|
||||||
|
func CompileScript(script string) ([]byte, []byte, error) { |
||||||
|
// Preprocess
|
||||||
|
mainInput, initInput := mutan.PreProcess(script) |
||||||
|
// Compile main script
|
||||||
|
mainScript, err := Compile(mainInput) |
||||||
|
if err != nil { |
||||||
|
return nil, nil, err |
||||||
|
} |
||||||
|
|
||||||
|
// Compile init script
|
||||||
|
initScript, err := Compile(initInput) |
||||||
|
if err != nil { |
||||||
|
return nil, nil, err |
||||||
|
} |
||||||
|
|
||||||
|
return mainScript, initScript, nil |
||||||
|
} |
Loading…
Reference in new issue