summaryrefslogtreecommitdiffstats
path: root/js/build/app.js
diff options
context:
space:
mode:
authorBernhard Posselt <dev@bernhard-posselt.com>2014-09-16 16:24:20 +0200
committerBernhard Posselt <dev@bernhard-posselt.com>2014-09-16 16:24:20 +0200
commit9e36ef31f9bf16d43326fd047619ada5ff16e072 (patch)
treee228816adedacfed87eb08e8bc86658536cbbe86 /js/build/app.js
parent6a7ac3d9da3dea4130eb08a07a0a0603418d54ab (diff)
parent21728afff571adfc508cf5fa473d094946ef188f (diff)
merge
Diffstat (limited to 'js/build/app.js')
-rw-r--r--js/build/app.js2252
1 files changed, 2252 insertions, 0 deletions
diff --git a/js/build/app.js b/js/build/app.js
new file mode 100644
index 000000000..442f2095e
--- /dev/null
+++ b/js/build/app.js
@@ -0,0 +1,2252 @@
+(function(window, document, angular, $, OC, csrfToken, undefined){
+
+'use strict';
+
+
+var app = angular.module('News', ['ngRoute', 'ngSanitize']);
+app.config(["$routeProvider", "$provide", "$httpProvider", function ($routeProvider, $provide, $httpProvider) {
+ 'use strict';
+
+ var feedType = {
+ FEED: 0,
+ FOLDER: 1,
+ STARRED: 2,
+ SUBSCRIPTIONS: 3,
+ SHARED: 4
+ };
+
+ // constants
+ $provide.constant('REFRESH_RATE', 60); // seconds
+ $provide.constant('ITEM_BATCH_SIZE', 50); // how many items to autopage by
+ $provide.constant('BASE_URL', OC.generateUrl('/apps/news'));
+ $provide.constant('FEED_TYPE', feedType);
+
+ // make sure that the CSRF header is only sent to the ownCloud domain
+ $provide.factory('CSRFInterceptor', ["$q", "BASE_URL", function ($q, BASE_URL) {
+ return {
+ request: function (config) {
+ if (config.url.indexOf(BASE_URL) === 0) {
+ config.headers.requesttoken = csrfToken;
+ }
+
+ return config || $q.when(config);
+ }
+ };
+ }]);
+ $httpProvider.interceptors.push('CSRFInterceptor');
+
+ // routing
+ var getResolve = function (type) {
+ return {
+ // request to items also returns feeds
+ data: [
+ '$http',
+ '$route',
+ '$q',
+ 'BASE_URL',
+ 'ITEM_BATCH_SIZE',
+ function ($http, $route, $q, BASE_URL, ITEM_BATCH_SIZE) {
+
+ var parameters = {
+ type: type,
+ limit: ITEM_BATCH_SIZE
+ };
+
+ if ($route.current.params.id !== undefined) {
+ parameters.id = $route.current.params.id;
+ }
+
+ var deferred = $q.defer();
+
+ $http({
+ url: BASE_URL + '/items',
+ method: 'GET',
+ params: parameters
+ }).success(function (data) {
+ deferred.resolve(data);
+ });
+
+ return deferred.promise;
+ }
+ ]
+ };
+ };
+
+ $routeProvider
+ .when('/items', {
+ controller: 'ContentController as Content',
+ templateUrl: 'content.html',
+ resolve: getResolve(feedType.SUBSCRIPTIONS),
+ type: feedType.SUBSCRIPTIONS
+ })
+ .when('/items/starred', {
+ controller: 'ContentController as Content',
+ templateUrl: 'content.html',
+ resolve: getResolve(feedType.STARRED),
+ type: feedType.STARRED
+ })
+ .when('/items/feeds/:id', {
+ controller: 'ContentController as Content',
+ templateUrl: 'content.html',
+ resolve: getResolve(feedType.FEED),
+ type: feedType.FEED
+ })
+ .when('/items/folders/:id', {
+ controller: 'ContentController as Content',
+ templateUrl: 'content.html',
+ resolve: getResolve(feedType.FOLDER),
+ type: feedType.FOLDER
+ });
+
+}]);
+
+
+app.run(["$rootScope", "$location", "$http", "$q", "$interval", "Loading", "ItemResource", "FeedResource", "FolderResource", "SettingsResource", "Publisher", "BASE_URL", "FEED_TYPE", "REFRESH_RATE", function ($rootScope, $location, $http, $q, $interval, Loading,
+ ItemResource, FeedResource, FolderResource, SettingsResource,
+ Publisher, BASE_URL, FEED_TYPE, REFRESH_RATE) {
+ 'use strict';
+
+ // show Loading screen
+ Loading.setLoading('global', true);
+
+ // listen to keys in returned queries to automatically distribute the
+ // incoming values to models
+ Publisher.subscribe(ItemResource).toChannels(['items', 'newestItemId',
+ 'starred']);
+ Publisher.subscribe(FolderResource).toChannels(['folders']);
+ Publisher.subscribe(FeedResource).toChannels(['feeds']);
+ Publisher.subscribe(SettingsResource).toChannels(['settings']);
+
+ // load feeds, settings and last read feed
+ var settingsDeferred = $q.defer();
+ $http.get(BASE_URL + '/settings').success(function (data) {
+ Publisher.publishAll(data);
+ settingsDeferred.resolve();
+ });
+
+ var activeFeedDeferred = $q.defer();
+ var path = $location.path();
+ $http.get(BASE_URL + '/feeds/active').success(function (data) {
+ var url;
+
+ switch (data.activeFeed.type) {
+
+ case FEED_TYPE.FEED:
+ url = '/items/feeds/' + data.activeFeed.id;
+ break;
+
+ case FEED_TYPE.FOLDER:
+ url = '/items/folders/' + data.activeFeed.id;
+ break;
+
+ case FEED_TYPE.STARRED:
+ url = '/items/starred';
+ break;
+
+ default:
+ url = '/items';
+ }
+
+ // only redirect if url is empty or faulty
+ if (!/^\/items(\/(starred|feeds\/\d+|folders\/\d+))?\/?$/.test(path)) {
+ $location.path(url);
+ }
+
+ activeFeedDeferred.resolve();
+ });
+
+ var folderDeferred = $q.defer();
+ $http.get(BASE_URL + '/folders').success(function (data) {
+ Publisher.publishAll(data);
+ folderDeferred.resolve();
+ });
+
+ var feedDeferred = $q.defer();
+ $http.get(BASE_URL + '/feeds').success(function (data) {
+ Publisher.publishAll(data);
+ feedDeferred.resolve();
+ });
+
+ // disable loading if all initial requests finished
+ $q.all(
+ [
+ settingsDeferred.promise,
+ activeFeedDeferred.promise,
+ feedDeferred.promise,
+ folderDeferred.promise
+ ]
+ )
+ .then(function () {
+ Loading.setLoading('global', false);
+ });
+
+ // refresh feeds and folders
+ $interval(function () {
+ $http.get(BASE_URL + '/feeds');
+ $http.get(BASE_URL + '/folders');
+ }, REFRESH_RATE * 1000);
+
+
+ $rootScope.$on('$routeChangeStart', function () {
+ Loading.setLoading('content', true);
+ });
+
+ $rootScope.$on('$routeChangeSuccess', function () {
+ Loading.setLoading('content', false);
+ });
+
+ // in case of wrong id etc show all items
+ $rootScope.$on('$routeChangeError', function () {
+ $location.path('/items');
+ });
+
+}]);
+app.controller('AppController',
+["Loading", "FeedResource", "FolderResource", function (Loading, FeedResource, FolderResource) {
+ 'use strict';
+
+ this.loading = Loading;
+
+ this.isFirstRun = function () {
+ return FeedResource.size() === 0 && FolderResource.size() === 0;
+ };
+
+}]);
+app.controller('ContentController',
+["Publisher", "FeedResource", "ItemResource", "SettingsResource", "data", "$route", "$routeParams", "FEED_TYPE", function (Publisher, FeedResource, ItemResource, SettingsResource, data,
+ $route, $routeParams, FEED_TYPE) {
+ 'use strict';
+
+ // dont cache items across multiple route changes
+ ItemResource.clear();
+
+ // distribute data to models based on key
+ Publisher.publishAll(data);
+
+
+ this.isAutoPagingEnabled = true;
+
+ this.getItems = function () {
+ return ItemResource.getAll();
+ };
+
+ this.toggleStar = function (itemId) {
+ ItemResource.toggleStar(itemId);
+ };
+
+ this.toggleItem = function (item) {
+ // TODO: unittest
+ if (this.isCompactView()) {
+ item.show = !item.show;
+ }
+ };
+
+ this.markRead = function (itemId) {
+ var item = ItemResource.get(itemId);
+
+ if (!item.keepUnread && item.unread === true) {
+ ItemResource.markItemRead(itemId);
+ FeedResource.markItemOfFeedRead(item.feedId);
+ }
+ };
+
+ this.getFeed = function (feedId) {
+ return FeedResource.getById(feedId);
+ };
+
+ this.toggleKeepUnread = function (itemId) {
+ var item = ItemResource.get(itemId);
+ if (!item.unread) {
+ FeedResource.markItemOfFeedUnread(item.feedId);
+ ItemResource.markItemRead(itemId, false);
+ }
+
+ item.keepUnread = !item.keepUnread;
+ };
+
+ this.orderBy = function () {
+ if (SettingsResource.get('oldestFirst')) {
+ return 'id';
+ } else {
+ return '-id';
+ }
+ };
+
+ this.isCompactView = function () {
+ return SettingsResource.get('compact');
+ };
+
+ this.autoPagingEnabled = function () {
+ return this.isAutoPagingEnabled;
+ };
+
+ this.markReadEnabled = function () {
+ return !SettingsResource.get('preventReadOnScroll');
+ };
+
+ this.scrollRead = function (itemIds) {
+ var ids = [];
+ var feedIds = [];
+
+ itemIds.forEach(function (itemId) {
+ var item = ItemResource.get(itemId);
+ if (!item.keepUnread) {
+ ids.push(itemId);
+ feedIds.push(item.feedId);
+ }
+ });
+
+ if (ids.length > 0) {
+ FeedResource.markItemsOfFeedsRead(feedIds);
+ ItemResource.markItemsRead(ids);
+ }
+ };
+
+ this.isFeed = function () {
+ return $route.current.$$route.type === FEED_TYPE.FEED;
+ };
+
+ this.autoPage = function () {
+ // in case a subsequent autopage request comes in wait until
+ // the current one finished and execute a request immediately afterwards
+ if (!this.isAutoPagingEnabled) {
+ this.autoPageAgain = true;
+ return;
+ }
+
+ this.isAutoPagingEnabled = false;
+ this.autoPageAgain = false;
+
+ var type = $route.current.$$route.type;
+ var id = $routeParams.id;
+ var oldestFirst = SettingsResource.get('oldestFirst');
+ var self = this;
+
+ ItemResource.autoPage(type, id, oldestFirst).success(function (data) {
+ Publisher.publishAll(data);
+
+ if (data.items.length > 0) {
+ self.isAutoPagingEnabled = true;
+ }
+
+ if (self.isAutoPagingEnabled && self.autoPageAgain) {
+ self.autoPage();
+ }
+ }).error(function () {
+ self.isAutoPagingEnabled = true;
+ });
+ };
+
+ this.getRelativeDate = function (timestamp) {
+ if (timestamp !== undefined && timestamp !== '') {
+ var languageCode = SettingsResource.get('language');
+ var date =
+ moment.unix(timestamp).locale(languageCode).fromNow() + '';
+ return date;
+ } else {
+ return '';
+ }
+ };
+
+}]);
+app.controller('NavigationController',
+["$route", "FEED_TYPE", "FeedResource", "FolderResource", "ItemResource", "SettingsResource", "Publisher", "$rootScope", "$location", "$q", function ($route, FEED_TYPE, FeedResource, FolderResource, ItemResource,
+ SettingsResource, Publisher, $rootScope, $location, $q) {
+ 'use strict';
+
+ this.feedError = '';
+ this.folderError = '';
+
+ this.getFeeds = function () {
+ return FeedResource.getAll();
+ };
+
+ this.getFolders = function () {
+ return FolderResource.getAll();
+ };
+
+ this.markFolderRead = function (folderId) {
+ FeedResource.markFolderRead(folderId);
+
+ FeedResource.getByFolderId(folderId).forEach(function (feed) {
+ ItemResource.markFeedRead(feed.id);
+ });
+ };
+
+ this.markFeedRead = function (feedId) {
+ ItemResource.markFeedRead(feedId);
+ FeedResource.markFeedRead(feedId);
+ };
+
+ this.markRead = function () {
+ ItemResource.markRead();
+ FeedResource.markRead();
+ };
+
+ this.isShowAll = function () {
+ return SettingsResource.get('showAll');
+ };
+
+ this.getFeedsOfFolder = function (folderId) {
+ return FeedResource.getByFolderId(folderId);
+ };
+
+ this.getUnreadCount = function () {
+ return FeedResource.getUnreadCount();
+ };
+
+ this.getFeedUnreadCount = function (feedId) {
+ var feed = FeedResource.getById(feedId);
+ if (feed !== undefined) {
+ return feed.unreadCount;
+ } else {
+ return 0;
+ }
+ };
+
+ this.getFolderUnreadCount= function (folderId) {
+ return FeedResource.getFolderUnreadCount(folderId);
+ };
+
+ this.getStarredCount = function () {
+ return ItemResource.getStarredCount();
+ };
+
+ this.toggleFolder = function (folderName) {
+ FolderResource.toggleOpen(folderName);
+ };
+
+ this.hasFeeds = function (folderId) {
+ return FeedResource.getFolderUnreadCount(folderId) !== undefined;
+ };
+
+ this.subFeedActive = function (folderId) {
+ var type = $route.current.$$route.type;
+
+ if (type === FEED_TYPE.FEED) {
+ var feed = FeedResource.getById($route.current.params.id);
+
+ if (feed !== undefined && feed.folderId === folderId) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ this.isSubscriptionsActive = function () {
+ return $route.current &&
+ $route.current.$$route.type === FEED_TYPE.SUBSCRIPTIONS;
+ };
+
+ this.isStarredActive = function () {
+ return $route.current &&
+ $route.current.$$route.type === FEED_TYPE.STARRED;
+ };
+
+ this.isFolderActive = function (folderId) {
+ var currentId = parseInt($route.current.params.id, 10);
+ return $route.current &&
+ $route.current.$$route.type === FEED_TYPE.FOLDER &&
+ currentId === folderId;
+ };
+
+ this.isFeedActive = function (feedId) {
+ var currentId = parseInt($route.current.params.id, 10);
+ return $route.current &&
+ $route.current.$$route.type === FEED_TYPE.FEED &&
+ currentId === feedId;
+ };
+
+ this.folderNameExists = function (folderName) {
+ folderName = folderName || '';
+ return FolderResource.get(folderName.trim()) !== undefined;
+ };
+
+ this.feedUrlExists = function (url) {
+ url = url || '';
+ url = url.trim();
+ return FeedResource.get(url) !== undefined ||
+ FeedResource.get('http://' + url) !== undefined;
+ };
+
+ this.createFeed = function (feed) {
+ var self = this;
+ this.newFolder = false;
+ this.addingFeed = true;
+
+ var newFolder = feed.newFolder;
+ var existingFolder = feed.existingFolder || {id: 0};
+
+ // we dont need to create a new folder
+ if (newFolder === undefined) {
+ // this is set to display the feed in any folder, even if the folder
+ // is closed or has no unread articles
+ existingFolder.getsFeed = true;
+
+ FeedResource.create(feed.url, existingFolder.id, undefined)
+ .then(function (data) {
+
+ Publisher.publishAll(data);
+
+ // set folder as default
+ $location.path('/items/feeds/' + data.feeds[0].id + '/');
+
+ }).finally(function () {
+ existingFolder.getsFeed = undefined;
+ feed.url = '';
+ self.addingFeed = false;
+ });
+
+ } else {
+ // create folder first and then the feed
+ FolderResource.create(newFolder).then(function (data) {
+
+ Publisher.publishAll(data);
+
+ // set the created folder on scope so its preselected for the
+ // next addition
+ feed.existingFolder = FolderResource.get(data.folders[0].name);
+ feed.newFolder = undefined;
+ self.createFeed(feed);
+ });
+ }
+ };
+
+ this.createFolder = function (folder) {
+ var self = this;
+ this.addingFolder = true;
+ FolderResource.create(folder.name).then(function (data) {
+ Publisher.publishAll(data);
+ }).finally(function () {
+ self.addingFolder = false;
+ folder.name = '';
+ });
+ };
+
+ this.moveFeed = function (feedId, folderId) {
+ var reload = false;
+ var feed = FeedResource.getById(feedId);
+
+ if (feed.folderId === folderId) {
+ return;
+ }
+
+ if (this.isFolderActive(feed.folderId) ||
+ this.isFolderActive(folderId)) {
+ reload = true;
+ }
+
+ FeedResource.move(feedId, folderId);
+
+ if (reload) {
+ $route.reload();
+ }
+ };
+
+ this.renameFeed = function (feed) {
+ FeedResource.rename(feed.id, feed.title);
+ feed.editing = false;
+ };
+
+ this.renameFolder = function (folder, name) {
+ folder.renameError = '';
+ this.renamingFolder = true;
+ var self = this;
+
+ if (folder.name === name) {
+ folder.renameError = '';
+ folder.editing = false;
+ this.renamingFolder = false;
+ } else {
+ FolderResource.rename(folder.name, name).then(function () {
+ folder.renameError = '';
+ folder.editing = false;
+ }, function (message) {
+ folder.renameError = message;
+ }).finally(function () {
+ self.renamingFolder = false;
+ });
+ }
+ };
+
+ this.reversiblyDeleteFeed = function (feed) {
+ FeedResource.reversiblyDelete(feed.id).finally(function () {
+ $route.reload();
+ });
+ };
+
+ this.undoDeleteFeed = function (feed) {
+ FeedResource.undoDelete(feed.id).finally(function () {
+ $route.reload();
+ });
+ };
+
+ this.deleteFeed = function (feed) {
+ FeedResource.delete(feed.url);
+ };
+
+
+ this.reversiblyDeleteFolder = function (folder) {
+ $q.all(
+ FeedResource.reversiblyDeleteFolder(folder.id),
+ FolderResource.reversiblyDelete(folder.name)
+ ).finally(function () {
+ $route.reload();
+ });
+ };
+
+ this.undoDeleteFolder = function (folder) {
+ $q.all(
+ FeedResource.undoDeleteFolder(folder.id),
+ FolderResource.undoDelete(folder.name)
+ ).finally(function () {
+ $route.reload();
+ });
+ };
+
+ this.deleteFolder = function (folder) {
+ FeedResource.deleteFolder(folder.id);
+ FolderResource.delete(folder.name);
+ };
+
+ var self = this;
+ $rootScope.$on('moveFeedToFolder', function (scope, data) {
+ self.moveFeed(data.feedId, data.folderId);
+ });
+
+}]);
+app.controller('SettingsController',
+["$route", "$q", "SettingsResource", "ItemResource", "OPMLParser", "OPMLImporter", "Publisher", function ($route, $q, SettingsResource, ItemResource, OPMLParser,
+ OPMLImporter, Publisher) {
+ 'use strict';
+
+ this.isOPMLImporting = false;
+ this.isArticlesImporting = false;
+ this.opmlImportError = false;
+ this.articleImportError = false;
+
+ var set = function (key, value) {
+ SettingsResource.set(key, value);
+
+ if (['showAll', 'oldestFirst', 'compact'].indexOf(key) >= 0) {
+ $route.reload();
+ }
+ };
+
+ this.toggleSetting = function (key) {
+ set(key, !this.getSetting(key));
+ };
+
+ this.getSetting = function (key) {
+ return SettingsResource.get(key);
+ };
+
+ this.importOPML = function (content) {
+ this.opmlImportError = false;
+ this.articleImportError = false;
+
+ try {
+ this.isOPMLImporting = false;
+ var parsedContent = OPMLParser.parse(content);
+
+ var self = this;
+ var jobSize = 5;
+
+ OPMLImporter.importFolders(parsedContent)
+ .then(function (feedQueue) {
+ return OPMLImporter.importFeedQueue(feedQueue, jobSize);
+ }).finally(function () {
+ self.isOPMLImporting = false;
+ });
+
+ } catch (error) {
+ this.isOPMLImporting = false;
+ this.opmlImportError = true;
+ }
+ };
+
+ this.importArticles = function (content) {
+ this.opmlImportError = false;
+ this.articleImportError = false;
+
+ try {
+ this.isArticlesImporting = true;
+ var articles = JSON.parse(content);
+
+ var self = this;
+ ItemResource.importArticles(articles).success(function (data) {
+ Publisher.publishAll(data);
+ }).finally(function () {
+ self.isArticlesImporting = false;
+ });
+
+ } catch (error) {
+ this.articleImportError = true;
+ this.isArticlesImporting = false;
+ }
+ };
+
+}]);
+app.filter('trustUrl', ["$sce", function ($sce) {
+ 'use strict';
+
+ return function (url) {
+ return $sce.trustAsResourceUrl(url);
+ };
+}]);
+app.filter('unreadCountFormatter', function () {
+ 'use strict';
+
+ return function (unreadCount) {
+ if (unreadCount > 999) {
+ return '999+';
+ }
+ return unreadCount;
+ };
+});
+app.factory('FeedResource', ["Resource", "$http", "BASE_URL", "$q", function (Resource, $http, BASE_URL, $q) {
+ 'use strict';
+
+ var FeedResource = function ($http, BASE_URL, $q) {
+ Resource.call(this, $http, BASE_URL, 'url');
+ this.ids = {};
+ this.unreadCount = 0;
+ this.folderUnreadCount = {};
+ this.folderIds = {};
+ this.$q = $q;
+ };
+
+ FeedResource.prototype = Object.create(Resource.prototype);
+
+ FeedResource.prototype.receive = function (data) {
+ Resource.prototype.receive.call(this, data);
+ this.updateUnreadCache();
+ this.updateFolderCache();
+ };
+
+
+ FeedResource.prototype.updateUnreadCache = function () {
+ this.unreadCount = 0;
+ this.folderUnreadCount = {};
+
+ var self = this;
+ this.values.forEach(function (feed) {
+ if (feed.unreadCount) {
+ self.unreadCount += feed.unreadCount;
+ }
+ if (feed.folderId !== undefined) {
+ self.folderUnreadCount[feed.folderId] =
+ self.folderUnreadCount[feed.folderId] || 0;
+ self.folderUnreadCount[feed.folderId] += feed.unreadCount;
+ }
+ });
+ };
+
+
+ FeedResource.prototype.updateFolderCache = function () {
+ this.folderIds = {};
+
+ var self = this;
+ this.values.forEach(function (feed) {
+ self.folderIds[feed.folderId] =
+ self.folderIds[feed.folderId] || [];
+ self.folderIds[feed.folderId].push(feed);
+ });
+ };
+
+
+ FeedResource.prototype.add = function (value) {
+ Resource.prototype.add.call(this, value);
+ if (value.id !== undefined) {
+ this.ids[value.id] = this.hashMap[value.url];
+ }
+ };
+
+
+ FeedResource.prototype.markRead = function () {
+ this.values.forEach(function (feed) {
+ feed.unreadCount = 0;
+ });
+
+ this.unreadCount = 0;
+ this.folderUnreadCount = {};
+ };
+
+
+ FeedResource.prototype.markFeedRead = function (feedId) {
+ this.ids[feedId].unreadCount = 0;
+ this.updateUnreadCache();
+ };
+
+
+ FeedResource.prototype.markFolderRead = function (folderId) {
+ this.values.forEach(function (feed) {
+ if (feed.folderId === folderId) {
+ feed.unreadCount = 0;
+ }
+ });
+
+ this.updateUnreadCache();
+ };
+
+
+ FeedResource.prototype.markItemOfFeedRead = function (feedId) {
+ this.ids[feedId].unreadCount -= 1;
+ this.updateUnreadCache();
+ };
+
+
+ FeedResource.prototype.markItemsOfFeedsRead = function (feedIds) {
+ var self = this;
+ feedIds.forEach(function (feedId) {
+ self.ids[feedId].unreadCount -= 1;
+ });
+
+ this.updateUnreadCache();
+ };
+
+
+ FeedResource.prototype.markItemOfFeedUnread = function (feedId) {
+ this.ids[feedId].unreadCount += 1;
+ this.updateUnreadCache();
+ };
+
+
+ FeedResource.prototype.getUnreadCount = function () {
+ return this.unreadCount;
+ };
+
+
+ FeedResource.prototype.getFolderUnreadCount = function (folderId) {
+ return this.folderUnreadCount[folderId];
+ };
+
+
+ FeedResource.prototype.getByFolderId = function (folderId) {
+ return this.folderIds[folderId] || [];
+ };
+
+
+ FeedResource.prototype.getById = function (feedId) {
+ return this.ids[feedId];
+ };
+
+
+ FeedResource.prototype.rename = function (id, title) {
+ return this.http({
+ method: 'POST',
+ url: this.BASE_URL + '/feeds/' + id + '/rename',
+ data: {
+ feedTitle: title
+ }
+ });
+ };
+
+
+ FeedResource.prototype.move = function (feedId, folderId) {
+ var feed = this.getById(feedId);
+ feed.folderId = folderId;
+
+ this.updateFolderCache();
+ this.updateUnreadCache();
+
+ return this.http({
+ method: 'POST',
+ url: this.BASE_URL + '/feeds/' + feed.id + '/move',
+ data: {
+ parentFolderId: folderId
+ }
+ });
+
+ };
+
+
+ FeedResource.prototype.create = function (url, folderId, title) {
+ url = url.trim();
+ if (!url.startsWith('http')) {
+ url = 'http://' + url;
+ }
+
+ if (title !== undefined) {
+ title = title.trim();
+ }
+
+ var feed = {
+ url: url,
+ folderId: folderId || 0,
+ title: title || url,
+ unreadCount: 0
+ };
+
+ this.add(feed);
+ this.updateFolderCache();
+
+ var deferred = this.$q.defer();
+
+ this.http({
+ method: 'POST',
+ url: this.BASE_URL + '/feeds',
+ data: {
+ url: url,
+ parentFolderId: folderId || 0,
+ title: title
+ }
+ }).success(function (data) {
+ deferred.resolve(data);
+ }).error(function (data) {
+ feed.faviconLink = '';
+ feed.error = data.message;
+ deferred.reject();
+ });
+
+ return deferred.promise;
+ };
+
+
+ FeedResource.prototype.reversiblyDelete = function (id, updateCache) {
+ var feed = this.getById(id);
+
+ if (feed) {
+ feed.deleted = true;
+ }
+
+ if (updateCache !== false) {
+ this.updateUnreadCache();
+ }
+
+ return this.http.delete(this.BASE_URL + '/feeds/' + id);
+ };
+
+
+ FeedResource.prototype.reversiblyDeleteFolder = function (folderId) {
+ var self = this;
+ var promises = [];
+ this.getByFolderId(folderId).forEach(function (feed) {
+ promises.push(self.reversiblyDelete(feed.id, false));
+ });
+
+ this.updateUnreadCache();
+
+ var deferred = this.$q.all(promises);
+ return deferred.promise;
+ };
+
+
+ FeedResource.prototype.delete = function (url, updateCache) {
+ var feed = this.get(url);
+ if (feed.id) {
+ delete this.ids[feed.id];
+ }
+
+ Resource.prototype.delete.call(this, url);
+
+ if (updateCache !== false) {
+ this.updateUnreadCache();
+ this.updateFolderCache();
+ }
+
+ return feed;
+ };
+
+
+ FeedResource.prototype.deleteFolder = function (folderId) {
+ var self = this;
+ this.getByFolderId(folderId).forEach(function (feed) {
+ self.delete(feed.url, false);
+ });
+
+ this.updateUnreadCache();
+ this.updateFolderCache();
+ };
+
+
+ FeedResource.prototype.undoDelete = function (id, updateCache) {
+ var feed = this.getById(id);
+
+ if (feed) {
+ feed.deleted = false;
+ }
+
+ if (updateCache !== false) {
+ this.updateUnreadCache();
+ }
+
+ return this.http.post(this.BASE_URL + '/feeds/' + id + '/restore');
+ };
+
+
+ FeedResource.prototype.undoDeleteFolder = function (folderId) {
+ var self = this;
+ var promises = [];
+
+ this.getByFolderId(folderId).forEach(function (feed) {
+ promises.push(self.undoDelete(feed.id, false));
+ });
+
+ this.updateUnreadCache();
+
+ var deferred = this.$q.all(promises);
+ return deferred.promise;
+ };
+
+
+ return new FeedResource($http, BASE_URL, $q);
+}]);
+app.factory('FolderResource', ["Resource", "$http", "BASE_URL", "$q", function (Resource, $http, BASE_URL, $q) {
+ 'use strict';
+
+ var FolderResource = function ($http, BASE_URL, $q) {
+ Resource.call(this, $http, BASE_URL, 'name');
+ this.deleted = null;
+ this.$q = $q;
+ };
+
+ FolderResource.prototype = Object.create(Resource.prototype);
+
+
+ FolderResource.prototype.toggleOpen = function (folderName) {
+ var folder = this.get(folderName);
+ folder.opened = !folder.opened;
+
+ return this.http({
+ url: this.BASE_URL + '/folders/' + folder.id + '/open',
+ method: 'POST',
+ data: {
+ folderId: folder.id,
+ open: folder.opened
+ }
+ });
+ };
+
+
+ FolderResource.prototype.rename = function (folderName, toFolderName) {
+ var folder = this.get(folderName);
+ var deferred = this.$q.defer();
+ var self = this;
+
+ this.http({
+ url: this.BASE_URL + '/folders/' + folder.id + '/rename',
+ method: 'POST',
+ data: {
+ folderName: toFolderName
+ }
+ }).success(function () {
+ folder.name = toFolderName;
+ delete self.hashMap[folderName];
+ self.hashMap[toFolderName] = folder;
+
+ deferred.resolve();
+ }).error(function (data) {
+ deferred.reject(data.message);
+ });
+
+ return deferred.promise;
+ };
+
+
+ FolderResource.prototype.create = function (folderName) {
+ folderName = folderName.trim();
+ var folder = {
+ name: folderName
+ };
+
+ this.add(folder);
+
+ var deferred = this.$q.defer();
+
+ this.http({
+ url: this.BASE_URL + '/folders',
+ method: 'POST',
+ data: {
+ folderName: folderName
+ }
+ }).success(function (data) {
+ deferred.resolve(data);
+ }).error(function (data) {
+ folder.error = data.message;
+ });