]> git.wh0rd.org Git - tt-rss.git/blob - prefs.js
rework user CSS support (bump schema)
[tt-rss.git] / prefs.js
1 var init_params = new Array();
2
3 var caller_subop = false;
4 var hotkey_prefix = false;
5 var hotkey_prefix_pressed = false;
6
7 var seq = "";
8
9 function feedlist_callback2(transport) {
10
11         try {   
12
13                 dijit.byId('feedConfigTab').attr('content', transport.responseText); 
14
15                 selectTab("feedConfig", true);
16
17                 if (caller_subop) {
18                         var tuple = caller_subop.split(":");
19                         if (tuple[0] == 'editFeed') {
20                                 window.setTimeout('editFeed('+tuple[1]+')', 100);
21                         }                               
22
23                         caller_subop = false;
24                 }
25                 notify("");
26
27         } catch (e) {
28                 exception_error("feedlist_callback2", e);
29         }
30 }
31
32 function filterlist_callback2(transport) {
33         dijit.byId('filterConfigTab').attr('content', transport.responseText); 
34         notify("");
35 }
36
37 function labellist_callback2(transport) {
38         try {
39                 dijit.byId('labelConfigTab').attr('content', transport.responseText); 
40                 notify("");
41         } catch (e) {
42                 exception_error("labellist_callback2", e);
43         }
44 }
45
46 function userlist_callback2(transport) {
47         try {
48                 dijit.byId('userConfigTab').attr('content', transport.responseText); 
49
50                 notify("");
51         } catch (e) {
52                 exception_error("userlist_callback2", e);
53         }
54 }
55
56 function prefslist_callback2(transport) {
57         try {
58                 dijit.byId('genConfigTab').attr('content', transport.responseText); 
59
60                 notify("");
61         } catch (e) {
62                 exception_error("prefslist_callback2", e);
63         }
64 }
65
66 function notify_callback2(transport) {
67         notify_info(transport.responseText);     
68 }
69
70 function updateFeedList(sort_key) {
71         new Ajax.Request("backend.php", {
72                 parameters: "?op=pref-feeds",
73                 onComplete: function(transport) { 
74                         feedlist_callback2(transport); 
75                 } });
76 }
77
78 function updateUsersList(sort_key) {
79
80         try {
81
82                 var user_search = $("user_search");
83                 var search = "";
84                 if (user_search) { search = user_search.value; }
85         
86                 var query = "?op=pref-users&sort="
87                         + param_escape(sort_key) +
88                         "&search=" + param_escape(search);
89         
90                 new Ajax.Request("backend.php", {
91                         parameters: query,
92                         onComplete: function(transport) { 
93                                 userlist_callback2(transport); 
94                         } });
95
96         } catch (e) {
97                 exception_error("updateUsersList", e);
98         }
99 }
100
101 function addUser() {
102
103         try {
104
105                 var login = prompt(__("Please enter login:"), "");
106         
107                 if (login == null) { 
108                         return false;
109                 }
110         
111                 if (login == "") {
112                         alert(__("Can't create user: no login specified."));
113                         return false;
114                 }
115         
116                 notify_progress("Adding user...");
117         
118                 var query = "?op=pref-users&subop=add&login=" +
119                         param_escape(login);
120                                 
121                 new Ajax.Request("backend.php", {
122                         parameters: query,
123                         onComplete: function(transport) { 
124                                 userlist_callback2(transport); 
125                         } });
126
127         } catch (e) {
128                 exception_error("addUser", e);
129         }
130 }
131
132 function editUser(id, event) {
133
134         try {
135                 if (!event || !event.ctrlKey) {
136
137                 notify_progress("Loading, please wait...");
138
139                 selectTableRows('prefUserList', 'none');
140                 selectTableRowById('UMRR-'+id, 'UMCHK-'+id, true);
141
142                 var query = "?op=pref-users&subop=edit&id=" +
143                         param_escape(id);
144
145                 new Ajax.Request("backend.php", {
146                         parameters: query,
147                         onComplete: function(transport) {
148                                         infobox_callback2(transport);
149                                         document.forms['user_edit_form'].login.focus(); 
150                                 } });
151
152                 } else if (event.ctrlKey) {
153                         var cb = $('UMCHK-' + id);
154                         cb.checked = !cb.checked;
155                         toggleSelectRow(cb);
156                 }
157
158         } catch (e) {
159                 exception_error("editUser", e);
160         }
161                 
162 }
163
164 function editFilter(id) {
165         try {
166
167                 var query = "backend.php?op=pref-filters&subop=edit&id=" + param_escape(id);
168
169                 if (dijit.byId("filterEditDlg"))
170                         dijit.byId("filterEditDlg").destroyRecursive();
171
172                 dialog = new dijit.Dialog({
173                         id: "filterEditDlg",
174                         title: __("Edit Filter"),
175                         style: "width: 600px",
176                         removeFilter: function() {
177                                 var title = this.attr('value').reg_exp;
178                                 var msg = __("Remove filter %s?").replace("%s", title);
179                 
180                                 if (confirm(msg)) {
181                                         this.hide();
182
183                                         notify_progress("Removing filter...");
184                 
185                                         var id = this.attr('value').id;
186
187                                         var query = "?op=pref-filters&subop=remove&ids="+
188                                                 param_escape(id);
189
190                                         new Ajax.Request("backend.php", {
191                                                 parameters: query,
192                                                 onComplete: function(transport) {
193                                                         updateFilterList();
194                                                 } });
195                                 }
196                         },
197
198                         execute: function() {
199                                 if (this.validate()) {
200
201                                         var query = "?op=rpc&subop=verifyRegexp&reg_exp=" + 
202                                                 param_escape(dialog.attr('value').reg_exp);
203
204                                         notify_progress("Verifying regular expression...");
205
206                                         new Ajax.Request("backend.php", {
207                                                 parameters: query,
208                                                 onComplete: function(transport) {
209                                                         handle_rpc_reply(transport);
210                                                         var response = transport.responseXML;
211
212                                                         if (response) {
213                                                                 var s = response.getElementsByTagName("status")[0].firstChild.nodeValue;
214         
215                                                                 notify('');
216
217                                                                 if (s == "INVALID") {
218                                                                         alert("Match regular expression seems to be invalid.");
219                                                                         return;
220                                                                 } else {
221                                                                         notify_progress("Saving data...", true);
222
223                                                                         console.log(dojo.objectToQuery(dialog.attr('value')));
224
225                                                                         new Ajax.Request("backend.php", {
226                                                                                 parameters: dojo.objectToQuery(dialog.attr('value')),
227                                                                                 onComplete: function(transport) {
228                                                                                         dialog.hide();
229                                                                                         updateFilterList();                             
230                                                                         }})
231                                                                 }       
232                                                         }
233                                         }});
234                                 }
235                         },
236                         href: query});
237
238                 dialog.show();
239
240
241         } catch (e) {
242                 exception_error("editFilter", e);
243         }
244 }
245
246 function getSelectedLabels() {
247         var tree = dijit.byId("labelTree");
248         var items = tree.model.getCheckedItems();
249         var rv = [];
250
251         items.each(function(item) {
252                 rv.push(tree.model.store.getValue(item, 'bare_id'));
253         });
254
255         return rv;
256 }
257
258 function getSelectedUsers() {
259         return getSelectedTableRowIds("prefUserList");
260 }
261
262 function getSelectedFeeds() {
263         var tree = dijit.byId("feedTree");
264         var items = tree.model.getCheckedItems();
265         var rv = [];
266
267         items.each(function(item) {
268                 rv.push(tree.model.store.getValue(item, 'bare_id'));
269         });
270
271         return rv;
272 }
273
274 function getSelectedFilters() {
275         var tree = dijit.byId("filterTree");
276         var items = tree.model.getCheckedItems();
277         var rv = [];
278
279         items.each(function(item) {
280                 rv.push(tree.model.store.getValue(item, 'bare_id'));
281         });
282
283         return rv;
284
285 }
286
287 /* function getSelectedFeedCats() {
288         return getSelectedTableRowIds("prefFeedCatList");
289 } */
290
291 function removeSelectedLabels() {
292
293         var sel_rows = getSelectedLabels();
294
295         if (sel_rows.length > 0) {
296
297                 var ok = confirm(__("Remove selected labels?"));
298
299                 if (ok) {
300                         notify_progress("Removing selected labels...");
301         
302                         var query = "?op=pref-labels&subop=remove&ids="+
303                                 param_escape(sel_rows.toString());
304
305                         new Ajax.Request("backend.php", {
306                                 parameters: query,
307                                 onComplete: function(transport) {
308                                                 labellist_callback2(transport);
309                                         } });
310
311                 }
312         } else {
313                 alert(__("No labels are selected."));
314         }
315
316         return false;
317 }
318
319 function removeSelectedUsers() {
320
321         try {
322
323                 var sel_rows = getSelectedUsers();
324         
325                 if (sel_rows.length > 0) {
326         
327                         var ok = confirm(__("Remove selected users? Neither default admin nor your account will be removed."));
328         
329                         if (ok) {
330                                 notify_progress("Removing selected users...");
331                 
332                                 var query = "?op=pref-users&subop=remove&ids="+
333                                         param_escape(sel_rows.toString());
334         
335                                 new Ajax.Request("backend.php", {
336                                         parameters: query,
337                                         onComplete: function(transport) { 
338                                                 userlist_callback2(transport); 
339                                         } });
340         
341                         }
342         
343                 } else {
344                         alert(__("No users are selected."));
345                 }
346
347         } catch (e) {
348                 exception_error("removeSelectedUsers", e);
349         }
350
351         return false;
352 }
353
354 function removeSelectedFilters() {
355
356         try {
357
358                 var sel_rows = getSelectedFilters();
359         
360                 if (sel_rows.length > 0) {
361         
362                         var ok = confirm(__("Remove selected filters?"));
363         
364                         if (ok) {
365                                 notify_progress("Removing selected filters...");
366                 
367                                 var query = "?op=pref-filters&subop=remove&ids="+
368                                         param_escape(sel_rows.toString());
369         
370                                 new Ajax.Request("backend.php", {
371                                                 parameters: query,
372                                                 onComplete: function(transport) {
373                                                                 filterlist_callback2(transport);
374                                         } });
375         
376                         }
377                 } else {
378                         alert(__("No filters are selected."));
379                 }
380
381         } catch (e) {
382                 exception_error("removeSelectedFilters", e);
383         }
384
385         return false;
386 }
387
388
389 function removeSelectedFeeds() {
390
391         try {
392
393                 var sel_rows = getSelectedFeeds();
394         
395                 if (sel_rows.length > 0) {
396         
397                         var ok = confirm(__("Unsubscribe from selected feeds?"));
398         
399                         if (ok) {
400         
401                                 notify_progress("Unsubscribing from selected feeds...", true);
402                 
403                                 var query = "?op=pref-feeds&subop=remove&ids="+
404                                         param_escape(sel_rows.toString());
405
406                                 console.log(query);
407
408                                 new Ajax.Request("backend.php", {
409                                         parameters: query,
410                                         onComplete: function(transport) {
411                                                 updateFeedList();
412                                                 } });
413                         }
414         
415                 } else {
416                         alert(__("No feeds are selected."));
417                 }
418
419         } catch (e) {
420                 exception_error("removeSelectedFeeds", e);
421         }
422         
423         return false;
424 }
425
426 function clearSelectedFeeds() {
427
428         var sel_rows = getSelectedFeeds();
429
430         if (sel_rows.length > 1) {
431                 alert(__("Please select only one feed."));
432                 return;
433         }
434
435         if (sel_rows.length > 0) {
436
437                 var ok = confirm(__("Erase all non-starred articles in selected feed?"));
438
439                 if (ok) {
440                         notify_progress("Clearing selected feed...");
441                         clearFeedArticles(sel_rows[0]);
442                 }
443
444         } else {
445
446                 alert(__("No feeds are selected."));
447
448         }
449         
450         return false;
451 }
452
453 function purgeSelectedFeeds() {
454
455         var sel_rows = getSelectedFeeds();
456
457         if (sel_rows.length > 0) {
458
459                 var pr = prompt(__("How many days of articles to keep (0 - use default)?"), "0");
460
461                 if (pr != undefined) {
462                         notify_progress("Purging selected feed...");
463
464                         var query = "?op=rpc&subop=purge&ids="+
465                                 param_escape(sel_rows.toString()) + "&days=" + pr;
466
467                         console.log(query);
468
469                         new Ajax.Request("prefs.php",   {
470                                 parameters: query,
471                                 onComplete: function(transport) {
472                                         notify('');
473                                 } });
474                 }
475
476         } else {
477
478                 alert(__("No feeds are selected."));
479
480         }
481         
482         return false;
483 }
484
485 function removeSelectedPrefProfiles() {
486
487         var sel_rows = getSelectedFeedCats();
488
489         if (sel_rows.length > 0) {
490
491                 var ok = confirm(__("Remove selected profiles? Active and default profiles will not be removed."));
492
493                 if (ok) {
494                         notify_progress("Removing selected profiles...");
495         
496                         var query = "?op=rpc&subop=remprofiles&ids="+
497                                 param_escape(sel_rows.toString());
498
499                         new Ajax.Request("backend.php", {
500                                 parameters: query,
501                                 onComplete: function(transport) {
502                                         editProfiles();
503                                 } });
504                 }
505
506         } else {
507                 alert(__("No profiles selected."));
508         }
509
510         return false;
511 }
512
513 function userEditCancel() {
514         closeInfoBox();
515         return false;
516 }
517
518 function userEditSave() {
519
520         try {
521
522                 var login = document.forms["user_edit_form"].login.value;
523         
524                 if (login.length == 0) {
525                         alert(__("Login field cannot be blank."));
526                         return;
527                 }
528                 
529                 notify_progress("Saving user...");
530         
531                 closeInfoBox();
532         
533                 var query = Form.serialize("user_edit_form");
534                 
535                 new Ajax.Request("backend.php", {
536                         parameters: query,
537                         onComplete: function(transport) { 
538                                 userlist_callback2(transport); 
539                         } });
540         
541         } catch (e) {
542                 exception_error("userEditSave", e);
543         }
544
545         return false;
546
547 }
548
549
550 function editSelectedUser() {
551         var rows = getSelectedUsers();
552
553         if (rows.length == 0) {
554                 alert(__("No users are selected."));
555                 return;
556         }
557
558         if (rows.length > 1) {
559                 alert(__("Please select only one user."));
560                 return;
561         }
562
563         notify("");
564
565         editUser(rows[0]);
566 }
567
568 function resetSelectedUserPass() {
569
570         try {
571
572                 var rows = getSelectedUsers();
573         
574                 if (rows.length == 0) {
575                         alert(__("No users are selected."));
576                         return;
577                 }
578         
579                 if (rows.length > 1) {
580                         alert(__("Please select only one user."));
581                         return;
582                 }
583         
584                 var ok = confirm(__("Reset password of selected user?"));
585         
586                 if (ok) {
587                         notify_progress("Resetting password for selected user...");
588                 
589                         var id = rows[0];
590                 
591                         var query = "?op=pref-users&subop=resetPass&id=" +
592                                 param_escape(id);
593         
594                         new Ajax.Request("backend.php", {
595                                 parameters: query,
596                                 onComplete: function(transport) { 
597                                         userlist_callback2(transport); 
598                                 } });
599         
600                 }
601
602         } catch (e) {
603                 exception_error("resetSelectedUserPass", e);
604         }
605 }
606
607 function selectedUserDetails() {
608
609         try {
610
611                 var rows = getSelectedUsers();
612         
613                 if (rows.length == 0) {
614                         alert(__("No users are selected."));
615                         return;
616                 }
617         
618                 if (rows.length > 1) {
619                         alert(__("Please select only one user."));
620                         return;
621                 }
622         
623                 notify_progress("Loading, please wait...");
624         
625                 var id = rows[0];
626         
627                 var query = "?op=pref-users&subop=user-details&id=" + id;
628
629                 new Ajax.Request("backend.php", {
630                         parameters: query,
631                         onComplete: function(transport) {
632                                         infobox_callback2(transport);
633                                 } });
634         } catch (e) {
635                 exception_error("selectedUserDetails", e);
636         }
637 }
638
639
640 function editSelectedFilter() {
641         var rows = getSelectedFilters();
642
643         if (rows.length == 0) {
644                 alert(__("No filters are selected."));
645                 return;
646         }
647
648         if (rows.length > 1) {
649                 alert(__("Please select only one filter."));
650                 return;
651         }
652
653         notify("");
654
655         editFilter(rows[0]);
656
657 }
658
659
660 function editSelectedFeed() {
661         var rows = getSelectedFeeds();
662
663         if (rows.length == 0) {
664                 alert(__("No feeds are selected."));
665                 return;
666         }
667
668         if (rows.length > 1) {
669                 return editSelectedFeeds();
670         }
671
672         notify("");
673
674         editFeed(rows[0], {});
675
676 }
677
678 function editSelectedFeeds() {
679
680         try {
681                 var rows = getSelectedFeeds();
682         
683                 if (rows.length == 0) {
684                         alert(__("No feeds are selected."));
685                         return;
686                 }
687         
688                 notify("");
689         
690                 var query = "backend.php?op=pref-feeds&subop=editfeeds&ids=" +
691                         param_escape(rows.toString());
692
693                 if (dijit.byId("feedEditDlg"))
694                         dijit.byId("feedEditDlg").destroyRecursive();
695
696                 dialog = new dijit.Dialog({
697                         id: "feedEditDlg",
698                         title: __("Edit Multiple Feeds"),
699                         style: "width: 600px",
700                         getChildByName: function (name) {
701                                 var rv = null
702                                 this.getChildren().each(
703                                         function(child) { 
704                                                 if (child.name == name) {
705                                                         rv = child;
706                                                         return;
707                                                 }
708                                         });
709                                 return rv;
710                         },
711                         toggleField: function (checkbox, elem, label) {
712                                 this.getChildByName(elem).attr('disabled', !checkbox.checked);
713
714                                 if ($(label))
715                                         if (checkbox.checked)
716                                                 $(label).removeClassName('insensitive');
717                                         else
718                                                 $(label).addClassName('insensitive');
719
720                         },
721                         execute: function() {
722                                 if (this.validate() && confirm(__("Save changes to selected feeds?"))) {
723                                         var query = dojo.objectToQuery(this.attr('value'));
724
725                                         /* Form.serialize ignores unchecked checkboxes */
726
727                                         if (!query.match("&rtl_content=") && 
728                                                         this.getChildByName('rtl_content').attr('disabled') == false) {
729                                                 query = query + "&rtl_content=false";
730                                         }
731                 
732                                         if (!query.match("&private=") && 
733                                                         this.getChildByName('private').attr('disabled') == false) {
734                                                 query = query + "&private=false";
735                                         }
736                 
737                                         if (!query.match("&cache_images=") && 
738                                                         this.getChildByName('cache_images').attr('disabled') == false) {
739                                                 query = query + "&cache_images=false";
740                                         }
741                 
742                                         if (!query.match("&include_in_digest=") && 
743                                                         this.getChildByName('include_in_digest').attr('disabled') == false) {
744                                                 query = query + "&include_in_digest=false";
745                                         }
746
747                                         console.log(query);
748                 
749                                         notify_progress("Saving data...", true);
750
751                                         new Ajax.Request("backend.php", {
752                                                 parameters: query,
753                                                 onComplete: function(transport) {
754                                                         dialog.hide();
755                                                         updateFeedList();
756                                         }})
757                                 }
758                         },
759                         href: query});
760
761                 dialog.show();
762
763         } catch (e) {
764                 exception_error("editSelectedFeeds", e);
765         }
766 }
767
768 function piggie(enable) {
769         if (enable) {
770                 console.log("I LOVEDED IT!");
771                 var piggie = $("piggie");
772
773                 Element.show(piggie);
774                 Position.Center(piggie);
775                 Effect.Puff(piggie);
776
777         }
778 }
779
780 function opmlImportComplete(iframe) {
781         try {
782                 if (!iframe.contentDocument.body.innerHTML) return false;
783
784                 notify('');
785
786                 if (dijit.byId('opmlImportDlg'))
787                         dijit.byId('opmlImportDlg').destroyRecursive();
788
789                 var content = iframe.contentDocument.body.innerHTML;
790
791                 dialog = new dijit.Dialog({
792                         id: "opmlImportDlg",
793                         title: __("OPML Import"),
794                         style: "width: 600px",
795                         onCancel: function() {
796                                 updateFeedList();       
797                         },
798                         content: content});
799
800                 dialog.show();
801
802         } catch (e) {
803                 exception_error("opmlImportComplete", e);
804         }
805 }
806
807 function opmlImport() {
808         
809         var opml_file = $("opml_file");
810
811         if (opml_file.value.length == 0) {
812                 alert(__("Please choose an OPML file first."));
813                 return false;
814         } else {
815                 notify_progress("Importing, please wait...", true);
816                 return true;
817         }
818 }
819
820 function updateFilterList() {
821         new Ajax.Request("backend.php", {
822                 parameters: "?op=pref-filters",
823                 onComplete: function(transport) {
824                         filterlist_callback2(transport);
825                 } });
826 }
827
828 function updateLabelList() {
829         new Ajax.Request("backend.php", {
830                 parameters: "?op=pref-labels",
831                 onComplete: function(transport) {
832                         labellist_callback2(transport);
833                 } });
834 }
835
836 function updatePrefsList() {
837         new Ajax.Request("backend.php", {
838                 parameters: "?op=pref-prefs",
839                 onComplete: function(transport) { 
840                         prefslist_callback2(transport); 
841                 } });
842 }
843
844 function selectTab(id, noupdate, subop) {
845         try {
846                 if (!noupdate) {
847                         notify_progress("Loading, please wait...");
848
849                         if (id == "feedConfig") {
850                                 updateFeedList();
851                         } else if (id == "filterConfig") {
852                                 updateFilterList();
853                         } else if (id == "labelConfig") {
854                                 updateLabelList();
855                         } else if (id == "genConfig") {
856                                 updatePrefsList();
857                         } else if (id == "userConfig") {
858                                 updateUsersList();
859                         }
860
861                         var tab = dijit.byId(id + "Tab");
862                         dijit.byId("pref-tabs").selectChild(tab);
863
864                 }
865         
866         } catch (e) {
867                 exception_error("selectTab", e);
868         }
869 }
870
871 function init_second_stage() {
872         try {
873
874                 document.onkeydown = pref_hotkey_handler;
875
876                 caller_subop = getURLParam('subop');
877
878                 if (getURLParam("subopparam")) {
879                         caller_subop = caller_subop + ":" + getURLParam("subopparam");
880                 }
881
882                 loading_set_progress(50);
883
884                 notify("");
885
886                 dojo.addOnLoad(function() {
887                         var tab = getURLParam('tab');
888
889                         if (tab) {
890                                 tab = dijit.byId(tab + "Tab");
891                                 if (tab) dijit.byId("pref-tabs").selectChild(tab);
892                         }
893                 });
894
895                 setTimeout("hotkey_prefix_timeout()", 5*1000);
896
897         } catch (e) {
898                 exception_error("init_second_stage", e);
899         }
900 }
901
902 function init() {
903
904         try {
905         
906                 dojo.require("dijit.layout.TabContainer");
907                 dojo.require("dijit.layout.BorderContainer");
908                 dojo.require("dijit.layout.AccordionContainer");
909                 dojo.require("dijit.layout.ContentPane");
910                 dojo.require("dijit.Dialog");
911                 dojo.require("dijit.form.Button");
912                 dojo.require("dijit.form.Select");
913                 dojo.require("dijit.form.FilteringSelect");
914                 dojo.require("dijit.form.TextBox");
915                 dojo.require("dijit.form.CheckBox");
916                 dojo.require("dijit.form.ValidationTextBox");
917                 dojo.require("dijit.form.RadioButton");
918                 dojo.require("dijit.form.Select");
919                 dojo.require("dijit.Toolbar");
920                 dojo.require("dojo.data.ItemFileWriteStore");
921                 dojo.require("dijit.Tree");
922                 dojo.require("dijit.form.DropDownButton");
923                 dojo.require("dijit.form.Form");
924                 dojo.require("dijit.Menu");
925                 dojo.require("dijit.tree.dndSource");
926                 dojo.require("dijit.InlineEditBox");
927                 dojo.require("dijit.ColorPalette");
928                 dojo.require("dijit.ProgressBar"); 
929                 dojo.require("dijit.form.SimpleTextarea");
930
931                 dojo.registerModulePath("lib", "..");
932                 dojo.registerModulePath("fox", "../..");
933
934                 dojo.require("lib.CheckBoxTree");
935                 dojo.require("fox.PrefFeedTree");
936                 dojo.require("fox.PrefFilterTree");
937                 dojo.require("fox.PrefLabelTree");
938
939                 dojo.addOnLoad(function() {
940                         loading_set_progress(50);
941
942                         new Ajax.Request("backend.php", {
943                                 parameters: {op: "rpc", subop: "sanityCheck"},
944                                         onComplete: function(transport) { 
945                                         backend_sanity_check_callback(transport);
946                                 } });
947                 });
948
949         } catch (e) {
950                 exception_error("init", e);
951         }
952 }
953
954 function validatePrefsReset() {
955         try {
956                 var ok = confirm(__("Reset to defaults?"));
957
958                 if (ok) {
959
960                         var query = Form.serialize("pref_prefs_form");
961                         query = query + "&subop=reset-config";
962                         console.log(query);
963
964                         new Ajax.Request("backend.php", {
965                                 parameters: query,
966                                 onComplete: function(transport) { 
967                                         var msg = transport.responseText;
968                                         if (msg.match("PREFS_THEME_CHANGED")) {
969                                                 window.location.reload();
970                                         } else {
971                                                 notify_info(msg);
972                                                 selectTab();
973                                         }
974                                 } });
975
976                 }
977
978         } catch (e) {
979                 exception_error("validatePrefsReset", e);
980         }
981
982         return false;
983
984 }
985
986
987 function pref_hotkey_handler(e) {
988         try {
989                 if (e.target.nodeName == "INPUT") return;
990
991                 var keycode;
992                 var shift_key = false;
993
994                 var cmdline = $('cmdline');
995
996                 try {
997                         shift_key = e.shiftKey;
998                 } catch (e) {
999
1000                 }
1001
1002                 if (window.event) {
1003                         keycode = window.event.keyCode;
1004                 } else if (e) {
1005                         keycode = e.which;
1006                 }
1007
1008                 var keychar = String.fromCharCode(keycode);
1009
1010                 if (keycode == 27) { // escape
1011                         if (Element.visible("hotkey_help_overlay")) {
1012                                 Element.hide("hotkey_help_overlay");
1013                         }
1014                         hotkey_prefix = false;
1015                         closeInfoBox();
1016                 } 
1017
1018                 if (keycode == 16) return; // ignore lone shift
1019                 if (keycode == 17) return; // ignore lone ctrl
1020
1021                 if ((keycode == 67 || keycode == 71) && !hotkey_prefix) {
1022                         hotkey_prefix = keycode;
1023
1024                         var date = new Date();
1025                         var ts = Math.round(date.getTime() / 1000);
1026
1027                         hotkey_prefix_pressed = ts;
1028
1029                         cmdline.innerHTML = keychar;
1030                         Element.show(cmdline);
1031
1032                         console.log("KP: PREFIX=" + keycode + " CHAR=" + keychar);
1033                         return;
1034                 }
1035
1036                 if (Element.visible("hotkey_help_overlay")) {
1037                         Element.hide("hotkey_help_overlay");
1038                 }
1039
1040                 if (keycode == 13 || keycode == 27) {
1041                         seq = "";
1042                 } else {
1043                         seq = seq + "" + keycode;
1044                 }
1045
1046                 /* Global hotkeys */
1047
1048                 Element.hide(cmdline);
1049
1050                 if (!hotkey_prefix) {
1051
1052                         if ((keycode == 191 || keychar == '?') && shift_key) { // ?
1053                                 if (!Element.visible("hotkey_help_overlay")) {
1054                                         //Element.show("hotkey_help_overlay");
1055                                         Effect.Appear("hotkey_help_overlay", {duration : 0.3});
1056                                 } else {
1057                                         Element.hide("hotkey_help_overlay");
1058                                 }
1059                                 return false;
1060                         }
1061
1062                         if (keycode == 191 || keychar == '/') { // /
1063                                 var search_boxes = new Array("label_search", 
1064                                         "feed_search", "filter_search", "user_search", "feed_browser_search");
1065
1066                                 for (var i = 0; i < search_boxes.length; i++) {
1067                                         var elem = $(search_boxes[i]);
1068                                         if (elem) {
1069                                                 $(search_boxes[i]).focus();
1070                                                 return false;
1071                                         }
1072                                 }
1073                         }
1074                 }
1075
1076                 /* Prefix c */
1077
1078                 if (hotkey_prefix == 67) { // c
1079                         hotkey_prefix = false;
1080
1081                         if (keycode == 70) { // f
1082                                 quickAddFilter();
1083                                 return false;
1084                         }
1085
1086                         if (keycode == 83) { // s
1087                                 quickAddFeed();
1088                                 return false;
1089                         }
1090
1091                         if (keycode == 85) { // u
1092                                 // no-op
1093                         }
1094
1095                         if (keycode == 67) { // c
1096                                 editFeedCats();
1097                                 return false;
1098                         }
1099
1100                         if (keycode == 84 && shift_key) { // T
1101                                 feedBrowser();
1102                                 return false;
1103                         }
1104
1105                 }
1106
1107                 /* Prefix g */
1108
1109                 if (hotkey_prefix == 71) { // g
1110
1111                         hotkey_prefix = false;
1112
1113                         if (keycode == 49 && $("genConfigTab")) { // 1
1114                                 selectTab("genConfig");
1115                                 return false;
1116                         }
1117
1118                         if (keycode == 50 && $("feedConfigTab")) { // 2
1119                                 selectTab("feedConfig");
1120                                 return false;
1121                         }
1122
1123                         if (keycode == 51 && $("filterConfigTab")) { // 4
1124                                 selectTab("filterConfig");
1125                                 return false;
1126                         }
1127
1128                         if (keycode == 52 && $("labelConfigTab")) { // 5
1129                                 selectTab("labelConfig");
1130                                 return false;
1131                         }
1132
1133                         if (keycode == 53 && $("userConfigTab")) { // 6
1134                                 selectTab("userConfig");
1135                                 return false;
1136                         }
1137
1138                         if (keycode == 88) { // x
1139                                 return gotoMain();
1140                         }
1141
1142                 }
1143
1144                 if ($("piggie")) {
1145                         if (seq.match("8073717369")) {
1146                                 seq = "";
1147                                 piggie(true);
1148                         } else {
1149                                 piggie(false);
1150                         }
1151                 }
1152
1153                 if (hotkey_prefix) {
1154                         console.log("KP: PREFIX=" + hotkey_prefix + " CODE=" + keycode + " CHAR=" + keychar);
1155                 } else {
1156                         console.log("KP: CODE=" + keycode + " CHAR=" + keychar);
1157                 }
1158
1159         } catch (e) {
1160                 exception_error("pref_hotkey_handler", e);
1161         }
1162 }
1163
1164 function editFeedCats() {
1165         try {
1166                 var query = "backend.php?op=pref-feeds&subop=editCats";
1167
1168                 if (dijit.byId("feedCatEditDlg"))
1169                         dijit.byId("feedCatEditDlg").destroyRecursive();
1170
1171                 dialog = new dijit.Dialog({
1172                         id: "feedCatEditDlg",
1173                         title: __("Feed Categories"),
1174                         style: "width: 600px",
1175                         getSelectedCategories: function() {
1176                                 return getSelectedTableRowIds("prefFeedCatList");
1177                         },
1178                         removeSelected: function() {
1179                                 var sel_rows = this.getSelectedCategories();
1180                         
1181                                 if (sel_rows.length > 0) {                      
1182                                         var ok = confirm(__("Remove selected categories?"));
1183                         
1184                                         if (ok) {
1185                                                 notify_progress("Removing selected categories...", true);
1186                                 
1187                                                 var query = "?op=pref-feeds&subop=editCats&action=remove&ids="+
1188                                                         param_escape(sel_rows.toString());
1189                         
1190                                                 new Ajax.Request("backend.php", {
1191                                                         parameters: query,
1192                                                         onComplete: function(transport) {
1193                                                                 notify('');
1194                                                                 dialog.attr('content', transport.responseText);
1195                                                                 updateFeedList();
1196                                                         } });
1197                         
1198                                         }
1199                         
1200                                 } else {        
1201                                         alert(__("No categories are selected."));                       
1202                                 }
1203                         },
1204                         addCategory: function() {
1205                                 if (this.validate()) {
1206                                         notify_progress("Creating category...");
1207
1208                                         var query = "?op=pref-feeds&subop=editCats&action=add&cat=" +
1209                                                 param_escape(this.attr('value').newcat);
1210
1211                                         new Ajax.Request("backend.php", {
1212                                                 parameters: query,
1213                                                 onComplete: function(transport) {
1214                                                         notify('');
1215                                                         dialog.attr('content', transport.responseText);
1216                                                         updateFeedList();
1217                                                 } });
1218                                 }
1219                         },
1220                         execute: function() {
1221                                 if (this.validate()) {
1222                                 }
1223                         },
1224                         href: query});
1225
1226                 dialog.show();
1227
1228         } catch (e) {
1229                 exception_error("editFeedCats", e);
1230         }
1231 }
1232
1233 function showFeedsWithErrors() {
1234         displayDlg('feedUpdateErrors');
1235 }
1236
1237 function opmlRegenKey() {
1238
1239         try {
1240                 var ok = confirm(__("Replace current OPML publishing address with a new one?"));
1241         
1242                 if (ok) {
1243         
1244                         notify_progress("Trying to change address...", true);
1245         
1246                         var query = "?op=rpc&subop=regenOPMLKey";
1247         
1248                         new Ajax.Request("backend.php", {
1249                                 parameters: query,
1250                                 onComplete: function(transport) {
1251                                                 var new_link = transport.responseXML.getElementsByTagName("link")[0];
1252         
1253                                                 var e = $('pub_opml_url');
1254         
1255                                                 if (new_link) {
1256                                                         e.href = new_link.firstChild.nodeValue;
1257                                                         e.innerHTML = new_link.firstChild.nodeValue;
1258         
1259                                                         new Effect.Highlight(e);
1260
1261                                                         notify('');
1262         
1263                                                 } else {
1264                                                         notify_error("Could not change feed URL.");
1265                                                 }
1266                                 } });
1267                 }
1268         } catch (e) {
1269                 exception_error("opmlRegenKey", e);
1270         }
1271         return false;
1272 }
1273
1274 function feedActionChange() {
1275         try {
1276                 var chooser = $("feedActionChooser");
1277                 var opid = chooser[chooser.selectedIndex].value;
1278
1279                 chooser.selectedIndex = 0;
1280                 feedActionGo(opid);
1281         } catch (e) {
1282                 exception_error("feedActionChange", e);
1283         }
1284 }
1285
1286 function feedActionGo(op) {     
1287         try {
1288                 if (op == "facEdit") {
1289
1290                         var rows = getSelectedFeeds();
1291
1292                         if (rows.length > 1) {
1293                                 editSelectedFeeds();
1294                         } else {
1295                                 editSelectedFeed();
1296                         }
1297                 }
1298
1299                 if (op == "facClear") {
1300                         clearSelectedFeeds();
1301                 }
1302
1303                 if (op == "facPurge") {
1304                         purgeSelectedFeeds();
1305                 }
1306
1307                 if (op == "facEditCats") {
1308                         editFeedCats();
1309                 }
1310
1311                 if (op == "facRescore") {
1312                         rescoreSelectedFeeds();
1313                 }
1314
1315                 if (op == "facUnsubscribe") {
1316                         removeSelectedFeeds();
1317                 }
1318
1319         } catch (e) {
1320                 exception_error("feedActionGo", e);
1321
1322         }
1323 }
1324
1325 function clearFeedArticles(feed_id) {
1326
1327         notify_progress("Clearing feed...");
1328
1329         var query = "?op=pref-feeds&quiet=1&subop=clear&id=" + feed_id;
1330
1331         new Ajax.Request("backend.php", {
1332                 parameters: query,
1333                 onComplete: function(transport) {
1334                                 notify('');
1335                         } });
1336
1337         return false;
1338 }
1339
1340 function rescoreSelectedFeeds() {
1341
1342         var sel_rows = getSelectedFeeds();
1343
1344         if (sel_rows.length > 0) {
1345
1346                 //var ok = confirm(__("Rescore last 100 articles in selected feeds?"));
1347                 var ok = confirm(__("Rescore articles in selected feeds?"));
1348
1349                 if (ok) {
1350                         notify_progress("Rescoring selected feeds...", true);
1351         
1352                         var query = "?op=pref-feeds&subop=rescore&quiet=1&ids="+
1353                                 param_escape(sel_rows.toString());
1354
1355                         new Ajax.Request("backend.php", {
1356                                 parameters: query,
1357                                 onComplete: function(transport) {
1358                                                 notify_callback2(transport);
1359                         } });
1360
1361                 }
1362         } else {
1363                 alert(__("No feeds are selected."));
1364         }
1365
1366         return false;
1367 }
1368
1369 function rescore_all_feeds() {
1370         var ok = confirm(__("Rescore all articles? This operation may take a lot of time."));
1371
1372         if (ok) {
1373                 notify_progress("Rescoring feeds...", true);
1374
1375                 var query = "?op=pref-feeds&subop=rescoreAll&quiet=1";
1376
1377                 new Ajax.Request("backend.php", {
1378                         parameters: query,
1379                         onComplete: function(transport) {
1380                                         notify_callback2(transport);
1381                 } });
1382         }
1383 }
1384
1385 function labelColorReset() {
1386         try {
1387                 var labels = getSelectedLabels();
1388
1389                 if (labels.length > 0) {
1390                         var ok = confirm(__("Reset selected labels to default colors?"));
1391
1392                         if (ok) {
1393                                 var query = "?op=pref-labels&subop=color-reset&ids="+
1394                                         param_escape(labels.toString());
1395
1396                                 new Ajax.Request("backend.php", {
1397                                         parameters: query,
1398                                         onComplete: function(transport) {
1399                                                 labellist_callback2(transport);
1400                                         } });
1401                         }
1402
1403                 } else {
1404                         alert(__("No labels are selected."));
1405                 }
1406
1407         } catch (e) {
1408                 exception_error("labelColorReset", e);
1409         }
1410 }
1411
1412
1413 function inPreferences() {
1414         return true;
1415 }
1416
1417 function editProfiles() {
1418         try {
1419
1420                 if (dijit.byId("profileEditDlg"))
1421                         dijit.byId("profileEditDlg").destroyRecursive();
1422
1423                 var query = "backend.php?op=dlg&id=editPrefProfiles";
1424
1425                 dialog = new dijit.Dialog({
1426                         id: "profileEditDlg",
1427                         title: __("Settings Profiles"),
1428                         style: "width: 600px",
1429                         getSelectedProfiles: function() {
1430                                 return getSelectedTableRowIds("prefFeedProfileList");
1431                         },
1432                         removeSelected: function() {
1433                                 var sel_rows = this.getSelectedProfiles();
1434                         
1435                                 if (sel_rows.length > 0) {                      
1436                                         var ok = confirm(__("Remove selected profiles? Active and default profiles will not be removed."));
1437                         
1438                                         if (ok) {
1439                                                 notify_progress("Removing selected profiles...", true);
1440                                 
1441                                                 var query = "?op=rpc&subop=remprofiles&ids="+
1442                                                         param_escape(sel_rows.toString());
1443                         
1444                                                 new Ajax.Request("backend.php", {
1445                                                         parameters: query,
1446                                                         onComplete: function(transport) {
1447                                                                 notify('');
1448                                                                 editProfiles();
1449                                                         } });
1450                         
1451                                         }
1452                         
1453                                 } else {        
1454                                         alert(__("No profiles are selected."));                 
1455                                 }
1456                         },
1457                         activateProfile: function() {
1458                                 var sel_rows = this.getSelectedProfiles();
1459                         
1460                                 if (sel_rows.length == 1) {
1461                         
1462                                         var ok = confirm(__("Activate selected profile?"));
1463                         
1464                                         if (ok) {
1465                                                 notify_progress("Loading, please wait...");
1466                                 
1467                                                 var query = "?op=rpc&subop=setprofile&id="+
1468                                                         param_escape(sel_rows.toString());
1469                         
1470                                                 new Ajax.Request("backend.php", {
1471                                                         parameters: query,
1472                                                         onComplete: function(transport) {
1473                                                                 window.location.reload();
1474                                                         } });
1475                                         }
1476                         
1477                                 } else {
1478                                         alert(__("Please choose a profile to activate."));
1479                                 }                       
1480                         },                                                                        
1481                         addProfile: function() {
1482                                 if (this.validate()) {
1483                                         notify_progress("Creating profile...", true);
1484
1485                                         var query = "?op=rpc&subop=addprofile&title=" + 
1486                                                 param_escape(dialog.attr('value').newprofile);
1487
1488                                         new Ajax.Request("backend.php", {
1489                                                 parameters: query,
1490                                                 onComplete: function(transport) {
1491                                                         notify('');
1492                                                         editProfiles();
1493                                                 } });
1494
1495                                 }
1496                         },
1497                         execute: function() {
1498                                 if (this.validate()) {
1499                                 }
1500                         },
1501                         href: query});
1502
1503                 dialog.show();
1504         } catch (e) {
1505                 exception_error("editProfiles", e);
1506         }
1507 }
1508
1509 function activatePrefProfile() {
1510
1511         var sel_rows = getSelectedFeedCats();
1512
1513         if (sel_rows.length == 1) {
1514
1515                 var ok = confirm(__("Activate selected profile?"));
1516
1517                 if (ok) {
1518                         notify_progress("Loading, please wait...");
1519         
1520                         var query = "?op=rpc&subop=setprofile&id="+
1521                                 param_escape(sel_rows.toString());
1522
1523                         new Ajax.Request("backend.php", {
1524                                 parameters: query,
1525                                 onComplete: function(transport) {
1526                                         window.location.reload();
1527                                 } });
1528                 }
1529
1530         } else {
1531                 alert(__("Please choose a profile to activate."));
1532         }
1533
1534         return false;
1535 }
1536
1537 function clearFeedAccessKeys() {
1538
1539         var ok = confirm(__("This will invalidate all previously generated feed URLs. Continue?"));
1540
1541         if (ok) {
1542                 notify_progress("Clearing URLs...");
1543
1544                 var query = "?op=rpc&subop=clearKeys";
1545
1546                 new Ajax.Request("backend.php", {
1547                         parameters: query,
1548                         onComplete: function(transport) { 
1549                                 notify_info("Generated URLs cleared.");
1550                         } });
1551         }
1552         
1553         return false;
1554 }
1555
1556 function handle_rpc_reply(transport, scheduled_call) {
1557         try {
1558                 if (transport.responseXML) {
1559
1560                         if (!transport_error_check(transport)) return false;
1561
1562                 } else {
1563                         notify_error("Error communicating with server.");
1564                 }
1565
1566         } catch (e) {
1567                 exception_error("handle_rpc_reply", e, transport);
1568         }
1569
1570         return true;
1571 }
1572
1573 function resetFeedOrder() {
1574         try {
1575                 notify_progress("Loading, please wait...");
1576
1577                 new Ajax.Request("backend.php", {
1578                         parameters: "?op=pref-feeds&subop=feedsortreset",
1579                         onComplete: function(transport) {
1580                                 updateFeedList();       
1581                         } });
1582
1583
1584         } catch (e) {
1585                 exception_error("resetFeedOrder");
1586         }
1587 }
1588
1589 function resetCatOrder() {
1590         try {
1591                 notify_progress("Loading, please wait...");
1592
1593                 new Ajax.Request("backend.php", {
1594                         parameters: "?op=pref-feeds&subop=catsortreset",
1595                         onComplete: function(transport) {
1596                                 updateFeedList();       
1597                         } });
1598
1599
1600         } catch (e) {
1601                 exception_error("resetCatOrder");
1602         }
1603 }
1604
1605 function editCat(id, item, event) {
1606         try {
1607                 var new_name = prompt(__('Rename category to:'), item.name);
1608
1609                 if (new_name && new_name != item.name) {
1610
1611                         notify_progress("Loading, please wait...");
1612
1613                         new Ajax.Request("backend.php", {
1614                         parameters: {
1615                                 op: 'pref-feeds', 
1616                                 subop: 'renamecat',
1617                                 id: id,
1618                                 title: new_name,
1619                         },
1620                         onComplete: function(transport) {
1621                                 updateFeedList();       
1622                         } });
1623                 }
1624
1625         } catch (e) {
1626                 exception_error("editCat", e);
1627         }
1628 }
1629
1630 function editLabel(id, event) {
1631         try {
1632                 var query = "backend.php?op=pref-labels&subop=edit&id=" +
1633                         param_escape(id);
1634
1635                 if (dijit.byId("labelEditDlg"))
1636                         dijit.byId("labelEditDlg").destroyRecursive();
1637
1638                 dialog = new dijit.Dialog({
1639                         id: "labelEditDlg",
1640                         title: __("Label Editor"),
1641                         style: "width: 600px",
1642                         setLabelColor: function(id, fg, bg) {
1643
1644                                 var kind = '';
1645                                 var color = '';
1646                 
1647                                 if (fg && bg) {
1648                                         kind = 'both';
1649                                 } else if (fg) {
1650                                         kind = 'fg';
1651                                         color = fg;
1652                                 } else if (bg) {
1653                                         kind = 'bg';
1654                                         color = bg;
1655                                 }
1656                 
1657                                 var query = "?op=pref-labels&subop=color-set&kind="+kind+
1658                                         "&ids=" + param_escape(id) + "&fg=" + param_escape(fg) + 
1659                                         "&bg=" + param_escape(bg) + "&color=" + param_escape(color);
1660                 
1661                 //              console.log(query);
1662                 
1663                                 var e = $("LICID-" + id);
1664                 
1665                                 if (e) {                
1666                                         if (fg) e.style.color = fg;
1667                                         if (bg) e.style.backgroundColor = bg;
1668                                 }
1669                 
1670                                 new Ajax.Request("backend.php", { parameters: query });
1671
1672                                 updateFilterList();
1673                         },
1674                         execute: function() {
1675                                 if (this.validate()) {
1676                                         var caption = this.attr('value').id;
1677                                         var caption = this.attr('value').caption;
1678                                         var fg_color = this.attr('value').fg_color;
1679                                         var bg_color = this.attr('value').bg_color;
1680                                         var query = dojo.objectToQuery(this.attr('value'));
1681
1682                                         dijit.byId('labelTree').setNameById(id, caption);
1683                                         this.setLabelColor(id, fg_color, bg_color);
1684                                         this.hide();
1685
1686                                         new Ajax.Request("backend.php", {
1687                                                 parameters: query,
1688                                                 onComplete: function(transport) {
1689                                                         updateFilterList();     
1690                                         } });
1691                                 }
1692                         },
1693                         href: query});
1694
1695                 dialog.show();
1696
1697         } catch (e) {
1698                 exception_error("editLabel", e);
1699         }
1700 }
1701
1702 function clearTwitterCredentials() {
1703         try {
1704                 var ok = confirm(__("This will clear your stored authentication information for Twitter. Continue?"));
1705
1706                 if (ok) {
1707                         notify_progress("Clearing credentials...");
1708
1709                         var query = "?op=pref-feeds&subop=remtwitterinfo";
1710
1711                         new Ajax.Request("backend.php", {
1712                                 parameters: query,
1713                                 onComplete: function(transport) { 
1714                                         notify_info("Twitter credentials have been cleared.");
1715                                         updateFeedList();
1716                                 } });
1717                 }
1718
1719         } catch (e) {
1720                 exception_error("clearTwitterCredentials", e);
1721         }
1722 }
1723
1724 function customizeCSS() {
1725         try {
1726                 var query = "backend.php?op=dlg&id=customizeCSS";
1727
1728                 if (dijit.byId("cssEditDlg"))
1729                         dijit.byId("cssEditDlg").destroyRecursive();
1730
1731                 dialog = new dijit.Dialog({
1732                         id: "cssEditDlg",
1733                         title: __("Customize stylesheet"),
1734                         style: "width: 600px",
1735                         execute: function() {
1736                                 notify_progress('Saving data...', true);
1737                                 new Ajax.Request("backend.php", {
1738                                         parameters: dojo.objectToQuery(this.attr('value')),
1739                                         onComplete: function(transport) { 
1740                                                 notify('');
1741                                                 window.location.reload();
1742                                 } });
1743
1744                         },
1745                         href: query});
1746
1747                 dialog.show();
1748
1749         } catch (e) {
1750                 exception_error("customizeCSS", e);
1751         }
1752 }