]> git.wh0rd.org Git - tt-rss.git/blob - js/prefs.js
remove duplicated code from hotkey actions handler
[tt-rss.git] / js / prefs.js
1 /* global dijit, __ */
2
3 let seq = "";
4
5 function notify_callback2(transport, sticky) {
6         notify_info(transport.responseText, sticky);
7 }
8
9 function updateFeedList() {
10
11         const user_search = $("feed_search");
12         let search = "";
13         if (user_search) { search = user_search.value; }
14
15         xhrPost("backend.php", { op: "pref-feeds", search: search }, (transport) => {
16                 dijit.byId('feedConfigTab').attr('content', transport.responseText);
17                 selectTab("feedConfig", true);
18                 notify("");
19         });
20 }
21
22 function checkInactiveFeeds() {
23         xhrPost("backend.php", { op: "pref-feeds", method: "getinactivefeeds" }, (transport) => {
24                 if (parseInt(transport.responseText) > 0) {
25                         Element.show(dijit.byId("pref_feeds_inactive_btn").domNode);
26                 }
27         });
28 }
29
30 function updateUsersList(sort_key) {
31         const user_search = $("user_search");
32         const search = user_search ? user_search.value : "";
33
34         const query = { op: "pref-users", sort:  sort_key, search: search };
35
36         xhrPost("backend.php", query, (transport) => {
37                 dijit.byId('userConfigTab').attr('content', transport.responseText);
38                 selectTab("userConfig", true)
39                 notify("");
40         });
41 }
42
43 function addUser() {
44         const login = prompt(__("Please enter login:"), "");
45
46         if (login == null) {
47                 return false;
48         }
49
50         if (login == "") {
51                 alert(__("Can't create user: no login specified."));
52                 return false;
53         }
54
55         notify_progress("Adding user...");
56
57         xhrPost("backend.php", { op: "pref-users", method: "add", login: login }, (transport) => {
58         notify_callback2(transport);
59         updateUsersList();
60     });
61
62 }
63
64 function editUser(id) {
65
66         const query = "backend.php?op=pref-users&method=edit&id=" +
67                 param_escape(id);
68
69         if (dijit.byId("userEditDlg"))
70                 dijit.byId("userEditDlg").destroyRecursive();
71
72         const dialog = new dijit.Dialog({
73                 id: "userEditDlg",
74                 title: __("User Editor"),
75                 style: "width: 600px",
76                 execute: function () {
77                         if (this.validate()) {
78                                 notify_progress("Saving data...", true);
79
80                                 xhrPost("backend.php", dojo.formToObject("user_edit_form"), (transport) => {
81                     dialog.hide();
82                     updateUsersList();
83                 });
84                         }
85                 },
86                 href: query
87         });
88
89         dialog.show();
90 }
91
92 function editFilter(id) {
93
94         const query = "backend.php?op=pref-filters&method=edit&id=" + param_escape(id);
95
96         if (dijit.byId("feedEditDlg"))
97                 dijit.byId("feedEditDlg").destroyRecursive();
98
99         if (dijit.byId("filterEditDlg"))
100                 dijit.byId("filterEditDlg").destroyRecursive();
101
102         const dialog = new dijit.Dialog({
103                 id: "filterEditDlg",
104                 title: __("Edit Filter"),
105                 style: "width: 600px",
106
107                 test: function () {
108                         const query = "backend.php?" + dojo.formToQuery("filter_edit_form") + "&savemode=test";
109
110                         editFilterTest(query);
111                 },
112                 selectRules: function (select) {
113                         $$("#filterDlg_Matches input[type=checkbox]").each(function (e) {
114                                 e.checked = select;
115                                 if (select)
116                                         e.parentNode.addClassName("Selected");
117                                 else
118                                         e.parentNode.removeClassName("Selected");
119                         });
120                 },
121                 selectActions: function (select) {
122                         $$("#filterDlg_Actions input[type=checkbox]").each(function (e) {
123                                 e.checked = select;
124
125                                 if (select)
126                                         e.parentNode.addClassName("Selected");
127                                 else
128                                         e.parentNode.removeClassName("Selected");
129
130                         });
131                 },
132                 editRule: function (e) {
133                         const li = e.parentNode;
134                         const rule = li.getElementsByTagName("INPUT")[1].value;
135                         addFilterRule(li, rule);
136                 },
137                 editAction: function (e) {
138                         const li = e.parentNode;
139                         const action = li.getElementsByTagName("INPUT")[1].value;
140                         addFilterAction(li, action);
141                 },
142                 removeFilter: function () {
143                         const msg = __("Remove filter?");
144
145                         if (confirm(msg)) {
146                                 this.hide();
147
148                                 notify_progress("Removing filter...");
149
150                                 const query = { op: "pref-filters", method: "remove", ids: this.attr('value').id };
151
152                                 xhrPost("backend.php", query, () => {
153                                         updateFilterList();
154                                 });
155                         }
156                 },
157                 addAction: function () {
158                         addFilterAction();
159                 },
160                 addRule: function () {
161                         addFilterRule();
162                 },
163                 deleteAction: function () {
164                         $$("#filterDlg_Actions li[class*=Selected]").each(function (e) {
165                                 e.parentNode.removeChild(e)
166                         });
167                 },
168                 deleteRule: function () {
169                         $$("#filterDlg_Matches li[class*=Selected]").each(function (e) {
170                                 e.parentNode.removeChild(e)
171                         });
172                 },
173                 execute: function () {
174                         if (this.validate()) {
175
176                                 notify_progress("Saving data...", true);
177
178                                 xhrPost("backend.php", dojo.formToObject("filter_edit_form"), () => {
179                                         dialog.hide();
180                                         updateFilterList();
181                                 });
182                         }
183                 },
184                 href: query
185         });
186
187         dialog.show();
188 }
189
190
191 function getSelectedLabels() {
192         const tree = dijit.byId("labelTree");
193         const items = tree.model.getCheckedItems();
194         const rv = [];
195
196         items.each(function(item) {
197                 rv.push(tree.model.store.getValue(item, 'bare_id'));
198         });
199
200         return rv;
201 }
202
203 function getSelectedUsers() {
204         return getSelectedTableRowIds("prefUserList");
205 }
206
207 function getSelectedFeeds() {
208         const tree = dijit.byId("feedTree");
209         const items = tree.model.getCheckedItems();
210         const rv = [];
211
212         items.each(function(item) {
213                 if (item.id[0].match("FEED:"))
214                         rv.push(tree.model.store.getValue(item, 'bare_id'));
215         });
216
217         return rv;
218 }
219
220 function getSelectedCategories() {
221         const tree = dijit.byId("feedTree");
222         const items = tree.model.getCheckedItems();
223         const rv = [];
224
225         items.each(function(item) {
226                 if (item.id[0].match("CAT:"))
227                         rv.push(tree.model.store.getValue(item, 'bare_id'));
228         });
229
230         return rv;
231 }
232
233 function getSelectedFilters() {
234         const tree = dijit.byId("filterTree");
235         const items = tree.model.getCheckedItems();
236         const 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 removeSelectedLabels() {
247
248         const sel_rows = getSelectedLabels();
249
250         if (sel_rows.length > 0) {
251
252                 const ok = confirm(__("Remove selected labels?"));
253
254                 if (ok) {
255                         notify_progress("Removing selected labels...");
256
257                         const query = { op: "pref-labels", method: "remove",
258                                 ids: sel_rows.toString() };
259
260                         xhrPost("backend.php",  query, () => {
261                                 updateLabelList();
262                         });
263                 }
264         } else {
265                 alert(__("No labels are selected."));
266         }
267
268         return false;
269 }
270
271 function removeSelectedUsers() {
272
273         const sel_rows = getSelectedUsers();
274
275         if (sel_rows.length > 0) {
276
277                 const ok = confirm(__("Remove selected users? Neither default admin nor your account will be removed."));
278
279                 if (ok) {
280                         notify_progress("Removing selected users...");
281
282                         const query = { op: "pref-users", method: "remove",
283                                 ids: sel_rows.toString() };
284
285                         xhrPost("backend.php", query, () => {
286                                 updateUsersList();
287                         });
288                 }
289
290         } else {
291                 alert(__("No users are selected."));
292         }
293
294         return false;
295 }
296
297 function removeSelectedFilters() {
298
299         const sel_rows = getSelectedFilters();
300
301         if (sel_rows.length > 0) {
302
303                 const ok = confirm(__("Remove selected filters?"));
304
305                 if (ok) {
306                         notify_progress("Removing selected filters...");
307
308                         const query = { op: "pref-filters", method: "remove",
309                                 ids:  sel_rows.toString() };
310
311                         xhrPost("backend.php", query, () => {
312                                 updateFilterList();
313                         });
314                 }
315         } else {
316                 alert(__("No filters are selected."));
317         }
318
319         return false;
320 }
321
322 function removeSelectedFeeds() {
323
324         const sel_rows = getSelectedFeeds();
325
326         if (sel_rows.length > 0) {
327
328                 const ok = confirm(__("Unsubscribe from selected feeds?"));
329
330                 if (ok) {
331
332                         notify_progress("Unsubscribing from selected feeds...", true);
333
334                         const query = { op: "pref-feeds", method: "remove",
335                                 ids: sel_rows.toString() };
336
337                         xhrPost("backend.php", query, () => {
338                                 updateFeedList();
339                         });
340                 }
341
342         } else {
343                 alert(__("No feeds are selected."));
344         }
345
346         return false;
347 }
348
349 function editSelectedUser() {
350         const rows = getSelectedUsers();
351
352         if (rows.length == 0) {
353                 alert(__("No users are selected."));
354                 return;
355         }
356
357         if (rows.length > 1) {
358                 alert(__("Please select only one user."));
359                 return;
360         }
361
362         notify("");
363
364         editUser(rows[0]);
365 }
366
367 function resetSelectedUserPass() {
368
369         const rows = getSelectedUsers();
370
371         if (rows.length == 0) {
372                 alert(__("No users are selected."));
373                 return;
374         }
375
376         if (rows.length > 1) {
377                 alert(__("Please select only one user."));
378                 return;
379         }
380
381         const ok = confirm(__("Reset password of selected user?"));
382
383         if (ok) {
384                 notify_progress("Resetting password for selected user...");
385
386                 const id = rows[0];
387
388                 xhrPost("backend.php", { op: "pref-users", method: "resetPass", id: id }, (transport) => {
389                         notify_info(transport.responseText, true);
390                 });
391
392         }
393 }
394
395 function selectedUserDetails() {
396
397         const rows = getSelectedUsers();
398
399         if (rows.length == 0) {
400                 alert(__("No users are selected."));
401                 return;
402         }
403
404         if (rows.length > 1) {
405                 alert(__("Please select only one user."));
406                 return;
407         }
408
409         const query = "backend.php?op=pref-users&method=userdetails&id=" + param_escape(rows[0]);
410
411         if (dijit.byId("userDetailsDlg"))
412                 dijit.byId("userDetailsDlg").destroyRecursive();
413
414         const dialog = new dijit.Dialog({
415                 id: "userDetailsDlg",
416                 title: __("User details"),
417                 style: "width: 600px",
418                 execute: function () {
419                         dialog.hide();
420                 },
421                 href: query
422         });
423
424         dialog.show();
425 }
426
427
428 function editSelectedFilter() {
429         const rows = getSelectedFilters();
430
431         if (rows.length == 0) {
432                 alert(__("No filters are selected."));
433                 return;
434         }
435
436         if (rows.length > 1) {
437                 alert(__("Please select only one filter."));
438                 return;
439         }
440
441         notify("");
442
443         editFilter(rows[0]);
444
445 }
446
447 function joinSelectedFilters() {
448         const rows = getSelectedFilters();
449
450         if (rows.length == 0) {
451                 alert(__("No filters are selected."));
452                 return;
453         }
454
455         const ok = confirm(__("Combine selected filters?"));
456
457         if (ok) {
458                 notify_progress("Joining filters...");
459
460                 xhrPost("backend.php", { op: "pref-filters", method: "join", ids: rows.toString() }, () => {
461                         updateFilterList();
462                 });
463         }
464 }
465
466 function editSelectedFeed() {
467         const rows = getSelectedFeeds();
468
469         if (rows.length == 0) {
470                 alert(__("No feeds are selected."));
471                 return;
472         }
473
474         if (rows.length > 1) {
475                 return editSelectedFeeds();
476         }
477
478         notify("");
479
480         editFeed(rows[0], {});
481
482 }
483
484 function editSelectedFeeds() {
485         const rows = getSelectedFeeds();
486
487         if (rows.length == 0) {
488                 alert(__("No feeds are selected."));
489                 return;
490         }
491
492         notify_progress("Loading, please wait...");
493
494         if (dijit.byId("feedEditDlg"))
495                 dijit.byId("feedEditDlg").destroyRecursive();
496
497         xhrPost("backend.php", { op: "pref-feeds", method: "editfeeds", ids: rows.toString() }, (transport) => {
498                 notify("");
499
500                 const dialog = new dijit.Dialog({
501                         id: "feedEditDlg",
502                         title: __("Edit Multiple Feeds"),
503                         style: "width: 600px",
504                         getChildByName: function (name) {
505                                 let rv = null;
506                                 this.getChildren().each(
507                                         function (child) {
508                                                 if (child.name == name) {
509                                                         rv = child;
510                                                         return;
511                                                 }
512                                         });
513                                 return rv;
514                         },
515                         toggleField: function (checkbox, elem, label) {
516                                 this.getChildByName(elem).attr('disabled', !checkbox.checked);
517
518                                 if ($(label))
519                                         if (checkbox.checked)
520                                                 $(label).removeClassName('insensitive');
521                                         else
522                                                 $(label).addClassName('insensitive');
523
524                         },
525                         execute: function () {
526                                 if (this.validate() && confirm(__("Save changes to selected feeds?"))) {
527                                         const query = this.attr('value');
528
529                                         /* normalize unchecked checkboxes because [] is not serialized */
530
531                                         Object.keys(query).each((key) => {
532                                                 let val = query[key];
533
534                                                 if (typeof val == "object" && val.length == 0)
535                                                         query[key] = ["off"];
536                                         });
537
538                                         notify_progress("Saving data...", true);
539
540                                         xhrPost("backend.php", query, () => {
541                                                 dialog.hide();
542                                                 updateFeedList();
543                                         });
544                                 }
545                         },
546                         content: transport.responseText
547                 });
548
549                 dialog.show();
550         });
551 }
552
553 function opmlImportComplete(iframe) {
554         if (!iframe.contentDocument.body.innerHTML) return false;
555
556         Element.show(iframe);
557
558         notify('');
559
560         if (dijit.byId('opmlImportDlg'))
561                 dijit.byId('opmlImportDlg').destroyRecursive();
562
563         const content = iframe.contentDocument.body.innerHTML;
564
565         const dialog = new dijit.Dialog({
566                 id: "opmlImportDlg",
567                 title: __("OPML Import"),
568                 style: "width: 600px",
569                 onCancel: function () {
570             window.location.reload();
571                 },
572                 execute: function () {
573                         window.location.reload();
574                 },
575                 content: content
576         });
577
578         dialog.show();
579 }
580
581 function opmlImport() {
582
583         const opml_file = $("opml_file");
584
585         if (opml_file.value.length == 0) {
586                 alert(__("Please choose an OPML file first."));
587                 return false;
588         } else {
589                 notify_progress("Importing, please wait...", true);
590
591                 Element.show("upload_iframe");
592
593                 return true;
594         }
595 }
596
597
598 function updateFilterList() {
599         const user_search = $("filter_search");
600         let search = "";
601         if (user_search) { search = user_search.value; }
602
603         xhrPost("backend.php", { op: "pref-filters", search: search }, (transport) => {
604         dijit.byId('filterConfigTab').attr('content', transport.responseText);
605         notify("");
606     });
607 }
608
609 function updateLabelList() {
610         xhrPost("backend.php", { op: "pref-labels" }, (transport) => {
611         dijit.byId('labelConfigTab').attr('content', transport.responseText);
612         notify("");
613     });
614 }
615
616 function updatePrefsList() {
617     xhrPost("backend.php", { op: "pref-prefs" }, (transport) => {
618         dijit.byId('genConfigTab').attr('content', transport.responseText);
619         notify("");
620     });
621 }
622
623 function updateSystemList() {
624     xhrPost("backend.php", { op: "pref-system" }, (transport) => {
625         dijit.byId('systemConfigTab').attr('content', transport.responseText);
626         notify("");
627     });
628 }
629
630 function selectTab(id, noupdate) {
631         if (!noupdate) {
632                 notify_progress("Loading, please wait...");
633
634                 switch (id) {
635                         case "feedConfig":
636                 updateFeedList();
637                                 break;
638                         case "filterConfig":
639                 updateFilterList();
640                                 break;
641                         case "labelConfig":
642                 updateLabelList();
643                                 break;
644                         case "genConfig":
645                 updatePrefsList();
646                                 break;
647                         case "userConfig":
648                 updateUsersList();
649                                 break;
650                         case "systemConfig":
651                 updateSystemList();
652                                 break;
653                         default:
654                                 console.warn("unknown tab", id);
655                 }
656
657                 const tab = dijit.byId(id + "Tab");
658                 dijit.byId("pref-tabs").selectChild(tab);
659
660         }
661 }
662
663 function init_second_stage() {
664         document.onkeydown = pref_hotkey_handler;
665         loading_set_progress(50);
666         notify("");
667
668         let tab = getURLParam('tab');
669
670         if (tab) {
671                 tab = dijit.byId(tab + "Tab");
672                 if (tab) dijit.byId("pref-tabs").selectChild(tab);
673         }
674
675         const method = getURLParam('method');
676
677         if (method == 'editFeed') {
678                 const param = getURLParam('methodparam');
679
680                 window.setTimeout(function() { editFeed(param) }, 100);
681         }
682
683         setInterval(hotkey_prefix_timeout, 5*1000);
684 }
685
686 function init() {
687         window.onerror = function (message, filename, lineno, colno, error) {
688                 report_error(message, filename, lineno, colno, error);
689         };
690
691         require(["dojo/_base/kernel",
692                 "dojo/ready",
693                 "dojo/parser",
694                 "dojo/_base/loader",
695                 "dojo/_base/html",
696                 "dijit/ColorPalette",
697                 "dijit/Dialog",
698                 "dijit/form/Button",
699                 "dijit/form/CheckBox",
700                 "dijit/form/DropDownButton",
701                 "dijit/form/FilteringSelect",
702         "dijit/form/MultiSelect",
703                 "dijit/form/Form",
704                 "dijit/form/RadioButton",
705                 "dijit/form/ComboButton",
706                 "dijit/form/Select",
707                 "dijit/form/SimpleTextarea",
708                 "dijit/form/TextBox",
709                 "dijit/form/ValidationTextBox",
710                 "dijit/InlineEditBox",
711                 "dijit/layout/AccordionContainer",
712                 "dijit/layout/AccordionPane",
713                 "dijit/layout/BorderContainer",
714                 "dijit/layout/ContentPane",
715                 "dijit/layout/TabContainer",
716                 "dijit/Menu",
717                 "dijit/ProgressBar",
718                 "dijit/Toolbar",
719                 "dijit/Tree",
720                 "dijit/tree/dndSource",
721                 "dojo/data/ItemFileWriteStore",
722                 "lib/CheckBoxStoreModel",
723                 "lib/CheckBoxTree",
724                 "fox/PrefFeedStore",
725                 "fox/PrefFilterStore",
726                 "fox/PrefFeedTree",
727                 "fox/PrefFilterTree",
728                 "fox/PrefLabelTree"], function (dojo, ready, parser) {
729
730                 ready(function () {
731                         try {
732                                 parser.parse();
733
734                                 loading_set_progress(50);
735
736                                 const clientTzOffset = new Date().getTimezoneOffset() * 60;
737
738                                 new Ajax.Request("backend.php", {
739                                         parameters: {
740                                                 op: "rpc", method: "sanityCheck",
741                                                 clientTzOffset: clientTzOffset
742                                         },
743                                         onComplete: function (transport) {
744                                                 backend_sanity_check_callback(transport);
745                                         }
746                                 });
747                         } catch (e) {
748                                 exception_error(e);
749                         }
750                 });
751         });
752 }
753
754
755 function validatePrefsReset() {
756         if (confirm(__("Reset to defaults?"))) {
757
758                 const query = "?op=pref-prefs&method=resetconfig";
759
760                 xhrPost("backend.php", { op: "pref-prefs", method: "resetconfig" }, (transport) => {
761             updatePrefsList();
762             notify_info(transport.responseText);
763         });
764         }
765
766         return false;
767 }
768
769 function pref_hotkey_handler(e) {
770     if (e.target.nodeName == "INPUT" || e.target.nodeName == "TEXTAREA") return;
771
772     const action_name = keyevent_to_action(e);
773
774     if (action_name) {
775         switch (action_name) {
776             case "feed_subscribe":
777                 quickAddFeed();
778                 return false;
779             case "create_label":
780                 addLabel();
781                 return false;
782             case "create_filter":
783                 quickAddFilter();
784                 return false;
785             case "help_dialog":
786                 helpDialog("main");
787                 return false;
788             default:
789                 console.log("unhandled action: " + action_name + "; keycode: " + e.which);
790         }
791         }
792 }
793
794 function removeCategory(id, item) {
795
796         const ok = confirm(__("Remove category %s? Any nested feeds would be placed into Uncategorized.").replace("%s", item.name));
797
798         if (ok) {
799                 const query = "?op=pref-feeds&method=removeCat&ids=" +
800                         param_escape(id);
801
802                 notify_progress("Removing category...");
803
804                 new Ajax.Request("backend.php", {
805                         parameters: query,
806                         onComplete: function (transport) {
807                                 notify('');
808                                 updateFeedList();
809                         }
810                 });
811         }
812 }
813
814 function removeSelectedCategories() {
815
816         const sel_rows = getSelectedCategories();
817
818         if (sel_rows.length > 0) {
819
820                 const ok = confirm(__("Remove selected categories?"));
821
822                 if (ok) {
823                         notify_progress("Removing selected categories...");
824
825                         const query = "?op=pref-feeds&method=removeCat&ids="+
826                                 param_escape(sel_rows.toString());
827
828                         new Ajax.Request("backend.php", {
829                                 parameters: query,
830                                 onComplete: function(transport) {
831                                                 updateFeedList();
832                                         } });
833
834                 }
835         } else {
836                 alert(__("No categories are selected."));
837         }
838
839         return false;
840 }
841
842 function createCategory() {
843         const title = prompt(__("Category title:"));
844
845         if (title) {
846
847                 notify_progress("Creating category...");
848
849                 const query = "?op=pref-feeds&method=addCat&cat=" +
850                         param_escape(title);
851
852                 new Ajax.Request("backend.php", {
853                         parameters: query,
854                         onComplete: function (transport) {
855                                 notify('');
856                                 updateFeedList();
857                         }
858                 });
859         }
860 }
861
862 function showInactiveFeeds() {
863         const query = "backend.php?op=pref-feeds&method=inactiveFeeds";
864
865         if (dijit.byId("inactiveFeedsDlg"))
866                 dijit.byId("inactiveFeedsDlg").destroyRecursive();
867
868         const dialog = new dijit.Dialog({
869                 id: "inactiveFeedsDlg",
870                 title: __("Feeds without recent updates"),
871                 style: "width: 600px",
872                 getSelectedFeeds: function () {
873                         return getSelectedTableRowIds("prefInactiveFeedList");
874                 },
875                 removeSelected: function () {
876                         const sel_rows = this.getSelectedFeeds();
877
878                         console.log(sel_rows);
879
880                         if (sel_rows.length > 0) {
881                                 const ok = confirm(__("Remove selected feeds?"));
882
883                                 if (ok) {
884                                         notify_progress("Removing selected feeds...", true);
885
886                                         const query = "?op=pref-feeds&method=remove&ids=" +
887                                                 param_escape(sel_rows.toString());
888
889                                         new Ajax.Request("backend.php", {
890                                                 parameters: query,
891                                                 onComplete: function (transport) {
892                                                         notify('');
893                                                         dialog.hide();
894                                                         updateFeedList();
895                                                 }
896                                         });
897                                 }
898
899                         } else {
900                                 alert(__("No feeds are selected."));
901                         }
902                 },
903                 execute: function () {
904                         if (this.validate()) {
905                         }
906                 },
907                 href: query
908         });
909
910         dialog.show();
911 }
912
913 function opmlRegenKey() {
914         const ok = confirm(__("Replace current OPML publishing address with a new one?"));
915
916         if (ok) {
917
918                 notify_progress("Trying to change address...", true);
919
920                 const query = "?op=pref-feeds&method=regenOPMLKey";
921
922                 new Ajax.Request("backend.php", {
923                         parameters: query,
924                         onComplete: function (transport) {
925                                 const reply = JSON.parse(transport.responseText);
926
927                                 const new_link = reply.link;
928
929                                 const e = $('pub_opml_url');
930
931                                 if (new_link) {
932                                         e.href = new_link;
933                                         e.innerHTML = new_link;
934
935                                         new Effect.Highlight(e);
936
937                                         notify('');
938
939                                 } else {
940                                         notify_error("Could not change feed URL.");
941                                 }
942                         }
943                 });
944         }
945         return false;
946 }
947
948 function labelColorReset() {
949         const labels = getSelectedLabels();
950
951         if (labels.length > 0) {
952                 const ok = confirm(__("Reset selected labels to default colors?"));
953
954                 if (ok) {
955                         const query = "?op=pref-labels&method=colorreset&ids=" +
956                                 param_escape(labels.toString());
957
958                         new Ajax.Request("backend.php", {
959                                 parameters: query,
960                                 onComplete: function (transport) {
961                                         updateLabelList();
962                                 }
963                         });
964                 }
965
966         } else {
967                 alert(__("No labels are selected."));
968         }
969 }
970
971 function inPreferences() {
972         return true;
973 }
974
975 function editProfiles() {
976
977         if (dijit.byId("profileEditDlg"))
978                 dijit.byId("profileEditDlg").destroyRecursive();
979
980         const query = "backend.php?op=pref-prefs&method=editPrefProfiles";
981
982         const dialog = new dijit.Dialog({
983                 id: "profileEditDlg",
984                 title: __("Settings Profiles"),
985                 style: "width: 600px",
986                 getSelectedProfiles: function () {
987                         return getSelectedTableRowIds("prefFeedProfileList");
988                 },
989                 removeSelected: function () {
990                         const sel_rows = this.getSelectedProfiles();
991
992                         if (sel_rows.length > 0) {
993                                 const ok = confirm(__("Remove selected profiles? Active and default profiles will not be removed."));
994
995                                 if (ok) {
996                                         notify_progress("Removing selected profiles...", true);
997
998                                         const query = { op: "rpc", method: "remprofiles",
999                                                 ids: sel_rows.toString() };
1000
1001                                         xhrPost("backend.php", query, () => {
1002                                                 notify('');
1003                                                 editProfiles();
1004                                         });
1005                                 }
1006
1007                         } else {
1008                                 alert(__("No profiles are selected."));
1009                         }
1010                 },
1011                 activateProfile: function () {
1012                         const sel_rows = this.getSelectedProfiles();
1013
1014                         if (sel_rows.length == 1) {
1015
1016                                 const ok = confirm(__("Activate selected profile?"));
1017
1018                                 if (ok) {
1019                                         notify_progress("Loading, please wait...");
1020
1021                     xhrPost("backend.php", { op: "rpc", method: "setprofile", id: sel_rows.toString() },  () => {
1022                         window.location.reload();
1023                     });
1024                                 }
1025
1026                         } else {
1027                                 alert(__("Please choose a profile to activate."));
1028                         }
1029                 },
1030                 addProfile: function () {
1031                         if (this.validate()) {
1032                                 notify_progress("Creating profile...", true);
1033
1034                                 const query = { op: "rpc", method: "addprofile", title: dialog.attr('value').newprofile };
1035
1036                                 xhrPost("backend.php", query, () => {
1037                                         notify('');
1038                                         editProfiles();
1039                                 });
1040
1041                         }
1042                 },
1043                 execute: function () {
1044                         if (this.validate()) {
1045                         }
1046                 },
1047                 href: query
1048         });
1049
1050         dialog.show();
1051 }
1052
1053 /*
1054 function activatePrefProfile() {
1055
1056         const sel_rows = getSelectedFeedCats();
1057
1058         if (sel_rows.length == 1) {
1059
1060                 const ok = confirm(__("Activate selected profile?"));
1061
1062                 if (ok) {
1063                         notify_progress("Loading, please wait...");
1064
1065                         xhrPost("backend.php", { op: "rpc", method: "setprofile", id: sel_rows.toString() },  () => {
1066                                 window.location.reload();
1067                         });
1068                 }
1069
1070         } else {
1071                 alert(__("Please choose a profile to activate."));
1072         }
1073
1074         return false;
1075 } */
1076
1077 function clearFeedAccessKeys() {
1078
1079         const ok = confirm(__("This will invalidate all previously generated feed URLs. Continue?"));
1080
1081         if (ok) {
1082                 notify_progress("Clearing URLs...");
1083
1084                 xhrPost("backend.php", { op: "pref-feeds", method: "clearKeys" }, () => {
1085             notify_info("Generated URLs cleared.");
1086         });
1087         }
1088
1089         return false;
1090 }
1091
1092 function resetFilterOrder() {
1093         notify_progress("Loading, please wait...");
1094
1095     xhrPost("backend.php", { op: "pref-filters", method: "filtersortreset" }, () => {
1096         updateFilterList();
1097     });
1098 }
1099
1100
1101 function resetFeedOrder() {
1102         notify_progress("Loading, please wait...");
1103
1104     xhrPost("backend.php", { op: "pref-feeds", method: "feedsortreset" }, () => {
1105         updateFeedList();
1106     });
1107 }
1108
1109 function resetCatOrder() {
1110         notify_progress("Loading, please wait...");
1111
1112         xhrPost("backend.php", { op: "pref-feeds", method: "catsortreset" }, () => {
1113                 updateFeedList();
1114         });
1115 }
1116
1117 function editCat(id, item) {
1118         const new_name = prompt(__('Rename category to:'), item.name);
1119
1120         if (new_name && new_name != item.name) {
1121
1122                 notify_progress("Loading, please wait...");
1123
1124                 xhrPost("backend.php", { op: 'pref-feeds', method: 'renamecat', id: id, title: new_name }, () => {
1125                         updateFeedList();
1126                 });
1127         }
1128 }
1129
1130 function editLabel(id) {
1131         const query = "backend.php?op=pref-labels&method=edit&id=" +
1132                 param_escape(id);
1133
1134         if (dijit.byId("labelEditDlg"))
1135                 dijit.byId("labelEditDlg").destroyRecursive();
1136
1137         const dialog = new dijit.Dialog({
1138                 id: "labelEditDlg",
1139                 title: __("Label Editor"),
1140                 style: "width: 600px",
1141                 setLabelColor: function (id, fg, bg) {
1142
1143                         let kind = '';
1144                         let color = '';
1145
1146                         if (fg && bg) {
1147                                 kind = 'both';
1148                         } else if (fg) {
1149                                 kind = 'fg';
1150                                 color = fg;
1151                         } else if (bg) {
1152                                 kind = 'bg';
1153                                 color = bg;
1154                         }
1155
1156                         const e = $("LICID-" + id);
1157
1158                         if (e) {
1159                                 if (fg) e.style.color = fg;
1160                                 if (bg) e.style.backgroundColor = bg;
1161                         }
1162
1163             const query = { op: "pref-labels", method: "colorset", kind: kind,
1164                 ids: id, fg: fg, bg: bg, color: color };
1165
1166             xhrPost("backend.php", query, () => {
1167                 updateFilterList(); // maybe there's labels in there
1168                         });
1169
1170                 },
1171                 execute: function () {
1172                         if (this.validate()) {
1173                                 const caption = this.attr('value').caption;
1174                                 const fg_color = this.attr('value').fg_color;
1175                                 const bg_color = this.attr('value').bg_color;
1176
1177                                 dijit.byId('labelTree').setNameById(id, caption);
1178                                 this.setLabelColor(id, fg_color, bg_color);
1179                                 this.hide();
1180
1181                                 xhrPost("backend.php", this.attr('value'), () => {
1182                     updateFilterList(); // maybe there's labels in there
1183                                 });
1184                         }
1185                 },
1186                 href: query
1187         });
1188
1189         dialog.show();
1190 }
1191
1192
1193 function customizeCSS() {
1194         const query = "backend.php?op=pref-prefs&method=customizeCSS";
1195
1196         if (dijit.byId("cssEditDlg"))
1197                 dijit.byId("cssEditDlg").destroyRecursive();
1198
1199         const dialog = new dijit.Dialog({
1200                 id: "cssEditDlg",
1201                 title: __("Customize stylesheet"),
1202                 style: "width: 600px",
1203                 execute: function () {
1204                         notify_progress('Saving data...', true);
1205
1206                         xhrPost("backend.php", this.attr('value'), () => {
1207                                 window.location.reload();
1208                         });
1209
1210                 },
1211                 href: query
1212         });
1213
1214         dialog.show();
1215 }
1216
1217 function insertSSLserial(value) {
1218         dijit.byId("SSL_CERT_SERIAL").attr('value', value);
1219 }
1220
1221 function gotoExportOpml(filename, settings) {
1222         const tmp = settings ? 1 : 0;
1223         document.location.href = "backend.php?op=opml&method=export&filename=" + filename + "&settings=" + tmp;
1224 }
1225
1226
1227 function batchSubscribe() {
1228         const query = "backend.php?op=pref-feeds&method=batchSubscribe";
1229
1230         // overlapping widgets
1231         if (dijit.byId("batchSubDlg")) dijit.byId("batchSubDlg").destroyRecursive();
1232         if (dijit.byId("feedAddDlg"))    dijit.byId("feedAddDlg").destroyRecursive();
1233
1234         const dialog = new dijit.Dialog({
1235                 id: "batchSubDlg",
1236                 title: __("Batch subscribe"),
1237                 style: "width: 600px",
1238                 execute: function () {
1239                         if (this.validate()) {
1240                                 notify_progress(__("Subscribing to feeds..."), true);
1241
1242                                 xhrPost("backend.php", this.attr('value'), () => {
1243                                         notify("");
1244                                         updateFeedList();
1245                                         dialog.hide();
1246                                 });
1247                         }
1248                 },
1249                 href: query
1250         });
1251
1252         dialog.show();
1253 }
1254
1255 function clearPluginData(name) {
1256         if (confirm(__("Clear stored data for this plugin?"))) {
1257                 notify_progress("Loading, please wait...");
1258
1259                 xhrPost("backend.php", { op: "pref-prefs", method: "clearplugindata", name: name }, () => {
1260                         notify('');
1261                         updatePrefsList();
1262                 });
1263         }
1264 }
1265
1266 function clearSqlLog() {
1267
1268         if (confirm(__("Clear all messages in the error log?"))) {
1269
1270                 notify_progress("Loading, please wait...");
1271
1272                 xhrPost("backend.php",  { op: "pref-system", method: "clearLog" }, () => {
1273                         updateSystemList();
1274                 });
1275
1276         }
1277 }
1278
1279 function updateSelectedPrompt() {
1280         // no-op shim for toggleSelectedRow()
1281 }
1282