RaaW

Reddit as a Weapon script. Parts and idea by /u/noeatnosleep, enhanced by /u/enim, /u/creesch, /u/skeeto, and /u/djimbob. RaaW adds links for page-wide voting and reporting. It adds a 'report to /r/spam' link, an 'analyze user submission domains' link, and a 'report to /r/botwatchman' link to userpages. RaaW disables the np. domain. RaaW Adds a 'show source' button for comments. DISCLIAMER: Use this at your own risk. If the report button is misued, you could be shadowbanned.

目前为 2014-10-12 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name RaaW
  3. // @version 3.1.6
  4. // @namespace RaaW
  5. // @run-at document-end
  6. // @description Reddit as a Weapon script. Parts and idea by /u/noeatnosleep, enhanced by /u/enim, /u/creesch, /u/skeeto, and /u/djimbob. RaaW adds links for page-wide voting and reporting. It adds a 'report to /r/spam' link, an 'analyze user submission domains' link, and a 'report to /r/botwatchman' link to userpages. RaaW disables the np. domain. RaaW Adds a 'show source' button for comments. DISCLIAMER: Use this at your own risk. If the report button is misued, you could be shadowbanned.
  7. // @include http://www.reddit.com/user/*
  8. // @include http://www.reddit.com/r/*
  9. // @include http://*reddit.com/*
  10. // @include https://www.reddit.com/user/*
  11. // @include https://www.reddit.com/r/*
  12. // @include https://*reddit.com/*
  13. // @require https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
  14. // ==/UserScript==
  15.  
  16. this.jQuery = jQuery.noConflict(true);
  17.  
  18. // define a basic object that we can extend with our functions so we do not accidentally
  19. // override other stuff
  20. var RaaW = {
  21. // ////////////////////////////////////////////////////////////////////////
  22. // constants
  23. // ////////////////////////////////////////////////////////////////////////
  24.  
  25. // some css properties for the links in the toolbox
  26. LINK_CSS: {
  27. 'color': '#000',
  28. },
  29.  
  30. // ////////////////////////////////////////////////////////////////////////
  31. // instance variables
  32. // ////////////////////////////////////////////////////////////////////////
  33.  
  34. raawToolbar: false,
  35.  
  36. // true if we are moderator on the current page (by checking if .moderator is present)
  37. // in <body class="...">
  38. isModerator: false,
  39.  
  40. currentPage: 'user',
  41.  
  42. // ////////////////////////////////////////////////////////////////////////
  43. // various helper functions
  44. // ////////////////////////////////////////////////////////////////////////
  45.  
  46. /**
  47. * Function grabs the username of the current viewed profile.
  48. *
  49. * Returns:
  50. * (string) username or undefined if not found
  51. */
  52. _getUsername: function() {
  53. return jQuery(document).find('.pagename.selected').text();
  54. },
  55.  
  56. _getModhash: function() {
  57. return unsafeWindow.reddit.modhash;
  58. },
  59.  
  60. // ////////////////////////////////////////////////////////////////////////
  61. // initialization
  62. // ////////////////////////////////////////////////////////////////////////
  63.  
  64. /**
  65. * Initialize RaaW. Will fetch some values like current page and after
  66. * that initialize the toolbar.
  67. */
  68. init: function() {
  69. // first gather all the information needed
  70. this._loadEnvironment();
  71.  
  72. // now add some elements we will need
  73. this._injectElements();
  74.  
  75. // add the toolbar
  76. this._generateToolbar();
  77.  
  78. // after we created everything connect it
  79. this._registerListener();
  80. },
  81.  
  82. /**
  83. * Load environment values like current page.
  84. */
  85. _loadEnvironment: function() {
  86. // set current page
  87. this.currentPage = document.URL.split('reddit.com')[1].split('/')[1];
  88.  
  89. // check if we are moderator
  90. this.isModerator = jQuery('body').hasClass('moderator');
  91. },
  92.  
  93. /**
  94. * Adds/modifies needed elements to the reddit page (e.g. 'toggle source' links).
  95. */
  96. _injectElements: function() {
  97. // add links 'toogle source' to comments
  98. var toggleSourceCodeEl = jQuery('<li><a class="raawToggleSourceCode" href="#">view source</a></li>');
  99. jQuery('.entry .flat-list').append(toggleSourceCodeEl);
  100.  
  101. //disable .np
  102. if (document.documentElement.lang === 'np') {
  103. document.documentElement.lang = 'en-us';
  104. }
  105.  
  106. // add subscriber class to body tag
  107. jQuery('body').addClass('subscriber');
  108.  
  109. // replace links on the page
  110. Array.forEach( document.links, function(a) {
  111. a.href = a.href.replace( "https://i.imgur.com", "http://imgur.com");
  112. a.href = a.href.replace( "https://imgur.com", "http://imgur.com");
  113. });
  114.  
  115. // set checkbox 'limit my search to /r/...' checked
  116. jQuery('form#search input[name="restrict_sr"]').prop('checked', true);
  117.  
  118. // add mod only stuff
  119. if(this.isModerator === true) {
  120. this._injectSaveAsMod();
  121. this._injectNuke();
  122. }
  123. },
  124.  
  125. /**
  126. * Register all click listener for the RaaW toolbar links. We do not distingish if we
  127. * are on /user or something else. There should be no noticeable impact on performance
  128. * and we save some maintenance effort.
  129. */
  130. _registerListener: function() {
  131. // we don't want js to bind 'this' to the global object. therefore we use a trick.
  132. // whenever you need a 'this' reference inside one of the functions pointing to
  133. // the RaaW object use 'that'
  134. var that = this;
  135.  
  136. // register click handler for the user toolbar links
  137. jQuery('#raawReportComment').click(function(e) {
  138. that.reportAll(e);
  139. });
  140. jQuery('#raawBotwatchmanSend').click(function(e) {
  141. that.botwatchmanSend(e);
  142. });
  143. jQuery('#raawAnalyzeSend').click(function(e) {
  144. that.analyzeSend(e);
  145. });
  146. jQuery('#raawReportUserToSpam').click(function(e) {
  147. that.reportUserToSpam(e);
  148. });
  149. jQuery('#raawAdminSend').click(function(e) {
  150. that.adminSend(e);
  151. });
  152.  
  153. // register handler for the other toolbar links
  154. jQuery('#raawDownvoteComment').click(function(e) {
  155. that.voteAll(e, -1);
  156. });
  157. jQuery('#raawUpvoteComment').click(function(e) {
  158. that.voteAll(e, 1);
  159. });
  160. jQuery('#raawComposeNew').click(function(e) {
  161. that.composeNew(e);
  162. });
  163.  
  164. jQuery('.raawToggleSourceCode').click(function(e) {
  165. that.toggleSourceCode(e);
  166. });
  167. },
  168.  
  169. // ////////////////////////////////////////////////////////////////////////
  170. // toolbar stuff
  171. // ////////////////////////////////////////////////////////////////////////
  172.  
  173. /**
  174. * Helper function used to create an a-element.
  175. *
  176. * Parameters:
  177. * id (string) - id attribute value
  178. * href (string) - href attribute value
  179. * text (string) - elements text
  180. *
  181. * Returns:
  182. * jQuery element instance
  183. */
  184. _generateToolbarLink: function(id, href, text) {
  185. var link = jQuery('<a id="' + id + '" href="' + href + '">' + text + '</a>');
  186. jQuery(link).css(this.LINK_CSS);
  187. return link;
  188. },
  189.  
  190. /**
  191. * Generate the toolbar on top of the page.
  192. */
  193. _generateToolbar: function() {
  194. // apply some styles to the header
  195. jQuery('#header').css({
  196. 'paddingTop': '18px'
  197. });
  198.  
  199. // create the new raaw toolbar and insert into body
  200. this.raawToolbar = jQuery('<div id="raawToolbar"></div>');
  201. jQuery('body').prepend(this.raawToolbar);
  202.  
  203. // apply style to the new toolbar
  204. jQuery(this.raawToolbar).css({
  205. 'color': '#000'
  206. , 'background-color': '#f0f0f0'
  207. , 'border-bottom': '1px solid #000'
  208. , 'font-family': 'erdana, arial, helvetica, sans-serif'
  209. , 'font-size': '90%'
  210. , 'height': '12px'
  211. , 'padding': '3px 0px 3px 6px'
  212. , 'text-transform': 'uppercase'
  213. , 'width': '100%'
  214. , 'z-index': '+999999'
  215. , 'position': 'fixed'
  216. , 'top': '0'
  217. });
  218.  
  219. // fill toolbar with content depending on parsed page
  220. var toolbarLinks = new Array();
  221. if(this.currentPage === 'user') {
  222. toolbarLinks.push(this._generateToolbarLink('raawReportComment', '#', 'REPORT ALL'));
  223. toolbarLinks.push(this._generateToolbarLink('raawBotwatchmanSend', '#', ' | /R/BOTWATCHMAN'));
  224. toolbarLinks.push(this._generateToolbarLink('raawAnalyzeSend', '#', ' | ANALYZE'));
  225. toolbarLinks.push(this._generateToolbarLink('raawReportUserToSpam', '#', ' | /R/SPAM'));
  226. toolbarLinks.push(this._generateToolbarLink('raawAdminSend', '#', ' | ADMIN'));
  227. } else {
  228. toolbarLinks.push(this._generateToolbarLink('raawDownvoteComment', '#', 'DOWNVOTE ALL'));
  229. toolbarLinks.push(this._generateToolbarLink('raawUpvoteComment', '#', ' | UPVOTE ALL'));
  230. toolbarLinks.push(this._generateToolbarLink('raawComposeNew', '#', ' | COMPOSE'));
  231. }
  232.  
  233. for(i = 0; i < toolbarLinks.length; i++) {
  234. jQuery(this.raawToolbar).append(toolbarLinks[i]);
  235. }
  236. },
  237.  
  238. // ////////////////////////////////////////////////////////////////////////
  239. // functions for user toolbar
  240. // ////////////////////////////////////////////////////////////////////////
  241.  
  242. /**
  243. * Report a given item using the reddit api.
  244. *
  245. * Parameters:
  246. * fullname (string) - fullname of item to report
  247. * el (jQuery el) - element to report (just for easier coding)
  248. * timeout (int) - timeout before request
  249. */
  250. _reportItem: function(fullname, el, timeout) {
  251. var that = this;
  252. setTimeout(function() {
  253. var data= {
  254. 'api_type': 'json'
  255. , 'thing_id': fullname
  256. , 'uh': that._getModhash()
  257. };
  258.  
  259. jQuery.post('http://www.reddit.com/api/report', data).done(function(response) {
  260. jQuery(el).hide(1000);
  261. }).error(function(response) {
  262. console.log(response);
  263. });
  264. }, timeout);
  265. },
  266.  
  267. /**
  268. * Report all items on the page.
  269. *
  270. * Parameters:
  271. * click (jQuery click event) - the jQuery click event.
  272. */
  273. reportAll: function(click) {
  274. click.preventDefault();
  275.  
  276. var isConfirmed = confirm("This will report all items on the page.");
  277. if (isConfirmed === true) {
  278. // load all fullname of the comments on the page
  279. var i = 0;
  280. var that = this;
  281. jQuery('div#siteTable .thing').each(function(index, el) {
  282. var fullname = jQuery(el).attr('data-fullname');
  283. that._reportItem(fullname, el, (400 * i) + 100);
  284. i++;
  285. });
  286.  
  287. // not accurate but will do
  288. alert('All items on this page were reported.');
  289. } else {
  290. alert('Report canceled');
  291. }
  292. },
  293.  
  294. /**
  295. * Open a new window to submit a user to /r/botwatchman.
  296. *
  297. * Parameters:
  298. * click (jQuery click event) - the jQuery click event.
  299. */
  300. botwatchmanSend: function(click) {
  301. click.preventDefault();
  302. var username = this._getUsername();
  303. window.open('http://www.reddit.com/r/botwatchman/submit?title=overview for ' + username + '&url=http://www.reddit.com/user/' + username);
  304. },
  305.  
  306. /**
  307. * Send a new message to /u/analyzereddit with subject 'analyze' and a username
  308. * as message.
  309. *
  310. * Parameters:
  311. * click (jQuery click event) - the jQuery click event.
  312. */
  313. analyzeSend: function(click) {
  314. click.preventDefault();
  315. var username = this._getUsername();
  316. window.open('http://www.reddit.com/message/compose/?to=analyzereddit&subject=analyze&message=' + username);
  317. },
  318.  
  319.  
  320. /**
  321. * Open a new window to report a user to /r/spam.
  322. *
  323. * Parameters:
  324. * click (jQuery click event) - the jQuery click event.
  325. */
  326. reportUserToSpam: function(click) {
  327. click.preventDefault();
  328. var username = this._getUsername();
  329. window.open('http://www.reddit.com/r/spam/submit?title=overview for '+ username + '&resubmit=true&url=http://www.reddit.com/user/' + username);
  330. },
  331.  
  332. /**
  333. * Open a new window to send a new message to /r/reddit.com.
  334. */
  335. adminSend: function(click){
  336. click.preventDefault();
  337. var username = this._getUsername();
  338. window.open('http://www.reddit.com/message/compose/?to=/r/reddit.com&message=/u/'+ username);
  339. },
  340.  
  341. // ////////////////////////////////////////////////////////////////////////
  342. // functions for default toolbar
  343. // ////////////////////////////////////////////////////////////////////////
  344.  
  345. /**
  346. * Makes an asynch ajax call to the reddit API after waiting for the given amount
  347. * of time.
  348. *
  349. * Parameters:
  350. * data (object) - data to send (dir, uh, id)
  351. * thing (jQuery el) - element the vote belongs to
  352. * timeout (int) - time to wait in miliseconds
  353. */
  354. _voteCallAPI: function(data, thing, timeout) {
  355. setTimeout(function() {
  356. console.log(data);
  357. jQuery.post('/api/vote', data).done(function(response) {
  358. jQuery(thing).hide(1000);
  359. }).error(function(response) {
  360. console.log('Error voting on item!');
  361. console.log(response);
  362. });
  363. }, timeout);
  364. },
  365.  
  366. /**
  367. * Up- or downvote all comment on a page.
  368. *
  369. * Parameters:
  370. * event (jQuery click event)
  371. * dir (int) - 1 upvote, -1 downvote, 0 none
  372. */
  373. voteAll: function(event, dir) {
  374. event.preventDefault();
  375. var things = jQuery('div.sitetable div.thing');
  376.  
  377. // gather the required fullnames to call the API
  378. for(i = 0; i < things.length; i++) {
  379. var thing = things[i];
  380. var fullname = jQuery(thing).attr('data-fullname');
  381. if(typeof fullname !== 'undefined') {
  382. // send request to the api
  383. var data= {
  384. 'dir': dir,
  385. 'id': fullname,
  386. 'uh': this._getModhash()
  387. };
  388.  
  389. this._voteCallAPI(data, thing, 100+(i*400));
  390. }
  391. }
  392. },
  393.  
  394. /**
  395. * Open a new window to compose a new message.
  396. *
  397. * Parameters:
  398. * click (jQuery click event) - the jQuery click event.
  399. */
  400. composeNew: function(click) {
  401. click.preventDefault();
  402. window.open('http://www.reddit.com/message/compose/');
  403. },
  404.  
  405. // ////////////////////////////////////////////////////////////////////////
  406. // 'view source' related functions
  407. // ////////////////////////////////////////////////////////////////////////
  408.  
  409. /**
  410. * Helper function to fetch the sourcecode of comments/links/messages using the
  411. * reddit api.
  412. *
  413. * Parameters:
  414. * url (string) - because of the diversity of the api provide a url with the needed attributes
  415. * fullname (string) - fullname needed to search if loading messages
  416. * callback (function(source)) - callback function to call when api call is done
  417. */
  418. _fetchSourceCode: function(url, fullname, callback) {
  419. jQuery.getJSON(url).done(function(response) {
  420. // check what type of posting we're looking at (check api for more information)
  421. var postingType = response.data.children[0].kind;
  422.  
  423. // unfortunately the returned json object has no unified structure so
  424. // we need a bit more logic here
  425. var source;
  426. if(postingType === 't1') { // comment
  427. source = response.data.children[0].data.body;
  428. } else if(postingType === 't3') { // link (post); will be empty for videos or similiar
  429. source = response.data.children[0].data.selftext;
  430. } else if(postingType === 't4') { // message
  431. // the current api url loads a message thread so we need to find the
  432. // desired message
  433. rawData = response.data.children[0].data;
  434. if(rawData.name === fullname) {
  435. source = rawData.body;
  436. } else {
  437. // search through replies
  438. var replies = rawData.replies.data.children;
  439. for(var i = 0; i < replies.length; i++) {
  440. var replyRaw = replies[i].data;
  441. if(replyRaw.name === fullname) {
  442. source = replyRaw.body;
  443. break;
  444. }
  445. }
  446. }
  447. }
  448. callback(source);
  449. });
  450. },
  451.  
  452. /**
  453. * Create a textarea to display source code
  454. *
  455. * Parameters:
  456. * source (string) - source code to display
  457. * fullname (string) - fullname of link/comment/message so we can later identify if we already loaded the source
  458. * prependTo (jQuery element) - element to prepend the textarea to
  459. */
  460. _createSourceCodeTextarea: function(source, fullname, prependTo) {
  461. // create a textarea to display source and add it to the dom
  462. var textAreaEl = jQuery('<textarea class="'+fullname+'">'+source+'</textarea>');
  463. jQuery(textAreaEl).css({
  464. 'display': 'block'
  465. , 'width': '90%'
  466. , 'height': '100px'
  467. });
  468.  
  469. // insert textarea
  470. jQuery(prependTo).prepend(textAreaEl);
  471. },
  472.  
  473. /**
  474. * Toggle source code.
  475. *
  476. * Parameters:
  477. * click (jQuery click event) - the jQuery click event.
  478. */
  479. toggleSourceCode: function(click) {
  480. click.preventDefault();
  481.  
  482. // grab the clicked link element
  483. var linkEl = jQuery(click.target);
  484.  
  485. // get the data-fullname attribute to provide an id to 'throw at the api'
  486. var dataFullname = jQuery(linkEl).closest('.thing').attr('data-fullname');
  487.  
  488. var isTextAreaPresent = jQuery('textarea.'+dataFullname);
  489. if(isTextAreaPresent.length == 1) {
  490. jQuery(isTextAreaPresent).toggle();
  491. } else {
  492. // figure out the element where we're going to insert the textarea
  493. var prependTo = jQuery(linkEl).parent().parent();
  494.  
  495. // do an ajax request to fetch the data from the api
  496. // because we cannot fetch a message and a link/comment with the same api call
  497. // we need to figure out, if we are on a message site
  498. var apiURL;
  499. if(this.currentPage === 'message') {
  500. // cut off t4_ for filtering
  501. messageId = dataFullname.slice(3, dataFullname.length);
  502. apiURL = '/message/messages/.json?mid='+messageId+'&count=1';
  503. } else {
  504. apiURL = '/api/info.json?id=' + dataFullname;
  505. }
  506.  
  507. var that = this;
  508. this._fetchSourceCode(apiURL, dataFullname, function(source) {
  509. that._createSourceCodeTextarea(source, dataFullname, prependTo);
  510. });
  511. }
  512. },
  513.  
  514. // ////////////////////////////////////////////////////////////////////////
  515. // 'save as mod' related stuff
  516. // ////////////////////////////////////////////////////////////////////////
  517.  
  518. /**
  519. * Place a 'save as mod' in the comment forms.
  520. *
  521. * Parameters:
  522. * el (jQuery element) - form element to place the button in; leave out to inject into all
  523. */
  524. _injectSaveAsMod: function(el) {
  525. var that = this;
  526. if(typeof el === 'undefined') {
  527. el = false;
  528. }
  529.  
  530. // no element given -> inject into all forms
  531. var injectHere = new Array();
  532. if(el === false) {
  533. injectHere = jQuery('.usertext-buttons');
  534. } else {
  535. injectHere.push(jQuery(el).find('.usertext-buttons')[0]);
  536. }
  537.  
  538. // inject between save and cancel
  539. for(i = 0; i < injectHere.length; i++) {
  540. // element where the buttons life in
  541. var divEl = injectHere[i];
  542.  
  543. // button to inject; register click function...
  544. var buttonEl = jQuery('<button type="button" class="raawSaveAsMod">save as mod</button>');
  545. jQuery(buttonEl).click(function(e) {
  546. that.saveAsMod(e);
  547. });
  548.  
  549. // find save button and add save as mod after that
  550. jQuery(divEl).find('button[type="submit"]').after(buttonEl);
  551. }
  552.  
  553. // remove the buttons from the edit form
  554. jQuery('div.entry .usertext-buttons button.raawSaveAsMod').remove();
  555.  
  556. // find all reply links
  557. var replyButtons = jQuery('ul.flat-list li a').filter(function(index, el) {
  558. return jQuery(el).text() === 'reply';
  559. });
  560.  
  561. for(i = 0; i < replyButtons.length; i++) {
  562. var button = replyButtons[i];
  563. jQuery(button).click(function(e) {
  564. setTimeout(function() {
  565. var allButtons = jQuery('button.raawSaveAsMod');
  566. for(i = 0; i < allButtons.length; i++) {
  567. var button = allButtons[i];
  568. jQuery(button).off('click');
  569. jQuery(button).click(function(e) {
  570. that.saveAsMod(e);
  571. });
  572. }
  573. }, 500);
  574. });
  575. }
  576. },
  577.  
  578. /**
  579. * Method will prevent a comment form to submit in the first place. Will fetch the
  580. * thing id to use it for distinguishing. After that will submit the form and when the
  581. * submit is finished distinguish the comment itself.
  582. *
  583. * Parameters:
  584. * click (jQuery click event)
  585. */
  586. saveAsMod: function(click) {
  587. click.preventDefault();
  588. var form = jQuery(click.target).closest('form.usertext');
  589.  
  590. // get parent
  591. var hiddenInput = jQuery(form).children('input[name="thing_id"]')[0];
  592. var parent = jQuery(hiddenInput).val();
  593.  
  594. // get comment text
  595. var textarea = jQuery(form).find('textarea')[0];
  596. var commentText = jQuery(textarea).val();
  597.  
  598. var modhash = this._getModhash();
  599. // post comment
  600. data = {
  601. 'api_type': 'json'
  602. , 'text': commentText
  603. , 'thing_id': parent
  604. , 'uh': modhash
  605. };
  606. jQuery.post('/api/comment', data).done(function(response) {
  607. if(response.json.errors.length > 0) {
  608. console.log('Error while posting comment:');
  609. console.log(response.json.errors);
  610. alert('Error while posting comment. Please check the console for more information!');
  611. return;
  612. }
  613.  
  614. // distinguish
  615. var commentData = response.json.data.things[0].data;
  616. var data = {
  617. 'id': commentData.id
  618. , 'api_type': 'json'
  619. , 'how': 'yes'
  620. , 'uh': modhash
  621. };
  622. jQuery.post('/api/distinguish', data).done(function(response) {
  623. if(response.json.errors.length > 0) {
  624. console.log('Error while posting comment:');
  625. console.log(response.json.errors);
  626. alert('Error while posting comment. Please check the console for more information!');
  627. return;
  628. }
  629.  
  630. location.reload();
  631. });
  632. });
  633. },
  634.  
  635. // ////////////////////////////////////////////////////////////////////////
  636. // nuke functions
  637. // ////////////////////////////////////////////////////////////////////////
  638.  
  639. /**
  640. * Find the a comment with the given id in a response object.
  641. *
  642. * Parameters:
  643. * commentId (string) - something like t1_abc
  644. * response (object) - response object returned by a API call
  645. *
  646. * Returns:
  647. * (object) or undefined
  648. */
  649. _findCommentInResponse: function(commentId, response) {
  650. var searchedComment;
  651.  
  652. // build a search queue to go through
  653. var search = new Array();
  654. for(var i = 0; i < response.length; i++) {
  655. var listing = response[i].data.children;
  656. for(var n = 0; n < listing.length; n++) {
  657. var content = listing[n];
  658.  
  659. // if data is something else than a comment skip
  660. if(content.kind !== 't1') {
  661. continue;
  662. } else {
  663. // the comment is the one we search
  664. if(content.data.id === commentId) {
  665. return content;
  666. } else {
  667. // comment is not what we search but maybe one of his replies?
  668. // add replies to search queue
  669. if(content.data.replies !== '') {
  670. search = search.concat(content.data.replies.data.children);
  671. }
  672. }
  673. }
  674. }
  675. }
  676.  
  677. while(search.length > 0) {
  678. var currentObj = search.pop();
  679.  
  680. // check if this is the right comment
  681. if(currentObj.data.id === commentId) {
  682. return currentObj;
  683. }
  684.  
  685. // add all the replies of this comment to the search array
  686. if(currentObj.data.replies !== '') {
  687. search = search.concat(currentObj.data.replies.data.children);
  688. }
  689. }
  690.  
  691. return searchedComment;
  692. },
  693.  
  694. /**
  695. * Will find all replies to the given comment.
  696. *
  697. * Parameters:
  698. * obj (object) - thing object returned by a API call
  699. *
  700. * Returns:
  701. * (Array) Maybe an empty array if no replies where found. Array holds the ids as a
  702. * string. E.g. '1234', 'a23pav', ...
  703. */
  704. _findAllReplies: function(obj) {
  705. var replies = new Array();
  706.  
  707. // check if there are replies
  708. if(obj.data.replies === '') {
  709. return replies;
  710. }
  711.  
  712. var search = new Array();
  713. for(var i = 0; i < obj.data.replies.data.children.length; i++) {
  714. var reply = obj.data.replies.data.children[i];
  715. replies.push(reply.data.id);
  716. if(reply.data.replies !== '') {
  717. search = search.concat(reply.data.replies.data.children);
  718. }
  719. }
  720.  
  721. while(search.length > 0) {
  722. var currentObj = search.pop();
  723.  
  724. // 'more' occures if there are more than 10 entries
  725. if(currentObj.kind === 'more') {
  726. continue;
  727. }
  728.  
  729. // add the id of the current reply
  730. replies.push(currentObj.data.id);
  731.  
  732. // add all replies to the reply to the search
  733. if(currentObj.data.replies !== '') {
  734. search = search.concat(currentObj.data.replies.data.children);
  735. }
  736. }
  737.  
  738. return replies;
  739. },
  740.  
  741. /**
  742. * Remove the given comment.
  743. *
  744. * Parameters:
  745. * commentId (string) - id of the comment to remove
  746. * timeout (int) - timeout in milliseconds
  747. */
  748. _nukeComment: function(commentId, timeout) {
  749. var that = this;
  750. setTimeout(function() {
  751. var data = {
  752. 'id': 't1_' + commentId
  753. , 'uh': that._getModhash()
  754. }
  755.  
  756. jQuery.post('/api/remove', data).done(function(response) {
  757. var el = jQuery('div.thing[data-fullname="t1_'+commentId+'"]');
  758. jQuery(el).hide(1000, function() {
  759. jQuery(el).remove();
  760. });
  761. }).error(function(response) {
  762. console.log(response);
  763. });
  764. }, timeout);
  765. },
  766.  
  767. /**
  768. * Inject the nuke button.
  769. */
  770. _injectNuke: function() {
  771. var nukeButton = jQuery('<a href="#" class="raawNuke" title="Nuke!">[Nuke]</a>');
  772.  
  773. // add click listener
  774. var that = this;
  775. jQuery(nukeButton).click(function(e) {
  776. e.preventDefault();
  777. var dataFullname = jQuery(this).closest('div.thing').attr('data-fullname');
  778. var link = jQuery('#siteTable').find('div.thing').attr('data-fullname').slice(3); // cut off t3_
  779.  
  780. // get all the comments for this thread and find the right parent comment
  781. jQuery.getJSON('/comments/'+link+'.json').done(function(response) {
  782. var searchedComment = that._findCommentInResponse(dataFullname.slice(3), response);
  783. if(typeof searchedComment !== 'undefined') {
  784. // extract all children
  785. var removeThese = that._findAllReplies(searchedComment);
  786.  
  787. // add the parent itself; but remove t1_ because thats how the other look to!
  788. removeThese.push(dataFullname.slice(3));
  789. for(var i = 0; i < removeThese.length; i++) {
  790. var childsDataFullname = removeThese[i];
  791. that._nukeComment(removeThese[i], (i * 750) + 100);
  792. }
  793. }
  794. });
  795. });
  796.  
  797. // insert button
  798. jQuery('div.commentarea div.thing p.tagline span.userattrs').prepend(nukeButton);
  799. }
  800. };
  801.  
  802. // initialize when document loaded
  803. jQuery(document).ready(function() {
  804. RaaW.init();
  805. });