]>
git.wh0rd.org - tt-rss.git/blob - viewfeed.js
1 var active_post_id
= false;
2 var last_article_view
= false;
3 var active_real_feed_id
= false;
5 var article_cache
= new Array();
7 var vgroup_last_feed
= false;
8 var post_under_pointer
= false;
10 var last_requested_article
= false;
12 var preload_id_batch
= [];
13 var preload_timeout_id
= false;
17 var catchup_id_batch
= [];
18 var catchup_timeout_id
= false;
20 function headlines_callback2(transport
, feed_cur_page
) {
22 handle_rpc_json(transport
);
24 loading_set_progress(25);
26 console
.log("headlines_callback2 [page=" + feed_cur_page
+ "]");
34 reply
= JSON
.parse(transport
.responseText
);
41 is_cat
= reply
['headlines']['is_cat'];
42 feed_id
= reply
['headlines']['id'];
44 setActiveFeedId(feed_id
, is_cat
);
46 var update_btn
= document
.forms
["main_toolbar_form"].update
;
48 update_btn
.disabled
= !(feed_id
>= 0 && !is_cat
);
51 if (feed_cur_page
== 0) {
52 $("headlines-frame").scrollTop
= 0;
56 var headlines_count
= reply
['headlines-info']['count'];
57 var headlines_unread
= reply
['headlines-info']['unread'];
59 vgroup_last_feed
= reply
['headlines-info']['vgroup_last_feed'];
61 if (parseInt(headlines_count
) < getInitParam("default_article_limit")) {
62 _infscroll_disable
= 1;
64 _infscroll_disable
= 0;
67 var counters
= reply
['counters'];
68 var articles
= reply
['articles'];
69 var runtime_info
= reply
['runtime-info'];
71 if (feed_cur_page
== 0) {
72 dijit
.byId("headlines-frame").attr('content',
73 reply
['headlines']['content']);
75 dijit
.byId("headlines-toolbar").attr('content',
76 reply
['headlines']['toolbar']);
78 var hsp
= $("headlines-spacer");
79 if (!hsp
) hsp
= new Element("DIV", {"id": "headlines-spacer"});
81 if (!_infscroll_disable
)
82 hsp
.innerHTML
= "<img src='images/indicator_tiny.gif'> " +
83 __("Loading, please wait...");
85 dijit
.byId('headlines-frame').domNode
.appendChild(hsp
);
90 if (headlines_count
> 0) {
91 console
.log("adding some more headlines...");
93 var c
= dijit
.byId("headlines-frame");
94 var ids
= getSelectedArticleIds2();
96 $("headlines-tmp").innerHTML
= reply
['headlines']['content'];
98 var hsp
= $("headlines-spacer");
101 c
.domNode
.removeChild(hsp
);
103 $$("#headlines-tmp > div").each(function(row
) {
104 row
.style
.display
= 'none';
105 c
.domNode
.appendChild(row
);
108 if (!hsp
) hsp
= new Element("DIV", {"id": "headlines-spacer"});
110 if (!_infscroll_disable
)
111 hsp
.innerHTML
= "<img src='images/indicator_tiny.gif'> " +
112 __("Loading, please wait...");
114 c
.domNode
.appendChild(hsp
);
116 console
.log("restore selected ids: " + ids
);
118 for (var i
= 0; i
< ids
.length
; i
++) {
119 markHeadline(ids
[i
]);
124 $$("#headlines-frame > div[id*=RROW]").each(
126 if (!Element
.visible(child
))
127 new Effect
.Appear(child
, { duration
: 0.5 });
131 console
.log("no new headlines received");
133 var hsp
= $("headlines-spacer");
135 if (hsp
) hsp
.innerHTML
= "";
140 for (var i
= 0; i
< articles
.length
; i
++) {
141 var a_id
= articles
[i
]['id'];
142 cache_inject(a_id
, articles
[i
]['content']);
145 console
.log("no cached articles received");
149 parse_counters(counters
);
154 console
.warn("headlines_callback: returned no XML object");
155 dijit
.byId("headlines-frame").attr('content', "<div class='whiteBox'>" +
156 __('Could not update headlines (invalid object received)') + "</div>");
159 _feed_cur_page
= feed_cur_page
;
160 _infscroll_request_sent
= 0;
165 exception_error("headlines_callback2", e
, transport
);
169 function render_article(article
) {
171 dijit
.byId("headlines-wrap-inner").addChild(
172 dijit
.byId("content-insert"));
174 var c
= dijit
.byId("content-insert");
177 c
.domNode
.scrollTop
= 0;
180 c
.attr('content', article
);
182 correctHeadlinesOffset(getActiveArticleId());
189 exception_error("render_article", e
);
193 function showArticleInHeadlines(id
) {
197 selectArticles("none");
199 var crow
= $("RROW-" + id
);
203 var article_is_unread
= crow
.hasClassName("Unread");
205 crow
.removeClassName("Unread");
207 selectArticles('none');
209 var upd_img_pic
= $("FUPDPIC-" + id
);
211 var cache_prefix
= "";
213 if (activeFeedIsCat()) {
219 var view_mode
= false;
222 view_mode
= document
.forms
['main_toolbar_form'].view_mode
;
223 view_mode
= view_mode
[view_mode
.selectedIndex
].value
;
228 if (upd_img_pic
&& (upd_img_pic
.src
.match("updated.png") ||
229 upd_img_pic
.src
.match("fresh_sign.png"))) {
231 upd_img_pic
.src
= "images/blank_icon.gif";
233 cache_invalidate(cache_prefix
+ getActiveFeedId());
235 /* cache_inject(cache_prefix + getActiveFeedId(),
236 $("headlines-frame").innerHTML,
237 getFeedUnread(getActiveFeedId())); */
239 } else if (article_is_unread
&& view_mode
== "all_articles") {
241 cache_invalidate(cache_prefix
+ getActiveFeedId());
243 /* cache_inject(cache_prefix + getActiveFeedId(),
244 $("headlines-frame").innerHTML,
245 getFeedUnread(getActiveFeedId())-1); */
247 } else if (article_is_unread
) {
248 cache_invalidate(cache_prefix
+ getActiveFeedId());
253 if (article_is_unread
)
254 _force_scheduled_update
= true;
257 exception_error("showArticleInHeadlines", e
);
261 function article_callback2(transport
, id
) {
263 console
.log("article_callback2 " + id
);
265 handle_rpc_json(transport
);
267 var reply
= JSON
.parse(transport
.responseText
);
270 var upic
= $('FUPDPIC-' + id
);
272 if (upic
) upic
.src
= 'images/blank_icon.gif';
274 if (id
!= last_requested_article
) {
275 console
.log("requested article id is out of sequence, aborting");
279 reply
.each(function(article
) {
280 if (active_post_id
== article
['id']) {
281 render_article(article
['content']);
283 cache_inject(article
['id'], article
['content']);
287 console
.warn("article_callback: returned invalid data");
289 render_article("<div class='whiteBox'>" +
290 __('Could not display article (invalid data received)') + "</div>");
293 var date
= new Date();
294 last_article_view
= date
.getTime() / 1000;
300 exception_error("article_callback2", e
, transport
);
306 console
.log("loading article: " + id
);
308 var cached_article
= cache_find(id
);
310 console
.log("cache check result: " + (cached_article
!= false));
314 var query
= "?op=view&id=" + param_escape(id
);
316 var neighbor_ids
= getRelativePostIds(active_post_id
);
318 /* only request uncached articles */
320 var cids_to_request
= Array();
322 for (var i
= 0; i
< neighbor_ids
.length
; i
++) {
323 if (!cache_check(neighbor_ids
[i
])) {
324 cids_to_request
.push(neighbor_ids
[i
]);
328 console
.log("additional ids: " + cids_to_request
.toString());
330 query
= query
+ "&cids=" + cids_to_request
.toString();
332 var crow
= $("RROW-" + id
);
333 var article_is_unread
= crow
.hasClassName("Unread");
336 showArticleInHeadlines(id
);
338 if (!cached_article
) {
340 var upic
= $('FUPDPIC-' + id
);
343 upic
.src
= getInitParam("sign_progress");
346 } else if (cached_article
&& article_is_unread
) {
348 query
= query
+ "&mode=prefetch";
350 render_article(cached_article
);
352 } else if (cached_article
) {
354 query
= query
+ "&mode=prefetch_old";
355 render_article(cached_article
);
361 last_requested_article
= id
;
365 new Ajax
.Request("backend.php", {
367 onComplete: function(transport
) {
368 article_callback2(transport
, id
);
374 exception_error("view", e
);
379 return toggleMark(id
);
383 return togglePub(id
);
386 function toggleMark(id
, client_only
) {
388 var query
= "?op=rpc&id=" + id
+ "&subop=mark";
390 var img
= $("FMPIC-" + id
);
394 if (img
.src
.match("mark_unset")) {
395 img
.src
= img
.src
.replace("mark_unset", "mark_set");
396 img
.alt
= __("Unstar article");
397 query
= query
+ "&mark=1";
400 img
.src
= img
.src
.replace("mark_set", "mark_unset");
401 img
.alt
= __("Star article");
402 query
= query
+ "&mark=0";
406 new Ajax
.Request("backend.php", {
408 onComplete: function(transport
) {
409 handle_rpc_json(transport
);
414 exception_error("toggleMark", e
);
418 function togglePub(id
, client_only
, no_effects
, note
) {
420 var query
= "?op=rpc&id=" + id
+ "&subop=publ";
422 if (note
!= undefined) {
423 query
= query
+ "¬e=" + param_escape(note
);
425 query
= query
+ "¬e=undefined";
428 var img
= $("FPPIC-" + id
);
432 if (img
.src
.match("pub_unset") || note
!= undefined) {
433 img
.src
= img
.src
.replace("pub_unset", "pub_set");
434 img
.alt
= __("Unpublish article");
435 query
= query
+ "&pub=1";
438 img
.src
= img
.src
.replace("pub_set", "pub_unset");
439 img
.alt
= __("Publish article");
441 query
= query
+ "&pub=0";
445 new Ajax
.Request("backend.php", {
447 onComplete: function(transport
) {
448 handle_rpc_json(transport
);
453 exception_error("togglePub", e
);
457 function moveToPost(mode
) {
461 var rows
= getVisibleArticleIds();
466 if (!$('RROW-' + active_post_id
)) {
467 active_post_id
= false;
470 if (active_post_id
== false) {
471 next_id
= getFirstVisibleHeadlineId();
472 prev_id
= getLastVisibleHeadlineId();
474 for (var i
= 0; i
< rows
.length
; i
++) {
475 if (rows
[i
] == active_post_id
) {
482 if (mode
== "next") {
486 cdmExpandArticle(next_id
);
487 cdmScrollToArticleId(next_id
);
490 correctHeadlinesOffset(next_id
);
491 view(next_id
, getActiveFeedId());
496 if (mode
== "prev") {
499 cdmExpandArticle(prev_id
);
500 cdmScrollToArticleId(prev_id
);
502 correctHeadlinesOffset(prev_id
);
503 view(prev_id
, getActiveFeedId());
509 exception_error("moveToPost", e
);
513 function toggleSelected(id
, force_on
) {
516 var cb
= $("RCHK-" + id
);
517 var row
= $("RROW-" + id
);
520 if (row
.hasClassName('Selected') && !force_on
) {
521 row
.removeClassName('Selected');
522 if (cb
) cb
.checked
= false;
524 row
.addClassName('Selected');
525 if (cb
) cb
.checked
= true;
529 exception_error("toggleSelected", e
);
533 function toggleUnread_afh(effect
) {
536 var elem
= effect
.element
;
537 elem
.style
.backgroundColor
= "";
540 exception_error("toggleUnread_afh", e
);
544 function toggleUnread(id
, cmode
, effect
) {
547 var row
= $("RROW-" + id
);
549 if (cmode
== undefined || cmode
== 2) {
550 if (row
.hasClassName("Unread")) {
551 row
.removeClassName("Unread");
554 new Effect
.Highlight(row
, {duration
: 1, startcolor
: "#fff7d5",
555 afterFinish
: toggleUnread_afh
,
556 queue
: { position
:'end', scope
: 'TMRQ-' + id
, limit
: 1 } } );
560 row
.addClassName("Unread");
563 } else if (cmode
== 0) {
565 row
.removeClassName("Unread");
568 new Effect
.Highlight(row
, {duration
: 1, startcolor
: "#fff7d5",
569 afterFinish
: toggleUnread_afh
,
570 queue
: { position
:'end', scope
: 'TMRQ-' + id
, limit
: 1 } } );
573 } else if (cmode
== 1) {
574 row
.addClassName("Unread");
577 if (cmode
== undefined) cmode
= 2;
579 var query
= "?op=rpc&subop=catchupSelected" +
580 "&cmode=" + param_escape(cmode
) + "&ids=" + param_escape(id
);
582 // notify_progress("Loading, please wait...");
584 new Ajax
.Request("backend.php", {
586 onComplete: function(transport
) {
587 handle_rpc_json(transport
);
593 exception_error("toggleUnread", e
);
597 function selectionRemoveLabel(id
, ids
) {
600 if (!ids
) var ids
= getSelectedArticleIds2();
602 if (ids
.length
== 0) {
603 alert(__("No articles are selected."));
607 // var ok = confirm(__("Remove selected articles from label?"));
611 var query
= "?op=rpc&subop=removeFromLabel&ids=" +
612 param_escape(ids
.toString()) + "&lid=" + param_escape(id
);
616 // notify_progress("Loading, please wait...");
618 cache_invalidate("F:" + (-11 - id
));
620 new Ajax
.Request("backend.php", {
622 onComplete: function(transport
) {
623 handle_rpc_json(transport
);
624 show_labels_in_headlines(transport
);
630 exception_error("selectionAssignLabel", e
);
635 function selectionAssignLabel(id
, ids
) {
638 if (!ids
) ids
= getSelectedArticleIds2();
640 if (ids
.length
== 0) {
641 alert(__("No articles are selected."));
645 // var ok = confirm(__("Assign selected articles to label?"));
649 cache_invalidate("F:" + (-11 - id
));
651 var query
= "?op=rpc&subop=assignToLabel&ids=" +
652 param_escape(ids
.toString()) + "&lid=" + param_escape(id
);
656 // notify_progress("Loading, please wait...");
658 new Ajax
.Request("backend.php", {
660 onComplete: function(transport
) {
661 handle_rpc_json(transport
);
662 show_labels_in_headlines(transport
);
668 exception_error("selectionAssignLabel", e
);
673 function selectionToggleUnread(set_state
, callback
, no_error
) {
675 var rows
= getSelectedArticleIds2();
677 if (rows
.length
== 0 && !no_error
) {
678 alert(__("No articles are selected."));
682 for (i
= 0; i
< rows
.length
; i
++) {
683 var row
= $("RROW-" + rows
[i
]);
685 if (set_state
== undefined) {
686 if (row
.hasClassName("Unread")) {
687 row
.removeClassName("Unread");
689 row
.addClassName("Unread");
693 if (set_state
== false) {
694 row
.removeClassName("Unread");
697 if (set_state
== true) {
698 row
.addClassName("Unread");
703 if (rows
.length
> 0) {
707 if (set_state
== undefined) {
709 } else if (set_state
== true) {
711 } else if (set_state
== false) {
715 var query
= "?op=rpc&subop=catchupSelected" +
716 "&cmode=" + cmode
+ "&ids=" + param_escape(rows
.toString());
718 notify_progress("Loading, please wait...");
720 new Ajax
.Request("backend.php", {
722 onComplete: function(transport
) {
723 handle_rpc_json(transport
);
724 if (callback
) callback(transport
);
730 exception_error("selectionToggleUnread", e
);
734 function selectionToggleMarked() {
737 var rows
= getSelectedArticleIds2();
739 if (rows
.length
== 0) {
740 alert(__("No articles are selected."));
744 for (i
= 0; i
< rows
.length
; i
++) {
745 toggleMark(rows
[i
], true, true);
748 if (rows
.length
> 0) {
750 var query
= "?op=rpc&subop=markSelected&ids=" +
751 param_escape(rows
.toString()) + "&cmode=2";
753 new Ajax
.Request("backend.php", {
755 onComplete: function(transport
) {
756 handle_rpc_json(transport
);
762 exception_error("selectionToggleMarked", e
);
766 function selectionTogglePublished() {
769 var rows
= getSelectedArticleIds2();
771 if (rows
.length
== 0) {
772 alert(__("No articles are selected."));
776 for (i
= 0; i
< rows
.length
; i
++) {
777 togglePub(rows
[i
], true, true);
780 if (rows
.length
> 0) {
782 var query
= "?op=rpc&subop=publishSelected&ids=" +
783 param_escape(rows
.toString()) + "&cmode=2";
785 new Ajax
.Request("backend.php", {
787 onComplete: function(transport
) {
788 handle_rpc_json(transport
);
794 exception_error("selectionToggleMarked", e
);
798 function getSelectedArticleIds2() {
802 $$("#headlines-frame > div[id*=RROW][class*=Selected]").each(
804 rv
.push(child
.id
.replace("RROW-", ""));
810 function getLoadedArticleIds() {
813 var children
= $$("#headlines-frame > div[id*=RROW-]");
815 children
.each(function(child
) {
816 rv
.push(child
.id
.replace("RROW-", ""));
823 // mode = all,none,unread,invert
824 function selectArticles(mode
) {
827 var children
= $$("#headlines-frame > div[id*=RROW]");
829 children
.each(function(child
) {
830 var id
= child
.id
.replace("RROW-", "");
831 var cb
= $("RCHK-" + id
);
834 child
.addClassName("Selected");
836 } else if (mode
== "unread") {
837 if (child
.hasClassName("Unread")) {
838 child
.addClassName("Selected");
841 child
.removeClassName("Selected");
844 } else if (mode
== "invert") {
845 if (child
.hasClassName("Selected")) {
846 child
.removeClassName("Selected");
849 child
.addClassName("Selected");
854 child
.removeClassName("Selected");
860 exception_error("selectArticles", e
);
864 function catchupPage() {
866 var fn
= getFeedName(getActiveFeedId(), activeFeedIsCat());
868 var str
= __("Mark all visible articles in %s as read?");
870 str
= str
.replace("%s", fn
);
872 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str
)) {
876 selectArticles('all');
877 selectionToggleUnread(false, 'viewCurrentFeed()', true)
878 selectArticles('none');
881 function deleteSelection() {
885 var rows
= getSelectedArticleIds2();
887 if (rows
.length
== 0) {
888 alert(__("No articles are selected."));
892 var fn
= getFeedName(getActiveFeedId(), activeFeedIsCat());
896 if (getActiveFeedId() != 0) {
897 str
= __("Delete %d selected articles in %s?");
899 str
= __("Delete %d selected articles?");
902 str
= str
.replace("%d", rows
.length
);
903 str
= str
.replace("%s", fn
);
905 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str
)) {
909 query
= "?op=rpc&subop=delete&ids=" + param_escape(rows
);
913 new Ajax
.Request("backend.php", {
915 onComplete: function(transport
) {
916 handle_rpc_json(transport
);
921 exception_error("deleteSelection", e
);
925 function archiveSelection() {
929 var rows
= getSelectedArticleIds2();
931 if (rows
.length
== 0) {
932 alert(__("No articles are selected."));
936 var fn
= getFeedName(getActiveFeedId(), activeFeedIsCat());
940 if (getActiveFeedId() != 0) {
941 str
= __("Archive %d selected articles in %s?");
944 str
= __("Move %d archived articles back?");
948 str
= str
.replace("%d", rows
.length
);
949 str
= str
.replace("%s", fn
);
951 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str
)) {
955 query
= "?op=rpc&subop="+op
+"&ids=" + param_escape(rows
);
959 for (var i
= 0; i
< rows
.length
; i
++) {
960 cache_invalidate(rows
[i
]);
963 new Ajax
.Request("backend.php", {
965 onComplete: function(transport
) {
966 handle_rpc_json(transport
);
971 exception_error("archiveSelection", e
);
975 function catchupSelection() {
979 var rows
= getSelectedArticleIds2();
981 if (rows
.length
== 0) {
982 alert(__("No articles are selected."));
986 var fn
= getFeedName(getActiveFeedId(), activeFeedIsCat());
988 var str
= __("Mark %d selected articles in %s as read?");
990 str
= str
.replace("%d", rows
.length
);
991 str
= str
.replace("%s", fn
);
993 if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str
)) {
997 selectionToggleUnread(false, 'viewCurrentFeed()', true)
1000 exception_error("catchupSelection", e
);
1004 function editArticleTags(id
) {
1005 var query
= "backend.php?op=dlg&id=editArticleTags¶m=" + param_escape(id
);
1007 if (dijit
.byId("editTagsDlg"))
1008 dijit
.byId("editTagsDlg").destroyRecursive();
1010 dialog
= new dijit
.Dialog({
1012 title
: __("Edit article Tags"),
1013 style
: "width: 600px",
1014 execute: function() {
1015 if (this.validate()) {
1016 var query
= dojo
.objectToQuery(this.attr('value'));
1018 notify_progress("Saving article tags...", true);
1020 new Ajax
.Request("backend.php", {
1022 onComplete: function(transport
) {
1026 var data
= JSON
.parse(transport
.responseText
);
1029 var tags_str
= data
.tags_str
;
1030 var id
= tags_str
.id
;
1032 var tags
= $("ATSTR-" + id
);
1033 var tooltip
= dijit
.byId("ATSTRTIP-" + id
);
1035 if (tags
) tags
.innerHTML
= tags_str
.content
;
1036 if (tooltip
) tooltip
.attr('label', tags_str
.content_full
);
1038 cache_invalidate(id
);
1047 var tmph
= dojo
.connect(dialog
, 'onLoad', function() {
1048 dojo
.disconnect(tmph
);
1050 new Ajax
.Autocompleter('tags_str', 'tags_choices',
1051 "backend.php?op=rpc&subop=completeTags",
1052 { tokens
: ',', paramName
: "search" });
1059 function cdmScrollToArticleId(id
) {
1061 var ctr
= $("headlines-frame");
1062 var e
= $("RROW-" + id
);
1064 if (!e
|| !ctr
) return;
1066 ctr
.scrollTop
= e
.offsetTop
;
1069 exception_error("cdmScrollToArticleId", e
);
1073 function cache_inject(id
, article
, param
) {
1076 if (!cache_check_param(id
, param
)) {
1077 //console.log("cache_article: miss: " + id + " [p=" + param + "]");
1079 var date
= new Date();
1080 var ts
= Math
.round(date
.getTime() / 1000);
1084 cache_obj
["id"] = id
;
1085 cache_obj
["data"] = article
;
1086 cache_obj
["param"] = param
;
1088 if (param
) id
= id
+ ":" + param
;
1090 cache_added
["TS:" + id
] = ts
;
1092 if (has_local_storage())
1093 sessionStorage
.setItem(id
, JSON
.stringify(cache_obj
));
1095 article_cache
.push(cache_obj
);
1098 //console.log("cache_article: hit: " + id + " [p=" + param + "]");
1101 exception_error("cache_inject", e
);
1105 function cache_find(id
) {
1107 if (has_local_storage()) {
1108 var cache_obj
= sessionStorage
.getItem(id
);
1111 cache_obj
= JSON
.parse(cache_obj
);
1114 return cache_obj
['data'];
1118 for (var i
= 0; i
< article_cache
.length
; i
++) {
1119 if (article_cache
[i
]["id"] == id
) {
1120 return article_cache
[i
]["data"];
1127 function cache_find_param(id
, param
) {
1129 if (has_local_storage()) {
1131 if (param
) id
= id
+ ":" + param
;
1133 var cache_obj
= sessionStorage
.getItem(id
);
1136 cache_obj
= JSON
.parse(cache_obj
);
1139 return cache_obj
['data'];
1143 for (var i
= 0; i
< article_cache
.length
; i
++) {
1144 if (article_cache
[i
]["id"] == id
&& article_cache
[i
]["param"] == param
) {
1145 return article_cache
[i
]["data"];
1153 function cache_check(id
) {
1154 if (has_local_storage()) {
1155 if (sessionStorage
.getItem(id
))
1158 for (var i
= 0; i
< article_cache
.length
; i
++) {
1159 if (article_cache
[i
]["id"] == id
) {
1167 function cache_check_param(id
, param
) {
1168 if (has_local_storage()) {
1170 if (param
) id
= id
+ ":" + param
;
1172 if (sessionStorage
.getItem(id
))
1176 for (var i
= 0; i
< article_cache
.length
; i
++) {
1177 if (article_cache
[i
]["id"] == id
&& article_cache
[i
]["param"] == param
) {
1185 function cache_expire() {
1186 if (has_local_storage()) {
1188 var date
= new Date();
1189 var timestamp
= Math
.round(date
.getTime() / 1000);
1191 for (var i
= 0; i
< sessionStorage
.length
; i
++) {
1193 var id
= sessionStorage
.key(i
);
1195 if (timestamp
- cache_added
["TS:" + id
] > 180) {
1196 sessionStorage
.removeItem(id
);
1201 while (article_cache
.length
> 25) {
1202 article_cache
.shift();
1207 function cache_flush() {
1208 if (has_local_storage()) {
1209 sessionStorage
.clear();
1211 article_cache
= new Array();
1215 function cache_invalidate(id
) {
1217 if (has_local_storage()) {
1221 for (var i
= 0; i
< sessionStorage
.length
; i
++) {
1222 var key
= sessionStorage
.key(i
);
1224 // console.warn("cache_invalidate: " + key_id + " cmp " + id);
1226 if (key
== id
|| key
.indexOf(id
+ ":") == 0) {
1227 sessionStorage
.removeItem(key
);
1238 while (i
< article_cache
.length
) {
1239 if (article_cache
[i
]["id"] == id
) {
1240 //console.log("cache_invalidate: removed id " + id);
1241 article_cache
.splice(i
, 1);
1248 //console.log("cache_invalidate: id not found: " + id);
1251 exception_error("cache_invalidate", e
);
1255 function getActiveArticleId() {
1256 return active_post_id
;
1259 function preloadBatchedArticles() {
1262 var query
= "?op=rpc&subop=getArticles&ids=" +
1263 preload_id_batch
.toString();
1265 new Ajax
.Request("backend.php", {
1267 onComplete: function(transport
) {
1269 preload_id_batch
= [];
1271 var articles
= JSON
.parse(transport
.responseText
);
1273 for (var i
= 0; i
< articles
.length
; i
++) {
1274 var id
= articles
[i
]['id'];
1275 if (!cache_check(id
)) {
1276 cache_inject(id
, articles
[i
]['content']);
1277 console
.log("preloaded article: " + id
);
1283 exception_error("preloadBatchedArticles", e
);
1287 function preloadArticleUnderPointer(id
) {
1289 if (getInitParam("bw_limit") == "1") return;
1291 if (post_under_pointer
== id
&& !cache_check(id
)) {
1293 console
.log("trying to preload article " + id
);
1295 var neighbor_ids
= getRelativePostIds(id
, 1);
1297 /* only request uncached articles */
1299 if (preload_id_batch
.indexOf(id
) == -1) {
1300 for (var i
= 0; i
< neighbor_ids
.length
; i
++) {
1301 if (!cache_check(neighbor_ids
[i
])) {
1302 preload_id_batch
.push(neighbor_ids
[i
]);
1307 if (preload_id_batch
.indexOf(id
) == -1)
1308 preload_id_batch
.push(id
);
1310 //console.log("preload ids batch: " + preload_id_batch.toString());
1312 window
.clearTimeout(preload_timeout_id
);
1313 preload_batch_timeout_id
= window
.setTimeout('preloadBatchedArticles()', 1000);
1317 exception_error("preloadArticleUnderPointer", e
);
1321 function postMouseIn(id
) {
1323 if (post_under_pointer
!= id
) {
1324 post_under_pointer
= id
;
1326 window
.setTimeout("preloadArticleUnderPointer(" + id
+ ")", 250);
1331 exception_error("postMouseIn", e
);
1335 function postMouseOut(id
) {
1337 post_under_pointer
= false;
1339 exception_error("postMouseOut", e
);
1343 function headlines_scroll_handler(e
) {
1345 var hsp
= $("headlines-spacer");
1347 if (!_infscroll_disable
) {
1348 if (hsp
&& (e
.scrollTop
+ e
.offsetHeight
> hsp
.offsetTop
) ||
1349 e
.scrollTop
+ e
.offsetHeight
> e
.scrollHeight
- 100) {
1354 if (hsp
) hsp
.innerHTML
= "";
1357 if (getInitParam("cdm_auto_catchup") == 1) {
1359 $$("#headlines-frame > div[id*=RROW][class*=Unread]").each(
1361 if ($("headlines-frame").scrollTop
>
1362 (child
.offsetTop
+ child
.offsetHeight
/2)) {
1364 var id
= child
.id
.replace("RROW-", "");
1366 if (catchup_id_batch
.indexOf(id
) == -1)
1367 catchup_id_batch
.push(id
);
1371 if (catchup_id_batch
.length
> 0) {
1372 window
.clearTimeout(catchup_timeout_id
);
1373 catchup_timeout_id
= window
.setTimeout('catchupBatchedArticles()',
1379 exception_error("headlines_scroll_handler", e
);
1383 function catchupBatchedArticles() {
1385 if (catchup_id_batch
.length
> 0) {
1387 var query
= "?op=rpc&subop=catchupSelected" +
1388 "&cmode=0&ids=" + param_escape(catchup_id_batch
.toString());
1390 new Ajax
.Request("backend.php", {
1392 onComplete: function(transport
) {
1393 handle_rpc_json(transport
);
1395 catchup_id_batch
.each(function(id
) {
1396 var elem
= $("RROW-" + id
);
1397 if (elem
) elem
.removeClassName("Unread");
1400 catchup_id_batch
= [];
1405 exception_error("catchupBatchedArticles", e
);
1409 function catchupRelativeToArticle(below
) {
1414 if (!getActiveArticleId()) {
1415 alert(__("No article is selected."));
1419 var visible_ids
= getVisibleArticleIds();
1421 var ids_to_mark
= new Array();
1424 for (var i
= 0; i
< visible_ids
.length
; i
++) {
1425 if (visible_ids
[i
] != getActiveArticleId()) {
1426 var e
= $("RROW-" + visible_ids
[i
]);
1428 if (e
&& e
.hasClassName("Unread")) {
1429 ids_to_mark
.push(visible_ids
[i
]);
1436 for (var i
= visible_ids
.length
-1; i
>= 0; i
--) {
1437 if (visible_ids
[i
] != getActiveArticleId()) {
1438 var e
= $("RROW-" + visible_ids
[i
]);
1440 if (e
&& e
.hasClassName("Unread")) {
1441 ids_to_mark
.push(visible_ids
[i
]);
1449 if (ids_to_mark
.length
== 0) {
1450 alert(__("No articles found to mark"));
1452 var msg
= __("Mark %d article(s) as read?").replace("%d", ids_to_mark
.length
);
1454 if (getInitParam("confirm_feed_catchup") != 1 || confirm(msg
)) {
1456 for (var i
= 0; i
< ids_to_mark
.length
; i
++) {
1457 var e
= $("RROW-" + ids_to_mark
[i
]);
1458 e
.removeClassName("Unread");
1461 var query
= "?op=rpc&subop=catchupSelected" +
1462 "&cmode=0" + "&ids=" + param_escape(ids_to_mark
.toString());
1464 new Ajax
.Request("backend.php", {
1466 onComplete: function(transport
) {
1467 handle_rpc_json(transport
);
1474 exception_error("catchupRelativeToArticle", e
);
1478 function cdmExpandArticle(id
) {
1483 var elem
= $("CICD-" + active_post_id
);
1485 var upd_img_pic
= $("FUPDPIC-" + id
);
1487 if (upd_img_pic
&& (upd_img_pic
.src
.match("updated.png") ||
1488 upd_img_pic
.src
.match("fresh_sign.png"))) {
1490 upd_img_pic
.src
= "images/blank_icon.gif";
1493 if (id
== active_post_id
&& Element
.visible(elem
))
1496 selectArticles("none");
1498 var old_offset
= $("RROW-" + id
).offsetTop
;
1500 if (active_post_id
&& elem
&& !getInitParam("cdm_expanded")) {
1502 Element
.show("CEXC-" + active_post_id
);
1505 active_post_id
= id
;
1507 elem
= $("CICD-" + id
);
1509 if (!Element
.visible(elem
)) {
1511 Element
.hide("CEXC-" + id
);
1513 if ($("CWRAP-" + id
).innerHTML
== "") {
1515 $("FUPDPIC-" + id
).src
= "images/indicator_tiny.gif";
1517 $("CWRAP-" + id
).innerHTML
= "<div class=\"insensitive\">" +
1518 __("Loading, please wait...") + "</div>";
1520 var query
= "?op=rpc&subop=cdmGetArticle&id=" + param_escape(id
);
1522 //console.log(query);
1524 new Ajax
.Request("backend.php", {
1526 onComplete: function(transport
) {
1527 $("FUPDPIC-" + id
).src
= 'images/blank_icon.gif';
1529 handle_rpc_json(transport
);
1531 var reply
= JSON
.parse(transport
.responseText
);
1534 var article
= reply
['article']['content'];
1535 var recv_id
= reply
['article']['id'];
1538 $("CWRAP-" + id
).innerHTML
= article
;
1541 $("CWRAP-" + id
).innerHTML
= __("Unable to load article.");
1549 var new_offset
= $("RROW-" + id
).offsetTop
;
1551 $("headlines-frame").scrollTop
+= (new_offset
-old_offset
);
1553 if ($("RROW-" + id
).offsetTop
!= old_offset
)
1554 $("headlines-frame").scrollTop
= new_offset
;
1556 toggleUnread(id
, 0, true);
1560 exception_error("cdmExpandArticle", e
);
1566 function fixHeadlinesOrder(ids
) {
1568 for (var i
= 0; i
< ids
.length
; i
++) {
1569 var e
= $("RROW-" + ids
[i
]);
1573 e
.removeClassName("even");
1574 e
.addClassName("odd");
1576 e
.removeClassName("odd");
1577 e
.addClassName("even");
1582 exception_error("fixHeadlinesOrder", e
);
1586 function getArticleUnderPointer() {
1587 return post_under_pointer
;
1590 function zoomToArticle(event
, id
) {
1592 var cached_article
= cache_find(id
);
1594 if (dijit
.byId("ATAB-" + id
))
1595 if (!event
|| !event
.shiftKey
)
1596 return dijit
.byId("content-tabs").selectChild(dijit
.byId("ATAB-" + id
));
1598 if (dijit
.byId("ATSTRTIP-" + id
))
1599 dijit
.byId("ATSTRTIP-" + id
).destroyRecursive();
1601 if (cached_article
) {
1602 //closeArticlePanel();
1604 var article_pane
= new dijit
.layout
.ContentPane({
1605 title
: __("Loading...") , content
: cached_article
,
1606 style
: 'padding : 0px;',
1610 dijit
.byId("content-tabs").addChild(article_pane
);
1612 if (!event
|| !event
.shiftKey
)
1613 dijit
.byId("content-tabs").selectChild(article_pane
);
1615 if ($("PTITLE-" + id
))
1616 article_pane
.attr('title', $("PTITLE-" + id
).innerHTML
);
1620 var query
= "?op=rpc&subop=getArticles&ids=" + param_escape(id
);
1622 notify_progress("Loading, please wait...", true);
1624 new Ajax
.Request("backend.php", {
1626 onComplete: function(transport
) {
1629 var reply
= JSON
.parse(transport
.responseText
);
1632 //closeArticlePanel();
1634 var content
= reply
[0]['content'];
1636 var article_pane
= new dijit
.layout
.ContentPane({
1637 title
: "article-" + id
, content
: content
,
1638 style
: 'padding : 0px;',
1642 dijit
.byId("content-tabs").addChild(article_pane
);
1644 if (!event
|| !event
.shiftKey
)
1645 dijit
.byId("content-tabs").selectChild(article_pane
);
1647 if ($("PTITLE-" + id
))
1648 article_pane
.attr('title', $("PTITLE-" + id
).innerHTML
);
1655 exception_error("zoomToArticle", e
);
1659 function scrollArticle(offset
) {
1662 var ci
= $("content-insert");
1664 ci
.scrollTop
+= offset
;
1667 var hi
= $("headlines-frame");
1669 hi
.scrollTop
+= offset
;
1674 exception_error("scrollArticle", e
);
1678 function show_labels_in_headlines(transport
) {
1680 var data
= JSON
.parse(transport
.responseText
);
1683 data
['info-for-headlines'].each(function(elem
) {
1684 var ctr
= $("HLLCTR-" + elem
.id
);
1686 if (ctr
) ctr
.innerHTML
= elem
.labels
;
1690 exception_error("show_labels_in_headlines", e
);
1694 function toggleHeadlineActions() {
1696 var e
= $("headlineActionsBody");
1697 var p
= $("headlineActionsDrop");
1699 if (!Element
.visible(e
)) {
1706 e
.style
.left
= (p
.offsetLeft
+ 1) + "px";
1707 e
.style
.top
= (p
.offsetTop
+ p
.offsetHeight
+ 2) + "px";
1710 exception_error("toggleHeadlineActions", e
);
1714 /* function publishWithNote(id, def_note) {
1716 if (!def_note) def_note = '';
1718 var note = prompt(__("Please enter a note for this article:"), def_note);
1720 if (note != undefined) {
1721 togglePub(id, false, false, note);
1725 exception_error("publishWithNote", e);
1729 function emailArticle(id
) {
1732 var ids
= getSelectedArticleIds2();
1734 if (ids
.length
== 0) {
1735 alert(__("No articles are selected."));
1739 id
= ids
.toString();
1742 if (dijit
.byId("emailArticleDlg"))
1743 dijit
.byId("emailArticleDlg").destroyRecursive();
1745 var query
= "backend.php?op=dlg&id=emailArticle¶m=" + param_escape(id
);
1747 dialog
= new dijit
.Dialog({
1748 id
: "emailArticleDlg",
1749 title
: __("Forward article by email"),
1750 style
: "width: 600px",
1751 execute: function() {
1752 if (this.validate()) {
1754 new Ajax
.Request("backend.php", {
1755 parameters
: dojo
.objectToQuery(this.attr('value')),
1756 onComplete: function(transport
) {
1758 var reply
= JSON
.parse(transport
.responseText
);
1760 var error
= reply
['error'];
1763 alert(__('Error sending email:') + ' ' + error
);
1765 notify_info('Your message has been sent.');
1774 var tmph
= dojo
.connect(dialog
, 'onLoad', function() {
1775 dojo
.disconnect(tmph
);
1777 new Ajax
.Autocompleter('emailArticleDlg_destination', 'emailArticleDlg_dst_choices',
1778 "backend.php?op=rpc&subop=completeEmails",
1779 { tokens
: '', paramName
: "search" });
1784 /* displayDlg('emailArticle', id,
1786 document.forms['article_email_form'].destination.focus();
1788 new Ajax.Autocompleter('destination', 'destination_choices',
1789 "backend.php?op=rpc&subop=completeEmails",
1790 { tokens: '', paramName: "search" });
1795 exception_error("emailArticle", e
);
1799 function dismissArticle(id
) {
1801 var elem
= $("RROW-" + id
);
1803 toggleUnread(id
, 0, true);
1805 new Effect
.Fade(elem
, {duration
: 0.5});
1807 active_post_id
= false;
1810 exception_error("dismissArticle", e
);
1814 function dismissSelectedArticles() {
1817 var ids
= getVisibleArticleIds();
1821 for (var i
= 0; i
< ids
.length
; i
++) {
1822 var elem
= $("RROW-" + ids
[i
]);
1824 if (elem
.className
&& elem
.hasClassName("Selected") &&
1825 ids
[i
] != active_post_id
) {
1826 new Effect
.Fade(elem
, {duration
: 0.5});
1834 selectionToggleUnread(false);
1836 fixHeadlinesOrder(tmp
);
1839 exception_error("dismissSelectedArticles", e
);
1843 function dismissReadArticles() {
1846 var ids
= getVisibleArticleIds();
1849 for (var i
= 0; i
< ids
.length
; i
++) {
1850 var elem
= $("RROW-" + ids
[i
]);
1852 if (elem
.className
&& !elem
.hasClassName("Unread") &&
1853 !elem
.hasClassName("Selected")) {
1855 new Effect
.Fade(elem
, {duration
: 0.5});
1861 fixHeadlinesOrder(tmp
);
1864 exception_error("dismissSelectedArticles", e
);
1868 function getVisibleArticleIds() {
1873 getLoadedArticleIds().each(function(id
) {
1874 var elem
= $("RROW-" + id
);
1875 if (elem
&& Element
.visible(elem
))
1880 exception_error("getVisibleArticleIds", e
);
1886 function cdmClicked(event
, id
) {
1888 var shift_key
= event
.shiftKey
;
1892 if (!event
.ctrlKey
) {
1894 if (!getInitParam("cdm_expanded")) {
1895 return cdmExpandArticle(id
);
1898 selectArticles("none");
1901 var elem
= $("RROW-" + id
);
1904 elem
.removeClassName("Unread");
1906 var upd_img_pic
= $("FUPDPIC-" + id
);
1908 if (upd_img_pic
&& (upd_img_pic
.src
.match("updated.png") ||
1909 upd_img_pic
.src
.match("fresh_sign.png"))) {
1911 upd_img_pic
.src
= "images/blank_icon.gif";
1914 active_post_id
= id
;
1916 var query
= "?op=rpc&subop=catchupSelected" +
1917 "&cmode=0&ids=" + param_escape(id
);
1919 new Ajax
.Request("backend.php", {
1921 onComplete: function(transport
) {
1922 handle_rpc_json(transport
);
1929 toggleSelected(id
, true);
1930 toggleUnread(id
, 0, false);
1931 zoomToArticle(event
, id
);
1935 exception_error("cdmClicked");
1941 function postClicked(event
, id
) {
1944 if (!event
.ctrlKey
) {
1947 postOpenInNewTab(event
, id
);
1952 exception_error("postClicked");
1956 function hlOpenInNewTab(event
, id
) {
1957 toggleUnread(id
, 0, false);
1958 zoomToArticle(event
, id
);
1961 function postOpenInNewTab(event
, id
) {
1962 closeArticlePanel(id
);
1963 zoomToArticle(event
, id
);
1966 function hlClicked(event
, id
) {
1968 if (event
.which
== 2) {
1971 } else if (event
.altKey
) {
1972 openArticleInNewWindow(id
);
1973 } else if (!event
.ctrlKey
) {
1978 toggleUnread(id
, 0, false);
1979 zoomToArticle(event
, id
);
1984 exception_error("hlClicked");
1988 function getFirstVisibleHeadlineId() {
1989 var rows
= getVisibleArticleIds();
1994 function getLastVisibleHeadlineId() {
1995 var rows
= getVisibleArticleIds();
1996 return rows
[rows
.length
-1];
1999 function openArticleInNewWindow(id
) {
2000 toggleUnread(id
, 0, false);
2001 window
.open("backend.php?op=la&id=" + id
);
2004 function isCdmMode() {
2005 return getInitParam("combined_display_mode");
2008 function markHeadline(id
) {
2009 var row
= $("RROW-" + id
);
2011 var check
= $("RCHK-" + id
);
2014 check
.checked
= true;
2017 row
.addClassName("Selected");
2021 function getRelativePostIds(id
, limit
) {
2027 if (!limit
) limit
= 3;
2029 var ids
= getVisibleArticleIds();
2031 for (var i
= 0; i
< ids
.length
; i
++) {
2033 for (var k
= 1; k
<= limit
; k
++) {
2034 if (i
> k
-1) tmp
.push(ids
[i
-k
]);
2035 if (i
< ids
.length
-k
) tmp
.push(ids
[i
+k
]);
2042 exception_error("getRelativePostIds", e
);
2048 function correctHeadlinesOffset(id
) {
2052 var container
= $("headlines-frame");
2053 var row
= $("RROW-" + id
);
2055 var viewport
= container
.offsetHeight
;
2057 var rel_offset_top
= row
.offsetTop
- container
.scrollTop
;
2058 var rel_offset_bottom
= row
.offsetTop
+ row
.offsetHeight
- container
.scrollTop
;
2060 //console.log("Rtop: " + rel_offset_top + " Rbtm: " + rel_offset_bottom);
2061 //console.log("Vport: " + viewport);
2063 if (rel_offset_top
<= 0 || rel_offset_top
> viewport
) {
2064 container
.scrollTop
= row
.offsetTop
;
2065 } else if (rel_offset_bottom
> viewport
) {
2067 /* doesn't properly work with Opera in some cases because
2068 Opera fucks up element scrolling */
2070 container
.scrollTop
= row
.offsetTop
+ row
.offsetHeight
- viewport
;
2074 exception_error("correctHeadlinesOffset", e
);
2079 function headlineActionsChange(elem
) {
2082 elem
.attr('value', 'false');
2084 exception_error("headlineActionsChange", e
);
2088 function closeArticlePanel() {
2090 var tabs
= dijit
.byId("content-tabs");
2091 var child
= tabs
.selectedChildWidget
;
2093 if (child
&& tabs
.getIndexOfChild(child
) > 0) {
2094 tabs
.removeChild(child
);
2097 if (dijit
.byId("content-insert"))
2098 dijit
.byId("headlines-wrap-inner").removeChild(
2099 dijit
.byId("content-insert"));
2103 function initHeadlinesMenu() {
2105 if (dijit
.byId("headlinesMenu"))
2106 dijit
.byId("headlinesMenu").destroyRecursive();
2111 nodes
= $$("#headlines-frame > div[id*=RROW]");
2113 nodes
= $$("#headlines-frame span[id*=RTITLE]");
2116 nodes
.each(function(node
) {
2120 var menu
= new dijit
.Menu({
2121 id
: "headlinesMenu",
2125 var tmph
= dojo
.connect(menu
, '_openMyself', function (event
) {
2126 var callerNode
= event
.target
, match
= null, tries
= 0;
2128 while (match
== null && callerNode
&& tries
<= 3) {
2129 match
= callerNode
.id
.match("^[A-Z]+[-]([0-9]+)$");
2130 callerNode
= callerNode
.parentNode
;
2134 if (match
) this.callerRowId
= parseInt(match
[1]);
2138 /* if (!isCdmMode())
2139 menu.addChild(new dijit.MenuItem({
2140 label: __("View article"),
2141 onClick: function(event) {
2142 view(this.getParent().callerRowId);
2145 menu
.addChild(new dijit
.MenuItem({
2146 label
: __("Open original article"),
2147 onClick: function(event
) {
2148 openArticleInNewWindow(this.getParent().callerRowId
);
2151 menu
.addChild(new dijit
.MenuItem({
2152 label
: __("View in a tt-rss tab"),
2153 onClick: function(event
) {
2154 hlOpenInNewTab(event
, this.getParent().callerRowId
);
2157 // menu.addChild(new dijit.MenuSeparator());
2159 var labels
= dijit
.byId("feedTree").model
.getItemsInCategory(-2);
2163 menu
.addChild(new dijit
.MenuSeparator());
2165 var labelAddMenu
= new dijit
.Menu({ownerMenu
: menu
});
2166 var labelDelMenu
= new dijit
.Menu({ownerMenu
: menu
});
2168 labels
.each(function(label
) {
2169 var id
= label
.id
[0];
2170 var bare_id
= id
.substr(id
.indexOf(":")+1);
2171 var name
= label
.name
[0];
2173 bare_id
= -11-bare_id
;
2175 labelAddMenu
.addChild(new dijit
.MenuItem({
2178 onClick: function(event
) {
2179 selectionAssignLabel(this.labelId
,
2180 [this.getParent().ownerMenu
.callerRowId
]);
2183 labelDelMenu
.addChild(new dijit
.MenuItem({
2186 onClick: function(event
) {
2187 selectionRemoveLabel(this.labelId
,
2188 [this.getParent().ownerMenu
.callerRowId
]);
2193 menu
.addChild(new dijit
.PopupMenuItem({
2194 label
: __("Assign label"),
2195 popup
: labelAddMenu
,
2198 menu
.addChild(new dijit
.PopupMenuItem({
2199 label
: __("Remove label"),
2200 popup
: labelDelMenu
,
2208 exception_error("initHeadlinesMenu", e
);
2212 function tweetArticle(id
) {
2214 var query
= "?op=rpc&subop=getTweetInfo&id=" + param_escape(id
);
2219 var ts
= d
.getTime();
2221 var w
= window
.open('backend.php?op=loading', 'ttrss_tweet',
2222 "status=0,toolbar=0,location=0,width=500,height=400,scrollbars=1,menubar=0");
2224 new Ajax
.Request("backend.php", {
2226 onComplete: function(transport
) {
2227 var ti
= JSON
.parse(transport
.responseText
);
2229 var share_url
= "http://twitter.com/share?_=" + ts
+
2230 "&text=" + param_escape(ti
.title
) +
2231 "&url=" + param_escape(ti
.link
);
2233 w
.location
.href
= share_url
;
2239 exception_error("tweetArticle", e
);
2243 function editArticleNote(id
) {
2246 var query
= "backend.php?op=dlg&id=editArticleNote¶m=" + param_escape(id
);
2248 if (dijit
.byId("editNoteDlg"))
2249 dijit
.byId("editNoteDlg").destroyRecursive();
2251 dialog
= new dijit
.Dialog({
2253 title
: __("Edit article note"),
2254 style
: "width: 600px",
2255 execute: function() {
2256 if (this.validate()) {
2257 var query
= dojo
.objectToQuery(this.attr('value'));
2259 notify_progress("Saving article note...", true);
2261 new Ajax
.Request("backend.php", {
2263 onComplete: function(transport
) {
2267 var reply
= JSON
.parse(transport
.responseText
);
2269 cache_invalidate(id
);
2271 var elem
= $("POSTNOTE-" + id
);
2275 elem
.innerHTML
= reply
.note
;
2277 if (reply
.raw_length
!= 0)
2278 new Effect
.Appear(elem
);
2290 exception_error("editArticleNote", e
);
2294 function player(elem
) {
2295 var aid
= elem
.getAttribute("audio-id");
2296 var status
= elem
.getAttribute("status");
2304 elem
.innerHTML
= __("Playing...");
2305 elem
.title
= __("Click to pause");
2306 elem
.addClassName("playing");
2310 elem
.innerHTML
= __("Play");
2311 elem
.title
= __("Click to play");
2312 elem
.removeClassName("playing");
2315 elem
.setAttribute("status", status
);
2317 alert("Your browser doesn't seem to support HTML5 audio.");