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