User:Sparky007/monobook.js

From wikishia

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
importScript('User:AzaToth/twinklefluff.js');
importScript('Wikipedia:WikiProject User scripts/Scripts/Add LI menu');
importStylesheet('Wikipedia:WikiProject User scripts/Scripts/Add LI menu/css');
importScript('User:AzaToth/twinklewarn.js');
importScript('User:AzaToth/twinklearv.js');
importScript('User:AzaToth/twinklespeedy.js');
importScript('User:AzaToth/twinklediff.js');
// Have debug on now.
//Status.debugLevel = 1;

/**
Twinklefluff revert and antivandalism utillity
*/
var VERSION = '1.0';
var MAXREV = 50; // maximum number of revision to lookup

// If TwinkleConfig aint exist.
if( typeof( TwinkleConfig ) == 'undefined' ) {
	TwinkleConfig = function() {};
}
/**
TwinkleConfig.userTalkPageMode may take arguments:
'window': open a new window, remmenber the opened window
'tab': opens in a new tab, if possible.
'blank': force open in a new window, even if a such window exist
*/
if( typeof( TwinkleConfig.userTalkPageMode ) == 'undefined' ) {
	TwinkleConfig.userTalkPageMode = 'window';
}

/**
TwinkleConfig.openTalkPage (array)
What types of actions that should result in opening of talk page
*/
if( typeof( TwinkleConfig.openTalkPage ) == 'undefined' ) {
	TwinkleConfig.openTalkPage = [ 'agf', 'norm', 'vand' ];
}

/**
TwinkleConfig.openAOLAnonTalkPage may take arguments:
true: to open Anon AOL talk pages on revert
false: to not open them
*/
if( typeof( TwinkleConfig.openAOLAnonTalkPage ) == 'undefined' ) {
	TwinkleConfig.openAOLAnonTalkPage = false;
}

/**
TwinkleConfig.addAdToSummary
If [[WP:TWINKLE|TWINKLE]] should be added or not to summary
*/
if( typeof( TwinkleConfig.addAdToSummary ) == 'undefined' ) {
	TwinkleConfig.addAdToSummary = true;
}

/**
TwinkleConfig.watchSpeedyPages (array)
What types of actions that should result in forced addition to watchlist
*/
if( typeof( TwinkleConfig.watchRevertedPages ) == 'undefined' ) {
	TwinkleConfig.watchRevertedPages = [ 'agf', 'norm', 'vand' ];
}

// a list of usernames, usually only bots, that vandalism revert is jumped over, that is
// if vandalism revert is choosen on such username, then it's target in on the revision before.
// This is for handeling quick bots that makes edits seconds after the original edit is made.
// This only affect vandalism rollback, for good faith rollback, it will stop, indicating a bot 
// has no faith, and for normal rollback, it will rollback that edit.
var WHITELIST = [
	'HagermanBot',
	'HBC AIV helperbot',
	'HBC AIV helperbot2',
	'HBC AIV helperbot3',
]

var revertXML;
var contentXML;
var contentDoc;
var editXML;
var vandal;
var type;
var goodRev;
var nbrOfRevisions;
var curStatus;
var curVersion = true;

function addRevertButtons() {

	var spanTag = function( color, content ) {
		var span = document.createElement( 'span' );
		span.style.color = color;
		span.appendChild( document.createTextNode( content ) );
		return span;
	}

	if( wgNamespaceNumber == -1 && wgCanonicalSpecialPageName == "Contributions" ) {
		var list = document.getElementById('bodyContent').getElementsByTagName( 'ul' )[0].getElementsByTagName( 'li' );
		var vandal = document.getElementById('contentSub').getElementsByTagName( 'a' )[0].getAttribute( 'title' ).replace(/^User( talk)?:/ , '').replace("'", "\\'");

		var revNode = document.createElement('strong');
		var revLink = document.createElement('a');
		revLink.appendChild( spanTag( 'Black', ' [' ) );
		revLink.appendChild( spanTag( 'SteelBlue', 'rollback' ) );
		revLink.appendChild( spanTag( 'Black', ']' ) );
		revNode.appendChild(revLink);

		var revVandNode = document.createElement('strong');
		var revVandLink = document.createElement('a');
		revVandLink.appendChild( spanTag( 'Black', ' [' ) );
		revVandLink.appendChild( spanTag( 'Red', 'vandalism' ) );
		revVandLink.appendChild( spanTag( 'Black', ']' ) );
		revVandNode.appendChild(revVandLink);

		for(var i in list ) {
			if( !list[i].lastChild || list[i].lastChild.nodeName != 'STRONG' ) {
				continue
			}

			var oldid = list[i].getElementsByTagName( 'a' )[1].getAttribute( 'href' ).split( 'oldid=' )[1];
			var page = list[i].getElementsByTagName( 'a' )[2].getAttribute( 'title' ).replace("'", "\\'");
			var tmpNode = revNode.cloneNode( true );
			tmpNode.firstChild.setAttribute( 'href', "javascript:revertPage('norm' , '" + vandal + "', " + oldid + ", '" + page + "')" );
			list[i].appendChild( tmpNode );
			var tmpNode = revVandNode.cloneNode( true );
			tmpNode.firstChild.setAttribute( 'href', "javascript:revertPage('vand' , '" + vandal + "', " + oldid + ", '" + page + "')" );
			list[i].appendChild( tmpNode );
		}


	} else {

		var otitle = getElementsByClassName( document.getElementById('bodyContent'), 'td' , 'diff-otitle' )[0];
		var ntitle = getElementsByClassName( document.getElementById('bodyContent'), 'td' , 'diff-ntitle' )[0];

		if( !ntitle ) {
			// Nothing to see here, move along...
			return;
		}

		if( !otitle.getElementsByTagName('a')[0] ) {
			// no previous revision available
			return;
		}

		// Lets first add a [edit this revision] link

		var oldrev = QueryString.get( 'oldid', decodeURI( otitle.getElementsByTagName( 'a' )[0].getAttribute( 'href' ).split( '&', 2 )[1] ) );

		var oldEditNode = document.createElement('strong');

		var oldEditLink = document.createElement('a');
		oldEditLink.href = "javascript:revertToRevision('" + oldrev + "')";
		oldEditLink.appendChild( spanTag( 'Black', '[' ) );
		oldEditLink.appendChild( spanTag( 'SaddleBrown', 'restore this version' ) );
		oldEditLink.appendChild( spanTag( 'Black', ']' ) );
		oldEditNode.appendChild(oldEditLink);

		var cur = otitle.insertBefore(oldEditNode, otitle.firstChild);
		otitle.insertBefore(document.createElement('br'), cur.nextSibling);

		if( ntitle.getElementsByTagName('a')[0].firstChild.nodeValue != 'Current revision' ) {
			// not latest revision
			curVersion = false;
			return;
		}

		vandal = ntitle.getElementsByTagName('a')[3].firstChild.nodeValue.replace("'", "\\'");

		var agfNode = document.createElement('strong');
		var vandNode = document.createElement('strong');
		var normNode = document.createElement('strong');

		var agfLink = document.createElement('a');
		var vandLink = document.createElement('a');
		var normLink = document.createElement('a');

		agfLink.href = "javascript:revertPage('agf' , '" + vandal + "')"; 
		vandLink.href = "javascript:revertPage('vand' , '" + vandal + "')"; 
		normLink.href = "javascript:revertPage('norm' , '" + vandal + "')"; 

		agfLink.appendChild( spanTag( 'Black', '[' ) );
		agfLink.appendChild( spanTag( 'DarkOliveGreen', 'rollback (AGF)' ) );
		agfLink.appendChild( spanTag( 'Black', ']' ) );

		vandLink.appendChild( spanTag( 'Black', '[' ) );
		vandLink.appendChild( spanTag( 'Red', 'rollback (VANDAL)' ) );
		vandLink.appendChild( spanTag( 'Black', ']' ) );

		normLink.appendChild( spanTag( 'Black', '[' ) );
		normLink.appendChild( spanTag( 'SteelBlue', 'rollback' ) );
		normLink.appendChild( spanTag( 'Black', ']' ) );

		agfNode.appendChild(agfLink);
		vandNode.appendChild(vandLink);
		normNode.appendChild(normLink);

		var cur = ntitle.insertBefore(agfNode, ntitle.firstChild);
		cur = ntitle.insertBefore(document.createTextNode(' || '), cur.nextSibling);
		cur = ntitle.insertBefore(normNode, cur.nextSibling);
		cur = ntitle.insertBefore(document.createTextNode(' || '), cur.nextSibling);
		cur = ntitle.insertBefore(vandNode, cur.nextSibling);
		cur = ntitle.insertBefore(document.createElement('br'), cur.nextSibling);
	}

}
addOnloadHook(addRevertButtons);

