// ==UserScript==
// @name           Mother Jones - Kevin Drum Killfile
// @namespace      http://sgd.homelinux.net/greasemonkey/
// @description    Implements kill file functionality for Kevin Drum's blog at Mother Jones
// @include        http://www.motherjones.com/kevin-drum/*
// ==/UserScript==

/*
$Id: kevindrumkillfile.user.js 21 2009-02-16 23:37:30Z stand $
This is a kill file script. It handles all the web log listed
above in the include directives. The script maintains a persistent kill file
list for the web log that can be personalized by you, the script user. A user
in the kill file will have his/her post comments blanked out. The killed
comment will still display its signature line.

The kill file is maintained via "kill links". This script places a kill link
next to each post comment. When you click this link, the author of the comment
will be added to the kill file.

The script places a similar unkill link next to each killed comment that allows
you to remove the comment author from the kill file.

If you are so inclined, you can manually manipulate the kill file list. It is
stored as a script parameter. To access, enter "about:config" in Firefox's
address bar. Type "greasemonkey" in the filter box. The kill file is stored
in a variable with a name that ends with "Web Log Killfile.*" where * is an
identifier for the web log. The list is delimited with the KF_DELIMITER
variable listed in this script. Double click the parameter to edit it. You'll
need to refresh any blog posts to see your changes.

This script is presented as is with no warrantee or nothin'. Modify it if you
want. If you want to report a bug, if you extend it to add new web logs, or
just make some cool modifications, email me at
stan [dot] dyck (at) gmail {dot} com.

*/
var KF_DELIMITER = "@@";
var KF_NAME = "KevinDrum";

/*
Declare associative arrays of functions. Each array holds
a set of functions that are different depending on which
web log we are viewing
*/
var f_getCommentNodes = new Array();
var f_extractAuthor = new Array();
var f_addLinkToSig = new Array();
var f_removeComment = new Array();

/*
The getCommentNodes function extracts all the comments
from the DOM document and returns them as an array
of DOM nodes. You need one for each web log.
*/
f_getCommentNodes['KevinDrum'] = function() {
	var commentItems = document.evaluate(
		"//div[starts-with(@class, 'comment ')]",
		document,
		null,
		XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
		null);
	var rtn = new Array();
	for(var i=0; i<(commentItems.snapshotLength); i++) {
		rtn.push(commentItems.snapshotItem(i));
	}
	return rtn;
}
//end of getCommentNodes functions


/*
The extractAuthor function takes a DOM node representing
a single comment and returns the author of the comment.
*/
f_extractAuthor['KevinDrum'] = function(commentNode) {
	 //I'm going to pull this from the img title attribute in the userPic div
	 var imgNodes = document.evaluate("div[@class='userPic']//img",
												 commentNode,
												 null,
												 XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
												 null);
	 var imgNode = imgNodes.snapshotItem(0);
	 return imgNode.attributes.getNamedItem("title").value;
	 
}
//End of extractAuthor functions

/*
The addLinkToSig function takes a DOM node representing a single comment,
a string representing the comment author's name and a boolean. The function
adds a (un)kill link to the comment node. If the boolean is true it should
be a kill link, false means it's an unkill link.
*/
f_addLinkToSig['KevinDrum'] = function(commentNode, author, kill) {
	 var linkNodes = document.evaluate("div[@class='links']/ul[@class='links']/li",
												  commentNode,
												  null,
												  XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
												  null);
	 
	 var lastLi = linkNodes.snapshotItem(linkNodes.snapshotLength -1);
	 var matchRE = new RegExp("<a .*href=.(un)?kill");
	 
	 //add the (un)kill link.
	 var t = kill? "kill": "unkill";

	 var killLi = document.createElement("li");
	 var killLink = document.createElement("a");
	 killLink.setAttribute("href", t + "('" + author + "')");
	 var atitle = kill? "Click to remove all posts by this author": "Click to reinstate all posts by this author (requires refresh)";
	 killLink.setAttribute("title", atitle);
	 killLink.innerHTML = t;
	 killLi.appendChild(killLink);
	 if(lastLi.innerHTML.match(matchRE)) {
		  lastLi.parentNode.replaceChild(killLi, lastLi);
	 } else {
		  lastLi.parentNode.appendChild(killLi);		  
	 }
}
//end of addLinkToSig functions

