Files
commafeed/src/main/webapp/js/controllers.js
Risto Kankkunen 8f9e8fd2ea Make subscription failures visible.
--HG--
extra : rebase_source : 9e7232b821665d9a6342c928d0b17ac3bdd9e6e7
2013-05-20 22:14:56 +03:00

959 lines
24 KiB
JavaScript

var module = angular.module('commafeed.controllers', []);
module.run(['$rootScope', function($rootScope) {
$rootScope.$on('emitPreviousEntry', function(event, args) {
$rootScope.$broadcast('previousEntry', args);
});
$rootScope.$on('emitNextEntry', function(event, args) {
$rootScope.$broadcast('nextEntry', args);
});
$rootScope.$on('emitMark', function(event, args) {
// args.entry - the entry
$rootScope.$broadcast('mark', args);
});
$rootScope.$on('emitMarkAll', function(event, args) {
// args.type
// args.id
// args.read
$rootScope.$broadcast('markAll', args);
});
$rootScope.$on('emitReload', function(event, args) {
$rootScope.$broadcast('reload');
});
}]);
module.controller('SubscribeCtrl', ['$scope', 'FeedService', 'CategoryService',
function($scope, FeedService, CategoryService) {
$scope.opts = {
backdropFade : true,
dialogFade : true
};
$scope.isOpen = false;
$scope.isOpenImport = false;
$scope.sub = {};
$scope.CategoryService = CategoryService;
$scope.open = function() {
$scope.sub = {
categoryId: 'all'
};
$scope.isOpen = true;
};
$scope.close = function() {
$scope.isOpen = false;
};
// 'ok', 'loading' or 'failed'
$scope.state = 'ok';
$scope.urlChanged = function() {
if ($scope.sub.url) {
$scope.state = 'loading';
$scope.sub.title = 'Loading...';
FeedService.fetch({
url : $scope.sub.url
}, function(data) {
$scope.state = 'ok';
$scope.sub.title = data.title;
$scope.sub.url = data.url;
}, function(data) {
$scope.state = 'failed';
$scope.sub.title = 'Loading failed. Invalid feed?';
});
}
};
$scope.save = function() {
if ($scope.state != 'ok') {
return;
}
if (!$scope.sub.categoryId) {
return;
}
FeedService.subscribe($scope.sub, function() {
CategoryService.init();
$scope.close();
}, function(data) {
$scope.state = 'failed';
$scope.sub.title = 'ERROR: ' + data.data;
});
};
$scope.openImport = function() {
$scope.isOpenImport = true;
};
$scope.closeImport = function() {
$scope.isOpenImport = false;
};
$scope.uploadComplete = function(contents, completed) {
CategoryService.init();
$scope.closeImport();
};
$scope.cat = {};
$scope.openCategory = function() {
$scope.isOpenCategory = true;
$scope.cat = {
parentId: 'all'
};
};
$scope.closeCategory = function() {
$scope.isOpenCategory = false;
};
$scope.saveCategory = function() {
CategoryService.add($scope.cat, function() {
CategoryService.init();
});
$scope.closeCategory();
};
}]);
module.controller('CategoryTreeCtrl', ['$scope', '$timeout', '$stateParams', '$window',
'$location', '$state', '$route', 'CategoryService', 'AnalyticsService',
function($scope, $timeout, $stateParams, $window, $location, $state, $route, CategoryService, AnalyticsService) {
$scope.selectedType = $stateParams._type;
$scope.selectedId = $stateParams._id;
$scope.starred = {
id: 'starred',
name: 'Starred'
};
$scope.$on('$stateChangeSuccess', function() {
$scope.selectedType = $stateParams._type;
$scope.selectedId = $stateParams._id;
});
$timeout(function refreshTree() {
AnalyticsService.track();
CategoryService.init(function() {
$timeout(refreshTree, 15000);
}, function() {
$timeout(refreshTree, 15000);
});
}, 15000);
$scope.CategoryService = CategoryService;
$scope.unreadCount = function(category) {
var count = 0;
var i;
if (category.children) {
for (i = 0; i < category.children.length; i++) {
count = count + $scope.unreadCount(category.children[i]);
}
}
if (category.feeds) {
for (i = 0; i < category.feeds.length; i++) {
var feed = category.feeds[i];
count = count + feed.unread;
}
}
return count;
};
var rootUnreadCount = function() {
return $scope.unreadCount($scope.CategoryService.subscriptions);
};
$scope.$watch(rootUnreadCount, function(value) {
var label = 'CommaFeed';
if (value > 0) {
label = value + ' - ' + label;
}
$window.document.title = label;
});
var mark = function(node, entry) {
var i;
if (node.children) {
for (i = 0; i < node.children.length; i++) {
mark(node.children[i], entry);
}
}
if (node.feeds) {
for (i = 0; i < node.feeds.length; i++) {
var feed = node.feeds[i];
if (feed.id == entry.feedId) {
var c = entry.read ? -1 : 1;
feed.unread = feed.unread + c;
}
}
}
};
$scope.$on('mark', function(event, args) {
mark($scope.CategoryService.subscriptions, args.entry);
});
}]);
module.controller('FeedDetailsCtrl', ['$scope', '$state', '$stateParams', 'FeedService', 'CategoryService', 'ProfileService', '$dialog',
function($scope, $state, $stateParams, FeedService, CategoryService, ProfileService, $dialog) {
$scope.CategoryService = CategoryService;
$scope.user = ProfileService.get();
$scope.sub = FeedService.get({
id : $stateParams._id
}, function(data) {
if (!data.categoryId)
data.categoryId = 'all';
});
$scope.back = function() {
$state.transitionTo('feeds.view', {
_id: $stateParams._id,
_type: 'feed'
});
};
$scope.unsubscribe = function() {
var sub = $scope.sub;
var title = 'Unsubscribe';
var msg = 'Unsubscribe from ' + sub.name + ' ?';
var btns = [ {
result : 'cancel',
label : 'Cancel'
}, {
result : 'ok',
label : 'OK',
cssClass : 'btn-primary'
} ];
$dialog.messageBox(title, msg, btns).open().then(
function(result) {
if (result == 'ok') {
var data = {
id : sub.id
};
FeedService.unsubscribe(data,
function() {
CategoryService.init();
});
$state.transitionTo('feeds.view', {
_id: 'all',
_type: 'category'
});
}
});
};
$scope.save = function() {
var sub = $scope.sub;
FeedService.modify({
id : sub.id,
name : sub.name,
categoryId : sub.categoryId
}, function() {
CategoryService.init();
$state.transitionTo('feeds.view', {
_id: 'all',
_type: 'category'
});
});
};
}]);
module.controller('CategoryDetailsCtrl', ['$scope', '$state', '$stateParams', 'FeedService', 'CategoryService', 'ProfileService', '$dialog',
function($scope, $state, $stateParams, FeedService, CategoryService, ProfileService, $dialog) {
$scope.CategoryService = CategoryService;
$scope.user = ProfileService.get();
$scope.isMeta = function() {
return parseInt($stateParams._id, 10) != $stateParams._id;
};
$scope.filterCurrent = function(elem) {
if (!$scope.category)
return true;
return elem.id != $scope.category.id;
};
CategoryService.init(function() {
if ($scope.isMeta()) {
$scope.category = {
id : $stateParams._id,
name : $stateParams._id
};
return;
}
for (var i = 0; i < CategoryService.flatCategories.length; i++) {
var cat = CategoryService.flatCategories[i];
if (cat.id == $stateParams._id) {
$scope.category = {
id: cat.id,
name: cat.orig.name,
parentId: cat.orig.parentId
};
break;
}
}
if (!$scope.category.parentId)
$scope.category.parentId = 'all';
});
$scope.back = function() {
$state.transitionTo('feeds.view', {
_id: $stateParams._id,
_type: 'category'
});
};
$scope.deleteCategory = function() {
var category = $scope.category;
var title = 'Delete category';
var msg = 'Delete category ' + category.name + ' ?';
var btns = [ {
result : 'cancel',
label : 'Cancel'
}, {
result : 'ok',
label : 'OK',
cssClass : 'btn-primary'
} ];
$dialog.messageBox(title, msg, btns).open().then(
function(result) {
if (result == 'ok') {
CategoryService.remove({
id : category.id
}, function() {
CategoryService.init();
});
$state.transitionTo('feeds.view', {
_id: 'all',
_type: 'category'
});
}
});
};
$scope.save = function() {
var cat = $scope.category;
CategoryService.modify({
id : cat.id,
name : cat.name,
parentId : cat.parentId
}, function() {
CategoryService.init();
$state.transitionTo('feeds.view', {
_id: 'all',
_type: 'category'
});
});
};
}]);
module.controller('ToolbarCtrl', ['$scope', '$http', '$state', '$stateParams',
'$route', '$location', 'SettingsService', 'EntryService', 'ProfileService', 'AnalyticsService', 'ServerService', 'FeedService',
function($scope, $http, $state, $stateParams, $route, $location,
SettingsService, EntryService, ProfileService, AnalyticsService, ServerService, FeedService) {
function totalActiveAjaxRequests() {
return ($http.pendingRequests.length + $.active);
}
$scope.session = ProfileService.get();
$scope.ServerService = ServerService.get();
$scope.settingsService = SettingsService;
$scope.loading = true;
$scope.$watch(totalActiveAjaxRequests, function() {
$scope.loading = (totalActiveAjaxRequests() !== 0);
});
$scope.$watch('settingsService.settings.readingMode', function(
newValue, oldValue) {
if (newValue && oldValue && newValue != oldValue) {
SettingsService.save();
}
});
$scope.$watch('settingsService.settings.readingOrder', function(
newValue, oldValue) {
if (newValue && oldValue && newValue != oldValue) {
SettingsService.save();
}
});
$scope.$watch('settingsService.settings.viewMode', function(
newValue, oldValue) {
if (newValue && oldValue && newValue != oldValue) {
SettingsService.save();
$scope.$emit('emitReload');
}
});
$scope.previousEntry = function() {
$scope.$emit('emitPreviousEntry');
};
$scope.nextEntry = function() {
$scope.$emit('emitNextEntry');
};
$scope.refresh = function() {
if($stateParams._type == 'feed'){
FeedService.refresh({
id : $stateParams._id
});
}
$scope.$emit('emitReload');
};
var markAll = function(olderThan) {
$scope.$emit('emitMarkAll', {
type : $stateParams._type,
id : $stateParams._id,
olderThan: olderThan,
read : true
});
};
$scope.markAllAsRead = function() {
markAll();
};
$scope.markAllDay = function() {
markAll(new Date().getTime() - 86400000);
};
$scope.markAllWeek = function() {
markAll(new Date().getTime() - 604800000);
};
$scope.markAllTwoWeeks = function() {
markAll(new Date().getTime() - 1209600000);
};
$scope.keywords = $stateParams._keywords;
$scope.search = function() {
if ($scope.keywords == $stateParams._keywords) {
$scope.refresh();
} else {
$state.transitionTo('feeds.search', {
_keywords : $scope.keywords
});
}
};
$scope.showButtons = function() {
return !$stateParams._keywords;
};
$scope.toggleOrder = function() {
var settings = $scope.settingsService.settings;
settings.readingOrder = settings.readingOrder == 'asc' ? 'desc' : 'asc';
};
$scope.toAdmin = function() {
$location.path('admin');
};
$scope.toSettings = function() {
$state.transitionTo('feeds.settings');
};
$scope.toProfile = function() {
$state.transitionTo('feeds.profile');
};
$scope.toHelp = function() {
$state.transitionTo('feeds.help');
};
$scope.toDonate = function() {
AnalyticsService.track('/donate');
$state.transitionTo('feeds.help');
};
}]);
module.controller('FeedListCtrl', ['$scope', '$stateParams', '$http', '$route',
'$window', 'EntryService', 'SettingsService', 'FeedService', 'CategoryService', 'AnalyticsService',
function($scope, $stateParams, $http, $route, $window, EntryService, SettingsService, FeedService, CategoryService, AnalyticsService) {
AnalyticsService.track();
$scope.selectedType = $stateParams._type;
$scope.selectedId = $stateParams._id;
$scope.keywords = $stateParams._keywords;
$scope.name = null;
$scope.message = null;
$scope.errorCount = 0;
$scope.timestamp = 0;
$scope.entries = [];
$scope.settingsService = SettingsService;
$scope.$watch('settingsService.settings.readingMode', function(newValue,
oldValue) {
if (newValue && oldValue && newValue != oldValue) {
$scope.$emit('emitReload');
}
});
$scope.$watch('settingsService.settings.readingOrder', function(newValue,
oldValue) {
if (newValue && oldValue && newValue != oldValue) {
$scope.$emit('emitReload');
}
});
$scope.limit = SettingsService.settings.viewMode == 'title' ? 10 : 3;
$scope.busy = false;
$scope.hasMore = true;
$scope.loadMoreEntries = function() {
if (!$scope.hasMore)
return;
if ($scope.busy)
return;
$scope.busy = true;
var limit = $scope.limit;
if ($scope.entries.length === 0) {
$window = angular.element($window);
if (SettingsService.settings.viewMode == 'title') {
limit = $window.height() / 33;
limit = parseInt(limit, 10) + 5;
} else {
limit = $window.height() / 97;
limit = parseInt(limit, 10) + 1;
}
}
var callback = function(data) {
for ( var i = 0; i < data.entries.length; i++) {
$scope.entries.push(data.entries[i]);
}
$scope.name = data.name;
$scope.message = data.message;
$scope.errorCount = data.errorCount;
$scope.timestamp = data.timestamp;
$scope.busy = false;
$scope.hasMore = data.entries.length == limit;
};
if (!$scope.keywords) {
var service = $scope.selectedType == 'feed' ? FeedService
: CategoryService;
service.entries({
id : $scope.selectedId,
readType : $scope.settingsService.settings.readingMode,
order : $scope.settingsService.settings.readingOrder,
offset : $scope.entries.length,
limit : limit
}, callback);
} else {
EntryService.search({
keywords : $scope.keywords,
offset : $scope.entries.length,
limit : limit
}, callback);
}
};
$scope.mark = function(entry, read) {
if (entry.read != read) {
entry.read = read;
$scope.$emit('emitMark', {
entry : entry
});
EntryService.mark({
id : entry.id,
read : read
});
}
};
$scope.markAll = function(olderThan) {
var service = $scope.selectedType == 'feed' ? FeedService
: CategoryService;
service.mark({
id : $scope.selectedId,
olderThan : olderThan || $scope.timestamp,
read : true
}, function() {
CategoryService.init(function() {
$scope.$emit('emitReload');
});
});
};
$scope.star = function(entry, star, event) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
if (entry.starred != star) {
entry.starred = star;
EntryService.star({
id : entry.id,
starred : star
});
}
};
$scope.isOpen = SettingsService.settings.viewMode == 'expanded';
$scope.entryClicked = function(entry, event) {
$scope.navigationMode = 'click';
if (!event || (!event.ctrlKey && event.which != 2)) {
if ($scope.current != entry || SettingsService.settings.viewMode == 'expanded') {
$scope.isOpen = true;
} else {
$scope.isOpen = !$scope.isOpen;
}
if ($scope.isOpen) {
$scope.mark(entry, true);
}
$scope.current = entry;
if(event) {
event.preventDefault();
event.stopPropagation();
}
} else {
$scope.mark(entry, true);
}
};
$scope.bodyClicked = function(entry, event) {
if (SettingsService.settings.viewMode == 'expanded' && $scope.current != entry) {
$scope.entryClicked(entry, event);
}
};
$scope.noop = function(event) {
if (!event.ctrlKey && event.which != 2) {
event.preventDefault();
event.stopPropagation();
}
};
var openNextEntry = function(event) {
var entry = null;
if ($scope.current) {
var index;
for ( var i = 0; i < $scope.entries.length; i++) {
if ($scope.current == $scope.entries[i]) {
index = i;
break;
}
}
index = index + 1;
if (index < $scope.entries.length) {
entry = $scope.entries[index];
}
} else if ($scope.entries.length > 0) {
entry = $scope.entries[0];
}
if (entry) {
$scope.entryClicked(entry, event);
}
};
var openPreviousEntry = function(event) {
var entry = null;
if ($scope.current) {
var index;
for ( var i = 0; i < $scope.entries.length; i++) {
if ($scope.current == $scope.entries[i]) {
index = i;
break;
}
}
index = index - 1;
if (index >= 0) {
entry = $scope.entries[index];
}
}
if (entry) {
$scope.entryClicked(entry, event);
}
};
$scope.onScroll = function(entry) {
$scope.navigationMode = 'scroll';
if (SettingsService.settings.viewMode == 'expanded') {
$scope.current = entry;
if(SettingsService.settings.scrollMarks) {
$scope.mark(entry, true);
}
}
};
Mousetrap.bind('j', function(e) {
$scope.$apply(function() {
openNextEntry(e);
});
});
Mousetrap.bind('n', function(e) {
$scope.$apply(function() {
openNextEntry(e);
});
});
Mousetrap.bind('k', function(e) {
$scope.$apply(function() {
openPreviousEntry(e);
});
});
Mousetrap.bind('p', function(e) {
$scope.$apply(function() {
openPreviousEntry(e);
});
});
Mousetrap.bind('o', function(e) {
$scope.$apply(function() {
if ($scope.current) {
$scope.entryClicked($scope.current, e);
}
});
});
Mousetrap.bind('enter', function(e) {
$scope.$apply(function() {
if ($scope.current) {
$scope.entryClicked($scope.current, e);
}
});
});
Mousetrap.bind('r', function(e) {
$scope.$apply(function() {
$scope.$emit('emitReload');
});
});
Mousetrap.bind('v', function(e) {
if ($scope.current) {
window.open($scope.current.url);
}
});
Mousetrap.bind('s', function(e) {
$scope.$apply(function() {
if ($scope.current) {
$scope.star($scope.current, !$scope.current.starred);
}
});
});
Mousetrap.bind('m', function(e) {
$scope.$apply(function() {
if ($scope.current) {
$scope.mark($scope.current, !$scope.current.read);
}
});
});
Mousetrap.bind('shift+a', function(e) {
$scope.$apply(function() {
$scope.markAll();
});
});
Mousetrap.bind('?', function(e) {
$scope.$apply(function() {
$scope.shortcutsModal = true;
});
});
$scope.$on('previousEntry', function(event, args) {
openPreviousEntry();
});
$scope.$on('nextEntry', function(event, args) {
openNextEntry();
});
$scope.$on('markAll', function(event, args) {
$scope.markAll(args.olderThan);
});
$scope.$on('reload', function(event, args) {
$scope.name = null;
$scope.entries = [];
$scope.message = null;
$scope.errorCount = 0;
$scope.timestamp = 0;
$scope.busy = false;
$scope.hasMore = true;
$scope.loadMoreEntries();
});
}]);
module.controller('ManageUsersCtrl', ['$scope', '$state', '$location', 'AdminUsersService',
function($scope, $state, $location, AdminUsersService) {
$scope.users = AdminUsersService.getAll();
$scope.selection = [];
$scope.gridOptions = {
data : 'users',
selectedItems : $scope.selection,
multiSelect : false,
showColumnMenu: true,
showFilter: true,
afterSelectionChange : function(item) {
$state.transitionTo('admin.useredit', {
_id : item.entity.id
});
}
};
$scope.addUser = function() {
$state.transitionTo('admin.useradd');
};
$scope.back = function() {
$location.path('/admin');
};
}]);
module.controller('ManageUserCtrl', ['$scope', '$state', '$stateParams', '$dialog', 'AdminUsersService',
function($scope, $state, $stateParams, $dialog, AdminUsersService) {
$scope.user = $stateParams._id ? AdminUsersService.get({
id : $stateParams._id
}) : {
enabled : true
};
$scope.alerts = [];
$scope.closeAlert = function(index) {
$scope.alerts.splice(index, 1);
};
var alertFunction = function(data) {
$scope.alerts.push({
msg : data.data,
type : 'error'
});
};
$scope.cancel = function() {
$state.transitionTo('admin.userlist');
};
$scope.save = function() {
$scope.alerts.splice(0, $scope.alerts.length);
AdminUsersService.save($scope.user, function() {
$state.transitionTo('admin.userlist');
}, alertFunction);
};
$scope.remove = function() {
var title = 'Delete user';
var msg = 'Delete user ' + $scope.user.name + ' ?';
var btns = [ {
result : 'cancel',
label : 'Cancel'
}, {
result : 'ok',
label : 'OK',
cssClass : 'btn-primary'
} ];
$dialog.messageBox(title, msg, btns).open().then(function(result) {
if (result == 'ok') {
AdminUsersService.remove({
id : $scope.user.id
}, function() {
$state.transitionTo('admin.userlist');
}, alertFunction);
}
});
};
}]);
module.controller('SettingsCtrl', ['$scope', '$location', 'SettingsService', 'AnalyticsService', 'ServerService',
function($scope, $location, SettingsService, AnalyticsService, ServerService) {
AnalyticsService.track();
$scope.ServerService = ServerService.get();
$scope.settingsService = SettingsService;
$scope.$watch('settingsService.settings', function(value) {
$scope.settings = angular.copy(value);
});
$scope.cancel = function() {
SettingsService.init(function() {
$location.path('/');
});
};
$scope.save = function() {
SettingsService.settings = $scope.settings;
SettingsService.save(function() {
window.location.href = window.location.href.substring(0, window.location.href.lastIndexOf('#'));
});
};
}]);
module.controller('ProfileCtrl', ['$scope', '$location', '$dialog', 'ProfileService', 'AnalyticsService',
function($scope, $location, $dialog, ProfileService, AnalyticsService) {
AnalyticsService.track();
$scope.user = ProfileService.get();
$scope.cancel = function() {
$location.path('/');
};
$scope.save = function() {
if (!$scope.profileForm.$valid) {
return;
}
var o = {
email : $scope.user.email,
password : $scope.user.password,
newApiKey : $scope.newApiKey
};
ProfileService.save(o, function() {
$location.path('/');
});
};
$scope.deleteAccount = function() {
var title = 'Delete account';
var msg = 'Delete your acount? There\'s no turning back!';
var btns = [ {
result : 'cancel',
label : 'Cancel'
}, {
result : 'ok',
label : 'OK',
cssClass : 'btn-primary'
} ];
$dialog.messageBox(title, msg, btns).open().then(function(result) {
if (result == 'ok') {
ProfileService.deleteAccount();
window.location.href = 'logout';
}
});
};
}]);
module.controller('ManageSettingsCtrl', ['$scope', '$location', '$state', 'AdminSettingsService',
function($scope, $location, $state, AdminSettingsService) {
$scope.settings = AdminSettingsService.get();
$scope.cancel = function() {
$location.path('/');
};
$scope.save = function() {
AdminSettingsService.save({}, $scope.settings, function() {
$location.path('/');
});
};
$scope.toUsers = function() {
$state.transitionTo('admin.userlist');
};
}]);
module.controller('HelpController', [ '$scope', 'CategoryService',
'AnalyticsService',
function($scope, CategoryService, AnalyticsService) {
AnalyticsService.track();
$scope.CategoryService = CategoryService;
$scope.categoryId = 'all';
} ]);
module.controller('FooterController', [ '$scope', function($scope) {
var baseUrl = window.location.href.substring(0, window.location.href.lastIndexOf('#'));
var hostname = window.location.hostname;
$scope.subToMeUrl = baseUrl + 'rest/feed/subscribe?url={feed}';
$scope.subToMeName = hostname.indexOf('www.commafeed.com') !== -1 ? 'CommaFeed' : 'CommaFeed (' + hostname + ')';
}]);