User:Altt311/Gadget/speedy.js

注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google ChromeFirefoxMicrosoft EdgeSafari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
//Code pasted from [[:en:WP:TW]] and localized.


// If FriendlyConfig aint exist.
if( typeof( FriendlyConfig ) == 'undefined' ) {
	FriendlyConfig = {};
}
 
/**
 FriendlyConfig.summaryAd (string)
 If ad should be added or not to summary, default [[WP:FRIENDLY|Friendly]]
 */
if( typeof( FriendlyConfig.summaryAd ) == 'undefined' ) {
	FriendlyConfig.summaryAd = " using [[WP:FRIENDLY|Friendly]]";
}
 
/**
 FriendlyConfig.deletionSummaryAd (string)
 If ad should be added or not to deletion summary, default [[WP:FRIENDLY|Friendly]]
 */
if( typeof( FriendlyConfig.deletionSummaryAd ) == 'undefined' ) {
	FriendlyConfig.deletionSummaryAd = " using [[WP:FRIENDLY|Friendly]]";
}
 
/**
 FriendlyConfig.watchSpeedyPages (array)
 What types of actions that should result in forced addition to watchlist
 */
if( typeof( FriendlyConfig.watchSpeedyPages ) == 'undefined' ) {
	FriendlyConfig.watchSpeedyPages = [];
}
 
/**
 FriendlyConfig.markSpeedyPagesAsMinor (boolean)
 If, when applying speedy template to page, to mark the edit as minor, default true
 */
if( typeof( FriendlyConfig.markSpeedyPagesAsMinor ) == 'undefined' ) {
	FriendlyConfig.markSpeedyPagesAsMinor = false;
}
 
/**
 FriendlyConfig.markSpeedyPagesAsPatrolled (boolean)
 If, when applying speedy template to page, to mark the page as patrolled, default true
 */
if( typeof( FriendlyConfig.markSpeedyPagesAsPatrolled ) == 'undefined' ) {
	FriendlyConfig.markSpeedyPagesAsPatrolled = true;
}
 
/**
 FriendlyConfig.notifyUserOnSpeedyDeletionNomination (array of strings)
 What types of actions that should result that the author of the page should be notified of nomination
 */
if( typeof( FriendlyConfig.notifyUserOnSpeedyDeletionNomination ) == 'undefined' ) {
	FriendlyConfig.notifyUserOnSpeedyDeletionNomination = ['g1', 'g2', 'g3', 'g4', 'g5', 'g7', 'g9', 'g11', 'g12', 'g13', 'g14', 'r4'];
}
 
/**
 FriendlyConfig.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( FriendlyConfig.welcomeUserOnSpeedyDeletionNotification ) == 'undefined' ) {
	FriendlyConfig.welcomeUserOnSpeedyDeletionNotification = FriendlyConfig.notifyUserOnSpeedyDeletionNomination;
}

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

/**
 FriendlyConfig.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( FriendlyConfig.userTalkPageMode ) == 'undefined' ) {
	FriendlyConfig.userTalkPageMode = 'tab';
}
 
/**
 FriendlyConfig.deleteTalkPageOnDelete (boolean)
 If talk page if exists should also be deleted (CSD G8) when spedying a page (admin only)
 */
if( typeof( FriendlyConfig.deleteTalkPageOnDelete ) == 'undefined' ) {
	FriendlyConfig.deleteTalkPageOnDelete = false;
}
 
/**
 FriendlyConfig.orphanNormalPagesOnSpeedyDelete (hash)
 Defines if all backlinks to a page should be removed.
 property 'exclude' defined actions not to orphan
 */
if( typeof( FriendlyConfig.orphanBacklinksOnSpeedyDelete ) == 'undefined' ) {
	FriendlyConfig.orphanBacklinksOnSpeedyDelete = { /*exclude: ['g6'],*/ orphan:false };
}

/**
 FriendlyConfig.checkDeleteDup (boolean)
 */