/*
The removeComment function takes a DOM node representing a blog
comment. The function should alter the contents of the node to
show it as a killed comment. What exactly it does (replace it with
some text, or remove it entirely) is up to you.
*/
f_removeComment['KevinDrum'] = function(commentNode) {
	 var sCommentTitle = document.evaluate("h3", commentNode, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
	 var commentTitle = sCommentTitle.snapshotItem(0);
	 commentTitle.innerHTML = "Dumb comment removed";

	 var sContent = document.evaluate("div[@class='content']", commentNode,  null ,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
	 var content = sContent.snapshotItem(0);
	 content.innerHTML = "<p>Comment removed</p>";
}
//end of removeComment functions.

/*
The section below contains the static code. Nothing below should
need to change.
*/
var u_getCommentNodes = f_getCommentNodes[KF_NAME];
var u_extractAuthor = f_extractAuthor[KF_NAME];
var u_addLinkToSig = f_addLinkToSig[KF_NAME];
var u_removeComment = f_removeComment[KF_NAME];

//A convenience function to remove whitespace on either side of a string.
String.prototype.trim = function() {
  return this.replace(/(^\s*)|(\s*$)/g, "");
}

//The main function run on the window.onLoad event and every time a (un)kill link is clicked.
function adjust() {
	var curKF = getKillArray();
	var comments = u_getCommentNodes();
	for(var i=0; i<comments.length; i++) {
		var userID = u_extractAuthor(comments[i]);
		var killMe = false; //user shouldn't be killed by default.
		for(var j=0; j<curKF.length; j++) {
			if(curKF[j] == userID) {  //found in kill list
				killMe = true;
				break;
			}
		}
		if(killMe) { //remove the comment and put in an  unkill link.
			u_removeComment(comments[i]);
		}
		u_addLinkToSig(comments[i], userID, !killMe); //put in the opposite link from their kill status
	}
}

//trap all click events and run them through this anonymous function.

document.addEventListener('click', function(event) {
	var clickTarget = unescape(event.target);
	var lMatcher = /.*\/(un)?kill\('(.*)'\)$/;  //finds the (un)kill link
	var match = lMatcher.exec(clickTarget);
	if(match != null) { //user clicked a (un)kill link.
		if(match[1] == null) {
			if(confirm("Add " + match[2] + " to your kill file?")) {
				addToKillFile(match[2]);
				adjust();
			}
		} else {
			if(confirm("Remove " + match[2] +
			" from your kill file? (You'll need to refresh to see " + match[2] +
			"'s comments on this page)")) {
				removeFromKillFile(match[2]);
				adjust();
			}
		}
		//prevent further processing of the click event.
		event.stopPropagation();
		event.preventDefault();
	}
}, true);

window.onload = adjust();

//returns an array of names on the kill list.
function getKillArray() {
	if(GM_getValue(KF_NAME, "") == "") {
		return new Array();
	} else {
		return GM_getValue(KF_NAME, "").split(KF_DELIMITER);
	}
}

/*
Adds the specified name to the kill file.
*/
function addToKillFile(name) {
	var curKF = getKillArray();
	for(var i=0; i<curKF.length; i++) {
		if(name == curKF[i]) return;
	}
	curKF.push(name);
	GM_setValue(KF_NAME, curKF.join(KF_DELIMITER));
}

/*
Removes the specified name from the kill file.
*/
function removeFromKillFile(name) {
	var curKF = getKillArray();
	var newKF = new Array();
	for(var i=0; i<curKF.length; i++) {
		if(curKF[i] != name)
			newKF.push(curKF[i]);
	}
	GM_setValue(KF_NAME, newKF.join(KF_DELIMITER));
}
//kevindrumkillfile.user.js
