summaryrefslogtreecommitdiffstats
path: root/js-old/service
diff options
context:
space:
mode:
Diffstat (limited to 'js-old/service')
-rw-r--r--js-old/service/FeedResource.js348
-rw-r--r--js-old/service/FolderResource.js123
-rw-r--r--js-old/service/ItemResource.js223
-rw-r--r--js-old/service/Loading.js27
-rw-r--r--js-old/service/OPMLImporter.js111
-rw-r--r--js-old/service/OPMLParser.js90
-rw-r--r--js-old/service/Publisher.js44
-rw-r--r--js-old/service/Resource.js90
-rw-r--r--js-old/service/SettingsResource.js85
9 files changed, 1141 insertions, 0 deletions
diff --git a/js-old/service/FeedResource.js b/js-old/service/FeedResource.js
new file mode 100644
index 000000000..275bb1936
--- /dev/null
+++ b/js-old/service/FeedResource.js
@@ -0,0 +1,348 @@
+/**
+ * Nextcloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2014
+ */
+app.factory('FeedResource', 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.locations = {};
+ 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.clear = function () {
+ Resource.prototype.clear.call(this);
+ this.unreadCount = 0;
+ this.folderUnreadCount = {};
+ this.folderIds = {};
+ this.ids = {};
+ this.locations = {};
+ };
+
+ 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];
+ }
+ if (value.location !== undefined) {
+ this.locations[value.location] = this.hashMap[value.url];
+ }
+ };
+
+
+ FeedResource.prototype.markRead = function () {
+ this.values.forEach(function (feed) {
+ feed.unreadCount = 0;
+ });
+
+ this.updateUnreadCache();
+ };
+
+
+ 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.getByLocation = function (location) {
+ return this.locations[location];
+ };
+
+
+ FeedResource.prototype.move = function (feedId, folderId) {
+ var feed = this.getById(feedId);
+ feed.folderId = folderId;
+
+ this.updateFolderCache();
+ this.updateUnreadCache();
+
+ return this.patch(feedId, {folderId: folderId});
+
+ };
+
+
+ FeedResource.prototype.create = function (url, folderId, title, user, password, fullDiscover) {
+ url = url.trim();
+ if (!url.startsWith('http')) {
+ url = 'https://' + url;
+ }
+
+ if (title !== undefined) {
+ title = title.trim();
+ }
+
+ var feed = {
+ url: url,
+ folderId: folderId || 0,
+ title: title || url,
+ unreadCount: 0
+ };
+
+ this.add(feed);
+ this.updateFolderCache();
+
+ return this.http({
+ method: 'POST',
+ url: this.BASE_URL + '/feeds',
+ data: {
+ url: url,
+ parentFolderId: folderId || 0,
+ title: title,
+ user: user || null,
+ password: password || null,
+ fullDiscover: fullDiscover
+ }
+ }).then(function (response) {
+ return response.data;
+ }, function (response) {
+ feed.faviconLink = '';
+ feed.error = response.data.message;
+ });
+ };
+
+
+ FeedResource.prototype.reversiblyDelete = function (id, updateCache, isFolder) {
+ var feed = this.getById(id);
+
+ // if a folder is deleted it does not have to trigger the delete
+ // attribute for the feed because the feed is not deleted, its just not
+ // displayed. Otherwise this causes the feed to also be deleted again
+ // because the folder destroys the feed's scope
+ if (feed && isFolder !== true) {
+ 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, true));
+ });
+
+ this.updateUnreadCache();
+
+ var deferred = this.$q.all(promises);
+ return deferred.promise;
+ };
+
+
+ FeedResource.prototype.delete = function (url, updateCache) {
+ var feed = this.get(url);
+ if (feed !== undefined && feed.id) {
+ delete this.ids[feed.id];
+ }
+
+ if (feed !== undefined && feed.location) {
+ delete this.locations[feed.location];
+ }
+
+ 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;
+ };
+
+
+ FeedResource.prototype.setOrdering = function (feedId, ordering) {
+ var feed = this.getById(feedId);
+
+ if (feed) {
+ feed.ordering = ordering;
+ var url = this.BASE_URL + '/feeds/' + feedId;
+ return this.http.patch(url, {
+ ordering: ordering
+ });
+ }
+ };
+
+
+ FeedResource.prototype.setPinned = function (feedId, isPinned) {
+ var feed = this.getById(feedId);
+
+ if (feed) {
+ feed.pinned = isPinned;
+ var url = this.BASE_URL + '/feeds/' + feedId;
+ return this.http.patch(url, {
+ pinned: isPinned
+ });
+ }
+ };
+
+
+ FeedResource.prototype.patch = function (feedId, diff) {
+ var feed = this.getById(feedId);
+
+ if (feed) {
+ Object.keys(diff).forEach(function (key) {
+ feed[key] = diff[key];
+ });
+ var url = this.BASE_URL + '/feeds/' + feedId;
+ return this.http.patch(url, diff);
+ }
+ };
+
+
+ FeedResource.prototype.toggleFullText = function (feedId) {
+ var feed = this.getById(feedId);
+
+ return this.patch(feedId, {fullTextEnabled: !feed.fullTextEnabled});
+ };
+
+
+ return new FeedResource($http, BASE_URL, $q);
+});
diff --git a/js-old/service/FolderResource.js b/js-old/service/FolderResource.js
new file mode 100644
index 000000000..43ff8422d
--- /dev/null
+++ b/js-old/service/FolderResource.js
@@ -0,0 +1,123 @@
+/**
+ * Nextcloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2014
+ */
+app.factory('FolderResource', 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;
+ this.ids = {};
+ };
+
+ FolderResource.prototype = Object.create(Resource.prototype);
+
+
+ FolderResource.prototype.add = function (value) {
+ Resource.prototype.add.call(this, value);
+ if (value.id !== undefined) {
+ this.ids[value.id] = this.hashMap[value.name];
+ }
+ };
+
+ FolderResource.prototype.clear = function () {
+ Resource.prototype.clear.call(this);
+ this.ids = {};
+ };
+
+ FolderResource.prototype.delete = function (name) {
+ var folder = this.get(name);
+ if (folder !== undefined && folder.id) {
+ delete this.ids[folder.id];
+ }
+
+ Resource.prototype.delete.call(this, name);
+
+ return folder;
+ };
+
+ 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 self = this;
+
+ return this.http({
+ url: this.BASE_URL + '/folders/' + folder.id + '/rename',
+ method: 'POST',
+ data: {
+ folderName: toFolderName
+ }
+ }).then(function () {
+ folder.name = toFolderName;
+ delete self.hashMap[folderName];
+ self.hashMap[toFolderName] = folder;
+ }, function (response) {
+ return response.data.message;
+ });
+ };
+
+ FolderResource.prototype.getById = function (id) {
+ return this.ids[id];
+ };
+
+ FolderResource.prototype.create = function (folderName) {
+ folderName = folderName.trim();
+ var folder = {
+ name: folderName
+ };
+
+ this.add(folder);
+
+ return this.http({
+ url: this.BASE_URL + '/folders',
+ method: 'POST',
+ data: {
+ folderName: folderName
+ }
+ }).then(function (response) {
+ return response.data;
+ }, function (response) {
+ folder.error = response.data.message;
+ });
+ };
+
+
+ FolderResource.prototype.reversiblyDelete = function (name) {
+ var folder = this.get(name);
+ var id = folder.id;
+ folder.deleted = true;
+ return this.http.delete(this.BASE_URL + '/folders/' + id);
+ };
+
+
+ FolderResource.prototype.undoDelete = function (name) {
+ var folder = this.get(name);
+ var id = folder.id;
+ folder.deleted = false;
+ return this.http.post(this.BASE_URL + '/folders/' + id + '/restore');
+ };
+
+
+ return new FolderResource($http, BASE_URL, $q);
+}); \ No newline at end of file
diff --git a/js-old/service/ItemResource.js b/js-old/service/ItemResource.js
new file mode 100644
index 000000000..fcfd2f28d
--- /dev/null
+++ b/js-old/service/ItemResource.js
@@ -0,0 +1,223 @@
+/**
+ * Nextcloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2014
+ */
+app.factory('ItemResource', function (Resource, $http, BASE_URL, ITEM_BATCH_SIZE) {
+ 'use strict';
+
+ var ItemResource = function ($http, BASE_URL, ITEM_BATCH_SIZE) {
+ Resource.call(this, $http, BASE_URL);
+ this.batchSize = ITEM_BATCH_SIZE;
+ this.clear();
+ };
+
+ ItemResource.prototype = Object.create(Resource.prototype);
+
+ ItemResource.prototype.clear = function () {
+ this.starredCount = 0;
+ this.lowestId = 0;
+ this.highestId = 0;
+ this.fingerprints = {};
+ Resource.prototype.clear.call(this);
+ };
+
+ ItemResource.prototype.receive = function (value, channel) {
+ switch (channel) {
+ case 'newestItemId':
+ this.newestItemId = value;
+ break;
+
+ case 'starred':
+ this.starredCount = value;
+ break;
+
+ default:
+ var self = this;
+ var importValues = [];
+ value.forEach(function (item) {
+ // initialize lowest and highest id
+ if (self.lowestId === 0) {
+ self.lowestId = item.id;
+ }
+ if (self.highestId === 0) {
+ self.highestId = item.id;
+ }
+
+ if (item.id > self.highestId) {
+ self.highestId = item.id;
+ }
+ if (item.id < self.lowestId) {
+ self.lowestId = item.id;
+ }
+
+ // filter out duplicates
+ if (self.fingerprints[item.fingerprint] === undefined) {
+ self.fingerprints[item.fingerprint] = true;
+ importValues.push(item);
+ }
+ });
+
+ Resource.prototype.receive.call(this, importValues, channel);
+ }
+ };
+
+
+ ItemResource.prototype.getNewestItemId = function () {
+ return this.newestItemId;
+ };
+
+
+ ItemResource.prototype.getStarredCount = function () {
+ return this.starredCount;
+ };
+
+
+ ItemResource.prototype.star = function (itemId, isStarred) {
+ if (isStarred === undefined) {
+ isStarred = true;
+ }
+
+ var it = this.get(itemId);
+ var url = this.BASE_URL +
+ '/items/' + it.feedId + '/' + it.guidHash + '/star';
+
+ it.starred = isStarred;
+
+ if (isStarred) {
+ this.starredCount += 1;
+ } else {
+ this.starredCount -= 1;
+ }
+
+ return this.http({
+ url: url,
+ method: 'POST',
+ data: {
+ isStarred: isStarred
+ }
+ });
+ };
+
+
+ ItemResource.prototype.toggleStar = function (itemId) {
+ if (this.get(itemId).starred) {
+ this.star(itemId, false);
+ } else {
+ this.star(itemId, true);
+ }
+ };
+
+
+ ItemResource.prototype.markItemRead = function (itemId, isRead) {
+ if (isRead === undefined) {
+ isRead = true;
+ }
+
+ this.get(itemId).unread = !isRead;
+
+ return this.http({
+ url: this.BASE_URL + '/items/' + itemId + '/read',
+ method: 'POST',
+ data: {
+ isRead: isRead
+ }
+ });
+ };
+
+
+ ItemResource.prototype.markItemsRead = function (itemIds) {
+ var self = this;
+
+ itemIds.forEach(function (itemId) {
+ self.get(itemId).unread = false;
+ });
+
+ return this.http({
+ url: this.BASE_URL + '/items/read/multiple',
+ method: 'POST',
+ data: {
+ itemIds: itemIds
+ }
+ });
+ };
+
+
+ ItemResource.prototype.markFeedRead = function (feedId, read) {
+ if (read === undefined) {
+ read = true;
+ }
+
+ var items = this.values.filter(function (element) {
+ return element.feedId === feedId;
+ });
+
+ items.forEach(function (item) {
+ item.unread = !read;
+ });
+
+ return this.http.post(this.BASE_URL + '/feeds/' + feedId + '/read', {
+ highestItemId: this.getNewestItemId()
+ });
+ };
+
+
+ ItemResource.prototype.markRead = function () {
+ this.values.forEach(function (item) {
+ item.unread = false;
+ });
+
+ return this.http({
+ url: this.BASE_URL + '/items/read',
+ method: 'POST',
+ data: {
+ highestItemId: this.getNewestItemId()
+ }
+ });
+ };
+
+
+ ItemResource.prototype.autoPage = function (type, id, oldestFirst, showAll, search) {
+ var offset;
+
+ if (oldestFirst) {
+ offset = this.highestId;
+ } else {
+ offset = this.lowestId;
+ }
+
+ return this.http({
+ url: this.BASE_URL + '/items',
+ method: 'GET',
+ params: {
+ type: type,
+ id: id,
+ offset: offset,
+ limit: this.batchSize,
+ oldestFirst: oldestFirst,
+ showAll: showAll,
+ search: search
+ }
+ });
+ };
+
+
+ ItemResource.prototype.importArticles = function (json) {
+ return this.http({
+ url: this.BASE_URL + '/feeds/import/articles',
+ method: 'POST',
+ data: {
+ json: json
+ }
+ }).then(function (response) {
+ return response.data;
+ });
+ };
+
+
+ return new ItemResource($http, BASE_URL, ITEM_BATCH_SIZE);
+}); \ No newline at end of file
diff --git a/js-old/service/Loading.js b/js-old/service/Loading.js
new file mode 100644
index 000000000..4e97e3428
--- /dev/null
+++ b/js-old/service/Loading.js
@@ -0,0 +1,27 @@
+/**
+ * Nextcloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2014
+ */
+app.service('Loading', function () {
+ 'use strict';
+
+ this.loading = {
+ global: false,
+ content: false,
+ autopaging: false
+ };
+
+ this.setLoading = function (area, isLoading) {
+ this.loading[area] = isLoading;
+ };
+
+ this.isLoading = function (area) {
+ return this.loading[area];
+ };
+
+}); \ No newline at end of file
diff --git a/js-old/service/OPMLImporter.js b/js-old/service/OPMLImporter.js
new file mode 100644
index 000000000..b2b52bc4c
--- /dev/null
+++ b/js-old/service/OPMLImporter.js
@@ -0,0 +1,111 @@
+/**
+ * Nextcloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2014
+ */
+app.service('OPMLImporter', function (FeedResource, FolderResource, Publisher, $q) {
+ 'use strict';
+ var startFeedJob = function (queue) {
+ var deferred = $q.defer();
+ try {
+ if (queue.length > 0) {
+ var feed = queue.pop();
+ var url = feed.url;
+ var title = feed.title;
+ var folderId = 0;
+ var folderName = feed.folderName;
+
+ if (folderName !== undefined &&
+ FolderResource.get(folderName) !== undefined) {
+ var folder = FolderResource.get(folderName);
+ folder.opened = true;
+ folderId = folder.id;
+
+ // display folder while adding the feed
+ folder.getsFeed = true;
+ folder.getsFeedCounter = folder.getsFeedCounter || 0;
+ folder.getsFeedCounter += 1;
+ }
+
+ // make sure to not add already existing feeds
+ if (url !== undefined && FeedResource.get(url) === undefined) {
+ FeedResource.create(url, folderId, title)
+ .then(function (data) {
+ Publisher.publishAll(data);
+ })
+ .finally(function () {
+ if (folderId !== 0) {
+ folder.getsFeedCounter -= 1;
+
+ if (folder.getsFeedCounter === 0) {
+ folder.getsFeed = false;
+ }
+ }
+ startFeedJob(queue);
+ });
+ }
+ } else {
+ deferred.resolve();
+ }
+ } catch (e) {
+ console.error(e);
+ deferred.resolve();
+ }
+
+ return deferred.promise;
+ };
+
+ this.importFolders = function (content) {
+ // assumption: folders are fast to create and we dont need a queue for
+ // them
+ var feedQueue = [];
+ var folderPromises = [];
+ content.folders.forEach(function (folder) {
+ if (folder.name !== undefined) {
+ // skip already created folders
+ if (FolderResource.get(folder.name) === undefined) {
+ var promise = FolderResource.create(folder.name)
+ .then(function (data) {
+ Publisher.publishAll(data);
+ });
+ folderPromises.push(promise);
+ }
+
+ folder.feeds.forEach(function (feed) {
+ feed.folderName = folder.name;
+ feedQueue.push(feed);
+ });
+ }
+ });
+ feedQueue = feedQueue.concat(content.feeds);
+
+ var deferred = $q.defer();
+
+ $q.all(folderPromises).finally(function () {
+ deferred.resolve(feedQueue);
+ });
+
+ return deferred.promise;
+ };
+
+ this.importFeedQueue = function (feedQueue, jobSize) {
+ // queue feeds to prevent server slowdown
+ var deferred = $q.defer();
+
+ var jobPromises = [];
+ for (var i = 0; i < jobSize; i += 1) {
+ jobPromises.push(startFeedJob(feedQueue));
+ }
+
+ $q.all(jobPromises).then(function () {
+ deferred.resolve();
+ });
+
+ return deferred.promise;
+ };
+
+}); \ No newline at end of file
diff --git a/js-old/service/OPMLParser.js b/js-old/service/OPMLParser.js
new file mode 100644
index 000000000..6752e1d1e
--- /dev/null
+++ b/js-old/service/OPMLParser.js
@@ -0,0 +1,90 @@
+/**
+ * Nextcloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2014
+ */
+app.service('OPMLParser', function () {
+ 'use strict';
+
+ var parseOutline = function (outline) {
+ var url = outline.attr('xmlUrl') || outline.attr('htmlUrl');
+ var name = outline.attr('title') || outline.attr('text') || url;
+
+ // folder
+ if (url === undefined) {
+ return {
+ type: 'folder',
+ name: name,
+ feeds: []
+ };
+
+ // feed
+ } else {
+ return {
+ type: 'feed',
+ name: name,
+ url: url
+ };
+ }
+ };
+
+ // there is only one level, so feeds in a folder in a folder should be
+ // attached to the root folder
+ var recursivelyParse = function (level, root, firstLevel) {
+ for (var i = 0; i < level.length; i += 1) {
+ var outline = $(level[i]);
+
+ var entry = parseOutline(outline);
+
+ if (entry.type === 'feed') {
+ root.feeds.push(entry);
+ } else {
+ // only first level should append folders
+ if (firstLevel) {
+ recursivelyParse(outline.children('outline'), entry, false);
+ root.folders.push(entry);
+ } else {
+ recursivelyParse(outline.children('outline'), root, false);
+ }
+ }
+ }
+
+ return root;
+ };
+
+ this.parse = function (fileContent) {
+ var xml = $.parseXML(fileContent);
+ var firstLevel = $(xml).find('body > outline');
+
+ var root = {
+ 'feeds': [],
+ 'folders': []
+ };
+
+ var parsedResult = recursivelyParse(firstLevel, root, true);
+
+ // merge folders with duplicate names
+ var folders = {};
+ parsedResult.folders.forEach(function (folder) {
+ if (folders[folder.name] === undefined) {
+ folders[folder.name] = folder;
+ } else {
+ folders[folder.name].feeds = folders[folder.name]
+ .feeds.concat(folder.feeds);
+ }
+ });
+
+ return {
+ 'feeds': parsedResult.feeds,
+ 'folders': Object.keys(folders).map(function (key) {
+ return folders[key];
+ })
+ };
+
+ };
+
+}); \ No newline at end of file
diff --git a/js-old/service/Publisher.js b/js-old/service/Publisher.js
new file mode 100644
index 000000000..0d0dcf9eb
--- /dev/null
+++ b/js-old/service/Publisher.js
@@ -0,0 +1,44 @@
+/**
+ * Nextcloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2014
+ */
+
+/*jshint undef:false*/
+app.service('Publisher', function () {
+ 'use strict';
+
+ this.channels = {};
+
+ this.subscribe = function (obj) {
+ var self = this;
+
+ return {
+ toChannels: function (channels) {
+ channels.forEach(function (channel) {
+ self.channels[channel] = self.channels[channel] || [];
+ self.channels[channel].push(obj);
+ });
+ }
+ };
+
+ };
+
+ this.publishAll = function (data) {
+ var self = this;
+
+ Object.keys(data).forEach(function (channel) {
+ var listeners = self.channels[channel];
+ if (listeners !== undefined) {
+ listeners.forEach(function (listener) {
+ listener.receive(data[channel], channel);
+ });
+ }
+ });
+ };
+
+}); \ No newline at end of file
diff --git a/js-old/service/Resource.js b/js-old/service/Resource.js
new file mode 100644
index 000000000..b5be87cb7
--- /dev/null
+++ b/js-old/service/Resource.js
@@ -0,0 +1,90 @@
+/**
+ * Nextcloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2014
+ */
+app.factory('Resource', function () {
+ 'use strict';
+
+ var Resource = function (http, BASE_URL, id) {
+ this.id = id || 'id';
+ this.values = [];
+ this.hashMap = {};
+ this.http = http;
+ this.BASE_URL = BASE_URL;
+ };
+
+
+ Resource.prototype.receive = function (objs) {
+ var self = this;
+ objs.forEach(function (obj) {
+ self.add(obj);
+ });
+ };
+
+
+ Resource.prototype.add = function (obj) {
+ var existing = this.hashMap[obj[this.id]];
+
+ if (existing === undefined) {
+ this.values.push(obj);
+ this.hashMap[obj[this.id]] = obj;
+ } else {
+ // copy values from new to old object if it exists already
+ Object.keys(obj).forEach(function (key) {
+ existing[key] = obj[key];
+ });
+ }
+ };
+