FeedTree.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. dojo.provide("fox.FeedTree");
  2. dojo.provide("fox.FeedStoreModel");
  3. dojo.require("dijit.Tree");
  4. dojo.require("dijit.Menu");
  5. dojo.declare("fox.FeedStoreModel", dijit.tree.ForestStoreModel, {
  6. getItemsInCategory: function (id) {
  7. if (!this.store._itemsByIdentity) return undefined;
  8. cat = this.store._itemsByIdentity['CAT:' + id];
  9. if (cat && cat.items)
  10. return cat.items;
  11. else
  12. return undefined;
  13. },
  14. getItemById: function(id) {
  15. return this.store._itemsByIdentity[id];
  16. },
  17. getFeedValue: function(feed, is_cat, key) {
  18. if (!this.store._itemsByIdentity) return undefined;
  19. if (is_cat)
  20. treeItem = this.store._itemsByIdentity['CAT:' + feed];
  21. else
  22. treeItem = this.store._itemsByIdentity['FEED:' + feed];
  23. if (treeItem)
  24. return this.store.getValue(treeItem, key);
  25. },
  26. getFeedName: function(feed, is_cat) {
  27. return this.getFeedValue(feed, is_cat, 'name');
  28. },
  29. getFeedUnread: function(feed, is_cat) {
  30. var unread = parseInt(this.getFeedValue(feed, is_cat, 'unread'));
  31. return (isNaN(unread)) ? 0 : unread;
  32. },
  33. setFeedUnread: function(feed, is_cat, unread) {
  34. return this.setFeedValue(feed, is_cat, 'unread', parseInt(unread));
  35. },
  36. setFeedValue: function(feed, is_cat, key, value) {
  37. if (!value) value = '';
  38. if (!this.store._itemsByIdentity) return undefined;
  39. if (is_cat)
  40. treeItem = this.store._itemsByIdentity['CAT:' + feed];
  41. else
  42. treeItem = this.store._itemsByIdentity['FEED:' + feed];
  43. if (treeItem)
  44. return this.store.setValue(treeItem, key, value);
  45. },
  46. getNextUnreadFeed: function (feed, is_cat) {
  47. if (!this.store._itemsByIdentity)
  48. return null;
  49. if (is_cat) {
  50. treeItem = this.store._itemsByIdentity['CAT:' + feed];
  51. items = this.store._arrayOfTopLevelItems;
  52. } else {
  53. treeItem = this.store._itemsByIdentity['FEED:' + feed];
  54. items = this.store._arrayOfAllItems;
  55. }
  56. for (var i = 0; i < items.length; i++) {
  57. if (items[i] == treeItem) {
  58. for (var j = i+1; j < items.length; j++) {
  59. var unread = this.store.getValue(items[j], 'unread');
  60. var id = this.store.getValue(items[j], 'id');
  61. if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
  62. }
  63. for (var j = 0; j < i; j++) {
  64. var unread = this.store.getValue(items[j], 'unread');
  65. var id = this.store.getValue(items[j], 'id');
  66. if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
  67. }
  68. }
  69. }
  70. return null;
  71. },
  72. hasCats: function() {
  73. if (this.store && this.store._itemsByIdentity)
  74. return this.store._itemsByIdentity['CAT:-1'] != undefined;
  75. else
  76. return false;
  77. },
  78. });
  79. dojo.declare("fox.FeedTree", dijit.Tree, {
  80. _createTreeNode: function(args) {
  81. var tnode = new dijit._TreeNode(args);
  82. if (args.item.icon)
  83. tnode.iconNode.src = args.item.icon[0];
  84. var id = args.item.id[0];
  85. var bare_id = parseInt(id.substr(id.indexOf(':')+1));
  86. if (bare_id < -10) {
  87. var span = dojo.doc.createElement('span');
  88. var fg_color = args.item.fg_color[0];
  89. var bg_color = args.item.bg_color[0];
  90. span.innerHTML = "&alpha;";
  91. span.className = 'labelColorIndicator';
  92. span.setStyle({
  93. color: fg_color,
  94. backgroundColor: bg_color});
  95. dojo.place(span, tnode.iconNode, 'replace');
  96. }
  97. if (id.match("FEED:") && bare_id > 0) {
  98. var menu = new dijit.Menu();
  99. menu.row_id = bare_id;
  100. menu.addChild(new dijit.MenuItem({
  101. label: __("Mark as read"),
  102. onClick: function() {
  103. catchupFeed(this.getParent().row_id);
  104. }}));
  105. menu.addChild(new dijit.MenuItem({
  106. label: __("Edit feed"),
  107. onClick: function() {
  108. editFeed(this.getParent().row_id, false);
  109. }}));
  110. menu.addChild(new dijit.MenuItem({
  111. label: __("Update feed"),
  112. onClick: function() {
  113. scheduleFeedUpdate(this.getParent().row_id, false);
  114. }}));
  115. menu.bindDomNode(tnode.domNode);
  116. tnode._menu = menu;
  117. }
  118. if (id.match("CAT:") && bare_id > 0) {
  119. var menu = new dijit.Menu();
  120. menu.row_id = bare_id;
  121. menu.addChild(new dijit.MenuItem({
  122. label: __("Mark as read"),
  123. onClick: function() {
  124. catchupFeed(this.getParent().row_id, true);
  125. }}));
  126. menu.bindDomNode(tnode.domNode);
  127. tnode._menu = menu;
  128. }
  129. //tnode.labelNode.innerHTML = args.label;
  130. return tnode;
  131. },
  132. getIconClass: function (item, opened) {
  133. return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
  134. },
  135. getLabelClass: function (item, opened) {
  136. return (item.unread == 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread";
  137. },
  138. getRowClass: function (item, opened) {
  139. return (!item.error || item.error == '') ? "dijitTreeRow" :
  140. "dijitTreeRow Error";
  141. },
  142. getLabel: function(item) {
  143. var name = String(item.name);
  144. /* Horrible */
  145. name = name.replace(/&quot;/g, "\"");
  146. name = name.replace(/&amp;/g, "&");
  147. name = name.replace(/&mdash;/g, "-");
  148. name = name.replace(/&lt;/g, "<");
  149. name = name.replace(/&gt;/g, ">");
  150. if (item.unread > 0) {
  151. return name + " (" + item.unread + ")";
  152. } else {
  153. return name;
  154. }
  155. },
  156. selectFeed: function(feed, is_cat) {
  157. if (is_cat)
  158. treeNode = this._itemNodesMap['CAT:' + feed];
  159. else
  160. treeNode = this._itemNodesMap['FEED:' + feed];
  161. if (treeNode) {
  162. treeNode = treeNode[0];
  163. if (!is_cat) this._expandNode(treeNode);
  164. this.set("selectedNodes", [treeNode]);
  165. }
  166. },
  167. setFeedIcon: function(feed, is_cat, src) {
  168. if (is_cat)
  169. treeNode = this._itemNodesMap['CAT:' + feed];
  170. else
  171. treeNode = this._itemNodesMap['FEED:' + feed];
  172. if (treeNode) {
  173. treeNode = treeNode[0];
  174. treeNode.iconNode.src = src;
  175. return true;
  176. }
  177. return false;
  178. },
  179. setFeedExpandoIcon: function(feed, is_cat, src) {
  180. if (is_cat)
  181. treeNode = this._itemNodesMap['CAT:' + feed];
  182. else
  183. treeNode = this._itemNodesMap['FEED:' + feed];
  184. if (treeNode) {
  185. treeNode = treeNode[0];
  186. treeNode.expandoNode.src = src;
  187. return true;
  188. }
  189. return false;
  190. },
  191. hasCats: function() {
  192. return this.model.hasCats();
  193. },
  194. hideRead: function (hide, show_special) {
  195. if (this.hasCats()) {
  196. var tree = this;
  197. var cats = this.model.store._arrayOfTopLevelItems;
  198. cats.each(function(cat) {
  199. var cat_unread = tree.hideReadFeeds(cat.items, hide, show_special);
  200. var id = String(cat.id);
  201. var node = tree._itemNodesMap[id];
  202. var bare_id = parseInt(id.substr(id.indexOf(":")+1));
  203. if (node) {
  204. var check_unread = tree.model.getFeedUnread(bare_id, true);
  205. if (hide && cat_unread == 0 && check_unread == 0) {
  206. Effect.Fade(node[0].rowNode, {duration : 0.3,
  207. queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
  208. } else {
  209. Element.show(node[0].rowNode);
  210. ++cat_unread;
  211. }
  212. }
  213. });
  214. } else {
  215. this.hideReadFeeds(this.model.store._arrayOfTopLevelItems, hide,
  216. show_special);
  217. }
  218. },
  219. hideReadFeeds: function (items, hide, show_special) {
  220. var tree = this;
  221. var cat_unread = 0;
  222. items.each(function(feed) {
  223. var id = String(feed.id);
  224. var bare_id = parseInt(feed.bare_id);;
  225. var unread = feed.unread[0];
  226. var node = tree._itemNodesMap[id];
  227. if (node) {
  228. if (hide && unread == 0 && (bare_id > 0 || !show_special)) {
  229. Effect.Fade(node[0].rowNode, {duration : 0.3,
  230. queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
  231. } else {
  232. Element.show(node[0].rowNode);
  233. ++cat_unread;
  234. }
  235. }
  236. });
  237. return cat_unread;
  238. },
  239. collapseCat: function(id) {
  240. if (!this.model.hasCats()) return;
  241. var tree = this;
  242. var node = tree._itemNodesMap['CAT:' + id][0];
  243. var item = tree.model.store._itemsByIdentity['CAT:' + id];
  244. if (node && item) {
  245. var hidden = tree.model.store.getValue(item, 'hidden');
  246. if (hidden)
  247. tree._expandNode(node);
  248. else
  249. tree._collapseNode(node);
  250. tree.model.store.setValue(item, 'hidden', !hidden);
  251. }
  252. },
  253. collapseHiddenCats: function() {
  254. if (!this.model.hasCats()) return;
  255. var cats = this.model.store._arrayOfTopLevelItems;
  256. var tree = this;
  257. dojo.forEach(cats, function(cat) {
  258. var hidden = tree.model.store.getValue(cat, 'hidden');
  259. var id = tree.model.store.getValue(cat, 'id');
  260. var node = tree._itemNodesMap[id][0];
  261. if (hidden)
  262. tree._collapseNode(node);
  263. else
  264. tree._expandNode(node);
  265. });
  266. },
  267. getVisibleUnreadFeeds: function() {
  268. var items = this.model.store._arrayOfAllItems;
  269. var rv = [];
  270. for (var i = 0; i < items.length; i++) {
  271. var id = String(items[i].id);
  272. var box = this._itemNodesMap[id];
  273. if (box) {
  274. var row = box[0].rowNode;
  275. var cat = false;
  276. try {
  277. cat = box[0].rowNode.parentNode.parentNode;
  278. } catch (e) { }
  279. if (row) {
  280. if (Element.visible(row) && (!cat || Element.visible(cat))) {
  281. var feed_id = String(items[i].bare_id);
  282. var is_cat = !id.match('FEED:');
  283. var unread = this.model.getFeedUnread(feed_id, is_cat);
  284. if (unread > 0)
  285. rv.push([feed_id, is_cat]);
  286. }
  287. }
  288. }
  289. }
  290. return rv;
  291. },
  292. getNextFeed: function (feed, is_cat) {
  293. if (is_cat) {
  294. treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
  295. } else {
  296. treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
  297. }
  298. items = this.model.store._arrayOfAllItems;
  299. var item = items[0];
  300. for (var i = 0; i < items.length; i++) {
  301. if (items[i] == treeItem) {
  302. for (var j = i+1; j < items.length; j++) {
  303. var id = String(items[j].id);
  304. var box = this._itemNodesMap[id];
  305. if (box) {
  306. var row = box[0].rowNode;
  307. var cat = box[0].rowNode.parentNode.parentNode;
  308. if (Element.visible(cat) && Element.visible(row)) {
  309. item = items[j];
  310. break;
  311. }
  312. }
  313. }
  314. break;
  315. }
  316. }
  317. if (item) {
  318. return [this.model.store.getValue(item, 'bare_id'),
  319. !this.model.store.getValue(item, 'id').match('FEED:')];
  320. } else {
  321. return false;
  322. }
  323. },
  324. getPreviousFeed: function (feed, is_cat) {
  325. if (is_cat) {
  326. treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
  327. } else {
  328. treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
  329. }
  330. items = this.model.store._arrayOfAllItems;
  331. var item = items[0];
  332. for (var i = 0; i < items.length; i++) {
  333. if (items[i] == treeItem) {
  334. for (var j = i-1; j > 0; j--) {
  335. var id = String(items[j].id);
  336. var box = this._itemNodesMap[id];
  337. if (box) {
  338. var row = box[0].rowNode;
  339. var cat = box[0].rowNode.parentNode.parentNode;
  340. if (Element.visible(cat) && Element.visible(row)) {
  341. item = items[j];
  342. break;
  343. }
  344. }
  345. }
  346. break;
  347. }
  348. }
  349. if (item) {
  350. return [this.model.store.getValue(item, 'bare_id'),
  351. !this.model.store.getValue(item, 'id').match('FEED:')];
  352. } else {
  353. return false;
  354. }
  355. },
  356. });