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