mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 17:56:25 +00:00
Key入力追加
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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'>
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
@@ -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')
|
||||
// })
|
||||
// }
|
||||
})
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user