YARCO.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. // ==UserScript==
  2. // @name Yet Another Reddit Comment Overwriter
  3. // @namespace https://github.com/adriantache/YARCO/
  4. // @description Local script to overwrite all your comments with random ASCII characters and delete them. This works because Reddit doesn't store editing history, so technically this is the only way to obfuscate the contents of the comments. Based on Reddit Overwrite script v.1.4.8.
  5. // @include https://*.reddit.com/user/*/comments/
  6. // @include http://*.reddit.com/user/*/comments/
  7. // @version 0.4
  8. // @run-at document-start
  9. // ==/UserScript==
  10. //EXTRA OPTIONS (disabled by default)
  11. let set_default_settings = false //set the default options I use [[overrides all the below]]
  12. let show_overwrite_button = false //show separate button to overwrite
  13. let show_delete_button = false //show separate button to delete
  14. let generate_individual_delete_buttons = false //generate per comment delete and overwrite links
  15. let only_delete_old_comments = false //ignore comments newer than the limit below
  16. let old_comments_limit = 2 //if above is active, number of days after which a comment is considered old
  17. let only_delete_by_subreddit = false //ignore comments from subreddits other than the one chosen in the dropdown
  18. let time_between_actions = 2000 //reddit API limit is 60 actions per minute so don't exceed that
  19. let only_delete_downvoted = false //only delete comments under a certain karma
  20. let downvote_limit = -1 //if above is active, only delete comments with karma <= to this
  21. let ignore_upvoted = false //ignore comments over a certain karma (useless if only_delete_downvoted is active)
  22. let upvote_limit = 50 //if above is active, ignore comments with karma >= to this
  23. let auto_delete = false //automatically delete comments when navigating to comments page [[USE WITH FILTERS!]]
  24. let reload_on_completion = false //reload page on completion
  25. let highlight_comments = false //highlight comments selected for deletion
  26. let generate_comment_exclusion_buttons = false //generate buttons to prevent certain comments from being deleted
  27. //DEBUG
  28. let safeMode = false //process comments without performing any actions, used for debugging
  29. // TODO add STOP button
  30. // TODO add optional confirmation dialog OR start up delay
  31. // TODO add logic to avoid posts and enable using script on other user pages (Overview and Submitted)
  32. // TODO check compatibility with new reddit
  33. // TODO implement dictionary instead of random characters to defeat overwrite detection
  34. // TODO add buttons to exclude individual comments
  35. // TODO add color coding to comments selected for deletion (or to exclude buttons)
  36. // reddit username
  37. unsafeWindow.user = '';
  38. // array of comments (more precisely author tags)
  39. unsafeWindow.comments = [];
  40. // top section contents
  41. unsafeWindow.div = null;
  42. //status text
  43. unsafeWindow.status_message = null;
  44. // subreddit selected for deletion
  45. unsafeWindow.subreddit = "ALL";
  46. unsafeWindow.subreddit_array = [];
  47. //store comments to be skipped from overwrite/delete
  48. unsafeWindow.comment_exclusion_array = [];
  49. // on page loaded, initialize the script
  50. window.addEventListener("DOMContentLoaded", init_script, false);
  51. function init_script(ev) {
  52. //if activated, set default settings for the extra options above
  53. if (set_default_settings) setDefaults();
  54. if (safeMode) setSafeModeDefaults();
  55. // get logged in username
  56. unsafeWindow.user = document.querySelector("span.user > a:not(.login-required)").innerHTML;
  57. // if not logged in exit
  58. if (!unsafeWindow.user) return;
  59. // retrieve all VISIBLE comments
  60. get_comments();
  61. // automatically start deletion process instead of generating buttons, if active
  62. if (auto_delete) {
  63. unsafeWindow.start_processing_comments(true, true);
  64. }
  65. else {
  66. // generate the top buttons
  67. generate_top_buttons();
  68. }
  69. }
  70. function get_comments() {
  71. // find all author tags to eventually get comments
  72. let comments = document.querySelectorAll("a.author");
  73. // filter out other authors
  74. unsafeWindow.comments = [].filter.call(comments, filter_author);
  75. // remove duplicates to fix double processing of comments to own posts
  76. unsafeWindow.comments = filter_duplicates(unsafeWindow.comments);
  77. //if active, filter out excluded comments
  78. if (generate_comment_exclusion_buttons && unsafeWindow.comment_exclusion_array.length !== 0) {
  79. unsafeWindow.comments = [].filter.call(unsafeWindow.comments, filter_exclusion);
  80. }
  81. // if active, filter out comments from the past 24 hours
  82. if (only_delete_old_comments) {
  83. unsafeWindow.comments = [].filter.call(unsafeWindow.comments, filter_time);
  84. }
  85. // if active, filter out comments from other subreddits than the chosen one
  86. if (only_delete_by_subreddit && unsafeWindow.subreddit !== "ALL") {
  87. unsafeWindow.comments = [].filter.call(unsafeWindow.comments, filter_subreddit);
  88. }
  89. // if active, filter out non downvoted comments
  90. if (only_delete_downvoted) {
  91. unsafeWindow.comments = [].filter.call(unsafeWindow.comments, filter_downvotes);
  92. }
  93. // if active, filter out upvoted comments
  94. if (ignore_upvoted) {
  95. unsafeWindow.comments = [].filter.call(unsafeWindow.comments, filter_upvotes);
  96. }
  97. update_status_text();
  98. if (highlight_comments) update_highlighting();
  99. }
  100. // append buttons to page
  101. function generate_top_buttons() {
  102. if (unsafeWindow.comments.length) {
  103. unsafeWindow.div = document.createElement("div");
  104. unsafeWindow.div.setAttribute('class', 'nextprev secure_delete_all');
  105. unsafeWindow.div.innerHTML = "";
  106. unsafeWindow.div.style.marginBottom = "10px";
  107. unsafeWindow.div.style.display = "flex";
  108. unsafeWindow.div.style.justifyContent = "flex-start";
  109. unsafeWindow.div.style.alignItems = "center";
  110. // make Subreddit Filter
  111. if (only_delete_by_subreddit) {
  112. //Create array of subreddits from comments
  113. unsafeWindow.subreddit_array = get_subreddit_array();
  114. let selectList = document.createElement("select");
  115. selectList.id = "subredditSelect";
  116. selectList.setAttribute('onChange', 'javascript: subreddit_select(this.value)')
  117. let selectedTitle = document.createElement("option");
  118. selectedTitle.selected = true;
  119. selectedTitle.disabled = true;
  120. selectedTitle.label = "Subreddit";
  121. selectList.append(selectedTitle);
  122. //Create and append the options
  123. for (let i = 0; i < unsafeWindow.subreddit_array.length; i++) {
  124. let option = document.createElement("option");
  125. option.value = unsafeWindow.subreddit_array[i];
  126. option.text = unsafeWindow.subreddit_array[i];
  127. selectList.appendChild(option);
  128. }
  129. unsafeWindow.div.appendChild(selectList);
  130. }
  131. // make Status message
  132. let status_div = document.createElement("div");
  133. status_div.style.marginLeft = "10px";
  134. unsafeWindow.status_message = document.createElement("p");
  135. unsafeWindow.status_message.setAttribute('class', 'status_message');
  136. unsafeWindow.status_message.innerHTML = "ERROR";
  137. status_div.appendChild(unsafeWindow.status_message);
  138. unsafeWindow.div.appendChild(status_div);
  139. // make Overwrite and Delete All link
  140. let odlink = document.createElement("a");
  141. odlink.setAttribute('class', 'bylink');
  142. odlink.setAttribute('onClick', 'javascript: start_processing_comments(true, true)');
  143. odlink.setAttribute('href', 'javascript:void(0)');
  144. odlink.style.marginLeft = "10px";
  145. odlink.appendChild(document.createTextNode('OVERWRITE AND DELETE'));
  146. unsafeWindow.div.appendChild(odlink);
  147. let br = document.createElement("br");
  148. unsafeWindow.div.appendChild(br);
  149. if (show_overwrite_button) {
  150. // make Overwrite All link
  151. let olink = document.createElement("a");
  152. olink.setAttribute('class', 'bylink');
  153. olink.setAttribute('onClick', 'javascript: start_processing_comments(true, false)');
  154. olink.setAttribute('href', 'javascript:void(0)');
  155. olink.style.marginLeft = "10px";
  156. olink.appendChild(document.createTextNode('OVERWRITE'));
  157. unsafeWindow.div.appendChild(olink);
  158. let br2 = document.createElement("br");
  159. unsafeWindow.div.appendChild(br2);
  160. }
  161. if (show_delete_button) {
  162. // make Delete All link
  163. let dlink = document.createElement("a");
  164. dlink.setAttribute('class', 'bylink');
  165. dlink.setAttribute('onClick', 'javascript: start_processing_comments(false, true)');
  166. dlink.setAttribute('href', 'javascript:void(0)');
  167. dlink.style.marginLeft = "10px";
  168. dlink.appendChild(document.createTextNode('DELETE'));
  169. unsafeWindow.div.appendChild(dlink);
  170. }
  171. if (safeMode) {
  172. // make Safe Mode message
  173. let safe_mode_div = document.createElement("div");
  174. safe_mode_div.style.marginLeft = "10px";
  175. let safe_mode_message = document.createElement("p");
  176. safe_mode_message.setAttribute('class', 'safe_mode_message');
  177. safe_mode_message.style.color = "green";
  178. safe_mode_message.innerHTML = "Safe Mode Active";
  179. safe_mode_div.appendChild(safe_mode_message);
  180. unsafeWindow.div.appendChild(safe_mode_div);
  181. }
  182. //add our div to the webpage
  183. document.querySelector("div.content")
  184. .insertBefore(unsafeWindow.div, document.querySelector("div.content").firstChild);
  185. //update status text now that we have defined unsafeWindow.status_message
  186. update_status_text();
  187. } else {
  188. let div = document.createElement("div");
  189. div.style.marginLeft = "15px";
  190. div.innerHTML = "YARCO: No comments found. Please check your active filters and try again.";
  191. document.querySelector("div.content").insertBefore(div, document.querySelector("div.content").firstChild);
  192. }
  193. //add individual comment buttons
  194. if (generate_individual_delete_buttons) unsafeWindow.generate_delete_buttons();
  195. //add comment exclusion buttons
  196. if (generate_comment_exclusion_buttons) unsafeWindow.generate_exclusion_buttons();
  197. }
  198. unsafeWindow.start_processing_comments = function (overwrite_all, delete_all) {
  199. //get comments again in case the user has scrolled and revealed more comments
  200. get_comments();
  201. let commentsArray = [];
  202. for (let i = 0; i < unsafeWindow.comments.length; i++) {
  203. //for each author, get ID of the input field of the comment
  204. let thing_id = unsafeWindow.comments[i].parentNode.parentNode.querySelector("form.usertext > input[name='thing_id']").value;
  205. //TODO remove this
  206. if (!thing_id) {
  207. console.log("ERROR! Thing ID undefined for", unsafeWindow.comments[i]);
  208. continue;
  209. }
  210. if (commentsArray.indexOf(thing_id) == -1) {
  211. commentsArray.push(thing_id);
  212. }
  213. }
  214. if (overwrite_all && delete_all) {
  215. unsafeWindow.overwrite_all(commentsArray, true);
  216. } else if (overwrite_all) {
  217. unsafeWindow.overwrite_all(commentsArray, false);
  218. } else if (delete_all) {
  219. unsafeWindow.delete_all(commentsArray);
  220. }
  221. //set status message while working
  222. if (unsafeWindow.status_message) {
  223. unsafeWindow.status_message.innerHTML = `Processing... ${unsafeWindow.comments.length} comments left.`;
  224. }
  225. }
  226. unsafeWindow.overwrite_all = function (comments, also_delete) {
  227. //get next comment id
  228. let thing_id = comments.shift();
  229. //overwrite the next comment in the stack
  230. unsafeWindow.overwrite_comment(thing_id);
  231. //if also deleting, add a timeout and delete the comment
  232. if (also_delete) unsafeWindow.setTimeout(unsafeWindow.delete_comment(thing_id), time_between_actions);
  233. //if there are still comments left, get next comment
  234. //increase timeout if also deleting
  235. if (comments.length) {
  236. unsafeWindow.setTimeout(unsafeWindow.overwrite_all, also_delete ? time_between_actions * 2 : time_between_actions, comments, also_delete);
  237. } else if (reload_on_completion) {
  238. if (unsafeWindow.status_message) unsafeWindow.status_message.innerHTML = "Reloading page...";
  239. unsafeWindow.setTimeout(reload_page, time_between_actions * 5);
  240. } else get_comments();
  241. }
  242. unsafeWindow.delete_all = function (comments) {
  243. unsafeWindow.delete_comment(comments.shift());
  244. //if there are still comments left, get next comment
  245. if (comments.length) unsafeWindow.setTimeout(unsafeWindow.delete_all, time_between_actions, comments);
  246. else if (reload_on_completion) {
  247. if (unsafeWindow.status_message) unsafeWindow.status_message.innerHTML = "Reloading page...";
  248. unsafeWindow.setTimeout(reload_page, time_between_actions * 5);
  249. }
  250. else get_comments();
  251. }
  252. unsafeWindow.overwrite_comment = function (thing_id) {
  253. if (safeMode) {
  254. console.log(`Safe mode active! Accessing overwrite function for ${thing_id}.`);
  255. //add your debug code here
  256. return;
  257. }
  258. try {
  259. //find edit form (hidden on page but active)
  260. let edit_form = document.querySelector(`input[name="thing_id"][value="${thing_id}"]`).parentNode;
  261. //if comment is currently being edited, cancel out of that
  262. let edit_cancel_btn = edit_form.querySelector("div.usertext-edit > div.bottom-area > div.usertext-buttons > button.cancel");
  263. edit_cancel_btn.click();
  264. //find edit button and click it
  265. let edit_btn = edit_form.parentNode.querySelector("ul > li > a.edit-usertext");
  266. if (edit_btn) edit_btn.click();
  267. //find edit textbox and replace the string with random chars
  268. let edit_textbox = edit_form.querySelector("div.usertext-edit > div > textarea");
  269. let repl_str = '';
  270. let chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz><.-,+!#$%^&*();:[]~";
  271. for (let i = 0; i < edit_textbox.value.length; i++) {
  272. if (edit_textbox.value.substr(i, 1) == '\n') {
  273. repl_str += '\n';
  274. } else {
  275. let random_char = Math.floor(Math.random() * chars.length);
  276. repl_str += chars.charAt(random_char, 1);
  277. }
  278. }
  279. //set edited value to the random string
  280. edit_textbox.value = repl_str;
  281. //find save comment button and click it
  282. let edit_save_btn = edit_form.querySelector("div.usertext-edit > div.bottom-area > div.usertext-buttons > button.save");
  283. edit_save_btn.click();
  284. } catch (e) {
  285. alert("Error interacting with overwrite form: " + e);
  286. console.log(e.stack);
  287. }
  288. }
  289. unsafeWindow.delete_comment = function (thing_id) {
  290. if (safeMode) {
  291. console.log(`Safe mode active! Accessing delete function for ${thing_id}.`);
  292. //add your debug code here
  293. return;
  294. }
  295. try {
  296. // get current status of comment editing box to prevent deleting comment before overwrite is complete
  297. let thing = document.querySelector("input[name='thing_id'][value='" + thing_id + "']");
  298. let status = thing.parentNode.querySelector("div.usertext-edit > div.bottom-area > div.usertext-buttons > span.status").innerHTML;
  299. //TODO remove this, just testing out where the weird bug is coming from
  300. if (status === null) throw Error("Status is null");
  301. if (status.indexOf("error") != -1) {
  302. alert("Failed to overwrite comment " + thing_id + " due to an unknown reddit error, skipping.");
  303. return;
  304. }
  305. // if status is submitting, there may be an internet connectivity error, so we retry
  306. if (status.indexOf("submitting") != -1) {
  307. unsafeWindow.setTimeout(unsafeWindow.delete_comment, time_between_actions * 2.5, thing_id);
  308. return;
  309. }
  310. // find delete button and click it and then yes confirmation button
  311. let del_form = thing.parentNode.parentNode.querySelector("ul.buttons > li > form.del-button");
  312. //TODO remove this, just testing out where the weird bug is coming from
  313. if (del_form === null) throw Error("Del_form is null");
  314. unsafeWindow.toggle(del_form.querySelector("span.main > a"));
  315. del_form.querySelector("span.error > a.yes").click();
  316. } catch (e) {
  317. alert("Error deleting comment: " + e);
  318. console.log(e.stack);
  319. }
  320. }
  321. //[UTILITY FUNCTIONS]
  322. function filter_author(comment) {
  323. return comment.innerHTML == unsafeWindow.user;
  324. }
  325. function filter_exclusion(comment) {
  326. return unsafeWindow.comment_exclusion_array.indexOf(comment) === -1;
  327. }
  328. function filter_time(comment) {
  329. let time = comment.parentNode.parentNode.querySelector("time").innerHTML;
  330. //always exclude comments from the past day
  331. if (time.indexOf("days") === -1) return false;
  332. let num_days = time.split(" ");
  333. return parseInt(num_days[0]) >= old_comments_limit;
  334. }
  335. function filter_subreddit(comment) {
  336. return comment.parentNode.parentNode.parentNode.querySelector("a.subreddit").innerHTML == unsafeWindow.subreddit;
  337. }
  338. function filter_downvotes(comment) {
  339. let score = comment.parentNode.parentNode.querySelector("span.score.likes")
  340. //if we do not have a score (may be hidden) we exclude the comment for this filter
  341. if (score == null || score.title == null) return false
  342. return score.title <= downvote_limit;
  343. }
  344. function filter_upvotes(comment) {
  345. let score = comment.parentNode.parentNode.querySelector("span.score.likes")
  346. //if we do not have a score (may be hidden) we include the comment for this filter
  347. if (score == null || score.title == null) return true
  348. return score.title <= upvote_limit;
  349. }
  350. function filter_duplicates(comments) {
  351. let array = [];
  352. // For self-posts, the same author tag will show up twice, once for the post author and
  353. //then for the comment author. this gets the thing_id for that tag and if there are two
  354. //consecutive tags it only keeps the second one. Otherwise, the script would process some
  355. //comments twice, leading to some filters not working properly.
  356. for (let i = 0; i < comments.length - 1; i++) {
  357. let this_comment = comments[i].parentNode.parentNode.querySelector("form.usertext > input[name='thing_id']").value;
  358. let next_comment = comments[i + 1].parentNode.parentNode.querySelector("form.usertext > input[name='thing_id']").value;
  359. if (this_comment != next_comment) array.push(comments[i]);
  360. }
  361. //since the loop excludes the final item, add it here (will be a comment author)
  362. array.push(comments[comments.length - 1]);
  363. return array;
  364. }
  365. function reload_page() {
  366. //scroll to top first to prevent scrolling to the last deleted comment position after reload
  367. unsafeWindow.scrollTo(0, 0);
  368. unsafeWindow.location.reload();
  369. }
  370. function get_subreddit_array() {
  371. let array = [];
  372. for (let i = 0; i < unsafeWindow.comments.length; i++) {
  373. let sub = unsafeWindow.comments[i].parentNode.parentNode.parentNode.querySelector("a.subreddit").innerHTML;
  374. if (array.indexOf(sub) === -1) array.push(sub);
  375. }
  376. // Sort the array case insensitive and add option to disable subreddit filtering
  377. array = array.sort(sort_ignore_caps);
  378. array.unshift("ALL");
  379. return array;
  380. }
  381. function sort_ignore_caps(a, b) {
  382. return a.toLowerCase().localeCompare(b.toLowerCase());
  383. }
  384. function update_status_text() {
  385. if (unsafeWindow.status_message === null) return;
  386. if (noCommentsFound()) {
  387. unsafeWindow.status_message = "Problem getting comments!";
  388. console.log("No comments found!", unsafeWindow.comments)
  389. }
  390. let message = "FOUND " + unsafeWindow.comments.length + " COMMENT";
  391. if (unsafeWindow.comments.length > 1) message += "S";
  392. if ((only_delete_by_subreddit && unsafeWindow.subreddit !== "ALL") ||
  393. only_delete_downvoted ||
  394. ignore_upvoted ||
  395. only_delete_old_comments) {
  396. message += "\n(filters active)";
  397. }
  398. unsafeWindow.status_message.innerHTML = message;
  399. }
  400. function update_highlighting() {
  401. unsafeWindow.comments.forEach((value) => {
  402. let bottomBar = value.parentNode.parentNode.parentNode.querySelector(".child");
  403. bottomBar.style.height = "5px";
  404. bottomBar.style.width = "20%";
  405. if (safeMode) bottomBar.style.background = "green";
  406. else bottomBar.style.background = "red";
  407. })
  408. //remove the bottom bar for excluded comments
  409. if (generate_comment_exclusion_buttons && comment_exclusion_array.length != 0) {
  410. comment_exclusion_array.forEach(value => {
  411. let bottomBar = value.parentNode.parentNode.parentNode.querySelector(".child");
  412. bottomBar.style.height = "0px";
  413. })
  414. }
  415. }
  416. function noCommentsFound() {
  417. return unsafeWindow.comments == null ||
  418. unsafeWindow.comments.length == 0 ||
  419. unsafeWindow.comments.some(value => value == null);
  420. }
  421. unsafeWindow.overwrite_delete = function (thing_id) {
  422. unsafeWindow.overwrite_comment(thing_id);
  423. unsafeWindow.setTimeout(unsafeWindow.delete_comment, time_between_actions, thing_id);
  424. }
  425. //function to regenerate secure delete buttons after only overwriting a comment
  426. unsafeWindow.overwrite_reload = function (thing_id) {
  427. unsafeWindow.overwrite_comment(thing_id);
  428. unsafeWindow.setTimeout(unsafeWindow.generate_delete_buttons, 500);
  429. }
  430. unsafeWindow.subreddit_select = function (option) {
  431. unsafeWindow.subreddit = option;
  432. get_comments();
  433. }
  434. unsafeWindow.exclude_comment = function (thing_id) {
  435. let comment = thing_id.parentNode.parentNode;
  436. let authorTag = comment.querySelector("a.author")
  437. if (unsafeWindow.comment_exclusion_array.indexOf(authorTag) == -1) {
  438. unsafeWindow.comment_exclusion_array.push(authorTag);
  439. }
  440. get_comments();
  441. }
  442. //[EXTRA FEATURES]
  443. //Add a "SECURE DELETE" button near each comment delete button
  444. unsafeWindow.generate_delete_buttons = function () {
  445. // first get comments again to bypass any active filters (see get_comments() for explanation)
  446. let comments = document.querySelectorAll("a.author");
  447. comments = [].filter.call(comments, filter_author);
  448. comments = filter_duplicates(comments);
  449. for (let i = 0; i < comments.length; i++) {
  450. try {
  451. // get the parent
  452. let main_parent = comments[i].parentNode.parentNode;
  453. let thing_id = main_parent.querySelector("form > input[name='thing_id']").value;
  454. let list = main_parent.querySelector("ul.flat-list");
  455. // add SECURE DELETE link to comments
  456. let secure_delete_link = document.createElement("li");
  457. secure_delete_link.setAttribute('class', 'secure_delete');
  458. let dlink = document.createElement("a");
  459. dlink.setAttribute('class', 'bylink secure_delete');
  460. dlink.setAttribute('onClick', 'javascript: overwrite_delete("' + thing_id + '")');
  461. dlink.setAttribute('href', 'javascript:void(0)');
  462. dlink.appendChild(document.createTextNode('SECURE DELETE'));
  463. secure_delete_link.appendChild(dlink);
  464. list.appendChild(secure_delete_link);
  465. // add OVERWRITE link to comments
  466. let overwrite_link = document.createElement("li");
  467. overwrite_link.setAttribute('class', 'overwrite');
  468. let olink = document.createElement("a");
  469. olink.setAttribute('class', 'bylink secure_delete');
  470. olink.setAttribute('onClick', 'javascript: overwrite_reload("' + thing_id + '")');
  471. olink.setAttribute('href', 'javascript:void(0)');
  472. olink.appendChild(document.createTextNode('OVERWRITE'));
  473. overwrite_link.appendChild(olink);
  474. list.appendChild(overwrite_link);
  475. } catch (e) {
  476. alert("Error adding Secure Delete links to comments.\nError: " + e);
  477. console.log(e.stack);
  478. }
  479. }
  480. }
  481. //Add an "EXCLUDE" button near each comment delete button
  482. unsafeWindow.generate_exclusion_buttons = function () {
  483. get_comments();
  484. for (let i = 0; i < unsafeWindow.comments.length; i++) {
  485. let comment = unsafeWindow.comments[i];
  486. try {
  487. // get the parent
  488. let main_parent = comment.parentNode.parentNode;
  489. let thing_id = main_parent.querySelector("form > input[name='thing_id']");
  490. let list = main_parent.querySelector("ul.flat-list");
  491. // add EXCLUDE link to comments
  492. let exclude_link = document.createElement("li");
  493. exclude_link.setAttribute('class', 'exclude');
  494. let elink = document.createElement("a");
  495. elink.setAttribute('class', 'bylink exclude');
  496. elink.onclick = function () {
  497. exclude_comment(thing_id)
  498. }
  499. // elink.setAttribute('onClick', 'javascript: exclude_comment("' + thing_id + '")');
  500. elink.setAttribute('href', 'javascript:void(0)');
  501. elink.appendChild(document.createTextNode('EXCLUDE'));
  502. exclude_link.appendChild(elink);
  503. list.appendChild(exclude_link);
  504. } catch (e) {
  505. alert("Error adding Exclude links to comments.\nError: " + e);
  506. console.log(e.stack);
  507. }
  508. }
  509. }
  510. //sets the defaults I like (tired of copy pasting for every update)
  511. function setDefaults() {
  512. generate_individual_delete_buttons = true;
  513. only_delete_old_comments = true;
  514. ignore_upvoted = true;
  515. upvote_limit = 10;
  516. reload_on_completion = true;
  517. highlight_comments = true;
  518. generate_comment_exclusion_buttons = true;
  519. }
  520. //if we are in safe mode we're not interacting with reddit so we eliminate the delays
  521. function setSafeModeDefaults() {
  522. time_between_actions = 0;
  523. reload_on_completion = false;
  524. }