]> git.wh0rd.org Git - tt-rss.git/blob - functions.js
small layout fix
[tt-rss.git] / functions.js
1 var hotkeys_enabled = true;
2 var debug_mode_enabled = false;
3 var xmlhttp_rpc = Ajax.getTransport();
4
5 /* add method to remove element from array */
6
7 Array.prototype.remove = function(s) {
8         for (var i=0; i < this.length; i++) {
9                 if (s == this[i]) this.splice(i, 1);
10         }
11 }
12
13 function browser_has_opacity() {
14         return navigator.userAgent.match("Gecko") != null || 
15                 navigator.userAgent.match("Opera") != null;
16 }
17
18 function is_msie() {
19         return navigator.userAgent.match("MSIE");
20 }
21
22 function is_opera() {
23         return navigator.userAgent.match("Opera");
24 }
25
26 function is_khtml() {
27         return navigator.userAgent.match("KHTML");
28 }
29
30 function is_safari() {
31         return navigator.userAgent.match("Safari");
32 }
33
34 function exception_error(location, e, silent) {
35         var msg;
36
37         if (e.fileName) {
38                 var base_fname = e.fileName.substring(e.fileName.lastIndexOf("/") + 1);
39         
40                 msg = "Exception: " + e.name + ", " + e.message + 
41                         "\nFunction: " + location + "()" +
42                         "\nLocation: " + base_fname + ":" + e.lineNumber;
43                 
44         } else {
45                 msg = "Exception: " + e + "\nFunction: " + location + "()";
46         }
47
48         debug("<b>EXCEPTION: " + msg + "</b>");
49
50         if (!silent) {
51                 alert(msg);
52         }
53 }
54
55 function disableHotkeys() {
56         hotkeys_enabled = false;
57 }
58
59 function enableHotkeys() {
60         hotkeys_enabled = true;
61 }
62
63 function xmlhttp_ready(obj) {
64         return obj.readyState == 4 || obj.readyState == 0 || !obj.readyState;
65 }
66
67 function open_article_callback(transport) {
68         try {
69
70                 if (transport.responseXML) {
71                         
72                         var link = transport.responseXML.getElementsByTagName("link")[0];
73                         var id = transport.responseXML.getElementsByTagName("id")[0];
74
75                         debug("open_article_callback, received link: " + link);
76
77                         if (link) {
78                                 debug("link url: " + link.firstChild.nodeValue);
79
80                                 window.open(link.firstChild.nodeValue, "_blank");
81
82                                 if (id) {
83                                         id = id.firstChild.nodeValue;
84                                         if (!document.getElementById("headlinesList")) {
85                                                 window.setTimeout("toggleUnread(" + id + ", 0)", 100);
86                                         }
87                                 }
88                         } else {
89                                 notify_error("Can't open article: received invalid article link");
90                         }
91                 } else {
92                         notify_error("Can't open article: received invalid XML");
93                 }
94
95         } catch (e) {
96                 exception_error("open_article_callback", e);
97         }
98 }
99
100 function param_escape(arg) {
101         if (typeof encodeURIComponent != 'undefined')
102                 return encodeURIComponent(arg); 
103         else
104                 return escape(arg);
105 }
106
107 function param_unescape(arg) {
108         if (typeof decodeURIComponent != 'undefined')
109                 return decodeURIComponent(arg); 
110         else
111                 return unescape(arg);
112 }
113
114 function delay(gap) {
115         var then,now; 
116         then=new Date().getTime();
117         now=then;
118         while((now-then)<gap) {
119                 now=new Date().getTime();
120         }
121 }
122
123 var notify_hide_timerid = false;
124
125 function hide_notify() {
126         var n = document.getElementById("notify");
127         if (n) {
128                 n.style.display = "none";
129         }
130
131
132 function notify_real(msg, no_hide, n_type) {
133
134         var n = document.getElementById("notify");
135         var nb = document.getElementById("notify_body");
136
137         if (!n || !nb) return;
138
139         if (notify_hide_timerid) {
140                 window.clearTimeout(notify_hide_timerid);
141         }
142
143         if (msg == "") {
144                 if (n.style.display == "block") {
145                         notify_hide_timerid = window.setTimeout("hide_notify()", 0);
146                 }
147                 return;
148         } else {
149                 n.style.display = "block";
150         }
151
152         /* types:
153
154                 1 - generic
155                 2 - progress
156                 3 - error
157                 4 - info
158
159         */
160
161         if (typeof __ != 'undefined') {
162                 msg = __(msg);
163         }
164
165         if (n_type == 1) {
166                 n.className = "notify";
167         } else if (n_type == 2) {
168                 n.className = "notifyProgress";
169                 msg = "<img src='images/indicator_white.gif'> " + msg;
170         } else if (n_type == 3) {
171                 n.className = "notifyError";
172                 msg = "<img src='images/sign_excl.gif'> " + msg;
173         } else if (n_type == 4) {
174                 n.className = "notifyInfo";
175                 msg = "<img src='images/sign_info.gif'> " + msg;
176         }
177
178 //      msg = "<img src='images/live_com_loading.gif'> " + msg;
179
180         nb.innerHTML = msg;
181
182         if (!no_hide) {
183                 notify_hide_timerid = window.setTimeout("hide_notify()", 3000);
184         }
185 }
186
187 function notify(msg, no_hide) {
188         notify_real(msg, no_hide, 1);
189 }
190
191 function notify_progress(msg, no_hide) {
192         notify_real(msg, no_hide, 2);
193 }
194
195 function notify_error(msg, no_hide) {
196         notify_real(msg, no_hide, 3);
197
198 }
199
200 function notify_info(msg, no_hide) {
201         notify_real(msg, no_hide, 4);
202 }
203
204 function printLockingError() {
205         notify_info("Please wait until operation finishes.");
206 }
207
208 function hotkey_handler(e) {
209
210         try {
211
212                 var keycode;
213                 var shift_key = false;
214
215                 try {
216                         shift_key = e.shiftKey;
217                 } catch (e) {
218
219                 }
220         
221                 if (!hotkeys_enabled) {
222                         debug("hotkeys disabled");
223                         return;
224                 }
225         
226                 if (window.event) {
227                         keycode = window.event.keyCode;
228                 } else if (e) {
229                         keycode = e.which;
230                 }
231
232                 if (keycode == 82) { // r
233                         return scheduleFeedUpdate(true);
234                 }
235
236                 if (keycode == 83) { // s
237                         return displayDlg("search", getActiveFeedId());
238                 }
239
240                 if (keycode == 85) { // u
241                         if (getActiveFeedId()) {
242                                 return viewfeed(getActiveFeedId(), "ForceUpdate");
243                         }
244                 }
245         
246                 if (keycode == 65) { // a
247                         return toggleDispRead();
248                 }
249         
250                 var feedlist = document.getElementById('feedList');
251         
252                 if (keycode == 74) { // j
253                         var feed = getActiveFeedId();
254                         var new_feed = getRelativeFeedId(feedlist, feed, 'prev');
255                         if (new_feed) viewfeed(new_feed, '');
256                 }
257         
258                 if (keycode == 75) { // k
259                         var feed = getActiveFeedId();
260                         var new_feed = getRelativeFeedId(feedlist, feed, 'next');
261                         if (new_feed) viewfeed(new_feed, '');
262                 }
263
264                 if (shift_key && (keycode == 78 || keycode == 40)) { // shift - n, down
265                         return catchupRelativeToArticle(1);
266                 }
267
268                 if (shift_key && (keycode == 80 || keycode == 38)) { // shift - p, up
269                         return catchupRelativeToArticle(0);                     
270                 }
271
272                 if (keycode == 78 || keycode == 40) { // n, down
273                         if (typeof moveToPost != 'undefined') {
274                                 return moveToPost('next');
275                         }
276                 }
277         
278                 if (keycode == 80 || keycode == 38) { // p, up
279                         if (typeof moveToPost != 'undefined') {
280                                 return moveToPost('prev');
281                         }
282                 }
283                 
284                 if (keycode == 68 && shift_key) { // d
285                         if (!debug_mode_enabled) {
286                                 document.getElementById('debug_output').style.display = 'block';
287                                 debug('debug mode activated');
288                         } else {
289                                 document.getElementById('debug_output').style.display = 'none';
290                         }
291
292                         debug_mode_enabled = !debug_mode_enabled;
293                 }
294
295                 if (keycode == 190 && shift_key) { // >
296                         viewFeedGoPage(1);
297                 }
298                 
299                 if (keycode == 188 && shift_key) { // <
300                         viewFeedGoPage(-1);
301                 }
302
303                 if (keycode == 191 && shift_key) { // ?
304                         viewFeedGoPage(0);
305                 }
306
307                 if (keycode == 69 && shift_key) { // e
308                         return editFeedDlg(getActiveFeedId());
309                 }
310
311                 if (keycode == 70 && shift_key) { // f
312                         if (getActiveFeedId()) {
313                                 return catchupCurrentFeed();
314                         }
315                 }
316
317                 if (keycode == 80 && shift_key) { // p 
318                         if (getActiveFeedId()) {
319                                 return catchupPage();
320                         }
321                 }
322
323                 if (keycode == 86) { // v
324                         if (getActiveArticleId()) {
325                                 openArticleInNewWindow(getActiveArticleId());
326                         }
327                 }
328
329                 if (keycode == 84) { // t
330
331                         var id = getActiveArticleId();
332
333                         if (id) {                               
334
335                                 var cb = document.getElementById("RCHK-" + id);
336
337                                 if (cb) {
338                                         cb.checked = !cb.checked;
339                                         toggleSelectRowById(cb, "RROW-" + id);
340                                 }
341                         }
342                 }
343
344                 if (keycode == 67) { // c
345                         var id = getActiveArticleId();
346
347                         if (id) {                               
348                                 toggleUnread(id, 0);
349                         }
350                 }
351
352                 if (keycode == 67 && shift_key) { // c
353                         if (typeof collapse_feedlist != 'undefined') {
354                                 return collapse_feedlist();
355                         }
356                 }
357
358                 if (keycode == 81 && shift_key) { // shift + q
359                         if (typeof catchupAllFeeds != 'undefined') {
360                                 return catchupAllFeeds();
361                         }
362                 }
363
364                 if (keycode == 73 && shift_key) { // shift + i
365                         if (document.getElementById("subtoolbar_search")) {
366                                 if (Element.visible("subtoolbar_search")) {
367                                         Element.hide("subtoolbar_search");
368                                         Element.show("subtoolbar_ftitle");
369                                         setTimeout("Element.focus('subtoolbar_search_box')", 100);
370                                 } else {
371                                         Element.show("subtoolbar_search");
372                                         Element.hide("subtoolbar_ftitle");
373                                 }
374                         }
375                 }
376
377                 if (typeof localHotkeyHandler != 'undefined') {
378                         try {
379                                 return localHotkeyHandler(e);
380                         } catch (e) {
381                                 exception_error("hotkey_handler, local:", e);
382                         }
383                 }
384
385                 debug("KP=" + keycode);
386         } catch (e) {
387                 exception_error("hotkey_handler", e);
388         }
389 }
390
391 function cleanSelectedList(element) {
392         var content = document.getElementById(element);
393
394         if (!document.getElementById("feedCatHolder")) {
395                 for (i = 0; i < content.childNodes.length; i++) {
396                         var child = content.childNodes[i];
397                         try {
398                                 child.className = child.className.replace("Selected", "");
399                         } catch (e) {
400                                 //
401                         }
402                 }
403         } else {
404                 for (i = 0; i < content.childNodes.length; i++) {
405                         var child = content.childNodes[i];
406                         if (child.id == "feedCatHolder") {
407                                 debug(child.id);
408                                 var fcat = child.lastChild;
409                                 for (j = 0; j < fcat.childNodes.length; j++) {
410                                         var feed = fcat.childNodes[j];
411                                         feed.className = feed.className.replace("Selected", "");
412                                 }               
413                         }
414                 } 
415         }
416 }
417
418
419 function cleanSelected(element) {
420         var content = document.getElementById(element);
421
422         for (i = 0; i < content.rows.length; i++) {
423                 content.rows[i].className = content.rows[i].className.replace("Selected", "");
424         }
425 }
426
427 function getVisibleUnreadHeadlines() {
428         var content = document.getElementById("headlinesList");
429
430         var rows = new Array();
431
432         for (i = 0; i < content.rows.length; i++) {
433                 var row_id = content.rows[i].id.replace("RROW-", "");
434                 if (row_id.length > 0 && content.rows[i].className.match("Unread")) {
435                                 rows.push(row_id);      
436                 }
437         }
438         return rows;
439 }
440
441 function getVisibleHeadlineIds() {
442
443         var content = document.getElementById("headlinesList");
444
445         var rows = new Array();
446
447         for (i = 0; i < content.rows.length; i++) {
448                 var row_id = content.rows[i].id.replace("RROW-", "");
449                 if (row_id.length > 0) {
450                                 rows.push(row_id);      
451                 }
452         }
453         return rows;
454 }
455
456 function getFirstVisibleHeadlineId() {
457         var rows = getVisibleHeadlineIds();
458         return rows[0];
459 }
460
461 function getLastVisibleHeadlineId() {
462         var rows = getVisibleHeadlineIds();
463         return rows[rows.length-1];
464 }
465
466 function markHeadline(id) {
467         var row = document.getElementById("RROW-" + id);
468         if (row) {
469                 var is_active = false;
470         
471                 if (row.className.match("Active")) {
472                         is_active = true;
473                 }
474                 row.className = row.className.replace("Selected", "");
475                 row.className = row.className.replace("Active", "");
476                 row.className = row.className.replace("Insensitive", "");
477                 
478                 if (is_active) {
479                         row.className = row.className = "Active";
480                 }
481                 
482                 var check = document.getElementById("RCHK-" + id);
483
484                 if (check) {
485                         check.checked = true;
486                 }
487
488                 row.className = row.className + "Selected"; 
489                 
490         }
491 }
492
493 function getFeedIds() {
494         var content = document.getElementById("feedsList");
495
496         var rows = new Array();
497
498         for (i = 0; i < content.rows.length; i++) {
499                 var id = content.rows[i].id.replace("FEEDR-", "");
500                 if (id.length > 0) {
501                         rows.push(id);
502                 }
503         }
504
505         return rows;
506 }
507
508 function setCookie(name, value, lifetime, path, domain, secure) {
509         
510         var d = false;
511         
512         if (lifetime) {
513                 d = new Date();
514                 d.setTime(d.getTime() + (lifetime * 1000));
515         }
516
517         debug("setCookie: " + name + " => " + value + ": " + d);
518         
519         int_setCookie(name, value, d, path, domain, secure);
520
521 }
522
523 function int_setCookie(name, value, expires, path, domain, secure) {
524         document.cookie= name + "=" + escape(value) +
525                 ((expires) ? "; expires=" + expires.toGMTString() : "") +
526                 ((path) ? "; path=" + path : "") +
527                 ((domain) ? "; domain=" + domain : "") +
528                 ((secure) ? "; secure" : "");
529 }
530
531 function delCookie(name, path, domain) {
532         if (getCookie(name)) {
533                 document.cookie = name + "=" +
534                 ((path) ? ";path=" + path : "") +
535                 ((domain) ? ";domain=" + domain : "" ) +
536                 ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
537         }
538 }
539                 
540
541 function getCookie(name) {
542
543         var dc = document.cookie;
544         var prefix = name + "=";
545         var begin = dc.indexOf("; " + prefix);
546         if (begin == -1) {
547             begin = dc.indexOf(prefix);
548             if (begin != 0) return null;
549         }
550         else {
551             begin += 2;
552         }
553         var end = document.cookie.indexOf(";", begin);
554         if (end == -1) {
555             end = dc.length;
556         }
557         return unescape(dc.substring(begin + prefix.length, end));
558 }
559
560 function disableContainerChildren(id, disable, doc) {
561
562         if (!doc) doc = document;
563
564         var container = doc.getElementById(id);
565
566         if (!container) {
567                 //alert("disableContainerChildren: element " + id + " not found");
568                 return;
569         }
570
571         for (var i = 0; i < container.childNodes.length; i++) {
572                 var child = container.childNodes[i];
573
574                 try {
575                         child.disabled = disable;
576                 } catch (E) {
577
578                 }
579
580                 if (disable) {
581                         if (child.className && child.className.match("button")) {
582                                 child.className = "disabledButton";
583                         }
584                 } else {
585                         if (child.className && child.className.match("disabledButton")) {
586                                 child.className = "button";
587                         }
588                 } 
589         }
590
591 }
592
593 function gotoPreferences() {
594         document.location.href = "prefs.php";
595 }
596
597 function gotoMain() {
598         document.location.href = "tt-rss.php";
599 }
600
601 function gotoExportOpml() {
602         document.location.href = "opml.php?op=Export";
603 }
604
605 function getActiveFeedId() {
606 //      return getCookie("ttrss_vf_actfeed");
607         try {
608                 debug("gAFID: " + active_feed_id);
609                 return active_feed_id;
610         } catch (e) {
611                 exception_error("getActiveFeedId", e);
612         }
613 }
614
615 function activeFeedIsCat() {
616         return active_feed_is_cat;
617 }
618
619 function setActiveFeedId(id) {
620 //      return setCookie("ttrss_vf_actfeed", id);
621         try {
622                 debug("sAFID(" + id + ")");
623                 active_feed_id = id;
624         } catch (e) {
625                 exception_error("setActiveFeedId", e);
626         }
627 }
628
629 function parse_counters(reply, scheduled_call) {
630         try {
631
632                 var feeds_found = 0;
633
634                 var elems = reply.getElementsByTagName("counter");
635
636                 for (var l = 0; l < elems.length; l++) {
637
638                         var id = elems[l].getAttribute("id");
639                         var t = elems[l].getAttribute("type");
640                         var ctr = elems[l].getAttribute("counter");
641                         var error = elems[l].getAttribute("error");
642                         var has_img = elems[l].getAttribute("hi");
643                         var updated = elems[l].getAttribute("updated");
644                         var title = elems[l].getAttribute("title");
645                 
646                         if (id == "global-unread") {
647                                 global_unread = ctr;
648                                 updateTitle();
649                                 continue;
650                         }
651
652                         if (id == "subscribed-feeds") {
653                                 feeds_found = ctr;
654                                 continue;
655                         }
656         
657                         if (t == "category") {
658                                 var catctr = document.getElementById("FCATCTR-" + id);
659                                 if (catctr) {
660                                         catctr.innerHTML = "(" + ctr + ")";
661                                         if (ctr > 0) {
662                                                 catctr.className = "catCtrHasUnread";
663                                         } else {
664                                                 catctr.className = "catCtrNoUnread";
665                                         }
666                                 }
667                                 continue;
668                         }
669                 
670                         var feedctr = document.getElementById("FEEDCTR-" + id);
671                         var feedu = document.getElementById("FEEDU-" + id);
672                         var feedr = document.getElementById("FEEDR-" + id);
673                         var feed_img = document.getElementById("FIMG-" + id);
674                         var feedlink = document.getElementById("FEEDL-" + id);
675                         var feedupd = document.getElementById("FLUPD-" + id);
676
677                         if (updated && feedlink) {
678                                 if (error) {
679                                         feedlink.title = "Error: " + error + " (" + updated + ")";
680                                 } else {
681                                         feedlink.title = "Updated: " + updated;
682                                 }
683                         }
684
685                         if (updated && feedupd) {
686                                 if (error) {
687                                         feedupd.innerHTML = updated + " (Error)";
688                                 } else {
689                                         feedupd.innerHTML = updated;
690                                 }
691                         }
692
693                         if (has_img && feed_img && !is_msie()) {
694                                 if (!feed_img.src.match(id + ".ico")) {
695                                         feed_img.src = getInitParam("icons_location") + "/" + id + ".ico";
696                                 }
697                         }
698
699                         if (feedlink && title) {
700                                 feedlink.innerHTML = title;
701                         }
702
703                         if (feedctr && feedu && feedr) {
704
705                                 if (feedu.innerHTML != ctr && id == getActiveFeedId() && scheduled_call) {
706                                         viewCurrentFeed();
707                                 }
708
709                                 var row_needs_hl = (ctr > 0 && ctr > parseInt(feedu.innerHTML));
710
711                                 feedu.innerHTML = ctr;
712
713                                 if (error) {
714                                         feedr.className = feedr.className.replace("feed", "error");
715                                 } else if (id > 0) {
716                                         feedr.className = feedr.className.replace("error", "feed");
717                                 }
718         
719                                 if (ctr > 0) {                                  
720                                         feedctr.className = "odd";
721                                         if (!feedr.className.match("Unread")) {
722                                                 var is_selected = feedr.className.match("Selected");
723                 
724                                                 feedr.className = feedr.className.replace("Selected", "");
725                                                 feedr.className = feedr.className.replace("Unread", "");
726                 
727                                                 feedr.className = feedr.className + "Unread";
728                 
729                                                 if (is_selected) {
730                                                         feedr.className = feedr.className + "Selected";
731                                                 }       
732                                                 
733                                         }
734
735                                         if (row_needs_hl) { 
736                                                 new Effect.Highlight(feedr, {duration: 1, startcolor: "#fff7d5",
737                                                         queue: { position:'end', scope: 'EFQ-' + id, limit: 1 } } );
738                                         }
739                                 } else {
740                                         feedctr.className = "invisible";
741                                         feedr.className = feedr.className.replace("Unread", "");
742                                 }                       
743                         }
744                 }
745
746                 hideOrShowFeeds(document, getInitParam("hide_read_feeds") == 1);
747
748                 var feeds_stored = number_of_feeds;
749
750                 debug("Feed counters, C: " + feeds_found + ", S:" + feeds_stored);
751
752                 if (feeds_stored != feeds_found) {
753                         number_of_feeds = feeds_found;
754
755                         if (feeds_stored != 0 && feeds_found != 0) {
756                                 debug("Subscribed feed number changed, refreshing feedlist");
757                                 setTimeout('updateFeedList(false, false)', 50);
758                         }
759                 }
760
761         } catch (e) {
762                 exception_error("parse_counters", e);
763         }
764 }
765
766 function parse_counters_reply(transport, scheduled_call) {
767
768         if (!transport.responseXML) {
769                 notify_error("Backend did not return valid XML", true);
770                 return;
771         }
772
773         var reply = transport.responseXML.firstChild;
774         
775         if (!reply) {
776                 notify_error("Backend did not return expected XML object", true);
777                 updateTitle("");
778                 return;
779         } 
780         
781         var error_code = false;
782         var error_msg = false;
783
784         if (reply.firstChild) {
785                 error_code = reply.firstChild.getAttribute("error-code");
786                 error_msg = reply.firstChild.getAttribute("error-msg");
787         }
788
789         if (!error_code) {      
790                 error_code = reply.getAttribute("error-code");
791                 error_msg = reply.getAttribute("error-msg");
792         }
793         
794         if (error_code && error_code != 0) {
795                 debug("refetch_callback: got error code " + error_code);
796                 return fatalError(error_code, error_msg);
797         }
798
799         var counters = reply.getElementsByTagName("counters")[0];
800         
801         parse_counters(counters, scheduled_call);
802
803         var runtime_info = reply.getElementsByTagName("runtime-info")[0];
804
805         parse_runtime_info(runtime_info);
806
807         if (getInitParam("feeds_sort_by_unread") == 1) {
808                         resort_feedlist();              
809         }       
810
811         hideOrShowFeeds(document, getInitParam("hide_read_feeds") == 1);
812
813 }
814
815 function all_counters_callback2(transport) {
816         try {
817                 debug("<b>all_counters_callback2 IN: " + transport + "</b>");
818                 parse_counters_reply(transport);
819                 debug("<b>all_counters_callback2 OUT: " + transport + "</b>");
820
821         } catch (e) {
822                 exception_error("all_counters_callback2", e);
823         }
824 }
825
826 function get_feed_unread(id) {
827         try {
828                 return parseInt(document.getElementById("FEEDU-" + id).innerHTML);      
829         } catch (e) {
830                 exception_error("get_feed_unread", e, true);
831                 return -1;
832         }
833 }
834
835 function get_feed_entry_unread(doc, elem) {
836
837         var id = elem.id.replace("FEEDR-", "");
838
839         if (id <= 0) {
840                 return -1;
841         }
842
843         try {
844                 return parseInt(doc.getElementById("FEEDU-" + id).innerHTML);   
845         } catch (e) {
846                 return -1;
847         }
848 }
849
850 function resort_category(doc, node) {
851         debug("resort_category: " + node);
852
853         if (node.hasChildNodes() && node.firstChild.nextSibling != false) {  
854                 for (i = 0; i < node.childNodes.length; i++) {
855                         if (node.childNodes[i].nodeName != "LI") { continue; }
856
857                         if (get_feed_entry_unread(doc, node.childNodes[i]) < 0) {
858                                 continue;
859                         }
860
861                         for (j = i+1; j < node.childNodes.length; j++) {                        
862                                 if (node.childNodes[j].nodeName != "LI") { continue; }  
863
864                                 var tmp_val = get_feed_entry_unread(doc, node.childNodes[i]);
865                                 var cur_val = get_feed_entry_unread(doc, node.childNodes[j]);
866
867                                 if (cur_val > tmp_val) {
868                                         tempnode_i = node.childNodes[i].cloneNode(true);
869                                         tempnode_j = node.childNodes[j].cloneNode(true);
870                                         node.replaceChild(tempnode_i, node.childNodes[j]);
871                                         node.replaceChild(tempnode_j, node.childNodes[i]);
872                                 }
873                         }
874
875                 }
876         }
877
878 }
879
880 function resort_feedlist() {
881         debug("resort_feedlist");
882
883         var fd = document;
884
885         if (fd.getElementById("feedCatHolder")) {
886
887                 var feeds = fd.getElementById("feedList");
888                 var child = feeds.firstChild;
889
890                 while (child) {
891
892                         if (child.id == "feedCatHolder") {
893                                 resort_category(fd, child.firstChild);
894                         }
895         
896                         child = child.nextSibling;
897                 }
898
899         } else {
900                 resort_category(fd, fd.getElementById("feedList"));
901         }
902 }
903
904 /** * @(#)isNumeric.js * * Copyright (c) 2000 by Sundar Dorai-Raj
905   * * @author Sundar Dorai-Raj
906   * * Email: sdoraira@vt.edu
907   * * This program is free software; you can redistribute it and/or
908   * * modify it under the terms of the GNU General Public License 
909   * * as published by the Free Software Foundation; either version 2 
910   * * of the License, or (at your option) any later version, 
911   * * provided that any use properly credits the author. 
912   * * This program is distributed in the hope that it will be useful,
913   * * but WITHOUT ANY WARRANTY; without even the implied warranty of
914   * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
915   * * GNU General Public License for more details at http://www.gnu.org * * */
916
917   var numbers=".0123456789";
918   function isNumeric(x) {
919     // is x a String or a character?
920     if(x.length>1) {
921       // remove negative sign
922       x=Math.abs(x)+"";
923       for(j=0;j<x.length;j++) {
924         // call isNumeric recursively for each character
925         number=isNumeric(x.substring(j,j+1));
926         if(!number) return number;
927       }
928       return number;
929     }
930     else {
931       // if x is number return true
932       if(numbers.indexOf(x)>=0) return true;
933       return false;
934     }
935   }
936
937
938 function hideOrShowFeeds(doc, hide) {
939
940         debug("hideOrShowFeeds: " + doc + ", " + hide);
941
942         var fd = document;
943
944         var list = fd.getElementById("feedList");
945
946         if (fd.getElementById("feedCatHolder")) {
947
948                 var feeds = fd.getElementById("feedList");
949                 var child = feeds.firstChild;
950
951                 while (child) {
952
953                         if (child.id == "feedCatHolder") {
954                                 hideOrShowFeedsCategory(fd, child.firstChild, hide, child.previousSibling);
955                         }
956         
957                         child = child.nextSibling;
958                 }
959
960         } else {
961                 hideOrShowFeedsCategory(fd, fd.getElementById("feedList"), hide);
962         }
963 }
964
965 function hideOrShowFeedsCategory(doc, node, hide, cat_node) {
966
967 //      debug("hideOrShowFeedsCategory: " + node + " (" + hide + ")");
968
969         var cat_unread = 0;
970
971         if (!node) {
972                 debug("hideOrShowFeeds: passed node is null, aborting");
973                 return;
974         }
975
976 //      debug("cat: " + node.id);
977
978         if (node.hasChildNodes() && node.firstChild.nextSibling != false) {  
979                 for (i = 0; i < node.childNodes.length; i++) {
980                         if (node.childNodes[i].nodeName != "LI") { continue; }
981
982                         if (node.childNodes[i].style != undefined) {
983
984                                 var has_unread = (node.childNodes[i].className != "feed" &&
985                                         node.childNodes[i].className != "label" && 
986                                         !(!getInitParam("hide_read_shows_special") && 
987                                                 node.childNodes[i].className == "virt") && 
988                                         node.childNodes[i].className != "error" && 
989                                         node.childNodes[i].className != "tag");
990         
991 //                              debug(node.childNodes[i].id + " --> " + has_unread);
992         
993                                 if (hide && !has_unread) {
994                                         //node.childNodes[i].style.display = "none";
995                                         var id = node.childNodes[i].id;
996                                         Effect.Fade(node.childNodes[i], {duration : 0.3, 
997                                                 queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
998                                 }
999         
1000                                 if (!hide) {
1001                                         node.childNodes[i].style.display = "list-item";
1002                                         //Effect.Appear(node.childNodes[i], {duration : 0.3});
1003                                 }
1004         
1005                                 if (has_unread) {
1006                                         node.childNodes[i].style.display = "list-item";
1007                                         cat_unread++;
1008                                         //Effect.Appear(node.childNodes[i], {duration : 0.3});
1009                                         //Effect.Highlight(node.childNodes[i]);
1010                                 }
1011                         }
1012                 }
1013         }       
1014
1015 //      debug("end cat: " + node.id + " unread " + cat_unread);
1016
1017         if (cat_unread == 0) {
1018                 if (cat_node.style == undefined) {
1019                         debug("ERROR: supplied cat_node " + cat_node + 
1020                                 " has no styles. WTF?");
1021                         return;
1022                 }
1023                 if (hide) {
1024                         //cat_node.style.display = "none";
1025                         Effect.Fade(cat_node, {duration : 0.3, 
1026                                 queue: { position: 'end', scope: 'CFADE-' + node.id, limit: 1 }});
1027                 } else {
1028                         cat_node.style.display = "list-item";
1029                 }
1030         } else {
1031                 try {
1032                         cat_node.style.display = "list-item";
1033                 } catch (e) {
1034                         debug(e);
1035                 }
1036         }
1037
1038 //      debug("unread for category: " + cat_unread);
1039 }
1040
1041 function selectTableRow(r, do_select) {
1042         r.className = r.className.replace("Selected", "");
1043         
1044         if (do_select) {
1045                 r.className = r.className + "Selected";
1046         }
1047 }
1048
1049 function selectTableRowById(elem_id, check_id, do_select) {
1050
1051         try {
1052
1053                 var row = document.getElementById(elem_id);
1054
1055                 if (row) {
1056                         selectTableRow(row, do_select);
1057                 }               
1058
1059                 var check = document.getElementById(check_id);
1060
1061                 if (check) {
1062                         check.checked = do_select;
1063                 }
1064         } catch (e) {
1065                 exception_error("selectTableRowById", e);
1066         }
1067 }
1068
1069 function selectTableRowsByIdPrefix(content_id, prefix, check_prefix, do_select, 
1070         classcheck, reset_others) {
1071
1072         var content = document.getElementById(content_id);
1073
1074         if (!content) {
1075                 alert("[selectTableRows] Element " + content_id + " not found.");
1076                 return;
1077         }
1078
1079         for (i = 0; i < content.rows.length; i++) {
1080                 if (Element.visible(content.rows[i])) {
1081                         if (!classcheck || content.rows[i].className.match(classcheck)) {
1082                 
1083                                 if (content.rows[i].id.match(prefix)) {
1084                                         selectTableRow(content.rows[i], do_select);
1085                                 
1086                                         var row_id = content.rows[i].id.replace(prefix, "");
1087                                         var check = document.getElementById(check_prefix + row_id);
1088         
1089                                         if (check) {
1090                                                 check.checked = do_select;
1091                                         }
1092                                 } else if (reset_others) {
1093                                         selectTableRow(content.rows[i], false);
1094         
1095                                         var row_id = content.rows[i].id.replace(prefix, "");
1096                                         var check = document.getElementById(check_prefix + row_id);
1097         
1098                                         if (check) {
1099                                                 check.checked = false;
1100                                         }
1101         
1102                                 }
1103                         } else if (reset_others) {
1104                                 selectTableRow(content.rows[i], false);
1105         
1106                                 var row_id = content.rows[i].id.replace(prefix, "");
1107                                 var check = document.getElementById(check_prefix + row_id);
1108         
1109                                 if (check) {
1110                                         check.checked = false;
1111                                 }
1112         
1113                         }
1114                 }
1115         }
1116 }
1117
1118 function getSelectedTableRowIds(content_id, prefix) {
1119
1120         var content = document.getElementById(content_id);
1121
1122         if (!content) {
1123                 alert("[getSelectedTableRowIds] Element " + content_id + " not found.");
1124                 return;
1125         }
1126
1127         var sel_rows = new Array();
1128
1129         for (i = 0; i < content.rows.length; i++) {
1130                 if (content.rows[i].id.match(prefix) && 
1131                                 content.rows[i].className.match("Selected")) {
1132                                 
1133                         var row_id = content.rows[i].id.replace(prefix + "-", "");
1134                         sel_rows.push(row_id);  
1135                 }
1136         }
1137
1138         return sel_rows;
1139
1140 }
1141
1142 function toggleSelectRowById(sender, id) {
1143         var row = document.getElementById(id);
1144
1145         if (sender.checked) {
1146                 if (!row.className.match("Selected")) {
1147                         row.className = row.className + "Selected";
1148                 }
1149         } else {
1150                 if (row.className.match("Selected")) {
1151                         row.className = row.className.replace("Selected", "");
1152                 }
1153         }
1154 }
1155
1156 function toggleSelectListRow(sender) {
1157         var parent_row = sender.parentNode;
1158
1159         if (sender.checked) {
1160                 if (!parent_row.className.match("Selected")) {
1161                         parent_row.className = parent_row.className + "Selected";
1162                 }
1163         } else {
1164                 if (parent_row.className.match("Selected")) {
1165                         parent_row.className = parent_row.className.replace("Selected", "");
1166                 }
1167         }
1168 }
1169
1170 function tSR(sender) {
1171         return toggleSelectRow(sender);
1172 }
1173
1174 function toggleSelectRow(sender) {
1175         var parent_row = sender.parentNode.parentNode;
1176
1177         if (sender.checked) {
1178                 if (!parent_row.className.match("Selected")) {
1179                         parent_row.className = parent_row.className + "Selected";
1180                 }
1181         } else {
1182                 if (parent_row.className.match("Selected")) {
1183                         parent_row.className = parent_row.className.replace("Selected", "");
1184                 }
1185         }
1186 }
1187
1188 function getRelativeFeedId(list, id, direction, unread_only) {  
1189         var rows = list.getElementsByTagName("LI");
1190         var feeds = new Array();
1191
1192         for (var i = 0; i < rows.length; i++) {
1193                 if (rows[i].id.match("FEEDR-")) {
1194
1195                         if (rows[i].id == "FEEDR-" + id || (Element.visible(rows[i]) && Element.visible(rows[i].parentNode))) {
1196
1197                                 if (!unread_only || 
1198                                                 (rows[i].className.match("Unread") || rows[i].id == "FEEDR-" + id)) {
1199                                         feeds.push(rows[i].id.replace("FEEDR-", ""));
1200                                 }
1201                         }
1202                 }
1203         }
1204
1205         if (!id) {
1206                 if (direction == "next") {
1207                         return feeds.shift();
1208                 } else {
1209                         return feeds.pop();
1210                 }
1211         } else {
1212                 if (direction == "next") {
1213                         var idx = feeds.indexOf(id);
1214                         if (idx != -1 && idx < feeds.length) {
1215                                 return feeds[idx+1];                                    
1216                         } else {
1217                                 return getRelativeFeedId(list, false, direction, unread_only);
1218                         }
1219                 } else {
1220                         var idx = feeds.indexOf(id);
1221                         if (idx > 0) {
1222                                 return feeds[idx-1];
1223                         } else {
1224                                 return getRelativeFeedId(list, false, direction, unread_only);
1225                         }
1226                 }
1227
1228         }
1229 }
1230
1231 function showBlockElement(id, h_id) {
1232         var elem = document.getElementById(id);
1233
1234         if (elem) {
1235                 elem.style.display = "block";
1236
1237                 if (h_id) {
1238                         elem = document.getElementById(h_id);
1239                         if (elem) {
1240                                 elem.style.display = "none";
1241                         }
1242                 }
1243         } else {
1244                 alert("[showBlockElement] can't find element with id " + id);
1245         } 
1246 }
1247
1248 function appearBlockElement_afh(effect) {
1249
1250 }
1251
1252 function checkboxToggleElement(elem, id) {
1253         if (elem.checked) {
1254                 Effect.SlideDown(id, {duration : 0.5});
1255         } else {
1256                 Effect.SlideUp(id, {duration : 0.5});
1257         }
1258 }
1259
1260 function appearBlockElement(id, h_id) {
1261
1262         try {
1263                 if (h_id) {
1264                         Effect.Fade(h_id);
1265                 }
1266                 Effect.SlideDown(id, {duration : 1.0, afterFinish: appearBlockElement_afh});
1267         } catch (e) {
1268                 exception_error("appearBlockElement", e);
1269         }
1270
1271 }
1272
1273 function hideParentElement(e) {
1274         e.parentNode.style.display = "none";
1275 }
1276
1277 function dropboxSelect(e, v) {
1278         for (i = 0; i < e.length; i++) {
1279                 if (e[i].value == v) {
1280                         e.selectedIndex = i;
1281                         break;
1282                 }
1283         }
1284 }
1285
1286 // originally stolen from http://www.11tmr.com/11tmr.nsf/d6plinks/MWHE-695L9Z
1287 // bugfixed just a little bit :-)
1288 function getURLParam(strParamName){
1289   var strReturn = "";
1290   var strHref = window.location.href;
1291
1292   if (strHref.indexOf("#") == strHref.length-1) {
1293                 strHref = strHref.substring(0, strHref.length-1);
1294   }
1295
1296   if ( strHref.indexOf("?") > -1 ){
1297     var strQueryString = strHref.substr(strHref.indexOf("?"));
1298     var aQueryString = strQueryString.split("&");
1299     for ( var iParam = 0; iParam < aQueryString.length; iParam++ ){
1300       if (aQueryString[iParam].indexOf(strParamName + "=") > -1 ){
1301         var aParam = aQueryString[iParam].split("=");
1302         strReturn = aParam[1];
1303         break;
1304       }
1305     }
1306   }
1307   return strReturn;
1308
1309
1310 function leading_zero(p) {
1311         var s = String(p);
1312         if (s.length == 1) s = "0" + s;
1313         return s;
1314 }
1315
1316 function closeInfoBox(cleanup) {
1317
1318         if (!is_msie() && !getInitParam("infobox_disable_overlay")) {
1319                 var overlay = document.getElementById("dialog_overlay");
1320                 if (overlay) {
1321                         overlay.style.display = "none";
1322                 }
1323         }
1324
1325         var box = document.getElementById('infoBox');
1326         var shadow = document.getElementById('infoBoxShadow');
1327
1328         if (shadow) {
1329                 shadow.style.display = "none";
1330         } else if (box) {
1331                 box.style.display = "none";
1332         }
1333
1334         if (cleanup) box.innerHTML = "&nbsp;";
1335
1336         enableHotkeys();
1337
1338         return false;
1339 }
1340
1341
1342 function displayDlg(id, param) {
1343
1344         notify_progress("Loading, please wait...", true);
1345
1346         disableHotkeys();
1347
1348         var query = "backend.php?op=dlg&id=" +
1349                 param_escape(id) + "&param=" + param_escape(param);
1350
1351         new Ajax.Request(query, {
1352                 onComplete: function (transport) {
1353                         infobox_callback2(transport);
1354                 } });
1355
1356         return false;
1357 }
1358
1359 function infobox_submit_callback2(transport) {
1360         closeInfoBox();
1361
1362         try {
1363                 // called from prefs, reload tab
1364                 if (active_tab) {
1365                         selectTab(active_tab, false);
1366                 }
1367         } catch (e) { }
1368
1369         if (transport.responseText) {
1370                 notify_info(transport.responseText);
1371         }
1372 }
1373
1374 function infobox_callback2(transport) {
1375         try {
1376
1377                 debug("infobox_callback2");
1378
1379                 if (!is_msie() && !getInitParam("infobox_disable_overlay")) {
1380                         var overlay = document.getElementById("dialog_overlay");
1381                         if (overlay) {
1382                                 overlay.style.display = "block";
1383                         }
1384                 }
1385
1386                 var box = document.getElementById('infoBox');
1387                 var shadow = document.getElementById('infoBoxShadow');
1388                 if (box) {                      
1389
1390 /*                              if (!is_safari()) {
1391                                 new Draggable(shadow);
1392                         } */
1393
1394                         box.innerHTML=transport.responseText;                   
1395                         if (shadow) {
1396                                 shadow.style.display = "block";
1397                         } else {
1398                                 box.style.display = "block";                            
1399                         }
1400                 }
1401
1402                 /* FIXME this needs to be moved out somewhere */
1403
1404                 if (document.getElementById("tags_choices")) {
1405                         new Ajax.Autocompleter('tags_str', 'tags_choices',
1406                                 "backend.php?op=rpc&subop=completeTags",
1407                                 { tokens: ',', paramName: "search" });
1408                 }
1409
1410                 notify("");
1411         } catch (e) {
1412                 exception_error("infobox_callback2", e);
1413         }
1414 }
1415
1416 function createFilter() {
1417
1418         var form = document.forms['filter_add_form'];
1419         var reg_exp = form.reg_exp.value;
1420
1421         if (reg_exp == "") {
1422                 alert(__("Can't add filter: nothing to match on."));
1423                 return false;
1424         }
1425
1426         var query = Form.serialize("filter_add_form");
1427
1428         new Ajax.Request("backend.php?" + query, {
1429                 onComplete: function (transport) {
1430                         infobox_submit_callback2(transport);
1431                 } });
1432         
1433         return true;
1434 }
1435
1436 function toggleSubmitNotEmpty(e, submit_id) {
1437         try {
1438                 document.getElementById(submit_id).disabled = (e.value == "")
1439         } catch (e) {
1440                 exception_error("toggleSubmitNotEmpty", e);
1441         }
1442 }
1443
1444 function isValidURL(s) {
1445         return s.match("http://") != null || s.match("https://") != null || s.match("feed://") != null;
1446 }
1447
1448 function subscribeToFeed() {
1449
1450         var form = document.forms['feed_add_form'];
1451         var feed_url = form.feed_url.value;
1452
1453         if (feed_url == "") {
1454                 alert(__("Can't subscribe: no feed URL given."));
1455                 return false;
1456         }
1457
1458         notify_progress(__("Subscribing to feed..."), true);
1459
1460         closeInfoBox();
1461
1462         var feeds_doc = document;
1463
1464 //      feeds_doc.location.href = "backend.php?op=error&msg=Loading,%20please wait...";
1465         
1466         var query = Form.serialize("feed_add_form");
1467         
1468         debug("subscribe q: " + query);
1469
1470         new Ajax.Request("backend.php", {
1471                 parameters: query,
1472                 onComplete: function(transport) { 
1473                         dlg_frefresh_callback(transport); 
1474                 } });
1475
1476         return false;
1477 }
1478
1479 function filterCR(e, f)
1480 {
1481      var key;
1482
1483      if(window.event)
1484           key = window.event.keyCode;     //IE
1485      else
1486           key = e.which;     //firefox
1487
1488         if (key == 13) {
1489                 if (typeof f != 'undefined') {
1490                         f();
1491                         return false;
1492                 } else {
1493                         return false;
1494                 }
1495         } else {
1496                 return true;
1497         }
1498 }
1499
1500 function getMainContext() {
1501         return this.window;
1502 }
1503
1504 function getFeedsContext() {
1505         return this.window;
1506 }
1507
1508 function getContentContext() {
1509         return this.window;
1510 }
1511
1512 function getHeadlinesContext() {
1513         return this.window;
1514 }
1515
1516 var debug_last_class = "even";
1517
1518 function debug(msg) {
1519
1520         if (debug_last_class == "even") {
1521                 debug_last_class = "odd";
1522         } else {
1523                 debug_last_class = "even";
1524         }
1525
1526         var c = document.getElementById('debug_output');
1527         if (c && c.style.display == "block") {
1528                 while (c.lastChild != 'undefined' && c.childNodes.length > 100) {
1529                         c.removeChild(c.lastChild);
1530                 }
1531         
1532                 var d = new Date();
1533                 var ts = leading_zero(d.getHours()) + ":" + leading_zero(d.getMinutes()) +
1534                         ":" + leading_zero(d.getSeconds());
1535                 c.innerHTML = "<li class=\"" + debug_last_class + "\"><span class=\"debugTS\">[" + ts + "]</span> " + 
1536                         msg + "</li>" + c.innerHTML;
1537         }
1538 }
1539
1540 function getInitParam(key) {
1541         return init_params[key];
1542 }
1543
1544 function storeInitParam(key, value) {
1545         debug("<b>storeInitParam is OBSOLETE: " + key + " => " + value + "</b>");
1546         init_params[key] = value;
1547 }
1548
1549 function fatalError(code, message) {
1550         try {   
1551
1552                 if (code == 6) {
1553                         window.location.href = "tt-rss.php";                    
1554                 } else if (code == 5) {
1555                         window.location.href = "update.php";
1556                 } else {
1557                         var fe = document.getElementById("fatal_error");
1558                         var fc = document.getElementById("fatal_error_msg");
1559         
1560                         if (message == "") message = "Unknown error";
1561
1562                         fc.innerHTML = "<img src='images/sign_excl.gif'> " + message + " (Code " + code + ")";
1563         
1564                         fe.style.display = "block";
1565                 }
1566
1567         } catch (e) {
1568                 exception_error("fatalError", e);
1569         }
1570 }
1571
1572 function getFeedName(id, is_cat) {      
1573         var d = getFeedsContext().document;
1574
1575         var e;
1576
1577         if (is_cat) {
1578                 e = d.getElementById("FCATN-" + id);
1579         } else {
1580                 e = d.getElementById("FEEDN-" + id);
1581         }
1582         if (e) {
1583                 return e.innerHTML.stripTags();
1584         } else {
1585                 return null;
1586         }
1587 }
1588
1589 function viewContentUrl(url) {
1590         getContentContext().location = url;
1591 }
1592
1593 function filterDlgCheckAction(sender) {
1594
1595         try {
1596
1597                 var action = sender[sender.selectedIndex].value;
1598
1599                 var form = document.forms["filter_add_form"];
1600         
1601                 if (!form) {
1602                         form = document.forms["filter_edit_form"];
1603                 }
1604
1605                 if (!form) {
1606                         debug("filterDlgCheckAction: can't find form!");
1607                         return;
1608                 }
1609
1610                 var action_param = form.action_param;
1611
1612                 if (!action_param) {
1613                         debug("filterDlgCheckAction: can't find action param!");
1614                         return;
1615                 }
1616
1617                 // if selected action supports parameters, enable params field
1618                 if (action == 4 || action == 6) {
1619                         action_param.disabled = false;
1620                 } else {
1621                         action_param.disabled = true;
1622                 }
1623
1624         } catch (e) {
1625                 exception_error(e, "filterDlgCheckAction");
1626         }
1627
1628 }
1629
1630 function explainError(code) {
1631         return displayDlg("explainError", code);
1632 }
1633
1634 // this only searches loaded headlines list, not in CDM
1635 function getRelativePostIds(id) {
1636
1637         debug("getRelativePostIds: " + id);
1638
1639         var ids = new Array();
1640         var container = document.getElementById("headlinesList");
1641
1642         if (container) {
1643                 var rows = container.rows;
1644
1645                 for (var i = 0; i < rows.length; i++) {
1646                         var r_id = rows[i].id.replace("RROW-", "");
1647
1648                         if (r_id == id) {
1649                                 if (i > 0) ids.push(rows[i-1].id.replace("RROW-", ""));
1650                                 if (i > 1) ids.push(rows[i-2].id.replace("RROW-", ""));
1651                                 if (i > 2) ids.push(rows[i-3].id.replace("RROW-", ""));
1652
1653                                 if (i < rows.length-1) ids.push(rows[i+1].id.replace("RROW-", ""));
1654                                 if (i < rows.length-2) ids.push(rows[i+2].id.replace("RROW-", ""));
1655                                 if (i < rows.length-3) ids.push(rows[i+3].id.replace("RROW-", ""));
1656
1657                                 return ids;
1658                         }
1659                 }
1660         }
1661
1662         return false;
1663 }
1664
1665 function openArticleInNewWindow(id) {
1666         try {
1667                 debug("openArticleInNewWindow: " + id);
1668
1669                 var query = "backend.php?op=rpc&subop=getArticleLink&id=" + id;
1670
1671                 debug(query);
1672
1673                 new Ajax.Request(query, {
1674                         onComplete: function(transport) { 
1675                                 open_article_callback(transport); 
1676                         } });
1677
1678
1679         } catch (e) {
1680                 exception_error("openArticleInNewWindow", e);
1681         }
1682 }
1683
1684 /* http://textsnippets.com/posts/show/835 */
1685
1686 Position.GetWindowSize = function(w) {
1687         w = w ? w : window;
1688         var width = w.innerWidth || (w.document.documentElement.clientWidth || w.document.body.clientWidth);
1689         var height = w.innerHeight || (w.document.documentElement.clientHeight || w.document.body.clientHeight);
1690         return [width, height]
1691 }
1692
1693 /* http://textsnippets.com/posts/show/836 */
1694
1695 Position.Center = function(element, parent) {
1696         var w, h, pw, ph;
1697         var d = Element.getDimensions(element);
1698         w = d.width;
1699         h = d.height;
1700         Position.prepare();
1701         if (!parent) {
1702                 var ws = Position.GetWindowSize();
1703                 pw = ws[0];
1704                 ph = ws[1];
1705         } else {
1706                 pw = parent.offsetWidth;
1707                 ph = parent.offsetHeight;
1708         }
1709         element.style.top = (ph/2) - (h/2) -  Position.deltaY + "px";
1710         element.style.left = (pw/2) - (w/2) -  Position.deltaX + "px";
1711 }
1712
1713
1714 function labeltest_callback(transport) {
1715         try {
1716                 var container = document.getElementById('label_test_result');
1717         
1718                 container.innerHTML = transport.responseText;
1719                 if (!Element.visible(container)) {
1720                         Effect.SlideDown(container, { duration : 0.5 });
1721                 }
1722
1723                 notify("");
1724         } catch (e) {
1725                 exception_error("labeltest_callback", e);
1726         }
1727 }
1728
1729 function labelTest() {
1730
1731         try {
1732                 var container = document.getElementById('label_test_result');
1733         
1734                 var form = document.forms['label_edit_form'];
1735         
1736                 var sql_exp = form.sql_exp.value;
1737                 var description = form.description.value;
1738         
1739                 notify_progress("Loading, please wait...");
1740         
1741                 var query = "backend.php?op=pref-labels&subop=test&expr=" +
1742                         param_escape(sql_exp) + "&descr=" + param_escape(description);
1743         
1744                 new Ajax.Request(query, {
1745                         onComplete: function (transport) {
1746                                 labeltest_callback(transport);
1747                         } });
1748         
1749                 return false;
1750
1751         } catch (e) {
1752                 exception_error("labelTest", e);
1753         }
1754 }
1755
1756 function isCdmMode() {
1757         return !document.getElementById("headlinesList");
1758 }
1759
1760 function getSelectedArticleIds2() {
1761         var rows = new Array();
1762         var cdm_mode = isCdmMode();
1763
1764         if (cdm_mode) {
1765                 rows = cdmGetSelectedArticles();
1766         } else {        
1767                 rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK");
1768         }
1769
1770         var ids = new Array();
1771
1772         for (var i = 0; i < rows.length; i++) {
1773                 var chk = document.getElementById("RCHK-" + rows[i]);
1774                 if (chk && chk.checked) {
1775                         ids.push(rows[i]);
1776                 }
1777         }
1778
1779         return ids;
1780 }
1781
1782 function displayHelpInfobox(topic_id) {
1783
1784         var url = "backend.php?op=help&tid=" + param_escape(topic_id);
1785
1786         var w = window.open(url, "ttrss_help", 
1787                 "status=0,toolbar=0,location=0,width=450,height=500,scrollbars=1,menubar=0");
1788
1789         return false;
1790 }
1791
1792