diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..53681b50 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "printWidth": 140, + "semi": false, + "tabWidth": 4, + "arrowParens": "avoid", + "endOfLine": "auto" +} diff --git a/src/main/app/api/index.html b/src/main/app/api/index.html index e78dbfa7..9bd7ed8d 100644 --- a/src/main/app/api/index.html +++ b/src/main/app/api/index.html @@ -1,86 +1,86 @@ - - Swagger UI - - - - - - - - - - - - - - - - - + + Swagger UI + + + + + + + + + + + + + + + + + - - - + - + $("#input_apiKey").change(function () { + var key = $("#input_apiKey")[0].value + log("key: " + key) + if (key && key.trim() != "") { + log("added key " + key) + window.authorizations.add("key", new ApiKeyAuthorization("api_key", key, "query")) + } + }) + window.swaggerUi.load() + }) + + - - + + -
 
-
- +
 
+
+ diff --git a/src/main/app/index.html b/src/main/app/index.html index 9da12ba3..c70705df 100644 --- a/src/main/app/index.html +++ b/src/main/app/index.html @@ -1,86 +1,86 @@ - -CommaFeed - - - - - - - - - - - - - - - - - - - - - - - - + + CommaFeed + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/app/js/controllers.js b/src/main/app/js/controllers.js index 44c30ded..efa72a3f 100644 --- a/src/main/app/js/controllers.js +++ b/src/main/app/js/controllers.js @@ -1,1536 +1,1722 @@ -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) { - // args.all - $rootScope.$broadcast('reload', args || {}); - }); - $rootScope.$on('emitEntrySearch', function(event, args) { - // args.keywords - $rootScope.$broadcast('entrySearch', args); - }); - $rootScope.$on('emitFeedSearch', function(event, args) { - $rootScope.$broadcast('feedSearch'); - }); -}]); - -module.controller('SubscribeCtrl', ['$scope', '$location', 'FeedService', 'CategoryService', 'MobileService', - function($scope, $location, FeedService, CategoryService, MobileService) { - - $scope.sub = { - categoryId : 'all' - }; - - $scope.CategoryService = CategoryService; - $scope.MobileService = MobileService; - - // 'ok', 'loading' or 'failed' - $scope.state = 'ok'; - $scope.urlChanged = function() { - if ($scope.sub.url && $scope.state != 'loading') { - $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; - $scope.stacktrace = null; - }, function(data) { - $scope.state = 'failed'; - $scope.sub.title = 'Loading failed. Invalid feed?'; - $scope.stacktrace = data.data; - }); - } - }; - - $scope.save = function() { - if ($scope.state != 'ok') { - return; - } - if (!$scope.sub.categoryId) { - return; - } - FeedService.subscribe($scope.sub, function() { - CategoryService.init(); - $location.path('/'); - }, function(data) { - $scope.state = 'failed'; - $scope.sub.title = 'ERROR: ' + data.data; - }); - }; - - $scope.back = function() { - $location.path('/'); - }; - }]); - -module.controller('NewCategoryCtrl', ['$scope', '$location', 'FeedService', 'CategoryService', 'MobileService', - function($scope, $location, FeedService, CategoryService, MobileService) { - - $scope.CategoryService = CategoryService; - $scope.MobileService = MobileService; - - $scope.cat = { - parentId : 'all' - }; - - $scope.saveCategory = function() { - CategoryService.add($scope.cat, function() { - CategoryService.init(); - }); - $location.path('/'); - }; - - $scope.back = function() { - $location.path('/'); - }; - }]); - -module.controller('ImportCtrl', ['$scope', '$location', 'FeedService', 'CategoryService', 'MobileService', - function($scope, $location, FeedService, CategoryService, MobileService) { - - $scope.back = function() { - $location.path('/'); - }; - }]); - -module.controller('CategoryTreeCtrl', [ - '$scope', - '$timeout', - '$stateParams', - '$window', - '$location', - '$state', - '$route', - 'CategoryService', - 'AnalyticsService', - 'EntryService', - 'MobileService', - function($scope, $timeout, $stateParams, $window, $location, $state, $route, CategoryService, AnalyticsService, EntryService, - MobileService) { - - $scope.selectedType = $stateParams._type; - $scope.selectedId = $stateParams._id; - - $scope.EntryService = EntryService; - $scope.MobileService = MobileService; - - $scope.starred = { - id : 'starred', - name : 'Starred' - }; - - $scope.tags = []; - $scope.$watch('EntryService.tags', function(newValue, oldValue) { - if (newValue) { - $scope.tags = []; - _.each(newValue, function(e) { - $scope.tags.push({ - id : e, - name : e, - isTag : true - }); - }); - } - }, true); - - $scope.$on('$stateChangeSuccess', function() { - $scope.selectedType = $stateParams._type; - $scope.selectedId = $stateParams._id; - }); - - $scope.resizeCallback = function(event, ui) { - $('.main-content').css('margin-left', $(ui.element).outerWidth(true) + 'px'); - }; - - $timeout(function refreshTree() { - AnalyticsService.track(); - CategoryService.refresh(function() { - $timeout(refreshTree, 30000); - }, function() { - $timeout(refreshTree, 30000); - }); - }, 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) { - Tinycon.setBubble(value); - }); - - 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; - } - } - } - }; - - var getCurrentIndex = function(id, type, flat) { - var index = -1; - for (var i = 0; i < flat.length; i++) { - var node = flat[i]; - if (node[0] == id && node[1] == type) { - index = i; - break; - } - } - return index; - }; - - var openNextNode = function() { - var f = CategoryService.flatAll; - var current = getCurrentIndex($scope.selectedId, $scope.selectedType, f); - current++; - if (current < f.length) { - $state.transitionTo('feeds.view', { - _type : f[current][1], - _id : f[current][0] - }); - } - }; - - var openPreviousNode = function() { - var f = CategoryService.flatAll; - var current = getCurrentIndex($scope.selectedId, $scope.selectedType, f); - current--; - if (current >= 0) { - $state.transitionTo('feeds.view', { - _type : f[current][1], - _id : f[current][0] - }); - } - }; - - Mousetrap.bind('shift+j', function(e) { - $scope.$apply(function() { - openNextNode(); - }); - return false; - }); - Mousetrap.bind('shift+n', function(e) { - $scope.$apply(function() { - openNextNode(); - }); - return false; - }); - - Mousetrap.bind('shift+p', function(e) { - $scope.$apply(function() { - openPreviousNode(); - }); - return false; - }); - Mousetrap.bind('shift+k', function(e) { - $scope.$apply(function() { - openPreviousNode(); - }); - return false; - }); - - $scope.$on('mark', function(event, args) { - mark($scope.CategoryService.subscriptions, args.entry); - }); - }]); - -module.controller('FeedDetailsCtrl', ['$scope', '$state', '$stateParams', 'FeedService', 'CategoryService', 'ProfileService', - function($scope, $state, $stateParams, FeedService, CategoryService, ProfileService) { - - $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 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; - $scope.error = null; - FeedService.modify({ - id : sub.id, - name : sub.name, - position : sub.position, - categoryId : sub.categoryId, - filter : sub.filter - }, function() { - CategoryService.init(); - $state.transitionTo('feeds.view', { - _id : 'all', - _type : 'category' - }); - }, function(e) { - $scope.error = e.data; - }); - }; - }]); - -module.controller('CategoryDetailsCtrl', ['$scope', '$state', '$stateParams', 'FeedService', 'CategoryService', 'ProfileService', - function($scope, $state, $stateParams, FeedService, CategoryService, ProfileService) { - $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, - position : cat.orig.position, - 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; - 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, - position : cat.position, - parentId : cat.parentId - }, function() { - CategoryService.init(); - $state.transitionTo('feeds.view', { - _id : 'all', - _type : 'category' - }); - }); - }; - }]); - -module.controller('TagDetailsCtrl', ['$scope', '$state', '$stateParams', 'FeedService', 'CategoryService', 'ProfileService', - function($scope, $state, $stateParams, FeedService, CategoryService, ProfileService) { - $scope.CategoryService = CategoryService; - $scope.user = ProfileService.get(); - - $scope.tag = $stateParams._id; - - $scope.back = function() { - $state.transitionTo('feeds.view', { - _id : $scope.tag, - _type : 'tag' - }); - }; - }]); - -module.controller('ToolbarCtrl', [ - '$scope', - '$state', - '$stateParams', - '$route', - '$location', - 'SettingsService', - 'EntryService', - 'ProfileService', - 'AnalyticsService', - 'ServerService', - 'FeedService', - 'MobileService', - function($scope, $state, $stateParams, $route, $location, SettingsService, EntryService, ProfileService, AnalyticsService, - ServerService, FeedService, MobileService) { - - $scope.keywords = $location.search().q; - $scope.session = ProfileService.get(); - $scope.ServerService = ServerService.get(); - $scope.settingsService = SettingsService; - $scope.MobileService = MobileService; - - $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() { - $scope.$emit('emitReload'); - }; - - $scope.refreshAll = function() { - $scope.$emit('emitReload', { - all : true - }); - }; - - var markAll = function(olderThan) { - $scope.$emit('emitMarkAll', { - type : $stateParams._type, - id : $stateParams._id, - olderThan : olderThan, - keywords : $location.search().q, - read : true - }); - }; - - $scope.markAllAsRead = function() { - markAll(); - }; - - $scope.markAll12Hours = function() { - markAll(new Date().getTime() - 43200000); - }; - - $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.search = function() { - var keywords = this.keywords; - $location.search('q', keywords); - $scope.$emit('emitEntrySearch', { - keywords : keywords - }); - }; - $scope.showButtons = function() { - return !$stateParams._keywords; - }; - - $scope.toggleOrder = function() { - var settings = $scope.settingsService.settings; - settings.readingOrder = settings.readingOrder == 'desc' ? 'asc' : 'desc'; - }; - - $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('FeedSearchCtrl', ['$scope', '$state', '$filter', '$timeout', 'CategoryService', - function($scope, $state, $filter, $timeout, CategoryService) { - $scope.feedSearchModal = false; - $scope.filter = null; - $scope.focus = null; - $scope.CategoryService = CategoryService; - - $scope.$watch('filter', function() { - $timeout(function() { - if ($scope.filtered) { - $scope.focus = $scope.filtered[0]; - } - }, 0); - }); - - var getCurrentIndex = function() { - var index = -1; - - if (!$scope.focus) { - return index; - } - - var filtered = $scope.filtered; - for (var i = 0; i < filtered.length; i++) { - if ($scope.focus.id == filtered[i].id) { - index = i; - break; - } - } - return index; - }; - - $scope.focusPrevious = function(e) { - var index = getCurrentIndex(); - if (index === 0) { - return; - } - $scope.focus = $scope.filtered[index - 1]; - - e.stopPropagation(); - e.preventDefault(); - }; - - $scope.focusNext = function(e) { - var index = getCurrentIndex(); - if (index == ($scope.filtered.length - 1)) { - return; - } - $scope.focus = $scope.filtered[index + 1]; - - e.stopPropagation(); - e.preventDefault(); - }; - - $scope.openFocused = function() { - if (!$scope.focus) { - return; - } - $scope.goToFeed($scope.focus.id); - }; - - $scope.goToFeed = function(id) { - $scope.close(); - $state.transitionTo('feeds.view', { - _type : 'feed', - _id : id - }); - }; - - $scope.open = function() { - $scope.filter = null; - $scope.feedSearchModal = true; - }; - - $scope.close = function() { - $scope.feedSearchModal = false; - }; - - Mousetrap.bind('g a', function(e) { - $scope.$apply(function() { - $state.transitionTo('feeds.view', { - _type : 'category', - _id : 'all' - }); - }); - return false; - }); - - Mousetrap.bind('g s', function(e) { - $scope.$apply(function() { - $state.transitionTo('feeds.view', { - _type : 'category', - _id : 'starred' - }); - }); - return false; - }); - - Mousetrap.bind('g u', function(e) { - $scope.$apply(function() { - $scope.open(); - }); - return false; - }); - - $scope.$on('feedSearch', function() { - $scope.open(); - }); - - }]); - -module.controller('FeedListCtrl', [ - '$scope', - '$stateParams', - '$http', - '$route', - '$state', - '$window', - '$timeout', - '$location', - 'EntryService', - 'SettingsService', - 'FeedService', - 'CategoryService', - 'AnalyticsService', - 'MobileService', - function($scope, $stateParams, $http, $route, $state, $window, $timeout, $location, EntryService, SettingsService, FeedService, - CategoryService, AnalyticsService, MobileService) { - - $window = angular.element($window); - AnalyticsService.track(); - - $scope.keywords = $location.search().q; - - $scope.selectedType = $stateParams._type; - $scope.selectedId = $stateParams._id; - - $scope.name = null; - $scope.message = null; - $scope.errorCount = 0; - $scope.timestamp = 0; - $scope.entries = []; - $scope.ignored_read_status = false; - $scope.font_size = 0; - - $scope.settingsService = SettingsService; - $scope.MobileService = MobileService; - $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.$watch('settingsService.settings.readingOrder', function(newValue, oldValue) { - if (newValue && oldValue && newValue != oldValue) { - $scope.$emit('emitReload'); - } - }); - $scope.$watch('settingsService.settings.theme', function(newValue, oldValue) { - if (newValue) { - angular.element('html').attr('id', 'theme-' + newValue); - } - }); - - $scope.limit = SettingsService.settings.viewMode == 'title' ? 10 : 5; - $scope.busy = false; - $scope.hasMore = true; - - $scope.loadMoreEntries = function() { - if (!$scope.hasMore) - return; - if ($scope.busy) - return; - $scope.busy = true; - - var limit = $scope.limit; - - var read_shown = SettingsService.settings.readingMode === 'all' || $scope.ignored_read_status; - var offset = read_shown ? $scope.entries.length : _.where($scope.entries, { - read : false - }).length; - 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++) { - var entry = data.entries[i]; - if (!_.some($scope.entries, { - id : entry.id - })) { - $scope.entries.push(entry); - } - } - $scope.name = data.name; - $scope.message = data.message; - $scope.errorCount = data.errorCount; - $scope.timestamp = data.timestamp; - $scope.busy = false; - $scope.hasMore = data.hasMore; - $scope.feedLink = data.feedLink; - $scope.ignored_read_status = data.ignoredReadStatus; - }; - - var data = { - id : $scope.selectedId, - readType : $scope.keywords ? 'all' : $scope.settingsService.settings.readingMode, - order : $scope.settingsService.settings.readingOrder, - offset : offset, - limit : limit, - keywords : $scope.keywords - }; - if ($scope.selectedType == 'feed') { - FeedService.entries(data, callback); - } else if ($scope.selectedType == 'category') { - CategoryService.entries(data, callback); - } else if ($scope.selectedType == 'tag') { - data.tag = data.id; - data.id = 'all'; - CategoryService.entries(data, callback); - } - }; - - var watch_scrolling = true; - var watch_current = true; - - $scope.$watch('current', function(newValue, oldValue) { - if (!watch_current) { - return; - } - if (newValue && newValue !== oldValue) { - var force = $scope.navigationMode == 'keyboard'; - - // timeout here to execute after dom update - $timeout(function() { - var docTop = $(window).scrollTop(); - var docBottom = docTop + $(window).height(); - - var elem = $('#entry_' + newValue.id); - var elemTop = elem.offset().top; - var elemBottom = elemTop + elem.height(); - - if (!force && (elemTop > docTop) && (elemBottom < docBottom)) { - // element is entirely visible - return; - } else { - var scrollTop = elemTop - $('#toolbar').outerHeight(); - var speed = SettingsService.settings.scrollSpeed; - watch_scrolling = false; - $('html, body').animate({ - scrollTop : scrollTop - }, speed, 'swing', function() { - watch_scrolling = true; - }); - } - }); - } - }); - - var scrollHandler = function() { - if (!watch_scrolling || _.size($scope.entries) === 0) { - return; - } - - $scope.navigationMode = 'scroll'; - if (SettingsService.settings.viewMode == 'expanded') { - var w = $(window); - var docTop = w.scrollTop(); - - var current = null; - for (var i = 0; i < $scope.entries.length; i++) { - var entry = $scope.entries[i]; - var e = $('#entry_' + entry.id); - if (e.offset().top + e.height() > docTop + $('#toolbar').outerHeight()) { - current = entry; - break; - } - } - - var previous = $scope.current; - $scope.current = current; - if (previous != current) { - if (SettingsService.settings.scrollMarks) { - $scope.mark($scope.current, true); - } - watch_current = false; - $scope.$apply(); - watch_current = true; - } - } - }; - var scrollListener = _.throttle(scrollHandler, 200); - $window.on('scroll', scrollListener); - $scope.$on('$destroy', function() { - return $window.off('scroll', scrollListener); - }); - - $scope.goToFeed = function(id) { - $state.transitionTo('feeds.view', { - _type : 'feed', - _id : id - }); - }; - - $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, - keywords : $location.search().q, - read : true - }, function() { - CategoryService.refresh(function() { - $scope.$emit('emitReload'); - }); - }); - }; - - $scope.markUpTo = function(entry) { - var entries = []; - for (var i = 0; i < $scope.entries.length; i++) { - var e = $scope.entries[i]; - if (!e.read) { - entries.push({ - id : e.id, - read : true - }); - e.read = true; - } - if (e == entry) { - break; - } - } - EntryService.markMultiple({ - requests : entries - }, function() { - CategoryService.refresh(); - }); - }; - - $scope.star = function(entry, star, event) { - if (event) { - event.preventDefault(); - event.stopPropagation(); - } - if (entry.starred != star) { - entry.starred = star; - EntryService.star({ - id : entry.id, - feedId : entry.feedId, - starred : star - }); - } - }; - - var getCurrentIndex = function() { - var index = -1; - if ($scope.current) { - for (var i = 0; i < $scope.entries.length; i++) { - if ($scope.current == $scope.entries[i]) { - index = i; - break; - } - } - } - return index; - }; - - var getNextEntry = function() { - var index = getCurrentIndex(); - if (index >= 0) { - index = index + 1; - if (index < $scope.entries.length) { - return $scope.entries[index]; - } - } else if ($scope.entries.length > 0) { - return $scope.entries[0]; - } - return null; - }; - - var getPreviousEntry = function() { - var index = getCurrentIndex(); - if (index >= 1) { - return $scope.entries[index - 1]; - } - return null; - }; - - var openNextEntry = function(event) { - var entry = getNextEntry(); - openEntry(entry, event); - }; - - var openPreviousEntry = function(event) { - var entry = getPreviousEntry(); - openEntry(entry, event); - }; - - var focusNextEntry = function(event) { - var entry = getNextEntry(); - - if (event) { - event.preventDefault(); - event.stopPropagation(); - } - - if (entry) { - $scope.current = entry; - } - }; - - var focusPreviousEntry = function(event) { - var entry = getPreviousEntry(); - - if (event) { - event.preventDefault(); - event.stopPropagation(); - } - - if (entry) { - $scope.current = entry; - } - }; - - $scope.isOpen = SettingsService.settings.viewMode == 'expanded'; - - var openEntry = function(entry, event) { - - if (event) { - event.preventDefault(); - event.stopPropagation(); - } - - if (!entry) { - return; - } - - 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 (getCurrentIndex() == $scope.entries.length - 1) { - $scope.loadMoreEntries(); - } - }; - - $scope.entryClicked = function(entry, event) { - - if (event && event.which === 3) { - // right click - return; - } - if (!event || (!event.ctrlKey && event.which != 2)) { - $scope.navigationMode = 'click'; - openEntry(entry, event); - } 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(); - } - }; - - // keyboard shortcuts - Mousetrap.bind('j', function(e) { - $scope.$apply(function() { - $scope.navigationMode = 'keyboard'; - openNextEntry(e); - }); - return false; - }); - Mousetrap.bind('n', function(e) { - $scope.$apply(function() { - $scope.navigationMode = 'keyboard'; - focusNextEntry(e); - }); - return false; - }); - Mousetrap.bind('k', function(e) { - $scope.$apply(function() { - $scope.navigationMode = 'keyboard'; - openPreviousEntry(e); - }); - return false; - }); - Mousetrap.bind('p', function(e) { - $scope.$apply(function() { - $scope.navigationMode = 'keyboard'; - focusPreviousEntry(e); - }); - return false; - }); - Mousetrap.bind('o', function(e) { - $scope.$apply(function() { - $scope.navigationMode = 'keyboard'; - if ($scope.current) { - openEntry($scope.current, e); - } - }); - return false; - }); - Mousetrap.bind('enter', function(e) { - $scope.$apply(function() { - $scope.navigationMode = 'keyboard'; - if ($scope.current) { - openEntry($scope.current, e); - } - }); - }); - Mousetrap.bind('r', function(e) { - $scope.$apply(function() { - $scope.$emit('emitReload'); - }); - return false; - }); - Mousetrap.bind('v', function(e) { - if ($scope.current) { - $scope.mark($scope.current, true); - window.open($scope.current.url); - } - return false; - }); - Mousetrap.bind('b', function(e) { - if ($scope.current) { - $scope.mark($scope.current, true); - - var url = $scope.current.url; - var a = document.createElement('a'); - a.href = url; - var evt = document.createEvent('MouseEvents'); - evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, true, false, false, true, 0, null); - a.dispatchEvent(evt); - } - return false; - }); - Mousetrap.bind('s', function(e) { - $scope.$apply(function() { - if ($scope.current) { - $scope.star($scope.current, !$scope.current.starred); - } - }); - return false; - }); - Mousetrap.bind('m', function(e) { - $scope.$apply(function() { - if ($scope.current) { - $scope.mark($scope.current, !$scope.current.read); - } - }); - return false; - }); - Mousetrap.bind('shift+a', function(e) { - $scope.$apply(function() { - $scope.markAll(); - }); - return false; - }); - - Mousetrap.bind('+', function(e) { - $scope.$apply(function() { - $scope.font_size = Math.min($scope.font_size + 1, 5); - }); - return false; - }); - - Mousetrap.bind('-', function(e) { - $scope.$apply(function() { - $scope.font_size = Math.max($scope.font_size - 1, 0); - }); - return false; - }); - - Mousetrap.bind('space', function(e) { - if (!$scope.current) { - $scope.$apply(function() { - $scope.navigationMode = 'keyboard'; - openNextEntry(e); - }); - } else if (!$scope.isOpen) { - $scope.$apply(function() { - $scope.navigationMode = 'keyboard'; - if ($scope.current) { - openEntry($scope.current, e); - } - }); - } else { - var docTop = $(window).scrollTop(); - var docBottom = docTop + $(window).height(); - - var elem = $('#entry_' + $scope.current.id); - var elemTop = elem.offset().top; - var elemBottom = elemTop + elem.height(); - - var bottomVisible = elemBottom < docBottom; - if (bottomVisible) { - $scope.$apply(function() { - $scope.navigationMode = 'keyboard'; - openNextEntry(e); - }); - } - } - }); - - Mousetrap.bind('shift+space', function(e) { - if (!$scope.current) { - return; - } else if (!$scope.isOpen) { - $scope.$apply(function() { - $scope.navigationMode = 'keyboard'; - if ($scope.current) { - openEntry($scope.current, e); - } - }); - } else { - var docTop = $(window).scrollTop(); - - var elem = $('#entry_' + $scope.current.id); - var elemTop = elem.offset().top; - - var topVisible = elemTop > docTop; - if (topVisible) { - $scope.$apply(function() { - $scope.navigationMode = 'keyboard'; - openPreviousEntry(e); - }); - } - } - }); - - Mousetrap.bind('f', function(e) { - $('body').toggleClass('full-screen'); - $('.main-content').css('margin-left', ''); - return false; - }); - - Mousetrap.bind('?', function(e) { - $scope.$apply(function() { - $scope.shortcutsModal = true; - }); - return false; - }); - - $scope.$on('previousEntry', function(event, args) { - $scope.navigationMode = 'keyboard'; - openPreviousEntry(); - }); - $scope.$on('nextEntry', function(event, args) { - $scope.navigationMode = 'keyboard'; - openNextEntry(); - }); - $scope.$on('markAll', function(event, args) { - $scope.markAll(args.olderThan); - }); - - var reload = function(all, keywords) { - $scope.keywords = keywords; - $location.search('q', keywords); - delete $scope.current; - $scope.name = null; - $scope.entries = []; - $scope.message = null; - $scope.errorCount = 0; - $scope.timestamp = 0; - $scope.busy = false; - $scope.hasMore = true; - $scope.loadMoreEntries(); - - if (all) { - FeedService.refreshAll(); - } else if ($scope.selectedType == 'feed') { - FeedService.refresh({ - id : $stateParams._id - }); - } - }; - - $scope.$on('entrySearch', function(event, args) { - reload(null, args.keywords); - }); - - $scope.$on('reload', function(event, args) { - reload(args.all, null); - }); - }]); - -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, - columnDefs : [{ - field : 'id', - displayName : 'ID' - }, { - field : 'name', - displayName : 'Name' - }, { - field : 'email', - cellClass : 'E-Mail' - }, { - field : 'created', - cellClass : 'Created', - cellFilter : 'entryDate' - }, { - field : 'lastLogin', - cellClass : 'Last login', - cellFilter : 'entryDate' - }, { - field : 'admin', - cellClass : 'Admin' - }, { - field : 'enabled', - cellClass : 'Enabled' - }], - - 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', 'AdminUsersService', - function($scope, $state, $stateParams, 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() { - AdminUsersService.remove({ - id : $scope.user.id - }, function() { - $state.transitionTo('admin.userlist'); - }, alertFunction); - }; - }]); - -module.controller('SettingsCtrl', ['$scope', '$location', 'SettingsService', 'AnalyticsService', 'LangService', - function($scope, $location, SettingsService, AnalyticsService, LangService) { - - AnalyticsService.track(); - - $scope.langs = LangService.langs; - - $scope.themes = ['default', 'bootstrap', 'dark', 'ebraminio', 'MRACHINI', 'nightsky', 'svetla', 'third']; - - $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', 'ProfileService', 'AnalyticsService', - function($scope, $location, 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() { - 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'); - }; - $scope.toMetrics = function() { - $state.transitionTo('admin.metrics'); - }; - }]); - -module.controller('HelpController', ['$scope', 'CategoryService', 'AnalyticsService', 'ServerService', - function($scope, CategoryService, AnalyticsService, ServerService) { - - AnalyticsService.track(); - $scope.CategoryService = CategoryService; - $scope.infos = ServerService.get(); - $scope.categoryId = 'all'; - $scope.order = 'desc'; - $scope.baseUrl = window.location.href.substring(0, window.location.href.lastIndexOf('#')); - - }]); - -module.controller('FooterController', ['$scope', '$sce', function($scope, $sce) { - var baseUrl = window.location.href.substring(0, window.location.href.lastIndexOf('#')); - var hostname = window.location.hostname; - var url = baseUrl + 'rest/feed/subscribe?url={feed}'; - var name = hostname.indexOf('www.commafeed.com') !== -1 ? 'CommaFeed' : 'CommaFeed (' + hostname + ')'; - var subToMeUrl = 'https://www.subtome.com/register-no-ui.html?name=' + name + '&url=' + url; - $scope.subToMeUrl = $sce.trustAsResourceUrl(subToMeUrl); - -}]); - -module.controller('MetricsCtrl', ['$scope', 'AdminMetricsService', function($scope, AdminMetricsService) { - $scope.metrics = AdminMetricsService.get(); -}]); - -module.controller('LoginCtrl', ['$scope', '$location', '$timeout', 'SessionService', 'ServerService', - function($scope, $location, $timeout, SessionService, ServerService) { - $scope.model = {}; - $scope.recovery_model = {}; - $scope.recovery = false; - $scope.recovery_enabled = false; - - ServerService.get(function(data) { - $scope.recovery_enabled = data.smtpEnabled; - }); - - var login = function(model) { - var success = function(data) { - window.location.href = window.location.href.substring(0, window.location.href.lastIndexOf('#')); - }; - var error = function(data) { - $scope.message = data.data; - }; - SessionService.login({ - name : model.name, - password : model.password - }, success, error); - } - $scope.demoLogin = function() { - login({ - name : 'demo', - password : 'demo' - }); - }; - - $scope.login = function() { - // autofilled fields do not trigger model update, do it manually - $('input[ng-model]').trigger('input'); - login($scope.model); - }; - - $scope.toggleRecovery = function() { - $scope.recovery = !$scope.recovery; - }; - - var recovery_success = function(data) { - $scope.recovery_message = "Email has ben sent. Check your inbox."; - }; - var recovery_error = function(data) { - $scope.recovery_message = data.data; - }; - $scope.recover = function() { - SessionService.passwordReset({ - email : $scope.recovery_model.email - }, recovery_success, recovery_error); - } - }]); - -module.controller('RegisterCtrl', ['$scope', '$location', 'SessionService', 'ServerService', - function($scope, $location, SessionService, ServerService) { - $scope.ServerService = ServerService.get(); - $scope.model = {}; - - $scope.register = function() { - var success = function(data) { - window.location.href = window.location.href.substring(0, window.location.href.lastIndexOf('#')); - }; - var error = function(data) { - $scope.messages = data.data.errors; - }; - SessionService.register($scope.model, success, error); - } - }]); +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) { + // args.all + $rootScope.$broadcast("reload", args || {}) + }) + $rootScope.$on("emitEntrySearch", function (event, args) { + // args.keywords + $rootScope.$broadcast("entrySearch", args) + }) + $rootScope.$on("emitFeedSearch", function (event, args) { + $rootScope.$broadcast("feedSearch") + }) + }, +]) + +module.controller("SubscribeCtrl", [ + "$scope", + "$location", + "FeedService", + "CategoryService", + "MobileService", + function ($scope, $location, FeedService, CategoryService, MobileService) { + $scope.sub = { + categoryId: "all", + } + + $scope.CategoryService = CategoryService + $scope.MobileService = MobileService + + // 'ok', 'loading' or 'failed' + $scope.state = "ok" + $scope.urlChanged = function () { + if ($scope.sub.url && $scope.state != "loading") { + $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 + $scope.stacktrace = null + }, + function (data) { + $scope.state = "failed" + $scope.sub.title = "Loading failed. Invalid feed?" + $scope.stacktrace = data.data + } + ) + } + } + + $scope.save = function () { + if ($scope.state != "ok") { + return + } + if (!$scope.sub.categoryId) { + return + } + FeedService.subscribe( + $scope.sub, + function () { + CategoryService.init() + $location.path("/") + }, + function (data) { + $scope.state = "failed" + $scope.sub.title = "ERROR: " + data.data + } + ) + } + + $scope.back = function () { + $location.path("/") + } + }, +]) + +module.controller("NewCategoryCtrl", [ + "$scope", + "$location", + "FeedService", + "CategoryService", + "MobileService", + function ($scope, $location, FeedService, CategoryService, MobileService) { + $scope.CategoryService = CategoryService + $scope.MobileService = MobileService + + $scope.cat = { + parentId: "all", + } + + $scope.saveCategory = function () { + CategoryService.add($scope.cat, function () { + CategoryService.init() + }) + $location.path("/") + } + + $scope.back = function () { + $location.path("/") + } + }, +]) + +module.controller("ImportCtrl", [ + "$scope", + "$location", + "FeedService", + "CategoryService", + "MobileService", + function ($scope, $location, FeedService, CategoryService, MobileService) { + $scope.back = function () { + $location.path("/") + } + }, +]) + +module.controller("CategoryTreeCtrl", [ + "$scope", + "$timeout", + "$stateParams", + "$window", + "$location", + "$state", + "$route", + "CategoryService", + "AnalyticsService", + "EntryService", + "MobileService", + function ( + $scope, + $timeout, + $stateParams, + $window, + $location, + $state, + $route, + CategoryService, + AnalyticsService, + EntryService, + MobileService + ) { + $scope.selectedType = $stateParams._type + $scope.selectedId = $stateParams._id + + $scope.EntryService = EntryService + $scope.MobileService = MobileService + + $scope.starred = { + id: "starred", + name: "Starred", + } + + $scope.tags = [] + $scope.$watch( + "EntryService.tags", + function (newValue, oldValue) { + if (newValue) { + $scope.tags = [] + _.each(newValue, function (e) { + $scope.tags.push({ + id: e, + name: e, + isTag: true, + }) + }) + } + }, + true + ) + + $scope.$on("$stateChangeSuccess", function () { + $scope.selectedType = $stateParams._type + $scope.selectedId = $stateParams._id + }) + + $scope.resizeCallback = function (event, ui) { + $(".main-content").css("margin-left", $(ui.element).outerWidth(true) + "px") + } + + $timeout(function refreshTree() { + AnalyticsService.track() + CategoryService.refresh( + function () { + $timeout(refreshTree, 30000) + }, + function () { + $timeout(refreshTree, 30000) + } + ) + }, 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) { + Tinycon.setBubble(value) + }) + + 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 + } + } + } + } + + var getCurrentIndex = function (id, type, flat) { + var index = -1 + for (var i = 0; i < flat.length; i++) { + var node = flat[i] + if (node[0] == id && node[1] == type) { + index = i + break + } + } + return index + } + + var openNextNode = function () { + var f = CategoryService.flatAll + var current = getCurrentIndex($scope.selectedId, $scope.selectedType, f) + current++ + if (current < f.length) { + $state.transitionTo("feeds.view", { + _type: f[current][1], + _id: f[current][0], + }) + } + } + + var openPreviousNode = function () { + var f = CategoryService.flatAll + var current = getCurrentIndex($scope.selectedId, $scope.selectedType, f) + current-- + if (current >= 0) { + $state.transitionTo("feeds.view", { + _type: f[current][1], + _id: f[current][0], + }) + } + } + + Mousetrap.bind("shift+j", function (e) { + $scope.$apply(function () { + openNextNode() + }) + return false + }) + Mousetrap.bind("shift+n", function (e) { + $scope.$apply(function () { + openNextNode() + }) + return false + }) + + Mousetrap.bind("shift+p", function (e) { + $scope.$apply(function () { + openPreviousNode() + }) + return false + }) + Mousetrap.bind("shift+k", function (e) { + $scope.$apply(function () { + openPreviousNode() + }) + return false + }) + + $scope.$on("mark", function (event, args) { + mark($scope.CategoryService.subscriptions, args.entry) + }) + }, +]) + +module.controller("FeedDetailsCtrl", [ + "$scope", + "$state", + "$stateParams", + "FeedService", + "CategoryService", + "ProfileService", + function ($scope, $state, $stateParams, FeedService, CategoryService, ProfileService) { + $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 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 + $scope.error = null + FeedService.modify( + { + id: sub.id, + name: sub.name, + position: sub.position, + categoryId: sub.categoryId, + filter: sub.filter, + }, + function () { + CategoryService.init() + $state.transitionTo("feeds.view", { + _id: "all", + _type: "category", + }) + }, + function (e) { + $scope.error = e.data + } + ) + } + }, +]) + +module.controller("CategoryDetailsCtrl", [ + "$scope", + "$state", + "$stateParams", + "FeedService", + "CategoryService", + "ProfileService", + function ($scope, $state, $stateParams, FeedService, CategoryService, ProfileService) { + $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, + position: cat.orig.position, + 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 + 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, + position: cat.position, + parentId: cat.parentId, + }, + function () { + CategoryService.init() + $state.transitionTo("feeds.view", { + _id: "all", + _type: "category", + }) + } + ) + } + }, +]) + +module.controller("TagDetailsCtrl", [ + "$scope", + "$state", + "$stateParams", + "FeedService", + "CategoryService", + "ProfileService", + function ($scope, $state, $stateParams, FeedService, CategoryService, ProfileService) { + $scope.CategoryService = CategoryService + $scope.user = ProfileService.get() + + $scope.tag = $stateParams._id + + $scope.back = function () { + $state.transitionTo("feeds.view", { + _id: $scope.tag, + _type: "tag", + }) + } + }, +]) + +module.controller("ToolbarCtrl", [ + "$scope", + "$state", + "$stateParams", + "$route", + "$location", + "SettingsService", + "EntryService", + "ProfileService", + "AnalyticsService", + "ServerService", + "FeedService", + "MobileService", + function ( + $scope, + $state, + $stateParams, + $route, + $location, + SettingsService, + EntryService, + ProfileService, + AnalyticsService, + ServerService, + FeedService, + MobileService + ) { + $scope.keywords = $location.search().q + $scope.session = ProfileService.get() + $scope.ServerService = ServerService.get() + $scope.settingsService = SettingsService + $scope.MobileService = MobileService + + $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 () { + $scope.$emit("emitReload") + } + + $scope.refreshAll = function () { + $scope.$emit("emitReload", { + all: true, + }) + } + + var markAll = function (olderThan) { + $scope.$emit("emitMarkAll", { + type: $stateParams._type, + id: $stateParams._id, + olderThan: olderThan, + keywords: $location.search().q, + read: true, + }) + } + + $scope.markAllAsRead = function () { + markAll() + } + + $scope.markAll12Hours = function () { + markAll(new Date().getTime() - 43200000) + } + + $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.search = function () { + var keywords = this.keywords + $location.search("q", keywords) + $scope.$emit("emitEntrySearch", { + keywords: keywords, + }) + } + $scope.showButtons = function () { + return !$stateParams._keywords + } + + $scope.toggleOrder = function () { + var settings = $scope.settingsService.settings + settings.readingOrder = settings.readingOrder == "desc" ? "asc" : "desc" + } + + $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("FeedSearchCtrl", [ + "$scope", + "$state", + "$filter", + "$timeout", + "CategoryService", + function ($scope, $state, $filter, $timeout, CategoryService) { + $scope.feedSearchModal = false + $scope.filter = null + $scope.focus = null + $scope.CategoryService = CategoryService + + $scope.$watch("filter", function () { + $timeout(function () { + if ($scope.filtered) { + $scope.focus = $scope.filtered[0] + } + }, 0) + }) + + var getCurrentIndex = function () { + var index = -1 + + if (!$scope.focus) { + return index + } + + var filtered = $scope.filtered + for (var i = 0; i < filtered.length; i++) { + if ($scope.focus.id == filtered[i].id) { + index = i + break + } + } + return index + } + + $scope.focusPrevious = function (e) { + var index = getCurrentIndex() + if (index === 0) { + return + } + $scope.focus = $scope.filtered[index - 1] + + e.stopPropagation() + e.preventDefault() + } + + $scope.focusNext = function (e) { + var index = getCurrentIndex() + if (index == $scope.filtered.length - 1) { + return + } + $scope.focus = $scope.filtered[index + 1] + + e.stopPropagation() + e.preventDefault() + } + + $scope.openFocused = function () { + if (!$scope.focus) { + return + } + $scope.goToFeed($scope.focus.id) + } + + $scope.goToFeed = function (id) { + $scope.close() + $state.transitionTo("feeds.view", { + _type: "feed", + _id: id, + }) + } + + $scope.open = function () { + $scope.filter = null + $scope.feedSearchModal = true + } + + $scope.close = function () { + $scope.feedSearchModal = false + } + + Mousetrap.bind("g a", function (e) { + $scope.$apply(function () { + $state.transitionTo("feeds.view", { + _type: "category", + _id: "all", + }) + }) + return false + }) + + Mousetrap.bind("g s", function (e) { + $scope.$apply(function () { + $state.transitionTo("feeds.view", { + _type: "category", + _id: "starred", + }) + }) + return false + }) + + Mousetrap.bind("g u", function (e) { + $scope.$apply(function () { + $scope.open() + }) + return false + }) + + $scope.$on("feedSearch", function () { + $scope.open() + }) + }, +]) + +module.controller("FeedListCtrl", [ + "$scope", + "$stateParams", + "$http", + "$route", + "$state", + "$window", + "$timeout", + "$location", + "EntryService", + "SettingsService", + "FeedService", + "CategoryService", + "AnalyticsService", + "MobileService", + function ( + $scope, + $stateParams, + $http, + $route, + $state, + $window, + $timeout, + $location, + EntryService, + SettingsService, + FeedService, + CategoryService, + AnalyticsService, + MobileService + ) { + $window = angular.element($window) + AnalyticsService.track() + + $scope.keywords = $location.search().q + + $scope.selectedType = $stateParams._type + $scope.selectedId = $stateParams._id + + $scope.name = null + $scope.message = null + $scope.errorCount = 0 + $scope.timestamp = 0 + $scope.entries = [] + $scope.ignored_read_status = false + $scope.font_size = 0 + + $scope.settingsService = SettingsService + $scope.MobileService = MobileService + $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.$watch("settingsService.settings.readingOrder", function (newValue, oldValue) { + if (newValue && oldValue && newValue != oldValue) { + $scope.$emit("emitReload") + } + }) + $scope.$watch("settingsService.settings.theme", function (newValue, oldValue) { + if (newValue) { + angular.element("html").attr("id", "theme-" + newValue) + } + }) + + $scope.limit = SettingsService.settings.viewMode == "title" ? 10 : 5 + $scope.busy = false + $scope.hasMore = true + + $scope.loadMoreEntries = function () { + if (!$scope.hasMore) return + if ($scope.busy) return + $scope.busy = true + + var limit = $scope.limit + + var read_shown = SettingsService.settings.readingMode === "all" || $scope.ignored_read_status + var offset = read_shown + ? $scope.entries.length + : _.where($scope.entries, { + read: false, + }).length + 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++) { + var entry = data.entries[i] + if ( + !_.some($scope.entries, { + id: entry.id, + }) + ) { + $scope.entries.push(entry) + } + } + $scope.name = data.name + $scope.message = data.message + $scope.errorCount = data.errorCount + $scope.timestamp = data.timestamp + $scope.busy = false + $scope.hasMore = data.hasMore + $scope.feedLink = data.feedLink + $scope.ignored_read_status = data.ignoredReadStatus + } + + var data = { + id: $scope.selectedId, + readType: $scope.keywords ? "all" : $scope.settingsService.settings.readingMode, + order: $scope.settingsService.settings.readingOrder, + offset: offset, + limit: limit, + keywords: $scope.keywords, + } + if ($scope.selectedType == "feed") { + FeedService.entries(data, callback) + } else if ($scope.selectedType == "category") { + CategoryService.entries(data, callback) + } else if ($scope.selectedType == "tag") { + data.tag = data.id + data.id = "all" + CategoryService.entries(data, callback) + } + } + + var watch_scrolling = true + var watch_current = true + + $scope.$watch("current", function (newValue, oldValue) { + if (!watch_current) { + return + } + if (newValue && newValue !== oldValue) { + var force = $scope.navigationMode == "keyboard" + + // timeout here to execute after dom update + $timeout(function () { + var docTop = $(window).scrollTop() + var docBottom = docTop + $(window).height() + + var elem = $("#entry_" + newValue.id) + var elemTop = elem.offset().top + var elemBottom = elemTop + elem.height() + + if (!force && elemTop > docTop && elemBottom < docBottom) { + // element is entirely visible + return + } else { + var scrollTop = elemTop - $("#toolbar").outerHeight() + var speed = SettingsService.settings.scrollSpeed + watch_scrolling = false + $("html, body").animate( + { + scrollTop: scrollTop, + }, + speed, + "swing", + function () { + watch_scrolling = true + } + ) + } + }) + } + }) + + var scrollHandler = function () { + if (!watch_scrolling || _.size($scope.entries) === 0) { + return + } + + $scope.navigationMode = "scroll" + if (SettingsService.settings.viewMode == "expanded") { + var w = $(window) + var docTop = w.scrollTop() + + var current = null + for (var i = 0; i < $scope.entries.length; i++) { + var entry = $scope.entries[i] + var e = $("#entry_" + entry.id) + if (e.offset().top + e.height() > docTop + $("#toolbar").outerHeight()) { + current = entry + break + } + } + + var previous = $scope.current + $scope.current = current + if (previous != current) { + if (SettingsService.settings.scrollMarks) { + $scope.mark($scope.current, true) + } + watch_current = false + $scope.$apply() + watch_current = true + } + } + } + var scrollListener = _.throttle(scrollHandler, 200) + $window.on("scroll", scrollListener) + $scope.$on("$destroy", function () { + return $window.off("scroll", scrollListener) + }) + + $scope.goToFeed = function (id) { + $state.transitionTo("feeds.view", { + _type: "feed", + _id: id, + }) + } + + $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, + keywords: $location.search().q, + read: true, + }, + function () { + CategoryService.refresh(function () { + $scope.$emit("emitReload") + }) + } + ) + } + + $scope.markUpTo = function (entry) { + var entries = [] + for (var i = 0; i < $scope.entries.length; i++) { + var e = $scope.entries[i] + if (!e.read) { + entries.push({ + id: e.id, + read: true, + }) + e.read = true + } + if (e == entry) { + break + } + } + EntryService.markMultiple( + { + requests: entries, + }, + function () { + CategoryService.refresh() + } + ) + } + + $scope.star = function (entry, star, event) { + if (event) { + event.preventDefault() + event.stopPropagation() + } + if (entry.starred != star) { + entry.starred = star + EntryService.star({ + id: entry.id, + feedId: entry.feedId, + starred: star, + }) + } + } + + var getCurrentIndex = function () { + var index = -1 + if ($scope.current) { + for (var i = 0; i < $scope.entries.length; i++) { + if ($scope.current == $scope.entries[i]) { + index = i + break + } + } + } + return index + } + + var getNextEntry = function () { + var index = getCurrentIndex() + if (index >= 0) { + index = index + 1 + if (index < $scope.entries.length) { + return $scope.entries[index] + } + } else if ($scope.entries.length > 0) { + return $scope.entries[0] + } + return null + } + + var getPreviousEntry = function () { + var index = getCurrentIndex() + if (index >= 1) { + return $scope.entries[index - 1] + } + return null + } + + var openNextEntry = function (event) { + var entry = getNextEntry() + openEntry(entry, event) + } + + var openPreviousEntry = function (event) { + var entry = getPreviousEntry() + openEntry(entry, event) + } + + var focusNextEntry = function (event) { + var entry = getNextEntry() + + if (event) { + event.preventDefault() + event.stopPropagation() + } + + if (entry) { + $scope.current = entry + } + } + + var focusPreviousEntry = function (event) { + var entry = getPreviousEntry() + + if (event) { + event.preventDefault() + event.stopPropagation() + } + + if (entry) { + $scope.current = entry + } + } + + $scope.isOpen = SettingsService.settings.viewMode == "expanded" + + var openEntry = function (entry, event) { + if (event) { + event.preventDefault() + event.stopPropagation() + } + + if (!entry) { + return + } + + 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 (getCurrentIndex() == $scope.entries.length - 1) { + $scope.loadMoreEntries() + } + } + + $scope.entryClicked = function (entry, event) { + if (event && event.which === 3) { + // right click + return + } + if (!event || (!event.ctrlKey && event.which != 2)) { + $scope.navigationMode = "click" + openEntry(entry, event) + } 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() + } + } + + // keyboard shortcuts + Mousetrap.bind("j", function (e) { + $scope.$apply(function () { + $scope.navigationMode = "keyboard" + openNextEntry(e) + }) + return false + }) + Mousetrap.bind("n", function (e) { + $scope.$apply(function () { + $scope.navigationMode = "keyboard" + focusNextEntry(e) + }) + return false + }) + Mousetrap.bind("k", function (e) { + $scope.$apply(function () { + $scope.navigationMode = "keyboard" + openPreviousEntry(e) + }) + return false + }) + Mousetrap.bind("p", function (e) { + $scope.$apply(function () { + $scope.navigationMode = "keyboard" + focusPreviousEntry(e) + }) + return false + }) + Mousetrap.bind("o", function (e) { + $scope.$apply(function () { + $scope.navigationMode = "keyboard" + if ($scope.current) { + openEntry($scope.current, e) + } + }) + return false + }) + Mousetrap.bind("enter", function (e) { + $scope.$apply(function () { + $scope.navigationMode = "keyboard" + if ($scope.current) { + openEntry($scope.current, e) + } + }) + }) + Mousetrap.bind("r", function (e) { + $scope.$apply(function () { + $scope.$emit("emitReload") + }) + return false + }) + Mousetrap.bind("v", function (e) { + if ($scope.current) { + $scope.mark($scope.current, true) + window.open($scope.current.url) + } + return false + }) + Mousetrap.bind("b", function (e) { + if ($scope.current) { + $scope.mark($scope.current, true) + + var url = $scope.current.url + var a = document.createElement("a") + a.href = url + var evt = document.createEvent("MouseEvents") + evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, true, false, false, true, 0, null) + a.dispatchEvent(evt) + } + return false + }) + Mousetrap.bind("s", function (e) { + $scope.$apply(function () { + if ($scope.current) { + $scope.star($scope.current, !$scope.current.starred) + } + }) + return false + }) + Mousetrap.bind("m", function (e) { + $scope.$apply(function () { + if ($scope.current) { + $scope.mark($scope.current, !$scope.current.read) + } + }) + return false + }) + Mousetrap.bind("shift+a", function (e) { + $scope.$apply(function () { + $scope.markAll() + }) + return false + }) + + Mousetrap.bind("+", function (e) { + $scope.$apply(function () { + $scope.font_size = Math.min($scope.font_size + 1, 5) + }) + return false + }) + + Mousetrap.bind("-", function (e) { + $scope.$apply(function () { + $scope.font_size = Math.max($scope.font_size - 1, 0) + }) + return false + }) + + Mousetrap.bind("space", function (e) { + if (!$scope.current) { + $scope.$apply(function () { + $scope.navigationMode = "keyboard" + openNextEntry(e) + }) + } else if (!$scope.isOpen) { + $scope.$apply(function () { + $scope.navigationMode = "keyboard" + if ($scope.current) { + openEntry($scope.current, e) + } + }) + } else { + var docTop = $(window).scrollTop() + var docBottom = docTop + $(window).height() + + var elem = $("#entry_" + $scope.current.id) + var elemTop = elem.offset().top + var elemBottom = elemTop + elem.height() + + var bottomVisible = elemBottom < docBottom + if (bottomVisible) { + $scope.$apply(function () { + $scope.navigationMode = "keyboard" + openNextEntry(e) + }) + } + } + }) + + Mousetrap.bind("shift+space", function (e) { + if (!$scope.current) { + return + } else if (!$scope.isOpen) { + $scope.$apply(function () { + $scope.navigationMode = "keyboard" + if ($scope.current) { + openEntry($scope.current, e) + } + }) + } else { + var docTop = $(window).scrollTop() + + var elem = $("#entry_" + $scope.current.id) + var elemTop = elem.offset().top + + var topVisible = elemTop > docTop + if (topVisible) { + $scope.$apply(function () { + $scope.navigationMode = "keyboard" + openPreviousEntry(e) + }) + } + } + }) + + Mousetrap.bind("f", function (e) { + $("body").toggleClass("full-screen") + $(".main-content").css("margin-left", "") + return false + }) + + Mousetrap.bind("?", function (e) { + $scope.$apply(function () { + $scope.shortcutsModal = true + }) + return false + }) + + $scope.$on("previousEntry", function (event, args) { + $scope.navigationMode = "keyboard" + openPreviousEntry() + }) + $scope.$on("nextEntry", function (event, args) { + $scope.navigationMode = "keyboard" + openNextEntry() + }) + $scope.$on("markAll", function (event, args) { + $scope.markAll(args.olderThan) + }) + + var reload = function (all, keywords) { + $scope.keywords = keywords + $location.search("q", keywords) + delete $scope.current + $scope.name = null + $scope.entries = [] + $scope.message = null + $scope.errorCount = 0 + $scope.timestamp = 0 + $scope.busy = false + $scope.hasMore = true + $scope.loadMoreEntries() + + if (all) { + FeedService.refreshAll() + } else if ($scope.selectedType == "feed") { + FeedService.refresh({ + id: $stateParams._id, + }) + } + } + + $scope.$on("entrySearch", function (event, args) { + reload(null, args.keywords) + }) + + $scope.$on("reload", function (event, args) { + reload(args.all, null) + }) + }, +]) + +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, + columnDefs: [ + { + field: "id", + displayName: "ID", + }, + { + field: "name", + displayName: "Name", + }, + { + field: "email", + cellClass: "E-Mail", + }, + { + field: "created", + cellClass: "Created", + cellFilter: "entryDate", + }, + { + field: "lastLogin", + cellClass: "Last login", + cellFilter: "entryDate", + }, + { + field: "admin", + cellClass: "Admin", + }, + { + field: "enabled", + cellClass: "Enabled", + }, + ], + + 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", + "AdminUsersService", + function ($scope, $state, $stateParams, 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 () { + AdminUsersService.remove( + { + id: $scope.user.id, + }, + function () { + $state.transitionTo("admin.userlist") + }, + alertFunction + ) + } + }, +]) + +module.controller("SettingsCtrl", [ + "$scope", + "$location", + "SettingsService", + "AnalyticsService", + "LangService", + function ($scope, $location, SettingsService, AnalyticsService, LangService) { + AnalyticsService.track() + + $scope.langs = LangService.langs + + $scope.themes = ["default", "bootstrap", "dark", "ebraminio", "MRACHINI", "nightsky", "svetla", "third"] + + $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", + "ProfileService", + "AnalyticsService", + function ($scope, $location, 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 () { + 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") + } + $scope.toMetrics = function () { + $state.transitionTo("admin.metrics") + } + }, +]) + +module.controller("HelpController", [ + "$scope", + "CategoryService", + "AnalyticsService", + "ServerService", + function ($scope, CategoryService, AnalyticsService, ServerService) { + AnalyticsService.track() + $scope.CategoryService = CategoryService + $scope.infos = ServerService.get() + $scope.categoryId = "all" + $scope.order = "desc" + $scope.baseUrl = window.location.href.substring(0, window.location.href.lastIndexOf("#")) + }, +]) + +module.controller("FooterController", [ + "$scope", + "$sce", + function ($scope, $sce) { + var baseUrl = window.location.href.substring(0, window.location.href.lastIndexOf("#")) + var hostname = window.location.hostname + var url = baseUrl + "rest/feed/subscribe?url={feed}" + var name = hostname.indexOf("www.commafeed.com") !== -1 ? "CommaFeed" : "CommaFeed (" + hostname + ")" + var subToMeUrl = "https://www.subtome.com/register-no-ui.html?name=" + name + "&url=" + url + $scope.subToMeUrl = $sce.trustAsResourceUrl(subToMeUrl) + }, +]) + +module.controller("MetricsCtrl", [ + "$scope", + "AdminMetricsService", + function ($scope, AdminMetricsService) { + $scope.metrics = AdminMetricsService.get() + }, +]) + +module.controller("LoginCtrl", [ + "$scope", + "$location", + "$timeout", + "SessionService", + "ServerService", + function ($scope, $location, $timeout, SessionService, ServerService) { + $scope.model = {} + $scope.recovery_model = {} + $scope.recovery = false + $scope.recovery_enabled = false + + ServerService.get(function (data) { + $scope.recovery_enabled = data.smtpEnabled + }) + + var login = function (model) { + var success = function (data) { + window.location.href = window.location.href.substring(0, window.location.href.lastIndexOf("#")) + } + var error = function (data) { + $scope.message = data.data + } + SessionService.login( + { + name: model.name, + password: model.password, + }, + success, + error + ) + } + $scope.demoLogin = function () { + login({ + name: "demo", + password: "demo", + }) + } + + $scope.login = function () { + // autofilled fields do not trigger model update, do it manually + $("input[ng-model]").trigger("input") + login($scope.model) + } + + $scope.toggleRecovery = function () { + $scope.recovery = !$scope.recovery + } + + var recovery_success = function (data) { + $scope.recovery_message = "Email has ben sent. Check your inbox." + } + var recovery_error = function (data) { + $scope.recovery_message = data.data + } + $scope.recover = function () { + SessionService.passwordReset( + { + email: $scope.recovery_model.email, + }, + recovery_success, + recovery_error + ) + } + }, +]) + +module.controller("RegisterCtrl", [ + "$scope", + "$location", + "SessionService", + "ServerService", + function ($scope, $location, SessionService, ServerService) { + $scope.ServerService = ServerService.get() + $scope.model = {} + + $scope.register = function () { + var success = function (data) { + window.location.href = window.location.href.substring(0, window.location.href.lastIndexOf("#")) + } + var error = function (data) { + $scope.messages = data.data.errors + } + SessionService.register($scope.model, success, error) + } + }, +]) diff --git a/src/main/app/js/directives.js b/src/main/app/js/directives.js index 200ebe83..ea7b6d00 100644 --- a/src/main/app/js/directives.js +++ b/src/main/app/js/directives.js @@ -1,373 +1,402 @@ -var module = angular.module('commafeed.directives', []); +var module = angular.module("commafeed.directives", []) -module.directive('focus', ['$timeout', function($timeout) { - return { - restrict : 'A', - link : function(scope, element, attrs) { - scope.$watch(attrs.focus, function(value) { - if (!value) - return; - $timeout(function() { - $(element).focus(); - }); - }); - } - }; -}]); +module.directive("focus", [ + "$timeout", + function ($timeout) { + return { + restrict: "A", + link: function (scope, element, attrs) { + scope.$watch(attrs.focus, function (value) { + if (!value) return + $timeout(function () { + $(element).focus() + }) + }) + }, + } + }, +]) -module.directive('confirmClick', [function() { - return { - priority : -1, - restrict : 'A', - link : function(scope, element, attrs) { - element.bind('click', function(e) { - var message = scope.$eval(attrs.confirmClick); - if (message && !confirm(message)) { - e.stopImmediatePropagation(); - e.preventDefault(); - } - }); - } - }; -}]); +module.directive("confirmClick", [ + function () { + return { + priority: -1, + restrict: "A", + link: function (scope, element, attrs) { + element.bind("click", function (e) { + var message = scope.$eval(attrs.confirmClick) + if (message && !confirm(message)) { + e.stopImmediatePropagation() + e.preventDefault() + } + }) + }, + } + }, +]) /** * Open a popup window pointing to the url in the href attribute */ -module.directive('popup', function() { - var opts = 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=800'; - return { - link : function(scope, elm, attrs) { - elm.bind('click', function(event) { - window.open(this.href, '', opts); - event.preventDefault(); - }); - } - }; -}); +module.directive("popup", function () { + var opts = "menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=800" + return { + link: function (scope, elm, attrs) { + elm.bind("click", function (event) { + window.open(this.href, "", opts) + event.preventDefault() + }) + }, + } +}) /** * entry tag handling */ -module.directive('tags', function() { - return { - restrict : 'E', - scope : { - entry : '=' - }, - replace : true, - templateUrl : 'templates/_tags.html', - controller : ['$scope', 'EntryService', function($scope, EntryService) { - $scope.select2Options = { - 'multiple' : true, - 'simple_tags' : true, - 'maximumInputLength' : 40, - tags : EntryService.tags - }; +module.directive("tags", function () { + return { + restrict: "E", + scope: { + entry: "=", + }, + replace: true, + templateUrl: "templates/_tags.html", + controller: [ + "$scope", + "EntryService", + function ($scope, EntryService) { + $scope.select2Options = { + multiple: true, + simple_tags: true, + maximumInputLength: 40, + tags: EntryService.tags, + } - $scope.$watch('entry.tags', function(newValue, oldValue) { - if (oldValue && newValue != oldValue) { - var data = { - entryId : $scope.entry.id, - tags : [] - }; - if (newValue) { - data.tags = newValue; - } - EntryService.tag(data); - } - }, true); - }] - }; -}); + $scope.$watch( + "entry.tags", + function (newValue, oldValue) { + if (oldValue && newValue != oldValue) { + var data = { + entryId: $scope.entry.id, + tags: [], + } + if (newValue) { + data.tags = newValue + } + EntryService.tag(data) + } + }, + true + ) + }, + ], + } +}) /** * Reusable favicon component */ -module.directive('favicon', function() { - var tpl = ''; - return { - restrict : 'E', - scope : { - url : '=' - }, - replace : true, - template : tpl - }; -}); +module.directive("favicon", function () { + var tpl = '' + return { + restrict: "E", + scope: { + url: "=", + }, + replace: true, + template: tpl, + } +}) /** * Support for the blur event */ -module.directive('ngBlur', function() { - return { - restrict : 'A', - link : function(scope, elm, attrs) { - elm.bind('blur', function() { - scope.$apply(attrs.ngBlur); - }); - } - }; -}); +module.directive("ngBlur", function () { + return { + restrict: "A", + link: function (scope, elm, attrs) { + elm.bind("blur", function () { + scope.$apply(attrs.ngBlur) + }) + }, + } +}) /** * Prevent mousewheel scrolling from propagating to the parent when scrollbar * reaches top or bottom */ -module.directive('mousewheelScrolling', function() { - return { - restrict : 'A', - link : function(scope, elem, attr) { - elem.bind('mousewheel', function(e, d) { - var t = $(this); - if (d > 0 && t.scrollTop() === 0) { - e.preventDefault(); - } else { - if (d < 0 && (t.scrollTop() == t.get(0).scrollHeight - t.innerHeight())) { - e.preventDefault(); - } - } - }); - } - }; -}); +module.directive("mousewheelScrolling", function () { + return { + restrict: "A", + link: function (scope, elem, attr) { + elem.bind("mousewheel", function (e, d) { + var t = $(this) + if (d > 0 && t.scrollTop() === 0) { + e.preventDefault() + } else { + if (d < 0 && t.scrollTop() == t.get(0).scrollHeight - t.innerHeight()) { + e.preventDefault() + } + } + }) + }, + } +}) /** * Needed to use recursive directives. Wrap a recursive element with a * tag */ -module.directive('recursive', ['$compile', function($compile) { - return { - restrict : 'E', - priority : 100000, - compile : function(tElement, tAttr) { - var contents = tElement.contents().remove(); - var compiledContents = null; - return function(scope, iElement, iAttr) { - if (!compiledContents) { - compiledContents = $compile(contents); - } - iElement.append(compiledContents(scope, function(clone) { - return clone; - })); - }; - } - }; -}]); +module.directive("recursive", [ + "$compile", + function ($compile) { + return { + restrict: "E", + priority: 100000, + compile: function (tElement, tAttr) { + var contents = tElement.contents().remove() + var compiledContents = null + return function (scope, iElement, iAttr) { + if (!compiledContents) { + compiledContents = $compile(contents) + } + iElement.append( + compiledContents(scope, function (clone) { + return clone + }) + ) + } + }, + } + }, +]) /** * Reusable category component */ -module.directive('category', [function() { - return { - scope : { - node : '=', - level : '=', - selectedType : '=', - selectedId : '=', - showLabel : '=', - showChildren : '=', - unreadCount : '&', - tag : '=' - }, - restrict : 'E', - replace : true, - templateUrl : 'templates/_category.html', - controller : ['$scope', '$state', 'FeedService', 'CategoryService', 'SettingsService', 'MobileService', - function($scope, $state, FeedService, CategoryService, SettingsService, MobileService) { - $scope.settingsService = SettingsService; +module.directive("category", [ + function () { + return { + scope: { + node: "=", + level: "=", + selectedType: "=", + selectedId: "=", + showLabel: "=", + showChildren: "=", + unreadCount: "&", + tag: "=", + }, + restrict: "E", + replace: true, + templateUrl: "templates/_category.html", + controller: [ + "$scope", + "$state", + "FeedService", + "CategoryService", + "SettingsService", + "MobileService", + function ($scope, $state, FeedService, CategoryService, SettingsService, MobileService) { + $scope.settingsService = SettingsService - $scope.getClass = function(level) { - if ($scope.showLabel) { - return 'indent' + level; - } - }; + $scope.getClass = function (level) { + if ($scope.showLabel) { + return "indent" + level + } + } - $scope.categoryLabel = function(category) { - return $scope.showLabel !== true ? $scope.showLabel : category.name; - }; + $scope.categoryLabel = function (category) { + return $scope.showLabel !== true ? $scope.showLabel : category.name + } - $scope.categoryCountLabel = function(category) { - var count = $scope.unreadCount({ - category : category - }); - var label = ''; - if (count > 0) { - label += count; - } - return label; - }; + $scope.categoryCountLabel = function (category) { + var count = $scope.unreadCount({ + category: category, + }) + var label = "" + if (count > 0) { + label += count + } + return label + } - $scope.feedCountLabel = function(feed) { - var label = ''; - if (feed.unread > 0) { - label += feed.unread; - } - return label; - }; + $scope.feedCountLabel = function (feed) { + var label = "" + if (feed.unread > 0) { + label += feed.unread + } + return label + } - $scope.feedClicked = function(id, event) { - // Could be called by a middle click - if (!event || (!event.ctrlKey && event.which == 1)) { - MobileService.toggleLeftMenu(); - if ($scope.selectedType == 'feed' && id == $scope.selectedId) { - $scope.$emit('emitReload'); - } else { - $state.transitionTo('feeds.view', { - _type : 'feed', - _id : id - }); - } + $scope.feedClicked = function (id, event) { + // Could be called by a middle click + if (!event || (!event.ctrlKey && event.which == 1)) { + MobileService.toggleLeftMenu() + if ($scope.selectedType == "feed" && id == $scope.selectedId) { + $scope.$emit("emitReload") + } else { + $state.transitionTo("feeds.view", { + _type: "feed", + _id: id, + }) + } - if (event) { - event.preventDefault(); - event.stopPropagation(); - } - } - }; + if (event) { + event.preventDefault() + event.stopPropagation() + } + } + } - $scope.categoryClicked = function(id, isTag) { - MobileService.toggleLeftMenu(); - var type = isTag ? 'tag' : 'category'; - if ($scope.selectedType == type && id == $scope.selectedId) { - $scope.$emit('emitReload'); - } else { - $state.transitionTo('feeds.view', { - _type : type, - _id : id - }); - } - }; + $scope.categoryClicked = function (id, isTag) { + MobileService.toggleLeftMenu() + var type = isTag ? "tag" : "category" + if ($scope.selectedType == type && id == $scope.selectedId) { + $scope.$emit("emitReload") + } else { + $state.transitionTo("feeds.view", { + _type: type, + _id: id, + }) + } + } - $scope.showFeedDetails = function(feed) { - $state.transitionTo('feeds.feed_details', { - _id : feed.id - }); - }; + $scope.showFeedDetails = function (feed) { + $state.transitionTo("feeds.feed_details", { + _id: feed.id, + }) + } - $scope.showCategoryDetails = function(id, isTag) { - if (isTag) { - $state.transitionTo('feeds.tag_details', { - _id : id - }); - } else { - $state.transitionTo('feeds.category_details', { - _id : id - }); - } - }; + $scope.showCategoryDetails = function (id, isTag) { + if (isTag) { + $state.transitionTo("feeds.tag_details", { + _id: id, + }) + } else { + $state.transitionTo("feeds.category_details", { + _id: id, + }) + } + } - $scope.toggleCategory = function(category, event) { - event.preventDefault(); - event.stopPropagation(); - category.expanded = !category.expanded; - if (category.id == 'all') { - return; - } - CategoryService.collapse({ - id : category.id, - collapse : !category.expanded - }); - }; - }] - }; -}]); + $scope.toggleCategory = function (category, event) { + event.preventDefault() + event.stopPropagation() + category.expanded = !category.expanded + if (category.id == "all") { + return + } + CategoryService.collapse({ + id: category.id, + collapse: !category.expanded, + }) + } + }, + ], + } + }, +]) -module.directive('draggable', function() { - return { - restrict : 'A', - link : function(scope, element, attrs) { - element.draggable({ - revert : 'invalid', - helper : 'clone', - distance : 10, - axis : 'y' - }).data('source', scope.$eval(attrs.draggable)); - } - }; -}); +module.directive("draggable", function () { + return { + restrict: "A", + link: function (scope, element, attrs) { + element + .draggable({ + revert: "invalid", + helper: "clone", + distance: 10, + axis: "y", + }) + .data("source", scope.$eval(attrs.draggable)) + }, + } +}) -module.directive('droppable', ['CategoryService', 'FeedService', function(CategoryService, FeedService) { - return { - restrict : 'A', - link : function(scope, element, attrs) { - element.droppable({ - tolerance : 'pointer', - over : function(event, ui) { +module.directive("droppable", [ + "CategoryService", + "FeedService", + function (CategoryService, FeedService) { + return { + restrict: "A", + link: function (scope, element, attrs) { + element.droppable({ + tolerance: "pointer", + over: function (event, ui) {}, + drop: function (event, ui) { + var draggable = angular.element(ui.draggable) - }, - drop : function(event, ui) { - var draggable = angular.element(ui.draggable); + var source = draggable.data("source") + var target = scope.$eval(attrs.droppable) - var source = draggable.data('source'); - var target = scope.$eval(attrs.droppable); + if (angular.equals(source, target)) { + return + } - if (angular.equals(source, target)) { - return; - } + var data = { + id: source.id, + name: source.name, + filter: source.filter, + } - var data = { - id : source.id, - name : source.name, - filter : source.filter - }; + if (source.children) { + // source is a category + } else { + // source is a feed - if (source.children) { - // source is a category + if (target.children) { + // target is a category + data.categoryId = target.id + data.position = 0 + } else { + // target is a feed + data.categoryId = target.categoryId + data.position = target.position + } - } else { - // source is a feed + FeedService.modify(data, function () { + CategoryService.init() + }) + } + scope.$apply() + }, + }) + }, + } + }, +]) - if (target.children) { - // target is a category - data.categoryId = target.id; - data.position = 0; - } else { - // target is a feed - data.categoryId = target.categoryId; - data.position = target.position; - } +module.directive("metricMeter", function () { + return { + scope: { + metric: "=", + label: "=", + }, + restrict: "E", + templateUrl: "templates/_metrics.meter.html", + } +}) - FeedService.modify(data, function() { - CategoryService.init(); - }); - } - scope.$apply(); - } - }); - } - }; -}]); +module.directive("metricGauge", function () { + return { + scope: { + metric: "=", + label: "=", + }, + restrict: "E", + templateUrl: "templates/_metrics.gauge.html", + } +}) -module.directive('metricMeter', function() { - return { - scope : { - metric : '=', - label : '=' - }, - restrict : 'E', - templateUrl : 'templates/_metrics.meter.html' - }; -}); - -module.directive('metricGauge', function() { - return { - scope : { - metric : '=', - label : '=' - }, - restrict : 'E', - templateUrl : 'templates/_metrics.gauge.html' - }; -}); - -module.directive('metricTimer', function() { - return { - scope : { - metric : '=', - label : '=' - }, - restrict : 'E', - templateUrl : 'templates/_metrics.timer.html' - }; -}); +module.directive("metricTimer", function () { + return { + scope: { + metric: "=", + label: "=", + }, + restrict: "E", + templateUrl: "templates/_metrics.timer.html", + } +}) diff --git a/src/main/app/js/filters.js b/src/main/app/js/filters.js index 87e2c9a1..610b8402 100644 --- a/src/main/app/js/filters.js +++ b/src/main/app/js/filters.js @@ -1,113 +1,119 @@ -var module = angular.module('commafeed.filters', []); +var module = angular.module("commafeed.filters", []) /** * smart date formatter */ -module.filter('entryDate', function() { - return function(timestamp, defaultValue) { - if (!timestamp) { - return defaultValue; - } +module.filter("entryDate", function () { + return function (timestamp, defaultValue) { + if (!timestamp) { + return defaultValue + } - var d = moment(timestamp); - var now = moment(); - var formatted; - if (Math.abs(d.diff(now)) < 86400000) { - formatted = d.fromNow(); - } else { - formatted = d.format('YYYY-MM-DD HH:mm'); - } - return formatted; - }; -}); + var d = moment(timestamp) + var now = moment() + var formatted + if (Math.abs(d.diff(now)) < 86400000) { + formatted = d.fromNow() + } else { + formatted = d.format("YYYY-MM-DD HH:mm") + } + return formatted + } +}) /** * rewrites iframes to use https if commafeed uses https */ -module.filter('iframeHttpsRewrite', function() { - return function(html) { - var result = html; - if (location.protocol === 'https:') { - var wrapper = $('
').html(html); - $('iframe', wrapper).each(function(i, elem) { - var e = $(elem); - e.attr('src', e.attr('src').replace(/^http:\/\//i, 'https://')); - }); - result = wrapper.html(); - } - return result; - }; -}); +module.filter("iframeHttpsRewrite", function () { + return function (html) { + var result = html + if (location.protocol === "https:") { + var wrapper = $("
").html(html) + $("iframe", wrapper).each(function (i, elem) { + var e = $(elem) + e.attr("src", e.attr("src").replace(/^http:\/\//i, "https://")) + }) + result = wrapper.html() + } + return result + } +}) /** * inserts title or alt-text after images, if any */ -module.filter('appendImageTitles', function() { - return function(html) { - var result = html; - var wrapper = $('
').html(html); - $('img', wrapper).each(function(i, elem) { - var e = $(elem); - var title = e.attr('title') || e.attr('alt'); - if (title) { - var text = $('').text(title); - e.after(text); - } - }); - result = wrapper.html(); - return result; - }; -}); +module.filter("appendImageTitles", function () { + return function (html) { + var result = html + var wrapper = $("
").html(html) + $("img", wrapper).each(function (i, elem) { + var e = $(elem) + var title = e.attr("title") || e.attr("alt") + if (title) { + var text = $('').text(title) + e.after(text) + } + }) + result = wrapper.html() + return result + } +}) /** * escapes the url */ -module.filter('escape', function() { - return encodeURIComponent; -}); +module.filter("escape", function () { + return encodeURIComponent +}) /** * returns a trusted html content */ -module.filter('trustHtml', ['$sce', function($sce) { - return function(val) { - return $sce.trustAsHtml(val); - }; -}]); +module.filter("trustHtml", [ + "$sce", + function ($sce) { + return function (val) { + return $sce.trustAsHtml(val) + } + }, +]) /** * returns a trusted url */ -module.filter('trustUrl', ['$sce', function($sce) { - return function(val) { - return $sce.trustAsResourceUrl(val); - }; -}]); +module.filter("trustUrl", [ + "$sce", + function ($sce) { + return function (val) { + return $sce.trustAsResourceUrl(val) + } + }, +]) /** * add the 'highlight-search' class to text matching keywords */ -module.filter('highlight', function() { - return function(html, keywords) { - if (keywords) { - var handleKeyword = function(token, html) { - var expr = new RegExp(token, 'gi'); - var container = $('').html(html); - var elements = container.find('*').addBack(); - var textNodes = elements.not('iframe').contents().not(elements); - textNodes.each(function() { - var replaced = this.nodeValue.replace(expr, '$&'); - $('').html(replaced).insertBefore(this); - $(this).remove(); - }); - return container.html(); - }; +module.filter("highlight", function () { + return function (html, keywords) { + if (keywords) { + var handleKeyword = function (token, html) { + var expr = new RegExp(token, "gi") + var container = $("").html(html) + var elements = container.find("*").addBack() + var textNodes = elements.not("iframe").contents().not(elements) + textNodes.each(function () { + var replaced = this.nodeValue.replace(expr, '$&') + $("").html(replaced).insertBefore(this) + $(this).remove() + }) + return container.html() + } - var tokens = keywords.split(' '); - for (var i = 0; i < tokens.length; i++) { - html = handleKeyword(tokens[i], html); - } - } - return html; - }; -}); \ No newline at end of file + var tokens = keywords.split(" ") + for (var i = 0; i < tokens.length; i++) { + html = handleKeyword(tokens[i], html) + } + } + return html + } +}) diff --git a/src/main/app/js/i18n.js b/src/main/app/js/i18n.js index 82c489cb..f0e3a6a0 100644 --- a/src/main/app/js/i18n.js +++ b/src/main/app/js/i18n.js @@ -1,35 +1,37 @@ -var module = angular.module('commafeed.i18n', []); +var module = angular.module("commafeed.i18n", []) -module.service('LangService', [function() { - this.langs = { - 'ar': 'العربية', - 'ca': 'Català', - 'en': 'English', - 'es': 'Español', - 'de': 'Deutsch', - 'fa': 'فارسی', - 'fr': 'Français', - 'gl': 'Galician', - 'glk': 'گیلکی', - 'hu': 'Magyar', - 'id': 'Indonesian', - 'ja': '日本語', - 'ko': '한국어', - 'nl': 'Nederlands', - 'nb': 'Norsk (bokmål)', - 'nn': 'Norsk (nynorsk)', - 'pt': 'Português', - 'pl': 'Polski', - 'ru': 'Русский', - 'fi': 'Suomi', - 'sv': 'Svenska', - 'zh': '简体中文', - 'it': 'Italiano', - 'tr': 'Türkçe', - 'cy': 'Cymraeg', - 'sk': 'Slovenčina', - 'da': 'Danish', - 'cs': 'Čeština', - 'ms': 'Bahasa Malaysian' - } -}]); +module.service("LangService", [ + function () { + this.langs = { + ar: "العربية", + ca: "Català", + en: "English", + es: "Español", + de: "Deutsch", + fa: "فارسی", + fr: "Français", + gl: "Galician", + glk: "گیلکی", + hu: "Magyar", + id: "Indonesian", + ja: "日本語", + ko: "한국어", + nl: "Nederlands", + nb: "Norsk (bokmål)", + nn: "Norsk (nynorsk)", + pt: "Português", + pl: "Polski", + ru: "Русский", + fi: "Suomi", + sv: "Svenska", + zh: "简体中文", + it: "Italiano", + tr: "Türkçe", + cy: "Cymraeg", + sk: "Slovenčina", + da: "Danish", + cs: "Čeština", + ms: "Bahasa Malaysian", + } + }, +]) diff --git a/src/main/app/js/main.js b/src/main/app/js/main.js index 8a51e0d0..6990260d 100644 --- a/src/main/app/js/main.js +++ b/src/main/app/js/main.js @@ -1,145 +1,172 @@ -var app = angular.module('commafeed', ['ngRoute', 'ngTouch', 'ngAnimate', 'ui.utils', 'ui.bootstrap', 'ui.router', 'ui.select2', - 'commafeed.directives', 'commafeed.controllers', 'commafeed.services', 'commafeed.filters', 'commafeed.i18n', 'ngSanitize', - 'infinite-scroll', 'ngGrid', 'chieffancypants.loadingBar', 'pascalprecht.translate']); +var app = angular.module("commafeed", [ + "ngRoute", + "ngTouch", + "ngAnimate", + "ui.utils", + "ui.bootstrap", + "ui.router", + "ui.select2", + "commafeed.directives", + "commafeed.controllers", + "commafeed.services", + "commafeed.filters", + "commafeed.i18n", + "ngSanitize", + "infinite-scroll", + "ngGrid", + "chieffancypants.loadingBar", + "pascalprecht.translate", +]) app.config([ - '$routeProvider', - '$stateProvider', - '$urlRouterProvider', - '$httpProvider', - '$compileProvider', - 'cfpLoadingBarProvider', - '$translateProvider', - function($routeProvider, $stateProvider, $urlRouterProvider, $httpProvider, $compileProvider, cfpLoadingBarProvider, - $translateProvider) { - - $translateProvider.useStaticFilesLoader({ - prefix : 'i18n/', - suffix : '.js' - }); - $translateProvider.preferredLanguage('en'); + "$routeProvider", + "$stateProvider", + "$urlRouterProvider", + "$httpProvider", + "$compileProvider", + "cfpLoadingBarProvider", + "$translateProvider", + function ( + $routeProvider, + $stateProvider, + $urlRouterProvider, + $httpProvider, + $compileProvider, + cfpLoadingBarProvider, + $translateProvider + ) { + $translateProvider.useStaticFilesLoader({ + prefix: "i18n/", + suffix: ".js", + }) + $translateProvider.preferredLanguage("en") - cfpLoadingBarProvider.includeSpinner = false; + cfpLoadingBarProvider.includeSpinner = false - $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|javascript):/); - var interceptor = ['$rootScope', '$q', '$injector', function(scope, $q, $injector) { - var f = {}; - - f.response = function(response) { - return response; - }; - - f.responseError = function(response) { - var status = response.status; - if (status == 401) { - $injector.get('$state').transitionTo('welcome'); - } - return $q.reject(response); - }; - return f; - }]; + $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|javascript):/) + var interceptor = [ + "$rootScope", + "$q", + "$injector", + function (scope, $q, $injector) { + var f = {} - $httpProvider.interceptors.push(interceptor); + f.response = function (response) { + return response + } - $stateProvider.state('feeds', { - 'abstract' : true, - url : '/feeds', - templateUrl : 'templates/feeds.html' - }); - $stateProvider.state('feeds.view', { - url : '/view/:_type/:_id', - templateUrl : 'templates/feeds.view.html', - controller : 'FeedListCtrl' - }); - $stateProvider.state('feeds.subscribe', { - url : '/subscribe', - templateUrl : 'templates/feeds.subscribe.html', - controller : 'SubscribeCtrl' - }); - $stateProvider.state('feeds.new_category', { - url : '/add_category', - templateUrl : 'templates/feeds.new_category.html', - controller : 'NewCategoryCtrl' - }); - $stateProvider.state('feeds.import', { - url : '/import', - templateUrl : 'templates/feeds.import.html', - controller : 'ImportCtrl' - }); - $stateProvider.state('feeds.search', { - url : '/search/:_keywords', - templateUrl : 'templates/feeds.view.html', - controller : 'FeedListCtrl' - }); - $stateProvider.state('feeds.feed_details', { - url : '/details/feed/:_id', - templateUrl : 'templates/feeds.feed_details.html', - controller : 'FeedDetailsCtrl' - }); - $stateProvider.state('feeds.category_details', { - url : '/details/category/:_id', - templateUrl : 'templates/feeds.category_details.html', - controller : 'CategoryDetailsCtrl' - }); - $stateProvider.state('feeds.tag_details', { - url : '/details/tag/:_id', - templateUrl : 'templates/feeds.tag_details.html', - controller : 'TagDetailsCtrl' - }); - $stateProvider.state('feeds.help', { - url : '/help', - templateUrl : 'templates/feeds.help.html', - controller : 'HelpController' - }); - $stateProvider.state('feeds.settings', { - url : '/settings', - templateUrl : 'templates/settings.html', - controller : 'SettingsCtrl' - }); - $stateProvider.state('feeds.profile', { - url : '/profile', - templateUrl : 'templates/profile.html', - controller : 'ProfileCtrl' - }); + f.responseError = function (response) { + var status = response.status + if (status == 401) { + $injector.get("$state").transitionTo("welcome") + } + return $q.reject(response) + } + return f + }, + ] - $stateProvider.state('admin', { - 'abstract' : true, - url : '/admin', - templateUrl : 'templates/admin.html' - }); - $stateProvider.state('admin.userlist', { - url : '/user/list', - templateUrl : 'templates/admin.userlist.html', - controller : 'ManageUsersCtrl' - }); - $stateProvider.state('admin.useradd', { - url : '/user/add', - templateUrl : 'templates/admin.useradd.html', - controller : 'ManageUserCtrl' - }); - $stateProvider.state('admin.useredit', { - url : '/user/edit/:_id', - templateUrl : 'templates/admin.useredit.html', - controller : 'ManageUserCtrl' - }); - $stateProvider.state('admin.settings', { - url : '/settings', - templateUrl : 'templates/admin.settings.html', - controller : 'ManageSettingsCtrl' - }); - $stateProvider.state('admin.metrics', { - url : '/metrics', - templateUrl : 'templates/admin.metrics.html', - controller : 'MetricsCtrl' - }); + $httpProvider.interceptors.push(interceptor) - $stateProvider.state('welcome', { - url : '/welcome', - templateUrl : 'templates/welcome.html' - }); + $stateProvider.state("feeds", { + abstract: true, + url: "/feeds", + templateUrl: "templates/feeds.html", + }) + $stateProvider.state("feeds.view", { + url: "/view/:_type/:_id", + templateUrl: "templates/feeds.view.html", + controller: "FeedListCtrl", + }) + $stateProvider.state("feeds.subscribe", { + url: "/subscribe", + templateUrl: "templates/feeds.subscribe.html", + controller: "SubscribeCtrl", + }) + $stateProvider.state("feeds.new_category", { + url: "/add_category", + templateUrl: "templates/feeds.new_category.html", + controller: "NewCategoryCtrl", + }) + $stateProvider.state("feeds.import", { + url: "/import", + templateUrl: "templates/feeds.import.html", + controller: "ImportCtrl", + }) + $stateProvider.state("feeds.search", { + url: "/search/:_keywords", + templateUrl: "templates/feeds.view.html", + controller: "FeedListCtrl", + }) + $stateProvider.state("feeds.feed_details", { + url: "/details/feed/:_id", + templateUrl: "templates/feeds.feed_details.html", + controller: "FeedDetailsCtrl", + }) + $stateProvider.state("feeds.category_details", { + url: "/details/category/:_id", + templateUrl: "templates/feeds.category_details.html", + controller: "CategoryDetailsCtrl", + }) + $stateProvider.state("feeds.tag_details", { + url: "/details/tag/:_id", + templateUrl: "templates/feeds.tag_details.html", + controller: "TagDetailsCtrl", + }) + $stateProvider.state("feeds.help", { + url: "/help", + templateUrl: "templates/feeds.help.html", + controller: "HelpController", + }) + $stateProvider.state("feeds.settings", { + url: "/settings", + templateUrl: "templates/settings.html", + controller: "SettingsCtrl", + }) + $stateProvider.state("feeds.profile", { + url: "/profile", + templateUrl: "templates/profile.html", + controller: "ProfileCtrl", + }) - $urlRouterProvider.when('/', '/feeds/view/category/all'); - $urlRouterProvider.when('/admin', '/admin/settings'); - $urlRouterProvider.otherwise('/'); + $stateProvider.state("admin", { + abstract: true, + url: "/admin", + templateUrl: "templates/admin.html", + }) + $stateProvider.state("admin.userlist", { + url: "/user/list", + templateUrl: "templates/admin.userlist.html", + controller: "ManageUsersCtrl", + }) + $stateProvider.state("admin.useradd", { + url: "/user/add", + templateUrl: "templates/admin.useradd.html", + controller: "ManageUserCtrl", + }) + $stateProvider.state("admin.useredit", { + url: "/user/edit/:_id", + templateUrl: "templates/admin.useredit.html", + controller: "ManageUserCtrl", + }) + $stateProvider.state("admin.settings", { + url: "/settings", + templateUrl: "templates/admin.settings.html", + controller: "ManageSettingsCtrl", + }) + $stateProvider.state("admin.metrics", { + url: "/metrics", + templateUrl: "templates/admin.metrics.html", + controller: "MetricsCtrl", + }) - }]); \ No newline at end of file + $stateProvider.state("welcome", { + url: "/welcome", + templateUrl: "templates/welcome.html", + }) + + $urlRouterProvider.when("/", "/feeds/view/category/all") + $urlRouterProvider.when("/admin", "/admin/settings") + $urlRouterProvider.otherwise("/") + }, +]) diff --git a/src/main/app/js/services.js b/src/main/app/js/services.js index 57fc7e34..5ef81077 100644 --- a/src/main/app/js/services.js +++ b/src/main/app/js/services.js @@ -1,336 +1,375 @@ -var module = angular.module('commafeed.services', ['ngResource']); +var module = angular.module("commafeed.services", ["ngResource"]) -module.service('AnalyticsService', ['$state', function($state) { - this.track = function(path) { - if (typeof ga === 'undefined') { - return; - } - path = path || $state.$current.url.prefix; - ga('send', 'pageview', { - page : path - }); - }; -}]); +module.service("AnalyticsService", [ + "$state", + function ($state) { + this.track = function (path) { + if (typeof ga === "undefined") { + return + } + path = path || $state.$current.url.prefix + ga("send", "pageview", { + page: path, + }) + } + }, +]) -module.service('MobileService', ['$state', function($state) { - this.leftMenu = false; - this.rightMenu = false; - this.toggleLeftMenu = function() { - this.leftMenu = !this.leftMenu; - $('body').toggleClass('left-menu-active'); - }; - this.toggleRightMenu = function() { - this.rightMenu = !this.rightMenu; - $('body').toggleClass('right-menu-active'); - }; - this.mobile = device.mobile() || device.tablet(); -}]); +module.service("MobileService", [ + "$state", + function ($state) { + this.leftMenu = false + this.rightMenu = false + this.toggleLeftMenu = function () { + this.leftMenu = !this.leftMenu + $("body").toggleClass("left-menu-active") + } + this.toggleRightMenu = function () { + this.rightMenu = !this.rightMenu + $("body").toggleClass("right-menu-active") + } + this.mobile = device.mobile() || device.tablet() + }, +]) -module.factory('ProfileService', ['$resource', function($resource) { - var res = $resource('rest/user/profile/'); - res.deleteAccount = $resource('rest/user/profile/deleteAccount').save; - return res; -}]); +module.factory("ProfileService", [ + "$resource", + function ($resource) { + var res = $resource("rest/user/profile/") + res.deleteAccount = $resource("rest/user/profile/deleteAccount").save + return res + }, +]) -module.factory('SessionService', ['$resource', function($resource) { - var res = {}; - res.login = $resource('rest/user/login').save; - res.register = $resource('rest/user/register').save; - res.passwordReset = $resource('rest/user/passwordReset').save; - return res; -}]); +module.factory("SessionService", [ + "$resource", + function ($resource) { + var res = {} + res.login = $resource("rest/user/login").save + res.register = $resource("rest/user/register").save + res.passwordReset = $resource("rest/user/passwordReset").save + return res + }, +]) -module.factory('SettingsService', ['$resource', '$translate', function($resource, $translate) { - var res = $resource('rest/user/settings'); +module.factory("SettingsService", [ + "$resource", + "$translate", + function ($resource, $translate) { + var res = $resource("rest/user/settings") - var s = {}; - s.settings = {}; - s.save = function(callback) { - res.save(s.settings, function(data) { - if (callback) { - callback(data); - } - }); - }; - s.init = function(callback) { - res.get(function(data) { - s.settings = data; - var lang = s.settings.language || 'en'; - $translate.use(lang); - if (lang === 'zh') { - lang = 'zh-cn'; - } else if (lang === 'ms') { - lang = 'ms-my'; - } - moment.locale(lang, {}); - if (callback) { - callback(data); - } - }); - }; - s.init(); - return s; -}]); + var s = {} + s.settings = {} + s.save = function (callback) { + res.save(s.settings, function (data) { + if (callback) { + callback(data) + } + }) + } + s.init = function (callback) { + res.get(function (data) { + s.settings = data + var lang = s.settings.language || "en" + $translate.use(lang) + if (lang === "zh") { + lang = "zh-cn" + } else if (lang === "ms") { + lang = "ms-my" + } + moment.locale(lang, {}) + if (callback) { + callback(data) + } + }) + } + s.init() + return s + }, +]) -module.factory('FeedService', ['$resource', '$http', function($resource, $http) { - var actions = { - entries : { - method : 'GET', - params : { - _method : 'entries' - } - }, - fetch : { - method : 'POST', - params : { - _method : 'fetch' - } - }, - mark : { - method : 'POST', - params : { - _method : 'mark' - } - }, - refresh : { - method : 'POST', - params : { - _method : 'refresh' - } - }, - refreshAll : { - method : 'GET', - params : { - _method : 'refreshAll' - } - }, - subscribe : { - method : 'POST', - params : { - _method : 'subscribe' - } - }, - unsubscribe : { - method : 'POST', - params : { - _method : 'unsubscribe' - } - }, - modify : { - method : 'POST', - params : { - _method : 'modify' - } - } - }; - var res = $resource('rest/feed/:_method', {}, actions); - res.get = $resource('rest/feed/get/:id').get; - return res; -}]); +module.factory("FeedService", [ + "$resource", + "$http", + function ($resource, $http) { + var actions = { + entries: { + method: "GET", + params: { + _method: "entries", + }, + }, + fetch: { + method: "POST", + params: { + _method: "fetch", + }, + }, + mark: { + method: "POST", + params: { + _method: "mark", + }, + }, + refresh: { + method: "POST", + params: { + _method: "refresh", + }, + }, + refreshAll: { + method: "GET", + params: { + _method: "refreshAll", + }, + }, + subscribe: { + method: "POST", + params: { + _method: "subscribe", + }, + }, + unsubscribe: { + method: "POST", + params: { + _method: "unsubscribe", + }, + }, + modify: { + method: "POST", + params: { + _method: "modify", + }, + }, + } + var res = $resource("rest/feed/:_method", {}, actions) + res.get = $resource("rest/feed/get/:id").get + return res + }, +]) -module.factory('CategoryService', ['$resource', '$http', function($resource, $http) { +module.factory("CategoryService", [ + "$resource", + "$http", + function ($resource, $http) { + var traverse = function (callback, category, parentName) { + callback(category, parentName) + var children = category.children + if (children) { + for (var c = 0; c < children.length; c++) { + traverse(callback, children[c], category.name) + } + } + } - var traverse = function(callback, category, parentName) { - callback(category, parentName); - var children = category.children; - if (children) { - for (var c = 0; c < children.length; c++) { - traverse(callback, children[c], category.name); - } - } - }; + // flatten categories + var flatten = function (category) { + var array = [] + var callback = function (category, parentName) { + var name = category.name + if (parentName) { + name += " (in " + parentName + ")" + } + array.push({ + id: category.id, + name: name, + orig: category, + }) + } + traverse(callback, category) + return array + } - // flatten categories - var flatten = function(category) { - var array = []; - var callback = function(category, parentName) { - var name = category.name; - if (parentName) { - name += (' (in ' + parentName + ')'); - } - array.push({ - id : category.id, - name : name, - orig : category - }); - }; - traverse(callback, category); - return array; - }; + // flatten feeds + var flatFeeds = function (category) { + var subs = [] + var callback = function (category) { + subs.push.apply(subs, category.feeds) + } + traverse(callback, category) + return subs + } - // flatten feeds - var flatFeeds = function(category) { - var subs = []; - var callback = function(category) { - subs.push.apply(subs, category.feeds); - }; - traverse(callback, category); - return subs; - }; + // flatten everything + var flatAll = function (category, a) { + a.push([category.id, "category"]) + _.each(category.children, function (child) { + flatAll(child, a) + }) + _.each(category.feeds, function (feed) { + a.push([feed.id, "feed"]) + }) + } - // flatten everything - var flatAll = function(category, a) { - a.push([category.id, 'category']); - _.each(category.children, function(child) { - flatAll(child, a); - }); - _.each(category.feeds, function(feed) { - a.push([feed.id, 'feed']); - }); - }; + var actions = { + get: { + method: "GET", + ignoreLoadingBar: true, + params: { + _method: "get", + }, + }, + entries: { + method: "GET", + params: { + _method: "entries", + }, + }, + mark: { + method: "POST", + params: { + _method: "mark", + }, + }, + add: { + method: "POST", + params: { + _method: "add", + }, + }, + remove: { + method: "POST", + params: { + _method: "delete", + }, + }, + modify: { + method: "POST", + params: { + _method: "modify", + }, + }, + collapse: { + method: "POST", + params: { + _method: "collapse", + }, + }, + } + var res = $resource("rest/category/:_method", {}, actions) + res.subscriptions = {} + res.flatCategories = {} + res.feeds = [] - var actions = { - get : { - method : 'GET', - ignoreLoadingBar : true, - params : { - _method : 'get' - } - }, - entries : { - method : 'GET', - params : { - _method : 'entries' - } - }, - mark : { - method : 'POST', - params : { - _method : 'mark' - } - }, - add : { - method : 'POST', - params : { - _method : 'add' - } - }, - remove : { - method : 'POST', - params : { - _method : 'delete' - } - }, - modify : { - method : 'POST', - params : { - _method : 'modify' - } - }, - collapse : { - method : 'POST', - params : { - _method : 'collapse' - } - } - }; - var res = $resource('rest/category/:_method', {}, actions); - res.subscriptions = {}; - res.flatCategories = {}; - res.feeds = []; + res.init = function (callback) { + res.get(function (data) { + res.subscriptions = data + res.flatCategories = flatten(data) + res.feeds = flatFeeds(data) - res.init = function(callback) { - res.get(function(data) { - res.subscriptions = data; - res.flatCategories = flatten(data); - res.feeds = flatFeeds(data); + res.flatAll = [] + flatAll(data, res.flatAll) + res.flatAll.splice(1, 0, ["starred", "category"]) - res.flatAll = []; - flatAll(data, res.flatAll); - res.flatAll.splice(1, 0, ['starred', 'category']); + if (callback) callback(data) + }) + } + res.refresh = function (success, error) { + res.get( + function (data) { + _.merge(res.subscriptions, data) + if (success) success(data) + }, + function (data) { + if (error) error(data) + } + ) + } - if (callback) - callback(data); - }); - }; - res.refresh = function(success, error) { - res.get(function(data) { - _.merge(res.subscriptions, data); - if (success) - success(data); - }, function(data) { - if (error) - error(data); - }); - }; + res.init() + return res + }, +]) - res.init(); - return res; -}]); +module.factory("EntryService", [ + "$resource", + "$http", + function ($resource, $http) { + var actions = { + search: { + method: "GET", + params: { + _method: "search", + }, + }, + mark: { + method: "POST", + ignoreLoadingBar: true, + params: { + _method: "mark", + }, + }, + markMultiple: { + method: "POST", + params: { + _method: "markMultiple", + }, + }, + star: { + method: "POST", + params: { + _method: "star", + }, + }, + tag: { + method: "POST", + params: { + _method: "tag", + }, + }, + } + var res = $resource("rest/entry/:_method", {}, actions) + res.tags = [] + var initTags = function () { + $http.get("rest/entry/tags").success(function (data) { + res.tags = [] + res.tags.push.apply(res.tags, data) + res.tags.sort() + }) + } + var oldTag = res.tag + res.tag = function (data) { + oldTag(data, function () { + initTags() + }) + } + initTags() + return res + }, +]) -module.factory('EntryService', ['$resource', '$http', function($resource, $http) { - var actions = { - search : { - method : 'GET', - params : { - _method : 'search' - } - }, - mark : { - method : 'POST', - ignoreLoadingBar : true, - params : { - _method : 'mark' - } - }, - markMultiple : { - method : 'POST', - params : { - _method : 'markMultiple' - } - }, - star : { - method : 'POST', - params : { - _method : 'star' - } - }, - tag : { - method : 'POST', - params : { - _method : 'tag' - } - } - }; - var res = $resource('rest/entry/:_method', {}, actions); - res.tags = []; - var initTags = function() { - $http.get('rest/entry/tags').success(function(data) { - res.tags = []; - res.tags.push.apply(res.tags, data); - res.tags.sort(); - }); - }; - var oldTag = res.tag; - res.tag = function(data) { - oldTag(data, function() { - initTags(); - }); - }; - initTags(); - return res; -}]); +module.factory("AdminUsersService", [ + "$resource", + function ($resource) { + var res = {} + res.get = $resource("rest/admin/user/get/:id").get + res.getAll = $resource("rest/admin/user/getAll").query + res.save = $resource("rest/admin/user/save").save + res.remove = $resource("rest/admin/user/delete").save + return res + }, +]) -module.factory('AdminUsersService', ['$resource', function($resource) { - var res = {}; - res.get = $resource('rest/admin/user/get/:id').get; - res.getAll = $resource('rest/admin/user/getAll').query; - res.save = $resource('rest/admin/user/save').save; - res.remove = $resource('rest/admin/user/delete').save; - return res; -}]); +module.factory("AdminSettingsService", [ + "$resource", + function ($resource) { + var res = $resource("rest/admin/settings/") + return res + }, +]) -module.factory('AdminSettingsService', ['$resource', function($resource) { - var res = $resource('rest/admin/settings/'); - return res; -}]); +module.factory("AdminMetricsService", [ + "$resource", + function ($resource) { + var res = $resource("rest/admin/metrics/") + return res + }, +]) -module.factory('AdminMetricsService', ['$resource', function($resource) { - var res = $resource('rest/admin/metrics/'); - return res; -}]); - -module.factory('ServerService', ['$resource', function($resource) { - var res = $resource('rest/server/get'); - return res; -}]); \ No newline at end of file +module.factory("ServerService", [ + "$resource", + function ($resource) { + var res = $resource("rest/server/get") + return res + }, +]) diff --git a/src/main/app/js/welcome.js b/src/main/app/js/welcome.js index 71dc2b23..f28681f2 100644 --- a/src/main/app/js/welcome.js +++ b/src/main/app/js/welcome.js @@ -1,7 +1,7 @@ -$(function() { - var reg = $('#register-panel'); - if (!reg) { - return; - } - $('#login-panel').height(reg.height()); -}); \ No newline at end of file +$(function () { + var reg = $("#register-panel") + if (!reg) { + return + } + $("#login-panel").height(reg.height()) +}) diff --git a/src/main/app/manifest.json b/src/main/app/manifest.json index 78489d88..2647fc2b 100644 --- a/src/main/app/manifest.json +++ b/src/main/app/manifest.json @@ -1,31 +1,31 @@ { - "name": "CommaFeed", - "icons": [ - { - "src": "app-icon-72.png", - "sizes": "72x72", - "type": "image/png", - "density": "1.5" - }, - { - "src": "app-icon-114.png", - "sizes": "96x96", - "type": "image/png", - "density": "2.0" - }, - { - "src": "app-icon-144.png", - "sizes": "144x144", - "type": "image/png", - "density": "3.0" - }, - { - "src": "app-icon-192.png", - "sizes": "192x192", - "type": "image/png", - "density": "4.0" - } - ], - "start_url": "/", - "display": "standalone" + "name": "CommaFeed", + "icons": [ + { + "src": "app-icon-72.png", + "sizes": "72x72", + "type": "image/png", + "density": "1.5" + }, + { + "src": "app-icon-114.png", + "sizes": "96x96", + "type": "image/png", + "density": "2.0" + }, + { + "src": "app-icon-144.png", + "sizes": "144x144", + "type": "image/png", + "density": "3.0" + }, + { + "src": "app-icon-192.png", + "sizes": "192x192", + "type": "image/png", + "density": "4.0" + } + ], + "start_url": "/", + "display": "standalone" } diff --git a/src/main/app/templates/_category.html b/src/main/app/templates/_category.html index d6f59fd8..0e849fcb 100644 --- a/src/main/app/templates/_category.html +++ b/src/main/app/templates/_category.html @@ -1,38 +1,66 @@
  • -
    - - -
    - +
    + + +
    +
  • diff --git a/src/main/app/templates/_feedsearch.html b/src/main/app/templates/_feedsearch.html index 2f87e9ed..da9bafab 100644 --- a/src/main/app/templates/_feedsearch.html +++ b/src/main/app/templates/_feedsearch.html @@ -1,29 +1,33 @@
    -
    - -
    -
    \ No newline at end of file +
    + +
    + diff --git a/src/main/app/templates/_footer.html b/src/main/app/templates/_footer.html index 167cc2b6..7130dd40 100644 --- a/src/main/app/templates/_footer.html +++ b/src/main/app/templates/_footer.html @@ -1,3 +1,3 @@
    - -
    \ No newline at end of file + + diff --git a/src/main/app/templates/_metrics.gauge.html b/src/main/app/templates/_metrics.gauge.html index f9b3dddc..f9abfc12 100644 --- a/src/main/app/templates/_metrics.gauge.html +++ b/src/main/app/templates/_metrics.gauge.html @@ -1,4 +1,4 @@
    - {{label}} - {{metric.value}} -
    \ No newline at end of file + {{label}} + {{metric.value}} + diff --git a/src/main/app/templates/_metrics.meter.html b/src/main/app/templates/_metrics.meter.html index a05402dc..c2cf9016 100644 --- a/src/main/app/templates/_metrics.meter.html +++ b/src/main/app/templates/_metrics.meter.html @@ -1,14 +1,13 @@
    - {{label}} -
    -
    Mean
    -
    {{metric.mean_rate | number:2}}
    + {{label}} +
    +
    Mean
    +
    {{metric.mean_rate | number:2}}
    -
    1/5/15 min
    -
    {{metric.m1_rate | number:2}} {{metric.m5_rate | number:2}} {{metric.m15_rate | number:2}}
    +
    1/5/15 min
    +
    {{metric.m1_rate | number:2}} {{metric.m5_rate | number:2}} {{metric.m15_rate | number:2}}
    -
    Total
    -
    {{metric.count}}
    - -
    -
    \ No newline at end of file +
    Total
    +
    {{metric.count}}
    + + diff --git a/src/main/app/templates/_metrics.timer.html b/src/main/app/templates/_metrics.timer.html index c84f499b..d77439d3 100644 --- a/src/main/app/templates/_metrics.timer.html +++ b/src/main/app/templates/_metrics.timer.html @@ -1,17 +1,16 @@
    - {{label}} -
    -
    Mean
    -
    {{metric.mean_rate | number:2}}
    + {{label}} +
    +
    Mean
    +
    {{metric.mean_rate | number:2}}
    -
    1/5/15 min
    -
    {{metric.m1_rate | number:2}} {{metric.m5_rate | number:2}} {{metric.m15_rate | number:2}}
    +
    1/5/15 min
    +
    {{metric.m1_rate | number:2}} {{metric.m5_rate | number:2}} {{metric.m15_rate | number:2}}
    -
    Total
    -
    {{metric.count}}
    - -
    min/max/mean (ms)
    -
    {{metric.min/1000000 | number:0}} {{metric.max/1000000 | number:0}} {{metric.mean/1000000 | number:0}}
    +
    Total
    +
    {{metric.count}}
    -
    -
    \ No newline at end of file +
    min/max/mean (ms)
    +
    {{metric.min/1000000 | number:0}} {{metric.max/1000000 | number:0}} {{metric.mean/1000000 | number:0}}
    + + diff --git a/src/main/app/templates/_shortcuts.html b/src/main/app/templates/_shortcuts.html index 507fe891..b94158d5 100644 --- a/src/main/app/templates/_shortcuts.html +++ b/src/main/app/templates/_shortcuts.html @@ -1,74 +1,73 @@
    -
    r
    -
    {{ 'about.shortcuts.refresh' | translate }}
    +
    r
    +
    {{ 'about.shortcuts.refresh' | translate }}
    -
    j
    -
    {{ 'about.shortcuts.open_next_entry' | translate }}
    +
    j
    +
    {{ 'about.shortcuts.open_next_entry' | translate }}
    -
    k
    -
    {{ 'about.shortcuts.open_previous_entry' | translate }}
    +
    k
    +
    {{ 'about.shortcuts.open_previous_entry' | translate }}
    -
    {{ 'about.shortcuts.spacebar' | translate }}
    -
    {{ 'about.shortcuts.move_page_down_up' | translate }}
    +
    {{ 'about.shortcuts.spacebar' | translate }}
    +
    {{ 'about.shortcuts.move_page_down_up' | translate }}
    -
    n
    -
    {{ 'about.shortcuts.focus_next_entry' | translate }}
    +
    n
    +
    {{ 'about.shortcuts.focus_next_entry' | translate }}
    -
    p
    -
    {{ 'about.shortcuts.focus_previous_entry' | translate }}
    +
    p
    +
    {{ 'about.shortcuts.focus_previous_entry' | translate }}
    -
    shift+j,shift+n
    -
    {{ 'about.shortcuts.open_next_feed' | translate }}
    +
    shift+j,shift+n
    +
    {{ 'about.shortcuts.open_next_feed' | translate }}
    -
    shift+k,shift+p
    -
    {{ 'about.shortcuts.open_previous_feed' | translate }}
    +
    shift+k,shift+p
    +
    {{ 'about.shortcuts.open_previous_feed' | translate }}
    -
    o, enter
    -
    {{ 'about.shortcuts.open_close_current_entry' | translate }}
    +
    o, enter
    +
    {{ 'about.shortcuts.open_close_current_entry' | translate }}
    -
    v
    -
    {{ 'about.shortcuts.open_current_entry_in_new_window' | translate }}
    +
    v
    +
    {{ 'about.shortcuts.open_current_entry_in_new_window' | translate }}
    -
    b
    -
    {{ 'about.shortcuts.open_current_entry_in_new_window_background' | translate }}
    +
    b
    +
    {{ 'about.shortcuts.open_current_entry_in_new_window_background' | translate }}
    -
    s
    -
    {{ 'about.shortcuts.star_unstar' | translate }}
    +
    s
    +
    {{ 'about.shortcuts.star_unstar' | translate }}
    -
    m
    -
    {{ 'about.shortcuts.mark_current_entry' | translate }}
    +
    m
    +
    {{ 'about.shortcuts.mark_current_entry' | translate }}
    -
    shift+a
    -
    {{ 'about.shortcuts.mark_all_as_read' | translate }}
    +
    shift+a
    +
    {{ 'about.shortcuts.mark_all_as_read' | translate }}
    -
    {{ 'about.shortcuts.mouse_middleclick' | translate }}
    -
    {{ 'about.shortcuts.open_in_new_tab_mark_as_read' | translate }}
    +
    {{ 'about.shortcuts.mouse_middleclick' | translate }}
    +
    {{ 'about.shortcuts.open_in_new_tab_mark_as_read' | translate }}
    -
    f
    -
    {{ 'about.shortcuts.fullscreen' | translate }}
    +
    f
    +
    {{ 'about.shortcuts.fullscreen' | translate }}
    -
    +,-
    -
    {{ 'about.shortcuts.font_size' | translate }}
    +
    +,-
    +
    {{ 'about.shortcuts.font_size' | translate }}
    -
    - g - - a -
    -
    {{ 'about.shortcuts.go_to_all' | translate }}
    +
    + g + + a +
    +
    {{ 'about.shortcuts.go_to_all' | translate }}
    -
    - g - - s -
    -
    {{ 'about.shortcuts.go_to_starred' | translate }}
    - -
    - g - - u -
    -
    {{ 'about.shortcuts.feed_search' | translate }}
    +
    + g + + s +
    +
    {{ 'about.shortcuts.go_to_starred' | translate }}
    +
    + g + + u +
    +
    {{ 'about.shortcuts.feed_search' | translate }}
    diff --git a/src/main/app/templates/_tags.html b/src/main/app/templates/_tags.html index 31923388..8c993b36 100644 --- a/src/main/app/templates/_tags.html +++ b/src/main/app/templates/_tags.html @@ -1,12 +1,12 @@ - - - {{ 'global.tags' | translate }} - - - {{tag}} - - - - - \ No newline at end of file + + + {{ 'global.tags' | translate }} + + + {{tag}} + + + + +
    diff --git a/src/main/app/templates/_toolbar.html b/src/main/app/templates/_toolbar.html index b4cddf6e..8f670109 100644 --- a/src/main/app/templates/_toolbar.html +++ b/src/main/app/templates/_toolbar.html @@ -1,136 +1,169 @@
    -
    diff --git a/src/main/app/templates/_tree.html b/src/main/app/templates/_tree.html index 444ced29..c583d07a 100644 --- a/src/main/app/templates/_tree.html +++ b/src/main/app/templates/_tree.html @@ -1,49 +1,86 @@ - diff --git a/src/main/app/templates/admin.html b/src/main/app/templates/admin.html index 1ee2e69a..b6db5921 100644 --- a/src/main/app/templates/admin.html +++ b/src/main/app/templates/admin.html @@ -1,3 +1,3 @@
    -
    -
    \ No newline at end of file +
    + diff --git a/src/main/app/templates/admin.metrics.html b/src/main/app/templates/admin.metrics.html index d853fcbc..a4c44e8d 100644 --- a/src/main/app/templates/admin.metrics.html +++ b/src/main/app/templates/admin.metrics.html @@ -1,28 +1,60 @@
    -
    - - - - - - - - +
    + + + + + - - + + - - - -
    -
    -
    - -
    -
    -
    \ No newline at end of file + + + + + + +
    +
    +
    + +
    +
    + diff --git a/src/main/app/templates/admin.settings.html b/src/main/app/templates/admin.settings.html index e9809291..3bba5b46 100644 --- a/src/main/app/templates/admin.settings.html +++ b/src/main/app/templates/admin.settings.html @@ -1,157 +1,183 @@
    - + -
    -
    -
    -
    -
    - -
    - - The URL in your address bar right now, up to the # (not included) -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - - Requires restart -
    -
    -
    - -
    - - Requires restart -
    -
    -
    - -
    - -
    -
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    -
    - - Don't use this unless you know what you're doing! -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - - 0 = keep forever -
    -
    -
    - -
    - -
    -
    -
    - -
    -
    - -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    \ No newline at end of file +
    +
    +
    +
    +
    + +
    + + The URL in your address bar right now, up to the # (not included) +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + + Requires restart +
    +
    +
    + +
    + + Requires restart +
    +
    +
    + +
    + +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + Don't use this unless you know what you're doing! +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + + 0 = keep forever +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + diff --git a/src/main/app/templates/admin.useradd.html b/src/main/app/templates/admin.useradd.html index ace68a95..9f3cfb0c 100644 --- a/src/main/app/templates/admin.useradd.html +++ b/src/main/app/templates/admin.useradd.html @@ -1,40 +1,40 @@
    - + - {{alert.msg}} + {{alert.msg}} -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - - -
    -
    -
    -
    \ No newline at end of file +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + +
    +
    +
    + diff --git a/src/main/app/templates/admin.useredit.html b/src/main/app/templates/admin.useredit.html index c8a9e4d1..08fa4acd 100644 --- a/src/main/app/templates/admin.useredit.html +++ b/src/main/app/templates/admin.useredit.html @@ -1,48 +1,55 @@
    - + - {{alert.msg}} + {{alert.msg}} -
    -
    - -
    - -
    -
    -
    - -
    - - Leave blank if you don't want to change the password. -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - - - -
    -
    -
    -
    \ No newline at end of file +
    +
    + +
    + +
    +
    +
    + +
    + + Leave blank if you don't want to change the password. +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + + +
    +
    +
    + diff --git a/src/main/app/templates/admin.userlist.html b/src/main/app/templates/admin.userlist.html index 1f68a9a6..6bb7577f 100644 --- a/src/main/app/templates/admin.userlist.html +++ b/src/main/app/templates/admin.userlist.html @@ -1,13 +1,13 @@
    - + -
    -
    - - -
    -
    -
    -
    \ No newline at end of file +
    +
    + + +
    +
    +
    + diff --git a/src/main/app/templates/feeds.category_details.html b/src/main/app/templates/feeds.category_details.html index d44441f8..ecac7c0a 100644 --- a/src/main/app/templates/feeds.category_details.html +++ b/src/main/app/templates/feeds.category_details.html @@ -1,49 +1,63 @@
    - -
    -
    - -
    - - {{ 'global.required' | translate }} -
    -
    + + +
    + +
    + + {{ 'global.required' | translate }} +
    +
    -
    - -
    - - {{ 'global.required' | translate }} -
    -
    +
    + +
    + + {{ 'global.required' | translate }} +
    +
    -
    - -
    - -
    -
    +
    + +
    + +
    +
    -
    - -
    - {{ 'global.link' | translate }} - {{ 'details.generate_api_key_first' | translate }} -
    -
    - -
    -
    - - - -
    -
    -
    +
    + +
    + {{ 'global.link' | translate }} + {{ 'details.generate_api_key_first' | translate }} +
    +
    +
    +
    + + + +
    +
    +
    diff --git a/src/main/app/templates/feeds.feed_details.html b/src/main/app/templates/feeds.feed_details.html index 66f1ebe1..faaaf117 100644 --- a/src/main/app/templates/feeds.feed_details.html +++ b/src/main/app/templates/feeds.feed_details.html @@ -1,90 +1,101 @@
    - -
    -
    {{ error }}
    -
    - - -
    -
    - - -
    -
    - -
    - - {{ 'global.required' | translate }} -
    -
    + + +
    {{ error }}
    +
    + + +
    +
    + + +
    +
    + +
    + + {{ 'global.required' | translate }} +
    +
    -
    - -
    - - {{ 'global.required' | translate }} -
    -
    +
    + +
    + + {{ 'global.required' | translate }} +
    +
    -
    - -
    - -
    -
    +
    + +
    + +
    +
    -
    - -
    - {{sub.lastRefresh|entryDate}} -
    -
    +
    + +
    + {{sub.lastRefresh|entryDate}} +
    +
    -
    - -
    - {{sub.nextRefresh|entryDate:('details.queued_for_refresh' | translate) }} -
    -
    +
    + +
    + {{sub.nextRefresh|entryDate:('details.queued_for_refresh' | translate) }} +
    +
    -
    - -
    - {{sub.message}} -
    -
    +
    + +
    + {{sub.message}} +
    +
    -
    - -
    - {{ 'global.link' | translate }} - {{ 'details.generate_api_key_first' | translate }} -
    -
    +
    + +
    + {{ 'global.link' | translate }} + {{ 'details.generate_api_key_first' | translate }} +
    +
    -
    - -
    - -

    -
    -
    - -
    -
    - - - -
    -
    -
    +
    + +
    + +

    +
    +
    +
    +
    + + + +
    +
    +
    diff --git a/src/main/app/templates/feeds.help.html b/src/main/app/templates/feeds.help.html index 1fccab89..a2bf2559 100644 --- a/src/main/app/templates/feeds.help.html +++ b/src/main/app/templates/feeds.help.html @@ -1,144 +1,163 @@
    -
    +
    +
    +

    + + {{ 'toolbar.about' | translate }} +

    +

    + {{ 'about.line1_prefix' | translate }} + GitHub + {{ 'about.line1_suffix' | translate }} +

    +

    + {{ 'about.line2_prefix' | translate }} + GitHub + {{ 'about.line2_suffix' | translate }} +

    + {{ 'about.version' | translate }} {{infos.version}} ({{infos.gitCommit}}) +
    -
    -

    - - {{ 'toolbar.about' | translate }} -

    -

    - {{ 'about.line1_prefix' | translate }} - GitHub - {{ 'about.line1_suffix' | translate }} -

    -

    - {{ 'about.line2_prefix' | translate }} - GitHub - {{ 'about.line2_suffix' | translate }} -

    - {{ 'about.version' | translate }} {{infos.version}} ({{infos.gitCommit}}) -
    +
    +

    + + {{ 'toolbar.donate' | translate }} +

    +

    {{ 'about.line3' | translate }}

    + + {{ 'about.line4' | translate }} + 1dymfUxqCWpyD7a6rQSqNy4rLVDBsAr5e +
    -
    -

    - - {{ 'toolbar.donate' | translate }} -

    -

    {{ 'about.line3' | translate }}

    - - {{ 'about.line4' | translate }} - 1dymfUxqCWpyD7a6rQSqNy4rLVDBsAr5e -
    +
    +

    + + {{ 'about.goodies.value' | translate }} +

    +

    + {{ 'about.goodies.android_app' | translate }}: + News+ extension + , + CommaFeed Reader + , + Cloudfeedlr +

    +

    + {{ 'about.goodies.chrome_extension' | translate }} +

    +

    + {{ 'about.goodies.firefox_extension' | translate }} +

    +

    + {{ 'about.goodies.opera_extension' | translate }} +

    -
    -

    - - {{ 'about.goodies.value' | translate }} -

    -

    - {{ 'about.goodies.android_app' | translate }}: - News+ extension - , - CommaFeed Reader - , - Cloudfeedlr -

    -

    - {{ 'about.goodies.chrome_extension' | translate }} -

    -

    - {{ 'about.goodies.firefox_extension' | translate }} -

    -

    - {{ 'about.goodies.opera_extension' | translate }} -

    +

    + {{ 'about.goodies.subscribe_url' | translate }}: + rest/feed/subscribe?url=FEED_URL_HERE +

    +

    + {{ 'about.goodies.subscribe_bookmarklet' | translate }}: + SubToMe +

    +

    + {{ 'about.goodies.next_unread_bookmarklet' | translate }}: +
    +
    + {{ 'subscribe.category' | translate }} + + + {{ 'global.link' | translate }} +

    +
    -

    - {{ 'about.goodies.subscribe_url' | translate }}: - rest/feed/subscribe?url=FEED_URL_HERE -

    -

    - {{ 'about.goodies.subscribe_bookmarklet' | translate }}: - SubToMe -

    -

    - {{ 'about.goodies.next_unread_bookmarklet' | translate }}: -
    -
    - {{ 'subscribe.category' | translate }} - - - {{ 'global.link' | translate }} -

    -
    +
    +

    + + {{ 'about.translation.value' | translate }} +

    +

    {{ 'about.translation.message' | translate }}

    +

    + + {{ 'about.translation.link' | translate }} + +

    +
    +
    +

    + + {{ 'about.rest_api.value' | translate }} +

    +

    {{ 'about.rest_api.line1' | translate }}

    +

    + {{ 'about.rest_api.link_to_documentation' | translate }} +

    +
    +
    +
    +
    +

    + + {{ 'about.keyboard_shortcuts' | translate }} +

    +
    +
    -
    -

    - - {{ 'about.translation.value' | translate }} -

    -

    {{ 'about.translation.message' | translate }}

    -

    - {{ 'about.translation.link' | translate }} -

    -
    -
    -

    - - {{ 'about.rest_api.value' | translate }} -

    -

    {{ 'about.rest_api.line1' | translate }}

    -

    - {{ 'about.rest_api.link_to_documentation' | translate }} -

    -
    -
    -
    -
    -

    - - {{ 'about.keyboard_shortcuts' | translate }} -

    -
    -
    - -
    -

    - - {{ 'about.announcements' | translate }} -

    - - -
    - - -
    +
    +

    + + {{ 'about.announcements' | translate }} +

    + + +
    +
    diff --git a/src/main/app/templates/feeds.html b/src/main/app/templates/feeds.html index 716d75aa..a4d509d6 100644 --- a/src/main/app/templates/feeds.html +++ b/src/main/app/templates/feeds.html @@ -1,13 +1,13 @@
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    \ No newline at end of file +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + diff --git a/src/main/app/templates/feeds.import.html b/src/main/app/templates/feeds.import.html index c41875fd..7b38b0aa 100644 --- a/src/main/app/templates/feeds.import.html +++ b/src/main/app/templates/feeds.import.html @@ -1,19 +1,19 @@
    - -
    -
    - -
    - -
    -
    -
    -
    - - -
    -
    -
    -
    \ No newline at end of file + +
    +
    + +
    + +
    +
    +
    +
    + + +
    +
    +
    + diff --git a/src/main/app/templates/feeds.new_category.html b/src/main/app/templates/feeds.new_category.html index 8382541e..90cb4d41 100644 --- a/src/main/app/templates/feeds.new_category.html +++ b/src/main/app/templates/feeds.new_category.html @@ -1,29 +1,33 @@
    - -
    -
    - -
    - - {{ 'global.required' | translate }} -
    -
    -
    - -
    - - {{ 'global.required' | translate }} -
    -
    -
    -
    - - -
    -
    -
    -
    \ No newline at end of file + +
    +
    + +
    + + {{ 'global.required' | translate }} +
    +
    +
    + +
    + + {{ 'global.required' | translate }} +
    +
    +
    +
    + + +
    +
    +
    + diff --git a/src/main/app/templates/feeds.subscribe.html b/src/main/app/templates/feeds.subscribe.html index 84967cbc..9cb86a71 100644 --- a/src/main/app/templates/feeds.subscribe.html +++ b/src/main/app/templates/feeds.subscribe.html @@ -1,39 +1,52 @@
    - -
    -
    - -
    - - {{ 'global.required' | translate }} -
    -
    -
    - -
    - - {{ 'global.required' | translate }} -
    -
    -
    - -
    - - {{ 'global.required' | translate }} -
    -
    -
    -
    - - -
    -
    -
    - -
    {{stacktrace}}
    -
    \ No newline at end of file + +
    +
    + +
    + + {{ 'global.required' | translate }} +
    +
    +
    + +
    + + {{ 'global.required' | translate }} +
    +
    +
    + +
    + + {{ 'global.required' | translate }} +
    +
    +
    +
    + + +
    +
    +
    + +
    {{stacktrace}}
    + diff --git a/src/main/app/templates/feeds.tag_details.html b/src/main/app/templates/feeds.tag_details.html index 66f440a5..893eb120 100644 --- a/src/main/app/templates/feeds.tag_details.html +++ b/src/main/app/templates/feeds.tag_details.html @@ -1,23 +1,27 @@
    - -
    -
    - -
    -
    - {{ 'global.link' | translate }} - {{ 'details.generate_api_key_first' | translate }} -
    -
    -
    - -
    -
    - -
    -
    -
    + +
    +
    + +
    +
    + {{ 'global.link' | translate }} + {{ 'details.generate_api_key_first' | translate }} +
    +
    +
    +
    +
    + +
    +
    +
    diff --git a/src/main/app/templates/feeds.view.html b/src/main/app/templates/feeds.view.html index a9085559..e72213df 100644 --- a/src/main/app/templates/feeds.view.html +++ b/src/main/app/templates/feeds.view.html @@ -1,155 +1,241 @@
    -
    -

    - - {{ 'tree.all' | translate }} - {{ 'tree.starred' | translate }} - - {{name}} - {{name}} - - - » - {{ 'view.search_for' | translate }} '{{ keywords }}' -

    -
    +
    +

    + + {{ 'tree.all' | translate }} + {{ 'tree.starred' | translate }} + + {{name}} + {{name}} + + + » + {{ 'view.search_for' | translate }} '{{ keywords }}' +

    +
    -
    -
    {{ 'view.error_while_loading_feed' | translate }} : {{ message }}
    -
    -
    - - - - - - - {{entry.feedName}} - - - - - - - -
    -
    -
    -
    - -
    - - {{ 'view.entry_source' | translate }} - - {{entry.feedName}} - - - - - ({{entry.categories}}) - -
    -
    -
    +
    +
    {{ 'view.error_while_loading_feed' | translate }} : {{ message }}
    +
    +
    + + + + + + + {{entry.feedName}} + + + + + + + +
    +
    +
    +
    + +
    + + {{ 'view.entry_source' | translate }} + + {{entry.feedName}} + + + + + ({{entry.categories}}) + +
    +
    +
    -
    -
    -
    -
    - - -
    - -
    - {{ 'global.download' | translate }} -
    -
    -
    -
    - -
    -
    - -
    +
    +
    +
    +
    + + +
    + +
    + + {{ 'global.download' | translate }} + +
    +
    +
    +
    + +
    +
    + +
    - + - - - - - - -
    -
    -
    -
    - {{ 'view.no_search_results' | translate }} - "{{name}}" {{ 'view.no_unread_items' | translate }} -
    -
    - -
    -
    -
    -
    + + + + + + +
    +
    +
    +
    + {{ 'view.no_search_results' | translate }} + "{{name}}" {{ 'view.no_unread_items' | translate }} +
    +
    + +
    +
    +
    +
    diff --git a/src/main/app/templates/profile.html b/src/main/app/templates/profile.html index 8c72b518..79a0438f 100644 --- a/src/main/app/templates/profile.html +++ b/src/main/app/templates/profile.html @@ -1,66 +1,90 @@
    - -
    -
    - -
    - {{user.name}} -
    -
    -
    - -
    - -
    -
    -
    - -
    - - {{ 'profile.minimum_6_chars' | translate }} -
    -
    -
    - -
    - - {{ 'profile.passwords_do_not_match' | translate }} -
    -
    + + +
    + +
    + {{user.name}} +
    +
    +
    + +
    + +
    +
    +
    + +
    + + {{ 'profile.minimum_6_chars' | translate }} +
    +
    +
    + +
    + + {{ 'profile.passwords_do_not_match' | translate }} +
    +
    -
    - -
    -
    {{user.apiKey}}
    - {{ 'profile.api_key_not_generated' | translate }} -
    -
    -
    - -
    -
    - - {{ 'profile.generate_new_api_key_info' | translate }} -
    -
    -
    -
    - - -
    +
    + +
    +
    {{user.apiKey}}
    + {{ 'profile.api_key_not_generated' | translate }} +
    +
    +
    + +
    +
    + + {{ 'profile.generate_new_api_key_info' | translate }} +
    +
    +
    +
    + + +
    -
    -
    - - - -
    -
    -
    -
    \ No newline at end of file +
    +
    + + + +
    +
    + + diff --git a/src/main/app/templates/settings.html b/src/main/app/templates/settings.html index b43fce60..60d96382 100644 --- a/src/main/app/templates/settings.html +++ b/src/main/app/templates/settings.html @@ -1,145 +1,151 @@
    - -
    -
    - -
    -
    -
    -
    -
    - - - - - {{ 'settings.general.language_contribute' | translate }} - -
    -
    - -
    -
    - -
    -
    -

    {{ 'settings.general.social_buttons' | translate }}

    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    -
    -
    -
    -
    - - - {{ 'settings.scroll_speed_help' | translate }} -
    -
    - - - - {{ 'settings.submit_your_theme' | translate }} - -
    -
    - - -
    -
    -
    -
    -
    -
    - - -
    -
    -
    \ No newline at end of file + +
    +
    + +
    +
    +
    +
    +
    + + + + + {{ 'settings.general.language_contribute' | translate }} + + +
    +
    + +
    +
    + +
    +
    +

    {{ 'settings.general.social_buttons' | translate }}

    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + + + {{ 'settings.scroll_speed_help' | translate }} +
    +
    + + + + + {{ 'settings.submit_your_theme' | translate }} + + +
    +
    + + +
    +
    +
    +
    +
    +
    + + +
    +
    + diff --git a/src/main/app/templates/welcome.html b/src/main/app/templates/welcome.html index 4bc6ee1c..7b82ea4a 100644 --- a/src/main/app/templates/welcome.html +++ b/src/main/app/templates/welcome.html @@ -1,111 +1,115 @@
    -
    -
    - - - -
    -
    Bloat-free feed reader
    - -
    -
    -
    -
    -

    Login

    - -
    -
    - - -
    -
    - - -
    - -
    -
    -
    -

    Password Recovery

    - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -

    Register

    -
    {{message}}
    -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - -
    -
    -
    -
    -
    -
    +
    +
    + + + +
    +
    Bloat-free feed reader
    + +
    +
    +
    +
    +

    Login

    + +
    +
    + + +
    +
    + + +
    + +
    +
    +
    +

    Password Recovery

    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +

    Register

    +
    {{message}}
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    +
    -
    - +
    +