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