]> git.wh0rd.org Git - tt-rss.git/blob - functions.js
fix broken piggie
[tt-rss.git] / functions.js
1 var hotkeys_enabled = true;
2
3 var xmlhttp_rpc = Ajax.getTransport();
4
5 function browser_has_opacity() {
6         return navigator.userAgent.match("Gecko") != null || 
7                 navigator.userAgent.match("Opera") != null;
8 }
9
10 function exception_error(location, e, silent) {
11         var msg;
12
13         if (e.fileName) {
14                 var base_fname = e.fileName.substring(e.fileName.lastIndexOf("/") + 1);
15         
16                 msg = "Exception: " + e.name + ", " + e.message + 
17                         "\nFunction: " + location + "()" +
18                         "\nLocation: " + base_fname + ":" + e.lineNumber;
19                 
20         } else {
21                 msg = "Exception: " + e + "\nFunction: " + location + "()";
22         }
23
24         debug("<b>EXCEPTION: " + msg + "</b>");
25
26         if (!silent) {
27                 alert(msg);
28         }
29 }
30
31 function disableHotkeys() {
32         hotkeys_enabled = false;
33 }
34
35 function enableHotkeys() {
36         hotkeys_enabled = true;
37 }
38
39 function xmlhttp_ready(obj) {
40         return obj.readyState == 4 || obj.readyState == 0 || !obj.readyState;
41 }
42
43 function notify_callback() {
44         var container = document.getElementById('notify');
45         if (xmlhttp.readyState == 4) {
46                 container.innerHTML=xmlhttp.responseText;
47         }
48 }
49
50 function rpc_notify_callback() {
51         var container = document.getElementById('notify');
52         if (xmlhttp_rpc.readyState == 4) {
53                 container.innerHTML=xmlhttp_rpc.responseText;
54         }
55 }
56
57 function param_escape(arg) {
58         if (typeof encodeURIComponent != 'undefined')
59                 return encodeURIComponent(arg); 
60         else
61                 return escape(arg);
62 }
63
64 function param_unescape(arg) {
65         if (typeof decodeURIComponent != 'undefined')
66                 return decodeURIComponent(arg); 
67         else
68                 return unescape(arg);
69 }
70
71 function delay(gap) {
72         var then,now; 
73         then=new Date().getTime();
74         now=then;
75         while((now-then)<gap) {
76                 now=new Date().getTime();
77         }
78 }
79
80 var notify_hide_timerid = false;
81 var notify_last_doc = false;
82
83 var notify_effect = false;
84
85 function hide_notify() {
86         if (notify_last_doc) {
87                 var n = notify_last_doc.getElementById("notify");               
88                 if (browser_has_opacity()) {
89                         if (notify_opacity >= 0) {
90                                 notify_opacity = notify_opacity - 0.1;
91                                 n.style.opacity = notify_opacity;
92                                 notify_hide_timerid = window.setTimeout("hide_notify()", 20);   
93                         } else {
94                                 n.style.display = "none";
95                                 n.style.opacity = 1;
96                         }
97                 } else {
98                         n.style.display = "none";
99                 }
100         }
101 }
102
103 function notify_real(msg, doc, no_hide, is_err) {
104
105         var n = doc.getElementById("notify");
106         var nb = doc.getElementById("notify_body");
107
108         if (!n || !nb) return;
109
110         if (notify_hide_timerid) {
111                 window.clearTimeout(notify_hide_timerid);
112         }
113
114         notify_last_doc = doc;
115         notify_opacity = 1;
116
117         if (msg == "") {
118                 if (n.style.display == "block") {
119                         notify_hide_timerid = window.setTimeout("hide_notify()", 0);
120                 }
121                 return;
122         } else {
123                 n.style.display = "block";
124         }
125
126         if (is_err) {
127                 n.style.backgroundColor = "#ffcccc";
128                 n.style.color = "black";
129                 n.style.borderColor = "#ff0000";
130         } else {
131                 n.style.backgroundColor = "#fff7d5";
132                 n.style.borderColor = "#d7c47a";
133                 n.style.color = "black";
134         }
135
136         nb.innerHTML = msg;
137
138         if (!no_hide) {
139                 notify_hide_timerid = window.setTimeout("hide_notify()", 3000);
140         }
141 }
142
143 function p_notify(msg, no_hide, is_err) {
144         notify_real(msg, parent.document, no_hide, is_err);
145 }
146
147 function notify(msg, no_hide, is_err) {
148         notify_real(msg, document, no_hide, is_err);
149 }
150
151 function printLockingError() {
152         notify("Please wait until operation finishes");}
153
154 function hotkey_handler(e) {
155
156         try {
157
158                 var keycode;
159         
160                 if (!hotkeys_enabled) return;
161         
162                 if (window.event) {
163                         keycode = window.event.keyCode;
164                 } else if (e) {
165                         keycode = e.which;
166                 }
167         
168                 if (keycode == 13 || keycode == 27) {
169                         seq = "";
170                 } else {
171                         seq = seq + "" + keycode;
172                 }
173
174                 var m_ctx = getMainContext();
175                 var f_ctx = getFeedsContext();
176                 var h_ctx = getHeadlinesContext();
177
178                 if (keycode == 82) { // r
179                         return m_ctx.scheduleFeedUpdate(true);
180                 }
181
182                 if (keycode == 83) { // r
183                         return m_ctx.displayDlg("search", getActiveFeedId());
184                 }
185
186                 if (keycode == 85) { // u
187                         if (getActiveFeedId()) {
188                                 return f_ctx.viewfeed(getActiveFeedId(), "ForceUpdate");
189                         }
190                 }
191         
192                 if (keycode == 65) { // a
193                         return m_ctx.toggleDispRead();
194                 }
195         
196                 var f_doc = m_ctx.frames["feeds-frame"].document;
197                 var feedlist = f_doc.getElementById('feedList');
198         
199                 if (keycode == 74) { // j
200                         var feed = getActiveFeedId();
201                         var new_feed = getRelativeFeedId(feedlist, feed, 'prev');
202                         if (new_feed) viewfeed(new_feed, '');
203                 }
204         
205                 if (keycode == 75) { // k
206                         var feed = getActiveFeedId();
207                         var new_feed = getRelativeFeedId(feedlist, feed, 'next');
208                         if (new_feed) viewfeed(new_feed, '');
209                 }
210
211                 if (keycode == 78 || keycode == 40) { // n, down
212                         return h_ctx.moveToPost('next');
213                 }
214         
215                 if (keycode == 80 || keycode == 38) { // p, up
216                         return h_ctx.moveToPost('prev');
217                 }
218                 
219                 if (typeof localHotkeyHandler != 'undefined') {
220                         try {
221                                 localHotkeyHandler(keycode);
222                         } catch (e) {
223                                 exception_error("hotkey_handler, local:", e);
224                         }
225                 }
226         } catch (e) {
227                 exception_error("hotkey_handler", e);
228         }
229 }
230
231 function cleanSelectedList(element) {
232         var content = document.getElementById(element);
233
234         if (!document.getElementById("feedCatHolder")) {
235                 for (i = 0; i < content.childNodes.length; i++) {
236                         var child = content.childNodes[i];
237                         try {
238                                 child.className = child.className.replace("Selected", "");
239                         } catch (e) {
240                                 //
241                         }
242                 }
243         } else {
244                 for (i = 0; i < content.childNodes.length; i++) {
245                         var child = content.childNodes[i];
246                         if (child.id == "feedCatHolder") {
247                                 parent.debug(child.id);
248                                 var fcat = child.lastChild;
249                                 for (j = 0; j < fcat.childNodes.length; j++) {
250                                         var feed = fcat.childNodes[j];
251                                         feed.className = feed.className.replace("Selected", "");
252                                 }               
253                         }
254                 } 
255         }
256 }
257
258
259 function cleanSelected(element) {
260         var content = document.getElementById(element);
261
262         for (i = 0; i < content.rows.length; i++) {
263                 content.rows[i].className = content.rows[i].className.replace("Selected", "");
264         }
265 }
266
267 function getVisibleUnreadHeadlines() {
268         var content = document.getElementById("headlinesList");
269
270         var rows = new Array();
271
272         for (i = 0; i < content.rows.length; i++) {
273                 var row_id = content.rows[i].id.replace("RROW-", "");
274                 if (row_id.length > 0 && content.rows[i].className.match("Unread")) {
275                                 rows.push(row_id);      
276                 }
277         }
278         return rows;
279 }
280
281 function getVisibleHeadlineIds() {
282
283         var content = document.getElementById("headlinesList");
284
285         var rows = new Array();
286
287         for (i = 0; i < content.rows.length; i++) {
288                 var row_id = content.rows[i].id.replace("RROW-", "");
289                 if (row_id.length > 0) {
290                                 rows.push(row_id);      
291                 }
292         }
293         return rows;
294 }
295
296 function getFirstVisibleHeadlineId() {
297         var rows = getVisibleHeadlineIds();
298         return rows[0];
299 }
300
301 function getLastVisibleHeadlineId() {
302         var rows = getVisibleHeadlineIds();
303         return rows[rows.length-1];
304 }
305
306 function markHeadline(id) {
307         var row = document.getElementById("RROW-" + id);
308         if (row) {
309                 var is_active = false;
310         
311                 if (row.className.match("Active")) {
312                         is_active = true;
313                 }
314                 row.className = row.className.replace("Selected", "");
315                 row.className = row.className.replace("Active", "");
316                 row.className = row.className.replace("Insensitive", "");
317                 
318                 if (is_active) {
319                         row.className = row.className = "Active";
320                 }
321                 
322                 var check = document.getElementById("RCHK-" + id);
323
324                 if (check) {
325                         check.checked = true;
326                 }
327
328                 row.className = row.className + "Selected"; 
329                 
330         }
331 }
332
333 function getFeedIds() {
334         var content = document.getElementById("feedsList");
335
336         var rows = new Array();
337
338         for (i = 0; i < content.rows.length; i++) {
339                 var id = content.rows[i].id.replace("FEEDR-", "");
340                 if (id.length > 0) {
341                         rows.push(id);
342                 }
343         }
344
345         return rows;
346 }
347
348 function setCookie(name, value, lifetime, path, domain, secure) {
349         
350         var d = false;
351         
352         if (lifetime) {
353                 d = new Date();
354                 d.setTime(lifetime * 1000);
355         }
356         
357         int_setCookie(name, value, d, path, domain, secure);
358
359 }
360
361 function int_setCookie(name, value, expires, path, domain, secure) {
362         document.cookie= name + "=" + escape(value) +
363                 ((expires) ? "; expires=" + expires.toGMTString() : "") +
364                 ((path) ? "; path=" + path : "") +
365                 ((domain) ? "; domain=" + domain : "") +
366                 ((secure) ? "; secure" : "");
367 }
368
369 function delCookie(name, path, domain) {
370         if (getCookie(name)) {
371                 document.cookie = name + "=" +
372                 ((path) ? ";path=" + path : "") +
373                 ((domain) ? ";domain=" + domain : "" ) +
374                 ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
375         }
376 }
377                 
378
379 function getCookie(name) {
380
381         var dc = document.cookie;
382         var prefix = name + "=";
383         var begin = dc.indexOf("; " + prefix);
384         if (begin == -1) {
385             begin = dc.indexOf(prefix);
386             if (begin != 0) return null;
387         }
388         else {
389             begin += 2;
390         }
391         var end = document.cookie.indexOf(";", begin);
392         if (end == -1) {
393             end = dc.length;
394         }
395         return unescape(dc.substring(begin + prefix.length, end));
396 }
397
398 function disableContainerChildren(id, disable, doc) {
399
400         if (!doc) doc = document;
401
402         var container = doc.getElementById(id);
403
404         if (!container) {
405                 //alert("disableContainerChildren: element " + id + " not found");
406                 return;
407         }
408
409         for (var i = 0; i < container.childNodes.length; i++) {
410                 var child = container.childNodes[i];
411
412                 try {
413                         child.disabled = disable;
414                 } catch (E) {
415
416                 }
417
418                 if (disable) {
419                         if (child.className && child.className.match("button")) {
420                                 child.className = "disabledButton";
421                         }
422                 } else {
423                         if (child.className && child.className.match("disabledButton")) {
424                                 child.className = "button";
425                         }
426                 } 
427         }
428
429 }
430
431 function gotoPreferences() {
432         document.location.href = "prefs.php";
433 }
434
435 function gotoMain() {
436         document.location.href = "tt-rss.php";
437 }
438
439 function gotoExportOpml() {
440         document.location.href = "opml.php?op=Export";
441 }
442
443 function getActiveFeedId() {
444 //      return getCookie("ttrss_vf_actfeed");
445         try {
446                 debug("gAFID: " + getMainContext().active_feed_id);
447                 return getMainContext().active_feed_id;
448         } catch (e) {
449                 exception_error("getActiveFeedId", e);
450         }
451 }
452
453 function activeFeedIsCat() {
454         return getMainContext().active_feed_is_cat;
455 }
456
457 function setActiveFeedId(id) {
458 //      return setCookie("ttrss_vf_actfeed", id);
459         try {
460                 debug("sAFID(" + id + ")");
461                 getMainContext().active_feed_id = id;
462         } catch (e) {
463                 exception_error("setActiveFeedId", e);
464         }
465 }
466
467 function parse_counters(reply, scheduled_call) {
468         try {
469                 var f_document = getFeedsContext().document;
470                 var title_obj = getMainContext();
471
472                 var feeds_found = 0;
473
474                 if (reply.firstChild && reply.firstChild.firstChild) {
475                         debug("<b>wrong element passed to parse_counters, adjusting.</b>");
476                         reply = reply.firstChild;
477                 }
478
479                 debug("F_DOC: " + f_document + ", T_OBJ: " + title_obj);
480
481                 for (var l = 0; l < reply.childNodes.length; l++) {
482                         if (!reply.childNodes[l] ||
483                                 typeof(reply.childNodes[l].getAttribute) == "undefined") {
484                                 // where did this come from?
485                                 continue;
486                         }
487
488                         var id = reply.childNodes[l].getAttribute("id");
489                         var t = reply.childNodes[l].getAttribute("type");
490                         var ctr = reply.childNodes[l].getAttribute("counter");
491                         var error = reply.childNodes[l].getAttribute("error");
492                         var has_img = reply.childNodes[l].getAttribute("hi");
493                         var updated = reply.childNodes[l].getAttribute("updated");
494         
495                         if (t == "feed") {
496                                 feeds_found++;
497                         }
498
499                         if (id == "global-unread") {
500                                 title_obj.global_unread = ctr;
501                                 title_obj.updateTitle();
502                                 continue;
503                         }
504         
505                         if (t == "category") {
506                                 var catctr = f_document.getElementById("FCATCTR-" + id);
507                                 if (catctr) {
508                                         catctr.innerHTML = "(" + ctr + " unread)";
509                                 }
510                                 continue;
511                         }
512                 
513                         var feedctr = f_document.getElementById("FEEDCTR-" + id);
514                         var feedu = f_document.getElementById("FEEDU-" + id);
515                         var feedr = f_document.getElementById("FEEDR-" + id);
516                         var feed_img = f_document.getElementById("FIMG-" + id);
517                         var feedlink = f_document.getElementById("FEEDL-" + id);
518                         var feedupd = f_document.getElementById("FLUPD-" + id);
519
520                         if (updated && feedlink) {
521                                 if (error) {
522                                         feedlink.title = "Error: " + error + " (" + updated + ")";
523                                 } else {
524                                         feedlink.title = "Updated: " + updated;
525                                 }
526                         }
527
528                         if (updated && feedupd) {
529                                 if (error) {
530                                         feedupd.innerHTML = updated + " (Error)";
531                                 } else {
532                                         feedupd.innerHTML = updated;
533                                 }
534                         }
535
536                         if (feedctr && feedu && feedr) {
537
538                                 if (feedu.innerHTML != ctr && id == getActiveFeedId() && scheduled_call) {
539                                         var hf = title_obj.parent.frames["headlines-frame"];
540                                         hf.location.reload(true);
541                                 }
542                 
543                                 feedu.innerHTML = ctr;
544
545                                 if (error) {
546                                         feedr.className = feedr.className.replace("feed", "error");
547                                 } else if (id > 0) {
548                                         feedr.className = feedr.className.replace("error", "feed");
549                                 }
550         
551                                 if (ctr > 0) {                                  
552                                         feedctr.className = "odd";
553                                         if (!feedr.className.match("Unread")) {
554                                                 var is_selected = feedr.className.match("Selected");
555                 
556                                                 feedr.className = feedr.className.replace("Selected", "");
557                                                 feedr.className = feedr.className.replace("Unread", "");
558                 
559                                                 feedr.className = feedr.className + "Unread";
560                 
561                                                 if (is_selected) {
562                                                         feedr.className = feedr.className + "Selected";
563                                                 }
564                 
565                                         }
566                                 } else {
567                                         feedctr.className = "invisible";
568                                         feedr.className = feedr.className.replace("Unread", "");
569                                 }                       
570                         }
571                 }
572
573                 var feeds_stored = getMainContext().number_of_feeds;
574
575                 debug("Feed counters, C: " + feeds_found + ", S:" + feeds_stored);
576
577                 if (feeds_stored != feeds_found) {
578                         if (feeds_found != 0) {
579                                 getMainContext().number_of_feeds = feeds_found;
580                         }
581                         if (feeds_stored != 0 && feeds_found != 0) {
582                                 debug("Subscribed feed number changed, refreshing feedlist");
583                                 updateFeedList();
584                         }
585                 }
586
587         } catch (e) {
588                 exception_error("parse_counters", e);
589         }
590 }
591
592 function all_counters_callback() {
593         if (xmlhttp_rpc.readyState == 4) {
594                 try {
595                         if (!xmlhttp_rpc.responseXML || !xmlhttp_rpc.responseXML.firstChild) {
596                                 debug("[all_counters_callback] backend did not return valid XML");
597                                 return;
598                         }
599
600                         debug("in all_counters_callback");
601
602                         var reply = xmlhttp_rpc.responseXML.firstChild;
603
604                         var counters = reply.firstChild;
605
606                         parse_counters(counters);
607
608                         var runtime = counters.nextSibling;
609
610                         if (runtime) {
611                                 getMainContext().parse_runtime_info(runtime);
612                         }
613
614                         if (getInitParam("feeds_sort_by_unread") == 1) {
615                                 resort_feedlist();              
616                         }       
617
618                         hideOrShowFeeds(document, getInitParam("hide_read_feeds") == 1);
619
620                 } catch (e) {
621                         exception_error("all_counters_callback", e);
622                 }
623         }
624 }
625
626 function get_feed_entry_unread(doc, elem) {
627
628         var id = elem.id.replace("FEEDR-", "");
629
630         if (id <= 0) {
631                 return -1;
632         }
633
634         try {
635                 return parseInt(doc.getElementById("FEEDU-" + id).innerHTML);   
636         } catch (e) {
637                 return -1;
638         }
639 }
640
641 function resort_category(doc, node) {
642         debug("resort_category: " + node);
643
644         if (node.hasChildNodes() && node.firstChild.nextSibling != false) {  
645                 for (i = 0; i < node.childNodes.length; i++) {
646                         if (node.childNodes[i].nodeName != "LI") { continue; }
647
648                         if (get_feed_entry_unread(doc, node.childNodes[i]) < 0) {
649                                 continue;
650                         }
651
652                         for (j = i+1; j < node.childNodes.length; j++) {                        
653                                 if (node.childNodes[j].nodeName != "LI") { continue; }  
654
655                                 var tmp_val = get_feed_entry_unread(doc, node.childNodes[i]);
656                                 var cur_val = get_feed_entry_unread(doc, node.childNodes[j]);
657
658                                 if (cur_val > tmp_val) {
659                                         tempnode_i = node.childNodes[i].cloneNode(true);
660                                         tempnode_j = node.childNodes[j].cloneNode(true);
661                                         node.replaceChild(tempnode_i, node.childNodes[j]);
662                                         node.replaceChild(tempnode_j, node.childNodes[i]);
663                                 }
664                         }
665
666                 }
667         }
668
669 }
670
671 function resort_feedlist() {
672         debug("resort_feedlist");
673
674         var fd = getFeedsContext().document;
675
676         if (fd.getElementById("feedCatHolder")) {
677
678                 var feeds = fd.getElementById("feedList");
679                 var child = feeds.firstChild;
680
681                 while (child) {
682
683                         if (child.id == "feedCatHolder") {
684                                 resort_category(fd, child.firstChild);
685                         }
686         
687                         child = child.nextSibling;
688                 }
689
690         } else {
691                 resort_category(fd, fd.getElementById("feedList"));
692         }
693 }
694
695 function update_all_counters(feed) {
696         if (xmlhttp_ready(xmlhttp_rpc)) {
697                 var query = "backend.php?op=rpc&subop=getAllCounters";
698
699                 if (feed > 0) {
700                         query = query + "&aid=" + feed;
701                 }
702
703                 xmlhttp_rpc.open("GET", query, true);
704                 xmlhttp_rpc.onreadystatechange=all_counters_callback;
705                 xmlhttp_rpc.send(null);
706         }
707 }
708
709 function popupHelp(tid) {
710         var w = window.open("backend.php?op=help&tid=" + tid,
711                 "Popup Help", 
712                 "menubar=no,location=no,resizable=yes,scrollbars=yes,status=no");
713 }
714
715 /** * @(#)isNumeric.js * * Copyright (c) 2000 by Sundar Dorai-Raj
716   * * @author Sundar Dorai-Raj
717   * * Email: sdoraira@vt.edu
718   * * This program is free software; you can redistribute it and/or
719   * * modify it under the terms of the GNU General Public License 
720   * * as published by the Free Software Foundation; either version 2 
721   * * of the License, or (at your option) any later version, 
722   * * provided that any use properly credits the author. 
723   * * This program is distributed in the hope that it will be useful,
724   * * but WITHOUT ANY WARRANTY; without even the implied warranty of
725   * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
726   * * GNU General Public License for more details at http://www.gnu.org * * */
727
728   var numbers=".0123456789";
729   function isNumeric(x) {
730     // is x a String or a character?
731     if(x.length>1) {
732       // remove negative sign
733       x=Math.abs(x)+"";
734       for(j=0;j<x.length;j++) {
735         // call isNumeric recursively for each character
736         number=isNumeric(x.substring(j,j+1));
737         if(!number) return number;
738       }
739       return number;
740     }
741     else {
742       // if x is number return true
743       if(numbers.indexOf(x)>=0) return true;
744       return false;
745     }
746   }
747
748
749 function hideOrShowFeeds(doc, hide) {
750
751         var fd = getFeedsContext().document;
752
753         var list = fd.getElementById("feedList");
754
755         if (fd.getElementById("feedCatHolder")) {
756
757                 var feeds = fd.getElementById("feedList");
758                 var child = feeds.firstChild;
759
760                 while (child) {
761
762                         if (child.id == "feedCatHolder") {
763                                 hideOrShowFeedsCategory(fd, child.firstChild, hide, child.previousSibling);
764                         }
765         
766                         child = child.nextSibling;
767                 }
768
769         } else {
770                 hideOrShowFeedsCategory(fd, fd.getElementById("feedList"), hide);
771         }
772 }
773
774 function hideOrShowFeedsCategory(doc, node, hide, cat_node) {
775
776 //      debug("hideOrShowFeedsCategory: " + node + " (" + hide + ")");
777
778         var cat_unread = 0;
779
780         if (node.hasChildNodes() && node.firstChild.nextSibling != false) {  
781                 for (i = 0; i < node.childNodes.length; i++) {
782                         if (node.childNodes[i].nodeName != "LI") { continue; }
783
784                         var has_unread = (node.childNodes[i].className != "feed");
785
786 //                      debug(node.childNodes[i].id + " --> " + has_unread);
787
788                         if (hide && !has_unread) {
789                                 node.childNodes[i].style.display = "none";
790                         }
791
792                         if (!hide) {
793                                 node.childNodes[i].style.display = "list-item";
794                         }
795
796                         if (has_unread) {
797                                 cat_unread++;
798                         }
799
800                 }
801         }
802
803         if (cat_unread == 0) {
804                 if (hide) {
805                         cat_node.style.display = "none";
806                 } else {
807                         cat_node.style.display = "list-item";
808                 }
809         }
810
811 //      debug("unread for category: " + cat_unread);
812 }
813
814 function selectTableRow(r, do_select) {
815         r.className = r.className.replace("Selected", "");
816         
817         if (do_select) {
818                 r.className = r.className + "Selected";
819         }
820 }
821
822 function selectTableRowById(elem_id, check_id, do_select) {
823
824         try {
825
826                 var row = document.getElementById(elem_id);
827
828                 if (row) {
829                         selectTableRow(row, do_select);
830                 }               
831
832                 var check = document.getElementById(check_id);
833
834                 if (check) {
835                         check.checked = do_select;
836                 }
837         } catch (e) {
838                 exception_error("selectTableRowById", e);
839         }
840 }
841
842 function selectTableRowsByIdPrefix(content_id, prefix, check_prefix, do_select, 
843         classcheck, reset_others) {
844
845         var content = document.getElementById(content_id);
846
847         if (!content) {
848                 alert("[selectTableRows] Element " + content_id + " not found.");
849                 return;
850         }
851
852         for (i = 0; i < content.rows.length; i++) {
853                 if (!classcheck || content.rows[i].className.match(classcheck)) {
854         
855                         if (content.rows[i].id.match(prefix)) {
856                                 selectTableRow(content.rows[i], do_select);
857                         
858                                 var row_id = content.rows[i].id.replace(prefix, "");
859                                 var check = document.getElementById(check_prefix + row_id);
860
861                                 if (check) {
862                                         check.checked = do_select;
863                                 }
864                         } else if (reset_others) {
865                                 selectTableRow(content.rows[i], false);
866
867                                 var row_id = content.rows[i].id.replace(prefix, "");
868                                 var check = document.getElementById(check_prefix + row_id);
869
870                                 if (check) {
871                                         check.checked = false;
872                                 }
873
874                         }
875                 } else if (reset_others) {
876                         selectTableRow(content.rows[i], false);
877
878                         var row_id = content.rows[i].id.replace(prefix, "");
879                         var check = document.getElementById(check_prefix + row_id);
880
881                         if (check) {
882                                 check.checked = false;
883                         }
884
885                 }
886         }
887 }
888
889 function getSelectedTableRowIds(content_id, prefix) {
890
891         var content = document.getElementById(content_id);
892
893         if (!content) {
894                 alert("[getSelectedTableRowIds] Element " + content_id + " not found.");
895                 return;
896         }
897
898         var sel_rows = new Array();
899
900         for (i = 0; i < content.rows.length; i++) {
901                 if (content.rows[i].id.match(prefix) && 
902                                 content.rows[i].className.match("Selected")) {
903                                 
904                         var row_id = content.rows[i].id.replace(prefix + "-", "");
905                         sel_rows.push(row_id);  
906                 }
907         }
908
909         return sel_rows;
910
911 }
912
913 function toggleSelectRowById(sender, id) {
914         var row = document.getElementById(id);
915
916         if (sender.checked) {
917                 if (!row.className.match("Selected")) {
918                         row.className = row.className + "Selected";
919                 }
920         } else {
921                 if (row.className.match("Selected")) {
922                         row.className = row.className.replace("Selected", "");
923                 }
924         }
925 }
926
927 function toggleSelectListRow(sender) {
928         var parent_row = sender.parentNode;
929
930         if (sender.checked) {
931                 if (!parent_row.className.match("Selected")) {
932                         parent_row.className = parent_row.className + "Selected";
933                 }
934         } else {
935                 if (parent_row.className.match("Selected")) {
936                         parent_row.className = parent_row.className.replace("Selected", "");
937                 }
938         }
939 }
940
941
942 function toggleSelectRow(sender) {
943         var parent_row = sender.parentNode.parentNode;
944
945         if (sender.checked) {
946                 if (!parent_row.className.match("Selected")) {
947                         parent_row.className = parent_row.className + "Selected";
948                 }
949         } else {
950                 if (parent_row.className.match("Selected")) {
951                         parent_row.className = parent_row.className.replace("Selected", "");
952                 }
953         }
954 }
955
956 function openExternalUrl(url) {
957         var w = window.open(url);
958 }
959
960 function getRelativeFeedId(list, id, direction, unread_only) {  
961         if (!id) {
962                 if (direction == "next") {
963                         for (i = 0; i < list.childNodes.length; i++) {
964                                 var child = list.childNodes[i];
965                                 if (child.id && child.id == "feedCatHolder") {
966                                         if (child.lastChild) {
967                                                 var cr = getRelativeFeedId(child.firstChild, id, direction);
968                                                 if (cr) return cr;                                      
969                                         }
970                                 } else if (child.id && child.id.match("FEEDR-")) {
971                                         return child.id.replace('FEEDR-', '');
972                                 }                               
973                         }
974                 }
975
976                 // FIXME select last feed doesn't work when only unread feeds are visible
977
978                 if (direction == "prev") {
979                         for (i = list.childNodes.length-1; i >= 0; i--) {
980                                 var child = list.childNodes[i];                         
981                                 if (child.id == "feedCatHolder") {
982                                         if (child.firstChild) {
983                                                 var cr = getRelativeFeedId(child.firstChild, id, direction);
984                                                 if (cr) return cr;                                      
985                                         }
986                                 } else if (child.id.match("FEEDR-")) {
987                                 
988                                         if (getInitParam("hide_read_feeds") == 1) {
989                                                 if (child.className != "feed") {
990                                                         alert(child.className);
991                                                         return child.id.replace('FEEDR-', '');                                          
992                                                 }                                                       
993                                         } else {
994                                                         return child.id.replace('FEEDR-', '');                                          
995                                         }                               
996                                 }                               
997                         }
998                 }
999         } else {
1000         
1001                 var feed = list.ownerDocument.getElementById("FEEDR-" + getActiveFeedId());
1002                 
1003                 if (getInitParam("hide_read_feeds") == 1) {
1004                         unread_only = true;
1005                 }
1006
1007                 if (direction == "next") {
1008
1009                         var e = feed;
1010
1011                         while (e) {
1012
1013                                 if (e.nextSibling) {
1014                                 
1015                                         e = e.nextSibling;
1016                                         
1017                                 } else if (e.parentNode.parentNode.nextSibling) {
1018
1019                                         var this_cat = e.parentNode.parentNode;
1020
1021                                         e = false;
1022
1023                                         if (this_cat && this_cat.nextSibling) {
1024                                                 while (!e && this_cat.nextSibling) {
1025                                                         this_cat = this_cat.nextSibling;
1026                                                         if (this_cat.id == "feedCatHolder") {
1027                                                                 e = this_cat.firstChild.firstChild;
1028                                                         }
1029                                                 }
1030                                         }
1031
1032                                 } else {
1033                                         e = false;
1034                            }
1035
1036                                 if (e) {
1037                                         if (!unread_only || (unread_only && e.className != "feed" && 
1038                                                         e.className != "error"))        {
1039                                                 return e.id.replace("FEEDR-", "");
1040                                         }
1041                                 }
1042                         }
1043                         
1044                 } else if (direction == "prev") {
1045
1046                         var e = feed;
1047
1048                         while (e) {
1049
1050                                 if (e.previousSibling) {
1051                                 
1052                                         e = e.previousSibling;
1053                                         
1054                                 } else if (e.parentNode.parentNode.previousSibling) {
1055
1056                                         var this_cat = e.parentNode.parentNode;
1057
1058                                         e = false;
1059
1060                                         if (this_cat && this_cat.previousSibling) {
1061                                                 while (!e && this_cat.previousSibling) {
1062                                                         this_cat = this_cat.previousSibling;
1063                                                         if (this_cat.id == "feedCatHolder") {
1064                                                                 e = this_cat.firstChild.lastChild;
1065                                                         }
1066                                                 }
1067                                         }
1068
1069                                 } else {
1070                                         e = false;
1071                            }
1072
1073                                 if (e) {
1074                                         if (!unread_only || (unread_only && e.className != "feed" && 
1075                                                         e.className != "error"))        {
1076                                                 return e.id.replace("FEEDR-", "");
1077                                         }
1078                                 }
1079                         }
1080                 }
1081         }
1082 }
1083
1084 function showBlockElement(id) {
1085         var elem = document.getElementById(id);
1086
1087         if (elem) {
1088                 elem.style.display = "block";
1089         } else {
1090                 alert("[showBlockElement] can't find element with id " + id);
1091         } 
1092 }
1093
1094 function hideParentElement(e) {
1095         e.parentNode.style.display = "none";
1096 }
1097
1098 function dropboxSelect(e, v) {
1099         for (i = 0; i < e.length; i++) {
1100                 if (e[i].value == v) {
1101                         e.selectedIndex = i;
1102                         break;
1103                 }
1104         }
1105 }
1106
1107 // originally stolen from http://www.11tmr.com/11tmr.nsf/d6plinks/MWHE-695L9Z
1108 // bugfixed just a little bit :-)
1109 function getURLParam(strParamName){
1110   var strReturn = "";
1111   var strHref = window.location.href;
1112
1113   if (strHref.indexOf("#") == strHref.length-1) {
1114                 strHref = strHref.substring(0, strHref.length-1);
1115   }
1116
1117   if ( strHref.indexOf("?") > -1 ){
1118     var strQueryString = strHref.substr(strHref.indexOf("?"));
1119     var aQueryString = strQueryString.split("&");
1120     for ( var iParam = 0; iParam < aQueryString.length; iParam++ ){
1121       if (aQueryString[iParam].indexOf(strParamName + "=") > -1 ){
1122         var aParam = aQueryString[iParam].split("=");
1123         strReturn = aParam[1];
1124         break;
1125       }
1126     }
1127   }
1128   return strReturn;
1129
1130
1131 function leading_zero(p) {
1132         var s = String(p);
1133         if (s.length == 1) s = "0" + s;
1134         return s;
1135 }
1136
1137 function closeInfoBox(cleanup) {
1138         var box = document.getElementById('infoBox');
1139         var shadow = document.getElementById('infoBoxShadow');
1140
1141         if (shadow) {
1142                 shadow.style.display = "none";
1143         } else if (box) {
1144                 box.style.display = "none";
1145         }
1146
1147         if (cleanup) box.innerHTML = "&nbsp;";
1148
1149         enableHotkeys();
1150
1151         return false;
1152 }
1153
1154
1155 function displayDlg(id, param) {
1156
1157         if (!xmlhttp_ready(xmlhttp)) {
1158                 printLockingError();
1159                 return
1160         }
1161
1162         notify("");
1163
1164         xmlhttp.open("GET", "backend.php?op=dlg&id=" +
1165                 param_escape(id) + "&param=" + param_escape(param), true);
1166         xmlhttp.onreadystatechange=infobox_callback;
1167         xmlhttp.send(null);
1168
1169         disableHotkeys();
1170
1171         return false;
1172 }
1173
1174 function infobox_submit_callback() {
1175         if (xmlhttp.readyState == 4) {
1176                 closeInfoBox();
1177
1178                 // called from prefs, reload tab
1179                 if (active_tab) {
1180                         selectTab(active_tab, false);
1181                 }
1182
1183                 notify(xmlhttp.responseText);
1184
1185         } 
1186 }
1187
1188 function infobox_callback() {
1189         if (xmlhttp.readyState == 4) {
1190                 var box = document.getElementById('infoBox');
1191                 var shadow = document.getElementById('infoBoxShadow');
1192                 if (box) {                      
1193                         box.innerHTML=xmlhttp.responseText;                     
1194                         if (shadow) {
1195                                 shadow.style.display = "block";
1196                         } else {
1197                                 box.style.display = "block";                            
1198                         }
1199                 }
1200         }
1201 }
1202
1203 function qaddFilter() {
1204
1205         if (!xmlhttp_ready(xmlhttp)) {
1206                 printLockingError();
1207                 return
1208         }
1209
1210         var query = Form.serialize("filter_add_form");
1211
1212         xmlhttp.open("GET", "backend.php?" + query, true);
1213         xmlhttp.onreadystatechange=infobox_submit_callback;
1214         xmlhttp.send(null);
1215
1216         return true;
1217 }
1218
1219 function toggleSubmitNotEmpty(e, submit_id) {
1220         try {
1221                 document.getElementById(submit_id).disabled = (e.value == "")
1222         } catch (e) {
1223                 exception_error("toggleSubmitNotEmpty", e);
1224         }
1225 }
1226
1227 function isValidURL(s) {
1228         return s.match("http://") != null || s.match("https://") != null;
1229 }
1230
1231 function qafAdd() {
1232
1233         if (!xmlhttp_ready(xmlhttp)) {
1234                 printLockingError();
1235                 return
1236         }
1237
1238         notify("Adding feed...");
1239
1240         closeInfoBox();
1241
1242         var feeds_doc = getFeedsContext().document;
1243
1244         feeds_doc.location.href = "backend.php?op=error&msg=Loading,%20please wait...";
1245         
1246         var query = Form.serialize("feed_add_form");
1247         
1248         xmlhttp.open("GET", "backend.php?" + query, true);
1249         xmlhttp.onreadystatechange=dlg_frefresh_callback;
1250         xmlhttp.send(null);
1251 }
1252
1253 function filterCR(e)
1254 {
1255      var key;
1256
1257      if(window.event)
1258           key = window.event.keyCode;     //IE
1259      else
1260           key = e.which;     //firefox
1261
1262      if(key == 13)
1263           return false;
1264      else
1265           return true;
1266 }
1267
1268 function getMainContext() {
1269         if (parent.window != window) {
1270                 return parent.window;
1271         } else {
1272                 return this.window;
1273         }
1274 }
1275
1276 function getFeedsContext() {
1277         try {
1278                 return getMainContext().frames["feeds-frame"];
1279         } catch (e) {
1280                 exception_error("getFeedsContext", e);
1281         }
1282 }
1283
1284
1285 function getHeadlinesContext() {
1286         try {
1287                 return getMainContext().frames["headlines-frame"];
1288         } catch (e) {
1289                 exception_error("getHeadlinesContext", e);
1290         }
1291 }
1292
1293 var debug_last_class = "even";
1294
1295 function debug(msg) {
1296         var ctx = getMainContext();
1297
1298         if (ctx.debug_last_class == "even") {
1299                 ctx.debug_last_class = "odd";
1300         } else {
1301                 ctx.debug_last_class = "even";
1302         }
1303
1304         var c = ctx.document.getElementById('debug_output');
1305         if (c && c.style.display == "block") {
1306                 while (c.lastChild != 'undefined' && c.childNodes.length > 100) {
1307                         c.removeChild(c.lastChild);
1308                 }
1309         
1310                 var d = new Date();
1311                 var ts = leading_zero(d.getHours()) + ":" + leading_zero(d.getMinutes()) +
1312                         ":" + leading_zero(d.getSeconds());
1313                 c.innerHTML = "<li class=\"" + ctx.debug_last_class + "\"><span class=\"debugTS\">[" + ts + "]</span> " + 
1314                         msg + "</li>" + c.innerHTML;
1315         }
1316 }
1317
1318 function getInitParam(key) {
1319         return getMainContext().init_params[key];
1320 }
1321
1322 function storeInitParam(key, value, is_client) {
1323         try {
1324                 if (!is_client) {
1325                         if (getMainContext().init_params[key] != value) {
1326                                 debug("storeInitParam: " + key + " => " + value);
1327                                 //new Ajax.Request("backend.php?op=rpc&subop=storeParam&key=" + 
1328                                 //      param_escape(key) + "&value=" + param_escape(value));   
1329                                 var f = getMainContext().document.getElementById("backReqBox");
1330                                 f.src = "backend.php?op=rpc&subop=storeParam&key=" + 
1331                                         param_escape(key) + "&value=" + param_escape(value);
1332                         }
1333                 }
1334                 getMainContext().init_params[key] = value;
1335         } catch (e) {
1336                 exception_error("storeInitParam", e);
1337         }
1338 }
1339
1340 /*
1341 function storeInitParams(params, is_client) {
1342         try {
1343                 var s = "";
1344
1345                 for (k in params) {
1346                         if (getMainContext().init_params[k] != params[k]) {
1347                                 s += k + "=" + params[k] + ";";
1348                                 getMainContext().init_params[k] = params[k];
1349                         }
1350                 } 
1351
1352                 debug("storeInitParams: " + s);
1353         
1354                 if (!is_client) {
1355                         new Ajax.Request("backend.php?op=rpc&subop=storeParams&str=" + s);
1356                 }
1357         } catch (e) {
1358                 exception_error("storeInitParams", e);
1359         }
1360 }*/
1361
1362 function fatalError(code, message) {
1363         try {   
1364                 var fe = document.getElementById("fatal_error");
1365                 var fc = document.getElementById("fatal_error_msg");
1366
1367                 fc.innerHTML = "Code " + code + ": " + message;
1368
1369                 fe.style.display = "block";
1370
1371         } catch (e) {
1372                 exception_error("fatalError", e);
1373         }
1374 }
1375
1376 function getFeedName(id, is_cat) {      
1377         var d = getFeedsContext().document;
1378
1379         var e;
1380
1381         if (is_cat) {
1382                 e = d.getElementById("FCATN-" + id);
1383         } else {
1384                 e = d.getElementById("FEEDN-" + id);
1385         }
1386         if (e) {
1387                 return e.innerHTML.stripTags();
1388         } else {
1389                 return null;
1390         }
1391 }