User:Shubinator/DYKcheck.js: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
adding check for various tags, including AfD and CSD
find hooks starting with "...that", as suggested at WT:DYK
Line 271: Line 271:
bodyHTML.indexOf('NewPP limit report'));
bodyHTML.indexOf('NewPP limit report'));
}
}
thisSection = thisSection.replace('that,', 'that ');
thisSection = thisSection.replace('that,', 'that ').replace('...that ', '... that ');
if (thisSection.indexOf("5x expan") != -1) {
if (thisSection.indexOf("5x expan") != -1) {
nom5x = true;
nom5x = true;

Revision as of 05:08, 26 April 2009

	// ***************************************************************** //
	//		  	    DYKcheck tool			     //
	//		  	     Version 1.1			     //
	// For quick installation, add					     //
	// importScript('User:Shubinator/DYKcheck.js');			     //
	// to your monobook.js						     //
	// See [[User:Shubinator/DYKcheck]] for more info, including	     //
	// configurable options and how to use the tool without installation //
	// or logging in.						     //
	// First version written by Shubinator in February 2009		     //
	// ***************************************************************** //

var onTTDYK, nextSection, urlJump, sections, currentTitle;
var partsProcessing, articleTitles, dates, nom5x;
var dateFormat, hookLengthYellow, hookLengthRed, check5xNoms, unlock, fixedSidebar; //configurable options
if (!hookLengthYellow) hookLengthYellow = 200;
if (!hookLengthRed) hookLengthRed = 220;
if (!check5xNoms) check5xNoms = "ifnom5x";
if (!fixedSidebar) fixedSidebar = "onttydk";

function scanArticle(title, output, html) {
	// the meat of the DYKcheck tool
	// calculates prose size of the given html
	// checks for inline citations and stub templates in the given html
	// passes info to checkTalk(), getFirstRevision(), checkMove(), and checkExpansion()
	
	if (!onTTDYK || (check5xNoms == "always") || (check5xNoms == "ifnom5x" && nom5x)) {
		partsProcessing = new Array(4);
	} else {
		partsProcessing = new Array(3);
	}
	dates = new Array(3);

	var proseDisp = document.createElement("li");
	proseDisp.id = "dyk-prose";
	output.appendChild(proseDisp);

	// calculate prose size
	var prose = calculateProse(html, true);
	var pList = html.getElementsByTagName("p");
	var word_count = 0;
	for (var i=0;i < pList.length; i++) {
		var para = pList[i];
		if (para.parentNode == html) {
			word_count += para.innerHTML.replace(/(<([^>]+)>)/ig,"").split(' ').length;
		}
	}
	proseDisp.innerHTML='<b>Prose size (text only): </b>' + prose + '&nbsp;B (' +
			word_count + ' words) "readable prose size"';
	if (prose < 1500) {
		proseDisp.style.cssText = "background-color:pink";
	}
	
	// check for inline citations
	if (html.innerHTML.indexOf('id="cite_ref-') == -1 && html.innerHTML.indexOf('id=cite_ref-') == -1) {
		var noref = document.createElement("li");
		noref.id = "no-ref";
		output.appendChild(noref);
		noref.innerHTML = 'No inline citations';
		noref.style.cssText = "background-color:pink";
	}
	
	// check if article is stub or if it has appeared in DYK or ITN
	if (html.innerHTML.indexOf('id="stub"') != -1 || html.innerHTML.indexOf('id=stub') != -1) {
		var stubAlert = document.createElement("li");
		stubAlert.id = "stub-alert";
		output.appendChild(stubAlert);
		stubAlert.innerHTML = 'Article is classified as a stub';
		stubAlert.style.cssText = "background-color:yellow";
	}
	checkTalk(title, output); //check talk page
	
	// check for various tags
	var alertColor = "yellow";
	var tagsFound = "";
	var imageList = new Array("Text_document_with_red_question_mark.svg", 
			"Question book-new.svg", "Ambox content.png", "Ambox style.png", 
			"Imbox style.png", "Copyright-problem.svg", "Copyright-problem paste.svg", 
			"Ambox globe content.svg", "Unbalanced scales.svg", "Ambox scales.svg", 
			"Ambox_contradict.svg", "Ambox warning orange.svg", "Acap.svg");
	var tagList = new Array("unverified content", "citations", "dispute", "cleanup", "cleanup",
			"copyright violations", "copyright violations", "globalization", "neutrality", 
			"neutrality", "contradiction", "dispute", "copyedit");
	if (html.innerHTML.indexOf("This article is being considered for deletion in accordance with Wikipedia's") != -1) {
		var afdIndex = html.innerHTML.indexOf('title="Wikipedia:Articles for deletion/') + 7;
		var afdLink = html.innerHTML.substring(afdIndex, html.innerHTML.indexOf('"', afdIndex));
		tagsFound += 'Article has been <b><a href="http://en.wikipedia.org/wiki/' + afdLink + '">nominated for deletion</a></b>. '
		alertColor = "pink";			
	} else if ((html.innerHTML.toLowerCase().indexOf('<table class="plainlinks ombox ombox-speedy"') != -1) || 
			(html.innerHTML.toLowerCase().indexOf('<table class="plainlinks ambox ambox-speedy"') != -1) || 
			(html.innerHTML.toLowerCase().indexOf('<table class="metadata plainlinks ombox ombox-speedy"') != -1) ||
			(html.innerHTML.toLowerCase().indexOf('<table class="metadata plainlinks ambox ambox-speedy"') != -1)) {
		tagsFound += "Article has been <b>tagged for speedy deletion</b>. "
		alertColor = "pink";
	}
	for (var i=0; i < imageList.length; i++) {
		if (html.innerHTML.indexOf(imageList[i]) != -1) {
			tagsFound += "Article has a " + tagList[i] + " tag. ";
		}
	}
	if (tagsFound != "") {
		var tagAlert = document.createElement("li");
		tagAlert.id = "tag-alert";
		output.appendChild(tagAlert);
		tagAlert.innerHTML = tagsFound;
		tagAlert.style.cssText = "background-color:" + alertColor;
	}
		
	// find creator of article and date
	getFirstRevision(title, output);
	
	// check if the article has been moved from userspace within last 100 edits
	if (wgNamespaceNumber != 2) {
		checkMove(title, output);
	} else {
		partsProcessing[2] = true;
	}
	
	// check for expansion start date, assuming now expanded to 5x (last 500 edits)
	if (!onTTDYK || (check5xNoms == "always") || (check5xNoms == "ifnom5x" && nom5x)) {
		checkExpansion(title, output, prose);
	}
}

function checkDocument() {
	// prepares for scan and passes info to scanArticle()
	onTTDYK = false;
	if (document.getElementById("dyk-stats-0")) {
		clearStats();
	} else {
		var output = document.createElement("ul");
		output.id = "dyk-stats-0";
		var dummy = document.getElementById("siteSub");
		dummy.parentNode.insertBefore(output, dummy.nextSibling);
		createHeaderAndProcessing(output);
		currentTitle = 0;
		var normalizedTitle = wgTitle.replace("%","%25").replace("+","%2B").replace("/","%2F");
		normalizedTitle = normalizedTitle.replace("?","%3F").replace("#","%23").replace("&","%26");
		if (wgNamespaceNumber == 2) {
			normalizedTitle = "User:" + normalizedTitle;
		}
		scanArticle(normalizedTitle, output, getBody());
	}
}

function checkTTDYK() {
	// finds the current nomination
	// can jump to a section if it shows up in the URL (i.e. http://en.wikipedia.org/wiki/T:TDYK#Older_nominations)
	// prepares for scan and passes info to checkHooks() and scanArticle() (through pit stop)
	
	onTTDYK = true;
	if (sections == null) {
		sections = document.getElementsByTagName("h4");
		nextSection = 0;
	}
	// Jumping code
	if (window.location.hash) {
		var sectionAt = window.location.hash;
		if (sectionAt != urlJump) {
			var jump = document.getElementById(sectionAt.substring(1, sectionAt.length));
			var next = jump.parentNode.nextSibling;
			while (next.nodeName.toLowerCase() != "h4") {
				next = next.nextSibling;
			}
			for (var i=0; i < sections.length; i++) {
				if (sections[i] == next) {
					nextSection = i;
					urlJump = sectionAt;
					break;
				}
			}
		}
	}
	
	if (nextSection == sections.length) {
		alert("Reached end of nominations; looping to beginning");
		nextSection = 0;
	}
	if (document.getElementById("dyk-stats-0")) {
		clearStats();
	}
	var firstOutput = document.createElement("ul");
	firstOutput.id = "dyk-stats-0";
	sections[nextSection].parentNode.insertBefore(firstOutput, sections[nextSection].previousSibling);
	var hook = checkHooks(firstOutput);
	if (!hook) {
		var errorDisp = document.createElement("div");
		errorDisp.id = "error-disp";
		errorDisp.style.cssText = 'color:red; font-weight:bold;';
		errorDisp.innerHTML = 'Error: Hook is not formatted correctly';
		firstOutput.parentNode.insertBefore(errorDisp, firstOutput);
		nextSection++;
		return;
	}
	createHeaderAndProcessing(document.getElementById("dyk-stats-0"));
	var tempHolder = document.createElement("div");
	tempHolder.id = "temp-holder";
	tempHolder.innerHTML = hook;
	var bolded = tempHolder.getElementsByTagName("b");
	articleTitlesTemp = new Array(bolded.length);
	var titlesCounter = 0;
	for (var i=0; i < bolded.length; i++) {
		var links = bolded[i].getElementsByTagName("a");
		if (links.length > 0) {
			for (var j=0; j < links.length; j++) {
				var title = links[j].getAttribute("title");
				articleTitlesTemp[titlesCounter] = title;
				titlesCounter++;
			}
		} else {
			var pointer = bolded[i];
			while (pointer != tempHolder) {
				if (pointer.nodeName.toLowerCase() == "a") {
					var title = pointer.getAttribute("title");
					articleTitlesTemp[titlesCounter] = title;
					titlesCounter++;
				}
				pointer = pointer.parentNode;
			}
		}
	}
	currentTitle = 0;
	articleTitles = new Array(titlesCounter);
	var hookOutput = document.getElementById("hook-container");
	for (var i=0; i < titlesCounter; i++) {
		var output;
		if (i == 0) {
			output = firstOutput;
		} else {
			output = document.createElement("ul");
			output.id = "dyk-stats-" + i;
			hookOutput.parentNode.insertBefore(output, hookOutput);
		}
		var articleDisp = document.createElement("li");
		articleDisp.id = "article-title" + i;
		output.appendChild(articleDisp);
		articleDisp.innerHTML = '<b>Article ' + (i+1) + ':</b> ' + articleTitlesTemp[i];
		articleTitles[i] = articleTitlesTemp[i];
	}
	if (titlesCounter == 1) {
		document.getElementById("article-title0").innerHTML = '<b>Article:</b> ' + articleTitles[0];
	} else if (titlesCounter == 0) {
		if (document.getElementById("dyk-processing")) {
			var processing = document.getElementById("dyk-processing");
			processing.parentNode.removeChild(processing);
		}
		var errorDisp = document.createElement("div");
		errorDisp.id = "error-disp";
		errorDisp.style.cssText = 'color:red; font-weight:bold;';
		errorDisp.innerHTML = 'Error: The nominated article must appear in bold';
		sections[nextSection].parentNode.insertBefore(errorDisp, firstOutput);
		nextSection++;
		return;
	}
	nextSection++;
	redirectPitStop(articleTitles[0], firstOutput, 0);
}

function checkHooks(output) {
	// gets the nomination section (complete with comments, etc) and passes this to helper function
	var hookOutput = document.createElement("ul");
	hookOutput.id = "hook-container";
	output.parentNode.insertBefore(hookOutput, output.nextSibling);
	var bodyHTML = getBody().innerHTML;
	var thisSection;
	if (nextSection != sections.length - 1) {
		thisSection = bodyHTML.substring(bodyHTML.indexOf(sections[nextSection].innerHTML) + sections[nextSection].innerHTML.length, 
				bodyHTML.indexOf(sections[nextSection+1].innerHTML));
	} else {
		thisSection = bodyHTML.substring(bodyHTML.indexOf(sections[nextSection].innerHTML) + sections[nextSection].innerHTML.length, 
				bodyHTML.indexOf('NewPP limit report'));
	}
	thisSection = thisSection.replace('that,', 'that ').replace('...that ', '... that ');
	if (thisSection.indexOf("5x expan") != -1) {
		nom5x = true;
	} else {
		nom5x = false;
	}
	return checkHooksHelper(hookOutput, thisSection, 0);
}

function checkHooksHelper(hookOutput, whatsLeft, num) {
	// recursively finds proposed hooks for a nom
	// identifies hooks starting with " ... that " and ending with "?"
	// does not count "... " or "(pictured)" in hook character count
	var questionIndex = whatsLeft.indexOf("?");
	var whatsLeftLowerCase = whatsLeft.toLowerCase();
	while ((whatsLeftLowerCase.indexOf("<a ", questionIndex) > 
			whatsLeftLowerCase.indexOf("</a>", questionIndex)) || 
			((whatsLeftLowerCase.indexOf("<a ", questionIndex) == -1) && 
			(whatsLeftLowerCase.indexOf("</a>", questionIndex) != -1)) ||
			(whatsLeftLowerCase.indexOf("<i>", questionIndex) > 
			whatsLeftLowerCase.indexOf("</i>", questionIndex)) || 
			((whatsLeftLowerCase.indexOf("<i>", questionIndex) == -1) && 
			(whatsLeftLowerCase.indexOf("</i>", questionIndex) != -1))) {
		questionIndex = whatsLeft.indexOf("?", questionIndex + 1);
	}
	if (whatsLeft.indexOf("... that ") != -1 && questionIndex != -1) {
		if (whatsLeft.indexOf("... that ") < questionIndex) {
			var hook = whatsLeft.substring(whatsLeft.indexOf("... that ") + 4, 
					questionIndex + 1);
			var hookTemp = document.createElement("div");
			hookTemp.id = "hook-temp";
			hookTemp.innerHTML = "<p>" + hook + "</p>";
			var hookLength = calculateProse(hookTemp, false);
			if (hookTemp.innerHTML.indexOf("pictured)") != -1 || 
					hookTemp.innerHTML.indexOf("(pictured") != -1) {
				hookLength = hookLength - 10;
			}
			var hookDisp = document.createElement("li");
			hookDisp.id = "hooks-" + num;
			if (num == 0) {
				hookDisp.innerHTML = '<b>Original Hook:</b> ' + hookLength + ' characters';
			} else {
				hookDisp.innerHTML = '<b>Alternate Hook '+num+'</b>: '+hookLength+' characters';
			}
			if (hookLength > hookLengthRed) {
				hookDisp.style.cssText = 'background-color:pink';
			} else if (hookLength > hookLengthYellow) {
				hookDisp.style.cssText = 'background-color:yellow';
			}
			hookOutput.appendChild(hookDisp);
			num = num + 1;
		}
		var parsed = whatsLeft.substring(questionIndex + 1, whatsLeft.length - 1);
		var lastHook = checkHooksHelper(hookOutput, parsed, num);
		if (!lastHook && hook) {
			lastHook = hook;
		}
		return lastHook;
	}
	return;
}

function redirectPitStop(title, output, i) {
	// checks if the nominated article is a redirect, passes info to checkTitle()
	var api = sajax_init_object();
	api.open('GET', wgScriptPath + '/api.php?action=query&titles=' + title + '&redirects&format=xml', true);
	api.onreadystatechange = function() {
		if (api.readyState  == 4) {
			if (api.status  == 200) {
				var response = api.responseXML.documentElement;
				var rs = response.getElementsByTagName("r");
				if (rs[0]) {
					title = rs[0].getAttribute("to");
				}
				checkTitle(title, output, i);
			} else {
				alert("XML error");
			}
		}
	};
	api.send(null);
}

function checkTitle(title, output, i) {
	// gets the given title from Wikipedia's server and passes it to scanArticle()
	var normalizedTitle = title.replace("%","%25").replace("+","%2B").replace("/","%2F");
	normalizedTitle = normalizedTitle.replace("?","%3F").replace("#","%23").replace("&","%26");
	var api = sajax_init_object();
	api.open('GET', wgScriptPath + '/index.php?title=' + normalizedTitle + '&action=render', true);
	api.onreadystatechange = function() {
		if (api.readyState  == 4) {
			if (api.status  == 200) {
				var ttdykTemp = document.createElement("div");
				ttdykTemp.id = "ttdyk-temp" + i;
				ttdykTemp.innerHTML = api.responseText;
				scanArticle(normalizedTitle, output, ttdykTemp);
			} else {
				alert("XML error");
			}
		}
	};
	api.send(null);
}

function clearStats() {
	// if scan results already exist, turn them off and remove highlighting
	if (!onTTDYK) {
		var oldStyle = document.getElementById("dyk-stats-0").className;
		var mainContent = getBody();
		var pList = mainContent.getElementsByTagName("p");
		for (var i=0; i < pList.length; i++) {
			if (pList[i].parentNode == mainContent) pList[i].style.cssText = oldStyle;
		}
	}
	if (document.getElementById("error-disp")) {
		var errorDisp = document.getElementById("error-disp");
		errorDisp.parentNode.removeChild(errorDisp);
	}
	var i=0;
	while (document.getElementById("dyk-stats-" + i)) {
		var output = document.getElementById("dyk-stats-" + i);
		output.parentNode.removeChild(output);
		i++;
	}
	if (document.getElementById("hook-container")) {
		var hookOutput = document.getElementById("hook-container");
		hookOutput.parentNode.removeChild(hookOutput);
	}
	if (document.getElementById("dyk-header")) {
		var header = document.getElementById("dyk-header");
		header.parentNode.removeChild(header);
	}
	if (document.getElementById("dyk-processing")) {
		var processing = document.getElementById("dyk-processing");
		processing.parentNode.removeChild(processing);
	}
}

function calculateProse(doc, highlight) {
	// calculates the prose of a given document
	// this function and its helper below are modified versions of
	// the prosesize tool (http://en.wikipedia.org/wiki/User:Dr_pda/prosesize.js)
	var pList = doc.getElementsByTagName("p");
	var prose_size = 0;
	for (var i=0; i < pList.length; i++) {
		if (pList[i].parentNode == doc) {
			prose_size += getReadable(pList[i], highlight);
			if (!onTTDYK && highlight) {
				pList[i].style.cssText = 'background-color:yellow';
			}
		}
	}
	return prose_size;
}

function getReadable(id, dehighlight) {
	// helper method for calculateProse()
	var textReadable = 0;
	for (var i=0; i < id.childNodes.length; i++) {
		if (id.childNodes[i].nodeName == '#text') {
			textReadable += id.childNodes[i].nodeValue.length;
		} else if (id.childNodes[i].className != 'reference') {
			textReadable += getReadable(id.childNodes[i], dehighlight);
		} else if (dehighlight) { //if the node's className is reference
			if (document.getElementById("dyk-stats-0").className != "") {
				id.childNodes[i].style.cssText = document.getElementById("dyk-stats-0").className;
			} else {
				id.childNodes[i].style.cssText = 'background-color:white';
			}	
		}
	}
	return textReadable;
}

function checkExpansion(title, output, current) {  
	// finds the start of expansion date (last 500 edits)
	// gets the last 500 unique revision ids for past revisions of the article and passes to helper function
	var api = sajax_init_object();
	api.open('GET', wgScriptPath + '/api.php?action=query&prop=revisions&titles=' + 
			title + '&&rvlimit=500&rvprop=ids|timestamp&rvdir=older&format=xml', true);
	api.onreadystatechange = function() {
		if (api.readyState  == 4) {
			if (api.status  == 200) {
				var expandTemp = document.createElement("div");
				expandTemp.id = "expand-temp";
				var response = api.responseXML.documentElement;
				var revIds = response.getElementsByTagName('rev');
				checkExpansionHelper(title, current, output, expandTemp, revIds, 0, revIds.length-1, -1);
			} else {
				alert("XML error");
			}
		}
	};
	api.send(null);
}

function checkExpansionHelper(title, current, output, expandTemp, revIds, min, max, expandIndex) {
	// helper for expansion check, used recursively
	// searches for start of expansion date using a binary search algorithm
	// assumes the article has been more or less increasing in size all the time
	// if the article length has yoyo-ed, this function won't give accurate results
	var mid = Math.ceil((max + min)/2);
	if ((((max - min) < 2) && (max != revIds.length - 1 || expandIndex != -1)) || expandIndex == -2) {
		var expandResult = document.createElement("li");
		expandResult.id = "expand-result";
		output.appendChild(expandResult);
		if (expandIndex < 0) {
			if (revIds.length == 500) {
				expandResult.innerHTML = 'Article has not been expanded 5x in the last 500 edits';
			} else {
				expandResult.innerHTML = 'Article has not been expanded 5x since it was created';
			}
		} else {
			var date = revIds[expandIndex-1].getAttribute('timestamp');
			expandResult.innerHTML = 'Assuming article is at 5x now, expansion began ' + 
					expandIndex + ' edits ago on ' + toNormalDate(date.substring(0,10));
			dates[2] = toDateObject(date);
		}
		partsProcessing[3] = true;
		doneProcessing();
		return;
	} else if ((max - min) < 2 && max == revIds.length - 1) {
		expandIndex = -2;
	}
	var api = sajax_init_object();
	api.open('GET', wgScriptPath + '/index.php?title=' + title + 
			'&action=render&redirect=no&oldid=' + revIds[mid].getAttribute('revid'), true);
	api.onreadystatechange = function() {
		if (api.readyState  == 4) {
			if (api.status  == 200) {
				expandTemp.innerHTML = api.responseText;
				var prose = calculateProse(expandTemp, false);
				// alert("Prose: " + prose + " 1x: " + current/5 + " Mid: " + mid + " Expand index: " + expandIndex); 
				// use above line to debug the expansion check
				if (prose < (current/5.0)) {
					if ((expandIndex > mid) || (expandIndex < 0)) {
						expandIndex = mid;
					}
					checkExpansionHelper(title, current, output, expandTemp, revIds, min, mid, expandIndex);
				} else {
					checkExpansionHelper(title, current, output, expandTemp, revIds, mid, max, expandIndex);
				}
			} else {
				alert("XML error");
				partsProcessing[3] = true;
				doneProcessing();
			}
		}
	};
	api.send(null);
}

function checkTalk(title, output) { 
	// checks the talk page of the article for DYK, ITN, or stub templates
	if (wgNamespaceNumber != 2) {
		title = "Talk:" + title;
	} else {
		title = title.replace("User:", "User talk:");
	}
	var api = sajax_init_object();
	api.open('GET', wgScriptPath + '/api.php?action=query&prop=revisions&format=xml&titles=' + 
			title + '&rvprop=content', true);
	api.onreadystatechange = function() { 
		if (api.readyState  == 4) {
			if (api.status  == 200) {
				var response = api.responseXML.documentElement;
				var revisions = response.getElementsByTagName('rev');
				var talkPage = revisions[0].firstChild.nodeValue;
				var result = '';
				var color = 'yellow';
				if ((talkPage.indexOf('class=stub') != -1 || talkPage.indexOf('class=Stub') != -1) && 
						(document.getElementById("stub-alert") == null)) {
					result += 'Article is classified as a stub ';
				}
				if (talkPage.indexOf('{{dyktalk') != -1) {
					result += 'Article has appeared on Did You Know before ';
					color = 'pink';
				}
				if (talkPage.indexOf('{{ITNtalk') != -1) {
					result += 'Article has appeared on In The News before ';
					color = 'pink';
				}
				if (result != '') {
					var talkResult = document.createElement("li");
					talkResult.id = "talk-result";
					output.appendChild(talkResult);
					talkResult.innerHTML = result;
					talkResult.style.cssText = 'background-color:' + color;
				}
				partsProcessing[0] = true;
				doneProcessing();
			} else {
				alert("XML error");
				partsProcessing[0] = true;
				doneProcessing();
			}
		} else {
			partsProcessing[0] = true;
			doneProcessing();
		}
	};
	api.send(null);
}

function getFirstRevision(title, output) {
	// finds the creator of the article, and the date created
	// also checks if the article was created as a redirect, finds non-redirect date if so
	var created = document.createElement("li");
	created.id = "creation-info";
	output.appendChild(created);
		
	var api = sajax_init_object();
	api.open('GET', wgScriptPath + '/api.php?action=query&prop=revisions&format=xml&titles=' + 
			title + '&rvlimit=4&rvprop=timestamp|user|content&rvdir=newer&redirect=no', true);
	api.onreadystatechange = function() { 
		if (api.readyState  == 4) {
			if (api.status  == 200) {
				var response = api.responseXML.documentElement;
				var revisions = response.getElementsByTagName('rev');
				var user = revisions[0].getAttribute('user');
				var timestamp = revisions[0].getAttribute('timestamp');
				created.innerHTML='<b>Article created </b> by ' + user + 
						' on ' + toNormalDate(timestamp.substring(0,10));
				dates[0] = toDateObject(timestamp);
				for (var i=0; i < revisions.length; i++) {
					if (revisions[i].firstChild) {
						var content = revisions[i].firstChild.nodeValue.replace(' ', '').replace(':', '').toUpperCase();
						if (content.indexOf('#REDIRECT[[') != -1 && i == 0) {
							created.innerHTML = created.innerHTML + ' as a redirect';
						} else if (content.indexOf('#REDIRECT[[') == -1) {
							if (i != 0) {
								var unRedirect = document.createElement("li");
								unRedirect.id = "expanded-from-redirect";
								output.appendChild(unRedirect);
								var urUser = revisions[i].getAttribute('user');
								var urTimestamp = revisions[i].getAttribute('timestamp');
								unRedirect.innerHTML = 'Article became a non-redirect on ' + 
										toNormalDate(urTimestamp.substring(0,10)) + ' by ' + urUser;
								dates[0] = toDateObject(urTimestamp);
							}
							break;
						}
					}
				}
				partsProcessing[1] = true;
				doneProcessing();
			} else {
				alert("XML error");
				partsProcessing[1] = true;
				doneProcessing();
			}
		}
	};
	api.send(null);
}

function checkMove(title, output) { 
	//checks the last 100 edits of an article for a move from userspace to current location
	var api = sajax_init_object();
	api.open('GET', wgScriptPath + '/api.php?action=query&prop=revisions&format=xml&titles=' + 
			title + '&rvlimit=100&rvprop=flags|timestamp|comment&rvdir=older', true);
	api.onreadystatechange = function() { 
		if (api.readyState  == 4) {
			if (api.status  == 200) {
				var response = api.responseXML.documentElement;
				var revisions = response.getElementsByTagName('rev');
				for (var i=0; i < revisions.length; i++) {
					if (revisions[i].getAttribute('comment')) {
						var comment = revisions[i].getAttribute('comment');
						if ((revisions[i].getAttribute('minor') == "") && (comment.substring(0,13) == "moved [[User:") 
								&& (comment.indexOf("to [[") != -1)) {
							var movedFrom = comment.substring(8, comment.indexOf("to [[") - 3);
							var date = revisions[i].getAttribute('timestamp');
							var moved = document.createElement("li");
							moved.id = "moved-userspace";
							output.appendChild(moved);
							moved.innerHTML = '<b>Article moved</b> from ' + movedFrom + 
									' on ' + toNormalDate(date.substring(0,10));
							dates[1] = toDateObject(date);
							break;
						}
					}
				}
				partsProcessing[2] = true;
				doneProcessing();
			} else {
				alert("XML error");
				partsProcessing[2] = true;
				doneProcessing();
			}
		}
	};
	api.send(null);
}

function doneProcessing() {
	// checks if all parts are done processing
	// if they are, the dates of creation and expansion are checked for within 10 days (rounded down, in nominator's favor)
	// then the next title (for multiple article noms) is processed (required to combat asynchronous threads)
	// if there are no more titles left (or not on T:TDYK), the processing message is removed
	var titleComplete = true;
	for (i=0; i < partsProcessing.length; i++) {
		if (partsProcessing[i] != true) {
			titleComplete = false;
			break;
		}
	}
	if (document.getElementById("dyk-processing") && titleComplete) {
		var curDate = new Date();
		var round1Winner = new Date();
		var winner = new Date();
		if (dates[1]) {
			round1Winner = dates[1]; 
		} else {
			round1Winner = dates[0];
		}
		if (dates[2] > round1Winner) {
			winner = dates[2];
		} else {
			winner = round1Winner;
		}
		var dateDifference = Math.floor((curDate.getTime() - winner.getTime())/(1000*60*60*24));
		if (dateDifference > 10) {
			var output = document.getElementById("dyk-stats-" + currentTitle);
			var notRecent = document.createElement("li");
			notRecent.id = "not-recent";
			output.appendChild(notRecent);
			if (!onTTDYK || (check5xNoms == "always") || (check5xNoms == "ifnom5x" && nom5x)) {
				notRecent.innerHTML = "Article has not been created or expanded 5x within the past 10 days (" + 
						dateDifference + " days)" + " <small>DYKcheck does not account for previous versions with " +
						'<a href="http://en.wikipedia.org/wiki/Wikipedia:Split">splits</a> or ' +
						'<a href="http://en.wikipedia.org/wiki/Wikipedia:Copyright_violations">copyright violations</a>.</small>';
			} else {
				notRecent.innerHTML = "Article was not created within the past 10 days (" + dateDifference + " days)";
			}
			notRecent.style.cssText = 'background-color:pink';
		}
		if (onTTDYK && currentTitle < (articleTitles.length - 1)) {
			currentTitle++;
			redirectPitStop(articleTitles[currentTitle], 
					document.getElementById("dyk-stats-" + (currentTitle)), currentTitle);
		} else {
			var processing = document.getElementById("dyk-processing");
			processing.parentNode.removeChild(processing);
		}
	}
}

function getBody() { 
	// gets the HTML body of the page
	// taken from the prosesize tool (http://en.wikipedia.org/wiki/User:Dr_pda/prosesize.js)
	var contentName;
	if (skin == 'monobook' || skin == 'chick' || skin == 'myskin' || skin == 'simple') {
		contentName = 'bodyContent';
	} else if (skin == 'modern') {
		contentName = 'mw_contentholder';
	} else if (skin == 'standard' || skin == 'cologneblue' || skin == 'nostalgia') {
		contentName = 'article';
	} else {
		// fallback case; the above covers all currently existing skins
		contentName = 'bodyContent';
	}
	// Same for all skins if previewing page
	if (wgAction == 'submit') contentName = 'wikiPreview';
	return document.getElementById(contentName);
}

function createHeaderAndProcessing(output) { 
	// makes the header above the scan results
	var header = document.createElement("span");
	header.id = "dyk-header";
	header.innerHTML = '<b><br/>DYK eligibility scan results: <small><i>(See <a href="http://en.wikipedia.org/wiki/' + 
			'User:Shubinator/DYKcheck">here</a> for details.)<i></small></b>';
	output.parentNode.insertBefore(header,output);
	var processing = document.createElement("span");
	processing.id = "dyk-processing";
	processing.innerHTML = '<br /><b><font color="crimson"> Processing... </font></b>';
	output.parentNode.insertBefore(processing, header);
}

function toNormalDate(utc) { 
	// converts the date part of a Wikipedia timestamp to a readable date
	var months=new Array("blank","January","February", "March", "April", "May", "June", 
			"July", "August", "September", "October", "November", "December");
	if (dateFormat == "british") {
		return (utc.substring(8,10) * 1) + ' ' + months[utc.substring(5,7) * 1] + ' ' + utc.substring(0,4);
	} else {
		return months[utc.substring(5,7) * 1] + ' ' + (utc.substring(8,10) * 1) + ', ' + utc.substring(0,4);
	}
}

function toDateObject(timestamp) { 
	// converts a Wikipedia timestamp to a Javascript Date object
	var date = new Date();
	date.setUTCFullYear(timestamp.substring(0,4), timestamp.substring(5,7) - 1, timestamp.substring(8,10));
	date.setUTCHours(timestamp.substring(11,13), timestamp.substring(14,16), timestamp.substring(17,19));
	return date;
}

function fixSidebar() { // part of the code to fix the sidebar; the rest is below the addOnloadHook function
	var content = document.getElementById("column-content");    // Find the main content column

	var footer = document.getElementById("footer");  // Find the footer
	footer.parentNode.removeChild(footer);    // Remove the footer from the global wrapper
	content.appendChild(footer);    // Place footer at the end of the content column;

	var tabs = document.getElementById("p-cactions");   // Find the top tab list
	tabs.parentNode.removeChild(tabs);    // Remove the tab list from the side column
	content.insertBefore(tabs,content.firstChild);    // Place tab list at the beginning of the content column

	var personal = document.getElementById("p-personal");   // Find the personal links list
	personal.parentNode.removeChild(personal);    // Remove the personal links list from the side column
	content.insertBefore(personal,content.firstChild);    // Place personal links list at the beginning of the content column
}

function dykCheck() { 
	// this function for casual use and anons
	if (((wgAction == 'view' || wgAction == 'submit' || wgAction == 'purge') && 
			(wgNamespaceNumber == 0 || wgNamespaceNumber == 2)) || unlock) {
		checkDocument();
	} else if (wgPageName == 'Template_talk:Did_you_know') {
		checkTTDYK();
	}
}

addOnloadHook(function () {
	if (((wgAction == 'view' || wgAction == 'submit' || wgAction == 'purge') && 
			(wgNamespaceNumber == 0 || wgNamespaceNumber == 2)) || unlock) {
		addPortletLink('p-tb', 'javascript:checkDocument()', 'DYK check', 
				't-dyk-check', 'Check if this article qualifies for DYK', '', '');
	} else if (wgPageName == 'Template_talk:Did_you_know') {
		addPortletLink('p-tb', 'javascript:checkTTDYK()', 'DYK check', 
				't-dyk-check', 'Check DYK nominations for eligibility', '', '');
	}
	if (wgUserName != null && (fixedSidebar == "always" || (fixedSidebar == "onttydk" 
			&& wgPageName == 'Template_talk:Did_you_know'))) {
		fixSidebar();
	}
});

// The code below for the fixed sidebar is a blend of two sources:
//		http://meta.wikimedia.org/wiki/Help:User_style/floating_quickbar 
// 		http://en.wikipedia.org/wiki/User:Omegatron/monobook.js/floatingSidebar.js
// None of the code below was written by me (Shubinator)

// This CSS should be hidden from older versions of IE using javascript instead of the attribute selector?

// Include style sheet inline so that script is self-contained:
if (wgUserName != null && (fixedSidebar == "always" || (fixedSidebar == "onttydk" 
		&& wgPageName == 'Template_talk:Did_you_know'))) {
document.write('<style type="text/css">' +
 
"   /* Fix the sidebar's position while you scroll */                           "+
'   div[id=column-one] {   /* Using the attribute selector hides this from IE */'+
'       position: fixed;                                                        '+
'       height: 100%;       /* If you shrink the browser too small, the     */  '+
'       overflow: auto;     /* side column will become scrollable, so stuff */  '+
'       z-index: 2;         /* is always accessible, albeit ugly            */  '+
'   }                                                                           '+
'                                                                               '+
'   #p-logo {               /* Make logo inline with other divs             */  '+
'       position:static;                                                        '+
'   }                                                                           '+
'                                                                               '+
'   #column-one {           /* Sidebar column start at the top screen edge  */  '+
'       padding-top: 0;                                                         '+
'   }                                                                           '+
'                                                                               '+
'   #p-lang .pBody ul{      /* Sets the language box to a fixed height and  */  '+
'       height: 6em;        /* scrollable if too long to fit on screen      */  '+
'       overflow: auto;                                                         '+
'   }                                                                           '+
'                                                                               '+
'   /* Fix the background image, too, so it looks nice as you scroll */         '+
'   body {                                                                      '+
'       background-attachment: fixed;                                           '+
'   }                                                                           '+
'                                                                               '+
"   /* Fix the footer so it looks nice and doesn't overlap the sidebar */       "+
'   #footer {                                                                   '+
'       margin-left: 13.6em;                                                    '+
'       border-left: solid 1px rgb(250, 189, 35);                               '+
'       -moz-border-radius-topleft: 1em;                                        '+
'       -moz-border-radius-bottomleft: 1em;                                     '+
'   }                                                                           '+
'                                                                               '+
'	/* Keep personal links at the top right */				'+
'	#p-personal {								'+
'		width:100%;							'+
'		white-space:nowrap;						'+
'		padding:0 0 0 0;						'+
'		margin:0;							'+
'		position:absolute;						'+
'		left:0px;							'+
'		top:0px;							'+
'		z-index: 0;							'+
'		border: none;							'+
'		background: none;						'+
'		overflow: visible;						'+
'		line-height: 1.2em;						'+
'	}									'+
'										'+
'	#p-personal h5 {							'+
'		display:none;							'+
'	}									'+
'	#p-personal .portlet,							'+
'	#p-personal .pBody {							'+
'		padding:0;							'+
'		margin:0;							'+
'		border: none;							'+
'		z-index:0;							'+
'		overflow: visible;						'+
'		background: none;						'+
'	}									'+
'	/* this is the ul contained in the portlet */				'+
'	#p-personal ul {							'+
'		border: none;							'+
'		line-height: 1.4em;						'+
'		color: #2f6fab;							'+
'		padding: 0em 2em 0 3em;						'+
'		margin: 0;							'+
'		text-align: right;						'+
'		text-transform: lowercase;					'+
'		list-style: none;						'+
'		z-index:0;							'+
'		background: none;						'+
'	}									'+
'	#p-personal li {							'+
'		z-index:0;							'+
'		border:none;							'+
'		padding:0;							'+
'		display: inline;						'+
'		color: #2f6fab;							'+
'		margin-left: 1em;						'+
'		line-height: 1.2em;						'+
'		background: none;						'+
'	}									'+
'	#p-personal li a {							'+
'		text-decoration: none;						'+
'		color: #005896;							'+
'		padding-bottom: 0.2em;						'+
'		background: none;						'+
'	}									'+
'	#p-personal li a:hover {						'+
'		background-color: White;					'+
'		padding-bottom: 0.2em;						'+
'		text-decoration: none;						'+
'	}									'+
'										'+
'<'+'/style>');
}