if( typeof( FriendlyConfig.checkDeleteDup ) == 'undefined' ) {
	FriendlyConfig.checkDeleteDup = true;
}


 
function Friendlyspeedy() {
	if( wgNamespaceNumber < 0 || wgCurRevisionId == false ) {
		return;
	}
	if( userIsInGroup( 'sysop' ) ) {
		mw.util.addPortletLink( 'p-cactions', "javascript:Friendlyspeedy.callback()", "速删", "friendly-csd", "快速删除", "");
	} else if ( userIsInGroup( 'autoconfirmed' ) ) {
		mw.util.addPortletLink( 'p-cactions', "javascript:Friendlyspeedy.callback()", "速删", "friendly-csd", "请求快速删除", "");
	}
	else
	{
		mw.util.addPortletLink( 'p-cactions', 'javascript:alert("您必须首先达到自动确认。");', "csd", "friendly-csd", "请求快速删除", "");
	}
}
$(Friendlyspeedy);
 
Friendlyspeedy.callback = function FriendlyspeedyCallback() {
	var Window = new SimpleWindow( 800, 500 );
	Window.setTitle( "选择快速删除的标准" );
 
	var form = new QuickForm( userIsInGroup( 'sysop' ) ? Friendlyspeedy.callback.evaluateSysop : Friendlyspeedy.callback.evaluateUser, 'change' );
	if( userIsInGroup( 'sysop' ) ) {
		form.append( {
				type: 'checkbox',
				list: [
					{
						label: '仅标记',
						value: 'tag_only',
						name: 'tag_only',
						checked: 'true',
						event: function( event ) {
							event.target.form.notify.disabled = ! event.target.checked;
							event.stopPropagation();
						}
					},
					{
						label: '移除链入',
						value: 'orphan_backlinks',
						name: 'orphan_backlinks',
						checked: FriendlyConfig.orphanBacklinksOnSpeedyDelete.orphan,
						event: function( event ) {
							FriendlyConfig.orphanBacklinksOnSpeedyDelete.orphan = event.target.checked;
							event.stopPropagation();
						}
					}
				]
			} );
	}
 
	form.append( {
			type: 'checkbox',
			list: [
				{
					label: '如果可能,通知创建者',
					value: 'notify',
					name: 'notify',
					checked: true,
					//disabled: userIsInGroup( 'sysop' ),
					event: function( event ) {
						event.stopPropagation();
					}
				}
			]
		}
	);
	if( wgNamespaceNumber ==  Namespace.IMAGE ) {
		form.append( {type:'header', label:'文件' } );
		form.append ( {
				type: 'radio',
				name: 'csd',
				list: [
					{ 
						label: 'I1: 重复的文件,而且所有的链入连接已经被修改为指向保留的文件',
						value: 'i1'
					},
					{
						label: 'I5: 被高分辨率与SVG文件取代的图片',
						value: 'i5',
					},
					{
						label: 'I6: 孤立而没有被条目使用的非自由版权文件',
						value: 'i6',
					},
					{
						label: 'I7: 被维基共享资源文件取代的文件',
						value: 'i7'
					}
				]
			} );
	}
 
	form.append( { type:'header', label:'常规' } );
	form.append( {
			type: 'radio',
			name: 'csd',
			list: [
				{ 
					label: 'G1: 没有实际内容或历史纪录的文章', 
					value: 'g1',
				},
				{ 
					label: 'G2: 测试页面',
					value: 'g2'
				},
				{ 
					label: 'G3: 纯粹破坏',
					value: 'g3'
				},
				{
					label: 'G4: 非常短的文章,没有定义或内容',
					value: 'g4'
				},
				{
					label: 'G5: 曾经根据Wikipedia:页面存废讨论、Wikipedia:页面存废讨论/疑似侵权、Wikipedia:文件存废讨论被删除后又重新创建的内容,无论标题是否相同', 
					value: 'g5'
				},
				{
					label: 'G7: 复制自其他中文维基计划,或是与其他中文维基计划内容相同的文章,或者是透过Transwiki系统移动的文章', 
					value: 'g7'
				},
				{
					label: 'G9: 任何内容只包括外部连接、参见、图书参考、类别标签、模板标签、跨语言连接的条目', 
					value: 'g9'
				},
				{
					label: 'G10: 任何由原作者提出删除请求的条目,如果作者能够合理地说明该条目是错误的创建,并且该条目只被该作者编辑过',
					value: 'g10'
				},
				{
					label: 'G11: 明显的以广告宣传为目的而建立的页面,或任何只有该条目名称中的人物或团体的联系方法',
					value: 'g11'
				},
				{
					label: 'G12: 未列明来源及语调负面的生者传记,无任何版本可回退',
					value: 'g12'
				},
				{
					label: 'G13: 明显的、拙劣的机器翻译',
					value: 'g13'
				},
				{
					label: 'G14: 超过两周没有进行任何翻译的非现代标准汉语条目,包括所有未翻译的外语、汉语方言以及文言文',
					value: 'g14'
				}
			]
		});

	form.append( { type:'header', label: '重定向' } );
	form.append( {
			type: 'radio',
			name: 'csd',
			list: [
				{ 
					label: 'R1: 指向不存在的页面', 
					value: 'r1'
				},
				{ 
					label: 'R2: 跨命名空间重定向', 
					value: 'r2'
				},
				{ 
					label: 'R3: 拼写错误的新页面', 
					value: 'r3'
				},
				{ 
					label: 'R4: 故意破坏的结果', 
					value: 'r4'
				}
			]
		} );
	if( wgNamespaceNumber ==  14 || wgNamespaceNumber == 15 ) {
		form.append( { type:'header', label: '分类' } );
		form.append( {
			type: 'radio',
			name: 'csd',
			list: [
				{ 
					label: 'O4: 空的类别,只有指向父类别的链接',
					value: 'o4'
				},
				{ 
					label: 'O5: 空的类别,已经清空24小时',
					value: 'o5'
				}
			]
		} );
	} if( wgNamespaceNumber ==  2 || wgNamespaceNumber == 3 ) {
		form.append( { type:'header', label: '用户页' } );
		form.append( {
			type: 'radio',
			name: 'csd',
			list: [
				{
					label: 'O1: 用户请求删除的他们自己的用户页子页面',
					value: 'o1'
				},
				{
					label: 'O3: 匿名用户的用户讨论页,其中的内容不再有用',
					value: 'o3'
				},
				{
					label: 'O6: 用户提出的用户页或讨论页,这些页面没有显著的滥用,也没有管理上维持该页面的需求',
					value: 'o6'
				}
			]
		} );
	} if( wgNamespaceNumber ==  1 || wgNamespaceNumber == 5 || wgNamespaceNumber == 7 || wgNamespaceNumber == 9 || wgNamespaceNumber == 11 || wgNamespaceNumber == 13 || wgNamespaceNumber == 15 || wgNamespaceNumber == 101 ) {
		form.append( { type:'header', label: '讨论' } );
		form.append( {
			type: 'radio',
			name: 'csd',
			list: [
				{
					label: 'O2: 已经删除的条目的讨论页',
					value: 'o2'
				},
				{
					label: 'O6: 用户提出的用户页或讨论页,这些页面没有显著的滥用,也没有管理上维持该页面的需求',
					value: 'o6'
				}
			]
		} );
	}
 
	var result = form.render();
	Window.setContent( result );
	Window.display();
}
 
