Skip to content

Hackape/dnd tab on pane #19

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 3 commits into from
Nov 7, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 8 additions & 2 deletions app/components/AceEditor/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ class AceEditor extends Component {
editor.setTheme(`ace/theme/${theme}`);
editor.$blockScrolling = Infinity;
// dispatch(EditorActions.registerEditor(this.state.name, editor, this.editorDOM));
if (tab.content) {
if (tab.editor) {
editor.setSession(tab.editor.getSession())
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tab.editor 是一个 ace Editor 实例。tab 在转移 tabGroup 的时候会把 tab.editor 一起带着走,但我找不到简单的方法去替换这个 editor instance 对应的 DOM,所以退而求其次,把它的 editorSession 转移到新建的 editor instance 里,效果也一样。

} else if (tab.content) {
const {body, path} = tab.content;
if (body) editor.setValue(body, -1);
require([`brace/mode/${getMode(path)}`], () =>
Expand All @@ -66,7 +68,11 @@ class AceEditor extends Component {
editor.focus();
tab.editor = editor;
editor.session.on('change', this.onChange)
setTimeout( () => editor.resize(), 0);
setTimeout( () => editor.resize(), 0)

editor.on('focus', () => {
this.props.dispatch(TabActions.activateTab(tab.id))
})
}

render () {
Expand Down
11 changes: 6 additions & 5 deletions app/components/DragAndDrop/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { connect } from 'react-redux'
import _ from 'lodash'
import { dragOverTarget, updateDragOverMeta, dragEnd } from './actions'
import * as PaneActions from '../Pane/actions'
import * as TabActions from '../Tab/actions'

@connect(state => state.DragAndDrop)
class DragAndDrop extends Component {
Expand Down Expand Up @@ -74,11 +75,11 @@ class DragAndDrop extends Component {
if (!source || !target) return
switch (`${source.type}_to_${target.type}`) {
case 'TAB_to_PANE':
if (meta.paneSplitDirection === 'center') {

} else {
dispatch(PaneActions.splitTo(target.id, meta.paneSplitDirection))
}
dispatch(PaneActions.splitTo(target.id, meta.paneSplitDirection))
.then(newPane => {
let tabGroupId = newPane.views[0]
dispatch(TabActions.moveTabToGroup(source.id, tabGroupId))
})
}
dispatch(dragEnd())
}
Expand Down
37 changes: 9 additions & 28 deletions app/components/Modal/actions.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,16 @@
/* @flow weak */
const createAction = (action) => {
var resolve, reject
var promise = new Promise((rs, rj) => { resolve = rs; reject = rj })
var baseAction = {
meta: { promise, resolve, reject },
then: promise.then.bind(promise),
catch: promise.catch.bind(promise)
}

return Object.assign(baseAction, action)
}
import { createAction } from 'redux-actions'
import { promiseActionMixin } from '../../utils'

export const MODAL_SHOW = 'MODAL_SHOW'
export function showModal (modalType, content) {
return createAction({
type: MODAL_SHOW,
payload: {modalType, content}
})
}
export const showModal = promiseActionMixin(
createAction(MODAL_SHOW, (modalType, content) => ({modalType, content}))
)

export const MODAL_DISMISS = 'MODAL_DISMISS'
export function dismissModal () {
return {
type: MODAL_DISMISS
}
}
export const dismissModal = createAction(MODAL_DISMISS)

export const MODAL_UPDATE = 'MODAL_UPDATE'
export function updateModal (content) {
return createAction({
type: MODAL_UPDATE,
payload: {content}
})
}
export const updateModal = promiseActionMixin(
createAction(MODAL_UPDATE, content => ({content}))
)
5 changes: 3 additions & 2 deletions app/components/Pane/actions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* @flow weak */
import { createAction } from 'redux-actions'
import { promiseActionMixin } from '../../utils'

export const PANE_INITIALIZE = 'PANE_INITIALIZE'
export const PANE_UNSET_COVER = 'PANE_UNSET_COVER'
Expand All @@ -21,6 +22,6 @@ export const split = createAction(PANE_SPLIT_WITH_KEY,
)

export const PANE_SPLIT = 'PANE_SPLIT'
export const splitTo = createAction(PANE_SPLIT,
(paneId, splitDirection) => ({paneId, splitDirection})
export const splitTo = promiseActionMixin(
createAction(PANE_SPLIT, (paneId, splitDirection) => ({paneId, splitDirection}))
)
21 changes: 13 additions & 8 deletions app/components/Pane/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ class Pane {
* @param {string} splitCount
*/
splitToDirection (splitDirection) {
let flexDirection
let flexDirection, newPane
if (splitDirection === 'center') return this
switch (splitDirection) {
case 'right':
case 'left':
Expand All @@ -109,23 +110,27 @@ class Pane {
// If flexDirection is same as parent's,
// then we can simply push the newly splitted view into parent's "views" array
if (parent && parent.flexDirection === flexDirection) {
let newPane = new Pane({views: ['']}, parent)
newPane = new Pane({views: ['']}, parent)
if (splitDirection === 'right' || splitDirection === 'bottom') {
this.addSibling(newPane)
} else {
this.addSibling(newPane, -1)
}
// If flexDirection is NOT the same as parent's,
// that means we should spawn a child pane
} else {
let curTabGroupId = this.views.pop()
this.views.push(new Pane({views:[curTabGroupId]}, this))

let childPane = new Pane({views: ['']}, this)
newPane = new Pane({views: ['']}, this)
if (splitDirection === 'right' || splitDirection === 'bottom') {
this.addChild(childPane, 1)
this.addChild(newPane, 1)
} else {
this.addChild(childPane, 0)
this.addChild(newPane, 0)
}
}

return newPane
}

splitPane (splitCount=this.views.length+1, flexDirection=this.flexDirection) {
Expand Down Expand Up @@ -270,11 +275,11 @@ export const PaneCrossReducer = handleActions({
var {PaneState, TabState} = allStates
var {paneId, splitDirection} = action.payload
var pane = getPaneById(paneId)
console.log(paneId+': '+splitDirection);
pane.splitToDirection(splitDirection)
var newPane = pane.splitToDirection(splitDirection)
action.meta.resolve(newPane)

return { ...allStates,
PaneState: {root: Pane.root, timestamp: Date.now()}
PaneState: {root: new Pane(Pane.root)}
}
}
})
Expand Down
5 changes: 5 additions & 0 deletions app/components/Tab/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,8 @@ export const updateTabFlags = (tabId, flag, value=true) => {
payload
}
}

export const TAB_MOVE_TO_GROUP = 'TAB_MOVE_TO_GROUP'
export const moveTabToGroup = createAction(TAB_MOVE_TO_GROUP,
(tabId, groupId) => ({tabId, groupId})
)
18 changes: 17 additions & 1 deletion app/components/Tab/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {
TAB_REMOVE_GROUP,
TAB_DISSOLVE_GROUP,
TAB_UPDATE,
TAB_UPDATE_FLAGS
TAB_UPDATE_FLAGS,
TAB_MOVE_TO_GROUP
} from './actions'

class Tab {
Expand Down Expand Up @@ -204,6 +205,21 @@ export default handleActions({
var tab = getTabById(tabId)
tab.updateFlags(flags)
return normalizeState(state)
},

[TAB_MOVE_TO_GROUP]: (state, action) => {
const {tabId, groupId} = action.payload
let tab = getTabById(tabId)
if (tab.group.id === groupId) return state

let tabGroup = getGroupById(groupId)
if (tab.isActive) {
tab.group.activateNextTab()
}
tab.group.removeTab(tab)
tabGroup.tabs.push(tab)
tabGroup.activateTab(tab)
return normalizeState(state)
}
}, _state)

Expand Down
1 change: 1 addition & 0 deletions app/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export path from './path'
export request from './request'
export setSelectionRange from './setSelectionRange'
export composeReducers from './composeReducers'
export promiseActionMixin from './promiseActionMixin'
18 changes: 18 additions & 0 deletions app/utils/promiseActionMixin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const promiseActionMixin = (actionCreator) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这是之前在 Modal/actions 里用就过的一个模式,就是给 action 补上 .then/.catch 方法,让它成为一个伪 promise,可以在任何需要的地方调用 action.meta.resolve/.reject 来出发 promise resolve/reject.

现在把它抽象出来放到 utils 里。

return function decoratedActionCreator () {
const action = actionCreator.apply(null, arguments)

let resolve, reject
let promise = new Promise((rs, rj) => { resolve = rs; reject = rj })
let meta = { promise, resolve, reject }

return {
...action,
meta: action.meta ? {...action.meta, ...meta} : meta,
then: promise.then.bind(promise),
catch: promise.catch.bind(promise)
}
}
}

export default promiseActionMixin