RaaW2

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.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name RaaW2
// @version 3.1.9
// @namespace RaaW2
// @run-at document-end
// @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.
// @include http://www.reddit.com/user/*
// @include http://www.reddit.com/r/*
// @include http://*reddit.com/*
// @include https://www.reddit.com/user/*
// @include https://www.reddit.com/r/*
// @include https://*reddit.com/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
// ==/UserScript==

this.jQuery = jQuery.noConflict(true);

// define a basic object that we can extend with our functions so we do not accidentally
// override other stuff
var RaaW = {
	// ////////////////////////////////////////////////////////////////////////
	// constants
	// ////////////////////////////////////////////////////////////////////////

	// some css properties for the links in the toolbox
	LINK_CSS: {
		'color': '#000',
	},

	// ////////////////////////////////////////////////////////////////////////
	// instance variables
	// ////////////////////////////////////////////////////////////////////////

	raawToolbar: false,

	// true if we are moderator on the current page (by checking if .moderator is present)
	// in <body class="...">
	isModerator: false,

	currentPage: 'user',

	// ////////////////////////////////////////////////////////////////////////
	// various helper functions
	// ////////////////////////////////////////////////////////////////////////

	/**
	 * Function grabs the username of the current viewed profile.
	 *
	 * Returns:
	 *  (string) username or undefined if not found
	 */
	_getUsername: function() {
		return jQuery(document).find('.pagename.selected').text();
	},

	_getModhash: function() {
		return unsafeWindow.reddit.modhash;
	},

	// ////////////////////////////////////////////////////////////////////////
	// initialization
	// ////////////////////////////////////////////////////////////////////////

	/**
	* Initialize RaaW. Will fetch some values like current page and after
	* that initialize the toolbar.
	*/
	init: function() {
		// first gather all the information needed
		this._loadEnvironment();

		// now add some elements we will need
		this._injectElements();

		// add the toolbar
		this._generateToolbar();

		// after we created everything connect it
		this._registerListener();
	},

	/**
	 * Load environment values like current page.
	 */
	_loadEnvironment: function() {
		// set current page
		this.currentPage = document.URL.split('reddit.com')[1].split('/')[1];

		// check if we are moderator
		this.isModerator = jQuery('body').hasClass('moderator');
	},

	/**
	 * Adds/modifies needed elements to the reddit page (e.g. 'toggle source' links).
	 */
	_injectElements: function() {
		// add links 'toogle source' to comments
		var toggleSourceCodeEl = jQuery('<li><a class="raawToggleSourceCode" href="#">view source</a></li>');
		jQuery('.entry .flat-list').append(toggleSourceCodeEl);

		//disable .np
		if (document.documentElement.lang === 'np') {
			document.documentElement.lang = 'en-us';
		}

		// add subscriber class to body tag
		jQuery('body').addClass('subscriber');

		// replace links on the page
		Array.forEach( document.links, function(a) {
			a.href = a.href.replace( "https://i.imgur.com", "http://imgur.com");
			a.href = a.href.replace( "https://imgur.com", "http://imgur.com");
		});

		// set checkbox 'limit my search to /r/...' checked
		jQuery('form#search input[name="restrict_sr"]').prop('checked', true);

		// add mod only stuff
		if(this.isModerator === true) {
			this._injectSaveAsMod();
			this._injectNuke();
		}
	},

	/**
	 * Register all click listener for the RaaW toolbar links. We do not distingish if we
	 * are on /user or something else. There should be no noticeable impact on performance
	 * and we save some maintenance effort.
	 */
	_registerListener: function() {
		// we don't want js to bind 'this' to the global object. therefore we use a trick.
		// whenever you need a 'this' reference inside one of the functions pointing to
		// the RaaW object use 'that'
		var that = this;

		// register click handler for the user toolbar links
		jQuery('#raawReportComment').click(function(e) {
			that.reportAll(e);
		});
		jQuery('#raawBotwatchmanSend').click(function(e) {
			that.botwatchmanSend(e);
		});
		jQuery('#raawAnalyzeSend').click(function(e) {
			that.analyzeSend(e);
		});
		jQuery('#raawReportUserToSpam').click(function(e) {
			that.reportUserToSpam(e);
		});
		jQuery('#raawAdminSend').click(function(e) {
			that.adminSend(e);
		});

		// register handler for the other toolbar links
		jQuery('#raawDownvoteComment').click(function(e) {
			that.voteAll(e, -1);
		});
		jQuery('#raawUpvoteComment').click(function(e) {
			that.voteAll(e, 1);
		});
		jQuery('#raawComposeNew').click(function(e) {
			that.composeNew(e);
		});

		jQuery('.raawToggleSourceCode').click(function(e) {
			that.toggleSourceCode(e);
		});
	},

	// ////////////////////////////////////////////////////////////////////////
	// toolbar stuff
	// ////////////////////////////////////////////////////////////////////////

	/**
	* Helper function used to create an a-element.
	*
	* Parameters:
	*  id (string) - id attribute value
	*  href (string) - href attribute value
	*  text (string) - elements text
	*
	* Returns:
	*  jQuery element instance
	*/
	_generateToolbarLink: function(id, href, text) {
		var link = jQuery('<a id="' + id + '" href="' + href + '">' + text + '</a>');
		jQuery(link).css(this.LINK_CSS);
		return link;
	},

	/**
	 * Generate the toolbar on top of the page.
	 */
	_generateToolbar: function() {
		// apply some styles to the header
		jQuery('#header').css({
			'paddingTop': '18px'
		});

		// create the new raaw toolbar and insert into body
		this.raawToolbar = jQuery('<div id="raawToolbar"></div>');
		jQuery('body').prepend(this.raawToolbar);

		// apply style to the new toolbar
		jQuery(this.raawToolbar).css({
			'color': '#000'
			, 'background-color': '#f0f0f0'
			, 'border-bottom': '1px solid #000'
			, 'font-family': 'erdana, arial, helvetica, sans-serif'
			, 'font-size': '90%'
			, 'height': '12px'
			, 'padding': '3px 0px 3px 6px'
			, 'text-transform': 'uppercase'
			, 'width': '100%'
			, 'z-index': '+999999'
			, 'position': 'fixed'
			, 'top': '0'
		});

		// fill toolbar with content depending on parsed page
		var toolbarLinks = new Array();
		if(this.currentPage === 'user') {
			toolbarLinks.push(this._generateToolbarLink('raawReportComment', '#', 'REPORT ALL'));
			toolbarLinks.push(this._generateToolbarLink('raawBotwatchmanSend', '#', ' | /R/BOTWATCHMAN'));
			toolbarLinks.push(this._generateToolbarLink('raawAnalyzeSend', '#', ' | ANALYZE'));
			toolbarLinks.push(this._generateToolbarLink('raawReportUserToSpam', '#', ' | /R/SPAM'));
			toolbarLinks.push(this._generateToolbarLink('raawAdminSend', '#', ' | ADMIN'));
		} else {
			toolbarLinks.push(this._generateToolbarLink('raawDownvoteComment', '#', 'DOWNVOTE ALL'));
			toolbarLinks.push(this._generateToolbarLink('raawUpvoteComment', '#', ' | UPVOTE ALL'));
			toolbarLinks.push(this._generateToolbarLink('raawComposeNew', '#', ' | COMPOSE'));
		}

		for(i = 0; i < toolbarLinks.length; i++) {
			jQuery(this.raawToolbar).append(toolbarLinks[i]);
		}
	},

	// ////////////////////////////////////////////////////////////////////////
	// functions for user toolbar
	// ////////////////////////////////////////////////////////////////////////

	/**
	 * Report a given item using the reddit api.
	 *
	 * Parameters:
	 *  fullname (string) - fullname of item to report
	 *  el (jQuery el) - element to report (just for easier coding)
	 *	timeout (int) - timeout before request
	 */
	_reportItem: function(fullname, el, timeout) {
		var that = this;
		setTimeout(function() {
			var data= {
				'api_type': 'json'
				, 'thing_id': fullname
				, 'other_reason': 'spam'
				, 'uh': that._getModhash()
			};

			jQuery.post('http://www.reddit.com/api/report', data).done(function(response) {
				jQuery(el).hide(1000);
			}).error(function(response) {
				console.log(response);
			});
		}, timeout);
	},

	/**
	 * Report all items on the page.
	 *
	 * Parameters:
	 *  click (jQuery click event) - the jQuery click event.
	 */
	reportAll: function(click) {
		click.preventDefault();

		var isConfirmed = confirm("This will report all items on the page.");
		if (isConfirmed === true) {
			// load all fullname of the comments on the page
			var i = 0;
			var that = this;
			jQuery('div#siteTable .thing').each(function(index, el) {
				var fullname = jQuery(el).attr('data-fullname');
				that._reportItem(fullname, el, (400 * i) + 100);
				i++;
			});

			// not accurate but will do
			alert('All items on this page were reported.');
		} else {
			alert('Report canceled');
		}
	},

	/**
	 * Open a new window to submit a user to /r/botwatchman.
	 *
	 * Parameters:
	 *  click (jQuery click event) - the jQuery click event.
	 */
	botwatchmanSend: function(click) {
		click.preventDefault();
		var username = this._getUsername();
		window.open('http://www.reddit.com/r/botwatchman/submit?title=overview for ' + username + '&url=http://www.reddit.com/user/' + username);
	},

	/**
	 * Send a new message to /u/analyzereddit with subject 'analyze' and a username
	 * as message.
	 *
	 * Parameters:
	 *  click (jQuery click event) - the jQuery click event.
	 */
	analyzeSend: function(click) {
		click.preventDefault();
		var username = this._getUsername();
		window.open('http://www.reddit.com/message/compose/?to=analyzereddit&subject=analyze&message=' + username);
	},


	/**
	 * Open a new window to report a user to /r/spam.
	 *
	 * Parameters:
	 *  click (jQuery click event) - the jQuery click event.
	 */
	reportUserToSpam: function(click) {
		click.preventDefault();
		var username = this._getUsername();
		window.open('http://www.reddit.com/r/spam/submit?title=overview for '+ username + '&resubmit=true&url=http://www.reddit.com/user/' + username);
	},

	/**
	 * Open a new window to send a new message to /r/reddit.com.
	 */
	adminSend: function(click){
		click.preventDefault();
		var username = this._getUsername();
		window.open('http://www.reddit.com/message/compose/?to=/r/reddit.com&subject=spammer&message=/u/'+ username + '/submitted');
	},

	// ////////////////////////////////////////////////////////////////////////
	// functions for default toolbar
	// ////////////////////////////////////////////////////////////////////////

	/**
		 * Makes an asynch ajax call to the reddit API after waiting for the given amount
		 * of time.
		 *
		 * Parameters:
		 *  data (object) - data to send (dir, uh, id)
		 *  thing (jQuery el) - element the vote belongs to
		 *  timeout (int) - time to wait in miliseconds
		 */
		_voteCallAPI: function(data, thing, timeout, callback) {
			setTimeout(function() {
				jQuery.post('/api/vote', data).done(function(response) {
					callback(data, thing);
				}).error(function(response) {
					console.log('Error voting on item!');
					console.log(response);
				});
			}, timeout);
		},

		/**
		 * Up- or downvote all comment on a page.
		 *
		 * Parameters:
		 *  event (jQuery click event)
		 *  dir (int) - 1 upvote, -1 downvote, 0 none
		 */
		voteAll: function(event, dir) {
			event.preventDefault();
			var things = jQuery('div.sitetable div.thing');

			// gather the required fullnames to call the API
			for(i = 0; i < things.length; i++) {
				var thing = things[i];
				var fullname = jQuery(thing).attr('data-fullname');
				if(typeof fullname !== 'undefined') {
					// send request to the api
					var data= {
						'dir': dir,
						'id': fullname,
						'uh': this._getModhash()
					};

					this._voteCallAPI(data, thing, 100+(i*400), function(data, thing) {
						var upArrow = jQuery(thing).find('div.arrow[aria-label="upvote"]');
						var downArrow = jQuery(thing).find('div.arrow[aria-label="downvote"]');
						var midcol = jQuery(thing).find('div.midcol');

						// not the fanciest way but prevents unexpected behaivour
						if(data.dir === 1) {
							jQuery(upArrow).addClass('upmod');
							jQuery(upArrow).removeClass('up');

							jQuery(downArrow).addClass('down')
							jQuery(downArrow).removeClass('downmod');

							jQuery(midcol).removeClass('dislikes');
							jQuery(midcol).addClass('likes');
						} else if(data.dir === -1) {
							jQuery(upArrow).addClass('up');
							jQuery(upArrow).removeClass('upmod');

							jQuery(downArrow).removeClass('down');
							jQuery(downArrow).addClass('downmod');

							jQuery(midcol).addClass('dislikes');
							jQuery(midcol).removeClass('likes');
						}
					});
				}
			}
		},

	/**
	 * Open a new window to compose a new message.
	 *
	 * Parameters:
	 *  click (jQuery click event) - the jQuery click event.
	 */
	composeNew: function(click) {
		click.preventDefault();
		window.open('http://www.reddit.com/message/compose/');
	},

	// ////////////////////////////////////////////////////////////////////////
	// 'view source' related functions
	// ////////////////////////////////////////////////////////////////////////

	/**
	 * Helper function to fetch the sourcecode of comments/links/messages using the
	 * reddit api.
	 *
	 * Parameters:
	 *  url (string) - because of the diversity of the api provide a url with the needed attributes
	 *  fullname (string) - fullname needed to search if loading messages
	 *  callback (function(source)) - callback function to call when api call is done
	 */
	_fetchSourceCode: function(url, fullname, callback) {
		jQuery.getJSON(url).done(function(response) {
			// check what type of posting we're looking at (check api for more information)
			var postingType = response.data.children[0].kind;

			// unfortunately the returned json object has no unified structure so
			// we need a bit more logic here
			var source;
			if(postingType === 't1') { // comment
				source = response.data.children[0].data.body;
			} else if(postingType === 't3') { // link (post); will be empty for videos or similiar
				source = response.data.children[0].data.selftext;
			} else if(postingType === 't4') { // message
					// the current api url loads a message thread so we need to find the
					// desired message
					rawData = response.data.children[0].data;
					if(rawData.name === fullname) {
						source = rawData.body;
					} else {
						// search through replies
						var replies = rawData.replies.data.children;
						for(var i = 0; i < replies.length; i++) {
							var replyRaw = replies[i].data;
							if(replyRaw.name === fullname) {
								source = replyRaw.body;
								break;
							}
						}
					}
				}
				callback(source);
			});
	},

	/**
	 * Create a textarea to display source code
	 *
	 * Parameters:
	 *  source (string) - source code to display
	 *  fullname (string) - fullname of link/comment/message so we can later identify if we already loaded the source
	 *  prependTo (jQuery element) - element to prepend the textarea to
	 */
	_createSourceCodeTextarea: function(source, fullname, prependTo) {
		// create a textarea to display source and add it to the dom
		var textAreaEl = jQuery('<textarea class="'+fullname+'">'+source+'</textarea>');
		jQuery(textAreaEl).css({
			'display': 'block'
			, 'width': '90%'
			, 'height': '100px'
		});

		// insert textarea
		jQuery(prependTo).prepend(textAreaEl);
	},

	/**
	 * Toggle source code.
	 *
	 * Parameters:
	 *  click (jQuery click event) - the jQuery click event.
	 */
	toggleSourceCode: function(click) {
		click.preventDefault();

			// grab the clicked link element
			var linkEl = jQuery(click.target);

			// get the data-fullname attribute to provide an id to 'throw at the api'
			var dataFullname = jQuery(linkEl).closest('.thing').attr('data-fullname');

			var isTextAreaPresent = jQuery('textarea.'+dataFullname);
			if(isTextAreaPresent.length == 1) {
				jQuery(isTextAreaPresent).toggle();
			} else {
				// figure out the element where we're going to insert the textarea
				var prependTo = jQuery(linkEl).parent().parent();

				// do an ajax request to fetch the data from the api
				// because we cannot fetch a message and a link/comment with the same api call
				// we need to figure out, if we are on a message site
				var apiURL;
				if(this.currentPage === 'message') {
						// cut off t4_ for filtering
						messageId =  dataFullname.slice(3, dataFullname.length);
						apiURL = '/message/messages/.json?mid='+messageId+'&count=1';
					} else {
						apiURL = '/api/info.json?id=' + dataFullname;
					}

					var that = this;
					this._fetchSourceCode(apiURL, dataFullname, function(source) {
						that._createSourceCodeTextarea(source, dataFullname, prependTo);
					});
			 }
	},

	// ////////////////////////////////////////////////////////////////////////
	// 'save as mod' related stuff
	// ////////////////////////////////////////////////////////////////////////

	/**
	 * Place a 'save as mod' in the comment forms.
	 *
	 * Parameters:
	 *  el (jQuery element) - form element to place the button in; leave out to inject into all
	 */
	_injectSaveAsMod: function(el) {
		var that = this;
		if(typeof el === 'undefined') {
			el = false;
		}

		// no element given -> inject into all forms
		var injectHere = new Array();
		if(el === false) {
			injectHere = jQuery('.usertext-buttons');
		} else {
			injectHere.push(jQuery(el).find('.usertext-buttons')[0]);
		}

		// inject between save and cancel
		for(i = 0; i < injectHere.length; i++) {
			// element where the buttons life in
			var divEl = injectHere[i];

			// button to inject; register click function...
			var buttonEl = jQuery('<button type="button" class="raawSaveAsMod">save as mod</button>');
			jQuery(buttonEl).click(function(e) {
				that.saveAsMod(e);
			});

			// find save button and add save as mod after that
			jQuery(divEl).find('button[type="submit"]').after(buttonEl);
		}

		// remove the buttons from the edit form
		jQuery('div.entry .usertext-buttons button.raawSaveAsMod').remove();

		// find all  reply links
		var replyButtons = jQuery('ul.flat-list li a').filter(function(index, el) {
			return jQuery(el).text() === 'reply';
		});

		for(i = 0; i < replyButtons.length; i++) {
			var button = replyButtons[i];
			jQuery(button).click(function(e) {
				setTimeout(function() {
					var allButtons = jQuery('button.raawSaveAsMod');
					for(i = 0; i < allButtons.length; i++) {
						var button = allButtons[i];
						jQuery(button).off('click');
						jQuery(button).click(function(e) {
							that.saveAsMod(e);
						});
					}
				}, 500);
			});
		}
	},

	/**
	 * Method will prevent a comment form to submit in the first place. Will fetch the
	 * thing id to use it for distinguishing. After that will submit the form and when the
	 * submit is finished distinguish the comment itself.
	 *
	 * Parameters:
	 *  click (jQuery click event)
	 */
	saveAsMod: function(click) {
		click.preventDefault();
		var form = jQuery(click.target).closest('form.usertext');

		// get parent
		var hiddenInput = jQuery(form).children('input[name="thing_id"]')[0];
		var parent = jQuery(hiddenInput).val();

		// get comment text
		var textarea = jQuery(form).find('textarea')[0];
		var commentText = jQuery(textarea).val();

		var modhash = this._getModhash();
		// post comment
		data = {
			'api_type': 'json'
			, 'text': commentText
			, 'thing_id': parent
			, 'uh': modhash
		};
		jQuery.post('/api/comment', data).done(function(response) {
			if(response.json.errors.length > 0) {
				console.log('Error while posting comment:');
				console.log(response.json.errors);
				alert('Error while posting comment. Please check the console for more information!');
				return;
			}

			// distinguish
			var commentData = response.json.data.things[0].data;
			var data = {
				'id': commentData.id
				, 'api_type': 'json'
				, 'how': 'yes'
				, 'uh': modhash
			};
			jQuery.post('/api/distinguish', data).done(function(response) {
				if(response.json.errors.length > 0) {
					console.log('Error while posting comment:');
					console.log(response.json.errors);
					alert('Error while posting comment. Please check the console for more information!');
					return;
				}

				location.reload();
			});
		});
	},

	// ////////////////////////////////////////////////////////////////////////
	// nuke functions
	// ////////////////////////////////////////////////////////////////////////

	/**
	 * Find the a comment with the given id in a response object.
	 *
	 * Parameters:
	 *	commentId (string) - something like t1_abc
	 *	response (object) - response object returned by a API call
	 *
	 * Returns:
	 *	(object) or undefined
	 */
	_findCommentInResponse: function(commentId, response) {
		var searchedComment;

		// build a search queue to go through
		var search = new Array();
		for(var i = 0; i < response.length; i++) {
			var listing = response[i].data.children;
			for(var n = 0; n < listing.length; n++) {
				var content = listing[n];

				// if data is something else than a comment skip
				if(content.kind !== 't1') {
					continue;
				} else {
					// the comment is the one we search
					if(content.data.id === commentId) {
						return content;
					} else {
						// comment is not what we search but maybe one of his replies?
						// add replies to search queue
						if(typeof content.data.replies !== 'undefined' && content.data.replies !== '') {
							search = search.concat(content.data.replies.data.children);
						}
					}
				}
			}
		}

		while(search.length > 0) {
			var currentObj = search.pop();

			// check if this is the right comment
			if(currentObj.data.id === commentId) {
				return currentObj;
			}

			// add all the replies of this comment to the search array
			if(currentObj.data.replies !== '') {
				search = search.concat(currentObj.data.replies.data.children);
			}
		}

		return searchedComment;
	},

	/**
	 * Will find all replies to the given comment.
	 *
	 * Parameters:
	 *	obj (object) - thing object returned by a API call
	 *
	 * Returns:
	 *	(Array) Maybe an empty array if no replies where found. Array holds the ids as a
	 *		string. E.g. '1234', 'a23pav', ...
	 */
	_findAllReplies: function(obj) {
		var replies = new Array();

		// check if there are replies
		if(obj.data.replies === '') {
			return replies;
		}

		var search = new Array();
		for(var i = 0; i < obj.data.replies.data.children.length; i++) {
			var reply = obj.data.replies.data.children[i];
			replies.push(reply.data.id);
			if(typeof reply.data.replies !== 'undefined' && reply.data.replies !== '') {
				search = search.concat(reply.data.replies.data.children);
			}
		}

		while(search.length > 0) {
			var currentObj = search.pop();

			// 'more' occures if there are more than 10 entries
			if(currentObj.kind === 'more') {
				continue;
			}

			// add the id of the current reply
			replies.push(currentObj.data.id);

			// add all replies to the reply to the search
			if(currentObj.data.replies !== '') {
				search = search.concat(currentObj.data.replies.data.children);
			}
		}

		return replies;
	},

	/**
	 * Remove the given comment.
	 *
	 * Parameters:
	 *	commentId (string) - id of the comment to remove
	 *	timeout (int) - timeout in milliseconds
	 */
	_nukeComment: function(commentId, timeout) {
		var that = this;
		setTimeout(function() {
			var data = {
				'id': 't1_' + commentId
				, 'uh': that._getModhash()
			}

			jQuery.post('/api/remove', data).done(function(response) {
				var el = jQuery('div.thing[data-fullname="t1_'+commentId+'"]');
				jQuery(el).hide(1000, function() {
					jQuery(el).remove();
				});
			}).error(function(response) {
				console.log(response);
			});
		}, timeout);
	},

	/**
	 * Inject the nuke button.
	 */
	_injectNuke: function() {
		var nukeButton = jQuery('<a href="#" class="raawNuke" title="Nuke!">[Nuke]</a>');

		// add click listener
		var that = this;
		jQuery(nukeButton).click(function(e) {
			e.preventDefault();
			var dataFullname = jQuery(this).closest('div.thing').attr('data-fullname');
			var link = jQuery('#siteTable').find('div.thing').attr('data-fullname').slice(3); // cut off t3_

			// get all the comments for this thread and find the right parent comment
			jQuery.getJSON('/comments/'+link+'.json').done(function(response) {
				var searchedComment = that._findCommentInResponse(dataFullname.slice(3), response);
				if(typeof searchedComment !== 'undefined') {
					// extract all children
					var removeThese = that._findAllReplies(searchedComment);

					// add the parent itself; but remove t1_ because thats how the other look to!
					removeThese.push(dataFullname.slice(3));
					for(var i = 0; i < removeThese.length; i++) {
						var childsDataFullname = removeThese[i];
						that._nukeComment(removeThese[i], (i * 750) + 100);
					}
				}
			});
		});

		// insert button
		jQuery('div.commentarea div.thing p.tagline span.userattrs').prepend(nukeButton);
	}
};

// initialize when document loaded
jQuery(document).ready(function() {
	RaaW.init();
});