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