Skip to content

rewrite Tab, Pane and DragAndDrop modules with mobx #104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Apr 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6019325
address Coding/WebIDE#154, smoothen split tab group overlay animation
hackape Apr 6, 2017
666185e
:truck: move miscellanous editor components to `EditorWrapper/Editors`
hackape Apr 6, 2017
7f88a9a
:sparkle: by default tab content contains a “tabless” codemirror edit…
hackape Apr 6, 2017
4338281
Merge branch 'master' into hackape/tab-group-refine
hackape Apr 7, 2017
cf7bfb4
:heavy_plus_sign::hammer::construction: add mobx deps, rewrite Tab mo…
hackape Apr 10, 2017
cbcc9dc
:construction: pass `contextMenuItems` from props interface, remove `…
hackape Apr 10, 2017
eebaec4
:construction: add `mapEntity` decorator
hackape Apr 10, 2017
6a4249e
:construction: add `defaultProps` decorator, connect `addTab` action …
hackape Apr 11, 2017
c7d2796
:construction: enhance Tab/TabGroup class
hackape Apr 12, 2017
d6f8db5
:construction: rewrite Tab module with mobx
hackape Apr 12, 2017
ad31fa5
:construction: apply the new Tab module, change references accordingly
hackape Apr 12, 2017
cbd18e5
:construction: :fire: remove old Tab module
hackape Apr 12, 2017
1eaf13b
:construction: apply new Tab module to Terminal module
hackape Apr 12, 2017
7763455
:hammer: rewrite dragAndDrop with mobx, to make it a util
hackape Apr 13, 2017
618dba6
:fire: DragAndDrop don’t need reducer/action no more, remove them
hackape Apr 13, 2017
4b35057
Merge branch 'master' into hackape/tab-group-refine
hackape Apr 13, 2017
07615b0
Merge branch 'master' into hackape/tab-group-refine
hackape Apr 17, 2017
9d9503e
:sparkle: add a set of actions utils that implement the redux API wit…
hackape Apr 18, 2017
c958e2d
:zap: enhance actions utils
hackape Apr 21, 2017
e9d820d
:construction: enhance Tab/TabGroup methods
hackape Apr 22, 2017
5a77f15
:construction: empty TabGroup will gen a TablessEditor by default, li…
hackape Apr 22, 2017
941b22c
:construction::hammer: hook up Tab related parts with the new mobx im…
hackape Apr 22, 2017
616f778
:construction::hammer: hook up Pane related parts with the new mobx i…
hackape Apr 22, 2017
71d4335
:bug: fix CodeMirrorEditor bootstrap process.
hackape Apr 22, 2017
19550ed
Merge branch 'master' into hackape/tab-group-refine
hackape Apr 22, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions app/commands/commandBindings/file.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/* @flow weak */
import { bindActionCreators } from 'redux'
import store, { getState, dispatch } from '../../store'
import mobxStore from '../../mobxStore'
import { path as pathUtil } from '../../utils'
import api from '../../backendAPI'
import * as _Modal from '../../components/Modal/actions'
import * as Tab from '../../components/Tab'
import * as TabActions from 'commons/Tab/actions'
import { notify } from '../../components/Notification/actions'

const Modal = bindActionCreators(_Modal, dispatch)
Expand Down Expand Up @@ -74,9 +75,9 @@ export default {
}).then(createFolderAtPath)
},
'file:save': (c) => {
const { TabState } = getState()
const activeTab = Tab.selectors.getActiveTab(TabState)
const content = activeTab ? ide.editors[activeTab.id].getValue() : ''
const { EditorTabState } = mobxStore
const activeTab = EditorTabState.activeTab
const content = activeTab ? activeTab.editor.getValue() : ''

if (!activeTab.path) {
const createFile = createFileWithContent(content)
Expand All @@ -86,17 +87,17 @@ export default {
selectionRange: [1, '/untitled'.length]
})
.then(createFile)
.then(path => dispatch(Tab.actions.updateTab({
.then(path => dispatch(TabActions.updateTab({
id: activeTab.id,
path,
title: path.replace(/^.*\/([^\/]+$)/, '$1')
})))
.then(() => dispatch(Tab.actions.updateTabFlags(activeTab.id, 'modified', false)))
.then(() => dispatch(TabActions.updateTabFlags(activeTab.id, 'modified', false)))
} else {
api.writeFile(activeTab.path, content)
.then(() => {
dispatch(Tab.actions.updateTabFlags(activeTab.id, 'modified', false))
dispatch(Tab.actions.updateTab({
dispatch(TabActions.updateTabFlags(activeTab.id, 'modified', false))
dispatch(TabActions.updateTab({
id: activeTab.id, content: { body: content }
}))
})
Expand Down
17 changes: 9 additions & 8 deletions app/commands/commandBindings/tab.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
/* @flow weak */
import store, { dispatch as $d } from '../../store'
import * as Tab from '../../components/Tab/actions'
import * as PaneActions from '../../components/Pane/actions'
import { dispatch as $d } from '../../store'
import store from 'app/mobxStore'
import * as Tab from 'commons/Tab/actions'
import * as PaneActions from 'components/Pane/actions'

export default {
'tab:close': c => {
$d(Tab.removeTab(c.context.id))
Tab.removeTab(c.context.id)
},

'tab:close_other': c => {
$d(Tab.removeOtherTab(c.context.id))
Tab.removeOtherTab(c.context.id)
},

'tab:close_all': c => {
$d(Tab.removeAllTab(c.context.id))
Tab.removeAllTab(c.context.id)
},

'tab:split_v': c => {
const panes = store.getState().PaneState.panes
const pane = Object.values(panes).find((pane) => (
const panes = store.PaneState.panes
const pane = panes.values().find(pane => (
pane.content && pane.content.type === 'tabGroup' && pane.content.id === c.context.tabGroupId
))
$d(PaneActions.splitTo(pane.id, 'bottom'))
Expand Down
118 changes: 118 additions & 0 deletions app/commons/Tab/TabBar.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React, { Component, PropTypes } from 'react'
import cx from 'classnames'
import { observer } from 'mobx-react'
import { dnd } from 'utils'
import { defaultProps } from 'utils/decorators'
import TabLabel from './TabLabel'
import Menu from 'components/Menu'
import ContextMenu from 'components/ContextMenu'

@defaultProps(props => ({
addTab: () => props.tabGroup.addTab(),
}))
@observer
class TabBar extends Component {
static propTypes = {
tabGroup: PropTypes.object.isRequired,
contextMenuItems: PropTypes.array.isRequired,
addTab: PropTypes.func,
closePane: PropTypes.func,
};

constructor (props) {
super(props)
this.state = {
showDropdownMenu: false,
showContextMenu: false,
contextMenuPos: {},
contextMenuContext: null,
}
}

render () {
const {
tabGroup,
addTab,
contextMenuItems,
} = this.props

const tabBarId = `tab_bar_${tabGroup.id}`
return (
<div id={tabBarId}
className='tab-bar'
data-droppable='TABBAR'
onDoubleClick={addTab}
>
<ul className='tab-labels'>
{tabGroup.tabs.map(tab =>
<TabLabel tab={tab} key={tab.id} openContextMenu={this.openContextMenu} />
)}
</ul>
{dnd.target.id === tabBarId ? <div className='tab-label-insert-pos'></div>: null}
<div className='tab-add-btn' onClick={addTab} >
<svg viewBox='0 0 12 16' version='1.1' aria-hidden='true'>
<path fillRule='evenodd' d='M12 9H7v5H5V9H0V7h5V2h2v5h5z'></path>
</svg>
</div>
<div className='tab-show-list'
onClick={e => { e.stopPropagation(); this.setState({ showDropdownMenu: true }) }}
>
<i className='fa fa-sort-desc' />
{this.renderDropdownMenu()}
</div>
<ContextMenu
items={contextMenuItems}
isActive={this.state.showContextMenu}
pos={this.state.contextMenuPos}
context={this.state.contextMenuContext}
deactivate={() => this.setState({ showContextMenu: false })}
/>
</div>
)
}

openContextMenu = (e, context) => {
e.stopPropagation()
e.preventDefault()

this.setState({
showContextMenu: true,
contextMenuPos: { x: e.clientX, y: e.clientY },
contextMenuContext: context,
})
}

renderDropdownMenu () {
if (!this.state.showDropdownMenu) return null
const dropdownMenuItems = this.makeDropdownMenuItems()
if (!dropdownMenuItems.length) return null
return <Menu className='top-down to-left'
items={dropdownMenuItems}
style={{ right: '2px' }}
deactivate={e=>this.setState({ showDropdownMenu: false })}
/>

}

makeDropdownMenuItems = () => {
let baseItems = this.props.tabGroup.siblings.length === 0 ? []
: [{
name: 'Close Pane',
command: this.props.closePane,
}]
const tabs = this.props.tabGroup.tabs
const tabLabelsItem = tabs && tabs.map(tab => ({
name: tab.title || 'untitled',
command: e => tab.activate(),
}))

if (tabLabelsItem.length) {
if (!baseItems.length) return tabLabelsItem
return baseItems.concat({ name: '-' }, tabLabelsItem)
} else {
return baseItems
}
}
}

export default TabBar
20 changes: 20 additions & 0 deletions app/commons/Tab/TabContent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React, { PropTypes } from 'react'
import cx from 'classnames'
import { observer } from 'mobx-react'

export const TabContent = ({ children }) => (
<div className='tab-content'>
<div className='tab-content-container'>{children}</div>
</div>
)

export const TabContentItem = observer(({ tab, children }) => (
<div className={cx('tab-content-item', { active: tab.isActive })}>
{children}
</div>
))

TabContentItem.propTypes = {
tab: PropTypes.object.isRequired,
}

49 changes: 49 additions & 0 deletions app/commons/Tab/TabLabel.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React, { Component, PropTypes } from 'react'
import cx from 'classnames'
import { observer } from 'mobx-react'
import { dnd } from 'utils'
import { defaultProps } from 'utils/decorators'
import { dispatch } from '../../store'

let TabLabel = observer(({tab, removeTab, activateTab, openContextMenu}) => {
const tabLabelId = `tab_label_${tab.id}`
return (
<li className={cx('tab-label', {
active: tab.isActive,
modified: tab.flags.modified
})}
id={tabLabelId}
data-droppable='TABLABEL'
draggable='true'
onClick={e => activateTab(tab.id)}
onDragStart={e => dnd.dragStart({ type: 'TAB', id: tab.id }) }
onContextMenu={e => openContextMenu(e, tab)}
>
{dnd.target.id === tabLabelId ? <div className='tab-label-insert-pos'></div>: null}
{tab.icon ? <div className={tab.icon}></div>: null}
<div className='title'>{tab.title}</div>
<div className='control'>
<i className='close' onClick={e => { e.stopPropagation(); removeTab(tab.id) }}>×</i>
<i className='dot'></i>
</div>
</li>
)
})

TabLabel.propTypes = {
tab: PropTypes.object.isRequired,
removeTab: PropTypes.func.isRequired,
activateTab: PropTypes.func.isRequired,
openContextMenu: PropTypes.func.isRequired,
}

TabLabel = defaultProps(props => ({
activateTab: function () {
props.tab.activate()
},
removeTab: function () {
props.tab.destroy()
},
}))(TabLabel)

export default TabLabel
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* @flow weak */
import { createAction } from 'redux-actions'
import { createAction } from 'utils/actions'

export const TAB_DISSOLVE_GROUP = 'TAB_DISSOLVE_GROUP'

Expand Down
5 changes: 5 additions & 0 deletions app/commons/Tab/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import TabStateScope from './state'
import TabBar from './TabBar'
import { TabContent, TabContentItem } from './TabContent'

export { TabBar, TabContent, TabContentItem, TabStateScope }
Loading