var $ = require('jquery'); var UniversalDApp = require('./universal-dapp.js'); var web3 = require('./web3-adapter.js'); var ace = require('brace'); require('./mode-solidity.js'); // The event listener needs to be registered as early as possible, because the // parent will send the message upon the "load" event. var filesToLoad = null; var loadFilesCallback = function(files) { filesToLoad = files; }; // will be replaced later window.addEventListener("message", function(ev) { if (typeof ev.data == typeof [] && ev.data[0] === "loadFiles") { loadFilesCallback(ev.data[1]); } }, false); var Base64 = require('js-base64').Base64; var run = function() { // ------------------ query params (hash) ---------------- 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); } function syncQueryParams() { $('#optimize').attr( 'checked', (getQueryParams().optimize == "true") ); } window.onhashchange = syncQueryParams; syncQueryParams(); // ------------------ gist load ---------------- function getGistId(str) { var idr = /[0-9A-Fa-f]{8,}/; var match = idr.exec(str); return match ? match[0] : null; } function loadFiles(files) { for (var f in files) { var key = fileKey(f); var content = files[f].content; if (key in window.localStorage && window.localStorage[key] != content) { var count = ''; var otherKey = key + count; while ((key + count) in window.localStorage) count = count - 1; window.localStorage[key + count] = window.localStorage[key]; } window.localStorage[key] = content; } SOL_CACHE_FILE = fileKey(Object.keys(files)[0]); updateFiles(); } var queryParams = getQueryParams(); var loadingFromGist = false; if (typeof queryParams['gist'] != undefined) { var gistId; if (queryParams['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 = queryParams['gist']; loadingFromGist = !!gistId; } if (loadingFromGist) $.ajax({ url: 'https://api.github.com/gists/'+gistId, jsonp: 'callback', dataType: 'jsonp', success: function(response){ if (response.data) { if (!response.data.files) { alert( "Gist load error: " + response.data.message ); return; } loadFiles(response.data.files); } } }); } loadFilesCallback = function(files) { loadFiles(files); }; if (filesToLoad !== null) loadFiles(filesToLoad); // ----------------- storage -------------------- function syncStorage() { 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(SOL_CACHE_FILE_PREFIX) !== 0) continue; count++; check(y) } } window.syncStorage = syncStorage; syncStorage() // ----------------- 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 sessions = {}; var Range = ace.acequire('ace/range').Range; var errMarkerId = null; var untitledCount = ''; if (!getFiles().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 = getFiles()[0]; var files = getFiles(); for (var x in files) { sessions[files[x]] = newEditorSession(files[x]) } editor.setSession( sessions[SOL_CACHE_FILE] ); editor.resize(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; } // ----------------- tabbed menu ------------------- $('#options li').click(function(ev){ var $el = $(this); var match = /[a-z]+View/.exec( $el.get(0).className ); if (!match) return; var cls = match[0]; if (!$el.hasClass('active')) { $el.parent().find('li').removeClass('active'); $('#optionViews').attr('class', '').addClass(cls); $el.addClass('active'); } else { $el.removeClass('active'); $('#optionViews').removeClass(cls); } }); // ----------------- execution context ------------- var $vmToggle = $('#vm'); var $web3Toggle = $('#web3'); var $web3endpoint = $('#web3Endpoint'); if (web3.providers && web3.currentProvider instanceof web3.providers.IpcProvider) $web3endpoint.val('ipc'); var executionContext = 'vm'; $vmToggle.get(0).checked = true; $vmToggle.on('change', executionContextChange ); $web3Toggle.on('change', executionContextChange ); $web3endpoint.on('change', function() { var endpoint = $web3endpoint.val(); if (endpoint == 'ipc') web3.setProvider(new web3.providers.IpcProvider()); else web3.setProvider(new web3.providers.HttpProvider(endpoint)); compile(); }); 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(); } // ------------------ gist publish -------------- var packageFiles = function() { var files = {}; var filesArr = getFiles(); for (var f in filesArr) { files[fileNameFromKey(filesArr[f])] = { content: localStorage[filesArr[f]] }; } return files; }; $('#gist').click(function(){ if (confirm("Are you sure you want to publish all your files anonymously as a public gist on github.com?")) { var files = packageFiles(); var description = "Created using browser-solidity: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://ethereum.github.io/browser-solidity/#version=" + getQueryParams().version + "&optimize="+ getQueryParams().optimize +"&gist="; $.ajax({ url: 'https://api.github.com/gists', type: 'POST', data: JSON.stringify({ description: description, public: true, files: files }) }).done(function(response) { 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, '_blank' ); } }); } }); $('#copyOver').click(function(){ var target = prompt( "To which other browser-solidity instance do you want to copy over all files?", "https://ethereum.github.io/browser-solidity/" ); if (target === null) return; var files = packageFiles(); var iframe = $('