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