跳到内容

MediaWiki:Gadget-autodel.js

来自国际维基教材——一个开放世界的免费教材
提示:保存后,修改可能不会立即生效,点击此处以了解如何绕过浏览器的缓存。
  • Mozilla/Firefox/Safari:按住Shift键的同时点击“Reload”,或按下Ctrl-Shift-R(苹果 Mac 上为Cmd-Shift-R);
  • Internet Explorer:按住Ctrl键的同时点击“Refresh”,或按下Ctrl-F5
  • Konqueror:直接点击“Reload”按钮,或按下F5
  • Opera用户可能需要在工具 → 首选项中彻底清除缓存。
/**
 * Replacement for the old [[MediaWiki:Gadget-autodel.js]] that is now on [[User:Mike.lifeguard/Gadget-autodel.js]]
 * Eases deletion of pages
 * Documentation at [[Help:Gadget-autodel.js]]
 *
 * @rev 1 (2012-07-02)
 * @author Rillke, 2012
 */
// List the global variables for jsHint-Validation. Please make sure that it passes https://jshint.node.org.cn/
// Scheme: globalVariable:allowOverwriting[, globalVariable:allowOverwriting][, globalVariable:allowOverwriting]
/*global jQuery:false, mediaWiki:false*/
 
// Set jsHint-options. You should not set forin or undef to false if your script does not validate.
/*jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, curly:false, browser:true*/
 
