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