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