function revertPage( pType, pVandal, rev, page ) {

	wgPageName = page || wgPageName;
	wgCurRevisionId = rev || wgCurRevisionId;


	try {
		vandal = pVandal;
		type = pType;
		Status.init( document.getElementById('bodyContent') );

		revertXML = sajax_init_object();
		Status.debug( 'revertXML' + revertXML );
		revertXML.overrideMimeType('text/xml');

		var query = {
			'action': 'query',
			'prop': 'revisions',
			'titles': wgPageName,
			'rvlimit': MAXREV,
			'rvprop': [ 'timestamp', 'user', 'comment' ],
			'format': 'xml'
		}

		Status.status( 'Querying revisions' );
		revertXML.onreadystatechange = revertPageCallback;
		revertXML.open( 'GET' , wgServer + wgScriptPath + '/api.php?' + QueryString.create( query ), true );
		revertXML.send( null );
	} catch(e) {
		if( e instanceof Exception ) {
			Status.error( 'Error: ' + e.what() );
		} else {
			Status.error( 'Error: ' + e );
		}
	}

}
function revertPageCallback() {

	if ( revertXML.readyState != 4 ){
		Status.progress('.');
		return;
	} 

	if( revertXML.status != 200 ){
		Status.error('Bad status , bailing out');
		return;
	}

	var doc = revertXML.responseXML.documentElement;

	if( !doc ) {
		Status.error( 'Possible failure in recieving document, will abort.' );
		return;
	}
	var revisions = doc.getElementsByTagName('rev');
	var top = revisions[0];
	Status.debug( 'revisions[0]: ' + top );

	if( top.getAttribute( 'revid' ) < wgCurRevisionId ) {
		Status.error( [ 'The recieved top revision id ', htmlNode( 'strong', top.getAttribute('revid') ), ' is less than our current revision id, this could indicate that the current revision has been deleted, the server is lagging, or that bad data has been recieved. Will stop proceeding at this point.' ] );
		return;
	}
	if( !top ) {
		Status.error( 'No top revision found,  this could indicate that the page has been deleted, or that a problem in the transmittion has occoured, will abort reversion ');
		return;
	}


	Status.status( [ 'Evaluating revisions to see if ', htmlNode( 'strong', vandal), ' is the last contributor...' ] );
	Status.debug( 'wgCurRevisionId: ' + wgCurRevisionId + ', top.getAttribute(revid): ' + top.getAttribute('revid') );

	if( wgCurRevisionId != top.getAttribute('revid') ) {
		Status.warn( [ 'Latest revision ', htmlNode( 'strong', top.getAttribute('revid') ), ' doesn\'t equals our revision ', htmlNode( 'strong', wgCurRevisionId) ] );
		Status.debug( 'top.getAttribute(user): ' + top.getAttribute( 'user' ) );

		if( top.getAttribute( 'user' ) == vandal ) {
			switch( type ) {
				case 'vand':
				Status.info( [ 'Latest revision is made by ', htmlNode( 'strong', vandal ) , ', as we assume vandalism, we continue to revert' ]);
				break;
				case 'afg':
				Status.warn( [ 'Latest revision is made by ', htmlNode( 'strong', vandal ) , ', as we assume good faith, we stop reverting, as the problem might have been fixed.' ]);
				return;
				default:
				Status.warn( [ 'Latest revision is made by ', htmlNode( 'strong', vandal ) , ', but we will stop reverting anyway.' ] );
				return;
			}
		} else if( 
			type == 'vand' && 
			WHITELIST.indexOf( top.getAttribute( 'user' ) ) != -1 && 
			top.nextSibling.getAttribute( 'pageId' ) == wgCurRevisionId 
		) {
			Status.info( [ 'Latest revision is made by ', htmlNode( 'strong', top.getAttribute( 'user' ) ), ', a trusted bot, and the revision before was made by our vandal, so we proceed with the revert.' ] );
			top = top.nextSibling;
		} else {
			Status.error( [ 'Latest revision is made by ', htmlNode( 'strong', top.getAttribute( 'user' ) ), ', so it might already been reverted, stopping  reverting.'] );
			return;
		}
	} 

	if( type == 'vand' && WHITELIST.indexOf( vandal ) != -1 ) {
		Status.info( [ 'Vandalism revert is choosen on ', htmlNode( 'strong', vandal ), ', as this is a whitelisted bot, we assume you wanted to revert vandalism made by the previous user instead.' ] );
		top = top.nextSibling;
		vandal = top.getAttribute( 'user' );
	} else if( type == 'agf'  && WHITELIST.indexOf( vandal ) != -1 ) {
		Status.warn( [ 'Good faith revert is choosen on ', htmlNode( 'strong', vandal ), ', as this is a whitelisted bot, it makes no sense at all to revert it as a good faith edit, will stop reverting.' ] );
		return;
	}

	Status.status( 'Finding last good revision...' );

	goodRev = top;
	nbrOfRevisions = 0;

	while( goodRev.getAttribute('user') == vandal ) {

		goodRev = goodRev.nextSibling;

		nbrOfRevisions++;

		if( goodRev == null ) {
			Status.error( [ 'No previous revision found, perhaps ', htmlNode( 'strong', vandal ), ' is the only contributor, or that the user has made more than ' + MAXREV + ' edits in a row.' ] );
			return;
		}
	}

	if( nbrOfRevisions == 0 ) {
		Status.error( "We where to revert zero revisions. As that makes no sense, we'll stop reverting this time. It could be that the edit already have been reverted, but the revision id was still the same." );
		return;
	}

	if( 
		type != 'vand' && 
		nbrOfRevisions > 1  && 
		!confirm( vandal + ' has done ' + nbrOfRevisions + ' edits in a row. Are you sure you want to revert them all?' ) 
	) {
		Status.info( 'Stopping reverting per user input' );
		return;
	}

	Status.progress( [ ' revision ', htmlNode( 'strong', goodRev.getAttribute( 'revid' ) ), ' that was made ', htmlNode( 'strong', nbrOfRevisions ), ' revisions ago by ', htmlNode( 'strong', goodRev.getAttribute( 'user' ) ) ] );

	Status.status( [ 'Getting content for revision ', htmlNode( 'strong', goodRev.getAttribute( 'revid' ) ) ] );
	var query = {
		'action': 'query',
		'prop': 'revisions',
		'titles': wgPageName,
		'rvlimit': 1,
		'rvprop': 'content',
		'rvstartid': goodRev.getAttribute( 'revid' ),
		'format': 'xml'
	}

	Status.debug( 'query:' + query.toSource() );

	// getting the content for the last good revision
	revertXML = sajax_init_object();
	revertXML.overrideMimeType('text/xml');
	revertXML.onreadystatechange = revertCallback2;
	revertXML.open( 'GET' , wgServer + wgScriptPath + '/api.php?' + QueryString.create( query ), true );
	revertXML.send( null );

}

function revertCallback2() {
	if ( revertXML.readyState != 4 ){
		Status.progress( '.' );
		return;
	} 

	if( revertXML.status != 200 ){
		Status.error( 'Bad status , bailing out' );
		return;
	}

	contentDoc = revertXML.responseXML.documentElement;
	if( !contentDoc ) {
		Status.error( 'Failed to recieve revision to revert to, will abort.');
		return;
	}

	Status.status( 'Grabbing edit form' );

	revertXML = sajax_init_object();
	revertXML.overrideMimeType('text/xml');
	revertXML.onreadystatechange = revertCallback3;

	var query = {
		'title': wgPageName,
		'action': 'submit'
	};

	Status.debug( 'query:' + query.toSource() );

	revertXML.open( 'GET' , wgServer + wgScriptPath + '/index.php?' + QueryString.create( query ), true );
	revertXML.send( null );
}

