User:Falcon Kirtaran/Scripts/iglooDevMain.js

/* ======================================================== *\ \* ======================================================== */ /* fixes: - fixed a bug that caused the history display to fail when the page title had an apostophe in it. - fixed a bug where the edit summary for warned users was not correct. - fixed a bug where server didn't recognise users with certain symbols in their name
 * igloo frontend manager - main

function iglooMain { this.internalCounter 	= 0; this.iglooBase			= new wa_document ; this.launch = function ( details ) { switch ( this.internalCounter ) { default: case 0: this.startload = new Date ; // step 1 of launching: build the loading interface. var t = 'igloo - ' + iglooSettings.versionString; var t2 = ''; for ( var i = 0; i < wgUserGroups.length; i ++ ) { if ( wgUserGroups[i] == 'sysop' ) { t2 += 'administrator|'; iglooSettings.mesysop = true; } else if ( wgUserGroups[i] == 'rollbacker' ) { t2 += 'rollback|'; } }					if ( t2 !== '' ) t += ' [' + t2.substr ( 0, t2.length - 1 ) + ']'; document.title = t;					this.iglooBase.wk_base.innerHTML= ''; // just destroy the mediawiki page content this.iglooInterface 			= new wa_window( this.iglooBase.wk_base ); this.iglooInterface.win_bg 		= '#ededff'; this.iglooInterface.win_maintfill	= false; this.iglooInterface.win_fill	= true; this.iglooInterface.applyAll ; // step 2 of launching: add text. this.iglooLoading			= new wa_window( this.iglooBase.wk_base ); this.iglooLoading.win_width = 210; this.iglooLoading.win_height= 17; this.iglooLoading.win_bd 	= '#bbbbff'; this.iglooLoading.win_bd_wd = 1; this.iglooLoading.win_bg 	= '#fdfdff'; this.iglooLoading.win_content = ' Finalising load. Please wait... ';					this.iglooLoading.applyAll ; this.iglooLoading.center('both', true, new Array(0, -100)); // step 3 of launching: verify session. this.iglooSession = new iglooSecurity ; if (typeof this.iglooSession.shutdown != 'undefined') return false; this.iglooSession.verifySession( 'initial' ); // increment counter this.internalCounter ++; break; case 1: // step 4 of launching: the session is verified, tell the user. this.iglooLoading.win_width = 330; this.iglooLoading.win_content = ' Verified session. Requesting from iglooNet... ';					this.iglooLoading.applyAll ; this.iglooLoading.center ( 'both', true, new Array ( 0, -100 ) ); // increment counter this.internalCounter ++; // run this.iglooNet = new iglooNet ; this.iglooNet.retrieve ( true ); break; case 2: // step 5 of lauching: load the user settings this.iglooLoading.win_width = 180; this.iglooLoading.win_content = ' Loading user settings... ';					this.iglooLoading.applyAll; this.iglooLoading.center ('both', true, new Array ( 0, -100 ) ); // increment counter this.internalCounter ++; // run this.iglooManageSettings = new iglooManageSettings ; this.iglooManageSettings.retrieve ; break; case 3: // display first run if relevant // increment counter this.internalCounter ++; if ( iglooSettings.firstRun == true ) { var url = iglooSettings.remoteHost + 'main.php?action=settings&do=set&session='+igloo.iglooSession.session+'&me='+encodeURIComponent(wgUserName)+'&setting=firstRun&value=false'; iglooImport( url, true, 'iglooFirstRun' ); wa ( ':api' ).get ( 'ig_firstrun', iglooSettings.localBase + 'config', 1 ).wait ( function { 							var firstruntext = 	wa ( ':api' ).results ['ig_firstrun']['query']['pages']['page']['revisions']['rev']['#text'], regTest = /firstrun:(.+?);;/i, o;							firstruntext = regTest.exec ( firstruntext );							firstruntext = firstruntext[1].replace ( '%CURRENTUSER%', wgUserName );							igloo.iglooLoading.win_width = 900;								igloo.iglooLoading.win_height = 400;								igloo.iglooLoading.win_content = firstruntext;								igloo.iglooLoading.applyAll ;							igloo.iglooLoading.center ( 'both', true );						 } ).run ; } else { this.launch ; } break; case 4: // finalising launch: the session is verified, tell the user. this.iglooLoading.win_width = 210; this.iglooLoading.win_height= 17; this.iglooLoading.win_content = ' Success. Building interface... ';					this.iglooLoading.applyAll ; this.iglooLoading.center ( 'both', true, new Array ( 0, -100 ) ); // increment counter this.internalCounter ++; // run setTimeout( "igloo.launch ;", 1000 ); break; case 5: this.endload = new Date ; // start the required program elements. this.iglooDiff = new iglooDiff ; this.iglooDiff.start ; this.iglooStatus = new iglooStatus ; this.iglooStatus.start ; this.iglooControls = new iglooControls ; this.iglooControls.start ; this.iglooChanges = new iglooChanges ; this.iglooChanges.start ; this.iglooActions = new iglooActions ; this.iglooManageSettings.initdisplay ; // hide the loading element this.iglooLoading.hide ; break; }		}		this.shutdown = function ( reason, retry ) { if (reason == null) { reason = ''; } else { reason = ' '+reason; } if (retry == 'retry') { reason += ' retry | help '; } if (retry == 'tryagain') { reason += ' new session '; } if ( typeof this.iglooChanges != 'undefined' ) 	this.iglooChanges.destroy ; if ( typeof this.iglooDiff != 'undefined' ) 	this.iglooDiff.destroy ; if ( typeof this.iglooControls != 'undefined' ) this.iglooControls.destroy ; if ( typeof this.iglooStatus != 'undefined' ) 	this.iglooStatus.destroy ; if ( typeof this.iglooSession != 'undefined' ) 	clearTimeout ( this.iglooSession.verificationTimer ); if ( typeof this.iglooNet != 'undefined' ) 		clearTimeout ( this.iglooNet.retrievalTimer ); this.iglooLoading.show ; this.iglooLoading.win_height = 0; this.iglooLoading.win_width = 350; this.iglooLoading.win_content = ' igloo has closed'+reason+' '; this.iglooLoading.applyAll ; this.iglooLoading.center ( 'both' ); return true; }	}	function iglooSecurity { this.userActivity = true; if ( (window.location.href.indexOf('&sessionkey=') == -1) || (window.location.href.indexOf('::::') == -1) ) { igloo.shutdown('invalid session provided', 'tryagain'); this.shutdown = true; return false; } this.session = window.location.href.substr(window.location.href.indexOf('&sessionkey=') + 12); this.session = this.session.substr(0, this.session.length - 4); this.verifySession = function ( type ) { this.internalCounter = 0; if ( this.userActivity == true ) { var alive = '&keep-alive=true'; } else { var alive = '&keep-alive=false'; } this.userActivity = false; iglooImport( iglooSettings.remoteHost + 'main.php?action=verify&user=' + encodeURIComponent ( wgUserName ) + '&verify=' + this.session + alive, true, 'iglooVerify' ); this.checkVerification ( type ); }		this.checkVerification = function ( type ) { if ( typeof iglooSessionVerified != 'undefined' ) if ( iglooSessionVerified != 'unknown' ) if ( iglooSessionVerified == 'ok' ) { iglooSessionVerified = 'unknown'; this.verificationTimer = setTimeout("igloo.iglooSession.verifySession;", 45 * 1000); if (type == 'initial') { igloo.launch; }				return true; } else { igloo.shutdown('session invalid or expired', 'tryagain'); return false; }			if ( this.internalCounter >= iglooSettings.serverTimeout ) { igloo.shutdown( 'verification failed - lost connection to iglooNet', 'retry' ); return false; } else { this.internalCounter ++; setTimeout("igloo.iglooSession.checkVerification('"+type+"');", 1000); }		}	}	function iglooManageSettings { // the iglooManageSettings module retrieves settings from the igloo server, and replaces the defaults where applicable. this.retrieve = function { this.internalCounter = 0; iglooImport ( iglooSettings.remoteHost + 'main.php?action=settings&me=' + encodeURIComponent(wgUserName) + '&do=get&session=' + igloo.iglooSession.session, true, 'iglooNetSettings' ); this.retrieveMain ; }		this.retrieveMain = function { thisSetting = false; if ( typeof iglooNetSettingsDone != 'undefined' ) if ( iglooNetSettingsDone != 'unknown' ) if ( iglooNetSettingsDone == 'ok' ) { // success this.overwritelocal ; // continue launch igloo.launch ; return true; } else { igloo.shutdown( 'session invalid or expired', 'tryagain' ); return false; }			if ( this.internalCounter >= ( iglooSettings.serverTimeout * 4 ) ) { igloo.shutdown( 'settings failed - lost connection to iglooNet', 'retry' ); return false; } else { this.internalCounter ++; thisSetting = this; setTimeout( "if ( thisSetting ) { thisSetting.retrieveMain ; }", 500 ); }		}		this.overwritelocal = function { for ( i in iglooNetSettings ) { if ( iglooSettings [i] !== undefined ) { iglooSettings [i] = iglooNetSettings [i]; }			}			return true; }		this.initdisplay = function { this.settingsMenu = new wa_window ; this.settingsMenu.win_alpha = 0.7; this.settingsMenu.win_bg = '#000000'; this.settingsMenu.win_disp = 'none'; this.settingsMenu.win_fill = true; this.settingsMenu.applyAll ; this.settingsMenuContent = new wa_window ; this.settingsMenuContent.win_bg = '#ccccff'; this.settingsMenuContent.win_width = 800; this.settingsMenuContent.win_height = 400; this.settingsMenuContent.win_padding = 0; this.settingsMenuContent.win_alpha = 1; this.settingsMenuContent.win_disp = 'none'; this.settingsMenuContent.win_bd = '2px solid #666688'; this.settingsMenuContent.win_content = '   '; this.settingsMenuContent.applyAll ; this.settingsMenuContent.center ( 'both', true ); // add tabs this.addtab ( 'info', 'user info' ); this.addtab ( 'interface', 'interface' ); this.addtab ( 'actions', 'actions' ); this.addtab ( 'filters', 'filters' ); this.addtab ( 'admin', 'admin' ); this.addtab ( 'close', 'close settings' ); // default tab this.switchtab ( 'info' ); }		this.showdisplay = function { this.settingsMenu.show ; this.settingsMenuContent.show ; return true; }		this.hidedisplay = function { this.settingsMenu.hide ; this.settingsMenuContent.hide ; return true; }		this.addtab = function ( tabid, tabtext ) { if ( ( ! tabid ) || ( ! tabtext ) ) return false; var tabscont = document.getElementById ( 'igloo-settings-tabs' ); tabscont.innerHTML += ' ' + tabtext + ' '; return tabscont; }		this.switchtab = function ( tabid ) { if ( ! tabid ) { throw 'igloo: unexpected settings call, tab is missing'; return false; } var tabcont = document.getElementById ( 'igloo-settings-content' ); switch ( tabid ) { case 'info': tabcont.innerHTML = ''; // blank tabcont.innerHTML = 'Welcome to the igloo settings panel. From here, you can update your igloo settings. igloo currently has the following data regarding your account:'; break; case 'close': this.hidedisplay ; break; default: throw 'igloo: unexpected settings call, tab content undefined'; break; }		}	}	function iglooNet { // the iglooNet module retrieves wiki data from the igloo server to help fight vandalism this.initial = true; this.lastUpdate = 0; this.iglooScores = []; this.iglooCount = 0; this.retrieve = function ( cacheBypass ) { if (typeof igloo.iglooStatus != 'undefined') igloo.iglooStatus.addStatus('Requesting data from iglooNet...'); this.internalCounter = 0; if (cacheBypass == true) { var cache = '&cachebypass=true'; } else { var cache = ''; } iglooImport(iglooSettings.remoteHost + 'main.php?action=retrieve'+cache+'&me=' + encodeURIComponent(wgUserName) + '&session=' + igloo.iglooSession.session, true, 'iglooRetrieve'); this.retrieveMain; }		this.retrieveMain = function { thisUpdate 		= false; if ( typeof iglooScoresDone != 'undefined' ) if ( iglooScoresDone != 'unknown' ) if ( iglooScoresDone == 'ok' ) { iglooScoresDone = 'unknown'; igloo.iglooNet.mergeUpdates ( iglooNetScores ); return true; } else { igloo.shutdown('session invalid or expired', 'tryagain'); return false; }			if (this.internalCounter >= (iglooSettings.serverTimeout * 4)) { igloo.shutdown('retrieval failed - lost connection to iglooNet', 'retry'); return false; } else { this.internalCounter ++; thisUpdate 		= this; setTimeout( "if ( thisUpdate ) { thisUpdate.retrieveMain ; }", 500 ); }		}		this.mergeUpdates = function(newUpdates) { // the merge updates function takes the data that the iglooNet server has just sent and merges it into the central iglooScores array that is used // to list the diffs to the user. var j = 0; for ( var i in newUpdates ) { // newUpdates[i][0] = u [or] p				// newUpdates[i][1] = score [or] flag // i 				= username [or] pagename if ( ! this.iglooScores[i] ) { // if we don't already have data on this item this.iglooScores[i] = []; this.iglooScores[i] = newUpdates[i]; } else { // if we DO already have data on this item, update it					this.iglooScores[i].length = 0; this.iglooScores[i] = []; this.iglooScores[i] = newUpdates[i]; }				j ++; this.iglooCount ++; }			if (this.initial == true) { igloo.launch; this.initial = false; }			this.retrievalTimer = setTimeout("igloo.iglooNet.retrieve;", 30 * 1000); }		this.scoreObject = function(object) { // generally, administrators/crats will be sent as a risk of 0 and rollbackers will be given 0.2. // trusted users, who have made over 250 edits will be assigned a score of 0.4 - mysteriously meaning // vandalism is likely to appear first, but there will always be an 'untrustworthy' edit to check. // by default, other users and IPs will have 0.5 - the server assigns higher scores based on user // actions var score 	= []; score.length= 0; score[0] 	= false; score[1]	= ''; if ( (igloo.iglooNet.iglooScores[object]) && (igloo.iglooNet.iglooScores[object][0] == 'u') ) { score[0] = igloo.iglooNet.iglooScores[object][1]; }			// if we have special data on this page, such as a whitelist of priority warning, append it here. // pages that are whitelisted will be sent with a priority of 0, regardless of the user score // pages that are flagged will gain a score of 0.7 // pages that are blacklisted will gain a score of 0.9 if ( (igloo.iglooNet.iglooScores[object]) && (igloo.iglooNet.iglooScores[object][0] == 'p') ) { switch (iglooScores[object][1]) { case 'w': score[0] = 0; score[1] = 'w'; break; case 'f': score[0] = 0.6; score[1] = 'f'; break; case 'b': score[0] = 0.9; score[1] = 'b'; break; }			}			return score; }		this.colourScore = function(score, defaultCol) { defaultCol = typeof ( defaultCol ) != 'undefined' ? defaultCol : '#777777'; if ( score === false ) return defaultCol; if (iglooSettings.enableFeedColour == false) { var col = defaultCol; } else if (score >= 0.8) { var col = iglooSettings.flagColours[0]; } else if (score >= 0.6) { var col = iglooSettings.flagColours[1]; } else if (score >= 0.4) { var col = iglooSettings.flagColours[2]; } else if (score >= 0.2) { var col = iglooSettings.flagColours[3]; } else if (score >= 0) { var col = iglooSettings.flagColours[4]; } else { var col = defaultCol; }			return col; }	}	function iglooChanges { // the iglooChanges object is the object that retrieves, sorts, manages and displays changes from Wikipedia this.recentChanges = [];	// main array, holding the changes this.viewedChanges = [];	// main array, holding diffs that should NOT be displayed (we've seen them already) this.serverDetails = [];	// main array, holding details from the server regarding users and pages this.start = function { // start the changed program this.startInterface; this.startTicker; }		this.startTicker = function { // perform the refresh ticks that grab info from the server this.updateContent; this.refreshTicker = setInterval("igloo.iglooChanges.updateContent;", iglooSettings.updateTime * 1000); }		this.startInterface = function { // this creates the basic interface into which changes are placed when they have been received. // essentially, it is a div that will contain clickable list elements. this.changeDisplay = new wa_window(igloo.iglooInterface); this.changeDisplay.win_width = 190; this.changeDisplay.win_height= parseInt(igloo.iglooInterface.win_obj.style.height) - 50; this.changeDisplay.win_bg = '#ffffff'; this.changeDisplay.win_bd_rt = '1px solid #000000'; this.changeDisplay.win_bd_bt = '1px solid #000000'; this.changeDisplay.win_padding = 0; this.changeDisplay.win_content = ''; this.changeDisplay.applyAll; this.logoDisplay = new wa_window(igloo.iglooInterface); this.logoDisplay.win_top = parseInt(igloo.iglooInterface.win_obj.style.height) - 50; this.logoDisplay.win_width = 190; this.logoDisplay.win_height= 50; this.logoDisplay.win_bg = '#ffffff'; this.logoDisplay.win_bd_tp = '1px solid #000000'; this.logoDisplay.win_padding = 0; this.logoDisplay.win_content = ''; this.logoDisplay.applyAll; }		this.addToViewed = function ( revid ) { // mark an oldid as viewed so we do not display it more than once in the display window. var sizeLimit = 30; this.viewedChanges.push(revid); if (this.viewedChanges.length > sizeLimit) this.viewedChanges.shift; return true; }		this.markViewed = function ( revid ) { this.addToViewed(revid); // next, remove it from the recentChanges array, and redisplay that. for (var i = 0; i < this.recentChanges.length; i ++) { if (this.recentChanges[i][2] == revid) { this.recentChanges.splice(i, 1); var change = i;				} }			this.displayChanges; }		this.updateContent = function { var update = new iglooUpdateChanges; }		this.displayChanges = function { var visibleChangeOutput = ''; for (var i = 0; i < this.recentChanges.length; i ++) { if (typeof this.recentChanges[i][4] == 'undefined') this.recentChanges[i][4] = 0.5; var backgroundColour = igloo.iglooNet.colourScore(this.recentChanges[i][4]); if (this.recentChanges[i][3] == true) { var newPage = ' N '; } else { var newPage = ''; } visibleChangeOutput += '<li onclick="igloo.iglooControls.action_loadFromFeed(\+this.recentChanges[i][0]+'\', \+this.recentChanges[i][1]+'\', \+this.recentChanges[i][2]+'\', '+this.recentChanges[i][3]+', '+this.recentChanges[i][4]+');" onmouseover="this.style.backgroundColor = \'#dddddd\';" onmouseout="this.style.backgroundColor = \+backgroundColour+'\';" style="cursor: pointer; width: 186px; padding: 2px; border-bottom: 1px solid #000000; list-style-type: none; list-style-image: none; marker-offset: 0px; background-color: '+backgroundColour+';">'+newPage+this.recentChanges[i][0]+''; }			document.getElementById('iglooChangesList').innerHTML = visibleChangeOutput; }		this.destroy = function { // calling this will destroy the interface and connections of this object. this.changeDisplay.hide; this.logoDisplay.hide; if (typeof this.refreshTicker != 'undefined') clearInterval(this.refreshTicker); }	}	function iglooUpdateChanges { // the iglooUpdate object handles making a request to the server, and returning an array of data. this.updateCounter 	= 0; this.update = function { switch(this.updateCounter) { default: case 0: // first, get some recent changes var aRequest = this; this.ajax 				= new wa_ajaxcall; this.ajax.requestUrl 	= iglooSettings.rootApi + '?format=xml&action=query&list=recentchanges&rcprop=user|title|ids&rctype=edit|new&rclimit=' + iglooSettings.updateQuantity; this.ajax.doRequest(function {												 		aRequest.updateCounter ++;														aRequest.update;												 }); break; case 1: // recent changes are held such that: // [0] = title // [1] = user // [2] = oldid // [3] = new page? // [4] = user vandal score // [5] = priority note - a priority note is assigned to pages that have priority for some reason. These will be displayed at the top of the list, regardless of the score of the user. this.tempChanges = []; var data = this.ajax.response.getElementsByTagName('rc'); for (var i = 0; i < data.length; i++) { this.tempChanges[i] 	= []; this.tempChanges[i][0]	= data[i].getAttribute('title'); this.tempChanges[i][1]	= data[i].getAttribute('user'); this.tempChanges[i][2]	= data[i].getAttribute('revid'); if (data[i].getAttribute('type') == 'edit') { this.tempChanges[i][3]	= false; } else { this.tempChanges[i][3]	= true; }					}					this.updateCounter ++; this.update; break; case 2: // we have the details - build the temporary changes array var score = []; for (var i = 0; i < this.tempChanges.length; i ++) { // if we have special data on this user, such as a priority score, append it here. // check for pages score.length = 0; score = igloo.iglooNet.scoreObject(this.tempChanges[i][0]); // check for users if (score[0] === false) { score.length = 0; score = igloo.iglooNet.scoreObject(this.tempChanges[i][1]); }						// backup if (score[0] === false) score[0] = iglooSettings.defaultUserScore; this.tempChanges[i][4] = score[0]; this.tempChanges[i][5] = score[1]; }					// we want to remove all duplicates from the temp array, by copying them into // another temp array only if they are not already there. var tempArray = []; for (var i = 0; i < this.tempChanges.length; i ++) { var t = false; for (var j = 0; j < tempArray.length; j ++) { if (this.tempChanges[i][0] == tempArray[j][0]) { t = true; break; }						}						if (t == false) tempArray.push(this.tempChanges[i]); }					// now, remove any elements that are on the viewed list that we do not wish to display to the user OR that were made by our user var limit = tempArray.length for (var i = 0; i < limit; i ++) { if ( (in_array(tempArray[i][2], igloo.iglooChanges.viewedChanges) == true) || ((tempArray[i][1] == wgUserName)&&(iglooSettings.hideOwn == true)) ) { tempArray.splice(i, 1); i --; limit --; } else { if (tempArray[i][0] == igloo.iglooDiff.currentDiff[0]) { // if this is the same title as the page we're viewing, update the display igloo.iglooChanges.addToViewed(tempArray[i][2]); igloo.iglooDiff.display(tempArray[i][0], tempArray[i][1], tempArray[i][2], tempArray[i][3], tempArray[i][4]); tempArray.splice(i, 1); i --; limit --; }						}					}					// we now have the full array of scores // go through the main recent changes array, check if there are any pages that match // here and there, delete them from the main array, then merge this one into the main one var i = 0; while (typeof igloo.iglooChanges.recentChanges[i] != 'undefined') { for (var j = 0; j < tempArray.length; j ++) { if (typeof igloo.iglooChanges.recentChanges[i] == 'undefined') break; if (igloo.iglooChanges.recentChanges[i][0] == tempArray[j][0]) { igloo.iglooChanges.recentChanges.splice(i, 1); i --; }						}						i ++; }					// recent changes array now holds all the data it did before EXCEPT titles that conflict with the new changes // merge the new changes into the old ones igloo.iglooChanges.recentChanges = tempArray.concat(igloo.iglooChanges.recentChanges); // now, sort the array based on the float values :)					igloo.iglooChanges.recentChanges = sort_array_multi(igloo.iglooChanges.recentChanges, 4, 'descending');					// check that we aren't over the hard limit for number of changes. If we are, remove those least likely to be vandalism.					if (igloo.iglooChanges.recentChanges.length > iglooSettings.updateLimit) {						igloo.iglooChanges.recentChanges = igloo.iglooChanges.recentChanges.splice(0, iglooSettings.updateLimit); }					// now, we have to display the changes to the user! 					igloo.iglooChanges.displayChanges;					break;			}		}		this.update;	}	function iglooDiff {		// the iglooDiff module is the object that displays and styles Wikiepdia diffs in the main window		this.previousDiff 	= [];		this.currentDiff 	= [];		this.displayCounter = 0;		this.displayHistory = [];		this.historyPosition = 0;		this.canAddToHist = true;		this.start = function { // this functions creates the diff window for future use, and displays the latest news in it :) this.startInterface; this.displayWelcome; }		this.startInterface = function { // this creates the basic interface into which changes are placed when they have been received. // essentially, it is a div that will contain clickable list elements. this.scoreDisplay = new wa_window ( igloo.iglooInterface ); this.scoreDisplay.win_left = 190; this.scoreDisplay.win_top = 79; this.scoreDisplay.win_width = parseInt ( igloo.iglooInterface.win_obj.style.width ) - 200; this.scoreDisplay.win_height= 11; this.scoreDisplay.win_bg = '#ffffff'; this.scoreDisplay.win_bd_bt = '1px solid #000000'; this.scoreDisplay.win_padding = 2; this.scoreDisplay.win_content = 'You are not yet viewing a diff'; this.scoreDisplay.applyAll ; this.diffDisplay = new wa_window ( igloo.iglooInterface ); this.diffDisplay.win_left = 190; this.diffDisplay.win_top = 95; this.diffDisplay.win_width = parseInt ( igloo.iglooInterface.win_obj.style.width ) - 200; this.diffDisplay.win_height= parseInt ( igloo.iglooInterface.win_obj.style.height ) - 255; this.diffDisplay.win_bg = '#ededff'; this.diffDisplay.win_padding = 5; this.diffDisplay.win_content = ' DIFFS INIT '; this.diffDisplay.applyAll ; }		this.displayWelcome = function { // this function specifically displays the welcome message in the diff window var welcomeRequest = new wa_mediawikiApi ; welcomeRequest.onCompleteAction = function ( data ) { var regTest = /welcome:(.+?);;/i, o;																	regResult = regTest.exec( this.data['page']['revisions'][0]['content'] ); o = regResult[1].replace ( '%CURRENTVERSION%', iglooSettings.version ); document.getElementById( 'iglooDiffDisplay' ).innerHTML = o;															}; welcomeRequest.getPage( iglooSettings.localBase + 'config', 1, 'content' ); }		this.display = function ( title, user, revisionId, newPage, diffScore ) { // this function displays the diff of an edit on the screen for the user // the user has displayed activity by initiating a diff display. igloo.iglooSession.userActivity = true; // update the holding variables. Some of these may be absent based on the origin of the display call. if (typeof this.currentDiff[0] != 'undefined') { this.previousDiff[0] = this.currentDiff[0]; this.previousDiff[1] = this.currentDiff[1]; this.previousDiff[2] = this.currentDiff[2]; this.previousDiff[3] = this.currentDiff[3]; this.previousDiff[4] = this.currentDiff[4]; } this.currentDiff[0] = title; this.currentDiff[1] = user; this.currentDiff[2] = revisionId; this.currentDiff[3] = newPage; this.currentDiff[4] = diffScore; // add to history this.manageHist; // decide upon the request to perform - is this a specific request, or a general one? if (!revisionId) { revisionId = false; var url = mw.config.get('wgServer') + mw.config.get('wgScript') + '?title=' + encodeURIComponent(title) + '&diff=cur&diffonly=true'; } else { var url = mw.config.get('wgServer') + mw.config.get('wgScript') + '?oldid=' + revisionId + '&diff=prev&diffonly=true'; }			var aDisplay = this; this.ajax = new wa_ajaxcall; this.ajax.requestUrl = url; this.ajax.doRequest(function { 										aDisplay.parseScreenScrape;									}); }		this.manageHist = function { // add the PREVIOUS page to the display history. if ( ( this.currentDiff[0] ) && ( this.currentDiff[1] ) && ( this.currentDiff[2] ) ) if (this.canAddToHist == true) { // first, remove any history between the current position and 0. if (this.historyPosition > 0) { var temp = []; temp.length = 0; temp = this.displayHistory.slice(this.historyPosition); this.displayHistory.length = 0; this.displayHistory = temp; this.historyPosition = 0; }				// then add the page var histEntry = []; histEntry.length = 0; histEntry[0] = this.currentDiff[0]; histEntry[1] = this.currentDiff[1]; histEntry[2] = this.currentDiff[2]; this.displayHistory.unshift(histEntry); if (this.displayHistory > iglooSettings.maxHistory) this.displayHistory.length = iglooSettings.maxHistory; }			this.canAddToHist = true; // handle greying of invalid options var backButton 		= document.getElementById('igloo-buttons-back-b'); var forwardButton 	= document.getElementById('igloo-buttons-forward-b'); var backUrl			= 'http://alejrb.x10hosting.com/igloo/igloo-back'; var forwardUrl		= 'http://alejrb.x10hosting.com/igloo/igloo-forward'; var grey 			= '-grey'; var filetype		= '.png'; if (this.displayHistory.length <= 1) { backButton.src = backUrl + grey + filetype; forwardButton.src = forwardUrl + grey + filetype; } else if ( (this.displayHistory.length > 1) && (this.historyPosition == 0) ) { backButton.src = backUrl + filetype; forwardButton.src = forwardUrl + grey + filetype; } else if ( (this.displayHistory.length > 1) && (this.historyPosition == (this.displayHistory.length - 1)) ) { backButton.src = backUrl + grey + filetype; forwardButton.src = forwardUrl + filetype; } else { backButton.src = backUrl + filetype; forwardButton.src = forwardUrl + filetype; } }		this.goBack = function(count) { if (this.displayHistory.length <= 0) return false; if (!count) count = 1; if ((this.historyPosition + count) > this.displayHistory.length) count = this.displayHistory.length; this.historyPosition += count; var doView = this.displayHistory[this.historyPosition]; this.canAddToHist = false; this.display(doView[0], doView[1], doView[2]); return true; }		this.goForward = function(count) { if (this.historyPosition <= 0) return false; if (!count) count = 1; if ( (this.historyPosition - count) < 0 ) { this.historyPosition = 0; } else { this.historyPosition -= count; } var doView = this.displayHistory[this.historyPosition]; this.canAddToHist = false; this.display(doView[0], doView[1], doView[2]); }		this.parseScreenScrape = function ( html ) { if ( html == null ) { html = this.ajax.response; } // CSS details: object widths var markerwidth = 14; var contentwidth = ( this.diffDisplay.win_width / 2 ) - markerwidth; // step 0 - build an XML document from the HTML for IE - cos it's rubbish var ie = false; if ( ! html.getElementById ) { // we're hacking for IE				ie = true; // get, then clean, the responseText html = this.ajax.pageRequest.responseText; html = html.substr(html.indexOf('<html')); html = html.replace(/ /g, '&#160;'); var doc = ie_create_document; var test = doc.loadXML(html); if (doc.parseError.errorCode != 0) { alert('Internet Explorer failed to parse the incoming page because igloo sanitised it incorrectly. XML parser returned:'+"\n"+doc.parseError.reason); return false; }				html = doc; }			// step 1 - build an array of the data that is displayed by the diff screen // this.diffData[0] = old // this.diffData[1] = new // #[0] = revision as of				// #[1] = username // #[2] = comment/summary this.diffData = []; this.diffData[0] = []; this.diffData[1] = []; for (var i = 0; i < 3; i ++) { if (html.getElementById) { // good browsers if (html.getElementById('mw-diff-otitle' + (i + 1)) != null) { this.diffData[0][i] = echo_nodes_recursive( html.getElementById('mw-diff-otitle' + (i + 1)) ); } if (html.getElementById('mw-diff-ntitle' + (i + 1)) != null) { this.diffData[1][i] = echo_nodes_recursive( html.getElementById('mw-diff-ntitle' + (i + 1)) ); } } else { // the trash that is IE					this.diffData[0][i] = ie_getElementById(html, 'mw-diff-otitle' + (i + 1)).text; this.diffData[1][i] = ie_getElementById(html, 'mw-diff-ntitle' + (i + 1)).text; }			}			// step 2 - remove that from the visible diff var allTables = html.getElementsByTagName('table'); for (var i = 0; i < allTables.length; i ++) { if (allTables[i].className == 'diff') break; }			if (i >= allTables.length) i = (allTables.length - 1); if (i < 0) { var newPage = true; } else { var newPage = false; } if (newPage == false) { var table = document.createElement('table'); table.className = 'diff'; // in order to add content to the table in IE, we must first add it to a diff. We also handle styling IE output here. if (ie) { var tempIEDiv 		= document.createElement('div'); var tempIETable 	= ie_cloneNode(allTables[i]); tempIEDiv.appendChild(tempIETable); //tempIEDiv.innerHTML = this.flag(tempIEDiv.innerHTML); tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/class='?diff-context'?/ig, 			'style="background-color: #ddddff;"'); tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/class='?diff-addedline'?/ig, 		'style="background-color: #ccddcc;"'); tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/class='?diff-deletedline'?/ig, 		'style="background-color: #ffffaa;"'); tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/class='?diff['>]/ig, 				'style="width: 100%; font-size: 12px; background-color: #ededff;"'); tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/(del |ins )class=['"]?.*?diffchange.*?['"]?(>)?/ig,	'$1style="text-decoration: none; font-weight: bold; color: #ff0000;"$2'); tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/class='?diff-marker'?/ig, 			'style="width: '+markerwidth+'px; font-size: 14px; font-weight: bold;"'); tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/class='?diff-content'?/ig, 			'style="width: '+contentwidth+'px;"'); table.appendChild(tempIEDiv); } else { table.innerHTML = allTables[i].innerHTML.toString; table.innerHTML = this.flagProfanity(table.innerHTML); }				// remove the built in rubbish if (table.getElementsByTagName('tr')[0] != null) table.getElementsByTagName('tr')[0].parentNode.removeChild(table.getElementsByTagName('tr')[0]); // add our own (basically rubbish) stuff // first, users var newTr = document.createElement('tr'); var oldEditor = this.diffData[0][1].substr( 0, this.diffData[0][1].indexOf('(talk') );				var newEditor = this.diffData[1][1].substr( 0, this.diffData[1][1].indexOf('(talk') ); // if we don't have the user for this diff, we might as well set it, even if something goes wrong; it's better than nothing if (typeof this.currentDiff[1] == 'undefined') this.currentDiff[1] = newEditor; var newTd1 = document.createElement('td'); newTd1.innerHTML = +oldEditor+; newTd1.setAttribute('colspan','2'); newTd1.setAttribute('align','center'); newTd1.setAttribute('width','50%'); var newTd2 = document.createElement('td'); newTd2.innerHTML = +newEditor+; newTd2.setAttribute('colspan','2'); newTd2.setAttribute('align','center'); newTd2.setAttribute('width','50%'); newTr.appendChild(newTd1); newTr.appendChild(newTd2); table.insertBefore(newTr, table.firstChild); // second, summaries var newTr = document.createElement('tr'); if ( (typeof this.diffData[0][2] != 'undefined') && (this.diffData[0][2] != false) ) { var oldSummary = this.diffData[0][2]; } else { var oldSummary = ''; } if ( (typeof this.diffData[1][2] != 'undefined') && (this.diffData[1][2] != false) ) { var newSummary = this.diffData[1][2]; } else { var newSummary = ''; } var newTd1 = document.createElement('td'); newTd1.innerHTML = +oldSummary+; newTd1.setAttribute('colspan','2'); newTd1.setAttribute('align','center'); var newTd2 = document.createElement('td'); newTd2.innerHTML = +newSummary+; newTd2.setAttribute('colspan','2'); newTd2.setAttribute('align','center'); newTr.appendChild(newTd1); newTr.appendChild(newTd2); table.insertBefore(newTr, table.childNodes[1]); } else { // step 2 - get the page content var table = document.createElement('div'); table.setAttribute('style', 'font-size: 12px;'); table.className = 'diff'; var text = this.ajax.pageRequest.responseText; text = text.substring(text.indexOf(' '), text.indexOf('<div class="printfooter"')); table.innerHTML = text; }			// step 3 - remove old details if (document.getElementById('iglooPageTitle') != null) document.getElementById('iglooPageTitle').parentNode.removeChild(document.getElementById('iglooPageTitle')); if (document.getElementById('iglooInnerDiv') != null) document.getElementById('iglooInnerDiv').parentNode.removeChild(document.getElementById('iglooInnerDiv')); document.getElementById('iglooDiffDisplay').innerHTML = ''; // step 4 - output the page title to the diff screen var pageTitle = document.createElement('div'); pageTitle.setAttribute('id', 'iglooPageTitle'); pageTitle.style.fontSize = '1.6em'; pageTitle.style.fontWeight = 'bold'; pageTitle.style.width = '100%'; pageTitle.style.marginBottom = '5px'; pageTitle.style.borderBottom = '1px solid #000'; if (this.currentDiff[3]) { var extra = '(NEW PAGE) '; } else { var extra = ''; } var pageTitleContent = document.createTextNode(extra + this.currentDiff[0]); pageTitle.appendChild(pageTitleContent); document.getElementById('iglooDiffDisplay').appendChild(pageTitle); // step 5 - output the table in question to the diff screen // here, we handle styling for NON-IE browsers if (!ie) { var style = document.createElement('style'); style.setAttribute('type', 'text/css'); var cssString = 'span.iglooProfanity { background-color: #ff99ff; font-weight: bold; text-decoration: underline; } table.diff { width: 100%; font-size: 12px; background-color: #ededff; } col.diff-marker { width: '+markerwidth+'px; font-size: 14px; font-weight: bold; } col.diff-content { width: '+contentwidth+'px; } td.diff-lineno { font-weight: bold; } td.diff-addedline { background-color: #ccffcc; } td.diff-deletedline { background-color: #ffffaa; } td.diff-context { background-color: #ddddff; } .diffchange { text-decoration: none; font-weight: bold; color: #ff0000; }'; var cssText = document.createTextNode(cssString); style.appendChild(cssText); document.getElementById('iglooDiffDisplay').appendChild(style); }			// the container div var innerDiv = document.createElement('div'); innerDiv.setAttribute('id', 'iglooInnerDiv'); innerDiv.style.margin = 'auto'; // stick the table of stuff into the div innerDiv.appendChild(table); // display everything in the window document.getElementById('iglooDiffDisplay').appendChild(innerDiv); document.getElementById('iglooDiffDisplay').innerHTML += ' '; // we can now revert this edit if (igloo.iglooActions.reversionEnabled == 'pause') igloo.iglooActions.reversionEnabled = 'yes'; // handle the diff scoring window this.updateScoreDisplay(this.currentDiff[4]); }		this.updateScoreDisplay = function(score) { if (score == null) { score = igloo.iglooNet.scoreObject(this.currentDiff[1]); score = score[0]; if (score === false) score = iglooSettings.defaultUserScore; }			if (score != null) { if (score >= 0.8) { this.scoreDisplay.win_content = 'igloo asserts that this edit is PROBABLE VANDALISM .'; } else if (score >= 0.6) { this.scoreDisplay.win_content = 'igloo asserts that this edit is possible vandalism .'; } else if (score >= 0.4) { this.scoreDisplay.win_content = 'igloo has little or no data on this diff, and cannot make a risk assertion.'; } else if (score >= 0.2) { this.scoreDisplay.win_content = 'igloo asserts that this edit is unlikely to be vandalism .'; } else if (score >= 0) { this.scoreDisplay.win_content = 'igloo asserts that this edit is free from vandalism .'; } else { this.scoreDisplay.win_content = 'iglooNet data for this diff is missing.'; }			} else { score = iglooSettings.defaultUserScore; this.scoreDisplay.win_content = 'iglooNet data for this diff is missing.'; }			this.scoreDisplay.win_bg = igloo.iglooNet.colourScore ( score, '#ffffff' ); this.scoreDisplay.applyAll; }		this.flagProfanity = function(html) { // this function flags profanity in the diff window var profanity = new Array(											/\b(f+(?:u|oo)[ck]{2,}(?:ing?|er|hole)?|s[e3]+x+[iey]*|r[a4]pe+|su[ck]+(?:s+|ed+)?|gang[- ]?bang(?:er|ing)?)\b/ig, /* sexual intercourse */											/\b(h[o0]+m[o0]+(?:sexual(?:it(?:y|e)+)?)?|(?:is +)?ga+[iy]+|lesb(?:ian|[o0]*))\b/ig, /* homosexuality */											/\b([ck][o0]+[ck]{2,}(?:head|face)?|d[o0]+n+g|p[3e]+n[iu]+s|p+[3e]{2,}|d[i1]+[ck]{2,}s*(?:su[ck]{2,}(?:er|ing)?)?|manh(?:[o0]{2,}|u+)d+|b[o0]+n+e*r+s*|ball[sz]+(?:a[ck]{2,})?)\b/ig, /* male genitalia */											/\b(cun+(?:t|[iey]+)|vag(?:ina)?s*|puss+[yie]+s*|fann+[yie]+s*)\b/ig, /* female genitalia */											/\b(t+i+t+(?:s*|[iey]+[sz]*)|breasts*|b+[o0]{2,}b+[ieys]*)\b/ig, /* breasts */											/\b(anal+|ass+|(?:bum+|butt+) ?(?:h[o0]+le|cr+a[ck]+|o(?:[ck]+s|x+))?)\b/ig, /* anus */											/\b((?:bull)?(?:s+hite*|ass+)(?:holes?)?|cr[a4*]+p+[iy]*|cru+d+)\b/ig, /* excretion */											/\b(w?hor?e|prostitute|slu+t|slag|cu+m+(?:ing)?)\b/ig, /* sexual */ /\b(nigg+(?:er|a+)s*)\b/ig, /* racism */ /\b(ret[a4]+r+d+(?:ed|s)?|f+[a4]+g+([o0]+t+)?s*|d[ou]+che?(ba+g)?|bast[ea]rds*|bit*ch)\b/ig, /* other insults */ /\b(q[qwerty]{5,}|[asdf]{8,}|[ghjkl]{8,}|[uiop]{8,}|([a-z])\2{6,})\b/ig, /* nonsense */ /\b(lol(?:l*ol|cat[sz]*)*|li+e+k)\b/ig, /* lolz */ /\b(ha?i+|he+ll+o+|(?:ha+|hee+|ho+)+|l[ou]+v+|ya|ye+h+)\b/ig, /* laughs/greetz */ /([!?;]{3,}|[.|]{4,}|={6,})/ig /* repeating characters */ );			for ( var i = 0, l = profanity.length; i < l; i ++ ) {				html = html.replace(profanity[i], ' $1 ');			}			return html;		}		this.destroy = function { // calling this will destroy the interface and connections of this object.			this.diffDisplay.hide ;			this.scoreDisplay.hide ;		}	}	function iglooHist  {		// the iglooHist object handles the retrieval and display of the history of a page, in order		// that it can be displayed to the user.		// timer var		this.timer = null;		this.delayValue = iglooSettings.histWinTimeout;		this.startInterface = function {			if (document.getElementById('igloo-buttons-history') == null) return false;			this.histCatcher = new wa_window(document.getElementById('igloo-buttons-history'));			this.histCatcher.win_top = 71;			this.histCatcher.win_left = -100;			this.histCatcher.win_width = 170;			this.histCatcher.win_height= 80;			this.histCatcher.win_alpha = 0; this.histCatcher.win_cursor = 'pointer'; this.histCatcher.win_disp = 'none'; this.histCatcher.applyAll; this.histDisplay = new wa_window(document.getElementById('igloo-buttons-history')); this.histDisplay.win_top = 77; this.histDisplay.win_left = -100; this.histDisplay.win_width = 170; this.histDisplay.win_bg = '#d0d0d0'; this.histDisplay.win_bd = '#000000'; this.histDisplay.win_bd_wd = 1; this.histDisplay.win_padding = 2; this.histDisplay.win_cursor = 'pointer'; this.histDisplay.win_disp = 'none'; this.histDisplay.win_content = ' loading page history - wait... '; this.histDisplay.applyAll; // unfortunately, these pseudo events cannot be detatched. See waLib.js for implementation. wa_attach (document.getElementById('igloo-buttons-history'), 'mouseenter', igloo.iglooHist.mouseOver); wa_attach (document.getElementById('igloo-buttons-history'), 'mouseleave', igloo.iglooHist.mouseOut); }		this.mouseOver = function { if ( igloo.iglooHist.timer ) { clearTimeout(igloo.iglooHist.timer); igloo.iglooHist.timer = false; } else { igloo.iglooHist.histDisplay.show; igloo.iglooHist.histCatcher.show; igloo.iglooHist.getHistory; }		}		this.mouseOut = function { igloo.iglooHist.timer = setTimeout(function { igloo.iglooHist.histDisplay.hide; igloo.iglooHist.histCatcher.hide; igloo.iglooHist.timer = false; }, igloo.iglooHist.delayValue * 1000); }		this.getHistory = function(callback, data) { // the get history module retrieves a page history and displays it to the user switch (callback) { default: case 0: document.getElementById('iglooPageHistory-cont').innerHTML = 'loading page history - wait...'; var pageHist = new wa_mediawikiApi; pageHist.onCompleteAction = function(data) { igloo.iglooHist.getHistory(1, data); }; pageHist.getPage(igloo.iglooDiff.currentDiff[0], 15, 'ids|user'); break; case 1: document.getElementById('iglooPageHistory-cont').style.display = 'block'; document.getElementById('iglooPageHistory-note').style.display = 'none'; var pageHistory = ''; for (var i = 0; i < data['page']['revisions'].length; i ++ ) { var revision = data['page']['revisions'][i]; var user = revision['user']; var score = igloo.iglooNet.scoreObject(user); var backgroundColour = igloo.iglooNet.colourScore(score[0], '#ffffff'); pageHistory += '<li id="iglooHist_'+revision['id']+'" onclick="igloo.iglooControls.action_loadFromFeed(\+igloo.iglooDiff.currentDiff[0].replace ('\, '\\\)+'\', \+revision['user']+'\', \+revision['id']+'\');" onmouseover="this.style.backgroundColor = \'#dddddd\';" onmouseout="this.style.backgroundColor = \+backgroundColour+'\';" style="cursor: pointer; width: 186px; padding: 2px; border-bottom: 1px solid #000000; list-style-type: none; list-style-image: none; marker-offset: 0px; background-color: '+backgroundColour+';">'+revision['user']+''; }					pageHistory += '- full history -'; document.getElementById('iglooPageHistory-cont').innerHTML = pageHistory; break; }		}	}	function iglooControls { // the igloo controls module handles attaching to, and watching, keyboard events, and performing the requested function this.blockActions = false; this.start = function { // this functions creates the diff window for future use, and displays the latest news in it :)			this.startInterface;			this.bindKeys;		}		this.startInterface = function {			this.controlDisplay = new wa_window(igloo.iglooInterface);			this.controlDisplay.win_left = 190;			this.controlDisplay.win_width = parseInt(igloo.iglooInterface.win_obj.style.width) - 192;			this.controlDisplay.win_height= 78;			this.controlDisplay.win_bg = '#fdfdff';			this.controlDisplay.win_bd_tp = '1px solid #000000';			this.controlDisplay.win_bd_bt = '1px solid #000000';			this.controlDisplay.win_padding = 1;			this.controlDisplay.win_content = ' CONTROLS INIT ';			this.controlDisplay.applyAll;			this.attachButtons;			igloo.iglooHist = new iglooHist;			igloo.iglooHist.startInterface;		}		this.attachButtons = function {			var parent = document.getElementById('iglooControlsDisplay'); var panelButton = ' '; panelButton += '<img id="igloo-buttons-back-b" src="http://alejrb.x10hosting.com/igloo/images/igloo-back-grey.png" onclick="igloo.iglooControls.action_historyBack;" /> '; panelButton += '<div id="igloo-buttons-forward" style="position: relative; float: left; padding-left: -1px; padding-top: -1px; width: 50px; height: 50px; margin-top: 2px; margin-left: 10px; cursor: pointer;"><img id="igloo-buttons-forward-b" src="http://alejrb.x10hosting.com/igloo/images/igloo-forward-grey.png" onclick="igloo.iglooControls.action_historyForward;" /> '; panelButton += '<div id="igloo-buttons-settings" style="position: relative; float: right; padding-left: -1px; padding-top: -1px; width: 73px; height: 73px; margin-top: 3px; margin-right: 5px; cursor: pointer;"><img src="http://alejrb.x10hosting.com/igloo/images/igloo-settings.png" onclick="igloo.iglooManageSettings.showdisplay ;" /> '; panelButton += '<div id="igloo-buttons-history" style="position: relative; float: right; padding-left: -1px; padding-top: -1px; width: 73px; height: 73px; margin-top: 3px; margin-right: 5px; cursor: pointer;"><img src="http://alejrb.x10hosting.com/igloo/images/igloo-hist.png" /> '; parent.innerHTML = panelButton; }		this.bindKeys = function { wa_attach(document, 'keypress', igloo.iglooControls.handleKeys); }		this.handleKeys = function(e) { // called when a key press is registered if (!e) e = window.event; var keyPress = e.keyCode ? e.keyCode : e.charCode; switch (keyPress) { case 8: // backspace igloo.iglooControls.action_historyBack ; break; case 32: // spacebar if (typeof igloo.iglooChanges.recentChanges[0] != 'undefined') { igloo.iglooControls.action_loadFromFeed(igloo.iglooChanges.recentChanges[0][0], igloo.iglooChanges.recentChanges[0][1], igloo.iglooChanges.recentChanges[0][2], igloo.iglooChanges.recentChanges[0][3], igloo.iglooChanges.recentChanges[0][4]); }					break; case 81: case 113: // q					if (typeof igloo.iglooDiff.currentDiff[0] != 'undefined') { igloo.iglooControls.action_revertDiff; }					break; }			if (e.preventDefault) { e.preventDefault; } else { return false; } return true; }		this.getPermission = function ( message, escalateFunction ) { this.blockActions = true; if ( ! this.userMessage ) { this.userMessage = new wa_window ; this.userMessage.win_alpha = 0.7; this.userMessage.win_bg = '#000000'; this.userMessage.win_fill = true; this.userMessage.applyAll ; } else { this.userMessage.show ; }			if ( ! this.userMessageContent ) { this.userMessageContent = new wa_window ; this.userMessageContent.win_bg = '#ccccff'; this.userMessageContent.win_width = 500; this.userMessageContent.win_height = 130; this.userMessageContent.win_padding = 5; this.userMessageContent.win_alpha = 1; this.userMessageContent.win_bd = '2px solid #666688'; this.userMessageContent.win_content = ' igloo needs your permission to continue...

'+message+'

continue | cancel  '; this.userMessageContent.applyAll ; this.userMessageContent.center ( 'both', true ); } else { this.userMessageContent.show ; this.userMessageContent.win_content = ' igloo needs your permission to continue...

'+message+'

continue | cancel  '; this.userMessageContent.applyAll ; this.userMessageContent.center ( 'both', true ); }			document.getElementById( 'igloo-permission-challenge-cont' ).onclick = function { igloo.iglooControls.blockActions = false; igloo.iglooControls.userMessage.hide; igloo.iglooControls.userMessageContent.hide; escalateFunction; } document.getElementById( 'igloo-permission-challenge-canc' ).onclick = function { igloo.iglooControls.blockActions = false; igloo.iglooControls.userMessage.hide; igloo.iglooControls.userMessageContent.hide; }; }		this.action_historyBack = function { if ( igloo.iglooControls.blockActions ) return false; igloo.iglooDiff.goBack(1); }		this.action_historyForward = function { if ( igloo.iglooControls.blockActions ) return false; igloo.iglooDiff.goForward(1); }		this.action_revertDiff = function { if ( igloo.iglooControls.blockActions ) return false; igloo.iglooActions.revertDiff; }		this.action_loadFromFeed = function (a, b, c, d, e) { if ( igloo.iglooControls.blockActions ) return false; igloo.iglooActions.reversionEnabled = 'pause'; igloo.iglooDiff.display(a, b, c, d, e); igloo.iglooChanges.markViewed(c); }		this.destroy = function { // calling this will destroy the interface and connections of this object. this.controlDisplay.hide; }	}	function iglooActions { // the iglooActions module handles the actual editing of the wiki, such as reversions and warnings this.reversionEnabled 		= 'yes'; this.lastRevertedRevision 	= false; this.revertedPage 			= false; this.warnWho 				= false; this.warningLevel			= false; this.revertDiff = function { this.lastRevertedRevision = igloo.iglooDiff.currentDiff[2]; var page = igloo.iglooDiff.currentDiff[0]; var user = igloo.iglooDiff.currentDiff[1]; var revid = igloo.iglooDiff.currentDiff[2]; var rev = new iglooRevert(page, user, revid); }		this.sendLinkToParent = function(linkText, activateAfter) { if ( activateAfter == null ) activateAfter = true; if ( ( window.opener != null ) && ( ! window.opener.closed ) ) { window.opener.location.href = linkText; window.opener.focus ; return true; }			return false; }		this.cancelActivity = function { }	}	function iglooRevert(page, user, revid) { var thisRevert 		= this; this.revertPage		= page; this.revertUser		= user; this.revertRevid	= revid; this.performRollback = function(callback, details) { switch (callback) { default: case 0: // check that reversion is switched on					if (igloo.iglooActions.reversionEnabled == 'no') { alert('You cannot revert this edit to ' + this.revertPage + ', because you made it using igloo'); return false; } if (igloo.iglooActions.reversionEnabled == 'pause') { alert('You cannot revert this edit to ' + this.revertPage + ', because a diff is still loading'); return false; } // notify user igloo.iglooStatus.addStatus('Attempting to revert the change to '+thisRevert.revertPage+' made by '+thisRevert.revertUser+' ...'); // prevent interference with this page while we are reverting it					igloo.iglooActions.reversionEnabled = 'pause'; // let the user know we're working... document.getElementById('iglooPageTitle').innerHTML = document.getElementById('iglooPageTitle').innerHTML + ' - reverting edit...'; // build the reversion summary var summary = iglooSettings.rollbackSummary; // attempt the actual rollback var thisReversion = new wa_mediawikiApi; thisReversion.onCompleteAction = function(success) { thisRevert.performRollback(1, success); }; thisReversion.rollbackPage(this.revertPage, this.revertUser, summary); // mark the edit we're reverting as bad var url = iglooSettings.remoteHost + 'main.php?action=markbad&session='+igloo.iglooSession.session+'&me='+encodeURIComponent(wgUserName)+'&user='+this.revertUser+'&revid='+this.revertRevid; iglooImport(url, true, 'iglooMark'); break; case 1: if (details == false) { igloo.iglooStatus.addStatus('Will not revert the edit to '+thisRevert.revertPage+' by '+thisRevert.revertUser+' because another user has already done so.'); //alert('igloo will not revert the edit to '+this.revertPage+', because another user has already done so'); if (this.revertPage == igloo.iglooDiff.currentDiff[0]) { igloo.iglooDiff.display(this.revertPage, true); igloo.iglooActions.reversionEnabled = 'no'; }					} else { var thisReversion = new wa_mediawikiApi; thisReversion.onCompleteAction = function(data) { thisRevert.performRollback(2, data); }; thisReversion.getPage(this.revertPage, 1, 'ids'); }					break; case 2: // retrieve page ID, so we do not redisplay in the feed igloo.iglooChanges.addToViewed(details['page']['revisions'][0]['id']); if (this.revertPage == igloo.iglooDiff.currentDiff[0]) igloo.iglooDiff.display(this.revertPage, wgUserName); // notify user igloo.iglooStatus.addStatus('Successfully reverted the change to '+thisRevert.revertPage+' made by '+thisRevert.revertUser+' !'); this.warnUser; break; }		}		this.warnUser = function(callback, details) { switch (callback) { default: case 0: // notify user igloo.iglooStatus.addStatus('Attempting to warn '+thisRevert.revertUser+' for vandalism on '+thisRevert.revertPage+' ...'); // get the user talk page var getUserPage = new wa_mediawikiApi; getUserPage.onCompleteAction = function(data) { thisRevert.warnUser(1, data); }; getUserPage.getPage('User_talk:' + this.revertUser, 1, 'content'); break; case 1: // set up the time management systems var months = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'); var currentDate = new Date; var currentMonth = currentDate.getMonth; var currentYear = currentDate.getFullYear; var currentTime = currentDate.getTime; // check for warnings on the user's talk page var warnings = []; // if the page already exists, we must analyse it for warnings if (typeof details['page']['revisions'] != 'undefined') { var pageData = details['page']['revisions'][0]['content']; var regTest = /.+?([0-9]{2}):([0-9]{2}), ([0-9]{1,2}) ([a-z]+?) ([0-9]{4})/gi; // get all the warnings on the page var i = 0; while (true) { var t = regTest.exec(pageData); if (t == null) break; warnings[i] = []; warnings[i][0] = t[1]; // template warnings[i][1] = t[2]; // level warnings[i][2] = t[3]; // hour warnings[i][3] = t[4]; // minute warnings[i][4] = t[5]; // day warnings[i][5] = t[6]; // month warnings[i][6] = t[7]; // year i ++; }						// we are only interested in the latest one if (typeof warnings[0] == 'undefined') { warnings[0] = []; warnings[0][0] = false; warnings[0][1] = 0; } var useWarning = warnings.length-1; // check when this warning was given for (var compareMonth = 0; compareMonth < months.length; compareMonth ++) { if (months[compareMonth] == warnings[useWarning][5]) break; }						var compareDate = new Date; compareDate.setFullYear(parseInt(warnings[useWarning][6]), compareMonth, parseInt(warnings[useWarning][4])); compareDate.setHours(parseInt(warnings[useWarning][2])); compareDate.setMinutes(parseInt(warnings[useWarning][3])); var compareTime = compareDate.getTime; // check if it is old enough to ignore for the purposes of incremental warnings var timeDiff = (currentTime + (currentDate.getTimezoneOffset * 60 * 1000)) - compareTime; if (timeDiff > (iglooSettings.warningsOldAfter * 24 * 60 * 60 * 1000)) { warnings[useWarning][1] = 0; } // check whether a header already exists for the current month. if not, create one var currentHeader = new RegExp('={2,4} *'+months[currentMonth]+' *'+currentYear+' *={2,4}', 'gi'); if (currentHeader.test(pageData) != true) { var header = '== '+months[currentMonth]+' '+currentYear+' =='; } else { var header = false; } }					// if the page does not exist, we can simply set warnings at the default (lowest) levels else { // set up the warning and date header for addition to the user's page warnings[0] = []; warnings[0][0] = false; warnings[0][1] = 0; var header = '== '+months[currentMonth]+' '+currentYear+' =='; var useWarning = 0; }					// decide upon which warning level to issue switch (warnings[useWarning][1]) { default: case 0: // use first level warning this.warningLevel = 1; break; case '1': // use second level warning this.warningLevel = 2; break; case '2': // use third level warning this.warningLevel = 3; break; case '3': // use final warning this.warningLevel = 4; break; case '4': case '4im': // perform report/block logic igloo.iglooStatus.addStatus ( 'Will not warn '+thisRevert.revertUser+' because they have already recieved a final warning.' ); this.reportUser ; this.warningLevel = false; break; }					// add the message to their talk page if (this.warningLevel == false) return false; var userPage = 'User_talk:' + this.revertUser; var message = iglooSettings.warningMessage; message = message.replace(/%LEVEL%/g, this.warningLevel); message = message.replace(/%PAGE%/g, this.revertPage); message = message.replace(/%DIFF%/g, mw.config.get('wgServer') + mw.config.get('wgScript') + '?oldid=' + this.revertRevid + '&diff=prev'); message = message.replace(/%MESSAGE%/g, iglooSettings.vandalTemplate); var summary = 'Level '+this.warningLevel+' warning re. vandalism on '+this.revertPage+' (['+'['+iglooSettings.localBase.substr(0, iglooSettings.localBase.length-1)+'|IG]'+'])'; if ( header != false ) message = header + '\n' + message; var userWarning = new wa_mediawikiApi ; if ( iglooSettings.notifyWarningDone == true ) userWarning.onCompleteAction = function { igloo.iglooStatus.addStatus( 'Successfully issued a level '+thisRevert.warningLevel+' warning to '+thisRevert.revertUser+' for vandalism on '+thisRevert.revertPage+' !' ); }; userWarning.editPage ( userPage, message, summary, false, 'appendtext' ); break; }		}		this.reportUser = function(callback, details) { // handle reporting of the user to AIV switch (callback) { default: case 0: // notify user igloo.iglooStatus.addStatus('Attempting to report '+thisRevert.revertUser+' to '+iglooSettings.aiv+' for vandalism after final warning...'); // get the aiv page var getAivPage = new wa_mediawikiApi; getAivPage.onCompleteAction = function(data) { thisRevert.reportUser(1, data); }; getAivPage.getPage(iglooSettings.aiv.replace(/ /g, '_'), 1, 'content'); break; case 1: // check whether they are already reported if (typeof details['page']['revisions'] == 'undefined') { igloo.iglooStatus.addStatus('Will not report '+thisRevert.revertUser+' because the report page does not appear to exist.'); return false; // error }					var pageData = details['page']['revisions'][0]['content']; if (pageData.indexOf('|' + thisRevert.revertUser + '}}') > -1) { igloo.iglooStatus.addStatus('Will not report '+thisRevert.revertUser+' because they have already been reported.'); return false; }					// check bots var getAivPage = new wa_mediawikiApi; getAivPage.onCompleteAction = function(data) { thisRevert.reportUser(2, data); }; getAivPage.getPage(iglooSettings.aiv.replace(/ /g, '_'), 1, 'content'); break; case 2: // check whether they are already reported if (typeof details['page']['revisions'] == 'undefined') { igloo.iglooStatus.addStatus('Will not report '+thisRevert.revertUser+' because the report page does not appear to exist.'); return false; // error }					var pageData = details['page']['revisions'][0]['content']; if (pageData.indexOf('|' + thisRevert.revertUser + '}}') > -1) { igloo.iglooStatus.addStatus('Will not report '+thisRevert.revertUser+' because they have already been reported.'); return false; }					// if we get here, we haven't found a report about them yet - so we can go ahead and do it					if (thisRevert.revertUser.match(/^[0-9]+\.[0-9]+\.[0-9]+\.?[0-9]*$/i) == true) { var ipUser = true; } else { var ipUser = false; } // build page link var aivLink = iglooSettings.aiv.replace(/ /g, '_'); // build the report var myReport = iglooSettings.aivMessage; if (ipUser == true) { myReport = myReport.replace(/%TEMPLATE%/g, iglooSettings.aivIp); } else { myReport = myReport.replace(/%TEMPLATE%/g, iglooSettings.aivUser); } myReport = myReport.replace(/%USER%/g, thisRevert.revertUser); // build the summary var mySummary = iglooSettings.aivSummary; mySummary = mySummary.replace(/%USER%/g, thisRevert.revertUser); // perform the edit var userReport = new wa_mediawikiApi; userReport.onCompleteAction = function { igloo.iglooStatus.addStatus('Successfully reported '+thisRevert.revertUser+' to AIV!'); }; userReport.editPage(aivLink, myReport, mySummary, false, iglooSettings.aivWhere); break; }		}		var userScore = igloo.iglooNet.scoreObject(this.revertUser); if ( userScore[0] === false ) userScore[0] = iglooSettings.defaultUserScore; if ( userScore[0] < 0.4 ) { igloo.iglooControls.getPermission ( 'You are attempting to revert a change that iglooNet believes is free from vandalism. Remember that igloo should only be used to revert blatant vandalism.', function (page, user, thisRevert) { thisRevert.performRollback(page, user); } ); } else { this.performRollback(page, this.revertUser); } }	function iglooStatus { // the iglooStatus module handles the display and updating of the status window where we keep track of the actions we've taken for the user this.idCounter = 1; this.start = function { this.startInterface; }		this.startInterface = function { var iglooCount = igloo.iglooNet.iglooCount; var iglooLoadTime = igloo.endload - igloo.startload; if ( iglooSettings.lastConnectIp !== 0 ) { var iglooLastConnection = ', last connected from ' + iglooSettings.lastConnectIp + ' ' + iglooSettings.lastConnectTime; } else { var iglooLastConnection = ''; } this.intDisplay = new wa_window(igloo.iglooInterface); this.intDisplay.win_left = 190; this.intDisplay.win_top = parseInt(igloo.iglooInterface.win_obj.style.height) - 150; this.intDisplay.win_width = parseInt(igloo.iglooInterface.win_obj.style.width) - 200; this.intDisplay.win_height= 140; this.intDisplay.win_bg = '#ddddee'; // #'ededff'; this.intDisplay.win_bd_tp = '1px solid #000000'; this.intDisplay.win_bd_lf = '1px solid #000000'; this.intDisplay.win_padding = 5; this.intDisplay.win_content = ' <div id="statusObj_0" class="statusObj">Welcome to igloo! This is your status window, where you see the actions that igloo is taking on your behalf. stats: iglooNet currently has data on ' + iglooCount + ' unique entities. stats: igloo loaded in: ' + iglooLoadTime + iglooLastConnection + ' '; this.intDisplay.applyAll; }		this.destroy = function { this.intDisplay.hide; }		this.addStatus = function(message) { var curDate = new Date; var sec = curDate.getSeconds; if (sec < 10) sec = '0' + sec; var mins = curDate.getMinutes; if ( mins == 0) mins = '00'; var hours = curDate.getHours; if ( hours == 0) hours = '00'; var dateString = hours + ':' + mins + ':' + sec; var statusId = this.idCounter; this.idCounter ++; var newStatus = document.createElement('div'); newStatus.id = 'statusObj_' + statusId; newStatus.className = 'statusObj'; newStatus.innerHTML = ' ' + dateString + ' - ' + message + ' '; //var newStatusText = document.createTextNode(dateString + ' - ' + message); //newStatus.appendChild(newStatusText); var statusObj = document.getElementById('iglooStatusDisplay'); statusObj.insertBefore(newStatus, statusObj.firstChild); return statusId; }		this.updateStatus = function(id, message, action) { // action = 'append', 'prepend', 'overwrite' or 'destroy' - default 'append' if (document.getElementById('statusObj_' + id)) { var statusObj = document.getElementById('statusObj_' + id); } else { return false; } switch (action) { default: case 'append': statusObj.innerHTML = statusObj.innerHTML + message; return statusObj.innerHTML; break; case 'prepend': statusObj.innerHTML = message + statusObj.innerHTML ; return statusObj.innerHTML; break; case 'overwrite': statusObj.innerHTML = message; return statusObj.innerHTML; break; case 'destroy': statusObj.parentElement.removeChild(statusObj); return true; break; }		}	}	// launch! var igloo = new iglooMain; igloo.launch;