Skip to content

Commit 7f87337

Browse files
committed
Detail
1 parent 1a98afe commit 7f87337

17 files changed

Lines changed: 900 additions & 649 deletions

browser/components/CodeEditor.js

Lines changed: 59 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,20 @@ import React, { PropTypes } from 'react'
22
import ReactDOM from 'react-dom'
33
import modes from '../lib/modes'
44
import _ from 'lodash'
5-
import fetchConfig from '../lib/fetchConfig'
6-
7-
const electron = require('electron')
8-
const remote = electron.remote
9-
const ipc = electron.ipcRenderer
105

116
const ace = window.ace
127

13-
let config = fetchConfig()
14-
ipc.on('config-apply', function (e, newConfig) {
15-
config = newConfig
16-
})
17-
188
export default class CodeEditor extends React.Component {
199
constructor (props) {
2010
super(props)
2111

22-
this.configApplyHandler = (e, config) => this.handleConfigApply(e, config)
23-
this.changeHandler = e => this.handleChange(e)
12+
this.changeHandler = (e) => this.handleChange(e)
2413
this.blurHandler = (e) => {
2514
if (e.relatedTarget === null) {
2615
return
2716
}
2817

29-
let isFocusingToSearch = e.relatedTarget.className && e.relatedTarget.className.split(' ').some(clss => {
18+
let isFocusingToSearch = e.relatedTarget.className && e.relatedTarget.className.split(' ').some((clss) => {
3019
return clss === 'ace_search_field' || clss === 'ace_searchbtn' || clss === 'ace_replacebtn' || clss === 'ace_searchbtn_close' || clss === 'ace_text-input'
3120
})
3221
if (isFocusingToSearch) {
@@ -38,7 +27,7 @@ export default class CodeEditor extends React.Component {
3827

3928
this.killedBuffer = ''
4029
this.execHandler = (e) => {
41-
console.log(e.command.name)
30+
console.info('ACE COMMAND >> %s', e.command.name)
4231
switch (e.command.name) {
4332
case 'gotolinestart':
4433
e.preventDefault()
@@ -84,7 +73,7 @@ export default class CodeEditor extends React.Component {
8473
this.afterExecHandler = (e) => {
8574
switch (e.command.name) {
8675
case 'find':
87-
Array.prototype.forEach.call(ReactDOM.findDOMNode(this).querySelectorAll('.ace_search_field, .ace_searchbtn, .ace_replacebtn, .ace_searchbtn_close'), el => {
76+
Array.prototype.forEach.call(ReactDOM.findDOMNode(this).querySelectorAll('.ace_search_field, .ace_searchbtn, .ace_replacebtn, .ace_searchbtn_close'), (el) => {
8877
el.removeEventListener('blur', this.blurHandler)
8978
el.addEventListener('blur', this.blurHandler)
9079
})
@@ -93,11 +82,6 @@ export default class CodeEditor extends React.Component {
9382
}
9483

9584
this.state = {
96-
fontSize: config['editor-font-size'],
97-
fontFamily: config['editor-font-family'],
98-
indentType: config['editor-indent-type'],
99-
indentSize: config['editor-indent-size'],
100-
themeSyntax: config['theme-syntax']
10185
}
10286

10387
this.silentChange = false
@@ -110,15 +94,15 @@ export default class CodeEditor extends React.Component {
11094
}
11195

11296
componentDidMount () {
113-
let { article } = this.props
114-
var el = ReactDOM.findDOMNode(this)
115-
var editor = this.editor = ace.edit(el)
97+
let { mode, value } = this.props
98+
let el = ReactDOM.findDOMNode(this)
99+
let editor = this.editor = ace.edit(el)
116100
editor.$blockScrolling = Infinity
117101
editor.renderer.setShowGutter(true)
118-
editor.setTheme('ace/theme/' + this.state.themeSyntax)
102+
editor.setTheme('ace/theme/xcode')
119103
editor.moveCursorTo(0, 0)
120104
editor.setReadOnly(!!this.props.readOnly)
121-
editor.setFontSize(this.state.fontSize)
105+
editor.setFontSize('14')
122106

123107
editor.on('blur', this.blurHandler)
124108

@@ -132,31 +116,19 @@ export default class CodeEditor extends React.Component {
132116
readOnly: true
133117
})
134118
editor.commands.addCommand({
135-
name: 'Emacs cursor up',
119+
name: 'Emacs kill buffer',
136120
bindKey: {mac: 'Ctrl-Y'},
137121
exec: function (editor) {
138122
editor.insert(this.killedBuffer)
139123
}.bind(this),
140124
readOnly: true
141125
})
142-
editor.commands.addCommand({
143-
name: 'Focus title',
144-
bindKey: {win: 'Esc', mac: 'Esc'},
145-
exec: function (editor, e) {
146-
let currentWindow = remote.getCurrentWebContents()
147-
if (config['switch-preview'] === 'rightclick') {
148-
currentWindow.send('detail-preview')
149-
}
150-
currentWindow.send('list-focus')
151-
},
152-
readOnly: true
153-
})
154126

155127
editor.commands.on('exec', this.execHandler)
156128
editor.commands.on('afterExec', this.afterExecHandler)
157129

158130
var session = editor.getSession()
159-
let mode = _.findWhere(modes, {name: article.mode})
131+
mode = _.find(modes, {name: mode})
160132
let syntaxMode = mode != null
161133
? mode.mode
162134
: 'text'
@@ -166,15 +138,12 @@ export default class CodeEditor extends React.Component {
166138
session.setTabSize(!isNaN(this.state.indentSize) ? parseInt(this.state.indentSize, 10) : 4)
167139
session.setOption('useWorker', false)
168140
session.setUseWrapMode(true)
169-
session.setValue(this.props.article.content)
141+
session.setValue(_.isString(value) ? value : '')
170142

171143
session.on('change', this.changeHandler)
172-
173-
ipc.on('config-apply', this.configApplyHandler)
174144
}
175145

176146
componentWillUnmount () {
177-
ipc.removeListener('config-apply', this.configApplyHandler)
178147
this.editor.getSession().removeListener('change', this.changeHandler)
179148
this.editor.removeListener('blur', this.blurHandler)
180149
this.editor.commands.removeListener('exec', this.execHandler)
@@ -183,41 +152,37 @@ export default class CodeEditor extends React.Component {
183152

184153
componentDidUpdate (prevProps, prevState) {
185154
var session = this.editor.getSession()
186-
if (this.props.article.key !== prevProps.article.key) {
187-
session.removeListener('change', this.changeHandler)
188-
session.setValue(this.props.article.content)
189-
session.getUndoManager().reset()
190-
session.on('change', this.changeHandler)
191-
}
192-
if (prevProps.article.mode !== this.props.article.mode) {
193-
let mode = _.findWhere(modes, {name: this.props.article.mode})
155+
156+
if (prevProps.mode !== this.props.mode) {
157+
let mode = _.find(modes, {name: this.props.mode})
194158
let syntaxMode = mode != null
195159
? mode.mode
196160
: 'text'
197-
session.setMode('ace/mode/' + syntaxMode)
161+
session.setMode('ace/mode' + syntaxMode)
198162
}
199163
}
200164

201165
handleConfigApply (e, config) {
202-
this.setState({
203-
fontSize: config['editor-font-size'],
204-
fontFamily: config['editor-font-family'],
205-
indentType: config['editor-indent-type'],
206-
indentSize: config['editor-indent-size'],
207-
themeSyntax: config['theme-syntax']
208-
}, function () {
209-
var editor = this.editor
210-
editor.setTheme('ace/theme/' + this.state.themeSyntax)
211-
212-
var session = editor.getSession()
213-
session.setUseSoftTabs(this.state.indentType === 'space')
214-
session.setTabSize(!isNaN(this.state.indentSize) ? parseInt(this.state.indentSize, 10) : 4)
215-
})
166+
// this.setState({
167+
// fontSize: config['editor-font-size'],
168+
// fontFamily: config['editor-font-family'],
169+
// indentType: config['editor-indent-type'],
170+
// indentSize: config['editor-indent-size'],
171+
// themeSyntax: config['theme-syntax']
172+
// }, function () {
173+
// var editor = this.editor
174+
// editor.setTheme('ace/theme/' + this.state.themeSyntax)
175+
176+
// var session = editor.getSession()
177+
// session.setUseSoftTabs(this.state.indentType === 'space')
178+
// session.setTabSize(!isNaN(this.state.indentSize) ? parseInt(this.state.indentSize, 10) : 4)
179+
// })
216180
}
181+
217182
handleChange (e) {
218183
if (this.props.onChange) {
219-
var value = this.editor.getValue()
220-
this.props.onChange(value)
184+
this.value = this.editor.getValue()
185+
this.props.onChange(e)
221186
}
222187
}
223188

@@ -237,25 +202,43 @@ export default class CodeEditor extends React.Component {
237202
this.editor.scrollToLine(num, false, false)
238203
}
239204

205+
focus () {
206+
this.editor.focus()
207+
}
208+
209+
blur () {
210+
this.editor.blur()
211+
}
212+
213+
reload () {
214+
let session = this.editor.getSession()
215+
session.removeListener('change', this.changeHandler)
216+
session.setValue(this.props.value)
217+
session.getUndoManager().reset()
218+
session.on('change', this.changeHandler)
219+
}
220+
240221
render () {
222+
let { className } = this.props
223+
241224
return (
242225
<div
243-
className={this.props.className == null ? 'CodeEditor' : 'CodeEditor ' + this.props.className}
226+
className={className == null
227+
? 'CodeEditor'
228+
: `CodeEditor ${className}`
229+
}
244230
style={{
245-
fontSize: this.state.fontSize,
246-
fontFamily: this.state.fontFamily.trim() + ', monospace'
231+
fontSize: '14px',
232+
fontFamily: 'monospace'
247233
}}
248234
/>
249235
)
250236
}
251237
}
252238

253239
CodeEditor.propTypes = {
254-
article: PropTypes.shape({
255-
content: PropTypes.string,
256-
mode: PropTypes.string,
257-
key: PropTypes.string
258-
}),
240+
value: PropTypes.string,
241+
mode: PropTypes.string,
259242
className: PropTypes.string,
260243
onBlur: PropTypes.func,
261244
onChange: PropTypes.func,
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import React, { PropTypes } from 'react'
2+
import CSSModules from 'browser/lib/CSSModules'
3+
import styles from './MarkdownEditor.styl'
4+
import CodeEditor from 'browser/components/CodeEditor'
5+
import MarkdownPreview from 'browser/components/MarkdownPreview'
6+
7+
class MarkdownEditor extends React.Component {
8+
constructor (props) {
9+
super(props)
10+
11+
this.state = {
12+
status: 'CODE'
13+
}
14+
}
15+
16+
handleChange (e) {
17+
this.value = this.refs.code.value
18+
this.props.onChange(e)
19+
}
20+
21+
handleContextMenu (e) {
22+
let newStatus = this.state.status === 'PREVIEW'
23+
? 'CODE'
24+
: 'PREVIEW'
25+
this.setState({
26+
status: newStatus
27+
}, () => {
28+
if (newStatus === 'CODE') {
29+
this.refs.code.focus()
30+
} else {
31+
this.refs.code.blur()
32+
this.refs.preview.focus()
33+
}
34+
})
35+
}
36+
37+
reload () {
38+
this.refs.code.reload()
39+
}
40+
41+
render () {
42+
let { className, value } = this.props
43+
44+
return (
45+
<div className={className == null
46+
? 'MarkdownEditor'
47+
: `MarkdownEditor ${className}`
48+
}
49+
onContextMenu={(e) => this.handleContextMenu(e)}
50+
>
51+
<CodeEditor styleName='codeEditor'
52+
ref='code'
53+
mode='markdown'
54+
value={value}
55+
onChange={(e) => this.handleChange(e)}
56+
/>
57+
<MarkdownPreview styleName={this.state.status === 'PREVIEW'
58+
? 'preview'
59+
: 'preview--hide'
60+
}
61+
style={this.props.ignorePreviewPointerEvents
62+
? {pointerEvents: 'none'} : {}
63+
}
64+
ref='preview'
65+
onContextMenu={(e) => this.handleContextMenu(e)}
66+
tabIndex='0'
67+
value={value}
68+
/>
69+
</div>
70+
)
71+
}
72+
}
73+
74+
MarkdownEditor.propTypes = {
75+
className: PropTypes.string,
76+
value: PropTypes.string,
77+
onChange: PropTypes.func,
78+
ignorePreviewPointerEvents: PropTypes.bool
79+
}
80+
81+
export default CSSModules(MarkdownEditor, styles)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.root
2+
position relative
3+
4+
.codeEditor
5+
absolute top bottom left right
6+
7+
.codeEditor--hide
8+
@extend .codeEditor
9+
10+
.preview
11+
display block
12+
absolute top bottom left right
13+
z-index 100
14+
background-color white
15+
height 100%
16+
width 100%
17+
18+
.preview--hide
19+
@extend .preview
20+
z-index 0
21+
opacity 0
22+
pointer-events none
23+

0 commit comments

Comments
 (0)