]> git.wh0rd.org - tt-rss.git/blame_incremental - viewfeed.js
lower max article cache size (30 to 20)
[tt-rss.git] / viewfeed.js
... / ...
CommitLineData
1var active_post_id = false;
2var _catchup_callback_func = false;
3var last_article_view = false;
4var active_real_feed_id = false;
5
6var _tag_active_post_id = false;
7var _tag_active_feed_id = false;
8var _tag_active_cdm = false;
9
10// FIXME: kludge, to restore scrollTop after tag editor terminates
11var _tag_cdm_scroll = false;
12
13// FIXME: kludges, needs proper implementation
14var _reload_feedlist_after_view = false;
15
16var _cdm_wd_timeout = false;
17var _cdm_wd_vishist = new Array();
18
19var article_cache = new Array();
20
21function catchup_callback() {
22 if (xmlhttp_rpc.readyState == 4) {
23 try {
24 debug("catchup_callback");
25 if (_catchup_callback_func) {
26 setTimeout(_catchup_callback_func, 100);
27 }
28 notify("");
29 all_counters_callback();
30 } catch (e) {
31 exception_error("catchup_callback", e);
32 }
33 }
34}
35
36function headlines_callback() {
37 if (xmlhttp.readyState == 4) {
38 debug("headlines_callback");
39 var f = document.getElementById("headlines-frame");
40 try {
41 f.scrollTop = 0;
42 } catch (e) { };
43
44 if (xmlhttp.responseXML) {
45 var headlines = xmlhttp.responseXML.getElementsByTagName("headlines")[0];
46 var counters = xmlhttp.responseXML.getElementsByTagName("counters")[0];
47
48 f.innerHTML = headlines.firstChild.nodeValue;
49
50 if (counters) {
51 debug("parsing piggybacked counters: " + counters);
52 parse_counters(counters, false);
53 }
54 } else {
55 debug("headlines_callback: returned no XML object");
56 f.innerHTML = xmlhttp.responseText;
57 update_all_counters();
58 }
59
60 if (typeof correctPNG != 'undefined') {
61 correctPNG();
62 }
63
64 if (_cdm_wd_timeout) window.clearTimeout(_cdm_wd_timeout);
65
66 if (!document.getElementById("headlinesList") &&
67 getInitParam("cdm_auto_catchup") == 1) {
68 debug("starting CDM watchdog");
69 _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 5000);
70 _cdm_wd_vishist = new Array();
71 } else {
72 debug("not in CDM mode or watchdog disabled");
73 }
74
75 if (_tag_cdm_scroll) {
76 try {
77 document.getElementById("headlinesInnerContainer").scrollTop = _tag_cdm_scroll;
78 _tag_cdm_scroll = false;
79 } catch (e) { }
80 }
81
82 notify("");
83 }
84}
85
86function render_article(article) {
87 try {
88 var f = document.getElementById("content-frame");
89 try {
90 f.scrollTop = 0;
91 } catch (e) { };
92
93 f.innerHTML = article;
94
95 } catch (e) {
96 exception_error("render_article", e);
97 }
98}
99
100function article_callback() {
101 if (xmlhttp.readyState == 4) {
102 debug("article_callback");
103
104 try {
105 if (xmlhttp.responseXML) {
106 var reply = xmlhttp.responseXML.firstChild.firstChild;
107
108 var articles = xmlhttp.responseXML.getElementsByTagName("article");
109
110 for (var i = 0; i < articles.length; i++) {
111 var a_id = articles[i].getAttribute("id");
112
113 debug("found id: " + a_id);
114
115 if (a_id == active_post_id) {
116 debug("active article, rendering...");
117 render_article(articles[i].firstChild.nodeValue);
118 }
119
120 cache_inject(a_id, articles[i].firstChild.nodeValue);
121 }
122
123 } else {
124 debug("article_callback: returned no XML object");
125 }
126 } catch (e) {
127 exception_error("article_callback", e);
128 }
129
130 var date = new Date();
131 last_article_view = date.getTime() / 1000;
132
133 if (typeof correctPNG != 'undefined') {
134 correctPNG();
135 }
136
137 if (_reload_feedlist_after_view) {
138 setTimeout('updateFeedList(false, false)', 50);
139 _reload_feedlist_after_view = false;
140 } else {
141 var counters = xmlhttp.responseXML.getElementsByTagName("counters")[0];
142
143 if (counters) {
144 debug("parsing piggybacked counters: " + counters);
145 parse_counters(counters, false);
146 } else {
147 update_all_counters();
148 }
149 }
150
151 notify("");
152 }
153}
154
155function view(id, feed_id, skip_history) {
156
157 try {
158 debug("loading article: " + id + "/" + feed_id);
159
160 active_real_feed_id = feed_id;
161
162 var cached_article = cache_find(id);
163
164 debug("cache check result: " + (cached_article != false));
165
166/* if (!skip_history) {
167 history_push("ARTICLE:" + id + ":" + feed_id);
168 } */
169
170 enableHotkeys();
171
172 active_post_id = id;
173 //setActiveFeedId(feed_id);
174
175 var query = "backend.php?op=view&id=" + param_escape(id) +
176 "&feed=" + param_escape(feed_id);
177
178 var date = new Date();
179
180 if (!xmlhttp_ready(xmlhttp) && last_article_view < date.getTime() / 1000 - 15) {
181 debug("<b>xmlhttp seems to be stuck at view, aborting</b>");
182 xmlhttp.abort();
183 }
184
185 if (cached_article || xmlhttp_ready(xmlhttp)) {
186
187 cleanSelected("headlinesList");
188
189 var crow = document.getElementById("RROW-" + active_post_id);
190
191 var article_is_unread = crow.className.match("Unread");
192 debug("article is unread: " + article_is_unread);
193
194 crow.className = crow.className.replace("Unread", "");
195
196 var upd_img_pic = document.getElementById("FUPDPIC-" + active_post_id);
197
198 if (upd_img_pic) {
199 upd_img_pic.src = "images/blank_icon.gif";
200 }
201
202 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
203 markHeadline(active_post_id);
204
205 var neighbor_ids = getRelativePostIds(active_post_id);
206
207 /* only request uncached articles */
208
209 var cids_to_request = Array();
210
211 for (var i = 0; i < neighbor_ids.length; i++) {
212 if (!cache_check(neighbor_ids[i])) {
213 cids_to_request.push(neighbor_ids[i]);
214 }
215 }
216
217 debug("additional ids: " + cids_to_request.toString());
218
219 /* additional info for piggyback counters */
220
221 if (tagsAreDisplayed()) {
222 query = query + "&omode=lt";
223 } else {
224 query = query + "&omode=flc";
225 }
226
227 var date = new Date();
228 var timestamp = Math.round(date.getTime() / 1000);
229 query = query + "&ts=" + timestamp;
230
231 query = query + "&cids=" + cids_to_request.toString();
232
233 if (!cached_article) {
234
235 notify_progress("Loading, please wait...");
236
237 debug(query);
238
239 xmlhttp.open("GET", query, true);
240 xmlhttp.onreadystatechange=article_callback;
241 xmlhttp.send(null);
242 } else if (cached_article && article_is_unread) {
243
244 query = query + "&mode=prefetch";
245
246 debug(query);
247
248 xmlhttp.open("GET", query, true);
249 xmlhttp.onreadystatechange=article_callback;
250 xmlhttp.send(null);
251
252 render_article(cached_article);
253
254 } else if (cached_article) {
255
256 render_article(cached_article);
257
258 }
259
260 cache_expire();
261
262 } else {
263 debug("xmlhttp busy (@view)");
264 printLockingError();
265 }
266
267 } catch (e) {
268 exception_error("view", e);
269 }
270}
271
272function toggleMark(id) {
273
274 if (!xmlhttp_ready(xmlhttp_rpc)) {
275 printLockingError();
276 return;
277 }
278
279 var query = "backend.php?op=rpc&id=" + id + "&subop=mark";
280
281 var mark_img = document.getElementById("FMARKPIC-" + id);
282 var vfeedu = document.getElementById("FEEDU--1");
283 var crow = document.getElementById("RROW-" + id);
284
285 if (mark_img.alt != "Reset mark") {
286 mark_img.src = "images/mark_set.png";
287 mark_img.alt = "Reset mark";
288 query = query + "&mark=1";
289
290 if (vfeedu && crow.className.match("Unread")) {
291 vfeedu.innerHTML = (+vfeedu.innerHTML) + 1;
292 }
293
294 } else {
295 mark_img.src = "images/mark_unset.png";
296 mark_img.alt = "Set mark";
297 query = query + "&mark=0";
298
299 if (vfeedu && crow.className.match("Unread")) {
300 vfeedu.innerHTML = (+vfeedu.innerHTML) - 1;
301 }
302
303 }
304
305 var vfeedctr = document.getElementById("FEEDCTR--1");
306 var vfeedr = document.getElementById("FEEDR--1");
307
308 if (vfeedu && vfeedctr) {
309 if ((+vfeedu.innerHTML) > 0) {
310 if (crow.className.match("Unread") && !vfeedr.className.match("Unread")) {
311 vfeedr.className = vfeedr.className + "Unread";
312 vfeedctr.className = "odd";
313 }
314 } else {
315 vfeedctr.className = "invisible";
316 vfeedr.className = vfeedr.className.replace("Unread", "");
317 }
318 }
319
320 debug("toggle starred for aid " + id);
321
322 new Ajax.Request(query);
323
324}
325
326function moveToPost(mode) {
327
328 // check for combined mode
329 if (!document.getElementById("headlinesList"))
330 return;
331
332 var rows = getVisibleHeadlineIds();
333
334 var prev_id;
335 var next_id;
336
337 if (!document.getElementById('RROW-' + active_post_id)) {
338 active_post_id = false;
339 }
340
341 if (active_post_id == false) {
342 next_id = getFirstVisibleHeadlineId();
343 prev_id = getLastVisibleHeadlineId();
344 } else {
345 for (var i = 0; i < rows.length; i++) {
346 if (rows[i] == active_post_id) {
347 prev_id = rows[i-1];
348 next_id = rows[i+1];
349 }
350 }
351 }
352
353 if (mode == "next") {
354 if (next_id != undefined) {
355 view(next_id, getActiveFeedId());
356 }
357 }
358
359 if (mode == "prev") {
360 if ( prev_id != undefined) {
361 view(prev_id, getActiveFeedId());
362 }
363 }
364}
365
366function toggleUnread(id, cmode) {
367 try {
368 if (!xmlhttp_ready(xmlhttp_rpc)) {
369 printLockingError();
370 return;
371 }
372
373 var row = document.getElementById("RROW-" + id);
374 if (row) {
375 var nc = row.className;
376 nc = nc.replace("Unread", "");
377 nc = nc.replace("Selected", "");
378
379 if (row.className.match("Unread")) {
380 row.className = nc;
381 } else {
382 row.className = nc + "Unread";
383 }
384
385 if (!cmode) cmode = 2;
386
387 var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
388 param_escape(id) + "&cmode=" + param_escape(cmode);
389
390 notify_progress("Loading, please wait...");
391
392 xmlhttp_rpc.open("GET", query, true);
393 xmlhttp_rpc.onreadystatechange=all_counters_callback;
394 xmlhttp_rpc.send(null);
395
396 }
397
398
399 } catch (e) {
400 exception_error("toggleUnread", e);
401 }
402}
403
404function selectionToggleUnread(cdm_mode, set_state, callback_func, no_error) {
405 try {
406 if (!xmlhttp_ready(xmlhttp_rpc)) {
407 printLockingError();
408 return;
409 }
410
411 var rows;
412
413 if (cdm_mode) {
414 rows = cdmGetSelectedArticles();
415 } else {
416 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
417 }
418
419 if (rows.length == 0 && !no_error) {
420 alert(__("No articles are selected."));
421 return;
422 }
423
424 for (i = 0; i < rows.length; i++) {
425 var row = document.getElementById("RROW-" + rows[i]);
426 if (row) {
427 var nc = row.className;
428 nc = nc.replace("Unread", "");
429 nc = nc.replace("Selected", "");
430
431 if (row.className.match("Unread")) {
432 row.className = nc + "Selected";
433 } else {
434 row.className = nc + "UnreadSelected";
435 }
436 }
437 }
438
439 if (rows.length > 0) {
440
441 var cmode = "";
442
443 if (set_state == undefined) {
444 cmode = "2";
445 } else if (set_state == true) {
446 cmode = "1";
447 } else if (set_state == false) {
448 cmode = "0";
449 }
450
451 var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
452 param_escape(rows.toString()) + "&cmode=" + cmode;
453
454 _catchup_callback_func = callback_func;
455
456 notify_progress("Loading, please wait...");
457
458 xmlhttp_rpc.open("GET", query, true);
459 xmlhttp_rpc.onreadystatechange=catchup_callback;
460 xmlhttp_rpc.send(null);
461
462 }
463
464 } catch (e) {
465 exception_error("selectionToggleUnread", e);
466 }
467}
468
469function selectionToggleMarked(cdm_mode) {
470 try {
471 if (!xmlhttp_ready(xmlhttp_rpc)) {
472 printLockingError();
473 return;
474 }
475
476 var rows;
477
478 if (cdm_mode) {
479 rows = cdmGetSelectedArticles();
480 } else {
481 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
482 }
483
484 if (rows.length == 0) {
485 alert(__("No articles are selected."));
486 return;
487 }
488
489 for (i = 0; i < rows.length; i++) {
490 var row = document.getElementById("RROW-" + rows[i]);
491 var mark_img = document.getElementById("FMARKPIC-" + rows[i]);
492
493 if (row && mark_img) {
494
495 if (mark_img.alt == "Set mark") {
496 mark_img.src = "images/mark_set.png";
497 mark_img.alt = "Reset mark";
498 mark_img.setAttribute('onclick',
499 'javascript:toggleMark('+rows[i]+', false)');
500
501 } else {
502 mark_img.src = "images/mark_unset.png";
503 mark_img.alt = "Set mark";
504 mark_img.setAttribute('onclick',
505 'javascript:toggleMark('+rows[i]+', true)');
506 }
507 }
508 }
509
510 if (rows.length > 0) {
511
512 var query = "backend.php?op=rpc&subop=markSelected&ids=" +
513 param_escape(rows.toString()) + "&cmode=2";
514
515 xmlhttp_rpc.open("GET", query, true);
516 xmlhttp_rpc.onreadystatechange=all_counters_callback;
517 xmlhttp_rpc.send(null);
518
519 }
520
521 } catch (e) {
522 exception_error("selectionToggleMarked", e);
523 }
524}
525
526function cdmGetSelectedArticles() {
527 var sel_articles = new Array();
528 var container = document.getElementById("headlinesInnerContainer");
529
530 for (i = 0; i < container.childNodes.length; i++) {
531 var child = container.childNodes[i];
532
533 if (child.id.match("RROW-") && child.className.match("Selected")) {
534 var c_id = child.id.replace("RROW-", "");
535 sel_articles.push(c_id);
536 }
537 }
538
539 return sel_articles;
540}
541
542// mode = all,none,unread
543function cdmSelectArticles(mode) {
544 var container = document.getElementById("headlinesInnerContainer");
545
546 for (i = 0; i < container.childNodes.length; i++) {
547 var child = container.childNodes[i];
548
549 if (child.id.match("RROW-")) {
550 var aid = child.id.replace("RROW-", "");
551
552 var cb = document.getElementById("RCHK-" + aid);
553
554 if (mode == "all") {
555 if (!child.className.match("Selected")) {
556 child.className = child.className + "Selected";
557 cb.checked = true;
558 }
559 } else if (mode == "unread") {
560 if (child.className.match("Unread") && !child.className.match("Selected")) {
561 child.className = child.className + "Selected";
562 cb.checked = true;
563 }
564 } else {
565 child.className = child.className.replace("Selected", "");
566 cb.checked = false;
567 }
568 }
569 }
570}
571
572function catchupPage() {
573
574 if (document.getElementById("headlinesList")) {
575 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', true, 'Unread', true);
576 selectionToggleUnread(false, false, 'viewCurrentFeed()', true);
577 selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false);
578 } else {
579 cdmSelectArticles('all');
580 selectionToggleUnread(true, false, 'viewCurrentFeed()', true)
581 cdmSelectArticles('none');
582 }
583}
584
585function labelFromSearch(search, search_mode, match_on, feed_id, is_cat) {
586
587 if (!xmlhttp_ready(xmlhttp_rpc)) {
588 printLockingError();
589 }
590
591 var title = prompt("Please enter label title:", "");
592
593 if (title) {
594
595 var query = "backend.php?op=labelFromSearch&search=" + param_escape(search) +
596 "&smode=" + param_escape(search_mode) + "&match=" + param_escape(match_on) +
597 "&feed=" + param_escape(feed_id) + "&is_cat=" + param_escape(is_cat) +
598 "&title=" + param_escape(title);
599
600 debug("LFS: " + query);
601
602 xmlhttp_rpc.open("GET", query, true);
603 xmlhttp_rpc.onreadystatechange=dlg_frefresh_callback;
604 xmlhttp_rpc.send(null);
605 }
606
607}
608
609function editArticleTags(id, feed_id, cdm_enabled) {
610 _tag_active_post_id = id;
611 _tag_active_feed_id = feed_id;
612 _tag_active_cdm = cdm_enabled;
613 try {
614 _tag_cdm_scroll = document.getElementById("headlinesInnerContainer").scrollTop;
615 } catch (e) { }
616 displayDlg('editArticleTags', id);
617}
618
619
620function tag_saved_callback() {
621 if (xmlhttp_rpc.readyState == 4) {
622 try {
623 debug("in tag_saved_callback");
624
625 closeInfoBox();
626 notify("");
627
628 if (tagsAreDisplayed()) {
629 _reload_feedlist_after_view = true;
630 }
631
632 if (!_tag_active_cdm) {
633 if (active_post_id == _tag_active_post_id) {
634 debug("reloading current article");
635 view(_tag_active_post_id, _tag_active_feed_id);
636 }
637 } else {
638 debug("reloading current feed");
639 viewCurrentFeed();
640 }
641
642 } catch (e) {
643 exception_error("catchup_callback", e);
644 }
645 }
646}
647
648function editTagsSave() {
649
650 if (!xmlhttp_ready(xmlhttp_rpc)) {
651 printLockingError();
652 }
653
654 notify_progress("Saving article tags...");
655
656 var form = document.forms["tag_edit_form"];
657
658 var query = Form.serialize("tag_edit_form");
659
660 xmlhttp_rpc.open("GET", "backend.php?op=rpc&subop=setArticleTags&" + query, true);
661 xmlhttp_rpc.onreadystatechange=tag_saved_callback;
662 xmlhttp_rpc.send(null);
663
664}
665
666function editTagsInsert() {
667 try {
668
669 var form = document.forms["tag_edit_form"];
670
671 var found_tags = form.found_tags;
672 var tags_str = form.tags_str;
673
674 var tag = found_tags[found_tags.selectedIndex].value;
675
676 if (tags_str.value.length > 0 &&
677 tags_str.value.lastIndexOf(", ") != tags_str.value.length - 2) {
678
679 tags_str.value = tags_str.value + ", ";
680 }
681
682 tags_str.value = tags_str.value + tag + ", ";
683
684 found_tags.selectedIndex = 0;
685
686 } catch (e) {
687 exception_error(e, "editTagsInsert");
688 }
689}
690
691function cdmWatchdog() {
692
693 try {
694
695 var ctr = document.getElementById("headlinesInnerContainer");
696
697 if (!ctr) return;
698
699 var ids = new Array();
700
701 var e = ctr.firstChild;
702
703 while (e) {
704 if (e.className && e.className == "cdmArticleUnread" && e.id &&
705 e.id.match("RROW-")) {
706
707 // article fits in viewport OR article is longer than viewport and
708 // its bottom is visible
709
710 if (ctr.scrollTop <= e.offsetTop && e.offsetTop + e.offsetHeight <=
711 ctr.scrollTop + ctr.offsetHeight) {
712
713// debug(e.id + " is visible " + e.offsetTop + "." +
714// (e.offsetTop + e.offsetHeight) + " vs " + ctr.scrollTop + "." +
715// (ctr.scrollTop + ctr.offsetHeight));
716
717 ids.push(e.id.replace("RROW-", ""));
718
719 } else if (e.offsetHeight > ctr.offsetHeight &&
720 e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
721 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight) {
722
723 ids.push(e.id.replace("RROW-", ""));
724
725 }
726
727 // method 2: article bottom is visible and is in upper 1/2 of the viewport
728
729/* if (e.offsetTop + e.offsetHeight >= ctr.scrollTop &&
730 e.offsetTop + e.offsetHeight <= ctr.scrollTop + ctr.offsetHeight/2) {
731
732 ids.push(e.id.replace("RROW-", ""));
733
734 } */
735
736 }
737
738 e = e.nextSibling;
739 }
740
741 debug("cdmWatchdog, ids= " + ids.toString());
742
743 if (ids.length > 0 && xmlhttp_ready(xmlhttp_rpc)) {
744
745 for (var i = 0; i < ids.length; i++) {
746 var e = document.getElementById("RROW-" + ids[i]);
747 if (e) {
748 e.className = e.className.replace("Unread", "");
749 }
750 }
751
752 var query = "backend.php?op=rpc&subop=catchupSelected&ids=" +
753 param_escape(ids.toString()) + "&cmode=0";
754
755 xmlhttp_rpc.open("GET", query, true);
756 xmlhttp_rpc.onreadystatechange=all_counters_callback;
757 xmlhttp_rpc.send(null);
758
759 }
760
761 _cdm_wd_timeout = window.setTimeout("cdmWatchdog()", 4000);
762
763 } catch (e) {
764 exception_error(e, "cdmWatchdog");
765 }
766
767}
768
769
770function cache_inject(id, article) {
771 if (!cache_check(id)) {
772 debug("cache_article: miss: " + id);
773
774 var cache_obj = new Array();
775
776 var d = new Date();
777
778 cache_obj["id"] = id;
779 cache_obj["entered"] = d.getTime() / 1000;
780 cache_obj["data"] = article;
781 cache_obj["last_access"] = 0;
782
783 //article_cache[id] = cache_obj;
784
785 article_cache.push(cache_obj);
786
787 } else {
788 debug("cache_article: hit: " + id);
789 }
790}
791
792function cache_find(id) {
793 for (var i = 0; i < article_cache.length; i++) {
794 if (article_cache[i]["id"] == id) {
795 var d = new Date();
796 article_cache[i]["last_access"] = d.getTime() / 1000;
797 return article_cache[i]["data"];
798 }
799 }
800 return false;
801}
802
803function cache_check(id) {
804 for (var i = 0; i < article_cache.length; i++) {
805 if (article_cache[i]["id"] == id) {
806 return true;
807 }
808 }
809 return false;
810}
811
812function cache_expire() {
813 while (article_cache.length > 20) {
814 article_cache.shift();
815 }
816}