').append(second));
- };
- var tableRow = function(description, data) {
- return tableRowItems(
- $('
').text(description),
- $('
').val(data));
- };
- var textRow = function(description, data, cls) {
- return tableRowItems(
- $('
').text(description),
- $('
').val(data),
- cls);
- };
- var getDetails = function(contract, source, contractName) {
- var button = $('
');
- var details = $('
')
- .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($('
Functions'));
- details.append($('
').text(funHashes));
- details.append($('
Gas Estimates'));
- details.append($('
').text(formatGasEstimates(contract.gasEstimates)));
- if (contract.runtimeBytecode && contract.runtimeBytecode.length > 0)
- details.append(tableRow('Runtime Bytecode', contract.runtimeBytecode));
- if (contract.assembly !== null)
- {
- details.append($('
Assembly'));
- var assembly = $('
').text(formatAssemblyText(contract.assembly, '', source));
- details.append(assembly);
- }
- button.click(function() { detailsOpen[contractName] = !detailsOpen[contractName]; details.toggle(); });
- if (detailsOpen[contractName])
- details.show();
- return $('
').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;
- };
-
- syncStorage();
-
+ storageHandler.sync();
};
module.exports = {
diff --git a/src/app/compiler.js b/src/app/compiler.js
new file mode 100644
index 0000000000..6d6fc42ed6
--- /dev/null
+++ b/src/app/compiler.js
@@ -0,0 +1,208 @@
+var queryParams = require('./query-params');
+var utils = require('./utils');
+var Renderer = require('./renderer');
+
+var Base64 = require('js-base64').Base64;
+
+function Compiler(web3, editor, handleGithubCall, outputField, hidingRHP, updateFiles) {
+ var renderer = new Renderer(web3, editor, this, updateFiles);
+
+ var compileJSON;
+ var compilerAcceptsMultipleFiles;
+
+ var previousInput = '';
+ var sourceAnnotations = [];
+
+ var cachedRemoteFiles = {};
+ var worker = null;
+
+ var compileTimeout = null;
+
+ function onChange() {
+ var input = editor.getValue();
+ if (input === "") {
+ editor.setCacheFileContent('');
+ return;
+ }
+ if (input === previousInput)
+ return;
+ previousInput = input;
+ if (compileTimeout) window.clearTimeout(compileTimeout);
+ compileTimeout = window.setTimeout(compile, 300);
+ }
+
+ editor.onChangeSetup(onChange);
+
+ var compile = function(missingInputs) {
+ editor.clearAnnotations();
+ sourceAnnotations = [];
+ outputField.empty();
+ var input = editor.getValue();
+ editor.setCacheFileContent(input)
+
+ var files = {};
+ files[editor.getCacheFile()] = input;
+ gatherImports(files, missingInputs, function(input, error) {
+ outputField.empty();
+ if (input === null) {
+ renderer.error(error);
+ } else {
+ var optimize = queryParams.get().optimize;
+ compileJSON(input, optimize ? 1 : 0);
+ }
+ });
+ };
+ this.compile = compile;
+
+ this.addAnnotation = function(annotation) {
+ sourceAnnotations[sourceAnnotations.length] = annotation;
+ editor.setAnnotations(sourceAnnotations);
+ };
+
+ this.setCompileJSON = function() {
+ compileJSON = function(source, optimize) { compilationFinished('{}'); };
+ };
+
+ function onCompilerLoaded(setVersionText) {
+ if (worker === null) {
+ var compile;
+ var missingInputs = [];
+ if ('_compileJSONCallback' in Module) {
+ compilerAcceptsMultipleFiles = true;
+ var missingInputsCallback = Module.Runtime.addFunction(function(path, contents, error) {
+ missingInputs.push(Module.Pointer_stringify(path));
+ });
+ var compileInternal = Module.cwrap("compileJSONCallback", "string", ["string", "number", "number"]);
+ compile = function(input, optimize) {
+ missingInputs.length = 0;
+ return compileInternal(input, optimize, missingInputsCallback);
+ };
+ } else if ('_compileJSONMulti' in Module) {
+ compilerAcceptsMultipleFiles = true;
+ compile = Module.cwrap("compileJSONMulti", "string", ["string", "number"]);
+ } else {
+ compilerAcceptsMultipleFiles = false;
+ compile = Module.cwrap("compileJSON", "string", ["string", "number"]);
+ }
+ compileJSON = function(source, optimize, cb) {
+ try {
+ var result = compile(source, optimize);
+ } catch (exception) {
+ result = JSON.stringify({error: 'Uncaught JavaScript exception:\n' + exception});
+ }
+ compilationFinished(result, missingInputs);
+ };
+ setVersionText(Module.cwrap("version", "string", [])());
+ }
+ previousInput = '';
+ onChange();
+ };
+ this.onCompilerLoaded = onCompilerLoaded;
+
+ function compilationFinished(result, missingInputs) {
+ var data;
+ var noFatalErrors = true; // ie warnings are ok
+
+ try {
+ data = JSON.parse(result);
+ } catch (exception) {
+ renderer.error('Invalid JSON output from the compiler: ' + exception);
+ return;
+ }
+
+ if (data['error'] !== undefined) {
+ renderer.error(data['error']);
+ if (utils.errortype(data['error']) !== 'warning') noFatalErrors = false;
+ }
+ if (data['errors'] != undefined) {
+ data['errors'].forEach(function(err) {
+ renderer.error(err);
+ if (utils.errortype(err) !== 'warning') noFatalErrors = false;
+ });
+ }
+
+ if (missingInputs !== undefined && missingInputs.length > 0)
+ compile(missingInputs);
+ else if (noFatalErrors && !hidingRHP())
+ renderer.contracts(data, editor.getValue());
+ }
+
+ this.initializeWorker = function(version, setVersionText) {
+ if (worker !== null)
+ worker.terminate();
+ worker = new Worker('worker.js');
+ worker.addEventListener('message', function(msg) {
+ var data = msg.data;
+ switch (data.cmd) {
+ case 'versionLoaded':
+ setVersionText(data.data);
+ compilerAcceptsMultipleFiles = !!data.acceptsMultipleFiles;
+ onCompilerLoaded(setVersionText);
+ break;
+ case 'compiled':
+ compilationFinished(data.data, data.missingInputs);
+ break;
+ };
+ });
+ worker.onerror = function(msg) { console.log(msg.data); };
+ worker.addEventListener('error', function(msg) { console.log(msg.data); });
+ compileJSON = function(source, optimize) {
+ worker.postMessage({cmd: 'compile', source: source, optimize: optimize});
+ };
+ worker.postMessage({cmd: 'loadVersion', data: 'https://ethereum.github.io/solc-bin/bin/' + version});
+ };
+
+ function gatherImports(files, importHints, cb) {
+ importHints = importHints || [];
+ if (!compilerAcceptsMultipleFiles)
+ {
+ cb(files[editor.getCacheFile()]);
+ return;
+ }
+ var importRegex = /^\s*import\s*[\'\"]([^\'\"]+)[\'\"];/g;
+ var reloop = false;
+ do {
+ reloop = false;
+ for (var fileName in files) {
+ var match;
+ while (match = importRegex.exec(files[fileName]))
+ importHints.push(match[1]);
+ }
+ while (importHints.length > 0) {
+ var m = importHints.pop();
+ if (m in files) continue;
+ if (editor.hasFile(m)) {
+ files[m] = window.localStorage[utils.fileKey(m)];
+ reloop = true;
+ } else if (m.startsWith('./') && editor.hasFile(m.slice(2))) {
+ files[m] = window.localStorage[utils.fileKey(m.slice(2))];
+ reloop = true;
+ } else if (m in cachedRemoteFiles) {
+ files[m] = cachedRemoteFiles[m];
+ reloop = true;
+ } else if (githubMatch = /^(https?:\/\/)?(www.)?github.com\/([^\/]*\/[^\/]*)\/(.*)/.exec(m)) {
+ handleGithubCall(function(result) {
+ if ('content' in result)
+ {
+ var content = Base64.decode(result.content);
+ cachedRemoteFiles[m] = content;
+ files[m] = content;
+ gatherImports(files, importHints, cb);
+ }
+ else
+ cb(null, "Unable to import \"" + m + "\"");
+ }).fail(function(){
+ cb(null, "Unable to import \"" + m + "\"");
+ });
+ return;
+ } else {
+ cb(null, "Unable to import \"" + m + "\"");
+ return;
+ }
+ }
+ } while (reloop);
+ cb(JSON.stringify({'sources':files}));
+ }
+}
+
+module.exports = Compiler
diff --git a/src/app/editor.js b/src/app/editor.js
new file mode 100644
index 0000000000..0f18c79a4b
--- /dev/null
+++ b/src/app/editor.js
@@ -0,0 +1,149 @@
+var utils = require('./utils');
+
+var ace = require('brace');
+require('../mode-solidity.js');
+
+function Editor(loadingFromGist) {
+
+ this.newFile = function() {
+ untitledCount = '';
+ while (window.localStorage[SOL_CACHE_UNTITLED + untitledCount])
+ untitledCount = (untitledCount - 0) + 1;
+ SOL_CACHE_FILE = SOL_CACHE_UNTITLED + untitledCount;
+ sessions[SOL_CACHE_FILE] = null;
+ this.setCacheFileContent('');
+ };
+
+ this.setCacheFileContent = function(content) {
+ window.localStorage.setItem(SOL_CACHE_FILE, content);
+ };
+
+ this.setCacheFile = function(cacheFile) {
+ SOL_CACHE_FILE = utils.fileKey(cacheFile);
+ };
+
+ this.getCacheFile = function() {
+ return utils.fileNameFromKey(SOL_CACHE_FILE);
+ };
+
+ this.cacheFileIsPresent = function() {
+ return !!SOL_CACHE_FILE;
+ };
+
+ this.setNextFile = function(fileKey) {
+ var index = this.getFiles().indexOf( fileKey );
+ this.setCacheFile(this.getFiles()[ Math.max(0, index - 1)]);
+ };
+
+ this.resetSession = function() {
+ editor.setSession( sessions[SOL_CACHE_FILE] );
+ editor.focus();
+ };
+
+ this.hasFile = function(name) {
+ return this.getFiles().indexOf(utils.fileKey(name)) !== -1
+ };
+
+ this.getFiles = function() {
+ var files = [];
+ for (var f in localStorage ) {
+ if (f.indexOf( utils.getCacheFilePrefix(), 0 ) === 0) {
+ files.push(f);
+ if (!sessions[f]) sessions[f] = newEditorSession(f);
+ }
+ }
+ return files;
+ }
+
+ this.packageFiles = function() {
+ var files = {};
+ var filesArr = this.getFiles();
+
+ for (var f in filesArr) {
+ files[utils.fileNameFromKey(filesArr[f])] = {
+ content: localStorage[filesArr[f]]
+ };
+ }
+ return files;
+ };
+
+ this.resize = function() {
+ editor.resize();
+ var session = editor.getSession();
+ 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));
+ }
+ }
+ };
+
+ this.getValue = function() {
+ return editor.getValue();
+ };
+
+ this.clearAnnotations = function() {
+ editor.getSession().clearAnnotations();
+ };
+
+ this.setAnnotations = function(sourceAnnotations) {
+ editor.getSession().setAnnotations(sourceAnnotations);
+ };
+
+ this.onChangeSetup = function(onChange) {
+ editor.getSession().on('change', onChange);
+ editor.on('changeSession', function(){
+ editor.getSession().on('change', onChange);
+ onChange();
+ })
+ };
+
+ this.handleErrorClick = function(errLine, errCol) {
+ editor.focus();
+ editor.gotoLine(errLine + 1, errCol - 1, true);
+ };
+
+ function newEditorSession(filekey) {
+ var s = new ace.EditSession(window.localStorage[filekey], "ace/mode/javascript")
+ s.setUndoManager(new ace.UndoManager());
+ s.setTabSize(4);
+ s.setUseSoftTabs(true);
+ sessions[filekey] = s;
+ return s;
+ }
+
+ function setupStuff(files) {
+ var untitledCount = '';
+ if (!files.length || window.localStorage['sol-cache']) {
+ if(loadingFromGist) return;
+ // 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 = files[0];
+
+ for (var x in files) {
+ sessions[files[x]] = newEditorSession(files[x])
+ }
+
+ editor.setSession( sessions[SOL_CACHE_FILE] );
+ editor.resize(true);
+ }
+
+ var SOL_CACHE_UNTITLED = utils.getCacheFilePrefix() + 'Untitled';
+ var SOL_CACHE_FILE = null;
+
+ var editor = ace.edit("input");
+ var sessions = {};
+
+ setupStuff(this.getFiles());
+}
+
+module.exports = Editor;
diff --git a/src/app/gist-handler.js b/src/app/gist-handler.js
new file mode 100644
index 0000000000..486b2dce6e
--- /dev/null
+++ b/src/app/gist-handler.js
@@ -0,0 +1,31 @@
+var queryParams = require('./query-params');
+
+function handleLoad(cb) {
+ var params = queryParams.get();
+ var loadingFromGist = false;
+ if (typeof params['gist'] != undefined) {
+ var gistId;
+ if (params['gist'] === '') {
+ var str = prompt("Enter the URL or ID of the Gist you would like to load.");
+ if (str !== '') {
+ gistId = getGistId( str );
+ loadingFromGist = !!gistId;
+ }
+ } else {
+ gistId = params['gist'];
+ loadingFromGist = !!gistId;
+ }
+ if (loadingFromGist) cb(gistId);
+ }
+ return loadingFromGist;
+}
+
+function getGistId(str) {
+ var idr = /[0-9A-Fa-f]{8,}/;
+ var match = idr.exec(str);
+ return match ? match[0] : null;
+}
+
+module.exports = {
+ handleLoad: handleLoad
+};
diff --git a/src/app/query-params.js b/src/app/query-params.js
new file mode 100644
index 0000000000..4789b965db
--- /dev/null
+++ b/src/app/query-params.js
@@ -0,0 +1,36 @@
+function getQueryParams() {
+ var qs = window.location.hash.substr(1);
+
+ if (window.location.search.length > 0) {
+ // use legacy query params instead of hash
+ window.location.hash = window.location.search.substr(1);
+ window.location.search = "";
+ }
+
+ var params = {};
+ var parts = qs.split("&");
+ for (var x in parts) {
+ var keyValue = parts[x].split("=");
+ if (keyValue[0] !== "") params[keyValue[0]] = keyValue[1];
+ }
+ return params;
+}
+
+function updateQueryParams(params) {
+ var currentParams = getQueryParams();
+ var keys = Object.keys(params);
+ for (var x in keys) {
+ currentParams[keys[x]] = params[keys[x]];
+ }
+ var queryString = "#";
+ var updatedKeys = Object.keys(currentParams);
+ for( var y in updatedKeys) {
+ queryString += updatedKeys[y] + "=" + currentParams[updatedKeys[y]] + "&";
+ }
+ window.location.hash = queryString.slice(0, -1);
+}
+
+module.exports = {
+ get: getQueryParams,
+ update: updateQueryParams,
+};
\ No newline at end of file
diff --git a/src/app/renderer.js b/src/app/renderer.js
new file mode 100644
index 0000000000..90640a9286
--- /dev/null
+++ b/src/app/renderer.js
@@ -0,0 +1,269 @@
+var $ = require('jquery');
+
+var UniversalDApp = require('../universal-dapp.js');
+
+var utils = require('./utils');
+
+function Renderer(web3, editor, compiler, updateFiles) {
+
+ var detailsOpen = {};
+ var executionContext = 'vm';
+
+ // Forcing all of this setup into its own scope.
+ (function(){
+ 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;
+ setProviderFromEndpoint();
+ }
+ compiler.compile();
+ }
+
+ function setProviderFromEndpoint() {
+ var endpoint = $web3endpoint.val();
+ if (endpoint == 'ipc')
+ web3.setProvider(new web3.providers.IpcProvider());
+ else
+ web3.setProvider(new web3.providers.HttpProvider(endpoint));
+ }
+
+ var $vmToggle = $('#vm');
+ var $web3Toggle = $('#web3');
+ var $web3endpoint = $('#web3Endpoint');
+
+ if (web3.providers && web3.currentProvider instanceof web3.providers.IpcProvider)
+ $web3endpoint.val('ipc');
+
+ $vmToggle.get(0).checked = true;
+
+ $vmToggle.on('change', executionContextChange );
+ $web3Toggle.on('change', executionContextChange );
+ $web3endpoint.on('change', function() {
+ setProviderFromEndpoint();
+ if (executionContext == 'web3') compiler.compile();
+ });
+ })();
+
+ function renderError(message) {
+ var type = utils.errortype(message);
+ var $pre = $("
").text(message);
+ var $error = $('
').prepend($pre);
+ $('#output').append( $error );
+ var err = message.match(/^([^:]*):([0-9]*):(([0-9]*):)? /);
+ if (err) {
+ var errFile = err[1];
+ var errLine = parseInt(err[2], 10) - 1;
+ var errCol = err[4] ? parseInt(err[4], 10) : 0;
+ if (errFile == '' || errFile == editor.getCacheFile()) {
+ compiler.addAnnotation({
+ row: errLine,
+ column: errCol,
+ text: message,
+ type: type
+ });
+ }
+ $error.click(function(ev){
+ if (errFile != '' && errFile != editor.getCacheFile() && editor.hasFile(errFile)) {
+ // Switch to file
+ editor.setCacheFile(errFile);
+ updateFiles();
+ //@TODO could show some error icon in files with errors
+ }
+ editor.handleErrorClick(errLine, errCol);
+ });
+ $error.find('.close').click(function(ev){
+ ev.preventDefault();
+ $error.remove();
+ return false;
+ });
+ }
+ };
+ this.error = renderError;
+
+ var combined = function(contractName, jsonInterface, bytecode){
+ return JSON.stringify([{name: contractName, interface: jsonInterface, bytecode: bytecode}]);
+ };
+
+ function renderContracts(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,
+ getAddress: function(){ return $('#txorigin').val(); },
+ getValue: function(){
+ var comp = $('#value').val().split(' ');
+ return web3.toWei(comp[0], comp.slice(1).join(' '));
+ },
+ 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();
+
+ $txOrigin = $('#txorigin');
+
+ function renderAccounts(err, accounts) {
+ if (err)
+ renderError(err.message);
+ if (accounts && accounts[0]){
+ $txOrigin.empty();
+ for( var a in accounts) { $txOrigin.append($('
').val(accounts[a]).text(accounts[a])); }
+ $txOrigin.val(accounts[0]);
+ } else $txOrigin.val('unknown');
+ }
+
+ dapp.getAccounts(renderAccounts);
+
+ $contractOutput.find('.title').click(function(ev){ $(this).closest('.contract').toggleClass('hide'); });
+ $('#output').append( $contractOutput );
+ $('.col2 input,textarea').click(function() { this.select(); });
+ };
+ this.contracts = renderContracts;
+
+ var tableRowItems = function(first, second, cls) {
+ return $('
')
+ .addClass(cls)
+ .append($('
').append(first))
+ .append($('
').append(second));
+ };
+ var tableRow = function(description, data) {
+ return tableRowItems(
+ $('
').text(description),
+ $('
').val(data));
+ };
+ var textRow = function(description, data, cls) {
+ return tableRowItems(
+ $('
').text(description),
+ $('
').val(data),
+ cls);
+ };
+
+ var getDetails = function(contract, source, contractName) {
+ var button = $('
');
+ var details = $('
')
+ .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($('
Functions'));
+ details.append($('
').text(funHashes));
+ details.append($('
Gas Estimates'));
+ details.append($('
').text(formatGasEstimates(contract.gasEstimates)));
+ if (contract.runtimeBytecode && contract.runtimeBytecode.length > 0)
+ details.append(tableRow('Runtime Bytecode', contract.runtimeBytecode));
+ if (contract.assembly !== null)
+ {
+ details.append($('
Assembly'));
+ var assembly = $('
').text(formatAssemblyText(contract.assembly, '', source));
+ details.append(assembly);
+ }
+ button.click(function() { detailsOpen[contractName] = !detailsOpen[contractName]; details.toggle(); });
+ if (detailsOpen[contractName])
+ details.show();
+ return $('
').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;
+ };
+
+ function gethDeploy(contractName, jsonInterface, bytecode){
+ var code = "";
+ var funABI = getConstructorInterface(JSON.parse(jsonInterface));
+
+ funABI.inputs.forEach(function(inp) {
+ code += "var " + inp.name + " = /* var of type " + inp.type + " here */ ;\n";
+ });
+
+ code += "var " + contractName + "Contract = web3.eth.contract(" + jsonInterface.replace("\n","") + ");"
+ +"\nvar " + contractName + " = " + contractName + "Contract.new(";
+
+ funABI.inputs.forEach(function(inp) {
+ code += "\n " + inp.name + ",";
+ });
+
+ code += "\n {"+
+ "\n from: web3.eth.accounts[0], "+
+ "\n data: '"+bytecode+"', "+
+ "\n gas: 3000000"+
+ "\n }, function(e, contract){"+
+ "\n console.log(e, contract);"+
+ "\n if (typeof contract.address != 'undefined') {"+
+ "\n console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);" +
+ "\n }" +
+ "\n })";
+
+
+ return code;
+ }
+
+ function getConstructorInterface(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;
+ }
+
+}
+
+module.exports = Renderer;
diff --git a/src/app/storage-handler.js b/src/app/storage-handler.js
new file mode 100644
index 0000000000..de78d205f9
--- /dev/null
+++ b/src/app/storage-handler.js
@@ -0,0 +1,42 @@
+var utils = require('./utils');
+
+function StorageHandler(updateFiles) {
+
+ this.sync = function() {
+
+ if (typeof chrome === 'undefined' || !chrome || !chrome.storage || !chrome.storage.sync) return;
+
+ var obj = {};
+ var done = false;
+ var count = 0
+ var dont = 0;
+
+ function check(key){
+ chrome.storage.sync.get( key, function(resp){
+ console.log("comparing to cloud", key, resp);
+ if (typeof resp[key] != 'undefined' && obj[key] !== resp[key] && confirm("Overwrite '" + fileNameFromKey(key) + "'? Click Ok to overwrite local file with file from cloud. Cancel will push your local file to the cloud.")) {
+ console.log("Overwriting", key );
+ localStorage.setItem( key, resp[key] );
+ updateFiles();
+ } else {
+ console.log( "add to obj", obj, key);
+ obj[key] = localStorage[key];
+ }
+ done++;
+ if (done >= count) chrome.storage.sync.set( obj, function(){
+ console.log( "updated cloud files with: ", obj, this, arguments);
+ })
+ })
+ }
+
+ for (var y in window.localStorage) {
+ console.log("checking", y);
+ obj[y] = window.localStorage.getItem(y);
+ if (y.indexOf(utils.getCacheFilePrefix()) !== 0) continue;
+ count++;
+ check(y);
+ }
+ };
+}
+
+module.exports = StorageHandler;
diff --git a/src/app/utils.js b/src/app/utils.js
new file mode 100644
index 0000000000..732935272d
--- /dev/null
+++ b/src/app/utils.js
@@ -0,0 +1,24 @@
+var SOL_CACHE_FILE_PREFIX = 'sol-cache-file-';
+
+function getCacheFilePrefix() {
+ return SOL_CACHE_FILE_PREFIX;
+}
+
+function fileKey( name ) {
+ return getCacheFilePrefix() + name;
+}
+
+function fileNameFromKey(key) {
+ return key.replace( getCacheFilePrefix(), '' );
+}
+
+function errortype(message) {
+ return message.match(/^.*:[0-9]*:[0-9]* Warning: /) ? 'warning' : 'error';
+}
+
+module.exports = {
+ getCacheFilePrefix: getCacheFilePrefix,
+ fileKey: fileKey,
+ fileNameFromKey: fileNameFromKey,
+ errortype: errortype
+};
diff --git a/src/universal-dapp.js b/src/universal-dapp.js
index a659447f79..c1bb5d493d 100644
--- a/src/universal-dapp.js
+++ b/src/universal-dapp.js
@@ -192,7 +192,6 @@ UniversalDApp.prototype.getInstanceInterface = function (contract, address, $tar
return;
$event = $('
');
-
var $close = $('
');
$close.click( function(){ $event.remove(); } );