// ==UserScript==
// @name          phpBB ignore users
// @description   Ignore posts by users you don't like on phpBB boards
// @namespace     http://www.mrphlip.com/
// @include       */viewtopic.php?*
// ==/UserScript==

// Note: these images are made from the subSilver SDK, which is
// Copyright  2001 phpBB Group and is for non-commercial use only.
ignorebutton = 
"data:image/png;base64,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"
unignorebutton =
"data:image/png;base64,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"
viewbutton =
"data:image/png;base64,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" +
"f0juULNv8Ly1Vc7Np1eKAAAAAASUVORK5CYII="

ignoreListStr = GM_getValue(location.hostname, "").split(':');
ignoreList = new Array();
for (i = 0; i < ignoreListStr.length; i++)
{
	a = parseInt(ignoreListStr[i], 10);
	if (!isNaN(a))
		ignoreList.push(a);
}

posts = new Array();

profileLinksXPath = document.evaluate("//a[contains(@href,'profile.php?mode=viewprofile')]", document, null, XPathResult.ANY_TYPE, null);
// manipulating the DOM invalidates the XPath, so iterate through it first
profileLinks = new Array();
while (i = profileLinksXPath.iterateNext())
	profileLinks.push(i);
for (i = 0; i < profileLinks.length; i++)
{
	matches = profileLinks[i].href.match(/u=(\d+)/);
	if (!matches) continue;
	post = new Object;
	post.uid = parseInt(matches[1], 10);
	post.tr2 = profileLinks[i];
	// the link is wrapped in its own table, so find that, then find the row of the main table it's in
	// (yay for using tables for layouts...)
	while (post.tr2 && post.tr2.nodeName.toLowerCase() != "table")
		post.tr2 = post.tr2.parentNode;
	while (post.tr2 && post.tr2.nodeName.toLowerCase() != "tr")
		post.tr2 = post.tr2.parentNode;
	if (!post.tr2) continue;
	post.tr1 = post.tr2.previousSibling;
	while (post.tr1 && post.tr1.nodeName.toLowerCase() != "tr")
		post.tr1 = post.tr1.previousSibling;
	if (!post.tr1) continue;
	// get the post number -- avoid counting a post twice
	postlink = document.evaluate(".//a[contains(@href,'viewtopic.php?p=')]", post.tr1, null, XPathResult.ANY_TYPE, null).iterateNext();
	if (!postlink) continue;
	matches = postlink.href.match(/p=(\d+)/);
	if (!matches) continue;
	post.pid = parseInt(matches[1], 10);
	if (posts[post.pid]) continue;
	posts[post.pid] = post;
	// get the user's name
	username = document.evaluate(".//span[@class='name']//b//child::text()", post.tr1, null, XPathResult.ANY_TYPE, null).iterateNext();
	if (!username) continue;
	post.username = username.nodeValue;
	
	profileLinks[i].parentNode.appendChild(document.createTextNode(' '));
	post.ignorelink = document.createElement('img');
	post.ignorelink.style.cursor = "pointer";
	profileLinks[i].parentNode.appendChild(post.ignorelink);
	// this hideous construction will make a closure to call toggleIgnore with the appropriate uid
	post.ignorelink.addEventListener('click', (function (uid){return function(){toggleIgnore(uid)}})(post.uid), false);
	
	post.ignored = (ignoreList.indexOf(post.uid) >= 0);
	if (post.ignored)
	{
		post.ignorelink.src = unignorebutton;
		post.ignorelink.alt = post.ignorelink.title = "Stop hiding posts from " + post.username
		hidePost(post);
	}
	else
	{
		post.ignorelink.src = ignorebutton;
		post.ignorelink.alt = post.ignorelink.title = "Hide posts from " + post.username
	}
}

function hidePost(post)
{
	if (!post.placeholder)
	{
		post.placeholder = document.createElement('tr');
		post.placeholder.id = post.pid;
		td = document.createElement('td');
		post.placeholder.appendChild(td);
		td.colSpan = 2;
		td.className = post.tr1.getElementsByTagName('td')[0].className;
		td.style.padding = "0.2em 1em";
		td.style.font = "italic 12px sans-serif";
		td.appendChild(document.createTextNode("A post by " + post.username + " "));
		img = document.createElement('img');
		img.src = viewbutton;
		img.alt = img.title = "Show this post";
		img.style.marginLeft = "10px";
		img.style.cursor = "pointer";
		td.appendChild(img);
		img.addEventListener('click', function(){showPost(post)}, false);
		post.tr1.parentNode.insertBefore(post.placeholder, post.tr1);
	}
	post.tr1.style.display = "none";
	post.tr2.style.display = "none";
	post.placeholder.style.display = "";
}
function showPost(post)
{
	post.tr1.style.display = "";
	post.tr2.style.display = "";
	if (post.placeholder)
		post.placeholder.style.display = "none";
}

function ignoreUser(uid)
{
	// make sure we don't overwrite a change made on another page
	newIgnoreListStr = GM_getValue(location.hostname, "").split(':');
	newIgnoreList = new Array();
	for (i = 0; i < newIgnoreListStr.length; i++)
	{
		a = parseInt(newIgnoreListStr[i], 10);
		if (!isNaN(a))
			newIgnoreList.push(a);
	}
	i = newIgnoreList.indexOf(uid);
	if (i < 0)
	{
		newIgnoreList.push(uid);
		GM_setValue(location.hostname, newIgnoreList.join(':'));
	}
	ignoreList.push(uid);
	for (i in posts)
	{
		if (posts[i].uid == uid)
		{
			hidePost(posts[i]);
			posts[i].ignorelink.src = unignorebutton;
			posts[i].ignorelink.alt = posts[i].ignorelink.title = "Stop hiding posts from " + posts[i].username
		}
	}
}
function unignoreUser(uid)
{
	// make sure we don't overwrite a change made on another page
	newIgnoreListStr = GM_getValue(location.hostname, "").split(':');
	newIgnoreList = new Array();
	for (i = 0; i < newIgnoreListStr.length; i++)
	{
		a = parseInt(newIgnoreListStr[i], 10);
		if (!isNaN(a))
			newIgnoreList.push(a);
	}
	i = newIgnoreList.indexOf(uid);
	if (i >= 0)
	{
		newIgnoreList.splice(i, 1);
		GM_setValue(location.hostname, newIgnoreList.join(':'));
	}
	i = ignoreList.indexOf(uid);
	if (i >= 0)
		ignoreList.splice(i, 1);
	for (i in posts)
	{
		if (posts[i].uid == uid)
		{
			showPost(posts[i]);
			posts[i].ignorelink.src = ignorebutton;
			posts[i].ignorelink.alt = posts[i].ignorelink.title = "Hide posts from " + posts[i].username
		}
	}
}
function toggleIgnore(uid)
{
	i = ignoreList.indexOf(uid);
	if (i < 0)
		ignoreUser(uid);
	else
		unignoreUser(uid);
}
