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