1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-20 13:11:44 +00:00

実装 - Hotkey

This commit is contained in:
Rokt33r
2015-08-22 23:57:37 +09:00
parent b88d5cfb06
commit da066fe694
24 changed files with 378 additions and 61 deletions

View File

@@ -4,12 +4,20 @@ var version = remote.getGlobal('version')
var React = require('react/addons') var React = require('react/addons')
var ExternalLink = require('../Mixins/ExternalLink') var ExternalLink = require('../Mixins/ExternalLink')
var KeyCaster = require('../Mixins/KeyCaster')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [ExternalLink], mixins: [ExternalLink, KeyCaster('aboutModal')],
propTypes: { propTypes: {
close: React.PropTypes.func close: React.PropTypes.func
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
}
},
render: function () { render: function () {
return ( return (
<div className='AboutModal modal'> <div className='AboutModal modal'>

View File

@@ -5,6 +5,8 @@ var LinkedState = require('../Mixins/LinkedState')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var KeyCaster = require('../Mixins/KeyCaster')
var UserStore = require('../Stores/UserStore') var UserStore = require('../Stores/UserStore')
var getOptions = function (input, callback) { var getOptions = function (input, callback) {
@@ -26,7 +28,7 @@ var getOptions = function (input, callback) {
} }
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('addMemberModal')],
propTypes: { propTypes: {
team: React.PropTypes.object, team: React.PropTypes.object,
close: React.PropTypes.func close: React.PropTypes.func
@@ -37,6 +39,16 @@ module.exports = React.createClass({
role: 'member' role: 'member'
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
case 'submitAddMemberModal':
this.handleSubmit()
break
}
},
handleSubmit: function () { handleSubmit: function () {
Hq Hq
.addMember(this.props.team.name, { .addMember(this.props.team.name, {

View File

@@ -2,19 +2,26 @@ var React = require('react')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var KeyCaster = require('../Mixins/KeyCaster')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [KeyCaster('codeDeleteModal')],
propTypes: { propTypes: {
planet: React.PropTypes.object, planet: React.PropTypes.object,
code: React.PropTypes.object, code: React.PropTypes.object,
close: React.PropTypes.func close: React.PropTypes.func
}, },
componentDidMount: function () { onKeyCast: function (e) {
React.findDOMNode(this).focus() switch (e.status) {
}, case 'submitCodeDeleteModal':
stopPropagation: function (e) { this.submit()
e.stopPropagation() break
case 'closeModal':
this.props.close()
break
}
}, },
submit: function () { submit: function () {
var planet = this.props.planet var planet = this.props.planet

View File

@@ -7,13 +7,19 @@ module.exports = React.createClass({
code: React.PropTypes.object, code: React.PropTypes.object,
planet: React.PropTypes.object planet: React.PropTypes.object
}, },
componentDidMount: function () {
// TODO: Hacked!! should fix later
setTimeout(function () {
React.findDOMNode(this.refs.form.refs.description).focus()
}.bind(this), 1)
},
render: function () { render: function () {
return ( return (
<div className='CodeEditModal modal'> <div className='CodeEditModal modal'>
<div className='modal-header'> <div className='modal-header'>
<h1>Edit Code</h1> <h1>Edit Code</h1>
</div> </div>
<CodeForm code={this.props.code} planet={this.props.planet} close={this.props.close}/> <CodeForm ref='form' code={this.props.code} planet={this.props.planet} close={this.props.close}/>
</div> </div>
) )
} }

View File

@@ -5,6 +5,7 @@ var Select = require('react-select')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var KeyCaster = require('../Mixins/KeyCaster')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
@@ -29,7 +30,7 @@ var getOptions = function (input, callback) {
} }
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('codeForm')],
propTypes: { propTypes: {
planet: React.PropTypes.object, planet: React.PropTypes.object,
close: React.PropTypes.func, close: React.PropTypes.func,
@@ -55,6 +56,16 @@ module.exports = React.createClass({
code: code code: code
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'submitCodeForm':
this.submit()
break
case 'closeModal':
this.props.close()
break
}
},
handleModeChange: function (selected) { handleModeChange: function (selected) {
var code = this.state.code var code = this.state.code
code.mode = selected code.mode = selected

View File

@@ -1,11 +1,12 @@
var React = require('react') var React = require('react')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var KeyCaster = require('../Mixins/KeyCaster')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('contactModal')],
propTypes: { propTypes: {
close: React.PropTypes.func close: React.PropTypes.func
}, },
@@ -18,6 +19,23 @@ module.exports = React.createClass({
} }
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
case 'submitContactModal':
if (this.state.isSent) {
this.props.close()
return
}
this.sendEmail()
break
}
},
componentDidMount: function () {
React.findDOMNode(this.refs.title).focus()
},
sendEmail: function () { sendEmail: function () {
Hq.sendEmail(this.state.mail) Hq.sendEmail(this.state.mail)
.then(function (res) { .then(function (res) {
@@ -36,7 +54,7 @@ module.exports = React.createClass({
<div className='contactForm'> <div className='contactForm'>
<div className='modal-body'> <div className='modal-body'>
<div className='formField'> <div className='formField'>
<input valueLink={this.linkState('mail.title')} placeholder='Title'/> <input ref='title' valueLink={this.linkState('mail.title')} placeholder='Title'/>
</div> </div>
<div className='formField'> <div className='formField'>
<textarea valueLink={this.linkState('mail.content')} placeholder='Content'/> <textarea valueLink={this.linkState('mail.content')} placeholder='Content'/>

View File

@@ -5,17 +5,19 @@ var React = require('react/addons')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var KeyCaster = require('../Mixins/KeyCaster')
var UserStore = require('../Stores/UserStore') var UserStore = require('../Stores/UserStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('editProfileModal')],
propTypes: { propTypes: {
user: React.PropTypes.shape({ user: React.PropTypes.shape({
name: React.PropTypes.string, name: React.PropTypes.string,
profileName: React.PropTypes.string, profileName: React.PropTypes.string,
email: React.PropTypes.string email: React.PropTypes.string
}) }),
close: React.PropTypes.func
}, },
getInitialState: function () { getInitialState: function () {
var user = this.props.user var user = this.props.user
@@ -34,6 +36,13 @@ module.exports = React.createClass({
passwordSubmitStatus: null passwordSubmitStatus: null
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
}
},
selectTab: function (tabName) { selectTab: function (tabName) {
return function () { return function () {
this.setState({currentTab: tabName}) this.setState({currentTab: tabName})

View File

@@ -96,6 +96,10 @@ module.exports = React.createClass({
handleLogoutClick: function () { handleLogoutClick: function () {
this.openModal(LogoutModal, {transitionTo: this.transitionTo}) this.openModal(LogoutModal, {transitionTo: this.transitionTo})
}, },
switchPlanetByIndex: function (index) {
var planetProps = this.refs.planets.props.children[index - 1].props
this.transitionTo('planet', {userName: planetProps.userName, planetName: planetProps.planetName})
},
render: function () { render: function () {
var params = this.getParams() var params = this.getParams()
@@ -110,12 +114,12 @@ module.exports = React.createClass({
return team.Planets == null ? planets : planets.concat(team.Planets) return team.Planets == null ? planets : planets.concat(team.Planets)
}, []))).map(function (planet, index) { }, []))).map(function (planet, index) {
return ( return (
<li key={planet.id} className={params.userName === planet.userName && params.planetName === planet.name ? 'active' : ''}> <li userName={planet.userName} planetName={planet.name} key={planet.id} className={params.userName === planet.userName && params.planetName === planet.name ? 'active' : ''}>
<Link to='planet' params={{userName: planet.userName, planetName: planet.name}}> <Link to='planet' params={{userName: planet.userName, planetName: planet.name}}>
{planet.name[0]} {planet.name[0]}
<div className='planetTooltip'>{planet.userName}/{planet.name}</div> <div className='planetTooltip'>{planet.userName}/{planet.name}</div>
</Link> </Link>
<div className='shortCut'>{index + 1}</div> {index < 9 ? (<div className='shortCut'>{index + 1}</div>) : null}
</li> </li>
) )
}) })
@@ -128,7 +132,7 @@ module.exports = React.createClass({
<ProfileImage size='55' email={this.state.currentUser.email}/> <ProfileImage size='55' email={this.state.currentUser.email}/>
</button> </button>
{popup} {popup}
<ul className='planetList'> <ul ref='planets' className='planetList'>
{planets} {planets}
</ul> </ul>
<button onClick={this.openPlanetCreateModal} className='newPlanet'> <button onClick={this.openPlanetCreateModal} className='newPlanet'>

View File

@@ -15,34 +15,52 @@ module.exports = React.createClass({
} }
}, },
componentDidMount: function () { componentDidMount: function () {
var codeButton = React.findDOMNode(this.refs.codeButton)
codeButton.addEventListener('keydown', this.handleKeyDown)
React.findDOMNode(this.refs.noteButton).addEventListener('keydown', this.handleKeyDown)
codeButton.focus()
}, },
stopPropagation: function (e) { componentWillUnmount: function () {
e.stopPropagation() React.findDOMNode(this.refs.codeButton).removeEventListener('keydown', this.handleKeyDown)
}, React.findDOMNode(this.refs.noteButton).removeEventListener('keydown', this.handleKeyDown)
selectCodeTab: function () {
this.setState({currentTab: 'code'})
},
selectNoteTab: function () {
this.setState({currentTab: 'note'})
}, },
handleKeyDown: function (e) { handleKeyDown: function (e) {
if (e.keyCode === 37 && e.metaKey) { if (e.keyCode === 37 && e.metaKey) {
this.selectCodeTab() this.selectCodeTab()
e.stopPropagation()
return
} }
if (e.keyCode === 39 && e.metaKey) { if (e.keyCode === 39 && e.metaKey) {
this.selectNoteTab() this.selectNoteTab()
e.stopPropagation()
return
} }
if (e.keyCode === 9) {
if (this.state.currentTab === 'code') React.findDOMNode(this.refs.form.refs.description).focus()
else React.findDOMNode(this.refs.form.refs.title).focus()
e.preventDefault()
}
},
selectCodeTab: function () {
this.setState({currentTab: 'code'}, function () {
React.findDOMNode(this.refs.codeButton).focus()
})
},
selectNoteTab: function () {
this.setState({currentTab: 'note'}, function () {
React.findDOMNode(this.refs.noteButton).focus()
})
}, },
render: function () { render: function () {
var modalBody var modalBody
if (this.state.currentTab === 'code') { if (this.state.currentTab === 'code') {
modalBody = ( modalBody = (
<CodeForm planet={this.props.planet} transitionTo={this.props.transitionTo} close={this.props.close}/> <CodeForm ref='form' planet={this.props.planet} transitionTo={this.props.transitionTo} close={this.props.close}/>
) )
} else { } else {
modalBody = ( modalBody = (
<NoteForm planet={this.props.planet} transitionTo={this.props.transitionTo} close={this.props.close}/> <NoteForm ref='form' planet={this.props.planet} transitionTo={this.props.transitionTo} close={this.props.close}/>
) )
} }
@@ -50,7 +68,8 @@ module.exports = React.createClass({
<div className='LaunchModal modal'> <div className='LaunchModal modal'>
<div className='modal-header'> <div className='modal-header'>
<div className='modal-tab'> <div className='modal-tab'>
<button className={this.state.currentTab === 'code' ? 'btn-primary active' : 'btn-default'} onClick={this.selectCodeTab}>Code</button><button className={this.state.currentTab === 'note' ? 'btn-primary active' : 'btn-default'} onClick={this.selectNoteTab}>Note</button> <button ref='codeButton' className={this.state.currentTab === 'code' ? 'btn-primary active' : 'btn-default'} onClick={this.selectCodeTab}>Code</button>
<button ref='noteButton' className={this.state.currentTab === 'note' ? 'btn-primary active' : 'btn-default'} onClick={this.selectNoteTab}>Note</button>
</div> </div>
</div> </div>
{modalBody} {modalBody}

View File

@@ -2,11 +2,24 @@
var React = require('react') var React = require('react')
var KeyCaster = require('../Mixins/KeyCaster')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [KeyCaster('logoutModal')],
propTypes: { propTypes: {
transitionTo: React.PropTypes.func, transitionTo: React.PropTypes.func,
close: React.PropTypes.func close: React.PropTypes.func
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
case 'submitLogoutModal':
this.logout()
break
}
},
logout: function () { logout: function () {
localStorage.removeItem('currentUser') localStorage.removeItem('currentUser')
localStorage.removeItem('token') localStorage.removeItem('token')

View File

@@ -2,16 +2,26 @@ var React = require('react')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var KeyCaster = require('../Mixins/KeyCaster')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [KeyCaster('noteDeleteModal')],
propTypes: { propTypes: {
planet: React.PropTypes.object, planet: React.PropTypes.object,
note: React.PropTypes.object, note: React.PropTypes.object,
close: React.PropTypes.func close: React.PropTypes.func
}, },
componentDidMount: function () { onKeyCast: function (e) {
React.findDOMNode(this).focus() switch (e.status) {
case 'submitNoteDeleteModal':
this.submit()
break
case 'closeModal':
this.props.close()
break
}
}, },
submit: function () { submit: function () {
var planet = this.props.planet var planet = this.props.planet

View File

@@ -8,13 +8,19 @@ module.exports = React.createClass({
note: React.PropTypes.object, note: React.PropTypes.object,
planet: React.PropTypes.object planet: React.PropTypes.object
}, },
componentDidMount: function () {
// TODO: Hacked!! should fix later
setTimeout(function () {
React.findDOMNode(this.refs.form.refs.title).focus()
}.bind(this), 1)
},
render: function () { render: function () {
return ( return (
<div className='NoteEditModal modal'> <div className='NoteEditModal modal'>
<div className='modal-header'> <div className='modal-header'>
<h1>Edit Note</h1> <h1>Edit Note</h1>
</div> </div>
<NoteForm note={this.props.note} planet={this.props.planet} close={this.props.close}/> <NoteForm ref='form' note={this.props.note} planet={this.props.planet} close={this.props.close}/>
</div> </div>
) )
} }

View File

@@ -1,11 +1,11 @@
var React = require('react/addons') var React = require('react/addons')
var ReactRouter = require('react-router')
var Select = require('react-select') var Select = require('react-select')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var Markdown = require('../Mixins/Markdown') var Markdown = require('../Mixins/Markdown')
var KeyCaster = require('../Mixins/KeyCaster')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
@@ -34,7 +34,7 @@ var EDIT_MODE = 0
var PREVIEW_MODE = 1 var PREVIEW_MODE = 1
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState, Markdown], mixins: [LinkedState, Markdown, KeyCaster('noteForm')],
propTypes: { propTypes: {
planet: React.PropTypes.object, planet: React.PropTypes.object,
close: React.PropTypes.func, close: React.PropTypes.func,
@@ -58,8 +58,15 @@ module.exports = React.createClass({
mode: EDIT_MODE mode: EDIT_MODE
} }
}, },
componentDidMount: function () { onKeyCast: function (e) {
React.findDOMNode(this.refs.title).focus() switch (e.status) {
case 'submitNoteForm':
this.submit()
break
case 'closeModal':
this.props.close()
break
}
}, },
handleTagsChange: function (selected, all) { handleTagsChange: function (selected, all) {
var note = this.state.note var note = this.state.note

View File

@@ -25,6 +25,7 @@ module.exports = React.createClass({
} }
}, },
openEditModal: function () { openEditModal: function () {
if (this.props.article == null) return
switch (this.props.article.type) { switch (this.props.article.type) {
case 'code' : case 'code' :
this.openModal(CodeEditModal, {code: this.props.article, planet: this.props.planet}) this.openModal(CodeEditModal, {code: this.props.article, planet: this.props.planet})
@@ -34,6 +35,7 @@ module.exports = React.createClass({
} }
}, },
openDeleteModal: function () { openDeleteModal: function () {
if (this.props.article == null) return
switch (this.props.article.type) { switch (this.props.article.type) {
case 'code' : case 'code' :
this.openModal(CodeDeleteModal, {code: this.props.article, planet: this.props.planet}) this.openModal(CodeDeleteModal, {code: this.props.article, planet: this.props.planet})

View File

@@ -1,6 +1,5 @@
var React = require('react/addons') var React = require('react/addons')
var ReactRouter = require('react-router') var ReactRouter = require('react-router')
var Link = ReactRouter.Link
var moment = require('moment') var moment = require('moment')
var ForceUpdate = require('../Mixins/ForceUpdate') var ForceUpdate = require('../Mixins/ForceUpdate')
@@ -51,8 +50,6 @@ module.exports = React.createClass({
var params = this.getParams() var params = this.getParams()
var isActive = article.type === 'code' ? this.isActive('codes') && parseInt(params.localId, 10) === article.localId : this.isActive('notes') && parseInt(params.localId, 10) === article.localId var isActive = article.type === 'code' ? this.isActive('codes') && parseInt(params.localId, 10) === article.localId : this.isActive('notes') && parseInt(params.localId, 10) === article.localId
var handleClick
if (article.type === 'code') { if (article.type === 'code') {
return ( return (
<li onClick={this.handleArticleClikck(article)} key={'code-' + article.id}> <li onClick={this.handleArticleClikck(article)} key={'code-' + article.id}>

View File

@@ -5,11 +5,12 @@ var React = require('react/addons')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var KeyCaster = require('../Mixins/KeyCaster')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('planetCreateModal')],
propTypes: { propTypes: {
ownerName: React.PropTypes.string, ownerName: React.PropTypes.string,
transitionTo: React.PropTypes.func, transitionTo: React.PropTypes.func,
@@ -30,9 +31,14 @@ module.exports = React.createClass({
componentDidMount: function () { componentDidMount: function () {
React.findDOMNode(this.refs.name).focus() React.findDOMNode(this.refs.name).focus()
}, },
onListen: function (res) { onKeyCast: function (e) {
if (res.status === 'planetCreated') { switch (e.status) {
this.props.close() case 'closeModal':
this.props.close()
break
case 'submitPlanetCreateModal':
this.handleSubmit()
break
} }
}, },
handleSubmit: function () { handleSubmit: function () {

View File

@@ -21,7 +21,21 @@ module.exports = React.createClass({
} }
}, },
componentDidMount: function () { componentDidMount: function () {
React.findDOMNode(this.refs.search).focus() var search = React.findDOMNode(this.refs.search)
search.addEventListener('keydown', this.handleSearchKeyDown)
},
componentWillUnmount: function () {
var search = React.findDOMNode(this.refs.search)
search.removeEventListener('keydown', this.handleSearchKeyDown)
},
handleSearchKeyDown: function (e) {
if (e.keyCode === 38 || e.keyCode === 40) {
var search = React.findDOMNode(this.refs.search)
search.blur()
}
if (e.keyCode !== 27 && (e.keyCode !== 13 || !e.metaKey)) {
e.stopPropagation()
}
}, },
openPlanetSettingModal: function () { openPlanetSettingModal: function () {
this.openModal(PlanetSettingModal, {planet: this.props.currentPlanet}) this.openModal(PlanetSettingModal, {planet: this.props.currentPlanet})

View File

@@ -3,9 +3,10 @@ var ReactRouter = require('react-router')
var Navigation = ReactRouter.Navigation var Navigation = ReactRouter.Navigation
var Modal = require('../Mixins/Modal') var Modal = require('../Mixins/Modal')
var LaunchModal = require('../Components/LaunchModal') var LaunchModal = require('../Components/LaunchModal')
var PlanetNavigator = React.createClass({ module.exports = React.createClass({
mixins: [Modal, Navigation], mixins: [Modal, Navigation],
propTypes: { propTypes: {
planet: React.PropTypes.shape({ planet: React.PropTypes.shape({
@@ -20,9 +21,6 @@ var PlanetNavigator = React.createClass({
isLaunchModalOpen: false isLaunchModalOpen: false
} }
}, },
submitLaunchModal: function (ret) {
this.setState({isLaunchModalOpen: false})
},
openLaunchModal: function () { openLaunchModal: function () {
this.openModal(LaunchModal, {planet: this.props.planet, transitionTo: this.transitionTo}) this.openModal(LaunchModal, {planet: this.props.planet, transitionTo: this.transitionTo})
}, },
@@ -54,5 +52,3 @@ var PlanetNavigator = React.createClass({
) )
} }
}) })
module.exports = PlanetNavigator

View File

@@ -3,11 +3,12 @@ var React = require('react/addons')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var KeyCaster = require('../Mixins/KeyCaster')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('planetSettingModal')],
propTypes: { propTypes: {
close: React.PropTypes.func, close: React.PropTypes.func,
planet: React.PropTypes.shape({ planet: React.PropTypes.shape({
@@ -35,6 +36,13 @@ module.exports = React.createClass({
deleteConfirmation: '' deleteConfirmation: ''
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
}
},
activePlanetProfile: function () { activePlanetProfile: function () {
this.setState({currentTab: 'profile'}) this.setState({currentTab: 'profile'})
}, },

View File

@@ -5,11 +5,12 @@ var React = require('react/addons')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var KeyCaster = require('../Mixins/KeyCaster')
var UserStore = require('../Stores/UserStore') var UserStore = require('../Stores/UserStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('teamCreateModal')],
propTypes: { propTypes: {
user: React.PropTypes.shape({ user: React.PropTypes.shape({
name: React.PropTypes.string name: React.PropTypes.string
@@ -24,6 +25,19 @@ module.exports = React.createClass({
} }
} }
}, },
componentDidMount: function () {
React.findDOMNode(this.refs.teamName).focus()
},
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
case 'submitTeamCreateModal':
this.handleSubmit()
break
}
},
handleSubmit: function () { handleSubmit: function () {
Hq.createTeam(this.props.user.name, this.state.team) Hq.createTeam(this.props.user.name, this.state.team)
.then(function (res) { .then(function (res) {
@@ -46,7 +60,7 @@ module.exports = React.createClass({
render: function () { render: function () {
return ( return (
<div className='TeamCreateModal modal'> <div className='TeamCreateModal modal'>
<input valueLink={this.linkState('team.name')} className='nameInput stripInput' placeholder='Create new team'/> <input ref='teamName' valueLink={this.linkState('team.name')} className='nameInput stripInput' placeholder='Create new team'/>
<button onClick={this.handleSubmit} className='submitButton'> <button onClick={this.handleSubmit} className='submitButton'>
<i className='fa fa-check'/> <i className='fa fa-check'/>

View File

@@ -8,6 +8,7 @@ var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var Helper = require('../Mixins/Helper') var Helper = require('../Mixins/Helper')
var KeyCaster = require('../Mixins/KeyCaster')
var UserStore = require('../Stores/UserStore') var UserStore = require('../Stores/UserStore')
@@ -30,7 +31,7 @@ var getOptions = function (input, callback) {
} }
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState, Reflux.listenTo(UserStore, 'onUserChange'), Helper], mixins: [LinkedState, Reflux.listenTo(UserStore, 'onUserChange'), Helper, KeyCaster('teamSettingsModal')],
propTypes: { propTypes: {
team: React.PropTypes.shape({ team: React.PropTypes.shape({
id: React.PropTypes.number, id: React.PropTypes.number,
@@ -38,7 +39,8 @@ module.exports = React.createClass({
profileName: React.PropTypes.string, profileName: React.PropTypes.string,
email: React.PropTypes.string, email: React.PropTypes.string,
Members: React.PropTypes.array Members: React.PropTypes.array
}) }),
close: React.PropTypes.func
}, },
getInitialState: function () { getInitialState: function () {
var team = this.props.team var team = this.props.team
@@ -55,6 +57,13 @@ module.exports = React.createClass({
updatingMember: false updatingMember: false
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
}
},
onUserChange: function (res) { onUserChange: function (res) {
var member var member
switch (res.status) { switch (res.status) {

View File

@@ -7,21 +7,29 @@ var State = ReactRouter.State
var Navigation = ReactRouter.Navigation var Navigation = ReactRouter.Navigation
var AuthFilter = require('../Mixins/AuthFilter') var AuthFilter = require('../Mixins/AuthFilter')
var KeyCaster = require('../Mixins/KeyCaster')
var HomeNavigator = require('../Components/HomeNavigator') var HomeNavigator = require('../Components/HomeNavigator')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [AuthFilter.OnlyUser, State, Navigation], mixins: [AuthFilter.OnlyUser, State, Navigation, KeyCaster('homeContainer')],
componentDidMount: function () { componentDidMount: function () {
if (this.isActive('homeEmpty')) { if (this.isActive('homeEmpty')) {
var user = JSON.parse(localStorage.getItem('currentUser')) var user = JSON.parse(localStorage.getItem('currentUser'))
this.transitionTo('userHome', {userName: user.name}) this.transitionTo('userHome', {userName: user.name})
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'switchPlanet':
this.refs.navigator.switchPlanetByIndex(e.data)
break
}
},
render: function () { render: function () {
return ( return (
<div className='HomeContainer'> <div className='HomeContainer'>
<HomeNavigator/> <HomeNavigator ref='navigator'/>
<RouteHandler/> <RouteHandler/>
</div> </div>
) )

View File

@@ -14,12 +14,13 @@ var Hq = require('../Services/Hq')
var Modal = require('../Mixins/Modal') var Modal = require('../Mixins/Modal')
var ArticleFilter = require('../Mixins/ArticleFilter') var ArticleFilter = require('../Mixins/ArticleFilter')
var Helper = require('../Mixins/Helper') var Helper = require('../Mixins/Helper')
var KeyCaster = require('../Mixins/KeyCaster')
var UserStore = require('../Stores/UserStore') var UserStore = require('../Stores/UserStore')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [ReactRouter.Navigation, ReactRouter.State, Modal, Reflux.listenTo(UserStore, 'onUserChange'), Reflux.listenTo(PlanetStore, 'onPlanetChange'), ArticleFilter, Helper], mixins: [ReactRouter.Navigation, ReactRouter.State, Modal, Reflux.listenTo(UserStore, 'onUserChange'), Reflux.listenTo(PlanetStore, 'onPlanetChange'), ArticleFilter, Helper, KeyCaster('planetContainer')],
propTypes: { propTypes: {
params: React.PropTypes.object, params: React.PropTypes.object,
planetName: React.PropTypes.string planetName: React.PropTypes.string
@@ -62,6 +63,28 @@ module.exports = React.createClass({
}) })
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'openLaunchModal':
this.refs.navigator.openLaunchModal()
break
case 'selectNextArticle':
this.selectNextArticle()
break
case 'selectPriorArticle':
this.selectPriorArticle()
break
case 'toggleFocusSearchInput':
this.toggleFocusSearchInput()
break
case 'openEditModal':
this.refs.detail.openEditModal()
break
case 'openDeleteModal':
this.refs.detail.openDeleteModal()
break
}
},
onPlanetChange: function (res) { onPlanetChange: function (res) {
if (this.state.planet == null) return if (this.state.planet == null) return
@@ -237,9 +260,17 @@ module.exports = React.createClass({
if (index > 0) { if (index > 0) {
this.selectArticleByListIndex(index - 1) this.selectArticleByListIndex(index - 1)
} else { } else {
React.findDOMNode(this).querySelector('.PlanetHeader .searchInput input').focus() React.findDOMNode(this.refs.header.refs.search).focus()
} }
}, },
toggleFocusSearchInput: function () {
var search = React.findDOMNode(this.refs.header.refs.search)
if (document.activeElement === search) {
React.findDOMNode(this.refs.header.refs.search).blur()
return
}
React.findDOMNode(this.refs.header.refs.search).focus()
},
handleSearchChange: function (e) { handleSearchChange: function (e) {
this.setState({search: e.target.value}, function () { this.setState({search: e.target.value}, function () {
this.selectArticleByListIndex(0) this.selectArticleByListIndex(0)
@@ -309,9 +340,6 @@ module.exports = React.createClass({
this.setState({search: '#' + tag}) this.setState({search: '#' + tag})
}.bind(this) }.bind(this)
}, },
focus: function () {
React.findDOMNode(this).focus()
},
render: function () { render: function () {
if (this.state.planet == null) return (<div/>) if (this.state.planet == null) return (<div/>)
@@ -346,6 +374,7 @@ module.exports = React.createClass({
return ( return (
<div className='PlanetContainer'> <div className='PlanetContainer'>
<PlanetHeader <PlanetHeader
ref='header'
search={this.state.search} search={this.state.search}
fetchPlanet={this.fetchPlanet} fetchPlanet={this.fetchPlanet}
onSearchChange={this.handleSearchChange} onSearchChange={this.handleSearchChange}

View File

@@ -0,0 +1,104 @@
var Reflux = require('reflux')
var state = {
}
var keyDown = Reflux.createAction()
var KeyStore = Reflux.createStore({
init: function () {
this.listenTo(keyDown, this.onKeyDown)
document.addEventListener('keydown', function (e) {
keyDown(e)
})
},
setState: function (newState, cb) {
for (var key in newState) {
state[key] = newState[key]
}
if (typeof cb === 'function') cb()
},
onKeyDown: function (e) {
console.log(e.keyCode)
console.log(state)
/*
Modals
*/
if (state.codeForm || state.noteForm || state.noteDeleteModal || state.codeDeleteModal || state.addMemberModal || state.aboutModal || state.editProfileModal || state.contactModal || state.teamCreateModal || state.planetCreateModal || state.planetSettingModal || state.teamSettingsModal || state.logoutModal) {
// ESC
if (e.keyCode === 27) this.cast('closeModal')
// Cmd + Enter
if (e.keyCode === 13 && e.metaKey) {
if (state.codeForm) this.cast('submitCodeForm')
if (state.noteForm) this.cast('submitNoteForm')
if (state.codeDeleteModal) this.cast('submitCodeDeleteModal')
if (state.noteDeleteModal) this.cast('submitNoteDeleteModal')
if (state.addMemberModal) this.cast('submitAddMemberModal')
if (state.contactModal) this.cast('submitContactModal')
if (state.teamCreateModal) this.cast('submitTeamCreateModal')
if (state.planetCreateModal) this.cast('submitPlanetCreateModal')
if (state.logoutModal) this.cast('submitLogoutModal')
}
return
}
/*
PlanetContainer
*/
if (state.planetContainer) {
// Cmd + Enter, A
if ((e.keyCode === 13 && e.metaKey) || e.keyCode === 65) this.cast('openLaunchModal')
// Esc
if (e.keyCode === 27) this.cast('toggleFocusSearchInput')
// Up
if (e.keyCode === 38) this.cast('selectPriorArticle')
// Down
if (e.keyCode === 40) this.cast('selectNextArticle')
// E
if (e.keyCode === 69) this.cast('openEditModal')
// D
if (e.keyCode === 68) this.cast('openDeleteModal')
}
/*
HomeContainer
*/
if (state.homeContainer) {
if (e.keyCode > 48 && e.keyCode < 58 && e.metaKey) {
this.cast('switchPlanet', e.keyCode - 48)
}
}
},
cast: function (status, data) {
this.trigger({
status: status,
data: data
})
}
})
module.exports = function (stateKey) {
return {
mixins: [Reflux.listenTo(KeyStore, 'onKeyCast')],
componentDidMount: function () {
var newState = {}
newState[stateKey] = true
KeyStore.setState(newState)
},
componentWillUnmount: function () {
var newState = {}
newState[stateKey] = false
KeyStore.setState(newState)
}
}
}