From 678af2747d6414379e81ee6856c7ec2f3cd5a890 Mon Sep 17 00:00:00 2001 From: François Schmidts Date: Sat, 30 Jan 2016 23:17:03 +0100 Subject: registering modifications on feeds / categories --- src/web/js/actions/RightPanelActions.js | 17 +++- src/web/js/components/RightPanel.react.js | 156 ++++++++++++++++++++---------- src/web/js/stores/RightPanelStore.js | 50 +++++++--- src/web/views/api/feed.py | 1 + 4 files changed, 155 insertions(+), 69 deletions(-) (limited to 'src') diff --git a/src/web/js/actions/RightPanelActions.js b/src/web/js/actions/RightPanelActions.js index c60bffcf..838690d1 100644 --- a/src/web/js/actions/RightPanelActions.js +++ b/src/web/js/actions/RightPanelActions.js @@ -1,6 +1,7 @@ +var jquery = require('jquery'); var JarrDispatcher = require('../dispatcher/JarrDispatcher'); var ActionTypes = require('../constants/JarrConstants'); -var jquery = require('jquery'); +var MenuActions = require('../actions/MenuActions'); var RightPanelActions = { loadArticle: function(article_id, was_read_before) { @@ -13,7 +14,19 @@ var RightPanelActions = { }); } ); - + }, + _apiReq: function(meth, id, obj_type, data, success_callback) { + var args = {type: meth, contentType: 'application/json', + url: "api/v2.0/" + obj_type + "/" + id} + if(data) {args.data = JSON.stringify(data);} + if(success_callback) {args.success = success_callback;} + jquery.ajax(args); + }, + putObj: function(id, obj_type, fields) { + this._apiReq('PUT', id, obj_type, fields, MenuActions.reload); + }, + delObj: function(id, obj_type, fields) { + this._apiReq('DELETE', id, obj_type, null, MenuActions.reload); }, }; diff --git a/src/web/js/components/RightPanel.react.js b/src/web/js/components/RightPanel.react.js index 2e2aac3e..fda7c976 100644 --- a/src/web/js/components/RightPanel.react.js +++ b/src/web/js/components/RightPanel.react.js @@ -4,11 +4,15 @@ var Glyphicon = require('react-bootstrap/Glyphicon'); var Button = require('react-bootstrap/Button'); var ButtonGroup = require('react-bootstrap/ButtonGroup'); +var RightPanelActions = require('../actions/RightPanelActions'); var RightPanelStore = require('../stores/RightPanelStore'); var JarrTime = require('./time.react'); var PanelMixin = { propTypes: {obj: React.PropTypes.object.isRequired}, + getInitialState: function() { + return {edit_mode: false, obj: this.props.obj}; + }, getHeader: function() { var icon = null; if(this.props.obj.icon_url){ @@ -46,7 +50,9 @@ var PanelMixin = { var items = []; var key; if(!this.state.edit_mode) { - this.fields.map(function(field) { + this.fields.filter(function(field) { + return field.type != 'ignore'; + }).map(function(field) { key = this.getKey('dt', field.key); items.push(
{field.title}
); key = this.getKey('dd', field.key); @@ -67,24 +73,30 @@ var PanelMixin = { } }.bind(this)); } else { - this.fields.map(function(field) { + items.push(
+ +
); + this.fields.filter(function(field) { + return field.type != 'ignore'; + }).map(function(field) { key = this.getKey('dd', field.key); items.push(
{field.title}
); key = this.getKey('dt', field.key); + var input = null; if(field.type == 'string' || field.type == 'link') { - items.push(
-
); + input = (); } else if (field.type == 'bool') { - items.push(
); + input = (); } + items.push(
{input}
); }.bind(this)); - items.push(
- -
); } return (
{items}
); }, @@ -99,15 +111,39 @@ var PanelMixin = { this.setState({edit_mode: !this.state.edit_mode}); }, onClickRemove: function() { + RightPanelActions.delObj(this.props.obj.id, this.obj_type); + }, + saveField: function(evnt) { + var obj = this.state.obj; + for(var i in this.fields) { + if(evnt.target.name == this.fields[i].key) { + if(this.fields[i].type == 'bool') { + obj[evnt.target.name] = evnt.target.checked; + } else { + obj[evnt.target.name] = evnt.target.value; + } + break; + } + } + this.setState({obj: obj}); + }, + saveObj: function() { + var to_push = {}; + this.fields.map(function(field) { + to_push[field.key] = this.state.obj[field.key]; + }.bind(this)); + this.setState({edit_mode: false}, function() { + RightPanelActions.putObj(this.props.obj.id, this.obj_type, to_push); + }.bind(this)); }, }; var Article = React.createClass({ mixins: [PanelMixin], - getInitialState: function() {return {edit_mode: false};}, - fields: [], isEditable: function() {return false;}, isRemovable: function() {return true;}, + fields: [], + obj_type: 'article', getTitle: function() {return this.props.obj.title;}, getBody: function() { return (
+ + - - ); }, - getBody: function() { - var filter_rows = []; - for(var i in this.state.filters) { - filter_rows.push(this.getFilterRow(i, this.state.filters[i])); + getFilterRows: function() { + var rows = []; + if(this.state.edit_mode) { + for(var i in this.state.obj.filters) { + rows.push(this.getFilterRow(i, this.state.obj.filters[i])); + } + return (
+
Filters
+
+ +
+ {rows} +
); } + rows = []; + rows.push(
Filters
); + for(var i in this.state.obj.filters) { + rows.push(
+ When {this.state.obj.filters[i]['action on']} on "{this.state.obj.filters[i].pattern}" ({this.state.obj.filters[i].type}) => {this.state.obj.filters[i].action} +
); + } + return
{rows}
; + }, + getBody: function() { return (
Created on
@@ -174,44 +235,37 @@ var Feed = React.createClass({
{this.getCore()} -
-
-
Filters
-
- - -
- {filter_rows} -
-
+ {this.getFilterRows()}
); }, addFilterRow: function() { - var filters = this.state.filters; - filters.push({action: null, action_on: null, - type: null, pattern: null}); - this.setState({filters: filters}); + var obj = this.state.obj; + obj.filters.push({action: "mark as read", 'action on': "match", + type: "simple match", pattern: ""}); + this.setState({obj: obj}); }, removeFilterRow: function(evnt) { - var filters = this.state.filters; - delete filters[evnt.target.getAttribute('data-index')]; - this.setState({filters: filters}); + var obj = this.state.obj; + delete obj.filters[evnt.target.getAttribute('data-index')]; + this.setState({obj: obj}); + }, + saveFilterChange: function(evnt) { + var index = evnt.target.getAttribute('data-index'); + var obj = this.state.obj; + obj.filters[index][evnt.target.name] = evnt.target.value; + this.setState({obj: obj}); }, }); var Category = React.createClass({ mixins: [PanelMixin], - getInitialState: function() {return {edit_mode: false};}, isEditable: function() { if(this.props.obj.id != 0) {return true;} else {return false;} }, isRemovable: function() {return this.isEditable();}, + obj_type: 'category', fields: [{'title': 'Category name', 'type': 'string', 'key': 'name'}], getTitle: function() {return this.props.obj.name;}, getBody: function() { @@ -299,7 +353,7 @@ var RightPanel = React.createClass({ RightPanelStore.removeChangeListener(this._onChange); }, _onChange: function() { - this.setState(RightPanelStore._datas); + this.setState(RightPanelStore.getAll()); }, }); diff --git a/src/web/js/stores/RightPanelStore.js b/src/web/js/stores/RightPanelStore.js index 85f336e4..6c268dfd 100644 --- a/src/web/js/stores/RightPanelStore.js +++ b/src/web/js/stores/RightPanelStore.js @@ -7,9 +7,13 @@ var MenuStore = require('../stores/MenuStore'); var RightPanelStore = assign({}, EventEmitter.prototype, { - _datas: {category: null, feed: null, article: null}, + category: null, + feed: null, + article: null, + current: null, getAll: function() { - return this._datas; + return {category: this.category, feed: this.feed, + article: this.article, current: this.current}; }, emitChange: function() { this.emit(CHANGE_EVENT); @@ -26,31 +30,45 @@ var RightPanelStore = assign({}, EventEmitter.prototype, { RightPanelStore.dispatchToken = JarrDispatcher.register(function(action) { switch(action.type) { case ActionTypes.PARENT_FILTER: - RightPanelStore._datas.article = null; + RightPanelStore.article = null; if(action.filter_id == null) { - RightPanelStore._datas.category = null; - RightPanelStore._datas.feed = null; - RightPanelStore._datas.current = null; + RightPanelStore.category = null; + RightPanelStore.feed = null; + RightPanelStore.current = null; } else if(action.filter_type == 'category_id') { - RightPanelStore._datas.category = MenuStore._datas.categories[action.filter_id]; - RightPanelStore._datas.feed = null; - RightPanelStore._datas.current = 'category'; + RightPanelStore.category = MenuStore._datas.categories[action.filter_id]; + RightPanelStore.feed = null; + RightPanelStore.current = 'category'; RightPanelStore.emitChange(); } else { - RightPanelStore._datas.feed = MenuStore._datas.feeds[action.filter_id]; - RightPanelStore._datas.category = MenuStore._datas.categories[RightPanelStore._datas.feed.category_id]; - RightPanelStore._datas.current = 'feed'; + RightPanelStore.feed = MenuStore._datas.feeds[action.filter_id]; + RightPanelStore.category = MenuStore._datas.categories[RightPanelStore.feed.category_id]; + RightPanelStore.current = 'feed'; RightPanelStore.emitChange(); } break; case ActionTypes.LOAD_ARTICLE: - RightPanelStore._datas.feed = MenuStore._datas.feeds[action.article.feed_id]; - RightPanelStore._datas.category = MenuStore._datas.categories[action.article.category_id]; - RightPanelStore._datas.article = action.article; - RightPanelStore._datas.current = 'article'; + RightPanelStore.feed = MenuStore._datas.feeds[action.article.feed_id]; + RightPanelStore.category = MenuStore._datas.categories[action.article.category_id]; + RightPanelStore.article = action.article; + RightPanelStore.current = 'article'; RightPanelStore.emitChange(); break; + case ActionTypes.RELOAD_MENU: + RightPanelStore.article = null; + if(RightPanelStore.category && !(RightPanelStore.category.id.toString() in action.categories)) { + RightPanelStore.category = null; + RightPanelStore.current = null; + } + if(RightPanelStore.feed && !(RightPanelStore.feed.id.toString() in action.feeds)) { + RightPanelStore.feed = null; + RightPanelStore.current = null; + } + if(RightPanelStore.current == 'article') { + RightPanelStore.current = null; + } + RightPanelStore.emitChange(); default: // pass } diff --git a/src/web/views/api/feed.py b/src/web/views/api/feed.py index dd9919bf..604620b4 100644 --- a/src/web/views/api/feed.py +++ b/src/web/views/api/feed.py @@ -22,6 +22,7 @@ FEED_ATTRS = {'title': {'type': str}, 'enabled': {'type': bool, 'default': True}, 'etag': {'type': str, 'default': ''}, 'icon_url': {'type': str, 'default': ''}, + 'filters': {'type': list}, 'last_modified': {'type': str}, 'last_retrieved': {'type': str}, 'last_error': {'type': str}, -- cgit