Skip to content

Commit 3e2eb6b

Browse files
committed
shakapacker and jquery and css working, I think
1 parent e7237de commit 3e2eb6b

11 files changed

+1124
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { React } from "react";
2+
3+
const TestComponent = () => {
4+
return (<div>hi</div>)
5+
}
6+
7+
export default TestComponent;
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
class @Article extends React.Component
2+
@propTypes =
3+
article: React.PropTypes.object
4+
authors: React.PropTypes.array
5+
articles: React.PropTypes.array
6+
rankSelect: React.PropTypes.bool
7+
from_issues_page: React.PropTypes.integer
8+
9+
constructor: (props) ->
10+
super(props)
11+
@state = {}
12+
@styles =
13+
statusCol:
14+
width: '120px'
15+
textAlign: 'center'
16+
padding: '8px 0'
17+
mainCol:
18+
padding: '8px 6px'
19+
actionsCol:
20+
width: '120px'
21+
textAlign: 'center'
22+
paddingBottom: '2px'
23+
label:
24+
marginRight: '4px'
25+
slug:
26+
fontWeight: 'bold'
27+
marginLeft: '3px'
28+
marginRight: '4px'
29+
headline:
30+
marginLeft: '4px'
31+
publishTime:
32+
marginRight: '4px'
33+
authors:
34+
marginLeft: '4px'
35+
secondaryLine:
36+
color: '#888'
37+
rankSelect:
38+
width: '60px'
39+
40+
################################################################################
41+
# Handlers
42+
################################################################################
43+
44+
handlePublish: (cb) =>
45+
@props.onAction('post', Routes.publish_article_draft_path(@props.article, @props.article.pending_draft.id), {}, cb)
46+
47+
handleUnpublish: (cb) =>
48+
@props.onAction('post', Routes.unpublish_article_path(@props.article), {}, cb)
49+
50+
handleDelete: (cb) =>
51+
@props.onAction('delete', Routes.article_path(@props.article), {}, cb)
52+
53+
handleRankSelect: (rank, cb) =>
54+
@props.onAction('patch', Routes.update_rank_article_path(@props.article), {article: {rank: rank}}, cb)
55+
cb()
56+
57+
################################################################################
58+
# Renderers
59+
################################################################################
60+
61+
renderButton: (type, text, handler, cond = true, confirm = null) ->
62+
return null if !cond
63+
`<Button type={type} text={text} onClick={handler} confirm={confirm}/>`
64+
65+
renderLink: (type, text, href, cond = true, confirm = null) ->
66+
return null if !cond
67+
gotoURL = (cb) ->
68+
window.location.href = href
69+
cb()
70+
`<Button type={type} text={text} onClick={gotoURL} confirm={confirm}/>`
71+
72+
renderWebStatus: ->
73+
if @props.article.has_web_published_draft
74+
if @props.article.has_pending_draft
75+
`<StatusLabel type="info">Web: Has Update</StatusLabel>`
76+
else
77+
`<StatusLabel type="success">Web: Published</StatusLabel>`
78+
else if @props.article.has_web_ready_draft
79+
`<StatusLabel type="info">Web: Ready</StatusLabel>`
80+
else
81+
`<StatusLabel type="danger">Web: Draft</StatusLabel>`
82+
83+
renderPrintStatus: ->
84+
if @props.article.has_print_ready_draft
85+
`<StatusLabel type="success">Print: Ready</StatusLabel>`
86+
else
87+
`<StatusLabel type="danger">Print: Draft</StatusLabel>`
88+
89+
renderActions: ->
90+
`<td style={this.styles.actionsCol}>
91+
{this.renderButton('success', 'Publish', this.handlePublish, (this.props.article.has_pending_draft &&
92+
!this.props.article.has_web_published_draft &&
93+
this.props.article.can_publish))}
94+
{this.renderButton('success', 'Publish Update', this.handlePublish, (this.props.article.has_pending_draft &&
95+
this.props.article.has_web_published_draft &&
96+
this.props.article.can_publish))}
97+
{this.renderButton('danger', 'Delete', this.handleDelete, (!this.props.article.has_web_published_draft &&
98+
this.props.article.can_destroy),
99+
'Are you sure that you want to delete this article? This will delete all drafts. ')}
100+
{this.renderButton('danger', 'Unpublish', this.handleUnpublish, (this.props.article.has_web_published_draft &&
101+
this.props.article.can_unpublish),
102+
'Are you sure that you want to unpublish this article? The publish time would change if you ' +
103+
'later publish it again. ')}
104+
{this.renderLink('default', 'View Drafts', Routes.article_drafts_path(this.props.article, {format: 'html'}))}
105+
</td>`
106+
107+
render: ->
108+
`<tr>
109+
<td style={this.styles.statusCol}>
110+
{this.renderWebStatus()}
111+
{this.renderPrintStatus()}
112+
{ this.props.rankSelect && this.props.article.can_update_rank &&
113+
<AutoSelect style={this.styles.rankSelect}
114+
titles={[99].concat(range(1, 20))}
115+
ids={[99].concat(range(1, 20))}
116+
initial={this.props.article.rank}
117+
onChange={this.handleRankSelect}/>
118+
}
119+
</td>
120+
<td style={this.styles.mainCol}>
121+
<p>
122+
<span style={this.styles.label} className="label label-default">{this.props.article.issue.short_name}</span>
123+
<span style={this.styles.label} className="label label-default">{this.props.article.section.name.toUpperCase()}</span>
124+
<span style={this.styles.label} className="label label-default">{this.props.article.newest_draft.primary_tag.toUpperCase()}</span>
125+
{
126+
(this.props.from_issues_page)
127+
? <a style={this.styles.slug} href={Routes.article_drafts_path(this.props.article, {format: 'html'})+"?issue="+String(this.props.from_issues_page)}>{this.props.article.slug}</a>
128+
: <a style={this.styles.slug} href={Routes.article_drafts_path(this.props.article, {format: 'html'})}>{this.props.article.slug}</a>
129+
}
130+
131+
<span style={this.styles.headline}>{this.props.article.newest_draft.headline}</span>
132+
</p>
133+
<p style={this.styles.secondaryLine}>
134+
{
135+
(this.props.article.oldest_web_published_draft != null &&
136+
this.props.article.oldest_web_published_draft != undefined)
137+
? <span style={this.styles.publishTime}>Published online {$.timeago(Date.parse(this.props.article.oldest_web_published_draft.published_at))}</span>
138+
: <span style={this.styles.publishTime}>Not published online yet</span>
139+
}
140+
141+
<span style={this.styles.authors}>Authored by {this.props.article.newest_draft.authors_string}</span>
142+
</p>
143+
</td>
144+
{this.renderActions()}
145+
</tr>`
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
class @ArticleList extends React.Component
2+
@propTypes =
3+
articles: React.PropTypes.array
4+
fetch: React.PropTypes.string
5+
hideSearch: React.PropTypes.bool
6+
rankSelect: React.PropTypes.bool
7+
from_issues_page: React.PropTypes.integer
8+
9+
appendArticles: (articles) =>
10+
@setState
11+
page: @state.page + 1
12+
articles: @state.articles.concat(articles)
13+
14+
loadNextPage: =>
15+
@setState loading: true
16+
axios.get(@nextPage).then (resp) =>
17+
if resp.data.error
18+
alert(resp.data.error)
19+
else
20+
@nextPage = resp.data.nextPage
21+
@setState
22+
loading: false
23+
@appendArticles(resp.data.articles)
24+
.catch (err) =>
25+
logError(err)
26+
alert("Unknown error. Please refresh the page. ")
27+
28+
componentDidMount: ->
29+
MessageBus.subscribe '/updates', (data) =>
30+
console.log('MessageBus update: ', data)
31+
if data.model == 'article'
32+
axios.get(Routes.article_path(data.id)).then (resp) =>
33+
if resp.data.error
34+
alert(resp.data.error)
35+
else
36+
@replaceArticle(resp.data.article)
37+
.catch (err) =>
38+
logError(err)
39+
alert("Unknown error. Please refresh the page. ")
40+
41+
if @props.fetch?
42+
@nextPage = @props.fetch
43+
@loadNextPage()
44+
45+
$(@refs.infiniteScrollTrigger).appear()
46+
$(@refs.infiniteScrollTrigger).on 'appear', =>
47+
return if @state.loading
48+
return unless @nextPage?
49+
@loadNextPage()
50+
51+
constructor: (props) ->
52+
super(props)
53+
@state =
54+
articles: @props.articles
55+
@styles =
56+
infiniteScrollTriggerRow:
57+
textAlign: 'center'
58+
fontSize: '40px'
59+
60+
replaceArticle: (article) ->
61+
articles = @state.articles.slice()
62+
index = _.findIndex(articles, {id: article.id})
63+
if index < 0
64+
return
65+
if article.destroyed
66+
articles.splice(index, 1)
67+
else
68+
articles[index] = article
69+
@setState(articles: articles)
70+
71+
handleAction: (article, method, path, params, cb) ->
72+
axios
73+
method: method,
74+
url: path,
75+
data: params
76+
.then (resp) =>
77+
cb() if cb?
78+
if resp.data.error
79+
alert(resp.data.error)
80+
else
81+
@replaceArticle(resp.data.article)
82+
.catch (err) =>
83+
logError(err)
84+
alert("Cannot complete the action. Please refresh the page and try again. ")
85+
86+
handleSearchKeyDown: (e) =>
87+
if e.keyCode == 13
88+
@setState articles: []
89+
@nextPage = Routes.articles_path(q: e.target.value)
90+
@loadNextPage()
91+
92+
render: ->
93+
`<table className="table">
94+
<thead>
95+
<tr>
96+
{ this.props.hideSearch ||
97+
<td colSpan="3">
98+
<input className="form-control" onKeyDown={this.handleSearchKeyDown} placeholder='Search for articles by volume (e.g. "V134 N7") or by text. Press ENTER to search. '/>
99+
</td>
100+
}
101+
</tr>
102+
</thead>
103+
<tbody>
104+
{
105+
this.state.articles.map(function(article, i) {
106+
return <Article rankSelect={this.props.rankSelect} from_issues_page={this.props.from_issues_page} article={article} authors={this.props.authors} articles={this.props.articles} key={article.id} onAction={this.handleAction.bind(this, article)}></Article>;
107+
}, this)
108+
}
109+
<tr style={this.styles.infiniteScrollTriggerRow} data-appear-top-offset="1000" ref="infiniteScrollTrigger">
110+
<td colSpan="3">{this.state.loading ? <i className="fa fa-spin fa-circle-o-notch"></i> : null }</td>
111+
</tr>
112+
</tbody>
113+
</table>`
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
class @AutoSelect extends React.Component
2+
@propTypes =
3+
onChange: React.PropTypes.func
4+
confirm: React.PropTypes.string
5+
titles: React.PropTypes.array
6+
ids: React.PropTypes.array
7+
prompt: React.PropTypes.string
8+
initial: React.PropTypes.number
9+
10+
# TODO: Investigate, is this the right way for things?
11+
componentWillReceiveProps: (nextProps) ->
12+
@setState value: nextProps.initial || -1
13+
14+
constructor: (props) ->
15+
@state =
16+
busy: false
17+
value: props.initial || -1
18+
19+
handleChange: (e) =>
20+
@setState value: e.target.value
21+
return if e.target.value < 0
22+
23+
if !@props.confirm? || confirm(@props.confirm)
24+
@setState(busy: true)
25+
@props.onChange e.target.value, =>
26+
@setState(busy: false)
27+
28+
render: ->
29+
styles = this.props.style || {}
30+
styles.WebkitAppearance = 'none'
31+
styles.backgroundImage = 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAJCAYAAAA/33wPAAAAvklEQVQoFY2QMQqEMBBFv7ERa/EMXkGw11K8QbDXzuN4BHv7QO6ifUgj7v4UAdlVM8Uwf+b9YZJISnlqrfEUZVlinucnBGKaJgghbiHOyLyFKIoCbdvecpyReYvo/Ma2bajrGtbaC58kCdZ1RZ7nl/4/4d5EsO/7nzl7IUtodBexMMagaRrs+06JLMvcNWmaOv2W/C/TMAyD58dxROgSmvxFFMdxoOs6lliWBXEcuzokXRbRoJRyvqqqQvye+QDMDz1D6yuj9wAAAABJRU5ErkJggg==)'
32+
styles.backgroundPosition = 'right center';
33+
styles.backgroundRepeat = 'no-repeat';
34+
styles.padding = '2px 10px';
35+
styles.borderRadius = '0';
36+
styles.border = '1px solid #DDD'
37+
38+
`<select value={this.state.value} style={styles} onChange={this.handleChange} disabled={this.state.busy}>
39+
{
40+
this.props.prompt != null && this.props.prompt != undefined &&
41+
<option key="-1" value="-1">{this.props.prompt}</option>
42+
}
43+
{
44+
this.props.titles.map(function(title, i) {
45+
return <option key={this.props.ids[i]} value={this.props.ids[i]}>{title}</option>
46+
}, this)
47+
}
48+
</select>`
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
class @Button extends React.Component
2+
@propTypes =
3+
text: React.PropTypes.string
4+
type: React.PropTypes.oneOf(['danger','info','warning','success','default'])
5+
onClick: React.PropTypes.func
6+
confirm: React.PropTypes.string
7+
highlighed: React.PropTypes.bool
8+
9+
constructor: (props) ->
10+
@state =
11+
busy: false
12+
13+
handleClick: =>
14+
if @state.busy
15+
logError("Button clicked while supposedly disabled. ")
16+
return
17+
18+
if (!@props.confirm?) || confirm(@props.confirm)
19+
@setState(busy: true)
20+
@props.onClick =>
21+
@setState(busy: false)
22+
23+
render: ->
24+
styles =
25+
display: 'block'
26+
marginBottom: '6px'
27+
width: '110px'
28+
29+
activeClass = if @props.highlighted then " active" else ""
30+
31+
`<button style={_.extend(styles, this.props.style)}
32+
className={"btn btn-sm btn-" + this.props.type + activeClass}
33+
disabled={this.state.busy}
34+
onClick={this.handleClick}>{this.state.busy ? <i className="fa fa-spin fa-circle-o-notch"></i> : this.props.text}</button>`

0 commit comments

Comments
 (0)