Commit 602faa7f authored by chriseth's avatar chriseth

Merge pull request #21 from d11e9/gh-pages

Add multiple files and local imports
parents ec718645 4c3dbae4
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
var multi = function(func) { return func.toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]; } var multi = function(func) { return func.toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]; }
var BALLOT_EXAMPLE = multi(function(){/*contract Ballot { var BALLOT_EXAMPLE = multi(function(){/*contract Ballot {
struct Voter { struct Voter {
uint weight; uint weight;
bool voted; bool voted;
......
...@@ -50,6 +50,9 @@ THE SOFTWARE. ...@@ -50,6 +50,9 @@ THE SOFTWARE.
<div id="editor"> <div id="editor">
<div id="files">
<span class="newFile" title="New File">+</span>
</div>
<div id="input"></div> <div id="input"></div>
</div> </div>
...@@ -79,20 +82,148 @@ THE SOFTWARE. ...@@ -79,20 +82,148 @@ THE SOFTWARE.
// ----------------- editor ---------------------- // ----------------- editor ----------------------
var SOL_CACHE_KEY = "sol-cache"; var SOL_CACHE_FILE_PREFIX = 'sol-cache-file-';
var SOL_CACHE_UNTITLED = SOL_CACHE_FILE_PREFIX + 'Untitled';
var SOL_CACHE_FILE = null;
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 ); var untitledCount = '';
editor.setValue( solCache || BALLOT_EXAMPLE, 1 ); if (!getFiles().length || window.localStorage['sol-cache']) {
// Backwards-compatibility
while (window.localStorage[SOL_CACHE_UNTITLED + untitledCount])
untitledCount = (untitledCount - 0) + 1;
SOL_CACHE_FILE = SOL_CACHE_UNTITLED + untitledCount;
window.localStorage[SOL_CACHE_FILE] = window.localStorage['sol-cache'] || BALLOT_EXAMPLE;
window.localStorage.removeItem('sol-cache');
}
SOL_CACHE_FILE = getFiles()[0];
editor.setValue( window.localStorage[SOL_CACHE_FILE], -1);
session.setMode("ace/mode/javascript"); session.setMode("ace/mode/javascript");
session.setTabSize(4); session.setTabSize(4);
session.setUseSoftTabs(true); session.setUseSoftTabs(true);
// ----------------- file selector-------------
var $filesEl = $('#files');
$filesEl.on('click','.newFile', function() {
while (window.localStorage[SOL_CACHE_UNTITLED + untitledCount])
untitledCount = (untitledCount - 0) + 1;
SOL_CACHE_FILE = SOL_CACHE_UNTITLED + untitledCount;
window.localStorage[SOL_CACHE_FILE] = '';
updateFiles();
})
$filesEl.on('click', '.file:not(.active)', showFileHandler);
$filesEl.on('click', '.file.active', function(ev) {
var $fileTabEl = $(this);
var originalName = $fileTabEl.find('.name').text();
ev.preventDefault();
if ($(this).find('input').length > 0) return false;
var $fileNameInputEl = $('<input value="'+originalName+'"/>');
$fileTabEl.html($fileNameInputEl);
$fileNameInputEl.focus();
$fileNameInputEl.select();
$fileNameInputEl.on('blur', handleRename);
$fileNameInputEl.keyup(handleRename);
function handleRename(ev) {
ev.preventDefault();
if (ev.which && ev.which !== 13) return false;
var newName = ev.target.value;
$fileNameInputEl.off('blur');
$fileNameInputEl.off('keyup');
if (newName !== originalName && confirm("Are you sure you want to rename: " + originalName + " to " + newName + '?')) {
var content = window.localStorage.getItem( fileKey(originalName) );
window.localStorage[fileKey( newName )] = content;
window.localStorage.removeItem( fileKey( originalName) );
SOL_CACHE_FILE = fileKey( newName );
}
updateFiles();
return false;
}
return false;
})
$filesEl.on('click', '.file .remove', function(ev) {
ev.preventDefault();
var name = $(this).parent().find('.name').text();
var index = getFiles().indexOf( fileKey(name) );
if (confirm("Are you sure you want to remove: " + name + " from local storage?")) {
window.localStorage.removeItem( fileKey( name ) );
SOL_CACHE_FILE = getFiles()[ Math.max(0, index - 1)];
updateFiles();
}
return false;
});
function showFileHandler(ev) {
ev.preventDefault();
SOL_CACHE_FILE = fileKey( $(this).find('.name').text() );
updateFiles();
return false;
}
function fileTabFromKey(key) {
var name = fileNameFromKey(key);
return $('#files .file').filter(function(){ return $(this).find('.name').text() == name; });
}
function updateFiles() {
$filesEl.find('.file').remove();
var files = getFiles();
for (var f in files) {
$filesEl.append(fileTabTemplate(files[f]));
}
if (SOL_CACHE_FILE) {
var active = fileTabFromKey(SOL_CACHE_FILE);
active.addClass('active');
editor.setValue( window.localStorage[SOL_CACHE_FILE] || '', -1);
editor.focus();
$('#input').toggle( true );
} else {
$('#input').toggle( false );
}
}
function fileTabTemplate(key) {
var name = fileNameFromKey(key);
return $('<span class="file"><span class="name">'+name+'</span><span class="remove">x</span></span>');
}
function fileKey( name ) {
return SOL_CACHE_FILE_PREFIX + name;
}
function fileNameFromKey(key) {
return key.replace( SOL_CACHE_FILE_PREFIX, '' );
}
function getFiles() {
var files = [];
for (var f in localStorage ) {
if (f.indexOf( SOL_CACHE_FILE_PREFIX, 0 ) === 0) {
files.push(f);
}
}
return files;
}
updateFiles();
// ----------------- version selector------------- // ----------------- version selector-------------
// var soljsonSources is provided by bin/list.js // var soljsonSources is provided by bin/list.js
...@@ -147,14 +278,14 @@ THE SOFTWARE. ...@@ -147,14 +278,14 @@ THE SOFTWARE.
$('#ghostbar').remove(); $('#ghostbar').remove();
$(document).unbind('mousemove'); $(document).unbind('mousemove');
dragging = false; dragging = false;
setEditorSize( delta ) setEditorSize(delta)
window.localStorage.setItem( EDITOR_SIZE_CACHE_KEY, delta ); window.localStorage.setItem(EDITOR_SIZE_CACHE_KEY, delta);
} }
}); });
// set cached defaults // set cached defaults
var cachedSize = window.localStorage.getItem( EDITOR_SIZE_CACHE_KEY ); var cachedSize = window.localStorage.getItem(EDITOR_SIZE_CACHE_KEY);
if (cachedSize) setEditorSize( cachedSize ); if (cachedSize) setEditorSize(cachedSize);
// ----------------- editor resize --------------- // ----------------- editor resize ---------------
...@@ -174,7 +305,7 @@ THE SOFTWARE. ...@@ -174,7 +305,7 @@ THE SOFTWARE.
window.onresize = onResize; window.onresize = onResize;
onResize(); onResize();
document.querySelector('#editor').addEventListener('change', onResize ); document.querySelector('#editor').addEventListener('change', onResize);
// ----------------- compiler ---------------------- // ----------------- compiler ----------------------
...@@ -183,14 +314,19 @@ THE SOFTWARE. ...@@ -183,14 +314,19 @@ THE SOFTWARE.
var previousInput = ''; var previousInput = '';
var sourceAnnotations = []; var sourceAnnotations = [];
var compile = function() { var compile = function() {
editor.getSession().clearAnnotations(); editor.getSession().clearAnnotations();
sourceAnnotations = []; sourceAnnotations = [];
editor.getSession().removeMarker(errMarkerId); editor.getSession().removeMarker(errMarkerId);
$('#output').empty(); $('#output').empty();
var input = editor.getValue(); var input = editor.getValue();
window.localStorage.setItem(SOL_CACHE_FILE, input);
var inputIncludingImports = includeLocalImports(input);
var optimize = document.querySelector('#optimize').checked; var optimize = document.querySelector('#optimize').checked;
try { try {
var data = $.parseJSON(compileJSON(input, optimize ? 1 : 0)); var data = $.parseJSON(compileJSON(inputIncludingImports, optimize ? 1 : 0));
} catch (exception) { } catch (exception) {
renderError("Uncaught JavaScript Exception:\n" + exception); renderError("Uncaught JavaScript Exception:\n" + exception);
return; return;
...@@ -205,11 +341,12 @@ THE SOFTWARE. ...@@ -205,11 +341,12 @@ THE SOFTWARE.
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 === "") { if (input === "") {
window.localStorage.setItem( SOL_CACHE_KEY, '' ) window.localStorage.setItem(SOL_CACHE_FILE, '')
return; return;
} }
if (input === previousInput) if (input === previousInput)
...@@ -225,6 +362,25 @@ THE SOFTWARE. ...@@ -225,6 +362,25 @@ THE SOFTWARE.
previousInput = ''; previousInput = '';
onChange(); onChange();
}; };
function includeLocalImports(input) {
var importRegex = /import\s[\'\"]([^\'\"]+)[\'\"];/g
var imports = [];
var matches = [];
var match;
while ((match = importRegex.exec(input)) !== null) {
if (match[1] && getFiles().indexOf(fileKey(match[1])) !== -1) {
imports.push(match[1])
matches.push(match[0])
}
}
for (var i in imports) {
imported = includeLocalImports(window.localStorage.getItem( fileKey(imports[i]) ))
input = input.replace(matches[i], imported);
}
return input;
}
if (Module) if (Module)
onCompilerLoaded(); onCompilerLoaded();
...@@ -240,8 +396,8 @@ THE SOFTWARE. ...@@ -240,8 +396,8 @@ THE SOFTWARE.
.append($('<pre class="error"></pre>').text(message)); .append($('<pre class="error"></pre>').text(message));
var err = message.match(/^:([0-9]*):([0-9]*)/) var err = message.match(/^:([0-9]*):([0-9]*)/)
if (err && err.length) { if (err && err.length) {
var errLine = parseInt( err[1], 10 ) - 1; var errLine = parseInt(err[1], 10) - 1;
var errCol = err[2] ? parseInt( err[2], 10 ) : 0; var errCol = err[2] ? parseInt(err[2], 10) : 0;
sourceAnnotations[sourceAnnotations.length] ={ sourceAnnotations[sourceAnnotations.length] ={
row: errLine, row: errLine,
column: errCol, column: errCol,
...@@ -257,14 +413,14 @@ THE SOFTWARE. ...@@ -257,14 +413,14 @@ THE SOFTWARE.
var funABI = getConstructorInterface($.parseJSON(interface)); var funABI = getConstructorInterface($.parseJSON(interface));
$.each(funABI.inputs, function(i, inp) { $.each(funABI.inputs, function(i, inp) {
code += "var "+inp.name+" = /* var of type " + inp.type + " here */ ;\n"; code += "var " + inp.name + " = /* var of type " + inp.type + " here */ ;\n";
}); });
code += "\nvar "+contractName+"Contract = web3.eth.contract("+interface.replace("\n","")+");" code += "\nvar " + contractName + "Contract = web3.eth.contract(" + interface.replace("\n","") + ");"
+"\nvar "+contractName+" = "+contractName+"Contract.new("; +"\nvar " + contractName + " = " + contractName + "Contract.new(";
$.each(funABI.inputs, function(i, inp) { $.each(funABI.inputs, function(i, inp) {
code += "\n "+inp.name+","; code += "\n " + inp.name + ",";
}); });
code += "\n {"+ code += "\n {"+
...@@ -283,13 +439,11 @@ THE SOFTWARE. ...@@ -283,13 +439,11 @@ THE SOFTWARE.
}; };
var combined = function(contractName, interface, bytecode){ var combined = function(contractName, interface, bytecode){
return JSON.stringify( [{name: contractName, interface: interface, bytecode: bytecode}]); return JSON.stringify([{name: contractName, interface: interface, bytecode: bytecode}]);
}; };
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];
...@@ -297,7 +451,7 @@ THE SOFTWARE. ...@@ -297,7 +451,7 @@ THE SOFTWARE.
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)
title.append($('<div class="size"/>').text((contract.bytecode.length / 2) + ' bytes')) title.append($('<div class="size"/>').text((contract.bytecode.length / 2) + ' bytes'))
body.append(getExecuteInterface(contract, contractName)) body.append(getExecuteInterface(contract, contractName))
...@@ -311,7 +465,7 @@ THE SOFTWARE. ...@@ -311,7 +465,7 @@ THE SOFTWARE.
title.click(function(ev){ $(this).parent().toggleClass('hide') }); title.click(function(ev){ $(this).parent().toggleClass('hide') });
} }
$('.col2 input,textarea').click(function() { this.select(); } ); $('.col2 input,textarea').click(function() { this.select(); });
}; };
var tableRowItems = function(first, second, cls) { var tableRowItems = function(first, second, cls) {
return $('<div class="row"/>') return $('<div class="row"/>')
...@@ -392,7 +546,7 @@ THE SOFTWARE. ...@@ -392,7 +546,7 @@ THE SOFTWARE.
return text; return text;
}; };
$('.asmOutput button').click(function() {$(this).parent().find('pre').toggle(); } ) $('.asmOutput button').click(function() {$(this).parent().find('pre').toggle(); })
// ----------------- VM ---------------------- // ----------------- VM ----------------------
...@@ -481,7 +635,7 @@ THE SOFTWARE. ...@@ -481,7 +635,7 @@ THE SOFTWARE.
var appendFunctions = function(address) { var appendFunctions = function(address) {
var instance = $('<div class="contractInstance"/>'); var instance = $('<div class="contractInstance"/>');
var title = $('<span class="title"/>').text('Contract at ' + address.toString('hex') ); var title = $('<span class="title"/>').text('Contract at ' + address.toString('hex'));
instance.append(title); instance.append(title);
$.each(abi, function(i, funABI) { $.each(abi, function(i, funABI) {
if (funABI.type != 'function') return; if (funABI.type != 'function') return;
......
...@@ -10,12 +10,66 @@ body { ...@@ -10,12 +10,66 @@ body {
width: auto; width: auto;
bottom: 0px; bottom: 0px;
right: 37em; right: 37em;
}
#files {
font-size: 15px;
height: 2.5em;
box-sizing: border-box;
line-height: 2em;
padding: 0.5em 0.5em 0;
}
#files .file,
#files .newFile {
display: inline-block;
padding: 0 0.6em;
box-sizing: border-box;
background-color: #f0f0f0;
cursor: pointer;
margin-right: 0.5em;
position: relative;
}
#files .newFile {
background-color: #B1EAC5;
font-weight: bold;
color: #4E775D;
}
#files .file.active {
font-weight: bold;
border-bottom: 0 none;
padding-right: 2.5em;
} }
#files .file .remove {
position: absolute;
right: 0;
top: 0;
height: 1.25em;
width: 1.25em;
line-height: 1em;
border-radius: 1em;
color: #FF8080;
display: none;
margin: 0.4em;
text-align: center;
}
#files .file input {
background-color: transparent;
border: 0 none;
border-bottom: 1px dotted black;
line-height: 1em;
margin: 0.5em 0;
}
#files .file.active .remove { display: inline-block; }
#input { #input {
font-size: 15px; font-size: 15px;
position: absolute; position: absolute;
top: 0; top: 2.5em;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment