1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 17:56:25 +00:00

Key入力追加

This commit is contained in:
Rokt33r
2015-10-31 18:21:42 +09:00
parent 3d0b79f674
commit 954e148be3
10 changed files with 164 additions and 31 deletions

View File

@@ -1,6 +1,6 @@
import React, { PropTypes} from 'react'
import { connect } from 'react-redux'
import { CREATE_MODE, IDLE_MODE, NEW } from 'boost/actions'
import { CREATE_MODE, EDIT_MODE, IDLE_MODE, NEW } from 'boost/actions'
// import UserNavigator from './HomePage/UserNavigator'
import ArticleNavigator from './HomePage/ArticleNavigator'
import ArticleTopBar from './HomePage/ArticleTopBar'
@@ -8,24 +8,102 @@ import ArticleList from './HomePage/ArticleList'
import ArticleDetail from './HomePage/ArticleDetail'
import _ from 'lodash'
import keygen from 'boost/keygen'
import { isModalOpen, closeModal } from 'boost/modal'
const TEXT_FILTER = 'TEXT_FILTER'
const FOLDER_FILTER = 'FOLDER_FILTER'
const TAG_FILTER = 'TAG_FILTER'
class HomePage extends React.Component {
componentDidMount () {
this.listener = (e) => this.handleKeyDown(e)
window.addEventListener('keydown', this.listener)
}
componentWillUnmount () {
window.removeEventListener('keydown', this.listener)
}
handleKeyDown (e) {
if (isModalOpen() && e.keyCode === 27) {
closeModal()
return
}
let { status } = this.props
let { nav, top, list, detail } = this.refs
if (top.isInputFocused() && !e.metaKey) {
if (e.keyCode === 13 || e.keyCode === 27) top.blurInput()
return
}
switch (status.mode) {
case CREATE_MODE:
case EDIT_MODE:
if (e.keyCode === 27) {
detail.handleCancelButtonClick()
}
if (e.keyCode === 13 && e.metaKey) {
detail.handleSaveButtonClick()
}
break
case IDLE_MODE:
if (e.keyCode === 69) {
detail.handleEditButtonClick()
}
if (e.keyCode === 68) {
detail.handleDeleteButtonClick()
}
// `detail`の`openDeleteConfirmMenu`の時。
if (detail.state.openDeleteConfirmMenu) {
if (e.keyCode === 27) {
detail.handleDeleteCancleButtonClick()
}
if (e.keyCode === 13 && e.metaKey) {
detail.handleDeleteConfirmButtonClick()
}
break
}
// `detail`の`openDeleteConfirmMenu`が`true`なら呼ばれない。
if (e.keyCode === 27) {
top.focusInput()
}
if (e.keyCode === 38) {
list.selectPriorArticle()
}
if (e.keyCode === 40) {
list.selectNextArticle()
}
if (e.keyCode === 13 && e.metaKey) {
nav.handleNewPostButtonClick()
}
}
}
render () {
let { dispatch, status, articles, activeArticle, folders } = this.props
let { dispatch, status, articles, activeArticle, folders, filters } = this.props
return (
<div className='HomePage'>
<ArticleNavigator
ref='nav'
dispatch={dispatch}
folders={folders}
status={status}
/>
<ArticleTopBar dispatch={dispatch} status={status}/>
<ArticleTopBar
ref='top'
dispatch={dispatch}
status={status}
/>
<ArticleList
ref='list'
dispatch={dispatch}
folders={folders}
articles={articles}
@@ -33,10 +111,12 @@ class HomePage extends React.Component {
activeArticle={activeArticle}
/>
<ArticleDetail
ref='detail'
dispatch={dispatch}
activeArticle={activeArticle}
folders={folders}
status={status}
filters={filters}
/>
</div>
)
@@ -139,7 +219,12 @@ function remap (state) {
folders,
status,
articles,
activeArticle
activeArticle,
filters: {
folder: folderFilters,
tag: tagFilters,
text: textFilters
}
}
}
@@ -153,7 +238,12 @@ HomePage.propTypes = {
articles: PropTypes.array,
activeArticle: PropTypes.shape(),
dispatch: PropTypes.func,
folders: PropTypes.array
folders: PropTypes.array,
filters: PropTypes.shape({
folder: PropTypes.array,
tag: PropTypes.array,
text: PropTypes.array
})
}
export default connect(remap)(HomePage)

View File

@@ -4,7 +4,7 @@ import _ from 'lodash'
import ModeIcon from 'boost/components/ModeIcon'
import MarkdownPreview from 'boost/components/MarkdownPreview'
import CodeEditor from 'boost/components/CodeEditor'
import { IDLE_MODE, CREATE_MODE, EDIT_MODE, switchMode, updateArticle, destroyArticle } from 'boost/actions'
import { IDLE_MODE, CREATE_MODE, EDIT_MODE, switchMode, switchArticle, switchFolder, updateArticle, destroyArticle } from 'boost/actions'
import aceModes from 'boost/ace-modes'
import Select from 'react-select'
import linkState from 'boost/linkState'
@@ -38,6 +38,11 @@ export default class ArticleDetail extends React.Component {
console.log('receive props')
})
}
let isEdit = nextProps.status.mode === EDIT_MODE || nextProps.status.mode === CREATE_MODE
if (isEdit && this.state.openDeleteConfirmMenu) {
this.setState({openDeleteConfirmMenu: false})
}
}
renderEmpty () {
@@ -135,7 +140,7 @@ export default class ArticleDetail extends React.Component {
}
handleSaveButtonClick (e) {
let { dispatch, folders } = this.props
let { dispatch, folders, filters } = this.props
let article = this.state.article
let newArticle = Object.assign({}, article)
@@ -147,6 +152,8 @@ export default class ArticleDetail extends React.Component {
dispatch(updateArticle(newArticle))
dispatch(switchMode(IDLE_MODE))
if (filters.folder.length !== 0) dispatch(switchFolder(folder.name))
dispatch(switchArticle(newArticle.key))
}
handleFolderKeyChange (e) {

View File

@@ -15,6 +15,26 @@ export default class ArticleList extends React.Component {
clearInterval(this.refreshTimer)
}
selectPriorArticle () {
let { articles, activeArticle, dispatch } = this.props
let targetIndex = articles.indexOf(activeArticle) - 1
let targetArticle = articles[targetIndex]
if (targetArticle != null) {
dispatch(switchArticle(targetArticle.key))
}
}
selectNextArticle () {
let { articles, activeArticle, dispatch } = this.props
let targetIndex = articles.indexOf(activeArticle) + 1
let targetArticle = articles[targetIndex]
if (targetArticle != null) {
dispatch(switchArticle(targetArticle.key))
}
}
handleArticleClick (article) {
let { dispatch } = this.props
return function (e) {

View File

@@ -7,6 +7,7 @@ import Preferences from 'boost/components/modal/Preferences'
import CreateNewFolder from 'boost/components/modal/CreateNewFolder'
import remote from 'remote'
let userName = remote.getGlobal('process').env.USER
export default class ArticleNavigator extends React.Component {
handlePreferencesButtonClick (e) {
@@ -51,8 +52,6 @@ export default class ArticleNavigator extends React.Component {
)
})
let userName = remote.getGlobal('process').env.USER
return (
<div className='ArticleNavigator'>
<div className='userInfo'>

View File

@@ -4,16 +4,29 @@ import ExternalLink from 'boost/components/ExternalLink'
import { setSearchFilter } from 'boost/actions'
export default class ArticleTopBar extends React.Component {
isInputFocused () {
return document.activeElement === ReactDOM.findDOMNode(this.refs.searchInput)
}
focusInput () {
ReactDOM.findDOMNode(this.refs.searchInput).focus()
}
blurInput () {
ReactDOM.findDOMNode(this.refs.searchInput).blur()
}
handleSearchChange (e) {
let { dispatch } = this.props
dispatch(setSearchFilter(e.target.value))
}
handleSearchClearButton (e) {
let { dispatch } = this.props
dispatch(setSearchFilter(''))
ReactDOM.findDOMNode(this.refs.searchInput).focus()
this.focusInput()
}
render () {

View File

@@ -7,6 +7,8 @@ import HomePage from './HomePage'
// import auth from 'boost/auth'
import store from 'boost/store'
import ReactDOM from 'react-dom'
import { isModalOpen, closeModal } from 'boost/modal'
import { IDLE_MODE, CREATE_MODE, EDIT_MODE } from 'boost/actions'
require('../styles/main/index.styl')
let routes = (
@@ -25,21 +27,4 @@ ReactDOM.render((
), el, function () {
let loadingCover = document.getElementById('loadingCover')
loadingCover.parentNode.removeChild(loadingCover)
// Refresh user information
// if (auth.user() != null) {
// fetchCurrentUser()
// .then(function (res) {
// let user = res.body
// store.dispatch(updateUser(user))
// })
// .catch(function (err) {
// if (err.status === 401) {
// auth.clear()
// if (window != null) window.location.reload()
// }
// console.error(err.message)
// console.log('Fetch failed')
// })
// }
})

View File

@@ -10,6 +10,7 @@ export const SWITCH_MODE = 'SWITCH_MODE'
export const SWITCH_ARTICLE = 'SWITCH_ARTICLE'
export const SET_SEARCH_FILTER = 'SET_SEARCH_FILTER'
export const SET_TAG_FILTER = 'SET_TAG_FILTER'
export const CLEAR_SEARCH = 'CLEAR_SEARCH'
// Status - mode
export const IDLE_MODE = 'IDLE_MODE'
@@ -18,8 +19,6 @@ export const EDIT_MODE = 'EDIT_MODE'
// Article status
export const NEW = 'NEW'
export const SYNCING = 'SYNCING'
export const UNSYNCED = 'UNSYNCED'
// DB
export function updateArticle (article) {
@@ -91,3 +90,9 @@ export function setTagFilter (tag) {
data: tag
}
}
export function clearSearch () {
return {
type: CLEAR_SEARCH
}
}

View File

@@ -17,7 +17,12 @@ export default class TagSelect extends React.Component {
e.preventDefault()
let tags = this.props.tags.slice(0)
let newTag = this.state.input
let newTag = this.state.input.trim()
if (newTag.length === 0) {
this.setState({input: ''})
return
}
tags.push(newTag)
tags = _.uniq(tags)

View File

@@ -40,3 +40,7 @@ export function closeModal () {
if (modalBase == null) { return }
modalBase.setState({component: null, componentProps: null, isHidden: true})
}
export function isModalOpen () {
return !modalBase.state.isHidden
}

View File

@@ -1,6 +1,6 @@
import { combineReducers } from 'redux'
import _ from 'lodash'
import { SWITCH_FOLDER, SWITCH_MODE, SWITCH_ARTICLE, SET_SEARCH_FILTER, SET_TAG_FILTER, ARTICLE_UPDATE, ARTICLE_DESTROY, FOLDER_CREATE, FOLDER_UPDATE, FOLDER_DESTROY, IDLE_MODE, CREATE_MODE } from './actions'
import { SWITCH_FOLDER, SWITCH_MODE, SWITCH_ARTICLE, SET_SEARCH_FILTER, SET_TAG_FILTER, CLEAR_SEARCH, ARTICLE_UPDATE, ARTICLE_DESTROY, FOLDER_CREATE, FOLDER_UPDATE, FOLDER_DESTROY, IDLE_MODE, CREATE_MODE } from './actions'
import dataStore from 'boost/dataStore'
import keygen from 'boost/keygen'
@@ -134,6 +134,11 @@ function status (state = initialStatus, action) {
state.search = `#${action.data}`
state.mode = IDLE_MODE
return state
case CLEAR_SEARCH:
state.search = ''
state.mode = IDLE_MODE
return state
default:
return state