]> git.wh0rd.org Git - tt-rss.git/blob - digest.js
51c824ee489f5c3bc902fa86f61c5521a816f51b
[tt-rss.git] / digest.js
1 var last_feeds = [];
2
3 var _active_feed_id = false;
4 var _active_feed_offset = false;
5 var _update_timeout = false;
6 var _feedlist_expanded = false;
7
8 function catchup_feed(feed_id, callback) {
9         try {
10
11                 var fn = find_feed(last_feeds, feed_id).title;
12
13                 if (confirm(__("Mark all articles in %s as read?").replace("%s", fn))) {
14
15                         var is_cat = "";
16
17                         if (feed_id < 0) is_cat = "true"; // KLUDGE
18
19                         var query = "?op=rpc&subop=catchupFeed&feed_id=" + 
20                                 feed_id + "&is_cat=" + is_cat;
21
22                         new Ajax.Request("backend.php", {
23                                 parameters: query, 
24                                 onComplete: function(transport) {
25                                         if (callback) callback(transport);
26         
27                                         update();
28                                 } });
29                 }
30
31         } catch (e) {
32                 exception_error("catchup_article", e);
33         }
34 }
35
36 function catchup_visible_articles(callback) {
37         try {
38                 var elems = $("headlines-content").getElementsByTagName("LI");
39                 var ids = [];
40                 
41                 for (var i = 0; i < elems.length; i++) {
42                         if (elems[i].id && elems[i].id.match("A-")) {
43                                 ids.push(elems[i].id.replace("A-", ""));
44                         }
45                 }
46
47                 var query = "?op=rpc&subop=catchupSelected" +
48                         "&cmode=0&ids=" + param_escape(ids);
49
50                 new Ajax.Request("backend.php", {
51                         parameters: query, 
52                         onComplete: function(transport) {
53                                 if (callback) callback(transport);
54
55                                 viewfeed(_active_feed_id, 0);
56                         } });
57
58         } catch (e) {
59                 exception_error("catchup_visible_articles", e);
60         }
61 }
62
63 function catchup_article(article_id, callback) {
64         try {
65                 var query = "?op=rpc&subop=catchupSelected" +
66                         "&cmode=0&ids=" + article_id;
67
68                 new Ajax.Request("backend.php", {
69                         parameters: query, 
70                         onComplete: function(transport) {
71                                 if (callback) callback(transport);
72                         } });
73
74         } catch (e) {
75                 exception_error("catchup_article", e);
76         }
77 }
78
79 function set_selected_feed(feed_id) {
80         try {
81                 var feeds = $("feeds-content").getElementsByTagName("LI");
82
83                 for (var i = 0; i < feeds.length; i++) {
84                         if (feeds[i].id == "F-" + feed_id)
85                                 feeds[i].className = "selected";
86                         else
87                                 feeds[i].className = "";
88                 }
89
90                 _active_feed_id = feed_id;
91
92         } catch (e) {
93                 exception_error("mark_selected_feed", e);
94         }
95 }
96
97 function zoom(article_id) {
98         try {
99                 var elem = $('A-' + article_id);
100
101                 if (elem) {
102                         var divs = elem.getElementsByTagName('DIV');
103                         
104                         for (var i = 0; i < divs.length; i++) {
105                                 if (divs[i].className == 'excerpt') 
106                                         Element.hide(divs[i]);
107
108                                 if (divs[i].className == 'content') 
109                                         Element.show(divs[i]);
110                         }
111                 }
112
113                 //catchup_article(article_id, 
114                 //      function() { update(); });
115
116         } catch (e) {
117                 exception_error("zoom", e);
118         }
119 }
120
121 function load_more() {
122         try {
123                 viewfeed(_active_feed_id, _active_feed_offset + 10);
124         } catch (e) {
125                 exception_error("load_more", e);
126         }
127 }
128
129 function update() {
130         try {
131                 console.log('updating feeds...');
132
133                 window.clearTimeout(_update_timeout);
134
135                 new Ajax.Request("backend.php", {
136                         parameters: "?op=rpc&subop=digest-init",
137                         onComplete: function(transport) {
138                                 fatal_error_check(transport);
139                                 parse_feeds(transport);
140                                 set_selected_feed(_active_feed_id);
141                                 } });
142
143                 _update_timeout = window.setTimeout('update()', 5*1000);
144         } catch (e) {
145                 exception_error("update", e);
146         }
147 }
148
149 function remove_headline_entry(article_id) {
150         try {
151                 var elem = $('A-' + article_id);
152
153                 if (elem) {
154                         elem.parentNode.removeChild(elem);
155                 }
156
157         } catch (e) {
158                 exception_error("remove_headline_entry", e);
159         }
160 }
161
162 function view(article_id, dismiss_only) {
163         try {
164                 remove_headline_entry(article_id);
165
166                 catchup_article(article_id, 
167                         function() { 
168                                 viewfeed(_active_feed_id, _active_feed_offset);
169                                 update();                               
170                         });
171
172                 return dismiss_only != true;
173         } catch (e) {
174                 exception_error("view", e);
175         }
176 }
177
178 function viewfeed(feed_id, offset) {
179         try {
180
181                 if (!feed_id) feed_id = _active_feed_id;
182
183                 if (!offset) {
184                         offset = 0;
185                 } else {
186                         offset = _active_feed_offset + offset;
187                 }
188
189                 var query = "backend.php?op=rpc&subop=digest-update&feed_id=" + 
190                                 param_escape(feed_id) + "&offset=" + offset;
191
192                 console.log(query);
193
194                 new Ajax.Request("backend.php", {
195                         parameters: query, 
196                         onComplete: function(transport) {
197                                 fatal_error_check(transport);
198                                 parse_headlines(transport, offset == 0);
199                                 set_selected_feed(feed_id);
200                                 _active_feed_offset = offset;
201                         } });
202
203         } catch (e) {
204                 exception_error("view", e);
205         }
206 }
207
208 function find_article(articles, article_id) {
209         try {
210                 for (var i = 0; i < articles.length; i++) {
211                         if (articles[i].id == article_id)
212                                 return articles[i];
213                 }
214
215                 return false;
216
217         } catch (e) {
218                 exception_error("find_article", e);
219         }
220 }
221
222 function find_feed(feeds, feed_id) {
223         try {
224                 for (var i = 0; i < feeds.length; i++) {
225                         if (feeds[i].id == feed_id)
226                                 return feeds[i];
227                 }
228
229                 return false;
230
231         } catch (e) {
232                 exception_error("find_feed", e);
233         }
234 }
235
236 function get_feed_icon(feed) {
237         try {
238                 if (feed.has_icon)
239                         return 'icons/' + feed.id + '.ico';
240
241                 if (feed.id == -1)
242                         return 'images/mark_set.png';
243
244                 if (feed.id == -2)
245                         return 'images/pub_set.png';
246
247                 if (feed.id == -3)
248                         return 'images/fresh.png';
249
250                 if (feed.id == -4) 
251                         return 'images/tag.png';
252
253                 if (feed.id < -10) 
254                         return 'images/label.png';
255
256                 return 'images/blank_icon.gif';
257
258         } catch (e) {
259                 exception_error("get_feed_icon", e);
260         }
261 }
262
263 function add_feed_entry(feed) {
264         try {
265                 var icon_part = "";
266
267                 icon_part = "<img src='" + get_feed_icon(feed) + "'/>";
268
269                 var tmp_html = "<li id=\"F-"+feed.id+"\" " +
270                                 "onmouseover=\"feed_mi(this)\" onmouseout=\"feed_mo(this)\">" + 
271                         icon_part +
272                         "<a href=\"#\" onclick=\"viewfeed("+feed.id+")\">" + feed.title + "</a>" +
273                         "<div class='unread-ctr'>" + 
274                                 "<img onclick=\"catchup_feed("+feed.id+")\" title=\"" + 
275                                         __("Mark as read") + 
276                                         "\" class=\"dismiss\" style='display : none' src=\"images/digest_checkbox.png\">" +
277                                 "<span class=\"unread\">" + feed.unread + "</span>" + 
278                         "</div>" +      
279                         "</li>";
280
281                 $("feeds-content").innerHTML += tmp_html;
282
283         } catch (e) {
284                 exception_error("add_feed_entry", e);
285         }
286 }
287
288 function add_headline_entry(article, feed) {
289         try {
290
291                 var icon_part = "";
292
293                 icon_part = "<img class='icon' src='" + get_feed_icon(feed) + "'/>";
294
295                 var mark_part = "";
296                 var publ_part = "";
297
298                 var tags_part = "";
299
300                 if (article.tags.length > 0) {
301
302                         tags_part = " " + __("in") + " ";
303
304                         for (var i = 0; i < Math.min(5, article.tags.length); i++) {
305                                 tags_part += "<a href=\"#\" onclick=\"viewfeed('" + 
306                                                 article.tags[i] + "')\">" + 
307                                         article.tags[i] + "</a>, ";
308                         }
309
310                         tags_part = tags_part.replace(/, $/, "");
311                         tags_part = "<span class=\"tags\">" + tags_part + "</span>";
312                 }
313
314                 if (article.marked)
315                         mark_part = "<img title='"+ __("Unstar article")+"' onclick=\"toggle_mark(this, "+article.id+")\" src='images/mark_set.png'>";
316                 else
317                         mark_part =     "<img title='"+__("Star article")+"' onclick=\"toggle_mark(this, "+article.id+")\" src='images/mark_unset.png'>";
318
319                 if (article.published)
320                         publ_part = "<img title='"+__("Unpublish article")+"' onclick=\"toggle_pub(this, "+article.id+")\" src='images/pub_set.png'>";
321                 else
322                         publ_part =     "<img title='"+__("Publish article")+"' onclick=\"toggle_pub(this, "+article.id+")\" src='images/pub_unset.png'>";
323
324
325                 var tmp_html = "<li id=\"A-"+article.id+"\">" + 
326                         icon_part +
327                         "<div class='digest-check'>" +
328                         mark_part +
329                         publ_part +
330                         "<img title='" + __("Mark as read") + "' onclick=\"view("+article.id+", true)\" src='images/digest_checkbox.png'>" +
331                         "</div>" + 
332                         "<a target=\"_blank\" href=\""+article.link+"\""+
333                                 "onclick=\"return view("+article.id+")\" class='title'>" + 
334                                 article.title + "</a>" +
335                         "<div class='body'>" + 
336                         "<div title=\""+__("Click to expand article")+"\" onclick=\"zoom("+article.id+")\" class='excerpt'>" + 
337                                 article.excerpt + "</div>" +
338                         "<div style='display : none' class='content'>" + 
339                                 article.content + "</div>" +
340                         "<div class='info'><a href=\#\" onclick=\"viewfeed("+feed.id+")\">" + 
341                                 feed.title + "</a> " + tags_part + " @ " + 
342                                 new Date(article.updated * 1000) + "</div>" +
343                         "</div></li>";
344
345                 $("headlines-content").innerHTML += tmp_html;
346
347         } catch (e) {
348                 exception_error("add_headline_entry", e);
349         }
350 }
351
352 function expand_feeds() {
353         try {
354                 _feedlist_expanded = true;
355
356                 redraw_feedlist(last_feeds);
357
358         } catch (e) {
359                 exception_error("expand_feeds", e);
360         }
361 }
362
363 function redraw_feedlist(feeds) {
364         try {
365
366                 $('feeds-content').innerHTML = "";
367
368                 var limit = 10;
369
370                 if (_feedlist_expanded) limit = feeds.length;
371
372                 for (var i = 0; i < Math.min(limit, feeds.length); i++) {
373                         add_feed_entry(feeds[i]);
374                 }
375
376                 if (feeds.length > limit) {
377                         $('feeds-content').innerHTML += "<li id='F-MORE-PROMPT'>" +
378                                 "<img src='images/blank_icon.gif'>" + 
379                                 "<a href=\"#\" onclick=\"expand_feeds()\">" +
380                                 __("%d more...").replace("%d", feeds.length-10) + 
381                                 "</a>" + "</li>";
382                 }
383
384         } catch (e) {
385                 exception_error("redraw_feedlist", e);
386         }
387 }
388
389 function parse_feeds(transport) {
390         try {
391
392                 if (!transport.responseXML) return;
393
394                 var feeds = transport.responseXML.getElementsByTagName('feeds')[0];
395
396                 if (feeds) {
397                         feeds = eval("(" + feeds.firstChild.nodeValue + ")");
398
399                         feeds.sort( function (a,b) 
400                                 { 
401                                         if (b.unread != a.unread)
402                                                 return (b.unread - a.unread) 
403                                         else
404                                                 if (a.title > b.title)
405                                                         return 1;
406                                                 else if (a.title < b.title)
407                                                         return -1;
408                                                 else
409                                                         return 0;                                       
410                                 });
411
412                         var all_articles = find_feed(feeds, -4);
413
414                         update_title(all_articles.unread);
415
416                         last_feeds = feeds;
417
418                         redraw_feedlist(feeds);
419                 }
420
421         } catch (e) {
422                 exception_error("parse_feeds", e);
423         }
424 }
425
426 function parse_headlines(transport, replace) {
427         try {
428                 if (!transport.responseXML) return;
429
430                 var headlines = transport.responseXML.getElementsByTagName('headlines')[0];
431                 var headlines_title = transport.responseXML.getElementsByTagName('headlines-title')[0];
432
433                 if (headlines && headlines_title) {
434                         headlines = eval("(" + headlines.firstChild.nodeValue + ")");
435
436                         var title = headlines_title.firstChild.nodeValue;
437
438                         $("headlines-title").innerHTML = title;
439
440                         if (replace) $('headlines-content').innerHTML = '';
441
442                         var pr = $('H-MORE-PROMPT');
443
444                         if (pr) pr.parentNode.removeChild(pr);
445
446                         for (var i = 0; i < headlines.length; i++) {
447                                 
448                                 if (!$('A-' + headlines[i].id)) {
449                                         add_headline_entry(headlines[i], 
450                                                         find_feed(last_feeds, headlines[i].feed_id));
451                                 }
452                         }
453
454                         if (pr) {
455                                 $('headlines-content').appendChild(pr);
456                         } else {
457                                 $('headlines-content').innerHTML += "<li id='H-MORE-PROMPT'>" +
458                                         "<div class='body'>" +
459                                         "<a href=\"javascript:catchup_visible_articles()\">" +
460                                         __("Mark as read") + "</a> | " + 
461                                         "<a href=\"javascript:load_more()\">" +
462                                         __("Load more...") + "</a>" + 
463                                         "</div></li>";
464                         }
465
466                         new Effect.Appear('headlines-content');
467                 }
468
469         } catch (e) {
470                 exception_error("parse_headlines", e);
471         }
472 }
473
474 function init() {
475         try {
476                 
477                 new Ajax.Request("backend.php", {
478                         parameters: "backend.php?op=rpc&subop=digest-init",
479                         onComplete: function(transport) {
480                                 parse_feeds(transport);
481                                 window.setTimeout('viewfeed(-4)', 100);
482                                 _update_timeout = window.setTimeout('update()', 5*1000);
483                                 } });
484
485         } catch (e) {
486                 exception_error("digest_init", e);
487         }
488 }
489
490 function toggle_mark(mark_img, id) {
491
492         try {
493
494                 var query = "?op=rpc&id=" + id + "&subop=mark";
495         
496                 query = query + "&afid=" + _active_feed_id;
497                 query = query + "&omode=c";
498
499                 if (!mark_img) return;
500
501                 if (mark_img.src.match("mark_unset")) {
502                         mark_img.src = mark_img.src.replace("mark_unset", "mark_set");
503                         mark_img.alt = __("Unstar article");
504                         query = query + "&mark=1";
505                 } else {
506                         mark_img.alt = __("Please wait...");
507                         query = query + "&mark=0";
508         
509                         mark_img.src = mark_img.src.replace("mark_set", "mark_unset");
510                         mark_img.alt = __("Star article");
511                 }
512
513                 new Ajax.Request("backend.php", {
514                         parameters: query,
515                         onComplete: function(transport) { 
516                                 update();
517                         } });
518
519         } catch (e) {
520                 exception_error("toggle_mark", e);
521         }
522 }
523
524 function toggle_pub(mark_img, id, note) {
525
526         try {
527
528                 var query = "?op=rpc&id=" + id + "&subop=publ";
529         
530                 query = query + "&afid=" + _active_feed_id;
531
532                 if (note != undefined) {
533                         query = query + "&note=" + param_escape(note);
534                 } else {
535                         query = query + "&note=undefined";
536                 }
537
538                 query = query + "&omode=c";
539
540                 if (!mark_img) return;
541
542                 if (mark_img.src.match("pub_unset") || note != undefined) {
543                         mark_img.src = mark_img.src.replace("pub_unset", "pub_set");
544                         mark_img.alt = __("Unpublish article");
545                         query = query + "&pub=1";
546
547                 } else {
548                         mark_img.alt = __("Please wait...");
549                         query = query + "&pub=0";
550         
551                         mark_img.src = mark_img.src.replace("pub_set", "pub_unset");
552                         mark_img.alt = __("Publish article");
553                 }
554
555                 new Ajax.Request("backend.php", {
556                         parameters: query,
557                         onComplete: function(transport) { 
558                                 update();
559                         } });
560
561         } catch (e) {
562                 exception_error("toggle_pub", e);
563         }
564 }
565
566 function fatal_error(code, msg) {
567         try {   
568
569                 if (code == 6) {
570                         window.location.href = "digest.php";
571                 } else if (code == 5) {
572                         window.location.href = "update.php";
573                 } else {
574         
575                         if (msg == "") msg = "Unknown error";
576
577                         console.error("Fatal error: " + code + "\n" + 
578                                 msg);
579                         
580                 }
581
582         } catch (e) {
583                 exception_error("fatalError", e);
584         }
585 }
586
587 function fatal_error_check(transport) {
588         try {
589                 if (transport.responseXML) {
590                         var error = transport.responseXML.getElementsByTagName("error")[0];
591
592                         if (error) {
593                                 var code = error.getAttribute("error-code");
594                                 var msg = error.getAttribute("error-msg");
595                                 if (code != 0) {
596                                         fatal_error(code, msg);
597                                         return false;
598                                 }
599                         }
600                 }
601         } catch (e) {
602                 exception_error("fatal_error_check", e);
603         }
604         return true;
605 }
606
607 function feed_mi(elem) {
608         try {
609                 var imgs = elem.getElementsByTagName('IMG');
610                 var spans = elem.getElementsByTagName('SPAN');
611
612                 for (var i = 0; i < imgs.length; i++) {
613                         if (imgs[i].className == "dismiss")
614                                 Element.show(imgs[i]);
615                 }
616
617                 for (var i = 0; i < spans.length; i++) {
618                         if (spans[i].className == "unread")
619                                 Element.hide(spans[i]);
620                 }
621
622
623         } catch (e) {
624                 exception_error("feed_mi", e);
625         }
626 }
627
628 function feed_mo(elem) {
629         try {
630                 var imgs = elem.getElementsByTagName('IMG');
631                 var spans = elem.getElementsByTagName('SPAN');
632
633                 for (var i = 0; i < imgs.length; i++) {
634                         if (imgs[i].className == "dismiss")
635                                 Element.hide(imgs[i]);
636                 }
637
638                 for (var i = 0; i < spans.length; i++) {
639                         if (spans[i].className == "unread")
640                                 Element.show(spans[i]);
641                 }
642
643         } catch (e) {
644                 exception_error("feed_mo", e);
645         }
646 }
647
648 function update_title(unread) {
649         try {
650                 document.title = "Tiny Tiny RSS";
651
652                 if (unread > 0)
653                         document.title += " (" + unread + ")";
654
655         } catch (e) {
656                 exception_error("update_title", e);
657         }
658 }
659