Skip to content

Commit fdea9a6

Browse files
committed
One-click to edit
1 parent 47169e1 commit fdea9a6

4 files changed

Lines changed: 143 additions & 39 deletions

File tree

browser/components/MarkdownPreview.js

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@ const electron = require('electron')
77
const shell = electron.shell
88

99
function handleAnchorClick (e) {
10+
e.preventDefault()
11+
e.stopPropagation()
1012
shell.openExternal(e.target.href)
13+
}
14+
15+
function stopPropagation (e) {
1116
e.preventDefault()
17+
e.stopPropagation()
1218
}
1319

1420
export default class MarkdownPreview extends React.Component {
@@ -29,18 +35,22 @@ export default class MarkdownPreview extends React.Component {
2935
}
3036

3137
addListener () {
32-
var anchors = ReactDOM.findDOMNode(this).querySelectorAll('a')
38+
var anchors = ReactDOM.findDOMNode(this).querySelectorAll('a:not(.lineAnchor)')
3339

3440
for (var i = 0; i < anchors.length; i++) {
3541
anchors[i].addEventListener('click', handleAnchorClick)
42+
anchors[i].addEventListener('mousedown', stopPropagation)
43+
anchors[i].addEventListener('mouseup', stopPropagation)
3644
}
3745
}
3846

3947
removeListener () {
40-
var anchors = ReactDOM.findDOMNode(this).querySelectorAll('a')
48+
var anchors = ReactDOM.findDOMNode(this).querySelectorAll('a:not(.lineAnchor)')
4149

4250
for (var i = 0; i < anchors.length; i++) {
4351
anchors[i].removeEventListener('click', handleAnchorClick)
52+
anchors[i].removeEventListener('mousedown', stopPropagation)
53+
anchors[i].removeEventListener('mouseup', stopPropagation)
4454
}
4555
}
4656

@@ -56,20 +66,49 @@ export default class MarkdownPreview extends React.Component {
5666
}
5767
}
5868

69+
handleMouseDown (e) {
70+
if (this.props.onMouseDown) {
71+
this.props.onMouseDown(e)
72+
}
73+
}
74+
75+
handleMouseUp (e) {
76+
if (this.props.onMouseUp) {
77+
this.props.onMouseUp(e)
78+
}
79+
}
80+
81+
handleMouseMove (e) {
82+
if (this.props.onMouseMove) {
83+
this.props.onMouseMove(e)
84+
}
85+
}
86+
5987
render () {
6088
let isEmpty = this.props.content.trim().length === 0
6189
let content = isEmpty
6290
? '(Empty content)'
6391
: this.props.content
6492
return (
65-
<div onDoubleClick={e => this.handleDoubleClick(e)} className={'MarkdownPreview' + (this.props.className != null ? ' ' + this.props.className : '') + (isEmpty ? ' empty' : '')} dangerouslySetInnerHTML={{__html: ' ' + markdown(content)}}/>
93+
<div
94+
className={'MarkdownPreview' + (this.props.className != null ? ' ' + this.props.className : '') + (isEmpty ? ' empty' : '')}
95+
onClick={e => this.handleClick(e)}
96+
onDoubleClick={e => this.handleDoubleClick(e)}
97+
onMouseDown={e => this.handleMouseDown(e)}
98+
onMouseMove={e => this.handleMouseMove(e)}
99+
onMouseUp={e => this.handleMouseUp(e)}
100+
dangerouslySetInnerHTML={{__html: ' ' + markdown(content)}}
101+
/>
66102
)
67103
}
68104
}
69105

