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