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
);