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