function revertCallback3() {
	if ( revertXML.readyState != 4 ){
		Status.progress( '.' );
		return;
	} 

	if( revertXML.status != 200 ){
		Status.error( 'Bad status , bailing out' );
		return;
	}

	Status.status( 'Updating the textbox...' );

	var doc = revertXML.responseXML;

	var form = doc.getElementById( 'editform' );
	Status.debug( 'editform: ' + form );
	if( !form ) {
		Status.error( 'couldn\'t grab element "editform", aborting, this could indicate failed respons from the server' );
		return;
	}
	form.style.display = 'none';


	var content = contentDoc.getElementsByTagName('rev')[0];
	if( !content ) {
		Status.error( 'we recieved no revision, something is wrong, bailing out!' );
		return;
	}

	var textbox = doc.getElementById( 'wpTextbox1' );

	textbox.value = "";

	var cn =  content.childNodes;

	for( var i in cn ) {
		textbox.value += cn[i].nodeValue ? cn[i].nodeValue : '';
	}

	Status.status( 'Updating the summary...' );
	var summary;



	switch( type ) {
		case 'agf':
		summary = "Reverted [[WP:AGF|good faith]] edits by [[Special:Contributions/" + vandal + "|" + vandal + "]] per policy concerns. Please read up on [[WP:POL#Key_policies|policies and guidelines]]. Thanks!" + ( TwinkleConfig.addAdToSummary ? ' [[WP:TWINKLE|TWINKLE]]' : '');
		break;
		case 'vand':
		summary = "Reverted " + nbrOfRevisions + " edit" + ( nbrOfRevisions > 1 ? "s" : '' ) + " by [[Special:Contributions/" + vandal + "|" + vandal + "]] identified as [[WP:VAND|vandalism]] to last revision by [[User:" + goodRev.getAttribute( 'user' ) + "|" + goodRev.getAttribute( 'user' ) + "]]." + ( TwinkleConfig.addAdToSummary ? ' [[WP:TWINKLE|TWINKLE]]' : '');
		break;
		case 'norm':
		summary = "Reverted " + nbrOfRevisions + " edit" + ( nbrOfRevisions > 1 ? "s" : '' ) + " by [[Special:Contributions/" + vandal + "|" + vandal + "]]  to last revision by  [[User:" + goodRev.getAttribute( 'user' ) + "|" + goodRev.getAttribute( 'user' ) + "]]." + ( TwinkleConfig.addAdToSummary ? ' [[WP:TWINKLE|TWINKLE]]' : '');
	}
	doc.getElementById( 'wpSummary' ).value = summary;
	doc.getElementById( 'wpMinoredit' ).checked = true;
	doc.getElementById( 'wpWatchthis' ).checked = ( TwinkleConfig.watchRevertedPages.indexOf( type ) != -1 );

	Status.status( [ 'Open user talk page edit form for user ', htmlNode( 'strong', vandal ) ]);

	var opentalk = true;

	if( TwinkleConfig.openTalkPage.indexOf( type ) != -1 ) {

		if( isIPAddress( vandal ) ) {
			Status.info( [ htmlNode( 'strong', vandal ), ' is an ip-address, checking if it\'s inside the AOL range' ] );

			if( AOLNetworks.some( function( net ) { return isInNetwork( vandal, net ) } )) {
				if( TwinkleConfig.openAOLAnonTalkPage ) {
					Status.info( [ htmlNode( 'strong', vandal ), ' is an AOL address. Per configuration, we will open talk page anyway' ] );
				} else {
					Status.warn( [ htmlNode( 'strong', vandal ), ' is an AOL address. will not open a edit form for the user talk page because AOL addresses are randomly assigned' ] );
					opentalk = false;
				}
			} else {
				Status.info( [ htmlNode( 'strong', vandal ), ' is an normal ip-address, opening user talk page' ] );
			}

		}

		if( opentalk ) {
			var query = {
				'title': 'User talk:' + vandal,
				'action': 'edit',
				'vanarticle': wgPageName.replace(/_/g, ' '),
				'vanarticlerevid': wgCurRevisionId,
				'vanarticlegoodrevid': goodRev.getAttribute( 'revid' ),
				'type': type,
				'count': nbrOfRevisions
			}

			Status.debug( 'query:' + query.toSource() );

			switch( TwinkleConfig.userTalkPageMode ) {
				case 'tab':
				window.open( wgServer + wgScriptPath + '/index.php?' + QueryString.create( query ), '_tab' );
				break;
				case 'blank':
				window.open( wgServer + wgScriptPath + '/index.php?' + QueryString.create( query ), '_blank', 'location=no,toolbar=no,status=no,directories=no,scrollbars=yes,width=1200,height=800' );
				break;
				case 'window':
				default :
				window.open( wgServer + wgScriptPath + '/index.php?' + QueryString.create( query ), 'twinklewarnwindow', 'location=no,toolbar=no,status=no,directories=no,scrollbars=yes,width=1200,height=800' );
				break;
			}
		}
	}

	document.getElementById('globalWrapper').appendChild( form );

	Status.status( 'Submitting the form...' );
	form.submit();
}

function revertToRevision( oldrev ) {

	try {
		Status.init( document.getElementById('bodyContent') );

		revertXML = sajax_init_object();
		revertXML.overrideMimeType('text/xml');

		var query = {
			'action': 'query',
			'prop': 'revisions',
			'titles': wgPageName,
			'rvlimit': 1,
			'rvstartid': oldrev,
			'rvprop': [ 'timestamp', 'user', 'comment', 'content' ],
			'format': 'xml'
		}

		Status.status( 'Querying revision' );
		revertXML.onreadystatechange = revertToRevisionCallback;
		revertXML.open( 'GET' , wgServer + wgScriptPath + '/api.php?' + QueryString.create( query ), true );
		revertXML.send( null );
	} catch(e) {
		if( e instanceof Exception ) {
			Status.error( 'Error: ' + e.what() );
		} else {
			Status.error( 'Error: ' + e );
		}
	}

}

function revertToRevisionCallback() {
	if ( revertXML.readyState != 4 ){
		Status.progress( '.' );
		return;
	} 

	if( revertXML.status != 200 ){
		Status.error( 'Bad status , bailing out' );
		return;
	}

	contentDoc = revertXML.responseXML.documentElement;

	Status.status( 'Grabbing edit form' );

	revertXML = sajax_init_object();
	revertXML.overrideMimeType('text/xml');
	revertXML.onreadystatechange = revertToRevisionCallback2;
	revertXML.open( 'GET' , wgServer + wgScriptPath + '/index.php?' + QueryString.create( { 'title': wgPageName, 'action': 'submit' } ), true );
	revertXML.send( null );
}

function revertToRevisionCallback2() {
	if ( revertXML.readyState != 4 ){
		Status.progress( '.' );
		return;
	} 

	if( revertXML.status != 200 ){
		Status.error( 'Bad status , bailing out' );
		return;
	}

	Status.status( 'Updating the textbox...' );

	var doc = revertXML.responseXML;

	var form = doc.getElementById( 'editform' );
	form.style.display = 'none';


	var content = contentDoc.getElementsByTagName('rev')[0];

	var textbox = doc.getElementById( 'wpTextbox1' );

	textbox.value = "";

	var cn =  content.childNodes;

	for( var i in cn ) {
		textbox.value += cn[i].nodeValue ? cn[i].nodeValue : '';
	}

	Status.status( 'Updating the summary...' );
	var summary = 'Reverted to revision ' + content.getAttribute( 'revid' ) + ' by [[User:' + content.getAttribute( 'user' ) + '|' + content.getAttribute( 'user' ) + ']].' + ( TwinkleConfig.addAdToSummary ? ' [[WP:TWINKLE|TWINKLE]]' : '');

	doc.getElementById( 'wpSummary' ).value = summary;
	doc.getElementById( 'wpMinoredit' ).checked = true;


	document.getElementById('globalWrapper').appendChild( form );

	Status.status( 'Submitting the form...' );
	form.submit();
};
// If TwinkleConfig aint exist.
if( typeof( TwinkleConfig ) == 'undefined' ) {
	TwinkleConfig = function() {};
}

/**
 TwinkleConfig.showSharedIPNotice may take arguments:
  true: to show shared ip notice if an IP address
  false: to not print the notice
*/
if( typeof( TwinkleConfig.showSharedIPNotice ) == 'undefined' ) {
	TwinkleConfig.showSharedIPNotice = true;
}

/**
 TwinkleConfig.addAdToSummary
 If [[WP:TWINKLE|TWINKLE]] should be added or not to summary
*/
if( typeof( TwinkleConfig.addAdToSummary ) == 'undefined' ) {
	TwinkleConfig.addAdToSummary = true;
}

