diff options
Diffstat (limited to 'src/web')
-rw-r--r-- | src/web/controllers/article.py | 6 | ||||
-rw-r--r-- | src/web/js/actions/RightPanelActions.js | 3 | ||||
-rw-r--r-- | src/web/js/components/MiddlePanel.react.js | 22 | ||||
-rw-r--r-- | src/web/js/stores/MenuStore.js | 7 | ||||
-rw-r--r-- | src/web/js/stores/MiddlePanelStore.js | 42 | ||||
-rw-r--r-- | src/web/static/css/one-page-app.css | 10 | ||||
-rw-r--r-- | src/web/views/views.py | 7 |
7 files changed, 71 insertions, 26 deletions
diff --git a/src/web/controllers/article.py b/src/web/controllers/article.py index 50e6757f..bc9ef36e 100644 --- a/src/web/controllers/article.py +++ b/src/web/controllers/article.py @@ -15,12 +15,6 @@ logger = logging.getLogger(__name__) class ArticleController(AbstractController): _db_cls = Article - def get(self, **filters): - article = super(ArticleController, self).get(**filters) - if not article.readed: - self.update({'id': article.id}, {'readed': True}) - return article - def challenge(self, ids): """Will return each id that wasn't found in the database.""" for id_ in ids: diff --git a/src/web/js/actions/RightPanelActions.js b/src/web/js/actions/RightPanelActions.js index 6a8d74bd..c60bffcf 100644 --- a/src/web/js/actions/RightPanelActions.js +++ b/src/web/js/actions/RightPanelActions.js @@ -3,12 +3,13 @@ var ActionTypes = require('../constants/JarrConstants'); var jquery = require('jquery'); var RightPanelActions = { - loadArticle: function(article_id) { + loadArticle: function(article_id, was_read_before) { jquery.getJSON('/getart/' + article_id, function(payload) { JarrDispatcher.dispatch({ type: ActionTypes.LOAD_ARTICLE, article: payload, + was_read_before: was_read_before, }); } ); diff --git a/src/web/js/components/MiddlePanel.react.js b/src/web/js/components/MiddlePanel.react.js index 90e11859..0bb0b51b 100644 --- a/src/web/js/components/MiddlePanel.react.js +++ b/src/web/js/components/MiddlePanel.react.js @@ -15,10 +15,12 @@ var TableLine = React.createClass({ title: React.PropTypes.string.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}; + return {read: this.props.read, liked: this.props.liked, + selected: false}; }, render: function() { var liked = this.state.liked ? 'l' : ''; @@ -28,14 +30,19 @@ var TableLine = React.createClass({ } else { icon = <Glyphicon glyph="ban-circle" />; } - var title = (<a href={'/article/redirect/' + this.props.article_id}> + var title = (<a href={'/article/redirect/' + this.props.article_id} + onClick={this.stopPropagation}> {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} />); - return (<div className="list-group-item" onClick={this.loadArticle}> + var clsses = "list-group-item"; + if(this.props.selected) { + clsses += " active"; + } + return (<div className={clsses} onClick={this.loadArticle}> <h5><strong>{title}</strong></h5><div /> <div>{read} {liked} {this.props.title}</div> </div> @@ -56,7 +63,13 @@ var TableLine = React.createClass({ evnt.stopPropagation(); }, loadArticle: function() { - RightPanelActions.loadArticle(this.props.article_id); + this.setState({active: true, read: true}, function() { + RightPanelActions.loadArticle( + this.props.article_id, this.props.read); + }.bind(this)); + }, + stopPropagation: function(evnt) { + evnt.stopPropagation(); }, }); @@ -207,6 +220,7 @@ var MiddlePanel = React.createClass({ read={article.read} liked={article.liked} date={article.date} + selected={article.selected} article_id={article.article_id} feed_id={article.feed_id} category_id={article.category_id} diff --git a/src/web/js/stores/MenuStore.js b/src/web/js/stores/MenuStore.js index 3a87384f..edc90a38 100644 --- a/src/web/js/stores/MenuStore.js +++ b/src/web/js/stores/MenuStore.js @@ -71,6 +71,13 @@ MenuStore.dispatchToken = JarrDispatcher.register(function(action) { }); MenuStore.emitChange(); break; + case ActionTypes.LOAD_ARTICLE: + if(!action.was_read_before) { + MenuStore._datas.categories[action.article.category_id].unread -= 1; + MenuStore._datas.feeds[action.article.feed_id].unread -= 1; + MenuStore.emitChange(); + } + break; default: // do nothing } diff --git a/src/web/js/stores/MiddlePanelStore.js b/src/web/js/stores/MiddlePanelStore.js index 83b8d942..1a0a4fab 100644 --- a/src/web/js/stores/MiddlePanelStore.js +++ b/src/web/js/stores/MiddlePanelStore.js @@ -8,8 +8,8 @@ var assign = require('object-assign'); var MiddlePanelStore = assign({}, EventEmitter.prototype, { filter_whitelist: ['filter', 'filter_id', 'filter_type', 'display_search', 'query', 'search_title', 'search_content'], - _datas: {filter: 'unread', articles: [], - filter_type: null, filter_id: null, + _datas: {articles: [], selected_article: null, + filter: 'unread', filter_type: null, filter_id: null, display_search: false, query: null, search_title: true, search_content: false}, getAll: function() { @@ -30,17 +30,26 @@ var MiddlePanelStore = assign({}, EventEmitter.prototype, { getArticles: function() { var key = null; var id = null; - var filter = this._datas.filter; if (this._datas.filter_type) { key = this._datas.filter_type; id = this._datas.filter_id; } - return this._datas.articles.filter(function(article) { - return ((!key || article[key] == id) - && (filter == 'all' - || (filter == 'unread' && !article.read) - || (filter == 'liked' && article.liked))); - }); + return this._datas.articles + .map(function(article) { + if(article.article_id == this._datas.selected_article) { + article.selected = true; + } else if(article.selected) { + article.selected = false; + } + return article; + }.bind(this)) + .filter(function(article) { + return (article.selected || ((!key || article[key] == id) + && (this._datas.filter == 'all' + || (this._datas.filter == 'unread' && !article.read) + || (this._datas.filter == 'liked' && article.liked)))); + }.bind(this)); + }, setArticles: function(articles) { if(articles || articles == []) { @@ -77,17 +86,14 @@ MiddlePanelStore.dispatchToken = JarrDispatcher.register(function(action) { case ActionTypes.RELOAD_MIDDLE_PANEL: changed = MiddlePanelStore.registerFilter(action); changed = MiddlePanelStore.setArticles(action.articles) || changed; - if(changed) {MiddlePanelStore.emitChange()}; break; case ActionTypes.PARENT_FILTER: changed = MiddlePanelStore.registerFilter(action); changed = MiddlePanelStore.setArticles(action.articles) || changed; - if(changed) {MiddlePanelStore.emitChange();} break; case ActionTypes.MIDDLE_PANEL_FILTER: changed = MiddlePanelStore.registerFilter(action); changed = MiddlePanelStore.setArticles(action.articles) || changed; - if(changed) {MiddlePanelStore.emitChange();} break; case ActionTypes.CHANGE_ATTR: var attr = action.attribute; @@ -99,7 +105,7 @@ MiddlePanelStore.dispatchToken = JarrDispatcher.register(function(action) { MiddlePanelStore._datas.articles[i][attr] = val; // avoiding redraw if not filter, display won't change anyway if(MiddlePanelStore._datas.filter != 'all') { - MiddlePanelStore.emitChange(); + changed = true; } } break; @@ -107,9 +113,19 @@ MiddlePanelStore.dispatchToken = JarrDispatcher.register(function(action) { } }); break; + case ActionTypes.LOAD_ARTICLE: + changed = true; + MiddlePanelStore._datas.selected_article = action.article.id; + for (var i in MiddlePanelStore._datas.articles) { + if(MiddlePanelStore._datas.articles[i].article_id == action.article.id) { + MiddlePanelStore._datas.articles[i].read = true; + console.log(MiddlePanelStore._datas.articles[i]); + } + } default: // pass } + if(changed) {MiddlePanelStore.emitChange();} }); module.exports = MiddlePanelStore; diff --git a/src/web/static/css/one-page-app.css b/src/web/static/css/one-page-app.css index 7b89b931..45e0440a 100644 --- a/src/web/static/css/one-page-app.css +++ b/src/web/static/css/one-page-app.css @@ -98,6 +98,16 @@ #middle-panel div.list-group-item:hover { background-color: #f0f0f0; } +#middle-panel div.list-group-item.active a { + color: #eee; +} +#middle-panel div.list-group-item.active:hover { + background-color: #4d94d1; + border-color: #4d94d1; +} +#middle-panel div.list-group-item:hover { + background-color: #f0f0f0; +} #middle-panel div.list-group-item>h5 { margin: 0px; } diff --git a/src/web/views/views.py b/src/web/views/views.py index 3e7bf80a..1ee3d06d 100644 --- a/src/web/views/views.py +++ b/src/web/views/views.py @@ -286,7 +286,7 @@ def _get_filters(in_dict): def _articles_to_json(articles, fd_hash=None): return jsonify(**{'articles': [{'title': art.title, 'liked': art.like, - 'read': art.readed, 'article_id': art.id, + 'read': art.readed, 'article_id': art.id, 'selected': False, 'feed_id': art.feed_id, 'category_id': art.category_id or 0, 'feed_title': fd_hash[art.feed_id]['title'] if fd_hash else None, 'icon_url': fd_hash[art.feed_id]['icon_url'] if fd_hash else None, @@ -309,7 +309,10 @@ def get_middle_panel(): @app.route('/getart/<int:article_id>') @login_required def get_article(article_id): - article = ArticleController(g.user.id).get(id=article_id).dump() + contr = ArticleController(g.user.id) + article = contr.get(id=article_id).dump() + if not article['readed']: + contr.update({'id': article_id}, {'readed': True}) article['category_id'] = article['category_id'] or 0 feed = FeedController(g.user.id).get(id=article['feed_id']) article['icon_url'] = url_for('icon.icon', url=feed.icon_url) \ |