ব্যবহারকারী:Pmlineditor/twinklespeedy.js

উইকিপিডিয়া, মুক্ত বিশ্বকোষ থেকে

লক্ষ্য করুন: প্রকাশ করার পর, পরিবর্তনগুলো দেখতে আপনাকে আপনার ব্রাউজারের ক্যাশে পরিষ্কার করার প্রয়োজন হতে পারে।

  • ফায়ারফক্স / সাফারি: পুনরায় লোড-এ ক্লিক করার সময় শিফট টিপে ধরে রাখুন, অথবা হয় Ctrl-F5 বা Ctrl-R টিপুন (ম্যাকে ⌘-R টিপুন)
  • গুগল ক্রোম: Ctrl-Shift-R (ম্যাকে ⌘-Shift-R) টিপুন
  • ইন্টারনেট এক্সপ্লোরার / এজ: Ctrl ধরে রাখা অবস্থায় Refresh-এ ক্লিক করুন, অথবা Ctrl-F5 টিপুন
  • অপেরা: Ctrl-F5 টিপুন।
// If TwinkleConfig aint exist.
if( typeof( TwinkleConfig ) == 'undefined' ) {
	TwinkleConfig = {};
}

/**
 TwinkleConfig.summaryAd (string)
 If ad should be added or not to summary, default [[WP:TWINKLE|TWINKLE]]
 */
if( typeof( TwinkleConfig.summaryAd ) == 'undefined' ) {
	TwinkleConfig.summaryAd = " [[WP:TW|(TW)]]";
}

/**
 TwinkleConfig.deletionSummaryAd (string)
 If ad should be added or not to deletion summary, default [[WP:TWINKLE|TWINKLE]]
 */
if( typeof( TwinkleConfig.deletionSummaryAd ) == 'undefined' ) {
	TwinkleConfig.deletionSummaryAd = " [[WP:TW|(TW)]]";
}

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

/**
 TwinkleConfig.markSpeedyPagesAsMinor (boolean)
 If, when applying speedy template to page, to mark the edit as minor, default true
 */
if( typeof( TwinkleConfig.markSpeedyPagesAsMinor ) == 'undefined' ) {
	TwinkleConfig.markSpeedyPagesAsMinor = false;
}

/**
 TwinkleConfig.markSpeedyPagesAsPatrolled (boolean)
 If, when applying speedy template to page, to mark the page as patrolled, default true
 */
if( typeof( TwinkleConfig.markSpeedyPagesAsPatrolled ) == 'undefined' ) {
	TwinkleConfig.markSpeedyPagesAsPatrolled = true;
}

/**
 TwinkleConfig.notifyUserOnSpeedyDeletionNomination (array of strings)
 What types of actions that should result that the author of the page should be notified of nomination
 */
if( typeof( TwinkleConfig.notifyUserOnSpeedyDeletionNomination ) == 'undefined' ) {
	TwinkleConfig.notifyUserOnSpeedyDeletionNomination = [ 'g1', 'g2', 'g3', 'g4', 'g10', 'g11', 'g12', 'a1', 'a2', 'a3', 'a4','a5', 'i1', 't2' ];
}

/**
 TwinkleConfig.welcomeUserOnSpeedyDeletionNotification (array of strings)
 On what types of speedy deletion notifications shall the user be welcomed
 with a {{firstarticle}} notice if his talk page has not yet been created.
 */
if( typeof( TwinkleConfig.welcomeUserOnSpeedyDeletionNotification ) == 'undefined' ) {
	TwinkleConfig.welcomeUserOnSpeedyDeletionNotification = TwinkleConfig.notifyUserOnSpeedyDeletionNomination;
}

/**
 TwinkleConfig.openUserTalkPageOnSpeedyDelete (array of strings)
 What types of actions that should result user talk page to be opened when speedily deleting (admin only)
 */
if( typeof( TwinkleConfig.openUserTalkPageOnSpeedyDelete ) == 'undefined' ) {
	TwinkleConfig.openUserTalkPageOnSpeedyDelete = [ 'g1', 'g2', 'g3', 'g4', 'g5', 'g10', 'g11', 'g12', 'a1', 'a3', 'a7', 'a9', 'a10', 'f3', 'f4', 'f5', 'f6', 'f7', 'f9', 'f11', 'u3', 't2' ];
}

/**
 TwinkleConfig.userTalkPageMode may take arguments:
 'window': open a new window, remember 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.deleteTalkPageOnDelete (boolean)
 If talk page if exists should also be deleted (QD G8) when speedying a page (admin only)
 */
if( typeof( TwinkleConfig.deleteTalkPageOnDelete ) == 'undefined' ) {
	TwinkleConfig.deleteTalkPageOnDelete = false;
}

/**
 TwinkleConfig.orphanNormalPagesOnSpeedyDelete (hash)
 Defines if all backlinks to a page should be removed.
 property 'exclude' defined actions not to orphan
 */
if( typeof( TwinkleConfig.orphanBacklinksOnSpeedyDelete ) == 'undefined' ) {
	TwinkleConfig.orphanBacklinksOnSpeedyDelete = { exclude: ['g6'], orphan:true };
}

/**
 TwinkleConfig.speedyWindowWidth (integer)
 Defines the width of the Twinkle SD window in pixels
 */
if( typeof( TwinkleConfig.speedyWindowWidth ) == 'undefined' ) {
	TwinkleConfig.speedyWindowWidth = 800;
}

/**
 TwinkleConfig.speedyWindowHeight (integer)
 Defines the height of the Twinkle SD window in pixels
 */
