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