]> git.wh0rd.org - tt-rss.git/blob - viewfeed.js
code cleanup
[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 // FIXME: kludges, needs proper implementation
6 var _reload_feedlist_after_view = false;
7
8 var _cdm_wd_timeout = false;
9 var _cdm_wd_vishist = new Array();
10
11 var article_cache = new Array();
12
13 var vgroup_last_feed = false;
14 var post_under_pointer = false;
15
16 var last_requested_article = false;
17
18 function catchup_callback2(transport, callback) {
19 try {
20 debug("catchup_callback2 " + transport + ", " + callback);
21 notify("");
22 all_counters_callback2(transport);
23 if (callback) {
24 setTimeout(callback, 10);
25 }
26 } catch (e) {
27 exception_error("catchup_callback2", e, transport);
28 }
29 }
30
31 function clean_feed_selections() {
32 try {
33 var feeds = $("feedList").getElementsByTagName("LI");
34
35 for (var i = 0; i < feeds.length; i++) {
36 if (feeds[i].id && feeds[i].id.match("FEEDR-")) {
37 feeds[i].className = feeds[i].className.replace("Selected", "");
38 }
39 if (feeds[i].id && feeds[i].id.match("FCAT-")) {
40 feeds[i].className = feeds[i].className.replace("Selected", "");
41 }
42 }
43 } catch (e) {
44 exception_error("clean_feed_selections", e);
45 }
46 }
47
48 function headlines_callback2(transport, feed_cur_page) {
49 try {
50
51 if (!transport.responseText && db) {
52 offlineConfirmModeChange();
53 return;
54 }
55
56 loading_set_progress(100);
57
58 debug("headlines_callback2 [page=" + feed_cur_page + "]");
59
60 if (!transport_error_check(transport)) return;
61
62 clean_feed_selections();
63
64 var is_cat = false;
65 var feed_id = false;
66
67 if (transport.responseXML) {
68 var headlines = transport.responseXML.getElementsByTagName("headlines")[0];
69 if (headlines) {
70 is_cat = headlines.getAttribute("is_cat");
71 feed_id = headlines.getAttribute("id");
72 setActiveFeedId(feed_id, is_cat);
73 }
74 }
75
76 var ll = $('FLL-' + feed_id);
77
78 if (!is_cat) {
79 var feedr = $("FEEDR-" + feed_id);
80 if (feedr && !feedr.className.match("Selected")) {
81 feedr.className = feedr.className + "Selected";
82 }
83 if (feedr && ll) feedr.removeChild(ll);
84 } else {
85 var feedr = $("FCAT-" + feed_id);
86 if (feedr && !feedr.className.match("Selected")) {
87 feedr.className = feedr.className + "Selected";
88 }
89
90 var fcap = $("FCAP-" + feed_id);
91 if (fcap && ll) fcap.removeChild(ll);
92
93 }
94
95 var img = $('FIMG-' + feed_id);
96
97 if (img && !is_cat) {
98 img.src = img.alt;
99 }
100
101 var f = $("headlines-frame");
102 try {
103 if (feed_cur_page == 0) {
104 debug("resetting headlines scrollTop");
105 f.scrollTop = 0;
106 }
107 } catch (e) { };
108
109 if (transport.responseXML) {
110 var headlines = transport.responseXML.getElementsByTagName("headlines")[0];
111 var headlines_count_obj = transport.responseXML.getElementsByTagName("headlines-count")[0];
112 var headlines_unread_obj = transport.responseXML.getElementsByTagName("headlines-unread")[0];
113 var disable_cache_obj = transport.responseXML.getElementsByTagName("disable-cache")[0];
114
115 var vgroup_last_feed_obj = transport.responseXML.getElementsByTagName("vgroup-last-feed")[0];
116
117 var headlines_count = headlines_count_obj.getAttribute("value");
118 var headlines_unread = headlines_unread_obj.getAttribute("value");
119 var disable_cache = disable_cache_obj.getAttribute("value") != "0";
120
121 vgroup_last_feed = vgroup_last_feed_obj.getAttribute("value");
122
123 if (headlines_count == 0) {
124 _infscroll_disable = 1;
125 } else {
126 _infscroll_disable = 0;
127 }
128
129 var counters = transport.responseXML.getElementsByTagName("counters")[0];
130 var articles = transport.responseXML.getElementsByTagName("article");
131 var runtime_info = transport.responseXML.getElementsByTagName("runtime-info");
132
133 if (feed_cur_page == 0) {
134 if (headlines) {
135 f.innerHTML = headlines.firstChild.nodeValue;
136
137 var cache_prefix = "";
138
139 if (is_cat) {
140 cache_prefix = "C:";
141 } else {
142 cache_prefix = "F:";
143 }
144
145 cache_invalidate(cache_prefix + feed_id);
146
147 if (!disable_cache) {
148 cache_inject(cache_prefix + feed_id,
149 headlines.firstChild.nodeValue, headlines_unread);
150 }
151
152 } else {
153 debug("headlines_callback: returned no data");
154 f.innerHTML = "<div class='whiteBox'>" + __('Could not update headlines (missing XML data)') + "</div>";
155
156 }
157 } else {
158 if (headlines) {
159 if (headlines_count > 0) {
160 debug("adding some more headlines...");
161
162 var c = $("headlinesList");
163
164 if (!c) {
165 c = $("headlinesInnerContainer");
166 }
167
168 var ids = getSelectedArticleIds2();
169
170 c.innerHTML = c.innerHTML + headlines.firstChild.nodeValue;
171
172 debug("restore selected ids: " + ids);
173
174 for (var i = 0; i < ids.length; i++) {
175 markHeadline(ids[i]);
176 }
177
178 } else {
179 debug("no new headlines received");
180 }
181 } else {
182 debug("headlines_callback: returned no data");
183 notify_error("Error while trying to load more headlines");
184 }
185
186 }
187
188 if (articles) {
189 for (var i = 0; i < articles.length; i++) {
190 var a_id = articles[i].getAttribute("id");
191 debug("found id: " + a_id);
192 cache_inject(a_id, articles[i].firstChild.nodeValue);
193 }
194 } else {
195 debug("no cached articles received");
196 }
197
198 if (counters) {
199 debug("parsing piggybacked counters: " + counters);
200 parse_counters(counters, false);
201 } else {
202 debug("counters container not found in reply, requesting...");
203 request_counters();
204 }
205
206 if (runtime_info) {
207 debug("parsing runtime info: " + runtime_info[0]);
208 parse_runtime_info(runtime_info[0]);
209 } else {
210 debug("counters container not found in reply");
211 }
212
213 } else {
214 debug("headlines_callback: returned no XML object");
215 f.innerHTML = "<div class='whiteBox'>" + __('Could not update headlines (missing XML object)') + "</div>";
216 }
217
218 if (typeof correctPNG != 'undefined') {
219 correctPNG();
220 }
221
222 if (_cdm_wd_timeout) window.clearTimeout(_cdm_wd_timeout);
223
224 if (!$("headlinesList") &&
225 getActiveFeedId() != -3 &&
226 getInitParam("cdm_auto_catchup") == 1) {
227 debug("starting CDM watchdog");
228 _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 5000);
229 _cdm_wd_vishist = new Array();
230 } else {
231 debug("not in CDM mode or watchdog disabled");
232 }
233
234 _feed_cur_page = feed_cur_page;
235 _infscroll_request_sent = 0;
236
237 notify("");
238
239 remove_splash();
240
241 } catch (e) {
242 exception_error("headlines_callback2", e, transport);
243 }
244 }
245
246 function render_article(article) {
247 try {
248 var f = $("content-frame");
249 try {
250 f.scrollTop = 0;
251 } catch (e) { };
252
253 var fi = $("content-insert");
254
255 try {
256 fi.scrollTop = 0;
257 } catch (e) { };
258
259 fi.innerHTML = article;
260
261 // article.evalScripts();
262
263 } catch (e) {
264 exception_error("render_article", e);
265 }
266 }
267
268 function showArticleInHeadlines(id) {
269
270 try {
271
272 cleanSelected("headlinesList");
273
274 var crow = $("RROW-" + id);
275
276 if (!crow) return;
277
278 var article_is_unread = crow.className.match("Unread");
279
280 crow.className = crow.className.replace("Unread", "");
281
282 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
283
284 var upd_img_pic = $("FUPDPIC-" + id);
285
286 var cache_prefix = "";
287
288 if (activeFeedIsCat()) {
289 cache_prefix = "C:";
290 } else {
291 cache_prefix = "F:";
292 }
293
294 var view_mode = false;
295
296 try {
297 view_mode = document.forms['main_toolbar_form'].view_mode;
298 view_mode = view_mode[view_mode.selectedIndex].value;
299 } catch (e) {
300 //
301 }
302
303 if (upd_img_pic && (upd_img_pic.src.match("updated.png") ||
304 upd_img_pic.src.match("fresh_sign.png"))) {
305
306 upd_img_pic.src = "images/blank_icon.gif";
307
308 cache_invalidate(cache_prefix + getActiveFeedId());
309
310 cache_inject(cache_prefix + getActiveFeedId(),
311 $("headlines-frame").innerHTML,
312 get_feed_unread(getActiveFeedId()));
313
314 } else if (article_is_unread && view_mode == "all_articles") {
315
316 cache_invalidate(cache_prefix + getActiveFeedId());
317
318 cache_inject(cache_prefix + getActiveFeedId(),
319 $("headlines-frame").innerHTML,
320 get_feed_unread(getActiveFeedId())-1);
321
322 } else if (article_is_unread) {
323 cache_invalidate(cache_prefix + getActiveFeedId());
324 }
325
326 markHeadline(id);
327
328 } catch (e) {
329 exception_error("showArticleInHeadlines", e);
330 }
331 }
332
333 function article_callback2(transport, id) {
334 try {
335 debug("article_callback2 " + id);
336
337 if (!transport.responseText && db) {
338 offlineConfirmModeChange();
339 return;
340 }
341
342 if (transport.responseXML) {
343
344 if (!transport_error_check(transport)) return;
345
346 /* var ll = $('LL-' + id);
347 var content = $('HLC-' + id);
348
349 if (ll && content) content.removeChild(ll); */
350
351 var upic = $('FUPDPIC-' + id);
352
353 if (upic) {
354 upic.src = 'images/blank_icon.gif';
355 }
356
357 if (id != last_requested_article) {
358 debug("requested article id is out of sequence, aborting");
359 return;
360 }
361
362 active_post_id = id;
363
364 debug("looking for articles to cache...");
365
366 var articles = transport.responseXML.getElementsByTagName("article");
367
368 for (var i = 0; i < articles.length; i++) {
369 var a_id = articles[i].getAttribute("id");
370
371 debug("found id: " + a_id);
372
373 if (a_id == active_post_id) {
374 debug("active article, rendering...");
375 render_article(articles[i].firstChild.nodeValue);
376 }
377
378 cache_inject(a_id, articles[i].firstChild.nodeValue);
379 }
380
381
382 showArticleInHeadlines(id);
383
384 if (db) {
385 db.execute("UPDATE articles SET unread = 0 WHERE id = ?", [id]);
386 }
387
388 var reply = transport.responseXML.firstChild.firstChild;
389
390 } else {
391 debug("article_callback: returned no XML object");
392 //var f = $("content-frame");
393 //f.innerHTML = "<div class='whiteBox'>" + __('Could not display article (missing XML object)') + "</div>";
394 }
395
396 var date = new Date();
397 last_article_view = date.getTime() / 1000;
398
399 if (typeof correctPNG != 'undefined') {
400 correctPNG();
401 }
402
403 if (_reload_feedlist_after_view) {
404 setTimeout('updateFeedList(false, false)', 50);
405 _reload_feedlist_after_view = false;
406 } else {
407 if (transport.responseXML) {
408 var counters = transport.responseXML.getElementsByTagName("counters")[0];
409
410 if (counters) {
411 debug("parsing piggybacked counters: " + counters);
412 parse_counters(counters, false);
413 } else {
414 debug("counters container not found in reply, requesting...");
415 request_counters();
416 }
417 }
418 }
419
420 notify("");
421 } catch (e) {
422 exception_error("article_callback2", e, transport);
423 }
424 }
425
426 function view(id) {
427 try {
428 debug("loading article: " + id);
429
430 if (offline_mode) return view_offline(id);
431
432 var cached_article = cache_find(id);
433
434 debug("cache check result: " + (cached_article != false));
435
436 enableHotkeys();
437 hideAuxDlg();
438
439 var query = "?op=view&id=" + param_escape(id);
440
441 var neighbor_ids = getRelativePostIds(active_post_id);
442
443 /* only request uncached articles */
444
445 var cids_to_request = Array();
446
447 for (var i = 0; i < neighbor_ids.length; i++) {
448 if (!cache_check(neighbor_ids[i])) {
449 cids_to_request.push(neighbor_ids[i]);
450 }
451 }
452
453 debug("additional ids: " + cids_to_request.toString());
454
455 /* additional info for piggyback counters */
456
457 if (tagsAreDisplayed()) {
458 query = query + "&omode=lt";
459 } else {
460 query = query + "&omode=flc";
461 }
462
463 query = query + "&cids=" + cids_to_request.toString();
464
465 var crow = $("RROW-" + id);
466 var article_is_unread = crow.className.match("Unread");
467
468 if (!async_counters_work) {
469 query = query + "&csync=true";
470 }
471
472 showArticleInHeadlines(id);
473
474 if (!cached_article) {
475
476 // notify_progress("Loading, please wait...", true);
477
478 /* var content = $('HLC-' + id);
479
480 if (content && !$('LL-' + id)) {
481 var ll = document.createElement('img');
482
483 ll.src = 'images/indicator_tiny.gif';
484 ll.className = 'hlLoading';
485 ll.id = 'LL-' + id;
486
487 content.appendChild(ll);
488
489 } */
490
491 var upic = $('FUPDPIC-' + id);
492
493 if (upic) {
494 upic.src = getInitParam("sign_progress");
495 }
496
497 } else if (cached_article && article_is_unread) {
498
499 query = query + "&mode=prefetch";
500
501 render_article(cached_article);
502
503 } else if (cached_article) {
504
505 query = query + "&mode=prefetch_old";
506 render_article(cached_article);
507
508 }
509
510 cache_expire();
511
512 last_requested_article = id;
513
514 new Ajax.Request("backend.php", {
515 parameters: query,
516 onComplete: function(transport) {
517 article_callback2(transport, id);
518 } });
519
520 return false;
521
522 } catch (e) {
523 exception_error("view", e);
524 }
525 }
526
527 function tMark(id) {
528 return toggleMark(id);
529 }
530
531 function tPub(id) {
532 return togglePub(id);
533 }
534
535 function tMark_afh_off(effect) {
536 try {
537 var elem = effect.effects[0].element;
538
539 debug("tMark_afh_off : " + elem.id);
540
541 if (elem) {
542 elem.src = elem.src.replace("mark_set", "mark_unset");
543 elem.alt = __("Star article");
544 Element.show(elem);
545 }
546
547 } catch (e) {
548 exception_error("tMark_afh_off", e);
549 }
550 }
551
552 function tPub_afh_off(effect) {
553 try {
554 var elem = effect.effects[0].element;
555
556 debug("tPub_afh_off : " + elem.id);
557
558 if (elem) {
559 elem.src = elem.src.replace("pub_set", "pub_unset");
560 elem.alt = __("Publish article");
561 Element.show(elem);
562 }
563
564 } catch (e) {
565 exception_error("tPub_afh_off", e);
566 }
567 }
568
569 function toggleMark(id, client_only, no_effects) {
570
571 try {
572
573 var query = "?op=rpc&id=" + id + "&subop=mark";
574
575 query = query + "&afid=" + getActiveFeedId();
576
577 if (tagsAreDisplayed()) {
578 query = query + "&omode=tl";
579 } else {
580 query = query + "&omode=flc";
581 }
582
583 var mark_img = $("FMPIC-" + id);
584
585 if (!mark_img) return;
586
587 var vfeedu = $("FEEDU--1");
588 var crow = $("RROW-" + id);
589
590 if (mark_img.src.match("mark_unset")) {
591 mark_img.src = mark_img.src.replace("mark_unset", "mark_set");
592 mark_img.alt = __("Unstar article");
593 query = query + "&mark=1";
594
595 if (db) {
596 db.execute("UPDATE articles SET marked = 1 WHERE id = ?", [id]);
597 }
598
599 } else {
600 //mark_img.src = "images/mark_unset.png";
601 mark_img.alt = __("Please wait...");
602 query = query + "&mark=0";
603
604 if ($("headlinesList") && !no_effects) {
605 Effect.Puff(mark_img, {duration : 0.25, afterFinish: tMark_afh_off});
606 } else {
607 mark_img.src = mark_img.src.replace("mark_set", "mark_unset");
608 mark_img.alt = __("Star article");
609 }
610
611 if (db) {
612 db.execute("UPDATE articles SET marked = 0 WHERE id = ?", [id]);
613 }
614
615 }
616
617 if (!no_effects) update_local_feedlist_counters();
618
619 if (!client_only) {
620 debug(query);
621
622 new Ajax.Request("backend.php", {
623 parameters: query,
624 onComplete: function(transport) {
625 all_counters_callback2(transport);
626 } });
627
628 }
629
630 } catch (e) {
631 exception_error("toggleMark", e);
632 }
633 }
634
635 function togglePub(id, client_only, no_effects, note) {
636
637 try {
638
639 var query = "?op=rpc&id=" + id + "&subop=publ";
640
641 query = query + "&afid=" + getActiveFeedId();
642
643 if (note != undefined) {
644 query = query + "&note=" + param_escape(note);
645 } else {
646 query = query + "&note=undefined";
647 }
648
649 if (tagsAreDisplayed()) {
650 query = query + "&omode=tl";
651 } else {
652 query = query + "&omode=flc";
653 }
654
655 var mark_img = $("FPPIC-" + id);
656
657 if (!mark_img) return;
658
659 var vfeedu = $("FEEDU--2");
660 var crow = $("RROW-" + id);
661
662 if (mark_img.src.match("pub_unset") || note != undefined) {
663 mark_img.src = mark_img.src.replace("pub_unset", "pub_set");
664 mark_img.alt = __("Unpublish article");
665 query = query + "&pub=1";
666
667 } else {
668 //mark_img.src = "images/pub_unset.png";
669 mark_img.alt = __("Please wait...");
670 query = query + "&pub=0";
671
672 if ($("headlinesList") && !no_effects) {
673 Effect.Puff(mark_img, {duration : 0.25, afterFinish: tPub_afh_off});
674 } else {
675 mark_img.src = mark_img.src.replace("pub_set", "pub_unset");
676 mark_img.alt = __("Publish article");
677 }
678 }
679
680 if (!client_only) {
681 new Ajax.Request("backend.php", {
682 parameters: query,
683 onComplete: function(transport) {
684 all_counters_callback2(transport);
685
686 var note = transport.responseXML.getElementsByTagName("note")[0];
687
688 if (note) {
689 var note_id = note.getAttribute("id");
690 var note_size = note.getAttribute("size");
691 var note_content = note.firstChild.nodeValue;
692
693 var container = $('POSTNOTE-' + note_id);
694
695 cache_invalidate(note_id);
696
697 if (container) {
698 if (note_size == "0") {
699 Element.hide(container);
700 } else {
701 container.innerHTML = note_content;
702 Element.show(container);
703 }
704 }
705 }
706
707 } });
708 }
709
710 } catch (e) {
711 exception_error("togglePub", e);
712 }
713 }
714
715 function correctHeadlinesOffset(id) {
716
717 try {
718
719 var hlist = $("headlinesList");
720 var container = $("headlinesInnerContainer");
721 var row = $("RROW-" + id);
722
723 var viewport = container.offsetHeight;
724
725 var rel_offset_top = row.offsetTop - container.scrollTop;
726 var rel_offset_bottom = row.offsetTop + row.offsetHeight - container.scrollTop;
727
728 debug("Rtop: " + rel_offset_top + " Rbtm: " + rel_offset_bottom);
729 debug("Vport: " + viewport);
730
731 if (rel_offset_top <= 0 || rel_offset_top > viewport) {
732 container.scrollTop = row.offsetTop;
733 } else if (rel_offset_bottom > viewport) {
734
735 /* doesn't properly work with Opera in some cases because
736 Opera fucks up element scrolling */
737
738 container.scrollTop = row.offsetTop + row.offsetHeight - viewport;
739 }
740
741 } catch (e) {
742 exception_error("correctHeadlinesOffset", e);
743 }
744
745 }
746
747 function moveToPost(mode) {
748
749 try {
750
751 var rows;
752
753 if (isCdmMode()) {
754 rows = cdmGetVisibleArticles();
755 } else {
756 rows = getVisibleHeadlineIds();
757 }
758
759 var prev_id = false;
760 var next_id = false;
761
762 if (!$('RROW-' + active_post_id)) {
763 active_post_id = false;
764 }
765
766 if (active_post_id == false) {
767 next_id = getFirstVisibleHeadlineId();
768 prev_id = getLastVisibleHeadlineId();
769 } else {
770 for (var i = 0; i < rows.length; i++) {
771 if (rows[i] == active_post_id) {
772 prev_id = rows[i-1];
773 next_id = rows[i+1];
774 }
775 }
776 }
777
778 if (mode == "next") {
779 if (next_id) {
780 if (isCdmMode()) {
781
782 if (!cdmArticleIsActuallyVisible(next_id)) {
783 cdmScrollToArticleId(next_id);
784 }
785 cdmSelectArticles("none");
786 toggleUnread(next_id, 0, true);
787 toggleSelected(next_id);
788
789 } else {
790 correctHeadlinesOffset(next_id);
791 view(next_id, getActiveFeedId());
792 }
793 }
794 }
795
796 if (mode == "prev") {
797 if (prev_id) {
798 if (isCdmMode()) {
799 cdmScrollToArticleId(prev_id);
800 cdmSelectArticles("none");
801 toggleUnread(prev_id, 0, true);
802 toggleSelected(prev_id);
803 } else {
804 correctHeadlinesOffset(prev_id);
805 view(prev_id, getActiveFeedId());
806 }
807 }
808 }
809
810 } catch (e) {
811 exception_error("moveToPost", e);
812 }
813 }
814
815 function toggleSelected(id) {
816 try {
817
818 var cb = $("RCHK-" + id);
819
820 var row = $("RROW-" + id);
821 if (row) {
822 var nc = row.className;
823
824 if (!nc.match("Selected")) {
825 nc = nc + "Selected";
826 if (cb) {
827 cb.checked = true;
828 }
829
830 // In CDM basically last selected article == active article
831 if (isCdmMode()) active_post_id = id;
832 } else {
833 nc = nc.replace("Selected", "");
834 if (cb) {
835 cb.checked = false;
836 }
837
838 }
839
840 row.className = nc;
841 }
842 } catch (e) {
843 exception_error("toggleSelected", e);
844 }
845 }
846
847 function toggleUnread_afh(effect) {
848 try {
849
850 var elem = effect.element;
851 elem.style.backgroundColor = "";
852
853 } catch (e) {
854 exception_error("toggleUnread_afh", e);
855 }
856 }
857
858 function toggleUnread(id, cmode, effect) {
859 try {
860
861 var row = $("RROW-" + id);
862 if (row) {
863 var nc = row.className;
864 var is_selected = row.className.match("Selected");
865 nc = nc.replace("Unread", "");
866 nc = nc.replace("Selected", "");
867
868 // since we are removing selection from the object, uncheck
869 // corresponding checkbox
870
871 var cb = $("RCHK-" + id);
872 if (cb) {
873 cb.checked = false;
874 }
875
876 // NOTE: I'm not sure that resetting selection here is a feature -fox
877
878 if (cmode == undefined || cmode == 2) {
879 if (row.className.match("Unread")) {
880 row.className = nc;
881
882 if (effect) {
883 new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
884 afterFinish: toggleUnread_afh,
885 queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
886 }
887
888 } else {
889 row.className = nc + "Unread";
890 }
891
892 if (db) {
893 db.execute("UPDATE articles SET unread = not unread "+
894 "WHERE id = ?", [id]);
895 }
896
897 } else if (cmode == 0) {
898 row.className = nc;
899
900 if (effect) {
901 new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
902 afterFinish: toggleUnread_afh,
903 queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
904 }
905
906 if (db) {
907 db.execute("UPDATE articles SET unread = 0 "+
908 "WHERE id = ?", [id]);
909 }
910
911 } else if (cmode == 1) {
912 row.className = nc + "Unread";
913
914 if (db) {
915 db.execute("UPDATE articles SET unread = 1 "+
916 "WHERE id = ?", [id]);
917 }
918
919 }
920
921 update_local_feedlist_counters();
922
923 // Disable unmarking as selected for the time being (16.05.08) -fox
924 if (is_selected) row.className = row.className + "Selected";
925
926 if (cmode == undefined) cmode = 2;
927
928 var query = "?op=rpc&subop=catchupSelected" +
929 "&cmode=" + param_escape(cmode) + "&ids=" + param_escape(id);
930
931 // notify_progress("Loading, please wait...");
932
933 new Ajax.Request("backend.php", {
934 parameters: query,
935 onComplete: function(transport) {
936 all_counters_callback2(transport);
937 } });
938
939 }
940
941 } catch (e) {
942 exception_error("toggleUnread", e);
943 }
944 }
945
946 function selectionRemoveLabel(id) {
947 try {
948
949 var ids = getSelectedArticleIds2();
950
951 if (ids.length == 0) {
952 alert(__("No articles are selected."));
953 return;
954 }
955
956 // var ok = confirm(__("Remove selected articles from label?"));
957
958 // if (ok) {
959
960 var query = "?op=rpc&subop=removeFromLabel&ids=" +
961 param_escape(ids.toString()) + "&lid=" + param_escape(id);
962
963 // notify_progress("Loading, please wait...");
964
965 cache_invalidate("F:" + (-11 - id));
966
967 new Ajax.Request("backend.php", {
968 parameters: query,
969 onComplete: function(transport) {
970 show_labels_in_headlines(transport);
971 all_counters_callback2(transport);
972 } });
973
974 // }
975
976 } catch (e) {
977 exception_error("selectionAssignLabel", e);
978
979 }
980 }
981
982 function selectionAssignLabel(id) {
983 try {
984
985 var ids = getSelectedArticleIds2();
986
987 if (ids.length == 0) {
988 alert(__("No articles are selected."));
989 return;
990 }
991
992 // var ok = confirm(__("Assign selected articles to label?"));
993
994 // if (ok) {
995
996 cache_invalidate("F:" + (-11 - id));
997
998 var query = "?op=rpc&subop=assignToLabel&ids=" +
999 param_escape(ids.toString()) + "&lid=" + param_escape(id);
1000
1001 // notify_progress("Loading, please wait...");
1002
1003 new Ajax.Request("backend.php", {
1004 parameters: query,
1005 onComplete: function(transport) {
1006 show_labels_in_headlines(transport);
1007 all_counters_callback2(transport);
1008 } });
1009
1010 // }
1011
1012 } catch (e) {
1013 exception_error("selectionAssignLabel", e);
1014
1015 }
1016 }
1017
1018 function selectionToggleUnread(cdm_mode, set_state, callback_func, no_error) {
1019 try {
1020 var rows;
1021
1022 if (cdm_mode) {
1023 rows = cdmGetSelectedArticles();
1024 } else {
1025 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1026 }
1027
1028 if (rows.length == 0 && !no_error) {
1029 alert(__("No articles are selected."));
1030 return;
1031 }
1032
1033 for (i = 0; i < rows.length; i++) {
1034 var row = $("RROW-" + rows[i]);
1035 if (row) {
1036 var nc = row.className;
1037 nc = nc.replace("Unread", "");
1038 nc = nc.replace("Selected", "");
1039
1040 if (set_state == undefined) {
1041 if (row.className.match("Unread")) {
1042 row.className = nc + "Selected";
1043 } else {
1044 row.className = nc + "UnreadSelected";
1045 }
1046 if (db) {
1047 db.execute("UPDATE articles SET unread = NOT unread WHERE id = ?",
1048 [rows[i]]);
1049 }
1050 }
1051
1052 if (set_state == false) {
1053 row.className = nc + "Selected";
1054 if (db) {
1055 db.execute("UPDATE articles SET unread = 0 WHERE id = ?",
1056 [rows[i]]);
1057 }
1058 }
1059
1060 if (set_state == true) {
1061 row.className = nc + "UnreadSelected";
1062 if (db) {
1063 db.execute("UPDATE articles SET unread = 1 WHERE id = ?",
1064 [rows[i]]);
1065 }
1066 }
1067 }
1068 }
1069
1070 if (rows.length > 0) {
1071
1072 update_local_feedlist_counters();
1073
1074 var cmode = "";
1075
1076 if (set_state == undefined) {
1077 cmode = "2";
1078 } else if (set_state == true) {
1079 cmode = "1";
1080 } else if (set_state == false) {
1081 cmode = "0";
1082 }
1083
1084 var query = "?op=rpc&subop=catchupSelected" +
1085 "&cmode=" + cmode + "&ids=" + param_escape(rows.toString());
1086
1087 notify_progress("Loading, please wait...");
1088
1089 new Ajax.Request("backend.php", {
1090 parameters: query,
1091 onComplete: function(transport) {
1092 catchup_callback2(transport, callback_func);
1093 } });
1094
1095 }
1096
1097 } catch (e) {
1098 exception_error("selectionToggleUnread", e);
1099 }
1100 }
1101
1102 function selectionToggleMarked(cdm_mode) {
1103 try {
1104
1105 var rows;
1106
1107 if (cdm_mode) {
1108 rows = cdmGetSelectedArticles();
1109 } else {
1110 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1111 }
1112
1113 if (rows.length == 0) {
1114 alert(__("No articles are selected."));
1115 return;
1116 }
1117
1118 for (i = 0; i < rows.length; i++) {
1119 toggleMark(rows[i], true, true);
1120 }
1121
1122 update_local_feedlist_counters();
1123
1124 if (rows.length > 0) {
1125
1126 var query = "?op=rpc&subop=markSelected&ids=" +
1127 param_escape(rows.toString()) + "&cmode=2";
1128
1129 query = query + "&afid=" + getActiveFeedId();
1130
1131 /* if (tagsAreDisplayed()) {
1132 query = query + "&omode=tl";
1133 } else {
1134 query = query + "&omode=flc";
1135 } */
1136
1137 query = query + "&omode=lc";
1138
1139 new Ajax.Request("backend.php", {
1140 parameters: query,
1141 onComplete: function(transport) {
1142 all_counters_callback2(transport);
1143 } });
1144
1145 }
1146
1147 } catch (e) {
1148 exception_error("selectionToggleMarked", e);
1149 }
1150 }
1151
1152 function selectionTogglePublished(cdm_mode) {
1153 try {
1154
1155 var rows;
1156
1157 if (cdm_mode) {
1158 rows = cdmGetSelectedArticles();
1159 } else {
1160 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1161 }
1162
1163 if (rows.length == 0) {
1164 alert(__("No articles are selected."));
1165 return;
1166 }
1167
1168 for (i = 0; i < rows.length; i++) {
1169 togglePub(rows[i], true, true);
1170 }
1171
1172 if (rows.length > 0) {
1173
1174 var query = "?op=rpc&subop=publishSelected&ids=" +
1175 param_escape(rows.toString()) + "&cmode=2";
1176
1177 query = query + "&afid=" + getActiveFeedId();
1178
1179 /* if (tagsAreDisplayed()) {
1180 query = query + "&omode=tl";
1181 } else {
1182 query = query + "&omode=flc";
1183 } */
1184
1185 query = query + "&omode=lc";
1186
1187 new Ajax.Request("backend.php", {
1188 parameters: query,
1189 onComplete: function(transport) {
1190 all_counters_callback2(transport);
1191 } });
1192
1193 }
1194
1195 } catch (e) {
1196 exception_error("selectionToggleMarked", e);
1197 }
1198 }
1199
1200 function cdmGetSelectedArticles() {
1201 var sel_articles = new Array();
1202 var container = $("headlinesInnerContainer");
1203
1204 for (i = 0; i < container.childNodes.length; i++) {
1205 var child = container.childNodes[i];
1206
1207 if (child.id && child.id.match("RROW-") && child.className.match("Selected")) {
1208 var c_id = child.id.replace("RROW-", "");
1209 sel_articles.push(c_id);
1210 }
1211 }
1212
1213 return sel_articles;
1214 }
1215
1216 function cdmGetVisibleArticles() {
1217 var sel_articles = new Array();
1218 var container = $("headlinesInnerContainer");
1219
1220 if (!container) return sel_articles;
1221
1222 for (i = 0; i < container.childNodes.length; i++) {
1223 var child = container.childNodes[i];
1224
1225 if (child.id && child.id.match("RROW-")) {
1226 var c_id = child.id.replace("RROW-", "");
1227 sel_articles.push(c_id);
1228 }
1229 }
1230
1231 return sel_articles;
1232 }
1233
1234 function cdmGetUnreadArticles() {
1235 var sel_articles = new Array();
1236 var container = $("headlinesInnerContainer");
1237
1238 for (i = 0; i < container.childNodes.length; i++) {
1239 var child = container.childNodes[i];
1240
1241 if (child.id && child.id.match("RROW-") && child.className.match("Unread")) {
1242 var c_id = child.id.replace("RROW-", "");
1243 sel_articles.push(c_id);
1244 }
1245 }
1246
1247 return sel_articles;
1248 }
1249
1250
1251 // mode = all,none,unread
1252 function cdmSelectArticles(mode) {
1253 var container = $("headlinesInnerContainer");
1254
1255 for (i = 0; i < container.childNodes.length; i++) {
1256 var child = container.childNodes[i];
1257
1258 if (child.id && child.id.match("RROW-")) {
1259 var aid = child.id.replace("RROW-", "");
1260
1261 var cb = $("RCHK-" + aid);
1262
1263 if (mode == "all") {
1264 if (!child.className.match("Selected")) {
1265 child.className = child.className + "Selected";
1266 cb.checked = true;
1267 }
1268 } else if (mode == "unread") {
1269 if (child.className.match("Unread") && !child.className.match("Selected")) {
1270 child.className = child.className + "Selected";
1271 cb.checked = true;
1272 }
1273 } else {
1274 child.className = child.className.replace("Selected", "");
1275 cb.checked = false;
1276 }
1277 }
1278 }
1279 }
1280
1281 function catchupPage() {
1282
1283 var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
1284
1285 var str = __("Mark all visible articles in %s as read?");
1286
1287 str = str.replace("%s", fn);
1288
1289 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
1290 return;
1291 }
1292
1293 if ($("headlinesList")) {
1294 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', true, 'Unread', true);
1295 selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
1296 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
1297 } else {
1298 cdmSelectArticles('all');
1299 selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
1300 cdmSelectArticles('none');
1301 }
1302 }
1303
1304 function deleteSelection() {
1305
1306 try {
1307
1308 var rows;
1309
1310 if ($("headlinesList")) {
1311 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1312 } else {
1313 rows = cdmGetSelectedArticles();
1314 }
1315
1316 if (rows.length == 0) {
1317 alert(__("No articles are selected."));
1318 return;
1319 }
1320
1321
1322 var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
1323 var str;
1324 var op;
1325
1326 if (getActiveFeedId() != 0) {
1327 str = __("Delete %d selected articles in %s?");
1328 } else {
1329 str = __("Delete %d selected articles?");
1330 }
1331
1332 str = str.replace("%d", rows.length);
1333 str = str.replace("%s", fn);
1334
1335 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
1336 return;
1337 }
1338
1339 query = "?op=rpc&subop=delete&ids=" + param_escape(rows);
1340
1341 debug(query);
1342
1343 new Ajax.Request("backend.php", {
1344 parameters: query,
1345 onComplete: function(transport) {
1346 viewCurrentFeed();
1347 } });
1348
1349 } catch (e) {
1350 exception_error("deleteSelection", e);
1351 }
1352 }
1353
1354 function archiveSelection() {
1355
1356 try {
1357
1358 var rows;
1359
1360 if ($("headlinesList")) {
1361 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1362 } else {
1363 rows = cdmGetSelectedArticles();
1364 }
1365
1366 if (rows.length == 0) {
1367 alert(__("No articles are selected."));
1368 return;
1369 }
1370
1371
1372 var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
1373 var str;
1374 var op;
1375
1376 if (getActiveFeedId() != 0) {
1377 str = __("Archive %d selected articles in %s?");
1378 op = "archive";
1379 } else {
1380 str = __("Move %d archived articles back?");
1381 op = "unarchive";
1382 }
1383
1384 str = str.replace("%d", rows.length);
1385 str = str.replace("%s", fn);
1386
1387 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
1388 return;
1389 }
1390
1391 query = "?op=rpc&subop="+op+"&ids=" + param_escape(rows);
1392
1393 debug(query);
1394
1395 for (var i = 0; i < rows.length; i++) {
1396 cache_invalidate(rows[i]);
1397 }
1398
1399 new Ajax.Request("backend.php", {
1400 parameters: query,
1401 onComplete: function(transport) {
1402 viewCurrentFeed();
1403 } });
1404
1405 } catch (e) {
1406 exception_error("archiveSelection", e);
1407 }
1408 }
1409
1410 function catchupSelection() {
1411
1412 try {
1413
1414 var rows;
1415
1416 if ($("headlinesList")) {
1417 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1418 } else {
1419 rows = cdmGetSelectedArticles();
1420 }
1421
1422 if (rows.length == 0) {
1423 alert(__("No articles are selected."));
1424 return;
1425 }
1426
1427
1428 var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
1429
1430 var str = __("Mark %d selected articles in %s as read?");
1431
1432 str = str.replace("%d", rows.length);
1433 str = str.replace("%s", fn);
1434
1435 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
1436 return;
1437 }
1438
1439 if ($("headlinesList")) {
1440 selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
1441 // selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
1442 } else {
1443 selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
1444 // cdmSelectArticles('none');
1445 }
1446
1447 } catch (e) {
1448 exception_error("catchupSelection", e);
1449 }
1450 }
1451
1452 function editArticleTags(id, feed_id, cdm_enabled) {
1453 displayDlg('editArticleTags', id,
1454 function () {
1455 new Ajax.Autocompleter('tags_str', 'tags_choices',
1456 "backend.php?op=rpc&subop=completeTags",
1457 { tokens: ',', paramName: "search" });
1458 });
1459 }
1460
1461 function editTagsSave() {
1462
1463 notify_progress("Saving article tags...");
1464
1465 var form = document.forms["tag_edit_form"];
1466
1467 var query = Form.serialize("tag_edit_form");
1468
1469 query = "?op=rpc&subop=setArticleTags&" + query;
1470
1471 debug(query);
1472
1473 new Ajax.Request("backend.php", {
1474 parameters: query,
1475 onComplete: function(transport) {
1476 try {
1477 debug("tags saved...");
1478
1479 closeInfoBox();
1480 notify("");
1481
1482 if (tagsAreDisplayed()) {
1483 _reload_feedlist_after_view = true;
1484 }
1485
1486 if (transport.responseXML) {
1487 var tags_str = transport.responseXML.getElementsByTagName("tags-str")[0];
1488
1489 if (tags_str) {
1490 var id = tags_str.getAttribute("id");
1491
1492 if (id) {
1493 var tags = $("ATSTR-" + id);
1494 if (tags) {
1495 tags.innerHTML = tags_str.firstChild.nodeValue;
1496 }
1497
1498 cache_invalidate(id);
1499 }
1500 }
1501 }
1502
1503 } catch (e) {
1504 exception_error("editTagsSave", e);
1505 }
1506 } });
1507 }
1508
1509 function editTagsInsert() {
1510 try {
1511
1512 var form = document.forms["tag_edit_form"];
1513
1514 var found_tags = form.found_tags;
1515 var tags_str = form.tags_str;
1516
1517 var tag = found_tags[found_tags.selectedIndex].value;
1518
1519 if (tags_str.value.length > 0 &&
1520 tags_str.value.lastIndexOf(", ") != tags_str.value.length - 2) {
1521
1522 tags_str.value = tags_str.value + ", ";
1523 }
1524
1525 tags_str.value = tags_str.value + tag + ", ";
1526
1527 found_tags.selectedIndex = 0;
1528
1529 } catch (e) {
1530 exception_error("editTagsInsert", e);
1531 }
1532 }
1533
1534 function cdmScrollViewport(where) {
1535 debug("cdmScrollViewport: " + where);
1536
1537 var ctr = $("headlinesInnerContainer");
1538
1539 if (!ctr) return;
1540
1541 if (where == "bottom") {
1542 ctr.scrollTop = ctr.scrollHeight;
1543 } else {
1544 ctr.scrollTop = where;
1545 }
1546 }
1547
1548 function cdmArticleIsBelowViewport(id) {
1549 try {
1550 var ctr = $("headlinesInnerContainer");
1551 var e = $("RROW-" + id);
1552
1553 if (!e || !ctr) return;
1554
1555 // article starts below viewport
1556
1557 if (ctr.scrollTop < e.offsetTop) {
1558 return true;
1559 } else {
1560 return false;
1561 }
1562
1563 } catch (e) {
1564 exception_error("cdmArticleIsVisible", e);
1565 }
1566 }
1567
1568 function cdmArticleIsAboveViewport(id) {
1569 try {
1570 var ctr = $("headlinesInnerContainer");
1571 var e = $("RROW-" + id);
1572
1573 if (!e || !ctr) return;
1574
1575 // article starts above viewport
1576
1577 if (ctr.scrollTop > e.offsetTop + e.offsetHeight) {
1578 return true;
1579 } else {
1580 return false;
1581 }
1582
1583 } catch (e) {
1584 exception_error("cdmArticleIsVisible", e);
1585 }
1586 }
1587
1588 function cdmScrollToArticleId(id) {
1589 try {
1590 var ctr = $("headlinesInnerContainer");
1591 var e = $("RROW-" + id);
1592
1593 if (!e || !ctr) return;
1594
1595 ctr.scrollTop = e.offsetTop;
1596
1597 } catch (e) {
1598 exception_error("cdmScrollToArticleId", e);
1599 }
1600 }
1601
1602 function cdmArticleIsActuallyVisible(id) {
1603 try {
1604 var ctr = $("headlinesInnerContainer");
1605 var e = $("RROW-" + id);
1606
1607 if (!e || !ctr) return;
1608
1609 // article fits in viewport OR article is longer than viewport and
1610 // its bottom is visible
1611
1612 if (ctr.scrollTop <= e.offsetTop && e.offsetTop + e.offsetHeight <=
1613 ctr.scrollTop + ctr.offsetHeight) {
1614
1615 return true;
1616
1617 } else if (e.offsetHeight > ctr.offsetHeight &&
1618 e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1619 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight) {
1620
1621 return true;
1622
1623 }
1624
1625 return false;
1626
1627 } catch (e) {
1628 exception_error("cdmArticleIsVisible", e);
1629 }
1630 }
1631
1632 function cdmWatchdog() {
1633
1634 try {
1635
1636 var ctr = $("headlinesInnerContainer");
1637
1638 if (!ctr) return;
1639
1640 var ids = new Array();
1641
1642 var e = ctr.firstChild;
1643
1644 while (e) {
1645 if (e.className && e.className == "cdmArticleUnread" && e.id &&
1646 e.id.match("RROW-")) {
1647
1648 // article fits in viewport OR article is longer than viewport and
1649 // its bottom is visible
1650
1651 if (ctr.scrollTop <= e.offsetTop && e.offsetTop + e.offsetHeight <=
1652 ctr.scrollTop + ctr.offsetHeight) {
1653
1654 // debug(e.id + " is visible " + e.offsetTop + "." +
1655 // (e.offsetTop + e.offsetHeight) + " vs " + ctr.scrollTop + "." +
1656 // (ctr.scrollTop + ctr.offsetHeight));
1657
1658 ids.push(e.id.replace("RROW-", ""));
1659
1660 } else if (e.offsetHeight > ctr.offsetHeight &&
1661 e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1662 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight) {
1663
1664 ids.push(e.id.replace("RROW-", ""));
1665
1666 }
1667
1668 // method 2: article bottom is visible and is in upper 1/2 of the viewport
1669
1670 /* if (e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1671 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight/2) {
1672
1673 ids.push(e.id.replace("RROW-", ""));
1674
1675 } */
1676
1677 }
1678
1679 e = e.nextSibling;
1680 }
1681
1682 debug("cdmWatchdog, ids= " + ids.toString());
1683
1684 if (ids.length > 0) {
1685
1686 for (var i = 0; i < ids.length; i++) {
1687 var e = $("RROW-" + ids[i]);
1688 if (e) {
1689 e.className = e.className.replace("Unread", "");
1690 }
1691 }
1692
1693 var query = "?op=rpc&subop=catchupSelected" +
1694 "&cmode=0" + "&ids=" + param_escape(ids.toString());
1695
1696 new Ajax.Request("backend.php", {
1697 parameters: query,
1698 onComplete: function(transport) {
1699 all_counters_callback2(transport);
1700 } });
1701
1702 }
1703
1704 _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 4000);
1705
1706 } catch (e) {
1707 exception_error("cdmWatchdog", e);
1708 }
1709
1710 }
1711
1712
1713 function cache_inject(id, article, param) {
1714 try {
1715 if (!cache_check_param(id, param)) {
1716 debug("cache_article: miss: " + id + " [p=" + param + "]");
1717
1718 if (db) {
1719
1720 var date = new Date();
1721 var ts = Math.round(date.getTime() / 1000);
1722
1723 db.execute("INSERT INTO cache (id, article, param, added) VALUES (?, ?, ?, ?)",
1724 [id, article, param, ts]);
1725 } else {
1726
1727 var cache_obj = new Array();
1728
1729 cache_obj["id"] = id;
1730 cache_obj["data"] = article;
1731 cache_obj["param"] = param;
1732
1733 article_cache.push(cache_obj);
1734 }
1735
1736 } else {
1737 debug("cache_article: hit: " + id + " [p=" + param + "]");
1738 }
1739 } catch (e) {
1740 exception_error("cache_inject", e);
1741 }
1742 }
1743
1744 function cache_find(id) {
1745
1746 if (db) {
1747 var rs = db.execute("SELECT article FROM cache WHERE id = ?", [id]);
1748 var a = false;
1749
1750 if (rs.isValidRow()) {
1751 var a = rs.field(0);
1752 }
1753
1754 rs.close();
1755
1756 return a;
1757
1758 } else {
1759 for (var i = 0; i < article_cache.length; i++) {
1760 if (article_cache[i]["id"] == id) {
1761 return article_cache[i]["data"];
1762 }
1763 }
1764 }
1765 return false;
1766 }
1767
1768 function cache_find_param(id, param) {
1769
1770 if (db) {
1771 var rs = db.execute("SELECT article FROM cache WHERE id = ? AND param = ?",
1772 [id, param]);
1773 var a = false;
1774
1775 if (rs.isValidRow()) {
1776 a = rs.field(0);
1777 }
1778
1779 rs.close();
1780
1781 return a;
1782
1783 } else {
1784 for (var i = 0; i < article_cache.length; i++) {
1785 if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
1786 return article_cache[i]["data"];
1787 }
1788 }
1789 }
1790 return false;
1791 }
1792
1793 function cache_check(id) {
1794
1795 if (db) {
1796 var rs = db.execute("SELECT COUNT(*) AS c FROM cache WHERE id = ?",
1797 [id]);
1798 var a = false;
1799
1800 if (rs.isValidRow()) {
1801 a = rs.field(0) != "0";
1802 }
1803
1804 rs.close();
1805
1806 return a;
1807
1808 } else {
1809 for (var i = 0; i < article_cache.length; i++) {
1810 if (article_cache[i]["id"] == id) {
1811 return true;
1812 }
1813 }
1814 }
1815 return false;
1816 }
1817
1818 function cache_check_param(id, param) {
1819
1820 if (db) {
1821 var rs = db.execute("SELECT COUNT(*) AS c FROM cache WHERE id = ? AND param = ?",
1822 [id, param]);
1823 var a = false;
1824
1825 if (rs.isValidRow()) {
1826 a = rs.field(0) != "0";
1827 }
1828
1829 rs.close();
1830
1831 return a;
1832
1833 } else {
1834 for (var i = 0; i < article_cache.length; i++) {
1835 if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
1836 return true;
1837 }
1838 }
1839 }
1840 return false;
1841 }
1842
1843 function cache_expire() {
1844 if (db) {
1845 var date = new Date();
1846 var ts = Math.round(date.getTime() / 1000);
1847
1848 db.execute("DELETE FROM cache WHERE added < ? - 1800 AND id LIKE 'FEEDLIST'", [ts]);
1849 db.execute("DELETE FROM cache WHERE added < ? - 600 AND (id LIKE 'F:%' OR id LIKE 'C:%')", [ts]);
1850 db.execute("DELETE FROM cache WHERE added < ? - 86400", [ts]);
1851
1852
1853 } else {
1854 while (article_cache.length > 25) {
1855 article_cache.shift();
1856 }
1857 }
1858 }
1859
1860 function cache_flush() {
1861 article_cache = new Array();
1862 }
1863
1864 function cache_invalidate(id) {
1865 try {
1866
1867 if (db) {
1868 rs = db.execute("DELETE FROM cache WHERE id = ?", [id]);
1869 return rs.rowsAffected != 0;
1870 } else {
1871
1872 var i = 0
1873
1874 while (i < article_cache.length) {
1875 if (article_cache[i]["id"] == id) {
1876 debug("cache_invalidate: removed id " + id);
1877 article_cache.splice(i, 1);
1878 return true;
1879 }
1880 i++;
1881 }
1882 }
1883
1884 debug("cache_invalidate: id not found: " + id);
1885 return false;
1886 } catch (e) {
1887 exception_error("cache_invalidate", e);
1888 }
1889 }
1890
1891 function getActiveArticleId() {
1892 return active_post_id;
1893 }
1894
1895 function cdmClicked(id) {
1896 try {
1897 var elem = $("RROW-" + id);
1898
1899 if (elem) {
1900 var id = elem.id.replace("RROW-", "");
1901 active_post_id = id;
1902
1903 // cdmSelectArticles("none");
1904 toggleUnread(id, 0, true);
1905 // toggleSelected(id);
1906
1907 }
1908 } catch (e) {
1909 exception_error("cdmClicked", e);
1910 }
1911 }
1912
1913 function preloadArticleUnderPointer(id) {
1914 try {
1915 if (getInitParam("bw_limit") == "1") return;
1916
1917 if (post_under_pointer == id && !cache_check(id)) {
1918
1919 debug("trying to preload article " + id);
1920
1921 var neighbor_ids = getRelativePostIds(id, 1);
1922
1923 /* only request uncached articles */
1924
1925 var cids_to_request = Array();
1926
1927 for (var i = 0; i < neighbor_ids.length; i++) {
1928 if (!cache_check(neighbor_ids[i])) {
1929 cids_to_request.push(neighbor_ids[i]);
1930 }
1931 }
1932 debug("additional ids: " + cids_to_request.toString());
1933
1934 cids_to_request.push(id);
1935
1936 var query = "?op=rpc&subop=getArticles&ids=" +
1937 cids_to_request.toString();
1938
1939 new Ajax.Request("backend.php", {
1940 parameters: query,
1941 onComplete: function(transport) {
1942 var articles = transport.responseXML.getElementsByTagName("article");
1943
1944 for (var i = 0; i < articles.length; i++) {
1945 var id = articles[i].getAttribute("id");
1946 if (!cache_check(id)) {
1947 cache_inject(id, articles[i].firstChild.nodeValue);
1948 debug("preloaded article: " + id);
1949 }
1950 }
1951 } });
1952 }
1953 } catch (e) {
1954 exception_error("preloadArticleUnderPointer", e);
1955 }
1956 }
1957
1958 function postMouseIn(id) {
1959 try {
1960 if (post_under_pointer != id) {
1961 post_under_pointer = id;
1962 if (!isCdmMode()) {
1963 window.setTimeout("preloadArticleUnderPointer(" + id + ")", 250);
1964 }
1965 }
1966
1967 } catch (e) {
1968 exception_error("postMouseIn", e);
1969 }
1970 }
1971
1972 function postMouseOut(id) {
1973 try {
1974 post_under_pointer = false;
1975 } catch (e) {
1976 exception_error("postMouseOut", e);
1977 }
1978 }
1979
1980 function headlines_scroll_handler() {
1981 try {
1982
1983 var e = $("headlinesInnerContainer");
1984
1985 var toolbar_form = document.forms["main_toolbar_form"];
1986
1987 debug((e.scrollTop + e.offsetHeight) + " vs " + e.scrollHeight + " dis? " +
1988 _infscroll_disable);
1989
1990 if (e.scrollTop + e.offsetHeight > e.scrollHeight - 100) {
1991 if (!_infscroll_disable) {
1992 debug("more cowbell!");
1993 viewNextFeedPage();
1994 }
1995 }
1996
1997 } catch (e) {
1998 exception_error("headlines_scroll_handler", e);
1999 }
2000 }
2001
2002 function catchupRelativeToArticle(below) {
2003
2004 try {
2005
2006
2007 if (!getActiveArticleId()) {
2008 alert(__("No article is selected."));
2009 return;
2010 }
2011
2012 var visible_ids;
2013
2014 if ($("headlinesList")) {
2015 visible_ids = getVisibleHeadlineIds();
2016 } else {
2017 visible_ids = cdmGetVisibleArticles();
2018 }
2019
2020 var ids_to_mark = new Array();
2021
2022 if (!below) {
2023 for (var i = 0; i < visible_ids.length; i++) {
2024 if (visible_ids[i] != getActiveArticleId()) {
2025 var e = $("RROW-" + visible_ids[i]);
2026
2027 if (e && e.className.match("Unread")) {
2028 ids_to_mark.push(visible_ids[i]);
2029 }
2030 } else {
2031 break;
2032 }
2033 }
2034 } else {
2035 for (var i = visible_ids.length-1; i >= 0; i--) {
2036 if (visible_ids[i] != getActiveArticleId()) {
2037 var e = $("RROW-" + visible_ids[i]);
2038
2039 if (e && e.className.match("Unread")) {
2040 ids_to_mark.push(visible_ids[i]);
2041 }
2042 } else {
2043 break;
2044 }
2045 }
2046 }
2047
2048 if (ids_to_mark.length == 0) {
2049 alert(__("No articles found to mark"));
2050 } else {
2051 var msg = __("Mark %d article(s) as read?").replace("%d", ids_to_mark.length);
2052
2053 if (confirm(msg)) {
2054
2055 for (var i = 0; i < ids_to_mark.length; i++) {
2056 var e = $("RROW-" + ids_to_mark[i]);
2057 e.className = e.className.replace("Unread", "");
2058 }
2059
2060 var query = "?op=rpc&subop=catchupSelected" +
2061 "&cmode=0" + "&ids=" + param_escape(ids_to_mark.toString());
2062
2063 new Ajax.Request("backend.php", {
2064 parameters: query,
2065 onComplete: function(transport) {
2066 catchup_callback2(transport);
2067 } });
2068
2069 }
2070 }
2071
2072 } catch (e) {
2073 exception_error("catchupRelativeToArticle", e);
2074 }
2075 }
2076
2077 function cdmExpandArticle(a_id) {
2078 try {
2079 var id = 'CICD-' + a_id;
2080
2081 try {
2082 Element.hide("CEXC-" + a_id);
2083 } catch (e) { }
2084
2085 Effect.Appear(id, {duration : 0.5,
2086 beforeStart: function(effect) {
2087 var h_id = 'CICH-' + a_id;
2088 var h_elem = $(h_id);
2089 if (h_elem) { h_elem.style.display = "none"; }
2090
2091 toggleUnread(a_id, 0);
2092 }});
2093
2094
2095 } catch (e) {
2096 exception_error("appearBlockElementF", e);
2097 }
2098
2099 }
2100
2101 function fixHeadlinesOrder(ids) {
2102 try {
2103 for (var i = 0; i < ids.length; i++) {
2104 var e = $("RROW-" + ids[i]);
2105
2106 if (e) {
2107 if (i % 2 == 0) {
2108 e.className = e.className.replace("even", "odd");
2109 } else {
2110 e.className = e.className.replace("odd", "even");
2111 }
2112 }
2113 }
2114 } catch (e) {
2115 exception_error("fixHeadlinesOrder", e);
2116 }
2117 }
2118
2119 function hideReadHeadlines() {
2120 try {
2121
2122 var ids = false;
2123 var vis_ids = new Array();
2124
2125 if ($("headlinesList")) {
2126 ids = getVisibleHeadlineIds();
2127 } else {
2128 ids = cdmGetVisibleArticles();
2129 }
2130
2131 var read_headlines_visible = true;
2132
2133 for (var i = 0; i < ids.length; i++) {
2134 var row = $("RROW-" + ids[i]);
2135
2136 if (row && row.className) {
2137 if (read_headlines_visible) {
2138 if (row.className.match("Unread") || row.className.match("Selected")) {
2139 Element.show(row);
2140 vis_ids.push(ids[i]);
2141 } else {
2142 //Effect.Fade(row, {duration : 0.3});
2143 Element.hide(row);
2144 }
2145 } else {
2146 Element.show(row);
2147 vis_ids.push(ids[i]);
2148 }
2149 }
2150 }
2151
2152 fixHeadlinesOrder(vis_ids);
2153
2154 read_headlines_visible = !read_headlines_visible;
2155
2156 } catch (e) {
2157 exception_error("hideReadHeadlines", e);
2158 }
2159 }
2160
2161 function invertHeadlineSelection() {
2162 try {
2163 var rows = new Array();
2164 var r = false;
2165
2166 if (!isCdmMode()) {
2167 r = document.getElementsByTagName("TR");
2168 } else {
2169 r = document.getElementsByTagName("DIV");
2170 }
2171
2172 for (var i = 0; i < r.length; i++) {
2173 if (r[i].id && r[i].id.match("RROW-")) {
2174 rows.push(r[i]);
2175 }
2176 }
2177
2178 for (var i = 0; i < rows.length; i++) {
2179 var nc = rows[i].className;
2180 var id = rows[i].id.replace("RROW-", "");
2181 var cb = $("RCHK-" + id);
2182
2183 if (!rows[i].className.match("Selected")) {
2184 nc = nc + "Selected";
2185 cb.checked = true;
2186 } else {
2187 nc = nc.replace("Selected", "");
2188 cb.checked = false;
2189 }
2190
2191 rows[i].className = nc;
2192
2193 }
2194
2195 } catch (e) {
2196 exception_error("invertHeadlineSelection", e);
2197 }
2198 }
2199
2200 function getArticleUnderPointer() {
2201 return post_under_pointer;
2202 }
2203
2204 function zoomToArticle(id) {
2205 try {
2206 var w = window.open("backend.php?op=view&mode=zoom&id=" + param_escape(id),
2207 "ttrss_zoom_" + id,
2208 "status=0,toolbar=0,location=0,width=450,height=300,scrollbars=1,menubar=0");
2209
2210 } catch (e) {
2211 exception_error("zoomToArticle", e);
2212 }
2213 }
2214
2215 function showOriginalArticleInline(id) {
2216 try {
2217
2218 var query = "?op=rpc&subop=getArticleLink&id=" + id;
2219
2220 notify_progress("Loading, please wait...", true);
2221
2222 new Ajax.Request("backend.php", {
2223 parameters: query,
2224 onComplete: function(transport) {
2225
2226 if (transport.responseXML) {
2227
2228 var link = transport.responseXML.getElementsByTagName("link")[0];
2229 var id = transport.responseXML.getElementsByTagName("id")[0];
2230
2231 notify("");
2232
2233 if (link && id) {
2234 link = link.firstChild.nodeValue;
2235
2236 var ci = $("content-insert");
2237
2238 var tmp = "<iframe id=\"inline_orig_article\" width=\""+ci.offsetWidth+"\" height=\""+ci.offsetHeight+"\" style=\"border-width : 0px;\" src=\""+link+"\"></iframe>";
2239
2240 render_article(tmp);
2241
2242 }
2243 }
2244 } });
2245
2246 } catch (e) {
2247 exception_error("showOriginalArticleInline", e);
2248 }
2249 }
2250
2251
2252 function scrollArticle(offset) {
2253 try {
2254 if (!isCdmMode()) {
2255 var ci = $("content-insert");
2256 if (ci) {
2257 ci.scrollTop += offset;
2258 }
2259 } else {
2260 var hi = $("headlinesInnerContainer");
2261 if (hi) {
2262 hi.scrollTop += offset;
2263 }
2264
2265 }
2266 } catch (e) {
2267 exception_error("scrollArticle", e);
2268 }
2269 }
2270
2271 function show_labels_in_headlines(transport) {
2272 try {
2273 if (transport.responseXML) {
2274 var info = transport.responseXML.getElementsByTagName("info-for-headlines")[0];
2275
2276 var elems = info.getElementsByTagName("entry");
2277
2278 for (var l = 0; l < elems.length; l++) {
2279 var e_id = elems[l].getAttribute("id");
2280
2281 if (e_id) {
2282
2283 var ctr = $("HLLCTR-" + e_id);
2284
2285 if (ctr) {
2286 ctr.innerHTML = elems[l].firstChild.nodeValue;
2287 }
2288 }
2289
2290 }
2291
2292 }
2293 } catch (e) {
2294 exception_error("show_labels_in_headlines", e);
2295
2296 }
2297 }
2298
2299 function toggleHeadlineActions() {
2300 try {
2301 var e = $("headlineActionsBody");
2302 var p = $("headlineActionsDrop");
2303
2304 if (!Element.visible(e)) {
2305 Element.show(e);
2306 } else {
2307 Element.hide(e);
2308 }
2309
2310 e.scrollTop = 0;
2311 e.style.left = (p.offsetLeft + 1) + "px";
2312 e.style.top = (p.offsetTop + p.offsetHeight + 2) + "px";
2313
2314 } catch (e) {
2315 exception_error("toggleHeadlineActions", e);
2316 }
2317 }
2318
2319 function publishWithNote(id, def_note) {
2320 try {
2321 if (!def_note) def_note = '';
2322
2323 var note = prompt(__("Please enter a note for this article:"), def_note);
2324
2325 if (note != undefined) {
2326 togglePub(id, false, false, note);
2327 }
2328
2329 } catch (e) {
2330 exception_error("publishWithNote", e);
2331 }
2332 }