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