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

記事が編集された状態で他の記事を見ようとすると警告をだす

This commit is contained in:
Rokt33r
2015-11-16 05:34:37 +09:00
parent df6a018fb6
commit 013f96a754
6 changed files with 248 additions and 13 deletions

View File

@@ -5,7 +5,20 @@ 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, switchArticle, switchFolder, clearSearch, updateArticle, destroyArticle, NEW } from 'boost/actions'
import {
IDLE_MODE,
CREATE_MODE,
EDIT_MODE,
switchMode,
switchArticle,
switchFolder,
clearSearch,
lockStatus,
unlockStatus,
updateArticle,
destroyArticle,
NEW
} from 'boost/actions'
import linkState from 'boost/linkState'
import FolderMark from 'boost/components/FolderMark'
import TagLink from 'boost/components/TagLink'
@@ -82,7 +95,12 @@ export default class ArticleDetail extends React.Component {
this.state = {
article: makeInstantArticle(props.activeArticle),
previewMode: false
previewMode: false,
isArticleEdited: false,
isTagChanged: false,
isTitleChanged: false,
isContentChanged: false,
isModeChanged: false
}
}
@@ -117,7 +135,11 @@ export default class ArticleDetail extends React.Component {
if (isModeChanged) {
Object.assign(nextState, {
openDeleteConfirmMenu: false,
previewMode: false
previewMode: false,
isArticleEdited: false,
isTagChanged: false,
isTitleChanged: false,
isContentChanged: false
})
}
@@ -224,6 +246,8 @@ export default class ArticleDetail extends React.Component {
handleCancelButtonClick (e) {
let { activeArticle, dispatch } = this.props
dispatch(unlockStatus())
if (activeArticle.status === NEW) dispatch(switchArticle(null))
dispatch(switchMode(IDLE_MODE))
}
@@ -236,6 +260,8 @@ export default class ArticleDetail extends React.Component {
let folder = _.findWhere(folders, {key: article.FolderKey})
if (folder == null) return false
dispatch(unlockStatus())
delete newArticle.status
newArticle.updatedAt = new Date()
if (newArticle.createdAt == null) {
@@ -263,19 +289,85 @@ export default class ArticleDetail extends React.Component {
this.setState({article: article})
}
handleTitleChange (e) {
let { article } = this.state
article.title = e.target.value
let _isTitleChanged = article.title !== this.props.activeArticle.title
let { isTagChanged, isContentChanged, isArticleEdited, isModeChanged } = this.state
let _isArticleEdited = _isTitleChanged || isTagChanged || isContentChanged || isModeChanged
this.setState({
article,
isTitleChanged: _isTitleChanged,
isArticleEdited: _isArticleEdited
}, () => {
if (isArticleEdited !== _isArticleEdited) {
let { dispatch } = this.props
if (_isArticleEdited) {
console.log('lockit')
dispatch(lockStatus())
} else {
console.log('unlockit')
dispatch(unlockStatus())
}
}
})
}
handleTagsChange (newTag, tags) {
let article = this.state.article
article.tags = tags
this.setState({article: article})
let _isTagChanged = _.difference(article.tags, this.props.activeArticle.tags).length > 0 || _.difference(this.props.activeArticle.tags, article.tags).length > 0
let { isTitleChanged, isContentChanged, isArticleEdited, isModeChanged } = this.state
let _isArticleEdited = _isTagChanged || isTitleChanged || isContentChanged || isModeChanged
this.setState({
article,
isTagChanged: _isTagChanged,
isArticleEdited: _isArticleEdited
}, () => {
if (isArticleEdited !== _isArticleEdited) {
let { dispatch } = this.props
if (_isArticleEdited) {
console.log('lockit')
dispatch(lockStatus())
} else {
console.log('unlockit')
dispatch(unlockStatus())
}
}
})
}
handleModeChange (value) {
let article = this.state.article
let { article } = this.state
article.mode = value
let _isModeChanged = article.mode !== this.props.activeArticle.mode
let { isTagChanged, isContentChanged, isArticleEdited, isTitleChanged } = this.state
let _isArticleEdited = _isModeChanged || isTagChanged || isContentChanged || isTitleChanged
this.setState({
article: article,
previewMode: false
article,
previewMode: false,
isModeChanged: _isModeChanged,
isArticleEdited: _isArticleEdited
}, () => {
if (isArticleEdited !== _isArticleEdited) {
let { dispatch } = this.props
if (_isArticleEdited) {
console.log('lockit')
dispatch(lockStatus())
} else {
console.log('unlockit')
dispatch(unlockStatus())
}
}
})
}
@@ -286,9 +378,29 @@ export default class ArticleDetail extends React.Component {
}
handleContentChange (e, value) {
let article = this.state.article
let { article } = this.state
article.content = value
this.setState({article: article})
let _isContentChanged = article.content !== this.props.activeArticle.content
let { isTagChanged, isModeChanged, isArticleEdited, isTitleChanged } = this.state
let _isArticleEdited = _isContentChanged || isTagChanged || isModeChanged || isTitleChanged
this.setState({
article,
isContentChanged: _isContentChanged,
isArticleEdited: _isArticleEdited
}, () => {
if (isArticleEdited !== _isArticleEdited) {
let { dispatch } = this.props
if (_isArticleEdited) {
console.log('lockit')
dispatch(lockStatus())
} else {
console.log('unlockit')
dispatch(unlockStatus())
}
}
})
}
handleTogglePreviewButtonClick (e) {
@@ -322,6 +434,7 @@ export default class ArticleDetail extends React.Component {
>
{folderOptions}
</select>
{this.state.isArticleEdited ? ' (edited)' : ''}
<TagSelect
tags={this.state.article.tags}
@@ -347,7 +460,7 @@ export default class ArticleDetail extends React.Component {
<div className='detailPanel'>
<div className='header'>
<div className='title'>
<input onKeyDown={e => this.handleTitleKeyDown(e)} placeholder='Title' ref='title' valueLink={this.linkState('article.title')}/>
<input onKeyDown={e => this.handleTitleKeyDown(e)} placeholder='Title' ref='title' value={this.state.article.title} onChange={e => this.handleTitleChange(e)}/>
</div>
<ModeSelect
ref='mode'
@@ -396,6 +509,7 @@ export default class ArticleDetail extends React.Component {
ArticleDetail.propTypes = {
status: PropTypes.shape(),
activeArticle: PropTypes.shape(),
activeUser: PropTypes.shape()
activeUser: PropTypes.shape(),
dispatch: PropTypes.func
}
ArticleDetail.prototype.linkState = linkState

View File

@@ -9,3 +9,4 @@
@require './lib/CreateNewFolder'
@require './lib/Preferences'
@require './lib/Tutorial'
@require './lib/EditedAlert'

View File

@@ -0,0 +1,28 @@
.EditedAlert.modal
width 350px
top 100px
.title
font-size 24px
margin-bottom 15px
.message
font-size 14px
margin-bottom 15px
.control
text-align right
button
border-radius 5px
height 33px
padding 0 15px
font-size 14px
background-color white
border 1px solid borderColor
border-radius 5px
margin-left 5px
&:hover
background-color darken(white, 10%)
&.primary
border-color brandColor
background-color brandColor
color white
&:hover
background-color lighten(brandColor, 10%)

View File

@@ -12,6 +12,8 @@ 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'
export const LOCK_STATUS = 'LOCK_STATUS'
export const UNLOCK_STATUS = 'UNLOCK_STATUS'
export const TOGGLE_TUTORIAL = 'TOGGLE_TUTORIAL'
// Status - mode
@@ -109,7 +111,19 @@ export function clearSearch () {
}
}
export function toggleTutorial() {
export function lockStatus () {
return {
type: LOCK_STATUS
}
}
export function unlockStatus () {
return {
type: UNLOCK_STATUS
}
}
export function toggleTutorial () {
return {
type: TOGGLE_TUTORIAL
}

View File

@@ -0,0 +1,35 @@
import React, { PropTypes } from 'react'
import store from 'boost/store'
import { unlockStatus } from 'boost/actions'
export default class EditedAlert extends React.Component {
handleNoButtonClick (e) {
this.props.close()
}
handleYesButtonClick (e) {
store.dispatch(unlockStatus())
store.dispatch(this.props.action)
this.props.close()
}
render () {
return (
<div className='EditedAlert modal'>
<div className='title'>Your article is still editing!</div>
<div className='message'>Do you really want to leave without finishing?</div>
<div className='control'>
<button onClick={e => this.handleNoButtonClick(e)}><i className='fa fa-fw fa-close'/> No</button>
<button onClick={e => this.handleYesButtonClick(e)} className='primary'><i className='fa fa-fw fa-check'/> Yes</button>
</div>
</div>
)
}
}
EditedAlert.propTypes = {
action: PropTypes.object,
close: PropTypes.func
}

View File

@@ -1,14 +1,42 @@
import { combineReducers } from 'redux'
import _ from 'lodash'
import { SWITCH_FOLDER, SWITCH_MODE, SWITCH_ARTICLE, SET_SEARCH_FILTER, SET_TAG_FILTER, CLEAR_SEARCH, TOGGLE_TUTORIAL, ARTICLE_UPDATE, ARTICLE_DESTROY, FOLDER_CREATE, FOLDER_UPDATE, FOLDER_DESTROY, FOLDER_REPLACE, IDLE_MODE, CREATE_MODE } from './actions'
import {
// Status action type
SWITCH_FOLDER,
SWITCH_MODE,
SWITCH_ARTICLE,
SET_SEARCH_FILTER,
SET_TAG_FILTER,
CLEAR_SEARCH,
LOCK_STATUS,
UNLOCK_STATUS,
TOGGLE_TUTORIAL,
// Article action type
ARTICLE_UPDATE,
ARTICLE_DESTROY,
// Folder action type
FOLDER_CREATE,
FOLDER_UPDATE,
FOLDER_DESTROY,
FOLDER_REPLACE,
// view mode
IDLE_MODE,
CREATE_MODE
} from './actions'
import dataStore from 'boost/dataStore'
import keygen from 'boost/keygen'
import activityRecord from 'boost/activityRecord'
import { openModal } from 'boost/modal'
import EditedAlert from 'boost/components/modal/EditedAlert'
const initialStatus = {
mode: IDLE_MODE,
search: '',
isTutorialOpen: false
isTutorialOpen: false,
isStatusLocked: false
}
let data = dataStore.getData()
@@ -134,10 +162,25 @@ function articles (state = initialArticles, action) {
function status (state = initialStatus, action) {
state = Object.assign({}, state)
switch (action.type) {
case TOGGLE_TUTORIAL:
state.isTutorialOpen = !state.isTutorialOpen
return state
case LOCK_STATUS:
state.isStatusLocked = true
return state
case UNLOCK_STATUS:
state.isStatusLocked = false
return state
}
// if status locked, status become unmutable
if (state.isStatusLocked) {
openModal(EditedAlert, {action})
return state
}
switch (action.type) {
case SWITCH_FOLDER:
state.mode = IDLE_MODE
state.search = `//${action.data} `