1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 01:36:22 +00:00

One-click to edit

This commit is contained in:
Rokt33r
2016-01-04 01:45:45 +09:00
parent 47169e19aa
commit fdea9a68a1
4 changed files with 144 additions and 40 deletions

View File

@@ -7,8 +7,14 @@ const electron = require('electron')
const shell = electron.shell const shell = electron.shell
function handleAnchorClick (e) { function handleAnchorClick (e) {
shell.openExternal(e.target.href)
e.preventDefault() e.preventDefault()
e.stopPropagation()
shell.openExternal(e.target.href)
}
function stopPropagation (e) {
e.preventDefault()
e.stopPropagation()
} }
export default class MarkdownPreview extends React.Component { export default class MarkdownPreview extends React.Component {
@@ -29,18 +35,22 @@ export default class MarkdownPreview extends React.Component {
} }
addListener () { addListener () {
var anchors = ReactDOM.findDOMNode(this).querySelectorAll('a') var anchors = ReactDOM.findDOMNode(this).querySelectorAll('a:not(.lineAnchor)')
for (var i = 0; i < anchors.length; i++) { for (var i = 0; i < anchors.length; i++) {
anchors[i].addEventListener('click', handleAnchorClick) anchors[i].addEventListener('click', handleAnchorClick)
anchors[i].addEventListener('mousedown', stopPropagation)
anchors[i].addEventListener('mouseup', stopPropagation)
} }
} }
removeListener () { removeListener () {
var anchors = ReactDOM.findDOMNode(this).querySelectorAll('a') var anchors = ReactDOM.findDOMNode(this).querySelectorAll('a:not(.lineAnchor)')
for (var i = 0; i < anchors.length; i++) { for (var i = 0; i < anchors.length; i++) {
anchors[i].removeEventListener('click', handleAnchorClick) anchors[i].removeEventListener('click', handleAnchorClick)
anchors[i].removeEventListener('mousedown', stopPropagation)
anchors[i].removeEventListener('mouseup', stopPropagation)
} }
} }
@@ -56,13 +66,39 @@ export default class MarkdownPreview extends React.Component {
} }
} }
handleMouseDown (e) {
if (this.props.onMouseDown) {
this.props.onMouseDown(e)
}
}
handleMouseUp (e) {
if (this.props.onMouseUp) {
this.props.onMouseUp(e)
}
}
handleMouseMove (e) {
if (this.props.onMouseMove) {
this.props.onMouseMove(e)
}
}
render () { render () {
let isEmpty = this.props.content.trim().length === 0 let isEmpty = this.props.content.trim().length === 0
let content = isEmpty let content = isEmpty
? '(Empty content)' ? '(Empty content)'
: this.props.content : this.props.content
return ( return (
<div onDoubleClick={e => this.handleDoubleClick(e)} className={'MarkdownPreview' + (this.props.className != null ? ' ' + this.props.className : '') + (isEmpty ? ' empty' : '')} dangerouslySetInnerHTML={{__html: ' ' + markdown(content)}}/> <div
className={'MarkdownPreview' + (this.props.className != null ? ' ' + this.props.className : '') + (isEmpty ? ' empty' : '')}
onClick={e => this.handleClick(e)}
onDoubleClick={e => this.handleDoubleClick(e)}
onMouseDown={e => this.handleMouseDown(e)}
onMouseMove={e => this.handleMouseMove(e)}
onMouseUp={e => this.handleMouseUp(e)}
dangerouslySetInnerHTML={{__html: ' ' + markdown(content)}}
/>
) )
} }
} }
@@ -70,6 +106,9 @@ export default class MarkdownPreview extends React.Component {
MarkdownPreview.propTypes = { MarkdownPreview.propTypes = {
onClick: PropTypes.func, onClick: PropTypes.func,
onDoubleClick: PropTypes.func, onDoubleClick: PropTypes.func,
onMouseUp: PropTypes.func,
onMouseDown: PropTypes.func,
onMouseMove: PropTypes.func,
className: PropTypes.string, className: PropTypes.string,
content: PropTypes.string content: PropTypes.string
} }

View File

@@ -0,0 +1,91 @@
import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom'
import MarkdownPreview from 'browser/components/MarkdownPreview'
import CodeEditor from 'browser/components/CodeEditor'
export const PREVIEW_MODE = 'PREVIEW_MODE'
export const EDIT_MODE = 'EDIT_MODE'
export default class ArticleEditor extends React.Component {
constructor (props) {
super(props)
this.isMouseDown = false
this.state = {
status: PREVIEW_MODE
}
}
componentWillReceiveProps (nextProps) {
}
switchPreviewMode () {
this.setState({
status: PREVIEW_MODE
})
}
switchEditMode () {
this.setState({
status: EDIT_MODE
}, function () {
this.refs.editor.editor.focus()
})
}
handlePreviewMouseDown (e) {
if (e.button === 2) return true
this.isDrag = false
this.isMouseDown = true
}
handlePreviewMouseMove () {
if (this.isMouseDown) this.isDrag = true
}
handlePreviewMouseUp () {
this.isMouseDown = false
if (!this.isDrag) {
this.switchEditMode()
}
}
handleBlurCodeEditor () {
if (this.props.mode === 'markdown') {
this.switchPreviewMode()
}
}
render () {
if (this.props.mode === 'markdown' && this.state.status === PREVIEW_MODE) {
return (
<div className='ArticleEditor'>
<MarkdownPreview
onMouseUp={e => this.handlePreviewMouseUp(e)}
onMouseDown={e => this.handlePreviewMouseDown(e)}
onMouseMove={e => this.handlePreviewMouseMove(e)}
content={this.props.content}
/>
<div className='ArticleDetail-panel-content-tooltip'>Click to Edit</div>
</div>
)
}
return (
<div className='ArticleEditor'>
<CodeEditor ref='editor'
onBlur={e => this.handleBlurCodeEditor(e)}
onChange={this.props.onChange}
mode={this.props.mode}
code={this.props.content}
/>
<div className='ArticleDetail-panel-content-tooltip'>Press ESC to watch Preview</div>
</div>
)
}
}
ArticleEditor.propTypes = {
content: PropTypes.string,
mode: PropTypes.string,
onChange: PropTypes.func
}

View File

@@ -2,8 +2,6 @@ import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import moment from 'moment' import moment from 'moment'
import _ from 'lodash' import _ from 'lodash'
import MarkdownPreview from 'browser/components/MarkdownPreview'
import CodeEditor from 'browser/components/CodeEditor'
import { import {
switchFolder, switchFolder,
cacheArticle, cacheArticle,
@@ -16,7 +14,7 @@ import ModeSelect from 'browser/components/ModeSelect'
import ShareButton from './ShareButton' import ShareButton from './ShareButton'
import { openModal, isModalOpen } from 'browser/lib/modal' import { openModal, isModalOpen } from 'browser/lib/modal'
import DeleteArticleModal from '../../modal/DeleteArticleModal' import DeleteArticleModal from '../../modal/DeleteArticleModal'
import ArticleEditor from './ArticleEditor'
const electron = require('electron') const electron = require('electron')
const ipc = electron.ipcRenderer const ipc = electron.ipcRenderer
const remote = electron.remote const remote = electron.remote
@@ -275,9 +273,7 @@ export default class ArticleDetail extends React.Component {
handleModeSelectKeyDown (e) { handleModeSelectKeyDown (e) {
if (e.keyCode === 9 && !e.shiftKey) { if (e.keyCode === 9 && !e.shiftKey) {
e.preventDefault() e.preventDefault()
this.setState({previewMode: false}, function () { this.refs.editor.switchEditMode()
this.refs.code.editor.focus()
})
} }
if (e.keyCode === 9 && e.shiftKey) { if (e.keyCode === 9 && e.shiftKey) {
e.preventDefault() e.preventDefault()
@@ -285,14 +281,6 @@ export default class ArticleDetail extends React.Component {
} }
} }
handlePreviewDoubleClick (e) {
this.setState({
previewMode: false
}, function () {
this.refs.code.editor.focus()
})
}
render () { render () {
let { folders, status, tags, activeArticle, modified, user } = this.props let { folders, status, tags, activeArticle, modified, user } = this.props
if (activeArticle == null) return this.renderEmpty() if (activeArticle == null) return this.renderEmpty()
@@ -369,27 +357,12 @@ export default class ArticleDetail extends React.Component {
/> />
</div> </div>
{status.isTutorialOpen ? modeSelectTutorialElement : null} {status.isTutorialOpen ? modeSelectTutorialElement : null}
<div className='ArticleDetail-panel-content'> <ArticleEditor
{this.state.article.mode === 'markdown' && this.state.previewMode ref='editor'
? (<MarkdownPreview
ref='preview'
onDoubleClick={e => this.handlePreviewDoubleClick(e)}
content={this.state.article.content} content={this.state.article.content}
/>)
: (<CodeEditor
ref='code'
onChange={(e, value) => this.handleContentChange(e, value)}
onBlur={e => this.handleCodeEditorBlur(e)}
readOnly={false}
mode={this.state.article.mode} mode={this.state.article.mode}
code={this.state.article.content} onChange={(e, content) => this.handleContentChange(e, content)}
/>)} />
{
this.state.article.mode === 'markdown' && this.state.previewMode
? <div className='ArticleDetail-panel-content-tooltip'>Double click to edit post</div>
: null
}
</div>
</div> </div>
</div> </div>
) )

View File

@@ -311,7 +311,7 @@ infoButton()
width 100% width 100%
font-size 24px font-size 24px
outline none outline none
.ArticleDetail-panel-content .ArticleEditor
absolute left right bottom absolute left right bottom
top 60px top 60px
.ArticleDetail-panel-content-tooltip .ArticleDetail-panel-content-tooltip
@@ -323,6 +323,7 @@ infoButton()
padding 0 15px padding 0 15px
opacity 0 opacity 0
transition 0.1s transition 0.1s
z-index 35
&:hover .ArticleDetail-panel-content-tooltip &:hover .ArticleDetail-panel-content-tooltip
opacity 1 opacity 1
.MarkdownPreview .MarkdownPreview