diff options
author | François Schmidts <francois.schmidts@gmail.com> | 2016-02-02 23:15:37 +0100 |
---|---|---|
committer | François Schmidts <francois.schmidts@gmail.com> | 2016-02-02 23:15:37 +0100 |
commit | 082bf39a7dd7296d4f51b6b124d185135dc00989 (patch) | |
tree | 6e12cf2b67b016aff38874c389b5bf8b5242749a /src/web/js/components/MiddlePanel.react.js | |
parent | fixing logging (diff) | |
parent | reload and fold all button (diff) | |
download | newspipe-082bf39a7dd7296d4f51b6b124d185135dc00989.tar.gz newspipe-082bf39a7dd7296d4f51b6b124d185135dc00989.tar.bz2 newspipe-082bf39a7dd7296d4f51b6b124d185135dc00989.zip |
Merge branch 'feature/categories'
close #22
close #23
Diffstat (limited to 'src/web/js/components/MiddlePanel.react.js')
-rw-r--r-- | src/web/js/components/MiddlePanel.react.js | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/src/web/js/components/MiddlePanel.react.js b/src/web/js/components/MiddlePanel.react.js new file mode 100644 index 00000000..e251447e --- /dev/null +++ b/src/web/js/components/MiddlePanel.react.js @@ -0,0 +1,261 @@ +var React = require('react'); + +var Row = require('react-bootstrap/lib/Row'); +var Button = require('react-bootstrap/lib/Button'); +var ButtonGroup = require('react-bootstrap/lib/ButtonGroup'); +var Glyphicon = require('react-bootstrap/lib/Glyphicon'); + +var MiddlePanelStore = require('../stores/MiddlePanelStore'); +var MiddlePanelActions = require('../actions/MiddlePanelActions'); +var RightPanelActions = require('../actions/RightPanelActions'); + +var JarrTime = require('./time.react'); + +var TableLine = React.createClass({ + propTypes: {article_id: React.PropTypes.number.isRequired, + feed_title: React.PropTypes.string.isRequired, + icon_url: React.PropTypes.string, + title: React.PropTypes.string.isRequired, + timestamp: React.PropTypes.number.isRequired, + date: React.PropTypes.string.isRequired, + read: React.PropTypes.bool.isRequired, + selected: React.PropTypes.bool.isRequired, + liked: React.PropTypes.bool.isRequired, + }, + getInitialState: function() { + return {read: this.props.read, liked: this.props.liked, + selected: false}; + }, + render: function() { + var liked = this.state.liked ? 'l' : ''; + var icon = null; + if(this.props.icon_url){ + icon = (<img width="16px" src={this.props.icon_url} />); + } else { + icon = <Glyphicon glyph="ban-circle" />; + } + var title = (<a href={'/article/redirect/' + this.props.article_id} + onClick={this.openRedirectLink}> + {icon} {this.props.feed_title} + </a>); + var read = (<Glyphicon glyph={this.state.read?"check":"unchecked"} + onClick={this.toogleRead} />); + var liked = (<Glyphicon glyph={this.state.liked?"star":"star-empty"} + onClick={this.toogleLike} />); + var clsses = "list-group-item"; + if(this.props.selected) { + clsses += " active"; + } + // FIXME https://github.com/yahoo/react-intl/issues/189 + // use FormattedRelative when fixed, will have to upgrade to ReactIntlv2 + return (<div className={clsses} onClick={this.loadArticle}> + <h5><strong>{title}</strong></h5> + <JarrTime text={this.props.date} + stamp={this.props.timestamp} /> + <div>{read} {liked} {this.props.title}</div> + </div> + ); + }, + openRedirectLink: function(evnt) { + if(!this.state.read) { + this.toogleRead(evnt); + } + }, + toogleRead: function(evnt) { + this.setState({read: !this.state.read}, function() { + MiddlePanelActions.changeRead(this.props.category_id, + this.props.feed_id, this.props.article_id, this.state.read); + }.bind(this)); + evnt.stopPropagation(); + }, + toogleLike: function(evnt) { + this.setState({liked: !this.state.liked}, function() { + MiddlePanelActions.changeLike(this.props.category_id, + this.props.feed_id, this.props.article_id, this.state.liked); + }.bind(this)); + evnt.stopPropagation(); + }, + loadArticle: function() { + this.setState({active: true, read: true}, function() { + RightPanelActions.loadArticle( + this.props.article_id, this.props.read); + }.bind(this)); + }, + stopPropagation: function(evnt) { + evnt.stopPropagation(); + }, +}); + +var MiddlePanelSearchRow = React.createClass({ + getInitialState: function() { + return {query: MiddlePanelStore._datas.query, + search_title: MiddlePanelStore._datas.search_title, + search_content: MiddlePanelStore._datas.search_content, + }; + }, + render: function() { + return (<Row> + <form onSubmit={this.launchSearch}> + <div className="input-group input-group-sm"> + <span className="input-group-addon"> + <span onClick={this.toogleSTitle}>Title</span> + <input id="search-title" type="checkbox" + onChange={this.toogleSTitle} + checked={this.state.search_title} + aria-label="Search title" /> + </span> + <span className="input-group-addon"> + <span onClick={this.toogleSContent}>Content</span> + <input id="search-content" type="checkbox" + onChange={this.toogleSContent} + checked={this.state.search_content} + aria-label="Search content" /> + </span> + <input type="text" className="form-control" + onChange={this.setQuery} + placeholder="Search text" /> + </div> + </form> + </Row> + ); + }, + setQuery: function(evnt) { + this.setState({query: evnt.target.value}); + }, + toogleSTitle: function() { + this.setState({search_title: !this.state.search_title}, + this.launchSearch); + }, + toogleSContent: function() { + this.setState({search_content: !this.state.search_content}, + this.launchSearch); + }, + launchSearch: function(evnt) { + if(this.state.query && (this.state.search_title + || this.state.search_content)) { + MiddlePanelActions.search({query: this.state.query, + title: this.state.search_title, + content: this.state.search_content}); + } + if(evnt) { + evnt.preventDefault(); + } + }, +}); + +var MiddlePanelFilter = React.createClass({ + getInitialState: function() { + return {filter: MiddlePanelStore._datas.filter, + display_search: MiddlePanelStore._datas.display_search}; + }, + render: function() { + var search_row = null; + if(this.state.display_search) { + search_row = <MiddlePanelSearchRow /> + } + return (<div> + <Row className="show-grid"> + <ButtonGroup> + <Button active={this.state.filter == "all"} + title="Display all articles" + onClick={this.setAllFilter} bsSize="small"> + <Glyphicon glyph="menu-hamburger" /> + </Button> + <Button active={this.state.filter == "unread"} + title="Display only unread article" + onClick={this.setUnreadFilter} + bsSize="small"> + <Glyphicon glyph="unchecked" /> + </Button> + <Button active={this.state.filter == "liked"} + title="Filter only liked articles" + onClick={this.setLikedFilter} + bsSize="small"> + <Glyphicon glyph="star" /> + </Button> + </ButtonGroup> + <ButtonGroup> + <Button onClick={this.toogleSearch} + title="Search through displayed articles" + bsSize="small"> + <Glyphicon glyph="search" /> + </Button> + </ButtonGroup> + <ButtonGroup> + <Button onClick={MiddlePanelActions.markAllAsRead} + title="Mark all displayed article as read" + bsSize="small"> + <Glyphicon glyph="trash" /> + </Button> + </ButtonGroup> + </Row> + {search_row} + </div> + ); + }, + setAllFilter: function() { + this.setState({filter: 'all'}, function() { + MiddlePanelActions.setFilter('all'); + }.bind(this)); + }, + setUnreadFilter: function() { + this.setState({filter: 'unread'}, function() { + MiddlePanelActions.setFilter('unread'); + }.bind(this)); + }, + setLikedFilter: function() { + this.setState({filter: 'liked'}, function() { + MiddlePanelActions.setFilter('liked'); + }.bind(this)); + }, + toogleSearch: function() { + this.setState({display_search: !this.state.display_search}, + function() { + if(!this.state.display_search) { + MiddlePanelActions.search_off(); + } + }.bind(this) + ); + }, +}); + +var MiddlePanel = React.createClass({ + getInitialState: function() { + return {filter: MiddlePanelStore._datas.filter, articles: []}; + }, + render: function() { + return (<Row className="show-grid"> + <div className="list-group"> + {this.state.articles.map(function(article){ + return (<TableLine key={"a" + article.article_id} + title={article.title} + icon_url={article.icon_url} + read={article.read} + liked={article.liked} + timestamp={article.timestamp} + date={article.date} + selected={article.selected} + article_id={article.article_id} + feed_id={article.feed_id} + locales={['en']} + category_id={article.category_id} + feed_title={article.feed_title} />);})} + </div> + </Row> + ); + }, + componentDidMount: function() { + MiddlePanelActions.reload(); + MiddlePanelStore.addChangeListener(this._onChange); + }, + componentWillUnmount: function() { + MiddlePanelStore.removeChangeListener(this._onChange); + }, + _onChange: function() { + this.setState({filter: MiddlePanelStore._datas.filter, + articles: MiddlePanelStore.getArticles()}); + }, +}); + +module.exports = {MiddlePanel: MiddlePanel, + MiddlePanelFilter: MiddlePanelFilter}; |