function blockTagAdd( tag, summary ) {

	var duration = null;
	if( tag != 'uw-block3') {
		var duration = prompt( 'What duration is the block for?' );
	}

	var reason = prompt( 'Reason for block?' );

	var notice = '{{subst:' + tag + ( duration ? '|time=' + duration : '' ) + ( reason ? '|reason=' + reason : '' ) + '|subst=subst:}} ~~' + '~~';
	var textbox = document.getElementById( 'wpTextbox1' );
	textbox.value += "\n" + notice;
	document.getElementById( 'wpMinoredit' ).checked = true;
	document.getElementById( 'wpSummary' ).value = summary + '.' + ( TwinkleConfig.addAdToSummary ? ' [[WP:TWINKLE|TWINKLE]]' : '');

	
}

function tagadd( tag , summary) {
	var article;

	if( QueryString.exists( 'vanarticle' ) ) {
		article = decodeURI(QueryString.get( 'vanarticle' )).replace( /^(Image|Category):/i, ':$1:' );
	} else {
		article = prompt('Which article?').replace( /^(Image|Category):/i, ':$1:' );
	}

	var textbox = document.getElementById( 'wpTextbox1' );

	if ( textbox.value.length > 0 ) {
		textbox.value += '\n';
	}

	var date = new Date();
	var notice = "";
	var header = "";

	var headerRe = new RegExp( "^===\\s*" + date.getUTCMonthName() + "\\s+" + date.getUTCFullYear() + "\\s*===", 'm' );

	if( !headerRe.exec( textbox.value ) ) {
		header += "=== " + date.getUTCMonthName() + " " + date.getUTCFullYear() + " ===\n";
	}

	notice += header;
	notice += "{{subst:" + tag + ( article ? '|' + article : '' ) + "|subst=subst:}} ~~" + "~~";
	if ( TwinkleConfig.showSharedIPNotice && isIPAddress( wgTitle ) ) {
		switch( QueryString.get( 'type' ) ) {
			case 'vand':
			notice +=  "\n:''If this is a shared [[IP address]], and you didn't make any [[Wikipedia:vandalism|unconstructive]] edits, please ignore this warning '' ";
			break;
			default:
			notice +=  "\n:''If this is a shared [[IP address]], and you didn't make the edit, please ignore this notice'' ";
			break;
		}
	}

	textbox.value += "\n" + notice;
	document.getElementById( 'wpSummary' ).value = summary + ( article ? ' on [[' + article + ']]'  : '' ) + '.' + ( TwinkleConfig.addAdToSummary ? ' [[WP:TWINKLE|TWINKLE]]' : '');
	document.getElementById( 'wpMinoredit' ).checked = true;
}

//Quick warning tabs
function add_warn_tabs() 
{ 
	var tabs = document.getElementById('p-cactions').getElementsByTagName('ul')[0];

	if ( wgNamespaceNumber == 3 && ( QueryString.equals( 'action', 'edit' ) || QueryString.equals( 'action', 'submit' ) ) ) {

		addlimenu(tabs, '[1]', 'generalnotefunc');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-vandalism1", "General note: Vandalism")', 'Vandalism', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-delete1", "General note: Page blanking, removal")', 'Page blanking, removal', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-test1", "General note: Tests")', 'Editing tests', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-upv1", "General note: Userpage vandalism")', 'Userpage vandalism', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-tpv1", "General note: Talkpage vandalism")', 'Talkpage vandalism', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-error1", "General note: Factual errors")', 'Factual errors', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-mos1", "General note: Manual of style")', 'Manual of style', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-agf1", "General note: Assume good faith")', 'AGF', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-npa1", "General note: Personal attack")', 'Personal attack', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-defamatory1", "General note: Defamatory")', 'Defamation', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-joke1", "General note: Improper humour")', 'Improper humour', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-biog1", "General note: Negative bio")', 'Negative bio', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-npov1", "General note: NPOV")', 'NPOV', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-spam1", "General note: Spam")', 'Spam', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-copyright1", "General note: Copyright")', 'Copyright', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-creation1", "General note: Creation")', 'Creation', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-image1", "General note: Image")', 'Image', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-notcensored1", "General note: Censorship")', 'Censorship', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-unsourced1", "General note: Unsourced")', 'Unsourced', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-move1", "General note: Moves")', 'Moves', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-afd1", "General note: Removing {{"+"afd}} templates")', 'Afd', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-speedy1", "General note: Removing {{"+"speedy deletion}} templates")', 'Speedy', '');
		addPortletLink('generalnotefunc', 'javascript:tagadd("uw-legal1", "General note: Legal threat")', 'Legal threat', '');

		addlimenu(tabs, '[2]', 'cautionfunc');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-vandalism2", "Caution: Vandalism")', 'Vandalism', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-delete2", "Caution: Page blanking, removal")', 'Page blanking, removal', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-test2", "Caution: Tests")', 'Editing tests', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-upv2", "Caution: Userpage vandalism")', 'Userpage vandalism', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-tpv2", "Caution: Talkpage vandalism")', 'Talkpage vandalism', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-error2", "Caution: Factual errors")', 'Factual errors', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-mos2", "Caution: Manual of style")', 'Manual of style', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-agf2", "Caution: Assume good faith")', 'AGF', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-npa2", "Caution: Personal attack")', 'Personal attack', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-defamatory2", "Caution: Defamatory")', 'Defamation', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-joke2", "Caution: Improper humour")', 'Improper humour', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-biog2", "Caution: Negative bio")', 'Negative bio', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-npov2", "Caution: NPOV")', 'NPOV', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-spam2", "Caution: Spam")', 'Spam', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-copyright2", "Caution: Copyright")', 'Copyright', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-creation2", "Caution: Creation")', 'Creation', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-image2", "Caution: Image")', 'Image', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-notcensored2", "Caution: Censorship")', 'Censorship', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-unsourced2", "Caution: Unsourced")', 'Unsourced', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-move2", "Caution: Moves")', 'Moves', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-afd2", "Caution: Removing {{"+"afd}} templates")', 'Afd', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-speedy2", "Caution: Removing {{"+"speedy deletion}} templates")', 'Speedy', '');
		addPortletLink('cautionfunc', 'javascript:tagadd("uw-legal2", "Caution: Legal threat")', 'Legal threat', '');

		addlimenu(tabs, '[3]', 'warningfunc');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-vandalism3", "Warning: Vandalism")', 'Vandalism', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-delete3", "Warning: Page blanking, removal")', 'Page blanking, removal', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-test3", "Warning: Tests")', 'Editing tests', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-upv3", "Warning: Userpage vandalism")', 'Userpage vandalism', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-tpv3", "Warning: Talkpage vandalism")', 'Talkpage vandalism', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-error3", "Warning: Factual errors")', 'Factual errors', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-mos3", "Warning: Manual of style")', 'Manual of style', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-agf3", "Warning: Assume good faith")', 'AGF', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-npa3", "Warning: Personal attack")', 'Personal attack', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-defamatory3", "Warning: Defamatory")', 'Defamation', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-joke3", "Warning: Improper humour")', 'Improper humour', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-biog3", "Warning: Negative bio")', 'Negative bio', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-npov3", "Warning: NPOV")', 'NPOV', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-spam3", "Warning: Spam")', 'Spam', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-copyright3", "Warning: Copyright")', 'Copyright', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-creation3", "Warning: Creation")', 'Creation', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-image3", "Warning: Image")', 'Image', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-notcensored3", "Warning: Censorship")', 'Censorship', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-unsourced3", "Warning: Unsourced")', 'Unsourced', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-move3", "Warning: Moves")', 'Moves', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-afd3", "Warning: Removing {{"+"afd}} templates")', 'Afd', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-speedy3", "Warning: Removing {{"+"speedy deletion}} templates")', 'Speedy', '');
		addPortletLink('warningfunc', 'javascript:tagadd("uw-legal3", "Warning: Legal threat")', 'Legal threat', '');

		addlimenu(tabs, '[4]', 'fwarningfunc');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-vandalism4", "Final warning: Vandalism")', 'Vandalism', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-vandalism4im", "Only warning: Vandalism")', 'Vandalism (im)', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-delete4", "Final warning: Page blanking, removal")', 'Page blanking, removal', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-delete4im", "Only warning: Page blanking, removal")', 'Page blanking, removal (im)', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-npa4", "Final warning: Personal attack")', 'Personal attack', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-npa4im", "Only warning: Personal attack")', 'Personal attack (im)', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-defamatory4", "Final warning: Defamatory")', 'Defamation', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-defamatory4im", "Only warning: Defamatory")', 'Defamation (im)', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-joke4", "Final warning: Improper humour")', 'Improper humour', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-biog4", "Final warning: Negative bio")', 'Negative bio', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-npov4", "Final warning: NPOV")', 'NPOV', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-spam4", "Final warning: Spam")', 'Spam', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-spam4im", "Only warning: Spam")', 'Spam (im)', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-copyright4", "Final warning: Copyright")', 'Copyright', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-creation4", "Final warning: Creation")', 'Creation', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-image4", "Final warning: Image")', 'Image', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-image4im", "Only warning: Image")', 'Image (im)', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-move4", "Final warning: Moves")', 'Moves', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-afd4", "Final Warning: Removing {{"+"afd}} templates")', 'Afd', '');
		addPortletLink('fwarningfunc', 'javascript:tagadd("uw-speedy4", "Final Warning: Removing {{"+"speedy deletion}} templates")', 'Speedy', '');

		addlimenu(tabs, '[S]', 'singlefunc');
		addPortletLink('singlefunc', 'javascript:tagadd("uw-3rr", "in danger of violating the [[WP:3RR|three-revert rule]]")', '3RR', '');

		if( userIsInGroup( 'sysop' ) ) {
			addlimenu(tabs, '[B]', 'blockfunc');
			addPortletLink('blockfunc', 'javascript:blockTagAdd("uw-block1", "You have been blocked")', 'Level 1', '');
			addPortletLink('blockfunc', 'javascript:blockTagAdd("uw-block2", "You have been blocked")', 'Level 2', '');
			addPortletLink('blockfunc', 'javascript:blockTagAdd("uw-block3", "You have been indefinitely blocked")', 'Level 3', '');
		}
	}
}
addOnloadHook(add_warn_tabs);;
//Status.debugLevel = 1;

