]> git.wh0rd.org Git - tt-rss.git/blob - js/prefs.js
remove update on checksum change (updated status has been removed); rtl stuff (unused)
[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("&private=") &&
714                                                                         this.getChildByName('private').attr('disabled') == false) {
715                                                                 query = query + "&private=false";
716                                                         }
717
718                                                         try {
719                                                                 if (!query.match("&cache_images=") &&
720                                                                                 this.getChildByName('cache_images').attr('disabled') == false) {
721                                                                         query = query + "&cache_images=false";
722                                                                 }
723                                                         } catch (e) { }
724
725                                                         if (!query.match("&include_in_digest=") &&
726                                                                         this.getChildByName('include_in_digest').attr('disabled') == false) {
727                                                                 query = query + "&include_in_digest=false";
728                                                         }
729
730                                                         if (!query.match("&always_display_enclosures=") &&
731                                                                         this.getChildByName('always_display_enclosures').attr('disabled') == false) {
732                                                                 query = query + "&always_display_enclosures=false";
733                                                         }
734
735                                                         if (!query.match("&mark_unread_on_update=") &&
736                                                                         this.getChildByName('mark_unread_on_update').attr('disabled') == false) {
737                                                                 query = query + "&mark_unread_on_update=false";
738                                                         }
739
740                                                         console.log(query);
741
742                                                         notify_progress("Saving data...", true);
743
744                                                         new Ajax.Request("backend.php", {
745                                                                 parameters: query,
746                                                                 onComplete: function(transport) {
747                                                                         dialog.hide();
748                                                                         updateFeedList();
749                                                         }});
750                                                 }
751                                         },
752                                         content: transport.responseText});
753
754                                         dialog.show();
755
756                         } });
757
758         } catch (e) {
759                 exception_error("editSelectedFeeds", e);
760         }
761 }
762
763 function piggie(enable) {
764         if (enable) {
765                 console.log("I LOVEDED IT!");
766                 var piggie = $("piggie");
767
768                 Element.show(piggie);
769                 Position.Center(piggie);
770                 Effect.Puff(piggie);
771
772         }
773 }
774
775 function opmlImportComplete(iframe) {
776         try {
777                 if (!iframe.contentDocument.body.innerHTML) return false;
778
779                 Element.show(iframe);
780
781                 notify('');
782
783                 if (dijit.byId('opmlImportDlg'))
784                         dijit.byId('opmlImportDlg').destroyRecursive();
785
786                 var content = iframe.contentDocument.body.innerHTML;
787
788                 dialog = new dijit.Dialog({
789                         id: "opmlImportDlg",
790                         title: __("OPML Import"),
791                         style: "width: 600px",
792                         onCancel: function() {
793                                 updateFeedList();
794                                 updateFilterList();
795                                 updateLabelList();
796                         },
797                         execute: function() {
798                                 updateFeedList();
799                                 updateFilterList();
800                                 updateLabelList();
801                                 this.hide();
802                         },
803                         content: content});
804
805                 dialog.show();
806
807         } catch (e) {
808                 exception_error("opmlImportComplete", e);
809         }
810 }
811
812 function opmlImport() {
813
814         var opml_file = $("opml_file");
815
816         if (opml_file.value.length == 0) {
817                 alert(__("Please choose an OPML file first."));
818                 return false;
819         } else {
820                 notify_progress("Importing, please wait...", true);
821
822                 Element.show("upload_iframe");
823
824                 return true;
825         }
826 }
827
828
829 function updateFilterList() {
830         var user_search = $("filter_search");
831         var search = "";
832         if (user_search) { search = user_search.value; }
833
834         new Ajax.Request("backend.php", {
835                 parameters: "?op=pref-filters&search=" + param_escape(search),
836                 onComplete: function(transport) {
837                         dijit.byId('filterConfigTab').attr('content', transport.responseText);
838                         notify("");
839                 } });
840 }
841
842 function updateLabelList() {
843         new Ajax.Request("backend.php", {
844                 parameters: "?op=pref-labels",
845                 onComplete: function(transport) {
846                         dijit.byId('labelConfigTab').attr('content', transport.responseText);
847                         notify("");
848                 } });
849 }
850
851 function updatePrefsList() {
852         new Ajax.Request("backend.php", {
853                 parameters: "?op=pref-prefs",
854                 onComplete: function(transport) {
855                         dijit.byId('genConfigTab').attr('content', transport.responseText);
856                         notify("");
857                 } });
858 }
859
860 function selectTab(id, noupdate, method) {
861         try {
862                 if (!noupdate) {
863                         notify_progress("Loading, please wait...");
864
865                         if (id == "feedConfig") {
866                                 updateFeedList();
867                         } else if (id == "filterConfig") {
868                                 updateFilterList();
869                         } else if (id == "labelConfig") {
870                                 updateLabelList();
871                         } else if (id == "genConfig") {
872                                 updatePrefsList();
873                         } else if (id == "userConfig") {
874                                 updateUsersList();
875                         }
876
877                         var tab = dijit.byId(id + "Tab");
878                         dijit.byId("pref-tabs").selectChild(tab);
879
880                 }
881
882         } catch (e) {
883                 exception_error("selectTab", e);
884         }
885 }
886
887 function init_second_stage() {
888         try {
889
890                 document.onkeydown = pref_hotkey_handler;
891                 loading_set_progress(50);
892                 notify("");
893
894                 dojo.addOnLoad(function() {
895                         var tab = getURLParam('tab');
896
897                         if (tab) {
898                                 tab = dijit.byId(tab + "Tab");
899                                 if (tab) dijit.byId("pref-tabs").selectChild(tab);
900                         }
901
902                         var method = getURLParam('method');
903
904                         if (method == 'editFeed') {
905                                 var param = getURLParam('methodparam');
906
907                                 window.setTimeout('editFeed(' + param + ')', 100);
908                         }
909                 });
910
911                 setTimeout("hotkey_prefix_timeout()", 5*1000);
912
913         } catch (e) {
914                 exception_error("init_second_stage", e);
915         }
916 }
917
918 function init() {
919
920         try {
921                 dojo.registerModulePath("lib", "..");
922                 dojo.registerModulePath("fox", "../../js/");
923
924                 dojo.require("dijit.ColorPalette");
925                 dojo.require("dijit.Dialog");
926                 dojo.require("dijit.form.Button");
927                 dojo.require("dijit.form.CheckBox");
928                 dojo.require("dijit.form.DropDownButton");
929                 dojo.require("dijit.form.FilteringSelect");
930                 dojo.require("dijit.form.Form");
931                 dojo.require("dijit.form.RadioButton");
932                 dojo.require("dijit.form.Select");
933                 dojo.require("dijit.form.SimpleTextarea");
934                 dojo.require("dijit.form.TextBox");
935                 dojo.require("dijit.form.ValidationTextBox");
936                 dojo.require("dijit.InlineEditBox");
937                 dojo.require("dijit.layout.AccordionContainer");
938                 dojo.require("dijit.layout.BorderContainer");
939                 dojo.require("dijit.layout.ContentPane");
940                 dojo.require("dijit.layout.TabContainer");
941                 dojo.require("dijit.Menu");
942                 dojo.require("dijit.ProgressBar");
943                 dojo.require("dijit.ProgressBar");
944                 dojo.require("dijit.Toolbar");
945                 dojo.require("dijit.Tree");
946                 dojo.require("dijit.tree.dndSource");
947                 dojo.require("dojo.data.ItemFileWriteStore");
948
949                 dojo.require("lib.CheckBoxTree");
950                 dojo.require("fox.PrefFeedTree");
951                 dojo.require("fox.PrefFilterTree");
952                 dojo.require("fox.PrefLabelTree");
953
954                 dojo.parser.parse();
955
956                 dojo.addOnLoad(function() {
957                         loading_set_progress(50);
958
959                         new Ajax.Request("backend.php", {
960                                 parameters: {op: "rpc", method: "sanityCheck"},
961                                         onComplete: function(transport) {
962                                         backend_sanity_check_callback(transport);
963                                 } });
964                 });
965
966         } catch (e) {
967                 exception_error("init", e);
968         }
969 }
970
971 function validatePrefsReset() {
972         try {
973                 var ok = confirm(__("Reset to defaults?"));
974
975                 if (ok) {
976
977                         query = "?op=pref-prefs&method=resetconfig";
978                         console.log(query);
979
980                         new Ajax.Request("backend.php", {
981                                 parameters: query,
982                                 onComplete: function(transport) {
983                                         var msg = transport.responseText;
984                                         if (msg.match("PREFS_THEME_CHANGED")) {
985                                                 window.location.reload();
986                                         } else {
987                                                 notify_info(msg);
988                                                 selectTab();
989                                         }
990                                 } });
991
992                 }
993
994         } catch (e) {
995                 exception_error("validatePrefsReset", e);
996         }
997
998         return false;
999
1000 }
1001
1002 function pref_hotkey_handler(e) {
1003         try {
1004
1005                 if (e.target.nodeName == "INPUT" || e.target.nodeName == "TEXTAREA") return;
1006
1007                 var keycode = false;
1008                 var shift_key = false;
1009
1010                 var cmdline = $('cmdline');
1011
1012                 try {
1013                         shift_key = e.shiftKey;
1014                 } catch (e) {
1015
1016                 }
1017
1018                 if (window.event) {
1019                         keycode = window.event.keyCode;
1020                 } else if (e) {
1021                         keycode = e.which;
1022                 }
1023
1024                 var keychar = String.fromCharCode(keycode);
1025
1026                 if (keycode == 27) { // escape
1027                         hotkey_prefix = false;
1028                 }
1029
1030                 if (keycode == 16) return; // ignore lone shift
1031                 if (keycode == 17) return; // ignore lone ctrl
1032
1033                 if (!shift_key) keychar = keychar.toLowerCase();
1034
1035                 var hotkeys = getInitParam("hotkeys");
1036
1037                 if (!hotkey_prefix && hotkeys[0].indexOf(keychar) != -1) {
1038
1039                         var date = new Date();
1040                         var ts = Math.round(date.getTime() / 1000);
1041
1042                         hotkey_prefix = keychar;
1043                         hotkey_prefix_pressed = ts;
1044
1045                         cmdline.innerHTML = keychar;
1046                         Element.show(cmdline);
1047
1048                         return true;
1049                 }
1050
1051                 Element.hide(cmdline);
1052
1053                 var hotkey = keychar.search(/[a-zA-Z0-9]/) != -1 ? keychar : "(" + keycode + ")";
1054                 hotkey = hotkey_prefix ? hotkey_prefix + " " + hotkey : hotkey;
1055                 hotkey_prefix = false;
1056
1057                 var hotkey_action = false;
1058                 var hotkeys = getInitParam("hotkeys");
1059
1060                 for (sequence in hotkeys[1]) {
1061                         if (sequence == hotkey) {
1062                                 hotkey_action = hotkeys[1][sequence];
1063                                 break;
1064                         }
1065                 }
1066
1067                 switch (hotkey_action) {
1068                 case "feed_subscribe":
1069                         quickAddFeed();
1070                         return false;
1071                 case "create_label":
1072                         addLabel();
1073                         return false;
1074                 case "create_filter":
1075                         quickAddFilter();
1076                         return false;
1077                 case "help_dialog":
1078                         //helpDialog("prefs");
1079                         return false;
1080                 default:
1081                         console.log("unhandled action: " + hotkey_action + "; hotkey: " + hotkey);
1082                 }
1083
1084         } catch (e) {
1085                 exception_error("hotkey_handler", e);
1086         }
1087 }
1088
1089 function removeCategory(id, item) {
1090         try {
1091
1092                 var ok = confirm(__("Remove category %s? Any nested feeds would be placed into Uncategorized.").replace("%s", item.name));
1093
1094                 if (ok) {
1095                         var query = "?op=pref-feeds&method=removeCat&ids="+
1096                                 param_escape(id);
1097
1098                         notify_progress("Removing category...");
1099
1100                         new Ajax.Request("backend.php", {
1101                                 parameters: query,
1102                                 onComplete: function(transport) {
1103                                         notify('');
1104                                         updateFeedList();
1105                                 } });
1106                         }
1107
1108         } catch (e) {
1109                 exception_error("removeCategory", e);
1110         }
1111 }
1112
1113 function removeSelectedCategories() {
1114
1115         var sel_rows = getSelectedCategories();
1116
1117         if (sel_rows.length > 0) {
1118
1119                 var ok = confirm(__("Remove selected categories?"));
1120
1121                 if (ok) {
1122                         notify_progress("Removing selected categories...");
1123
1124                         var query = "?op=pref-feeds&method=removeCat&ids="+
1125                                 param_escape(sel_rows.toString());
1126
1127                         new Ajax.Request("backend.php", {
1128                                 parameters: query,
1129                                 onComplete: function(transport) {
1130                                                 updateFeedList();
1131                                         } });
1132
1133                 }
1134         } else {
1135                 alert(__("No categories are selected."));
1136         }
1137
1138         return false;
1139 }
1140
1141 function createCategory() {
1142         try {
1143                 var title = prompt(__("Category title:"));
1144
1145                 if (title) {
1146
1147                         notify_progress("Creating category...");
1148
1149                         var query = "?op=pref-feeds&method=addCat&cat=" +
1150                                 param_escape(title);
1151
1152                         new Ajax.Request("backend.php", {
1153                                 parameters: query,
1154                                 onComplete: function(transport) {
1155                                         notify('');
1156                                         updateFeedList();
1157                                 } });
1158                 }
1159
1160         } catch (e) {
1161                 exception_error("createCategory", e);
1162         }
1163 }
1164
1165 function showInactiveFeeds() {
1166         try {
1167                 var query = "backend.php?op=pref-feeds&method=inactiveFeeds";
1168
1169                 if (dijit.byId("inactiveFeedsDlg"))
1170                         dijit.byId("inactiveFeedsDlg").destroyRecursive();
1171
1172                 dialog = new dijit.Dialog({
1173                         id: "inactiveFeedsDlg",
1174                         title: __("Feeds without recent updates"),
1175                         style: "width: 600px",
1176                         getSelectedFeeds: function() {
1177                                 return getSelectedTableRowIds("prefInactiveFeedList");
1178                         },
1179                         removeSelected: function() {
1180                                 var sel_rows = this.getSelectedFeeds();
1181
1182                                 console.log(sel_rows);
1183
1184                                 if (sel_rows.length > 0) {
1185                                         var ok = confirm(__("Remove selected feeds?"));
1186
1187                                         if (ok) {
1188                                                 notify_progress("Removing selected feeds...", true);
1189
1190                                                 var query = "?op=pref-feeds&method=remove&ids="+
1191                                                         param_escape(sel_rows.toString());
1192
1193                                                 new Ajax.Request("backend.php", {
1194                                                         parameters: query,
1195                                                         onComplete: function(transport) {
1196                                                                 notify('');
1197                                                                 dialog.hide();
1198                                                                 updateFeedList();
1199                                                         } });
1200                                         }
1201
1202                                 } else {
1203                                         alert(__("No feeds are selected."));
1204                                 }
1205                         },
1206                         execute: function() {
1207                                 if (this.validate()) {
1208                                 }
1209                         },
1210                         href: query});
1211
1212                 dialog.show();
1213
1214         } catch (e) {
1215                 exception_error("showInactiveFeeds", e);
1216         }
1217
1218 }
1219
1220 function opmlRegenKey() {
1221
1222         try {
1223                 var ok = confirm(__("Replace current OPML publishing address with a new one?"));
1224
1225                 if (ok) {
1226
1227                         notify_progress("Trying to change address...", true);
1228
1229                         var query = "?op=rpc&method=regenOPMLKey";
1230
1231                         new Ajax.Request("backend.php", {
1232                                 parameters: query,
1233                                 onComplete: function(transport) {
1234                                                 var reply = JSON.parse(transport.responseText);
1235
1236                                                 var new_link = reply.link;
1237
1238                                                 var e = $('pub_opml_url');
1239
1240                                                 if (new_link) {
1241                                                         e.href = new_link;
1242                                                         e.innerHTML = new_link;
1243
1244                                                         new Effect.Highlight(e);
1245
1246                                                         notify('');
1247
1248                                                 } else {
1249                                                         notify_error("Could not change feed URL.");
1250                                                 }
1251                                 } });
1252                 }
1253         } catch (e) {
1254                 exception_error("opmlRegenKey", e);
1255         }
1256         return false;
1257 }
1258
1259 function feedActionChange() {
1260         try {
1261                 var chooser = $("feedActionChooser");
1262                 var opid = chooser[chooser.selectedIndex].value;
1263
1264                 chooser.selectedIndex = 0;
1265                 feedActionGo(opid);
1266         } catch (e) {
1267                 exception_error("feedActionChange", e);
1268         }
1269 }
1270
1271 function feedActionGo(op) {
1272         try {
1273                 if (op == "facEdit") {
1274
1275                         var rows = getSelectedFeeds();
1276
1277                         if (rows.length > 1) {
1278                                 editSelectedFeeds();
1279                         } else {
1280                                 editSelectedFeed();
1281                         }
1282                 }
1283
1284                 if (op == "facClear") {
1285                         clearSelectedFeeds();
1286                 }
1287
1288                 if (op == "facPurge") {
1289                         purgeSelectedFeeds();
1290                 }
1291
1292                 if (op == "facEditCats") {
1293                         editFeedCats();
1294                 }
1295
1296                 if (op == "facRescore") {
1297                         rescoreSelectedFeeds();
1298                 }
1299
1300                 if (op == "facUnsubscribe") {
1301                         removeSelectedFeeds();
1302                 }
1303
1304         } catch (e) {
1305                 exception_error("feedActionGo", e);
1306
1307         }
1308 }
1309
1310 function clearFeedArticles(feed_id) {
1311
1312         notify_progress("Clearing feed...");
1313
1314         var query = "?op=pref-feeds&quiet=1&method=clear&id=" + feed_id;
1315
1316         new Ajax.Request("backend.php", {
1317                 parameters: query,
1318                 onComplete: function(transport) {
1319                                 notify('');
1320                         } });
1321
1322         return false;
1323 }
1324
1325 function rescoreSelectedFeeds() {
1326
1327         var sel_rows = getSelectedFeeds();
1328
1329         if (sel_rows.length > 0) {
1330
1331                 //var ok = confirm(__("Rescore last 100 articles in selected feeds?"));
1332                 var ok = confirm(__("Rescore articles in selected feeds?"));
1333
1334                 if (ok) {
1335                         notify_progress("Rescoring selected feeds...", true);
1336
1337                         var query = "?op=pref-feeds&method=rescore&quiet=1&ids="+
1338                                 param_escape(sel_rows.toString());
1339
1340                         new Ajax.Request("backend.php", {
1341                                 parameters: query,
1342                                 onComplete: function(transport) {
1343                                                 notify_callback2(transport);
1344                         } });
1345
1346                 }
1347         } else {
1348                 alert(__("No feeds are selected."));
1349         }
1350
1351         return false;
1352 }
1353
1354 function rescore_all_feeds() {
1355         var ok = confirm(__("Rescore all articles? This operation may take a lot of time."));
1356
1357         if (ok) {
1358                 notify_progress("Rescoring feeds...", true);
1359
1360                 var query = "?op=pref-feeds&method=rescoreAll&quiet=1";
1361
1362                 new Ajax.Request("backend.php", {
1363                         parameters: query,
1364                         onComplete: function(transport) {
1365                                         notify_callback2(transport);
1366                 } });
1367         }
1368 }
1369
1370 function labelColorReset() {
1371         try {
1372                 var labels = getSelectedLabels();
1373
1374                 if (labels.length > 0) {
1375                         var ok = confirm(__("Reset selected labels to default colors?"));
1376
1377                         if (ok) {
1378                                 var query = "?op=pref-labels&method=colorreset&ids="+
1379                                         param_escape(labels.toString());
1380
1381                                 new Ajax.Request("backend.php", {
1382                                         parameters: query,
1383                                         onComplete: function(transport) {
1384                                                 updateLabelList();
1385                                         } });
1386                         }
1387
1388                 } else {
1389                         alert(__("No labels are selected."));
1390                 }
1391
1392         } catch (e) {
1393                 exception_error("labelColorReset", e);
1394         }
1395 }
1396
1397
1398 function inPreferences() {
1399         return true;
1400 }
1401
1402 function editProfiles() {
1403         try {
1404
1405                 if (dijit.byId("profileEditDlg"))
1406                         dijit.byId("profileEditDlg").destroyRecursive();
1407
1408                 var query = "backend.php?op=dlg&method=editPrefProfiles";
1409
1410                 dialog = new dijit.Dialog({
1411                         id: "profileEditDlg",
1412                         title: __("Settings Profiles"),
1413                         style: "width: 600px",
1414                         getSelectedProfiles: function() {
1415                                 return getSelectedTableRowIds("prefFeedProfileList");
1416                         },
1417                         removeSelected: function() {
1418                                 var sel_rows = this.getSelectedProfiles();
1419
1420                                 if (sel_rows.length > 0) {
1421                                         var ok = confirm(__("Remove selected profiles? Active and default profiles will not be removed."));
1422
1423                                         if (ok) {
1424                                                 notify_progress("Removing selected profiles...", true);
1425
1426                                                 var query = "?op=rpc&method=remprofiles&ids="+
1427                                                         param_escape(sel_rows.toString());
1428
1429                                                 new Ajax.Request("backend.php", {
1430                                                         parameters: query,
1431                                                         onComplete: function(transport) {
1432                                                                 notify('');
1433                                                                 editProfiles();
1434                                                         } });
1435
1436                                         }
1437
1438                                 } else {
1439                                         alert(__("No profiles are selected."));
1440                                 }
1441                         },
1442                         activateProfile: function() {
1443                                 var sel_rows = this.getSelectedProfiles();
1444
1445                                 if (sel_rows.length == 1) {
1446
1447                                         var ok = confirm(__("Activate selected profile?"));
1448
1449                                         if (ok) {
1450                                                 notify_progress("Loading, please wait...");
1451
1452                                                 var query = "?op=rpc&method=setprofile&id="+
1453                                                         param_escape(sel_rows.toString());
1454
1455                                                 new Ajax.Request("backend.php", {
1456                                                         parameters: query,
1457                                                         onComplete: function(transport) {
1458                                                                 window.location.reload();
1459                                                         } });
1460                                         }
1461
1462                                 } else {
1463                                         alert(__("Please choose a profile to activate."));
1464                                 }
1465                         },
1466                         addProfile: function() {
1467                                 if (this.validate()) {
1468                                         notify_progress("Creating profile...", true);
1469
1470                                         var query = "?op=rpc&method=addprofile&title=" +
1471                                                 param_escape(dialog.attr('value').newprofile);
1472
1473                                         new Ajax.Request("backend.php", {
1474                                                 parameters: query,
1475                                                 onComplete: function(transport) {
1476                                                         notify('');
1477                                                         editProfiles();
1478                                                 } });
1479
1480                                 }
1481                         },
1482                         execute: function() {
1483                                 if (this.validate()) {
1484                                 }
1485                         },
1486                         href: query});
1487
1488                 dialog.show();
1489         } catch (e) {
1490                 exception_error("editProfiles", e);
1491         }
1492 }
1493
1494 function activatePrefProfile() {
1495
1496         var sel_rows = getSelectedFeedCats();
1497
1498         if (sel_rows.length == 1) {
1499
1500                 var ok = confirm(__("Activate selected profile?"));
1501
1502                 if (ok) {
1503                         notify_progress("Loading, please wait...");
1504
1505                         var query = "?op=rpc&method=setprofile&id="+
1506                                 param_escape(sel_rows.toString());
1507
1508                         new Ajax.Request("backend.php", {
1509                                 parameters: query,
1510                                 onComplete: function(transport) {
1511                                         window.location.reload();
1512                                 } });
1513                 }
1514
1515         } else {
1516                 alert(__("Please choose a profile to activate."));
1517         }
1518
1519         return false;
1520 }
1521
1522 function clearFeedAccessKeys() {
1523
1524         var ok = confirm(__("This will invalidate all previously generated feed URLs. Continue?"));
1525
1526         if (ok) {
1527                 notify_progress("Clearing URLs...");
1528
1529                 var query = "?op=rpc&method=clearKeys";
1530
1531                 new Ajax.Request("backend.php", {
1532                         parameters: query,
1533                         onComplete: function(transport) {
1534                                 notify_info("Generated URLs cleared.");
1535                         } });
1536         }
1537
1538         return false;
1539 }
1540
1541 function clearArticleAccessKeys() {
1542
1543         var ok = confirm(__("This will invalidate all previously shared article URLs. Continue?"));
1544
1545         if (ok) {
1546                 notify_progress("Clearing URLs...");
1547
1548                 var query = "?op=rpc&method=clearArticleKeys";
1549
1550                 new Ajax.Request("backend.php", {
1551                         parameters: query,
1552                         onComplete: function(transport) {
1553                                 notify_info("Shared URLs cleared.");
1554                         } });
1555         }
1556
1557         return false;
1558 }
1559 function resetFeedOrder() {
1560         try {
1561                 notify_progress("Loading, please wait...");
1562
1563                 new Ajax.Request("backend.php", {
1564                         parameters: "?op=pref-feeds&method=feedsortreset",
1565                         onComplete: function(transport) {
1566                                 updateFeedList();
1567                         } });
1568
1569
1570         } catch (e) {
1571                 exception_error("resetFeedOrder");
1572         }
1573 }
1574
1575 function resetCatOrder() {
1576         try {
1577                 notify_progress("Loading, please wait...");
1578
1579                 new Ajax.Request("backend.php", {
1580                         parameters: "?op=pref-feeds&method=catsortreset",
1581                         onComplete: function(transport) {
1582                                 updateFeedList();
1583                         } });
1584
1585
1586         } catch (e) {
1587                 exception_error("resetCatOrder");
1588         }
1589 }
1590
1591 function toggleHiddenFeedCats() {
1592         try {
1593                 notify_progress("Loading, please wait...");
1594
1595                 new Ajax.Request("backend.php", {
1596                         parameters: "?op=pref-feeds&method=togglehiddenfeedcats",
1597                         onComplete: function(transport) {
1598                                 updateFeedList();
1599                         } });
1600
1601         } catch (e) {
1602                 exception_error("toggleHiddenFeedCats");
1603         }
1604 }
1605
1606 function editCat(id, item, event) {
1607         try {
1608                 var new_name = prompt(__('Rename category to:'), item.name);
1609
1610                 if (new_name && new_name != item.name) {
1611
1612                         notify_progress("Loading, please wait...");
1613
1614                         new Ajax.Request("backend.php", {
1615                         parameters: {
1616                                 op: 'pref-feeds',
1617                                 method: 'renamecat',
1618                                 id: id,
1619                                 title: new_name,
1620                         },
1621                         onComplete: function(transport) {
1622                                 updateFeedList();
1623                         } });
1624                 }
1625
1626         } catch (e) {
1627                 exception_error("editCat", e);
1628         }
1629 }
1630
1631 function editLabel(id, event) {
1632         try {
1633                 var query = "backend.php?op=pref-labels&method=edit&id=" +
1634                         param_escape(id);
1635
1636                 if (dijit.byId("labelEditDlg"))
1637                         dijit.byId("labelEditDlg").destroyRecursive();
1638
1639                 dialog = new dijit.Dialog({
1640                         id: "labelEditDlg",
1641                         title: __("Label Editor"),
1642                         style: "width: 600px",
1643                         setLabelColor: function(id, fg, bg) {
1644
1645                                 var kind = '';
1646                                 var color = '';
1647
1648                                 if (fg && bg) {
1649                                         kind = 'both';
1650                                 } else if (fg) {
1651                                         kind = 'fg';
1652                                         color = fg;
1653                                 } else if (bg) {
1654                                         kind = 'bg';
1655                                         color = bg;
1656                                 }
1657
1658                                 var query = "?op=pref-labels&method=colorset&kind="+kind+
1659                                         "&ids=" + param_escape(id) + "&fg=" + param_escape(fg) +
1660                                         "&bg=" + param_escape(bg) + "&color=" + param_escape(color);
1661
1662                 //              console.log(query);
1663
1664                                 var e = $("LICID-" + id);
1665
1666                                 if (e) {
1667                                         if (fg) e.style.color = fg;
1668                                         if (bg) e.style.backgroundColor = bg;
1669                                 }
1670
1671                                 new Ajax.Request("backend.php", { parameters: query });
1672
1673                                 updateFilterList();
1674                         },
1675                         execute: function() {
1676                                 if (this.validate()) {
1677                                         var caption = this.attr('value').caption;
1678                                         var fg_color = this.attr('value').fg_color;
1679                                         var bg_color = this.attr('value').bg_color;
1680                                         var query = dojo.objectToQuery(this.attr('value'));
1681
1682                                         dijit.byId('labelTree').setNameById(id, caption);
1683                                         this.setLabelColor(id, fg_color, bg_color);
1684                                         this.hide();
1685
1686                                         new Ajax.Request("backend.php", {
1687                                                 parameters: query,
1688                                                 onComplete: function(transport) {
1689                                                         updateFilterList();
1690                                         } });
1691                                 }
1692                         },
1693                         href: query});
1694
1695                 dialog.show();
1696
1697         } catch (e) {
1698                 exception_error("editLabel", e);
1699         }
1700 }
1701
1702 function clearTwitterCredentials() {
1703         try {
1704                 var ok = confirm(__("This will clear your stored authentication information for Twitter. Continue?"));
1705
1706                 if (ok) {
1707                         notify_progress("Clearing credentials...");
1708
1709                         var query = "?op=pref-feeds&method=remtwitterinfo";
1710
1711                         new Ajax.Request("backend.php", {
1712                                 parameters: query,
1713                                 onComplete: function(transport) {
1714                                         notify_info("Twitter credentials have been cleared.");
1715                                         updateFeedList();
1716                                 } });
1717                 }
1718
1719         } catch (e) {
1720                 exception_error("clearTwitterCredentials", e);
1721         }
1722 }
1723
1724 function customizeCSS() {
1725         try {
1726                 var query = "backend.php?op=dlg&method=customizeCSS";
1727
1728                 if (dijit.byId("cssEditDlg"))
1729                         dijit.byId("cssEditDlg").destroyRecursive();
1730
1731                 dialog = new dijit.Dialog({
1732                         id: "cssEditDlg",
1733                         title: __("Customize stylesheet"),
1734                         style: "width: 600px",
1735                         execute: function() {
1736                                 notify_progress('Saving data...', true);
1737                                 new Ajax.Request("backend.php", {
1738                                         parameters: dojo.objectToQuery(this.attr('value')),
1739                                         onComplete: function(transport) {
1740                                                 notify('');
1741                                                 window.location.reload();
1742                                 } });
1743
1744                         },
1745                         href: query});
1746
1747                 dialog.show();
1748
1749         } catch (e) {
1750                 exception_error("customizeCSS", e);
1751         }
1752 }
1753
1754 function insertSSLserial(value) {
1755         try {
1756                 dijit.byId("SSL_CERT_SERIAL").attr('value', value);
1757         } catch (e) {
1758                 exception_error("insertSSLcerial", e);
1759         }
1760 }
1761
1762 function gotoExportOpml(filename, settings) {
1763         tmp = settings ? 1 : 0;
1764         document.location.href = "backend.php?op=opml&method=export&filename=" + filename + "&settings=" + tmp;
1765 }
1766
1767
1768 function batchSubscribe() {
1769         try {
1770                 var query = "backend.php?op=dlg&method=batchSubscribe";
1771
1772                 // overlapping widgets
1773                 if (dijit.byId("batchSubDlg")) dijit.byId("batchSubDlg").destroyRecursive();
1774                 if (dijit.byId("feedAddDlg"))   dijit.byId("feedAddDlg").destroyRecursive();
1775
1776                 var dialog = new dijit.Dialog({
1777                         id: "batchSubDlg",
1778                         title: __("Batch subscribe"),
1779                         style: "width: 600px",
1780                         execute: function() {
1781                                 if (this.validate()) {
1782                                         console.log(dojo.objectToQuery(this.attr('value')));
1783
1784                                         notify_progress(__("Subscribing to feeds..."), true);
1785
1786                                         new Ajax.Request("backend.php", {
1787                                                 parameters: dojo.objectToQuery(this.attr('value')),
1788                                                 onComplete: function(transport) {
1789                                                         notify("");
1790                                                         updateFeedList();
1791                                                         dialog.hide();
1792                                                 } });
1793                                         }
1794                         },
1795                         href: query});
1796
1797                 dialog.show();
1798         } catch (e) {
1799                 exception_error("batchSubscribe", e);
1800         }
1801 }
1802
1803
1804 function toggleAdvancedPrefs() {
1805         try {
1806                 notify_progress("Loading, please wait...");
1807
1808                 new Ajax.Request("backend.php", {
1809                         parameters: "?op=pref-prefs&method=toggleadvanced",
1810                         onComplete: function(transport) {
1811                                 updatePrefsList();
1812                         } });
1813
1814         } catch (e) {
1815                 exception_error("toggleAdvancedPrefs", e);
1816         }
1817 }
1818
1819 function clearPluginData(name) {
1820         try {
1821                 if (confirm(__("Clear stored data for this plugin?"))) {
1822                         notify_progress("Loading, please wait...");
1823
1824                         new Ajax.Request("backend.php", {
1825                                 parameters: "?op=pref-prefs&method=clearplugindata&name=" + param_escape(name),
1826                                 onComplete: function(transport) {
1827                                         notify('');
1828                                         updatePrefsList();
1829                                 } });
1830                 }
1831         } catch (e) {
1832                 exception_error("clearPluginData", e);
1833         }
1834 }