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