]> git.wh0rd.org Git - tt-rss.git/blob - js/FeedTree.js
Merge pull request #61 from hydrian/master
[tt-rss.git] / js / FeedTree.js
1 dojo.provide("fox.FeedTree");
2 dojo.provide("fox.FeedStoreModel");
3
4 dojo.require("dijit.Tree");
5 dojo.require("dijit.Menu");
6
7 dojo.declare("fox.FeedStoreModel", dijit.tree.ForestStoreModel, {
8         getItemsInCategory: function (id) {
9                 if (!this.store._itemsByIdentity) return undefined;
10
11                 cat = this.store._itemsByIdentity['CAT:' + id];
12
13                 if (cat && cat.items)
14                         return cat.items;
15                 else
16                         return undefined;
17
18         },
19         getItemById: function(id) {
20                 return this.store._itemsByIdentity[id];
21         },
22         getFeedValue: function(feed, is_cat, key) {
23                 if (!this.store._itemsByIdentity) return undefined;
24
25                 if (is_cat)
26                         treeItem = this.store._itemsByIdentity['CAT:' + feed];
27                 else
28                         treeItem = this.store._itemsByIdentity['FEED:' + feed];
29
30                 if (treeItem)
31                         return this.store.getValue(treeItem, key);
32         },
33         getFeedName: function(feed, is_cat) {
34                 return this.getFeedValue(feed, is_cat, 'name');
35         },
36         getFeedUnread: function(feed, is_cat) {
37                 var unread = parseInt(this.getFeedValue(feed, is_cat, 'unread'));
38                 return (isNaN(unread)) ? 0 : unread;
39         },
40         setFeedUnread: function(feed, is_cat, unread) {
41                 return this.setFeedValue(feed, is_cat, 'unread', parseInt(unread));
42         },
43         setFeedValue: function(feed, is_cat, key, value) {
44                 if (!value) value = '';
45                 if (!this.store._itemsByIdentity) return undefined;
46
47                 if (is_cat)
48                         treeItem = this.store._itemsByIdentity['CAT:' + feed];
49                 else
50                         treeItem = this.store._itemsByIdentity['FEED:' + feed];
51
52                 if (treeItem)
53                         return this.store.setValue(treeItem, key, value);
54         },
55         getNextUnreadFeed: function (feed, is_cat) {
56                 if (!this.store._itemsByIdentity)
57                         return null;
58
59                 if (is_cat) {
60                         treeItem = this.store._itemsByIdentity['CAT:' + feed];
61                         items = this.store._arrayOfTopLevelItems;
62                 } else {
63                         treeItem = this.store._itemsByIdentity['FEED:' + feed];
64                         items = this.store._arrayOfAllItems;
65                 }
66
67                 for (var i = 0; i < items.length; i++) {
68                         if (items[i] == treeItem) {
69
70                                 for (var j = i+1; j < items.length; j++) {
71                                         var unread = this.store.getValue(items[j], 'unread');
72                                         var id = this.store.getValue(items[j], 'id');
73
74                                         if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
75                                 }
76
77                                 for (var j = 0; j < i; j++) {
78                                         var unread = this.store.getValue(items[j], 'unread');
79                                         var id = this.store.getValue(items[j], 'id');
80
81                                         if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
82                                 }
83                         }
84                 }
85
86                 return null;
87         },
88         hasCats: function() {
89                 if (this.store && this.store._itemsByIdentity)
90                         return this.store._itemsByIdentity['CAT:-1'] != undefined;
91                 else
92                         return false;
93         },
94 });
95
96 dojo.declare("fox.FeedTree", dijit.Tree, {
97         _onKeyPress: function(/* Event */ e) {
98                 return; // Stop dijit.Tree from interpreting keystrokes
99         },
100         _createTreeNode: function(args) {
101                 var tnode = new dijit._TreeNode(args);
102
103                 if (args.item.icon)
104                         tnode.iconNode.src = args.item.icon[0];
105
106                 var id = args.item.id[0];
107                 var bare_id = parseInt(id.substr(id.indexOf(':')+1));
108
109                 if (bare_id < -10) {
110                         var span = dojo.doc.createElement('span');
111                         var fg_color = args.item.fg_color[0];
112                         var bg_color = args.item.bg_color[0];
113
114                         span.innerHTML = "&alpha;";
115                         span.className = 'labelColorIndicator';
116                         span.setStyle({
117                                 color: fg_color,
118                                 backgroundColor: bg_color});
119
120                         dojo.place(span, tnode.iconNode, 'replace');
121                 }
122
123                 if (id.match("FEED:")) {
124                         var menu = new dijit.Menu();
125                         menu.row_id = bare_id;
126
127                         menu.addChild(new dijit.MenuItem({
128                                 label: __("Mark as read"),
129                                 onClick: function() {
130                                         catchupFeed(this.getParent().row_id);
131                                 }}));
132
133                         if (bare_id > 0) {
134                                 menu.addChild(new dijit.MenuItem({
135                                         label: __("Edit feed"),
136                                         onClick: function() {
137                                                 editFeed(this.getParent().row_id, false);
138                                         }}));
139
140                                 /* menu.addChild(new dijit.MenuItem({
141                                         label: __("Update feed"),
142                                         onClick: function() {
143                                                 heduleFeedUpdate(this.getParent().row_id, false);
144                                         }})); */
145                         }
146
147                         menu.bindDomNode(tnode.domNode);
148                         tnode._menu = menu;
149                 }
150
151                 if (id.match("CAT:") && bare_id >= 0) {
152                         var menu = new dijit.Menu();
153                         menu.row_id = bare_id;
154
155                         menu.addChild(new dijit.MenuItem({
156                                 label: __("Mark as read"),
157                                 onClick: function() {
158                                         catchupFeed(this.getParent().row_id, true);
159                                 }}));
160
161                         menu.bindDomNode(tnode.domNode);
162                         tnode._menu = menu;
163                 }
164
165                 if (id.match("CAT:") && bare_id == -1) {
166                         var menu = new dijit.Menu();
167                         menu.row_id = bare_id;
168
169                         menu.addChild(new dijit.MenuItem({
170                                 label: __("Mark all feeds as read"),
171                                 onClick: function() {
172                                         catchupAllFeeds();
173                                 }}));
174
175                         menu.bindDomNode(tnode.domNode);
176                         tnode._menu = menu;
177                 }
178
179
180                 //tnode.labelNode.innerHTML = args.label;
181                 return tnode;
182         },
183         getIconClass: function (item, opened) {
184                 return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
185         },
186         getLabelClass: function (item, opened) {
187                 return (item.unread == 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread";
188         },
189         getRowClass: function (item, opened) {
190                 return (!item.error || item.error == '') ? "dijitTreeRow" :
191                         "dijitTreeRow Error";
192         },
193         getLabel: function(item) {
194                 var name = String(item.name);
195
196                 /* Horrible */
197                 name = name.replace(/&quot;/g, "\"");
198                 name = name.replace(/&amp;/g, "&");
199                 name = name.replace(/&mdash;/g, "-");
200                 name = name.replace(/&lt;/g, "<");
201                 name = name.replace(/&gt;/g, ">");
202
203                 var label;
204
205                 if (item.unread > 0) {
206                         label = name + " (" + item.unread + ")";
207                 } else {
208                         label = name;
209                 }
210
211                 return label;
212         },
213         selectFeed: function(feed, is_cat) {
214                 if (is_cat)
215                         treeNode = this._itemNodesMap['CAT:' + feed];
216                 else
217                         treeNode = this._itemNodesMap['FEED:' + feed];
218
219                 if (treeNode) {
220                         treeNode = treeNode[0];
221                         if (!is_cat) this._expandNode(treeNode);
222                         this.set("selectedNodes", [treeNode]);
223                 }
224         },
225         setFeedIcon: function(feed, is_cat, src) {
226                 if (is_cat)
227                         treeNode = this._itemNodesMap['CAT:' + feed];
228                 else
229                         treeNode = this._itemNodesMap['FEED:' + feed];
230
231                 if (treeNode) {
232                         treeNode = treeNode[0];
233                         treeNode.iconNode.src = src;
234                         return true;
235                 }
236                 return false;
237         },
238         setFeedExpandoIcon: function(feed, is_cat, src) {
239                 if (is_cat)
240                         treeNode = this._itemNodesMap['CAT:' + feed];
241                 else
242                         treeNode = this._itemNodesMap['FEED:' + feed];
243
244                 if (treeNode) {
245                         treeNode = treeNode[0];
246                         treeNode.expandoNode.src = src;
247                         return true;
248                 }
249
250                 return false;
251         },
252         hasCats: function() {
253                 return this.model.hasCats();
254         },
255         hideReadCat: function (cat, hide, show_special) {
256                 if (this.hasCats()) {
257                         var tree = this;
258
259                         if (cat && cat.items) {
260                                 var cat_unread = tree.hideReadFeeds(cat.items, hide, show_special);
261
262                                 var id = String(cat.id);
263                                 var node = tree._itemNodesMap[id];
264                                 var bare_id = parseInt(id.substr(id.indexOf(":")+1));
265
266                                 if (node) {
267                                         var check_unread = tree.model.getFeedUnread(bare_id, true);
268
269                                         if (hide && cat_unread == 0 && check_unread == 0) {
270                                                 Effect.Fade(node[0].rowNode, {duration : 0.3,
271                                                         queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
272                                         } else {
273                                                 Element.show(node[0].rowNode);
274                                                 ++cat_unread;
275                                         }
276                                 }
277                         }
278                 }
279         },
280         hideRead: function (hide, show_special) {
281                 if (this.hasCats()) {
282
283                         var tree = this;
284                         var cats = this.model.store._arrayOfTopLevelItems;
285
286                         cats.each(function(cat) {
287                                 tree.hideReadCat(cat, hide, show_special);
288                         });
289
290                 } else {
291                         this.hideReadFeeds(this.model.store._arrayOfTopLevelItems, hide,
292                                 show_special);
293                 }
294         },
295         hideReadFeeds: function (items, hide, show_special) {
296                 var tree = this;
297                 var cat_unread = 0;
298
299                 items.each(function(feed) {
300                         var id = String(feed.id);
301
302                         // it's a subcategory
303                         if (feed.items) {
304                                 tree.hideReadCat(feed, hide, show_special);
305                         } else {        // it's a feed
306                                 var bare_id = parseInt(feed.bare_id);;
307
308                                 var unread = feed.unread[0];
309                                 var node = tree._itemNodesMap[id];
310
311                                 if (node) {
312                                         if (hide && unread == 0 && (bare_id > 0 || bare_id < -10 || !show_special)) {
313                                                 Effect.Fade(node[0].rowNode, {duration : 0.3,
314                                                         queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
315                                         } else {
316                                                 Element.show(node[0].rowNode);
317                                                 ++cat_unread;
318                                         }
319                                 }
320                         }
321                 });
322
323                 return cat_unread;
324         },
325         collapseCat: function(id) {
326                 if (!this.model.hasCats()) return;
327
328                 var tree = this;
329
330                 var node = tree._itemNodesMap['CAT:' + id][0];
331                 var item = tree.model.store._itemsByIdentity['CAT:' + id];
332
333                 if (node && item) {
334                         if (!node.isExpanded)
335                                 tree._expandNode(node);
336                         else
337                                 tree._collapseNode(node);
338
339                 }
340         },
341         getVisibleUnreadFeeds: function() {
342                 var items = this.model.store._arrayOfAllItems;
343                 var rv = [];
344
345                 for (var i = 0; i < items.length; i++) {
346                         var id = String(items[i].id);
347                         var box = this._itemNodesMap[id];
348
349                         if (box) {
350                                 var row = box[0].rowNode;
351                                 var cat = false;
352
353                                 try {
354                                         cat = box[0].rowNode.parentNode.parentNode;
355                                 } catch (e) { }
356
357                                 if (row) {
358                                         if (Element.visible(row) && (!cat || Element.visible(cat))) {
359                                                 var feed_id = String(items[i].bare_id);
360                                                 var is_cat = !id.match('FEED:');
361                                                 var unread = this.model.getFeedUnread(feed_id, is_cat);
362
363                                                 if (unread > 0)
364                                                         rv.push([feed_id, is_cat]);
365
366                                         }
367                                 }
368                         }
369                 }
370
371                 return rv;
372         },
373         getNextFeed: function (feed, is_cat) {
374                 if (is_cat) {
375                         treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
376                 } else {
377                         treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
378                 }
379
380                 items = this.model.store._arrayOfAllItems;
381                 var item = items[0];
382
383                 for (var i = 0; i < items.length; i++) {
384                         if (items[i] == treeItem) {
385
386                                 for (var j = i+1; j < items.length; j++) {
387                                         var id = String(items[j].id);
388                                         var box = this._itemNodesMap[id];
389
390                                         if (box) {
391                                                 var row = box[0].rowNode;
392                                                 var cat = box[0].rowNode.parentNode.parentNode;
393
394                                                 if (Element.visible(cat) && Element.visible(row)) {
395                                                         item = items[j];
396                                                         break;
397                                                 }
398                                         }
399                                 }
400                                 break;
401                         }
402                 }
403
404                 if (item) {
405                         return [this.model.store.getValue(item, 'bare_id'),
406                                                 !this.model.store.getValue(item, 'id').match('FEED:')];
407                 } else {
408                         return false;
409                 }
410         },
411         getPreviousFeed: function (feed, is_cat) {
412                 if (is_cat) {
413                         treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
414                 } else {
415                         treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
416                 }
417
418                 items = this.model.store._arrayOfAllItems;
419                 var item = items[0];
420
421                 for (var i = 0; i < items.length; i++) {
422                         if (items[i] == treeItem) {
423
424                                 for (var j = i-1; j > 0; j--) {
425                                         var id = String(items[j].id);
426                                         var box = this._itemNodesMap[id];
427
428                                         if (box) {
429                                                 var row = box[0].rowNode;
430                                                 var cat = box[0].rowNode.parentNode.parentNode;
431
432                                                 if (Element.visible(cat) && Element.visible(row)) {
433                                                         item = items[j];
434                                                         break;
435                                                 }
436                                         }
437
438                                 }
439                                 break;
440                         }
441                 }
442
443                 if (item) {
444                         return [this.model.store.getValue(item, 'bare_id'),
445                                                 !this.model.store.getValue(item, 'id').match('FEED:')];
446                 } else {
447                         return false;
448                 }
449
450         },
451         getFeedCategory: function(feed) {
452                 try {
453                         return this.getNodesByItem(this.model.store.
454                                         _itemsByIdentity["FEED:" + feed])[0].
455                                         getParent().item.bare_id[0];
456
457                 } catch (e) {
458                         return false;
459                 }
460         },
461 });