cache input in localStoarage, tidy ui

ballot: extract into separate file
input: cache in localstoage on successful compile
input: reset to ballot if empty

ui: styling / padding / spacing
ui: allow collapsing on contract instances
pull/1/head
d11e9 9 years ago
parent a5a7013333
commit 31786a1135
  1. 68
      ballot.sol.js
  2. 264
      index.html
  3. 2
      stylesheets/styles.css

@ -0,0 +1,68 @@
var multi = function(func) { return func.toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]; }
var BALLOT_EXAMPLE = multi(function(){/*contract Ballot {
struct Voter {
uint weight;
bool voted;
uint8 vote;
address delegate;
}
struct Proposal {
uint voteCount;
}
address chairperson;
mapping(address => Voter) voters;
Proposal[] proposals;
// Create a new ballot with $(_numProposals) different proposals.
function Ballot(uint8 _numProposals) {
chairperson = msg.sender;
voters[chairperson].weight = 1;
proposals.length = _numProposals;
}
// Give $(voter) the right to vote on this ballot.
// May only be called by $(chairperson).
function giveRightToVote(address voter) {
if (msg.sender != chairperson || voters[voter].voted) return;
voters[voter].weight = 1;
}
// Delegate your vote to the voter $(to).
function delegate(address to) {
Voter sender = voters[msg.sender]; // assigns reference
if (sender.voted) return;
while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender)
to = voters[to].delegate;
if (to == msg.sender) return;
sender.voted = true;
sender.delegate = to;
Voter delegate = voters[to];
if (delegate.voted)
proposals[delegate.vote].voteCount += sender.weight;
else
delegate.weight += sender.weight;
}
// Give a single vote to proposal $(proposal).
function vote(uint8 proposal) {
Voter sender = voters[msg.sender];
if (sender.voted || proposal >= proposals.length) return;
sender.voted = true;
sender.vote = proposal;
proposals[proposal].voteCount += sender.weight;
}
function winningProposal() constant returns (uint8 winningProposal) {
uint256 winningVoteCount = 0;
for (uint8 proposal = 0; proposal < proposals.length; proposal++) {
if (proposals[proposal].voteCount > winningVoteCount) {
winningVoteCount = proposals[proposal].voteCount;
winningProposal = proposal;
}
++proposal;
}
}
}
*/});

