]> git.wh0rd.org Git - tt-rss.git/blob - viewfeed.js
do not try to process missing article categories
[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         try {
378
379                 if (!xmlhttp_ready(xmlhttp_rpc)) {
380                         printLockingError();
381                         return;
382                 }
383         
384                 var query = "backend.php?op=rpc&id=" + id + "&subop=mark";
385         
386                 query = query + "&afid=" + getActiveFeedId();
387         
388                 if (tagsAreDisplayed()) {
389                         query = query + "&omode=tl";
390                 } else {
391                         query = query + "&omode=flc";
392                 }
393         
394                 var mark_img = document.getElementById("FMPIC-" + id);
395                 var vfeedu = document.getElementById("FEEDU--1");
396                 var crow = document.getElementById("RROW-" + id);
397         
398                 if (mark_img.alt != "Reset mark") {
399                         mark_img.src = "images/mark_set.png";
400                         mark_img.alt = "Reset mark";
401                         query = query + "&mark=1";
402         
403 /*                      if (vfeedu && crow.className.match("Unread")) {
404                                 vfeedu.innerHTML = (+vfeedu.innerHTML) + 1;
405                         } */
406         
407                 } else {
408                         //mark_img.src = "images/mark_unset.png";
409                         mark_img.alt = "Please wait...";
410                         query = query + "&mark=0";
411         
412 /*                      if (vfeedu && crow.className.match("Unread")) {
413                                 vfeedu.innerHTML = (+vfeedu.innerHTML) - 1;
414                         } */
415         
416                         if (document.getElementById("headlinesList")) {
417                                 Effect.Puff(mark_img, {duration : 0.25, afterFinish: tMark_afh_off});
418                         } else { 
419                                 mark_img.src = "images/mark_unset.png";
420                                 mark_img.alt = "Set mark";
421                         }
422                 }
423         
424 /*              var vfeedctr = document.getElementById("FEEDCTR--1");
425                 var vfeedr = document.getElementById("FEEDR--1");
426         
427                 if (vfeedu && vfeedctr) {
428                         if ((+vfeedu.innerHTML) > 0) {
429                                 if (crow.className.match("Unread") && !vfeedr.className.match("Unread")) {
430                                         vfeedr.className = vfeedr.className + "Unread";
431                                         vfeedctr.className = "odd";
432                                 }
433                         } else {
434                                 vfeedctr.className = "invisible";
435                                 vfeedr.className = vfeedr.className.replace("Unread", "");
436                         }
437                 }
438         
439                 debug("toggle starred for aid " + id);
440         
441                 //new Ajax.Request(query); */
442
443                 debug(query);
444
445                 xmlhttp_rpc.open("GET", query, true);
446                 xmlhttp_rpc.onreadystatechange=all_counters_callback;
447                 xmlhttp_rpc.send(null);
448
449         } catch (e) {
450                 exception_error("toggleMark", e);
451         }
452 }
453
454 function togglePub(id) {
455
456         try {
457
458                 if (!xmlhttp_ready(xmlhttp_rpc)) {
459                         printLockingError();
460                         return;
461                 }
462         
463                 var query = "backend.php?op=rpc&id=" + id + "&subop=publ";
464         
465                 query = query + "&afid=" + getActiveFeedId();
466         
467                 if (tagsAreDisplayed()) {
468                         query = query + "&omode=tl";
469                 } else {
470                         query = query + "&omode=flc";
471                 }
472         
473                 var mark_img = document.getElementById("FPPIC-" + id);
474                 var vfeedu = document.getElementById("FEEDU--2");
475                 var crow = document.getElementById("RROW-" + id);
476         
477                 if (mark_img.alt != "Unpublish") {
478                         mark_img.src = "images/pub_set.png";
479                         mark_img.alt = "Unpublish";
480                         query = query + "&pub=1";
481         
482 /*                      if (vfeedu && crow.className.match("Unread")) {
483                                 vfeedu.innerHTML = (+vfeedu.innerHTML) + 1;
484                         } */
485         
486                 } else {
487                         //mark_img.src = "images/pub_unset.png";
488                         mark_img.alt = "Please wait...";
489                         query = query + "&pub=0";
490         
491 /*                      if (vfeedu && crow.className.match("Unread")) {
492                                 vfeedu.innerHTML = (+vfeedu.innerHTML) - 1;
493                         } */
494
495                         if (document.getElementById("headlinesList")) {
496                                 Effect.Puff(mark_img, {duration : 0.25, afterFinish: tPub_afh_off});
497                         } else { 
498                                 mark_img.src = "images/pub_unset.png";
499                                 mark_img.alt = "Publish";
500                         }
501                 }
502         
503 /*              var vfeedctr = document.getElementById("FEEDCTR--2");
504                 var vfeedr = document.getElementById("FEEDR--2");
505         
506                 if (vfeedu && vfeedctr) {
507                         if ((+vfeedu.innerHTML) > 0) {
508                                 if (crow.className.match("Unread") && !vfeedr.className.match("Unread")) {
509                                         vfeedr.className = vfeedr.className + "Unread";
510                                         vfeedctr.className = "odd";
511                                 }
512                         } else {
513                                 vfeedctr.className = "invisible";
514                                 vfeedr.className = vfeedr.className.replace("Unread", "");
515                         }
516                 }
517         
518                 debug("toggle published for aid " + id);
519         
520                 new Ajax.Request(query); */
521
522                 xmlhttp_rpc.open("GET", query, true);
523                 xmlhttp_rpc.onreadystatechange=all_counters_callback;
524                 xmlhttp_rpc.send(null);
525
526         } catch (e) {
527
528                 exception_error("togglePub", e);
529         }
530 }
531
532 function correctHeadlinesOffset(id) {
533         
534         try {
535
536                 var hlist = document.getElementById("headlinesList");
537                 var container = document.getElementById("headlinesInnerContainer");
538                 var row = document.getElementById("RROW-" + id);
539         
540                 var viewport = container.offsetHeight;
541         
542                 var rel_offset_top = row.offsetTop - container.scrollTop;
543                 var rel_offset_bottom = row.offsetTop + row.offsetHeight - container.scrollTop;
544         
545                 debug("Rtop: " + rel_offset_top + " Rbtm: " + rel_offset_bottom);
546                 debug("Vport: " + viewport);
547
548                 if (rel_offset_top <= 0 || rel_offset_top > viewport) {
549                         container.scrollTop = row.offsetTop;
550                 } else if (rel_offset_bottom > viewport) {
551
552                         /* doesn't properly work with Opera in some cases because
553                                 Opera fucks up element scrolling */
554
555                         container.scrollTop = row.offsetTop + row.offsetHeight - viewport;              
556                 } 
557
558         } catch (e) {
559                 exception_error("correctHeadlinesOffset", e);
560         }
561
562 }
563
564 function moveToPost(mode) {
565
566         // check for combined mode
567         if (!document.getElementById("headlinesList"))
568                 return;
569
570         var rows = getVisibleHeadlineIds();
571
572         var prev_id = false;
573         var next_id = false;
574
575         if (!document.getElementById('RROW-' + active_post_id)) {
576                 active_post_id = false;
577         }
578
579         if (active_post_id == false) {
580                 next_id = getFirstVisibleHeadlineId();
581                 prev_id = getLastVisibleHeadlineId();
582         } else {        
583                 for (var i = 0; i < rows.length; i++) {
584                         if (rows[i] == active_post_id) {
585                                 prev_id = rows[i-1];
586                                 next_id = rows[i+1];                    
587                         }
588                 }
589         }
590
591         if (mode == "next") {
592                 if (next_id) {
593                         correctHeadlinesOffset(next_id);
594                         view(next_id, getActiveFeedId());
595                 }
596         }
597
598         if (mode == "prev") {
599                 if (prev_id) {
600                         correctHeadlinesOffset(prev_id);
601                         view(prev_id, getActiveFeedId());
602                 }
603         } 
604 }
605
606 function toggleUnread(id, cmode) {
607         try {
608                 if (!xmlhttp_ready(xmlhttp_rpc)) {
609                         printLockingError();
610                         return;
611                 }
612         
613                 var row = document.getElementById("RROW-" + id);
614                 if (row) {
615                         var nc = row.className;
616                         nc = nc.replace("Unread", "");
617                         nc = nc.replace("Selected", "");
618
619                         if (row.className.match("Unread")) {
620                                 row.className = nc;
621                         } else {
622                                 row.className = nc + "Unread";
623                         }
624
625                         if (!cmode) cmode = 2;
626
627                         var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
628                                 param_escape(id) + "&cmode=" + param_escape(cmode);
629
630                         notify_progress("Loading, please wait...");
631
632                         xmlhttp_rpc.open("GET", query, true);
633                         xmlhttp_rpc.onreadystatechange=all_counters_callback;
634                         xmlhttp_rpc.send(null);
635
636                 }
637
638
639         } catch (e) {
640                 exception_error("toggleUnread", e);
641         }
642 }
643
644 function selectionToggleUnread(cdm_mode, set_state, callback_func, no_error) {
645         try {
646                 if (!xmlhttp_ready(xmlhttp_rpc)) {
647                         printLockingError();
648                         return;
649                 }
650         
651                 var rows;
652
653                 if (cdm_mode) {
654                         rows = cdmGetSelectedArticles();
655                 } else {        
656                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
657                 }
658
659                 if (rows.length == 0 && !no_error) {
660                         alert(__("No articles are selected."));
661                         return;
662                 }
663
664                 for (i = 0; i < rows.length; i++) {
665                         var row = document.getElementById("RROW-" + rows[i]);
666                         if (row) {
667                                 var nc = row.className;
668                                 nc = nc.replace("Unread", "");
669                                 nc = nc.replace("Selected", "");
670
671                                 if (set_state == undefined) {
672                                         if (row.className.match("Unread")) {
673                                                 row.className = nc + "Selected";
674                                         } else {
675                                                 row.className = nc + "UnreadSelected";
676                                         }
677                                 }
678
679                                 if (set_state == false) {
680                                         row.className = nc + "Selected";
681                                 }
682
683                                 if (set_state == true) {
684                                         row.className = nc + "UnreadSelected";
685                                 }
686                         }
687                 }
688
689                 if (rows.length > 0) {
690
691                         var cmode = "";
692
693                         if (set_state == undefined) {
694                                 cmode = "2";
695                         } else if (set_state == true) {
696                                 cmode = "1";
697                         } else if (set_state == false) {
698                                 cmode = "0";
699                         }
700
701                         var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
702                                 param_escape(rows.toString()) + "&cmode=" + cmode;
703
704                         _catchup_callback_func = callback_func;
705
706                         notify_progress("Loading, please wait...");
707
708                         xmlhttp_rpc.open("GET", query, true);
709                         xmlhttp_rpc.onreadystatechange=catchup_callback;
710                         xmlhttp_rpc.send(null);
711
712                 }
713
714         } catch (e) {
715                 exception_error("selectionToggleUnread", e);
716         }
717 }
718
719 function selectionToggleMarked(cdm_mode) {
720         try {
721                 if (!xmlhttp_ready(xmlhttp_rpc)) {
722                         printLockingError();
723                         return;
724                 }
725         
726                 var rows;
727                 
728                 if (cdm_mode) {
729                         rows = cdmGetSelectedArticles();
730                 } else {        
731                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
732                 }       
733
734                 if (rows.length == 0) {
735                         alert(__("No articles are selected."));
736                         return;
737                 }
738
739                 for (i = 0; i < rows.length; i++) {
740                         var row = document.getElementById("RROW-" + rows[i]);
741                         var mark_img = document.getElementById("FMPIC-" + rows[i]);
742
743                         if (row && mark_img) {
744
745                                 if (mark_img.alt == "Set mark") {
746                                         mark_img.src = "images/mark_set.png";
747                                         mark_img.alt = "Reset mark";
748                                         //mark_img.setAttribute('onclick', 
749                                         //      'javascript:toggleMark('+rows[i]+', false)');
750                 
751                                 } else {
752                                         mark_img.src = "images/mark_unset.png";
753                                         mark_img.alt = "Set mark";
754
755                                         //mark_img.alt = "Please wait...";
756
757                                         //mark_img.setAttribute('onclick', 
758                                         //      'javascript:toggleMark('+rows[i]+', true)');
759
760                                         //Effect.Puff(mark_img, {duration : 0.25, afterFinish: tMark_afh_off});
761
762                                 }
763                         }
764                 }
765
766                 if (rows.length > 0) {
767
768                         var query = "backend.php?op=rpc&subop=markSelected&ids=" +
769                                 param_escape(rows.toString()) + "&cmode=2";
770
771                         query = query + "&afid=" + getActiveFeedId();
772
773                         if (tagsAreDisplayed()) {
774                                 query = query + "&omode=tl";
775                         } else {
776                                 query = query + "&omode=flc";
777                         }
778
779                         xmlhttp_rpc.open("GET", query, true);
780                         xmlhttp_rpc.onreadystatechange=all_counters_callback;
781                         xmlhttp_rpc.send(null);
782
783                 }
784
785         } catch (e) {
786                 exception_error("selectionToggleMarked", e);
787         }
788 }
789
790 function selectionTogglePublished(cdm_mode) {
791         try {
792                 if (!xmlhttp_ready(xmlhttp_rpc)) {
793                         printLockingError();
794                         return;
795                 }
796         
797                 var rows;
798                 
799                 if (cdm_mode) {
800                         rows = cdmGetSelectedArticles();
801                 } else {        
802                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
803                 }       
804
805                 if (rows.length == 0) {
806                         alert(__("No articles are selected."));
807                         return;
808                 }
809
810                 for (i = 0; i < rows.length; i++) {
811                         var row = document.getElementById("RROW-" + rows[i]);
812                         var mark_img = document.getElementById("FPPIC-" + rows[i]);
813
814                         if (row && mark_img) {
815
816                                 if (mark_img.alt == "Publish") {
817                                         mark_img.src = "images/pub_set.png";
818                                         mark_img.alt = "Unpublish";
819 //                                      mark_img.setAttribute('onclick', 
820 //                                              'javascript:togglePub('+rows[i]+', false)');
821
822                                 } else {
823                                         mark_img.src = "images/pub_unset.png";
824                                         mark_img.alt = "Publish";
825 //                                      mark_img.setAttribute('onclick', 
826 //                                              'javascript:togglePub('+rows[i]+', true)');
827
828 //                                      Effect.Puff(mark_img, {duration : 0.25, afterFinish: tPub_afh_off});
829
830                                 }
831                         }
832                 }
833
834                 if (rows.length > 0) {
835
836                         var query = "backend.php?op=rpc&subop=publishSelected&ids=" +
837                                 param_escape(rows.toString()) + "&cmode=2";
838
839                         query = query + "&afid=" + getActiveFeedId();
840
841                         if (tagsAreDisplayed()) {
842                                 query = query + "&omode=tl";
843                         } else {
844                                 query = query + "&omode=flc";
845                         }
846
847                         xmlhttp_rpc.open("GET", query, true);
848                         xmlhttp_rpc.onreadystatechange=all_counters_callback;
849                         xmlhttp_rpc.send(null);
850
851                 }
852
853         } catch (e) {
854                 exception_error("selectionToggleMarked", e);
855         }
856 }
857
858 function cdmGetSelectedArticles() {
859         var sel_articles = new Array();
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-") && child.className.match("Selected")) {
866                         var c_id = child.id.replace("RROW-", "");
867                         sel_articles.push(c_id);
868                 }
869         }
870
871         return sel_articles;
872 }
873
874 function cdmGetVisibleArticles() {
875         var sel_articles = new Array();
876         var container = document.getElementById("headlinesInnerContainer");
877
878         for (i = 0; i < container.childNodes.length; i++) {
879                 var child = container.childNodes[i];
880
881                 if (child.id.match("RROW-")) {
882                         var c_id = child.id.replace("RROW-", "");
883                         sel_articles.push(c_id);
884                 }
885         }
886
887         return sel_articles;
888 }
889
890 function cdmGetUnreadArticles() {
891         var sel_articles = new Array();
892         var container = document.getElementById("headlinesInnerContainer");
893
894         for (i = 0; i < container.childNodes.length; i++) {
895                 var child = container.childNodes[i];
896
897                 if (child.id.match("RROW-") && child.className.match("Unread")) {
898                         var c_id = child.id.replace("RROW-", "");
899                         sel_articles.push(c_id);
900                 }
901         }
902
903         return sel_articles;
904 }
905
906
907 // mode = all,none,unread
908 function cdmSelectArticles(mode) {
909         var container = document.getElementById("headlinesInnerContainer");
910
911         for (i = 0; i < container.childNodes.length; i++) {
912                 var child = container.childNodes[i];
913
914                 if (child.id.match("RROW-")) {
915                         var aid = child.id.replace("RROW-", "");
916
917                         var cb = document.getElementById("RCHK-" + aid);
918
919                         if (mode == "all") {
920                                 if (!child.className.match("Selected")) {
921                                         child.className = child.className + "Selected";
922                                         cb.checked = true;
923                                 }
924                         } else if (mode == "unread") {
925                                 if (child.className.match("Unread") && !child.className.match("Selected")) {
926                                         child.className = child.className + "Selected";
927                                         cb.checked = true;
928                                 }
929                         } else {
930                                 child.className = child.className.replace("Selected", "");
931                                 cb.checked = false;
932                         }
933                 }               
934         }
935 }
936
937 function catchupPage() {
938
939         var fn = getFeedName(getActiveFeedId(), active_feed_is_cat);
940         
941         var str = __("Mark all visible articles in %s as read?");
942
943         str = str.replace("%s", fn);
944
945         if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
946                 return;
947         }
948
949         if (document.getElementById("headlinesList")) {
950                 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', true, 'Unread', true);
951                 selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
952                 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
953         } else {
954                 cdmSelectArticles('all');
955                 selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
956                 cdmSelectArticles('none');
957         }
958 }
959
960 function catchupSelection() {
961
962         try {
963
964                 var rows;
965         
966                 if (document.getElementById("headlinesList")) {
967                         rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
968                 } else {        
969                         rows = cdmGetSelectedArticles();
970                 }
971         
972                 if (rows.length == 0) {
973                         alert(__("No articles are selected."));
974                         return;
975                 }
976         
977         
978                 var fn = getFeedName(getActiveFeedId(), active_feed_is_cat);
979                 
980                 var str = __("Mark all selected articles in %s as read?");
981         
982                 str = str.replace("%s", fn);
983         
984                 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
985                         return;
986                 }
987         
988                 if (document.getElementById("headlinesList")) {
989                         selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
990         //              selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
991                 } else {
992                         selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
993         //              cdmSelectArticles('none');
994                 }
995
996         } catch (e) {
997                 exception_error("catchupSelection", e);
998         }
999 }
1000
1001
1002 function labelFromSearch(search, search_mode, match_on, feed_id, is_cat) {
1003
1004         if (!xmlhttp_ready(xmlhttp_rpc)) {
1005                 printLockingError();
1006         }
1007
1008         var title = prompt(__("Please enter label title:"), "");
1009
1010         if (title) {
1011
1012                 var query = "backend.php?op=labelFromSearch&search=" + param_escape(search) +
1013                         "&smode=" + param_escape(search_mode) + "&match=" + param_escape(match_on) +
1014                         "&feed=" + param_escape(feed_id) + "&is_cat=" + param_escape(is_cat) + 
1015                         "&title=" + param_escape(title);
1016
1017                 debug("LFS: " + query);
1018         
1019                 xmlhttp_rpc.open("GET", query, true);
1020                 xmlhttp_rpc.onreadystatechange=dlg_frefresh_callback;
1021                 xmlhttp_rpc.send(null);
1022         }
1023
1024 }
1025
1026 function editArticleTags(id, feed_id, cdm_enabled) {
1027         _tag_active_post_id = id;
1028         _tag_active_feed_id = feed_id;
1029         _tag_active_cdm = cdm_enabled;
1030
1031         cache_invalidate(id);
1032
1033         try {
1034                 _tag_cdm_scroll = document.getElementById("headlinesInnerContainer").scrollTop;
1035         } catch (e) { }
1036         displayDlg('editArticleTags', id);
1037 }
1038
1039
1040 function tag_saved_callback() {
1041         if (xmlhttp_rpc.readyState == 4) {
1042                 try {
1043                         debug("in tag_saved_callback");
1044
1045                         closeInfoBox();
1046                         notify("");
1047
1048                         if (tagsAreDisplayed()) {
1049                                 _reload_feedlist_after_view = true;
1050                         }
1051
1052                         if (!_tag_active_cdm) {
1053                                 if (active_post_id == _tag_active_post_id) {
1054                                         debug("reloading current article");
1055                                         view(_tag_active_post_id, _tag_active_feed_id);                 
1056                                 }
1057                         } else {
1058                                 debug("reloading current feed");
1059                                 viewCurrentFeed();
1060                         }
1061
1062                 } catch (e) {
1063                         exception_error("catchup_callback", e);
1064                 }
1065         }
1066 }
1067
1068 function editTagsSave() {
1069
1070         if (!xmlhttp_ready(xmlhttp_rpc)) {
1071                 printLockingError();
1072         }
1073
1074         notify_progress("Saving article tags...");
1075
1076         var form = document.forms["tag_edit_form"];
1077
1078         var query = Form.serialize("tag_edit_form");
1079
1080         query = "backend.php?op=rpc&subop=setArticleTags&" + query;
1081
1082         debug(query);
1083
1084         xmlhttp_rpc.open("GET", query, true);                   
1085         xmlhttp_rpc.onreadystatechange=tag_saved_callback;
1086         xmlhttp_rpc.send(null);
1087
1088 }
1089
1090 function editTagsInsert() {
1091         try {
1092
1093                 var form = document.forms["tag_edit_form"];
1094
1095                 var found_tags = form.found_tags;
1096                 var tags_str = form.tags_str;
1097
1098                 var tag = found_tags[found_tags.selectedIndex].value;
1099
1100                 if (tags_str.value.length > 0 && 
1101                                 tags_str.value.lastIndexOf(", ") != tags_str.value.length - 2) {
1102
1103                         tags_str.value = tags_str.value + ", ";
1104                 }
1105
1106                 tags_str.value = tags_str.value + tag + ", ";
1107
1108                 found_tags.selectedIndex = 0;
1109                 
1110         } catch (e) {
1111                 exception_error(e, "editTagsInsert");
1112         }
1113 }
1114
1115 function cdmWatchdog() {
1116
1117         try {
1118
1119                 var ctr = document.getElementById("headlinesInnerContainer");
1120
1121                 if (!ctr) return;
1122
1123                 var ids = new Array();
1124
1125                 var e = ctr.firstChild;
1126
1127                 while (e) {
1128                         if (e.className && e.className == "cdmArticleUnread" && e.id &&
1129                                         e.id.match("RROW-")) {
1130
1131                                 // article fits in viewport OR article is longer than viewport and
1132                                 // its bottom is visible
1133
1134                                 if (ctr.scrollTop <= e.offsetTop && e.offsetTop + e.offsetHeight <=
1135                                                 ctr.scrollTop + ctr.offsetHeight) {
1136
1137 //                                      debug(e.id + " is visible " + e.offsetTop + "." + 
1138 //                                              (e.offsetTop + e.offsetHeight) + " vs " + ctr.scrollTop + "." +
1139 //                                              (ctr.scrollTop + ctr.offsetHeight));
1140
1141                                         ids.push(e.id.replace("RROW-", ""));
1142
1143                                 } else if (e.offsetHeight > ctr.offsetHeight &&
1144                                                 e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1145                                                 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight) {
1146
1147                                         ids.push(e.id.replace("RROW-", "")); 
1148
1149                                 }
1150
1151                                 // method 2: article bottom is visible and is in upper 1/2 of the viewport
1152
1153 /*                              if (e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1154                                                 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight/2) {
1155
1156                                         ids.push(e.id.replace("RROW-", "")); 
1157
1158                                 } */
1159
1160                         }
1161
1162                         e = e.nextSibling;
1163                 }
1164
1165                 debug("cdmWatchdog, ids= " + ids.toString());
1166
1167                 if (ids.length > 0 && xmlhttp_ready(xmlhttp_rpc)) {
1168
1169                         for (var i = 0; i < ids.length; i++) {
1170                                 var e = document.getElementById("RROW-" + ids[i]);
1171                                 if (e) {
1172                                         e.className = e.className.replace("Unread", "");
1173                                 }
1174                         }
1175
1176                         var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
1177                                 param_escape(ids.toString()) + "&cmode=0";
1178
1179                         xmlhttp_rpc.open("GET", query, true);
1180                         xmlhttp_rpc.onreadystatechange=all_counters_callback;
1181                         xmlhttp_rpc.send(null); 
1182
1183                 }
1184
1185                 _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 4000);
1186
1187         } catch (e) {
1188                 exception_error(e, "cdmWatchdog");
1189         }
1190
1191 }
1192
1193
1194 function cache_inject(id, article) {
1195         if (!cache_check(id)) {
1196                 debug("cache_article: miss: " + id);
1197
1198                 var cache_obj = new Array();
1199
1200                 cache_obj["id"] = id;
1201                 cache_obj["data"] = article;
1202
1203                 article_cache.push(cache_obj);
1204
1205         } else {
1206                 debug("cache_article: hit: " + id);
1207         }
1208 }
1209
1210 function cache_find(id) {
1211         for (var i = 0; i < article_cache.length; i++) {
1212                 if (article_cache[i]["id"] == id) {
1213                         return article_cache[i]["data"];
1214                 }
1215         }
1216         return false;
1217 }
1218
1219 function cache_check(id) {
1220         for (var i = 0; i < article_cache.length; i++) {
1221                 if (article_cache[i]["id"] == id) {
1222                         return true;
1223                 }
1224         }
1225         return false;
1226 }
1227
1228 function cache_expire() {
1229         while (article_cache.length > 20) {
1230                 article_cache.shift();
1231         }
1232 }
1233
1234 function cache_invalidate(id) {
1235         var i = 0
1236
1237         try {   
1238
1239                 while (i < article_cache.length) {
1240                         if (article_cache[i]["id"] == id) {
1241                                 debug("cache_invalidate: removed id " + id);
1242                                 article_cache.splice(i, 1);
1243                                 return true;
1244                         }
1245                         i++;
1246                 }
1247                 debug("cache_invalidate: id not found: " + id);
1248                 return false;
1249         } catch (e) {
1250                 exception_error("cache_invalidate", e);
1251         }
1252 }
1253
1254 function getActiveArticleId() {
1255         return active_post_id;
1256 }
1257
1258 function cdmMouseIn(elem) {
1259         try {
1260                 if (elem.id && elem.id.match("RROW-")) {
1261                         var id = elem.id.replace("RROW-", "");
1262                         active_post_id = id;
1263                 }
1264         } catch (e) {
1265                 exception_error("cdmMouseIn", e);
1266         }
1267
1268 }
1269
1270 function cdmMouseOut(elem) {
1271         active_post_id = false;
1272 }
1273
1274 function headlines_scroll_handler() {
1275         try {
1276
1277                 var e = document.getElementById("headlinesInnerContainer");
1278
1279                 if (e.scrollTop + e.offsetHeight > e.scrollHeight - 300) {
1280                         debug("more cowbell!");
1281
1282                         viewNextFeedPage();
1283                 }
1284
1285         } catch (e) {
1286                 exception_error("headlines_scroll_handler", e);
1287         }
1288 }
1289
1290 function catchupRelativeToArticle(below) {
1291
1292         try {
1293
1294                 if (!xmlhttp_ready(xmlhttp_rpc)) {
1295                         printLockingError();
1296                 }
1297         
1298                 if (!getActiveArticleId()) {
1299                         alert(__("No article is selected."));
1300                         return;
1301                 }
1302
1303                 var visible_ids;
1304
1305                 if (document.getElementById("headlinesList")) {
1306                         visible_ids = getVisibleHeadlineIds();
1307                 } else {
1308                         visible_ids = cdmGetVisibleArticles();
1309                 }
1310
1311                 var ids_to_mark = new Array();
1312
1313                 if (!below) {
1314                         for (var i = 0; i < visible_ids.length; i++) {
1315                                 if (visible_ids[i] != getActiveArticleId()) {
1316                                         var e = document.getElementById("RROW-" + visible_ids[i]);
1317
1318                                         if (e && e.className.match("Unread")) {
1319                                                 ids_to_mark.push(visible_ids[i]);
1320                                         }
1321                                 } else {
1322                                         break;
1323                                 }
1324                         }
1325                 } else {
1326                         for (var i = visible_ids.length-1; i >= 0; i--) {
1327                                 if (visible_ids[i] != getActiveArticleId()) {
1328                                         var e = document.getElementById("RROW-" + visible_ids[i]);
1329
1330                                         if (e && e.className.match("Unread")) {
1331                                                 ids_to_mark.push(visible_ids[i]);
1332                                         }
1333                                 } else {
1334                                         break;
1335                                 }
1336                         }
1337                 }
1338
1339                 if (ids_to_mark.length == 0) {
1340                         alert(__("No articles found to mark"));
1341                 } else {
1342                         var msg = __("Mark %d article(s) as read?").replace("%d", ids_to_mark.length);
1343
1344                         if (confirm(msg)) {
1345
1346                                 for (var i = 0; i < ids_to_mark.length; i++) {
1347                                         var e = document.getElementById("RROW-" + ids_to_mark[i]);
1348                                         e.className = e.className.replace("Unread", "");
1349                                 }
1350
1351                                 var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
1352                                         param_escape(ids_to_mark.toString()) + "&cmode=0";
1353
1354                                 xmlhttp_rpc.open("GET", query, true);
1355                                 xmlhttp_rpc.onreadystatechange=catchup_callback;
1356                                 xmlhttp_rpc.send(null);
1357         
1358                         }
1359                 }
1360
1361         } catch (e) {
1362                 exception_error("catchupRelativeToArticle", e);
1363         }
1364 }