Commit fc29644f authored by Iuri Matias's avatar Iuri Matias

Refactor other tabs, start refactoring compile tab

move compile tab styles to its own file refactor: simplify some methods; transform functions into blocks move events to its own method move compiler and compiler import out of _dependencies simplify passing registry to compile tab move queryParams & remove _dependencies var refactor optimize param move to compile tab logic extract code for compiler container into a separate module remove unused method move compiler imports logic out of the UI
parent 454778e4
...@@ -444,13 +444,17 @@ Please make a backup of your contracts and start using http://remix.ethereum.org ...@@ -444,13 +444,17 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
registry.get('compilersartefacts').api registry.get('compilersartefacts').api
) )
let settings = new SettingsTab(self._components.registry) let settings = new SettingsTab(self._components.registry)
let analysis = new AnalysisTab(self._components.registry) let analysis = new AnalysisTab(registry)
let debug = new DebuggerTab(self._components.registry) let debug = new DebuggerTab()
let support = new SupportTab(self._components.registry) let support = new SupportTab()
let test = new TestTab(self._components.registry, compileTab) let test = new TestTab(self._components.registry, compileTab)
let sourceHighlighters = registry.get('editor').api.sourceHighlighters let sourceHighlighters = registry.get('editor').api.sourceHighlighters
let configProvider = self._components.filesProviders['config'] let configProvider = self._components.filesProviders['config']
registry.get('app').api.event.register('tabChanged', (tabName) => {
if (tabName === 'Support') support.loadTab()
})
appManager.init([ appManager.init([
{ profile: this.profile(), api: this }, { profile: this.profile(), api: this },
{ profile: udapp.profile(), api: udapp }, { profile: udapp.profile(), api: udapp },
......
This diff is collapsed.
const async = require('async')
var remixTests = require('remix-tests')
var Compiler = require('remix-solidity').Compiler
var CompilerImport = require('../../compiler/compiler-imports')
// TODO: move this to the UI
const addTooltip = require('../../ui/tooltip')
class CompileTab {
constructor (queryParams, fileManager, editor, config, fileProviders) {
this.queryParams = queryParams
this.compilerImport = new CompilerImport()
this.compiler = new Compiler((url, cb) => this.importFileCb(url, cb))
this.fileManager = fileManager
this.editor = editor
this.config = config
this.fileProviders = fileProviders
}
init () {
this.optimize = this.queryParams.get().optimize
this.optimize = this.optimize === 'true'
this.queryParams.update({ optimize: this.optimize })
this.compiler.setOptimize(this.optimize)
}
setOptimize (newOptimizeValue) {
this.optimize = newOptimizeValue
this.queryParams.update({ optimize: this.optimize })
this.compiler.setOptimize(this.optimize)
}
runCompiler () {
this.fileManager.saveCurrentFile()
this.editor.clearAnnotations()
var currentFile = this.config.get('currentFile')
if (!currentFile && !/.(.sol)$/.exec(currentFile)) return
// only compile *.sol file.
var target = currentFile
var sources = {}
var provider = this.fileManager.fileProviderOf(currentFile)
if (!provider) return console.log('cannot compile ' + currentFile + '. Does not belong to any explorer')
provider.get(target, (error, content) => {
if (error) return console.log(error)
sources[target] = { content }
this.compiler.compile(sources, target)
})
}
importExternal (url, cb) {
this.compilerImport.import(url,
// TODO: move to an event that is generated, the UI shouldn't be here
(loadingMsg) => { addTooltip(loadingMsg) },
(error, content, cleanUrl, type, url) => {
if (error) return cb(error)
if (this._deps.fileProviders[type]) {
this._deps.fileProviders[type].addReadOnly(cleanUrl, content, url)
}
cb(null, content)
})
}
importFileCb (url, filecb) {
if (url.indexOf('/remix_tests.sol') !== -1) return filecb(null, remixTests.assertLibCode)
var provider = this._deps.fileManager.fileProviderOf(url)
if (provider) {
if (provider.type === 'localhost' && !provider.isConnected()) {
return filecb(`file provider ${provider.type} not available while trying to resolve ${url}`)
}
return provider.exists(url, (error, exist) => {
if (error) return filecb(error)
if (exist) {
return provider.get(url, filecb)
}
this.importExternal(url, filecb)
})
}
if (this.compilerImport.isRelativeImport(url)) {
// try to resolve localhost modules (aka truffle imports)
var splitted = /([^/]+)\/(.*)$/g.exec(url)
return async.tryEach([
(cb) => { this.importFileCb('localhost/installed_contracts/' + url, cb) },
(cb) => { if (!splitted) { cb('URL not parseable: ' + url) } else { this.importFileCb('localhost/installed_contracts/' + splitted[1] + '/contracts/' + splitted[2], cb) } },
(cb) => { this.importFileCb('localhost/node_modules/' + url, cb) },
(cb) => { if (!splitted) { cb('URL not parseable: ' + url) } else { this.importFileCb('localhost/node_modules/' + splitted[1] + '/contracts/' + splitted[2], cb) } }],
(error, result) => { filecb(error, result) }
)
}
this.importExternal(url, filecb)
}
}
module.exports = CompileTab
/* global Worker */
const yo = require('yo-yo')
var minixhr = require('minixhr')
var helper = require('../../../lib/helper')
const addTooltip = require('../../ui/tooltip')
const styleGuide = require('../../ui/styles-guide/theme-chooser')
const styles = styleGuide.chooser()
var css = require('../styles/compile-tab-styles')
class CompilerContainer {
constructor (compileTabLogic, editor, config, queryParams) {
this._view = {}
this.compileTabLogic = compileTabLogic
this.editor = editor
this.config = config
this.queryParams = queryParams
this.data = {
hideWarnings: config.get('hideWarnings') || false,
autoCompile: config.get('autoCompile'),
compileTimeout: null,
timeout: 300,
allversions: null,
selectedVersion: null,
defaultVersion: 'soljson-v0.5.1+commit.c8a2cb62.js', // this default version is defined: in makeMockCompiler (for browser test) and in package.json (downloadsolc_root) for the builtin compiler
baseurl: 'https://solc-bin.ethereum.org/bin'
}
this.listenToEvents()
}
listenToEvents () {
this.editor.event.register('contentChanged', this.scheduleCompilation.bind(this))
this.editor.event.register('sessionSwitched', this.scheduleCompilation.bind(this))
this.compileTabLogic.compiler.event.register('compilationDuration', (speed) => {
if (!this._view.warnCompilationSlow) return
if (speed > 1000) {
const msg = `Last compilation took ${speed}ms. We suggest to turn off autocompilation.`
this._view.warnCompilationSlow.setAttribute('title', msg)
this._view.warnCompilationSlow.style.visibility = 'visible'
} else {
this._view.warnCompilationSlow.style.visibility = 'hidden'
}
})
this.editor.event.register('contentChanged', () => {
if (!this._view.compileIcon) return
this._view.compileIcon.classList.add(`${css.bouncingIcon}`) // @TODO: compileView tab
})
this.compileTabLogic.compiler.event.register('loadingCompiler', () => {
if (!this._view.compileIcon) return
this._view.compileIcon.classList.add(`${css.spinningIcon}`)
this._view.warnCompilationSlow.style.visibility = 'hidden'
this._view.compileIcon.setAttribute('title', 'compiler is loading, please wait a few moments.')
})
this.compileTabLogic.compiler.event.register('compilationStarted', () => {
if (!this._view.compileIcon) return
this._view.compileIcon.classList.remove(`${css.bouncingIcon}`)
this._view.compileIcon.classList.add(`${css.spinningIcon}`)
this._view.compileIcon.setAttribute('title', 'compiling...')
})
this.compileTabLogic.compiler.event.register('compilerLoaded', () => {
if (!this._view.compileIcon) return
this._view.compileIcon.classList.remove(`${css.spinningIcon}`)
this._view.compileIcon.setAttribute('title', '')
})
this.compileTabLogic.compiler.event.register('compilationFinished', (success, data, source) => {
if (!this._view.compileIcon) return
this._view.compileIcon.style.color = styles.colors.black
this._view.compileIcon.classList.remove(`${css.spinningIcon}`)
this._view.compileIcon.classList.remove(`${css.bouncingIcon}`)
this._view.compileIcon.setAttribute('title', 'idle')
})
}
render () {
this.compileTabLogic.compiler.event.register('compilerLoaded', (version) => this.setVersionText(version))
this.fetchAllVersion((allversions, selectedVersion) => {
this.data.allversions = allversions
this.data.selectedVersion = selectedVersion
if (this._view.versionSelector) this._updateVersionSelector()
})
this._view.warnCompilationSlow = yo`<i title="Compilation Slow" style="visibility:hidden" class="${css.warnCompilationSlow} fa fa-exclamation-triangle" aria-hidden="true"></i>`
this._view.compileIcon = yo`<i class="fa fa-refresh ${css.icon}" aria-hidden="true"></i>`
this._view.compileButton = yo`<div class="${css.compileButton}" onclick=${this.compile.bind(this)} id="compile" title="Compile source code">${this._view.compileIcon} Start to compile (Ctrl-S)</div>`
this._view.autoCompile = yo`<input class="${css.autocompile}" onchange=${this.updateAutoCompile.bind(this)} id="autoCompile" type="checkbox" title="Auto compile">`
this._view.hideWarningsBox = yo`<input class="${css.autocompile}" onchange=${this.hideWarnings.bind(this)} id="hideWarningsBox" type="checkbox" title="Hide warnings">`
if (this.data.autoCompile) this._view.autoCompile.setAttribute('checked', '')
if (this.data.hideWarnings) this._view.hideWarningsBox.setAttribute('checked', '')
this._view.optimize = yo`<input onchange=${this.onchangeOptimize.bind(this)} id="optimize" type="checkbox">`
if (this.compileTabLogic.optimize) this._view.optimize.setAttribute('checked', '')
this._view.versionSelector = yo`
<select onchange=${this.onchangeLoadVersion.bind(this)} class="${css.select}" id="versionSelector" disabled>
<option disabled selected>Select new compiler version</option>
</select>`
this._view.version = yo`<span id="version"></span>`
this._view.compileContainer = yo`
<div class="${css.compileContainer}">
<div class="${css.info}">
<span>Current version:</span> ${this._view.version}
<div class="${css.crow}">
${this._view.versionSelector}
</div>
<div class="${css.compileButtons}">
<div class=${css.checkboxes}>
<div class="${css.autocompileContainer}">
${this._view.autoCompile}
<label for="autoCompile" class="${css.autocompileText}">Auto compile</label>
</div>
<div class="${css.optimizeContainer}">
<div>${this._view.optimize}</div>
<label for="optimize" class="${css.checkboxText}">Enable Optimization</label>
</div>
<div class=${css.hideWarningsContainer}>
${this._view.hideWarningsBox}
<label for="hideWarningsBox" class="${css.autocompileText}">Hide warnings</label>
</div>
</div>
${this._view.compileButton}
</div>
</div>
</div>`
return this._view.compileContainer
}
updateAutoCompile (event) {
this.config.set('autoCompile', this._view.autoCompile.checked)
}
compile (event) {
this.compileTabLogic.runCompiler()
}
hideWarnings (event) {
this.config.set('hideWarnings', this._view.hideWarningsBox.checked)
this.compile()
}
onchangeOptimize () {
this.compileTabLogic.setOptimize(!!this._view.optimize.checked)
this.compileTabLogic.runCompiler()
}
onchangeLoadVersion (event) {
this.data.selectedVersion = this._view.versionSelector.value
this._updateVersionSelector()
}
_updateVersionSelector () {
this._view.versionSelector.innerHTML = ''
this._view.versionSelector.appendChild(yo`<option disabled selected>Select new compiler version</option>`)
this.data.allversions.forEach(build => this._view.versionSelector.appendChild(yo`<option value=${build.path}>${build.longVersion}</option>`))
this._view.versionSelector.removeAttribute('disabled')
this.queryParams.update({ version: this.data.selectedVersion })
var url
if (this.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 (this.data.selectedVersion.indexOf('soljson') !== 0 || helper.checkSpecialChars(this.data.selectedVersion)) {
return console.log('loading ' + this.data.selectedVersion + ' not allowed')
}
url = `${this.data.baseurl}/${this.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.
this.compileTabLogic.compiler.loadVersion(true, url)
this.setVersionText('(loading using worker)')
} else {
this.compileTabLogic.compiler.loadVersion(false, url)
this.setVersionText('(loading)')
}
}
setVersionText (text) {
this.data.version = text
if (this._view.version) this._view.version.innerText = text
}
fetchAllVersion (callback) {
minixhr(`${this.data.baseurl}/list.json`, (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 = this.data.defaultVersion
if (this.queryParams.get().version) selectedVersion = this.queryParams.get().version
} catch (e) {
addTooltip('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)
})
}
scheduleCompilation () {
if (!this.config.get('autoCompile')) return
if (this.data.compileTimeout) window.clearTimeout(this.data.compileTimeout)
this.data.compileTimeout = window.setTimeout(() => this.compileTabLogic.runCompiler(), this.data.timeout)
}
}
module.exports = CompilerContainer
const csjs = require('csjs-inject')
const styleGuide = require('../../ui/styles-guide/theme-chooser')
const styles = styleGuide.chooser()
const css = csjs`
.title {
font-size: 1.1em;
font-weight: bold;
margin-bottom: 1em;
}
.panicError {
color: red;
font-size: 20px;
}
.crow {
display: flex;
overflow: auto;
clear: both;
padding: .2em;
}
.checkboxText {
font-weight: normal;
}
.crow label {
cursor:pointer;
}
.crowNoFlex {
overflow: auto;
clear: both;
}
.select {
font-weight: bold;
margin: 10px 0px;
${styles.rightPanel.settingsTab.dropdown_SelectCompiler};
}
.info {
${styles.rightPanel.settingsTab.box_SolidityVersionInfo}
margin-bottom: 1em;
word-break: break-word;
}
.compileTabView {
padding: 2%;
}
.contract {
display: block;
margin: 3% 0;
}
.compileContainer {
${styles.rightPanel.compileTab.box_CompileContainer};
margin-bottom: 2%;
}
.autocompileContainer {
display: flex;
align-items: center;
}
.hideWarningsContainer {
display: flex;
align-items: center;
}
.autocompile {}
.autocompileTitle {
font-weight: bold;
margin: 1% 0;
}
.autocompileText {
margin: 1% 0;
font-size: 12px;
overflow: hidden;
word-break: normal;
line-height: initial;
}
.warnCompilationSlow {
color: ${styles.rightPanel.compileTab.icon_WarnCompilation_Color};
margin-left: 1%;
}
.compileButtons {
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: flex-end;
}
.name {
display: flex;
}
.size {
display: flex;
}
.checkboxes {
display: flex;
width: 100%;
justify-content: space-between;
flex-wrap: wrap;
}
.compileButton {
${styles.rightPanel.compileTab.button_Compile};
width: 100%;
margin: 15px 0 10px 0;
font-size: 12px;
}
.container {
${styles.rightPanel.compileTab.box_CompileContainer};
margin: 0;
margin-bottom: 2%;
}
.contractContainer {
display: flex;
align-items: center;
margin-bottom: 2%;
}
.optimizeContainer {
display: flex;
}
.contractNames {
${styles.rightPanel.compileTab.dropdown_CompileContract};
width:78%;
}
.contractHelperButtons {
display: flex;
cursor: pointer;
text-align: center;
justify-content: flex-end;
margin: 15px 15px 10px 0;
}
.copyButton {
${styles.rightPanel.compileTab.button_Publish};
padding: 0 7px;
min-width: 50px;
width: auto;
margin-left: 5px;
background-color: inherit;
border: inherit;
}
.bytecodeButton {
min-width: 80px;
}
.copyIcon {
margin-right: 5px;
}
.details {
${styles.rightPanel.compileTab.button_Details};
min-width: 70px;
width: 80px;
}
.publish {
display: flex;
align-items: center;
margin-left: 10px;
cursor: pointer;
}
.log {
${styles.rightPanel.compileTab.box_CompileContainer};
display: flex;
flex-direction: column;
margin-bottom: 5%;
overflow: visible;
}
.key {
margin-right: 5px;
color: ${styles.rightPanel.text_Primary};
text-transform: uppercase;
width: 100%;
}
.value {
display: flex;
width: 100%;
margin-top: 1.5%;
}
.questionMark {
margin-left: 2%;
cursor: pointer;
color: ${styles.rightPanel.icon_Color_TogglePanel};
}
.questionMark:hover {
color: ${styles.rightPanel.icon_HoverColor_TogglePanel};
}
.detailsJSON {
padding: 8px 0;
background-color: ${styles.rightPanel.modalDialog_BackgroundColor_Primary};
border: none;
color: ${styles.rightPanel.modalDialog_text_Secondary};
}
.icon {
margin-right: 0.3em;
}
.spinningIcon {
margin-right: .3em;
animation: spin 2s linear infinite;
}
.bouncingIcon {
margin-right: .3em;
animation: bounce 2s infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@-webkit-keyframes bounce {
0% {
margin-bottom: 0;
color: ${styles.colors.transparent};
}
70% {
margin-bottom: 0;
color: ${styles.rightPanel.text_Secondary};
}
100% {
margin-bottom: 0;
color: ${styles.colors.transparent};
}
}
`
module.exports = css
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