if( typeof( TwinkleConfig.speedyWindowHeight ) == 'undefined' ) {
	TwinkleConfig.speedyWindowHeight = 500;
}


function twinklespeedy() {
	// Disable on:
	// * special pages
	// * pages with neither a page nor local file revision
	if( wgNamespaceNumber < 0 ||
	(wgArticleId==0 && (wgNamespaceNumber!=6 || (document.getElementById("mw-imagepage-section-filehistory") && !(document.getElementById("mw-sharedupload")))))
	)  return;
	
	if( userIsInGroup( 'sysop' ) ) {
		twAddPortletLink( "javascript:twinklespeedy.callback()", "QD", "tw-csd", "Quickly delete according to WP:QD", "");
	} else if (twinkleConfigExists) {
		twAddPortletLink( "javascript:twinklespeedy.callback()", "QD", "tw-csd", "Request quick deletion according to WP:QD", "");
	}
	else
	{
		twAddPortletLink( 'javascript:alert("Your account is too new to use Twinkle.");', 'QD', 'tw-csd', 'Request quick deletion according to WP:QD', '');
	}
}
window.TwinkleInit = (window.TwinkleInit || []).concat(twinklespeedy); //schedule initializer

twinklespeedy.callback = function twinklespeedyCallback() {
	var Window = new SimpleWindow( TwinkleConfig.speedyWindowWidth, TwinkleConfig.speedyWindowHeight );
	Window.setTitle( "Choose criteria for quick deletion" );

	var form = new QuickForm( userIsInGroup( 'sysop' ) ? twinklespeedy.callback.evaluateSysop : twinklespeedy.callback.evaluateUser, 'change' );
	if( userIsInGroup( 'sysop' ) ) {
		form.append( {
				type: 'checkbox',
				list: [
					{
						label: 'Tag page only, don\'t delete',
						value: 'tag_only',
						name: 'tag_only',
						tooltip: 'If you just want to tag the page, instead of deleting it now',
						event: function( event ) {
							event.target.form.notify.disabled = ! event.target.checked;
							event.target.form.notify.checked = event.target.checked;
							event.stopPropagation();
						}
					},
					{
						label: 'unlink links to this page',
						value: 'orphan_backlinks',
						name: 'orphan_backlinks',
						tooltip: 'If you want to orphan the current page. If checked, excludes will still apply',
						event: function( event ) {
							TwinkleConfig.orphanBacklinksOnSpeedyDelete.orphan = event.target.checked;
							event.stopPropagation();
						}
					}
				]
			} );
	}

	form.append( {
			type: 'checkbox',
			list: [
				{
					label: 'Notify if possible',
					value: 'notify',
					name: 'notify',
					tooltip: 'If a notification is defined in the configuration, then notify if this is true, else no notification',
					checked: !userIsInGroup( 'sysop' ),
					disabled: userIsInGroup( 'sysop' ),
					event: function( event ) {
						event.stopPropagation();
					}
				}
			]
		}
	);
	if( wgNamespaceNumber ==  Namespace.IMAGE ) {
		form.append( {type:'header', label:'Files' } );
		form.append ( {
				type: 'radio',
				name: 'csd',
				list: [
						{ 
							label: 'I1: Prohibited image',
							value: 'prohibitedimage',
							tooltip: 'Most media uploads are not allowed on Simple English Wikipedia. They should be uploaded to Wikimedia Commons instead. There are a few exceptions to this rule. Firstly, all spoken articles should be uploaded here, as they are for local use. Secondly, there are some logos that Commons does not accept, but are needed here, for example Image:Wiki.png, which is used as the Wikipedia logo.' 
						},
	 
					]

			} );
	}

	if( wgNamespaceNumber ==  0 || wgNamespaceNumber == 1 ) {
		form.append( { type:'header', label:'Articles' } );
		form.append( {
			type: 'radio',
			name: 'csd',
			list: [
					{
						label: 'A1: Little or no meaning',
						value: 'nocontext',
						tooltip: 'Is very short and providing little or no meaning (e.g., "He is a funny man that has created Factory and the Hacienda. And, by the way, his wife is great."). Having a small amount of content is not a reason to delete if it has useful information.'
					},
					{
						label: 'A2: No content',
						value: 'nocontent',
						tooltip: 'Has no content. This includes any article consisting only of links (including hyperlinks, category tags and "see also" sections), a rephrasing of the title, and/or attempts to correspond with the person or group named by its title. This does not include disambiguation pages.'
					},
					{
						label: 'A3: Article that exists on another Wikimedia project',
						value: 'transwiki',
						tooltip: 'Has been copied and pasted from another Wikipedia: Any article or section from an article that has been copied and pasted with little or no change.'
					},
	                                {
						label: 'A4: People, groups, companies or websites that are not notable.',
						value: 'notability',
						tooltip: 'An article about a real person, group of people, band, club, company, or web content that does not say why it is important. If not everyone agrees that the subject is not notable or there has been a previous RfD, the article may not be quickly deleted, and should be discussed at RfD instead.'
					},
					{
						label: 'A5: Not written in English',
						value: 'foreign',
						tooltip: 'Any article that is not written in English. An article that is written in any other languages but English.'
					},
					{
						label: 'A6: Obvious hoax',
						value: 'hoax',
						tooltip: 'Is an obvious hoax. An article that is surely fake or impossible.'
					}
				]

		} );
	}
	if( wgNamespaceNumber ==  14 || wgNamespaceNumber == 15 ) {
		form.append( { type:'header', label: 'Categories' } );
		form.append( {
			type: 'radio',
			name: 'csd',
			list: [
					{ 
						label: 'C1: Empty categories',
						value: 'catempty',
						tooltip: '(with no articles or subcategories for at least four days) whose only content includes links to parent categories. However, this can not be used on categories still being discussed on WP:RfD, or disambiguation categories. If the category wasn\'t newly made, it is possible that it used to have articles, and more inspection is needed.'
					},
					{
						label: 'C2: Quick renaming',
						value: 'catqr',
						tooltip: 'Empty categories that have already been renamed.'
					},
					{
						label: 'C3: Template categories',
						value: 'catfd',
						tooltip: 'If a category contains articles from only one template (such as Category:Cleanup needed from \{\{cleanup\}\}) and the template is deleted after being discussed, the category can also be deleted without being discussed.'
					}
				]

		} );
	} if( wgNamespaceNumber ==  2 || wgNamespaceNumber == 3 ) {
		form.append( { type:'header', label: 'User pages' } );
		form.append( {
			type: 'radio',
			name: 'csd',
			list: [
					{
						label: 'U1: User request',
						value: 'userreq',
						tooltip: 'User pages can be deleted if its user wants to, but there are some exceptions. '
					},
					{
						label: 'U2: Non-existent user',
						value: 'nouser',
						tooltip: 'User pages of users that do not exist. Administrators should check Special:Contributions and Special:DeletedContributions.'
					},
				]

		} );
	} if( wgNamespaceNumber ==  10 || wgNamespaceNumber == 11 ) {
		form.append( { type:'header', label: 'Templates' } );
		form.append( {
			type: 'radio',
			name: 'csd',
			list: [
			       
					{ 
						label: 'T2: They are deprecated or replaced by a newer template and are completely unused and not linked to.',
						value: 'replaced'
					},
				]

		} );
	} 

	form.append( { type:'header', label:'General criteria' } );
	form.append( {
			type: 'radio',
			name: 'csd',
			list: [
					{ 
						label: 'G1: Nonsense', 
						value: 'nonsense', 
						tooltip: 'All of the text is nonsense. Nonsense includes content that does not make sense or is not meaningful. However, this does not include bad writing, bad words, vandalism, things that are fake or impossible, or parts which are not in English. ' },
					{ 
						label: 'G2: Test page',
						value: 'test',
						tooltip: 'It is a test page, such as "Can I really create a page here?".' 
					},
					{ 
						label: 'G3: Complete vandalism',
						value: 'vandalism',
						tooltip: 'The content is completely vandalism.'
					},
					{ 
						label: 'G3: Pagemove vandalism', 
						value: 'pagemove',
						tooltip: 'Nonsense redirects that are created from the cleanup of page move vandalism'
					},
					{
						label: 'G4: Recreation of deleted material already deleted at RfD',
						value: 'repost',
						tooltip: 'Creation of content that is already deleted. It includes an identical or similar copy, with any title, of a page that was deleted, after being discussed in Requests for deletion, unless it was undeleted due to another discussion or was recreated in the user space. Before deleting again, the Administrator should be sure that the content is similar and not just a new article on the same subject. This rule cannot be used if the content had already been quickly deleted before.'
					},
	//No G5 on this wiki
					{
						label: 'G6: History merge', 
						value: 'histmerge',
						tooltip: 'Temporarily deleting a page in order to merge page histories' 
					},
					{
						label: 'G6: Make way for move', 
						value: 'move',
						tooltip: 'Making way for a move like reversing a redirect' 
					},
					{
						label: 'G6: Closed Request for deletion as delete',
						value: 'afd',
						tooltip: 'An admin has closed a Requests for deletion debate as a "delete"'
					},
					{
						label: 'G6: Housekeeping',
						value: 'g6',
						tooltip: 'Other non-controversial "housekeeping" tasks'
					},
					{
						label: 'G7: Author requests deletion',
						value: 'author',
						tooltip: 'Any page whose original author wants deletion, can be quickly deleted, but only if most of the page was written by that author and was created as a mistake. If the author blanks the page, this can mean that he or she wants it deleted.'
					},
					{
						label: 'G7: Author blanked',
						value: 'blanked',
						tooltip: ' If the author blanks the page, this can be taken as a deletion request'
					},
					{
						label: 'G8: Pages dependent on deleted or non-existent pages',
						value: 'talk',
						tooltip: '... can be deleted, unless they contain discussion on deletion that can\'t be found anywhere else. Subpages of a talk page can only be deleted under this rule if their top-level page does not exist. This also applies to broken redirects. However, this cannot be used on user talk pages or talk pages of images on Commons.'
					},
	// No G9, as this is not a criterion that is used frequently
					{ 
						label: 'G10: Attack page',
						value: 'attack', 
						tooltip: 'Pages that were only created to insult a person or thing (such as "John Q. Doe is dumb"). This includes articles on a living person that is insult and without sources, where there is no NPOV version in the edit history to revert to.'
					},
					{ 
						label: 'G11: Obvious advertising',
						value: 'spam', 
						tooltip: 'Pages which were created only to say good things about a company, item, group or service and which would need to be written again so that they can sound like an encyclopedia. However, simply having a company, item, group or service as its subject does not mean that an article can be deleted because of this rule: an article that is obvious advertising should have content that shouldn\'t be in an encyclopedia. If a page has already gone through RfD or QD and was not deleted, it should not be quickly deleted using this rule.'
					},
					{ 
						label: 'G12: Obviously breaking copyright law', 
						value: 'copyvio', 
						tooltip: 'Obviously breaking copyright law like a page which is 1) Copied from another website which does not have a license that can be used with Wikipedia; 2) Containing no content in the page history that is worth being saved. 3) Made by one person instead of being created on wiki and then copied by another website such as one of the many Wikipedia mirror websites. 4) Added by someone who doesn\'t tell if he got permission to do so or not, or if his claim has a large chance of not being true;' 
					}
				]
		});

	form.append( { type:'header', label: 'Redirects' } );
	form.append( {
			type: 'radio',
			name: 'csd',
			list: [
				{ 
                                        label: 'R1: Redirects to a non-existent page.', 
					value: 'redirnone', 
					tooltip: 'Redirects to a non-existent page.'
				},
				{ 

					label: 'R2: Redirects from mainspace to any other namespace except the Category:, Template:, Wikipedia:, Help: and Portal: namespaces', 
					value: 'rediruser', 
					tooltip: '(this does not include the Wikipedia shortcut pseudo-namespaces). If this was the result of a page move, consider waiting a day or two before deleting the redirect'
				},
				{ 
					label: 'R3: Redirects as a result of an implausible typo that were recently created', 
					value: 'redirtypo', 
					tooltip: 'However, redirects from common misspellings or misnomers are generally useful, as are redirects in other languages'
				}
			]
		} );
	var result = form.render();
	Window.setContent( result );
	Window.display();
}

