Skip to content

Commit b90208e

Browse files
author
Olha Kurkaiedova
authored
Merge pull request #122 from xsnippet/react-update
[Components] Moved non-component methods to entries files
2 parents aaea1e0 + 483c0db commit b90208e

23 files changed

+297
-246
lines changed

.babelrc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
{
22
"presets": ["react", "env"],
33
"plugins": [
4-
"syntax-dynamic-import"
4+
"syntax-dynamic-import",
5+
"transform-class-properties",
6+
"transform-object-rest-spread"
57
]
68
}

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
"babel-eslint": "^8.2.3",
5151
"babel-loader": "^7.1.4",
5252
"babel-plugin-syntax-dynamic-import": "^6.18.0",
53+
"babel-plugin-transform-class-properties": "^6.24.1",
54+
"babel-plugin-transform-object-rest-spread": "^6.26.0",
5355
"babel-preset-env": "^1.7.0",
5456
"babel-preset-react": "^6.24.1",
5557
"clean-webpack-plugin": "^0.1.17",

src/actions/index.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import parseLinkHeader from 'parse-link-header'
2-
import * as misc from '../misc'
2+
import { getApiUri } from '../misc/url'
33

44
export const setRecentSnippets = snippets => ({
55
type: 'SET_RECENT_SNIPPETS',
@@ -15,7 +15,7 @@ export const fetchRecentSnippets = marker => (dispatch) => {
1515
let qs = ''
1616
if (marker) { qs = `&marker=${marker}` }
1717

18-
return fetch(misc.getApiUri(`snippets?limit=20${qs}`))
18+
return fetch(getApiUri(`snippets?limit=20${qs}`))
1919
.then((response) => {
2020
const links = parseLinkHeader(response.headers.get('Link'))
2121

@@ -31,7 +31,7 @@ export const setSnippet = snippet => ({
3131
})
3232

3333
export const fetchSnippet = id => dispatch => (
34-
fetch(misc.getApiUri(`snippets/${id}`))
34+
fetch(getApiUri(`snippets/${id}`))
3535
.then(response => response.json())
3636
.then(json => dispatch(setSnippet(json)))
3737
)
@@ -42,13 +42,13 @@ export const setSyntaxes = syntaxes => ({
4242
})
4343

4444
export const fetchSyntaxes = dispatch => (
45-
fetch(misc.getApiUri('syntaxes'))
45+
fetch(getApiUri('syntaxes'))
4646
.then(response => response.json())
4747
.then(json => dispatch(setSyntaxes(json)))
4848
)
4949

5050
export const postSnippet = (snippet, onSuccess) => dispatch => (
51-
fetch(misc.getApiUri('snippets'), {
51+
fetch(getApiUri('snippets'), {
5252
method: 'POST',
5353
headers: {
5454
'Accept': 'application/json',

src/components/ListBox.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ class ListBox extends React.Component {
77
this.state = {
88
selected: null,
99
}
10-
this.onClick = this.onClick.bind(this)
1110
}
1211

1312
componentWillReceiveProps(nextProps) {
@@ -29,7 +28,7 @@ class ListBox extends React.Component {
2928
}
3029
}
3130

32-
onClick(e) {
31+
onClick = e => {
3332
const { value } = e.target.dataset
3433

3534
this.setState({ selected: value })

src/components/ListBoxWithSearch.jsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
import React from 'react'
22

33
import ListBox from './ListBox'
4-
import * as misc from '../misc'
4+
import { regExpEscape } from '../misc/reqExp'
55

66
class ListBoxWithSearch extends React.PureComponent {
77
constructor(props) {
88
super(props)
99
this.state = {
1010
searchQuery: null,
1111
}
12-
this.onSearch = this.onSearch.bind(this)
1312
}
1413

15-
onSearch(e) {
14+
onSearch = e => {
1615
this.setState({ searchQuery: e.target.value.trim() })
1716
}
1817

@@ -31,7 +30,7 @@ class ListBoxWithSearch extends React.PureComponent {
3130
// Filter out only those items that match search query. If no query is
3231
// set, do nothing and use the entire set.
3332
if (searchQuery) {
34-
const regExp = new RegExp(misc.regExpEscape(searchQuery), 'gi')
33+
const regExp = new RegExp(regExpEscape(searchQuery), 'gi')
3534
items = items.filter(item => item.name.match(regExp))
3635
}
3736

src/components/NewSnippet.jsx

Lines changed: 55 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3,121 +3,120 @@ import { connect } from 'react-redux'
33
import AceEditor from 'react-ace'
44
import { WithContext as Tags } from 'react-tag-input'
55

6-
import brace from 'brace'
7-
import 'brace/ext/modelist'
86
import 'brace/theme/textmate'
97

10-
import Joi from 'joi'
11-
128
import Notification from './common/Notification'
139
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'
1519

1620
import '../styles/NewSnippet.styl'
1721

1822
class NewSnippet extends React.Component {
1923
constructor(props) {
2024
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+
3026
this.state = {
3127
content: '',
3228
title: '',
3329
tags: [],
3430
syntax: '',
3531
validationError: null,
3632
}
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)
5333
}
5434

5535
componentDidMount() {
5636
const { dispatch } = this.props
57-
dispatch(actions.fetchSyntaxes)
37+
dispatch(fetchSyntaxes)
5838
}
5939

60-
onTagAdded(tag) {
40+
onTagAdded = tag => {
6141
if (tag && tag.text) {
6242
this.setState({ tags: [...this.state.tags, tag] }, () => {
63-
this.recalcLangHeaderHeight()
43+
recalcLangHeaderHeight()
6444
})
6545
}
6646
}
6747

68-
onTagRemoved(i) {
48+
onTagRemoved = i => {
6949
const { tags } = this.state
7050

7151
this.setState({ tags: tags.filter((tag, index) => index !== i) }, () => {
72-
this.recalcLangHeaderHeight()
52+
recalcLangHeaderHeight()
7353
})
7454
}
7555

76-
onTagBlur(tag) {
56+
onTagBlur = tag => {
7757
this.onTagAdded({ id: tag, text: tag })
7858
}
7959

80-
onSyntaxClick(syntax) {
60+
onSyntaxClick = syntax => {
8161
this.setState({ syntax })
8262
}
8363

84-
onInputChange(e) {
64+
onInputChange = e => {
8565
const { name, value } = e.target
8666

8767
this.setState({ [name]: value })
8868
}
8969

90-
postSnippet(e) {
70+
validate = () => {
71+
const { content } = this.state
72+
73+
return validateSnippet({ content: content.trim() })
74+
}
75+
76+
post = e => {
9177
e.preventDefault()
9278
const { dispatch, history } = this.props
93-
const { error } = Joi.validate({ content: this.state.content.trim() }, this.schema)
79+
const { error } = this.validate()
9480

9581
this.setState({ validationError: error })
9682

97-
if (error === null) {
83+
if (!error) {
9884
const {
9985
content, title, tags, syntax,
10086
} = this.state
10187

102-
dispatch(actions.postSnippet({
88+
dispatch(postSnippet({
10389
content, title, tags: tags.map(tag => tag.text), syntax,
10490
}, json => history.push(`/${json.id}`)))
10591
}
10692
}
10793

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 => ({
11298
name: modesByName[item].caption,
11399
value: item,
114100
}))
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
115114

116115
return (
117116
<form
118117
className="new-snippet"
119118
key="New Snippet"
120-
onSubmit={this.postSnippet}
119+
onSubmit={this.post}
121120
role="presentation"
122121
>
123122
<div className="new-snippet-code-wrapper">
@@ -127,52 +126,41 @@ class NewSnippet extends React.Component {
127126
placeholder="Title"
128127
name="title"
129128
type="text"
130-
value={this.state.title}
129+
value={title}
131130
onChange={this.onInputChange}
132131
/>
133132
<Tags
134133
placeholder="Tags"
135-
tags={this.state.tags}
134+
tags={tags}
136135
handleDelete={this.onTagRemoved}
137136
handleAddition={this.onTagAdded}
138137
handleInputBlur={this.onTagBlur}
139-
delimiters={
140-
[this.keys.TAB, this.keys.SPACE, this.keys.ENTER, this.keys.COMMA]
141-
}
138+
delimiters={delimeterKeys}
142139
/>
143140
</div>
144141
<div className="new-snippet-code">
145142
<AceEditor
146-
mode={mode.name}
143+
mode={getCurrentModeName(syntax)}
147144
width="100%"
148145
height="100%"
149146
focus
150147
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}
159150
editorProps={{ $blockScrolling: Infinity }}
160-
value={this.state.content}
151+
value={content}
161152
onChange={(content) => { this.setState({ content }) }}
162153
/>
163154

164155
<div className="new-snippet-code-bottom-bar">
165-
<Notification
166-
message="Content is required :("
167-
show={!!this.state.validationError}
168-
/>
156+
{this.renderValidationError()}
169157
<input type="submit" value="POST SNIPPET" />
170158
</div>
171159
</div>
172160
</div>
173161
<div className="new-snippet-lang-wrapper">
174162
<ListBoxWithSearch
175-
items={syntaxes}
163+
items={this.getSyntaxes()}
176164
onClick={this.onSyntaxClick}
177165
/>
178166
</div>

src/components/RecentSnippetItem.jsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
import React from 'react'
22
import { Link } from 'react-router-dom'
3-
import brace from 'brace'
43

5-
import * as misc from '../misc'
6-
import conf from '../conf'
4+
import { getCurrentModeCaption } from '../misc/modes'
5+
import { downloadSnippet } from '../misc/download'
6+
import { getSnippetTitle, formatDate } from '../misc/snippet'
7+
import { getRawUrl } from '../misc/url'
78

89
const RecentSnippetItem = ({ snippet }) => {
9-
const { modesByName } = brace.acequire('ace/ext/modelist')
10-
const mode = modesByName[snippet.get('syntax')] || modesByName.text
11-
const syntax = mode.caption
12-
const snippetTitle = snippet.get('title') || `#${snippet.get('id')}, Untitled`
13-
const download = () => misc.downloadSnippet(snippet)
14-
const rawUrl = conf.RAW_SNIPPET_URI_FORMAT.replace('%s', snippet.get('id'))
10+
const syntax = getCurrentModeCaption(snippet.get('syntax'))
11+
const title = getSnippetTitle(snippet)
12+
const rawUrl = getRawUrl(snippet.get('id'))
13+
14+
const download = () => downloadSnippet(snippet)
1515

1616
return (
1717
<li className="recent-snippet-item">
1818
<div className="recent-snippet-meta">
1919
<div>
20-
<Link to={`${snippet.get('id')}`} className="recent-snippet-meta-title">{snippetTitle}</Link>
20+
<Link to={`${snippet.get('id')}`} className="recent-snippet-meta-title">{title}</Link>
2121
<div className="recent-snippet-meta-tags">
2222
{snippet.get('tags').map(item => <span className="recent-snippet-meta-tag" key={item}>{item}</span>)}
2323
</div>
2424
</div>
25-
<span className="recent-snippet-meta-info">{misc.formatDate(snippet.get('created_at'))}, by Guest</span>
25+
<span className="recent-snippet-meta-info">{formatDate(snippet.get('created_at'))}, by Guest</span>
2626
</div>
2727
<div className="recent-snippet-actions">
2828
<span className="recent-snippet-lang">{syntax}</span>

0 commit comments

Comments
 (0)