aboutsummaryrefslogtreecommitdiff
path: root/src/web
diff options
context:
space:
mode:
Diffstat (limited to 'src/web')
-rw-r--r--src/web/controllers/article.py6
-rw-r--r--src/web/js/actions/RightPanelActions.js3
-rw-r--r--src/web/js/components/MiddlePanel.react.js22
-rw-r--r--src/web/js/stores/MenuStore.js7
-rw-r--r--src/web/js/stores/MiddlePanelStore.js42
-rw-r--r--src/web/static/css/one-page-app.css10
-rw-r--r--src/web/views/views.py7
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) \
bgstack15