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