]> git.wh0rd.org - tt-rss.git/blob - js/viewfeed.js
previous patch, fix typo
[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.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 if (_active_article_id) {
1252 var row = $("RROW-" + _active_article_id);
1253 if (row) row.removeClassName("active");
1254 }
1255
1256 _active_article_id = child.id.replace("RROW-", "");
1257 showArticleInHeadlines(_active_article_id, true);
1258 updateSelectedPrompt();
1259 break;
1260 }
1261 }
1262 }
1263
1264 if (!_infscroll_disable) {
1265 if ((hsp && e.scrollTop + e.offsetHeight >= hsp.offsetTop - hsp.offsetHeight) ||
1266 (e.scrollHeight != 0 &&
1267 ((e.scrollTop + e.offsetHeight) / e.scrollHeight >= 0.7))) {
1268
1269 if (hsp)
1270 hsp.innerHTML = "<img src='images/indicator_tiny.gif'> " +
1271 __("Loading, please wait...");
1272
1273 loadMoreHeadlines();
1274 return;
1275
1276 }
1277 } else {
1278 if (hsp) hsp.innerHTML = "";
1279 }
1280
1281 if (getInitParam("cdm_auto_catchup") == 1) {
1282
1283 // let's get DOM some time to settle down
1284 var ts = new Date().getTime();
1285 if (ts - _last_headlines_update < 100) return;
1286
1287 $$("#headlines-frame > div[id*=RROW][class*=Unread]").each(
1288 function(child) {
1289 if (child.hasClassName("Unread") && $("headlines-frame").scrollTop >
1290 (child.offsetTop + child.offsetHeight/2)) {
1291
1292 var id = child.id.replace("RROW-", "");
1293
1294 if (catchup_id_batch.indexOf(id) == -1)
1295 catchup_id_batch.push(id);
1296
1297 //console.log("auto_catchup_batch: " + catchup_id_batch.toString());
1298 }
1299
1300 });
1301
1302 if (catchup_id_batch.length > 0) {
1303 window.clearTimeout(catchup_timeout_id);
1304
1305 if (!_infscroll_request_sent) {
1306 catchup_timeout_id = window.setTimeout('catchupBatchedArticles()',
1307 500);
1308 }
1309 }
1310 }
1311
1312 } catch (e) {
1313 console.warn("headlines_scroll_handler: " + e);
1314 }
1315 }
1316
1317 function catchupBatchedArticles() {
1318 try {
1319 if (catchup_id_batch.length > 0 && !_infscroll_request_sent) {
1320
1321 // make a copy of the array
1322 var batch = catchup_id_batch.slice();
1323 var query = "?op=rpc&method=catchupSelected" +
1324 "&cmode=0&ids=" + param_escape(batch.toString());
1325
1326 console.log(query);
1327
1328 new Ajax.Request("backend.php", {
1329 parameters: query,
1330 onComplete: function(transport) {
1331 handle_rpc_json(transport);
1332
1333 reply = JSON.parse(transport.responseText);
1334 var batch = reply.ids;
1335
1336 batch.each(function(id) {
1337 console.log(id);
1338 var elem = $("RROW-" + id);
1339 if (elem) elem.removeClassName("Unread");
1340 catchup_id_batch.remove(id);
1341 });
1342
1343 } });
1344 }
1345
1346 } catch (e) {
1347 exception_error("catchupBatchedArticles", e);
1348 }
1349 }
1350
1351 function catchupRelativeToArticle(below, id) {
1352
1353 try {
1354
1355 if (!id) id = getActiveArticleId();
1356
1357 if (!id) {
1358 alert(__("No article is selected."));
1359 return;
1360 }
1361
1362 var visible_ids = getVisibleArticleIds();
1363
1364 var ids_to_mark = new Array();
1365
1366 if (!below) {
1367 for (var i = 0; i < visible_ids.length; i++) {
1368 if (visible_ids[i] != id) {
1369 var e = $("RROW-" + visible_ids[i]);
1370
1371 if (e && e.hasClassName("Unread")) {
1372 ids_to_mark.push(visible_ids[i]);
1373 }
1374 } else {
1375 break;
1376 }
1377 }
1378 } else {
1379 for (var i = visible_ids.length-1; i >= 0; i--) {
1380 if (visible_ids[i] != id) {
1381 var e = $("RROW-" + visible_ids[i]);
1382
1383 if (e && e.hasClassName("Unread")) {
1384 ids_to_mark.push(visible_ids[i]);
1385 }
1386 } else {
1387 break;
1388 }
1389 }
1390 }
1391
1392 if (ids_to_mark.length == 0) {
1393 alert(__("No articles found to mark"));
1394 } else {
1395 var msg = ngettext("Mark %d article as read?", "Mark %d articles as read?", ids_to_mark.length).replace("%d", ids_to_mark.length);
1396
1397 if (getInitParam("confirm_feed_catchup") != 1 || confirm(msg)) {
1398
1399 for (var i = 0; i < ids_to_mark.length; i++) {
1400 var e = $("RROW-" + ids_to_mark[i]);
1401 e.removeClassName("Unread");
1402 }
1403
1404 var query = "?op=rpc&method=catchupSelected" +
1405 "&cmode=0" + "&ids=" + param_escape(ids_to_mark.toString());
1406
1407 new Ajax.Request("backend.php", {
1408 parameters: query,
1409 onComplete: function(transport) {
1410 handle_rpc_json(transport);
1411 } });
1412
1413 }
1414 }
1415
1416 } catch (e) {
1417 exception_error("catchupRelativeToArticle", e);
1418 }
1419 }
1420
1421 function cdmCollapseArticle(event, id, unmark) {
1422 try {
1423 if (unmark == undefined) unmark = true;
1424
1425 var row = $("RROW-" + id);
1426 var elem = $("CICD-" + id);
1427
1428 if (elem && row) {
1429 var collapse = $$("div#RROW-" + id +
1430 " span[class='collapseBtn']")[0];
1431
1432 Element.hide(elem);
1433 Element.show("CEXC-" + id);
1434 Element.hide(collapse);
1435
1436 if (unmark) {
1437 row.removeClassName("active");
1438
1439 markHeadline(id, false);
1440
1441 if (id == getActiveArticleId()) {
1442 setActiveArticleId(0);
1443 }
1444
1445 updateSelectedPrompt();
1446 }
1447
1448 if (event) Event.stop(event);
1449
1450 PluginHost.run(PluginHost.HOOK_ARTICLE_COLLAPSED, id);
1451 }
1452
1453 } catch (e) {
1454 exception_error("cdmCollapseArticle", e);
1455 }
1456 }
1457
1458 function cdmExpandArticle(id, noexpand) {
1459 try {
1460 console.log("cdmExpandArticle " + id);
1461
1462 if (!$("RROW-" + id)) return false;
1463
1464 var oldrow = $("RROW-" + getActiveArticleId());
1465
1466 var elem = $("CICD-" + getActiveArticleId());
1467
1468 if (id == getActiveArticleId() && Element.visible(elem))
1469 return true;
1470
1471 selectArticles("none");
1472
1473 var old_offset = $("RROW-" + id).offsetTop;
1474
1475 if (getActiveArticleId() && elem && !getInitParam("cdm_expanded")) {
1476 var collapse = $$("div#RROW-" + getActiveArticleId() +
1477 " span[class='collapseBtn']")[0];
1478
1479 Element.hide(elem);
1480 Element.show("CEXC-" + getActiveArticleId());
1481 Element.hide(collapse);
1482 }
1483
1484 if (oldrow) oldrow.removeClassName("active");
1485
1486 setActiveArticleId(id);
1487
1488 elem = $("CICD-" + id);
1489
1490 var collapse = $$("div#RROW-" + id +
1491 " span[class='collapseBtn']")[0];
1492
1493 var cencw = $("CENCW-" + id);
1494
1495 if (!Element.visible(elem) && !noexpand) {
1496 if (cencw) {
1497 cencw.innerHTML = htmlspecialchars_decode(cencw.innerHTML);
1498 cencw.setAttribute('id', '');
1499 Element.show(cencw);
1500 }
1501
1502 Element.show(elem);
1503 Element.hide("CEXC-" + id);
1504 Element.show(collapse);
1505 }
1506
1507 var new_offset = $("RROW-" + id).offsetTop;
1508
1509 if (old_offset > new_offset)
1510 $("headlines-frame").scrollTop -= (old_offset-new_offset);
1511
1512 if (!noexpand)
1513 toggleUnread(id, 0, true);
1514 toggleSelected(id);
1515 $("RROW-" + id).addClassName("active");
1516
1517 PluginHost.run(PluginHost.HOOK_ARTICLE_EXPANDED, id);
1518
1519 } catch (e) {
1520 exception_error("cdmExpandArticle", e);
1521 }
1522
1523 return false;
1524 }
1525
1526 function getArticleUnderPointer() {
1527 return post_under_pointer;
1528 }
1529
1530 function scrollArticle(offset) {
1531 try {
1532 if (!isCdmMode()) {
1533 var ci = $("content-insert");
1534 if (ci) {
1535 ci.scrollTop += offset;
1536 }
1537 } else {
1538 var hi = $("headlines-frame");
1539 if (hi) {
1540 hi.scrollTop += offset;
1541 }
1542
1543 }
1544 } catch (e) {
1545 exception_error("scrollArticle", e);
1546 }
1547 }
1548
1549 function show_labels_in_headlines(transport) {
1550 try {
1551 var data = JSON.parse(transport.responseText);
1552
1553 if (data) {
1554 data['info-for-headlines'].each(function(elem) {
1555 var ctr = $("HLLCTR-" + elem.id);
1556
1557 if (ctr) ctr.innerHTML = elem.labels;
1558 });
1559 }
1560 } catch (e) {
1561 exception_error("show_labels_in_headlines", e);
1562 }
1563 }
1564
1565 function dismissArticle(id) {
1566 try {
1567 var elem = $("RROW-" + id);
1568
1569 if (!elem) return;
1570
1571 toggleUnread(id, 0, true);
1572
1573 new Effect.Fade(elem, {duration : 0.5});
1574
1575 if (id == getActiveArticleId()) {
1576 setActiveArticleId(0);
1577 }
1578
1579 } catch (e) {
1580 exception_error("dismissArticle", e);
1581 }
1582 }
1583
1584 function dismissSelectedArticles() {
1585 try {
1586
1587 var ids = getVisibleArticleIds();
1588 var tmp = [];
1589 var sel = [];
1590
1591 for (var i = 0; i < ids.length; i++) {
1592 var elem = $("RROW-" + ids[i]);
1593
1594 if (elem.className && elem.hasClassName("Selected") &&
1595 ids[i] != getActiveArticleId()) {
1596 new Effect.Fade(elem, {duration : 0.5});
1597 sel.push(ids[i]);
1598 } else {
1599 tmp.push(ids[i]);
1600 }
1601 }
1602
1603 if (sel.length > 0)
1604 selectionToggleUnread(false);
1605
1606
1607 } catch (e) {
1608 exception_error("dismissSelectedArticles", e);
1609 }
1610 }
1611
1612 function dismissReadArticles() {
1613 try {
1614
1615 var ids = getVisibleArticleIds();
1616 var tmp = [];
1617
1618 for (var i = 0; i < ids.length; i++) {
1619 var elem = $("RROW-" + ids[i]);
1620
1621 if (elem.className && !elem.hasClassName("Unread") &&
1622 !elem.hasClassName("Selected")) {
1623
1624 new Effect.Fade(elem, {duration : 0.5});
1625 } else {
1626 tmp.push(ids[i]);
1627 }
1628 }
1629
1630 } catch (e) {
1631 exception_error("dismissSelectedArticles", e);
1632 }
1633 }
1634
1635 function getVisibleArticleIds() {
1636 var ids = [];
1637
1638 try {
1639
1640 getLoadedArticleIds().each(function(id) {
1641 var elem = $("RROW-" + id);
1642 if (elem && Element.visible(elem))
1643 ids.push(id);
1644 });
1645
1646 } catch (e) {
1647 exception_error("getVisibleArticleIds", e);
1648 }
1649
1650 return ids;
1651 }
1652
1653 function cdmClicked(event, id) {
1654 try {
1655 //var shift_key = event.shiftKey;
1656
1657 if (!event.ctrlKey) {
1658
1659 if (!getInitParam("cdm_expanded")) {
1660 return cdmExpandArticle(id);
1661 } else {
1662
1663 var elem = $("RROW-" + getActiveArticleId());
1664
1665 if (elem) elem.removeClassName("active");
1666
1667 selectArticles("none");
1668 toggleSelected(id);
1669
1670 var elem = $("RROW-" + id);
1671 var article_is_unread = elem.hasClassName("Unread");
1672
1673 elem.removeClassName("Unread");
1674 elem.addClassName("active");
1675
1676 setActiveArticleId(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 !event.shiftKey;
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
1706 openArticleInNewWindow(id);
1707 }
1708
1709 var unread_in_buffer = $$("#headlines-frame > div[id*=RROW][class*=Unread]").length
1710 request_counters(unread_in_buffer == 0);
1711
1712 } catch (e) {
1713 exception_error("cdmClicked");
1714 }
1715
1716 return false;
1717 }
1718
1719 function hlClicked(event, id) {
1720 try {
1721 if (event.which == 2) {
1722 view(id);
1723 return true;
1724 } else if (event.ctrlKey) {
1725 toggleSelected(id, true);
1726 toggleUnread(id, 0, false);
1727 openArticleInNewWindow(id);
1728 return false;
1729 } else {
1730 view(id);
1731 return false;
1732 }
1733
1734 } catch (e) {
1735 exception_error("hlClicked");
1736 }
1737 }
1738
1739 function getFirstVisibleHeadlineId() {
1740 var rows = getVisibleArticleIds();
1741 return rows[0];
1742
1743 }
1744
1745 function getLastVisibleHeadlineId() {
1746 var rows = getVisibleArticleIds();
1747 return rows[rows.length-1];
1748 }
1749
1750 function openArticleInNewWindow(id) {
1751 toggleUnread(id, 0, false);
1752 window.open("backend.php?op=article&method=redirect&id=" + id);
1753 }
1754
1755 function isCdmMode() {
1756 return getInitParam("combined_display_mode");
1757 }
1758
1759 function markHeadline(id, marked) {
1760 if (marked == undefined) marked = true;
1761
1762 var row = $("RROW-" + id);
1763 if (row) {
1764 var check = dijit.getEnclosingWidget(
1765 row.getElementsByClassName("rchk")[0]);
1766
1767 if (check) {
1768 check.attr("checked", marked);
1769 }
1770
1771 if (marked)
1772 row.addClassName("Selected");
1773 else
1774 row.removeClassName("Selected");
1775 }
1776 }
1777
1778 function getRelativePostIds(id, limit) {
1779
1780 var tmp = [];
1781
1782 try {
1783
1784 if (!limit) limit = 6; //3
1785
1786 var ids = getVisibleArticleIds();
1787
1788 for (var i = 0; i < ids.length; i++) {
1789 if (ids[i] == id) {
1790 for (var k = 1; k <= limit; k++) {
1791 //if (i > k-1) tmp.push(ids[i-k]);
1792 if (i < ids.length-k) tmp.push(ids[i+k]);
1793 }
1794 break;
1795 }
1796 }
1797
1798 } catch (e) {
1799 exception_error("getRelativePostIds", e);
1800 }
1801
1802 return tmp;
1803 }
1804
1805 function correctHeadlinesOffset(id) {
1806
1807 try {
1808
1809 var container = $("headlines-frame");
1810 var row = $("RROW-" + id);
1811
1812 if (!container || !row) return;
1813
1814 var viewport = container.offsetHeight;
1815
1816 var rel_offset_top = row.offsetTop - container.scrollTop;
1817 var rel_offset_bottom = row.offsetTop + row.offsetHeight - container.scrollTop;
1818
1819 //console.log("Rtop: " + rel_offset_top + " Rbtm: " + rel_offset_bottom);
1820 //console.log("Vport: " + viewport);
1821
1822 if (rel_offset_top <= 0 || rel_offset_top > viewport) {
1823 container.scrollTop = row.offsetTop;
1824 } else if (rel_offset_bottom > viewport) {
1825
1826 /* doesn't properly work with Opera in some cases because
1827 Opera fucks up element scrolling */
1828
1829 container.scrollTop = row.offsetTop + row.offsetHeight - viewport;
1830 }
1831
1832 } catch (e) {
1833 exception_error("correctHeadlinesOffset", e);
1834 }
1835
1836 }
1837
1838 function headlineActionsChange(elem) {
1839 try {
1840 eval(elem.value);
1841 elem.attr('value', 'false');
1842 } catch (e) {
1843 exception_error("headlineActionsChange", e);
1844 }
1845 }
1846
1847 function closeArticlePanel() {
1848
1849 if (dijit.byId("content-insert"))
1850 dijit.byId("headlines-wrap-inner").removeChild(
1851 dijit.byId("content-insert"));
1852 }
1853
1854 function initHeadlinesMenu() {
1855 try {
1856 if (dijit.byId("headlinesMenu"))
1857 dijit.byId("headlinesMenu").destroyRecursive();
1858
1859 var ids = [];
1860
1861 if (!isCdmMode()) {
1862 nodes = $$("#headlines-frame > div[id*=RROW]");
1863 } else {
1864 nodes = $$("#headlines-frame span[id*=RTITLE]");
1865 }
1866
1867 nodes.each(function(node) {
1868 ids.push(node.id);
1869 });
1870
1871 var menu = new dijit.Menu({
1872 id: "headlinesMenu",
1873 targetNodeIds: ids,
1874 });
1875
1876 var tmph = dojo.connect(menu, '_openMyself', function (event) {
1877 var callerNode = event.target, match = null, tries = 0;
1878
1879 while (match == null && callerNode && tries <= 3) {
1880 match = callerNode.id.match("^[A-Z]+[-]([0-9]+)$");
1881 callerNode = callerNode.parentNode;
1882 ++tries;
1883 }
1884
1885 if (match) this.callerRowId = parseInt(match[1]);
1886
1887 });
1888
1889 /* if (!isCdmMode())
1890 menu.addChild(new dijit.MenuItem({
1891 label: __("View article"),
1892 onClick: function(event) {
1893 view(this.getParent().callerRowId);
1894 }})); */
1895
1896 menu.addChild(new dijit.MenuItem({
1897 label: __("Open original article"),
1898 onClick: function(event) {
1899 openArticleInNewWindow(this.getParent().callerRowId);
1900 }}));
1901
1902 menu.addChild(new dijit.MenuItem({
1903 label: __("Display article URL"),
1904 onClick: function(event) {
1905 displayArticleUrl(this.getParent().callerRowId);
1906 }}));
1907
1908 menu.addChild(new dijit.MenuSeparator());
1909
1910 menu.addChild(new dijit.MenuItem({
1911 label: __("Toggle unread"),
1912 onClick: function(event) {
1913 var ids = getSelectedArticleIds2();
1914 // cast to string
1915 var id = this.getParent().callerRowId + "";
1916 ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
1917
1918 selectionToggleUnread(undefined, false, true, ids);
1919 }}));
1920
1921 menu.addChild(new dijit.MenuItem({
1922 label: __("Toggle marked"),
1923 onClick: function(event) {
1924 var ids = getSelectedArticleIds2();
1925 // cast to string
1926 var id = this.getParent().callerRowId + "";
1927 ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
1928
1929 selectionToggleMarked(undefined, false, true, ids);
1930 }}));
1931
1932 menu.addChild(new dijit.MenuItem({
1933 label: __("Toggle published"),
1934 onClick: function(event) {
1935 var ids = getSelectedArticleIds2();
1936 // cast to string
1937 var id = this.getParent().callerRowId + "";
1938 ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
1939
1940 selectionTogglePublished(undefined, false, true, ids);
1941 }}));
1942
1943 menu.addChild(new dijit.MenuSeparator());
1944
1945 menu.addChild(new dijit.MenuItem({
1946 label: __("Mark above as read"),
1947 onClick: function(event) {
1948 catchupRelativeToArticle(0, this.getParent().callerRowId);
1949 }}));
1950
1951 menu.addChild(new dijit.MenuItem({
1952 label: __("Mark below as read"),
1953 onClick: function(event) {
1954 catchupRelativeToArticle(1, this.getParent().callerRowId);
1955 }}));
1956
1957
1958 var labels = dijit.byId("feedTree").model.getItemsInCategory(-2);
1959
1960 if (labels) {
1961
1962 menu.addChild(new dijit.MenuSeparator());
1963
1964 var labelAddMenu = new dijit.Menu({ownerMenu: menu});
1965 var labelDelMenu = new dijit.Menu({ownerMenu: menu});
1966
1967 labels.each(function(label) {
1968 var id = label.id[0];
1969 var bare_id = id.substr(id.indexOf(":")+1);
1970 var name = label.name[0];
1971
1972 bare_id = feed_to_label_id(bare_id);
1973
1974 labelAddMenu.addChild(new dijit.MenuItem({
1975 label: name,
1976 labelId: bare_id,
1977 onClick: function(event) {
1978 var ids = getSelectedArticleIds2();
1979 // cast to string
1980 var id = this.getParent().ownerMenu.callerRowId + "";
1981
1982 ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
1983
1984 selectionAssignLabel(this.labelId, ids);
1985 }}));
1986
1987 labelDelMenu.addChild(new dijit.MenuItem({
1988 label: name,
1989 labelId: bare_id,
1990 onClick: function(event) {
1991 var ids = getSelectedArticleIds2();
1992 // cast to string
1993 var id = this.getParent().ownerMenu.callerRowId + "";
1994
1995 ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
1996
1997 selectionRemoveLabel(this.labelId, ids);
1998 }}));
1999
2000 });
2001
2002 menu.addChild(new dijit.PopupMenuItem({
2003 label: __("Assign label"),
2004 popup: labelAddMenu,
2005 }));
2006
2007 menu.addChild(new dijit.PopupMenuItem({
2008 label: __("Remove label"),
2009 popup: labelDelMenu,
2010 }));
2011
2012 }
2013
2014 menu.startup();
2015
2016 } catch (e) {
2017 exception_error("initHeadlinesMenu", e);
2018 }
2019 }
2020
2021 function cache_set(id, obj) {
2022 //console.log("cache_set: " + id);
2023 if (has_storage)
2024 try {
2025 sessionStorage[id] = obj;
2026 } catch (e) {
2027 sessionStorage.clear();
2028 }
2029 }
2030
2031 function cache_get(id) {
2032 if (has_storage)
2033 return sessionStorage[id];
2034 }
2035
2036 function cache_clear() {
2037 if (has_storage)
2038 sessionStorage.clear();
2039 }
2040
2041 function cache_delete(id) {
2042 if (has_storage)
2043 sessionStorage.removeItem(id);
2044 }
2045
2046 function cancelSearch() {
2047 try {
2048 _search_query = "";
2049 viewCurrentFeed();
2050 } catch (e) {
2051 exception_error("cancelSearch", e);
2052 }
2053 }
2054
2055 function setSelectionScore() {
2056 try {
2057 var ids = getSelectedArticleIds2();
2058
2059 if (ids.length > 0) {
2060 console.log(ids);
2061
2062 var score = prompt(__("Please enter new score for selected articles:"), score);
2063
2064 if (score != undefined) {
2065 var query = "op=article&method=setScore&id=" + param_escape(ids.toString()) +
2066 "&score=" + param_escape(score);
2067
2068 new Ajax.Request("backend.php", {
2069 parameters: query,
2070 onComplete: function(transport) {
2071 var reply = JSON.parse(transport.responseText);
2072 if (reply) {
2073 console.log(ids);
2074
2075 ids.each(function(id) {
2076 var row = $("RROW-" + id);
2077
2078 if (row) {
2079 var pic = row.getElementsByClassName("hlScorePic")[0];
2080
2081 if (pic) {
2082 pic.src = pic.src.replace(/score_.*?\.png/,
2083 reply["score_pic"]);
2084 pic.setAttribute("score", score);
2085 }
2086 }
2087 });
2088 }
2089 } });
2090 }
2091
2092 } else {
2093 alert(__("No articles are selected."));
2094 }
2095 } catch (e) {
2096 exception_error("setSelectionScore", e);
2097 }
2098 }
2099
2100 function changeScore(id, pic) {
2101 try {
2102 var score = pic.getAttribute("score");
2103
2104 var new_score = prompt(__("Please enter new score for this article:"), score);
2105
2106 if (new_score != undefined) {
2107
2108 var query = "op=article&method=setScore&id=" + param_escape(id) +
2109 "&score=" + param_escape(new_score);
2110
2111 new Ajax.Request("backend.php", {
2112 parameters: query,
2113 onComplete: function(transport) {
2114 var reply = JSON.parse(transport.responseText);
2115
2116 if (reply) {
2117 pic.src = pic.src.replace(/score_.*?\.png/, reply["score_pic"]);
2118 pic.setAttribute("score", new_score);
2119 }
2120 } });
2121 }
2122 } catch (e) {
2123 exception_error("changeScore", e);
2124 }
2125 }
2126
2127 function displayArticleUrl(id) {
2128 try {
2129 var query = "op=rpc&method=getlinktitlebyid&id=" + param_escape(id);
2130
2131 new Ajax.Request("backend.php", {
2132 parameters: query,
2133 onComplete: function(transport) {
2134 var reply = JSON.parse(transport.responseText);
2135
2136 if (reply && reply.link) {
2137 prompt(__("Article URL:"), reply.link);
2138 }
2139 } });
2140 } catch (e) {
2141 exception_error("changeScore", e);
2142 }
2143 }
2144
2145 function openSelectedAttachment(elem) {
2146 try {
2147 var url = elem[elem.selectedIndex].value;
2148
2149 if (url) {
2150 window.open(url);
2151 elem.selectedIndex = 0;
2152 }
2153
2154 } catch (e) {
2155 exception_error("openSelectedAttachment", e);
2156 }
2157 }