( function ( $, mw ) {
"use strict";
 
var autoDel = null,
	server = mw.config.get('wgServer'),
	articlePath = mw.config.get('wgArticlePath');
	

if ( (-1 === $.inArray(mw.config.get('wgCanonicalSpecialPageName'), ['Contributions', 'Whatlinkshere', 'Log', 'Prefixindex', 'Newpages'])) &&
	(!mw.config.get('wgArticleId') || -1 === $.inArray(mw.config.get('wgAction'), ['submit', 'view', 'edit', 'delete'])) ) return;
	
mw.util.addCSS('.autodel-dellink { background-color:#CEEDB4; font-size:.8em; position:relative; top:-0.5em; }');
 
autoDel = {
	aDelInstall: function() {
		var p = mw.util.addPortletLink('p-cactions', '#', 'Add DeleteLinks', 'ca-dellink', 'generate deletion links');
		if (p) {
			p = $(p);
		} else {
			return;
		}
		p.click(function(e) {
			e.preventDefault();
			autoDel.tasks = ['aDelQueryDefaultReason', 'aDelAddDelLinks'];
			autoDel.nextTask();
		});
		
		if ('delete' === mw.config.get('wgAction') && mw.util.getParamValue('submitdelete')) {
			$('#mw-content-text').prepend($('<p>').addClass('error').text(
				"Either you are using an old version of autoDel or you opened a link in a new tab. " +
				"Deletion via URL is evil and therefore not done. " + 
				"If you are using the latest version of autoDel, simply click the delete link. " + 
				"An in-page-dialog will be opened. You can submit deletion immediately pressing the enter-key. " +
				"While it makes your account vulnerable, you can skip this dialog adding "
			), $('<code>', { text: 'window.skipAutodelConfirm = true;' }),
			$('<a>', { text: " to your common.js", href: 'Special:MyPage/common.js' }),
			$('<p>').addClass('error').text(
				"If you decided to add it to your js, be careful where you are clicking and double-check the tool tips."
			));
		}
		
		// Providing functionality for {{Instant-nuke}}
		// Additional safeguard: only run on the delinker-command-page or those the user wants it
		window.autodelPages = $.extend({'User:CommonsDelinker/commands': true}, window.autodelPages);
		if (!window.autodelPages[mw.config.get('wgPageName')]) return;
		
		var $ins = $('.instant-nuke').css('display', 'inline-block').attr('title', 'Invoke immediate deletion');
		$ins.each(function(i, el) {
			try {
				var $el = $(el),
					h = $el.find('a:first').attr('href'),
					pg_ = mw.util.getParamValue('title', h),
					pg = pg_.replace(/_/g, ' '),
					r = mw.util.getParamValue('wpReason', h),
					bt = $el.find('.selToBlock').text(),
					$b = $el.parents(bt),
					// WikiUrlencode does too much, same for encodeURIComponent
					$ol = $b.find('a[href$="' + encodeURI(pg_).replace(/\'/g, '%27').replace(/\"/g, '%22') + '"]');
				
				$el.data('autoDel', { page: pg, $parent: $b, $oLink: $ol, reason: r });
				
				if (!autoDel.aDelPages[pg]) autoDel.aDelPages[pg] = [];
				autoDel.aDelPages[pg].push($el);
				
				$(el).find('a').attr('title', 'Delete ' + pg);
				
				$el.click(autoDel.__aDelConfirmDelete);
			} catch (ex) {}
		});
	},
	aDelQueryDefaultReason: function() {
		var c = mw.cookie.get('com-autodel-reason');
		
		this.reason = c || 'per [[COM:SPEEDY]]';
		this.prompt([{
			message: 'default reason',
			prefill: this.reason,
			returnvalue: 'reason',
			cleanUp: true,
			noEmpty: true,
			byteLimit: 250,
			parseReason: true
		}], "Adding links: Set the default reason.");
	},
	aDelAddDelLinks: function() {
		if (this.delLinksAdded) return;
		
		var tryDecode = function(title) {
			try {
				// MediaWiki also encodes "=" even if not required (not a query string)
				if (title) title = decodeURIComponent(title);
				return title;
			} catch(ex2) {
				try {
					if (title) title = decodeURI(title);
				} catch (ex) {}
				return title;
			}
		};
	
		var tryDecodeComponent = function(title) {
			try {
				if (title) title = decodeURIComponent(title);
			} catch (ex) {}
			return title;
		};
	
		var addLink = function(pg, $el) {
			if (!pg) return;
			if (0 === pg.indexOf(mw.config.get('wgFormattedNamespaces')[-1])) return;
			
			pg = pg.replace(/_/g, ' ');
			
			var $dLink = $('<a>', { 'class': 'autodel-dellink', href: '#', text: 'Delete!', title: 'Delete ' + pg });
			$el.wrap('<span>').after($dLink);
				
			$dLink.data('autoDel', { page: pg, $parent: $el.parent(), $oLink: $el });
			$dLink.click(autoDel.__aDelConfirmDelete);
			
			if (!autoDel.aDelPages[pg]) autoDel.aDelPages[pg] = [];
			autoDel.aDelPages[pg].push($dLink);
			
			return true;
		};
		
		$('#mw-content-text').find('a').each(function(i, el) {
			var $el = $(el),
				h = $el.attr('href'),
				pg, REArticle, m;
				
			if ($el.hasClass('new')) return;

			pg = mw.util.getParamValue('title', h);			
			if (addLink(tryDecodeComponent(pg), $el)) return;
			
			REArticle = new RegExp('^' + mw.RegExp.escape(articlePath.replace('$1', '')) + '(.+?)(?:#.*)?$');
			m = h.match(REArticle);
			if (m) if (addLink(tryDecode(m[1]), $el)) return;
			
			REArticle = new RegExp(mw.RegExp.escape(server + articlePath.replace('$1', '')) + '(.+?)(?:#.*)?$');
			m = h.match(REArticle);
			if (m) if (addLink(tryDecode(m[1]), $el)) return;
			
		});
		this.delLinksAdded = true;
		
		// Finally save the reason into a cookie
		mw.cookie.set('com-autodel-reason', this.reason, {
			expires: 14, // expires in 14 days
			path: '/' // domain-wide, entire wiki
		});
	},
	__aDelConfirmDelete: function(e) {
		e.preventDefault();
		e.stopPropagation();
		
		var $dLink = $(this),
			d = $dLink.data('autoDel'),
			$toRemove = $dLink,
			$toBlock = d.$parent, 
			$toSetNew = d.$oLink;
		
		// Add all links with the same target page
		$.each(autoDel.aDelPages[d.page], function(i, el) {
			var $el = $(el),
				di = $el.data('autoDel');
			
			if (!di) return;
			$toRemove = $toRemove.add($el);
			$toBlock  = $toBlock.add(di.$parent);
			$toSetNew = $toSetNew.add(di.$oLink);
		});
		var wasValidLink = !!$dLink.inView().length && (/[Dd]elete/.test($dLink.text()) || /\/16px-Gr%C3%BCnerm%C3%BClleimer\.svg\.png$/.test($dLink.find('img').attr('src')) && $dLink.find('img').inView().length );
		// The last param is the check whether the delete-link was probably faked
		autoDel.secureCall('aDelConfirmDelete', d.page, $toRemove, $toBlock, $toSetNew, d.reason, wasValidLink);
	},
	aDelFillInfoNode: function(page, $node) {
		var query, isFile = (0 === page.indexOf(mw.config.get('wgFormattedNamespaces')[6]));
		if (isFile) {
			query = {
				action: 'query',
				prop: 'imageinfo|info',
				intoken: 'delete',
				iiprop: 'user|timestamp|url',
				iiurlwidth: 250,
				iiurlheight: 250,
				iilimit: 1,
				titles: page
			};
		} else {
			query = {
				action: 'query',
				prop: 'info|revisions',
				rvprop: 'user|timestamp',
				rvlimit: 1,
				rvdir: 'newer',
				intoken: 'delete',
				titles: page
			};
		}
		this.queryAPI(query, function(r) {
			var pgs = r.query.pages,
				rv,
				type = "page",
				pg;
			$.each(pgs, function(i, pgObj) {
				pg = pgObj;
			});

			autoDel.deletetoken = pg.deletetoken;
			
			$node.append($('<div>').append(
				$('<span>').text("You are going to delete "), 
				$('<a>', { href: mw.util.getUrl(pg.title), text: pg.title }),
				$('<span>').text(" (" + pg.length + " Bytes, PageID: " + pg.pageid + ", Changed: " + pg.touched + ").")
			));
			if ('undefined' !== typeof pg.missing) return $('.ui-dialog').find('.ui-button-green').button('option', 'disabled', true);
			if (isFile) {
				if (!pg.imageinfo) return;
				rv = pg.imageinfo[0];
				type = "file";
				$node.append($('<img>', { src: rv.thumburl, height: rv.height, width: rv.width }));
			} else {
				if (!pg.revisions) return;
				rv = pg.revisions[0];
			}
			$node.append($('<div>').text("This " + type + " was created by " + rv.user + " on " + rv.timestamp ));
		});
	},
	aDelConfirmDelete: function(page, $dLink, $toBlock, $toSetNew, reason, wasValidLink) {
		var $infoNode = $('<div>', { css: { 'min-height': '300px' } });
	
		this.tasks = ['aDelExecDelete'];
		this.pageToDelete = page;
		this.$toRemove = $dLink;
		this.$toBlock = $toBlock;
		this.$toSetNew = $toSetNew;
		
		// WARNING: SETTING THIS IN YOUR common.js WILL IMMEDIATELY DELETE ON CLICK
		// Always watch the tooltip to prevent accidental wrong deletions
		// You are responsible if you delete the world!
		if (window.skipAutodelConfirm && wasValidLink) {
			if (reason) this.reason = reason;
			return this.nextTask();
		}
		
		this.secureCall('aDelFillInfoNode', page, $infoNode);
		
		this.prompt([{
			message: 'Delete reason (used in the deletion log)',
			prefill: reason || this.reason,
			returnvalue: 'reason',
			cleanUp: true,
			appendNode: $infoNode,
			noEmpty: true,
			byteLimit: 250,
			parseReason: true
		}], "WARNING: You are going to DELETE " + page);
	},
	aDelExecDelete: function() {
		var $toRemove = this.$toRemove,
			$toBlock = this.$toBlock,
			$toSetNew = this.$toSetNew,
			pg = autoDel.pageToDelete;
			
		$toBlock.block({ message: 'Deleting', css: { color: '#A0C828', fontWeight: 'bold', background:'none', border:'none', width: '8em' } });
		if (autoDel.deletetoken) mw.user.tokens.set('deleteToken', autoDel.deletetoken);
		
		mw.loader.using(['ext.gadget.libAPI'], function() {
			mw.libs.commons.api.deletePage({
				cb: function() {
					autoDel.secureCall('aDelExecDeleteCB', $toBlock, $toSetNew, $toRemove, pg);
				},
				// r-result, query, text
				errCb: function(t, r, q) {
					if (r && r.error && r.error.code === 'missingtitle') {
						$toBlock.block({ message: 'Not found!', css: { color: '#C8A028', fontWeight: 'bold', background:'none', border:'none', width: '10em' } });
						$toBlock.unblock( { fadeOut: 5000 } );
					} else {
						$toBlock.unblock();
						autoDel.fail(t);
					}
				},
				title: pg,
				reason: autoDel.reason
			});
			//console.log(pg); autoDel.aDelExecDeleteCB()
		});
	},
	aDelExecDeleteCB: function($toBlock, $toSetNew, $toRemove, pg) {
		$toBlock.unblock();
		$toSetNew.addClass('new');
		if ($toSetNew.hasClass('image')) $toSetNew.find('img').fadeTo(500, 0.5);
		$toRemove.remove();
		delete this.aDelPages[pg];
	},
	aDelPages: {}
};

mw.loader.using([
	'ext.gadget.jquery.blockUI', 
	'ext.gadget.AjaxQuickDelete', 
	'ext.gadget.jquery.in-view', 
	'mediawiki.util', 
	'mediawiki.user', 
	'mediawiki.cookie',
	'user'
], function() {
	// Merge into AjaxQuickDelete
	autoDel = $.extend(window.AjaxQuickDelete, autoDel);

	// Fire off the rest as soon as the dom is ready
	$( document ).ready( function() { autoDel.secureCall('aDelInstall'); } );
});

}( jQuery, mediaWiki ));
华夏公益教科书