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