User:EpochFail/No Biting Test.js

/** * The NICE interface modification for (monobook) Wikipedia * * This file contains the entire javascript used to produce the No Biting * interface modification. */

NICE = new Object ACCOUNT_NAME = "User:EpochFail"

/** * Query String * * Maps the querystring to an object */ NICE.mapQueryString = function(qString) { var string = qString var params = {} if( qString.length == 0 ) { return params }	qString.replace(/\+/, ' ') var args = qString.split('&') for( var i = 0; i < args.length; ++i ) { var pair = args[i].split( '=' ) var key = decodeURIComponent( pair[0] ), value = key if( pair.length == 2 ) { value = decodeURIComponent( pair[1] ) }		params[key] = value }	return params }

var params = NICE.mapQueryString(location.search.substring(1, location.search.length)) if(params.undo){ NICE.warn = true NICE.box = true NICE.updateTimeout = 1000 NICE.noobLimit = 100 NICE.requestTimeout = 10000 NICE.reverted = new Object NICE.reverted.anon        = null NICE.reverted.revisionId  = params.undo NICE.reverted.username    = null NICE.reverted.userRevs    = null NICE.reverted.timestamp   = null /**	 * Trim *	 * Cuts whitespace from both sides of a string. */	String.prototype.trim = function { return this.replace(/^\s+|\s+$/g,"") }	/**	 * Import CSS *	 * Adds a link to a new CSS file to the header of the document. */	function importCSS(page) { var url = mw.config.get('wgScript') + '?title=' + encodeURIComponent(page.replace(/ /g,'_')).replace('%2F','/').replace('%3A',':') + '&action=raw&ctype=text/css' var cssLink = document.createElement("link") cssLink.rel = "stylesheet" cssLink.type = "text/css" cssLink.href = url document.getElementsByTagName("head")[0].appendChild(cssLink) return cssLink }	/**	 * Save and Post Message *	 * This is an event handler called when the user wants to save their revert. */	NICE.saveAndPostMessage = function(e){ if(NICE.saveForm.messageBoxDisplayed && document.getElementById("niceExplaination").value.trim.length > 0){ NICE.postMessageOnUserTalk(				NICE.reverted.username,				document.getElementById("niceHeader").value,				document.getElementById("niceExplaination").value			) //Don't do anything ever. e.stopPropagation e.preventDefault e.returnValue = false }else{ NICE.logger.revert(				NICE.warn, 				NICE.box, 				NICE.reverted.username, 				NICE.reverted.userRevs, 				wgUserName, 				NICE.reverted.revisionId,				null,				null			) }	}	/**	 * Create Save Form When Ready *	 * A simple timeout function that creates the SaveForm object as soon as the * interface is ready. */	NICE.createSaveFormWhenReady = function{ if(document.getElementById("editform")){ NICE.saveForm = new NICE.SaveForm(document.getElementsByClassName("editOptions")[0]) NICE.updateSaveFormWhenReady }			else{ setTimeout('NICE.createSaveFormWhenReady', NICE.updateTimeout) }	}	/**	 * Update Save Form When Ready *	 * A simple timeout function that updates the SaveForm with information as soon * as it is ready to be updated. */	NICE.updateSaveFormWhenReady = function{ if(			NICE.reverted.username != null && 			NICE.reverted.revisionId != null && 			NICE.reverted.userRevs != null		) {			NICE.logger.undo(				NICE.box, 				NICE.warn, 				NICE.reverted.username, 				NICE.reverted.userRevs, 				wgUserName, 				NICE.reverted.revisionId			) //Don't do anything is the user being reverted is not yet registered. if(!NICE.reverted.anon){ if(NICE.warn && NICE.reverted.userRevs <= NICE.noobLimit){ NICE.saveForm.showWarning }				if(NICE.box){ NICE.saveForm.initMessageBox(NICE.reverted.revisionId, NICE.reverted.username) NICE.saveForm.showMessageBox }			}		}		else{ setTimeout('NICE.updateSaveFormWhenReady', NICE.updateTimeout) }	}	/**	 * Show Error When Ready *	 * A simple timeout function that waits to shows an error as soon as the * interface is ready. *	 */	NICE.showErrorWhenReady = function(message){ if(NICE.saveForm){ NICE.saveForm.showError(message) }		else{ setTimeout('NICE.showErrorWhenReady("' + message + '")', NICE.updateTimeout) }	}	/**	 * Wikipedia API Handler *	 * A simple object for interacting with Wikipedia's API. */	NICE.WPAPIHandler = function{ }	NICE.WPAPIHandler.requests = new Array; NICE.WPAPIHandler.timeoutSeconds = NICE.requestTimeout; NICE.WPAPIHandler.url = "http://en.wikipedia.org/w/api.php"; /**		 * Timeout *		 * Stops a long running request and calls its error message */		NICE.WPAPIHandler.timeout = function(requestId){ var request = this.requests[requestId]; if(request){ request.errorFun("Request to Wikipedia database timed out."); }			try{ request.abort; }catch(e){ //then don't abort I guess }		}		/**		 * Perform Request *		 * Uses a callback function to perform a request to the WP api. */		NICE.WPAPIHandler.performGET = function(params, successFun, args, errorFun){ this.performRequest(params, successFun, args, errorFun, "GET") }		/**		 * Perform Request *		 * Uses a callback function to perform a request to the WP api. */		NICE.WPAPIHandler.performPOST = function(params, successFun, args, errorFun){ this.performRequest(params, successFun, args, errorFun, "POST") }		NICE.WPAPIHandler.performRequest = function(params, successFun, args, errorFun, type){ var paramString = "foo=foo" for(key in params){ paramString += "&" + key + "=" + this.escape(params[key]) }			var request = this.createRequest; if(!request){ errorFun("Your browser does not support the ability to make requests to the Wikipedia database."); return; }			if(type=="POST"){ request.open("POST", this.url, true); request.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); request.setRequestHeader("Content-length", paramString.length); }			else{ request.open("GET", this.url+"?"+paramString, true); }			request.setRequestHeader("Pragma", "cache=yes"); request.setRequestHeader("Cache-Control", "no-transform"); request.setRequestHeader("Connection", "close"); request.successFun = successFun request.errorFun = errorFun request.args = args request.onreadystatechange = function { if (this.readyState != 4) return; if (this.status != 200){ this.errorFun("The Wikipedia server responded with an error: " + this.status + " " + this.statusText + ": " + this.responseText); return; }				clearTimeout(this.timeoutRef); this.successFun(this.responseText, this.args); return; }			var currentRequestId = this.requests.length this.requests[currentRequestId] = request request.timeoutRef = setTimeout("NICE.WPAPIHandler.timeout(" + currentRequestId + ")", this.timeoutSeconds) if(type=="POST"){ request.send(paramString) }			else{ request.send(null) }		}		/**		 * Create Request *		 * Generates an appropriate XMLHttpRequest object for the browser being * used or raises an exception. */		NICE.WPAPIHandler.createRequest = function { var requestObject; try { requestObject = new XMLHttpRequest; } catch (e) { try { requestObject=new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { requestObject=new ActiveXObject("Microsoft.XMLHTTP"); } catch (oc) { requestObject=null; }				}			}			return requestObject; }		/**		 * Escape *		 * Performs a normal URL escape, but also escapes the "+" symbol. This is * essential for generating edit tokens. */		NICE.WPAPIHandler.escape = function(string){ return escape(string).replace(/\+/, "%2B") }	/**	 * Save Form * 	 * This object represents a DOM widget in the HTML document *	 */	NICE.SaveForm = function(editOptions){ this.messageBoxDisplayed = false this.editOptions = editOptions this.errorMessage = document.createElement("div") var errorHeader = document.createElement("h2") errorHeader.innerHTML = "The NO BITING interface failed to load." this.errorBody = document.createElement("div") this.errorMessage.appendChild(errorHeader) this.errorMessage.appendChild(this.errorBody) this.errorMessage.id = "errorMessage" this.warnDiv = document.createElement("div") this.warnDiv.id = "warning" this.warnDiv.innerHTML = '' + ' \n' + '	 Note: You are reverting a new editor. Don&apos;t bite.\n' + ' \n' + ' \n' + '	Analysis suggests that reverting this editor is likely to \n' + '	discourage them from making future contributions.\n' + ' \n'; this.saveOptions = document.createElement("div"); this.saveOptions.id = "saveOptions"; this.normalSelector = document.createElement("a"); this.normalSelector.innerHTML = "Normal"; this.normalSelector.id = "normalSelector"; this.normalSelector.className="selected"; this.normalSelector.onclick = function(a){ NICE.saveForm.hideMessageBox }		this.saveOptions.appendChild(this.normalSelector); this.niceSelector = document.createElement("a"); this.niceSelector.innerHTML = "Be Very Nice"; this.niceSelector.id = "niceSelector"; this.niceSelector.className=""; this.niceSelector.onclick = function(a){ NICE.saveForm.showMessageBox }		this.saveOptions.appendChild(this.niceSelector); this.oldForm = document.createElement("div"); this.oldForm.id="oldForm"; this.messageForm = document.createElement("div"); this.messageForm.id = "messageForm"; this.messageForm.style.display="none"; this.messageForm.style.width="48%"; this.formMessage = document.createElement("p"); this.formMessage.style.display="none"; this.finalBreak = document.createElement("br"); this.finalBreak.style.clear="both"; }		/**		 * Show Error *		 * Will show an error to the user in the DOM. If there is already an * error displayed, this error will over-write it. */		NICE.SaveForm.prototype.showError = function(message){ this.errorBody.innerHTML = message; if(!this.errorMessage.parent){ //Load style importCSS(ACCOUNT_NAME + '/error_message.css') if(this.saveOptions.parentNode){ this.editOptions.parentNode.insertBefore(this.errorMessage, this.saveOptions) }				else{ this.editOptions.parentNode.insertBefore(this.errorMessage, this.editOptions) }			}		}		/**		 * Show Warning *		 * Calling this method displayes the new user warning to the user. */		NICE.SaveForm.prototype.showWarning = function{ //Load style importCSS(ACCOUNT_NAME + '/warn.css'); this.copyWarn = document.getElementById("editpage-copywarn") this.copyWarn.style.display = "none"; if(this.errorMessage.parentNode){ this.editOptions.parentNode.insertBefore(this.warnDiv, this.errorMessage); }			else if(this.saveOptions.parentNode){ this.editOptions.parentNode.insertBefore(this.warnDiv, this.saveOptions); }			else{ this.editOptions.parentNode.insertBefore(this.warnDiv, this.editOptions); }		}		/**		 * Init Message Box *		 * This method modifies the save form for saving changes to a revert * to include the form elements for adding information to a talk page. */		NICE.SaveForm.prototype.initMessageBox = function(revertedId, revertedUser){ //Load style importCSS(ACCOUNT_NAME + '/message_box.css'); this.editOptions.parentNode.insertBefore(this.saveOptions, this.editOptions); this.editOptions.appendChild(this.oldForm); this.oldForm.innerHTML = this.editOptions.innerHTML; this.editOptions.innerHTML = ""; this.formMessage.innerHTML= '' + 'The form below will allow you to both save your changes to ' + '' + mw.config.get('wgPageName') + ' and post a breif message to ' + '' + revertedUser + '&apos;s talk page explaining the revert. ' + 				'This is your opportunity to help a new user learn the ropes.' this.editOptions.appendChild(this.formMessage); this.messageForm.innerHTML = '' + ' ' + 			'	' + '		 ' + 			'			Message header' + '			 (This will be posted on ' + revertedUser + '&apos;s talk page) ' + '		 ' + 			'	 ' + 			' ' + 			' ' + 			'' + ' ' + 			' ' + 			'	' + '		 ' + 			'			Explaination' + '			 (Consider explaining the appropriate Wikipedia Policy) ' + '		 ' + 			'	 ' + 			' ' + 			' '; this.editOptions.appendChild(this.messageForm); this.editOptions.appendChild(this.oldForm); this.editOptions.appendChild(this.finalBreak); document.getElementById('editform').addEventListener("submit", NICE.saveAndPostMessage, false); }		/**		 * Show Message Box *		 * Displays the message box form to the user. */		NICE.SaveForm.prototype.showMessageBox = function{ if(this.messageBoxDisplayed){ return true }			this.normalSelector.className=""; this.niceSelector.className="selected"; this.oldForm.style.width="48%"; this.messageForm.style.display="block"; this.formMessage.style.display="block"; this.messageBoxDisplayed = true; }		/**		 * Hide Message Box *		 * Hides the message box form from the user. */		NICE.SaveForm.prototype.hideMessageBox = function{ if(!this.messageBoxDisplayed){ return true; }			this.normalSelector.className     = "selected"; this.niceSelector.className       = ""; this.oldForm.style.width      = "96%"; this.messageForm.style.display = "none"; this.formMessage.style.display = "none"; this.messageBoxDisplayed = false; }	/**	 * Logger * 	 * This object is intended to be used as a simple interface for logging that * uses a the insertion of a Javascript tag to the header of the document in * order to make arbitrary GET requests to any server. */	NICE.Logger = function(url){ this.url = url; }		/**		 * Revert *		 * Logs the event that an editor successfully reverted a revision. */		NICE.Logger.prototype.revert = function(warn, box, revertedUser, revertedUserRevs, revertingUser, revisionReverted, newTalkRevision, prevTalkRevision){ this.log(				{					"action":            "revert",					"timestamp":          NICE.reverted.timestamp,					"warn":               warn,					"box":                box,					"user_reverted":      revertedUser.substring(0,200),					"user_reverted_revs": revertedUserRevs,					"user_reverting":     revertingUser.substring(0,200),					"revision_reverted":  revisionReverted,					"new_talk_revision":  newTalkRevision,					"prev_talk_revision": prevTalkRevision				}			) }		/**		 * Undo *		 * Logs the event that an editor successfully loaded the undo page. */		NICE.Logger.prototype.undo = function(warn, box, userToBeReverted, userRevs, userReverting, revisionToBeReverted){ this.log(				{					"action":                  "undo",					"warn":                     warn,					"box":                      box,					"user_to_be_reverted":      userToBeReverted.substring(0,200),					"user_to_be_reverted_revs": userRevs,					"user_reverting":           userReverting.substring(0,200),					"revision_to_be_reverted":  revisionToBeReverted				}			) }		/**		 * Error *		 * Logs errors that a user encounters while interacting with the interface. */		NICE.Logger.prototype.error = function(revertingUser, revisionToBeReverted, operation, message){ this.log(				{					"action":                  "error",					"timestamp":                NICE.reverted.timestamp,					"user_reverting":           revertingUser.substring(0,200),					"revision_to_be_reverted":  revisionToBeReverted,					"operation":                operation,					"message":                  message.substring(0,200)				}			) }		/**		 * Log *		 * A function which formats an object into GET parameters and adds a * script tag to the head of the document. */		NICE.Logger.prototype.log = function(obj){ if(obj.action){ var queryString = "?logging=logging" for(key in obj){ queryString += "&" + key + "=" + this.escape(obj[key]) }				//alert("logging: " + queryString); this.sendRequest(queryString); }		}		/**		 * Send Request *		 * Sends a get request to the provided url the query string by adding a * script tag to the head of a document. */		NICE.Logger.prototype.sendRequest = function(queryString){ var tag = document.createElement("script") tag.setAttribute("src", this.url + queryString) tag.setAttribute('type','text/javascript') document.getElementsByTagName('head')[0].appendChild(tag) }		/**		 * Escape *		 * Properly escapes URL parameters by changing javascript's "null" to a * more useful "/n" sequence. */		NICE.Logger.prototype.escape = function(thing){ if(thing == null){ return escape("/n") }			else{ return escape(thing) }		}	NICE.logger = new NICE.Logger("http://www-users.cs.umn.edu/~halfak/wpInterfaceLogger.php") /**	 * Post Message On User Talk *	 * Retrieves an edittoken for the user's talk page and starets the sequence of * calls to add a message to the page. */	NICE.postMessageOnUserTalk = function(username, header, message){ var params = { "action": "query", "prop": "info", "intoken": "edit", "titles": 'User_talk:' + username, "format": "json" }		var args = { "username": username, "header": header, "message": ' This message was added using the NICE gadget. ' + message }		/* This function will be called in window scope */ var finishPostingAndLogging = function(result, args){ try{ var res = eval("(" + result + ")") }			catch(e){ NICE.logger.error(mw.config.get('wgUserName'), NICE.reverted.revisionId, "Searching for edit token for user talk page", "Unable to process JSON result: " + result) if(confirm('Unable to post to ' + NICE.reverted.username + '\'s talk page. Continue with revert?')){ document.getElementById("editform").submit }				return }			try{ for(thing in res.query.pages){ var page = res.query.pages[thing] }				var editToken = page.edittoken }			catch(e){ NICE.logger.error(mw.config.get('wgUserName'), NICE.reverted.revisionId, "Looking for edit token in result", "Invalid result structure: " + result) if(confirm('Unable to post to ' + NICE.reverted.username + '\'s talk page. Continue with revert?')){ document.getElementById("editform").submit }				return }			var params = { "action": 'edit', "title":  'User_talk:' + args.username, "section": 'new', "summary": args.header, "text":   args.message, "token":  editToken, "format": 'json', }			NICE.WPAPIHandler.performPOST(				params, 				function(result, args){					try{						var res = eval("(" + result + ")")					}catch(e){						NICE.logger.error(mw.config.get('wgUserName'), NICE.reverted.revisionId, "Posting to user's talk page", "Unable to process JSON result: " + result)						if(confirm('Unable to post to ' + NICE.reverted.username + '\'s talk page. Continue with revert?')){							NICE.logger.revert( NICE.warn, NICE.box, NICE.reverted.username, NICE.reverted.userRevs, wgUserName, NICE.reverted.revisionId, null, null )							document.getElementById("editform").submit						}						return					}					try{						var newRevId = null						var oldRevId = null						newRevId = res.edit.newrevid,						oldRevId = res.edit.oldrevid					}catch(e){						NICE.logger.error(mw.config.get('wgUserName'), NICE.reverted.revisionId, "Logging a successful revert", "Invalid result structure: " + result)						//do not return here. If we don't have the newRevId and oldRevId, we can still log the revert.					}					NICE.logger.revert( NICE.warn, NICE.box, NICE.reverted.username, NICE.reverted.userRevs, wgUserName, NICE.reverted.revisionId, newRevId, oldRevId )					document.getElementById("editform").submit				}, 				{},				function(message){					NICE.logger.error(mw.config.get('wgUserName'), NICE.reverted.revisionId, "Posting on user's talk page", message)					if(confirm('Unable to post to ' + NICE.reverted.username + '\'s talk page. Continue with revert?')){						document.getElementById("editform").submit					}				}			) }		NICE.WPAPIHandler.performGET(			params, 			finishPostingAndLogging, 			args, 			function(message){				NICE.logger.error(mw.config.get('wgUserName'), NICE.reverted.revisionId, "Asking for edit token", message)				if(confirm('Unable to post to ' + NICE.reverted.username + '\'s talk page. Continue with revert?')){					document.getElementById("editform").submit				}			}		) }	NICE.loadRevertedUserInformation = function(revisionId){ //Start AJAX call sequence var params = { "action": 'query', "prop": 'revisions', "revids": revisionId, "rvprop": 'user', "format": 'json' }		NICE.WPAPIHandler.performGET(			params, 			function(result, args){				try{					var res = eval("(" + result + ")")				}				catch(e){					NICE.logger.error(mw.config.get('wgUserName'), NICE.reverted.revisionId, "Searching for username using revisionId", "Unable to process JSON result" + result)					showErrorWhenReady("The Wikipedia server returned an invalid result while asking for user information.")					return				}				try{					for(thing in res.query.pages){						var page = res.query.pages[thing]					}					NICE.reverted.username = page.revisions[0].user					if(page.revisions[0].anon){						NICE.reverted.anon = true					}					else{						NICE.reverted.anon = false					}				}				catch(e){					NICE.reverted.username = ""					NICE.logger.error(mw.config.get('wgUserName'), NICE.reverted.revisionId, "Looking for username in result", "Invalid result structure: " + result)					showErrorWhenReady("The Wikipedia server returned an invalid result while asking for user information.") return }				if(NICE.reverted.anon){ //do nothing NICE.reverted.userRevs = 0 return }				var params = { "action": 'query', "list": 'users', "ususers": NICE.reverted.username, "usprop": 'editcount', "format": 'json' }				NICE.WPAPIHandler.performGET(					params, 					function(result, args){						try{							var res = eval("(" + result + ")")						}						catch(e){							NICE.logger.error(mw.config.get('wgUserName'), NICE.reverted.revisionId, "Searching for editcount using username", "Unable to process JSON result: " + result)							showErrorWhenReady("The Wikipedia server returned an invalid result while asking for user information.")							return						}						try{							NICE.reverted.userRevs = res.query.users[0].editcount						}						catch(e){							NICE.logger.error(mw.config.get('wgUserName'), NICE.reverted.revisionId, "Looking for editcount in result", "Invalid result structure: " + result)							showErrorWhenReady("The Wikipedia server returned an invalid result while asking for user information.")							return						}					}, 					{},					function(message){						NICE.logger.error(mw.config.get('wgUserName'), NICE.reverted.revisionId, "Requesting edit count of user", message) showErrorWhenReady(message) }				)			}, 			{}, 			function(message){				NICE.logger.error(mw.config.get('wgUserName'), NICE.reverted.revisionId, "Searching for username using revisionId", message)				showErrorWhenReady(message)			}		) }

/* Start getting work done */ NICE.loadRevertedUserInformation(NICE.reverted.revisionId) //Start ready catcher NICE.createSaveFormWhenReady }