]> git.wh0rd.org Git - tt-rss.git/blob - viewfeed.js
getLabelCounters: ignore hidden feeds
[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 var vgroup_last_feed = false;
21 var post_under_pointer = false;
22
23 var last_requested_article = false;
24
25 function catchup_callback() {
26         if (xmlhttp_rpc.readyState == 4) {
27                 try {
28                         debug("catchup_callback");
29                         notify("");                     
30                         all_counters_callback2(xmlhttp_rpc);
31                         if (_catchup_callback_func) {
32                                 setTimeout(_catchup_callback_func, 10); 
33                         }
34                 } catch (e) {
35                         exception_error("catchup_callback", e);
36                 }
37         }
38 }
39
40 function catchup_callback2(transport, callback) {
41         try {
42                 debug("catchup_callback2 " + transport + ", " + callback);
43                 notify("");                     
44                 all_counters_callback2(transport);
45                 if (callback) {
46                         setTimeout(callback, 10);       
47                 }
48         } catch (e) {
49                 exception_error("catchup_callback2", e);
50         }
51 }
52
53 function clean_feed_selections() {
54         try {
55                 var feeds = document.getElementById("feedList").getElementsByTagName("LI");
56
57                 for (var i = 0; i < feeds.length; i++) {
58                         if (feeds[i].id && feeds[i].id.match("FEEDR-")) {
59                                 feeds[i].className = feeds[i].className.replace("Selected", "");
60                         }                       
61                         if (feeds[i].id && feeds[i].id.match("FCAT-")) {
62                                 feeds[i].className = feeds[i].className.replace("Selected", "");
63                         }
64                 }
65         } catch (e) {
66                 exception_error("clean_feed_selections", e);
67         }
68 }
69
70 function headlines_callback2(transport, feed_cur_page) {
71         try {
72
73                 loading_set_progress(100);
74
75                 debug("headlines_callback2 [page=" + feed_cur_page + "]");
76
77                 clean_feed_selections();
78         
79                 var is_cat = false;
80                 var feed_id = false;
81
82                 if (transport.responseXML) {
83                         var headlines = transport.responseXML.getElementsByTagName("headlines")[0];
84                         if (headlines) {
85                                 is_cat = headlines.getAttribute("is_cat");
86                                 feed_id = headlines.getAttribute("id");
87                                 setActiveFeedId(feed_id, is_cat);
88                         }
89                 }
90
91                 if (!is_cat) {
92                         var feedr = document.getElementById("FEEDR-" + feed_id);
93                         if (feedr && !feedr.className.match("Selected")) {      
94                                 feedr.className = feedr.className + "Selected";
95                         } 
96                 } else {
97                         var feedr = document.getElementById("FCAT-" + feed_id);
98                         if (feedr && !feedr.className.match("Selected")) {      
99                                 feedr.className = feedr.className + "Selected";
100                         } 
101                 }
102         
103                 var f = document.getElementById("headlines-frame");
104                 try {
105                         if (feed_cur_page == 0) { 
106                                 debug("resetting headlines scrollTop");
107                                 f.scrollTop = 0; 
108                         }
109                 } catch (e) { };
110         
111                 if (transport.responseXML) {
112                         var headlines = transport.responseXML.getElementsByTagName("headlines")[0];
113                         var headlines_count_obj = transport.responseXML.getElementsByTagName("headlines-count")[0];
114                         var headlines_unread_obj = transport.responseXML.getElementsByTagName("headlines-unread")[0];
115                         var disable_cache_obj = transport.responseXML.getElementsByTagName("disable-cache")[0];
116
117                         var vgroup_last_feed_obj =  transport.responseXML.getElementsByTagName("vgroup-last-feed")[0];
118
119                         var headlines_count = headlines_count_obj.getAttribute("value");
120                         var headlines_unread = headlines_unread_obj.getAttribute("value");
121                         var disable_cache = disable_cache_obj.getAttribute("value") != "0";
122
123                         vgroup_last_feed = vgroup_last_feed_obj.getAttribute("value");
124
125                         if (headlines_count == 0) {
126                                 _infscroll_disable = 1;
127                         } else {
128                                 _infscroll_disable = 0;
129                         }
130
131                         var counters = transport.responseXML.getElementsByTagName("counters")[0];
132                         var articles = transport.responseXML.getElementsByTagName("article");
133                         var runtime_info = transport.responseXML.getElementsByTagName("runtime-info");
134         
135                         if (feed_cur_page == 0) {
136                                 if (headlines) {
137                                         f.innerHTML = headlines.firstChild.nodeValue;
138
139                                         var cache_prefix = "";
140
141                                         if (is_cat) {
142                                                 cache_prefix = "C:";
143                                         } else {
144                                                 cache_prefix = "F:";
145                                         }
146
147                                         cache_invalidate(cache_prefix + feed_id);
148
149                                         if (!disable_cache) {
150                                                 cache_inject(cache_prefix + feed_id,
151                                                         headlines.firstChild.nodeValue, headlines_unread);
152                                         }
153
154                                 } else {
155                                         debug("headlines_callback: returned no data");
156                                 f.innerHTML = "<div class='whiteBox'>" + __('Could not update headlines (missing XML data)') + "</div>";
157         
158                                 }
159                         } else {
160                                 if (headlines) {
161                                         if (headlines_count > 0) {
162                                                 debug("adding some more headlines...");
163         
164                                                 var c = document.getElementById("headlinesList");
165                 
166                                                 if (!c) {
167                                                         c = document.getElementById("headlinesInnerContainer");
168                                                 }
169
170                                                 var ids = getSelectedArticleIds2();
171         
172                                                 c.innerHTML = c.innerHTML + headlines.firstChild.nodeValue;
173
174                                                 debug("restore selected ids: " + ids);
175
176                                                 for (var i = 0; i < ids.length; i++) {
177                                                         markHeadline(ids[i]);
178                                                 }
179
180                                                 subtoolbarSearch();
181
182                                         } else {
183                                                 debug("no new headlines received");
184                                         }
185                                 } else {
186                                         debug("headlines_callback: returned no data");
187                                         notify_error("Error while trying to load more headlines");      
188                                 }
189
190                         }
191         
192                         if (articles) {
193                                 for (var i = 0; i < articles.length; i++) {
194                                         var a_id = articles[i].getAttribute("id");
195                                         debug("found id: " + a_id);
196                                         cache_inject(a_id, articles[i].firstChild.nodeValue);
197                                 }
198                         } else {
199                                 debug("no cached articles received");
200                         }
201         
202                         if (counters) {
203                                 debug("parsing piggybacked counters: " + counters);
204                                 parse_counters(counters, false);
205                         } else {
206                                 debug("counters container not found in reply, requesting...");
207                                 request_counters();
208                         }
209         
210                         if (runtime_info) {
211                                 debug("parsing runtime info: " + runtime_info[0]);
212                                 parse_runtime_info(runtime_info[0]);
213                         } else {
214                                 debug("counters container not found in reply");
215                         }
216         
217                 } else {
218                         debug("headlines_callback: returned no XML object");
219                         f.innerHTML = "<div class='whiteBox'>" + __('Could not update headlines (missing XML object)') + "</div>";
220                 }
221         
222                 if (typeof correctPNG != 'undefined') {
223                         correctPNG();
224                 }
225         
226                 if (_cdm_wd_timeout) window.clearTimeout(_cdm_wd_timeout);
227         
228                 if (!document.getElementById("headlinesList") && 
229                                 getActiveFeedId() != -3 &&
230                                 getInitParam("cdm_auto_catchup") == 1) {
231                         debug("starting CDM watchdog");
232                         _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 5000);
233                         _cdm_wd_vishist = new Array();
234                 } else {
235                         debug("not in CDM mode or watchdog disabled");
236                 }
237         
238                 if (_tag_cdm_scroll) {
239                         try {
240                                 document.getElementById("headlinesInnerContainer").scrollTop = _tag_cdm_scroll;
241                                 _tag_cdm_scroll = false;
242                                 debug("resetting headlinesInner scrollTop");
243         
244                         } catch (e) { }
245                 }
246         
247                 _feed_cur_page = feed_cur_page;
248                 _infscroll_request_sent = 0;
249
250                 notify("");
251
252                 remove_splash();
253
254         } catch (e) {
255                 exception_error("headlines_callback2", e);
256         }
257 }
258
259 function render_article(article) {
260         try {
261                 var f = document.getElementById("content-frame");
262                 try {
263                         f.scrollTop = 0;
264                 } catch (e) { };
265
266                 var fi = document.getElementById("content-insert");
267
268                 try {
269                         fi.scrollTop = 0;
270                 } catch (e) { };
271
272                 fi.innerHTML = article;
273
274         } catch (e) {
275                 exception_error("render_article", e);
276         }
277 }
278
279 function showArticleInHeadlines(id) {
280
281         try {
282
283                 cleanSelected("headlinesList");
284         
285                 var crow = document.getElementById("RROW-" + id);
286
287                 if (!crow) return;
288
289                 var article_is_unread = crow.className.match("Unread");
290                         
291                 crow.className = crow.className.replace("Unread", "");
292
293                 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
294         
295                 var upd_img_pic = document.getElementById("FUPDPIC-" + id);
296
297                 var cache_prefix = "";
298                                 
299                 if (activeFeedIsCat()) {
300                         cache_prefix = "C:";
301                 } else {
302                         cache_prefix = "F:";
303                 }
304
305                 var view_mode = false;
306
307                 try {
308                         view_mode = document.forms['main_toolbar_form'].view_mode;      
309                         view_mode = view_mode[view_mode.selectedIndex].value;
310                 } catch (e) {
311                         exception_error("showArticleInHeadlines/viewmode", e, true);
312                 }
313
314                 if (upd_img_pic && upd_img_pic.src.match("updated.png")) {
315                         upd_img_pic.src = "images/blank_icon.gif";
316
317                         cache_invalidate(cache_prefix + getActiveFeedId());
318
319                         cache_inject(cache_prefix + getActiveFeedId(),
320                                 document.getElementById("headlines-frame").innerHTML,
321                                 get_feed_unread(getActiveFeedId()));
322
323                 } else if (article_is_unread && view_mode == "all_articles") {
324
325                         cache_invalidate(cache_prefix + getActiveFeedId());
326
327                         cache_inject(cache_prefix + getActiveFeedId(),
328                                 document.getElementById("headlines-frame").innerHTML,
329                                 get_feed_unread(getActiveFeedId())-1);
330
331                 } else if (article_is_unread) {
332                         cache_invalidate(cache_prefix + getActiveFeedId());
333                 }
334
335                 markHeadline(id);
336
337         } catch (e) {
338                 exception_error("showArticleInHeadlines", e);
339         }
340 }
341
342 function article_callback2(transport, id, feed_id) {
343         try {
344                 debug("article_callback2 " + id);
345
346                 if (transport.responseXML) {
347
348                         debug("looking for articles to cache...");
349
350                         var articles = transport.responseXML.getElementsByTagName("article");
351
352                         for (var i = 0; i < articles.length; i++) {
353                                 var a_id = articles[i].getAttribute("id");
354
355                                 debug("found id: " + a_id);
356
357                                 if (a_id == active_post_id) {
358                                         debug("active article, rendering...");                                  
359                                         render_article(articles[i].firstChild.nodeValue);
360                                 }
361
362                                 cache_inject(a_id, articles[i].firstChild.nodeValue);
363                         }
364
365                         if (id != last_requested_article) {
366                                 debug("requested article id is out of sequence, aborting");
367                                 return;
368                         }
369
370                         active_real_feed_id = feed_id;
371                         active_post_id = id; 
372
373                         showArticleInHeadlines(id);     
374
375                         var reply = transport.responseXML.firstChild.firstChild;
376                 
377                 } else {
378                         debug("article_callback: returned no XML object");
379                         //var f = document.getElementById("content-frame");
380                         //f.innerHTML = "<div class='whiteBox'>" + __('Could not display article (missing XML object)') + "</div>";
381                 }
382
383                 var date = new Date();
384                 last_article_view = date.getTime() / 1000;
385
386                 if (typeof correctPNG != 'undefined') {
387                         correctPNG();
388                 }
389
390                 if (_reload_feedlist_after_view) {
391                         setTimeout('updateFeedList(false, false)', 50);                 
392                         _reload_feedlist_after_view = false;
393                 } else {
394                         var counters = transport.responseXML.getElementsByTagName("counters")[0];
395
396                         if (counters) {
397                                 debug("parsing piggybacked counters: " + counters);
398                                 parse_counters(counters, false);
399                         } else {
400                                 debug("counters container not found in reply, requesting...");
401                                 request_counters();
402                         }
403                 }
404
405                 notify("");
406         } catch (e) {
407                 exception_error("article_callback2", e);
408         }
409 }
410
411 function view(id, feed_id, skip_history) {
412         
413         try {
414                 debug("loading article: " + id + "/" + feed_id);
415         
416                 var cached_article = cache_find(id);
417
418                 debug("cache check result: " + (cached_article != false));
419         
420                 enableHotkeys();
421         
422                 //setActiveFeedId(feed_id);
423
424                 var query = "backend.php?op=view&id=" + param_escape(id) +
425                         "&feed=" + param_escape(feed_id);
426
427                 var date = new Date();
428
429                 var neighbor_ids = getRelativePostIds(active_post_id);
430
431                 /* only request uncached articles */
432
433                 var cids_to_request = Array();
434
435                 for (var i = 0; i < neighbor_ids.length; i++) {
436                         if (!cache_check(neighbor_ids[i])) {
437                                 cids_to_request.push(neighbor_ids[i]);
438                         }
439                 }
440
441                 debug("additional ids: " + cids_to_request.toString());                 
442
443                 /* additional info for piggyback counters */
444
445                 if (tagsAreDisplayed()) {
446                         query = query + "&omode=lt";
447                 } else {
448                         query = query + "&omode=flc";
449                 }
450
451                 var date = new Date();
452                 var timestamp = Math.round(date.getTime() / 1000);
453                 query = query + "&ts=" + timestamp;
454
455                 query = query + "&cids=" + cids_to_request.toString();
456
457                 var crow = document.getElementById("RROW-" + id);
458                 var article_is_unread = crow.className.match("Unread");
459
460                 if (!async_counters_work) {
461                         query = query + "&csync=true";
462                 }
463
464                 showArticleInHeadlines(id);
465
466                 if (!cached_article) {
467
468                         notify_progress("Loading, please wait...", true);
469
470                 } else if (cached_article && article_is_unread) {
471
472                         query = query + "&mode=prefetch";
473
474                         render_article(cached_article);
475
476                 } else if (cached_article) {
477
478                         query = query + "&mode=prefetch_old";
479                         render_article(cached_article);
480
481                 }
482
483                 cache_expire();
484
485                 last_requested_article = id;
486
487                 new Ajax.Request(query, {
488                         onComplete: function(transport) { 
489                                 article_callback2(transport, id, feed_id); 
490                         } });
491
492                 return false;
493
494         } catch (e) {
495                 exception_error("view", e);
496         }
497 }
498
499 function tMark(id) {
500         return toggleMark(id);
501 }
502
503 function tPub(id) {
504         return togglePub(id);
505 }
506
507 function tMark_afh_off(effect) {
508         try {
509                 var elem = effect.effects[0].element;
510
511                 debug("tMark_afh_off : " + elem.id);
512
513                 if (elem) {
514                         elem.src = elem.src.replace("mark_set", "mark_unset");
515                         elem.alt = __("Star article");
516                         Element.show(elem);
517                 }
518
519         } catch (e) {
520                 exception_error("tMark_afh_off", e);
521         }
522 }
523
524 function tPub_afh_off(effect) {
525         try {
526                 var elem = effect.effects[0].element;
527
528                 debug("tPub_afh_off : " + elem.id);
529
530                 if (elem) {
531                         elem.src = elem.src.replace("pub_set", "pub_unset");
532                         elem.alt = __("Publish article");
533                         Element.show(elem);
534                 }
535
536         } catch (e) {
537                 exception_error("tPub_afh_off", e);
538         }
539 }
540
541 function toggleMark(id, client_only, no_effects) {
542
543         try {
544
545                 var query = "backend.php?op=rpc&id=" + id + "&subop=mark";
546         
547                 query = query + "&afid=" + getActiveFeedId();
548         
549                 if (tagsAreDisplayed()) {
550                         query = query + "&omode=tl";
551                 } else {
552                         query = query + "&omode=flc";
553                 }
554         
555                 var mark_img = document.getElementById("FMPIC-" + id);
556                 var vfeedu = document.getElementById("FEEDU--1");
557                 var crow = document.getElementById("RROW-" + id);
558         
559                 if (mark_img.src.match("mark_unset")) {
560                         mark_img.src = mark_img.src.replace("mark_unset", "mark_set");
561                         mark_img.alt = __("Unstar article");
562                         query = query + "&mark=1";
563
564                 } else {
565                         //mark_img.src = "images/mark_unset.png";
566                         mark_img.alt = __("Please wait...");
567                         query = query + "&mark=0";
568         
569                         if (document.getElementById("headlinesList") && !no_effects) {
570                                 Effect.Puff(mark_img, {duration : 0.25, afterFinish: tMark_afh_off});
571                         } else { 
572                                 mark_img.src = mark_img.src.replace("mark_set", "mark_unset");
573                                 mark_img.alt = __("Star article");
574                         }
575                 }
576
577                 if (!client_only) {
578                         debug(query);
579
580                         new Ajax.Request(query, {
581                                 onComplete: function(transport) { 
582                                         all_counters_callback2(transport); 
583                                 } });
584
585                 }
586
587         } catch (e) {
588                 exception_error("toggleMark", e);
589         }
590 }
591
592 function togglePub(id, client_only, no_effects) {
593
594         try {
595
596                 var query = "backend.php?op=rpc&id=" + id + "&subop=publ";
597         
598                 query = query + "&afid=" + getActiveFeedId();
599         
600                 if (tagsAreDisplayed()) {
601                         query = query + "&omode=tl";
602                 } else {
603                         query = query + "&omode=flc";
604                 }
605         
606                 var mark_img = document.getElementById("FPPIC-" + id);
607                 var vfeedu = document.getElementById("FEEDU--2");
608                 var crow = document.getElementById("RROW-" + id);
609         
610                 if (mark_img.src.match("pub_unset")) {
611                         mark_img.src = mark_img.src.replace("pub_unset", "pub_set");
612                         mark_img.alt = __("Unpublish article");
613                         query = query + "&pub=1";
614         
615
616                 } else {
617                         //mark_img.src = "images/pub_unset.png";
618                         mark_img.alt = __("Please wait...");
619                         query = query + "&pub=0";
620         
621                         if (document.getElementById("headlinesList") && !no_effects) {
622                                 Effect.Puff(mark_img, {duration : 0.25, afterFinish: tPub_afh_off});
623                         } else { 
624                                 mark_img.src = mark_img.src.replace("pub_set", "pub_unset");
625                                 mark_img.alt = __("Publish article");
626                         }
627                 }
628
629                 if (!client_only) {
630                         new Ajax.Request(query, {
631                                 onComplete: function(transport) { 
632                                         all_counters_callback2(transport); 
633                                 } });
634                 }
635
636         } catch (e) {
637
638                 exception_error("togglePub", e);
639         }
640 }
641
642 function correctHeadlinesOffset(id) {
643         
644         try {
645
646                 var hlist = document.getElementById("headlinesList");
647                 var container = document.getElementById("headlinesInnerContainer");
648                 var row = document.getElementById("RROW-" + id);
649         
650                 var viewport = container.offsetHeight;
651         
652                 var rel_offset_top = row.offsetTop - container.scrollTop;
653                 var rel_offset_bottom = row.offsetTop + row.offsetHeight - container.scrollTop;
654         
655                 debug("Rtop: " + rel_offset_top + " Rbtm: " + rel_offset_bottom);
656                 debug("Vport: " + viewport);
657
658                 if (rel_offset_top <= 0 || rel_offset_top > viewport) {
659                         container.scrollTop = row.offsetTop;
660                 } else if (rel_offset_bottom > viewport) {
661
662                         /* doesn't properly work with Opera in some cases because
663                                 Opera fucks up element scrolling */
664
665                         container.scrollTop = row.offsetTop + row.offsetHeight - viewport;              
666                 } 
667
668         } catch (e) {
669                 exception_error("correctHeadlinesOffset", e);
670         }
671
672 }
673
674 function moveToPost(mode) {
675
676         try {
677
678                 var rows;
679
680                 if (isCdmMode()) {
681                         rows = cdmGetVisibleArticles();
682                 } else {
683                         rows = getVisibleHeadlineIds();
684                 }
685                 
686                 var prev_id = false;
687                 var next_id = false;
688                 
689                 if (!document.getElementById('RROW-' + active_post_id)) {
690                         active_post_id = false;
691                 }
692                 
693                 if (active_post_id == false) {
694                         next_id = getFirstVisibleHeadlineId();
695                         prev_id = getLastVisibleHeadlineId();
696                 } else {        
697                         for (var i = 0; i < rows.length; i++) {
698                                 if (rows[i] == active_post_id) {
699                                         prev_id = rows[i-1];
700                                         next_id = rows[i+1];                    
701                                 }
702                         }
703                 }
704                 
705                 if (mode == "next") {
706                         if (next_id) {
707                                 if (isCdmMode()) {
708         
709                                         if (!cdmArticleIsActuallyVisible(next_id)) {
710                                                 cdmScrollToArticleId(next_id);
711                                         }
712                                         cdmSelectArticles("none");
713                                         toggleUnread(next_id, 0, true);
714                                         toggleSelected(next_id);
715
716                                 } else {
717                                         correctHeadlinesOffset(next_id);
718                                         view(next_id, getActiveFeedId());
719                                 }
720                         }
721                 }
722                 
723                 if (mode == "prev") {
724                         if (prev_id) {
725                                 if (isCdmMode()) {
726                                         cdmScrollToArticleId(prev_id);
727                                         cdmSelectArticles("none");
728                                         toggleUnread(prev_id, 0, true);
729                                         toggleSelected(prev_id);
730                                 } else {
731                                         correctHeadlinesOffset(prev_id);
732                                         view(prev_id, getActiveFeedId());
733                                 }
734                         }
735                 } 
736
737         } catch (e) {
738                 exception_error("moveToPost", e);
739         }
740 }
741
742 function toggleSelected(id) {
743         try {
744         
745                 var cb = document.getElementById("RCHK-" + id);
746
747                 var row = document.getElementById("RROW-" + id);
748                 if (row) {
749                         var nc = row.className;
750                         
751                         if (!nc.match("Selected")) {
752                                 nc = nc + "Selected";
753                                 if (cb) {
754                                         cb.checked = true;
755                                 }
756
757                                 // In CDM basically last selected article == active article
758                                 if (isCdmMode()) active_post_id = id;
759                         } else {
760                                 nc = nc.replace("Selected", "");
761                                 if (cb) {
762                                         cb.checked = false;
763                                 }
764
765                         }
766
767                         row.className = nc;
768                 }
769         } catch (e) {
770                 exception_error("toggleSelected", e);
771         }
772 }
773
774 function toggleUnread_afh(effect) {
775         try {
776
777                 var elem = effect.element;
778                 elem.style.backgroundColor = "";
779
780         } catch (e) {
781                 exception_error("toggleUnread_afh", e);
782         }
783
784
785 function toggleUnread(id, cmode, effect) {
786         try {
787         
788                 var row = document.getElementById("RROW-" + id);
789                 if (row) {
790                         var nc = row.className;
791                         var is_selected = row.className.match("Selected");
792                         nc = nc.replace("Unread", "");
793                         nc = nc.replace("Selected", "");
794
795                         // since we are removing selection from the object, uncheck
796                         // corresponding checkbox
797
798                         var cb = document.getElementById("RCHK-" + id);
799                         if (cb) {
800                                 cb.checked = false;
801                         }
802
803                         // NOTE: I'm not sure that resetting selection here is a feature -fox
804
805                         if (cmode == undefined || cmode == 2) {
806                                 if (row.className.match("Unread")) {
807                                         row.className = nc;
808
809                                         if (effect) {
810                                                 new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
811                                                         afterFinish: toggleUnread_afh,
812                                                         queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
813                                         } 
814
815                                 } else {
816                                         row.className = nc + "Unread";
817                                 }
818                         } else if (cmode == 0) {
819                                 row.className = nc;
820
821                                 if (effect) {
822                                         new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
823                                                 afterFinish: toggleUnread_afh,
824                                                 queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
825                                 } 
826                         } else if (cmode == 1) {
827                                 row.className = nc + "Unread";
828                         }
829
830                         // Disable unmarking as selected for the time being (16.05.08) -fox
831                         if (is_selected) row.className = row.className + "Selected";
832
833                         if (cmode == undefined) cmode = 2;
834
835                         var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
836                                 param_escape(id) + "&cmode=" + param_escape(cmode);
837
838 //                      notify_progress("Loading, please wait...");
839
840                         new Ajax.Request(query, {
841                                 onComplete: function(transport) { 
842                                         all_counters_callback2(transport); 
843                                 } });
844
845                 }
846
847
848         } catch (e) {
849                 exception_error("toggleUnread", e);
850         }
851 }
852
853 function selectionRemoveLabel(id) {
854         try {
855
856                 var ids = getSelectedArticleIds2();
857
858                 if (ids.length == 0) {
859                         alert(__("No articles are selected."));
860                         return;
861                 }
862
863                 var ok = confirm(__("Remove selected articles from label?"));
864
865                 if (ok) {
866
867                         var query = "backend.php?op=rpc&subop=removeFromLabel&ids=" +
868                                 param_escape(ids.toString()) + "&lid=" + param_escape(id);
869
870 //                      notify_progress("Loading, please wait...");
871
872                         new Ajax.Request(query, {
873                                 onComplete: function(transport) { 
874                                         viewCurrentFeed();
875                                 } });
876
877                 }
878
879         } catch (e) {
880                 exception_error("selectionAssignLabel", e);
881
882         }
883 }
884
885 function selectionAssignLabel(id) {
886         try {
887
888                 var ids = getSelectedArticleIds2();
889
890                 if (ids.length == 0) {
891                         alert(__("No articles are selected."));
892                         return;
893                 }
894
895                 var ok = confirm(__("Assign selected articles to label?"));
896
897                 if (ok) {
898
899                         var query = "backend.php?op=rpc&subop=assignToLabel&ids=" +
900                                 param_escape(ids.toString()) + "&lid=" + param_escape(id);
901
902 //                      notify_progress("Loading, please wait...");
903
904                         new Ajax.Request(query, {
905                                 onComplete: function(transport) { 
906                                         all_counters_callback2(transport); 
907                                 } });
908
909                 }
910
911         } catch (e) {
912                 exception_error("selectionAssignLabel", e);
913
914         }
915 }
916
917 function selectionToggleUnread(cdm_mode, set_state, callback_func, no_error) {
918         try {
919                 var rows;
920
921                 if (cdm_mode) {
922                         rows = cdmGetSelectedArticles();
923                 } else {        
924                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
925                 }
926
927                 if (rows.length == 0 && !no_error) {
928                         alert(__("No articles are selected."));
929                         return;
930                 }
931
932                 for (i = 0; i < rows.length; i++) {
933                         var row = document.getElementById("RROW-" + rows[i]);
934                         if (row) {
935                                 var nc = row.className;
936                                 nc = nc.replace("Unread", "");
937                                 nc = nc.replace("Selected", "");
938
939                                 if (set_state == undefined) {
940                                         if (row.className.match("Unread")) {
941                                                 row.className = nc + "Selected";
942                                         } else {
943                                                 row.className = nc + "UnreadSelected";
944                                         }
945                                 }
946
947                                 if (set_state == false) {
948                                         row.className = nc + "Selected";
949                                 }
950
951                                 if (set_state == true) {
952                                         row.className = nc + "UnreadSelected";
953                                 }
954                         }
955                 }
956
957                 if (rows.length > 0) {
958
959                         var cmode = "";
960
961                         if (set_state == undefined) {
962                                 cmode = "2";
963                         } else if (set_state == true) {
964                                 cmode = "1";
965                         } else if (set_state == false) {
966                                 cmode = "0";
967                         }
968
969                         var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
970                                 param_escape(rows.toString()) + "&cmode=" + cmode;
971
972                         notify_progress("Loading, please wait...");
973
974                         new Ajax.Request(query, {
975                                 onComplete: function(transport) { 
976                                         catchup_callback2(transport, callback_func); 
977                                 } });
978
979                 }
980
981         } catch (e) {
982                 exception_error("selectionToggleUnread", e);
983         }
984 }
985
986 function selectionToggleMarked(cdm_mode) {
987         try {
988         
989                 var rows;
990                 
991                 if (cdm_mode) {
992                         rows = cdmGetSelectedArticles();
993                 } else {        
994                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
995                 }       
996
997                 if (rows.length == 0) {
998                         alert(__("No articles are selected."));
999                         return;
1000                 }
1001
1002                 for (i = 0; i < rows.length; i++) {
1003                         toggleMark(rows[i], true, true);
1004                 }
1005
1006                 if (rows.length > 0) {
1007
1008                         var query = "backend.php?op=rpc&subop=markSelected&ids=" +
1009                                 param_escape(rows.toString()) + "&cmode=2";
1010
1011                         query = query + "&afid=" + getActiveFeedId();
1012
1013 /*                      if (tagsAreDisplayed()) {
1014                                 query = query + "&omode=tl";
1015                         } else {
1016                                 query = query + "&omode=flc";
1017                         } */
1018
1019                         query = query + "&omode=lc";
1020
1021                         new Ajax.Request(query, {
1022                                 onComplete: function(transport) { 
1023                                         all_counters_callback2(transport); 
1024                                 } });
1025
1026                 }
1027
1028         } catch (e) {
1029                 exception_error("selectionToggleMarked", e);
1030         }
1031 }
1032
1033 function selectionTogglePublished(cdm_mode) {
1034         try {
1035         
1036                 var rows;
1037                 
1038                 if (cdm_mode) {
1039                         rows = cdmGetSelectedArticles();
1040                 } else {        
1041                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1042                 }       
1043
1044                 if (rows.length == 0) {
1045                         alert(__("No articles are selected."));
1046                         return;
1047                 }
1048
1049                 for (i = 0; i < rows.length; i++) {
1050                         togglePub(rows[i], true, true);
1051                 }
1052
1053                 if (rows.length > 0) {
1054
1055                         var query = "backend.php?op=rpc&subop=publishSelected&ids=" +
1056                                 param_escape(rows.toString()) + "&cmode=2";
1057
1058                         query = query + "&afid=" + getActiveFeedId();
1059
1060 /*                      if (tagsAreDisplayed()) {
1061                                 query = query + "&omode=tl";
1062                         } else {
1063                                 query = query + "&omode=flc";
1064                         } */
1065
1066                         query = query + "&omode=lc";
1067
1068                         new Ajax.Request(query, {
1069                                 onComplete: function(transport) { 
1070                                         all_counters_callback2(transport); 
1071                                 } });
1072
1073                 }
1074
1075         } catch (e) {
1076                 exception_error("selectionToggleMarked", e);
1077         }
1078 }
1079
1080 function cdmGetSelectedArticles() {
1081         var sel_articles = new Array();
1082         var container = document.getElementById("headlinesInnerContainer");
1083
1084         for (i = 0; i < container.childNodes.length; i++) {
1085                 var child = container.childNodes[i];
1086
1087                 if (child.id && child.id.match("RROW-") && child.className.match("Selected")) {
1088                         var c_id = child.id.replace("RROW-", "");
1089                         sel_articles.push(c_id);
1090                 }
1091         }
1092
1093         return sel_articles;
1094 }
1095
1096 function cdmGetVisibleArticles() {
1097         var sel_articles = new Array();
1098         var container = document.getElementById("headlinesInnerContainer");
1099
1100         if (!container) return sel_articles;
1101
1102         for (i = 0; i < container.childNodes.length; i++) {
1103                 var child = container.childNodes[i];
1104
1105                 if (child.id && child.id.match("RROW-")) {
1106                         var c_id = child.id.replace("RROW-", "");
1107                         sel_articles.push(c_id);
1108                 }
1109         }
1110
1111         return sel_articles;
1112 }
1113
1114 function cdmGetUnreadArticles() {
1115         var sel_articles = new Array();
1116         var container = document.getElementById("headlinesInnerContainer");
1117
1118         for (i = 0; i < container.childNodes.length; i++) {
1119                 var child = container.childNodes[i];
1120
1121                 if (child.id && child.id.match("RROW-") && child.className.match("Unread")) {
1122                         var c_id = child.id.replace("RROW-", "");
1123                         sel_articles.push(c_id);
1124                 }
1125         }
1126
1127         return sel_articles;
1128 }
1129
1130
1131 // mode = all,none,unread
1132 function cdmSelectArticles(mode) {
1133         var container = document.getElementById("headlinesInnerContainer");
1134
1135         for (i = 0; i < container.childNodes.length; i++) {
1136                 var child = container.childNodes[i];
1137
1138                 if (child.id && child.id.match("RROW-")) {
1139                         var aid = child.id.replace("RROW-", "");
1140
1141                         var cb = document.getElementById("RCHK-" + aid);
1142
1143                         if (mode == "all") {
1144                                 if (!child.className.match("Selected")) {
1145                                         child.className = child.className + "Selected";
1146                                         cb.checked = true;
1147                                 }
1148                         } else if (mode == "unread") {
1149                                 if (child.className.match("Unread") && !child.className.match("Selected")) {
1150                                         child.className = child.className + "Selected";
1151                                         cb.checked = true;
1152                                 }
1153                         } else {
1154                                 child.className = child.className.replace("Selected", "");
1155                                 cb.checked = false;
1156                         }
1157                 }               
1158         }
1159 }
1160
1161 function catchupPage() {
1162
1163         var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
1164         
1165         var str = __("Mark all visible articles in %s as read?");
1166
1167         str = str.replace("%s", fn);
1168
1169         if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
1170                 return;
1171         }
1172
1173         if (document.getElementById("headlinesList")) {
1174                 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', true, 'Unread', true);
1175                 selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
1176                 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
1177         } else {
1178                 cdmSelectArticles('all');
1179                 selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
1180                 cdmSelectArticles('none');
1181         }
1182 }
1183
1184 function catchupSelection() {
1185
1186         try {
1187
1188                 var rows;
1189         
1190                 if (document.getElementById("headlinesList")) {
1191                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1192                 } else {        
1193                         rows = cdmGetSelectedArticles();
1194                 }
1195         
1196                 if (rows.length == 0) {
1197                         alert(__("No articles are selected."));
1198                         return;
1199                 }
1200         
1201         
1202                 var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
1203                 
1204                 var str = __("Mark %d selected articles in %s as read?");
1205         
1206                 str = str.replace("%d", rows.length);
1207                 str = str.replace("%s", fn);
1208         
1209                 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
1210                         return;
1211                 }
1212         
1213                 if (document.getElementById("headlinesList")) {
1214                         selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
1215         //              selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
1216                 } else {
1217                         selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
1218         //              cdmSelectArticles('none');
1219                 }
1220
1221         } catch (e) {
1222                 exception_error("catchupSelection", e);
1223         }
1224 }
1225
1226 function editArticleTags(id, feed_id, cdm_enabled) {
1227         _tag_active_post_id = id;
1228         _tag_active_feed_id = feed_id;
1229         _tag_active_cdm = cdm_enabled;
1230
1231         cache_invalidate(id);
1232
1233         try {
1234                 _tag_cdm_scroll = document.getElementById("headlinesInnerContainer").scrollTop;
1235         } catch (e) { }
1236         displayDlg('editArticleTags', id);
1237 }
1238
1239
1240 function tag_saved_callback(transport) {
1241         try {
1242                 debug("in tag_saved_callback");
1243
1244                 closeInfoBox();
1245                 notify("");
1246
1247                 if (tagsAreDisplayed()) {
1248                         _reload_feedlist_after_view = true;
1249                 }
1250
1251                 if (!_tag_active_cdm) {
1252                         if (active_post_id == _tag_active_post_id) {
1253                                 debug("reloading current article");
1254                                 view(_tag_active_post_id, _tag_active_feed_id);                 
1255                         }
1256                 } else {
1257                         debug("reloading current feed");
1258                         viewCurrentFeed();
1259                 }
1260
1261         } catch (e) {
1262                 exception_error("catchup_callback", e);
1263         }
1264 }
1265
1266 function editTagsSave() {
1267
1268         notify_progress("Saving article tags...");
1269
1270         var form = document.forms["tag_edit_form"];
1271
1272         var query = Form.serialize("tag_edit_form");
1273
1274         query = "backend.php?op=rpc&subop=setArticleTags&" + query;
1275
1276         debug(query);
1277
1278         new Ajax.Request(query, {
1279                 onComplete: function(transport) {
1280                                 tag_saved_callback(transport);
1281                         } });
1282
1283 }
1284
1285 function editTagsInsert() {
1286         try {
1287
1288                 var form = document.forms["tag_edit_form"];
1289
1290                 var found_tags = form.found_tags;
1291                 var tags_str = form.tags_str;
1292
1293                 var tag = found_tags[found_tags.selectedIndex].value;
1294
1295                 if (tags_str.value.length > 0 && 
1296                                 tags_str.value.lastIndexOf(", ") != tags_str.value.length - 2) {
1297
1298                         tags_str.value = tags_str.value + ", ";
1299                 }
1300
1301                 tags_str.value = tags_str.value + tag + ", ";
1302
1303                 found_tags.selectedIndex = 0;
1304                 
1305         } catch (e) {
1306                 exception_error("editTagsInsert", e);
1307         }
1308 }
1309
1310 function cdmScrollViewport(where) {
1311         debug("cdmScrollViewport: " + where);
1312
1313         var ctr = document.getElementById("headlinesInnerContainer");
1314
1315         if (!ctr) return;
1316
1317         if (where == "bottom") {
1318                 ctr.scrollTop = ctr.scrollHeight;
1319         } else {
1320                 ctr.scrollTop = where;
1321         }
1322 }
1323
1324 function cdmArticleIsBelowViewport(id) {
1325         try {
1326                 var ctr = document.getElementById("headlinesInnerContainer");
1327                 var e = document.getElementById("RROW-" + id);
1328
1329                 if (!e || !ctr) return;
1330
1331                 // article starts below viewport
1332
1333                 if (ctr.scrollTop < e.offsetTop) {
1334                         return true;
1335                 } else {        
1336                         return false;
1337                 }
1338
1339         } catch (e) {
1340                 exception_error("cdmArticleIsVisible", e);
1341         }
1342 }
1343
1344 function cdmArticleIsAboveViewport(id) {
1345         try {
1346                 var ctr = document.getElementById("headlinesInnerContainer");
1347                 var e = document.getElementById("RROW-" + id);
1348
1349                 if (!e || !ctr) return;
1350
1351                 // article starts above viewport
1352
1353                 if (ctr.scrollTop > e.offsetTop + e.offsetHeight) {
1354                         return true;
1355                 } else {        
1356                         return false;
1357                 }
1358
1359         } catch (e) {
1360                 exception_error("cdmArticleIsVisible", e);
1361         }
1362 }
1363
1364 function cdmScrollToArticleId(id) {
1365         try {
1366                 var ctr = document.getElementById("headlinesInnerContainer");
1367                 var e = document.getElementById("RROW-" + id);
1368
1369                 if (!e || !ctr) return;
1370
1371                 ctr.scrollTop = e.offsetTop;
1372
1373         } catch (e) {
1374                 exception_error("cdmScrollToArticleId", e);
1375         }
1376 }
1377
1378 function cdmArticleIsActuallyVisible(id) {
1379         try {
1380                 var ctr = document.getElementById("headlinesInnerContainer");
1381                 var e = document.getElementById("RROW-" + id);
1382
1383                 if (!e || !ctr) return;
1384
1385                 // article fits in viewport OR article is longer than viewport and
1386                 // its bottom is visible
1387
1388                 if (ctr.scrollTop <= e.offsetTop && e.offsetTop + e.offsetHeight <=
1389                                 ctr.scrollTop + ctr.offsetHeight) {
1390
1391                         return true;
1392                 
1393                 } else if (e.offsetHeight > ctr.offsetHeight &&
1394                                 e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1395                                 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight) {
1396
1397                         return true;
1398
1399                 }
1400
1401                 return false;
1402
1403         } catch (e) {
1404                 exception_error("cdmArticleIsVisible", e);
1405         }
1406 }
1407
1408 function cdmWatchdog() {
1409
1410         try {
1411
1412                 var ctr = document.getElementById("headlinesInnerContainer");
1413
1414                 if (!ctr) return;
1415
1416                 var ids = new Array();
1417
1418                 var e = ctr.firstChild;
1419
1420                 while (e) {
1421                         if (e.className && e.className == "cdmArticleUnread" && e.id &&
1422                                         e.id.match("RROW-")) {
1423
1424                                 // article fits in viewport OR article is longer than viewport and
1425                                 // its bottom is visible
1426
1427                                 if (ctr.scrollTop <= e.offsetTop && e.offsetTop + e.offsetHeight <=
1428                                                 ctr.scrollTop + ctr.offsetHeight) {
1429
1430 //                                      debug(e.id + " is visible " + e.offsetTop + "." + 
1431 //                                              (e.offsetTop + e.offsetHeight) + " vs " + ctr.scrollTop + "." +
1432 //                                              (ctr.scrollTop + ctr.offsetHeight));
1433
1434                                         ids.push(e.id.replace("RROW-", ""));
1435
1436                                 } else if (e.offsetHeight > ctr.offsetHeight &&
1437                                                 e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1438                                                 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight) {
1439
1440                                         ids.push(e.id.replace("RROW-", "")); 
1441
1442                                 }
1443
1444                                 // method 2: article bottom is visible and is in upper 1/2 of the viewport
1445
1446 /*                              if (e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1447                                                 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight/2) {
1448
1449                                         ids.push(e.id.replace("RROW-", "")); 
1450
1451                                 } */
1452
1453                         }
1454
1455                         e = e.nextSibling;
1456                 }
1457
1458                 debug("cdmWatchdog, ids= " + ids.toString());
1459
1460                 if (ids.length > 0) {
1461
1462                         for (var i = 0; i < ids.length; i++) {
1463                                 var e = document.getElementById("RROW-" + ids[i]);
1464                                 if (e) {
1465                                         e.className = e.className.replace("Unread", "");
1466                                 }
1467                         }
1468
1469                         var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
1470                                 param_escape(ids.toString()) + "&cmode=0";
1471
1472                         new Ajax.Request(query, {
1473                                 onComplete: function(transport) { 
1474                                         all_counters_callback2(transport); 
1475                                 } });
1476
1477                 }
1478
1479                 _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 4000);
1480
1481         } catch (e) {
1482                 exception_error("cdmWatchdog", e);
1483         }
1484
1485 }
1486
1487
1488 function cache_inject(id, article, param) {
1489         if (!cache_check_param(id, param)) {
1490                 debug("cache_article: miss: " + id + " [p=" + param + "]");
1491
1492                 var cache_obj = new Array();
1493
1494                 cache_obj["id"] = id;
1495                 cache_obj["data"] = article;
1496                 cache_obj["param"] = param;
1497
1498                 article_cache.push(cache_obj);
1499
1500         } else {
1501                 debug("cache_article: hit: " + id + " [p=" + param + "]");
1502         }
1503 }
1504
1505 function cache_find(id) {
1506         for (var i = 0; i < article_cache.length; i++) {
1507                 if (article_cache[i]["id"] == id) {
1508                         return article_cache[i]["data"];
1509                 }
1510         }
1511         return false;
1512 }
1513
1514 function cache_find_param(id, param) {
1515         for (var i = 0; i < article_cache.length; i++) {
1516                 if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
1517                         return article_cache[i]["data"];
1518                 }
1519         }
1520         return false;
1521 }
1522
1523 function cache_check(id) {
1524         for (var i = 0; i < article_cache.length; i++) {
1525                 if (article_cache[i]["id"] == id) {
1526                         return true;
1527                 }
1528         }
1529         return false;
1530 }
1531
1532 function cache_check_param(id, param) {
1533         for (var i = 0; i < article_cache.length; i++) {
1534
1535 //              debug("cache_check_param " + article_cache[i]["id"] + ":" + 
1536 //                      article_cache[i]["param"] + " vs " + id + ":" + param);
1537
1538                 if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
1539                         return true;
1540                 }
1541         }
1542         return false;
1543 }
1544
1545 function cache_expire() {
1546         while (article_cache.length > 25) {
1547                 article_cache.shift();
1548         }
1549 }
1550
1551 function cache_empty() {
1552         article_cache = new Array();
1553 }
1554
1555 function cache_invalidate(id) {
1556         var i = 0
1557
1558         try {   
1559
1560                 while (i < article_cache.length) {
1561                         if (article_cache[i]["id"] == id) {
1562                                 debug("cache_invalidate: removed id " + id);
1563                                 article_cache.splice(i, 1);
1564                                 return true;
1565                         }
1566                         i++;
1567                 }
1568                 debug("cache_invalidate: id not found: " + id);
1569                 return false;
1570         } catch (e) {
1571                 exception_error("cache_invalidate", e);
1572         }
1573 }
1574
1575 function getActiveArticleId() {
1576         return active_post_id;
1577 }
1578
1579 function cdmClicked(id) {
1580         try {
1581                 var elem = document.getElementById("RROW-" + id);
1582
1583                 if (elem) {
1584                         var id = elem.id.replace("RROW-", "");
1585                         active_post_id = id;
1586
1587                         cdmSelectArticles("none");
1588                         toggleUnread(id, 0, true);
1589                         toggleSelected(id);
1590
1591                 }
1592         } catch (e) {
1593                 exception_error("cdmClicked", e);
1594         } 
1595 }
1596
1597 function preload_article_callback(transport) {
1598         try {
1599                 if (transport.responseXML) {
1600                         var articles = transport.responseXML.getElementsByTagName("article");
1601
1602                         for (var i = 0; i < articles.length; i++) {
1603                                 var id = articles[i].getAttribute("id");
1604                                 if (!cache_check(id)) {
1605                                         cache_inject(id, articles[i].firstChild.nodeValue);                             
1606                                         debug("preloaded article: " + id);
1607                                 }
1608                         }
1609                 }
1610         } catch (e) {
1611                 exception_error("preload_article_callback", e);
1612         }
1613 }
1614
1615 function preloadArticleUnderPointer(id) {
1616         try {
1617                 if (getInitParam("bw_limit") == "1") return;
1618
1619                 if (post_under_pointer == id && !cache_check(id)) {
1620
1621                         debug("trying to preload article " + id);
1622
1623                         var neighbor_ids = getRelativePostIds(id, 1);
1624
1625                         /* only request uncached articles */
1626
1627                         var cids_to_request = Array();
1628
1629                         for (var i = 0; i < neighbor_ids.length; i++) {
1630                                 if (!cache_check(neighbor_ids[i])) {
1631                                         cids_to_request.push(neighbor_ids[i]);
1632                                 }
1633                         }
1634                         debug("additional ids: " + cids_to_request.toString());
1635
1636                         cids_to_request.push(id);
1637
1638                         var query = "backend.php?op=rpc&subop=getArticles&ids=" + 
1639                                 cids_to_request.toString();
1640                         new Ajax.Request(query, {
1641                                 onComplete: function(transport) { 
1642                                         preload_article_callback(transport);
1643                         } });
1644                 }
1645         } catch (e) {
1646                 exception_error("preloadArticleUnderPointer", e);
1647         }
1648 }
1649
1650 function postMouseIn(id) {
1651         try {
1652                 if (post_under_pointer != id) {
1653                         post_under_pointer = id;
1654                         if (!isCdmMode()) {
1655                                 window.setTimeout("preloadArticleUnderPointer(" + id + ")", 250);
1656                         }
1657                 }
1658
1659         } catch (e) {
1660                 exception_error("postMouseIn", e);
1661         }
1662 }
1663
1664 function postMouseOut(id) {
1665         try {
1666                 post_under_pointer = false;
1667         } catch (e) {
1668                 exception_error("postMouseOut", e);
1669         }
1670 }
1671
1672 function headlines_scroll_handler() {
1673         try {
1674
1675                 var e = document.getElementById("headlinesInnerContainer");
1676
1677                 // don't do infinite scrolling when Limit == All
1678
1679                 var toolbar_form = document.forms["main_toolbar_form"];
1680
1681                 var limit = toolbar_form.limit[toolbar_form.limit.selectedIndex];
1682                 if (limit.value != 0) {
1683                 
1684                         debug((e.scrollTop + e.offsetHeight) + " vs " + e.scrollHeight + " dis? " +
1685                                 _infscroll_disable);
1686
1687                         if (e.scrollTop + e.offsetHeight > e.scrollHeight - 100) {
1688                                 if (!_infscroll_disable) {
1689                                         debug("more cowbell!");
1690                                         viewNextFeedPage();
1691                                 }
1692                         }
1693                 }
1694
1695         } catch (e) {
1696                 exception_error("headlines_scroll_handler", e);
1697         }
1698 }
1699
1700 function catchupRelativeToArticle(below) {
1701
1702         try {
1703
1704                 if (!xmlhttp_ready(xmlhttp_rpc)) {
1705                         printLockingError();
1706                 }
1707         
1708                 if (!getActiveArticleId()) {
1709                         alert(__("No article is selected."));
1710                         return;
1711                 }
1712
1713                 var visible_ids;
1714
1715                 if (document.getElementById("headlinesList")) {
1716                         visible_ids = getVisibleHeadlineIds();
1717                 } else {
1718                         visible_ids = cdmGetVisibleArticles();
1719                 }
1720
1721                 var ids_to_mark = new Array();
1722
1723                 if (!below) {
1724                         for (var i = 0; i < visible_ids.length; i++) {
1725                                 if (visible_ids[i] != getActiveArticleId()) {
1726                                         var e = document.getElementById("RROW-" + visible_ids[i]);
1727
1728                                         if (e && e.className.match("Unread")) {
1729                                                 ids_to_mark.push(visible_ids[i]);
1730                                         }
1731                                 } else {
1732                                         break;
1733                                 }
1734                         }
1735                 } else {
1736                         for (var i = visible_ids.length-1; i >= 0; i--) {
1737                                 if (visible_ids[i] != getActiveArticleId()) {
1738                                         var e = document.getElementById("RROW-" + visible_ids[i]);
1739
1740                                         if (e && e.className.match("Unread")) {
1741                                                 ids_to_mark.push(visible_ids[i]);
1742                                         }
1743                                 } else {
1744                                         break;
1745                                 }
1746                         }
1747                 }
1748
1749                 if (ids_to_mark.length == 0) {
1750                         alert(__("No articles found to mark"));
1751                 } else {
1752                         var msg = __("Mark %d article(s) as read?").replace("%d", ids_to_mark.length);
1753
1754                         if (confirm(msg)) {
1755
1756                                 for (var i = 0; i < ids_to_mark.length; i++) {
1757                                         var e = document.getElementById("RROW-" + ids_to_mark[i]);
1758                                         e.className = e.className.replace("Unread", "");
1759                                 }
1760
1761                                 var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
1762                                         param_escape(ids_to_mark.toString()) + "&cmode=0";
1763
1764                                 new Ajax.Request(query, {
1765                                         onComplete: function(transport) { 
1766                                                 catchup_callback2(transport); 
1767                                         } });
1768
1769                         }
1770                 }
1771
1772         } catch (e) {
1773                 exception_error("catchupRelativeToArticle", e);
1774         }
1775 }
1776
1777 function cdmExpandArticle(a_id) {
1778         try {
1779                 var id = 'CICD-' + a_id;
1780
1781                 try {
1782                         Element.hide("CEXC-" + a_id);
1783                 } catch (e) { } 
1784
1785                 Effect.Appear(id, {duration : 0.5, 
1786                         beforeStart: function(effect) { 
1787                                 var h_id = 'CICH-' + a_id;
1788                                 var h_elem = document.getElementById(h_id);
1789                                 if (h_elem) { h_elem.style.display = "none"; }
1790
1791                                 toggleUnread(a_id, 0);
1792                         }});
1793
1794
1795         } catch (e) {
1796                 exception_error("appearBlockElementF", e);
1797         }
1798
1799 }
1800
1801 function fixHeadlinesOrder(ids) {
1802         try {
1803                 for (var i = 0; i < ids.length; i++) {
1804                         var e = document.getElementById("RROW-" + ids[i]);
1805
1806                         if (e) {
1807                                 if (i % 2 == 0) {
1808                                         e.className = e.className.replace("even", "odd");
1809                                 } else {
1810                                         e.className = e.className.replace("odd", "even");
1811                                 }
1812                         }
1813                 }
1814         } catch (e) {
1815                 exception_error("fixHeadlinesOrder", e);
1816         }
1817 }
1818
1819 function subtoolbarSearch() {
1820         try {
1821
1822                 var q = document.getElementById("subtoolbar_search_box");
1823                 
1824                 if (!q) return;
1825
1826                 q = q.value.toUpperCase();
1827
1828                 var ids = false;
1829                 var vis_ids = new Array();
1830
1831                 if (document.getElementById("headlinesList")) {
1832                         ids = getVisibleHeadlineIds();
1833                 } else {
1834                         ids = cdmGetVisibleArticles();
1835                 }
1836
1837                 for (var i = 0; i < ids.length; i++) {
1838                         var title = document.getElementById("RTITLE-" + ids[i]);
1839
1840                         if (title) {
1841                                 if (!title.innerHTML.toUpperCase().match(q)) {
1842                                         Element.hide(document.getElementById("RROW-" + ids[i]));
1843                                 } else {
1844                                         Element.show(document.getElementById("RROW-" + ids[i]));
1845                                         vis_ids.push(ids[i]);
1846                                 }
1847                         }
1848                 }
1849
1850                 fixHeadlinesOrder(vis_ids);
1851
1852         } catch (e) {
1853                 exception_error("subtoolbarSearch", e);
1854         } 
1855 }
1856
1857 function hideReadHeadlines() {
1858         try {
1859
1860                 var ids = false;
1861                 var vis_ids = new Array();
1862
1863                 if (document.getElementById("headlinesList")) {
1864                         ids = getVisibleHeadlineIds();
1865                 } else {
1866                         ids = cdmGetVisibleArticles();
1867                 }
1868
1869                 var read_headlines_visible = true;
1870
1871                 for (var i = 0; i < ids.length; i++) {
1872                         var row = document.getElementById("RROW-" + ids[i]);
1873
1874                         if (row && row.className) {
1875                                 if (read_headlines_visible) {
1876                                         if (row.className.match("Unread") || row.className.match("Selected")) {
1877                                                 Element.show(row);
1878                                                 vis_ids.push(ids[i]);
1879                                         } else {
1880                                                 //Effect.Fade(row, {duration : 0.3});
1881                                                 Element.hide(row);
1882                                         }
1883                                 } else {
1884                                         Element.show(row);
1885                                         vis_ids.push(ids[i]);
1886                                 }
1887                         }
1888                 }
1889                 
1890                 fixHeadlinesOrder(vis_ids);
1891
1892                 read_headlines_visible = !read_headlines_visible;
1893
1894         } catch (e) {
1895                 exception_error("hideReadHeadlines", e);
1896         } 
1897 }
1898
1899 function invertHeadlineSelection() {
1900         try {
1901                 var rows = new Array();
1902                 var r = false;
1903                 
1904                 if (!isCdmMode()) {             
1905                         r = document.getElementsByTagName("TR");
1906                 } else {
1907                         r = document.getElementsByTagName("DIV");
1908                 }
1909
1910                 for (var i = 0; i < r.length; i++) {
1911                         if (r[i].id && r[i].id.match("RROW-")) {
1912                                 rows.push(r[i]);
1913                         }
1914                 }
1915                 
1916                 for (var i = 0; i < rows.length; i++) {
1917                         var nc = rows[i].className;
1918                         var id = rows[i].id.replace("RROW-", "");
1919                         var cb = document.getElementById("RCHK-" + id);
1920
1921                         if (!rows[i].className.match("Selected")) {
1922                                 nc = nc + "Selected";
1923                                 cb.checked = true;
1924                         } else {
1925                                 nc = nc.replace("Selected", "");
1926                                 cb.checked = false;
1927                         }
1928
1929                         rows[i].className = nc;
1930
1931                 }
1932
1933         } catch (e) {
1934                 exception_error("invertHeadlineSelection", e);
1935         }
1936 }
1937
1938 function getArticleUnderPointer() {
1939         return post_under_pointer;
1940 }
1941
1942 function zoomToArticle(id) {
1943         try {
1944                 var w = window.open("backend.php?op=view&mode=zoom&id=" + param_escape(id), 
1945                         "ttrss_zoom_" + id,
1946                         "status=0,toolbar=0,location=0,width=450,height=300,scrollbars=1,menubar=0");
1947
1948         } catch (e) {
1949                 exception_error("zoomToArticle", e);
1950         }
1951 }
1952
1953 function showOriginalArticleInline(id) {
1954         try {
1955
1956                 var query = "backend.php?op=rpc&subop=getArticleLink&id=" + id;
1957
1958                 notify_progress("Loading, please wait...", true);
1959
1960                 new Ajax.Request(query, {
1961                         onComplete: function(transport) { 
1962
1963                                 if (transport.responseXML) {
1964                         
1965                                         var link = transport.responseXML.getElementsByTagName("link")[0];
1966                                         var id = transport.responseXML.getElementsByTagName("id")[0];
1967
1968                                         notify("");
1969
1970                                         if (link && id) {
1971                                                 link = link.firstChild.nodeValue;
1972
1973                                                 var ci = document.getElementById("content-insert");
1974
1975                                                 var tmp = "<iframe id=\"inline_orig_article\" width=\""+ci.offsetWidth+"\" height=\""+ci.offsetHeight+"\" style=\"border-width : 0px;\" src=\""+link+"\"></iframe>";
1976
1977                                                 render_article(tmp);
1978
1979                                         }
1980                                 }
1981                         } });
1982
1983         } catch (e) {
1984                 exception_error("showOriginalArticleInline", e);
1985         }
1986 }
1987
1988
1989 function scrollArticle(offset) {
1990         try {
1991                 if (!isCdmMode()) {
1992                         var ci = document.getElementById("content-insert");
1993                         if (ci) {
1994                                 ci.scrollTop += offset;
1995                         }
1996                 } else {
1997                         var hi = document.getElementById("headlinesInnerContainer");
1998                         if (hi) {
1999                                 hi.scrollTop += offset;
2000                         }
2001
2002                 }
2003         } catch (e) {
2004                 exception_error("scrollArticle", e);
2005         }
2006 }