]> git.wh0rd.org Git - tt-rss.git/blob - prefs.js
make debug window draggable
[tt-rss.git] / prefs.js
1 var xmlhttp = false;
2
3 var active_feed_cat = false;
4 var active_label = false;
5 var active_tab = false;
6 var feed_to_expand = false;
7
8 var xmlhttp = Ajax.getTransport();
9
10 var init_params = new Array();
11
12 var caller_subop = false;
13 var sanity_check_done = false;
14 var hotkey_prefix = false;
15
16 function infobox_callback() {
17         if (xmlhttp.readyState == 4) {
18                 infobox_callback2(xmlhttp);
19         }
20 }
21
22 function infobox_submit_callback() {
23         if (xmlhttp.readyState == 4) {
24                 infobox_submit_callback2(xmlhttp);
25         }
26 }
27
28
29 function replace_pubkey_callback() {
30         if (xmlhttp.readyState == 4) {
31                 try {   
32                         var link = document.getElementById("pubGenAddress");
33
34                         if (xmlhttp.responseXML) {
35
36                                 var new_link = xmlhttp.responseXML.getElementsByTagName("link")[0];
37
38                                 if (new_link) {
39                                         link.href = new_link.firstChild.nodeValue;
40                                         //link.innerHTML = new_link.firstChild.nodeValue;
41
42                                         new Effect.Highlight(link);
43
44                                         notify_info("Published feed URL changed.");
45                                 } else {
46                                         notify_error("Could not change feed URL.");
47                                 }
48
49                         } else {
50                                 notify_error("Could not change feed URL.");
51                         }
52                 } catch (e) {
53                         exception_error("replace_pubkey_callback", e);
54                 }
55         }
56 }
57
58 function expand_feed_callback() {
59         if (xmlhttp.readyState == 4) {
60                 try {   
61                         var container = document.getElementById("BRDET-" + feed_to_expand);     
62                         container.innerHTML=xmlhttp.responseText;
63 //                      container.style.display = "block";
64                         Effect.Appear(container, {duration : 0.5});
65                 } catch (e) {
66                         exception_error("expand_feed_callback", e);
67                 }
68         }
69 }
70
71 function feedlist_callback() {
72         if (xmlhttp.readyState == 4) {
73                 try {   
74                         var container = document.getElementById('prefContent'); 
75                         container.innerHTML=xmlhttp.responseText;
76                         selectTab("feedConfig", true);
77
78                         if (caller_subop) {
79                                 var tuple = caller_subop.split(":");
80                                 if (tuple[0] == 'editFeed') {
81                                         window.setTimeout('editFeed('+tuple[1]+')', 100);
82                                 }                               
83
84                                 caller_subop = false;
85                         }
86                         if (typeof correctPNG != 'undefined') {
87                                 correctPNG();
88                         }
89                         notify("");
90                         remove_splash();
91
92                 } catch (e) {
93                         exception_error("feedlist_callback", e);
94                 }
95         }
96 }
97
98 /* stub for subscription dialog */
99
100 function dlg_frefresh_callback(transport) {
101
102         try {
103                 var container = document.getElementById('prefContent'); 
104                 container.innerHTML=transport.responseText;
105                 selectTab("feedConfig", true);
106
107                 if (caller_subop) {
108                         var tuple = caller_subop.split(":");
109                         if (tuple[0] == 'editFeed') {
110                                 window.setTimeout('editFeed('+tuple[1]+')', 100);
111                         }                               
112
113                         caller_subop = false;
114                 }
115                 if (typeof correctPNG != 'undefined') {
116                         correctPNG();
117                 }
118                 notify("");
119         } catch (e) {
120                 exception_error("feedlist_callback", e);
121         }
122
123 }
124
125 function filterlist_callback() {
126         var container = document.getElementById('prefContent');
127         if (xmlhttp.readyState == 4) {
128                 container.innerHTML=xmlhttp.responseText;
129                 if (typeof correctPNG != 'undefined') {
130                         correctPNG();
131                 }
132                 notify("");
133                 remove_splash();
134         }
135 }
136
137 function labellist_callback() {
138         var container = document.getElementById('prefContent');
139         if (xmlhttp.readyState == 4) {
140                 closeInfoBox();
141                 container.innerHTML=xmlhttp.responseText;
142                 if (active_label) {
143                         var row = document.getElementById("LILRR-" + active_label);
144                         if (row) {
145                                 if (!row.className.match("Selected")) {
146                                         row.className = row.className + "Selected";
147                                 }               
148                         }
149                         var checkbox = document.getElementById("LICHK-" + active_label);
150                         
151                         if (checkbox) {
152                                 checkbox.checked = true;
153                         }
154                 }
155                 if (typeof correctPNG != 'undefined') {
156                         correctPNG();
157                 }
158                 notify("");
159                 remove_splash();
160         }
161 }
162
163 function feed_browser_callback() {
164         var container = document.getElementById('prefContent');
165         if (xmlhttp.readyState == 4) {
166                 container.innerHTML=xmlhttp.responseText;
167                 notify("");
168                 remove_splash();
169         }
170 }
171
172 function userlist_callback() {
173         var container = document.getElementById('prefContent');
174         if (xmlhttp.readyState == 4) {
175                 container.innerHTML=xmlhttp.responseText;
176                 notify("");
177                 remove_splash();
178         }
179 }
180
181 function prefslist_callback() {
182         var container = document.getElementById('prefContent');
183         if (xmlhttp.readyState == 4) {
184                 container.innerHTML=xmlhttp.responseText;
185                 notify("");
186                 remove_splash();
187         }
188 }
189
190 function gethelp_callback() {
191         var container = document.getElementById('prefHelpBox');
192         if (xmlhttp.readyState == 4) {
193
194                 container.innerHTML = xmlhttp.responseText;
195                 container.style.display = "block";
196
197         }
198 }
199
200 function notify_callback() {
201         if (xmlhttp.readyState == 4) {
202                 notify_info(xmlhttp.responseText);
203         } 
204 }
205
206 function prefs_reset_callback() {
207         if (xmlhttp.readyState == 4) {
208                 notify_info(xmlhttp.responseText);
209                 selectTab();
210         } 
211 }
212
213
214 function changepass_callback() {
215         try {
216                 if (xmlhttp.readyState == 4) {
217         
218                         if (xmlhttp.responseText.indexOf("ERROR: ") == 0) {
219                                 notify_error(xmlhttp.responseText.replace("ERROR: ", ""));
220                         } else {
221                                 notify_info(xmlhttp.responseText);
222                                 var warn = document.getElementById("default_pass_warning");
223                                 if (warn) warn.style.display = "none";
224                         }
225         
226                         document.forms['change_pass_form'].reset();
227
228                 } 
229         } catch (e) {
230                 exception_error("changepass_callback", e);
231         }
232 }
233
234 function infobox_feed_cat_callback() {
235         if (xmlhttp.readyState == 4) {
236                 try {
237
238                         infobox_callback();
239
240                         if (document.getElementById("prefFeedCatList")) {
241                                 var elems = document.getElementById("prefFeedCatList").getElementsByTagName("SPAN");
242
243                                 for (var i = 0; i < elems.length; i++) {
244                                         if (elems[i].id && elems[i].id.match("FCATT-")) {
245                                                 var cat_id = elems[i].id.replace("FCATT-", "");
246
247                                                 new Ajax.InPlaceEditor(elems[i],
248                                                         'backend.php?op=pref-feeds&subop=editCats&action=save&cid=' + cat_id);
249                                         }
250                                 }
251                         }
252
253                 } catch (e) {
254                         exception_error("infobox_feed_cat_callback", e);
255                 }
256         }
257 }
258
259 function updateFeedList(sort_key) {
260
261         if (!xmlhttp_ready(xmlhttp)) {
262                 printLockingError();
263                 return
264         }
265
266         var feed_search = document.getElementById("feed_search");
267         var search = "";
268         if (feed_search) { search = feed_search.value; }
269
270         var slat = document.getElementById("show_last_article_times");
271
272         var slat_checked = false;
273         if (slat) {
274                 slat_checked = slat.checked;
275         }
276
277         xmlhttp.open("GET", "backend.php?op=pref-feeds" +
278                 "&sort=" + param_escape(sort_key) + 
279                 "&slat=" + param_escape(slat_checked) +
280                 "&search=" + param_escape(search), true);
281         xmlhttp.onreadystatechange=feedlist_callback;
282         xmlhttp.send(null);
283
284 }
285
286 function updateUsersList(sort_key) {
287
288         if (!xmlhttp_ready(xmlhttp)) {
289                 printLockingError();
290                 return
291         }
292
293         var user_search = document.getElementById("user_search");
294         var search = "";
295         if (user_search) { search = user_search.value; }
296
297         xmlhttp.open("GET", "backend.php?op=pref-users&sort="
298                 + param_escape(sort_key) +
299                 "&search=" + param_escape(search), true);
300         xmlhttp.onreadystatechange=userlist_callback;
301         xmlhttp.send(null);
302
303 }
304
305 function addLabel() {
306
307         if (!xmlhttp_ready(xmlhttp)) {
308                 printLockingError();
309                 return
310         }
311
312         var form = document.forms['label_edit_form'];
313
314         var sql_exp = form.sql_exp.value;
315         var description = form.description.value;
316
317         if (sql_exp == "") {
318                 alert(__("Can't create label: missing SQL expression."));
319                 return false;
320         }
321
322         if (description == "") {
323                 alert(__("Can't create label: missing caption."));
324                 return false;
325         }
326
327         var query = Form.serialize("label_edit_form");
328
329         // we can be called from some other tab
330         active_tab = "labelConfig";
331
332         xmlhttp.open("GET", "backend.php?op=pref-labels&subop=add&" + query, true);                     
333         xmlhttp.onreadystatechange=infobox_submit_callback;
334         xmlhttp.send(null);
335 }
336
337 function addFeed() {
338
339         if (!xmlhttp_ready(xmlhttp)) {
340                 printLockingError();
341                 return
342         }
343
344         var link = document.getElementById("fadd_link");
345
346         if (link.value.length == 0) {
347                 alert(__("Error: No feed URL given."));
348         } else if (!isValidURL(link.value)) {
349                 alert(__("Error: Invalid feed URL."));
350         } else {
351                 notify_progress("Adding feed...");
352
353                 xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=add&from=tt-rss&feed_url=" +
354                         param_escape(link.value), true);
355                 xmlhttp.onreadystatechange=feedlist_callback;
356                 xmlhttp.send(null);
357
358                 link.value = "";
359
360         }
361
362 }
363
364 function addFeedCat() {
365
366         if (!xmlhttp_ready(xmlhttp)) {
367                 printLockingError();
368                 return
369         }
370
371         var cat = document.getElementById("fadd_cat");
372
373         if (cat.value.length == 0) {
374                 alert(__("Can't add category: no name specified."));
375         } else {
376                 notify_progress("Adding feed category...");
377
378                 xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=editCats&action=add&cat=" +
379                         param_escape(cat.value), true);
380                 xmlhttp.onreadystatechange=infobox_callback;
381                 xmlhttp.send(null);
382
383                 link.value = "";
384
385         }
386
387 }
388 function addUser() {
389
390         if (!xmlhttp_ready(xmlhttp)) {
391                 printLockingError();
392                 return
393         }
394
395         var sqlexp = document.getElementById("uadd_box");
396
397         if (sqlexp.value.length == 0) {
398                 alert(__("Can't add user: no login specified."));
399         } else {
400                 notify_progress("Adding user...");
401
402                 xmlhttp.open("GET", "backend.php?op=pref-users&subop=add&login=" +
403                         param_escape(sqlexp.value), true);                      
404                         
405                 xmlhttp.onreadystatechange=userlist_callback;
406                 xmlhttp.send(null);
407
408                 sqlexp.value = "";
409         }
410
411 }
412
413 function editLabel(id) {
414
415         if (!xmlhttp_ready(xmlhttp)) {
416                 printLockingError();
417                 return
418         }
419
420         disableHotkeys();
421
422         notify_progress("Loading, please wait...");
423
424 //      document.getElementById("label_create_btn").disabled = true;
425
426         active_label = id;
427
428         selectTableRowsByIdPrefix('prefLabelList', 'LILRR-', 'LICHK-', false);
429         selectTableRowById('LILRR-'+id, 'LICHK-'+id, true);
430
431         xmlhttp.open("GET", "backend.php?op=pref-labels&subop=edit&id=" +
432                 param_escape(id), true);
433         xmlhttp.onreadystatechange=infobox_callback;
434         xmlhttp.send(null);
435
436 }
437
438 function editUser(id) {
439
440         if (!xmlhttp_ready(xmlhttp)) {
441                 printLockingError();
442                 return
443         }
444
445         disableHotkeys();
446
447         notify_progress("Loading, please wait...");
448
449         selectTableRowsByIdPrefix('prefUserList', 'UMRR-', 'UMCHK-', false);
450         selectTableRowById('UMRR-'+id, 'UMCHK-'+id, true);
451
452         xmlhttp.open("GET", "backend.php?op=pref-users&subop=edit&id=" +
453                 param_escape(id), true);
454         xmlhttp.onreadystatechange=infobox_callback;
455         xmlhttp.send(null);
456
457 }
458
459 function editFilter(id) {
460
461         if (!xmlhttp_ready(xmlhttp)) {
462                 printLockingError();
463                 return
464         }
465
466         disableHotkeys();
467
468         notify_progress("Loading, please wait...");
469
470 //      document.getElementById("create_filter_btn").disabled = true;
471
472         selectTableRowsByIdPrefix('prefFilterList', 'FILRR-', 'FICHK-', false);
473         selectTableRowById('FILRR-'+id, 'FICHK-'+id, true);
474
475         xmlhttp.open("GET", "backend.php?op=pref-filters&subop=edit&id=" + param_escape(id), true);
476         xmlhttp.onreadystatechange=infobox_callback;
477         xmlhttp.send(null);
478 }
479
480 function editFeed(feed) {
481
482 //      notify("Editing feed...");
483
484         if (!xmlhttp_ready(xmlhttp)) {
485                 printLockingError();
486                 return
487         }
488
489         disableHotkeys();
490
491         notify_progress("Loading, please wait...");
492
493 /*      document.getElementById("subscribe_to_feed_btn").disabled = true;
494
495         try {
496                 document.getElementById("top25_feeds_btn").disabled = true;
497         } catch (e) {
498                 // this button is not always available, no-op if not found
499         } */
500
501         // clean selection from all rows & select row being edited
502         selectTableRowsByIdPrefix('prefFeedList', 'FEEDR-', 'FRCHK-', false);
503         selectTableRowById('FEEDR-'+feed, 'FRCHK-'+feed, true);
504
505         xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=editfeed&id=" +
506                 param_escape(feed), true);
507
508         xmlhttp.onreadystatechange=infobox_callback;
509         xmlhttp.send(null);
510
511 }
512
513 function editFeedCat(cat) {
514
515         if (!xmlhttp_ready(xmlhttp)) {
516                 printLockingError();
517                 return
518         }
519
520         disableHotkeys();
521
522         notify_progress("Loading, please wait...");
523
524         active_feed_cat = cat;
525
526         xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=editCats&action=edit&id=" +
527                 param_escape(cat), true);
528         xmlhttp.onreadystatechange=infobox_callback;
529         xmlhttp.send(null);
530
531 }
532
533 function getSelectedLabels() {
534         return getSelectedTableRowIds("prefLabelList", "LILRR");
535 }
536
537 function getSelectedUsers() {
538         return getSelectedTableRowIds("prefUserList", "UMRR");
539 }
540
541 function getSelectedFeeds() {
542         return getSelectedTableRowIds("prefFeedList", "FEEDR");
543 }
544
545 function getSelectedFilters() {
546         return getSelectedTableRowIds("prefFilterList", "FILRR");
547 }
548
549 function getSelectedFeedCats() {
550         return getSelectedTableRowIds("prefFeedCatList", "FCATR");
551 }
552
553 function getSelectedFeedsFromBrowser() {
554
555         var list = document.getElementById("browseFeedList");
556         if (!list) list = document.getElementById("browseBigFeedList");
557
558         var selected = new Array();
559         
560         for (i = 0; i < list.childNodes.length; i++) {
561                 var child = list.childNodes[i];
562                 if (child.id && child.id.match("FBROW-")) {
563                         var id = child.id.replace("FBROW-", "");
564                         
565                         var cb = document.getElementById("FBCHK-" + id);
566
567                         if (cb.checked) {
568                                 selected.push(id);
569                         }
570                 }
571         }
572
573         return selected;
574 }
575
576 function removeSelectedLabels() {
577
578         if (!xmlhttp_ready(xmlhttp)) {
579                 printLockingError();
580                 return
581         }
582
583         var sel_rows = getSelectedLabels();
584
585         if (sel_rows.length > 0) {
586
587                 var ok = confirm(__("Remove selected labels?"));
588
589                 if (ok) {
590                         notify_progress("Removing selected labels...");
591         
592                         xmlhttp.open("GET", "backend.php?op=pref-labels&subop=remove&ids="+
593                                 param_escape(sel_rows.toString()), true);
594                         xmlhttp.onreadystatechange=labellist_callback;
595                         xmlhttp.send(null);
596                 }
597         } else {
598                 alert(__("No labels are selected."));
599         }
600
601         return false;
602 }
603
604 function removeSelectedUsers() {
605
606         if (!xmlhttp_ready(xmlhttp)) {
607                 printLockingError();
608                 return
609         }
610
611         var sel_rows = getSelectedUsers();
612
613         if (sel_rows.length > 0) {
614
615                 var ok = confirm(__("Remove selected users?"));
616
617                 if (ok) {
618                         notify_progress("Removing selected users...");
619         
620                         xmlhttp.open("GET", "backend.php?op=pref-users&subop=remove&ids="+
621                                 param_escape(sel_rows.toString()), true);
622                         xmlhttp.onreadystatechange=userlist_callback;
623                         xmlhttp.send(null);
624                 }
625
626         } else {
627                 alert(__("No users are selected."));
628         }
629
630         return false;
631 }
632
633 function removeSelectedFilters() {
634
635         if (!xmlhttp_ready(xmlhttp)) {
636                 printLockingError();
637                 return
638         }
639
640         var sel_rows = getSelectedFilters();
641
642         if (sel_rows.length > 0) {
643
644                 var ok = confirm(__("Remove selected filters?"));
645
646                 if (ok) {
647                         notify_progress("Removing selected filters...");
648         
649                         xmlhttp.open("GET", "backend.php?op=pref-filters&subop=remove&ids="+
650                                 param_escape(sel_rows.toString()), true);
651                         xmlhttp.onreadystatechange=filterlist_callback;
652                         xmlhttp.send(null);
653                 }
654         } else {
655                 alert(__("No filters are selected."));
656         }
657
658         return false;
659 }
660
661
662 function removeSelectedFeeds() {
663
664         if (!xmlhttp_ready(xmlhttp)) {
665                 printLockingError();
666                 return
667         }
668
669         var sel_rows = getSelectedFeeds();
670
671         if (sel_rows.length > 0) {
672
673                 var ok = confirm(__("Unsubscribe from selected feeds?"));
674
675                 if (ok) {
676
677                         notify_progress("Unsubscribing from selected feeds...");
678         
679                         xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=remove&ids="+
680                                 param_escape(sel_rows.toString()), true);
681                         xmlhttp.onreadystatechange=feedlist_callback;
682                         xmlhttp.send(null);
683                 }
684
685         } else {
686
687                 alert(__("No feeds are selected."));
688
689         }
690         
691         return false;
692 }
693
694 function clearSelectedFeeds() {
695
696         if (!xmlhttp_ready(xmlhttp)) {
697                 printLockingError();
698                 return
699         }
700
701         var sel_rows = getSelectedFeeds();
702
703         if (sel_rows.length > 1) {
704                 alert(__("Please select only one feed."));
705                 return;
706         }
707
708         if (sel_rows.length > 0) {
709
710                 var ok = confirm(__("Erase all non-starred articles in selected feed?"));
711
712                 if (ok) {
713                         notify_progress("Clearing selected feed...");
714                         clearFeedArticles(sel_rows[0]);
715                 }
716
717         } else {
718
719                 alert(__("No feeds are selected."));
720
721         }
722         
723         return false;
724 }
725
726 function purgeSelectedFeeds() {
727
728         if (!xmlhttp_ready(xmlhttp)) {
729                 printLockingError();
730                 return
731         }
732
733         var sel_rows = getSelectedFeeds();
734
735         if (sel_rows.length > 0) {
736
737                 var pr = prompt(__("How many days of articles to keep (0 - use default)?"), "0");
738
739                 if (pr != undefined) {
740                         notify_progress("Purging selected feed...");
741
742                         var query = "backend.php?op=rpc&subop=purge&ids="+
743                                 param_escape(sel_rows.toString()) + "&days=" + pr;
744
745                         debug(query);
746
747                         new Ajax.Request(query, {
748                                 onComplete: function(transport) {
749                                         notify('');
750                                 } });
751                 }
752
753         } else {
754
755                 alert(__("No feeds are selected."));
756
757         }
758         
759         return false;
760 }
761
762 function removeSelectedFeedCats() {
763
764         if (!xmlhttp_ready(xmlhttp)) {
765                 printLockingError();
766                 return
767         }
768
769         var sel_rows = getSelectedFeedCats();
770
771         if (sel_rows.length > 0) {
772
773                 var ok = confirm(__("Remove selected categories?"));
774
775                 if (ok) {
776                         notify_progress("Removing selected categories...");
777         
778                         xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=editCats&action=remove&ids="+
779                                 param_escape(sel_rows.toString()), true);
780                         xmlhttp.onreadystatechange=infobox_callback;
781                         xmlhttp.send(null);
782                 }
783
784         } else {
785
786                 alert(__("No categories are selected."));
787
788         }
789
790         return false;
791 }
792
793 function feedEditCancel() {
794
795         if (!xmlhttp_ready(xmlhttp)) {
796                 printLockingError();
797                 return
798         }
799
800         try {
801                 document.getElementById("subscribe_to_feed_btn").disabled = false;
802                 document.getElementById("top25_feeds_btn").disabled = false;
803         } catch (e) {
804                 // this button is not always available, no-op if not found
805         }
806
807         closeInfoBox();
808
809         selectPrefRows('feed', false); // cleanup feed selection
810
811         return false;
812 }
813
814 function feedCatEditCancel() {
815
816         if (!xmlhttp_ready(xmlhttp)) {
817                 printLockingError();
818                 return
819         }
820
821         active_feed_cat = false;
822
823 //      notify("Operation cancelled.");
824
825         xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=editCats", true);
826         xmlhttp.onreadystatechange=infobox_callback;
827         xmlhttp.send(null);
828
829         return false;
830 }
831
832 function feedEditSave() {
833
834         try {
835         
836                 if (!xmlhttp_ready(xmlhttp)) {
837                         printLockingError();
838                         return
839                 }
840
841                 // FIXME: add parameter validation
842
843                 var query = Form.serialize("edit_feed_form");
844
845                 notify_progress("Saving feed...");
846
847                 xmlhttp.open("POST", "backend.php", true);
848                 xmlhttp.onreadystatechange=feedlist_callback;
849                 xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
850                 xmlhttp.send(query);
851
852                 closeInfoBox();
853
854                 return false;
855
856         } catch (e) {
857                 exception_error("feedEditSave", e);
858         } 
859 }
860
861 function feedCatEditSave() {
862
863         if (!xmlhttp_ready(xmlhttp)) {
864                 printLockingError();
865                 return
866         }
867
868         notify_progress("Saving category...");
869
870         var query = Form.serialize("feed_cat_edit_form");
871
872         xmlhttp.open("GET", "backend.php?" + query, true);
873         xmlhttp.onreadystatechange=infobox_callback;
874         xmlhttp.send(null);
875
876         active_feed_cat = false;
877
878         return false;
879 }
880
881 function labelEditCancel() {
882
883         if (!xmlhttp_ready(xmlhttp)) {
884                 printLockingError();
885                 return
886         }
887
888         try {
889                 document.getElementById("label_create_btn").disabled = false;
890                 selectPrefRows('label', false); // cleanup feed selection
891         } catch (e) { }
892
893         active_label = false;
894
895         closeInfoBox();
896
897         return false;
898 }
899
900 function userEditCancel() {
901
902         if (!xmlhttp_ready(xmlhttp)) {
903                 printLockingError();
904                 return
905         }
906
907         selectPrefRows('user', false); // cleanup feed selection
908         closeInfoBox();
909
910         return false;
911 }
912
913 function filterEditCancel() {
914
915         if (!xmlhttp_ready(xmlhttp)) {
916                 printLockingError();
917                 return
918         }
919
920         try {
921                 document.getElementById("create_filter_btn").disabled = false;
922                 selectPrefRows('filter', false); // cleanup feed selection
923         } catch (e) { }
924
925         closeInfoBox();
926
927         return false;
928 }
929
930 function labelEditSave() {
931
932         var label = active_label;
933
934         if (!xmlhttp_ready(xmlhttp)) {
935                 printLockingError();
936                 return
937         }
938
939 /*      if (!is_opera()) {
940
941                 var sql_exp = document.forms["label_edit_form"].sql_exp.value;
942                 var description = document.forms["label_edit_form"].description.value;
943         
944                 if (sql_exp.length == 0) {
945                         alert("SQL Expression cannot be blank.");
946                         return false;
947                 }
948         
949                 if (description.length == 0) {
950                         alert("Caption field cannot be blank.");
951                         return false;
952                 }
953         } */
954
955         closeInfoBox();
956
957         notify_progress("Saving label...");
958
959         active_label = false;
960
961         query = Form.serialize("label_edit_form");
962
963         xmlhttp.open("GET", "backend.php?" + query, true);              
964         xmlhttp.onreadystatechange=labellist_callback;
965         xmlhttp.send(null);
966
967         return false;
968 }
969
970 function userEditSave() {
971
972         if (!xmlhttp_ready(xmlhttp)) {
973                 printLockingError();
974                 return
975         }
976
977         var login = document.forms["user_edit_form"].login.value;
978
979         if (login.length == 0) {
980                 alert(__("Login field cannot be blank."));
981                 return;
982         }
983         
984         notify_progress("Saving user...");
985
986         closeInfoBox();
987
988         var query = Form.serialize("user_edit_form");
989         
990         xmlhttp.open("GET", "backend.php?" + query, true);                      
991         xmlhttp.onreadystatechange=userlist_callback;
992         xmlhttp.send(null);
993
994         return false;
995 }
996
997
998 function filterEditSave() {
999
1000         if (!xmlhttp_ready(xmlhttp)) {
1001                 printLockingError();
1002                 return
1003         }
1004
1005 /*      if (!is_opera()) {
1006                 var reg_exp = document.forms["filter_edit_form"].reg_exp.value;
1007         
1008                 if (reg_exp.length == 0) {
1009                         alert("Filter expression field cannot be blank.");
1010                         return;
1011                 }
1012         } */
1013
1014         notify_progress("Saving filter...");
1015
1016         var query = Form.serialize("filter_edit_form");
1017
1018         closeInfoBox();
1019
1020         document.getElementById("create_filter_btn").disabled = false;
1021
1022         xmlhttp.open("GET", "backend.php?" + query, true);
1023         xmlhttp.onreadystatechange=filterlist_callback;
1024         xmlhttp.send(null);
1025
1026         return false;
1027 }
1028
1029 function editSelectedLabel() {
1030         var rows = getSelectedLabels();
1031
1032         if (rows.length == 0) {
1033                 alert(__("No labels are selected."));
1034                 return;
1035         }
1036
1037         if (rows.length > 1) {
1038                 alert(__("Please select only one label."));
1039                 return;
1040         }
1041
1042         notify("");
1043
1044         editLabel(rows[0]);
1045
1046 }
1047
1048 function editSelectedUser() {
1049         var rows = getSelectedUsers();
1050
1051         if (rows.length == 0) {
1052                 alert(__("No users are selected."));
1053                 return;
1054         }
1055
1056         if (rows.length > 1) {
1057                 alert(__("Please select only one user."));
1058                 return;
1059         }
1060
1061         notify("");
1062
1063         editUser(rows[0]);
1064 }
1065
1066 function resetSelectedUserPass() {
1067         var rows = getSelectedUsers();
1068
1069         if (rows.length == 0) {
1070                 alert(__("No users are selected."));
1071                 return;
1072         }
1073
1074         if (rows.length > 1) {
1075                 alert(__("Please select only one user."));
1076                 return;
1077         }
1078
1079         var ok = confirm(__("Reset password of selected user?"));
1080
1081         if (ok) {
1082                 notify_progress("Resetting password for selected user...");
1083         
1084                 var id = rows[0];
1085         
1086                 xmlhttp.open("GET", "backend.php?op=pref-users&subop=resetPass&id=" +
1087                         param_escape(id), true);
1088                 xmlhttp.onreadystatechange=userlist_callback;
1089                 xmlhttp.send(null);
1090         }
1091 }
1092
1093 function selectedUserDetails() {
1094
1095         if (!xmlhttp_ready(xmlhttp)) {
1096                 printLockingError();
1097                 return
1098         }
1099
1100         var rows = getSelectedUsers();
1101
1102         if (rows.length == 0) {
1103                 alert(__("No users are selected."));
1104                 return;
1105         }
1106
1107         if (rows.length > 1) {
1108                 alert(__("Please select only one user."));
1109                 return;
1110         }
1111
1112         notify_progress("Loading, please wait...");
1113
1114         var id = rows[0];
1115
1116         xmlhttp.open("GET", "backend.php?op=user-details&id=" + id, true);
1117         xmlhttp.onreadystatechange=infobox_callback;
1118         xmlhttp.send(null);
1119
1120 }
1121
1122 function selectedFeedDetails() {
1123
1124         if (!xmlhttp_ready(xmlhttp)) {
1125                 printLockingError();
1126                 return
1127         }
1128
1129         var rows = getSelectedFeeds();
1130
1131         if (rows.length == 0) {
1132                 alert(__("No feeds are selected."));
1133                 return;
1134         }
1135
1136         if (rows.length > 1) {
1137                 alert(__("Please select only one feed."));
1138                 return;
1139         }
1140
1141 //      var id = rows[0];
1142
1143         notify("");
1144
1145         xmlhttp.open("GET", "backend.php?op=feed-details&id=" + 
1146                 param_escape(rows.toString()), true);
1147         xmlhttp.onreadystatechange=infobox_callback;
1148         xmlhttp.send(null);
1149
1150 }
1151
1152 function editSelectedFilter() {
1153         var rows = getSelectedFilters();
1154
1155         if (rows.length == 0) {
1156                 alert(__("No filters are selected."));
1157                 return;
1158         }
1159
1160         if (rows.length > 1) {
1161                 alert(__("Please select only one filter."));
1162                 return;
1163         }
1164
1165         notify("");
1166
1167         editFilter(rows[0]);
1168
1169 }
1170
1171
1172 function editSelectedFeed() {
1173         var rows = getSelectedFeeds();
1174
1175         if (rows.length == 0) {
1176                 alert(__("No feeds are selected."));
1177                 return;
1178         }
1179
1180         if (rows.length > 1) {
1181                 alert(__("Please select one feed."));
1182                 return;
1183         }
1184
1185         notify("");
1186
1187         editFeed(rows[0]);
1188
1189 }
1190
1191 function editSelectedFeedCat() {
1192         var rows = getSelectedFeedCats();
1193
1194         if (rows.length == 0) {
1195                 alert(__("No categories are selected."));
1196                 return;
1197         }
1198
1199         if (rows.length > 1) {
1200                 alert(__("Please select only one category."));
1201                 return;
1202         }
1203
1204         notify("");
1205
1206         editFeedCat(rows[0]);
1207
1208 }
1209
1210 function piggie(enable) {
1211         if (enable) {
1212                 debug("I LOVEDED IT!");
1213                 var piggie = document.getElementById("piggie");
1214
1215                 Element.show(piggie);
1216                 Position.Center(piggie);
1217                 Effect.Puff(piggie);
1218
1219         }
1220 }
1221
1222 function validateOpmlImport() {
1223         
1224         var opml_file = document.getElementById("opml_file");
1225
1226         if (opml_file.value.length == 0) {
1227                 alert(__("No OPML file to upload."));
1228                 return false;
1229         } else {
1230                 return true;
1231         }
1232 }
1233
1234 function updateFilterList(sort_key) {
1235
1236         if (!xmlhttp_ready(xmlhttp)) {
1237                 printLockingError();
1238                 return
1239         }
1240
1241         var filter_search = document.getElementById("filter_search");
1242         var search = "";
1243         if (filter_search) { search = filter_search.value; }
1244
1245         xmlhttp.open("GET", "backend.php?op=pref-filters&sort=" + 
1246                 param_escape(sort_key) + 
1247                 "&search=" + param_escape(search), true);
1248         xmlhttp.onreadystatechange=filterlist_callback;
1249         xmlhttp.send(null);
1250
1251 }
1252
1253 function updateLabelList(sort_key) {
1254
1255         if (!xmlhttp_ready(xmlhttp)) {
1256                 printLockingError();
1257                 return
1258         }
1259
1260         var label_search = document.getElementById("label_search");
1261         var search = "";
1262         if (label_search) { search = label_search.value; }
1263
1264         xmlhttp.open("GET", "backend.php?op=pref-labels&sort=" + 
1265                 param_escape(sort_key) +
1266                 "&search=" + param_escape(search), true);
1267         xmlhttp.onreadystatechange=labellist_callback;
1268         xmlhttp.send(null);
1269 }
1270
1271 function updatePrefsList() {
1272
1273         if (!xmlhttp_ready(xmlhttp)) {
1274                 printLockingError();
1275                 return
1276         }
1277
1278         xmlhttp.open("GET", "backend.php?op=pref-prefs", true);
1279         xmlhttp.onreadystatechange=prefslist_callback;
1280         xmlhttp.send(null);
1281
1282 }
1283
1284 function selectTab(id, noupdate, subop) {
1285
1286 //      alert(id);
1287
1288         if (!id) id = active_tab;
1289
1290         try {
1291
1292                 if (!xmlhttp_ready(xmlhttp)) {
1293                         printLockingError();
1294                         return
1295                 }
1296
1297                 try {
1298                         var c = document.getElementById('prefContent'); 
1299                         c.scrollTop = 0;
1300                 } catch (e) { };
1301
1302                 if (!noupdate) {
1303
1304                         debug("selectTab: " + id + "(NU: " + noupdate + ")");
1305         
1306                         notify_progress("Loading, please wait...");
1307         
1308                         // close active infobox if needed
1309                         closeInfoBox();
1310         
1311                         // clean up all current selections, just in case
1312                         active_feed_cat = false;
1313                         active_label = false;
1314
1315 //                      Effect.Fade("prefContent", {duration: 1, to: 0.01, 
1316 //                              queue: { position:'end', scope: 'FEED_TAB', limit: 1 } } );
1317
1318                         if (id == "feedConfig") {
1319                                 updateFeedList();
1320                         } else if (id == "filterConfig") {
1321                                 updateFilterList();
1322                         } else if (id == "labelConfig") {
1323                                 updateLabelList();
1324                         } else if (id == "genConfig") {
1325                                 updatePrefsList();
1326                         } else if (id == "userConfig") {
1327                                 updateUsersList();
1328                         } else if (id == "feedBrowser") {
1329                                 updateBigFeedBrowser();
1330                         }
1331                 }
1332
1333                 /* clean selection from all tabs */
1334         
1335                 var tabs_holder = document.getElementById("prefTabs");
1336                 var tab = tabs_holder.firstChild;
1337
1338                 while (tab) {
1339                         if (tab.className && tab.className.match("prefsTabSelected")) {
1340                                 tab.className = "prefsTab";
1341                         }
1342                         tab = tab.nextSibling;
1343                 }
1344
1345                 /* mark new tab as selected */
1346
1347                 tab = document.getElementById(id + "Tab");
1348         
1349                 if (tab) {
1350                         if (!tab.className.match("Selected")) {
1351                                 tab.className = tab.className + "Selected";
1352                         }
1353                 }
1354         
1355                 active_tab = id;
1356
1357         } catch (e) {
1358                 exception_error("selectTab", e);
1359         }
1360 }
1361
1362 function backend_sanity_check_callback() {
1363
1364         if (xmlhttp.readyState == 4) {
1365
1366                 try {
1367
1368                         if (sanity_check_done) {
1369                                 fatalError(11, "Sanity check request received twice. This can indicate "+
1370                               "presence of Firebug or some other disrupting extension. "+
1371                                         "Please disable it and try again.");
1372                                 return;
1373                         }
1374
1375                         if (!xmlhttp.responseXML) {
1376                                 fatalError(3, "[D001, Received reply is not XML]: " + xmlhttp.responseText);
1377                                 return;
1378                         }
1379         
1380                         var reply = xmlhttp.responseXML.firstChild.firstChild;
1381         
1382                         if (!reply) {
1383                                 fatalError(3, "[D002, Invalid RPC reply]: " + xmlhttp.responseText);
1384                                 return;
1385                         }
1386         
1387                         var error_code = reply.getAttribute("error-code");
1388                 
1389                         if (error_code && error_code != 0) {
1390                                 return fatalError(error_code, reply.getAttribute("error-msg"));
1391                         }
1392         
1393                         debug("sanity check ok");
1394
1395                         var params = reply.nextSibling;
1396
1397                         if (params) {
1398                                 debug('reading init-params...');
1399                                 var param = params.firstChild;
1400
1401                                 while (param) {
1402                                         var k = param.getAttribute("key");
1403                                         var v = param.getAttribute("value");
1404                                         debug(k + " => " + v);
1405                                         init_params[k] = v;                                     
1406                                         param = param.nextSibling;
1407                                 }
1408                         }
1409
1410                         sanity_check_done = true;
1411
1412                         init_second_stage();
1413
1414                 } catch (e) {
1415                         exception_error("backend_sanity_check_callback", e);
1416                 }
1417         } 
1418 }
1419
1420 function init_second_stage() {
1421
1422         try {
1423                 active_tab = getInitParam("prefs_active_tab");
1424                 if (!active_tab || active_tab == '0') active_tab = "genConfig";
1425
1426                 document.onkeydown = pref_hotkey_handler;
1427
1428                 var tab = getURLParam('tab');
1429                 
1430                 caller_subop = getURLParam('subop');
1431
1432                 if (tab) {
1433                         active_tab = tab;
1434                 }
1435
1436                 if (navigator.userAgent.match("Opera")) {       
1437                         setTimeout("selectTab()", 500);
1438                 } else {
1439                         selectTab(active_tab);
1440                 }
1441                 notify("");
1442
1443                 loading_set_progress(60);
1444
1445         } catch (e) {
1446                 exception_error("init_second_stage", e);
1447         }
1448 }
1449
1450 function init() {
1451
1452         try {
1453         
1454                 if (arguments.callee.done) return;
1455                 arguments.callee.done = true;           
1456
1457                 if (getURLParam('debug')) {
1458                         Element.show("debug_output");
1459                         debug('debug mode activated');
1460                 }
1461
1462                 new Draggable('debug_output');
1463
1464                 // IE kludge
1465                 if (!xmlhttp) {
1466                         document.getElementById("prefContent").innerHTML = 
1467                                 "<b>Fatal error:</b> This program needs XmlHttpRequest " + 
1468                                 "to function properly. Your browser doesn't seem to support it.";
1469                         return;
1470                 }
1471
1472                 loading_set_progress(30);
1473
1474                 xmlhttp.open("GET", "backend.php?op=rpc&subop=sanityCheck", true);
1475                 xmlhttp.onreadystatechange=backend_sanity_check_callback;
1476                 xmlhttp.send(null);
1477
1478         } catch (e) {
1479                 exception_error("init", e);
1480         }
1481 }
1482
1483 function categorizeSelectedFeeds() {
1484
1485         if (!xmlhttp_ready(xmlhttp)) {
1486                 printLockingError();
1487                 return
1488         }
1489
1490         var sel_rows = getSelectedFeeds();
1491
1492         var cat_sel = document.getElementById("sfeed_set_fcat");
1493         var cat_id = cat_sel[cat_sel.selectedIndex].value;
1494
1495         if (sel_rows.length > 0) {
1496
1497                 notify_progress("Changing category of selected feeds...");
1498
1499                 xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=categorize&ids="+
1500                         param_escape(sel_rows.toString()) + "&cat_id=" + param_escape(cat_id), true);
1501                 xmlhttp.onreadystatechange=feedlist_callback;
1502                 xmlhttp.send(null);
1503
1504         } else {
1505
1506                 alert(__("No feeds are selected."));
1507
1508         }
1509
1510 }
1511
1512 function validatePrefsReset() {
1513         try {
1514                 var ok = confirm(__("Reset to defaults?"));
1515
1516                 if (ok) {
1517
1518                         var query = Form.serialize("pref_prefs_form");
1519                         query = query + "&subop=reset-config";
1520                         debug(query);
1521
1522                         xmlhttp.open("POST", "backend.php", true);
1523                         xmlhttp.onreadystatechange=prefs_reset_callback;
1524                         xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
1525                         xmlhttp.send(query);
1526                 }
1527
1528         } catch (e) {
1529                 exception_error("validatePrefsSave", e);
1530         }
1531
1532         return false;
1533
1534 }
1535
1536 function browseFeeds(limit) {
1537
1538         xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=browse", true);
1539         xmlhttp.onreadystatechange=infobox_callback;
1540         xmlhttp.send(null);
1541
1542 }
1543
1544 function feedBrowserSubscribe() {
1545         try {
1546
1547                 var selected = getSelectedFeedsFromBrowser();
1548
1549                 if (selected.length > 0) {
1550                         closeInfoBox();
1551                         xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=massSubscribe&ids="+
1552                                 param_escape(selected.toString()), true);
1553                         xmlhttp.onreadystatechange=feedlist_callback;
1554                         xmlhttp.send(null);
1555                 } else {
1556                         alert(__("No feeds are selected."));
1557                 }
1558
1559         } catch (e) {
1560                 exception_error("feedBrowserSubscribe", e);
1561         }
1562 }
1563
1564 function updateBigFeedBrowser(limit) {
1565
1566         if (!xmlhttp_ready(xmlhttp)) {
1567                 printLockingError();
1568                 return
1569         }
1570
1571         var query = "backend.php?op=pref-feed-browser";
1572
1573         var limit_sel = document.getElementById("feedBrowserLimit");
1574
1575         if (limit_sel) {
1576                 var limit = limit_sel[limit_sel.selectedIndex].value;
1577                 query = query + "&limit=" + param_escape(limit);
1578         }
1579
1580         xmlhttp.open("GET", query, true);
1581         xmlhttp.onreadystatechange=feed_browser_callback;
1582         xmlhttp.send(null);
1583 }
1584
1585 function browserToggleExpand(id) {
1586         try {
1587 /*              if (feed_to_expand && feed_to_expand != id) {
1588                         var d = document.getElementById("BRDET-" + feed_to_expand);
1589                         d.style.display = "none";
1590                 } */
1591
1592                 if (!xmlhttp_ready(xmlhttp)) {
1593                         printLockingError();
1594                         return
1595                 }
1596
1597 /*              if (feed_to_expand && id != feed_to_expand) {
1598                         Effect.Fade('BRDET-' + feed_to_expand, {duration : 0.5});
1599                 } */
1600
1601                 var d = document.getElementById("BRDET-" + id);
1602         
1603                 if (Element.visible(d)) {
1604                         Effect.Fade(d, {duration : 0.5});
1605                 } else {
1606                         feed_to_expand = id;
1607
1608                         xmlhttp.open("GET", "backend.php?op=pref-feed-browser&subop=details&id="
1609                                 + param_escape(id), true);
1610                         xmlhttp.onreadystatechange=expand_feed_callback;
1611                         xmlhttp.send(null);
1612                 }
1613
1614         } catch (e) {
1615                 exception_error("browserToggleExpand", e);
1616         }
1617 }
1618
1619 function selectPrefRows(kind, select) {
1620
1621         if (kind) {
1622                 var opbarid = false;    
1623                 var nchk = false;
1624                 var nrow = false;
1625                 var lname = false;
1626
1627                 if (kind == "feed") {
1628                         opbarid = "feedOpToolbar";
1629                         nrow = "FEEDR-";
1630                         nchk = "FRCHK-";                        
1631                         lname = "prefFeedList";
1632                 } else if (kind == "fcat") {
1633                         opbarid = "catOpToolbar";
1634                         nrow = "FCATR-";
1635                         nchk = "FCCHK-";
1636                         lname = "prefFeedCatList";
1637                 } else if (kind == "filter") {
1638                         opbarid = "filterOpToolbar";
1639                         nrow = "FILRR-";
1640                         nchk = "FICHK-";
1641                         lname = "prefFilterList";
1642                 } else if (kind == "label") {
1643                         opbarid = "labelOpToolbar";
1644                         nrow = "LILRR-";
1645                         nchk = "LICHK-";
1646                         lname = "prefLabelList";
1647                 } else if (kind == "user") {
1648                         opbarid = "userOpToolbar";
1649                         nrow = "UMRR-";
1650                         nchk = "UMCHK-";
1651                         lname = "prefUserList";
1652                 }
1653
1654                 if (opbarid) {
1655                         selectTableRowsByIdPrefix(lname, nrow, nchk, select);
1656                         disableContainerChildren(opbarid, !select);
1657                 }
1658
1659         } 
1660 }
1661
1662
1663 function toggleSelectPrefRow(sender, kind) {
1664
1665         toggleSelectRow(sender);
1666
1667         if (kind) {
1668                 var opbarid = false;    
1669                 var nsel = -1;
1670                 
1671                 if (kind == "feed") {
1672                         opbarid = "feedOpToolbar";
1673                         nsel = getSelectedFeeds();
1674                 } else if (kind == "fcat") {
1675                         opbarid = "catOpToolbar";
1676                         nsel = getSelectedFeedCats();
1677                 } else if (kind == "filter") {
1678                         opbarid = "filterOpToolbar";
1679                         nsel = getSelectedFilters();
1680                 } else if (kind == "label") {
1681                         opbarid = "labelOpToolbar";
1682                         nsel = getSelectedLabels();
1683                 } else if (kind == "user") {
1684                         opbarid = "userOpToolbar";
1685                         nsel = getSelectedUsers();
1686                 }
1687
1688                 if (opbarid && nsel != -1) {
1689                         disableContainerChildren(opbarid, nsel == false);
1690                 }
1691
1692         } 
1693 }
1694
1695 function toggleSelectFBListRow(sender) {
1696         toggleSelectListRow(sender);
1697         disableContainerChildren("fbrOpToolbar", getSelectedFeedsFromBrowser() == 0);
1698 }
1699
1700 var seq = "";
1701
1702 function pref_hotkey_handler(e) {
1703         try {
1704
1705                 var keycode;
1706                 var shift_key = false;
1707
1708                 try {
1709                         shift_key = e.shiftKey;
1710                 } catch (e) {
1711
1712                 }
1713
1714                 if (window.event) {
1715                         keycode = window.event.keyCode;
1716                 } else if (e) {
1717                         keycode = e.which;
1718                 }
1719
1720                 var keychar = String.fromCharCode(keycode);
1721
1722                 if (keycode == 27) { // escape
1723                         if (Element.visible("hotkey_help_overlay")) {
1724                                 Element.hide("hotkey_help_overlay");
1725                         }
1726                         hotkey_prefix = false;
1727                         closeInfoBox();
1728                 } 
1729
1730                 if (!hotkeys_enabled) {
1731                         debug("hotkeys disabled");
1732                         return;
1733                 }
1734
1735                 if (keycode == 16) return; // ignore lone shift
1736
1737                 if ((keycode == 67 || keycode == 71) && !hotkey_prefix) {
1738                         hotkey_prefix = keycode;
1739                         debug("KP: PREFIX=" + keycode + " CHAR=" + keychar);
1740                         return;
1741                 }
1742
1743                 if (Element.visible("hotkey_help_overlay")) {
1744                         Element.hide("hotkey_help_overlay");
1745                 }
1746
1747                 if (keycode == 13 || keycode == 27) {
1748                         seq = "";
1749                 } else {
1750                         seq = seq + "" + keycode;
1751                 }
1752
1753                 /* Global hotkeys */
1754
1755                 if (!hotkey_prefix) {
1756
1757                         if (keycode == 68 && shift_key) { // d
1758                                 if (!Element.visible("debug_output")) {
1759                                         Element.show("debug_output");
1760                                         debug('debug mode activated');
1761                                 } else {
1762                                         Element.hide("debug_output");
1763                                 }
1764                                 return;
1765                         }
1766         
1767                         if ((keycode == 191 || keychar == '?') && shift_key) { // ?
1768                                 if (!Element.visible("hotkey_help_overlay")) {
1769                                         //Element.show("hotkey_help_overlay");
1770                                         Effect.Appear("hotkey_help_overlay", {duration : 0.3});
1771                                 } else {
1772                                         Element.hide("hotkey_help_overlay");
1773                                 }
1774                                 return false;
1775                         }
1776
1777                         if (keycode == 191 || keychar == '/') { // /
1778                                 var search_boxes = new Array("label_search", 
1779                                         "feed_search", "filter_search", "user_search");
1780
1781                                 for (var i = 0; i < search_boxes.length; i++) {
1782                                         var elem = document.getElementById(search_boxes[i]);
1783                                         if (elem) {
1784                                                 focus_element(search_boxes[i]);
1785                                                 return false;
1786                                         }
1787                                 }
1788                         }
1789                 }
1790
1791                 /* Prefix c */
1792
1793                 if (hotkey_prefix == 67) { // c
1794                         hotkey_prefix = false;
1795
1796                         if (keycode == 70) { // f
1797                                 displayDlg("quickAddFilter");
1798                                 return false;
1799                         }
1800
1801                         if (keycode == 83) { // s
1802                                 displayDlg("quickAddFeed");
1803                                 return false;
1804                         }
1805
1806                         if (keycode == 76) { // l
1807                                 displayDlg("quickAddLabel");
1808                                 return false;
1809                         }
1810
1811                         if (keycode == 85) { // u
1812                                 // no-op
1813                         }
1814
1815                         if (keycode == 67) { // c
1816                                 editFeedCats();
1817                                 return false;
1818                         }
1819
1820                         if (keycode == 84 && shift_key) { // T
1821                                 browseFeeds();
1822                                 return false;
1823                         }
1824
1825                 }
1826
1827                 /* Prefix g */
1828
1829                 if (hotkey_prefix == 71) { // g
1830
1831                         hotkey_prefix = false;
1832
1833                         if (keycode == 49 && document.getElementById("genConfigTab")) { // 1
1834                                 selectTab("genConfig");
1835                                 return false;
1836                         }
1837
1838                         if (keycode == 50 && document.getElementById("feedConfigTab")) { // 2
1839                                 selectTab("feedConfig");
1840                                 return false;
1841                         }
1842
1843                         if (keycode == 51 && document.getElementById("feedBrowserTab")) { // 3
1844                                 selectTab("feedBrowser");
1845                                 return false;
1846                         }
1847
1848                         if (keycode == 52 && document.getElementById("filterConfigTab")) { // 4
1849                                 selectTab("filterConfig");
1850                                 return false;
1851                         }
1852
1853                         if (keycode == 53 && document.getElementById("labelConfigTab")) { // 5
1854                                 selectTab("labelConfig");
1855                                 return false;
1856                         }
1857
1858                         if (keycode == 54 && document.getElementById("userConfigTab")) { // 6
1859                                 selectTab("userConfig");
1860                                 return false;
1861                         }
1862
1863                         if (keycode == 88) { // x
1864                                 return gotoMain();
1865                         }
1866
1867                 }
1868
1869                 if (document.getElementById("piggie")) {
1870         
1871                         if (seq.match("807371717369")) {
1872                                 seq = "";
1873                                 piggie(true);
1874                         } else {
1875                                 piggie(false);
1876                         }
1877                 }
1878
1879                 if (hotkey_prefix) {
1880                         debug("KP: PREFIX=" + hotkey_prefix + " CODE=" + keycode + " CHAR=" + keychar);
1881                 } else {
1882                         debug("KP: CODE=" + keycode + " CHAR=" + keychar);
1883                 }
1884
1885         } catch (e) {
1886                 exception_error("pref_hotkey_handler", e);
1887         }
1888 }
1889
1890 function editFeedCats() {
1891         if (!xmlhttp_ready(xmlhttp)) {
1892                 printLockingError();
1893                 return
1894         }
1895
1896         document.getElementById("subscribe_to_feed_btn").disabled = true;
1897
1898         try {
1899                 document.getElementById("top25_feeds_btn").disabled = true;
1900         } catch (e) {
1901                 // this button is not always available, no-op if not found
1902         }
1903
1904         xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=editCats", true);
1905         xmlhttp.onreadystatechange=infobox_feed_cat_callback;
1906         xmlhttp.send(null);
1907 }
1908
1909 function showFeedsWithErrors() {
1910         displayDlg('feedUpdateErrors');
1911 }
1912
1913 function changeUserPassword() {
1914
1915         try {
1916
1917                 if (!xmlhttp_ready(xmlhttp)) {
1918                         printLockingError();
1919                         return false;
1920                 }
1921         
1922                 var f = document.forms["change_pass_form"];
1923
1924                 if (f) {
1925                         if (f.OLD_PASSWORD.value == "") {
1926                                 new Effect.Highlight(f.OLD_PASSWORD);
1927                                 notify_error("Old password cannot be blank.");
1928                                 return false;
1929                         }
1930
1931                         if (f.NEW_PASSWORD.value == "") {
1932                                 new Effect.Highlight(f.NEW_PASSWORD);
1933                                 notify_error("New password cannot be blank.");
1934                                 return false;
1935                         }
1936
1937                         if (f.CONFIRM_PASSWORD.value == "") {
1938                                 new Effect.Highlight(f.CONFIRM_PASSWORD);
1939                                 notify_error("Entered passwords do not match.");
1940                                 return false;
1941                         }
1942
1943                         if (f.CONFIRM_PASSWORD.value != f.NEW_PASSWORD.value) {
1944                                 new Effect.Highlight(f.CONFIRM_PASSWORD);
1945                                 new Effect.Highlight(f.NEW_PASSWORD);
1946                                 notify_error("Entered passwords do not match.");
1947                                 return false;
1948                         }
1949
1950                 }
1951
1952                 var query = Form.serialize("change_pass_form");
1953         
1954                 notify_progress("Trying to change password...");
1955         
1956                 xmlhttp.open("POST", "backend.php", true);
1957                 xmlhttp.onreadystatechange=changepass_callback;
1958                 xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
1959                 xmlhttp.send(query);
1960
1961         } catch (e) {
1962                 exception_error("changeUserPassword", e);
1963         }
1964         
1965         return false;
1966 }
1967
1968 function changeUserEmail() {
1969
1970         try {
1971
1972                 if (!xmlhttp_ready(xmlhttp)) {
1973                         printLockingError();
1974                         return false;
1975                 }
1976         
1977                 var query = Form.serialize("change_email_form");
1978         
1979                 notify_progress("Trying to change e-mail...");
1980         
1981                 xmlhttp.open("POST", "backend.php", true);
1982                 xmlhttp.onreadystatechange=notify_callback;
1983                 xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
1984                 xmlhttp.send(query);
1985
1986         } catch (e) {
1987                 exception_error("changeUserPassword", e);
1988         }
1989         
1990         return false;
1991
1992 }
1993
1994 function feedlistToggleSLAT() {
1995         notify_progress("Loading, please wait...");
1996         updateFeedList()
1997 }
1998
1999 function pubRegenKey() {
2000
2001         if (!xmlhttp_ready(xmlhttp)) {
2002                 printLockingError();
2003                 return false;
2004         }
2005
2006         var ok = confirm(__("Replace current publishing address with a new one?"));
2007
2008         if (ok) {
2009
2010                 notify_progress("Trying to change address...");
2011
2012                 xmlhttp.open("GET", "backend.php?op=rpc&subop=regenPubKey");
2013                 xmlhttp.onreadystatechange=replace_pubkey_callback;
2014                 xmlhttp.send(null);
2015         }
2016
2017         return false;
2018 }
2019
2020 function pubToClipboard() {
2021
2022         try {
2023
2024                 if (!xmlhttp_ready(xmlhttp)) {
2025                         printLockingError();
2026                         return false;
2027                 }
2028         
2029                 var link = document.getElementById("pubGenAddress");
2030                 alert(link.href);
2031
2032         } catch (e) {
2033                 exception_error("pubToClipboard", e);
2034         }
2035
2036         return false; 
2037 }
2038
2039 function validatePrefsSave() {
2040         try {
2041
2042                 var ok = confirm(__("Save current configuration?"));
2043
2044                 if (ok) {
2045
2046                         var query = Form.serialize("pref_prefs_form");
2047                         query = query + "&subop=save-config";
2048                         debug(query);
2049
2050                         xmlhttp.open("POST", "backend.php", true);
2051                         xmlhttp.onreadystatechange=notify_callback;
2052                         xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2053                         xmlhttp.send(query);
2054                 }
2055
2056         } catch (e) {
2057                 exception_error("validatePrefsSave", e);
2058         }
2059
2060         return false;
2061 }
2062
2063 function feedActionChange() {
2064         try {
2065                 var chooser = document.getElementById("feedActionChooser");
2066                 var opid = chooser[chooser.selectedIndex].value;
2067
2068                 chooser.selectedIndex = 0;
2069                 feedActionGo(opid);
2070         } catch (e) {
2071                 exception_error("feedActionChange", e);
2072         }
2073 }
2074
2075 function feedActionGo(op) {     
2076         try {
2077                 if (op == "facEdit") {
2078                         editSelectedFeed();
2079                 }
2080
2081                 if (op == "facClear") {
2082                         clearSelectedFeeds();
2083                 }
2084
2085                 if (op == "facPurge") {
2086                         purgeSelectedFeeds();
2087                 }
2088
2089                 if (op == "facEditCats") {
2090                         editFeedCats();
2091                 }
2092
2093                 if (op == "facRescore") {
2094                         rescoreSelectedFeeds();
2095                 }
2096
2097                 if (op == "facUnsubscribe") {
2098                         removeSelectedFeeds();
2099                 }
2100
2101         } catch (e) {
2102                 exception_error("feedActionGo", e);
2103
2104         }
2105 }
2106
2107 function clearFeedArticles(feed_id) {
2108
2109         notify_progress("Clearing feed...");
2110
2111         var query = "backend.php?op=pref-feeds&quiet=1&subop=clear&id=" + feed_id;
2112
2113         new Ajax.Request(query, {
2114                 onComplete: function(transport) {
2115                                 notify('');
2116                         } });
2117
2118         return false;
2119 }
2120
2121 function rescoreSelectedFeeds() {
2122
2123         if (!xmlhttp_ready(xmlhttp)) {
2124                 printLockingError();
2125                 return
2126         }
2127
2128         var sel_rows = getSelectedFeeds();
2129
2130         if (sel_rows.length > 0) {
2131
2132                 //var ok = confirm(__("Rescore last 100 articles in selected feeds?"));
2133                 var ok = confirm(__("Rescore articles in selected feeds?"));
2134
2135                 if (ok) {
2136                         notify_progress("Rescoring selected feeds...");
2137         
2138                         xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=rescore&quiet=1&ids="+
2139                                 param_escape(sel_rows.toString()), true);
2140                         xmlhttp.onreadystatechange=notify_callback;
2141                         xmlhttp.send(null);
2142                 }
2143         } else {
2144                 alert(__("No feeds are selected."));
2145         }
2146
2147         return false;
2148 }
2149
2150 function rescore_all_feeds() {
2151                 var ok = confirm(__("Rescore all articles? This operation may take a lot of time."));
2152
2153                 if (ok) {
2154                         notify_progress("Rescoring feeds...");
2155
2156                         xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=rescoreAll&quiet=1", true);
2157                         xmlhttp.onreadystatechange=notify_callback;
2158                         xmlhttp.send(null);
2159                 }
2160 }