注意:儲存之後,你可能要兜過你嘅瀏覽器快取至睇到更改。Internet Explorer: 撳住Ctrl掣再撳重新整理掣。 Firefox: 撳住Shift掣再撳重新載入(又或者撳Ctrl-Shift-R)。 Google Chrome同埋Safari用戶就噉撳個重載掣。
// If TwinkleConfig aint exist.
if( typeof( TwinkleConfig ) == 'undefined' ) {
	TwinkleConfig = function() {};
}

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

function twinkleimage() {
	if( wgNamespaceNumber == 6 ) {
		mw.util.addPortletLink( 'p-cactions', "javascript:twinkleimage.callback()", "di", "tw-di", "Nominate image for relative speedy deletion", "");
	}
}

$(twinkleimage);

twinkleimage.callback = function twinkleimageCallback() {
	var Window = new SimpleWindow( 600, 300 );
	Window.setTitle( "Image for pseudo-speedy deletion" );
	var form = new QuickForm( twinkleimage.callback.evaluate );
	var field = form.append( {
			type: 'field',
			label: 'Type of action wanted'
		} );
	field.append( {
			type: 'radio',
			name: 'type',
			event: twinkleimage.callback.choice,
			list: [
				{
					label: 'No source',
					value: 'no source',
					checked: true,
					tooltip: 'Image or media has no source information'
				},
				{
					label: 'No license',
					value: 'no license',
					tooltip: 'Image or media does not have information on its copyright status'
				},
				{
					label: 'No fair use rationale',
					value: 'no fair use rationale',
					tooltip: 'Image or media is claimed to be used under Wikipedia\'s fair use policy but has no explanation as to why it is permitted under the policy'
				},
				{
					label: 'Disputed fair use rationale',
					value: 'disputed fair use rationale',
					tooltip: 'Image or media has a fair use rationale that is disputed'
				},

				{
					label: 'Orphaned fair use',
					value: 'orphaned fair use',
					tooltip: 'Image or media is unlicensed for use on Wikipedia and allowed only under a claim of fair use per Wikipedia:Non-free content, but it is not used in any articles'
				},
				{
					label: 'Replaceable fair use',
					value: 'replaceable fair use',
					tooltip: 'Image or media may fail Wikipedia\'s first non-free content criterion in that it illustrates a subject for which a free image might reasonably be found or created that adequately provides the same information'
				}
			]
		} );
	form.append( {
			type: 'div',
			label: 'Work area',
			name: 'work_area'
		} );
	var result = form.render();
	Window.setContent( result );
	Window.display();

	// We must init the
	var evt = document.createEvent( "Event" );
	evt.initEvent( 'change', true, true );
	result.type[0].dispatchEvent( evt );
}

twinkleimage.callback.choice = function twinkleimageCallbackChoose(event) {
	var value = event.target.value;
	var root = event.target.form;
	var work_area = new QuickForm.element( { 
			type: 'div',
			name: 'work_area'
		} );

	switch( value ) {
	case 'disputed fair use rationale':
		work_area.append( {
				type: 'textarea',
				name: 'reason',
				label: 'Concern: '
			} );
		break;
	case 'orphaned fair use':
		work_area.append( {
				type: 'input',
				name: 'replacement',
				label: 'Replacement: '
			} );
		break;
	case 'replaceable fair use':
		work_area.append( {
				type: 'checkbox',
				name: 'old_image',
				list: [
					{
						label: 'Old image',
						tooltip: 'Image was uploaded before 2006-07-13'
					}
				]
			} );
		break;
	}
	work_area.append( { type:'submit' } );
	work_area = work_area.render();
	root.replaceChild( work_area, root.lastChild );
}

twinkleimage.callback.evaluate = function twinkleimageCallbackEvaluate(event) {
	var types = event.target.type;
	for( var i = 0; i < types.length; ++i ) {
		if( types[i].checked ) {
			var type = types[i].value;
			break;
		}
	}
	if( event.target.reason ) {
		var reason = event.target.reason.value;
	}
	if( event.target.old_image ) {
		var old_image = event.target.old_image.checked;
	}

	var params = { reason: reason, old_image: old_image, type: type };
	Status.init( event.target );
	
	// Tagging image
	var query = {
		'title': wgPageName,
		'action': 'submit'
	};

	var wikipedia_wiki = new Wikipedia.wiki( 'Tagging image with deletion tag', query, twinkleimage.callbacks.taggingImage );
	wikipedia_wiki.params = params;
	wikipedia_wiki.get();

	// Notifying uploader
	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;
		var query = {
			'title': 'User talk:' + user,
			'action': 'submit'
		};
		var wikipedia_wiki = new Wikipedia.wiki( 'Notifying of initial contributor (' + user + ')', query, twinkleimage.callbacks.userNotification );
		wikipedia_wiki.params = self.params;
		wikipedia_wiki.get();
	}
	var wikipedia_api = new Wikipedia.api( 'Grabbing data of initial contributor', query, callback );
	wikipedia_api.params = params;
	wikipedia_api.post();

	// adding tag to captions
	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, twinkleimage.callbacks.tagInstancesMain );
	wikipedia_api.params = params;
	wikipedia_api.post();
}

