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