Friendlyspeedy.normalizeHash = {
	'g1': 'g1',
	'g2': 'g2',
	'g3': 'g3',
	'g4': 'g4',
	'g5': 'g5',
	'g7': 'g7',
	'g9': 'g9',
	'g10': 'g10',
	'g11': 'g11',
	'g12': 'g12',
	'g13': 'g13',
	'g14': 'g14',
	'r1': 'r1',
	'r2': 'r2',
	'r3': 'r3', 
	'r4': 'r4',
	'i1': 'i1',
	'i5': 'i5',
	'i6': 'i6',
	'i7': 'i7',
	'o1': 'o1',
	'o2': 'o2',
	'o3': 'o3',
	'o4': 'o4',
	'o5': 'o5',
	'o6': 'o6'
};
 
Friendlyspeedy.reasonHash = {
	'g1': '无实际内容',
	'g2': '测试页',
	'g3': '破坏',
	'g4': '非常短而无定义或内容',
	'g5': '曾经依存废讨论被删除的重建内容',
	'g7': '与其他中文维基计划内容相同的文章',
	'g8': '删除以便移动',
	'g9': '内容只包含参考、链接、模板或/及分类',
	'g10': '作者请求',
	'g11': '广告或宣传',
	'g12': '未列明来源或违反Wikipedia:生者传记的负面内容',
	'g13': '明显且拙劣的机器翻译',
	'g14': '超过两周没有翻译的非现代标准汉语条目',
	'r1': '重定向页指向不存在的页面',
	'r2': '跨名字空间重定向',
	'r3': '名称错误的重定向',
	'r4': '重定向破坏',
	'o1': '用户请求删除自己的用户页',
	'o2': '孤立的讨论页',
	'o3': '匿名用户的讨论页', 
	'o4': '空的类别',
	'o5': '空的类别: 被清空24小时',
	'o6' : '用户页或讨论页已没有管理的需求',
	'i1': '重复的图片',
	'i5': '已有图片取代',
	'i6': '孤立而没有被条目使用的非自由版权图片',
	'i7': '与维基共享资源重复的档案'
};
 
