From a9b2e59824a8888691fa47fad14dbf980361023c Mon Sep 17 00:00:00 2001 From: serapath Date: Wed, 11 Apr 2018 23:36:51 +0100 Subject: [PATCH 1/3] refactor settings tab --- src/app/tabs/settings-tab.js | 489 ++++++++++++++++++++--------------- 1 file changed, 279 insertions(+), 210 deletions(-) diff --git a/src/app/tabs/settings-tab.js b/src/app/tabs/settings-tab.js index 8b3bd1fbf3..39d7876172 100644 --- a/src/app/tabs/settings-tab.js +++ b/src/app/tabs/settings-tab.js @@ -1,74 +1,123 @@ -/* global Option, Worker */ -var $ = require('jquery') +/* global Worker */ var yo = require('yo-yo') -var request = require('request') -var QueryParams = require('../../lib/query-params') +var csjs = require('csjs-inject') +var minixhr = require('minixhr') var remixLib = require('remix-lib') -var Storage = remixLib.Storage -var styleGuide = require('../ui/styles-guide/theme-chooser') +var QueryParams = require('../../lib/query-params') var helper = require('../../lib/helper') var modal = require('../ui/modal-dialog-custom') var tooltip = require('../ui/tooltip') var copyToClipboard = require('../ui/copy-to-clipboard') +var styleGuide = require('../ui/styles-guide/theme-chooser') -var css = require('./styles/settings-tab-styles') - -function SettingsTab (appAPI = {}, appEvents = {}, opts = {}) { - var queryParams = new QueryParams() - - var optionVM = yo`` - var personal = yo`` - var warnText = `Transaction sent over Web3 will use the web3.personal API - be sure the endpoint is opened before enabling it. - This mode allows to provide the passphrase in the Remix interface without having to unlock the account. - Although this is very convenient, you should completely trust the backend you are connected to (Geth, Parity, ...). - It is not recommended (and also most likely not relevant) to use this mode with an injected provider (Mist, Metamask, ...) or with JavaScript VM. - Remix never persist any passphrase.` - var warnPersonalMode = yo`` - - // Gist settings - var gistAccessToken = yo`` - var token = appAPI.config.get('settings/gist-access-token') - if (token) gistAccessToken.value = token - var gistAddToken = yo` { appAPI.config.set('settings/gist-access-token', gistAccessToken.value); tooltip('Access token saved') }} value="Save" type="button">` - var gistRemoveToken = yo` { gistAccessToken.value = ''; appAPI.config.set('settings/gist-access-token', ''); tooltip('Access token removed') }} value="Remove" type="button">` - - var el = yo` -
+var styles = styleGuide.chooser() +var Storage = remixLib.Storage +var EventManager = remixLib.EventManager + +module.exports = class SettingsTab { + constructor (api = {}, events = {}, opts = {}) { + const self = this + self._opts = opts + self._api = api + self._events = events + self._components = {} + self._view = { /* eslint-disable */ + el: null, + optionVM: null, personal: null, optimize: null, warnPersonalMode: null, + pluginInput: null, versionSelector: null, version: null, + theme: { dark: null, light: null }, + config: { + solidity: null, general: null, themes: null, + plugin: null, remixd: null, localremixd: null + } + } /* eslint-enable */ + self.data = { allversions: null, selectedVersion: null } + self.event = new EventManager() + self._components.queryParams = new QueryParams() + self._components.themeStorage = new Storage('style:') + self.data.optimize = !!self._components.queryParams.get().optimize + self._components.queryParams.update({ optimize: self.data.optimize }) + self._api.setOptimize(self.data.optimize, false) + self.data.currentTheme = self._components.themeStorage.get('theme') || 'light' + self._events.compiler.register('compilerLoaded', (version) => self.setVersionText(version)) + self.fetchAllVersion((allversions, selectedVersion) => { + self.data.allversions = allversions + self.data.selectedVersion = selectedVersion + if (self._view.versionSelector) self._updateVersionSelector() + }) + } + render () { + const self = this + if (self._view.el) return self._view.el + + // Gist settings + var gistAccessToken = yo`` + var token = self._api.config.get('settings/gist-access-token') + if (token) gistAccessToken.value = token + var gistAddToken = yo` { self._api.config.set('settings/gist-access-token', gistAccessToken.value); tooltip('Access token saved') }} value="Save" type="button">` + var gistRemoveToken = yo` { gistAccessToken.value = ''; self._api.config.set('settings/gist-access-token', ''); tooltip('Access token removed') }} value="Remove" type="button">` + self._view.gistToken = yo`
${gistAccessToken}${copyToClipboard(() => self._api.config.get('settings/gist-access-token'))}${gistAddToken}${gistRemoveToken}
` + // + self._view.optionVM = yo`` + if (self._api.config.get('settings/always-use-vm')) self._view.optionVM.setAttribute('checked', '') + self._view.personal = yo`` + if (self._api.config.get('settings/personal-mode')) self._view.personal.setAttribute('checked', '') + self._view.optimize = yo`` + if (self.data.optimize) self._view.optimize.setAttribute('checked', '') + var warnText = `Transaction sent over Web3 will use the web3.personal API - be sure the endpoint is opened before enabling it. + This mode allows to provide the passphrase in the Remix interface without having to unlock the account. + Although this is very convenient, you should completely trust the backend you are connected to (Geth, Parity, ...). + It is not recommended (and also most likely not relevant) to use this mode with an injected provider (Mist, Metamask, ...) or with JavaScript VM. + Remix never persist any passphrase.`.split('\n').map(s => s.trim()).join(' ') + self._view.warnPersonalMode = yo`` + self._view.pluginInput = yo`` + self._view.versionSelector = yo` + ` + if (self.data.allversions && self.data.selectedVersion) self._updateVersionSelector() + self._view.version = yo`` + self._view.theme.light = yo`` + self._view.theme.dark = yo`` + self._view.theme[self.data.currentTheme].setAttribute('checked', 'checked') + self._view.config.solidity = yo`
Solidity version
- Current version: + Current version: ${self._view.version}
- + ${self._view.versionSelector}
-
+
` + self._view.config.general = yo`
-
General settings
-
-
${optionVM}
- Always use Ethereum VM at Load -
-
-
- Text Wrap -
-
-
- Enable Optimization -
-
-
${personal}
- Enable Personal Mode ${warnPersonalMode} +
General settings
+
+
${self._view.optionVM}
+ Always use Ethereum VM at Load +
+
+
+ Text Wrap +
+
+
${self._view.optimize}
+ Enable Optimization +
+
+
${self._view.personal}>
+ Enable Personal Mode ${self._view.warnPersonalMode}> +
-
Gist Access Token
Manage the access token used to publish to Gist.
Go to github token page (link below) to create a new token and save it in Remix. Make sure this token has only 'create gist' permission.
-
${gistAccessToken}${copyToClipboard(() => appAPI.config.get('settings/gist-access-token'))}${gistAddToken}${gistRemoveToken}
+ ${self._view.gistToken}
-
+ ` + self._view.config.themes = yo`
Themes
@@ -76,14 +125,15 @@ function SettingsTab (appAPI = {}, appEvents = {}, opts = {}) { Selecting a theme will trigger a page reload
- + ${self._view.theme.light}
- + ${self._view.theme.dark}
-
+ ` + self._view.config.plugin = yo`
Plugin
@@ -92,11 +142,12 @@ function SettingsTab (appAPI = {}, appEvents = {}, opts = {}) { Do not use this alpha feature if you are not sure what you are doing!
- - -
+ ${self._view.pluginInput} + +
- + ` + self._view.config.remixd = yo`
Remixd
@@ -107,7 +158,8 @@ function SettingsTab (appAPI = {}, appEvents = {}, opts = {}) {
Installation:
npm install remixd -g
-
+
` + self._view.config.localremixd = yo`
Running Remix locally
@@ -116,166 +168,183 @@ function SettingsTab (appAPI = {}, appEvents = {}, opts = {}) { https://www.npmjs.com/package/remix-ide
npm install remix-ide -g
- as an electron app: + as an electron app:
https://github.com/horizon-games/remix-app -
-
- ` - - function loadPlugin () { - var json = el.querySelector('#plugininput').value - try { - json = JSON.parse(json) - } catch (e) { - modal.alert('cannot parse the plugin definition to JSON') - return + ` + self._view.el = yo` +
+ ${self._view.config.solidity} + ${self._view.config.general} + ${self._view.config.themes} + ${self._view.config.plugin} + ${self._view.config.remixd} + ${self._view.config.localremixd} +
` + function onchangeOption (event) { + self._api.config.set('settings/always-use-vm', !self._api.config.get('settings/always-use-vm')) } - appEvents.rhp.trigger('plugin-loadRequest', [json]) - } - - appEvents.compiler.register('compilerLoaded', (version) => { - setVersionText(version, el) - }) - - optionVM.checked = appAPI.config.get('settings/always-use-vm') || false - optionVM.addEventListener('change', event => { - appAPI.config.set('settings/always-use-vm', !appAPI.config.get('settings/always-use-vm')) - }) - - personal.checked = appAPI.config.get('settings/personal-mode') || false - personal.addEventListener('change', event => { - appAPI.config.set('settings/personal-mode', !appAPI.config.get('settings/personal-mode')) - }) - - var optimize = el.querySelector('#optimize') - if ((queryParams.get().optimize === 'true')) { - optimize.setAttribute('checked', true) - appAPI.setOptimize(true, false) - } else { - queryParams.update({ optimize: false }) - appAPI.setOptimize(false, false) - } - - optimize.addEventListener('change', function () { - var optimize = this.checked - queryParams.update({ optimize: optimize }) - appAPI.setOptimize(optimize, true) - }) - - var themeStorage = new Storage('style:') - var currTheme = themeStorage.get('theme') - var themeDark = el.querySelector('#themeDark') - var themeLight = el.querySelector('#themeLight') - - if (currTheme === 'dark') { - themeDark.setAttribute('checked', 'checked') - } else { - themeLight.setAttribute('checked', 'checked') - } - - themeDark.addEventListener('change', function () { - console.log('change dark theme') - styleGuide.switchTheme('dark') - window.location.reload() - }) - - themeLight.addEventListener('change', function () { - console.log('change to light theme') - styleGuide.switchTheme('light') - window.location.reload() - }) - - // ----------------- version selector------------- - - // clear and disable the version selector - var versionSelector = el.querySelector('#versionSelector') - versionSelector.innerHTML = '' - versionSelector.setAttribute('disabled', true) - - // load the new version upon change - versionSelector.addEventListener('change', function () { - loadVersion(versionSelector.value, queryParams, opts.compiler, el) - }) - - var header = new Option('Select new compiler version') - header.disabled = true - header.selected = true - versionSelector.appendChild(header) - - request.get({ - url: 'https://solc-bin.ethereum.org/bin/list.json', - json: true - }, (error, response, data) => { - if (error || !data) { - tooltip('Cannot load compiler version list. It might have been blocked by an advertisement blocker. Please try deactivating any of them from this page and reload.') - - // loading failed for some reason, fall back to local compiler - versionSelector.append(new Option('latest local version', 'builtin')) - loadVersion('builtin', queryParams, opts.compiler, el) - return + function onloadPlugin (event) { + try { + var json = JSON.parse(self._view.pluginInput.value) + } catch (e) { + return modal.alert('cannot parse the plugin definition to JSON') + } + // @TODO: BAD! REFACTOR: no module should trigger events of another modules emitter + self._events.rhp.trigger('plugin-loadRequest', [json]) } - - // populate version dropdown with all available compiler versions (descending order) - $.each(data.builds.slice().reverse(), function (i, build) { - versionSelector.appendChild(new Option(build.longVersion, build.path)) - }) - - versionSelector.removeAttribute('disabled') - - // always include the local version - versionSelector.appendChild(new Option('latest local version', 'builtin')) - - // find latest release - var selectedVersion = data.releases[data.latestRelease] - - // override with the requested version - if (queryParams.get().version) { - selectedVersion = queryParams.get().version + function onswitch2darkTheme (event) { + styleGuide.switchTheme('dark') + window.location.reload() } - - loadVersion(selectedVersion, queryParams, opts.compiler, el) - }) - - return { render () { return el } } -} - -function setVersionText (text, el) { - el.querySelector('#version').innerText = text -} - -function loadVersion (version, queryParams, compiler, el) { - queryParams.update({ version: version }) - var url - if (version === 'builtin') { - var location = window.document.location - location = location.protocol + '//' + location.host + '/' + location.pathname - if (location.endsWith('index.html')) { - location = location.substring(0, location.length - 10) + function onswitch2lightTheme (event) { + styleGuide.switchTheme('light') + window.location.reload() } - if (!location.endsWith('/')) { - location += '/' + function onchangeOptimize (event) { + self.data.optimize = !!self._view.optimize.checked + self._components.queryParams.update({ optimize: self.data.optimize }) + self._api.setOptimize(self.data.optimize, true) } - - url = location + 'soljson.js' - } else { - if (version.indexOf('soljson') !== 0 || helper.checkSpecialChars(version)) { - console.log('loading ' + version + ' not allowed') - return + function onchangeLoadVersion (event) { + self.data.selectedVersion = self._view.versionSelector.value + self._updateVersionSelector() + } + function onchangePersonal (event) { + self._api.config.set('settings/personal-mode', !self._api.config.get('settings/personal-mode')) + } + return self._view.el + } + setVersionText (text) { + const self = this + self.data.version = text + if (self._view.version) self._view.version.innerText = text + } + _updateVersionSelector () { + const self = this + self._view.versionSelector.innerHTML = '' + self._view.versionSelector.appendChild(yo``) + self.data.allversions.forEach(build => self._view.versionSelector.appendChild(yo``)) + self._view.versionSelector.removeAttribute('disabled') + self._components.queryParams.update({ version: self.data.selectedVersion }) + var url + if (self.data.selectedVersion === 'builtin') { + var location = window.document.location + location = location.protocol + '//' + location.host + '/' + location.pathname + if (location.endsWith('index.html')) location = location.substring(0, location.length - 10) + if (!location.endsWith('/')) location += '/' + url = location + 'soljson.js' + } else { + if (self.data.selectedVersion.indexOf('soljson') !== 0 || helper.checkSpecialChars(self.data.selectedVersion)) { + return console.log('loading ' + self.data.selectedVersion + ' not allowed') + } + url = 'https://ethereum.github.io/solc-bin/bin/' + self.data.selectedVersion + } + var isFirefox = typeof InstallTrigger !== 'undefined' + if (document.location.protocol !== 'file:' && Worker !== undefined && isFirefox) { + // Workers cannot load js on "file:"-URLs and we get a + // "Uncaught RangeError: Maximum call stack size exceeded" error on Chromium, + // resort to non-worker version in that case. + self._opts.compiler.loadVersion(true, url) + self.setVersionText('(loading using worker)') + } else { + self._opts.compiler.loadVersion(false, url) + self.setVersionText('(loading)') } - url = 'https://solc-bin.ethereum.org/bin/' + version } - var isFirefox = typeof InstallTrigger !== 'undefined' - if (document.location.protocol !== 'file:' && Worker !== undefined && isFirefox) { - // Workers cannot load js on "file:"-URLs and we get a - // "Uncaught RangeError: Maximum call stack size exceeded" error on Chromium, - // resort to non-worker version in that case. - compiler.loadVersion(true, url) - setVersionText('(loading using worker)', el) - } else { - compiler.loadVersion(false, url) - setVersionText('(loading)', el) + fetchAllVersion (callback) { + var self = this + minixhr('https://ethereum.github.io/solc-bin/bin/list.json', function (json, event) { + // @TODO: optimise and cache results to improve app loading times + var allversions, selectedVersion + if (event.type !== 'error') { + try { + const data = JSON.parse(json) + allversions = data.builds.slice().reverse() + selectedVersion = data.releases[data.latestRelease] + if (self._components.queryParams.get().version) selectedVersion = self._components.queryParams.get().version + } catch (e) { + tooltip('Cannot load compiler version list. It might have been blocked by an advertisement blocker. Please try deactivating any of them from this page and reload.') + } + } else { + allversions = [{ path: 'builtin', longVersion: 'latest local version' }] + selectedVersion = 'builtin' + } + callback(allversions, selectedVersion) + }) } } -module.exports = SettingsTab +const css = csjs` + .settingsTabView { + padding: 2%; + display: flex; + } + .info { + ${styles.rightPanel.settingsTab.box_SolidityVersionInfo} + margin-bottom: 1em; + word-break: break-word; + } + .title { + font-size: 1.1em; + font-weight: bold; + margin-bottom: 1em; + } + .crow { + display: flex; + overflow: auto; + clear: both; + padding: .2em; + } + .checkboxText { + font-weight: normal; + } + .crow label { + cursor:pointer; + } + .crowNoFlex { + overflow: auto; + clear: both; + } + .attention { + margin-bottom: 1em; + padding: .5em; + font-weight: bold; + } + .select { + font-weight: bold; + margin-top: 1em; + ${styles.rightPanel.settingsTab.dropdown_SelectCompiler} + } + .heading { + margin-bottom: 0; + } + .explaination { + margin-top: 3px; + margin-bottom: 3px; + } + input { + margin-right: 5px; + cursor: pointer; + } + input[type=radio] { + margin-top: 2px; + } + .pluginTextArea { + font-family: unset; + } + .pluginLoad { + vertical-align: top; + } + i.warnIt { + color: ${styles.appProperties.warningText_Color}; + } + .icon { + margin-right: .5em; + } + .remixdinstallation { + padding: 3px; + border-radius: 2px; + margin-left: 5px; + } +` From 80de10cd495f2afe9491cd2150a2d95f718b61f0 Mon Sep 17 00:00:00 2001 From: serapath Date: Sun, 15 Apr 2018 21:13:19 +0100 Subject: [PATCH 2/3] fix compilers url --- src/app/tabs/settings-tab.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/app/tabs/settings-tab.js b/src/app/tabs/settings-tab.js index 39d7876172..555a7ed57a 100644 --- a/src/app/tabs/settings-tab.js +++ b/src/app/tabs/settings-tab.js @@ -31,7 +31,11 @@ module.exports = class SettingsTab { plugin: null, remixd: null, localremixd: null } } /* eslint-enable */ - self.data = { allversions: null, selectedVersion: null } + self.data = { + allversions: null, + selectedVersion: null, + baseurl: 'https://solc-bin.ethereum.org/bin' + } self.event = new EventManager() self._components.queryParams = new QueryParams() self._components.themeStorage = new Storage('style:') @@ -238,7 +242,7 @@ module.exports = class SettingsTab { if (self.data.selectedVersion.indexOf('soljson') !== 0 || helper.checkSpecialChars(self.data.selectedVersion)) { return console.log('loading ' + self.data.selectedVersion + ' not allowed') } - url = 'https://ethereum.github.io/solc-bin/bin/' + self.data.selectedVersion + url = `${self.data.baseurl}/${self.data.selectedVersion}` } var isFirefox = typeof InstallTrigger !== 'undefined' if (document.location.protocol !== 'file:' && Worker !== undefined && isFirefox) { @@ -254,7 +258,7 @@ module.exports = class SettingsTab { } fetchAllVersion (callback) { var self = this - minixhr('https://ethereum.github.io/solc-bin/bin/list.json', function (json, event) { + minixhr(`${self.data.baseurl}/list.json`, function (json, event) { // @TODO: optimise and cache results to improve app loading times var allversions, selectedVersion if (event.type !== 'error') { From 698fc6f7966bb1448f140a35d0d2ee7070e4dd8a Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 15 May 2018 09:20:15 +0200 Subject: [PATCH 3/3] integrate gist token --- src/app/tabs/settings-tab.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/app/tabs/settings-tab.js b/src/app/tabs/settings-tab.js index 555a7ed57a..176c0b7a9a 100644 --- a/src/app/tabs/settings-tab.js +++ b/src/app/tabs/settings-tab.js @@ -94,7 +94,7 @@ module.exports = class SettingsTab { ` self._view.config.general = yo`
-
General settings
+
General settings
${self._view.optionVM}
Always use Ethereum VM at Load @@ -111,15 +111,15 @@ module.exports = class SettingsTab {
${self._view.personal}>
Enable Personal Mode ${self._view.warnPersonalMode}>
-
+ + ` + self._view.gistToken = yo`
Gist Access Token
Manage the access token used to publish to Gist.
Go to github token page (link below) to create a new token and save it in Remix. Make sure this token has only 'create gist' permission.
-
- ${self._view.gistToken} -
+
${self._view.gistToken}
` self._view.config.themes = yo`
@@ -180,6 +180,7 @@ module.exports = class SettingsTab {
${self._view.config.solidity} ${self._view.config.general} + ${self._view.gistToken} ${self._view.config.themes} ${self._view.config.plugin} ${self._view.config.remixd} @@ -351,4 +352,7 @@ const css = csjs` border-radius: 2px; margin-left: 5px; } + .savegisttoken { + margin-left: 5px; + } `