@ -18,7 +18,7 @@ body {
left: 0px; left: 0px;
width: auto; width: auto;
bottom: 0px; bottom: 0px;
right: 32em; right: 37em;
} }
#input { #input {
@ -28,33 +28,30 @@ body {
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
min-width: 20vw;
} }
#righthand-panel { #righthand-panel {
position: absolute; position: absolute;
top: 0; top: 0;
width: 32em; width: 37em;
max-width: 80vw;
right: 0; right: 0;
bottom: 0px; bottom: 0px;
overflow: auto; overflow: auto;
border-left: 1px solid #ccc; border-left: 1px dotted black;
box-sizing: border-box;
} }
#output { #output {
border-top: 1px solid #ccc; border-top: 1px dotted black;
background-color: white; display: block;
position: absolute;
top: 18em;
left: 0;
right: 0;
bottom: 0px;
} }
#header { #header {
font-size: 14px; font-size: 14px;
padding: 1em; padding: 1em;
font-size: 12px; font-size: 12px;
height: 18em;
} }
#header h1 { #header h1 {
@ -86,60 +83,102 @@ body {
width: 100%; width: 100%;
display: block; display: block;
} }
.runButton {
width: 16em;
text-align: left;
overflow: hidden;
margin-right: 0.6em;
}
.contractInstance { .contractInstance {
margin-left: 2em; background-color: #ccc;
margin-bottom: 20px; margin-bottom: 1em;
padding: 0.6em;
} }
.contractInstance.hide > *:not(.title) {
display: none;
}
.contractOutput {
border-bottom: 1px solid #ccc; .contractInstance .contractProperty input,
.contractInstance .contractProperty button {
text-align: left;
padding: 0.3em;
width: 50%;
margin: 0;
}
.contractOutput .contractInstance .contractProperty {
margin-bottom: 0;
}
.contractOutput .contractInstance .contractProperty .output {
padding: 0.4em; padding: 0.4em;
box-sizing: border-box; background-color: #333;
color: white;
margin-bottom: 1em;
display: block;
} }
.contractInstance .contractProperty .output:empty { display: none; }
.contractOutput .title { .contractOutput {
margin: 0; border-bottom: 1px dotted black;
cursor: pointer; padding: 0.6em;
box-sizing: border-box;
}
.contractOutput .contractProperty {
margin-bottom: 0.6em;
}
.contractOutput .contractProperty .output {
display: inline;
} }
.contractOutput .body { .contractOutput .body {
display: none;
margin-top: 10px; margin-top: 10px;
} }
.contractOutput.show .body { .contractOutput.hide {
display: block; background-color: #4C4C67;
color: white;
} }
.contractOutput .title:before { .contractOutput.hide > *:not(.title) {
content: "\25B6"; display: none;
color: #ccc; }
.title {
margin: 0;
cursor: pointer;
font-family: monospace;
font-weight: bold;
}
.title:before {
content: "\25BC";
opacity: 0.5;
margin-right: 0.4em; margin-right: 0.4em;
font-size: 10px; font-size: 10px;
} }
.contractOutput.show .title:before { .hide > .title:before {
content: "\25BC"; content: "\25B6";
} }
.contractOutput > .title {
border-bottom: #4C4C67;
}
.title .size {
font-weight: normal;
float: right;
}
.solError { .solError {
position: absolute; position: absolute;
background-color: rgba(255, 0, 0, 0.5); background-color: rgba(255, 0, 0, 0.2);
z-index:40; z-index:40;
} }
.error { .error {
background-color: rgba(255, 0, 0, 0.5); background-color: rgba(255, 0, 0, 0.5);
border-radius: 0; border-radius: 0;
border: 0 none; word-wrap: break-word;
border: 1px solid #D00909;
} }
#ghostbar { #ghostbar {
@ -164,6 +203,15 @@ body {
z-index: 999; z-index: 999;
} }
input[readonly] {
padding: .4em;
border: 1px solid #ccc;
box-sizing: border-box;
display: block;
width: 100%;
}
</style> </style>
<script src="libs/jquery-2.1.3.min.js"></script> <script src="libs/jquery-2.1.3.min.js"></script>
<script src="libs/ace.js"></script> <script src="libs/ace.js"></script>
@ -171,75 +219,15 @@ body {
<script src="soljson.js"></script> <script src="soljson.js"></script>
<script src="ethereumjs-vm.js"></script> <script src="ethereumjs-vm.js"></script>
<script src="web3.min.js"></script> <script src="web3.min.js"></script>
<script src="ballot.sol.js"></script>
</head> </head>
<body> <body>
<div id="editor"> <div id="editor">
<div id="input">contract Ballot { <div id="input"></div>
struct Voter {
uint weight;
bool voted;
uint8 vote;
address delegate;
}
struct Proposal {
uint voteCount;
}
address chairperson;
mapping(address => Voter) voters;
Proposal[] proposals;
// Create a new ballot with $(_numProposals) different proposals.
function Ballot(uint8 _numProposals) {
chairperson = msg.sender;
voters[chairperson].weight = 1;
proposals.length = _numProposals;
}
// Give $(voter) the right to vote on this ballot.
// May only be called by $(chairperson).
function giveRightToVote(address voter) {
if (msg.sender != chairperson || voters[voter].voted) return;
voters[voter].weight = 1;
}
// Delegate your vote to the voter $(to).
function delegate(address to) {
Voter sender = voters[msg.sender]; // assigns reference
if (sender.voted) return;
while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender)
to = voters[to].delegate;
if (to == msg.sender) return;
sender.voted = true;
sender.delegate = to;
Voter delegate = voters[to];
if (delegate.voted)
proposals[delegate.vote].voteCount += sender.weight;
else
delegate.weight += sender.weight;
}
// Give a single vote to proposal $(proposal).
function vote(uint8 proposal) {
Voter sender = voters[msg.sender];
if (sender.voted || proposal >= proposals.length) return;
sender.voted = true;
sender.vote = proposal;
proposals[proposal].voteCount += sender.weight;
}
function winningProposal() constant returns (uint8 winningProposal) {
uint256 winningVoteCount = 0;
for (uint8 proposal = 0; proposal < proposals.length; proposal++) {
if (proposals[proposal].voteCount > winningVoteCount) {
winningVoteCount = proposals[proposal].voteCount;
winningProposal = proposal;
}
++proposal;
}
}
}
</div>
</div> </div>
<div id="righthand-panel"> <div id="righthand-panel">
@ -261,8 +249,12 @@ body {
<div id="output"></div> <div id="output"></div>
</div> </div>
<script> <script>
// ----------------- resizeable ui --------------- // ----------------- resizeable ui ---------------
var dragging = false; var dragging = false;
@ -299,11 +291,17 @@ body {
// ----------------- editor ---------------------- // ----------------- editor ----------------------
var SOL_CACHE_KEY = "sol-cache";
var editor = ace.edit("input"); var editor = ace.edit("input");
var session = editor.getSession(); var session = editor.getSession();
var Range = ace.require('ace/range').Range; var Range = ace.require('ace/range').Range;
var errMarkerId = null; var errMarkerId = null;
var solCache = window.localStorage.getItem( SOL_CACHE_KEY );
editor.setValue( solCache || BALLOT_EXAMPLE, 1 );
session.setMode("ace/mode/javascript"); session.setMode("ace/mode/javascript");
session.setTabSize(4); session.setTabSize(4);
session.setUseSoftTabs(true); session.setUseSoftTabs(true);
@ -326,7 +324,7 @@ body {
window.onresize = onResize; window.onresize = onResize;
onResize(); onResize();
document.querySelector('#editorWrap').addEventListener('change', onResize ); document.querySelector('#editor').addEventListener('change', onResize );
// ----------------- compiler ---------------------- // ----------------- compiler ----------------------
@ -349,11 +347,16 @@ body {
renderError(data['error']); renderError(data['error']);
else else
renderContracts(data, input); renderContracts(data, input);
} }
var compileTimeout = null; var compileTimeout = null;
var onChange = function() { var onChange = function() {
var input = editor.getValue(); var input = editor.getValue();
if (input == previousInput) if (input === "") {
window.localStorage.setItem( SOL_CACHE_KEY, '' )
return;
}
if (input === previousInput)
return; return;
previousInput = input; previousInput = input;
if (compileTimeout) window.clearTimeout(compileTimeout); if (compileTimeout) window.clearTimeout(compileTimeout);
@ -362,23 +365,26 @@ body {
onChange(); onChange();
editor.getSession().on('change', onChange); editor.getSession().on('change', onChange);
document.querySelector('#optimize').addEventListener('change', compile); document.querySelector('#optimize').addEventListener('change', compile);
// ----------------- compiler output renderer ---------------------- // ----------------- compiler output renderer ----------------------
var detailsOpen = {}; var detailsOpen = {};
var renderError = function(message) { var renderError = function(message) {
var $output = $('#output').empty()
var err = message.match(/^:([0-9]*):([0-9]*)/) var err = message.match(/^:([0-9]*):([0-9]*)/)
var errLine = parseInt( err[1], 10 ) - 1; if (err && err.length) {
var errCol = parseInt( err[2], 10 ); var errLine = parseInt( err[1], 10 ) - 1;
$('#output').empty().append($('<pre class="error"></pre>').text(message)); var errCol = err[2] ? parseInt( err[2], 10 ) : 0;
errMarkerId = editor.getSession().addMarker(new Range(errLine, 0, errLine, 1), "solError", "fullLine"); $output.append($('<pre class="error"></pre>').text(message));
editor.getSession().setAnnotations([{ editor.getSession().setAnnotations([{
row: errLine, row: errLine,
column: errCol, column: errCol,
text: message, text: message,
type: "error" type: "error"
}]); }]);
}
}; };
var gethDeploy = function(contractName, interface, bytecode){ var gethDeploy = function(contractName, interface, bytecode){
@ -412,32 +418,33 @@ body {
}; };
var renderContracts = function(data, source) { var renderContracts = function(data, source) {
window.localStorage.setItem( SOL_CACHE_KEY, source );
$('#output').empty(); $('#output').empty();
for (var contractName in data.contracts) { for (var contractName in data.contracts) {
var contract = data.contracts[contractName]; var contract = data.contracts[contractName];
var title =$('<h3 class="title"/>').text(contractName); var title = $('<h3 class="title"/>').text(contractName);
var contractOutput = $('<div class="contractOutput"/>') var contractOutput = $('<div class="contractOutput"/>')
.append(title); .append(title);
var body = $('<div class="body" />') var body = $('<div class="body" />')
contractOutput.append( body ); contractOutput.append( body );
if (contract.bytecode.length > 0) if (contract.bytecode.length > 0)
body.append($('<div class="size"/>').text((contract.bytecode.length / 2) + ' bytes')) title.append($('<div class="size"/>').text((contract.bytecode.length / 2) + ' bytes'))
.append(getExecuteInterface(contract, contractName)) body.append(getExecuteInterface(contract, contractName))
.append(tableRow('Bytecode', contract.bytecode)); .append(tableRow('Bytecode', contract.bytecode));
body.append(tableRow('Interface', contract['interface'])) body.append(tableRow('Interface', contract['interface']))
.append(textRow('Web3 deploy', gethDeploy(contractName.toLowerCase(),contract['interface'],contract.bytecode))) .append(textRow('Web3 deploy', gethDeploy(contractName.toLowerCase(),contract['interface'],contract.bytecode), 'deploy'))
.append(getDetails(contract, source, contractName)); .append(getDetails(contract, source, contractName));
$('#output').append(contractOutput); $('#output').append(contractOutput);
title.click(function(ev){ title.click(function(ev){ $(this).parent().toggleClass('hide') });
$(this).parent().toggleClass('show')
})
} }
$('.col2 input,textarea').click(function() { this.select(); } ); $('.col2 input,textarea').click(function() { this.select(); } );
}; };
var tableRowItems = function(first, second) { var tableRowItems = function(first, second, cls) {
return $('<div class="row"/>') return $('<div class="row"/>')
.addClass(cls)
.append($('<div class="col1">').append(first)) .append($('<div class="col1">').append(first))
.append($('<div class="col2">').append(second)); .append($('<div class="col2">').append(second));
}; };
@ -446,10 +453,11 @@ body {
$('<span/>').text(description), $('<span/>').text(description),
$('<input readonly="readonly"/>').val(data)); $('<input readonly="readonly"/>').val(data));
}; };
var textRow = function(description, data) { var textRow = function(description, data, cls) {
return tableRowItems( return tableRowItems(
$('<strong/>').text(description), $('<strong/>').text(description),
$('<textarea readonly="readonly" class="gethDeployText"/>').val(data)); $('<textarea readonly="readonly" class="gethDeployText"/>').val(data),
cls);
}; };
var getDetails = function(contract, source, contractName) { var getDetails = function(contract, source, contractName) {
var button = $('<button>Details</button>'); var button = $('<button>Details</button>');
@ -561,7 +569,7 @@ body {
inputs += inp.type + ' ' + inp.name; inputs += inp.type + ' ' + inp.name;
}); });
var inputField = $('<input/>').attr('placeholder', inputs); var inputField = $('<input/>').attr('placeholder', inputs);
var outputSpan = $('<div/>'); var outputSpan = $('<div class="output"/>');
var button = $('<button/>') var button = $('<button/>')
.text(args.bytecode ? 'Create' : fun.displayName()) .text(args.bytecode ? 'Create' : fun.displayName())
.click(function() { .click(function() {
@ -570,7 +578,7 @@ body {
if (data.slice(0, 2) == '0x') data = data.slice(2); if (data.slice(0, 2) == '0x') data = data.slice(2);
if (isConstructor) if (isConstructor)
data = args.bytecode + data.slice(8); data = args.bytecode + data.slice(8);
outputSpan.text(' ...'); outputSpan.text('...');
runTx(data, args.address, function(err, result) { runTx(data, args.address, function(err, result) {
if (err) if (err)
outputSpan.text(err); outputSpan.text(err);
@ -585,7 +593,7 @@ body {
}); });
if (!isConstructor) if (!isConstructor)
button.addClass('runButton'); button.addClass('runButton');
var c = $('<div/>') var c = $('<div class="contractProperty"/>')
.append(button); .append(button);
if (args.abi.inputs.length > 0) if (args.abi.inputs.length > 0)
c.append(inputField); c.append(inputField);
@ -599,7 +607,8 @@ body {
var appendFunctions = function(address) { var appendFunctions = function(address) {
var instance = $('<div class="contractInstance"/>'); var instance = $('<div class="contractInstance"/>');
instance.append($('<span/>').text('Contract at address ' + address.toString('hex'))); var title = $('<span class="title"/>').text('Contract at ' + address.toString('hex') );
instance.append(title);
$.each(abi, function(i, funABI) { $.each(abi, function(i, funABI) {
if (funABI.type != 'function') return; if (funABI.type != 'function') return;
instance.append(getCallButton({ instance.append(getCallButton({
@ -608,6 +617,7 @@ body {
})); }));
}); });
execInter.append(instance); execInter.append(instance);
title.click(function(ev){ $(this).parent().toggleClass('hide') });
}; };
execInter execInter

@ -8,7 +8,6 @@ body {
} }
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
color:#222;
margin: 20px 0 10px; margin: 20px 0 10px;
} }
@ -29,7 +28,6 @@ h2 {
} }
h3, h4, h5, h6 { h3, h4, h5, h6 {
color:#494949;
} }
a { a {

Loading…
Cancel
Save