Friendlyspeedy.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( "页面不存在,可能已被删除" );
				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, Friendlyspeedy.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, Friendlyspeedy.callbacks.sysop.deletePage );
			wikipedia_wiki.params = self.params;
			wikipedia_wiki.followRedirect = false;
			wikipedia_wiki.get();
 
			if( 
				FriendlyConfig.deleteTalkPageOnDelete && 
				self.params.normalized != 'i7' &&
				wgNamespaceNumber % 2 == 0 && 
				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, Friendlyspeedy.callbacks.sysop.deleteTalkPage );
				wikipedia_wiki.params = self.params;
				wikipedia_wiki.followRedirect = false;
				wikipedia_wiki.get();
			}

			// 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, Friendlyspeedy.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();
			}
 
			if( wgNamespaceNumber == 6 && self.params.normalized != 'i7' ) {
				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 image links', query, Friendlyspeedy.callbacks.sysop.unlinkImageInstancesMain );
				wikipedia_api.params = self.params;
				wikipedia_api.post();
			}
			var doOrphan = FriendlyConfig.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, Friendlyspeedy.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, Friendlyspeedy.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( FriendlyConfig.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 ), 'Friendlywarnwindow', '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, Friendlyspeedy.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() + "]])" + "; " + FriendlyConfig.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, Friendlyspeedy.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, image deletion is b0rked :(
				form = this.responseXML.getElementsByTagName( 'form' )[0];
				var postData = {
					'wpDeleteReasonList': 'other',
					'wpReason': "[[WP:CSD#O2|CSD O2]] 重定向到已经删除的页面\"" + wgPageName + "\"" + FriendlyConfig.deletionSummaryAd,
					'wpEditToken': form.wpEditToken.value
				}
			} else {
 
				var postData = {
					'wpWatch': form.wpWatch.checked ? '' : undefined,
					'wpDeleteReasonList': 'other',
					'wpReason': "[[WP:CSD#O2|CSD O2]] 重定向到已经删除的页面\"" + wgPageName + "\"" + FriendlyConfig.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 instances image', '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, Friendlyspeedy.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 image 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': "移除已经删除的图像" + self.params.image + " ([[WP:CSD#" + self.params.normalized.toUpperCase() + "|CSD " + self.params.normalized.toUpperCase() + "]])" + "; " + FriendlyConfig.deletionSummaryAd,
				'wpTextbox1': text
			};
			self.post( postData );
		},
		deletePage: function( self ) {
			var form = this.responseXML.getElementById( 'deleteconfirm' );
			if( ! form ) { // Hell, image deletion is b0rked :(
				form = this.responseXML.getElementsByTagName( 'form' )[0];
				var postData = {
					'wpDeleteReasonList': 'other',
					'wpReason': "[[WP:CSD#" + self.params.normalized.toUpperCase() + "|CSD " + self.params.normalized.toUpperCase() + "]] " + self.params.reason + FriendlyConfig.deletionSummaryAd,
					'wpEditToken': form.wpEditToken.value
				}
				self.post( postData );
			} else {
 
				var postData = {
					'wpWatch': (self.params.watch || form.wpWatch.checked) ? '' : undefined,
					'wpDeleteReasonList': 'other',
					'wpReason': "[[WP:CSD#" + self.params.normalized.toUpperCase() + "|CSD " + self.params.normalized.toUpperCase() + "]] " + self.params.reason + FriendlyConfig.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': "[[WP:CSD#O2|CSD O2]] 孤立的讨论页" + FriendlyConfig.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( "页面不存在,可能已被删除" );
				return;
			}
			var query = { 
				'title': wgPageName, 
				'action': 'submit'
			};
 
			var wikipedia_wiki = new Wikipedia.wiki( 'Tagging page', query, Friendlyspeedy.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;
 
			if( FriendlyConfig.checkDeleteDup ){
				self.statelem.status( 'Checking for tags on the page...' );
 
				var tag = /(\{\{(?:db-?|delete|d|Delete|D)\|?.*?\}\})/.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 'i7':
					var filename = prompt( 'Please enter the name of the image on Commons:', wgPageName.replace( '_', ' ' ) );
					if (filename == null)
					{
						self.statelem.error( 'Aborted by user.' );
						return;
					}
					if( filename == '' ) {
						filename = wgPageName.replace( '_', ' ' );
					}
					var date = new Date();
					var code = "\{\{Nowcommons|" + filename + "\}\}";
					break;
				case 'i1':
				case 'i5':
					var img = prompt( 'Enter the image this is redundant to, excluding the "File:" prefix:' );
					if (img == null)
					{
						self.statelem.error( 'Aborted by user.' );
						return;
					}
					code = "\{\{d|" +  self.params.value.toUpperCase() + "|" + img + "\}\}";
					break;
				default:
					code = "\{\{d|" +  self.params.value.toUpperCase() + "\}\}";
					break;
			}
 
			if( FriendlyConfig.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, Friendlyspeedy.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();
			}
 
			var postData = {
				'wpMinoredit': FriendlyConfig.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': "请求快速删除([[WP:CSD#" + self.params.normalized.toUpperCase() + "|CSD " + self.params.normalized.toUpperCase() + "]])" + FriendlyConfig.summaryAd,
				'wpTextbox1': code + "\n" + text
			};
			self.post( postData );
		},
		userNotification: function( self ) {
			var nowelcome = FriendlyConfig.welcomeUserOnSpeedyDeletionNotification.indexOf( self.params.normalized ) == -1;
			var form = self.responseXML.getElementById( 'editform' );
			var text = form.wpTextbox1.value;
			text += "\n\{\{subst:db-notice|target=" + wgPageName + "\}\}--\~\~\~\~";
			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': '通知:请求快速删除\[\[' + wgPageName + '\]\].' + FriendlyConfig.summaryAd,
				'wpTextbox1': text
			};
			self.post( postData );
		}
	}
}
 
