]> git.wh0rd.org Git - tt-rss.git/blob - viewfeed.js
CDM mode: add article selection, rework moveToPost()
[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) {
101                                 _infscroll_disable = 1;
102                         } else {
103                                 _infscroll_disable = 0;
104                         }
105
106                         var counters = transport.responseXML.getElementsByTagName("counters")[0];
107                         var articles = transport.responseXML.getElementsByTagName("article");
108                         var runtime_info = transport.responseXML.getElementsByTagName("runtime-info");
109         
110                         if (feed_cur_page == 0) {
111                                 if (headlines) {
112                                         f.innerHTML = headlines.firstChild.nodeValue;
113
114                                         var cache_prefix = "";
115
116                                         if (is_cat) {
117                                                 cache_prefix = "C:";
118                                         } else {
119                                                 cache_prefix = "F:";
120                                         }
121
122                                         cache_invalidate(cache_prefix + active_feed_id);
123
124                                         if (!disable_cache) {
125                                                 cache_inject(cache_prefix + active_feed_id,
126                                                         headlines.firstChild.nodeValue, headlines_unread);
127                                         }
128
129                                 } else {
130                                         debug("headlines_callback: returned no data");
131                                 f.innerHTML = "<div class='whiteBox'>" + __('Could not update headlines (missing XML data)') + "</div>";
132         
133                                 }
134                         } else {
135                                 if (headlines) {
136                                         if (headlines_count > 0) {
137                                                 debug("adding some more headlines...");
138         
139                                                 var c = document.getElementById("headlinesList");
140                 
141                                                 if (!c) {
142                                                         c = document.getElementById("headlinesInnerContainer");
143                                                 }
144
145                                                 var ids = getSelectedArticleIds2();
146         
147                                                 c.innerHTML = c.innerHTML + headlines.firstChild.nodeValue;
148
149                                                 debug("restore selected ids: " + ids);
150
151                                                 for (var i = 0; i < ids.length; i++) {
152                                                         markHeadline(ids[i]);
153                                                 }
154
155                                                 subtoolbarSearch();
156
157                                         } else {
158                                                 debug("no new headlines received");
159                                         }
160                                 } else {
161                                         debug("headlines_callback: returned no data");
162                                         notify_error("Error while trying to load more headlines");      
163                                 }
164         
165                         }
166         
167                         if (articles) {
168                                 for (var i = 0; i < articles.length; i++) {
169                                         var a_id = articles[i].getAttribute("id");
170                                         debug("found id: " + a_id);
171                                         cache_inject(a_id, articles[i].firstChild.nodeValue);
172                                 }
173                         } else {
174                                 debug("no cached articles received");
175                         }
176         
177                         if (counters) {
178                                 debug("parsing piggybacked counters: " + counters);
179                                 parse_counters(counters, false);
180                         } else {
181                                 debug("counters container not found in reply");
182                         }
183         
184                         if (runtime_info) {
185                                 debug("parsing runtime info: " + runtime_info[0]);
186                                 parse_runtime_info(runtime_info[0]);
187                         } else {
188                                 debug("counters container not found in reply");
189                         }
190         
191                 } else {
192                         debug("headlines_callback: returned no XML object");
193                         f.innerHTML = "<div class='whiteBox'>" + __('Could not update headlines (missing XML object)') + "</div>";
194                 }
195         
196                 if (typeof correctPNG != 'undefined') {
197                         correctPNG();
198                 }
199         
200                 if (_cdm_wd_timeout) window.clearTimeout(_cdm_wd_timeout);
201         
202                 if (!document.getElementById("headlinesList") && 
203                                 getInitParam("cdm_auto_catchup") == 1) {
204                         debug("starting CDM watchdog");
205                         _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 5000);
206                         _cdm_wd_vishist = new Array();
207                 } else {
208                         debug("not in CDM mode or watchdog disabled");
209                 }
210         
211                 if (_tag_cdm_scroll) {
212                         try {
213                                 document.getElementById("headlinesInnerContainer").scrollTop = _tag_cdm_scroll;
214                                 _tag_cdm_scroll = false;
215                                 debug("resetting headlinesInner scrollTop");
216         
217                         } catch (e) { }
218                 }
219         
220                 _feed_cur_page = feed_cur_page;
221                 _infscroll_request_sent = 0;
222
223                 notify("");
224         } catch (e) {
225                 exception_error("headlines_callback2", e);
226         }
227 }
228
229 function render_article(article) {
230         try {
231                 var f = document.getElementById("content-frame");
232                 try {
233                         f.scrollTop = 0;
234                 } catch (e) { };
235
236                 f.innerHTML = article;
237
238         } catch (e) {
239                 exception_error("render_article", e);
240         }
241 }
242
243 function showArticleInHeadlines(id) {
244
245         try {
246
247                 cleanSelected("headlinesList");
248         
249                 var crow = document.getElementById("RROW-" + id);
250
251                 if (!crow) return;
252
253                 var article_is_unread = crow.className.match("Unread");
254                         
255                 crow.className = crow.className.replace("Unread", "");
256
257                 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
258         
259                 var upd_img_pic = document.getElementById("FUPDPIC-" + id);
260
261                 var cache_prefix = "";
262                                 
263                 if (activeFeedIsCat()) {
264                         cache_prefix = "C:";
265                 } else {
266                         cache_prefix = "F:";
267                 }
268
269                 var view_mode = false;
270
271                 try {
272                         view_mode = document.forms['main_toolbar_form'].view_mode;      
273                         view_mode = view_mode[view_mode.selectedIndex].value;
274                 } catch (e) {
275                         exception_error("showArticleInHeadlines/viewmode", e, true);
276                 }
277
278                 if (upd_img_pic && upd_img_pic.src.match("updated.png")) {
279                         upd_img_pic.src = "images/blank_icon.gif";
280
281                         cache_invalidate(cache_prefix + getActiveFeedId());
282
283                         cache_inject(cache_prefix + getActiveFeedId(),
284                                 document.getElementById("headlines-frame").innerHTML,
285                                 get_feed_unread(getActiveFeedId()));
286
287                 } else if (article_is_unread && view_mode == "all_articles") {
288
289                         cache_invalidate(cache_prefix + getActiveFeedId());
290
291                         cache_inject(cache_prefix + getActiveFeedId(),
292                                 document.getElementById("headlines-frame").innerHTML,
293                                 get_feed_unread(getActiveFeedId())-1);
294
295                 } else if (article_is_unread) {
296                         cache_invalidate(cache_prefix + getActiveFeedId());
297                 }
298
299                 markHeadline(id);
300
301         } catch (e) {
302                 exception_error("showArticleInHeadlines", e);
303         }
304 }
305
306 function article_callback2(transport, id, feed_id) {
307         try {
308                 debug("article_callback2 " + id);
309
310                 if (transport.responseXML) {
311
312                         active_real_feed_id = feed_id;
313                         active_post_id = id; 
314
315                         showArticleInHeadlines(id);     
316
317                         var reply = transport.responseXML.firstChild.firstChild;
318
319                         var articles = transport.responseXML.getElementsByTagName("article");
320
321                         for (var i = 0; i < articles.length; i++) {
322                                 var a_id = articles[i].getAttribute("id");
323
324                                 debug("found id: " + a_id);
325
326                                 if (a_id == active_post_id) {
327                                         debug("active article, rendering...");                                  
328                                         render_article(articles[i].firstChild.nodeValue);
329                                 }
330
331                                 cache_inject(a_id, articles[i].firstChild.nodeValue);
332                         }
333                 
334                 } else {
335                         debug("article_callback: returned no XML object");
336                         var f = document.getElementById("content-frame");
337                         f.innerHTML = "<div class='whiteBox'>" + __('Could not display article (missing XML object)') + "</div>";
338                 }
339
340                 var date = new Date();
341                 last_article_view = date.getTime() / 1000;
342
343                 if (typeof correctPNG != 'undefined') {
344                         correctPNG();
345                 }
346
347                 if (_reload_feedlist_after_view) {
348                         setTimeout('updateFeedList(false, false)', 50);                 
349                         _reload_feedlist_after_view = false;
350                 } else {
351                         var counters = transport.responseXML.getElementsByTagName("counters")[0];
352
353                         if (counters) {
354                                 debug("parsing piggybacked counters: " + counters);
355                                 parse_counters(counters, false);
356                         } else {
357                                 debug("counters container not found in reply");
358                         }
359                 }
360
361                 notify("");
362         } catch (e) {
363                 exception_error("article_callback2", e);
364         }
365 }
366
367 function view(id, feed_id, skip_history) {
368         
369         try {
370                 debug("loading article: " + id + "/" + feed_id);
371         
372                 var cached_article = cache_find(id);
373
374                 debug("cache check result: " + (cached_article != false));
375         
376                 enableHotkeys();
377         
378                 //setActiveFeedId(feed_id);
379
380                 var query = "backend.php?op=view&id=" + param_escape(id) +
381                         "&feed=" + param_escape(feed_id);
382
383                 var date = new Date();
384
385                 var neighbor_ids = getRelativePostIds(active_post_id);
386
387                 /* only request uncached articles */
388
389                 var cids_to_request = Array();
390
391                 for (var i = 0; i < neighbor_ids.length; i++) {
392                         if (!cache_check(neighbor_ids[i])) {
393                                 cids_to_request.push(neighbor_ids[i]);
394                         }
395                 }
396
397                 debug("additional ids: " + cids_to_request.toString());                 
398
399                 /* additional info for piggyback counters */
400
401                 if (tagsAreDisplayed()) {
402                         query = query + "&omode=lt";
403                 } else {
404                         query = query + "&omode=flc";
405                 }
406
407                 var date = new Date();
408                 var timestamp = Math.round(date.getTime() / 1000);
409                 query = query + "&ts=" + timestamp;
410
411                 query = query + "&cids=" + cids_to_request.toString();
412
413                 var crow = document.getElementById("RROW-" + id);
414                 var article_is_unread = crow.className.match("Unread");
415
416                 showArticleInHeadlines(id);
417
418                 if (!cached_article) {
419
420                         notify_progress("Loading, please wait...");
421
422                 } else if (cached_article && article_is_unread) {
423
424                         query = query + "&mode=prefetch";
425
426                         render_article(cached_article);
427
428                 } else if (cached_article) {
429
430                         query = query + "&mode=prefetch_old";
431                         render_article(cached_article);
432                 }
433
434                 cache_expire();
435
436                 new Ajax.Request(query, {
437                         onComplete: function(transport) { 
438                                 article_callback2(transport, id, feed_id); 
439                         } });
440
441         } catch (e) {
442                 exception_error("view", e);
443         }
444 }
445
446 function tMark(id) {
447         return toggleMark(id);
448 }
449
450 function tPub(id) {
451         return togglePub(id);
452 }
453
454 function tMark_afh_off(effect) {
455         try {
456                 var elem = effect.effects[0].element;
457
458                 debug("tMark_afh_off : " + elem.id);
459
460                 if (elem) {
461                         elem.src = elem.src.replace("mark_set", "mark_unset");
462                         elem.alt = __("Star article");
463                         Element.show(elem);
464                 }
465
466         } catch (e) {
467                 exception_error("tMark_afh_off", e);
468         }
469 }
470
471 function tPub_afh_off(effect) {
472         try {
473                 var elem = effect.effects[0].element;
474
475                 debug("tPub_afh_off : " + elem.id);
476
477                 if (elem) {
478                         elem.src = elem.src.replace("pub_set", "pub_unset");
479                         elem.alt = __("Publish article");
480                         Element.show(elem);
481                 }
482
483         } catch (e) {
484                 exception_error("tPub_afh_off", e);
485         }
486 }
487
488 function toggleMark(id, client_only, no_effects) {
489
490         try {
491
492                 var query = "backend.php?op=rpc&id=" + id + "&subop=mark";
493         
494                 query = query + "&afid=" + getActiveFeedId();
495         
496                 if (tagsAreDisplayed()) {
497                         query = query + "&omode=tl";
498                 } else {
499                         query = query + "&omode=flc";
500                 }
501         
502                 var mark_img = document.getElementById("FMPIC-" + id);
503                 var vfeedu = document.getElementById("FEEDU--1");
504                 var crow = document.getElementById("RROW-" + id);
505         
506                 if (mark_img.src.match("mark_unset")) {
507                         mark_img.src = mark_img.src.replace("mark_unset", "mark_set");
508                         mark_img.alt = __("Unstar article");
509                         query = query + "&mark=1";
510         
511 /*                      if (vfeedu && crow.className.match("Unread")) {
512                                 vfeedu.innerHTML = (+vfeedu.innerHTML) + 1;
513                         } */
514         
515                 } else {
516                         //mark_img.src = "images/mark_unset.png";
517                         mark_img.alt = __("Please wait...");
518                         query = query + "&mark=0";
519         
520 /*                      if (vfeedu && crow.className.match("Unread")) {
521                                 vfeedu.innerHTML = (+vfeedu.innerHTML) - 1;
522                         } */
523         
524                         if (document.getElementById("headlinesList") && !no_effects) {
525                                 Effect.Puff(mark_img, {duration : 0.25, afterFinish: tMark_afh_off});
526                         } else { 
527                                 mark_img.src = mark_img.src.replace("mark_set", "mark_unset");
528                                 mark_img.alt = __("Star article");
529                         }
530                 }
531         
532 /*              var vfeedctr = document.getElementById("FEEDCTR--1");
533                 var vfeedr = document.getElementById("FEEDR--1");
534         
535                 if (vfeedu && vfeedctr) {
536                         if ((+vfeedu.innerHTML) > 0) {
537                                 if (crow.className.match("Unread") && !vfeedr.className.match("Unread")) {
538                                         vfeedr.className = vfeedr.className + "Unread";
539                                         vfeedctr.className = "odd";
540                                 }
541                         } else {
542                                 vfeedctr.className = "invisible";
543                                 vfeedr.className = vfeedr.className.replace("Unread", "");
544                         }
545                 }
546         
547                 debug("toggle starred for aid " + id);
548         
549                 //new Ajax.Request(query); */
550
551                 if (!client_only) {
552                         debug(query);
553
554                         new Ajax.Request(query, {
555                                 onComplete: function(transport) { 
556                                         all_counters_callback2(transport); 
557                                 } });
558
559                 }
560
561         } catch (e) {
562                 exception_error("toggleMark", e);
563         }
564 }
565
566 function togglePub(id, client_only, no_effects) {
567
568         try {
569
570                 var query = "backend.php?op=rpc&id=" + id + "&subop=publ";
571         
572                 query = query + "&afid=" + getActiveFeedId();
573         
574                 if (tagsAreDisplayed()) {
575                         query = query + "&omode=tl";
576                 } else {
577                         query = query + "&omode=flc";
578                 }
579         
580                 var mark_img = document.getElementById("FPPIC-" + id);
581                 var vfeedu = document.getElementById("FEEDU--2");
582                 var crow = document.getElementById("RROW-" + id);
583         
584                 if (mark_img.src.match("pub_unset")) {
585                         mark_img.src = mark_img.src.replace("pub_unset", "pub_set");
586                         mark_img.alt = __("Unpublish article");
587                         query = query + "&pub=1";
588         
589 /*                      if (vfeedu && crow.className.match("Unread")) {
590                                 vfeedu.innerHTML = (+vfeedu.innerHTML) + 1;
591                         } */
592         
593                 } else {
594                         //mark_img.src = "images/pub_unset.png";
595                         mark_img.alt = __("Please wait...");
596                         query = query + "&pub=0";
597         
598 /*                      if (vfeedu && crow.className.match("Unread")) {
599                                 vfeedu.innerHTML = (+vfeedu.innerHTML) - 1;
600                         } */
601
602                         if (document.getElementById("headlinesList") && !no_effects) {
603                                 Effect.Puff(mark_img, {duration : 0.25, afterFinish: tPub_afh_off});
604                         } else { 
605                                 mark_img.src = mark_img.src.replace("pub_set", "pub_unset");
606                                 mark_img.alt = __("Publish article");
607                         }
608                 }
609         
610 /*              var vfeedctr = document.getElementById("FEEDCTR--2");
611                 var vfeedr = document.getElementById("FEEDR--2");
612         
613                 if (vfeedu && vfeedctr) {
614                         if ((+vfeedu.innerHTML) > 0) {
615                                 if (crow.className.match("Unread") && !vfeedr.className.match("Unread")) {
616                                         vfeedr.className = vfeedr.className + "Unread";
617                                         vfeedctr.className = "odd";
618                                 }
619                         } else {
620                                 vfeedctr.className = "invisible";
621                                 vfeedr.className = vfeedr.className.replace("Unread", "");
622                         }
623                 }
624         
625                 debug("toggle published for aid " + id);
626         
627                 new Ajax.Request(query); */
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
738 /*      } else {
739                         var rows = cdmGetVisibleArticles();
740
741                         if (mode == "next") {
742
743                                 for (var i = 0; i < rows.length; i++) {
744
745                                         if (cdmArticleIsActuallyVisible(rows[i]) ||
746                                                         cdmArticleIsBelowViewport(rows[i])) {
747
748                                                 if (!cdmArticleIsActuallyVisible(rows[i])) {
749                                                         cdmScrollToArticleId(rows[i]);
750                                                 }
751                                                 //setTimeout("toggleUnread(" + rows[i] + ", undefined, true)", 500);
752                                                 cdmSelectArticles("none");
753                                                 toggleUnread(rows[i], undefined, true);
754                                                 toggleSelected(rows[i]);
755
756                                                 return;
757                                         }
758                                 }
759
760                                 cdmScrollViewport('bottom');
761
762                         } else if (mode == "prev") {
763
764                                 for (var i = 0; i < rows.length; i++) {
765
766                                         if (cdmArticleIsAboveViewport(rows[i]) &&
767                                                                 !cdmArticleIsAboveViewport(rows[i+1])) {
768
769                                                 cdmScrollToArticleId(rows[i]);
770                                                 //setTimeout("toggleUnread(" + rows[i] + ", undefined, true)", 500);
771                                                 cdmSelectArticles("none");
772                                                 toggleUnread(rows[i], undefined, true);
773                                                 cdmSelectArticleById(rows[i]);
774
775                                                 break;
776                                         } 
777                                 }
778
779                         } 
780         
781                 } */
782
783         } catch (e) {
784                 exception_error(e, "moveToPost");
785         }
786 }
787
788 function toggleSelected(id) {
789         try {
790         
791                 var cb = document.getElementById("RCHK-" + id);
792
793                 var row = document.getElementById("RROW-" + id);
794                 if (row) {
795                         var nc = row.className;
796                         
797                         if (!nc.match("Selected")) {
798                                 nc = nc + "Selected";
799                                 if (cb) {
800                                         cb.checked = true;
801                                 }
802
803                                 // In CDM basically last selected article == active article
804                                 if (isCdmMode()) active_post_id = id;
805                         } else {
806                                 nc = nc.replace("Selected", "");
807                                 if (cb) {
808                                         cb.checked = false;
809                                 }
810
811                         }
812
813                         row.className = nc;
814                 }
815         } catch (e) {
816                 exception_error(e, "toggleSelected");
817         }
818 }
819
820 function toggleUnread_afh(effect) {
821         try {
822
823                 var elem = effect.element;
824                 elem.style.backgroundColor = "";
825
826         } catch (e) {
827                 exception_error(e, "toggleUnread_afh");
828         }
829
830
831 function toggleUnread(id, cmode, effect) {
832         try {
833         
834                 var row = document.getElementById("RROW-" + id);
835                 if (row) {
836                         var nc = row.className;
837                         var is_selected = row.className.match("Selected");
838                         nc = nc.replace("Unread", "");
839                         nc = nc.replace("Selected", "");
840
841                         // since we are removing selection from the object, uncheck
842                         // corresponding checkbox
843
844                         var cb = document.getElementById("RCHK-" + id);
845                         if (cb) {
846                                 cb.checked = false;
847                         }
848
849                         // NOTE: I'm not sure that resetting selection here is a feature -fox
850
851                         if (cmode == undefined || cmode == 2) {
852                                 if (row.className.match("Unread")) {
853                                         row.className = nc;
854
855                                         if (effect) {
856                                                 new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
857                                                         afterFinish: toggleUnread_afh,
858                                                         queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
859                                         } 
860
861                                 } else {
862                                         row.className = nc + "Unread";
863                                 }
864                         } else if (cmode == 0) {
865                                 row.className = nc;
866
867                                 if (effect) {
868                                         new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
869                                                 afterFinish: toggleUnread_afh,
870                                                 queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
871                                 } 
872                         } else if (cmode == 1) {
873                                 row.className = nc + "Unread";
874                         }
875
876                         // Disable unmarking as selected for the time being (16.05.08) -fox
877                         if (is_selected) row.className = row.className + "Selected";
878
879                         if (cmode == undefined) cmode = 2;
880
881                         var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
882                                 param_escape(id) + "&cmode=" + param_escape(cmode);
883
884 //                      notify_progress("Loading, please wait...");
885
886                         new Ajax.Request(query, {
887                                 onComplete: function(transport) { 
888                                         all_counters_callback2(transport); 
889                                 } });
890
891                 }
892
893
894         } catch (e) {
895                 exception_error("toggleUnread", e);
896         }
897 }
898
899 function selectionToggleUnread(cdm_mode, set_state, callback_func, no_error) {
900         try {
901                 var rows;
902
903                 if (cdm_mode) {
904                         rows = cdmGetSelectedArticles();
905                 } else {        
906                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
907                 }
908
909                 if (rows.length == 0 && !no_error) {
910                         alert(__("No articles are selected."));
911                         return;
912                 }
913
914                 for (i = 0; i < rows.length; i++) {
915                         var row = document.getElementById("RROW-" + rows[i]);
916                         if (row) {
917                                 var nc = row.className;
918                                 nc = nc.replace("Unread", "");
919                                 nc = nc.replace("Selected", "");
920
921                                 if (set_state == undefined) {
922                                         if (row.className.match("Unread")) {
923                                                 row.className = nc + "Selected";
924                                         } else {
925                                                 row.className = nc + "UnreadSelected";
926                                         }
927                                 }
928
929                                 if (set_state == false) {
930                                         row.className = nc + "Selected";
931                                 }
932
933                                 if (set_state == true) {
934                                         row.className = nc + "UnreadSelected";
935                                 }
936                         }
937                 }
938
939                 if (rows.length > 0) {
940
941                         var cmode = "";
942
943                         if (set_state == undefined) {
944                                 cmode = "2";
945                         } else if (set_state == true) {
946                                 cmode = "1";
947                         } else if (set_state == false) {
948                                 cmode = "0";
949                         }
950
951                         var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
952                                 param_escape(rows.toString()) + "&cmode=" + cmode;
953
954                         notify_progress("Loading, please wait...");
955
956                         new Ajax.Request(query, {
957                                 onComplete: function(transport) { 
958                                         catchup_callback2(transport, callback_func); 
959                                 } });
960
961                 }
962
963         } catch (e) {
964                 exception_error("selectionToggleUnread", e);
965         }
966 }
967
968 function selectionToggleMarked(cdm_mode) {
969         try {
970         
971                 var rows;
972                 
973                 if (cdm_mode) {
974                         rows = cdmGetSelectedArticles();
975                 } else {        
976                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
977                 }       
978
979                 if (rows.length == 0) {
980                         alert(__("No articles are selected."));
981                         return;
982                 }
983
984                 for (i = 0; i < rows.length; i++) {
985                         toggleMark(rows[i], true, true);
986                 }
987
988                 if (rows.length > 0) {
989
990                         var query = "backend.php?op=rpc&subop=markSelected&ids=" +
991                                 param_escape(rows.toString()) + "&cmode=2";
992
993                         query = query + "&afid=" + getActiveFeedId();
994
995 /*                      if (tagsAreDisplayed()) {
996                                 query = query + "&omode=tl";
997                         } else {
998                                 query = query + "&omode=flc";
999                         } */
1000
1001                         query = query + "&omode=lc";
1002
1003                         new Ajax.Request(query, {
1004                                 onComplete: function(transport) { 
1005                                         all_counters_callback2(transport); 
1006                                 } });
1007
1008                 }
1009
1010         } catch (e) {
1011                 exception_error("selectionToggleMarked", e);
1012         }
1013 }
1014
1015 function selectionTogglePublished(cdm_mode) {
1016         try {
1017         
1018                 var rows;
1019                 
1020                 if (cdm_mode) {
1021                         rows = cdmGetSelectedArticles();
1022                 } else {        
1023                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1024                 }       
1025
1026                 if (rows.length == 0) {
1027                         alert(__("No articles are selected."));
1028                         return;
1029                 }
1030
1031                 for (i = 0; i < rows.length; i++) {
1032                         togglePub(rows[i], true, true);
1033                 }
1034
1035                 if (rows.length > 0) {
1036
1037                         var query = "backend.php?op=rpc&subop=publishSelected&ids=" +
1038                                 param_escape(rows.toString()) + "&cmode=2";
1039
1040                         query = query + "&afid=" + getActiveFeedId();
1041
1042 /*                      if (tagsAreDisplayed()) {
1043                                 query = query + "&omode=tl";
1044                         } else {
1045                                 query = query + "&omode=flc";
1046                         } */
1047
1048                         query = query + "&omode=lc";
1049
1050                         new Ajax.Request(query, {
1051                                 onComplete: function(transport) { 
1052                                         all_counters_callback2(transport); 
1053                                 } });
1054
1055                 }
1056
1057         } catch (e) {
1058                 exception_error("selectionToggleMarked", e);
1059         }
1060 }
1061
1062 function cdmGetSelectedArticles() {
1063         var sel_articles = new Array();
1064         var container = document.getElementById("headlinesInnerContainer");
1065
1066         for (i = 0; i < container.childNodes.length; i++) {
1067                 var child = container.childNodes[i];
1068
1069                 if (child.id.match("RROW-") && child.className.match("Selected")) {
1070                         var c_id = child.id.replace("RROW-", "");
1071                         sel_articles.push(c_id);
1072                 }
1073         }
1074
1075         return sel_articles;
1076 }
1077
1078 function cdmGetVisibleArticles() {
1079         var sel_articles = new Array();
1080         var container = document.getElementById("headlinesInnerContainer");
1081
1082         for (i = 0; i < container.childNodes.length; i++) {
1083                 var child = container.childNodes[i];
1084
1085                 if (child.id.match("RROW-")) {
1086                         var c_id = child.id.replace("RROW-", "");
1087                         sel_articles.push(c_id);
1088                 }
1089         }
1090
1091         return sel_articles;
1092 }
1093
1094 function cdmGetUnreadArticles() {
1095         var sel_articles = new Array();
1096         var container = document.getElementById("headlinesInnerContainer");
1097
1098         for (i = 0; i < container.childNodes.length; i++) {
1099                 var child = container.childNodes[i];
1100
1101                 if (child.id.match("RROW-") && child.className.match("Unread")) {
1102                         var c_id = child.id.replace("RROW-", "");
1103                         sel_articles.push(c_id);
1104                 }
1105         }
1106
1107         return sel_articles;
1108 }
1109
1110
1111 // mode = all,none,unread
1112 function cdmSelectArticles(mode) {
1113         var container = document.getElementById("headlinesInnerContainer");
1114
1115         for (i = 0; i < container.childNodes.length; i++) {
1116                 var child = container.childNodes[i];
1117
1118                 if (child.id.match("RROW-")) {
1119                         var aid = child.id.replace("RROW-", "");
1120
1121                         var cb = document.getElementById("RCHK-" + aid);
1122
1123                         if (mode == "all") {
1124                                 if (!child.className.match("Selected")) {
1125                                         child.className = child.className + "Selected";
1126                                         cb.checked = true;
1127                                 }
1128                         } else if (mode == "unread") {
1129                                 if (child.className.match("Unread") && !child.className.match("Selected")) {
1130                                         child.className = child.className + "Selected";
1131                                         cb.checked = true;
1132                                 }
1133                         } else {
1134                                 child.className = child.className.replace("Selected", "");
1135                                 cb.checked = false;
1136                         }
1137                 }               
1138         }
1139 }
1140
1141 function catchupPage() {
1142
1143         var fn = getFeedName(getActiveFeedId(), active_feed_is_cat);
1144         
1145         var str = __("Mark all visible articles in %s as read?");
1146
1147         str = str.replace("%s", fn);
1148
1149         if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
1150                 return;
1151         }
1152
1153         if (document.getElementById("headlinesList")) {
1154                 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', true, 'Unread', true);
1155                 selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
1156                 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
1157         } else {
1158                 cdmSelectArticles('all');
1159                 selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
1160                 cdmSelectArticles('none');
1161         }
1162 }
1163
1164 function catchupSelection() {
1165
1166         try {
1167
1168                 var rows;
1169         
1170                 if (document.getElementById("headlinesList")) {
1171                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1172                 } else {        
1173                         rows = cdmGetSelectedArticles();
1174                 }
1175         
1176                 if (rows.length == 0) {
1177                         alert(__("No articles are selected."));
1178                         return;
1179                 }
1180         
1181         
1182                 var fn = getFeedName(getActiveFeedId(), active_feed_is_cat);
1183                 
1184                 var str = __("Mark %d selected articles in %s as read?");
1185         
1186                 str = str.replace("%d", rows.length);
1187                 str = str.replace("%s", fn);
1188         
1189                 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
1190                         return;
1191                 }
1192         
1193                 if (document.getElementById("headlinesList")) {
1194                         selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
1195         //              selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
1196                 } else {
1197                         selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
1198         //              cdmSelectArticles('none');
1199                 }
1200
1201         } catch (e) {
1202                 exception_error("catchupSelection", e);
1203         }
1204 }
1205
1206
1207 function labelFromSearch(search, search_mode, match_on, feed_id, is_cat) {
1208
1209         if (!xmlhttp_ready(xmlhttp_rpc)) {
1210                 printLockingError();
1211         }
1212
1213         var title = prompt(__("Please enter label title:"), "");
1214
1215         if (title) {
1216
1217                 var query = "backend.php?op=labelFromSearch&search=" + param_escape(search) +
1218                         "&smode=" + param_escape(search_mode) + "&match=" + param_escape(match_on) +
1219                         "&feed=" + param_escape(feed_id) + "&is_cat=" + param_escape(is_cat) + 
1220                         "&title=" + param_escape(title);
1221
1222                 debug("LFS: " + query);
1223
1224                 new Ajax.Request(query, {
1225                         onComplete: function(transport) {
1226                                         dlg_frefresh_callback(transport);
1227                                 } });
1228         }
1229 }
1230
1231 function editArticleTags(id, feed_id, cdm_enabled) {
1232         _tag_active_post_id = id;
1233         _tag_active_feed_id = feed_id;
1234         _tag_active_cdm = cdm_enabled;
1235
1236         cache_invalidate(id);
1237
1238         try {
1239                 _tag_cdm_scroll = document.getElementById("headlinesInnerContainer").scrollTop;
1240         } catch (e) { }
1241         displayDlg('editArticleTags', id);
1242 }
1243
1244
1245 function tag_saved_callback(transport) {
1246         try {
1247                 debug("in tag_saved_callback");
1248
1249                 closeInfoBox();
1250                 notify("");
1251
1252                 if (tagsAreDisplayed()) {
1253                         _reload_feedlist_after_view = true;
1254                 }
1255
1256                 if (!_tag_active_cdm) {
1257                         if (active_post_id == _tag_active_post_id) {
1258                                 debug("reloading current article");
1259                                 view(_tag_active_post_id, _tag_active_feed_id);                 
1260                         }
1261                 } else {
1262                         debug("reloading current feed");
1263                         viewCurrentFeed();
1264                 }
1265
1266         } catch (e) {
1267                 exception_error("catchup_callback", e);
1268         }
1269 }
1270
1271 function editTagsSave() {
1272
1273         notify_progress("Saving article tags...");
1274
1275         var form = document.forms["tag_edit_form"];
1276
1277         var query = Form.serialize("tag_edit_form");
1278
1279         query = "backend.php?op=rpc&subop=setArticleTags&" + query;
1280
1281         debug(query);
1282
1283         new Ajax.Request(query, {
1284                 onComplete: function(transport) {
1285                                 tag_saved_callback(transport);
1286                         } });
1287
1288 }
1289
1290 function editTagsInsert() {
1291         try {
1292
1293                 var form = document.forms["tag_edit_form"];
1294
1295                 var found_tags = form.found_tags;
1296                 var tags_str = form.tags_str;
1297
1298                 var tag = found_tags[found_tags.selectedIndex].value;
1299
1300                 if (tags_str.value.length > 0 && 
1301                                 tags_str.value.lastIndexOf(", ") != tags_str.value.length - 2) {
1302
1303                         tags_str.value = tags_str.value + ", ";
1304                 }
1305
1306                 tags_str.value = tags_str.value + tag + ", ";
1307
1308                 found_tags.selectedIndex = 0;
1309                 
1310         } catch (e) {
1311                 exception_error(e, "editTagsInsert");
1312         }
1313 }
1314
1315 function cdmScrollViewport(where) {
1316         debug("cdmScrollViewport: " + where);
1317
1318         var ctr = document.getElementById("headlinesInnerContainer");
1319
1320         if (!ctr) return;
1321
1322         if (where == "bottom") {
1323                 ctr.scrollTop = ctr.scrollHeight;
1324         } else {
1325                 ctr.scrollTop = where;
1326         }
1327 }
1328
1329 function cdmArticleIsBelowViewport(id) {
1330         try {
1331                 var ctr = document.getElementById("headlinesInnerContainer");
1332                 var e = document.getElementById("RROW-" + id);
1333
1334                 if (!e || !ctr) return;
1335
1336                 // article starts below viewport
1337
1338                 if (ctr.scrollTop < e.offsetTop) {
1339                         return true;
1340                 } else {        
1341                         return false;
1342                 }
1343
1344         } catch (e) {
1345                 exception_error(e, "cdmArticleIsVisible");
1346         }
1347 }
1348
1349 function cdmArticleIsAboveViewport(id) {
1350         try {
1351                 var ctr = document.getElementById("headlinesInnerContainer");
1352                 var e = document.getElementById("RROW-" + id);
1353
1354                 if (!e || !ctr) return;
1355
1356                 // article starts above viewport
1357
1358                 if (ctr.scrollTop > e.offsetTop + e.offsetHeight) {
1359                         return true;
1360                 } else {        
1361                         return false;
1362                 }
1363
1364         } catch (e) {
1365                 exception_error(e, "cdmArticleIsVisible");
1366         }
1367 }
1368
1369 function cdmScrollToArticleId(id) {
1370         try {
1371                 var ctr = document.getElementById("headlinesInnerContainer");
1372                 var e = document.getElementById("RROW-" + id);
1373
1374                 if (!e || !ctr) return;
1375
1376                 ctr.scrollTop = e.offsetTop;
1377
1378         } catch (e) {
1379                 exception_error(e, "cdmScrollToArticleId");
1380         }
1381 }
1382
1383 function cdmArticleIsActuallyVisible(id) {
1384         try {
1385                 var ctr = document.getElementById("headlinesInnerContainer");
1386                 var e = document.getElementById("RROW-" + id);
1387
1388                 if (!e || !ctr) return;
1389
1390                 // article fits in viewport OR article is longer than viewport and
1391                 // its bottom is visible
1392
1393                 if (ctr.scrollTop <= e.offsetTop && e.offsetTop + e.offsetHeight <=
1394                                 ctr.scrollTop + ctr.offsetHeight) {
1395
1396                         return true;
1397                 
1398                 } else if (e.offsetHeight > ctr.offsetHeight &&
1399                                 e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1400                                 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight) {
1401
1402                         return true;
1403
1404                 }
1405
1406                 return false;
1407
1408         } catch (e) {
1409                 exception_error(e, "cdmArticleIsVisible");
1410         }
1411 }
1412
1413 function cdmWatchdog() {
1414
1415         try {
1416
1417                 var ctr = document.getElementById("headlinesInnerContainer");
1418
1419                 if (!ctr) return;
1420
1421                 var ids = new Array();
1422
1423                 var e = ctr.firstChild;
1424
1425                 while (e) {
1426                         if (e.className && e.className == "cdmArticleUnread" && e.id &&
1427                                         e.id.match("RROW-")) {
1428
1429                                 // article fits in viewport OR article is longer than viewport and
1430                                 // its bottom is visible
1431
1432                                 if (ctr.scrollTop <= e.offsetTop && e.offsetTop + e.offsetHeight <=
1433                                                 ctr.scrollTop + ctr.offsetHeight) {
1434
1435 //                                      debug(e.id + " is visible " + e.offsetTop + "." + 
1436 //                                              (e.offsetTop + e.offsetHeight) + " vs " + ctr.scrollTop + "." +
1437 //                                              (ctr.scrollTop + ctr.offsetHeight));
1438
1439                                         ids.push(e.id.replace("RROW-", ""));
1440
1441                                 } else if (e.offsetHeight > ctr.offsetHeight &&
1442                                                 e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1443                                                 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight) {
1444
1445                                         ids.push(e.id.replace("RROW-", "")); 
1446
1447                                 }
1448
1449                                 // method 2: article bottom is visible and is in upper 1/2 of the viewport
1450
1451 /*                              if (e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1452                                                 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight/2) {
1453
1454                                         ids.push(e.id.replace("RROW-", "")); 
1455
1456                                 } */
1457
1458                         }
1459
1460                         e = e.nextSibling;
1461                 }
1462
1463                 debug("cdmWatchdog, ids= " + ids.toString());
1464
1465                 if (ids.length > 0) {
1466
1467                         for (var i = 0; i < ids.length; i++) {
1468                                 var e = document.getElementById("RROW-" + ids[i]);
1469                                 if (e) {
1470                                         e.className = e.className.replace("Unread", "");
1471                                 }
1472                         }
1473
1474                         var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
1475                                 param_escape(ids.toString()) + "&cmode=0";
1476
1477                         new Ajax.Request(query, {
1478                                 onComplete: function(transport) { 
1479                                         all_counters_callback2(transport); 
1480                                 } });
1481
1482                 }
1483
1484                 _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 4000);
1485
1486         } catch (e) {
1487                 exception_error(e, "cdmWatchdog");
1488         }
1489
1490 }
1491
1492
1493 function cache_inject(id, article, param) {
1494         if (!cache_check_param(id, param)) {
1495                 debug("cache_article: miss: " + id + " [p=" + param + "]");
1496
1497                 var cache_obj = new Array();
1498
1499                 cache_obj["id"] = id;
1500                 cache_obj["data"] = article;
1501                 cache_obj["param"] = param;
1502
1503                 article_cache.push(cache_obj);
1504
1505         } else {
1506                 debug("cache_article: hit: " + id + " [p=" + param + "]");
1507         }
1508 }
1509
1510 function cache_find(id) {
1511         for (var i = 0; i < article_cache.length; i++) {
1512                 if (article_cache[i]["id"] == id) {
1513                         return article_cache[i]["data"];
1514                 }
1515         }
1516         return false;
1517 }
1518
1519 function cache_find_param(id, param) {
1520         for (var i = 0; i < article_cache.length; i++) {
1521                 if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
1522                         return article_cache[i]["data"];
1523                 }
1524         }
1525         return false;
1526 }
1527
1528 function cache_check(id) {
1529         for (var i = 0; i < article_cache.length; i++) {
1530                 if (article_cache[i]["id"] == id) {
1531                         return true;
1532                 }
1533         }
1534         return false;
1535 }
1536
1537 function cache_check_param(id, param) {
1538         for (var i = 0; i < article_cache.length; i++) {
1539
1540 //              debug("cache_check_param " + article_cache[i]["id"] + ":" + 
1541 //                      article_cache[i]["param"] + " vs " + id + ":" + param);
1542
1543                 if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
1544                         return true;
1545                 }
1546         }
1547         return false;
1548 }
1549
1550 function cache_expire() {
1551         while (article_cache.length > 20) {
1552                 article_cache.shift();
1553         }
1554 }
1555
1556 function cache_empty() {
1557         article_cache = new Array();
1558 }
1559
1560 function cache_invalidate(id) {
1561         var i = 0
1562
1563         try {   
1564
1565                 while (i < article_cache.length) {
1566                         if (article_cache[i]["id"] == id) {
1567                                 debug("cache_invalidate: removed id " + id);
1568                                 article_cache.splice(i, 1);
1569                                 return true;
1570                         }
1571                         i++;
1572                 }
1573                 debug("cache_invalidate: id not found: " + id);
1574                 return false;
1575         } catch (e) {
1576                 exception_error("cache_invalidate", e);
1577         }
1578 }
1579
1580 function getActiveArticleId() {
1581         return active_post_id;
1582 }
1583
1584 function cdmClicked(elem) {
1585         try {
1586                 if (elem.id && elem.id.match("RROW-")) {
1587                         var id = elem.id.replace("RROW-", "");
1588                         active_post_id = id;
1589
1590                         cdmSelectArticles("none");
1591                         toggleSelected(id);
1592
1593                 }
1594         } catch (e) {
1595                 exception_error("cdmMouseIn", e);
1596         } 
1597 }
1598
1599 function cdmMouseIn(elem) {
1600 /*      try {
1601                 if (elem.id && elem.id.match("RROW-")) {
1602                         var id = elem.id.replace("RROW-", "");
1603                         active_post_id = id;
1604                 }
1605         } catch (e) {
1606                 exception_error("cdmMouseIn", e);
1607         } */
1608 }
1609
1610 function cdmMouseOut(elem) {
1611         //active_post_id = false;
1612 }
1613
1614 function headlines_scroll_handler() {
1615         try {
1616
1617                 var e = document.getElementById("headlinesInnerContainer");
1618
1619                 // don't do infinite scrolling when Limit == All
1620
1621                 var toolbar_form = document.forms["main_toolbar_form"];
1622
1623                 var limit = toolbar_form.limit[toolbar_form.limit.selectedIndex];
1624                 if (limit.value != 0) {
1625                 
1626                         debug((e.scrollTop + e.offsetHeight) + " vs " + e.scrollHeight + " dis? " +
1627                                 _infscroll_disable);
1628
1629                         if (e.scrollTop + e.offsetHeight > e.scrollHeight - 100) {
1630                                 if (!_infscroll_disable) {
1631                                         debug("more cowbell!");
1632                                         viewNextFeedPage();
1633                                 }
1634                         }
1635                 }
1636
1637         } catch (e) {
1638                 exception_error("headlines_scroll_handler", e);
1639         }
1640 }
1641
1642 function catchupRelativeToArticle(below) {
1643
1644         try {
1645
1646                 if (!xmlhttp_ready(xmlhttp_rpc)) {
1647                         printLockingError();
1648                 }
1649         
1650                 if (!getActiveArticleId()) {
1651                         alert(__("No article is selected."));
1652                         return;
1653                 }
1654
1655                 var visible_ids;
1656
1657                 if (document.getElementById("headlinesList")) {
1658                         visible_ids = getVisibleHeadlineIds();
1659                 } else {
1660                         visible_ids = cdmGetVisibleArticles();
1661                 }
1662
1663                 var ids_to_mark = new Array();
1664
1665                 if (!below) {
1666                         for (var i = 0; i < visible_ids.length; i++) {
1667                                 if (visible_ids[i] != getActiveArticleId()) {
1668                                         var e = document.getElementById("RROW-" + visible_ids[i]);
1669
1670                                         if (e && e.className.match("Unread")) {
1671                                                 ids_to_mark.push(visible_ids[i]);
1672                                         }
1673                                 } else {
1674                                         break;
1675                                 }
1676                         }
1677                 } else {
1678                         for (var i = visible_ids.length-1; i >= 0; i--) {
1679                                 if (visible_ids[i] != getActiveArticleId()) {
1680                                         var e = document.getElementById("RROW-" + visible_ids[i]);
1681
1682                                         if (e && e.className.match("Unread")) {
1683                                                 ids_to_mark.push(visible_ids[i]);
1684                                         }
1685                                 } else {
1686                                         break;
1687                                 }
1688                         }
1689                 }
1690
1691                 if (ids_to_mark.length == 0) {
1692                         alert(__("No articles found to mark"));
1693                 } else {
1694                         var msg = __("Mark %d article(s) as read?").replace("%d", ids_to_mark.length);
1695
1696                         if (confirm(msg)) {
1697
1698                                 for (var i = 0; i < ids_to_mark.length; i++) {
1699                                         var e = document.getElementById("RROW-" + ids_to_mark[i]);
1700                                         e.className = e.className.replace("Unread", "");
1701                                 }
1702
1703                                 var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
1704                                         param_escape(ids_to_mark.toString()) + "&cmode=0";
1705
1706                                 new Ajax.Request(query, {
1707                                         onComplete: function(transport) { 
1708                                                 catchup_callback2(transport); 
1709                                         } });
1710
1711                         }
1712                 }
1713
1714         } catch (e) {
1715                 exception_error("catchupRelativeToArticle", e);
1716         }
1717 }
1718
1719 function cdmExpandArticle(a_id) {
1720         try {
1721                 var id = 'CICD-' + a_id;
1722
1723                 Effect.Appear(id, {duration : 0.5, 
1724                         beforeStart: function(effect) { 
1725                                 var h_id = 'CICH-' + a_id;
1726                                 var h_elem = document.getElementById(h_id);
1727                                 if (h_elem) { h_elem.style.display = "none"; }
1728
1729                                 toggleUnread(a_id, 0);
1730                         }});
1731
1732
1733         } catch (e) {
1734                 exception_error("appearBlockElementF", e);
1735         }
1736
1737 }
1738
1739 function fixHeadlinesOrder(ids) {
1740         try {
1741                 for (var i = 0; i < ids.length; i++) {
1742                         var e = document.getElementById("RROW-" + ids[i]);
1743
1744                         if (e) {
1745                                 if (i % 2 == 0) {
1746                                         e.className = e.className.replace("even", "odd");
1747                                 } else {
1748                                         e.className = e.className.replace("odd", "even");
1749                                 }
1750                         }
1751                 }
1752         } catch (e) {
1753                 exception_error("fixHeadlinesOrder", e);
1754         }
1755 }
1756
1757 function subtoolbarSearch() {
1758
1759         try {
1760
1761                 var q = document.getElementById("subtoolbar_search_box");
1762                 
1763                 if (!q) return;
1764
1765                 q = q.value.toUpperCase();
1766
1767                 var ids = false;
1768                 var vis_ids = new Array();
1769
1770                 if (document.getElementById("headlinesList")) {
1771                         ids = getVisibleHeadlineIds();
1772                 } else {
1773                         ids = cdmGetVisibleArticles();
1774                 }
1775
1776                 for (var i = 0; i < ids.length; i++) {
1777                         var title = document.getElementById("RTITLE-" + ids[i]);
1778
1779                         if (title) {
1780                                 if (!title.innerHTML.toUpperCase().match(q)) {
1781                                         Element.hide(document.getElementById("RROW-" + ids[i]));
1782                                 } else {
1783                                         Element.show(document.getElementById("RROW-" + ids[i]));
1784                                         vis_ids.push(ids[i]);
1785                                 }
1786                         }
1787                 }
1788
1789                 fixHeadlinesOrder(vis_ids);
1790
1791         } catch (e) {
1792                 exception_error("subtoolbarSearch", e);
1793         }
1794
1795 }