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