twinkleimage.callbacks = {
	taggingImage: function( self ) {
		var form = self.responseXML.getElementById('editform');
		var text = '';
		switch( self.params.type ) {
		case 'disputed fair use rationale':
			text += "\{\{di-disputed fair use rationale|date=\{\{subst:#time:j F Y\}\}" + ( self.params.reason ? "|concern=" + self.params.reason : '') + "\}\}";
			break;
		case 'orphaned fair use':
			text += "\{\{di-orphaned fair use|date=\{\{subst:#time:j F Y\}\}" + ( self.params.reason ? "|replacement=" + self.params.reason : '') + "\}\}";
			break;
		case 'replaceable fair use':
			text += "\{\{di-replaceable fair use|date=\{\{subst:#time:j F Y\}\}" + ( self.params.old_image ? "|old image=yes" : '') + "\}\}";
			break;
		default:
			text += "\{\{di-" + self.params.type + "|date=\{\{subst:#time:j F Y\}\}\}\}";
			break;
		}
		var postData = {
			'wpMinoredit': undefined, // Per 
			'wpWatchthis': form.wpWatchthis.checked ? '' : undefined,
			'wpStarttime': form.wpStarttime.value,
			'wpEdittime': form.wpEdittime.value,
			'wpAutoSummary': form.wpAutoSummary.value,
			'wpEditToken': form.wpEditToken.value,
			'wpSummary': "This image is up for deletion per \[\[WP:CSD\]\]." + TwinkleConfig.summaryAd,
			'wpTextbox1': text + form.wpTextbox1.value
		};
		self.post( postData );
	},
	userNotification: function( self ) {
		var form = self.responseXML.getElementById( 'editform' );
		var text = form.wpTextbox1.value;
		text += "\n\{\{subst:di-" + self.params.type + "-notice|1=" + wgTitle + "\}\} \~\~\~\~";
		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,
			'wpSummary': 'Notification: Deletion of \[\[' + wgPageName + '\]\].' + TwinkleConfig.summaryAd,
			'wpTextbox1': text
		};
		self.post( postData );
	},
	tagInstancesMain: function( self ) {
		var statusIndicator = document.createElement( 'div' );
		Status.status( [ statusIndicator ] );
		statusIndicator.appendChild( document.createTextNode( 'Tagging instances image, status: ' ) );
		statusIndicator.appendChild( document.createTextNode( '0%' ) );
		var xmlDoc = self.responseXML;
		var nsResolver = xmlDoc.createNSResolver( xmlDoc.ownerDocument == null ? xmlDoc.documentElement : xmlDoc.ownerDocument.documentElement);
		var snapshot = xmlDoc.evaluate('//imageusage/iu/@title', xmlDoc, nsResolver, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );

		var total = snapshot.snapshotLength * 2;

		imageTaggingCounter = 0;
		var onsuccess = function( wikipedia_wiki ) {
			var obj = wikipedia_wiki.params.obj;
			var total = wikipedia_wiki.params.total;
			obj.replaceChild( document.createTextNode( parseInt( 100 * ++imageTaggingCounter/total ) + '%' ), obj.lastChild );
			if( imageTaggingCounter == total ) {
				Status.info( 'tagging of instances completed.' );
				Wikipedia.removeCheckpoint();
			}
		}
		var onloaded = onsuccess;

		var onloading = function( self ) {}


		Wikipedia.addCheckpoint();
		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( "Tagging of " + title, query, twinkleimage.callbacks.tagInstances );
			wikipedia_wiki.params = { title:title, total:total, obj:statusIndicator, days: self.params.old_image ? 2 : 7 };
			wikipedia_wiki.onloading = onloading;
			wikipedia_wiki.onloaded = onloaded;
			wikipedia_wiki.onsuccess = onsuccess;
			wikipedia_wiki.get();
		}
	},
	tagInstances: function( self ) {
		var form = self.responseXML.getElementById('editform');
		var text = form.wpTextbox1.value;
		var old_text = text;
		var wikiPage = new Mediawiki.Page( text );

		var tag = "\{\{deletable image-caption|1=\{\{subst:#time:l, j F Y| + " + self.params.days + " days\}\}\}\}";
		wikiPage.addToImageComment( wgTitle, tag );

		text = wikiPage.getText();
		if( text == old_text ) {
			// Nothing to do, return
			self.onsuccess( self );
			Wikipedia.actionCompleted();
			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,
			'wpSummary': 'Tagging [[:Image:' + wgTitle + "]] which is up for deletion per [[WP:CSD|CSD]] " + TwinkleConfig.summaryAd,
			'wpTextbox1': text
		};
		self.post( postData );
	}
}