1
0
mirror of https://github.com/BoostIo/Boostnote synced 2026-05-26 01:12:29 +00:00

using Repository class

This commit is contained in:
Rokt33r
2016-05-03 15:37:14 +09:00
parent 1d2ca469fc
commit 45c627b0a5
8 changed files with 151 additions and 747 deletions

View File

@@ -1,16 +1,21 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './Repository.styl'
import actions from 'browser/main/actions'
import RepositoryManager from 'browser/lib/RepositoryManager'
import styles from './RepositorySection.styl'
import Repository from 'browser/lib/Repository'
class Repository extends React.Component {
class RepositorySection extends React.Component {
handleUnlinkButtonClick (e) {
let { dispatch, repository } = this.props
RepositoryManager.removeRepo(repository)
Repository.find(repository.key)
.then((repositoryInstance) => {
return repositoryInstance.unmount()
})
.then(() => {
dispatch(actions.removeRepo(repository))
dispatch({
type: 'REMOVE_REPOSITORY',
key: repository.key
})
})
}
@@ -40,7 +45,7 @@ class Repository extends React.Component {
return (
<div
className='Repository'
className='RepositorySection'
styleName='root'
>
<div styleName='header'>
@@ -76,7 +81,7 @@ class Repository extends React.Component {
}
}
Repository.propTypes = {
RepositorySection.propTypes = {
repository: PropTypes.shape({
name: PropTypes.string,
folders: PropTypes.arrayOf(PropTypes.shape({
@@ -86,4 +91,4 @@ Repository.propTypes = {
dispatch: PropTypes.func
}
export default CSSModules(Repository, styles)
export default CSSModules(RepositorySection, styles)

View File

@@ -1,11 +1,10 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './SideNav.styl'
import actions from 'browser/main/actions'
import { openModal, isModalOpen } from 'browser/lib/modal'
import Preferences from '../../modal/Preferences'
import CreateNewFolder from '../../modal/CreateNewFolder'
import Repository from './Repository'
import RepositorySection from './RepositorySection'
import NewRepositoryModal from '../../modal/NewRepositoryModal'
const ipc = require('electron').ipcRenderer
@@ -39,13 +38,11 @@ class SideNav extends React.Component {
handleFolderButtonClick (name) {
return (e) => {
let { dispatch } = this.props
dispatch(actions.switchFolder(name))
}
}
handleAllFoldersButtonClick (e) {
let { dispatch } = this.props
dispatch(actions.setSearchFilter(''))
}
handleNewRepositoryButtonClick (e) {
@@ -55,8 +52,8 @@ class SideNav extends React.Component {
render () {
let { repositories, dispatch } = this.props
let repositorieElements = repositories.map((repo) => {
return <Repository
key={repo.name}
return <RepositorySection
key={repo.key}
repository={repo}
dispatch={dispatch}
/>
@@ -108,17 +105,6 @@ class SideNav extends React.Component {
SideNav.propTypes = {
dispatch: PropTypes.func,
status: PropTypes.shape({
folderId: PropTypes.number
}),
user: PropTypes.object,
folders: PropTypes.array,
allArticles: PropTypes.array,
articles: PropTypes.array,
modified: PropTypes.array,
activeArticle: PropTypes.shape({
key: PropTypes.string
}),
repositories: PropTypes.array
}

View File

@@ -1,30 +1,31 @@
import React, { PropTypes} from 'react'
import { connect } from 'react-redux'
import ReactDOM from 'react-dom'
import { toggleTutorial } from '../actions'
import SideNav from './SideNav'
import ArticleTopBar from './ArticleTopBar'
import ArticleList from './ArticleList'
import ArticleDetail from './ArticleDetail'
import _ from 'lodash'
import { isModalOpen, closeModal } from 'browser/lib/modal'
import Repository from 'browser/lib/Repository'
const electron = require('electron')
const remote = electron.remote
const TEXT_FILTER = 'TEXT_FILTER'
const FOLDER_FILTER = 'FOLDER_FILTER'
const FOLDER_EXACT_FILTER = 'FOLDER_EXACT_FILTER'
const TAG_FILTER = 'TAG_FILTER'
const OSX = global.process.platform === 'darwin'
class HomePage extends React.Component {
componentDidMount () {
// React自体のKey入力はfocusされていないElementからは動かないため、
// `window`に直接かける
this.keyHandler = e => this.handleKeyDown(e)
window.addEventListener('keydown', this.keyHandler)
let { dispatch } = this.props
// Bind directly to window
// this.keyHandler = (e) => this.handleKeyDown(e)
// window.addEventListener('keydown', this.keyHandler)
// Reload all data
Repository.loadAll()
.then((allData) => {
dispatch({type: 'INIT_ALL', data: allData})
})
}
componentWillUnmount () {
@@ -32,216 +33,72 @@ class HomePage extends React.Component {
}
handleKeyDown (e) {
if (isModalOpen()) {
if (e.keyCode === 13 && (OSX ? e.metaKey : e.ctrlKey)) {
remote.getCurrentWebContents().send('modal-confirm')
}
if (e.keyCode === 27) closeModal()
return
}
// if (isModalOpen()) {
// if (e.keyCode === 13 && (OSX ? e.metaKey : e.ctrlKey)) {
// remote.getCurrentWebContents().send('modal-confirm')
// }
// if (e.keyCode === 27) closeModal()
// return
// }
let { status, dispatch } = this.props
let { top, list } = this.refs
let listElement = ReactDOM.findDOMNode(list)
// let { dispatch } = this.props
// let { top, list } = this.refs
// let listElement = ReactDOM.findDOMNode(list)
if (status.isTutorialOpen) {
dispatch(toggleTutorial())
e.preventDefault()
return
}
// if (status.isTutorialOpen) {
// // dispatch(toggleTutorial())
// e.preventDefault()
// return
// }
if (e.keyCode === 13 && top.isInputFocused()) {
listElement.focus()
return
}
if (e.keyCode === 27 && top.isInputFocused()) {
if (status.search.length > 0) top.escape()
else listElement.focus()
return
}
// if (e.keyCode === 13 && top.isInputFocused()) {
// listElement.focus()
// return
// }
// if (e.keyCode === 27 && top.isInputFocused()) {
// // if (status.search.length > 0) top.escape()
// // else listElement.focus()
// return
// }
// Search inputがfocusされていたら大体のキー入力は無視される。
if (e.keyCode === 27) {
if (document.activeElement !== listElement) {
listElement.focus()
} else {
top.focusInput()
}
return
}
// // Search inputがfocusされていたら大体のキー入力は無視される。
// if (e.keyCode === 27) {
// if (document.activeElement !== listElement) {
// listElement.focus()
// } else {
// top.focusInput()
// }
// return
// }
}
render () {
let { dispatch, status, user, articles, allArticles, modified, activeArticle, folders, tags } = this.props
let { repositories } = this.props
return (
<div className='HomePage'>
<SideNav
ref='nav'
dispatch={dispatch}
repositories={repositories}
status={status}
user={user}
folders={folders}
allArticles={allArticles}
articles={articles}
modified={modified}
activeArticle={activeArticle}
{...this.props}
/>
<ArticleTopBar
ref='top'
dispatch={dispatch}
status={status}
folders={folders}
{...this.props}
/>
<ArticleList
ref='list'
dispatch={dispatch}
folders={folders}
articles={articles}
modified={modified}
activeArticle={activeArticle}
{...this.props}
/>
<ArticleDetail
ref='detail'
dispatch={dispatch}
status={status}
tags={tags}
user={user}
folders={folders}
modified={modified}
activeArticle={activeArticle}
{...this.props}
/>
</div>
)
}
}
// Ignore invalid key
function ignoreInvalidKey (key) {
return key.length > 0 && !key.match(/^\/\/$/) && !key.match(/^\/$/) && !key.match(/^#$/) && !key.match(/^--/)
}
// Build filter object by key
function buildFilter (key) {
if (key.match(/^\/\/.+/)) {
return {type: FOLDER_EXACT_FILTER, value: key.match(/^\/\/(.+)$/)[1]}
}
if (key.match(/^\/.+/)) {
return {type: FOLDER_FILTER, value: key.match(/^\/(.+)$/)[1]}
}
if (key.match(/^#(.+)/)) {
return {type: TAG_FILTER, value: key.match(/^#(.+)$/)[1]}
}
return {type: TEXT_FILTER, value: key}
}
function isContaining (target, needle) {
return target.match(new RegExp(_.escapeRegExp(needle), 'i'))
}
function startsWith (target, needle) {
return target.match(new RegExp('^' + _.escapeRegExp(needle), 'i'))
}
function remap (state) {
let { user, folders, status } = state
let _articles = state.articles
let articles = _articles != null ? _articles.data : []
let modified = _articles != null ? _articles.modified : []
articles.sort((a, b) => {
let match = new Date(b.updatedAt) - new Date(a.updatedAt)
if (match === 0) match = b.title.localeCompare(a.title)
if (match === 0) match = b.key.localeCompare(a.key)
return match
})
let allArticles = articles.slice()
let tags = _.uniq(allArticles.reduce((sum, article) => {
if (!_.isArray(article.tags)) return sum
return sum.concat(article.tags)
}, []))
if (status.search.split(' ').some(key => key === '--unsaved')) articles = articles.filter(article => _.findWhere(modified, {key: article.key}))
// Filter articles
let filters = status.search.split(' ')
.map(key => key.trim())
.filter(ignoreInvalidKey)
.map(buildFilter)
let folderExactFilters = filters.filter(filter => filter.type === FOLDER_EXACT_FILTER)
let folderFilters = filters.filter(filter => filter.type === FOLDER_FILTER)
let textFilters = filters.filter(filter => filter.type === TEXT_FILTER)
let tagFilters = filters.filter(filter => filter.type === TAG_FILTER)
let targetFolders
if (folders != null) {
let exactTargetFolders = folders.filter(folder => {
return _.find(folderExactFilters, filter => filter.value.toLowerCase() === folder.name.toLowerCase())
})
let fuzzyTargetFolders = folders.filter(folder => {
return _.find(folderFilters, filter => startsWith(folder.name.replace(/_/g, ''), filter.value.replace(/_/g, '')))
})
targetFolders = status.targetFolders = exactTargetFolders.concat(fuzzyTargetFolders)
if (targetFolders.length > 0) {
articles = articles.filter(article => {
return _.findWhere(targetFolders, {key: article.FolderKey})
})
}
if (textFilters.length > 0) {
articles = textFilters.reduce((articles, textFilter) => {
return articles.filter(article => {
return isContaining(article.title, textFilter.value) || isContaining(article.content, textFilter.value)
})
}, articles)
}
if (tagFilters.length > 0) {
articles = tagFilters.reduce((articles, tagFilter) => {
return articles.filter(article => {
return _.find(article.tags, tag => isContaining(tag, tagFilter.value))
})
}, articles)
}
}
// Grab active article
let activeArticle = _.findWhere(articles, {key: status.articleKey})
if (activeArticle == null) activeArticle = articles[0]
let { repositories } = state
return {
user,
folders,
status,
articles,
allArticles,
modified,
activeArticle,
tags,
repositories
}
}
HomePage.propTypes = {
status: PropTypes.shape(),
user: PropTypes.shape({
name: PropTypes.string
}),
articles: PropTypes.array,
allArticles: PropTypes.array,
modified: PropTypes.array,
activeArticle: PropTypes.shape(),
dispatch: PropTypes.func,
folders: PropTypes.array,
tags: PropTypes.array,
repositories: PropTypes.array
}
export default connect(remap)(HomePage)
export default connect((x) => x)(HomePage)