@@ -3,121 +3,120 @@ import { connect } from 'react-redux'
3
3
import AceEditor from 'react-ace'
4
4
import { WithContext as Tags } from 'react-tag-input'
5
5
6
- import brace from 'brace'
7
- import 'brace/ext/modelist'
8
6
import 'brace/theme/textmate'
9
7
10
- import Joi from 'joi'
11
-
12
8
import Notification from './common/Notification'
13
9
import ListBoxWithSearch from './ListBoxWithSearch'
14
- import * as actions from '../actions'
10
+ import { fetchSyntaxes , postSnippet } from '../actions'
11
+
12
+ import { validateSnippet } from '../entries/snippetValidation'
13
+ import { getCurrentModeName , getModesByName } from '../misc/modes'
14
+ import { onEditorLoad } from '../misc/editor'
15
+ import { recalcLangHeaderHeight } from '../misc/dom'
16
+
17
+ import { delimeterKeys } from '../entries/keyboardKeys'
18
+ import { defaultOptions } from '../entries/aceEditorOptions'
15
19
16
20
import '../styles/NewSnippet.styl'
17
21
18
22
class NewSnippet extends React . Component {
19
23
constructor ( props ) {
20
24
super ( props )
21
- this . schema = Joi . object ( ) . keys ( {
22
- content : Joi . string ( ) . required ( ) ,
23
- } )
24
- this . keys = {
25
- TAB : 9 ,
26
- SPACE : 32 ,
27
- ENTER : 13 ,
28
- COMMA : 188 ,
29
- }
25
+
30
26
this . state = {
31
27
content : '' ,
32
28
title : '' ,
33
29
tags : [ ] ,
34
30
syntax : '' ,
35
31
validationError : null ,
36
32
}
37
- this . recalcLangHeaderHeight = ( ) => {
38
- const newSnippetHeaderHeight = document . getElementsByClassName ( 'new-snippet-code-header' ) [ 0 ] . offsetHeight
39
-
40
- document . getElementsByClassName ( 'new-snippet-lang-header' ) [ 0 ]
41
- . setAttribute ( 'style' , `height:${ newSnippetHeaderHeight } px` )
42
- }
43
- this . onEditorLoad = ( editor ) => {
44
- // we want to disable built-in find in favor of browser's one
45
- editor . commands . removeCommand ( 'find' )
46
- }
47
- this . postSnippet = this . postSnippet . bind ( this )
48
- this . onSyntaxClick = this . onSyntaxClick . bind ( this )
49
- this . onInputChange = this . onInputChange . bind ( this )
50
- this . onTagAdded = this . onTagAdded . bind ( this )
51
- this . onTagRemoved = this . onTagRemoved . bind ( this )
52
- this . onTagBlur = this . onTagBlur . bind ( this )
53
33
}
54
34
55
35
componentDidMount ( ) {
56
36
const { dispatch } = this . props
57
- dispatch ( actions . fetchSyntaxes )
37
+ dispatch ( fetchSyntaxes )
58
38
}
59
39
60
- onTagAdded ( tag ) {
40
+ onTagAdded = tag => {
61
41
if ( tag && tag . text ) {
62
42
this . setState ( { tags : [ ...this . state . tags , tag ] } , ( ) => {
63
- this . recalcLangHeaderHeight ( )
43
+ recalcLangHeaderHeight ( )
64
44
} )
65
45
}
66
46
}
67
47
68
- onTagRemoved ( i ) {
48
+ onTagRemoved = i => {
69
49
const { tags } = this . state
70
50
71
51
this . setState ( { tags : tags . filter ( ( tag , index ) => index !== i ) } , ( ) => {
72
- this . recalcLangHeaderHeight ( )
52
+ recalcLangHeaderHeight ( )
73
53
} )
74
54
}
75
55
76
- onTagBlur ( tag ) {
56
+ onTagBlur = tag => {
77
57
this . onTagAdded ( { id : tag , text : tag } )
78
58
}
79
59
80
- onSyntaxClick ( syntax ) {
60
+ onSyntaxClick = syntax => {
81
61
this . setState ( { syntax } )
82
62
}
83
63
84
- onInputChange ( e ) {
64
+ onInputChange = e => {
85
65
const { name, value } = e . target
86
66
87
67
this . setState ( { [ name ] : value } )
88
68
}
89
69
90
- postSnippet ( e ) {
70
+ validate = ( ) => {
71
+ const { content } = this . state
72
+
73
+ return validateSnippet ( { content : content . trim ( ) } )
74
+ }
75
+
76
+ post = e => {
91
77
e . preventDefault ( )
92
78
const { dispatch, history } = this . props
93
- const { error } = Joi . validate ( { content : this . state . content . trim ( ) } , this . schema )
79
+ const { error } = this . validate ( )
94
80
95
81
this . setState ( { validationError : error } )
96
82
97
- if ( error === null ) {
83
+ if ( ! error ) {
98
84
const {
99
85
content, title, tags, syntax,
100
86
} = this . state
101
87
102
- dispatch ( actions . postSnippet ( {
88
+ dispatch ( postSnippet ( {
103
89
content, title, tags : tags . map ( tag => tag . text ) , syntax,
104
90
} , json => history . push ( `/${ json . id } ` ) ) )
105
91
}
106
92
}
107
93
108
- render ( ) {
109
- const { modesByName } = brace . acequire ( 'ace/ext/modelist' )
110
- const mode = modesByName [ this . state . syntax ] || modesByName . text
111
- const syntaxes = this . props . syntaxes . map ( item => ( {
94
+ getSyntaxes = ( ) => {
95
+ const { modesByName } = getModesByName ( )
96
+
97
+ return this . props . syntaxes . map ( item => ( {
112
98
name : modesByName [ item ] . caption ,
113
99
value : item ,
114
100
} ) )
101
+ }
102
+
103
+ renderValidationError = ( ) => {
104
+ const { validationError } = this . state
105
+
106
+ return validationError && < Notification
107
+ message = "Content is required :("
108
+ show = { ! ! validationError }
109
+ />
110
+ }
111
+
112
+ render ( ) {
113
+ const { syntax, content, title, tags } = this . state
115
114
116
115
return (
117
116
< form
118
117
className = "new-snippet"
119
118
key = "New Snippet"
120
- onSubmit = { this . postSnippet }
119
+ onSubmit = { this . post }
121
120
role = "presentation"
122
121
>
123
122
< div className = "new-snippet-code-wrapper" >
@@ -127,52 +126,41 @@ class NewSnippet extends React.Component {
127
126
placeholder = "Title"
128
127
name = "title"
129
128
type = "text"
130
- value = { this . state . title }
129
+ value = { title }
131
130
onChange = { this . onInputChange }
132
131
/>
133
132
< Tags
134
133
placeholder = "Tags"
135
- tags = { this . state . tags }
134
+ tags = { tags }
136
135
handleDelete = { this . onTagRemoved }
137
136
handleAddition = { this . onTagAdded }
138
137
handleInputBlur = { this . onTagBlur }
139
- delimiters = {
140
- [ this . keys . TAB , this . keys . SPACE , this . keys . ENTER , this . keys . COMMA ]
141
- }
138
+ delimiters = { delimeterKeys }
142
139
/>
143
140
</ div >
144
141
< div className = "new-snippet-code" >
145
142
< AceEditor
146
- mode = { mode . name }
143
+ mode = { getCurrentModeName ( syntax ) }
147
144
width = "100%"
148
145
height = "100%"
149
146
focus
150
147
theme = "textmate"
151
- onLoad = { this . onEditorLoad }
152
- setOptions = { {
153
- showFoldWidgets : false ,
154
- useWorker : false ,
155
- fontSize : '13px' ,
156
- maxLines : Infinity ,
157
- showPrintMargin : false ,
158
- } }
148
+ onLoad = { onEditorLoad }
149
+ setOptions = { defaultOptions }
159
150
editorProps = { { $blockScrolling : Infinity } }
160
- value = { this . state . content }
151
+ value = { content }
161
152
onChange = { ( content ) => { this . setState ( { content } ) } }
162
153
/>
163
154
164
155
< div className = "new-snippet-code-bottom-bar" >
165
- < Notification
166
- message = "Content is required :("
167
- show = { ! ! this . state . validationError }
168
- />
156
+ { this . renderValidationError ( ) }
169
157
< input type = "submit" value = "POST SNIPPET" />
170
158
</ div >
171
159
</ div >
172
160
</ div >
173
161
< div className = "new-snippet-lang-wrapper" >
174
162
< ListBoxWithSearch
175
- items = { syntaxes }
163
+ items = { this . getSyntaxes ( ) }
176
164
onClick = { this . onSyntaxClick }
177
165
/>
178
166
</ div >
0 commit comments