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