PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/media/js/newsblur/models/feeds.js

https://github.com/samuelclay/NewsBlur
JavaScript | 349 lines | 266 code | 70 blank | 13 comment | 66 complexity | 2a0cadc7867c2bbd2f8c007bdba0f7ae MD5 | raw file
Possible License(s): MIT, GPL-2.0, BSD-3-Clause
  1. NEWSBLUR.Models.Feed = Backbone.Model.extend({
  2. initialize: function() {
  3. _.bindAll(this, 'on_change', 'delete_feed', 'update_folder_counts');
  4. // this.bind('change', this.on_change);
  5. this.bind('change:ps', this.change_counts);
  6. this.bind('change:nt', this.change_counts);
  7. this.bind('change:ng', this.change_counts);
  8. this.bind('change:selected', this.update_folder_visibility);
  9. this.views = [];
  10. this.folders = [];
  11. },
  12. on_change: function() {
  13. if (!('selected' in this.changedAttributes())) {
  14. NEWSBLUR.log(['Feed Change', this.changedAttributes(), this.previousAttributes()]);
  15. }
  16. },
  17. change_counts: function(data, count, options) {
  18. options = options || {};
  19. console.log(["change_counts", data, count, options]);
  20. this.update_folder_counts();
  21. if (this.get('selected') && options.refresh_feeds) {
  22. console.log(["Selected feed count change", this]);
  23. NEWSBLUR.reader.feed_unread_count(this.id);
  24. }
  25. },
  26. force_update_counts: function() {
  27. NEWSBLUR.reader.feed_unread_count(this.id);
  28. },
  29. update_folder_counts: function() {
  30. _.each(this.folders, function(folder) {
  31. folder.trigger('change:counts');
  32. });
  33. },
  34. update_folder_visibility: function() {
  35. _.each(this.folders, function(folder) {
  36. folder.trigger('change:feed_selected');
  37. });
  38. },
  39. delete_feed: function(options) {
  40. options = options || {};
  41. var view = options.view || this.get_view();
  42. NEWSBLUR.reader.flags['reloading_feeds'] = true;
  43. NEWSBLUR.assets.delete_feed(this.id, view.options.folder_title, function() {
  44. NEWSBLUR.reader.flags['reloading_feeds'] = false;
  45. });
  46. view.delete_feed();
  47. },
  48. move_to_folder: function(to_folder, options) {
  49. options = options || {};
  50. var view = options.view || this.get_view();
  51. var in_folder = view.options.folder_title;
  52. if (in_folder == to_folder) return false;
  53. NEWSBLUR.reader.flags['reloading_feeds'] = true;
  54. NEWSBLUR.assets.move_feed_to_folder(this.id, in_folder, to_folder, function() {
  55. NEWSBLUR.reader.flags['reloading_feeds'] = false;
  56. _.delay(function() {
  57. NEWSBLUR.reader.$s.$feed_list.css('opacity', 1).animate({'opacity': 0}, {
  58. 'duration': 100,
  59. 'complete': function() {
  60. NEWSBLUR.app.feed_list.make_feeds();
  61. }
  62. });
  63. }, 250);
  64. });
  65. return true;
  66. },
  67. move_to_folders: function(to_folders, options) {
  68. options = options || {};
  69. var view = options.view || this.get_view();
  70. var in_folders = this.in_folders();
  71. if (_.isEqual(in_folders, to_folders)) return false;
  72. NEWSBLUR.reader.flags['reloading_feeds'] = true;
  73. NEWSBLUR.assets.move_feed_to_folders(this.id, in_folders, to_folders, function() {
  74. NEWSBLUR.reader.flags['reloading_feeds'] = false;
  75. _.delay(function() {
  76. NEWSBLUR.reader.$s.$feed_list.css('opacity', 1).animate({'opacity': 0}, {
  77. 'duration': 100,
  78. 'complete': function() {
  79. NEWSBLUR.app.feed_list.make_feeds();
  80. }
  81. });
  82. }, 250);
  83. });
  84. return true;
  85. },
  86. parent_folder_names: function() {
  87. var names = _.compact(_.flatten(_.map(this.folders, function(folder) {
  88. return folder.parent_folder_names();
  89. })));
  90. return names;
  91. },
  92. in_folders: function() {
  93. var in_folders = _.pluck(_.pluck(this.folders, 'options'), 'title');
  94. return in_folders;
  95. },
  96. rename: function(new_title) {
  97. this.set('feed_title', new_title);
  98. NEWSBLUR.assets.rename_feed(this.id, new_title);
  99. },
  100. get_view: function($feed, fallback) {
  101. var found_view = _.detect(this.views, function(view) {
  102. if ($feed) {
  103. return view.el == $feed.get(0);
  104. } else {
  105. return true;
  106. }
  107. });
  108. if (!found_view && fallback && this.views.length) {
  109. found_view = this.views[0];
  110. }
  111. return found_view;
  112. },
  113. is_social: function() {
  114. return false;
  115. },
  116. is_feed: function() {
  117. return true;
  118. },
  119. is_starred: function() {
  120. return false;
  121. },
  122. is_light: function() {
  123. var is_light = this._is_light;
  124. if (!_.isUndefined(is_light)) {
  125. return is_light;
  126. }
  127. var color = this.get('favicon_color');
  128. if (!color) return false;
  129. var r = parseInt(color.substr(0, 2), 16) / 255.0;
  130. var g = parseInt(color.substr(2, 2), 16) / 255.0;
  131. var b = parseInt(color.substr(4, 2), 16) / 255.0;
  132. is_light = $.textColor({r: r, g: g, b: b}) != 'white';
  133. this._is_light = is_light;
  134. return is_light;
  135. },
  136. unread_counts: function() {
  137. var starred_feed = NEWSBLUR.assets.starred_feeds.get_feed(this.id);
  138. return {
  139. ps: this.get('ps') || 0,
  140. nt: this.get('nt') || 0,
  141. ng: this.get('ng') || 0,
  142. st: starred_feed && starred_feed.get('count') || 0
  143. };
  144. },
  145. has_unreads: function(options) {
  146. options = options || {};
  147. var unread_view = NEWSBLUR.assets.preference('unread_view');
  148. if (options.include_selected && this.get('selected')) {
  149. return true;
  150. }
  151. if (!this.get('active')) return false;
  152. if (unread_view <= -1) {
  153. return !!(this.get('ng') || this.get('nt') || this.get('ps'));
  154. } else if (unread_view == 0) {
  155. return !!(this.get('nt') || this.get('ps'));
  156. } else if (unread_view >= 2) {
  157. var starred_feed = NEWSBLUR.assets.starred_feeds.get_feed(this.id);
  158. return starred_feed && starred_feed.get('count');
  159. } else if (unread_view > 0) {
  160. return !!(this.get('ps'));
  161. }
  162. },
  163. relative_last_story_date: function() {
  164. var diff = this.get('last_story_seconds_ago');
  165. var lasthour = 60*60;
  166. var lastday = 24*60*60;
  167. if (diff > 1000*60*60*24*365*20 || diff <= 0) {
  168. return "Never";
  169. } else if (diff < lasthour) {
  170. return Inflector.pluralize("minute", Math.floor(diff/60), true) + " ago";
  171. } else if (diff < lastday) {
  172. return Inflector.pluralize("hour", Math.floor(diff/60/60), true) + " ago";
  173. } else {
  174. return Inflector.pluralize("day", Math.floor(diff/60/60/24), true) + " ago";
  175. }
  176. },
  177. highlighted_in_folder: function(folder_title) {
  178. return !!(this.get('highlighted') &&
  179. this.get('highlighted_in_folders') &&
  180. _.contains(this.get('highlighted_in_folders'), folder_title));
  181. },
  182. highlight_in_folder: function(folder_title, on, off, options) {
  183. options = options || {};
  184. if (!this.get('highlighted_in_folders')) {
  185. this.set('highlighted_in_folders', [], {silent: true});
  186. }
  187. if (!off && (on || !_.contains(this.get('highlighted_in_folders'), folder_title))) {
  188. this.set('highlighted_in_folders',
  189. this.get('highlighted_in_folders').concat(folder_title), {silent: true});
  190. } else {
  191. this.set('highlighted_in_folders',
  192. _.without(this.get('highlighted_in_folders'), folder_title), {silent: true});
  193. }
  194. this.set('highlighted', !!this.get('highlighted_in_folders').length, {silent: true});
  195. if (!options.silent) this.trigger('change:highlighted');
  196. },
  197. highlight_in_all_folders: function(on, off, options) {
  198. options = options || {};
  199. if (!this.get('highlighted_in_folders')) {
  200. this.set('highlighted_in_folders', [], {silent: true});
  201. }
  202. var folders = _.unique(this.in_folders()) || [];
  203. if (!off && (on || !this.get('highlighted_in_folders').length)) {
  204. this.set('highlighted_in_folders', folders, {silent: true});
  205. } else {
  206. this.set('highlighted_in_folders', [], {silent: true});
  207. }
  208. this.set('highlighted', !!this.get('highlighted_in_folders').length, {silent: true});
  209. if (!options.silent) this.trigger('change:highlighted');
  210. }
  211. });
  212. NEWSBLUR.Collections.Feeds = Backbone.Collection.extend({
  213. model: NEWSBLUR.Models.Feed,
  214. url: '/reader/feeds',
  215. active_feed: null,
  216. initialize: function() {
  217. this.bind('change', this.detect_active_feed);
  218. },
  219. // ===========
  220. // = Actions =
  221. // ===========
  222. fetch: function(options) {
  223. var data = {
  224. 'v': 2
  225. };
  226. options = _.extend({
  227. data: data,
  228. silent: true
  229. }, options);
  230. return Backbone.Collection.prototype.fetch.call(this, options);
  231. },
  232. parse: function(data) {
  233. _.each(data.feeds, function(feed) {
  234. feed.selected = false;
  235. });
  236. return data.feeds;
  237. },
  238. deselect: function() {
  239. this.each(function(feed){
  240. feed.set('selected', false);
  241. });
  242. },
  243. // ==================
  244. // = Model Managers =
  245. // ==================
  246. selected: function() {
  247. return this.detect(function(feed) { return feed.get('selected'); });
  248. },
  249. active: function() {
  250. return this.select(function(feed) { return feed.get('active'); });
  251. },
  252. has_chosen_feeds: function() {
  253. return this.any(function(feed) {
  254. return feed.get('active');
  255. });
  256. },
  257. has_unfetched_feeds: function() {
  258. return this.any(function(feed) {
  259. return feed.get('not_yet_fetched');
  260. });
  261. },
  262. // ============
  263. // = Counters =
  264. // ============
  265. search_indexed: function() {
  266. var indexed = this.select(function(feed) {
  267. return feed.get('search_indexed');
  268. }).length;
  269. return indexed;
  270. },
  271. // ==========
  272. // = Events =
  273. // ==========
  274. detect_active_feed: function() {
  275. this.active_feed = this.detect(function(feed) {
  276. return feed.get('selected');
  277. });
  278. }
  279. });