/**
* Last diff tab, show difference between last revision and the one before
*/
function lastdiff() 
{
	if( wgNamespaceNumber >= 0 ) {
		var query = {
			'title': wgPageName,
			'diff': 'cur',
			'oldid': 'prev'
		};
		var l = addPortletLink('p-cactions', wgServer + wgScriptPath + '/index.php?' + QueryString.create( query ), 'last', '' );
		l.lastChild.title="Show most recent diff";
	}
}
addOnloadHook(lastdiff);

var dataXML;
var ntitle;
var me;

function diffSincePrevUserButton() { 
	if( wgNamespaceNumber < 0 ) {
		return;
	}

	if( !QueryString.exists( 'diff' ) ) {
		// Not diff page
		return;
	} 

	ntitle = getElementsByClassName( document.getElementById('bodyContent'), 'td' , 'diff-ntitle' )[0];

	if( !ntitle ) {
		// Nothing to see here, move along...
		return;
	}

	var l = addPortletLink('p-cactions', "javascript:diffSincePrevUserInit(false);", 'since', '' );
	l.lastChild.title="Show difference between last diff and the revision made by previous user";

	var l = addPortletLink('p-cactions', "javascript:diffSincePrevUserInit(true);", 'since mine', '' );
	l.lastChild.title="Show difference between last diff and my last revision";
}
addOnloadHook(diffSincePrevUserButton);

function diffSincePrevUserInit(me) {
	try {
		Status.init( document.getElementById('bodyContent') );
		var rev = wgCurRevisionId;
		var user;
		if( me ) {
			Status.debug( '"me" is choosen' );
			user = wgUserName;
		} else if( vandal ) { 
			Status.debug( 'vandal ' + vandal + ' already defined' );
			// twinklefluff or simlar have already parsed this thingi
			user = vandal;
		} else {
			Status.debug( 'testing 3:rd element' );
			user = ntitle.getElementsByTagName('a')[3].firstChild.nodeValue;
			Status.debug( '3:rd element: ' + user );
			if( user == 'Current revision' ) {
				Status.debug( 'testing 6:th element' );
				user = ntitle.getElementsByTagName('a')[6].firstChild.nodeValue;
				Status.debug( '6:th element: ' + user );
			}
		}

		diffSincePrevUser( user, rev, me );
	} catch(e) {
		if(e.what){
			alert(e.what())
		} else {
			alert(e);
		}
	}
}

function diffSincePrevUser( user, rev, pMe ) {

	me = pMe;
	dataXML = sajax_init_object();

	dataXML.overrideMimeType('text/xml');

	var query = {
		'prop': 'revisions',
		'format': 'xml',
		'action': 'query',
		'titles': wgPageName,
		'rvlimit': 50,
		'rvprop': 'user',
		'rvendid': wgCurRevisionId
	};

	Status.debug( "Query string:" + QueryString.create( query ), 1 );
	Status.status( 'Querying revisions' );

	dataXML.open( 'GET', wgServer + wgScriptPath + "/api.php?" + QueryString.create( query ) , true );

	dataXML.onreadystatechange = function() {
		if ( dataXML.readyState != 4 ){
			Status.progress('.');		
			return;
		} 

		if( dataXML.status != 200 ){
			Status.error('Bad status , bailing out');		
			return;
		}
		Status.progress(' Done.');		

		var doc = dataXML.responseXML.documentElement;
		var revisions = doc.getElementsByTagName('rev');
		Status.debug( 'length: ' + revisions.length, 1 );

		var curNode = revisions[0];

		Status.debug( 'curNode: ' + curNode, 1 );
		Status.debug( 'user: ' + user, 1 );
		Status.debug( "rev: " + rev, 1 );

		var last = null;

		Status.status( 'Finding last revision made by user...' );

		while( curNode != null ) {
			Status.debug( 'curNode: ' + curNode.getAttribute( 'revid' ), 1 );


			if( me ) {
				if( curNode.getAttribute( 'revid' ) < rev && curNode.getAttribute( 'user' ) == user ) {
					Status.debug( "found rev and user", 1 );
					last = curNode.getAttribute( 'revid' );
					break;
				} 
			} else {
				if( curNode.getAttribute( 'revid' ) < rev && curNode.getAttribute( 'user' ) != user ) {
					Status.debug( "found rev and user", 1 );
					last = curNode.getAttribute( 'revid' );
					break;
				} 
			}
			curNode = curNode.nextSibling;
		}

		if( last == null ) {
			Status.error( [ 'No previos revision found, or ', user , ' is only contributor ' ] );
			return;
		}

		var query = {
			'title': wgPageName,
			'oldid': last,
			'diff': rev
		};

		window.location = wgServer + wgScriptPath + '/index.php?' + QueryString.create( query );

	};
	dataXML.send( null );

};
// If TwinkleConfig aint exist.
if( typeof( TwinkleConfig ) == 'undefined' ) {
	TwinkleConfig = function() {};
}

/**
TwinkleConfig.addAdToSummary
If [[WP:TWINKLE|TWINKLE]] should be added or not to summary
*/
if( typeof( TwinkleConfig.addAdToSummary ) == 'undefined' ) {
	TwinkleConfig.addAdToSummary = true;
}

/**
TwinkleConfig.addAdToDeletionSummary
If [[WP:TWINKLE|TWINKLE]] should be added or not to the deletion summary (admin only)
*/
if( typeof( TwinkleConfig.addAdToDeletionSummary ) == 'undefined' ) {
	TwinkleConfig.addAdToDeletionSummary = true;
}

/**
TwinkleConfig.watchSpeedyPages (array)
What types of actions that should result in forced addition to watchlist
*/
if( typeof( TwinkleConfig.watchSpeedyPages ) == 'undefined' ) {
	TwinkleConfig.watchSpeedyPages = [ 'g3', 'g5', 'g10', 'g11', 'g12' ];
}

/**
TwinkleConfig.deleteTalkPageOnDelete
If talk page if exists should also be deleted (CSD G8) when spedying a page (admin only)
*/
if( typeof( TwinkleConfig.deleteTalkPageOnDelete ) == 'undefined' ) {
	TwinkleConfig.deleteTalkPageOnDelete = false;
}

function twinkleSpeedyDelete() {
	if( wgNamespaceNumber < 0 || wgCurRevisionId == false ) {
		return;
	}
	if( userIsInGroup( 'sysop' ) ) {
		addPortletLink('p-cactions', "javascript:twinklespeedy( 'csd' )", "db (csd)", "ca-db0", "Speedy delete according to WP:CSD", "");
		addPortletLink('p-cactions', "javascript:twinklespeedy( 'reason' )", "db (reason)", "ca-db0", "Speedy deletion with reason", "");
	} else {
		addPortletLink('p-cactions', "javascript:twinklespeedy( 'csd' )", "db (csd)", "ca-db0", "Request speedy deletion according to WP:CSD", "");
		addPortletLink('p-cactions', "javascript:twinklespeedy( 'reason' )", "db (reason)", "ca-db0", "Request speedy deletion with reason", "");
	}	
}
addOnloadHook(twinkleSpeedyDelete);

