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