]>
git.wh0rd.org - tt-rss.git/blob - js/prefs.js
1358b940412b56baff866f0fcb165dc144dead01
5 function notify_callback2(transport
, sticky
) {
6 notify_info(transport
.responseText
, sticky
);
9 function updateFeedList() {
11 const user_search
= $("feed_search");
13 if (user_search
) { search
= user_search
.value
; }
15 xhrPost("backend.php", { op
: "pref-feeds", search
: search
}, (transport
) => {
16 dijit
.byId('feedConfigTab').attr('content', transport
.responseText
);
17 selectTab("feedConfig", true);
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
);
30 function updateUsersList(sort_key
) {
31 const user_search
= $("user_search");
32 const search
= user_search
? user_search
.value
: "";
34 const query
= { op
: "pref-users", sort
: sort_key
, search
: search
};
36 xhrPost("backend.php", query
, (transport
) => {
37 dijit
.byId('userConfigTab').attr('content', transport
.responseText
);
38 selectTab("userConfig", true)
44 const login
= prompt(__("Please enter login:"), "");
51 alert(__("Can't create user: no login specified."));
55 notify_progress("Adding user...");
57 xhrPost("backend.php", { op
: "pref-users", method
: "add", login
: login
}, (transport
) => {
58 notify_callback2(transport
);
64 function editUser(id
) {
66 const query
= "backend.php?op=pref-users&method=edit&id=" +
69 if (dijit
.byId("userEditDlg"))
70 dijit
.byId("userEditDlg").destroyRecursive();
72 const dialog
= new dijit
.Dialog({
74 title
: __("User Editor"),
75 style
: "width: 600px",
76 execute: function () {
77 if (this.validate()) {
78 notify_progress("Saving data...", true);
80 xhrPost("backend.php", dojo
.formToObject("user_edit_form"), (transport
) => {
92 function editFilter(id
) {
94 const query
= "backend.php?op=pref-filters&method=edit&id=" + param_escape(id
);
96 if (dijit
.byId("feedEditDlg"))
97 dijit
.byId("feedEditDlg").destroyRecursive();
99 if (dijit
.byId("filterEditDlg"))
100 dijit
.byId("filterEditDlg").destroyRecursive();
102 const dialog
= new dijit
.Dialog({
104 title
: __("Edit Filter"),
105 style
: "width: 600px",
108 const query
= "backend.php?" + dojo
.formToQuery("filter_edit_form") + "&savemode=test";
110 editFilterTest(query
);
112 selectRules: function (select
) {
113 $$("#filterDlg_Matches input[type=checkbox]").each(function (e
) {
116 e
.parentNode
.addClassName("Selected");
118 e
.parentNode
.removeClassName("Selected");
121 selectActions: function (select
) {
122 $$("#filterDlg_Actions input[type=checkbox]").each(function (e
) {
126 e
.parentNode
.addClassName("Selected");
128 e
.parentNode
.removeClassName("Selected");
132 editRule: function (e
) {
133 const li
= e
.parentNode
;
134 const rule
= li
.getElementsByTagName("INPUT")[1].value
;
135 addFilterRule(li
, rule
);
137 editAction: function (e
) {
138 const li
= e
.parentNode
;
139 const action
= li
.getElementsByTagName("INPUT")[1].value
;
140 addFilterAction(li
, action
);
142 removeFilter: function () {
143 const msg
= __("Remove filter?");
148 notify_progress("Removing filter...");
150 const query
= { op
: "pref-filters", method
: "remove", ids
: this.attr('value').id
};
152 xhrPost("backend.php", query
, () => {
157 addAction: function () {
160 addRule: function () {
163 deleteAction: function () {
164 $$("#filterDlg_Actions li[class*=Selected]").each(function (e
) {
165 e
.parentNode
.removeChild(e
)
168 deleteRule: function () {
169 $$("#filterDlg_Matches li[class*=Selected]").each(function (e
) {
170 e
.parentNode
.removeChild(e
)
173 execute: function () {
174 if (this.validate()) {
176 notify_progress("Saving data...", true);
178 xhrPost("backend.php", dojo
.formToObject("filter_edit_form"), () => {
191 function getSelectedLabels() {
192 const tree
= dijit
.byId("labelTree");
193 const items
= tree
.model
.getCheckedItems();
196 items
.each(function(item
) {
197 rv
.push(tree
.model
.store
.getValue(item
, 'bare_id'));
203 function getSelectedUsers() {
204 return getSelectedTableRowIds("prefUserList");
207 function getSelectedFeeds() {
208 const tree
= dijit
.byId("feedTree");
209 const items
= tree
.model
.getCheckedItems();
212 items
.each(function(item
) {
213 if (item
.id
[0].match("FEED:"))
214 rv
.push(tree
.model
.store
.getValue(item
, 'bare_id'));
220 function getSelectedCategories() {
221 const tree
= dijit
.byId("feedTree");
222 const items
= tree
.model
.getCheckedItems();
225 items
.each(function(item
) {
226 if (item
.id
[0].match("CAT:"))
227 rv
.push(tree
.model
.store
.getValue(item
, 'bare_id'));
233 function getSelectedFilters() {
234 const tree
= dijit
.byId("filterTree");
235 const items
= tree
.model
.getCheckedItems();
238 items
.each(function(item
) {
239 rv
.push(tree
.model
.store
.getValue(item
, 'bare_id'));
246 function removeSelectedLabels() {
248 const sel_rows
= getSelectedLabels();
250 if (sel_rows
.length
> 0) {
252 const ok
= confirm(__("Remove selected labels?"));
255 notify_progress("Removing selected labels...");
257 const query
= { op
: "pref-labels", method
: "remove",
258 ids
: sel_rows
.toString() };
260 xhrPost("backend.php", query
, () => {
265 alert(__("No labels are selected."));
271 function removeSelectedUsers() {
273 const sel_rows
= getSelectedUsers();
275 if (sel_rows
.length
> 0) {
277 const ok
= confirm(__("Remove selected users? Neither default admin nor your account will be removed."));
280 notify_progress("Removing selected users...");
282 const query
= { op
: "pref-users", method
: "remove",
283 ids
: sel_rows
.toString() };
285 xhrPost("backend.php", query
, () => {
291 alert(__("No users are selected."));
297 function removeSelectedFilters() {
299 const sel_rows
= getSelectedFilters();
301 if (sel_rows
.length
> 0) {
303 const ok
= confirm(__("Remove selected filters?"));
306 notify_progress("Removing selected filters...");
308 const query
= { op
: "pref-filters", method
: "remove",
309 ids
: sel_rows
.toString() };
311 xhrPost("backend.php", query
, () => {
316 alert(__("No filters are selected."));
322 function removeSelectedFeeds() {
324 const sel_rows
= getSelectedFeeds();
326 if (sel_rows
.length
> 0) {
328 const ok
= confirm(__("Unsubscribe from selected feeds?"));
332 notify_progress("Unsubscribing from selected feeds...", true);
334 const query
= { op
: "pref-feeds", method
: "remove",
335 ids
: sel_rows
.toString() };
337 xhrPost("backend.php", query
, () => {
343 alert(__("No feeds are selected."));
349 function editSelectedUser() {
350 const rows
= getSelectedUsers();
352 if (rows
.length
== 0) {
353 alert(__("No users are selected."));
357 if (rows
.length
> 1) {
358 alert(__("Please select only one user."));
367 function resetSelectedUserPass() {
369 const rows
= getSelectedUsers();
371 if (rows
.length
== 0) {
372 alert(__("No users are selected."));
376 if (rows
.length
> 1) {
377 alert(__("Please select only one user."));
381 const ok
= confirm(__("Reset password of selected user?"));
384 notify_progress("Resetting password for selected user...");
388 xhrPost("backend.php", { op
: "pref-users", method
: "resetPass", id
: id
}, (transport
) => {
389 notify_info(transport
.responseText
, true);
395 function selectedUserDetails() {
397 const rows
= getSelectedUsers();
399 if (rows
.length
== 0) {
400 alert(__("No users are selected."));
404 if (rows
.length
> 1) {
405 alert(__("Please select only one user."));
409 const query
= "backend.php?op=pref-users&method=userdetails&id=" + param_escape(rows
[0]);
411 if (dijit
.byId("userDetailsDlg"))
412 dijit
.byId("userDetailsDlg").destroyRecursive();
414 const dialog
= new dijit
.Dialog({
415 id
: "userDetailsDlg",
416 title
: __("User details"),
417 style
: "width: 600px",
418 execute: function () {
428 function editSelectedFilter() {
429 const rows
= getSelectedFilters();
431 if (rows
.length
== 0) {
432 alert(__("No filters are selected."));
436 if (rows
.length
> 1) {
437 alert(__("Please select only one filter."));
447 function joinSelectedFilters() {
448 const rows
= getSelectedFilters();
450 if (rows
.length
== 0) {
451 alert(__("No filters are selected."));
455 const ok
= confirm(__("Combine selected filters?"));
458 notify_progress("Joining filters...");
460 xhrPost("backend.php", { op
: "pref-filters", method
: "join", ids
: rows
.toString() }, () => {
466 function editSelectedFeed() {
467 const rows
= getSelectedFeeds();
469 if (rows
.length
== 0) {
470 alert(__("No feeds are selected."));
474 if (rows
.length
> 1) {
475 return editSelectedFeeds();
480 editFeed(rows
[0], {});
484 function editSelectedFeeds() {
485 const rows
= getSelectedFeeds();
487 if (rows
.length
== 0) {
488 alert(__("No feeds are selected."));
492 notify_progress("Loading, please wait...");
494 if (dijit
.byId("feedEditDlg"))
495 dijit
.byId("feedEditDlg").destroyRecursive();
497 xhrPost("backend.php", { op
: "pref-feeds", method
: "editfeeds", ids
: rows
.toString() }, (transport
) => {
500 const dialog
= new dijit
.Dialog({
502 title
: __("Edit Multiple Feeds"),
503 style
: "width: 600px",
504 getChildByName: function (name
) {
506 this.getChildren().each(
508 if (child
.name
== name
) {
515 toggleField: function (checkbox
, elem
, label
) {
516 this.getChildByName(elem
).attr('disabled', !checkbox
.checked
);
519 if (checkbox
.checked
)
520 $(label
).removeClassName('insensitive');
522 $(label
).addClassName('insensitive');
525 execute: function () {
526 if (this.validate() && confirm(__("Save changes to selected feeds?"))) {
527 const query
= this.attr('value');
529 /* normalize unchecked checkboxes because [] is not serialized */
531 Object
.keys(query
).each((key
) => {
532 let val
= query
[key
];
534 if (typeof val
== "object" && val
.length
== 0)
535 query
[key
] = ["off"];
538 notify_progress("Saving data...", true);
540 xhrPost("backend.php", query
, () => {
546 content
: transport
.responseText
553 function opmlImportComplete(iframe
) {
554 if (!iframe
.contentDocument
.body
.innerHTML
) return false;
556 Element
.show(iframe
);
560 if (dijit
.byId('opmlImportDlg'))
561 dijit
.byId('opmlImportDlg').destroyRecursive();
563 const content
= iframe
.contentDocument
.body
.innerHTML
;
565 const dialog
= new dijit
.Dialog({
567 title
: __("OPML Import"),
568 style
: "width: 600px",
569 onCancel: function () {
570 window
.location
.reload();
572 execute: function () {
573 window
.location
.reload();
581 function opmlImport() {
583 const opml_file
= $("opml_file");
585 if (opml_file
.value
.length
== 0) {
586 alert(__("Please choose an OPML file first."));
589 notify_progress("Importing, please wait...", true);
591 Element
.show("upload_iframe");
598 function updateFilterList() {
599 const user_search
= $("filter_search");
601 if (user_search
) { search
= user_search
.value
; }
603 xhrPost("backend.php", { op
: "pref-filters", search
: search
}, (transport
) => {
604 dijit
.byId('filterConfigTab').attr('content', transport
.responseText
);
609 function updateLabelList() {
610 xhrPost("backend.php", { op
: "pref-labels" }, (transport
) => {
611 dijit
.byId('labelConfigTab').attr('content', transport
.responseText
);
616 function updatePrefsList() {
617 xhrPost("backend.php", { op
: "pref-prefs" }, (transport
) => {
618 dijit
.byId('genConfigTab').attr('content', transport
.responseText
);
623 function updateSystemList() {
624 xhrPost("backend.php", { op
: "pref-system" }, (transport
) => {
625 dijit
.byId('systemConfigTab').attr('content', transport
.responseText
);
630 function selectTab(id
, noupdate
) {
632 notify_progress("Loading, please wait...");
654 console
.warn("unknown tab", id
);
657 const tab
= dijit
.byId(id
+ "Tab");
658 dijit
.byId("pref-tabs").selectChild(tab
);
663 function init_second_stage() {
664 document
.onkeydown
= pref_hotkey_handler
;
665 loading_set_progress(50);
668 let tab
= getURLParam('tab');
671 tab
= dijit
.byId(tab
+ "Tab");
672 if (tab
) dijit
.byId("pref-tabs").selectChild(tab
);
675 const method
= getURLParam('method');
677 if (method
== 'editFeed') {
678 const param
= getURLParam('methodparam');
680 window
.setTimeout(function() { editFeed(param
) }, 100);
683 setInterval(hotkey_prefix_timeout
, 5*1000);
687 window
.onerror = function (message
, filename
, lineno
, colno
, error
) {
688 report_error(message
, filename
, lineno
, colno
, error
);
691 require(["dojo/_base/kernel",
696 "dijit/ColorPalette",
699 "dijit/form/CheckBox",
700 "dijit/form/DropDownButton",
701 "dijit/form/FilteringSelect",
702 "dijit/form/MultiSelect",
704 "dijit/form/RadioButton",
705 "dijit/form/ComboButton",
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",
720 "dijit/tree/dndSource",
721 "dojo/data/ItemFileWriteStore",
722 "lib/CheckBoxStoreModel",
725 "fox/PrefFilterStore",
727 "fox/PrefFilterTree",
728 "fox/PrefLabelTree"], function (dojo
, ready
, parser
) {
734 loading_set_progress(50);
736 const clientTzOffset
= new Date().getTimezoneOffset() * 60;
738 new Ajax
.Request("backend.php", {
740 op
: "rpc", method
: "sanityCheck",
741 clientTzOffset
: clientTzOffset
743 onComplete: function (transport
) {
744 backend_sanity_check_callback(transport
);
755 function validatePrefsReset() {
756 if (confirm(__("Reset to defaults?"))) {
758 const query
= "?op=pref-prefs&method=resetconfig";
760 xhrPost("backend.php", { op
: "pref-prefs", method
: "resetconfig" }, (transport
) => {
762 notify_info(transport
.responseText
);
769 function pref_hotkey_handler(e
) {
770 if (e
.target
.nodeName
== "INPUT" || e
.target
.nodeName
== "TEXTAREA") return;
772 const action_name
= keyevent_to_action(e
);
775 switch (action_name
) {
776 case "feed_subscribe":
782 case "create_filter":
789 console
.log("unhandled action: " + action_name
+ "; keycode: " + e
.which
);
794 function removeCategory(id
, item
) {
796 const ok
= confirm(__("Remove category %s? Any nested feeds would be placed into Uncategorized.").replace("%s", item
.name
));
799 const query
= "?op=pref-feeds&method=removeCat&ids=" +
802 notify_progress("Removing category...");
804 new Ajax
.Request("backend.php", {
806 onComplete: function (transport
) {
814 function removeSelectedCategories() {
816 const sel_rows
= getSelectedCategories();
818 if (sel_rows
.length
> 0) {
820 const ok
= confirm(__("Remove selected categories?"));
823 notify_progress("Removing selected categories...");
825 const query
= "?op=pref-feeds&method=removeCat&ids="+
826 param_escape(sel_rows
.toString());
828 new Ajax
.Request("backend.php", {
830 onComplete: function(transport
) {
836 alert(__("No categories are selected."));
842 function createCategory() {
843 const title
= prompt(__("Category title:"));
847 notify_progress("Creating category...");
849 const query
= "?op=pref-feeds&method=addCat&cat=" +
852 new Ajax
.Request("backend.php", {
854 onComplete: function (transport
) {
862 function showInactiveFeeds() {
863 const query
= "backend.php?op=pref-feeds&method=inactiveFeeds";
865 if (dijit
.byId("inactiveFeedsDlg"))
866 dijit
.byId("inactiveFeedsDlg").destroyRecursive();
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");
875 removeSelected: function () {
876 const sel_rows
= this.getSelectedFeeds();
878 console
.log(sel_rows
);
880 if (sel_rows
.length
> 0) {
881 const ok
= confirm(__("Remove selected feeds?"));
884 notify_progress("Removing selected feeds...", true);
886 const query
= "?op=pref-feeds&method=remove&ids=" +
887 param_escape(sel_rows
.toString());
889 new Ajax
.Request("backend.php", {
891 onComplete: function (transport
) {
900 alert(__("No feeds are selected."));
903 execute: function () {
904 if (this.validate()) {
913 function opmlRegenKey() {
914 const ok
= confirm(__("Replace current OPML publishing address with a new one?"));
918 notify_progress("Trying to change address...", true);
920 const query
= "?op=pref-feeds&method=regenOPMLKey";
922 new Ajax
.Request("backend.php", {
924 onComplete: function (transport
) {
925 const reply
= JSON
.parse(transport
.responseText
);
927 const new_link
= reply
.link
;
929 const e
= $('pub_opml_url');
933 e
.innerHTML
= new_link
;
935 new Effect
.Highlight(e
);
940 notify_error("Could not change feed URL.");
948 function labelColorReset() {
949 const labels
= getSelectedLabels();
951 if (labels
.length
> 0) {
952 const ok
= confirm(__("Reset selected labels to default colors?"));
955 const query
= "?op=pref-labels&method=colorreset&ids=" +
956 param_escape(labels
.toString());
958 new Ajax
.Request("backend.php", {
960 onComplete: function (transport
) {
967 alert(__("No labels are selected."));
971 function inPreferences() {
975 function editProfiles() {
977 if (dijit
.byId("profileEditDlg"))
978 dijit
.byId("profileEditDlg").destroyRecursive();
980 const query
= "backend.php?op=pref-prefs&method=editPrefProfiles";
982 const dialog
= new dijit
.Dialog({
983 id
: "profileEditDlg",
984 title
: __("Settings Profiles"),
985 style
: "width: 600px",
986 getSelectedProfiles: function () {
987 return getSelectedTableRowIds("prefFeedProfileList");
989 removeSelected: function () {
990 const sel_rows
= this.getSelectedProfiles();
992 if (sel_rows
.length
> 0) {
993 const ok
= confirm(__("Remove selected profiles? Active and default profiles will not be removed."));
996 notify_progress("Removing selected profiles...", true);
998 const query
= { op
: "rpc", method
: "remprofiles",
999 ids
: sel_rows
.toString() };
1001 xhrPost("backend.php", query
, () => {
1008 alert(__("No profiles are selected."));
1011 activateProfile: function () {
1012 const sel_rows
= this.getSelectedProfiles();
1014 if (sel_rows
.length
== 1) {
1016 const ok
= confirm(__("Activate selected profile?"));
1019 notify_progress("Loading, please wait...");
1021 xhrPost("backend.php", { op
: "rpc", method
: "setprofile", id
: sel_rows
.toString() }, () => {
1022 window
.location
.reload();
1027 alert(__("Please choose a profile to activate."));
1030 addProfile: function () {
1031 if (this.validate()) {
1032 notify_progress("Creating profile...", true);
1034 const query
= { op
: "rpc", method
: "addprofile", title
: dialog
.attr('value').newprofile
};
1036 xhrPost("backend.php", query
, () => {
1043 execute: function () {
1044 if (this.validate()) {
1054 function activatePrefProfile() {
1056 const sel_rows = getSelectedFeedCats();
1058 if (sel_rows.length == 1) {
1060 const ok = confirm(__("Activate selected profile?"));
1063 notify_progress("Loading, please wait...");
1065 xhrPost("backend.php", { op: "rpc", method: "setprofile", id: sel_rows.toString() }, () => {
1066 window.location.reload();
1071 alert(__("Please choose a profile to activate."));
1077 function clearFeedAccessKeys() {
1079 const ok
= confirm(__("This will invalidate all previously generated feed URLs. Continue?"));
1082 notify_progress("Clearing URLs...");
1084 xhrPost("backend.php", { op
: "pref-feeds", method
: "clearKeys" }, () => {
1085 notify_info("Generated URLs cleared.");
1092 function resetFilterOrder() {
1093 notify_progress("Loading, please wait...");
1095 xhrPost("backend.php", { op
: "pref-filters", method
: "filtersortreset" }, () => {
1101 function resetFeedOrder() {
1102 notify_progress("Loading, please wait...");
1104 xhrPost("backend.php", { op
: "pref-feeds", method
: "feedsortreset" }, () => {
1109 function resetCatOrder() {
1110 notify_progress("Loading, please wait...");
1112 xhrPost("backend.php", { op
: "pref-feeds", method
: "catsortreset" }, () => {
1117 function editCat(id
, item
) {
1118 const new_name
= prompt(__('Rename category to:'), item
.name
);
1120 if (new_name
&& new_name
!= item
.name
) {
1122 notify_progress("Loading, please wait...");
1124 xhrPost("backend.php", { op
: 'pref-feeds', method
: 'renamecat', id
: id
, title
: new_name
}, () => {
1130 function editLabel(id
) {
1131 const query
= "backend.php?op=pref-labels&method=edit&id=" +
1134 if (dijit
.byId("labelEditDlg"))
1135 dijit
.byId("labelEditDlg").destroyRecursive();
1137 const dialog
= new dijit
.Dialog({
1139 title
: __("Label Editor"),
1140 style
: "width: 600px",
1141 setLabelColor: function (id
, fg
, bg
) {
1156 const e
= $("LICID-" + id
);
1159 if (fg
) e
.style
.color
= fg
;
1160 if (bg
) e
.style
.backgroundColor
= bg
;
1163 const query
= { op
: "pref-labels", method
: "colorset", kind
: kind
,
1164 ids
: id
, fg
: fg
, bg
: bg
, color
: color
};
1166 xhrPost("backend.php", query
, () => {
1167 updateFilterList(); // maybe there's labels in there
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
;
1177 dijit
.byId('labelTree').setNameById(id
, caption
);
1178 this.setLabelColor(id
, fg_color
, bg_color
);
1181 xhrPost("backend.php", this.attr('value'), () => {
1182 updateFilterList(); // maybe there's labels in there
1193 function customizeCSS() {
1194 const query
= "backend.php?op=pref-prefs&method=customizeCSS";
1196 if (dijit
.byId("cssEditDlg"))
1197 dijit
.byId("cssEditDlg").destroyRecursive();
1199 const dialog
= new dijit
.Dialog({
1201 title
: __("Customize stylesheet"),
1202 style
: "width: 600px",
1203 execute: function () {
1204 notify_progress('Saving data...', true);
1206 xhrPost("backend.php", this.attr('value'), () => {
1207 window
.location
.reload();
1217 function insertSSLserial(value
) {
1218 dijit
.byId("SSL_CERT_SERIAL").attr('value', value
);
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
;
1227 function batchSubscribe() {
1228 const query
= "backend.php?op=pref-feeds&method=batchSubscribe";
1230 // overlapping widgets
1231 if (dijit
.byId("batchSubDlg")) dijit
.byId("batchSubDlg").destroyRecursive();
1232 if (dijit
.byId("feedAddDlg")) dijit
.byId("feedAddDlg").destroyRecursive();
1234 const dialog
= new dijit
.Dialog({
1236 title
: __("Batch subscribe"),
1237 style
: "width: 600px",
1238 execute: function () {
1239 if (this.validate()) {
1240 notify_progress(__("Subscribing to feeds..."), true);
1242 xhrPost("backend.php", this.attr('value'), () => {
1255 function clearPluginData(name
) {
1256 if (confirm(__("Clear stored data for this plugin?"))) {
1257 notify_progress("Loading, please wait...");
1259 xhrPost("backend.php", { op
: "pref-prefs", method
: "clearplugindata", name
: name
}, () => {
1266 function clearSqlLog() {
1268 if (confirm(__("Clear all messages in the error log?"))) {
1270 notify_progress("Loading, please wait...");
1272 xhrPost("backend.php", { op
: "pref-system", method
: "clearLog" }, () => {
1279 function updateSelectedPrompt() {
1280 // no-op shim for toggleSelectedRow()