function twinklespeedy( type ) {
	twinklespeedy.type = type;
	switch( type ) {
		case 'csd':
		twinklespeedy.Window = new SimpleWindow( 800, 400 );
		twinklespeedy.Window.setTitle( "Choose criteria for speedy deletion" );

		function createOption( value, text ) {
			var div = document.createElement( 'div' );
			var input = document.createElement( 'input' );
			input.value = value;
			input.name = 'csd';
			input.id = 'wp' + value;
			input.type = 'radio';
			var label = document.createElement( 'label' );
			label.setAttribute( 'for', value );
			label.appendChild( document.createTextNode( text ) );
			div.appendChild( input );
			div.appendChild( label );

			return div;
		}
		var form = document.createElement( 'form' );
		form.addEventListener( 'change', twinklespeedy.csd, true );
		form.appendChild( createOption( 'nonsense', 'G1: Patent nonsense.' ) );
		form.appendChild( createOption( 'test', 'G2: Test page.' ) );
		form.appendChild( createOption( 'vandalism', 'G3: Vandalism.' ) );
		form.appendChild( createOption( 'pagemove', 'G3: Nonsense redirects that are created from the cleanup of page move vandalism.' ) );
		form.appendChild( createOption( 'repost', 'G4: Copies of material that was previously deleted after an XfD discussion.' ) );
		form.appendChild( createOption( 'banned', 'G5: Contributions made by a banned user.' ) );
		form.appendChild( createOption( 'histmerge', 'G6: History merge.' ) );
		form.appendChild( createOption( 'move', 'G6: Making way for a noncontroversial move.' ) );
		form.appendChild( createOption( 'afd', 'G6: An admin has closed an Articles for deletion debate as a "delete".' ) );
		form.appendChild( createOption( 'g6', 'G6: Other non-controversial "housekeeping" tasks' ) );
		form.appendChild( createOption( 'author', 'G7: Speedy request by only editor.' ) );
		form.appendChild( createOption( 'blanked', 'G7: Page blanked by only editor.' ) );
		form.appendChild( createOption( 'talk', 'G8: Talk page of a deleted or nonexistent page.' ) );
		form.appendChild( createOption( 'attack', 'G10: Attack page intended to disparage its subject.' ) );
		form.appendChild( createOption( 'spam', 'G11: Pages that exist only to promote a company, product, or service.' ) );
		form.appendChild( createOption( 'copyvio', 'G12: Blatant copyright violation.' ) );
		form.appendChild( document.createElement( 'hr' ) );
		form.appendChild( createOption( 'nocontext', 'A1: Very short articles without context.' ) );
		form.appendChild( createOption( 'foreign', 'A2: Foreign language article duplicated on other Wikimedia project.' ) );
		form.appendChild( createOption( 'nocontent', 'A3: No content other than external links of whatever kind, or an attempt to contact subject of article.' ) );
		form.appendChild( createOption( 'transwiki', 'A5: Transwikification completed.' ) );
		form.appendChild( createOption( 'bio', 'A7: Non-notable biography / article about a person, group, company, or website that does not assert the notability of the subject.' ) );
		form.appendChild( document.createElement( 'hr' ) );
		form.appendChild( createOption( 'redirnone', 'R1: Redirect to non-existent page.' ) );
		form.appendChild( createOption( 'rediruser', 'R2: Redirect to user page.' ) );
		form.appendChild( createOption( 'redirtypo', 'R3: Redirect that is a result of an implausible typo.' ) );
		form.appendChild( document.createElement( 'hr' ) );
		form.appendChild( createOption( 'redundantimage', 'I1: Same or better image exists on Wikipedia (not for now on Commons).' ) );
		form.appendChild( createOption( 'noimage', 'I2: Corrupt or empty image.' ) );
		form.appendChild( createOption( 'noncom', 'I3: "No commercial use" or "by permission" images uploaded after target date.' ) );
		form.appendChild( createOption( 'unksource', 'I4: Lack of licensing.' ) );
		form.appendChild( createOption( 'unfree', 'I5: Unused copyright image.' ) );
		form.appendChild( createOption( 'norat', 'I6: Image with fair use tag but no fair use rationale.' ) );
		form.appendChild( createOption( 'badfairuse', 'I7: Bad fair use rationale - image tagged for fair use under a rationale that is patently irrelevant to the actual image.' ) );
		form.appendChild( createOption( 'nowcommons', 'I8: Images available as bit-for-bit identical copies on the Wikimedia Commons,' ) );
		form.appendChild( document.createElement( 'hr' ) );
		form.appendChild( createOption( 'catempty', 'C1: Category that is empty for at least four days and has never contained anything other than links to parent categories.' ) );
		form.appendChild( createOption( 'catfd', 'C3: Category that is used solely by a template that has been deleted.' ) );
		form.appendChild( document.createElement( 'hr' ) );
		form.appendChild( createOption( 'userreq', 'U1: User\'s subpage requested to be deleted by the user with whom it is associated.' ) );
		form.appendChild( createOption( 'nouser', 'U2: Userpages of users who do not exist.' ) );
		form.appendChild( document.createElement( 'hr' ) );
		form.appendChild( createOption( 'disparage', 'T1: Templates that are divisive and inflammatory.' ) );
		form.appendChild( document.createElement( 'hr' ) );
		form.appendChild( createOption( 'emptyportal', 'P2: Underpopulated portal.' ) );


		twinklespeedy.Window.setContent( form );
		twinklespeedy.Window.display();

		break;
		case 'reason':
		var criteria = prompt( "Enter reason for speedy deletion" );
		if( !criteria ) {
			return; // User abort action
		}
		if( userIsInGroup( 'sysop' ) ) {
			twinklespeedy.summary = "Speedy deletion, with reason: " + criteria + "." + ( TwinkleConfig.addAdToDeletionSummary ? ' [[WP:TWINKLE|TWINKLE]].' : '');
		} else {
			twinklespeedy.summary = "Requesting speedy deletion." + ( TwinkleConfig.addAdToSummary ? ' [[WP:TWINKLE|TWINKLE]]' : '');
		}
		twinklespeedy.code = "{{d" + "b" + ( criteria ? '|' + criteria : '' ) + "}}";
		Status.init( document.getElementById('bodyContent') );

		Status.status( 'Grabbing page' );

		editXML = sajax_init_object();
		editXML.overrideMimeType('text/xml');
		if( userIsInGroup( 'sysop' ) ) {
			editXML.open( 'GET' , wgServer + wgScriptPath + '/index.php?' + QueryString.create( { 'title': wgPageName, 'action': 'delete' } ), true);
		} else {
			editXML.open( 'GET' , wgServer + wgScriptPath + '/index.php?' + QueryString.create( { 'title': wgPageName, 'action': 'submit' } ), true);
		}
		editXML.onreadystatechange = twinklespeedyCallback;
		editXML.send( null );
		break;
	}
}
twinklespeedy.csd = function(e) {
	var convarr = {
		'nonsense': 'g1',
		'test': 'g2',
		'vandalism': 'g3',
		'pagemove': 'g3',
		'repost': 'g4',
		'banned': 'g5',
		'histmerge': 'g6',
		'move': 'g6',
		'afd': 'g6',
		'g6': 'g6',
		'author': 'g7',
		'blanked': 'g7',
		'talk': 'g8',
		'attack': 'g10',
		'spam': 'g11',
		'copyvio': 'g12',
		'nocontext': 'a1',
		'foreign': 'a2',
		'nocontent': 'a3', 
		'transwiki': 'a5',
		'bio': 'a7',
		'redirnone': 'r1',
		'rediruser': 'r2',
		'redirtypo': 'r3',
		'redundantimage': 'i1',
		'noimage': 'i2',
		'noncom': 'i3',
		'unksource': 'i4',
		'unfree': 'i5',
		'norat': 'i6',
		'badfairuse': 'i7',
		'nowcommons': 'i8',
		'catempty': 'c1',
		'catfd': 'c3',
		'userreq': 'u1',
		'nouser': 'u2',
		'disparage': 't1',
		'emptyportal': 'p2'
	};
	var reasarr = {
		'nonsense': 'was patent nonsense',
		'test': 'was a test page',
		'vandalism': 'was pure vandalism',
		'pagemove': 'was a nonsense redirect that where created as a byproduct after a cleanup of pagemove',
		'repost': 'was a copy of material previously deleted per XfD',
		'banned': 'was a contribution was made by a banned user',
		'histmerge': 'merging of history',
		'move': 'making way for a non-controversial move',
		'afd': 'deleting page per result of AfD',
		'g6': 'non-controversial housekeeping',
		'author': 'only editor requested deletion',
		'blanked': 'only editor has blanked the page',
		'talk': 'was a talk page of deleted or nonexistent page',
		'attack': 'was a attack page intented to disparage it\'s subject',
		'spam': 'page existed only to promote',
		'copyvio': 'was a blatant copyright violation',
		'nocontext': 'was a very short article without context',
		'foreign': 'was a foreign language page',
		'nocontent': 'had no content except for eventual external links or contact information', 
		'transwiki': 'completed transwikification',
		'bio': 'was a non-notable biography / article about a person, group, company, or website that does not assert the notability of the subject',
		'redirnone': 'was a redirect to an non-existent page',
		'rediruser': 'was a redirect to an user',
		'redirtypo': 'was a redirect based on an implausible typo',
		'redundantimage': 'same or better image exists on Wikipedia',
		'noimage': 'was a corrupt or empty image',
		'noncom': 'was an image with non-comercial use only restriction and uploaded after target date',
		'unksource': 'was an image lacking sources',
		'unfree': 'an unfree image that hasn\'t been used for more than seven days',
		'norat': 'was an image with fair use tag but no fair use rationale',
		'badfairuse': 'was an image with bad fair use rationale',
		'nowcommons': 'was an image that an bit-to-bit copy exists on wikimedia commons',
		'catempty': 'was an empty category',
		'catfd': 'was an category with sole purpouse been used by a now deleted template',
		'userreq': 'was a userpage, and it\'s user requested deletion',
		'nouser': 'was a userpage without any user',
		'disparage': 'was an divisive and inflammatory template',
		'emptyportal': 'was an underpopulated portal'
	};

	var value = e.target.value;
	var normalized = convarr[ value ];
	twinklespeedy.watch = TwinkleConfig.watchSpeedyPages.indexOf( normalized ) != -1;
	var reason = reasarr[ value ];
	if( userIsInGroup( 'sysop' ) ) {
		twinklespeedy.summary = "Speedy deleted per ([[WP:CSD#" + normalized + "|CSD " + normalized + "]]), " + reason + "." + ( TwinkleConfig.addAdToDeletionSummary ? ' [[WP:TWINKLE|TWINKLE]]' : '');
	} else {
		twinklespeedy.summary = "Requesting speedy deletion ([[WP:CSD#" + normalized + "|CSD " + normalized + "]])." + ( TwinkleConfig.addAdToSummary ? ' [[WP:TWINKLE|TWINKLE]]' : '');
		switch( normalized ) {
			case 'i8':
			var date = new Date();
			twinklespeedy.code = "{{" + "NowCommons" + "|month=" + date.getUTCMonthName() + "|day=" + date.getUTCDate() + "|year=" + date.getUTCFullYear() + "|1=" + wgPageName.replace( '_', ' ' ) + "}}";
			break;
			case 'g12':
			url = prompt( 'please enter url if available, including the http://' );
			if( url == null ) {
				return;
			}
			twinklespeedy.code = "{{d" + "b-" +  value + "|url=" + url + "}}";
			break;
			case 'i1':
			img = prompt( 'enter the image this is redundant to, excluding the Image: prefix' );
			if( img == null ) {
				return;
			}
			twinklespeedy.code = "{{d" + "b-" +  value + "|1=" + img + "}}";
			break;
			default:
			twinklespeedy.code = "{{d" + "b-" +  value + "}}";
			break;
		}
	}
	twinklespeedy.Window.close();
	Status.init( document.getElementById('bodyContent') );

	Status.status( 'Grabbing page' );

	editXML = sajax_init_object();
	editXML.overrideMimeType('text/xml');

	if( userIsInGroup( 'sysop' ) ) {
		editXML.open( 'GET' , wgServer + wgScriptPath + '/index.php?' + QueryString.create( { 'title': wgPageName, 'action': 'delete' } ), true);
	} else {
		editXML.open( 'GET' , wgServer + wgScriptPath + '/index.php?' + QueryString.create( { 'title': wgPageName, 'action': 'submit' } ), true);
	}
	editXML.onreadystatechange = twinklespeedyCallback;
	editXML.send( null );
}


