1 var active_post_id = false;
2 var last_article_view = false;
3 var active_real_feed_id = false;
5 // FIXME: kludges, needs proper implementation
6 var _reload_feedlist_after_view = false;
8 var _cdm_wd_timeout = false;
9 var _cdm_wd_vishist = new Array();
11 var article_cache = new Array();
13 var vgroup_last_feed = false;
14 var post_under_pointer = false;
16 var last_requested_article = false;
18 function catchup_callback2(transport, callback) {
20 debug("catchup_callback2 " + transport + ", " + callback);
22 all_counters_callback2(transport);
24 setTimeout(callback, 10);
27 exception_error("catchup_callback2", e, transport);
31 function clean_feed_selections() {
33 var feeds = $("feedList").getElementsByTagName("LI");
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", "");
39 if (feeds[i].id && feeds[i].id.match("FCAT-")) {
40 feeds[i].className = feeds[i].className.replace("Selected", "");
44 exception_error("clean_feed_selections", e);
48 function headlines_callback2(transport, feed_cur_page) {
51 if (!transport.responseText && db) {
52 offlineConfirmModeChange();
56 loading_set_progress(100);
58 debug("headlines_callback2 [page=" + feed_cur_page + "]");
60 if (!transport_error_check(transport)) return;
62 clean_feed_selections();
67 if (transport.responseXML) {
68 var headlines = transport.responseXML.getElementsByTagName("headlines")[0];
70 is_cat = headlines.getAttribute("is_cat");
71 feed_id = headlines.getAttribute("id");
72 setActiveFeedId(feed_id, is_cat);
77 var feedr = $("FEEDR-" + feed_id);
78 if (feedr && !feedr.className.match("Selected")) {
79 feedr.className = feedr.className + "Selected";
82 var feedr = $("FCAT-" + feed_id);
83 if (feedr && !feedr.className.match("Selected")) {
84 feedr.className = feedr.className + "Selected";
88 var f = $("headlines-frame");
90 if (feed_cur_page == 0) {
91 debug("resetting headlines scrollTop");
96 if (transport.responseXML) {
97 var headlines = transport.responseXML.getElementsByTagName("headlines")[0];
98 var headlines_count_obj = transport.responseXML.getElementsByTagName("headlines-count")[0];
99 var headlines_unread_obj = transport.responseXML.getElementsByTagName("headlines-unread")[0];
100 var disable_cache_obj = transport.responseXML.getElementsByTagName("disable-cache")[0];
102 var vgroup_last_feed_obj = transport.responseXML.getElementsByTagName("vgroup-last-feed")[0];
104 var headlines_count = headlines_count_obj.getAttribute("value");
105 var headlines_unread = headlines_unread_obj.getAttribute("value");
106 var disable_cache = disable_cache_obj.getAttribute("value") != "0";
108 vgroup_last_feed = vgroup_last_feed_obj.getAttribute("value");
110 if (headlines_count == 0) {
111 _infscroll_disable = 1;
113 _infscroll_disable = 0;
116 var counters = transport.responseXML.getElementsByTagName("counters")[0];
117 var articles = transport.responseXML.getElementsByTagName("article");
118 var runtime_info = transport.responseXML.getElementsByTagName("runtime-info");
120 if (feed_cur_page == 0) {
122 f.innerHTML = headlines.firstChild.nodeValue;
124 var cache_prefix = "";
132 cache_invalidate(cache_prefix + feed_id);
134 if (!disable_cache) {
135 cache_inject(cache_prefix + feed_id,
136 headlines.firstChild.nodeValue, headlines_unread);
140 debug("headlines_callback: returned no data");
141 f.innerHTML = "<div class='whiteBox'>" + __('Could not update headlines (missing XML data)') + "</div>";
146 if (headlines_count > 0) {
147 debug("adding some more headlines...");
149 var c = $("headlinesList");
152 c = $("headlinesInnerContainer");
155 var ids = getSelectedArticleIds2();
157 c.innerHTML = c.innerHTML + headlines.firstChild.nodeValue;
159 debug("restore selected ids: " + ids);
161 for (var i = 0; i < ids.length; i++) {
162 markHeadline(ids[i]);
166 debug("no new headlines received");
169 debug("headlines_callback: returned no data");
170 notify_error("Error while trying to load more headlines");
176 for (var i = 0; i < articles.length; i++) {
177 var a_id = articles[i].getAttribute("id");
178 debug("found id: " + a_id);
179 cache_inject(a_id, articles[i].firstChild.nodeValue);
182 debug("no cached articles received");
186 debug("parsing piggybacked counters: " + counters);
187 parse_counters(counters, false);
189 debug("counters container not found in reply, requesting...");
194 debug("parsing runtime info: " + runtime_info[0]);
195 parse_runtime_info(runtime_info[0]);
197 debug("counters container not found in reply");
201 debug("headlines_callback: returned no XML object");
202 f.innerHTML = "<div class='whiteBox'>" + __('Could not update headlines (missing XML object)') + "</div>";
205 if (typeof correctPNG != 'undefined') {
209 if (_cdm_wd_timeout) window.clearTimeout(_cdm_wd_timeout);
211 if (!$("headlinesList") &&
212 getActiveFeedId() != -3 &&
213 getInitParam("cdm_auto_catchup") == 1) {
214 debug("starting CDM watchdog");
215 _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 5000);
216 _cdm_wd_vishist = new Array();
218 debug("not in CDM mode or watchdog disabled");
221 _feed_cur_page = feed_cur_page;
222 _infscroll_request_sent = 0;
229 exception_error("headlines_callback2", e, transport);
233 function render_article(article) {
235 var f = $("content-frame");
240 var fi = $("content-insert");
246 fi.innerHTML = article;
249 exception_error("render_article", e);
253 function showArticleInHeadlines(id) {
257 cleanSelected("headlinesList");
259 var crow = $("RROW-" + id);
263 var article_is_unread = crow.className.match("Unread");
265 crow.className = crow.className.replace("Unread", "");
267 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
269 var upd_img_pic = $("FUPDPIC-" + id);
271 var cache_prefix = "";
273 if (activeFeedIsCat()) {
279 var view_mode = false;
282 view_mode = document.forms['main_toolbar_form'].view_mode;
283 view_mode = view_mode[view_mode.selectedIndex].value;
288 if (upd_img_pic && upd_img_pic.src.match("updated.png")) {
289 upd_img_pic.src = "images/blank_icon.gif";
291 cache_invalidate(cache_prefix + getActiveFeedId());
293 cache_inject(cache_prefix + getActiveFeedId(),
294 $("headlines-frame").innerHTML,
295 get_feed_unread(getActiveFeedId()));
297 } else if (article_is_unread && view_mode == "all_articles") {
299 cache_invalidate(cache_prefix + getActiveFeedId());
301 cache_inject(cache_prefix + getActiveFeedId(),
302 $("headlines-frame").innerHTML,
303 get_feed_unread(getActiveFeedId())-1);
305 } else if (article_is_unread) {
306 cache_invalidate(cache_prefix + getActiveFeedId());
312 exception_error("showArticleInHeadlines", e);
316 function article_callback2(transport, id, feed_id) {
318 debug("article_callback2 " + id);
320 if (!transport.responseText && db) {
321 offlineConfirmModeChange();
325 if (transport.responseXML) {
327 if (!transport_error_check(transport)) return;
329 debug("looking for articles to cache...");
331 var articles = transport.responseXML.getElementsByTagName("article");
333 for (var i = 0; i < articles.length; i++) {
334 var a_id = articles[i].getAttribute("id");
336 debug("found id: " + a_id);
338 if (a_id == active_post_id) {
339 debug("active article, rendering...");
340 render_article(articles[i].firstChild.nodeValue);
343 cache_inject(a_id, articles[i].firstChild.nodeValue);
346 if (id != last_requested_article) {
347 debug("requested article id is out of sequence, aborting");
351 active_real_feed_id = feed_id;
354 showArticleInHeadlines(id);
357 db.execute("UPDATE articles SET unread = 0 WHERE id = ?", [id]);
360 var reply = transport.responseXML.firstChild.firstChild;
363 debug("article_callback: returned no XML object");
364 //var f = $("content-frame");
365 //f.innerHTML = "<div class='whiteBox'>" + __('Could not display article (missing XML object)') + "</div>";
368 var date = new Date();
369 last_article_view = date.getTime() / 1000;
371 if (typeof correctPNG != 'undefined') {
375 if (_reload_feedlist_after_view) {
376 setTimeout('updateFeedList(false, false)', 50);
377 _reload_feedlist_after_view = false;
379 if (transport.responseXML) {
380 var counters = transport.responseXML.getElementsByTagName("counters")[0];
383 debug("parsing piggybacked counters: " + counters);
384 parse_counters(counters, false);
386 debug("counters container not found in reply, requesting...");
394 exception_error("article_callback2", e, transport);
398 function view(id, feed_id, skip_history) {
401 debug("loading article: " + id + "/" + feed_id);
403 if (offline_mode) return view_offline(id, feed_id);
405 var cached_article = cache_find(id);
407 debug("cache check result: " + (cached_article != false));
411 //setActiveFeedId(feed_id);
413 var query = "backend.php?op=view&id=" + param_escape(id) +
414 "&feed=" + param_escape(feed_id);
416 var date = new Date();
418 var neighbor_ids = getRelativePostIds(active_post_id);
420 /* only request uncached articles */
422 var cids_to_request = Array();
424 for (var i = 0; i < neighbor_ids.length; i++) {
425 if (!cache_check(neighbor_ids[i])) {
426 cids_to_request.push(neighbor_ids[i]);
430 debug("additional ids: " + cids_to_request.toString());
432 /* additional info for piggyback counters */
434 if (tagsAreDisplayed()) {
435 query = query + "&omode=lt";
437 query = query + "&omode=flc";
440 var date = new Date();
441 var timestamp = Math.round(date.getTime() / 1000);
442 query = query + "&ts=" + timestamp;
444 query = query + "&cids=" + cids_to_request.toString();
446 var crow = $("RROW-" + id);
447 var article_is_unread = crow.className.match("Unread");
449 if (!async_counters_work) {
450 query = query + "&csync=true";
453 showArticleInHeadlines(id);
455 if (!cached_article) {
457 notify_progress("Loading, please wait...", true);
459 } else if (cached_article && article_is_unread) {
461 query = query + "&mode=prefetch";
463 render_article(cached_article);
465 } else if (cached_article) {
467 query = query + "&mode=prefetch_old";
468 render_article(cached_article);
474 last_requested_article = id;
476 new Ajax.Request(query, {
477 onComplete: function(transport) {
478 article_callback2(transport, id, feed_id);
484 exception_error("view", e);
489 return toggleMark(id);
493 return togglePub(id);
496 function tMark_afh_off(effect) {
498 var elem = effect.effects[0].element;
500 debug("tMark_afh_off : " + elem.id);
503 elem.src = elem.src.replace("mark_set", "mark_unset");
504 elem.alt = __("Star article");
509 exception_error("tMark_afh_off", e);
513 function tPub_afh_off(effect) {
515 var elem = effect.effects[0].element;
517 debug("tPub_afh_off : " + elem.id);
520 elem.src = elem.src.replace("pub_set", "pub_unset");
521 elem.alt = __("Publish article");
526 exception_error("tPub_afh_off", e);
530 function toggleMark(id, client_only, no_effects) {
534 var query = "backend.php?op=rpc&id=" + id + "&subop=mark";
536 query = query + "&afid=" + getActiveFeedId();
538 if (tagsAreDisplayed()) {
539 query = query + "&omode=tl";
541 query = query + "&omode=flc";
544 var mark_img = $("FMPIC-" + id);
546 if (!mark_img) return;
548 var vfeedu = $("FEEDU--1");
549 var crow = $("RROW-" + id);
551 if (mark_img.src.match("mark_unset")) {
552 mark_img.src = mark_img.src.replace("mark_unset", "mark_set");
553 mark_img.alt = __("Unstar article");
554 query = query + "&mark=1";
557 db.execute("UPDATE articles SET marked = 1 WHERE id = ?", [id]);
561 //mark_img.src = "images/mark_unset.png";
562 mark_img.alt = __("Please wait...");
563 query = query + "&mark=0";
565 if ($("headlinesList") && !no_effects) {
566 Effect.Puff(mark_img, {duration : 0.25, afterFinish: tMark_afh_off});
568 mark_img.src = mark_img.src.replace("mark_set", "mark_unset");
569 mark_img.alt = __("Star article");
573 db.execute("UPDATE articles SET marked = 0 WHERE id = ?", [id]);
578 if (!no_effects) update_local_feedlist_counters();
583 new Ajax.Request(query, {
584 onComplete: function(transport) {
585 all_counters_callback2(transport);
591 exception_error("toggleMark", e);
595 function togglePub(id, client_only, no_effects) {
599 var query = "backend.php?op=rpc&id=" + id + "&subop=publ";
601 query = query + "&afid=" + getActiveFeedId();
603 if (tagsAreDisplayed()) {
604 query = query + "&omode=tl";
606 query = query + "&omode=flc";
609 var mark_img = $("FPPIC-" + id);
611 if (!mark_img) return;
613 var vfeedu = $("FEEDU--2");
614 var crow = $("RROW-" + id);
616 if (mark_img.src.match("pub_unset")) {
617 mark_img.src = mark_img.src.replace("pub_unset", "pub_set");
618 mark_img.alt = __("Unpublish article");
619 query = query + "&pub=1";
623 //mark_img.src = "images/pub_unset.png";
624 mark_img.alt = __("Please wait...");
625 query = query + "&pub=0";
627 if ($("headlinesList") && !no_effects) {
628 Effect.Puff(mark_img, {duration : 0.25, afterFinish: tPub_afh_off});
630 mark_img.src = mark_img.src.replace("pub_set", "pub_unset");
631 mark_img.alt = __("Publish article");
636 new Ajax.Request(query, {
637 onComplete: function(transport) {
638 all_counters_callback2(transport);
644 exception_error("togglePub", e);
648 function correctHeadlinesOffset(id) {
652 var hlist = $("headlinesList");
653 var container = $("headlinesInnerContainer");
654 var row = $("RROW-" + id);
656 var viewport = container.offsetHeight;
658 var rel_offset_top = row.offsetTop - container.scrollTop;
659 var rel_offset_bottom = row.offsetTop + row.offsetHeight - container.scrollTop;
661 debug("Rtop: " + rel_offset_top + " Rbtm: " + rel_offset_bottom);
662 debug("Vport: " + viewport);
664 if (rel_offset_top <= 0 || rel_offset_top > viewport) {
665 container.scrollTop = row.offsetTop;
666 } else if (rel_offset_bottom > viewport) {
668 /* doesn't properly work with Opera in some cases because
669 Opera fucks up element scrolling */
671 container.scrollTop = row.offsetTop + row.offsetHeight - viewport;
675 exception_error("correctHeadlinesOffset", e);
680 function moveToPost(mode) {
687 rows = cdmGetVisibleArticles();
689 rows = getVisibleHeadlineIds();
695 if (!$('RROW-' + active_post_id)) {
696 active_post_id = false;
699 if (active_post_id == false) {
700 next_id = getFirstVisibleHeadlineId();
701 prev_id = getLastVisibleHeadlineId();
703 for (var i = 0; i < rows.length; i++) {
704 if (rows[i] == active_post_id) {
711 if (mode == "next") {
715 if (!cdmArticleIsActuallyVisible(next_id)) {
716 cdmScrollToArticleId(next_id);
718 cdmSelectArticles("none");
719 toggleUnread(next_id, 0, true);
720 toggleSelected(next_id);
723 correctHeadlinesOffset(next_id);
724 view(next_id, getActiveFeedId());
729 if (mode == "prev") {
732 cdmScrollToArticleId(prev_id);
733 cdmSelectArticles("none");
734 toggleUnread(prev_id, 0, true);
735 toggleSelected(prev_id);
737 correctHeadlinesOffset(prev_id);
738 view(prev_id, getActiveFeedId());
744 exception_error("moveToPost", e);
748 function toggleSelected(id) {
751 var cb = $("RCHK-" + id);
753 var row = $("RROW-" + id);
755 var nc = row.className;
757 if (!nc.match("Selected")) {
758 nc = nc + "Selected";
763 // In CDM basically last selected article == active article
764 if (isCdmMode()) active_post_id = id;
766 nc = nc.replace("Selected", "");
776 exception_error("toggleSelected", e);
780 function toggleUnread_afh(effect) {
783 var elem = effect.element;
784 elem.style.backgroundColor = "";
787 exception_error("toggleUnread_afh", e);
791 function toggleUnread(id, cmode, effect) {
794 var row = $("RROW-" + id);
796 var nc = row.className;
797 var is_selected = row.className.match("Selected");
798 nc = nc.replace("Unread", "");
799 nc = nc.replace("Selected", "");
801 // since we are removing selection from the object, uncheck
802 // corresponding checkbox
804 var cb = $("RCHK-" + id);
809 // NOTE: I'm not sure that resetting selection here is a feature -fox
811 if (cmode == undefined || cmode == 2) {
812 if (row.className.match("Unread")) {
816 new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
817 afterFinish: toggleUnread_afh,
818 queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
822 row.className = nc + "Unread";
826 db.execute("UPDATE articles SET unread = not unread "+
827 "WHERE id = ?", [id]);
830 } else if (cmode == 0) {
834 new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
835 afterFinish: toggleUnread_afh,
836 queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
840 db.execute("UPDATE articles SET unread = 0 "+
841 "WHERE id = ?", [id]);
844 } else if (cmode == 1) {
845 row.className = nc + "Unread";
848 db.execute("UPDATE articles SET unread = 1 "+
849 "WHERE id = ?", [id]);
854 update_local_feedlist_counters();
856 // Disable unmarking as selected for the time being (16.05.08) -fox
857 if (is_selected) row.className = row.className + "Selected";
859 if (cmode == undefined) cmode = 2;
861 var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
862 param_escape(id) + "&cmode=" + param_escape(cmode);
864 // notify_progress("Loading, please wait...");
866 new Ajax.Request(query, {
867 onComplete: function(transport) {
868 all_counters_callback2(transport);
874 exception_error("toggleUnread", e);
878 function selectionRemoveLabel(id) {
881 var ids = getSelectedArticleIds2();
883 if (ids.length == 0) {
884 alert(__("No articles are selected."));
888 // var ok = confirm(__("Remove selected articles from label?"));
892 var query = "backend.php?op=rpc&subop=removeFromLabel&ids=" +
893 param_escape(ids.toString()) + "&lid=" + param_escape(id);
895 // notify_progress("Loading, please wait...");
897 cache_invalidate("F:" + (-11 - id));
899 new Ajax.Request(query, {
900 onComplete: function(transport) {
901 show_labels_in_headlines(transport);
902 all_counters_callback2(transport);
908 exception_error("selectionAssignLabel", e);
913 function selectionAssignLabel(id) {
916 var ids = getSelectedArticleIds2();
918 if (ids.length == 0) {
919 alert(__("No articles are selected."));
923 // var ok = confirm(__("Assign selected articles to label?"));
927 cache_invalidate("F:" + (-11 - id));
929 var query = "backend.php?op=rpc&subop=assignToLabel&ids=" +
930 param_escape(ids.toString()) + "&lid=" + param_escape(id);
932 // notify_progress("Loading, please wait...");
934 new Ajax.Request(query, {
935 onComplete: function(transport) {
936 show_labels_in_headlines(transport);
937 all_counters_callback2(transport);
943 exception_error("selectionAssignLabel", e);
948 function selectionToggleUnread(cdm_mode, set_state, callback_func, no_error) {
953 rows = cdmGetSelectedArticles();
955 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
958 if (rows.length == 0 && !no_error) {
959 alert(__("No articles are selected."));
963 for (i = 0; i < rows.length; i++) {
964 var row = $("RROW-" + rows[i]);
966 var nc = row.className;
967 nc = nc.replace("Unread", "");
968 nc = nc.replace("Selected", "");
970 if (set_state == undefined) {
971 if (row.className.match("Unread")) {
972 row.className = nc + "Selected";
974 row.className = nc + "UnreadSelected";
977 db.execute("UPDATE articles SET unread = NOT unread WHERE id = ?",
982 if (set_state == false) {
983 row.className = nc + "Selected";
985 db.execute("UPDATE articles SET unread = 0 WHERE id = ?",
990 if (set_state == true) {
991 row.className = nc + "UnreadSelected";
993 db.execute("UPDATE articles SET unread = 1 WHERE id = ?",
1000 if (rows.length > 0) {
1002 update_local_feedlist_counters();
1006 if (set_state == undefined) {
1008 } else if (set_state == true) {
1010 } else if (set_state == false) {
1014 var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
1015 param_escape(rows.toString()) + "&cmode=" + cmode;
1017 notify_progress("Loading, please wait...");
1019 new Ajax.Request(query, {
1020 onComplete: function(transport) {
1021 catchup_callback2(transport, callback_func);
1027 exception_error("selectionToggleUnread", e);
1031 function selectionToggleMarked(cdm_mode) {
1037 rows = cdmGetSelectedArticles();
1039 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1042 if (rows.length == 0) {
1043 alert(__("No articles are selected."));
1047 for (i = 0; i < rows.length; i++) {
1048 toggleMark(rows[i], true, true);
1051 update_local_feedlist_counters();
1053 if (rows.length > 0) {
1055 var query = "backend.php?op=rpc&subop=markSelected&ids=" +
1056 param_escape(rows.toString()) + "&cmode=2";
1058 query = query + "&afid=" + getActiveFeedId();
1060 /* if (tagsAreDisplayed()) {
1061 query = query + "&omode=tl";
1063 query = query + "&omode=flc";
1066 query = query + "&omode=lc";
1068 new Ajax.Request(query, {
1069 onComplete: function(transport) {
1070 all_counters_callback2(transport);
1076 exception_error("selectionToggleMarked", e);
1080 function selectionTogglePublished(cdm_mode) {
1086 rows = cdmGetSelectedArticles();
1088 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1091 if (rows.length == 0) {
1092 alert(__("No articles are selected."));
1096 for (i = 0; i < rows.length; i++) {
1097 togglePub(rows[i], true, true);
1100 if (rows.length > 0) {
1102 var query = "backend.php?op=rpc&subop=publishSelected&ids=" +
1103 param_escape(rows.toString()) + "&cmode=2";
1105 query = query + "&afid=" + getActiveFeedId();
1107 /* if (tagsAreDisplayed()) {
1108 query = query + "&omode=tl";
1110 query = query + "&omode=flc";
1113 query = query + "&omode=lc";
1115 new Ajax.Request(query, {
1116 onComplete: function(transport) {
1117 all_counters_callback2(transport);
1123 exception_error("selectionToggleMarked", e);
1127 function cdmGetSelectedArticles() {
1128 var sel_articles = new Array();
1129 var container = $("headlinesInnerContainer");
1131 for (i = 0; i < container.childNodes.length; i++) {
1132 var child = container.childNodes[i];
1134 if (child.id && child.id.match("RROW-") && child.className.match("Selected")) {
1135 var c_id = child.id.replace("RROW-", "");
1136 sel_articles.push(c_id);
1140 return sel_articles;
1143 function cdmGetVisibleArticles() {
1144 var sel_articles = new Array();
1145 var container = $("headlinesInnerContainer");
1147 if (!container) return sel_articles;
1149 for (i = 0; i < container.childNodes.length; i++) {
1150 var child = container.childNodes[i];
1152 if (child.id && child.id.match("RROW-")) {
1153 var c_id = child.id.replace("RROW-", "");
1154 sel_articles.push(c_id);
1158 return sel_articles;
1161 function cdmGetUnreadArticles() {
1162 var sel_articles = new Array();
1163 var container = $("headlinesInnerContainer");
1165 for (i = 0; i < container.childNodes.length; i++) {
1166 var child = container.childNodes[i];
1168 if (child.id && child.id.match("RROW-") && child.className.match("Unread")) {
1169 var c_id = child.id.replace("RROW-", "");
1170 sel_articles.push(c_id);
1174 return sel_articles;
1178 // mode = all,none,unread
1179 function cdmSelectArticles(mode) {
1180 var container = $("headlinesInnerContainer");
1182 for (i = 0; i < container.childNodes.length; i++) {
1183 var child = container.childNodes[i];
1185 if (child.id && child.id.match("RROW-")) {
1186 var aid = child.id.replace("RROW-", "");
1188 var cb = $("RCHK-" + aid);
1190 if (mode == "all") {
1191 if (!child.className.match("Selected")) {
1192 child.className = child.className + "Selected";
1195 } else if (mode == "unread") {
1196 if (child.className.match("Unread") && !child.className.match("Selected")) {
1197 child.className = child.className + "Selected";
1201 child.className = child.className.replace("Selected", "");
1208 function catchupPage() {
1210 var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
1212 var str = __("Mark all visible articles in %s as read?");
1214 str = str.replace("%s", fn);
1216 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
1220 if ($("headlinesList")) {
1221 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', true, 'Unread', true);
1222 selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
1223 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
1225 cdmSelectArticles('all');
1226 selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
1227 cdmSelectArticles('none');
1231 function catchupSelection() {
1237 if ($("headlinesList")) {
1238 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1240 rows = cdmGetSelectedArticles();
1243 if (rows.length == 0) {
1244 alert(__("No articles are selected."));
1249 var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
1251 var str = __("Mark %d selected articles in %s as read?");
1253 str = str.replace("%d", rows.length);
1254 str = str.replace("%s", fn);
1256 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
1260 if ($("headlinesList")) {
1261 selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
1262 // selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
1264 selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
1265 // cdmSelectArticles('none');
1269 exception_error("catchupSelection", e);
1273 function editArticleTags(id, feed_id, cdm_enabled) {
1274 displayDlg('editArticleTags', id);
1278 function tag_saved_callback(transport) {
1280 debug("in tag_saved_callback");
1285 if (tagsAreDisplayed()) {
1286 _reload_feedlist_after_view = true;
1290 if (transport.responseXML) {
1291 var tags_str = transport.responseXML.getElementsByTagName("tags-str")[0];
1294 var id = tags_str.getAttribute("id");
1297 var tags = $("ATSTR-" + id);
1299 tags.innerHTML = tags_str.firstChild.nodeValue;
1306 exception_error("tag_saved_callback", e);
1310 function editTagsSave() {
1312 notify_progress("Saving article tags...");
1314 var form = document.forms["tag_edit_form"];
1316 var query = Form.serialize("tag_edit_form");
1318 query = "backend.php?op=rpc&subop=setArticleTags&" + query;
1322 new Ajax.Request(query, {
1323 onComplete: function(transport) {
1324 tag_saved_callback(transport);
1329 function editTagsInsert() {
1332 var form = document.forms["tag_edit_form"];
1334 var found_tags = form.found_tags;
1335 var tags_str = form.tags_str;
1337 var tag = found_tags[found_tags.selectedIndex].value;
1339 if (tags_str.value.length > 0 &&
1340 tags_str.value.lastIndexOf(", ") != tags_str.value.length - 2) {
1342 tags_str.value = tags_str.value + ", ";
1345 tags_str.value = tags_str.value + tag + ", ";
1347 found_tags.selectedIndex = 0;
1350 exception_error("editTagsInsert", e);
1354 function cdmScrollViewport(where) {
1355 debug("cdmScrollViewport: " + where);
1357 var ctr = $("headlinesInnerContainer");
1361 if (where == "bottom") {
1362 ctr.scrollTop = ctr.scrollHeight;
1364 ctr.scrollTop = where;
1368 function cdmArticleIsBelowViewport(id) {
1370 var ctr = $("headlinesInnerContainer");
1371 var e = $("RROW-" + id);
1373 if (!e || !ctr) return;
1375 // article starts below viewport
1377 if (ctr.scrollTop < e.offsetTop) {
1384 exception_error("cdmArticleIsVisible", e);
1388 function cdmArticleIsAboveViewport(id) {
1390 var ctr = $("headlinesInnerContainer");
1391 var e = $("RROW-" + id);
1393 if (!e || !ctr) return;
1395 // article starts above viewport
1397 if (ctr.scrollTop > e.offsetTop + e.offsetHeight) {
1404 exception_error("cdmArticleIsVisible", e);
1408 function cdmScrollToArticleId(id) {
1410 var ctr = $("headlinesInnerContainer");
1411 var e = $("RROW-" + id);
1413 if (!e || !ctr) return;
1415 ctr.scrollTop = e.offsetTop;
1418 exception_error("cdmScrollToArticleId", e);
1422 function cdmArticleIsActuallyVisible(id) {
1424 var ctr = $("headlinesInnerContainer");
1425 var e = $("RROW-" + id);
1427 if (!e || !ctr) return;
1429 // article fits in viewport OR article is longer than viewport and
1430 // its bottom is visible
1432 if (ctr.scrollTop <= e.offsetTop && e.offsetTop + e.offsetHeight <=
1433 ctr.scrollTop + ctr.offsetHeight) {
1437 } else if (e.offsetHeight > ctr.offsetHeight &&
1438 e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1439 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight) {
1448 exception_error("cdmArticleIsVisible", e);
1452 function cdmWatchdog() {
1456 var ctr = $("headlinesInnerContainer");
1460 var ids = new Array();
1462 var e = ctr.firstChild;
1465 if (e.className && e.className == "cdmArticleUnread" && e.id &&
1466 e.id.match("RROW-")) {
1468 // article fits in viewport OR article is longer than viewport and
1469 // its bottom is visible
1471 if (ctr.scrollTop <= e.offsetTop && e.offsetTop + e.offsetHeight <=
1472 ctr.scrollTop + ctr.offsetHeight) {
1474 // debug(e.id + " is visible " + e.offsetTop + "." +
1475 // (e.offsetTop + e.offsetHeight) + " vs " + ctr.scrollTop + "." +
1476 // (ctr.scrollTop + ctr.offsetHeight));
1478 ids.push(e.id.replace("RROW-", ""));
1480 } else if (e.offsetHeight > ctr.offsetHeight &&
1481 e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1482 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight) {
1484 ids.push(e.id.replace("RROW-", ""));
1488 // method 2: article bottom is visible and is in upper 1/2 of the viewport
1490 /* if (e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
1491 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight/2) {
1493 ids.push(e.id.replace("RROW-", ""));
1502 debug("cdmWatchdog, ids= " + ids.toString());
1504 if (ids.length > 0) {
1506 for (var i = 0; i < ids.length; i++) {
1507 var e = $("RROW-" + ids[i]);
1509 e.className = e.className.replace("Unread", "");
1513 var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
1514 param_escape(ids.toString()) + "&cmode=0";
1516 new Ajax.Request(query, {
1517 onComplete: function(transport) {
1518 all_counters_callback2(transport);
1523 _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 4000);
1526 exception_error("cdmWatchdog", e);
1532 function cache_inject(id, article, param) {
1534 if (!cache_check_param(id, param)) {
1535 debug("cache_article: miss: " + id + " [p=" + param + "]");
1540 var date = new Date();
1541 var ts = Math.round(date.getTime() / 1000);
1543 db.execute("INSERT INTO cache (id, article, param, added) VALUES (?, ?, ?, ?)",
1544 [id, article, param, ts]);
1547 var cache_obj = new Array();
1549 cache_obj["id"] = id;
1550 cache_obj["data"] = article;
1551 cache_obj["param"] = param;
1553 article_cache.push(cache_obj);
1557 debug("cache_article: hit: " + id + " [p=" + param + "]");
1560 exception_error("cache_inject", e);
1564 function cache_find(id) {
1567 var rs = db.execute("SELECT article FROM cache WHERE id = ?", [id]);
1570 if (rs.isValidRow()) {
1571 var a = rs.field(0);
1579 for (var i = 0; i < article_cache.length; i++) {
1580 if (article_cache[i]["id"] == id) {
1581 return article_cache[i]["data"];
1588 function cache_find_param(id, param) {
1591 var rs = db.execute("SELECT article FROM cache WHERE id = ? AND param = ?",
1595 if (rs.isValidRow()) {
1604 for (var i = 0; i < article_cache.length; i++) {
1605 if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
1606 return article_cache[i]["data"];
1613 function cache_check(id) {
1616 var rs = db.execute("SELECT COUNT(*) AS c FROM cache WHERE id = ?",
1620 if (rs.isValidRow()) {
1621 a = rs.field(0) != "0";
1629 for (var i = 0; i < article_cache.length; i++) {
1630 if (article_cache[i]["id"] == id) {
1638 function cache_check_param(id, param) {
1641 var rs = db.execute("SELECT COUNT(*) AS c FROM cache WHERE id = ? AND param = ?",
1645 if (rs.isValidRow()) {
1646 a = rs.field(0) != "0";
1654 for (var i = 0; i < article_cache.length; i++) {
1655 if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
1663 function cache_expire() {
1665 var date = new Date();
1666 var ts = Math.round(date.getTime() / 1000);
1668 db.execute("DELETE FROM cache WHERE added < ? - 1800 AND id LIKE 'FEEDLIST'", [ts]);
1669 db.execute("DELETE FROM cache WHERE added < ? - 600 AND (id LIKE 'F:%' OR id LIKE 'C:%')", [ts]);
1670 db.execute("DELETE FROM cache WHERE added < ? - 86400", [ts]);
1674 while (article_cache.length > 25) {
1675 article_cache.shift();
1680 function cache_empty() {
1681 article_cache = new Array();
1684 function cache_invalidate(id) {
1688 rs = db.execute("DELETE FROM cache WHERE id = ?", [id]);
1689 return rs.rowsAffected != 0;
1694 while (i < article_cache.length) {
1695 if (article_cache[i]["id"] == id) {
1696 debug("cache_invalidate: removed id " + id);
1697 article_cache.splice(i, 1);
1704 debug("cache_invalidate: id not found: " + id);
1707 exception_error("cache_invalidate", e);
1711 function getActiveArticleId() {
1712 return active_post_id;
1715 function cdmClicked(id) {
1717 var elem = $("RROW-" + id);
1720 var id = elem.id.replace("RROW-", "");
1721 active_post_id = id;
1723 // cdmSelectArticles("none");
1724 toggleUnread(id, 0, true);
1725 // toggleSelected(id);
1729 exception_error("cdmClicked", e);
1733 function preload_article_callback(transport) {
1735 if (transport.responseXML) {
1736 var articles = transport.responseXML.getElementsByTagName("article");
1738 for (var i = 0; i < articles.length; i++) {
1739 var id = articles[i].getAttribute("id");
1740 if (!cache_check(id)) {
1741 cache_inject(id, articles[i].firstChild.nodeValue);
1742 debug("preloaded article: " + id);
1747 exception_error("preload_article_callback", e);
1751 function preloadArticleUnderPointer(id) {
1753 if (getInitParam("bw_limit") == "1") return;
1755 if (post_under_pointer == id && !cache_check(id)) {
1757 debug("trying to preload article " + id);
1759 var neighbor_ids = getRelativePostIds(id, 1);
1761 /* only request uncached articles */
1763 var cids_to_request = Array();
1765 for (var i = 0; i < neighbor_ids.length; i++) {
1766 if (!cache_check(neighbor_ids[i])) {
1767 cids_to_request.push(neighbor_ids[i]);
1770 debug("additional ids: " + cids_to_request.toString());
1772 cids_to_request.push(id);
1774 var query = "backend.php?op=rpc&subop=getArticles&ids=" +
1775 cids_to_request.toString();
1776 new Ajax.Request(query, {
1777 onComplete: function(transport) {
1778 preload_article_callback(transport);
1782 exception_error("preloadArticleUnderPointer", e);
1786 function postMouseIn(id) {
1788 if (post_under_pointer != id) {
1789 post_under_pointer = id;
1791 window.setTimeout("preloadArticleUnderPointer(" + id + ")", 250);
1796 exception_error("postMouseIn", e);
1800 function postMouseOut(id) {
1802 post_under_pointer = false;
1804 exception_error("postMouseOut", e);
1808 function headlines_scroll_handler() {
1811 var e = $("headlinesInnerContainer");
1813 // don't do infinite scrolling when Limit == All
1815 var toolbar_form = document.forms["main_toolbar_form"];
1817 var limit = toolbar_form.limit[toolbar_form.limit.selectedIndex];
1818 if (limit.value != 0) {
1820 debug((e.scrollTop + e.offsetHeight) + " vs " + e.scrollHeight + " dis? " +
1821 _infscroll_disable);
1823 if (e.scrollTop + e.offsetHeight > e.scrollHeight - 100) {
1824 if (!_infscroll_disable) {
1825 debug("more cowbell!");
1832 exception_error("headlines_scroll_handler", e);
1836 function catchupRelativeToArticle(below) {
1841 if (!getActiveArticleId()) {
1842 alert(__("No article is selected."));
1848 if ($("headlinesList")) {
1849 visible_ids = getVisibleHeadlineIds();
1851 visible_ids = cdmGetVisibleArticles();
1854 var ids_to_mark = new Array();
1857 for (var i = 0; i < visible_ids.length; i++) {
1858 if (visible_ids[i] != getActiveArticleId()) {
1859 var e = $("RROW-" + visible_ids[i]);
1861 if (e && e.className.match("Unread")) {
1862 ids_to_mark.push(visible_ids[i]);
1869 for (var i = visible_ids.length-1; i >= 0; i--) {
1870 if (visible_ids[i] != getActiveArticleId()) {
1871 var e = $("RROW-" + visible_ids[i]);
1873 if (e && e.className.match("Unread")) {
1874 ids_to_mark.push(visible_ids[i]);
1882 if (ids_to_mark.length == 0) {
1883 alert(__("No articles found to mark"));
1885 var msg = __("Mark %d article(s) as read?").replace("%d", ids_to_mark.length);
1889 for (var i = 0; i < ids_to_mark.length; i++) {
1890 var e = $("RROW-" + ids_to_mark[i]);
1891 e.className = e.className.replace("Unread", "");
1894 var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
1895 param_escape(ids_to_mark.toString()) + "&cmode=0";
1897 new Ajax.Request(query, {
1898 onComplete: function(transport) {
1899 catchup_callback2(transport);
1906 exception_error("catchupRelativeToArticle", e);
1910 function cdmExpandArticle(a_id) {
1912 var id = 'CICD-' + a_id;
1915 Element.hide("CEXC-" + a_id);
1918 Effect.Appear(id, {duration : 0.5,
1919 beforeStart: function(effect) {
1920 var h_id = 'CICH-' + a_id;
1921 var h_elem = $(h_id);
1922 if (h_elem) { h_elem.style.display = "none"; }
1924 toggleUnread(a_id, 0);
1929 exception_error("appearBlockElementF", e);
1934 function fixHeadlinesOrder(ids) {
1936 for (var i = 0; i < ids.length; i++) {
1937 var e = $("RROW-" + ids[i]);
1941 e.className = e.className.replace("even", "odd");
1943 e.className = e.className.replace("odd", "even");
1948 exception_error("fixHeadlinesOrder", e);
1952 function hideReadHeadlines() {
1956 var vis_ids = new Array();
1958 if ($("headlinesList")) {
1959 ids = getVisibleHeadlineIds();
1961 ids = cdmGetVisibleArticles();
1964 var read_headlines_visible = true;
1966 for (var i = 0; i < ids.length; i++) {
1967 var row = $("RROW-" + ids[i]);
1969 if (row && row.className) {
1970 if (read_headlines_visible) {
1971 if (row.className.match("Unread") || row.className.match("Selected")) {
1973 vis_ids.push(ids[i]);
1975 //Effect.Fade(row, {duration : 0.3});
1980 vis_ids.push(ids[i]);
1985 fixHeadlinesOrder(vis_ids);
1987 read_headlines_visible = !read_headlines_visible;
1990 exception_error("hideReadHeadlines", e);
1994 function invertHeadlineSelection() {
1996 var rows = new Array();
2000 r = document.getElementsByTagName("TR");
2002 r = document.getElementsByTagName("DIV");
2005 for (var i = 0; i < r.length; i++) {
2006 if (r[i].id && r[i].id.match("RROW-")) {
2011 for (var i = 0; i < rows.length; i++) {
2012 var nc = rows[i].className;
2013 var id = rows[i].id.replace("RROW-", "");
2014 var cb = $("RCHK-" + id);
2016 if (!rows[i].className.match("Selected")) {
2017 nc = nc + "Selected";
2020 nc = nc.replace("Selected", "");
2024 rows[i].className = nc;
2029 exception_error("invertHeadlineSelection", e);
2033 function getArticleUnderPointer() {
2034 return post_under_pointer;
2037 function zoomToArticle(id) {
2039 var w = window.open("backend.php?op=view&mode=zoom&id=" + param_escape(id),
2041 "status=0,toolbar=0,location=0,width=450,height=300,scrollbars=1,menubar=0");
2044 exception_error("zoomToArticle", e);
2048 function showOriginalArticleInline(id) {
2051 var query = "backend.php?op=rpc&subop=getArticleLink&id=" + id;
2053 notify_progress("Loading, please wait...", true);
2055 new Ajax.Request(query, {
2056 onComplete: function(transport) {
2058 if (transport.responseXML) {
2060 var link = transport.responseXML.getElementsByTagName("link")[0];
2061 var id = transport.responseXML.getElementsByTagName("id")[0];
2066 link = link.firstChild.nodeValue;
2068 var ci = $("content-insert");
2070 var tmp = "<iframe id=\"inline_orig_article\" width=\""+ci.offsetWidth+"\" height=\""+ci.offsetHeight+"\" style=\"border-width : 0px;\" src=\""+link+"\"></iframe>";
2072 render_article(tmp);
2079 exception_error("showOriginalArticleInline", e);
2084 function scrollArticle(offset) {
2087 var ci = $("content-insert");
2089 ci.scrollTop += offset;
2092 var hi = $("headlinesInnerContainer");
2094 hi.scrollTop += offset;
2099 exception_error("scrollArticle", e);
2103 function show_labels_in_headlines(transport) {
2105 if (transport.responseXML) {
2106 var info = transport.responseXML.getElementsByTagName("info-for-headlines")[0];
2108 var elems = info.getElementsByTagName("entry");
2110 for (var l = 0; l < elems.length; l++) {
2111 var e_id = elems[l].getAttribute("id");
2115 var ctr = $("HLLCTR-" + e_id);
2118 ctr.innerHTML = elems[l].firstChild.nodeValue;
2126 exception_error("show_labels_in_headlines", e);
2131 function toggleHeadlineActions() {
2133 var e = $("headlineActionsBody");
2134 var p = $("headlineActionsDrop");
2136 if (!Element.visible(e)) {
2143 e.style.left = (p.offsetLeft + 1) + "px";
2144 e.style.top = (p.offsetTop + p.offsetHeight + 2) + "px";
2147 exception_error("toggleHeadlineActions", e);