@@ -2,25 +2,16 @@ import React, { PropTypes } from 'react'
22import ReactDOM from 'react-dom'
33import moment from 'moment'
44import _ from 'lodash'
5- import ModeIcon from 'browser/components/ModeIcon'
65import MarkdownPreview from 'browser/components/MarkdownPreview'
76import CodeEditor from 'browser/components/CodeEditor'
87import {
9- IDLE_MODE ,
10- EDIT_MODE ,
11- switchMode ,
12- switchArticle ,
138 switchFolder ,
14- clearSearch ,
15- lockStatus ,
16- unlockStatus ,
17- updateArticle ,
18- destroyArticle ,
19- NEW
9+ cacheArticle ,
10+ saveArticle ,
11+ destroyArticle
2012} from '../../actions'
2113import linkState from 'browser/lib/linkState'
2214import FolderMark from 'browser/components/FolderMark'
23- import TagLink from '../TagLink'
2415import TagSelect from 'browser/components/TagSelect'
2516import ModeSelect from 'browser/components/ModeSelect'
2617import activityRecord from 'browser/lib/activityRecord'
@@ -123,45 +114,31 @@ export default class ArticleDetail extends React.Component {
123114 clearInterval ( this . refreshTimer )
124115 }
125116
126- componentDidUpdate ( prevProps ) {
127- let isModeChanged = prevProps . status . mode !== this . props . status . mode
128- if ( isModeChanged && this . props . status . mode === EDIT_MODE ) {
129- ReactDOM . findDOMNode ( this . refs . title ) . focus ( )
130- }
131- }
132-
133117 componentWillReceiveProps ( nextProps ) {
134- let nextState = { }
118+ if ( nextProps . activeArticle == null || this . props . activeArticle == null || nextProps . activeArticle . key !== this . props . activeArticle . key ) {
119+ let nextArticle = nextProps . activeArticle
120+ let nextModified = nextArticle != null ? _ . findWhere ( nextProps . modified , { key : nextArticle . key } ) : null
135121
136- let isArticleChanged = nextProps . activeArticle != null && ( nextProps . activeArticle . key !== this . state . article . key )
137- let isModeChanged = nextProps . status . mode !== this . props . status . mode
122+ let article = Object . assign ( { } , nextProps . activeArticle , nextModified )
138123
139- // Reset article input
140- if ( isArticleChanged || ( isModeChanged && nextProps . status . mode !== IDLE_MODE ) ) {
141- Object . assign ( nextState , {
142- article : makeInstantArticle ( nextProps . activeArticle )
124+ this . setState ( {
125+ article
143126 } )
144127 }
128+ }
145129
146- // Clean state
147- if ( isModeChanged ) {
148- Object . assign ( nextState , {
149- openDeleteConfirmMenu : false ,
150- previewMode : false ,
151- isArticleEdited : false ,
152- isTagChanged : false ,
153- isTitleChanged : false ,
154- isContentChanged : false
155- } )
156- }
130+ cacheArticle ( ) {
131+ let { dispatch } = this . props
157132
158- this . setState ( nextState )
133+ dispatch ( cacheArticle ( this . props . activeArticle . key , this . state . article ) )
159134 }
160135
161136 renderEmpty ( ) {
162137 return (
163138 < div className = 'ArticleDetail empty' >
164- Command(⌘) + Enter to create a new post
139+ < div className = 'ArticleDetail-empty-box' >
140+ < div className = 'ArticleDetail-empty-box-message' > Command(⌘) + N< br /> to create a new post</ div >
141+ </ div >
165142 </ div >
166143 )
167144 }
@@ -176,123 +153,46 @@ export default class ArticleDetail extends React.Component {
176153
177154 handleSaveButtonClick ( e ) {
178155 let { dispatch, folders, status } = this . props
179- let article = this . state . article
180- let newArticle = Object . assign ( { } , article )
181-
182- let folder = _ . findWhere ( folders , { key : article . FolderKey } )
183- if ( folder == null ) return false
184156
185- dispatch ( unlockStatus ( ) )
186-
187- newArticle . status = null
188- newArticle . updatedAt = new Date ( )
189- newArticle . title = newArticle . title . trim ( )
190- if ( newArticle . createdAt == null ) {
191- newArticle . createdAt = new Date ( )
192- if ( newArticle . title . length === 0 ) {
193- newArticle . title = `Created at ${ moment ( newArticle . createdAt ) . format ( 'YYYY/MM/DD HH:mm' ) } `
194- }
195- activityRecord . emit ( 'ARTICLE_CREATE' , { mode : newArticle . mode } )
196- } else {
197- activityRecord . emit ( 'ARTICLE_UPDATE' , { mode : newArticle . mode } )
157+ let targetFolderKey = this . state . article . FolderKey
158+ dispatch ( saveArticle ( this . props . activeArticle . key , this . state . article ) , true )
159+ if ( status . targetFolders . length > 0 ) {
160+ let targetFolder = _ . findWhere ( folders , { key : targetFolderKey } )
161+ dispatch ( switchFolder ( targetFolder . name ) )
198162 }
199-
200- dispatch ( updateArticle ( newArticle ) )
201- dispatch ( switchMode ( IDLE_MODE ) )
202- // Folder filterがかかっている時に、
203- // Searchを初期化し、更新先のFolder filterをかける
204- // かかれていない時に
205- // Searchを初期化する
206- if ( status . targetFolders . length > 0 ) dispatch ( switchFolder ( folder . name ) )
207- else dispatch ( clearSearch ( ) )
208- dispatch ( switchArticle ( newArticle . key ) )
209163 }
210164
211165 handleFolderKeyChange ( e ) {
212166 let article = this . state . article
213167 article . FolderKey = e . target . value
214168
215- this . setState ( { article : article } )
169+ this . setState ( { article : article } , ( ) => this . cacheArticle ( ) )
216170 }
217171
218172 handleTitleChange ( e ) {
219173 let { article } = this . state
220174 article . title = e . target . value
221- let _isTitleChanged = article . title !== this . props . activeArticle . title
222-
223- let { isTagChanged, isContentChanged, isArticleEdited, isModeChanged } = this . state
224- let _isArticleEdited = _isTitleChanged || isTagChanged || isContentChanged || isModeChanged
225175
226176 this . setState ( {
227- article,
228- isTitleChanged : _isTitleChanged ,
229- isArticleEdited : _isArticleEdited
230- } , ( ) => {
231- if ( isArticleEdited !== _isArticleEdited ) {
232- let { dispatch } = this . props
233- if ( _isArticleEdited ) {
234- console . log ( 'lockit' )
235- dispatch ( lockStatus ( ) )
236- } else {
237- console . log ( 'unlockit' )
238- dispatch ( unlockStatus ( ) )
239- }
240- }
241- } )
177+ article
178+ } , ( ) => this . cacheArticle ( ) )
242179 }
243180
244181 handleTagsChange ( newTag , tags ) {
245182 let article = this . state . article
246183 article . tags = tags
247184
248- let _isTagChanged = _ . difference ( article . tags , this . props . activeArticle . tags ) . length > 0 || _ . difference ( this . props . activeArticle . tags , article . tags ) . length > 0
249-
250- let { isTitleChanged, isContentChanged, isArticleEdited, isModeChanged } = this . state
251- let _isArticleEdited = _isTagChanged || isTitleChanged || isContentChanged || isModeChanged
252-
253185 this . setState ( {
254- article,
255- isTagChanged : _isTagChanged ,
256- isArticleEdited : _isArticleEdited
257- } , ( ) => {
258- if ( isArticleEdited !== _isArticleEdited ) {
259- let { dispatch } = this . props
260- if ( _isArticleEdited ) {
261- console . log ( 'lockit' )
262- dispatch ( lockStatus ( ) )
263- } else {
264- console . log ( 'unlockit' )
265- dispatch ( unlockStatus ( ) )
266- }
267- }
268- } )
186+ article
187+ } , ( ) => this . cacheArticle ( ) )
269188 }
270189
271190 handleModeChange ( value ) {
272191 let { article } = this . state
273192 article . mode = value
274- let _isModeChanged = article . mode !== this . props . activeArticle . mode
275-
276- let { isTagChanged, isContentChanged, isArticleEdited, isTitleChanged } = this . state
277- let _isArticleEdited = _isModeChanged || isTagChanged || isContentChanged || isTitleChanged
278-
279193 this . setState ( {
280- article,
281- previewMode : false ,
282- isModeChanged : _isModeChanged ,
283- isArticleEdited : _isArticleEdited
284- } , ( ) => {
285- if ( isArticleEdited !== _isArticleEdited ) {
286- let { dispatch } = this . props
287- if ( _isArticleEdited ) {
288- console . log ( 'lockit' )
289- dispatch ( lockStatus ( ) )
290- } else {
291- console . log ( 'unlockit' )
292- dispatch ( unlockStatus ( ) )
293- }
294- }
295- } )
194+ article
195+ } , ( ) => this . cacheArticle ( ) )
296196 }
297197
298198 handleModeSelectBlur ( ) {
@@ -302,34 +202,12 @@ export default class ArticleDetail extends React.Component {
302202 }
303203
304204 handleContentChange ( e , value ) {
305- let { status } = this . props
306- if ( status . mode === IDLE_MODE ) {
307- return
308- }
309-
310205 let { article } = this . state
311206 article . content = value
312- let _isContentChanged = article . content !== this . props . activeArticle . content
313-
314- let { isTagChanged, isModeChanged, isArticleEdited, isTitleChanged } = this . state
315- let _isArticleEdited = _isContentChanged || isTagChanged || isModeChanged || isTitleChanged
316207
317208 this . setState ( {
318- article,
319- isContentChanged : _isContentChanged ,
320- isArticleEdited : _isArticleEdited
321- } , ( ) => {
322- if ( isArticleEdited !== _isArticleEdited ) {
323- let { dispatch } = this . props
324- if ( _isArticleEdited ) {
325- console . log ( 'lockit' )
326- dispatch ( lockStatus ( ) )
327- } else {
328- console . log ( 'unlockit' )
329- dispatch ( unlockStatus ( ) )
330- }
331- }
332- } )
209+ article
210+ } , ( ) => this . cacheArticle ( ) )
333211 }
334212
335213 handleTogglePreviewButtonClick ( e ) {
@@ -373,14 +251,16 @@ export default class ArticleDetail extends React.Component {
373251 }
374252
375253 render ( ) {
376- let { folders, status, tags, activeArticle, user } = this . props
377-
254+ let { folders, status, tags, activeArticle, modified , user } = this . props
255+ if ( activeArticle == null ) return this . renderEmpty ( )
378256 let folderOptions = folders . map ( folder => {
379257 return (
380258 < option key = { folder . key } value = { folder . key } > { folder . name } </ option >
381259 )
382260 } )
383261
262+ let isUnsaved = ! ! _ . findWhere ( modified , { key : activeArticle . key } )
263+
384264 return (
385265 < div className = 'ArticleDetail' >
386266 < div className = 'ArticleDetail-info' >
@@ -392,7 +272,13 @@ export default class ArticleDetail extends React.Component {
392272 >
393273 { folderOptions }
394274 </ select >
395- { this . state . isArticleEdited ? ' (edited)' : '' }
275+ < span className = 'ArticleDetail-info-status'
276+ children = {
277+ isUnsaved
278+ ? < span > < span className = 'unsaved-mark' > ●</ span > Unsaved</ span >
279+ : `Created : ${ moment ( this . state . article . createdAt ) . format ( 'YYYY/MM/DD' ) } Updated : ${ moment ( this . state . article . updatedAt ) . format ( 'YYYY/MM/DD' ) } `
280+ }
281+ />
396282
397283 < div className = 'ArticleDetail-info-control' >
398284 < ShareButton
@@ -404,8 +290,8 @@ export default class ArticleDetail extends React.Component {
404290 < i className = 'fa fa-fw fa-clipboard' /> < span className = 'tooltip' > Copy to clipboard</ span >
405291 </ button >
406292
407- < button onClick = { e => this . handleEditButtonClick ( e ) } >
408- < i className = 'fa fa-fw fa-edit ' /> < span className = 'tooltip' > Save (⌘ + s)</ span >
293+ < button onClick = { e => this . handleSaveButtonClick ( e ) } >
294+ < i className = 'fa fa-fw fa-save ' /> < span className = 'tooltip' > Save (⌘ + s)</ span >
409295 </ button >
410296 < button onClick = { e => this . handleDeleteButtonClick ( e ) } >
411297 < i className = 'fa fa-fw fa-trash' /> < span className = 'tooltip' > Delete</ span >
@@ -426,24 +312,22 @@ export default class ArticleDetail extends React.Component {
426312
427313 < div className = 'ArticleDetail-panel' >
428314 < div className = 'ArticleDetail-panel-header' >
429- < ModeSelect
430- ref = 'mode'
431- onChange = { e => this . handleModeChange ( e ) }
432- value = { this . state . article . mode }
433- className = 'ArticleDetail-panel-header-mode'
434- onBlur = { ( ) => this . handleModeSelectBlur ( ) }
435- />
436315 < div className = 'ArticleDetail-panel-header-title' >
437316 < input
438317 onKeyDown = { e => this . handleTitleKeyDown ( e ) }
439- placeholder = { this . state . article . createdAt == null
440- ? `Created at ${ moment ( ) . format ( 'YYYY/MM/DD HH:mm' ) } `
441- : 'Title' }
318+ placeholder = '(Untitled)'
442319 ref = 'title'
443320 value = { this . state . article . title }
444321 onChange = { e => this . handleTitleChange ( e ) }
445322 />
446323 </ div >
324+ < ModeSelect
325+ ref = 'mode'
326+ onChange = { e => this . handleModeChange ( e ) }
327+ value = { this . state . article . mode }
328+ className = 'ArticleDetail-panel-header-mode'
329+ onBlur = { ( ) => this . handleModeSelectBlur ( ) }
330+ />
447331 </ div >
448332 { status . isTutorialOpen ? modeSelectTutorialElement : null }
449333
@@ -466,6 +350,7 @@ export default class ArticleDetail extends React.Component {
466350ArticleDetail . propTypes = {
467351 status : PropTypes . shape ( ) ,
468352 activeArticle : PropTypes . shape ( ) ,
353+ modified : PropTypes . array ,
469354 user : PropTypes . shape ( ) ,
470355 folders : PropTypes . array ,
471356 tags : PropTypes . array ,
0 commit comments