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