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