]> git.wh0rd.org Git - tt-rss.git/blob - viewfeed.js
some more placeholders for dashboard
[tt-rss.git] / viewfeed.js
1 var active_post_id = false;
2 var last_article_view = false;
3 var active_real_feed_id = false;
4
5 var _tag_active_post_id = false;
6 var _tag_active_feed_id = false;
7 var _tag_active_cdm = false;
8
9 // FIXME: kludge, to restore scrollTop after tag editor terminates
10 var _tag_cdm_scroll = false;
11
12 // FIXME: kludges, needs proper implementation
13 var _reload_feedlist_after_view = false;
14
15 var _cdm_wd_timeout = false;
16 var _cdm_wd_vishist = new Array();
17
18 var article_cache = new Array();
19
20 function catchup_callback() {
21         if (xmlhttp_rpc.readyState == 4) {
22                 try {
23                         debug("catchup_callback");
24                         notify("");                     
25                         all_counters_callback2(xmlhttp_rpc);
26                         if (_catchup_callback_func) {
27                                 setTimeout(_catchup_callback_func, 10); 
28                         }
29                 } catch (e) {
30                         exception_error("catchup_callback", e);
31                 }
32         }
33 }
34
35 function catchup_callback2(transport, callback) {
36         try {
37                 debug("catchup_callback2 " + transport + ", " + callback);
38                 notify("");                     
39                 all_counters_callback2(transport);
40                 if (callback) {
41                         setTimeout(callback, 10);       
42                 }
43         } catch (e) {
44                 exception_error("catchup_callback2", e);
45         }
46 }
47
48 function clean_feed_selections() {
49         try {
50                 var feeds = document.getElementById("feedList").getElementsByTagName("LI");
51
52                 for (var i = 0; i < feeds.length; i++) {
53                         if (feeds[i].id && feeds[i].id.match("FEEDR-")) {
54                                 feeds[i].className = feeds[i].className.replace("Selected", "");
55                         }                       
56                 }
57         } catch (e) {
58                 exception_error("clean_feed_selections", e);
59         }
60 }
61
62 function headlines_callback2(transport, active_feed_id, is_cat, feed_cur_page) {
63         try {
64
65                 debug("headlines_callback2 [page=" + feed_cur_page + "]");
66
67                 clean_feed_selections();
68
69                 setActiveFeedId(active_feed_id);
70                 
71                 if (is_cat != undefined) {
72                         active_feed_is_cat = is_cat;
73                 }
74         
75                 if (!is_cat) {
76                         var feedr = document.getElementById("FEEDR-" + active_feed_id);
77                         if (feedr && !feedr.className.match("Selected")) {      
78                                 feedr.className = feedr.className + "Selected";
79                         } 
80                 }
81         
82                 var f = document.getElementById("headlines-frame");
83                 try {
84                         if (feed_cur_page == 0) { 
85                                 debug("resetting headlines scrollTop");
86                                 f.scrollTop = 0; 
87                         }
88                 } catch (e) { };
89         
90                 if (transport.responseXML) {
91                         var headlines = transport.responseXML.getElementsByTagName("headlines")[0];
92                         var headlines_count_obj = transport.responseXML.getElementsByTagName("headlines-count")[0];
93                         var headlines_unread_obj = transport.responseXML.getElementsByTagName("headlines-unread")[0];
94                         var disable_cache_obj = transport.responseXML.getElementsByTagName("disable-cache")[0];
95
96                         var headlines_count = headlines_count_obj.getAttribute("value");
97                         var headlines_unread = headlines_unread_obj.getAttribute("value");
98                         var disable_cache = disable_cache_obj.getAttribute("value") != "0";
99
100                         if (headlines_count == 0) _infscroll_disable = 1;
101         
102                         var counters = transport.responseXML.getElementsByTagName("counters")[0];
103                         var articles = transport.responseXML.getElementsByTagName("article");
104                         var runtime_info = transport.responseXML.getElementsByTagName("runtime-info");
105         
106                         if (feed_cur_page == 0) {
107                                 if (headlines) {
108                                         f.innerHTML = headlines.firstChild.nodeValue;
109
110                                         var cache_prefix = "";
111
112                                         if (is_cat) {
113                                                 cache_prefix = "C:";
114                                         } else {
115                                                 cache_prefix = "F:";
116                                         }
117
118                                         cache_invalidate(cache_prefix + active_feed_id);
119
120                                         if (!disable_cache) {
121                                                 cache_inject(cache_prefix + active_feed_id,
122                                                         headlines.firstChild.nodeValue, headlines_unread);
123                                         }
124
125                                 } else {
126                                         debug("headlines_callback: returned no data");
127                                 f.innerHTML = "<div class='whiteBox'>" + __('Could not update headlines (missing XML data)') + "</div>";
128         
129                                 }
130                         } else {
131                                 if (headlines) {
132                                         if (headlines_count > 0) {
133                                                 debug("adding some more headlines...");
134         
135                                                 var c = document.getElementById("headlinesList");
136                 
137                                                 if (!c) {
138                                                         c = document.getElementById("headlinesInnerContainer");
139                                                 }
140
141                                                 var ids = getSelectedArticleIds2();
142         
143                                                 c.innerHTML = c.innerHTML + headlines.firstChild.nodeValue;
144
145                                                 debug("restore selected ids: " + ids);
146
147                                                 for (var i = 0; i < ids.length; i++) {
148                                                         markHeadline(ids[i]);
149                                                 }
150
151                                         } else {
152                                                 debug("no new headlines received");
153                                         }
154                                 } else {
155                                         debug("headlines_callback: returned no data");
156                                         notify_error("Error while trying to load more headlines");      
157                                 }
158         
159                         }
160         
161                         if (articles) {
162                                 for (var i = 0; i < articles.length; i++) {
163                                         var a_id = articles[i].getAttribute("id");
164                                         debug("found id: " + a_id);
165                                         cache_inject(a_id, articles[i].firstChild.nodeValue);
166                                 }
167                         } else {
168                                 debug("no cached articles received");
169                         }
170         
171                         if (counters) {
172                                 debug("parsing piggybacked counters: " + counters);
173                                 parse_counters(counters, false);
174                         } else {
175                                 debug("counters container not found in reply");
176                         }
177         
178                         if (runtime_info) {
179                                 debug("parsing runtime info: " + runtime_info[0]);
180                                 parse_runtime_info(runtime_info[0]);
181                         } else {
182                                 debug("counters container not found in reply");
183                         }
184         
185                 } else {
186                         debug("headlines_callback: returned no XML object");
187                         f.innerHTML = "<div class='whiteBox'>" + __('Could not update headlines (missing XML object)') + "</div>";
188                 }
189         
190                 if (typeof correctPNG != 'undefined') {
191                         correctPNG();
192                 }
193         
194                 if (_cdm_wd_timeout) window.clearTimeout(_cdm_wd_timeout);
195         
196                 if (!document.getElementById("headlinesList") && 
197                                 getInitParam("cdm_auto_catchup") == 1) {
198                         debug("starting CDM watchdog");
199                         _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 5000);
200                         _cdm_wd_vishist = new Array();
201                 } else {
202                         debug("not in CDM mode or watchdog disabled");
203                 }
204         
205                 if (_tag_cdm_scroll) {
206                         try {
207                                 document.getElementById("headlinesInnerContainer").scrollTop = _tag_cdm_scroll;
208                                 _tag_cdm_scroll = false;
209                                 debug("resetting headlinesInner scrollTop");
210         
211                         } catch (e) { }
212                 }
213         
214                 _feed_cur_page = feed_cur_page;
215                 _infscroll_request_sent = 0;
216
217                 notify("");
218         } catch (e) {
219                 exception_error("headlines_callback2", e);
220         }
221 }
222
223 function render_article(article) {
224         try {
225                 var f = document.getElementById("content-frame");
226                 try {
227                         f.scrollTop = 0;
228                 } catch (e) { };
229
230                 f.innerHTML = article;
231
232         } catch (e) {
233                 exception_error("render_article", e);
234         }
235 }
236
237 function showArticleInHeadlines(id) {
238
239         try {
240
241                 cleanSelected("headlinesList");
242         
243                 var crow = document.getElementById("RROW-" + id);
244
245                 if (!crow) return;
246
247                 var article_is_unread = crow.className.match("Unread");
248                         
249                 crow.className = crow.className.replace("Unread", "");
250
251                 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
252         
253                 var upd_img_pic = document.getElementById("FUPDPIC-" + id);
254
255                 var cache_prefix = "";
256                                 
257                 if (activeFeedIsCat()) {
258                         cache_prefix = "C:";
259                 } else {
260                         cache_prefix = "F:";
261                 }
262
263                 var view_mode = false;
264
265                 try {
266                         view_mode = document.forms['main_toolbar_form'].view_mode;      
267                         view_mode = view_mode[view_mode.selectedIndex].value;
268                 } catch (e) {
269                         exception_error("showArticleInHeadlines/viewmode", e, true);
270                 }
271
272                 if (upd_img_pic && upd_img_pic.src.match("updated.png")) {
273                         upd_img_pic.src = "images/blank_icon.gif";
274
275                         cache_invalidate(cache_prefix + getActiveFeedId());
276
277                         cache_inject(cache_prefix + getActiveFeedId(),
278                                 document.getElementById("headlines-frame").innerHTML,
279                                 get_feed_unread(getActiveFeedId()));
280
281                 } else if (article_is_unread && view_mode == "all_articles") {
282
283                         cache_invalidate(cache_prefix + getActiveFeedId());
284
285                         cache_inject(cache_prefix + getActiveFeedId(),
286                                 document.getElementById("headlines-frame").innerHTML,
287                                 get_feed_unread(getActiveFeedId())-1);
288
289                 } else if (article_is_unread) {
290                         cache_invalidate(cache_prefix + getActiveFeedId());
291                 }
292
293                 markHeadline(id);
294
295         } catch (e) {
296                 exception_error("showArticleInHeadlines", e);
297         }
298 }
299
300 function article_callback2(transport, id, feed_id) {
301         try {
302                 debug("article_callback2 " + id);
303
304                 if (transport.responseXML) {
305
306                         active_real_feed_id = feed_id;
307                         active_post_id = id; 
308
309                         showArticleInHeadlines(id);     
310
311                         var reply = transport.responseXML.firstChild.firstChild;
312
313                         var articles = transport.responseXML.getElementsByTagName("article");
314
315                         for (var i = 0; i < articles.length; i++) {
316                                 var a_id = articles[i].getAttribute("id");
317
318                                 debug("found id: " + a_id);
319
320                                 if (a_id == active_post_id) {
321                                         debug("active article, rendering...");                                  
322                                         render_article(articles[i].firstChild.nodeValue);
323                                 }
324
325                                 cache_inject(a_id, articles[i].firstChild.nodeValue);
326                         }
327                 
328                 } else {
329                         debug("article_callback: returned no XML object");
330                         var f = document.getElementById("content-frame");
331                         f.innerHTML = "<div class='whiteBox'>" + __('Could not display article (missing XML object)') + "</div>";
332                 }
333
334                 var date = new Date();
335                 last_article_view = date.getTime() / 1000;
336
337                 if (typeof correctPNG != 'undefined') {
338                         correctPNG();
339                 }
340
341                 if (_reload_feedlist_after_view) {
342                         setTimeout('updateFeedList(false, false)', 50);                 
343                         _reload_feedlist_after_view = false;
344                 } else {
345                         var counters = transport.responseXML.getElementsByTagName("counters")[0];
346
347                         if (counters) {
348                                 debug("parsing piggybacked counters: " + counters);
349                                 parse_counters(counters, false);
350                         } else {
351                                 debug("counters container not found in reply");
352                         }
353                 }
354
355                 notify("");
356         } catch (e) {
357                 exception_error("article_callback2", e);
358         }
359 }
360
361 function view(id, feed_id, skip_history) {
362         
363         try {
364                 debug("loading article: " + id + "/" + feed_id);
365         
366                 var cached_article = cache_find(id);
367
368                 debug("cache check result: " + (cached_article != false));
369         
370                 enableHotkeys();
371         
372                 //setActiveFeedId(feed_id);
373
374                 var query = "backend.php?op=view&id=" + param_escape(id) +
375                         "&feed=" + param_escape(feed_id);
376
377                 var date = new Date();
378
379                 var neighbor_ids = getRelativePostIds(active_post_id);
380
381                 /* only request uncached articles */
382
383                 var cids_to_request = Array();
384
385                 for (var i = 0; i < neighbor_ids.length; i++) {
386                         if (!cache_check(neighbor_ids[i])) {
387                                 cids_to_request.push(neighbor_ids[i]);
388                         }
389                 }
390
391                 debug("additional ids: " + cids_to_request.toString());                 
392
393                 /* additional info for piggyback counters */
394
395                 if (tagsAreDisplayed()) {
396                         query = query + "&omode=lt";
397                 } else {
398                         query = query + "&omode=flc";
399                 }
400
401                 var date = new Date();
402                 var timestamp = Math.round(date.getTime() / 1000);
403                 query = query + "&ts=" + timestamp;
404
405                 query = query + "&cids=" + cids_to_request.toString();
406
407                 var crow = document.getElementById("RROW-" + id);
408                 var article_is_unread = crow.className.match("Unread");
409
410                 showArticleInHeadlines(id);
411
412                 if (!cached_article) {
413
414                         notify_progress("Loading, please wait...");
415
416                 } else if (cached_article && article_is_unread) {
417
418                         query = query + "&mode=prefetch";
419
420                         render_article(cached_article);
421
422                 } else if (cached_article) {
423
424                         query = query + "&mode=prefetch_old";
425                         render_article(cached_article);
426                 }
427
428                 cache_expire();
429
430                 new Ajax.Request(query, {
431                         onComplete: function(transport) { 
432                                 article_callback2(transport, id, feed_id); 
433                         } });
434
435         } catch (e) {
436                 exception_error("view", e);
437         }
438 }
439
440 function tMark(id) {
441         return toggleMark(id);
442 }
443
444 function tPub(id) {
445         return togglePub(id);
446 }
447
448 function tMark_afh_off(effect) {
449         try {
450                 var elem = effect.effects[0].element;
451
452                 debug("tMark_afh_off : " + elem.id);
453
454                 if (elem) {
455                         elem.src = elem.src.replace("mark_set", "mark_unset");
456                         elem.alt = __("Star article");
457                         Element.show(elem);
458                 }
459
460         } catch (e) {
461                 exception_error("tMark_afh_off", e);
462         }
463 }
464
465 function tPub_afh_off(effect) {
466         try {
467                 var elem = effect.effects[0].element;
468
469                 debug("tPub_afh_off : " + elem.id);
470
471                 if (elem) {
472                         elem.src = elem.src.replace("pub_set", "pub_unset");
473                         elem.alt = __("Publish article");
474                         Element.show(elem);
475                 }
476
477         } catch (e) {
478                 exception_error("tPub_afh_off", e);
479         }
480 }
481
482 function toggleMark(id, client_only, no_effects) {
483
484         try {
485
486                 var query = "backend.php?op=rpc&id=" + id + "&subop=mark";
487         
488                 query = query + "&afid=" + getActiveFeedId();
489         
490                 if (tagsAreDisplayed()) {
491                         query = query + "&omode=tl";
492                 } else {
493                         query = query + "&omode=flc";
494                 }
495         
496                 var mark_img = document.getElementById("FMPIC-" + id);
497                 var vfeedu = document.getElementById("FEEDU--1");
498                 var crow = document.getElementById("RROW-" + id);
499         
500                 if (mark_img.src.match("mark_unset")) {
501                         mark_img.src = mark_img.src.replace("mark_unset", "mark_set");
502                         mark_img.alt = __("Unstar article");
503                         query = query + "&mark=1";
504         
505 /*                      if (vfeedu && crow.className.match("Unread")) {
506                                 vfeedu.innerHTML = (+vfeedu.innerHTML) + 1;
507                         } */
508         
509                 } else {
510                         //mark_img.src = "images/mark_unset.png";
511                         mark_img.alt = __("Please wait...");
512                         query = query + "&mark=0";
513         
514 /*                      if (vfeedu && crow.className.match("Unread")) {
515                                 vfeedu.innerHTML = (+vfeedu.innerHTML) - 1;
516                         } */
517         
518                         if (document.getElementById("headlinesList") && !no_effects) {
519                                 Effect.Puff(mark_img, {duration : 0.25, afterFinish: tMark_afh_off});
520                         } else { 
521                                 mark_img.src = mark_img.src.replace("mark_set", "mark_unset");
522                                 mark_img.alt = __("Star article");
523                         }
524                 }
525         
526 /*              var vfeedctr = document.getElementById("FEEDCTR--1");
527                 var vfeedr = document.getElementById("FEEDR--1");
528         
529                 if (vfeedu && vfeedctr) {
530                         if ((+vfeedu.innerHTML) > 0) {
531                                 if (crow.className.match("Unread") && !vfeedr.className.match("Unread")) {
532                                         vfeedr.className = vfeedr.className + "Unread";
533                                         vfeedctr.className = "odd";
534                                 }
535                         } else {
536                                 vfeedctr.className = "invisible";
537                                 vfeedr.className = vfeedr.className.replace("Unread", "");
538                         }
539                 }
540         
541                 debug("toggle starred for aid " + id);
542         
543                 //new Ajax.Request(query); */
544
545                 if (!client_only) {
546                         debug(query);
547
548                         new Ajax.Request(query, {
549                                 onComplete: function(transport) { 
550                                         all_counters_callback2(transport); 
551                                 } });
552
553                 }
554
555         } catch (e) {
556                 exception_error("toggleMark", e);
557         }
558 }
559
560 function togglePub(id, client_only, no_effects) {
561
562         try {
563
564                 var query = "backend.php?op=rpc&id=" + id + "&subop=publ";
565         
566                 query = query + "&afid=" + getActiveFeedId();
567         
568                 if (tagsAreDisplayed()) {
569                         query = query + "&omode=tl";
570                 } else {
571                         query = query + "&omode=flc";
572                 }
573         
574                 var mark_img = document.getElementById("FPPIC-" + id);
575                 var vfeedu = document.getElementById("FEEDU--2");
576                 var crow = document.getElementById("RROW-" + id);
577         
578                 if (mark_img.src.match("pub_unset")) {
579                         mark_img.src = mark_img.src.replace("pub_unset", "pub_set");
580                         mark_img.alt = __("Unpublish article");
581                         query = query + "&pub=1";
582         
583 /*                      if (vfeedu && crow.className.match("Unread")) {
584                                 vfeedu.innerHTML = (+vfeedu.innerHTML) + 1;
585                         } */
586         
587                 } else {
588                         //mark_img.src = "images/pub_unset.png";
589                         mark_img.alt = __("Please wait...");
590                         query = query + "&pub=0";
591         
592 /*                      if (vfeedu && crow.className.match("Unread")) {
593                                 vfeedu.innerHTML = (+vfeedu.innerHTML) - 1;
594                         } */
595
596                         if (document.getElementById("headlinesList") && !no_effects) {
597                                 Effect.Puff(mark_img, {duration : 0.25, afterFinish: tPub_afh_off});
598                         } else { 
599                                 mark_img.src = mark_img.src.replace("pub_set", "pub_unset");
600                                 mark_img.alt = __("Publish article");
601                         }
602                 }
603         
604 /*              var vfeedctr = document.getElementById("FEEDCTR--2");
605                 var vfeedr = document.getElementById("FEEDR--2");
606         
607                 if (vfeedu && vfeedctr) {
608                         if ((+vfeedu.innerHTML) > 0) {
609                                 if (crow.className.match("Unread") && !vfeedr.className.match("Unread")) {
610                                         vfeedr.className = vfeedr.className + "Unread";
611                                         vfeedctr.className = "odd";
612                                 }
613                         } else {
614                                 vfeedctr.className = "invisible";
615                                 vfeedr.className = vfeedr.className.replace("Unread", "");
616                         }
617                 }
618         
619                 debug("toggle published for aid " + id);
620         
621                 new Ajax.Request(query); */
622
623                 if (!client_only) {
624                         new Ajax.Request(query, {
625                                 onComplete: function(transport) { 
626                                         all_counters_callback2(transport); 
627                                 } });
628                 }
629
630         } catch (e) {
631
632                 exception_error("togglePub", e);
633         }
634 }
635
636 function correctHeadlinesOffset(id) {
637         
638         try {
639
640                 var hlist = document.getElementById("headlinesList");
641                 var container = document.getElementById("headlinesInnerContainer");
642                 var row = document.getElementById("RROW-" + id);
643         
644                 var viewport = container.offsetHeight;
645         
646                 var rel_offset_top = row.offsetTop - container.scrollTop;
647                 var rel_offset_bottom = row.offsetTop + row.offsetHeight - container.scrollTop;
648         
649                 debug("Rtop: " + rel_offset_top + " Rbtm: " + rel_offset_bottom);
650                 debug("Vport: " + viewport);
651
652                 if (rel_offset_top <= 0 || rel_offset_top > viewport) {
653                         container.scrollTop = row.offsetTop;
654                 } else if (rel_offset_bottom > viewport) {
655
656                         /* doesn't properly work with Opera in some cases because
657                                 Opera fucks up element scrolling */
658
659                         container.scrollTop = row.offsetTop + row.offsetHeight - viewport;              
660                 } 
661
662         } catch (e) {
663                 exception_error("correctHeadlinesOffset", e);
664         }
665
666 }
667
668 function moveToPost(mode) {
669
670         // check for combined mode
671         if (!document.getElementById("headlinesList"))
672                 return;
673
674         var rows = getVisibleHeadlineIds();
675
676         var prev_id = false;
677         var next_id = false;
678
679         if (!document.getElementById('RROW-' + active_post_id)) {
680                 active_post_id = false;
681         }
682
683         if (active_post_id == false) {
684                 next_id = getFirstVisibleHeadlineId();
685                 prev_id = getLastVisibleHeadlineId();
686         } else {        
687                 for (var i = 0; i < rows.length; i++) {
688                         if (rows[i] == active_post_id) {
689                                 prev_id = rows[i-1];
690                                 next_id = rows[i+1];                    
691                         }
692                 }
693         }
694
695         if (mode == "next") {
696                 if (next_id) {
697                         correctHeadlinesOffset(next_id);
698                         view(next_id, getActiveFeedId());
699                 }
700         }
701
702         if (mode == "prev") {
703                 if (prev_id) {
704                         correctHeadlinesOffset(prev_id);
705                         view(prev_id, getActiveFeedId());
706                 }
707         } 
708 }
709
710 function toggleUnread(id, cmode) {
711         try {
712         
713                 var row = document.getElementById("RROW-" + id);
714                 if (row) {
715                         var nc = row.className;
716                         nc = nc.replace("Unread", "");
717                         nc = nc.replace("Selected", "");
718
719                         if (cmode == undefined || cmode == 2) {
720                                 if (row.className.match("Unread")) {
721                                         row.className = nc;
722                                 } else {
723                                         row.className = nc + "Unread";
724                                 }
725                         } else if (cmode == 0) {
726                                 row.className = nc;
727                         } else if (cmode == 1) {
728                                 row.className = nc + "Unread";
729                         }
730
731                         if (cmode == undefined) cmode = 2;
732
733                         var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
734                                 param_escape(id) + "&cmode=" + param_escape(cmode);
735
736 //                      notify_progress("Loading, please wait...");
737
738                         new Ajax.Request(query, {
739                                 onComplete: function(transport) { 
740                                         all_counters_callback2(transport); 
741                                 } });
742
743                 }
744
745
746         } catch (e) {
747                 exception_error("toggleUnread", e);
748         }
749 }
750
751 function selectionToggleUnread(cdm_mode, set_state, callback_func, no_error) {
752         try {
753                 var rows;
754
755                 if (cdm_mode) {
756                         rows = cdmGetSelectedArticles();
757                 } else {        
758                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
759                 }
760
761                 if (rows.length == 0 && !no_error) {
762                         alert(__("No articles are selected."));
763                         return;
764                 }
765
766                 for (i = 0; i < rows.length; i++) {
767                         var row = document.getElementById("RROW-" + rows[i]);
768                         if (row) {
769                                 var nc = row.className;
770                                 nc = nc.replace("Unread", "");
771                                 nc = nc.replace("Selected", "");
772
773                                 if (set_state == undefined) {
774                                         if (row.className.match("Unread")) {
775                                                 row.className = nc + "Selected";
776                                         } else {
777                                                 row.className = nc + "UnreadSelected";
778                                         }
779                                 }
780
781                                 if (set_state == false) {
782                                         row.className = nc + "Selected";
783                                 }
784
785                                 if (set_state == true) {
786                                         row.className = nc + "UnreadSelected";
787                                 }
788                         }
789                 }
790
791                 if (rows.length > 0) {
792
793                         var cmode = "";
794
795                         if (set_state == undefined) {
796                                 cmode = "2";
797                         } else if (set_state == true) {
798                                 cmode = "1";
799                         } else if (set_state == false) {
800                                 cmode = "0";
801                         }
802
803                         var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
804                                 param_escape(rows.toString()) + "&cmode=" + cmode;
805
806                         notify_progress("Loading, please wait...");
807
808                         new Ajax.Request(query, {
809                                 onComplete: function(transport) { 
810                                         catchup_callback2(transport, callback_func); 
811                                 } });
812
813                 }
814
815         } catch (e) {
816                 exception_error("selectionToggleUnread", e);
817         }
818 }
819
820 function selectionToggleMarked(cdm_mode) {
821         try {
822         
823                 var rows;
824                 
825                 if (cdm_mode) {
826                         rows = cdmGetSelectedArticles();
827                 } else {        
828                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
829                 }       
830
831                 if (rows.length == 0) {
832                         alert(__("No articles are selected."));
833                         return;
834                 }
835
836                 for (i = 0; i < rows.length; i++) {
837                         toggleMark(rows[i], true, true);
838                 }
839
840                 if (rows.length > 0) {
841
842                         var query = "backend.php?op=rpc&subop=markSelected&ids=" +
843                                 param_escape(rows.toString()) + "&cmode=2";
844
845                         query = query + "&afid=" + getActiveFeedId();
846
847 /*                      if (tagsAreDisplayed()) {
848                                 query = query + "&omode=tl";
849                         } else {
850                                 query = query + "&omode=flc";
851                         } */
852
853                         query = query + "&omode=lc";
854
855                         new Ajax.Request(query, {
856                                 onComplete: function(transport) { 
857                                         all_counters_callback2(transport); 
858                                 } });
859
860                 }
861
862         } catch (e) {
863                 exception_error("selectionToggleMarked", e);
864         }
865 }
866
867 function selectionTogglePublished(cdm_mode) {
868         try {
869         
870                 var rows;
871                 
872                 if (cdm_mode) {
873                         rows = cdmGetSelectedArticles();
874                 } else {        
875                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
876                 }       
877
878                 if (rows.length == 0) {
879                         alert(__("No articles are selected."));
880                         return;
881                 }
882
883                 for (i = 0; i < rows.length; i++) {
884                         togglePub(rows[i], true, true);
885                 }
886
887                 if (rows.length > 0) {
888
889                         var query = "backend.php?op=rpc&subop=publishSelected&ids=" +
890                                 param_escape(rows.toString()) + "&cmode=2";
891
892                         query = query + "&afid=" + getActiveFeedId();
893
894 /*                      if (tagsAreDisplayed()) {
895                                 query = query + "&omode=tl";
896                         } else {
897                                 query = query + "&omode=flc";
898                         } */
899
900                         query = query + "&omode=lc";
901
902                         new Ajax.Request(query, {
903                                 onComplete: function(transport) { 
904                                         all_counters_callback2(transport); 
905                                 } });
906
907                 }
908
909         } catch (e) {
910                 exception_error("selectionToggleMarked", e);
911         }
912 }
913
914 function cdmGetSelectedArticles() {
915         var sel_articles = new Array();
916         var container = document.getElementById("headlinesInnerContainer");
917
918         for (i = 0; i < container.childNodes.length; i++) {
919                 var child = container.childNodes[i];
920
921                 if (child.id.match("RROW-") && child.className.match("Selected")) {
922                         var c_id = child.id.replace("RROW-", "");
923                         sel_articles.push(c_id);
924                 }
925         }
926
927         return sel_articles;
928 }
929
930 function cdmGetVisibleArticles() {
931         var sel_articles = new Array();
932         var container = document.getElementById("headlinesInnerContainer");
933
934         for (i = 0; i < container.childNodes.length; i++) {
935                 var child = container.childNodes[i];
936
937                 if (child.id.match("RROW-")) {
938                         var c_id = child.id.replace("RROW-", "");
939                         sel_articles.push(c_id);
940                 }
941         }
942
943         return sel_articles;
944 }
945
946 function cdmGetUnreadArticles() {
947         var sel_articles = new Array();
948         var container = document.getElementById("headlinesInnerContainer");
949
950         for (i = 0; i < container.childNodes.length; i++) {
951                 var child = container.childNodes[i];
952
953                 if (child.id.match("RROW-") && child.className.match("Unread")) {
954                         var c_id = child.id.replace("RROW-", "");
955                         sel_articles.push(c_id);
956                 }
957         }
958
959         return sel_articles;
960 }
961
962
963 // mode = all,none,unread
964 function cdmSelectArticles(mode) {
965         var container = document.getElementById("headlinesInnerContainer");
966
967         for (i = 0; i < container.childNodes.length; i++) {
968                 var child = container.childNodes[i];
969
970                 if (child.id.match("RROW-")) {
971                         var aid = child.id.replace("RROW-", "");
972
973                         var cb = document.getElementById("RCHK-" + aid);
974
975                         if (mode == "all") {
976                                 if (!child.className.match("Selected")) {
977                                         child.className = child.className + "Selected";
978                                         cb.checked = true;
979                                 }
980                         } else if (mode == "unread") {
981                                 if (child.className.match("Unread") && !child.className.match("Selected")) {
982                                         child.className = child.className + "Selected";
983                                         cb.checked = true;
984                                 }
985                         } else {
986                                 child.className = child.className.replace("Selected", "");
987                                 cb.checked = false;
988                         }
989                 }               
990         }
991 }
992
993 function catchupPage() {
994
995         var fn = getFeedName(getActiveFeedId(), active_feed_is_cat);
996         
997         var str = __("Mark all visible articles in %s as read?");
998
999         str = str.replace("%s", fn);
1000
1001         if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
1002                 return;
1003         }
1004
1005         if (document.getElementById("headlinesList")) {
1006                 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', true, 'Unread', true);
1007                 selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
1008                 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
1009         } else {
1010                 cdmSelectArticles('all');
1011                 selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
1012                 cdmSelectArticles('none');
1013         }
1014 }
1015
1016 function catchupSelection() {
1017
1018         try {
1019
1020                 var rows;
1021         
1022                 if (document.getElementById("headlinesList")) {
1023                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1024                 } else {        
1025                         rows = cdmGetSelectedArticles();
1026                 }
1027         
1028                 if (rows.length == 0) {
1029                         alert(__("No articles are selected."));
1030                         return;
1031                 }
1032         
1033         
1034                 var fn = getFeedName(getActiveFeedId(), active_feed_is_cat);
1035                 
1036                 var str = __("Mark %d selected articles in %s as read?");
1037         
1038                 str = str.replace("%d", rows.length);
1039                 str = str.replace("%s", fn);
1040         
1041                 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
1042                         return;
1043                 }
1044         
1045                 if (document.getElementById("headlinesList")) {
1046                         selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
1047         //              selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
1048                 } else {
1049                         selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
1050         //              cdmSelectArticles('none');
1051                 }
1052
1053         } catch (e) {
1054                 exception_error("catchupSelection", e);
1055         }
1056 }
1057
1058
1059 function labelFromSearch(search, search_mode, match_on, feed_id, is_cat) {
1060
1061         if (!xmlhttp_ready(xmlhttp_rpc)) {
1062                 printLockingError();
1063         }
1064
1065         var title = prompt(__("Please enter label title:"), "");
1066
1067         if (title) {
1068
1069                 var query = "backend.php?op=labelFromSearch&search=" + param_escape(search) +
1070                         "&smode=" + param_escape(search_mode) + "&match=" + param_escape(match_on) +
1071                         "&feed=" + param_escape(feed_id) + "&is_cat=" + param_escape(is_cat) + 
1072                         "&title=" + param_escape(title);
1073
1074                 debug("LFS: " + query);
1075
1076                 new Ajax.Request(query, {
1077                         onComplete: function(transport) {
1078                                         dlg_frefresh_callback(transport);
1079                                 } });
1080         }
1081 }
1082
1083 function editArticleTags(id, feed_id, cdm_enabled) {
1084         _tag_active_post_id = id;
1085         _tag_active_feed_id = feed_id;
1086         _tag_active_cdm = cdm_enabled;
1087
1088         cache_invalidate(id);
1089
1090         try {
1091                 _tag_cdm_scroll = document.getElementById("headlinesInnerContainer").scrollTop;
1092         } catch (e) { }
1093         displayDlg('editArticleTags', id);
1094 }
1095
1096
1097 function tag_saved_callback(transport) {
1098         try {
1099                 debug("in tag_saved_callback");
1100
1101                 closeInfoBox();
1102                 notify("");
1103
1104                 if (tagsAreDisplayed()) {
1105                         _reload_feedlist_after_view = true;
1106                 }
1107
1108                 if (!_tag_active_cdm) {
1109                         if (active_post_id == _tag_active_post_id) {
1110                                 debug("reloading current article");
1111                                 view(_tag_active_post_id, _tag_active_feed_id);                 
1112                         }
1113                 } else {
1114                         debug("reloading current feed");
1115                         viewCurrentFeed();
1116                 }
1117
1118         } catch (e) {
1119                 exception_error("catchup_callback", e);
1120         }
1121 }
1122
1123 function editTagsSave() {
1124
1125         notify_progress("Saving article tags...");
1126
1127         var form = document.forms["tag_edit_form"];
1128
1129         var query = Form.serialize("tag_edit_form");
1130
1131         query = "backend.php?op=rpc&subop=setArticleTags&" + query;
1132
1133         debug(query);
1134
1135         new Ajax.Request(query, {
1136                 onComplete: function(transport) {
1137                                 tag_saved_callback(transport);
1138                         } });
1139
1140 }
1141
1142 function editTagsInsert() {
1143         try {
1144
1145                 var form = document.forms["tag_edit_form"];
1146
1147                 var found_tags = form.found_tags;
1148                 var tags_str = form.tags_str;
1149
1150                 var tag = found_tags[found_tags.selectedIndex].value;
1151
1152                 if (tags_str.value.length > 0 && 
1153                                 tags_str.value.lastIndexOf(", ") != tags_str.value.length - 2) {
1154
1155                         tags_str.value = tags_str.value + ", ";
1156                 }
1157
1158                 tags_str.value = tags_str.value + tag + ", ";
1159
1160                 found_tags.selectedIndex = 0;
1161                 
1162         } catch (e) {
1163                 exception_error(e, "editTagsInsert");
1164         }
1165 }
1166
1167 function cdmWatchdog() {
1168
1169         try {
1170
1171                 var ctr = document.getElementById("headlinesInnerContainer");
1172
1173                 if (!ctr) return;
1174
1175                 var ids = new Array();
1176
1177                 var e = ctr.firstChild;
1178
1179                 while (e) {
1180                         if (e.className && e.className == "cdmArticleUnread" && e.id &&
1181                                         e.id.match("RROW-")) {
1182
1183                                 // article fits in viewport OR article is longer than viewport and
1184                                 // its bottom is visible
1185
1186                                 if (ctr.scrollTop <= e.offsetTop && e.offsetTop + e.offsetHeight <=
1187                                                 ctr.scrollTop + ctr.offsetHeight) {
1188
1189 //                                      debug(e.id + " is visible " + e.offsetTop + "." + 
1190 //                                              (e.offsetTop + e.offsetHeight) + " vs " + ctr.scrollTop + "." +
1191 //                                              (ctr.scrollTop + ctr.offsetHeight));
1192
1193                                         ids.push(e.id.replace("RROW-", ""));
1194
1195                                 } else if (e.offsetHeight > ctr.offsetHeight &&
1196                                                 e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1197                                                 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight) {
1198
1199                                         ids.push(e.id.replace("RROW-", "")); 
1200
1201                                 }
1202
1203                                 // method 2: article bottom is visible and is in upper 1/2 of the viewport
1204
1205 /*                              if (e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1206                                                 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight/2) {
1207
1208                                         ids.push(e.id.replace("RROW-", "")); 
1209
1210                                 } */
1211
1212                         }
1213
1214                         e = e.nextSibling;
1215                 }
1216
1217                 debug("cdmWatchdog, ids= " + ids.toString());
1218
1219                 if (ids.length > 0) {
1220
1221                         for (var i = 0; i < ids.length; i++) {
1222                                 var e = document.getElementById("RROW-" + ids[i]);
1223                                 if (e) {
1224                                         e.className = e.className.replace("Unread", "");
1225                                 }
1226                         }
1227
1228                         var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
1229                                 param_escape(ids.toString()) + "&cmode=0";
1230
1231                         new Ajax.Request(query, {
1232                                 onComplete: function(transport) { 
1233                                         all_counters_callback2(transport); 
1234                                 } });
1235
1236                 }
1237
1238                 _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 4000);
1239
1240         } catch (e) {
1241                 exception_error(e, "cdmWatchdog");
1242         }
1243
1244 }
1245
1246
1247 function cache_inject(id, article, param) {
1248         if (!cache_check_param(id, param)) {
1249                 debug("cache_article: miss: " + id + " [p=" + param + "]");
1250
1251                 var cache_obj = new Array();
1252
1253                 cache_obj["id"] = id;
1254                 cache_obj["data"] = article;
1255                 cache_obj["param"] = param;
1256
1257                 article_cache.push(cache_obj);
1258
1259         } else {
1260                 debug("cache_article: hit: " + id + " [p=" + param + "]");
1261         }
1262 }
1263
1264 function cache_find(id) {
1265         for (var i = 0; i < article_cache.length; i++) {
1266                 if (article_cache[i]["id"] == id) {
1267                         return article_cache[i]["data"];
1268                 }
1269         }
1270         return false;
1271 }
1272
1273 function cache_find_param(id, param) {
1274         for (var i = 0; i < article_cache.length; i++) {
1275                 if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
1276                         return article_cache[i]["data"];
1277                 }
1278         }
1279         return false;
1280 }
1281
1282 function cache_check(id) {
1283         for (var i = 0; i < article_cache.length; i++) {
1284                 if (article_cache[i]["id"] == id) {
1285                         return true;
1286                 }
1287         }
1288         return false;
1289 }
1290
1291 function cache_check_param(id, param) {
1292         for (var i = 0; i < article_cache.length; i++) {
1293
1294 //              debug("cache_check_param " + article_cache[i]["id"] + ":" + 
1295 //                      article_cache[i]["param"] + " vs " + id + ":" + param);
1296
1297                 if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
1298                         return true;
1299                 }
1300         }
1301         return false;
1302 }
1303
1304 function cache_expire() {
1305         while (article_cache.length > 20) {
1306                 article_cache.shift();
1307         }
1308 }
1309
1310 function cache_invalidate(id) {
1311         var i = 0
1312
1313         try {   
1314
1315                 while (i < article_cache.length) {
1316                         if (article_cache[i]["id"] == id) {
1317                                 debug("cache_invalidate: removed id " + id);
1318                                 article_cache.splice(i, 1);
1319                                 return true;
1320                         }
1321                         i++;
1322                 }
1323                 debug("cache_invalidate: id not found: " + id);
1324                 return false;
1325         } catch (e) {
1326                 exception_error("cache_invalidate", e);
1327         }
1328 }
1329
1330 function getActiveArticleId() {
1331         return active_post_id;
1332 }
1333
1334 function cdmMouseIn(elem) {
1335         try {
1336                 if (elem.id && elem.id.match("RROW-")) {
1337                         var id = elem.id.replace("RROW-", "");
1338                         active_post_id = id;
1339                 }
1340         } catch (e) {
1341                 exception_error("cdmMouseIn", e);
1342         }
1343
1344 }
1345
1346 function cdmMouseOut(elem) {
1347         active_post_id = false;
1348 }
1349
1350 function headlines_scroll_handler() {
1351         try {
1352
1353                 var e = document.getElementById("headlinesInnerContainer");
1354
1355                 // don't do infinite scrolling when Limit == All
1356
1357                 var toolbar_form = document.forms["main_toolbar_form"];
1358
1359                 var limit = toolbar_form.limit[toolbar_form.limit.selectedIndex];
1360                 if (limit.value != 0) {
1361                         if (e.scrollTop + e.offsetHeight > e.scrollHeight - 50) {
1362                                 if (!_infscroll_disable) {
1363                                         debug("more cowbell!");
1364                                         viewNextFeedPage();
1365                                 }
1366                         }
1367                 }
1368
1369         } catch (e) {
1370                 exception_error("headlines_scroll_handler", e);
1371         }
1372 }
1373
1374 function catchupRelativeToArticle(below) {
1375
1376         try {
1377
1378                 if (!xmlhttp_ready(xmlhttp_rpc)) {
1379                         printLockingError();
1380                 }
1381         
1382                 if (!getActiveArticleId()) {
1383                         alert(__("No article is selected."));
1384                         return;
1385                 }
1386
1387                 var visible_ids;
1388
1389                 if (document.getElementById("headlinesList")) {
1390                         visible_ids = getVisibleHeadlineIds();
1391                 } else {
1392                         visible_ids = cdmGetVisibleArticles();
1393                 }
1394
1395                 var ids_to_mark = new Array();
1396
1397                 if (!below) {
1398                         for (var i = 0; i < visible_ids.length; i++) {
1399                                 if (visible_ids[i] != getActiveArticleId()) {
1400                                         var e = document.getElementById("RROW-" + visible_ids[i]);
1401
1402                                         if (e && e.className.match("Unread")) {
1403                                                 ids_to_mark.push(visible_ids[i]);
1404                                         }
1405                                 } else {
1406                                         break;
1407                                 }
1408                         }
1409                 } else {
1410                         for (var i = visible_ids.length-1; i >= 0; i--) {
1411                                 if (visible_ids[i] != getActiveArticleId()) {
1412                                         var e = document.getElementById("RROW-" + visible_ids[i]);
1413
1414                                         if (e && e.className.match("Unread")) {
1415                                                 ids_to_mark.push(visible_ids[i]);
1416                                         }
1417                                 } else {
1418                                         break;
1419                                 }
1420                         }
1421                 }
1422
1423                 if (ids_to_mark.length == 0) {
1424                         alert(__("No articles found to mark"));
1425                 } else {
1426                         var msg = __("Mark %d article(s) as read?").replace("%d", ids_to_mark.length);
1427
1428                         if (confirm(msg)) {
1429
1430                                 for (var i = 0; i < ids_to_mark.length; i++) {
1431                                         var e = document.getElementById("RROW-" + ids_to_mark[i]);
1432                                         e.className = e.className.replace("Unread", "");
1433                                 }
1434
1435                                 var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
1436                                         param_escape(ids_to_mark.toString()) + "&cmode=0";
1437
1438                                 new Ajax.Request(query, {
1439                                         onComplete: function(transport) { 
1440                                                 catchup_callback2(transport); 
1441                                         } });
1442
1443                         }
1444                 }
1445
1446         } catch (e) {
1447                 exception_error("catchupRelativeToArticle", e);
1448         }
1449 }
1450
1451 function cdmExpandArticle(a_id) {
1452         try {
1453                 var id = 'CICD-' + a_id;
1454
1455                 Effect.Appear(id, {duration : 0.5, 
1456                         beforeStart: function(effect) { 
1457                                 var h_id = 'CICH-' + a_id;
1458                                 var h_elem = document.getElementById(h_id);
1459                                 if (h_elem) { h_elem.style.display = "none"; }
1460
1461                                 toggleUnread(a_id, 0);
1462                         }});
1463
1464
1465         } catch (e) {
1466                 exception_error("appearBlockElementF", e);
1467         }
1468
1469 }
1470
1471