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