twinklespeedy.normalizeHash = {
	'nonsense': 'g1',
	'test': 'g2',
	'vandalism': 'g3',
	'pagemove': 'g3',
	'repost': 'g4',
	'histmerge': 'g6',
	'move': 'g6',
	'afd': 'g6',
	'g6': 'g6',
	'author': 'g7',
	'blanked': 'g7',
	'talk': 'g8',
	'attack': 'g10',
	'spam': 'g11',
	'copyvio': 'g12',
	'nocontext': 'a1',
	'nocontent': 'a2',
	'transwiki': 'a3',
	'notability': 'a4',
	'foreign': 'a5',
	'redirnone': 'r1',
	'rediruser': 'r2',
	'redirtypo': 'r3',
	'prohibitedimage': 'f1',
	'catempty': 'c1',
	'catqr': 'c2',
	'catfd': 'c3',
	'userreq': 'u1',
	'nouser': 'u2',
	'replaced':'t2'
};

twinklespeedy.reasonHash = {
		'nonsense': 'was all nonsense',
		'test': 'was a test page',
		'vandalism': 'was vandalism',
		'pagemove': 'was a redirect created during cleanup of page move vandalism',
		'repost': 'was a copy of a page that was deleted by RfD',
		'histmerge': 'was in the way of trying to fix or clean up something',
		'move': 'was in the way of making a move',
		'afd': 'was closed as delete in a RfD',
		'g6': 'was housekeeping',
		'author': 'was asked to be deleted by the author',
		'blanked': 'was implied to be deleted by the author',
		'talk': 'was a talk page of a page that does not exist',
		'attack': 'was an attack page',
		'spam': 'was advertising',
		'copyvio': 'was breaking copyright law',
		'nocontext': 'was a page that had little or no meaning',
		'nocontent': 'was a page that had no content', 
		'transwiki': 'was copied from another Wikipedia',
		'notability': 'was a page that didn\'t say why the subject was notable',
		'foreign': 'was not written in English',
		'hoax': 'was obviously a hoax (not true)',
		'redirnone': 'was a redirect to a page that does not exist',
		'rediruser': 'was a redirect to the Talk:, User: or User talk: space',
		'redirtypo': 'was a redirect with an uncommon typo',
		'prohibitedimage': 'was an image/media that is not allowed on Wikipedia',
		'catempty': 'was an empty category',
		'catqr': 'was a renamed category',
		'catfd': 'was a category containing articles from a now deleted template',
		'userreq': 'was a user page whose user requested deletion',
		'nouser': 'was a user page of a user that did not exist',
		'replaced': 'was deprecated or replaced by a newer template and are completely unused and not linked to'
};

