Commit e17ef151 authored by d11e9's avatar d11e9

allow publishing gists and toggle rhp

parent 31ca4c4d
...@@ -49,579 +49,640 @@ THE SOFTWARE. ...@@ -49,579 +49,640 @@ THE SOFTWARE.
</head> </head>
<body> <body>
<div id="editor"> <div id="editor">
<div id="files"> <div id="files">
<span class="newFile" title="New File">+</span> <span class="newFile" title="New File">+</span>
</div> <span class="toggleRHP" title="Toggle right hand panel"></span>
<div id="input"></div> </div>
<div id="dragbar"></div> <div id="input"></div>
</div> <div id="dragbar"></div>
</div>
<div id="righthand-panel">
<div id="header"> <div id="righthand-panel">
<img id="solIcon" src="solidity.svg"> <div id="header">
<h1>Solidity realtime<br/>compiler and runtime</h1> <img id="solIcon" src="solidity.svg">
<div class="info"> <h1>Solidity realtime<br/>compiler and runtime</h1>
<p>Version: <span id="version">(loading)</span><br/> <div class="info">
Change to: <select id="versionSelector"></select><br/> <p>Version: <span id="version">(loading)</span><br/>
<code>tx.origin = <span id="txorigin"/></code></p> Change to: <select id="versionSelector"></select><br/>
</div> <button id="gist">Share</button>
<div id="optimizeBox"> <code>tx.origin = <span id="txorigin"/></code></p>
<label for="editorWrap"><input id="editorWrap" type="checkbox">Text Wrap</label> </div>
<label for="optimize"><input id="optimize" type="checkbox">Enable Optimization</label> <div id="optimizeBox">
<span id="executionContext"> <label for="editorWrap"><input id="editorWrap" type="checkbox">Text Wrap</label>
<label for="vm" title="Execution environment does not connect to any node, everything is local and in memory only."> <label for="optimize"><input id="optimize" type="checkbox">Enable Optimization</label>
<input id="vm" type="radio" value="vm" checked name="executionContext"> <span id="executionContext">
JavaScript VM <label for="vm" title="Execution environment does not connect to any node, everything is local and in memory only.">
</label> <input id="vm" type="radio" value="vm" checked name="executionContext">
<label for="web3" title="Execution environment connects to node at localhost, transactions will be sent to the network and can cause loss of money or worse!"> JavaScript VM
<input id="web3" type="radio" value="web3" name="executionContext"> </label>
Web3 Provider <label for="web3" title="Execution environment connects to node at localhost, transactions will be sent to the network and can cause loss of money or worse!">
</label> <input id="web3" type="radio" value="web3" name="executionContext">
</span> Web3 Provider
</div> </label>
</div> </span>
<div id="output"></div> </div>
</div> </div>
<div id="output"></div>
</div>
<script>
<script>
// ----------------- editor ----------------------
var SOL_CACHE_FILE_PREFIX = 'sol-cache-file-'; // ----------------- editor ----------------------
var SOL_CACHE_UNTITLED = SOL_CACHE_FILE_PREFIX + 'Untitled';
var SOL_CACHE_FILE = null; var SOL_CACHE_FILE_PREFIX = 'sol-cache-file-';
var SOL_CACHE_UNTITLED = SOL_CACHE_FILE_PREFIX + 'Untitled';
var editor = ace.edit("input"); var SOL_CACHE_FILE = null;
var session = editor.getSession();
var Range = ace.require('ace/range').Range; var editor = ace.edit("input");
var errMarkerId = null; var session = editor.getSession();
var Range = ace.require('ace/range').Range;
var untitledCount = ''; var errMarkerId = null;
if (!getFiles().length || window.localStorage['sol-cache']) {
// Backwards-compatibility var untitledCount = '';
while (window.localStorage[SOL_CACHE_UNTITLED + untitledCount]) if (!getFiles().length || window.localStorage['sol-cache']) {
untitledCount = (untitledCount - 0) + 1; // Backwards-compatibility
SOL_CACHE_FILE = SOL_CACHE_UNTITLED + untitledCount; while (window.localStorage[SOL_CACHE_UNTITLED + untitledCount])
window.localStorage[SOL_CACHE_FILE] = window.localStorage['sol-cache'] || BALLOT_EXAMPLE; untitledCount = (untitledCount - 0) + 1;
window.localStorage.removeItem('sol-cache'); 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); SOL_CACHE_FILE = getFiles()[0];
editor.resize(true);
session.setMode("ace/mode/javascript"); editor.setValue( window.localStorage[SOL_CACHE_FILE], -1);
session.setTabSize(4); editor.resize(true);
session.setUseSoftTabs(true); session.setMode("ace/mode/javascript");
session.setTabSize(4);
// ----------------- execution context ------------- session.setUseSoftTabs(true);
var $vmToggle = $('#vm'); // ----------------- execution context -------------
var $web3Toggle = $('#web3');
var $vmToggle = $('#vm');
var executionContext = 'vm'; var $web3Toggle = $('#web3');
$vmToggle.get(0).checked = true;
var executionContext = 'vm';
$vmToggle.on('change', executionContextChange ); $vmToggle.get(0).checked = true;
$web3Toggle.on('change', executionContextChange );
$vmToggle.on('change', executionContextChange );
function executionContextChange (ev) { $web3Toggle.on('change', executionContextChange );
if (ev.target.value == 'web3' && !confirm("Are you sure you want to connect to a local ethereum node?") ) {
$vmToggle.get(0).checked = true; function executionContextChange (ev) {
executionContext = 'vm'; if (ev.target.value == 'web3' && !confirm("Are you sure you want to connect to a local ethereum node?") ) {
} else executionContext = ev.target.value; $vmToggle.get(0).checked = true;
compile(); executionContext = 'vm';
} } else executionContext = ev.target.value;
compile();
}
// ----------------- file selector------------- // ------------------ gist publish --------------
var $filesEl = $('#files'); $('#gist').click(function(){
$filesEl.on('click','.newFile', function() { //Get Github Authorization Token with proper scope, print to console
while (window.localStorage[SOL_CACHE_UNTITLED + untitledCount]) var note = ((new Date()).toString() + Math.random().toString());
untitledCount = (untitledCount - 0) + 1; var description = "Ethereum Contracts Gist created using soleditor at: https://chriseth.github.io/browser-solidity";
SOL_CACHE_FILE = SOL_CACHE_UNTITLED + untitledCount; $.ajax({
window.localStorage[SOL_CACHE_FILE] = ''; url: 'https://api.github.com/authorizations',
updateFiles(); type: 'POST',
}) beforeSend: function(xhr) {
xhr.setRequestHeader("Authorization", "Basic " + "c29sZWRpdG9yOmRlY2VudHJhbGlzZWV2ZXJ5dGhpbmc=");
$filesEl.on('click', '.file:not(.active)', showFileHandler); },
data: JSON.stringify({
$filesEl.on('click', '.file.active', function(ev) { scopes:["gist"],
var $fileTabEl = $(this); note: note
var originalName = $fileTabEl.find('.name').text(); })
ev.preventDefault(); }).done(function(response) {
if ($(this).find('input').length > 0) return false; //Create a Gist with token from above
var $fileNameInputEl = $('<input value="'+originalName+'"/>'); var files = {};
$fileTabEl.html($fileNameInputEl); files["00" + response.hashed_token] = { content: description + " at " + new Date() }
$fileNameInputEl.focus(); var filesArr = getFiles();
$fileNameInputEl.select(); for(var f in filesArr) { files[fileNameFromKey(filesArr[f])] = { content: localStorage[filesArr[f]] } }
$fileNameInputEl.on('blur', handleRename); var data = JSON.stringify({
$fileNameInputEl.keyup(handleRename); description: description,
public: true,
function handleRename(ev) { files: files
ev.preventDefault(); });
if (ev.which && ev.which !== 13) return false;
var newName = ev.target.value; $.ajax({
$fileNameInputEl.off('blur'); url: 'https://api.github.com/gists',
$fileNameInputEl.off('keyup'); type: 'POST',
beforeSend: function(xhr) {
if (newName !== originalName && confirm("Are you sure you want to rename: " + originalName + " to " + newName + '?')) { xhr.setRequestHeader("Authorization", "token " + response.token);
var content = window.localStorage.getItem( fileKey(originalName) ); },
window.localStorage[fileKey( newName )] = content; data: data
window.localStorage.removeItem( fileKey( originalName) ); }).done(function(response) {
SOL_CACHE_FILE = fileKey( newName ); if (response.html_url && confirm("Created a gist at " + response.html_url + " Would you like to open it in a new window?")) {
} window.open( response.html_url );
}
updateFiles(); });
return false; });
}
})
return false;
})
// ----------------- file selector-------------
$filesEl.on('click', '.file .remove', function(ev) {
ev.preventDefault(); var $filesEl = $('#files');
var name = $(this).parent().find('.name').text();
var index = getFiles().indexOf( fileKey(name) ); $filesEl.on('click','.newFile', function() {
while (window.localStorage[SOL_CACHE_UNTITLED + untitledCount])
if (confirm("Are you sure you want to remove: " + name + " from local storage?")) { untitledCount = (untitledCount - 0) + 1;
window.localStorage.removeItem( fileKey( name ) ); SOL_CACHE_FILE = SOL_CACHE_UNTITLED + untitledCount;
SOL_CACHE_FILE = getFiles()[ Math.max(0, index - 1)]; window.localStorage[SOL_CACHE_FILE] = '';
updateFiles(); updateFiles();
} })
return false;
}); $filesEl.on('click', '.file:not(.active)', showFileHandler);
function showFileHandler(ev) { $filesEl.on('click', '.file.active', function(ev) {
ev.preventDefault(); var $fileTabEl = $(this);
SOL_CACHE_FILE = fileKey( $(this).find('.name').text() ); var originalName = $fileTabEl.find('.name').text();
updateFiles(); ev.preventDefault();
return false; if ($(this).find('input').length > 0) return false;
} var $fileNameInputEl = $('<input value="'+originalName+'"/>');
$fileTabEl.html($fileNameInputEl);
function fileTabFromKey(key) { $fileNameInputEl.focus();
var name = fileNameFromKey(key); $fileNameInputEl.select();
return $('#files .file').filter(function(){ return $(this).find('.name').text() == name; }); $fileNameInputEl.on('blur', handleRename);
} $fileNameInputEl.keyup(handleRename);
function handleRename(ev) {
function updateFiles() { ev.preventDefault();
$filesEl.find('.file').remove(); if (ev.which && ev.which !== 13) return false;
var files = getFiles(); var newName = ev.target.value;
for (var f in files) { $fileNameInputEl.off('blur');
$filesEl.append(fileTabTemplate(files[f])); $fileNameInputEl.off('keyup');
}
if (newName !== originalName && confirm("Are you sure you want to rename: " + originalName + " to " + newName + '?')) {
if (SOL_CACHE_FILE) { var content = window.localStorage.getItem( fileKey(originalName) );
var active = fileTabFromKey(SOL_CACHE_FILE); window.localStorage[fileKey( newName )] = content;
active.addClass('active'); window.localStorage.removeItem( fileKey( originalName) );
editor.setValue( window.localStorage[SOL_CACHE_FILE] || '', -1); SOL_CACHE_FILE = fileKey( newName );
editor.focus(); }
$('#input').toggle( true );
} else { updateFiles();
$('#input').toggle( false ); return false;
} }
}
return false;
function fileTabTemplate(key) { })
var name = fileNameFromKey(key);
return $('<span class="file"><span class="name">'+name+'</span><span class="remove">x</span></span>'); $filesEl.on('click', '.file .remove', function(ev) {
} ev.preventDefault();
var name = $(this).parent().find('.name').text();
function fileKey( name ) { var index = getFiles().indexOf( fileKey(name) );
return SOL_CACHE_FILE_PREFIX + name;
} if (confirm("Are you sure you want to remove: " + name + " from local storage?")) {
window.localStorage.removeItem( fileKey( name ) );
function fileNameFromKey(key) { SOL_CACHE_FILE = getFiles()[ Math.max(0, index - 1)];
return key.replace( SOL_CACHE_FILE_PREFIX, '' ); updateFiles();
} }
return false;
function getFiles() { });
var files = [];
for (var f in localStorage ) { function showFileHandler(ev) {
if (f.indexOf( SOL_CACHE_FILE_PREFIX, 0 ) === 0) { ev.preventDefault();
files.push(f); SOL_CACHE_FILE = fileKey( $(this).find('.name').text() );
} updateFiles();
} return false;
return files; }
}
function fileTabFromKey(key) {
updateFiles(); var name = fileNameFromKey(key);
return $('#files .file').filter(function(){ return $(this).find('.name').text() == name; });
// ----------------- version selector------------- }
// var soljsonSources is provided by bin/list.js
$('option', '#versionSelector').remove(); function updateFiles() {
$.each(soljsonSources, function(i, file) { $filesEl.find('.file').remove();
if (file) { var files = getFiles();
var version = file.replace(/soljson-(.*).js/, "$1"); for (var f in files) {
$('#versionSelector').append(new Option(version, file)); $filesEl.append(fileTabTemplate(files[f]));
} }
});
$('#versionSelector').change(function() { if (SOL_CACHE_FILE) {
Module = null; var active = fileTabFromKey(SOL_CACHE_FILE);
compileJSON = null; active.addClass('active');
var script = document.createElement('script'); editor.setValue( window.localStorage[SOL_CACHE_FILE] || '', -1);
script.type = 'text/javascript'; editor.focus();
script.src = 'bin/' + $('#versionSelector').val(); $('#input').toggle( true );
$('head').append(script); } else {
onCompilerLoaded(); $('#input').toggle( false );
}); }
}
// ----------------- resizeable ui ---------------
function fileTabTemplate(key) {
var EDITOR_SIZE_CACHE_KEY = "editor-size-cache"; var name = fileNameFromKey(key);
var dragging = false; return $('<span class="file"><span class="name">'+name+'</span><span class="remove">x</span></span>');
$('#dragbar').mousedown(function(e){ }
e.preventDefault();
dragging = true; function fileKey( name ) {
var main = $('#righthand-panel'); return SOL_CACHE_FILE_PREFIX + name;
var ghostbar = $('<div id="ghostbar">', { }
css: {
top: main.offset().top, function fileNameFromKey(key) {
left: main.offset().left return key.replace( SOL_CACHE_FILE_PREFIX, '' );
} }
}).prependTo('body');
function getFiles() {
$(document).mousemove(function(e){ var files = [];
ghostbar.css("left",e.pageX+2); for (var f in localStorage ) {
}); if (f.indexOf( SOL_CACHE_FILE_PREFIX, 0 ) === 0) {
}); files.push(f);
}
var $body = $('body'); }
return files;
function setEditorSize (delta) { }
$('#righthand-panel').css("width", delta);
$('#editor').css("right", delta); updateFiles();
onResize();
} // ----------------- version selector-------------
$(document).mouseup(function(e){ // var soljsonSources is provided by bin/list.js
if (dragging) { $('option', '#versionSelector').remove();
var delta = $body.width() - e.pageX+2; $.each(soljsonSources, function(i, file) {
$('#ghostbar').remove(); if (file) {
$(document).unbind('mousemove'); var version = file.replace(/soljson-(.*).js/, "$1");
dragging = false; $('#versionSelector').append(new Option(version, file));
setEditorSize(delta); }
window.localStorage.setItem(EDITOR_SIZE_CACHE_KEY, delta); });
} $('#versionSelector').change(function() {
}); Module = null;
compileJSON = null;
// set cached defaults var script = document.createElement('script');
var cachedSize = window.localStorage.getItem(EDITOR_SIZE_CACHE_KEY); script.type = 'text/javascript';
if (cachedSize) setEditorSize(cachedSize); script.src = 'bin/' + $('#versionSelector').val();
$('head').append(script);
onCompilerLoaded();
// ----------------- editor resize --------------- });
function onResize() { // ----------------- resizeable ui ---------------
editor.resize();
session.setUseWrapMode(document.querySelector('#editorWrap').checked); var EDITOR_SIZE_CACHE_KEY = "editor-size-cache";
if(session.getUseWrapMode()) { var dragging = false;
var characterWidth = editor.renderer.characterWidth; $('#dragbar').mousedown(function(e){
var contentWidth = editor.container.ownerDocument.getElementsByClassName("ace_scroller")[0].clientWidth; e.preventDefault();
dragging = true;
if(contentWidth > 0) { var main = $('#righthand-panel');
session.setWrapLimit(parseInt(contentWidth / characterWidth, 10)); var ghostbar = $('<div id="ghostbar">', {
} css: {
} top: main.offset().top,
} left: main.offset().left
window.onresize = onResize; }
onResize(); }).prependTo('body');
document.querySelector('#editor').addEventListener('change', onResize); $(document).mousemove(function(e){
document.querySelector('#editorWrap').addEventListener('change', onResize); ghostbar.css("left",e.pageX+2);
});
});
// ----------------- compiler ----------------------
var compileJSON; var $body = $('body');
var previousInput = ''; function setEditorSize (delta) {
var sourceAnnotations = []; $('#righthand-panel').css("width", delta);
var compile = function() { $('#editor').css("right", delta);
onResize();
editor.getSession().clearAnnotations(); }
sourceAnnotations = [];
editor.getSession().removeMarker(errMarkerId); function getEditorSize(){
$('#output').empty(); window.localStorage[EDITOR_SIZE_CACHE_KEY] = $('#righthand-panel').width();
var input = editor.getValue(); }
window.localStorage.setItem(SOL_CACHE_FILE, input);
$(document).mouseup(function(e){
var inputIncludingImports = includeLocalImports(input); if (dragging) {
var optimize = document.querySelector('#optimize').checked; var delta = $body.width() - e.pageX+2;
$('#ghostbar').remove();
try { $(document).unbind('mousemove');
var data = $.parseJSON(compileJSON(inputIncludingImports, optimize ? 1 : 0)); dragging = false;
} catch (exception) { setEditorSize(delta);
renderError("Uncaught JavaScript Exception:\n" + exception); window.localStorage.setItem(EDITOR_SIZE_CACHE_KEY, delta);
return; }
} });
var noFatalErrors = true; // ie warnings are ok // set cached defaults
var cachedSize = window.localStorage.getItem(EDITOR_SIZE_CACHE_KEY);
if (data['error'] !== undefined) { if (cachedSize) setEditorSize(cachedSize);
renderError(data['error']); else getEditorSize();
if (errortype(data['error']) !== 'warning') noFatalErrors = false;
}
if (data['errors'] != undefined) { // ----------------- toggle right hand panel
$.each(data['errors'], function(i, err) {
renderError(err); var toggledRHP = false;
if (errortype(err) !== 'warning') noFatalErrors = false; $('.toggleRHP').click(function(){
}); toggledRHP = !toggledRHP;
} setEditorSize( toggledRHP ? 0 : window.localStorage[EDITOR_SIZE_CACHE_KEY] );
$('.toggleRHP').toggleClass('toggled', toggledRHP)
if (noFatalErrors) renderContracts(data, input); });
}
// ----------------- editor resize ---------------
var compileTimeout = null;
var onChange = function() { function onResize() {
var input = editor.getValue(); editor.resize();
if (input === "") { session.setUseWrapMode(document.querySelector('#editorWrap').checked);
window.localStorage.setItem(SOL_CACHE_FILE, ''); if(session.getUseWrapMode()) {
return; var characterWidth = editor.renderer.characterWidth;
} var contentWidth = editor.container.ownerDocument.getElementsByClassName("ace_scroller")[0].clientWidth;
if (input === previousInput)
return; if(contentWidth > 0) {
previousInput = input; session.setWrapLimit(parseInt(contentWidth / characterWidth, 10));
if (compileTimeout) window.clearTimeout(compileTimeout); }
compileTimeout = window.setTimeout(compile, 300); }
}; }
window.onresize = onResize;
var onCompilerLoaded = function() { onResize();
compileJSON = Module.cwrap("compileJSON", "string", ["string", "number"]);
$('#version').text(Module.cwrap("version", "string", [])()); document.querySelector('#editor').addEventListener('change', onResize);
previousInput = ''; document.querySelector('#editorWrap').addEventListener('change', onResize);
onChange();
};
// ----------------- compiler ----------------------
function includeLocalImports(input) { var compileJSON;
var importRegex = /import\s[\'\"]([^\'\"]+)[\'\"];/g;
var imports = []; var previousInput = '';
var matches = []; var sourceAnnotations = [];
var match; var compile = function() {
while ((match = importRegex.exec(input)) !== null) {
if (match[1] && getFiles().indexOf(fileKey(match[1])) !== -1) { editor.getSession().clearAnnotations();
imports.push(match[1]); sourceAnnotations = [];
matches.push(match[0]); editor.getSession().removeMarker(errMarkerId);
} $('#output').empty();
} var input = editor.getValue();
for (var i in imports) { window.localStorage.setItem(SOL_CACHE_FILE, input);
imported = includeLocalImports(window.localStorage.getItem( fileKey(imports[i]) ));
input = input.replace(matches[i], imported); var inputIncludingImports = includeLocalImports(input);
} var optimize = document.querySelector('#optimize').checked;
return input;
} try {
var data = $.parseJSON(compileJSON(inputIncludingImports, optimize ? 1 : 0));
if (Module) } catch (exception) {
onCompilerLoaded(); renderError("Uncaught JavaScript Exception:\n" + exception);
return;
editor.getSession().on('change', onChange); }
document.querySelector('#optimize').addEventListener('change', compile); var noFatalErrors = true; // ie warnings are ok
// ----------------- compiler output renderer ---------------------- if (data['error'] !== undefined) {
var detailsOpen = {}; renderError(data['error']);
if (errortype(data['error']) !== 'warning') noFatalErrors = false;
function errortype(message) { }
return message.match(/^[0-9:]* Warning: /) ? 'warning' : 'error'; if (data['errors'] != undefined) {
} $.each(data['errors'], function(i, err) {
renderError(err);
var renderError = function(message) { if (errortype(err) !== 'warning') noFatalErrors = false;
var type = errortype(message); });
var $pre = $("<pre />").text(message); }
var $error = $('<div class="sol ' + type + '"><div class="close">x</div></div>').prepend($pre);
$('#output').append( $error ); if (noFatalErrors) renderContracts(data, input);
var err = message.match(/^:([0-9]*):([0-9]*)/);
if (err && err.length) { }
var errLine = parseInt(err[1], 10) - 1;
var errCol = err[2] ? parseInt(err[2], 10) : 0; var compileTimeout = null;
sourceAnnotations[sourceAnnotations.length] = { var onChange = function() {
row: errLine, var input = editor.getValue();
column: errCol, if (input === "") {
text: message, window.localStorage.setItem(SOL_CACHE_FILE, '');
type: type return;
}; }
editor.getSession().setAnnotations(sourceAnnotations); if (input === previousInput)
$error.click(function(ev){ return;
editor.focus(); previousInput = input;
editor.gotoLine(errLine + 1, errCol - 1, true); if (compileTimeout) window.clearTimeout(compileTimeout);
}); compileTimeout = window.setTimeout(compile, 300);
$error.find('.close').click(function(ev){ };
ev.preventDefault();
$error.remove(); var onCompilerLoaded = function() {
return false; compileJSON = Module.cwrap("compileJSON", "string", ["string", "number"]);
}); $('#version').text(Module.cwrap("version", "string", [])());
} previousInput = '';
}; onChange();
};
var gethDeploy = function(contractName, interface, bytecode){
var code = ""; function includeLocalImports(input) {
var funABI = getConstructorInterface($.parseJSON(interface)); var importRegex = /import\s[\'\"]([^\'\"]+)[\'\"];/g;
var imports = [];
$.each(funABI.inputs, function(i, inp) { var matches = [];
code += "var " + inp.name + " = /* var of type " + inp.type + " here */ ;\n"; var match;
}); while ((match = importRegex.exec(input)) !== null) {
if (match[1] && getFiles().indexOf(fileKey(match[1])) !== -1) {
code += "var " + contractName + "Contract = web3.eth.contract(" + interface.replace("\n","") + ");" imports.push(match[1]);
+"\nvar " + contractName + " = " + contractName + "Contract.new("; matches.push(match[0]);
}
$.each(funABI.inputs, function(i, inp) { }
code += "\n " + inp.name + ","; for (var i in imports) {
}); imported = includeLocalImports(window.localStorage.getItem( fileKey(imports[i]) ));
input = input.replace(matches[i], imported);
code += "\n {"+ }
"\n from: web3.eth.accounts[0], "+ return input;
"\n data: '"+bytecode+"', "+ }
"\n gas: 3000000"+
"\n }, function(e, contract){"+ if (Module)
"\n if (typeof contract.address != 'undefined') {"+ onCompilerLoaded();
"\n console.log(e, contract);"+
"\n console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);" + editor.getSession().on('change', onChange);
"\n }" +
"\n })"; document.querySelector('#optimize').addEventListener('change', compile);
// ----------------- compiler output renderer ----------------------
return code; var detailsOpen = {};
};
function errortype(message) {
var combined = function(contractName, interface, bytecode){ return message.match(/^[0-9:]* Warning: /) ? 'warning' : 'error';
return JSON.stringify([{name: contractName, interface: interface, bytecode: bytecode}]); }
}; var renderError = function(message) {
var type = errortype(message);
var renderContracts = function(data, source) { var $pre = $("<pre />").text(message);
for (var contractName in data.contracts) { var $error = $('<div class="sol ' + type + '"><div class="close">x</div></div>').prepend($pre);
var contract = data.contracts[contractName]; $('#output').append( $error );
var dapp = new UniversalDApp([{ var err = message.match(/^:([0-9]*):([0-9]*)/);
name: contractName, if (err && err.length) {
interface: contract['interface'], var errLine = parseInt(err[1], 10) - 1;
bytecode: contract.bytecode var errCol = err[2] ? parseInt(err[2], 10) : 0;
}], { sourceAnnotations[sourceAnnotations.length] = {
vm: executionContext === 'vm', row: errLine,
removable: false, column: errCol,
removable_instances: true text: message,
}); type: type
var $contractOutput = dapp.render(); };
$contractOutput editor.getSession().setAnnotations(sourceAnnotations);
.append(textRow('Bytecode', contract.bytecode)) $error.click(function(ev){
.append(textRow('Interface', contract['interface'])) editor.focus();
.append(textRow('Web3 deploy', gethDeploy(contractName.toLowerCase(),contract['interface'],contract.bytecode), 'deploy')) editor.gotoLine(errLine + 1, errCol - 1, true);
.append(textRow('uDApp', combined(contractName,contract['interface'],contract.bytecode), 'deploy')) });
.append(getDetails(contract, source, contractName)); $error.find('.close').click(function(ev){
ev.preventDefault();
if (executionContext === 'vm') $('#txorigin').text('0x' + dapp.address.toString('hex')); $error.remove();
else web3.eth.getAccounts( function(err,accounts) { return false;
if (err) renderError(err.message); });
$('#txorigin').text(accounts[0]); }
}); };
$contractOutput.find('.title').click(function(ev){ $(this).closest('.udapp').toggleClass('hide') }); var gethDeploy = function(contractName, interface, bytecode){
$('#output').append( $contractOutput ); var code = "";
} var funABI = getConstructorInterface($.parseJSON(interface));
$('.col2 input,textarea').click(function() { this.select(); });
}; $.each(funABI.inputs, function(i, inp) {
var tableRowItems = function(first, second, cls) { code += "var " + inp.name + " = /* var of type " + inp.type + " here */ ;\n";
return $('<div class="row"/>') });
.addClass(cls)
.append($('<div class="col1">').append(first)) code += "var " + contractName + "Contract = web3.eth.contract(" + interface.replace("\n","") + ");"
.append($('<div class="col2">').append(second)); +"\nvar " + contractName + " = " + contractName + "Contract.new(";
};
var tableRow = function(description, data) { $.each(funABI.inputs, function(i, inp) {
return tableRowItems( code += "\n " + inp.name + ",";
$('<span/>').text(description), });
$('<input readonly="readonly"/>').val(data));
}; code += "\n {"+
var textRow = function(description, data, cls) { "\n from: web3.eth.accounts[0], "+
return tableRowItems( "\n data: '"+bytecode+"', "+
$('<strong/>').text(description), "\n gas: 3000000"+
$('<textarea readonly="readonly" class="gethDeployText"/>').val(data), "\n }, function(e, contract){"+
cls); "\n if (typeof contract.address != 'undefined') {"+
}; "\n console.log(e, contract);"+
var getDetails = function(contract, source, contractName) { "\n console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);" +
var button = $('<button>Toggle Details</button>'); "\n }" +
var details = $('<div style="display: none;"/>') "\n })";
.append(tableRow('Solidity Interface', contract.solidity_interface))
.append(tableRow('Opcodes', contract.opcodes));
var funHashes = ''; return code;
for (var fun in contract.functionHashes) };
funHashes += contract.functionHashes[fun] + ' ' + fun + '\n';
details.append($('<span class="col1">Functions</span>')); var combined = function(contractName, interface, bytecode){
details.append($('<pre/>').text(funHashes)); return JSON.stringify([{name: contractName, interface: interface, bytecode: bytecode}]);
details.append($('<span class="col1">Gas Estimates</span>'));
details.append($('<pre/>').text(formatGasEstimates(contract.gasEstimates))); };
if (contract.runtimeBytecode && contract.runtimeBytecode.length > 0)
details.append(tableRow('Runtime Bytecode', contract.runtimeBytecode)); var renderContracts = function(data, source) {
if (contract.assembly !== null) for (var contractName in data.contracts) {
{ var contract = data.contracts[contractName];
details.append($('<span class="col1">Assembly</span>')); var dapp = new UniversalDApp([{
var assembly = $('<pre/>').text(formatAssemblyText(contract.assembly, '', source)); name: contractName,
details.append(assembly); interface: contract['interface'],
} bytecode: contract.bytecode
button.click(function() { detailsOpen[contractName] = !detailsOpen[contractName]; details.toggle(); }); }], {
if (detailsOpen[contractName]) vm: executionContext === 'vm',
details.show(); removable: false,
return $('<div class="contractDetails"/>').append(button).append(details); removable_instances: true
}; });
var formatGasEstimates = function(data) { var $contractOutput = dapp.render();
var gasToText = function(g) { return g === null ? 'unknown' : g; } $contractOutput
var text = ''; .append(textRow('Bytecode', contract.bytecode))
if ('creation' in data) .append(textRow('Interface', contract['interface']))
text += 'Creation: ' + gasToText(data.creation[0]) + ' + ' + gasToText(data.creation[1]) + '\n'; .append(textRow('Web3 deploy', gethDeploy(contractName.toLowerCase(),contract['interface'],contract.bytecode), 'deploy'))
text += 'External:\n'; .append(textRow('uDApp', combined(contractName,contract['interface'],contract.bytecode), 'deploy'))
for (var fun in data.external) .append(getDetails(contract, source, contractName));
text += ' ' + fun + ': ' + gasToText(data.external[fun]) + '\n';
text += 'Internal:\n'; if (executionContext === 'vm') $('#txorigin').text('0x' + dapp.address.toString('hex'));
for (var fun in data.internal) else web3.eth.getAccounts( function(err,accounts) {
text += ' ' + fun + ': ' + gasToText(data.internal[fun]) + '\n'; if (err) renderError(err.message);
return text; $('#txorigin').text(accounts[0]);
}; });
var formatAssemblyText = function(asm, prefix, source) {
if (typeof(asm) == typeof('') || asm === null || asm === undefined) $contractOutput.find('.title').click(function(ev){ $(this).closest('.udapp').toggleClass('hide') });
return prefix + asm + '\n'; $('#output').append( $contractOutput );
var text = prefix + '.code\n'; }
$.each(asm['.code'], function(i, item) { $('.col2 input,textarea').click(function() { this.select(); });
var v = item.value === undefined ? '' : item.value; };
var src = ''; var tableRowItems = function(first, second, cls) {
if (item.begin !== undefined && item.end != undefined) return $('<div class="row"/>')
src = source.slice(item.begin, item.end).replace('\n', '\\n', 'g'); .addClass(cls)
if (src.length > 30) .append($('<div class="col1">').append(first))
src = src.slice(0, 30) + '...'; .append($('<div class="col2">').append(second));
if (item.name != 'tag') };
text += ' '; var tableRow = function(description, data) {
text += prefix + item.name + ' ' + v + '\t\t\t' + src + '\n'; return tableRowItems(
}); $('<span/>').text(description),
text += prefix + '.data\n'; $('<input readonly="readonly"/>').val(data));
if (asm['.data']) };
$.each(asm['.data'], function(i, item) { var textRow = function(description, data, cls) {
text += ' ' + prefix + '' + i + ':\n'; return tableRowItems(
text += formatAssemblyText(item, prefix + ' ', source); $('<strong/>').text(description),
}); $('<textarea readonly="readonly" class="gethDeployText"/>').val(data),
cls);
return text; };
}; var getDetails = function(contract, source, contractName) {
var button = $('<button>Toggle Details</button>');
$('.asmOutput button').click(function() {$(this).parent().find('pre').toggle(); }); var details = $('<div style="display: none;"/>')
.append(tableRow('Solidity Interface', contract.solidity_interface))
var getConstructorInterface = function(abi) { .append(tableRow('Opcodes', contract.opcodes));
var funABI = {'name':'','inputs':[],'type':'constructor','outputs':[]}; var funHashes = '';
for (var i = 0; i < abi.length; i++) for (var fun in contract.functionHashes)
if (abi[i].type == 'constructor') { funHashes += contract.functionHashes[fun] + ' ' + fun + '\n';
funABI.inputs = abi[i].inputs || []; details.append($('<span class="col1">Functions</span>'));
break; details.append($('<pre/>').text(funHashes));
} details.append($('<span class="col1">Gas Estimates</span>'));
return funABI; details.append($('<pre/>').text(formatGasEstimates(contract.gasEstimates)));
}; if (contract.runtimeBytecode && contract.runtimeBytecode.length > 0)
details.append(tableRow('Runtime Bytecode', contract.runtimeBytecode));
</script> if (contract.assembly !== null)
{
details.append($('<span class="col1">Assembly</span>'));
var assembly = $('<pre/>').text(formatAssemblyText(contract.assembly, '', source));
details.append(assembly);
}
button.click(function() { detailsOpen[contractName] = !detailsOpen[contractName]; details.toggle(); });
if (detailsOpen[contractName])
details.show();
return $('<div class="contractDetails"/>').append(button).append(details);
};
var formatGasEstimates = function(data) {
var gasToText = function(g) { return g === null ? 'unknown' : g; }
var text = '';
if ('creation' in data)
text += 'Creation: ' + gasToText(data.creation[0]) + ' + ' + gasToText(data.creation[1]) + '\n';
text += 'External:\n';
for (var fun in data.external)
text += ' ' + fun + ': ' + gasToText(data.external[fun]) + '\n';
text += 'Internal:\n';
for (var fun in data.internal)
text += ' ' + fun + ': ' + gasToText(data.internal[fun]) + '\n';
return text;
};
var formatAssemblyText = function(asm, prefix, source) {
if (typeof(asm) == typeof('') || asm === null || asm === undefined)
return prefix + asm + '\n';
var text = prefix + '.code\n';
$.each(asm['.code'], function(i, item) {
var v = item.value === undefined ? '' : item.value;
var src = '';
if (item.begin !== undefined && item.end != undefined)
src = source.slice(item.begin, item.end).replace('\n', '\\n', 'g');
if (src.length > 30)
src = src.slice(0, 30) + '...';
if (item.name != 'tag')
text += ' ';
text += prefix + item.name + ' ' + v + '\t\t\t' + src + '\n';
});
text += prefix + '.data\n';
if (asm['.data'])
$.each(asm['.data'], function(i, item) {
text += ' ' + prefix + '' + i + ':\n';
text += formatAssemblyText(item, prefix + ' ', source);
});
return text;
};
$('.asmOutput button').click(function() {$(this).parent().find('pre').toggle(); });
var getConstructorInterface = function(abi) {
var funABI = {'name':'','inputs':[],'type':'constructor','outputs':[]};
for (var i = 0; i < abi.length; i++)
if (abi[i].type == 'constructor') {
funABI.inputs = abi[i].inputs || [];
break;
}
return funABI;
};
</script>
</body> </body>
</html> </html>
...@@ -17,7 +17,7 @@ body { ...@@ -17,7 +17,7 @@ body {
height: 2.5em; height: 2.5em;
box-sizing: border-box; box-sizing: border-box;
line-height: 2em; line-height: 2em;
padding: 0.5em 0.5em 0; padding: 0.5em 0 0;
} }
#files .file, #files .file,
...@@ -31,12 +31,28 @@ body { ...@@ -31,12 +31,28 @@ body {
position: relative; position: relative;
} }
#files .newFile { #files .newFile,
#files .toggleRHP {
background-color: #B1EAC5; background-color: #B1EAC5;
font-weight: bold; font-weight: bold;
color: #4E775D; color: #4E775D;
} }
#files .toggleRHP {
float: right;
cursor: pointer;
}
#files .toggleRHP:before {
content: ">>";
width: 2em;
padding: 0 0.6em;
box-sizing: border-box;
}
#files .toggleRHP.toggled:before {
content: "<<";
}
#files .file.active { #files .file.active {
font-weight: bold; font-weight: bold;
border-bottom: 0 none; border-bottom: 0 none;
......
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