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