]>
git.wh0rd.org - tt-rss.git/blob - js/viewfeed.js
4c6d903660cc2279d5c01214b4b007b685baad76
1 var article_cache
= new Array();
3 var _active_article_id
= 0;
5 var vgroup_last_feed
= false;
6 var post_under_pointer
= false;
8 var last_requested_article
= false;
10 var catchup_id_batch
= [];
11 var catchup_timeout_id
= false;
13 var cids_requested
= [];
14 var loaded_article_ids
= [];
16 var has_storage
= 'sessionStorage' in window
&& window
['sessionStorage'] !== null;
18 function headlines_callback2(transport
, offset
, background
, infscroll_req
) {
20 handle_rpc_json(transport
);
22 loading_set_progress(25);
24 console
.log("headlines_callback2 [offset=" + offset
+ "] B:" + background
+ " I:" + infscroll_req
);
32 reply
= JSON
.parse(transport
.responseText
);
39 is_cat
= reply
['headlines']['is_cat'];
40 feed_id
= reply
['headlines']['id'];
43 var content
= reply
['headlines']['content'];
45 if (getInitParam("cdm_auto_catchup") == 1) {
46 content
= content
+ "<div id='headlines-spacer'></div>";
51 setActiveFeedId(feed_id
, is_cat
);
53 dijit
.getEnclosingWidget(
54 document
.forms
["main_toolbar_form"].update
).attr('disabled',
55 is_cat
|| feed_id
<= 0);
58 if (infscroll_req
== false) {
59 $("headlines-frame").scrollTop
= 0;
63 var headlines_count
= reply
['headlines-info']['count'];
65 vgroup_last_feed
= reply
['headlines-info']['vgroup_last_feed'];
67 if (parseInt(headlines_count
) < getInitParam("default_article_limit")) {
68 _infscroll_disable
= 1;
70 _infscroll_disable
= 0;
73 var counters
= reply
['counters'];
74 var articles
= reply
['articles'];
75 //var runtime_info = reply['runtime-info'];
77 if (infscroll_req
== false) {
78 loaded_article_ids
= [];
80 dijit
.byId("headlines-frame").attr('content',
81 reply
['headlines']['content']);
83 dijit
.byId("headlines-toolbar").attr('content',
84 reply
['headlines']['toolbar']);
86 $$("#headlines-frame > div[id*=RROW]").each(function(row
) {
87 if (loaded_article_ids
.indexOf(row
.id
) != -1) {
88 row
.parentNode
.removeChild(row
);
90 loaded_article_ids
.push(row
.id
);
94 if (getInitParam("cdm_auto_catchup") == 1) {
95 var hsp
= $("headlines-spacer");
96 if (!hsp
) hsp
= new Element("DIV", {"id": "headlines-spacer"});
97 dijit
.byId('headlines-frame').domNode
.appendChild(hsp
);
103 $("feed_title").innerHTML
+= "<span id='cancel_search'>" +
104 " (<a href='#' onclick='cancelSearch()'>" + __("Cancel search") + "</a>)" +
110 if (headlines_count
> 0 && feed_id
== getActiveFeedId() && is_cat
== activeFeedIsCat()) {
111 console
.log("adding some more headlines: " + headlines_count
);
113 var c
= dijit
.byId("headlines-frame");
114 var ids
= getSelectedArticleIds2();
117 $("headlines-tmp").innerHTML
= reply
['headlines']['content'];
119 var hsp
= $("headlines-spacer");
122 c
.domNode
.removeChild(hsp
);
124 $$("#headlines-tmp > div").each(function(row
) {
125 if (row
.className
== 'cdmFeedTitle') {
126 row
.style
.display
= 'none';
127 c
.domNode
.appendChild(row
);
129 } else if (loaded_article_ids
.indexOf(row
.id
) == -1) {
130 row
.style
.display
= 'none';
131 c
.domNode
.appendChild(row
);
133 loaded_article_ids
.push(row
.id
);
135 row
.parentNode
.removeChild(row
);
139 if (!hsp
) hsp
= new Element("DIV", {"id": "headlines-spacer"});
141 fixHeadlinesOrder(getLoadedArticleIds());
143 if (getInitParam("cdm_auto_catchup") == 1) {
144 c
.domNode
.appendChild(hsp
);
147 console
.log("added " + new_elems
.size() + " headlines");
149 if (new_elems
.size() == 0)
150 _infscroll_disable
= true;
152 console
.log("restore selected ids: " + ids
);
154 for (var i
= 0; i
< ids
.length
; i
++) {
155 markHeadline(ids
[i
]);
160 new_elems
.each(function(child
) {
161 var cb
= dijit
.byId(child
.id
.replace("RROW-", "RCHK-"));
164 dojo
.parser
.parse(child
);
166 if (!Element
.visible(child
))
167 new Effect
.Appear(child
, { duration
: 0.5 });
169 c
.domNode
.removeChild(child
);
174 console
.log("no new headlines received");
176 var hsp
= $("headlines-spacer");
178 if (hsp
) hsp
.innerHTML
= "";
183 for (var i
= 0; i
< articles
.length
; i
++) {
184 var a_id
= articles
[i
]['id'];
185 cache_set("article:" + a_id
, articles
[i
]['content']);
188 console
.log("no cached articles received");
192 parse_counters(counters
);
194 request_counters(true);
196 } else if (transport
.responseText
) {
197 console
.error("Invalid object received: " + transport
.responseText
);
198 dijit
.byId("headlines-frame").attr('content', "<div class='whiteBox'>" +
199 __('Could not update headlines (invalid object received - see error console for details)') +
202 //notify_error("Error communicating with server.");
203 Element
.show(dijit
.byId("net-alert").domNode
);
206 _infscroll_request_sent
= 0;
211 exception_error("headlines_callback2", e
, transport
);
215 function render_article(article
) {
217 dijit
.byId("headlines-wrap-inner").addChild(
218 dijit
.byId("content-insert"));
220 var c
= dijit
.byId("content-insert");
223 c
.domNode
.scrollTop
= 0;
226 c
.attr('content', article
);
228 correctHeadlinesOffset(getActiveArticleId());
235 exception_error("render_article", e
);
239 function showArticleInHeadlines(id
) {
243 selectArticles("none");
245 var crow
= $("RROW-" + id
);
249 var article_is_unread
= crow
.hasClassName("Unread");
251 crow
.removeClassName("Unread");
253 selectArticles('none');
255 var view_mode
= false;
258 view_mode
= document
.forms
['main_toolbar_form'].view_mode
;
259 view_mode
= view_mode
[view_mode
.selectedIndex
].value
;
266 if (article_is_unread
)
267 _force_scheduled_update
= true;
270 exception_error("showArticleInHeadlines", e
);
274 function article_callback2(transport
, id
) {
276 console
.log("article_callback2 " + id
);
278 handle_rpc_json(transport
);
283 reply
= JSON
.parse(transport
.responseText
);
290 reply
.each(function(article
) {
291 if (getActiveArticleId() == article
['id']) {
292 render_article(article
['content']);
294 cids_requested
.remove(article
['id']);
296 cache_set("article:" + article
['id'], article
['content']);
299 // if (id != last_requested_article) {
300 // console.log("requested article id is out of sequence, aborting");
304 } else if (transport
.responseText
) {
305 console
.error("Invalid object received: " + transport
.responseText
);
307 render_article("<div class='whiteBox'>" +
308 __('Could not display article (invalid object received - see error console for details)') + "</div>");
310 Element
.show(dijit
.byId("net-alert").domNode
);
313 var unread_in_buffer
= $$("#headlines-frame > div[id*=RROW][class*=Unread]").length
314 request_counters(unread_in_buffer
== 0);
316 headlines_scroll_handler($("headlines-frame"));
319 if (!_infscroll_disable &&
320 $$("#headlines-frame > div[id*=RROW]").last().hasClassName("Selected")) {
330 exception_error("article_callback2", e
, transport
);
336 var crow
= $("RROW-" + id
);
340 console
.log("loading article: " + id
);
342 var cached_article
= cache_get("article:" + id
);
344 console
.log("cache check result: " + (cached_article
!= false));
348 var query
= "?op=article&method=view&id=" + param_escape(id
);
350 var neighbor_ids
= getRelativePostIds(id
);
352 /* only request uncached articles */
354 var cids_to_request
= [];
356 for (var i
= 0; i
< neighbor_ids
.length
; i
++) {
357 if (cids_requested
.indexOf(neighbor_ids
[i
]) == -1)
358 if (!cache_get("article:" + neighbor_ids
[i
])) {
359 cids_to_request
.push(neighbor_ids
[i
]);
360 cids_requested
.push(neighbor_ids
[i
]);
364 console
.log("additional ids: " + cids_to_request
.toString());
366 query
= query
+ "&cids=" + cids_to_request
.toString();
368 var article_is_unread
= crow
.hasClassName("Unread");
370 setActiveArticleId(id
);
371 showArticleInHeadlines(id
);
373 if (cached_article
&& article_is_unread
) {
375 query
= query
+ "&mode=prefetch";
377 render_article(cached_article
);
379 } else if (cached_article
) {
381 query
= query
+ "&mode=prefetch_old";
382 render_article(cached_article
);
384 // if we don't need to request any relative ids, we might as well skip
385 // the server roundtrip altogether
386 if (cids_to_request
.length
== 0) {
389 if (!_infscroll_disable &&
390 $$("#headlines-frame > div[id*=RROW]").last().hasClassName("Selected")) {
398 headlines_scroll_handler($("headlines-frame"));
404 last_requested_article
= id
;
408 if (article_is_unread
) {
409 decrementFeedCounter(getActiveFeedId(), activeFeedIsCat());
412 new Ajax
.Request("backend.php", {
414 onComplete: function(transport
) {
415 article_callback2(transport
, id
);
421 exception_error("view", e
);
425 function toggleMark(id
, client_only
) {
427 var query
= "?op=rpc&id=" + id
+ "&method=mark";
429 var img
= $("FMPIC-" + id
);
433 if (img
.src
.match("mark_unset")) {
434 img
.src
= img
.src
.replace("mark_unset", "mark_set");
435 img
.alt
= __("Unstar article");
436 query
= query
+ "&mark=1";
439 img
.src
= img
.src
.replace("mark_set", "mark_unset");
440 img
.alt
= __("Star article");
441 query
= query
+ "&mark=0";
445 new Ajax
.Request("backend.php", {
447 onComplete: function(transport
) {
448 handle_rpc_json(transport
);
453 exception_error("toggleMark", e
);
457 function togglePub(id
, client_only
, no_effects
, note
) {
459 var query
= "?op=rpc&id=" + id
+ "&method=publ";
461 if (note
!= undefined) {
462 query
= query
+ "¬e=" + param_escape(note
);
464 query
= query
+ "¬e=undefined";
467 var img
= $("FPPIC-" + id
);
471 if (img
.src
.match("pub_unset") || note
!= undefined) {
472 img
.src
= img
.src
.replace("pub_unset", "pub_set");
473 img
.alt
= __("Unpublish article");
474 query
= query
+ "&pub=1";
477 img
.src
= img
.src
.replace("pub_set", "pub_unset");
478 img
.alt
= __("Publish article");
480 query
= query
+ "&pub=0";
484 new Ajax
.Request("backend.php", {
486 onComplete: function(transport
) {
487 handle_rpc_json(transport
);
492 exception_error("togglePub", e
);
496 function moveToPost(mode
, noscroll
) {
500 var rows
= getVisibleArticleIds();
505 if (!$('RROW-' + getActiveArticleId())) {
506 setActiveArticleId(0);
509 if (!getActiveArticleId()) {
511 prev_id
= rows
[rows
.length
-1]
513 for (var i
= 0; i
< rows
.length
; i
++) {
514 if (rows
[i
] == getActiveArticleId()) {
516 // Account for adjacent identical article ids.
517 if (i
> 0) prev_id
= rows
[i
-1];
519 for (var j
= i
+1; j
< rows
.length
; j
++) {
520 if (rows
[j
] != getActiveArticleId()) {
530 if (mode
== "next") {
531 if (next_id
|| getActiveArticleId()) {
534 var article
= $("RROW-" + getActiveArticleId());
535 var ctr
= $("headlines-frame");
537 if (!noscroll
&& article
&& article
.offsetTop
+ article
.offsetHeight
>
538 ctr
.scrollTop
+ ctr
.offsetHeight
) {
540 scrollArticle(ctr
.offsetHeight
/2);
542 } else if (next_id
) {
543 cdmExpandArticle(next_id
);
544 cdmScrollToArticleId(next_id
, noscroll
);
547 } else if (next_id
) {
548 correctHeadlinesOffset(next_id
);
549 view(next_id
, getActiveFeedId());
554 if (mode
== "prev") {
555 if (prev_id
|| getActiveArticleId()) {
558 var article
= $("RROW-" + getActiveArticleId());
559 var prev_article
= $("RROW-" + prev_id
);
560 var ctr
= $("headlines-frame");
562 if (!getInitParam("cdm_expanded")) {
563 cdmExpandArticle(prev_id
);
564 cdmScrollToArticleId(prev_id
, true);
567 if (!noscroll
&& article
&& article
.offsetTop
< ctr
.scrollTop
) {
568 scrollArticle(-ctr
.offsetHeight
/3);
569 } else if (!noscroll
&& prev_article
&&
570 prev_article
.offsetTop
< ctr
.scrollTop
) {
571 cdmExpandArticle(prev_id
);
572 scrollArticle(-ctr
.offsetHeight
/3);
573 } else if (prev_id
) {
574 cdmExpandArticle(prev_id
);
575 cdmScrollToArticleId(prev_id
, noscroll
);
579 } else if (prev_id
) {
580 correctHeadlinesOffset(prev_id
);
581 view(prev_id
, getActiveFeedId());
587 exception_error("moveToPost", e
);
591 function toggleSelected(id
, force_on
) {
594 var cb
= dijit
.byId("RCHK-" + id
);
595 var row
= $("RROW-" + id
);
598 if (row
.hasClassName('Selected') && !force_on
) {
599 row
.removeClassName('Selected');
600 if (cb
) cb
.attr("checked", false);
602 row
.addClassName('Selected');
603 if (cb
) cb
.attr("checked", true);
607 exception_error("toggleSelected", e
);
611 function toggleUnread_afh(effect
) {
614 var elem
= effect
.element
;
615 elem
.style
.backgroundColor
= "";
618 exception_error("toggleUnread_afh", e
);
622 function toggleUnread(id
, cmode
, effect
) {
625 var row
= $("RROW-" + id
);
627 if (cmode
== undefined || cmode
== 2) {
628 if (row
.hasClassName("Unread")) {
629 row
.removeClassName("Unread");
632 new Effect
.Highlight(row
, {duration
: 1, startcolor
: "#fff7d5",
633 afterFinish
: toggleUnread_afh
,
634 queue
: { position
:'end', scope
: 'TMRQ-' + id
, limit
: 1 } } );
638 row
.addClassName("Unread");
641 } else if (cmode
== 0) {
643 row
.removeClassName("Unread");
646 new Effect
.Highlight(row
, {duration
: 1, startcolor
: "#fff7d5",
647 afterFinish
: toggleUnread_afh
,
648 queue
: { position
:'end', scope
: 'TMRQ-' + id
, limit
: 1 } } );
651 } else if (cmode
== 1) {
652 row
.addClassName("Unread");
655 if (cmode
== undefined) cmode
= 2;
657 var query
= "?op=rpc&method=catchupSelected" +
658 "&cmode=" + param_escape(cmode
) + "&ids=" + param_escape(id
);
660 // notify_progress("Loading, please wait...");
662 new Ajax
.Request("backend.php", {
664 onComplete: function(transport
) {
665 handle_rpc_json(transport
);
671 exception_error("toggleUnread", e
);
675 function selectionRemoveLabel(id
, ids
) {
678 if (!ids
) ids
= getSelectedArticleIds2();
680 if (ids
.length
== 0) {
681 alert(__("No articles are selected."));
685 var query
= "?op=rpc&method=removeFromLabel&ids=" +
686 param_escape(ids
.toString()) + "&lid=" + param_escape(id
);
690 new Ajax
.Request("backend.php", {
692 onComplete: function(transport
) {
693 handle_rpc_json(transport
);
694 show_labels_in_headlines(transport
);
698 exception_error("selectionAssignLabel", e
);
703 function selectionAssignLabel(id
, ids
) {
706 if (!ids
) ids
= getSelectedArticleIds2();
708 if (ids
.length
== 0) {
709 alert(__("No articles are selected."));
713 var query
= "?op=rpc&method=assignToLabel&ids=" +
714 param_escape(ids
.toString()) + "&lid=" + param_escape(id
);
718 new Ajax
.Request("backend.php", {
720 onComplete: function(transport
) {
721 handle_rpc_json(transport
);
722 show_labels_in_headlines(transport
);
726 exception_error("selectionAssignLabel", e
);
731 function selectionToggleUnread(set_state
, callback
, no_error
) {
733 var rows
= getSelectedArticleIds2();
735 if (rows
.length
== 0 && !no_error
) {
736 alert(__("No articles are selected."));
740 for (var i
= 0; i
< rows
.length
; i
++) {
741 var row
= $("RROW-" + rows
[i
]);
743 if (set_state
== undefined) {
744 if (row
.hasClassName("Unread")) {
745 row
.removeClassName("Unread");
747 row
.addClassName("Unread");
751 if (set_state
== false) {
752 row
.removeClassName("Unread");
755 if (set_state
== true) {
756 row
.addClassName("Unread");
761 if (rows
.length
> 0) {
765 if (set_state
== undefined) {
767 } else if (set_state
== true) {
769 } else if (set_state
== false) {
773 var query
= "?op=rpc&method=catchupSelected" +
774 "&cmode=" + cmode
+ "&ids=" + param_escape(rows
.toString());
776 notify_progress("Loading, please wait...");
778 new Ajax
.Request("backend.php", {
780 onComplete: function(transport
) {
781 handle_rpc_json(transport
);
782 if (callback
) callback(transport
);
788 exception_error("selectionToggleUnread", e
);
792 function selectionToggleMarked() {
795 var rows
= getSelectedArticleIds2();
797 if (rows
.length
== 0) {
798 alert(__("No articles are selected."));
802 for (var i
= 0; i
< rows
.length
; i
++) {
803 toggleMark(rows
[i
], true, true);
806 if (rows
.length
> 0) {
808 var query
= "?op=rpc&method=markSelected&ids=" +
809 param_escape(rows
.toString()) + "&cmode=2";
811 new Ajax
.Request("backend.php", {
813 onComplete: function(transport
) {
814 handle_rpc_json(transport
);
820 exception_error("selectionToggleMarked", e
);
824 function selectionTogglePublished() {
827 var rows
= getSelectedArticleIds2();
829 if (rows
.length
== 0) {
830 alert(__("No articles are selected."));
834 for (var i
= 0; i
< rows
.length
; i
++) {
835 togglePub(rows
[i
], true, true);
838 if (rows
.length
> 0) {
840 var query
= "?op=rpc&method=publishSelected&ids=" +
841 param_escape(rows
.toString()) + "&cmode=2";
843 new Ajax
.Request("backend.php", {
845 onComplete: function(transport
) {
846 handle_rpc_json(transport
);
852 exception_error("selectionToggleMarked", e
);
856 function getSelectedArticleIds2() {
860 $$("#headlines-frame > div[id*=RROW][class*=Selected]").each(
862 rv
.push(child
.id
.replace("RROW-", ""));
868 function getLoadedArticleIds() {
871 var children
= $$("#headlines-frame > div[id*=RROW-]");
873 children
.each(function(child
) {
874 rv
.push(child
.id
.replace("RROW-", ""));
881 // mode = all,none,unread,invert,marked,published
882 function selectArticles(mode
) {
885 var children
= $$("#headlines-frame > div[id*=RROW]");
887 children
.each(function(child
) {
888 var id
= child
.id
.replace("RROW-", "");
889 var cb
= dijit
.byId("RCHK-" + id
);
892 child
.addClassName("Selected");
893 if (cb
) cb
.attr("checked", true);
894 } else if (mode
== "unread") {
895 if (child
.hasClassName("Unread")) {
896 child
.addClassName("Selected");
897 if (cb
) cb
.attr("checked", true);
899 child
.removeClassName("Selected");
900 if (cb
) cb
.attr("checked", false);
902 } else if (mode
== "marked") {
903 var img
= $("FMPIC-" + child
.id
.replace("RROW-", ""));
905 if (img
&& img
.src
.match("mark_set")) {
906 child
.addClassName("Selected");
907 if (cb
) cb
.attr("checked", true);
909 child
.removeClassName("Selected");
910 if (cb
) cb
.attr("checked", false);
912 } else if (mode
== "published") {
913 var img
= $("FPPIC-" + child
.id
.replace("RROW-", ""));
915 if (img
&& img
.src
.match("pub_set")) {
916 child
.addClassName("Selected");
917 if (cb
) cb
.attr("checked", true);
919 child
.removeClassName("Selected");
920 if (cb
) cb
.attr("checked", false);
923 } else if (mode
== "invert") {
924 if (child
.hasClassName("Selected")) {
925 child
.removeClassName("Selected");
926 if (cb
) cb
.attr("checked", false);
928 child
.addClassName("Selected");
929 if (cb
) cb
.attr("checked", true);
933 child
.removeClassName("Selected");
934 if (cb
) cb
.attr("checked", false);
939 exception_error("selectArticles", e
);
943 function catchupPage() {
945 var fn
= getFeedName(getActiveFeedId(), activeFeedIsCat());
947 var str
= __("Mark all visible articles in %s as read?");
949 str
= str
.replace("%s", fn
);
951 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str
)) {
955 selectArticles('all');
956 selectionToggleUnread(false, 'viewCurrentFeed()', true);
957 selectArticles('none');
960 function deleteSelection() {
964 var rows
= getSelectedArticleIds2();
966 if (rows
.length
== 0) {
967 alert(__("No articles are selected."));
971 var fn
= getFeedName(getActiveFeedId(), activeFeedIsCat());
974 if (getActiveFeedId() != 0) {
975 str
= __("Delete %d selected articles in %s?");
977 str
= __("Delete %d selected articles?");
980 str
= str
.replace("%d", rows
.length
);
981 str
= str
.replace("%s", fn
);
983 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str
)) {
987 query
= "?op=rpc&method=delete&ids=" + param_escape(rows
);
991 new Ajax
.Request("backend.php", {
993 onComplete: function(transport
) {
994 handle_rpc_json(transport
);
999 exception_error("deleteSelection", e
);
1003 function archiveSelection() {
1007 var rows
= getSelectedArticleIds2();
1009 if (rows
.length
== 0) {
1010 alert(__("No articles are selected."));
1014 var fn
= getFeedName(getActiveFeedId(), activeFeedIsCat());
1018 if (getActiveFeedId() != 0) {
1019 str
= __("Archive %d selected articles in %s?");
1022 str
= __("Move %d archived articles back?");
1026 str
= str
.replace("%d", rows
.length
);
1027 str
= str
.replace("%s", fn
);
1029 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str
)) {
1033 query
= "?op=rpc&method="+op
+"&ids=" + param_escape(rows
);
1037 for (var i
= 0; i
< rows
.length
; i
++) {
1038 cache_delete("article:" + rows
[i
]);
1041 new Ajax
.Request("backend.php", {
1043 onComplete: function(transport
) {
1044 handle_rpc_json(transport
);
1049 exception_error("archiveSelection", e
);
1053 function catchupSelection() {
1057 var rows
= getSelectedArticleIds2();
1059 if (rows
.length
== 0) {
1060 alert(__("No articles are selected."));
1064 var fn
= getFeedName(getActiveFeedId(), activeFeedIsCat());
1066 var str
= __("Mark %d selected articles in %s as read?");
1068 str
= str
.replace("%d", rows
.length
);
1069 str
= str
.replace("%s", fn
);
1071 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str
)) {
1075 selectionToggleUnread(false, 'viewCurrentFeed()', true);
1078 exception_error("catchupSelection", e
);
1082 function editArticleTags(id
) {
1083 var query
= "backend.php?op=dlg&method=editArticleTags¶m=" + param_escape(id
);
1085 if (dijit
.byId("editTagsDlg"))
1086 dijit
.byId("editTagsDlg").destroyRecursive();
1088 dialog
= new dijit
.Dialog({
1090 title
: __("Edit article Tags"),
1091 style
: "width: 600px",
1092 execute: function() {
1093 if (this.validate()) {
1094 var query
= dojo
.objectToQuery(this.attr('value'));
1096 notify_progress("Saving article tags...", true);
1098 new Ajax
.Request("backend.php", {
1100 onComplete: function(transport
) {
1104 var data
= JSON
.parse(transport
.responseText
);
1107 var tags_str
= article
.tags
;
1108 var id
= tags_str
.id
;
1110 var tags
= $("ATSTR-" + id
);
1111 var tooltip
= dijit
.byId("ATSTRTIP-" + id
);
1113 if (tags
) tags
.innerHTML
= tags_str
.content
;
1114 if (tooltip
) tooltip
.attr('label', tags_str
.content_full
);
1116 cache_delete("article:" + id
);
1125 var tmph
= dojo
.connect(dialog
, 'onLoad', function() {
1126 dojo
.disconnect(tmph
);
1128 new Ajax
.Autocompleter('tags_str', 'tags_choices',
1129 "backend.php?op=rpc&method=completeTags",
1130 { tokens
: ',', paramName
: "search" });
1137 function cdmScrollToArticleId(id
, force
) {
1139 var ctr
= $("headlines-frame");
1140 var e
= $("RROW-" + id
);
1142 if (!e
|| !ctr
) return;
1144 if (force
|| e
.offsetTop
+e
.offsetHeight
> (ctr
.scrollTop
+ctr
.offsetHeight
) ||
1145 e
.offsetTop
< ctr
.scrollTop
) {
1146 ctr
.scrollTop
= e
.offsetTop
;
1150 exception_error("cdmScrollToArticleId", e
);
1154 function setActiveArticleId(id
) {
1155 _active_article_id
= id
;
1158 function getActiveArticleId() {
1159 return _active_article_id
;
1162 function postMouseIn(id
) {
1163 post_under_pointer
= id
;
1166 function postMouseOut(id
) {
1167 post_under_pointer
= false;
1170 function headlines_scroll_handler(e
) {
1172 var hsp
= $("headlines-spacer");
1174 if (!_infscroll_disable
) {
1175 if ((hsp
&& e
.scrollTop
+ e
.offsetHeight
>= hsp
.offsetTop
- hsp
.offsetHeight
) ||
1176 (e
.scrollHeight
!= 0 &&
1177 ((e
.scrollTop
+ e
.offsetHeight
) / e
.scrollHeight
>= 0.7))) {
1180 hsp
.innerHTML
= "<img src='images/indicator_tiny.gif'> " +
1181 __("Loading, please wait...");
1183 loadMoreHeadlines();
1188 if (hsp
) hsp
.innerHTML
= "";
1191 if (getInitParam("cdm_auto_catchup") == 1) {
1193 $$("#headlines-frame > div[id*=RROW][class*=Unread]").each(
1195 if ($("headlines-frame").scrollTop
>
1196 (child
.offsetTop
+ child
.offsetHeight
/2)) {
1198 var id
= child
.id
.replace("RROW-", "");
1200 if (catchup_id_batch
.indexOf(id
) == -1)
1201 catchup_id_batch
.push(id
);
1203 //console.log("auto_catchup_batch: " + catchup_id_batch.toString());
1207 if (catchup_id_batch
.length
> 0) {
1208 window
.clearTimeout(catchup_timeout_id
);
1210 if (!_infscroll_request_sent
) {
1211 catchup_timeout_id
= window
.setTimeout('catchupBatchedArticles()',
1218 console
.warn("headlines_scroll_handler: " + e
);
1222 function catchupBatchedArticles() {
1224 if (catchup_id_batch
.length
> 0 && !_infscroll_request_sent
) {
1226 // make a copy of the array
1227 var batch
= catchup_id_batch
.slice();
1228 var query
= "?op=rpc&method=catchupSelected" +
1229 "&cmode=0&ids=" + param_escape(batch
.toString());
1233 new Ajax
.Request("backend.php", {
1235 onComplete: function(transport
) {
1236 handle_rpc_json(transport
);
1238 batch
.each(function(id
) {
1239 var elem
= $("RROW-" + id
);
1240 if (elem
) elem
.removeClassName("Unread");
1241 catchup_id_batch
.remove(id
);
1248 exception_error("catchupBatchedArticles", e
);
1252 function catchupRelativeToArticle(below
, id
) {
1256 if (!id
) id
= getActiveArticleId();
1259 alert(__("No article is selected."));
1263 var visible_ids
= getVisibleArticleIds();
1265 var ids_to_mark
= new Array();
1268 for (var i
= 0; i
< visible_ids
.length
; i
++) {
1269 if (visible_ids
[i
] != id
) {
1270 var e
= $("RROW-" + visible_ids
[i
]);
1272 if (e
&& e
.hasClassName("Unread")) {
1273 ids_to_mark
.push(visible_ids
[i
]);
1280 for (var i
= visible_ids
.length
-1; i
>= 0; i
--) {
1281 if (visible_ids
[i
] != id
) {
1282 var e
= $("RROW-" + visible_ids
[i
]);
1284 if (e
&& e
.hasClassName("Unread")) {
1285 ids_to_mark
.push(visible_ids
[i
]);
1293 if (ids_to_mark
.length
== 0) {
1294 alert(__("No articles found to mark"));
1296 var msg
= __("Mark %d article(s) as read?").replace("%d", ids_to_mark
.length
);
1298 if (getInitParam("confirm_feed_catchup") != 1 || confirm(msg
)) {
1300 for (var i
= 0; i
< ids_to_mark
.length
; i
++) {
1301 var e
= $("RROW-" + ids_to_mark
[i
]);
1302 e
.removeClassName("Unread");
1305 var query
= "?op=rpc&method=catchupSelected" +
1306 "&cmode=0" + "&ids=" + param_escape(ids_to_mark
.toString());
1308 new Ajax
.Request("backend.php", {
1310 onComplete: function(transport
) {
1311 handle_rpc_json(transport
);
1318 exception_error("catchupRelativeToArticle", e
);
1322 function cdmCollapseArticle(event
, id
) {
1324 var row
= $("RROW-" + id
);
1325 var elem
= $("CICD-" + id
);
1328 var collapse
= $$("div#RROW-" + id
+
1329 " span[class='collapseBtn']")[0];
1332 Element
.show("CEXC-" + id
);
1333 Element
.hide(collapse
);
1335 markHeadline(id
, false);
1337 if (id
== getActiveArticleId()) {
1338 setActiveArticleId(0);
1341 if (event
) Event
.stop(event
);
1345 exception_error("cdmCollapseArticle", e
);
1349 function cdmExpandArticle(id
) {
1352 console
.log("cdmExpandArticle " + id
);
1356 var elem
= $("CICD-" + getActiveArticleId());
1358 if (id
== getActiveArticleId() && Element
.visible(elem
))
1361 selectArticles("none");
1363 var old_offset
= $("RROW-" + id
).offsetTop
;
1365 if (getActiveArticleId() && elem
&& !getInitParam("cdm_expanded")) {
1366 var collapse
= $$("div#RROW-" + getActiveArticleId() +
1367 " span[class='collapseBtn']")[0];
1370 Element
.show("CEXC-" + getActiveArticleId());
1371 Element
.hide(collapse
);
1374 setActiveArticleId(id
);
1376 if (!getInitParam("cdm_expanded")) {
1377 cdmScrollToArticleId(id
, true);
1380 elem
= $("CICD-" + id
);
1382 var collapse
= $$("div#RROW-" + id
+
1383 " span[class='collapseBtn']")[0];
1385 var cencw
= $("CENCW-" + id
);
1387 if (!Element
.visible(elem
)) {
1389 cencw
.innerHTML
= htmlspecialchars_decode(cencw
.innerHTML
);
1390 cencw
.setAttribute('id', '');
1394 Element
.hide("CEXC-" + id
);
1395 Element
.show(collapse
);
1398 /* var new_offset = $("RROW-" + id).offsetTop;
1400 $("headlines-frame").scrollTop += (new_offset-old_offset);
1402 if ($("RROW-" + id).offsetTop != old_offset)
1403 $("headlines-frame").scrollTop = new_offset; */
1405 toggleUnread(id
, 0, true);
1409 exception_error("cdmExpandArticle", e
);
1415 function fixHeadlinesOrder(ids
) {
1417 for (var i
= 0; i
< ids
.length
; i
++) {
1418 var e
= $("RROW-" + ids
[i
]);
1422 e
.removeClassName("even");
1423 e
.addClassName("odd");
1425 e
.removeClassName("odd");
1426 e
.addClassName("even");
1431 exception_error("fixHeadlinesOrder", e
);
1435 function getArticleUnderPointer() {
1436 return post_under_pointer
;
1439 function scrollArticle(offset
) {
1442 var ci
= $("content-insert");
1444 ci
.scrollTop
+= offset
;
1447 var hi
= $("headlines-frame");
1449 hi
.scrollTop
+= offset
;
1454 exception_error("scrollArticle", e
);
1458 function show_labels_in_headlines(transport
) {
1460 var data
= JSON
.parse(transport
.responseText
);
1463 data
['info-for-headlines'].each(function(elem
) {
1464 var ctr
= $("HLLCTR-" + elem
.id
);
1466 if (ctr
) ctr
.innerHTML
= elem
.labels
;
1470 exception_error("show_labels_in_headlines", e
);
1474 function dismissArticle(id
) {
1476 var elem
= $("RROW-" + id
);
1478 toggleUnread(id
, 0, true);
1480 new Effect
.Fade(elem
, {duration
: 0.5});
1482 if (id
== getActiveArticleId()) {
1483 setActiveArticleId(0);
1487 exception_error("dismissArticle", e
);
1491 function dismissSelectedArticles() {
1494 var ids
= getVisibleArticleIds();
1498 for (var i
= 0; i
< ids
.length
; i
++) {
1499 var elem
= $("RROW-" + ids
[i
]);
1501 if (elem
.className
&& elem
.hasClassName("Selected") &&
1502 ids
[i
] != getActiveArticleId()) {
1503 new Effect
.Fade(elem
, {duration
: 0.5});
1511 selectionToggleUnread(false);
1513 fixHeadlinesOrder(tmp
);
1516 exception_error("dismissSelectedArticles", e
);
1520 function dismissReadArticles() {
1523 var ids
= getVisibleArticleIds();
1526 for (var i
= 0; i
< ids
.length
; i
++) {
1527 var elem
= $("RROW-" + ids
[i
]);
1529 if (elem
.className
&& !elem
.hasClassName("Unread") &&
1530 !elem
.hasClassName("Selected")) {
1532 new Effect
.Fade(elem
, {duration
: 0.5});
1538 fixHeadlinesOrder(tmp
);
1541 exception_error("dismissSelectedArticles", e
);
1545 function getVisibleArticleIds() {
1550 getLoadedArticleIds().each(function(id
) {
1551 var elem
= $("RROW-" + id
);
1552 if (elem
&& Element
.visible(elem
))
1557 exception_error("getVisibleArticleIds", e
);
1563 function cdmClicked(event
, id
) {
1565 //var shift_key = event.shiftKey;
1569 if (!event
.ctrlKey
) {
1571 if (!getInitParam("cdm_expanded")) {
1572 return cdmExpandArticle(id
);
1575 selectArticles("none");
1578 var elem
= $("RROW-" + id
);
1579 var article_is_unread
= elem
.hasClassName("Unread");
1582 elem
.removeClassName("Unread");
1584 setActiveArticleId(id
);
1586 if (article_is_unread
) {
1587 decrementFeedCounter(getActiveFeedId(), activeFeedIsCat());
1590 var query
= "?op=rpc&method=catchupSelected" +
1591 "&cmode=0&ids=" + param_escape(id
);
1593 new Ajax
.Request("backend.php", {
1595 onComplete: function(transport
) {
1596 handle_rpc_json(transport
);
1599 return !event
.shiftKey
;
1603 toggleSelected(id
, true);
1605 var elem
= $("RROW-" + id
);
1606 var article_is_unread
= elem
.hasClassName("Unread");
1608 if (article_is_unread
) {
1609 decrementFeedCounter(getActiveFeedId(), activeFeedIsCat());
1612 toggleUnread(id
, 0, false);
1614 openArticleInNewWindow(id
);
1617 var unread_in_buffer
= $$("#headlines-frame > div[id*=RROW][class*=Unread]").length
1618 request_counters(unread_in_buffer
== 0);
1621 exception_error("cdmClicked");
1627 function hlClicked(event
, id
) {
1629 if (event
.which
== 2) {
1632 } else if (event
.ctrlKey
) {
1633 toggleSelected(id
, true);
1634 toggleUnread(id
, 0, false);
1635 openArticleInNewWindow(id
);
1643 exception_error("hlClicked");
1647 function getFirstVisibleHeadlineId() {
1648 var rows
= getVisibleArticleIds();
1653 function getLastVisibleHeadlineId() {
1654 var rows
= getVisibleArticleIds();
1655 return rows
[rows
.length
-1];
1658 function openArticleInNewWindow(id
) {
1659 toggleUnread(id
, 0, false);
1660 window
.open("backend.php?op=article&method=redirect&id=" + id
);
1663 function isCdmMode() {
1664 return getInitParam("combined_display_mode");
1667 function markHeadline(id
, marked
) {
1668 if (marked
== undefined) marked
= true;
1670 var row
= $("RROW-" + id
);
1672 var check
= dijit
.byId("RCHK-" + id
);
1675 check
.attr("checked", marked
);
1679 row
.addClassName("Selected");
1681 row
.removeClassName("Selected");
1685 function getRelativePostIds(id
, limit
) {
1691 if (!limit
) limit
= 6; //3
1693 var ids
= getVisibleArticleIds();
1695 for (var i
= 0; i
< ids
.length
; i
++) {
1697 for (var k
= 1; k
<= limit
; k
++) {
1698 //if (i > k-1) tmp.push(ids[i-k]);
1699 if (i
< ids
.length
-k
) tmp
.push(ids
[i
+k
]);
1706 exception_error("getRelativePostIds", e
);
1712 function correctHeadlinesOffset(id
) {
1716 var container
= $("headlines-frame");
1717 var row
= $("RROW-" + id
);
1719 if (!container
|| !row
) return;
1721 var viewport
= container
.offsetHeight
;
1723 var rel_offset_top
= row
.offsetTop
- container
.scrollTop
;
1724 var rel_offset_bottom
= row
.offsetTop
+ row
.offsetHeight
- container
.scrollTop
;
1726 //console.log("Rtop: " + rel_offset_top + " Rbtm: " + rel_offset_bottom);
1727 //console.log("Vport: " + viewport);
1729 if (rel_offset_top
<= 0 || rel_offset_top
> viewport
) {
1730 container
.scrollTop
= row
.offsetTop
;
1731 } else if (rel_offset_bottom
> viewport
) {
1733 /* doesn't properly work with Opera in some cases because
1734 Opera fucks up element scrolling */
1736 container
.scrollTop
= row
.offsetTop
+ row
.offsetHeight
- viewport
;
1740 exception_error("correctHeadlinesOffset", e
);
1745 function headlineActionsChange(elem
) {
1748 elem
.attr('value', 'false');
1750 exception_error("headlineActionsChange", e
);
1754 function closeArticlePanel() {
1756 if (dijit
.byId("content-insert"))
1757 dijit
.byId("headlines-wrap-inner").removeChild(
1758 dijit
.byId("content-insert"));
1761 function initHeadlinesMenu() {
1763 if (dijit
.byId("headlinesMenu"))
1764 dijit
.byId("headlinesMenu").destroyRecursive();
1769 nodes
= $$("#headlines-frame > div[id*=RROW]");
1771 nodes
= $$("#headlines-frame span[id*=RTITLE]");
1774 nodes
.each(function(node
) {
1778 var menu
= new dijit
.Menu({
1779 id
: "headlinesMenu",
1783 var tmph
= dojo
.connect(menu
, '_openMyself', function (event
) {
1784 var callerNode
= event
.target
, match
= null, tries
= 0;
1786 while (match
== null && callerNode
&& tries
<= 3) {
1787 match
= callerNode
.id
.match("^[A-Z]+[-]([0-9]+)$");
1788 callerNode
= callerNode
.parentNode
;
1792 if (match
) this.callerRowId
= parseInt(match
[1]);
1796 /* if (!isCdmMode())
1797 menu.addChild(new dijit.MenuItem({
1798 label: __("View article"),
1799 onClick: function(event) {
1800 view(this.getParent().callerRowId);
1803 menu
.addChild(new dijit
.MenuItem({
1804 label
: __("Open original article"),
1805 onClick: function(event
) {
1806 openArticleInNewWindow(this.getParent().callerRowId
);
1809 menu
.addChild(new dijit
.MenuSeparator());
1811 menu
.addChild(new dijit
.MenuItem({
1812 label
: __("Mark above as read"),
1813 onClick: function(event
) {
1814 catchupRelativeToArticle(0, this.getParent().callerRowId
);
1817 menu
.addChild(new dijit
.MenuItem({
1818 label
: __("Mark below as read"),
1819 onClick: function(event
) {
1820 catchupRelativeToArticle(1, this.getParent().callerRowId
);
1824 var labels
= dijit
.byId("feedTree").model
.getItemsInCategory(-2);
1828 menu
.addChild(new dijit
.MenuSeparator());
1830 var labelAddMenu
= new dijit
.Menu({ownerMenu
: menu
});
1831 var labelDelMenu
= new dijit
.Menu({ownerMenu
: menu
});
1833 labels
.each(function(label
) {
1834 var id
= label
.id
[0];
1835 var bare_id
= id
.substr(id
.indexOf(":")+1);
1836 var name
= label
.name
[0];
1838 bare_id
= -11-bare_id
;
1840 labelAddMenu
.addChild(new dijit
.MenuItem({
1843 onClick: function(event
) {
1844 var ids
= getSelectedArticleIds2();
1846 var id
= this.getParent().ownerMenu
.callerRowId
+ "";
1848 ids
= ids
.size() != 0 && ids
.indexOf(id
) != -1 ? ids
: [id
];
1850 selectionAssignLabel(this.labelId
, ids
);
1853 labelDelMenu
.addChild(new dijit
.MenuItem({
1856 onClick: function(event
) {
1857 var ids
= getSelectedArticleIds2();
1859 var id
= this.getParent().ownerMenu
.callerRowId
+ "";
1861 ids
= ids
.size() != 0 && ids
.indexOf(id
) != -1 ? ids
: [id
];
1863 selectionRemoveLabel(this.labelId
, ids
);
1868 menu
.addChild(new dijit
.PopupMenuItem({
1869 label
: __("Assign label"),
1870 popup
: labelAddMenu
,
1873 menu
.addChild(new dijit
.PopupMenuItem({
1874 label
: __("Remove label"),
1875 popup
: labelDelMenu
,
1883 exception_error("initHeadlinesMenu", e
);
1888 function player(elem
) {
1889 var aid
= elem
.getAttribute("audio-id");
1890 var status
= elem
.getAttribute("status");
1898 elem
.innerHTML
= __("Playing...");
1899 elem
.title
= __("Click to pause");
1900 elem
.addClassName("playing");
1904 elem
.innerHTML
= __("Play");
1905 elem
.title
= __("Click to play");
1906 elem
.removeClassName("playing");
1909 elem
.setAttribute("status", status
);
1911 alert("Your browser doesn't seem to support HTML5 audio.");
1915 function cache_set(id
, obj
) {
1916 //console.log("cache_set: " + id);
1919 sessionStorage
[id
] = obj
;
1921 sessionStorage
.clear();
1925 function cache_get(id
) {
1927 return sessionStorage
[id
];
1930 function cache_clear() {
1932 sessionStorage
.clear();
1935 function cache_delete(id
) {
1937 sessionStorage
.removeItem(id
);
1940 function cancelSearch() {
1945 exception_error("cancelSearch", e
);
1949 function setSelectionScore() {
1951 var ids
= getSelectedArticleIds2();
1953 if (ids
.length
> 0) {
1956 var score
= prompt(__("Please enter new score for selected articles:"), score
);
1958 if (score
!= undefined) {
1959 var query
= "op=rpc&method=setScore&id=" + param_escape(ids
.toString()) +
1960 "&score=" + param_escape(score
);
1962 new Ajax
.Request("backend.php", {
1964 onComplete: function(transport
) {
1965 var reply
= JSON
.parse(transport
.responseText
);
1969 ids
.each(function(id
) {
1970 var row
= $("RROW-" + id
);
1973 var pic
= row
.getElementsByClassName("hlScorePic")[0];
1976 pic
.src
= pic
.src
.replace(/score_.*?\.png/,
1977 reply
["score_pic"]);
1978 pic
.setAttribute("score", score
);
1987 alert(__("No articles are selected."));
1990 exception_error("setSelectionScore", e
);
1994 function changeScore(id
, pic
) {
1996 var score
= pic
.getAttribute("score");
1998 var new_score
= prompt(__("Please enter new score for this article:"), score
);
2000 if (new_score
!= undefined) {
2002 var query
= "op=rpc&method=setScore&id=" + param_escape(id
) +
2003 "&score=" + param_escape(new_score
);
2005 new Ajax
.Request("backend.php", {
2007 onComplete: function(transport
) {
2008 var reply
= JSON
.parse(transport
.responseText
);
2011 pic
.src
= pic
.src
.replace(/score_.*?\.png/, reply
["score_pic"]);
2012 pic
.setAttribute("score", new_score
);
2017 exception_error("changeScore", e
);