Merge pull request #1959 from ethereum/issue#1949-abstract_panel

Issue#1949 abstract panel
pull/3094/head
yann300 6 years ago committed by GitHub
commit 18be51f96b
  1. 2
      package.json
  2. 45
      src/app.js
  3. 24
      src/app/components/main-panel.js
  4. 111
      src/app/components/panel.js
  5. 43
      src/app/components/swap-panel-api.js
  6. 102
      src/app/components/swap-panel-component.js
  7. 84
      src/app/components/swap-panel.js
  8. 20
      src/app/components/vertical-icons-api.js
  9. 6
      src/app/components/vertical-icons.js
  10. 8
      src/app/panels/main-view.js
  11. 1
      src/app/ui/landing-page/landing-page.js
  12. 19
      src/framingService.js

@ -67,8 +67,8 @@
"yo-yoify": "^3.7.3" "yo-yoify": "^3.7.3"
}, },
"dependencies": { "dependencies": {
"http-server": "^0.11.1",
"remix-plugin": "0.0.2-alpha.6", "remix-plugin": "0.0.2-alpha.6",
"http-server": "^0.11.1",
"remixd": "0.1.8-alpha.6" "remixd": "0.1.8-alpha.6"
}, },
"repository": { "repository": {

@ -33,12 +33,6 @@ var TransactionReceiptResolver = require('./transactionReceiptResolver')
const PluginManagerComponent = require('./app/components/plugin-manager-component') const PluginManagerComponent = require('./app/components/plugin-manager-component')
const VerticalIconsComponent = require('./app/components/vertical-icons-component')
const VerticalIconsApi = require('./app/components/vertical-icons-api')
const SwapPanelComponent = require('./app/components/swap-panel-component')
const SwapPanelApi = require('./app/components/swap-panel-api')
const CompileTab = require('./app/tabs/compile-tab') const CompileTab = require('./app/tabs/compile-tab')
const SettingsTab = require('./app/tabs/settings-tab') const SettingsTab = require('./app/tabs/settings-tab')
const AnalysisTab = require('./app/tabs/analysis-tab') const AnalysisTab = require('./app/tabs/analysis-tab')
@ -55,6 +49,9 @@ import framingService from './framingService'
import { MainView } from './app/panels/main-view' import { MainView } from './app/panels/main-view'
import { ThemeModule } from './app/tabs/theme-module' import { ThemeModule } from './app/tabs/theme-module'
import { NetworkModule } from './app/tabs/network-module' import { NetworkModule } from './app/tabs/network-module'
import { SwapPanel } from './app/components/swap-panel'
import { MainPanel } from './app/components/main-panel'
import { VerticalIcons } from './app/components/vertical-icons'
var css = csjs` var css = csjs`
html { box-sizing: border-box; } html { box-sizing: border-box; }
@ -324,8 +321,6 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
const appManager = new RemixAppManager(appStore) const appManager = new RemixAppManager(appStore)
registry.put({api: appManager, name: 'appmanager'}) registry.put({api: appManager, name: 'appmanager'})
const mainPanelComponent = new SwapPanelComponent('mainPanel', appStore, appManager, { default: false, displayHeader: false })
// ----------------- file manager ---------------------------- // ----------------- file manager ----------------------------
self._components.fileManager = new FileManager() self._components.fileManager = new FileManager()
const fileManager = self._components.fileManager const fileManager = self._components.fileManager
@ -339,8 +334,19 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
const themeModule = new ThemeModule(registry) const themeModule = new ThemeModule(registry)
registry.put({api: themeModule, name: 'themeModule'}) registry.put({api: themeModule, name: 'themeModule'})
// ----------------- landing page ----------------------------
// Need to have Home initialized before VerticalIconComponent render to access profile of it for icon
const landingPage = new LandingPage(appManager, appStore)
// ----------------- Vertical Icon ----------------------------
const verticalIcons = new VerticalIcons('swapPanel', appStore, landingPage)
registry.put({api: verticalIcons, name: 'verticalicon'})
const swapPanel = new SwapPanel(appStore)
const mainPanel = new MainPanel(appStore)
// ----------------- main view ---------------------- // ----------------- main view ----------------------
self._components.mainview = new MainView(appStore, appManager, mainPanelComponent) self._components.mainview = new MainView(appStore, appManager, mainPanel)
registry.put({ api: self._components.mainview, name: 'mainview' }) registry.put({ api: self._components.mainview, name: 'mainview' })
// ----------------- Renderer ----------------- // ----------------- Renderer -----------------
@ -359,27 +365,17 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
// TODOs those are instanciated before hand. should be instanciated on demand // TODOs those are instanciated before hand. should be instanciated on demand
const pluginManagerComponent = new PluginManagerComponent() const pluginManagerComponent = new PluginManagerComponent()
const swapPanelComponent = new SwapPanelComponent('swapPanel', appStore, appManager, { default: true, displayHeader: true })
registry.put({api: appManager.proxy(), name: 'pluginmanager'}) registry.put({api: appManager.proxy(), name: 'pluginmanager'})
pluginManagerComponent.setApp(appManager) pluginManagerComponent.setApp(appManager)
pluginManagerComponent.setStore(appStore) pluginManagerComponent.setStore(appStore)
// Need to have Home initialized before VerticalIconComponent render to access profile of it for icon
const landingPage = new LandingPage(appManager, appStore)
// ----------------- Vertical Icon ----------------------------
const verticalIconsComponent = new VerticalIconsComponent('swapPanel', appStore, landingPage.profile)
const swapPanelApi = new SwapPanelApi(swapPanelComponent, verticalIconsComponent) // eslint-disable-line
const mainPanelApi = new SwapPanelApi(mainPanelComponent, verticalIconsComponent) // eslint-disable-line
const verticalIconsApi = new VerticalIconsApi(verticalIconsComponent) // eslint-disable-line
registry.put({api: verticalIconsApi, name: 'verticalicon'})
self._components.mainview.init() self._components.mainview.init()
self._components.fileManager.init() self._components.fileManager.init()
self._view.mainpanel.appendChild(self._components.mainview.render()) self._view.mainpanel.appendChild(self._components.mainview.render())
self._view.iconpanel.appendChild(verticalIconsComponent.render()) self._view.iconpanel.appendChild(verticalIcons.render())
self._view.swappanel.appendChild(swapPanelComponent.render()) self._view.swappanel.appendChild(swapPanel.render())
let filePanel = new FilePanel() let filePanel = new FilePanel()
registry.put({api: filePanel, name: 'filepanel'}) registry.put({api: filePanel, name: 'filepanel'})
@ -423,7 +419,6 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
fileManager.api(), fileManager.api(),
sourceHighlighters.api(), sourceHighlighters.api(),
filePanel.api(), filePanel.api(),
// { profile: support.profile(), api: support },
settings.api(), settings.api(),
pluginManagerComponent.api(), pluginManagerComponent.api(),
networkModule.api(), networkModule.api(),
@ -440,7 +435,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
...appManager.plugins() ...appManager.plugins()
]) ])
framingService.start(appStore, swapPanelApi, verticalIconsApi, mainPanelApi, this._components.resizeFeature) framingService.start(appStore, swapPanel, verticalIcons, mainPanel, this._components.resizeFeature)
// The event listener needs to be registered as early as possible, because the // The event listener needs to be registered as early as possible, because the
// parent will send the message upon the "load" event. // parent will send the message upon the "load" event.
@ -467,7 +462,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
txLogger.event.register('debuggingRequested', (hash) => { txLogger.event.register('debuggingRequested', (hash) => {
if (!appStore.isActive('debugger')) appManager.activateOne('debugger') if (!appStore.isActive('debugger')) appManager.activateOne('debugger')
debug.debugger().debug(hash) debug.debugger().debug(hash)
verticalIconsApi.select('debugger') verticalIcons.select('debugger')
}) })
let transactionContextAPI = { let transactionContextAPI = {

@ -0,0 +1,24 @@
import { AbstractPanel } from './panel'
const yo = require('yo-yo')
const csjs = require('csjs-inject')
const css = csjs`
.pluginsContainer {
height: 100%;
display: flex;
overflow-y: hidden;
}
`
export class MainPanel extends AbstractPanel {
constructor (appStore, options) {
super('mainPanel', appStore, options)
}
render () {
return yo`
<div class=${css.pluginsContainer}>
${this.view}
</div>`
}
}

@ -0,0 +1,111 @@
import { EventEmitter } from 'events'
const registry = require('../../global/registry')
const csjs = require('csjs-inject')
const yo = require('yo-yo')
const css = csjs`
.plugins {
height: 100%;
}
.plugItIn {
display : none;
height : 100%;
}
.plugItIn > div {
overflow-y : auto;
height : 100%;
width : 100%;
}
.plugItIn.active {
display : block;
}
.pluginsContainer {
height: 100%;
overflow-y: hidden;
}
`
// Events are : 'toggle' | 'showing'
/** Abstract class used for hosting the view of a plugin */
export class AbstractPanel {
constructor (panelName, appStore, opts) {
this.events = new EventEmitter()
this.contents = {}
this.active = undefined
// View where the plugin HTMLElement leaves
this.view = yo`<div id="plugins" class="${css.plugins}"></div>`
appStore.event.on('activate', (name) => {
const api = appStore.getOne(name)
const profile = api.profile
if (profile.location !== panelName) return
if (!profile.location && !opts.default) return
if (profile.icon && api.render && typeof api.render === 'function') {
this.add(name, api.render())
}
})
appStore.event.on('deactivate', (name) => {
if (this.contents[name]) this.remove(name)
})
const verticalIcon = registry.get('verticalicon').api
// Toggle content
verticalIcon.events.on('toggleContent', (name) => {
if (!this.contents[name]) return
if (this.active === name) {
this.events.emit('toggle', name)
}
this.showContent(name)
this.events.emit('showing', name)
})
// Force opening
verticalIcon.events.on('showContent', (name) => {
if (!this.contents[name]) return
this.showContent(name)
this.events.emit('showing', name)
})
}
/**
* Add the plugin to the panel
* @param {String} name the name of the plugin
* @param {HTMLElement} content the HTMLContent of the plugin
*/
add (name, content) {
if (this.contents[name]) throw new Error(`Plugin ${name} already rendered`)
content.style.height = '100%'
content.style.width = '100%'
content.style.border = '0'
this.contents[name] = yo`<div class="${css.plugItIn}" >${content}</div>`
this.view.appendChild(this.contents[name])
}
/**
* Remove a plugin from the panel
* @param {String} name The name of the plugin to remove
*/
remove (name) {
const el = this.contents[name]
delete this.contents[name]
if (el) el.parentElement.removeChild(el)
}
/**
* Display the content of this specific plugin
* @param {String} name The name of the plugin to display the content
*/
showContent (name) {
if (!this.contents[name]) throw new Error(`Plugin ${name} is not yet activated`)
// hiding the current view and display the `moduleName`
if (this.active) {
this.contents[this.active].style.display = 'none'
}
this.contents[name].style.display = 'block'
this.active = name
}
}

@ -1,43 +0,0 @@
import EventEmmitter from 'events'
class SwapPanelApi {
constructor (swapPanelComponent, verticalIconsComponent) {
this.event = new EventEmmitter()
this.component = swapPanelComponent
this.currentContent
verticalIconsComponent.events.on('toggleContent', (moduleName) => {
if (!swapPanelComponent.contents[moduleName]) return
if (this.currentContent === moduleName) {
this.event.emit('toggle', moduleName)
return
}
this.showContent(moduleName)
this.event.emit('showing', moduleName)
})
verticalIconsComponent.events.on('showContent', (moduleName) => {
if (!swapPanelComponent.contents[moduleName]) return
this.showContent(moduleName)
this.event.emit('showing', moduleName)
})
}
showContent (moduleName) {
this.component.showContent(moduleName)
this.currentContent = moduleName
}
/*
content: DOM element
by appManager
*/
add (profile, content) {
return this.component.add(profile.name, content)
}
remove (profile) {
return this.component.remove(profile.name)
}
}
module.exports = SwapPanelApi

@ -1,102 +0,0 @@
var yo = require('yo-yo')
var csjs = require('csjs-inject')
class SwapPanelComponent {
constructor (name, appStore, appManager, opt) {
this.name = name
this.opt = opt
this.store = appStore
// list of contents
this.contents = {}
// name of the current displayed content
this.currentNode
this.store.event.on('activate', (name) => {
const api = this.store.getOne(name)
const profile = api.profile
if (((profile.location === this.name) || (!profile.location && opt.default)) &&
profile.icon && api.render && typeof api.render === 'function') {
this.add(name, api.render())
}
})
this.store.event.on('deactivate', (name) => {
if (this.contents[name]) this.remove(name)
})
this.store.event.on('add', (api) => { })
this.store.event.on('remove', (api) => { })
}
showContent (moduleName) {
// hiding the current view and display the `moduleName`
if (this.contents[moduleName]) {
if (this.currentNode) {
this.contents[this.currentNode].style.display = 'none'
}
this.contents[moduleName].style.display = 'block'
this.currentNode = moduleName
var api = this.store.getOne(moduleName)
this.header.querySelector('h6').innerHTML = api.profile ? api.profile.displayName : ' - '
return
}
}
add (moduleName, content) {
content.style.height = '100%'
content.style.width = '100%'
content.style.border = '0'
this.contents[moduleName] = yo`<div class=${css.plugItIn} >${content}</div>`
this.view.appendChild(this.contents[moduleName])
}
remove (moduleName) {
let el = this.contents[moduleName]
if (el) el.parentElement.removeChild(el)
}
render () {
this.view = yo`
<div id='plugins' class=${css.plugins}>
</div>
`
this.header = yo`<header class="${css.swapitHeader}"><h6 class="${css.swapitTitle}"></h6></header>`
if (!this.opt.displayHeader) this.header.style.display = 'none'
return yo`<div class=${css.pluginsContainer}>
${this.header}
${this.view}
</div>`
}
}
module.exports = SwapPanelComponent
const css = csjs`
.plugins {
height : 95%;
}
.plugItIn {
display : none;
height : 100%;
}
.plugItIn > div {
overflow-y : auto;
height : 100%;
width : 100%;
}
.plugItIn.active {
display : block;
}
.pluginsContainer {
height: 100%;
overflow-y: hidden;
}
.swapitTitle {
text-transform: uppercase;
}
.swapitHeader {
height: 35px;
padding-top: 10px;
padding-left: 27px;
}
`

@ -0,0 +1,84 @@
import { AbstractPanel } from './panel'
const csjs = require('csjs-inject')
const yo = require('yo-yo')
const css = csjs`
.panel {
height: 100%;
overflow-y: hidden;
}
.swapitTitle {
text-transform: uppercase;
}
.swapitHeader {
height: 35px;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.swapitHeader h6 {
margin: 0;
}
.icons i {
height: 80%;
cursor: pointer;
}
.pluginsContainer {
height: calc(100% - 35px);
overflow: auto;
}
`
const options = {
default: true,
displayHeader: true
}
export class SwapPanel extends AbstractPanel {
constructor (appStore) {
super('swapPanel', appStore, options)
this.header = this.renderHeader()
this.store = appStore
}
/**
* Display content and update the header
* @param {String} name The name of the plugin to display
*/
showContent (name) {
super.showContent(name)
yo.update(this.header, this.renderHeader())
}
/** The header of the swap panel */
renderHeader () {
let name = ' - '
let hasSettings = false
if (this.active) {
const { profile } = this.store.getOne(this.active)
name = profile.displayName ? profile.displayName : profile.name
hasSettings = profile.settings || false
}
return yo`
<header class="${css.swapitHeader}">
<h6 class="${css.swapitTitle}">${name}</h6>
<div class="${css.icons}">
${hasSettings
? yo`<i class="fas fa-cog"></i>`
: yo`<i></i>`}
</div>
</header>`
}
render () {
return yo`
<section class="${css.panel}">
${this.header}
<div class="${css.pluginsContainer}">
${this.view}
</div>
</section>`
}
}

@ -1,20 +0,0 @@
// API
class VerticalIconsApi {
constructor (verticalIconsComponent) {
this.component = verticalIconsComponent
}
addIcon (mod) {
this.component.addIcon(mod)
}
removeIcon (mod) {
this.component.removeIcon(mod)
}
select (moduleName) {
this.component.select(moduleName)
}
}
module.exports = VerticalIconsApi

@ -6,7 +6,7 @@ let globalRegistry = require('../../global/registry')
const EventEmitter = require('events') const EventEmitter = require('events')
// Component // Component
class VerticalIconComponent { export class VerticalIcons {
constructor (name, appStore, homeProfile) { constructor (name, appStore, homeProfile) {
this.store = appStore this.store = appStore
@ -78,7 +78,7 @@ class VerticalIconComponent {
this.icons[name] = yo` this.icons[name] = yo`
<div <div
class="${css.icon}" class="${css.icon}"
onclick="${(e) => { this._iconClick(name) }}" onclick="${() => { this._iconClick(name) }}"
plugin="${name}" title="${title}" > plugin="${name}" title="${title}" >
<img class="image" src="${icon}" alt="${name}" /> <img class="image" src="${icon}" alt="${name}" />
</div>` </div>`
@ -359,8 +359,6 @@ class VerticalIconComponent {
} }
} }
module.exports = VerticalIconComponent
const css = csjs` const css = csjs`
.homeIcon { .homeIcon {
display: block; display: block;

@ -28,7 +28,7 @@ var css = csjs`
` `
export class MainView { export class MainView {
constructor (appStore, appManager, mainPanelComponent) { constructor (appStore, appManager, mainPanel) {
var self = this var self = this
self.event = new EventManager() self.event = new EventManager()
self._view = {} self._view = {}
@ -38,7 +38,7 @@ export class MainView {
self._components.registry.put({api: self._components.editor, name: 'editor'}) self._components.registry.put({api: self._components.editor, name: 'editor'})
self.appStore = appStore self.appStore = appStore
self.appManager = appManager self.appManager = appManager
self.mainPanelComponent = mainPanelComponent self.mainPanel = mainPanel
} }
init () { init () {
var self = this var self = this
@ -52,7 +52,7 @@ export class MainView {
self.tabProxy = new TabProxy(self._deps.fileManager, self._components.editor, self.appStore, self.appManager) self.tabProxy = new TabProxy(self._deps.fileManager, self._components.editor, self.appStore, self.appManager)
let showApp = function (name) { let showApp = function (name) {
self._deps.fileManager.unselectCurrentFile() self._deps.fileManager.unselectCurrentFile()
self.mainPanelComponent.showContent(name) self.mainPanel.showContent(name)
self._view.editor.style.display = 'none' self._view.editor.style.display = 'none'
self._components.contextView.hide() self._components.contextView.hide()
self._view.mainPanel.style.display = 'block' self._view.mainPanel.style.display = 'block'
@ -178,7 +178,7 @@ export class MainView {
if (self._view.el) return self._view.el if (self._view.el) return self._view.el
self._view.editor = self._components.editor.render() self._view.editor = self._components.editor.render()
self._view.editor.style.display = 'none' self._view.editor.style.display = 'none'
self._view.mainPanel = self.mainPanelComponent.render() self._view.mainPanel = self.mainPanel.render()
self._view.terminal = self._components.terminal.render() self._view.terminal = self._components.terminal.render()
self._view.content = yo` self._view.content = yo`
<div class=${css.content}> <div class=${css.content}>

@ -17,7 +17,6 @@ let css = csjs`
text-decoration: underline; text-decoration: underline;
} }
.homeContainer { .homeContainer {
height: 105%!important; /* @todo should be removed once swap_it and mainview will be separated */
user-select:none; user-select:none;
} }
.jumbotronContainer { .jumbotronContainer {

@ -1,27 +1,26 @@
export default { export default {
start: (appStore, swapPanelApi, verticalIconApi, mainPanelApi, resizeFeature) => { start: (appStore, swapPanel, verticalIcon, mainPanel, resizeFeature) => {
swapPanelApi.event.on('toggle', () => { swapPanel.events.on('toggle', () => {
resizeFeature.panel1.clientWidth !== 0 ? resizeFeature.minimize() : resizeFeature.maximise() resizeFeature.panel1.clientWidth !== 0 ? resizeFeature.minimize() : resizeFeature.maximise()
}) })
swapPanelApi.event.on('showing', () => { swapPanel.events.on('showing', () => {
resizeFeature.panel1.clientWidth === 0 ? resizeFeature.maximise() : '' resizeFeature.panel1.clientWidth === 0 ? resizeFeature.maximise() : ''
}) })
mainPanelApi.event.on('toggle', () => { mainPanel.events.on('toggle', () => {
resizeFeature.maximise() resizeFeature.maximise()
}) })
// mainPanelApi.event.on('showing', (moduleName) => {})
verticalIconApi.select('fileExplorers') verticalIcon.select('fileExplorers')
mainPanelApi.showContent('home') mainPanel.showContent('home')
document.addEventListener('keypress', (e) => { document.addEventListener('keypress', (e) => {
if (e.shiftKey && e.ctrlKey) { if (e.shiftKey && e.ctrlKey) {
if (e.code === 'KeyF') { // Ctrl+Shift+F if (e.code === 'KeyF') { // Ctrl+Shift+F
verticalIconApi.select('fileExplorers') verticalIcon.select('fileExplorers')
} else if (e.code === 'KeyA') { // Ctrl+Shift+A } else if (e.code === 'KeyA') { // Ctrl+Shift+A
verticalIconApi.select('pluginManager') verticalIcon.select('pluginManager')
} else if (e.code === 'KeyS') { // Ctrl+Shift+S } else if (e.code === 'KeyS') { // Ctrl+Shift+S
verticalIconApi.select('settings') verticalIcon.select('settings')
} }
e.preventDefault() e.preventDefault()
} }

Loading…
Cancel
Save