Friendlyspeedy.callback.evaluateSysop = function FriendlyspeedyCallbackEvaluateSysop(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 Friendlyspeedy.callback.evaluateUser(e);
	}
 
	var value = e.target.value;
	var normalized = Friendlyspeedy.normalizeHash[ value ];
 
	var params = {
		value: value,
		normalized: normalized,
		watch: false,
		reason: Friendlyspeedy.reasonHash[ value ],
		openusertalk: FriendlyConfig.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, Friendlyspeedy.callbacks.sysop.main );
	wikipedia_api.params = params;
	wikipedia_api.post();
}
 
Friendlyspeedy.callback.evaluateUser = function FriendlyspeedyCallbackEvaluateUser(e) {
	wgPageName = wgPageName.replace( /_/g, ' ' ); // for queen/king/whatever and country!
	var value = e.target.value;
	var normalized = Friendlyspeedy.normalizeHash[ value ];
 
	var params = {
		value: value,
		normalized: normalized,
		watch: false,
		usertalk: FriendlyConfig.notifyUserOnSpeedyDeletionNomination.indexOf( normalized ) != -1 && e.target.form.notify.checked,
		rcid: QueryString.exists( 'rcid' ) ? QueryString.get( 'rcid' ) : ''
	};
 
	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, Friendlyspeedy.callbacks.user.main );
	wikipedia_api.params = params;
	wikipedia_api.post();
 
}