@@ -2,43 +2,34 @@ import React, { PropTypes } from 'react'
22import ReactDOM from 'react-dom'
33import modes from '../lib/modes'
44import _ 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
116const ace = window . ace
127
13- let config = fetchConfig ( )
14- ipc . on ( 'config-apply' , function ( e , newConfig ) {
15- config = newConfig
16- } )
8+ const defaultEditorFontFamily = [ 'Monaco' , 'Menlo' , 'Ubuntu Mono' , 'Consolas' , 'source-code-pro' , 'monospace' ]
179
1810export default class CodeEditor extends React . Component {
1911 constructor ( props ) {
2012 super ( props )
2113
22- this . configApplyHandler = ( e , config ) => this . handleConfigApply ( e , config )
23- this . changeHandler = e => this . handleChange ( e )
14+ this . changeHandler = ( e ) => this . handleChange ( e )
2415 this . blurHandler = ( e ) => {
25- if ( e . relatedTarget === null ) {
26- return
27- }
28-
29- let isFocusingToSearch = e . relatedTarget . className && e . relatedTarget . className . split ( ' ' ) . some ( clss => {
30- return clss === 'ace_search_field' || clss === 'ace_searchbtn' || clss === 'ace_replacebtn' || clss === 'ace_searchbtn_close' || clss === 'ace_text-input'
31- } )
32- if ( isFocusingToSearch ) {
33- return
16+ e . stopPropagation ( )
17+ let el = e . relatedTarget
18+ let isStillFocused = false
19+ while ( el != null ) {
20+ if ( el === this . refs . root ) {
21+ isStillFocused = true
22+ break
23+ }
24+ el = el . parentNode
3425 }
3526
36- if ( this . props . onBlur ) this . props . onBlur ( e )
27+ if ( ! isStillFocused && this . props . onBlur != null ) this . props . onBlur ( e )
3728 }
3829
3930 this . killedBuffer = ''
4031 this . execHandler = ( e ) => {
41- console . log ( e . command . name )
32+ console . info ( 'ACE COMMAND >> %s' , e . command . name )
4233 switch ( e . command . name ) {
4334 case 'gotolinestart' :
4435 e . preventDefault ( )
@@ -84,7 +75,7 @@ export default class CodeEditor extends React.Component {
8475 this . afterExecHandler = ( e ) => {
8576 switch ( e . command . name ) {
8677 case 'find' :
87- Array . prototype . forEach . call ( ReactDOM . findDOMNode ( this ) . querySelectorAll ( '.ace_search_field, .ace_searchbtn, .ace_replacebtn, .ace_searchbtn_close' ) , el => {
78+ Array . prototype . forEach . call ( ReactDOM . findDOMNode ( this ) . querySelectorAll ( '.ace_search_field, .ace_searchbtn, .ace_replacebtn, .ace_searchbtn_close' ) , ( el ) => {
8879 el . removeEventListener ( 'blur' , this . blurHandler )
8980 el . addEventListener ( 'blur' , this . blurHandler )
9081 } )
@@ -93,11 +84,6 @@ export default class CodeEditor extends React.Component {
9384 }
9485
9586 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' ]
10187 }
10288
10389 this . silentChange = false
@@ -110,15 +96,16 @@ export default class CodeEditor extends React.Component {
11096 }
11197
11298 componentDidMount ( ) {
113- let { article } = this . props
114- var el = ReactDOM . findDOMNode ( this )
115- var editor = this . editor = ace . edit ( el )
99+ let { mode, value, theme, fontSize } = this . props
100+ this . value = value
101+ let el = ReactDOM . findDOMNode ( this )
102+ let editor = this . editor = ace . edit ( el )
116103 editor . $blockScrolling = Infinity
117104 editor . renderer . setShowGutter ( true )
118- editor . setTheme ( 'ace/theme/' + this . state . themeSyntax )
105+ editor . setTheme ( 'ace/theme/' + theme )
119106 editor . moveCursorTo ( 0 , 0 )
120107 editor . setReadOnly ( ! ! this . props . readOnly )
121- editor . setFontSize ( this . state . fontSize )
108+ editor . setFontSize ( fontSize )
122109
123110 editor . on ( 'blur' , this . blurHandler )
124111
@@ -132,92 +119,71 @@ export default class CodeEditor extends React.Component {
132119 readOnly : true
133120 } )
134121 editor . commands . addCommand ( {
135- name : 'Emacs cursor up ' ,
122+ name : 'Emacs kill buffer ' ,
136123 bindKey : { mac : 'Ctrl-Y' } ,
137124 exec : function ( editor ) {
138125 editor . insert ( this . killedBuffer )
139126 } . bind ( this ) ,
140127 readOnly : true
141128 } )
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- } )
154129
155130 editor . commands . on ( 'exec' , this . execHandler )
156131 editor . commands . on ( 'afterExec' , this . afterExecHandler )
157132
158133 var session = editor . getSession ( )
159- let mode = _ . findWhere ( modes , { name : article . mode } )
134+ mode = _ . find ( modes , { name : mode } )
160135 let syntaxMode = mode != null
161136 ? mode . mode
162137 : 'text'
163138 session . setMode ( 'ace/mode/' + syntaxMode )
164139
165- session . setUseSoftTabs ( this . state . indentType === 'space' )
166- session . setTabSize ( ! isNaN ( this . state . indentSize ) ? parseInt ( this . state . indentSize , 10 ) : 4 )
167- session . setOption ( 'useWorker' , false )
140+ session . setUseSoftTabs ( this . props . indentType === 'space' )
141+ session . setTabSize ( this . props . indentSize )
142+ session . setOption ( 'useWorker' , true )
168143 session . setUseWrapMode ( true )
169- session . setValue ( this . props . article . content )
144+ session . setValue ( _ . isString ( value ) ? value : '' )
170145
171146 session . on ( 'change' , this . changeHandler )
172-
173- ipc . on ( 'config-apply' , this . configApplyHandler )
174147 }
175148
176149 componentWillUnmount ( ) {
177- ipc . removeListener ( 'config-apply' , this . configApplyHandler )
178150 this . editor . getSession ( ) . removeListener ( 'change' , this . changeHandler )
179151 this . editor . removeListener ( 'blur' , this . blurHandler )
180152 this . editor . commands . removeListener ( 'exec' , this . execHandler )
181153 this . editor . commands . removeListener ( 'afterExec' , this . afterExecHandler )
182154 }
183155
184156 componentDidUpdate ( prevProps , prevState ) {
185- 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 } )
157+ let { value } = this . props
158+ this . value = value
159+ let editor = this . editor
160+ let session = this . editor . getSession ( )
161+
162+ if ( prevProps . mode !== this . props . mode ) {
163+ let mode = _ . find ( modes , { name : this . props . mode } )
194164 let syntaxMode = mode != null
195165 ? mode . mode
196166 : 'text'
197167 session . setMode ( 'ace/mode/' + syntaxMode )
198168 }
169+ if ( prevProps . theme !== this . props . theme ) {
170+ editor . setTheme ( 'ace/theme/' + this . props . theme )
171+ }
172+ if ( prevProps . fontSize !== this . props . fontSize ) {
173+ editor . setFontSize ( this . props . fontSize )
174+ }
175+ if ( prevProps . indentSize !== this . props . indentSize ) {
176+ session . setTabSize ( this . props . indentSize )
177+ }
178+ if ( prevProps . indentType !== this . props . indentType ) {
179+ session . setUseSoftTabs ( this . props . indentType === 'space' )
180+ }
199181 }
200182
201- 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- } )
216- }
217183 handleChange ( e ) {
218184 if ( this . props . onChange ) {
219- var value = this . editor . getValue ( )
220- this . props . onChange ( value )
185+ this . value = this . editor . getValue ( )
186+ this . props . onChange ( e )
221187 }
222188 }
223189
@@ -237,33 +203,59 @@ export default class CodeEditor extends React.Component {
237203 this . editor . scrollToLine ( num , false , false )
238204 }
239205
206+ focus ( ) {
207+ this . editor . focus ( )
208+ }
209+
210+ blur ( ) {
211+ this . editor . blur ( )
212+ }
213+
214+ reload ( ) {
215+ let session = this . editor . getSession ( )
216+ session . removeListener ( 'change' , this . changeHandler )
217+ session . setValue ( this . props . value )
218+ session . getUndoManager ( ) . reset ( )
219+ session . on ( 'change' , this . changeHandler )
220+ }
221+
240222 render ( ) {
223+ let { className, fontFamily } = this . props
224+ fontFamily = _ . isString ( fontFamily ) && fontFamily . length > 0
225+ ? [ fontFamily ] . concat ( defaultEditorFontFamily )
226+ : defaultEditorFontFamily
241227 return (
242228 < div
243- className = { this . props . className == null ? 'CodeEditor' : 'CodeEditor ' + this . props . className }
229+ className = { className == null
230+ ? 'CodeEditor'
231+ : `CodeEditor ${ className } `
232+ }
233+ ref = 'root'
234+ tabIndex = '-1'
244235 style = { {
245- fontSize : this . state . fontSize ,
246- fontFamily : this . state . fontFamily . trim ( ) + ', monospace'
236+ fontFamily : fontFamily . join ( ', ' )
247237 } }
248238 />
249239 )
250240 }
251241}
252242
253243CodeEditor . propTypes = {
254- article : PropTypes . shape ( {
255- content : PropTypes . string ,
256- mode : PropTypes . string ,
257- key : PropTypes . string
258- } ) ,
244+ value : PropTypes . string ,
245+ mode : PropTypes . string ,
259246 className : PropTypes . string ,
260247 onBlur : PropTypes . func ,
261248 onChange : PropTypes . func ,
262249 readOnly : PropTypes . bool
263250}
264251
265252CodeEditor . defaultProps = {
266- readOnly : false
253+ readOnly : false ,
254+ theme : 'xcode' ,
255+ fontSize : 14 ,
256+ fontFamily : 'Monaco, Consolas' ,
257+ indentSize : 4 ,
258+ indentType : 'space'
267259}
268260
269261export default CodeEditor
0 commit comments