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