forked from Archives/Athou_commafeed
added needed fields in models and needed libraries for frontend (#67)
This commit is contained in:
@@ -35,6 +35,8 @@ public class FeedCategory extends AbstractModel {
|
||||
|
||||
private boolean collapsed;
|
||||
|
||||
private Integer position;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -86,4 +88,12 @@ public class FeedCategory extends AbstractModel {
|
||||
this.collapsed = collapsed;
|
||||
}
|
||||
|
||||
public Integer getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(Integer position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ public class FeedSubscription extends AbstractModel {
|
||||
@OneToMany(mappedBy = "subscription", cascade = CascadeType.REMOVE)
|
||||
private Set<FeedEntryStatus> statuses;
|
||||
|
||||
private Integer position;
|
||||
|
||||
public Feed getFeed() {
|
||||
return feed;
|
||||
}
|
||||
@@ -73,4 +75,12 @@ public class FeedSubscription extends AbstractModel {
|
||||
this.statuses = statuses;
|
||||
}
|
||||
|
||||
public Integer getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(Integer position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import java.util.List;
|
||||
import javax.ejb.ApplicationException;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import com.commafeed.backend.dao.FeedEntryDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||
@@ -50,7 +52,7 @@ public class FeedSubscriptionService {
|
||||
FeedCategory category) {
|
||||
|
||||
final String pubUrl = applicationSettingsService.get().getPublicUrl();
|
||||
if (pubUrl == null) {
|
||||
if (StringUtils.isBlank(pubUrl)) {
|
||||
throw new FeedSubscriptionException(
|
||||
"Public URL of this CommaFeed instance is not set");
|
||||
}
|
||||
|
||||
@@ -8,19 +8,36 @@ import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.wordnik.swagger.annotations.ApiClass;
|
||||
import com.wordnik.swagger.annotations.ApiProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@XmlRootElement
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@ApiClass("Entry details")
|
||||
public class Category implements Serializable {
|
||||
|
||||
@ApiProperty("category id")
|
||||
private String id;
|
||||
|
||||
@ApiProperty("parent category id")
|
||||
private String parentId;
|
||||
|
||||
@ApiProperty("category id")
|
||||
private String name;
|
||||
|
||||
@ApiProperty("category children categories")
|
||||
private List<Category> children = Lists.newArrayList();
|
||||
|
||||
@ApiProperty("category feeds")
|
||||
private List<Subscription> feeds = Lists.newArrayList();
|
||||
|
||||
@ApiProperty("wether the category is expanded or collapsed")
|
||||
private boolean expanded;
|
||||
|
||||
@ApiProperty("position of the category in the list")
|
||||
private Integer position;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -68,4 +85,13 @@ public class Category implements Serializable {
|
||||
public void setExpanded(boolean expanded) {
|
||||
this.expanded = expanded;
|
||||
}
|
||||
|
||||
public Integer getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(Integer position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,6 +29,7 @@ public class Subscription implements Serializable {
|
||||
Subscription sub = new Subscription();
|
||||
sub.setId(subscription.getId());
|
||||
sub.setName(subscription.getTitle());
|
||||
sub.setPosition(subscription.getPosition());
|
||||
sub.setMessage(feed.getMessage());
|
||||
sub.setErrorCount(feed.getErrorCount());
|
||||
sub.setFeedUrl(feed.getUrl());
|
||||
@@ -77,6 +78,9 @@ public class Subscription implements Serializable {
|
||||
@ApiProperty(value = "category id")
|
||||
private String categoryId;
|
||||
|
||||
@ApiProperty("position of the subscription's in the list")
|
||||
private Integer position;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -165,4 +169,12 @@ public class Subscription implements Serializable {
|
||||
this.iconUrl = iconUrl;
|
||||
}
|
||||
|
||||
public Integer getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(Integer position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -289,6 +289,19 @@ public class CategoryREST extends AbstractResourceREST {
|
||||
return Response.ok(Status.OK).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/unreadCount")
|
||||
@ApiOperation(value = "Get unread count for feed subscriptions", responseClass = "List[com.commafeed.frontend.model.UnreadCount]")
|
||||
public Response getUnreadCount() {
|
||||
List<UnreadCount> list = Lists.newArrayList();
|
||||
Map<Long, Long> unreadCount = feedEntryStatusDAO
|
||||
.getUnreadCount(getUser());
|
||||
for (Map.Entry<Long, Long> e : unreadCount.entrySet()) {
|
||||
list.add(new UnreadCount(e.getKey(), e.getValue()));
|
||||
}
|
||||
return Response.ok(list).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/get")
|
||||
@ApiOperation(value = "Get feed categories", notes = "Get all categories and subscriptions of the user", responseClass = "com.commafeed.frontend.model.Category")
|
||||
@@ -308,19 +321,6 @@ public class CategoryREST extends AbstractResourceREST {
|
||||
return Response.ok(root).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/unreadCount")
|
||||
@ApiOperation(value = "Get unread count for feed subscriptions", responseClass = "List[com.commafeed.frontend.model.UnreadCount]")
|
||||
public Response getUnreadCount() {
|
||||
List<UnreadCount> list = Lists.newArrayList();
|
||||
Map<Long, Long> unreadCount = feedEntryStatusDAO
|
||||
.getUnreadCount(getUser());
|
||||
for (Map.Entry<Long, Long> e : unreadCount.entrySet()) {
|
||||
list.add(new UnreadCount(e.getKey(), e.getValue()));
|
||||
}
|
||||
return Response.ok(list).build();
|
||||
}
|
||||
|
||||
private Category buildCategory(Long id, List<FeedCategory> categories,
|
||||
List<FeedSubscription> subscriptions, Map<Long, Long> unreadCount) {
|
||||
Category category = new Category();
|
||||
@@ -335,6 +335,7 @@ public class CategoryREST extends AbstractResourceREST {
|
||||
subscriptions, unreadCount);
|
||||
child.setId(String.valueOf(c.getId()));
|
||||
child.setName(c.getName());
|
||||
child.setPosition(c.getPosition());
|
||||
if (c.getParent() != null && c.getParent().getId() != null) {
|
||||
child.setParentId(String.valueOf(c.getParent().getId()));
|
||||
}
|
||||
@@ -345,7 +346,7 @@ public class CategoryREST extends AbstractResourceREST {
|
||||
Collections.sort(category.getChildren(), new Comparator<Category>() {
|
||||
@Override
|
||||
public int compare(Category o1, Category o2) {
|
||||
return ObjectUtils.compare(o1.getName(), o2.getName());
|
||||
return ObjectUtils.compare(o1.getPosition(), o2.getPosition());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -364,7 +365,7 @@ public class CategoryREST extends AbstractResourceREST {
|
||||
Collections.sort(category.getFeeds(), new Comparator<Subscription>() {
|
||||
@Override
|
||||
public int compare(Subscription o1, Subscription o2) {
|
||||
return ObjectUtils.compare(o1.getName(), o2.getName());
|
||||
return ObjectUtils.compare(o1.getPosition(), o2.getPosition());
|
||||
}
|
||||
});
|
||||
return category;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
<group name="lib">
|
||||
<js minimize="false">/vendor/jquery/*.js</js>
|
||||
<js minimize="false">/vendor/jqueryui/*.js</js>
|
||||
<js minimize="false">/vendor/jquery-mousewheel/*.js</js>
|
||||
<js minimize="false">/vendor/bootstrap/*.js</js>
|
||||
<js minimize="false">/vendor/angularjs/*.js</js>
|
||||
|
||||
@@ -145,9 +145,9 @@ function($scope, $timeout, $stateParams, $window, $location, $state, $route, Cat
|
||||
$timeout(function refreshTree() {
|
||||
AnalyticsService.track();
|
||||
CategoryService.init(function() {
|
||||
$timeout(refreshTree, 15000);
|
||||
$timeout(refreshTree, 30000);
|
||||
}, function() {
|
||||
$timeout(refreshTree, 15000);
|
||||
$timeout(refreshTree, 30000);
|
||||
});
|
||||
}, 15000);
|
||||
|
||||
|
||||
@@ -15,34 +15,44 @@ module.directive('focus', [ '$timeout', function($timeout) {
|
||||
};
|
||||
} ]);
|
||||
|
||||
|
||||
/**
|
||||
* Open a popup window pointing to the url in the href attribute
|
||||
*/
|
||||
module.directive('popup', function() {
|
||||
return {
|
||||
link : function(scope, elm, attrs) {
|
||||
elm.bind('click', function(event) {
|
||||
window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=800');
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
module
|
||||
.directive(
|
||||
'popup',
|
||||
function() {
|
||||
return {
|
||||
link : function(scope, elm, attrs) {
|
||||
elm
|
||||
.bind(
|
||||
'click',
|
||||
function(event) {
|
||||
window
|
||||
.open(this.href, '',
|
||||
'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=800');
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Reusable favicon component
|
||||
*/
|
||||
module.directive('favicon', function() {
|
||||
return {
|
||||
restrict : 'E',
|
||||
scope : {
|
||||
url : '='
|
||||
},
|
||||
replace : true,
|
||||
template : '<img ng-src="{{url}}" class="favicon" onError="this.src=\'images/default_favicon.gif\'"></img>'
|
||||
};
|
||||
});
|
||||
module
|
||||
.directive(
|
||||
'favicon',
|
||||
function() {
|
||||
return {
|
||||
restrict : 'E',
|
||||
scope : {
|
||||
url : '='
|
||||
},
|
||||
replace : true,
|
||||
template : '<img ng-src="{{url}}" class="favicon" onError="this.src=\'images/default_favicon.gif\'"></img>'
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Support for the blur event
|
||||
@@ -61,11 +71,11 @@ module.directive('ngBlur', function() {
|
||||
/**
|
||||
* Fired when the top of the element is not visible anymore
|
||||
*/
|
||||
module.directive('onScrollMiddle', function () {
|
||||
module.directive('onScrollMiddle', function() {
|
||||
return {
|
||||
restrict : 'A',
|
||||
link : function(scope, element, attrs) {
|
||||
|
||||
|
||||
var w = $(window);
|
||||
var e = $(element);
|
||||
var d = $(document);
|
||||
@@ -75,7 +85,8 @@ module.directive('onScrollMiddle', function () {
|
||||
return;
|
||||
var docTop = w.scrollTop();
|
||||
var elemTop = e.offset().top;
|
||||
var threshold = docTop === 0 ? elemTop - 1 : docTop + w.height() / 3;
|
||||
var threshold = docTop === 0 ? elemTop - 1 : docTop
|
||||
+ w.height() / 3;
|
||||
return (elemTop > threshold) ? 'below' : 'above';
|
||||
};
|
||||
var up = function() {
|
||||
@@ -84,27 +95,31 @@ module.directive('onScrollMiddle', function () {
|
||||
var docTop = w.scrollTop();
|
||||
var elemTop = e.offset().top;
|
||||
var elemBottom = elemTop + e.height();
|
||||
var threshold = docTop === 0 ? elemBottom - 1 : docTop + w.height() / 3;
|
||||
var threshold = docTop === 0 ? elemBottom - 1 : docTop
|
||||
+ w.height() / 3;
|
||||
return (elemBottom > threshold) ? 'below' : 'above';
|
||||
};
|
||||
|
||||
|
||||
w.data.scrollPosition = d.scrollTop();
|
||||
w.data.scrollDirection = 'down';
|
||||
if(!w.data.scrollInit){
|
||||
w.bind('scroll', function(e) {
|
||||
var scroll = d.scrollTop();
|
||||
w.data.scrollDirection = (scroll - w.data.scrollPosition > 0) ? 'down' : 'up';
|
||||
w.data.scrollPosition = scroll;
|
||||
scope.$apply();
|
||||
});
|
||||
if (!w.data.scrollInit) {
|
||||
w.bind('scroll',
|
||||
function(e) {
|
||||
var scroll = d.scrollTop();
|
||||
w.data.scrollDirection = (scroll
|
||||
- w.data.scrollPosition > 0) ? 'down'
|
||||
: 'up';
|
||||
w.data.scrollPosition = scroll;
|
||||
scope.$apply();
|
||||
});
|
||||
w.data.scrollInit = true;
|
||||
}
|
||||
scope.$watch(down, function downCallback(value, oldValue) {
|
||||
if(value && value != oldValue && value == 'above')
|
||||
if (value && value != oldValue && value == 'above')
|
||||
scope.$eval(attrs.onScrollMiddle);
|
||||
});
|
||||
scope.$watch(up, function upCallback(value, oldValue) {
|
||||
if(value && value != oldValue && value == 'below')
|
||||
if (value && value != oldValue && value == 'below')
|
||||
scope.$eval(attrs.onScrollMiddle);
|
||||
});
|
||||
}
|
||||
@@ -145,7 +160,8 @@ module.directive('scrollTo', [ '$timeout', function($timeout) {
|
||||
} ]);
|
||||
|
||||
/**
|
||||
* Prevent mousewheel scrolling from propagating to the parent when scrollbar reaches top or bottom
|
||||
* Prevent mousewheel scrolling from propagating to the parent when scrollbar
|
||||
* reaches top or bottom
|
||||
*/
|
||||
module.directive('mousewheelScrolling', function() {
|
||||
return {
|
||||
@@ -168,7 +184,8 @@ module.directive('mousewheelScrolling', function() {
|
||||
});
|
||||
|
||||
/**
|
||||
* Needed to use recursive directives. Wrap a recursive element with a <recursive> tag
|
||||
* Needed to use recursive directives. Wrap a recursive element with a
|
||||
* <recursive> tag
|
||||
*/
|
||||
module.directive('recursive', [ '$compile', function($compile) {
|
||||
return {
|
||||
@@ -196,7 +213,7 @@ module.directive('category', [ function() {
|
||||
return {
|
||||
scope : {
|
||||
node : '=',
|
||||
level: '=',
|
||||
level : '=',
|
||||
selectedType : '=',
|
||||
selectedId : '=',
|
||||
showLabel : '=',
|
||||
@@ -217,15 +234,16 @@ module.directive('category', [ function() {
|
||||
function($scope, $state, $dialog, FeedService, CategoryService,
|
||||
SettingsService, MobileService) {
|
||||
$scope.settingsService = SettingsService;
|
||||
|
||||
|
||||
$scope.getClass = function(level) {
|
||||
if ($scope.showLabel){
|
||||
if ($scope.showLabel) {
|
||||
return 'indent' + level;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
$scope.categoryLabel = function(category) {
|
||||
return $scope.showLabel !== true ? $scope.showLabel : category.name;
|
||||
return $scope.showLabel !== true ? $scope.showLabel
|
||||
: category.name;
|
||||
};
|
||||
|
||||
$scope.categoryCountLabel = function(category) {
|
||||
@@ -272,16 +290,16 @@ module.directive('category', [ function() {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
$scope.showFeedDetails = function(feed) {
|
||||
$state.transitionTo('feeds.feed_details', {
|
||||
_id: feed.id
|
||||
_id : feed.id
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
$scope.showCategoryDetails = function(category) {
|
||||
$state.transitionTo('feeds.category_details', {
|
||||
_id: category.id
|
||||
_id : category.id
|
||||
});
|
||||
};
|
||||
|
||||
@@ -340,3 +358,39 @@ module.directive('spinner', function() {
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
module.directive('draggable', function() {
|
||||
return {
|
||||
restrict : 'A',
|
||||
link : function(scope, element, attrs) {
|
||||
element.draggable({
|
||||
revert: true
|
||||
}).data('source', scope.$eval(attrs.draggable));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
module.directive('droppable', function($compile) {
|
||||
return {
|
||||
restrict : 'A',
|
||||
link : function(scope, element, attrs) {
|
||||
element.droppable({
|
||||
tolerance: 'pointer',
|
||||
over: function(event, ui) {
|
||||
console.log(scope.$eval(attrs.droppable));
|
||||
},
|
||||
drop : function(event, ui) {
|
||||
var draggable = angular.element(ui.draggable);
|
||||
|
||||
|
||||
var index = draggable.data('index');
|
||||
var source = draggable.data('source');
|
||||
|
||||
console.log(source)
|
||||
|
||||
scope.$apply();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
<li>
|
||||
<div class="pointer tree-item" ui-if="showLabel" ng-class="getClass(level - 1)">
|
||||
<div class="pointer tree-item" ui-if="showLabel" ng-class="getClass(level - 1)" draggable="node" droppable="node">
|
||||
<div class="dropdown pull-right">
|
||||
<div class="pull-right" ng-click="showCategoryDetails(node)">
|
||||
<i class="icon-wrench config pointer"></i>
|
||||
@@ -11,7 +11,7 @@
|
||||
<i ng-class="{'icon-star' : node.id == 'starred', 'icon-inbox': node.id == 'all'}" ng-show="!showChildren"></i>
|
||||
</span>
|
||||
<span ng-class="{selected: (node.id == selectedId && selectedType == 'category'), unread: unreadCount({category:node})}">
|
||||
{{categoryLabel(node)}} {{categoryCountLabel(node)}}
|
||||
{{categoryLabel(node)}} {{categoryCountLabel(node)}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -23,7 +23,7 @@
|
||||
unread-count="unreadCount({category:category})">
|
||||
</category>
|
||||
</recursive>
|
||||
<li ng-repeat="feed in node.feeds" ng-class="getClass(level)" class="tree-item"
|
||||
<li ng-repeat="feed in node.feeds" ng-class="getClass(level)" class="tree-item" draggable="feed" droppable="feed"
|
||||
ng-show="settingsService.settings.showRead == true || feed.unread > 0">
|
||||
<div class="pull-right" ng-click="showFeedDetails(feed)">
|
||||
<i class="icon-wrench config pointer"></i>
|
||||
|
||||
12
src/main/webapp/vendor/jqueryui/jquery-ui.1.10.3.min.js
vendored
Normal file
12
src/main/webapp/vendor/jqueryui/jquery-ui.1.10.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user