remix-project mirror
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
remix-project/index.html

638 lines
20 KiB

9 years ago
<html>
<head>
<meta charset="utf-8">
9 years ago
<!--
The MIT License (MIT)
Copyright (c) 2014, 2015, the individual contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
9 years ago
<meta http-equiv="X-UA-Compatible" content="chrome=1">
9 years ago
<title>Solidity realtime compiler and runtime</title>
9 years ago
<link rel="stylesheet" href="stylesheets/styles.css">
<link rel="stylesheet" href="stylesheets/pygment_trac.css">
<link rel="stylesheet" href="stylesheets/universal-dapp.css">
<link rel="stylesheet" href="stylesheets/browser-solidity.css">
9 years ago
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<style type="text/css">
9 years ago
</style>
<script src="bin/list.js"></script>
<script src="libs/jquery-2.1.3.min.js"></script>
9 years ago
<script src="libs/ace.js"></script>
<script src="libs/mode-solidity.js"></script>
<script src="bin/soljson-latest.js"></script>
<script src="libs/ethereumjs-vm.js"></script>
<script src="libs/universal-dapp.js"></script>
<script src="libs/web3.min.js"></script>
<script src="ballot.sol.js"></script>
9 years ago
</head>
<body>
<div id="editor">
<div id="files">
<span class="newFile" title="New File">+</span>
</div>
<div id="input"></div>
<div id="dragbar"></div>
</div>
<div id="righthand-panel">
<div id="header">
<img id="solIcon" src="solidity.svg">
<h1>Solidity realtime<br/>compiler and runtime</h1>
<div class="info">
<p>Version: <span id="version">(loading)</span><br/>
Change to: <select id="versionSelector"></select><br/>
<code>tx.origin = <span id="txorigin"/></code></p>
</div>
<div id="optimizeBox">
<label for="editorWrap"><input id="editorWrap" type="checkbox">Text Wrap</label>
<label for="optimize"><input id="optimize" type="checkbox">Enable Optimization</label>
<span id="executionContext">
<label for="vm" title="Execution environment does not connect to any node, everything is local and in memory only.">
<input id="vm" type="radio" value="vm" checked name="executionContext">
JavaScript VM
</label>
<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!">
<input id="web3" type="radio" value="web3" name="executionContext">
Web3 Provider
</label>
</span>
</div>
</div>
<div id="output"></div>
9 years ago
</div>
<script>
// ----------------- editor ----------------------
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 session = editor.getSession();
var Range = ace.require('ace/range').Range;
var errMarkerId = null;
var untitledCount = '';
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];
9 years ago
editor.setValue( window.localStorage[SOL_CACHE_FILE], -1);
editor.resize(true);
session.setMode("ace/mode/javascript");
9 years ago
session.setTabSize(4);
session.setUseSoftTabs(true);
// ----------------- execution context -------------
var $vmToggle = $('#vm');
var $web3Toggle = $('#web3');
var executionContext = 'vm';
$vmToggle.get(0).checked = true;
$vmToggle.on('change', executionContextChange );
$web3Toggle.on('change', executionContextChange );
function executionContextChange (ev) {
if (ev.target.value == 'web3' && !confirm("Are you sure you want to connect to a local ethereum node?") ) {
$vmToggle.get(0).checked = true;
executionContext = 'vm';
} else executionContext = ev.target.value;
compile();
}
9 years ago
// ----------------- file selector-------------
var $filesEl = $('#files');
9 years ago
$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();
9 years ago
})
9 years ago
$filesEl.on('click', '.file:not(.active)', showFileHandler);
9 years ago
9 years ago
$filesEl.on('click', '.file.active', function(ev) {
var $fileTabEl = $(this);
var originalName = $fileTabEl.find('.name').text();
ev.preventDefault();
9 years ago
if ($(this).find('input').length > 0) return false;
var $fileNameInputEl = $('<input value="'+originalName+'"/>');
9 years ago
$fileTabEl.html($fileNameInputEl);
$fileNameInputEl.focus();
$fileNameInputEl.select();
9 years ago
$fileNameInputEl.on('blur', handleRename);
$fileNameInputEl.keyup(handleRename);
9 years ago
function handleRename(ev) {
ev.preventDefault();
if (ev.which && ev.which !== 13) return false;
var newName = ev.target.value;
$fileNameInputEl.off('blur');
$fileNameInputEl.off('keyup');
9 years ago
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 );
}
9 years ago
updateFiles();
return false;
9 years ago
}
return false;
})
9 years ago
$filesEl.on('click', '.file .remove', function(ev) {
ev.preventDefault();
9 years ago
var name = $(this).parent().find('.name').text();
var index = getFiles().indexOf( fileKey(name) );
9 years ago
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)];
9 years ago
updateFiles();
}
return false;
});
9 years ago
9 years ago
function showFileHandler(ev) {
ev.preventDefault();
SOL_CACHE_FILE = fileKey( $(this).find('.name').text() );
9 years ago
updateFiles();
return false;
9 years ago
}
function fileTabFromKey(key) {
var name = fileNameFromKey(key);
9 years ago
return $('#files .file').filter(function(){ return $(this).find('.name').text() == name; });
9 years ago
}
9 years ago
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 );
}
9 years ago
}
function fileTabTemplate(key) {
var name = fileNameFromKey(key);
return $('<span class="file"><span class="name">'+name+'</span><span class="remove">x</span></span>');
9 years ago
}
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;
}
9 years ago
updateFiles();
// ----------------- version selector-------------
// var soljsonSources is provided by bin/list.js
$('option', '#versionSelector').remove();
$.each(soljsonSources, function(i, file) {
if (file) {
var version = file.replace(/soljson-(.*).js/, "$1");
$('#versionSelector').append(new Option(version, file));
}
});
$('#versionSelector').change(function() {
Module = null;
compileJSON = null;
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'bin/' + $('#versionSelector').val();
$('head').append(script);
onCompilerLoaded();
});
// ----------------- resizeable ui ---------------
var EDITOR_SIZE_CACHE_KEY = "editor-size-cache";
var dragging = false;
$('#dragbar').mousedown(function(e){
e.preventDefault();
dragging = true;
var main = $('#righthand-panel');
var ghostbar = $('<div id="ghostbar">', {
css: {
top: main.offset().top,
left: main.offset().left
}
}).prependTo('body');
$(document).mousemove(function(e){
9 years ago
ghostbar.css("left",e.pageX+2);
});
});
var $body = $('body');
function setEditorSize (delta) {
$('#righthand-panel').css("width", delta);
$('#editor').css("right", delta);
onResize();
}
9 years ago
$(document).mouseup(function(e){
if (dragging) {
var delta = $body.width() - e.pageX+2;
$('#ghostbar').remove();
$(document).unbind('mousemove');
dragging = false;
setEditorSize(delta);
9 years ago
window.localStorage.setItem(EDITOR_SIZE_CACHE_KEY, delta);
}
});
// set cached defaults
9 years ago
var cachedSize = window.localStorage.getItem(EDITOR_SIZE_CACHE_KEY);
if (cachedSize) setEditorSize(cachedSize);
// ----------------- editor resize ---------------
function onResize() {
editor.resize();
session.setUseWrapMode(document.querySelector('#editorWrap').checked);
if(session.getUseWrapMode()) {
var characterWidth = editor.renderer.characterWidth;
var contentWidth = editor.container.ownerDocument.getElementsByClassName("ace_scroller")[0].clientWidth;
if(contentWidth > 0) {
session.setWrapLimit(parseInt(contentWidth / characterWidth, 10));
}
}
}
window.onresize = onResize;
onResize();
9 years ago
document.querySelector('#editor').addEventListener('change', onResize);
document.querySelector('#editorWrap').addEventListener('change', onResize);
// ----------------- compiler ----------------------
var compileJSON;
var previousInput = '';
var sourceAnnotations = [];
var compile = function() {
editor.getSession().clearAnnotations();
sourceAnnotations = [];
editor.getSession().removeMarker(errMarkerId);
$('#output').empty();
var input = editor.getValue();
9 years ago
window.localStorage.setItem(SOL_CACHE_FILE, input);
9 years ago
var inputIncludingImports = includeLocalImports(input);
var optimize = document.querySelector('#optimize').checked;
try {
var data = $.parseJSON(compileJSON(inputIncludingImports, optimize ? 1 : 0));
} catch (exception) {
renderError("Uncaught JavaScript Exception:\n" + exception);
return;
}
var noFatalErrors = true; // ie warnings are ok
if (data['error'] !== undefined) {
renderError(data['error']);
if (errortype(data['error']) !== 'warning') noFatalErrors = false;
}
if (data['errors'] != undefined) {
$.each(data['errors'], function(i, err) {
renderError(err);
if (errortype(err) !== 'warning') noFatalErrors = false;
});
}
if (noFatalErrors) renderContracts(data, input);
}
var compileTimeout = null;
var onChange = function() {
var input = editor.getValue();
if (input === "") {
window.localStorage.setItem(SOL_CACHE_FILE, '');
return;
}
if (input === previousInput)
return;
previousInput = input;
if (compileTimeout) window.clearTimeout(compileTimeout);
compileTimeout = window.setTimeout(compile, 300);
};
var onCompilerLoaded = function() {
compileJSON = Module.cwrap("compileJSON", "string", ["string", "number"]);
$('#version').text(Module.cwrap("version", "string", [])());
previousInput = '';
onChange();
};
9 years ago
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]) ));
9 years ago
input = input.replace(matches[i], imported);
}
return input;
}
if (Module)
onCompilerLoaded();
editor.getSession().on('change', onChange);
document.querySelector('#optimize').addEventListener('change', compile);
// ----------------- compiler output renderer ----------------------
var detailsOpen = {};
function errortype(message) {
return message.match(/^[0-9:]* Warning: /) ? 'warning' : 'error';
}
var renderError = function(message) {
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 );
var err = message.match(/^:([0-9]*):([0-9]*)/);
if (err && err.length) {
9 years ago
var errLine = parseInt(err[1], 10) - 1;
var errCol = err[2] ? parseInt(err[2], 10) : 0;
sourceAnnotations[sourceAnnotations.length] = {
row: errLine,
column: errCol,
text: message,
type: type
};
editor.getSession().setAnnotations(sourceAnnotations);
$error.click(function(ev){
editor.focus();
editor.gotoLine(errLine + 1, errCol - 1, true);
});
$error.find('.close').click(function(ev){
ev.preventDefault();
$error.remove();
return false;
});
}
};
var gethDeploy = function(contractName, interface, bytecode){
var code = "";
var funABI = getConstructorInterface($.parseJSON(interface));
$.each(funABI.inputs, function(i, inp) {
9 years ago
code += "var " + inp.name + " = /* var of type " + inp.type + " here */ ;\n";
});
code += "var " + contractName + "Contract = web3.eth.contract(" + interface.replace("\n","") + ");"
9 years ago
+"\nvar " + contractName + " = " + contractName + "Contract.new(";
$.each(funABI.inputs, function(i, inp) {
9 years ago
code += "\n " + inp.name + ",";
});
code += "\n {"+
"\n from: web3.eth.accounts[0], "+
"\n data: '"+bytecode+"', "+
"\n gas: 3000000"+
"\n }, function(e, contract){"+
"\n if (typeof contract.address != 'undefined') {"+
"\n console.log(e, contract);"+
"\n console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);" +
"\n }" +
"\n })";
return code;
};
var combined = function(contractName, interface, bytecode){
9 years ago
return JSON.stringify([{name: contractName, interface: interface, bytecode: bytecode}]);
};
var renderContracts = function(data, source) {
var udappContracts = [];
for (var contractName in data.contracts) {
var contract = data.contracts[contractName];
udappContracts.push({
name: contractName,
interface: contract['interface'],
bytecode: contract.bytecode
});
}
var dapp = new UniversalDApp(udappContracts, {
vm: executionContext === 'vm',
removable: false,
removable_instances: true,
renderOutputModifier: function(contractName, $contractOutput) {
var contract = data.contracts[contractName];
return $contractOutput
.append(textRow('Bytecode', contract.bytecode))
.append(textRow('Interface', contract['interface']))
.append(textRow('Web3 deploy', gethDeploy(contractName.toLowerCase(),contract['interface'],contract.bytecode), 'deploy'))
.append(textRow('uDApp', combined(contractName,contract['interface'],contract.bytecode), 'deploy'))
.append(getDetails(contract, source, contractName));
}});
var $contractOutput = dapp.render();
if (executionContext === 'vm')
$('#txorigin').text('0x' + dapp.address.toString('hex'));
else
web3.eth.getAccounts(function(err, accounts) {
if (err)
renderError(err.message);
$('#txorigin').text(accounts[0]);
});
$contractOutput.find('.title').click(function(ev){
console.log($(this));
$(this).closest('.contract').toggleClass('hide');
});
$('#output').append( $contractOutput );
9 years ago
$('.col2 input,textarea').click(function() { this.select(); });
};
var tableRowItems = function(first, second, cls) {
return $('<div class="row"/>')
.addClass(cls)
.append($('<div class="col1">').append(first))
.append($('<div class="col2">').append(second));
};
var tableRow = function(description, data) {
return tableRowItems(
$('<span/>').text(description),
$('<input readonly="readonly"/>').val(data));
};
var textRow = function(description, data, cls) {
return tableRowItems(
$('<strong/>').text(description),
$('<textarea readonly="readonly" class="gethDeployText"/>').val(data),
cls);
};
var getDetails = function(contract, source, contractName) {
var button = $('<button>Toggle Details</button>');
var details = $('<div style="display: none;"/>')
.append(tableRow('Solidity Interface', contract.solidity_interface))
.append(tableRow('Opcodes', contract.opcodes));
var funHashes = '';
for (var fun in contract.functionHashes)
funHashes += contract.functionHashes[fun] + ' ' + fun + '\n';
details.append($('<span class="col1">Functions</span>'));
details.append($('<pre/>').text(funHashes));
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));
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>
9 years ago
</body>
</html>