function twinklespeedyCallback() {
	if ( editXML.readyState != 4 ){
		Status.progress('.');		
		return;
	} 

	if( editXML.status != 200 ){
		Status.error('Bad status , bailing out');		
		return;
	}

	Status.progress(' Done');

	// when we grabbed the page, it wasn't there
	if( editXML.responseText.indexOf( 'var wgCurRevisionId = false;' ) != -1 ) {
		Status.error( "It seems that the page doesn't exists, perhaps it has already been deleted'" );
		return;
	}

	var doc = editXML.responseXML;
	var form;

	if( userIsInGroup( 'sysop' ) ) {
		Status.status( 'Deleting page...' );

		form = doc.getElementById( 'deleteconfirm' );
		form.style.display = 'none';

		doc.getElementById( 'wpReason' ).value = twinklespeedy.summary;
		if( twinklespeedy.watch ) {
			doc.getElementById( 'wpWatch' ).checked = true;
		}

		if( TwinkleConfig.deleteTalkPageOnDelete && wgNamespaceNumber % 2 == 0 && document.getElementById( 'ca-talk' ).className != 'new' ) {
			var talk_page = namespaces[ wgNamespaceNumber  + 1 ] + ':' + wgTitle;
			var query = {
				'title': talk_page,
				'action': 'delete'
			};
			var win_ref = window.open(  wgServer + wgScriptPath + '/index.php?' + QueryString.create( query ), 'talkpage' , 'scrollbars=yes,width=800,height=400' );
			win_ref.watch = twinklespeedy.watch;
			win_ref.ad = TwinkleConfig.addAdToDeletionSummary;
			win_ref.onload = function() {
				if( this.watch ) {
					this.document.getElementById( 'wpWatch' ).checked = true;
				}
				this.document.getElementById( 'wpReason' ).value = "Speedy deleted per ([[WP:CSD#g8|CSD g8]]), was a talk page of deleted page." + ( this.ad ? ' [[WP:TWINKLE|TWINKLE]]' : '');
				this.document.getElementById( 'deleteconfirm' ).submit();
			}
			win_ref.onsubmit = function() { this.onload = function() { this.close() } };
		}
	} else {

		form = doc.getElementById( 'editform' );
		form.style.display = 'none';

		var textbox = doc.getElementById( 'wpTextbox1' );

		var text = textbox.value;

		Status.status( 'Checking for tags on the page...' );

		var tag = /(\{\{(?:db-?|delete)\|?.*?\}\})/.exec( text );

		if( tag ) {
			Status.warn( [ htmlNode( 'strong', tag[0] ) , " is alread placed on the page." ] )
			return;
		}

		var xfd = /(\{\{(?:[aitcm]fd|md1)[^{}]*?\}\})/i.exec( text );

		if( xfd && !confirm( "The deletion related template " + xfd[0] + " is already present on the page, do you still want to revert?" ) ) {
			return;
		}

		Status.progress(' Done');

		Status.status( 'Submitting form...' );

		textbox.value = twinklespeedy.code + "\n" + textbox.value;
		doc.getElementById( 'wpSummary' ).value = twinklespeedy.summary;	
		doc.getElementById( 'wpMinoredit' ).checked = true;
		if( twinklespeedy.watch ) {
			doc.getElementById( 'wpWatchthis' ).checked = true;
		}

	}
	document.getElementById('globalWrapper').appendChild( form );
	form.submit();	

	Status.progress(' Done');
};
// If TwinkleConfig aint exist.
if( typeof( TwinkleConfig ) == 'undefined' ) {
	TwinkleConfig = function() {};
}

/**
TwinkleConfig.addAdToSummary
If [[WP:TWINKLE|TWINKLE]] should be added or not to summary
*/
if( typeof( TwinkleConfig.addAdToSummary ) == 'undefined' ) {
	TwinkleConfig.addAdToSummary = true;
}