70106
MarkdownPreview.propTypes = {
71107
onClick: PropTypes.func,
72108
onDoubleClick: PropTypes.func,
109+
onMouseUp: PropTypes.func,
110+
onMouseDown: PropTypes.func,
111+
onMouseMove: PropTypes.func,
73112
className: PropTypes.string,
74113
content: PropTypes.string
75114
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import React, { PropTypes } from 'react'
2+
import ReactDOM from 'react-dom'
3+
import MarkdownPreview from 'browser/components/MarkdownPreview'
4+
import CodeEditor from 'browser/components/CodeEditor'
5+
6+
export const PREVIEW_MODE = 'PREVIEW_MODE'
7+
export const EDIT_MODE = 'EDIT_MODE'
8+
9+
export default class ArticleEditor extends React.Component {
10+
constructor (props) {
11+
super(props)
12+
this.isMouseDown = false
13+
this.state = {
14+
status: PREVIEW_MODE
15+
}
16+
}
17+
18+
componentWillReceiveProps (nextProps) {
19+
}
20+
21+
switchPreviewMode () {
22+
this.setState({
23+
status: PREVIEW_MODE
24+
})
25+
}
26+
27+
switchEditMode () {
28+
this.setState({
29+
status: EDIT_MODE
30+
}, function () {
31+
this.refs.editor.editor.focus()
32+
})
33+
}
34+
35+
handlePreviewMouseDown (e) {
36+
if (e.button === 2) return true
37+
this.isDrag = false
38+
this.isMouseDown = true
39+
}
40+
41+
handlePreviewMouseMove () {
42+
if (this.isMouseDown) this.isDrag = true
43+
}
44+
45+
handlePreviewMouseUp () {
46+
this.isMouseDown = false
47+
if (!this.isDrag) {
48+
this.switchEditMode()
49+
}
50+
}
51+
52+
handleBlurCodeEditor () {
53+
if (this.props.mode === 'markdown') {
54+
this.switchPreviewMode()
55+
}
56+
}
57+
58+
render () {
59+
if (this.props.mode === 'markdown' && this.state.status === PREVIEW_MODE) {
60+
return (
61+
<div className='ArticleEditor'>
62+
<MarkdownPreview
63+
onMouseUp={e => this.handlePreviewMouseUp(e)}
64+
onMouseDown={e => this.handlePreviewMouseDown(e)}
65+
onMouseMove={e => this.handlePreviewMouseMove(e)}
66+
content={this.props.content}
67+
/>
68+
<div className='ArticleDetail-panel-content-tooltip'>Click to Edit</div>
69+
</div>
70+
)
71+
}
72+
73+
return (
74+
<div className='ArticleEditor'>
75+
<CodeEditor ref='editor'
76+
onBlur={e => this.handleBlurCodeEditor(e)}
77+
onChange={this.props.onChange}
78+
mode={this.props.mode}
79+
code={this.props.content}
80+
/>
81+
<div className='ArticleDetail-panel-content-tooltip'>Press ESC to watch Preview</div>
82+
</div>
83+
)
84+
}
85+
}
86+
87+
ArticleEditor.propTypes = {
88+
content: PropTypes.string,
89+
mode: PropTypes.string,
90+
onChange: PropTypes.func
91+
}

browser/main/HomePage/ArticleDetail/index.js

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import React, { PropTypes } from 'react'
22
import ReactDOM from 'react-dom'
33
import moment from 'moment'
44
import _ from 'lodash'
5-
import MarkdownPreview from 'browser/components/MarkdownPreview'
6-
import CodeEditor from 'browser/components/CodeEditor'
75
import {
86
switchFolder,
97
cacheArticle,
@@ -16,7 +14,7 @@ import ModeSelect from 'browser/components/ModeSelect'
1614
import ShareButton from './ShareButton'
1715
import { openModal, isModalOpen } from 'browser/lib/modal'
1816
import DeleteArticleModal from '../../modal/DeleteArticleModal'
19-
17+
import ArticleEditor from './ArticleEditor'
2018
const electron = require('electron')
2119
const ipc = electron.ipcRenderer
2220
const remote = electron.remote
@@ -275,24 +273,14 @@ export default class ArticleDetail extends React.Component {
275273
handleModeSelectKeyDown (e) {
276274
if (e.keyCode === 9 && !e.shiftKey) {
277275
e.preventDefault()
278-
this.setState({previewMode: false}, function () {
279-
this.refs.code.editor.focus()
280-
})
276+
this.refs.editor.switchEditMode()
281277
}
282278
if (e.keyCode === 9 && e.shiftKey) {
283279
e.preventDefault()
284280
ReactDOM.findDOMNode(this.refs.title).focus()
285281
}
286282
}
287283

288-
handlePreviewDoubleClick (e) {
289-
this.setState({
290-
previewMode: false
291-
}, function () {
292-
this.refs.code.editor.focus()
293-
})
294-
}
295-
296284
render () {
297285
let { folders, status, tags, activeArticle, modified, user } = this.props
298286
if (activeArticle == null) return this.renderEmpty()
@@ -369,27 +357,12 @@ export default class ArticleDetail extends React.Component {
369357
/>
370358
</div>
371359
{status.isTutorialOpen ? modeSelectTutorialElement : null}
372-
<div className='ArticleDetail-panel-content'>
373-
{this.state.article.mode === 'markdown' && this.state.previewMode
374-
? (<MarkdownPreview
375-
ref='preview'
376-
onDoubleClick={e => this.handlePreviewDoubleClick(e)}
377-
content={this.state.article.content}
378-
/>)
379-
: (<CodeEditor
380-
ref='code'
381-
onChange={(e, value) => this.handleContentChange(e, value)}
382-
onBlur={e => this.handleCodeEditorBlur(e)}
383-
readOnly={false}
384-
mode={this.state.article.mode}
385-
code={this.state.article.content}
386-
/>)}
387-
{
388-
this.state.article.mode === 'markdown' && this.state.previewMode
389-
? <div className='ArticleDetail-panel-content-tooltip'>Double click to edit post</div>
390-
: null
391-
}
392-
</div>
360+
<ArticleEditor
361+
ref='editor'
362+
content={this.state.article.content}
363+
mode={this.state.article.mode}
364+
onChange={(e, content) => this.handleContentChange(e, content)}
365+
/>
393366
</div>
394367
</div>
395368
)

browser/styles/main/ArticleDetail.styl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ infoButton()
311311
width 100%
312312
font-size 24px
313313
outline none
314-
.ArticleDetail-panel-content
314+
.ArticleEditor
315315
absolute left right bottom
316316
top 60px
317317
.ArticleDetail-panel-content-tooltip
@@ -323,6 +323,7 @@ infoButton()
323323
padding 0 15px
324324
opacity 0
325325
transition 0.1s
326+
z-index 35
326327
&:hover .ArticleDetail-panel-content-tooltip
327328
opacity 1
328329
.MarkdownPreview

0 commit comments

Comments
 (0)