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