// Twinklefluff vandalsim reporting tool
// Orignallity an updated version of ARV 2.1, but nut much code left from that day now

//Status.debugLevel = 1;
var AIVpageName = 'Wikipedia:Administrator_intervention_against_vandalism';
var section = '1';

var xmlObject;

addOnloadHook( twinkleARVBase );
function twinkleARVBase(){
	var username;


	if ( wgNamespaceNumber == 3 || wgNamespaceNumber == 2 || ( wgNamespaceNumber == -1 && wgTitle == "Contributions" )){

		// If we are on the contributions page, need to parse some then
		if( wgNamespaceNumber == -1 && wgTitle == "Contributions" ) {
			username = document.getElementById( 'contentSub' ).getElementsByTagName( 'a' )[0].getAttribute('title').split(':')[1];
		} else {
			username = wgTitle.split( '/' )[0]; // only first part before any slashes
		}

		if( !username ) {
			// Something is fishy, there was no user? lets about everything
			throw "given username was " + username + " and thus makes no sense.";
		}

		var name = 'Report';
		var title = 'Report user to AIV';

		if( isIPAddress( username ) ) {
			name = 'Report IP';
			title = 'Report IP to AIV';
		}

		var tabs = document.getElementById('p-cactions').getElementsByTagName('ul')[0];
		addlimenu(tabs, name, 'ca-report' );
		addPortletLink( 'ca-report', 'javascript:twinklearv( "' + username + '" )' , name , 'td-report', title, '' );
		addPortletLink( 'ca-report', 'javascript:twinklearv( "' + username + '", "final" )' , 'final' , 'ca-report-final', title + ' (final warning already given)', '' );
		addPortletLink( 'ca-report', 'javascript:twinklearv( "' + username + '", "postblock" )' , 'post block' , 'ca-report-postblock', title + ' (vandalism after release of block)', '' );
		addPortletLink( 'ca-report', 'javascript:twinklearv( "' + username + '", "sock" )' , 'sock puppet' , 'ca-report-sock', title + ' (Account is a sock puppet account)', '' );
		if( !isIPAddress( username ) ) {
			addPortletLink( 'ca-report', 'javascript:twinklearv( "' + username + '", "username" )' , 'username' , 'ca-report-username', title + ' (inflammatory username)', '' );
			addPortletLink( 'ca-report', 'javascript:twinklearv( "' + username + '", "vandalonly" )' , 'vandal only' , 'ca-report-vandalonly', title + ' (vandalism only account)', '' );
		}
	}
}

function twinklearv( vandal, final ){
	twinklearv.vandal = vandal;
	final = final || false;

	if( vandal == wgUserName ){
		alert( 'You don\'t want to report yourself , do you?' );
		return;
	}


	if( final ) {
		twinklearv.reason = 'Vandalism';

		if( QueryString.exists( 'vanarticle' ) ) {
			twinklearv.reason += ' on [[' + QueryString.get( 'vanarticle' ).replace( /^(Image|Category):/i, ':$1:' ) + ']]';

			if( QueryString.exists( 'vanarticlerevid' ) ) {
				var query = {
					'title': QueryString.get( 'vanarticle' ),
					'diff': QueryString.get( 'vanarticlerevid' ),
					'oldid': QueryString.exists( 'vanarticlegoodrevid' ) ? QueryString.get( 'vanarticlegoodrevid' )  : 'prev'
				};
				twinklearv.reason += '  ([' +  wgServer + wgScriptPath + '/index.php?' + QueryString.create( query ) + ' diff])';
			}
		}
		switch( final ) {
			case 'final':
			twinklearv.reason += ' after final warning.';
			break;
			case 'postblock':
			twinklearv.reason += ' after release of block.';
			break;
			case 'username':
			twinklearv.reason = 'Username may be rude ,inflammatory, unnecessarily long/confusing, too similar to an existing user, contains the name of an organization or website, or is otherwise inappropriate.';
			break;
			case 'vandalonly':
			twinklearv.reason += ', contributions indicate vandalism-only account.';
			break;
			case 'sock':
			var sock = prompt( 'Please enter the username of the sock puppeteer if possible.');
			twinklearv.reason += ', contributions indicate account as a sock puppet account' + ( sock ? ' of sock puppeteer {{userlinks|' + sock + '}}' : '' ) + '.';
		}

	} else if( !( twinklearv.reason = prompt( 'Reason:' ) ) ) {
		return;
	}

	Status.init( document.getElementById( 'bodyContent' ) );

	Status.status( "Please wait..." );
	Status.debug( 'Initiating xmlObject' );

	xmlObject = sajax_init_object();
	xmlObject.overrideMimeType('text/xml');

	if ( !xmlObject ) {
		Status.error( "Unable to open XML Request object , bailing out." );
		return false;
	}

	Status.status( "Grabbing page" );

	var query = {
		'title': AIVpageName,
		'action': 'submit',
		'section': section
	};

	xmlObject.open( 'GET' , wgServer + wgScriptPath + '/index.php?' + QueryString.create( query ), true );
	xmlObject.onreadystatechange = function() {
		var vandal = twinklearv.vandal;
		var reason = twinklearv.reason;

		if( xmlObject.readyState != 4 ) {
			Status.progress( '.' );
			return;
		}

		if( xmlObject.status != 200 ) {
			Status.error( 'Bad status. bailing out.' );
			return;
		}

		Status.progress( " Done." );

		var doc = xmlObject.responseXML;

		var form = doc.getElementById( 'editform' );
		var textbox = doc.getElementById( 'wpTextbox1' );
		var summary = doc.getElementById( 'wpSummary' );

		form.style.display = 'none';

		Status.status( 'Searching for existing report...' );

		var re = new RegExp( "\\{\\{\\s*(?:(?:[Ii][Pp])?[Vv]andal|[Uu]serlinks)\\s*\\|\\s*" + RegExp.escape( vandal, true ) + "\\s*\\}\\}" );

		var myArr;
		if( ( myArr = re.exec( textbox.value ) ) ) {
			Status.debug( 'match: ' + myArr[0] );

			Status.info( 'Report already present, will not add a new one' );
			return;
		}

		Status.progress( " Done." );

		Status.status( 'Adding new report...' );

		textbox.value += '*{{' + ( isIPAddress( vandal ) ? 'IPvandal' : 'vandal' ) + '|' + vandal + '}} - ' + reason + ' ~~' + '~~';

		summary.value = 'Reporting [[Special:Contributions/' + vandal + '|' + vandal + ']].'+ ( TwinkleConfig.addAdToSummary ? ' [[WP:TWINKLE|TWINKLE]]' : '');	

		doc.getElementById( 'wpMinoredit' ).checked = true;

		Status.progress( " Done." );

		Status.status( 'Submitting form...' );

		document.getElementById('globalWrapper').appendChild( form );
		form.submit();	

		Status.progress( " Done." );

	}
	xmlObject.send( null );
};
/*<pre>*/
/*The CSS for this to work is on the talk page.*/
function addlimenu(tabs, name, id)
{
    (na = document.createElement("a")).appendChild(document.createTextNode(name));
    na.href = "#";
    var mn = document.createElement("ul");
    (li = document.createElement("li")).appendChild(na);
    li.appendChild(mn);
    if(id) li.id = id;
    li.className = 'tabmenu';
    tabs.appendChild(li);
    return mn;  // useful because it gives us the <ul> to add <li>s to
}
/*</pre>[[Category:Wikipedia scripts]]*/;
/*<pre>*/
#p-cactions ul
{
	overflow:visible;
}

#p-cactions li
{
	border: 2px solid lightgrey;
	position: relative;
	float: left;
	-moz-border-radius-topleft: .5em;
	-moz-border-radius-topright: .5em;
}

.tabmenu ul li
{
	display: block;
	width: 100% !important;
	min-width: 10em !important;
	border: 0px;
	margin: 0px;
	padding: .1em;
	border: 1px solid #aaaaaa !important;
	border-collapse: collapse;
	text-align: center;
	background-color: #F8FCFF !important;
	white-space: nowrap !important;
}

.tabmenu ul
{
	display: none;
	width: auto;
	z-index: 2;
	position: absolute;
	top: 1em;
	margin: 0px;
	background-color: grey;
}
.tabmenu * {
	-moz-border-radius: 0px !important;
}
.tabmenu:hover ul
{
	display: block;
}

.tabmenu ul li:hover
{
	background-color: #e8ecef !important;
}
.tabmenu ul a {
	background-color: transparent !important;
}
/*</pre>*/;