twinklespeedy.callbacks = {
	sysop: {
		main: function( self ) {
			var xmlDoc = self.responseXML;
			var normal = xmlDoc.evaluate( '//normalized/n/@to', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;
			if( normal ) {
				wgPageName = normal;
			}
			var exists = xmlDoc.evaluate( 'boolean(//pages/page[not(@missing)])', xmlDoc, null, XPathResult.BOOLEAN_TYPE, null ).booleanValue;

			if( ! exists ) {
				self.statelem.error( "It seems that the page doesn't exists, perhaps it has already been deleted" );
				return;
			}

			if( self.params.openusertalk ) {
				// Open talk page of first contributor
				var query = {
					'action': 'query',
					'prop': 'revisions',
					'titles': wgPageName,
					'rvlimit': 1,
					'rvprop': 'user',
					'rvdir': 'newer'
				}

				var wikipedia_api = new Wikipedia.api( 'Grabbing username of initial contributor', query, twinklespeedy.callbacks.sysop.openUserTalkPage );
				wikipedia_api.params = self.params;
				wikipedia_api.post();
			}
			
			var query = { 
				'title': wgPageName, 
				'action': 'delete'
			};

			var wikipedia_wiki = new Wikipedia.wiki( 'Deleting page', query, twinklespeedy.callbacks.sysop.deletePage );
			wikipedia_wiki.params = self.params;
			wikipedia_wiki.followRedirect = false;
			wikipedia_wiki.get();

			if( 
				TwinkleConfig.deleteTalkPageOnDelete && 
				self.params.normalized != 'f8' &&
				wgNamespaceNumber % 2 == 0 && 
				wgNamespaceNumber != Namespace.USER && 
				document.getElementById( 'ca-talk' ).className != 'new' 
			) {
				var talk_page = namespaces[ wgNamespaceNumber  + 1 ] + ':' + wgTitle;
				var query = query = {
					'title': talk_page,
					'action': 'delete'
				};
				var wikipedia_wiki = new Wikipedia.wiki( 'Deleting talk page', query, twinklespeedy.callbacks.sysop.deleteTalkPage );
				wikipedia_wiki.params = self.params;
				wikipedia_wiki.followRedirect = false;
				wikipedia_wiki.get();
			}

			if( wgNamespaceNumber == 6 && self.params.normalized != 'f8' ) {
				var query = {
					'action': 'query',
					'list': 'imageusage',
					'titles': wgPageName,
					'iulimit': userIsInGroup( 'sysop' ) ? 5000 : 500 // 500 is max for normal users, 5000 for bots and sysops
				};
				var wikipedia_api = new Wikipedia.api( 'Grabbing file links', query, twinklespeedy.callbacks.sysop.unlinkImageInstancesMain );
				wikipedia_api.params = self.params;
				wikipedia_api.post();
			}
			var doOrphan = TwinkleConfig.orphanBacklinksOnSpeedyDelete;
			if( 
				doOrphan.orphan && 
				doOrphan.exclude.indexOf( self.params.normalized.toLowerCase() ) == -1 
			) {
				var query = {
					'action': 'query',
					'list': 'backlinks',
					'blfilterredir': 'nonredirects',
					'bltitle': wgPageName,
					'bllimit': userIsInGroup( 'sysop' ) ? 5000 : 500, // 500 is max for normal users, 5000 for bots and sysops
					'blnamespace': [0, 100] // Main namespace and portal namespace only, keep on talk pages.
				};
				var wikipedia_api = new Wikipedia.api( 'Grabbing backlinks', query, twinklespeedy.callbacks.sysop.unlinkBacklinksMain );
				wikipedia_api.params = self.params;
				wikipedia_api.post();
			}
			var query = {
				'action': 'query',
				'list': 'backlinks',
				'blfilterredir': 'redirects',
				'bltitle': wgPageName,
				'bllimit': userIsInGroup( 'sysop' ) ? 5000 : 500 // 500 is max for normal users, 5000 for bots and sysops
			};
			var wikipedia_api = new Wikipedia.api( 'Grabbing redirects', query, twinklespeedy.callbacks.sysop.deleteRedirectsMain );
			wikipedia_api.params = self.params;
			wikipedia_api.post();

		},
		openUserTalkPage: function( self ) {
			var xmlDoc = self.responseXML;
			var user = xmlDoc.evaluate( '//rev/@user', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;
			var statusIndicator = new Status('Opening user talk page edit form for user ' + user, 'opening');
			
			var query = {
				'title': 'User talk:' + user,
				'action': 'edit',
				'preview': 'yes',
				'vanarticle': wgPageName.replace(/_/g, ' ')
			};
			switch( TwinkleConfig.userTalkPageMode ) {
			case 'tab':
				window.open( mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?' + QueryString.create( query ), '_tab' );
				break;
			case 'blank':
				window.open( mw.config.get('wgServer') + mw.config.get('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( mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?' + QueryString.create( query ), 'twinklewarnwindow', 'location=no,toolbar=no,status=no,directories=no,scrollbars=yes,width=1200,height=800' );
				break;
			}
			
			statusIndicator.info( 'complete' );
		},
		unlinkBacklinksMain: function( self ) {
			var xmlDoc = self.responseXML;
			var snapshot = xmlDoc.evaluate('//backlinks/bl/@title', xmlDoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );

			if( snapshot.snapshotLength == 0 ) {
				return;
			}

			var statusIndicator = new Status('Removing backlinks', '0%');

			var total = snapshot.snapshotLength * 2;

			var onsuccess = function( self ) {
				var obj = self.params.obj;
				var total = self.params.total;
				var now = parseInt( 100 * ++(self.params.current)/total ) + '%';
				obj.update( now );
				self.statelem.unlink();
				if( self.params.current >= total ) {
					obj.info( now + ' (completed)' );
					Wikipedia.removeCheckpoint();
				}
			}
			var onloaded = onsuccess;

			var onloading = function( self ) {}


			Wikipedia.addCheckpoint();
			if( snapshot.snapshotLength == 0 ) {
				statusIndicator.info( '100% (completed)' );
				Wikipedia.removeCheckpoint();
				return;
			}

			var params = clone( self.params );
			params.current = 0;
			params.total = total;
			params.obj = statusIndicator;
			params.page = wgPageName;


			for ( var i = 0; i < snapshot.snapshotLength; ++i ) {
				var title = snapshot.snapshotItem(i).value;
				var query = {
					'title': title,
					'action': 'submit'
				}
				var wikipedia_wiki = new Wikipedia.wiki( "Unlinking on " + title, query, twinklespeedy.callbacks.sysop.unlinkBacklinks );
				wikipedia_wiki.params = params;
				wikipedia_wiki.onloading = onloading;
				wikipedia_wiki.onloaded = onloaded;
				wikipedia_wiki.onsuccess = onsuccess;
				wikipedia_wiki.get();
			}
		},
		unlinkBacklinks: function( self ) {
			var form = self.responseXML.getElementById('editform');
			var text = form.wpTextbox1.value;
			var old_text = text;
			var wikiPage = new Mediawiki.Page( text );
			wikiPage.removeLink( self.params.page );

			text = wikiPage.getText();
			if( text == old_text ) {
				// Nothing to do, return
				self.onsuccess( self );
				Wikipedia.actionCompleted( self );
				return;
			}
			var postData = {
				'wpMinoredit': form.wpMinoredit.checked ? '' : undefined,
				'wpWatchthis': undefined,
				'wpStarttime': form.wpStarttime.value,
				'wpEdittime': form.wpEdittime.value,
				'wpAutoSummary': form.wpAutoSummary.value,
				'wpEditToken': form.wpEditToken.value,
				'wpSection': '',
				'wpSummary': 'Removing backlinks to ' + self.params.page + " that has been speedily deleted per ([[WP:CSD#" + self.params.normalized.toUpperCase() + "|CSD " + self.params.normalized.toUpperCase() + "]])" + "; " + TwinkleConfig.deletionSummaryAd,
				'wpTextbox1': text
			};
			self.post( postData );
		},
		deleteRedirectsMain: function( self ) {
			var xmlDoc = self.responseXML;
			var snapshot = xmlDoc.evaluate('//backlinks/bl/@title', xmlDoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );

			var total = snapshot.snapshotLength * 2;

			if( snapshot.snapshotLength == 0 ) {
				return;
			}

			var statusIndicator = new Status('Deleting redirects', '0%');

			var onsuccess = function( self ) {
				var obj = self.params.obj;
				var total = self.params.total;
				var now = parseInt( 100 * ++(self.params.current)/total ) + '%';
				obj.update( now );
				self.statelem.unlink();
				if( self.params.current >= total ) {
					obj.info( now + ' (completed)' );
					Wikipedia.removeCheckpoint();
				}
			}
			var onloaded = onsuccess;

			var onloading = function( self ) {}


			Wikipedia.addCheckpoint();
			if( snapshot.snapshotLength == 0 ) {
				statusIndicator.info( '100% (completed)' );
				Wikipedia.removeCheckpoint();
				return;
			}

			var params = clone( self.params );
			params.current = 0;
			params.total = total;
			params.obj = statusIndicator;


			for ( var i = 0; i < snapshot.snapshotLength; ++i ) {
				var title = snapshot.snapshotItem(i).value;
				var query = {
					'title': title,
					'action': 'delete'
				}
				var wikipedia_wiki = new Wikipedia.wiki( "Deleting " + title, query, twinklespeedy.callbacks.sysop.deleteRedirects );
				wikipedia_wiki.params = params;
				wikipedia_wiki.onloading = onloading;
				wikipedia_wiki.onloaded = onloaded;
				wikipedia_wiki.onsuccess = onsuccess;
				wikipedia_wiki.followRedirect = false;
				wikipedia_wiki.get();
			}
		},
		deleteRedirects: function( self ) {
			var form = this.responseXML.getElementById( 'deleteconfirm' );
			if( ! form ) { // Hell, file deletion is b0rked :(
				form = this.responseXML.getElementsByTagName( 'form' )[0];
				var postData = {
					'wpDeleteReasonList': 'other',
					'wpReason': "Quickly deleted per [[WP:QD#G8|QD G8]], redirect to deleted page \"" + wgPageName + "\"." + TwinkleConfig.deletionSummaryAd,
					'wpEditToken': form.wpEditToken.value
				}
			} else {

				var postData = {
					'wpWatch': form.wpWatch.checked ? '' : undefined,
					'wpDeleteReasonList': 'other',
					'wpReason': "Quickly deleted per [[WP:QD#G8|QD G8]], redirect to deleted page \"" + wgPageName + "\"." + TwinkleConfig.deletionSummaryAd,
					'wpEditToken': form.wpEditToken.value
				}
			}
			self.post( postData );
		},
		unlinkImageInstancesMain: function( self ) {
			var xmlDoc = self.responseXML;
			var snapshot = xmlDoc.evaluate('//imageusage/iu/@title', xmlDoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );

			if( snapshot.snapshotLength == 0 ) {
				return;
			}

			var statusIndicator = new Status('Unlinking file instances ', '0%');

			var total = snapshot.snapshotLength * 2;

			var onsuccess = function( self ) {
				var obj = self.params.obj;
				var total = self.params.total;
				var now = parseInt( 100 * ++(self.params.current)/total ) + '%';
				obj.update( now );
				self.statelem.unlink();
				if( self.params.current >= total ) {
					obj.info( now + ' (completed)' );
					Wikipedia.removeCheckpoint();
				}
			}
			var onloaded = onsuccess;

			var onloading = function( self ) {}


			Wikipedia.addCheckpoint();
			if( snapshot.snapshotLength == 0 ) {
					statusIndicator.info( '100% (completed)' );
					Wikipedia.removeCheckpoint();
					return;
			}

			var params = clone( self.params );
			params.current = 0;
			params.total = total;
			params.obj = statusIndicator;
			params.image = wgTitle;

			for ( var i = 0; i < snapshot.snapshotLength; ++i ) {
				var title = snapshot.snapshotItem(i).value;
				var query = {
					'title': title,
					'action': 'submit'
				}
				var wikipedia_wiki = new Wikipedia.wiki( "Unlinking on " + title, query, twinklespeedy.callbacks.sysop.unlinkImageInstances );
				wikipedia_wiki.params = params;
				wikipedia_wiki.onloading = onloading;
				wikipedia_wiki.onloaded = onloaded;
				wikipedia_wiki.onsuccess = onsuccess;
				wikipedia_wiki.get();
			}
		},
		unlinkImageInstances: function( self ) {
			var form = self.responseXML.getElementById('editform');
			var text = form.wpTextbox1.value;
			var old_text = text;
			var wikiPage = new Mediawiki.Page( text );
			wikiPage.commentOutImage( self.params.image, 'Commented out because file was deleted' );

			text = wikiPage.getText();
			if( text == old_text ) {
				// Nothing to do, return
				self.onsuccess( self );
				Wikipedia.actionCompleted( self );
				return;
			}
			var postData = {
				'wpMinoredit': form.wpMinoredit.checked ? '' : undefined,
				'wpWatchthis': undefined,
				'wpStarttime': form.wpStarttime.value,
				'wpEdittime': form.wpEdittime.value,
				'wpAutoSummary': form.wpAutoSummary.value,
				'wpEditToken': form.wpEditToken.value,
				'wpSection': '',
				'wpSummary': 'Removing instance of file ' + self.params.image + " that has been quickly deleted per ([[WP:QD#" + self.params.normalized.toUpperCase() + "|QD " + self.params.normalized.toUpperCase() + "]])" + "; " + TwinkleConfig.deletionSummaryAd,
				'wpTextbox1': text
			};
			self.post( postData );
		},
		deletePage: function( self ) {
			var form = this.responseXML.getElementById( 'deleteconfirm' );
			if( ! form ) { // Hell, file deletion is b0rked :(
				form = this.responseXML.getElementsByTagName( 'form' )[0];
				var postData = {
					'wpDeleteReasonList': 'other',
					'wpReason': "Quickly deleted per [[WP:QD#" + self.params.normalized.toUpperCase() + "|QD " + self.params.normalized.toUpperCase() + "]], " + self.params.reason + "." + TwinkleConfig.deletionSummaryAd,
					'wpEditToken': form.wpEditToken.value
				}
				self.post( postData );
			} else {

				var postData = {
					'wpWatch': (self.params.watch || form.wpWatch.checked) ? '' : undefined,
					'wpDeleteReasonList': 'other',
					'wpReason': "Quickly deleted per [[WP:QD#" + self.params.normalized.toUpperCase() + "|QD " + self.params.normalized.toUpperCase() + "]], " + self.params.reason + "." + TwinkleConfig.deletionSummaryAd,
					'wpEditToken': form.wpEditToken.value
				}
				self.post( postData );
			}
		},
		deleteTalkPage: function( self ) {
			form = this.responseXML.getElementById( 'deleteconfirm' );

			var postData = {
				'wpWatch': (self.params.watch || form.wpWatch.checked) ? '' : undefined,
				'wpDeleteReasonList': 'other',
				'wpReason': "Quickly deleted per [[WP:QD#G8|QD G8]], was a talk page or redirect of a deleted or nonexistent page." + TwinkleConfig.deletionSummaryAd,
				'wpEditToken': form.wpEditToken.value
			}
			self.post( postData );
		}
	},
	user: {
		main: function( self ) {
			var xmlDoc = self.responseXML;

			var exists = xmlDoc.evaluate( 'boolean(//pages/page[not(@missing)])', xmlDoc, null, XPathResult.BOOLEAN_TYPE, null ).booleanValue;

			if( ! exists ) {
				self.statelem.error( "It seems that the page doesn't exists, perhaps it has already been deleted" );
				return;
			}
			var query = { 
				'title': wgPageName, 
				'action': 'submit'
			};

			var wikipedia_wiki = new Wikipedia.wiki( 'Tagging page', query, twinklespeedy.callbacks.user.tagPage );
			wikipedia_wiki.params = self.params;
			wikipedia_wiki.followRedirect = false;
			wikipedia_wiki.get();
		},
		tagPage: function( self ) {
			form = this.responseXML.getElementById( 'editform' );

			var text = form.wpTextbox1.value;

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

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

			if( tag ) {
				self.statelem.error( [ htmlNode( 'strong', tag[0] ) , " is already placed on the page." ] )
				return;
			}

			var xfd = /(\{\{(?:[rsaitcm]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 apply CSD template?" ) ) {
				return;
			}
			var code;
			switch( self.params.normalized ) {
				case 'g12':
					var url = prompt( 'Please enter the URL if available, including the "http://":' );
					if (url == null)
					{
						self.statelem.error( 'Aborted by user.' );
						return;
					}
					code = "\{\{QD|" +  self.params.normalized + "|url=" + url + "\}\}";
					break;
				default:
					code = "\{\{QD|" +  self.params.normalized + "\}\}";
					break;
			}

			if( TwinkleConfig.markSpeedyPagesAsPatrolled && self.params.rcid != '' ) {
				var query = {
					'title': wgPageName,
					'action': 'markpatrolled',
					'rcid': self.params.rcid
				};

				var wikipedia_wiki = new Wikipedia.wiki( 'Marking page as patrolled', query );
				wikipedia_wiki.post();
			}

			// Notification to first contributor
			var query = {
				'action': 'query',
				'prop': 'revisions',
				'titles': wgPageName,
				'rvlimit': 1,
				'rvprop': 'user',
				'rvdir': 'newer'
			}
			var callback = function( self ) {
				var xmlDoc = self.responseXML;
				var user = xmlDoc.evaluate( '//rev/@user', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;
				if( wgPageName != ( 'User talk:' + user ) ) {
					var query = {
						'title': 'User talk:' + user,
						'action': 'submit'
					};
					var wikipedia_wiki = new Wikipedia.wiki( 'Notifying of initial contributor (' + user + ')', query, twinklespeedy.callbacks.user.userNotification );
					wikipedia_wiki.params = self.params;
					wikipedia_wiki.get();
				} else {
					Status.info( 'Info', 'Current page is initial contributor\'s talk page, aborting notification' );
				}
			}

			if( self.params.usertalk ) {
				var wikipedia_api = new Wikipedia.api( 'Grabbing data of initial contributor', query, callback );
				wikipedia_api.params = self.params;
				wikipedia_api.post();
			}

			//wrap SD template in noinclude tags if we are in template space.
			//won't work with userboxes in userspace, or any other transcluded page outside template space
			if (self.params.wgCanonicalNamespace == "Template") code = "<noinclude>" + code + "</noinclude>";

			//Remove tags that become superfluous with this action
			text = text.replace(/{\{\s*(New unreviewed article|Userspace draft)\s*(\|(?:{{[^{}]*}}|[^{}])*)?}}\s*/ig, "");

			var postData = {
				'wpMinoredit': TwinkleConfig.markSpeedyPagesAsMinor ? '' : undefined,
				'wpWatchthis': (self.params.watch || form.wpWatchthis.checked ) ? '' : undefined,
				'wpStarttime': form.wpStarttime.value,
				'wpEdittime': form.wpEdittime.value,
				'wpAutoSummary': form.wpAutoSummary.value,
				'wpEditToken': form.wpEditToken.value,
				'wpSection': '',
				'wpSummary': "Requesting quick deletion ([[WP:QD#" + self.params.normalized.toUpperCase() + "|QD " + self.params.normalized.toUpperCase() + "]])." + TwinkleConfig.summaryAd,
				'wpTextbox1': code + "\n" + text
			};
			self.post( postData );
		},
		userNotification: function( self ) {
			var nowelcome = TwinkleConfig.welcomeUserOnSpeedyDeletionNotification.indexOf( self.params.normalized ) == -1;
			var form = self.responseXML.getElementById( 'editform' );
			var text = form.wpTextbox1.value;

			text += "\n\{\{subst:QD-notice|page=" + wgPageName + "|cat=" + self.params.normalized + "|reason=" + twinklespeedy.reasonHash[ self.params.value ] + "\}\} \~\~\~\~";
			var postData = {
				'wpMinoredit': form.wpMinoredit.checked ? '' : undefined,
				'wpWatchthis': form.wpWatchthis.checked ? '' : undefined,
				'wpStarttime': form.wpStarttime.value,
				'wpEdittime': form.wpEdittime.value,
				'wpAutoSummary': form.wpAutoSummary.value,
				'wpEditToken': form.wpEditToken.value,

				'wpSection': '',
				'wpSummary': 'Notification: Quick deletion nomination of \[\[' + wgPageName + '\]\].' + TwinkleConfig.summaryAd,
				'wpTextbox1': text
			};
			self.post( postData );
		}
	}
}

twinklespeedy.callback.evaluateSysop = function twinklespeedyCallbackEvaluateSysop(e) {

	wgPageName = wgPageName.replace( /_/g, ' ' ); // for queen/king/whatever and country!

	var tag_only = e.target.form.tag_only;
	if( tag_only && tag_only.checked ) {
		return twinklespeedy.callback.evaluateUser(e);
	}

	var value = e.target.value;
	var normalized = twinklespeedy.normalizeHash[ value ];

	var params = {
		value: value,
		normalized: normalized,
		watch: TwinkleConfig.watchSpeedyPages.indexOf( normalized ) != -1,
		reason: twinklespeedy.reasonHash[ value ],
		openusertalk: TwinkleConfig.openUserTalkPageOnSpeedyDelete.indexOf( normalized ) != -1
	};
	Status.init( e.target.form );

	var query = {
		'action': 'query',
		'titles': wgPageName
	}
	var wikipedia_api = new Wikipedia.api( 'Checking if page exists', query, twinklespeedy.callbacks.sysop.main );
	wikipedia_api.params = params;
	wikipedia_api.post();
}

twinklespeedy.callback.evaluateUser = function twinklespeedyCallbackEvaluateUser(e) {
	wgPageName = wgPageName.replace( /_/g, ' ' ); // for queen/king/whatever and country!
	var value = e.target.value;
	var normalized = twinklespeedy.normalizeHash[ value ];

	var params = {
		value: value,
		normalized: normalized,
		watch: TwinkleConfig.watchSpeedyPages.indexOf( normalized ) != -1,
		usertalk: TwinkleConfig.notifyUserOnSpeedyDeletionNomination.indexOf( normalized ) != -1 && e.target.form.notify.checked,
		rcid: QueryString.exists( 'rcid' ) ? QueryString.get( 'rcid' ) : '',
		wgCanonicalNamespace : wgCanonicalNamespace
	};

	Status.init( e.target.form );

	Wikipedia.actionCompleted.redirect = wgPageName;
	Wikipedia.actionCompleted.notice = "Tagging complete";

	var query = {
		'action': 'query',
		'titles': wgPageName
	}

	var wikipedia_api = new Wikipedia.api( 'Checking if page exists', query, twinklespeedy.callbacks.user.main );
	wikipedia_api.params = params;
	wikipedia_api.post();

}