Add global state and right click menu using redux

This commit is contained in:
Joey Payne 2016-02-19 12:48:47 -07:00
commit 54d64cc124
10 changed files with 190 additions and 81 deletions

13
app/actions/index.jsx Normal file
View file

@ -0,0 +1,13 @@
import * as types from '../constants'
export function updateContextMenu(items) {
return { type: types.UPDATE_CONTEXT_MENU, items }
}
export function openContextMenu(x, y){
return {type: types.OPEN_CONTEXT_MENU, x, y}
}
export function closeContextMenu(){
return {type: types.CLOSE_CONTEXT_MENU}
}

3
app/constants/index.jsx Normal file
View file

@ -0,0 +1,3 @@
export const UPDATE_CONTEXT_MENU = "UPDATE_CONTEXT_MENU"
export const OPEN_CONTEXT_MENU = "OPEN_CONTEXT_MENU"
export const CLOSE_CONTEXT_MENU = "CLOSE_CONTEXT_MENU"

View file

@ -11,6 +11,20 @@ import Delete from 'material-ui/lib/svg-icons/action/delete'
import Divider from 'material-ui/lib/divider'
import moment from 'moment'
import mui from 'material-ui'
import {Provider} from 'react-redux'
import { createStore } from 'redux'
import rootReducer from './reducers'
import * as ContextMenuActions from './actions'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
function getStore(reducer, initialState){
return createStore(reducer, initialState)
}
const store = getStore(rootReducer)
const {
Popover,
@ -43,11 +57,18 @@ class Main extends React.Component {
createTables()
this.state = {
entries: [],
contextMenuOpen: false,
contextMenuItems: this.context.contextMenuItems
}
}
static get childContextTypes(){
return {muiTheme: React.PropTypes.object}
}
getChildContext() {
return {
muiTheme: getMuiTheme(DefaultRawTheme)
}
}
entriesTapped = () => {
r.table('notes').getAll('jyapayne@gmail.com', {index: 'account_id'}).run().then(
@ -58,33 +79,27 @@ class Main extends React.Component {
};
handleRequestClose = () => {
this.setState({
contextMenuOpen: false,
})
this.props.contextMenuActions.closeContextMenu()
};
tapped = () => {
console.log('tapped')
console.log(this.context.contextMenuItems)
};
render() {
const { contextMenu, contextMenuActions } = this.props
return (
<div onTouchTap={this.tapped}>
<div className="fill-height">
<div style={{position: 'absolute',
width: 1,
height: 1,
top: this.state.popTop,
left: this.state.popLeft}} ref='menuPos'></div>
top: contextMenu.y,
left: contextMenu.x}} ref='menuPos'></div>
<Popover
open={this.state.contextMenuOpen}
open={contextMenu.opened}
anchorEl={this.refs.menuPos}
anchorOrigin={{horizontal: 'middle', vertical: 'bottom'}}
targetOrigin={{horizontal: 'left', vertical: 'top'}}
onRequestClose={this.handleRequestClose}>
<Menu desktop={true}>
{this.state.contextMenuItems.map(function (el, i){
{contextMenu.items.map(function (el, i){
return el;
})}
</Menu>
@ -94,39 +109,40 @@ class Main extends React.Component {
id="library-nav"
ref="libraryNav"
entriesTapped={this.entriesTapped}
className="left inline fill-height"/>
className="left inline fill-height"
{...contextMenuActions}
/>
</div>
)
}
}
class S extends React.Component {
static get childContextTypes(){
return {muiTheme: React.PropTypes.object,
contextMenuItems: React.PropTypes.array}
}
getChildContext() {
return {
muiTheme: getMuiTheme(DefaultRawTheme),
contextMenuItems: []
}
}
render(){
return <Main />
}
}
Main.propTypes = {
contextMenu: React.PropTypes.object.isRequired,
contextMenuActions: React.PropTypes.object.isRequired
}
Main.contextTypes = {
contextMenuItems: React.PropTypes.array.isRequired
};
function mapStateToProps(state) {
return {
contextMenu: state.contextMenu
}
}
function mapDispatchToProps(dispatch) {
return {
contextMenuActions: bindActionCreators(ContextMenuActions, dispatch)
}
}
let App = connect(
mapStateToProps,
mapDispatchToProps
)(Main)
export default App
ReactDOM.render(
<S />,
<Provider store={store}><App /></Provider>,
document.getElementById('main')
);

View file

@ -1,4 +1,5 @@
import React from 'react'
import ReactDOM from 'react-dom'
import mui from 'material-ui'
import getMuiTheme from 'material-ui/lib/styles/getMuiTheme'
@ -18,6 +19,16 @@ import { SelectableContainerEnhance } from 'material-ui/lib/hoc/selectable-enhan
const colors = styles.Colors
function eventFire(el, etype){
if (el.fireEvent) {
el.fireEvent('on' + etype);
} else {
var evObj = document.createEvent('Events');
evObj.initEvent(etype, true, false);
el.dispatchEvent(evObj);
}
}
const {AppBar,
AppCanvas,
FontIcon,
@ -71,7 +82,6 @@ export default class LibraryNav extends React.Component {
constructor(props, context){
super(props, context)
console.log(this.state)
this.state = {
open: false,
navItems: [
@ -109,6 +119,17 @@ export default class LibraryNav extends React.Component {
],
notebooks: [
{'state': 'editing', 'title': '', 'notes': 0},
{'state': 'displaying', 'title': 'FieldNotes', 'notes': 10},
{'state': 'displaying', 'title': 'FieldNotes', 'notes': 10},
{'state': 'displaying', 'title': 'FieldNotes', 'notes': 10},
{'state': 'displaying', 'title': 'FieldNotes', 'notes': 10},
{'state': 'displaying', 'title': 'FieldNotes', 'notes': 10},
{'state': 'displaying', 'title': 'FieldNotes', 'notes': 10},
{'state': 'displaying', 'title': 'FieldNotes', 'notes': 10},
{'state': 'displaying', 'title': 'FieldNotes', 'notes': 10},
{'state': 'displaying', 'title': 'FieldNotes', 'notes': 10},
{'state': 'displaying', 'title': 'FieldNotes', 'notes': 10},
{'state': 'displaying', 'title': 'FieldNotes', 'notes': 10},
{'state': 'displaying', 'title': 'FieldNotes', 'notes': 10}
]
}
@ -139,6 +160,10 @@ export default class LibraryNav extends React.Component {
nb.state = 'displaying'
this.setState({notebooks: this.state.notebooks})
}
else if(nb.title){
nb.state = 'displaying'
this.setState({notebooks: this.state.notebooks})
}
};
addNotebookTapped = () => {
@ -160,49 +185,53 @@ export default class LibraryNav extends React.Component {
}
};
renameTapped = (i) => {
var nbs = this.state.notebooks
nbs[i].state = 'editing'
this.setState({notebooks: nbs})
this.props.closeContextMenu()
//ReactDOM.findDOMNode(this.refs[nbs[i].title+i]).click()
}
deleteTapped = (i) => {
var nbs = this.state.notebooks
nbs.splice(i, 1)
this.setState({notebooks: nbs})
this.props.closeContextMenu()
}
contextMenuItems = (i) => {
return [
<MenuItem
key='rename'
primaryText="Rename"
leftIcon={<Edit />}
onTouchTap={this.renameTapped.bind(this, i)}/>,
<Divider key='div1'/>,
<MenuItem
key='delete'
primaryText="Delete"
onTouchTap={this.deleteTapped.bind(this, i)}
leftIcon={<Delete />} />
]
};
noteBookTapped = (i, ev) => {
var nativeEvent = ev.nativeEvent
if(nativeEvent.button == 2){
//Right click
var x = nativeEvent.pageX
var y = nativeEvent.pageY
this.context.contextMenuItems = [
<MenuItem primaryText="Rename" leftIcon={<Edit />} />,
<Divider />,
<MenuItem primaryText="Delete" leftIcon={<Delete />} />
]
this.setState({
popTop: y,
popLeft: x,
open: true
})
this.props.updateContextMenu(this.contextMenuItems(i))
this.props.openContextMenu(x, y)
}
};
handleRequestClose = () => {
this.setState({
open: false,
})
};
render(){
return (
<div id={this.props.id} className={this.props.className || ""}>
<div style={{position: 'absolute', width: 1, height: 1, top: this.state.popTop, left: this.state.popLeft}} ref='menuPos'></div>
<Popover
open={this.state.open}
anchorEl={this.refs.menuPos}
anchorOrigin={{horizontal: 'middle', vertical: 'bottom'}}
targetOrigin={{horizontal: 'left', vertical: 'top'}}
onRequestClose={this.handleRequestClose}>
<Menu desktop={true}>
<MenuItem primaryText="Rename" leftIcon={<Edit />} />
<Divider />
<MenuItem primaryText="Delete" leftIcon={<Delete />} />
</Menu>
</Popover>
<SelectableList subheader="Library">
{this.state.navItems.map((item, i) => {
return <ListItem
@ -216,6 +245,7 @@ export default class LibraryNav extends React.Component {
})}
</SelectableList>
<Divider />
<div>
<List subheader={<div>
<div className="inline">NoteBooks</div>
<IconButton
@ -227,6 +257,7 @@ export default class LibraryNav extends React.Component {
color={colors.grey500}/>
</IconButton>
</div>}>
<div>
{this.state.notebooks.map((notebook, i) =>{
var l = null
@ -252,6 +283,7 @@ export default class LibraryNav extends React.Component {
l = <ListItem
key={i}
primaryText={notebook.title}
ref={notebook.title+i}
className="noselect"
onTouchTap={this.noteBookTapped.bind(this, i)}
leftIcon={<NoteBook color={colors.grey500}/>}
@ -260,14 +292,11 @@ export default class LibraryNav extends React.Component {
}
return l
})}
</div>
</List>
</div>
</div>
)
}
}
LibraryNav.contextTypes = {
contextMenuItems: React.PropTypes.array.isRequired
};

View file

@ -0,0 +1,31 @@
import { UPDATE_CONTEXT_MENU, OPEN_CONTEXT_MENU, CLOSE_CONTEXT_MENU } from '../constants'
const initialState =
{
opened: false,
x: 0,
y: 0,
items: []
}
export default function contextMenu(state = initialState, action){
switch (action.type) {
case UPDATE_CONTEXT_MENU:
return Object.assign({}, state,{
items: action.items
})
case OPEN_CONTEXT_MENU:
return Object.assign({}, state, {
opened: true,
x: action.x,
y: action.y
})
case CLOSE_CONTEXT_MENU:
return Object.assign({}, state, {
opened: false
})
default:
return state
}
}

8
app/reducers/index.jsx Normal file
View file

@ -0,0 +1,8 @@
import { combineReducers } from 'redux'
import contextMenu from './contextMenu'
const rootReducer = combineReducers({
contextMenu
})
export default rootReducer