MediaWiki:MultipleFileDelete.js

// /** * Selectively delete multiple files or pages directly on certain special pages. * Based on WHAM2 code by Ozuzanna. * @author Spottra  * @author KhangND  * @author Thundercraft5  */ /* jshint esversion: 5 */ (function($, mw) {	var userGroups = mw.config.get("wgUserGroups"),		specialPage = mw.config.get("wgCanonicalSpecialPageName"),		supportedPages = [			[				'Listredirects',				'Lonelypages',				'Ancientpages',				'Fewestrevisions',				'Withoutinterwiki',				'Shortpages',				'Uncategorizedfiles',				'Uncategorizedpages',				'Uncategorizedtemplates',				'Unorganizedtemplates',				'Unusedcategories',				'Unusedtemplates',				'BrokenRedirects',				'Unusedcategories',				'Unusedtemplates',				'Deadendpages',				'Shortpages',			], [				'Allpages',				'Prefixindex',				'Whatlinkshere',			], [				'Unusedimages',				'Newimages'			],		];

const strings = { start: 'Selective Delete', delete:	'Delete Selected', check: 'Check All', uncheck: 'Uncheck All', noselect: 'No files selected.', enter: 'Please enter the delete reason!', reason: 'Housekeeping', error: 'Failed to delete', success: 'Successfully deleted', invert: 'Invert selection', uninvert: 'Uninvert selection' };

var logger = (function {		Object.keys(this).forEach(function(method) { this[method] = this[method].bind(null, '[MultipleFileDelete] [' + method.toUpperCase + ']:'); }, this);

return this; }).call({ error: console.error, warn: console.warn, log: console.log, debug: mw.log, });

// load protections if (!supportedPages.flat.includes(specialPage) // not from list		|| !/staff|sysop|content-moderator|wiki-specialist|wiki-representative|soap/.test(userGroups.join('\n')) //not in group		|| window.mfdLoaded // double loading		// exclude page(s)		|| (window.mfdExclude && (window.mfdExclude === page || window.mfdExclude.indexOf(page) >= 0))		) { return logger.log('Page is not supported, or script is double loading, exiting...'); }

window.mfdLoaded = true;

var btnProps = { css: { cursor: 'pointer', height: 'initial', 'margin-left': 3, }		},		$wrapper = $, $oldButton, specialPageType = supportedPages.findIndex(function(pages) {			return pages.indexOf(specialPage) >= 0;		}) + 1, time = 0, wgArticlePath = mw.config.get('wgArticlePath').replace(/\$1/, ''); api = new mw.Api, i18Messages = [ 'start', 'delete', 'check', 'uncheck', 'enter', 'reason', 'noselect', 'error', 'success', 'uninvert', 'invert', ];

function init { // create wrapper with start button $wrapper = $(' ', {			html: $(' ', $.extend({				class: 'btn-mfd-start',				text: strings.start,				click: start,			}, btnProps))		});

$([			'.mw-allpages-body', 			'.mw-prefixindex-body', 			'.mw-spcontent > p:first-of-type',			'.mw-spcontent > p:last-of-type',			'body.mw-special-Whatlinkshere #mw-content-text > p:first-of-type',			'body.mw-special-Newimages .mw-body-content',		].join(', ')).before($wrapper);

$([			'.mw-prefixindex-body', 			'.mw-allpages-body',			'body.mw-special-Whatlinkshere #mw-content-text'		].join(', ')).after($wrapper.clone); }

function start { $('.btn-mfd-start').after(			// delete button			$(' ', $.extend({				class: 'btn-mfd-delete',				text: strings.delete,				click: performDelete,			}, btnProps)),			// check all button			$(' ', $.extend({				class: "btn-mfd-check",				text: strings.check,				click: performCheck,			}, btnProps)),			// invert selection button			$(' ', $.extend({				class: "btn-mfd-invert",				text: strings.invert,				click: invertSelection,			}, btnProps))		); $oldButton = $('.btn-mfd-start').remove;

// create checkboxes and add before items var $chk = $(' ', {			class: "selectiveDel",			type: "checkbox",		});

switch (specialPageType) { case 1: mw.util.$content.find('ol li a:first-child').each(function {					$(this).before($chk.clone);					selectHax(this);				});

break; case 2: if ($('.mw-allpages-chunk').length) { // Allpages $('.mw-allpages-chunk li > a').each(function {						$(this).before($chk.clone);						selectHax(this);					}); } else if ($('#mw-whatlinkshere-list').length) { // WhatLinksHere $('#mw-whatlinkshere-list > li > a').each(function {						$(this).before($chk.clone);						selectHax(this);					}); } else { //PrefixIndex $('.mw-prefixindex-list > li a, .gallery-image-wrapper').each(function {						$(this).before($chk.clone);						selectHax(this);					}); }

break; default: $('.gallerytext > a, .gallery-image-wrapper').each(function {					$(this).has('.image.lightbox').before($chk.clone);					selectHax(this);				}); }	}

function performDelete { var selected = $('.selectiveDel:checked'); if (!selected.length) return alert(strings.noselect);

var deleteReason = prompt(strings.enter, strings.reason); if (!deleteReason) return; // lock delete button $(this) .attr('disabled', true) .text("Deleting Pages...") .css({				'background-repeat': 'no-repeat',				'background-position': 'center'			});

selected.each(function(i) {			var $link = $(this).parent.find('a').first;			var page;

if (specialPageType === 3) { page = $link.attr('href') .replace(wgArticlePath, '') .replace(mw.config.get('wgServer'), ''); } else { page = $link.attr('title') || $link.text; }

apiDelete(				page,				deleteReason,				$link,				i+1,				selected.length // reload indicator			); });	}

function performCheck { var $btn = $('.btn-mfd-check'); var $checkboxes = $('.selectiveDel'); if ($btn.first.text === strings.uncheck) { $checkboxes.each(function {				this.checked = false;			});

$btn.text(strings.check); } else { $checkboxes.each(function {				this.checked = true;			});

$btn.text(strings.uncheck); }		displayCount; }

function selectHax(elem) { // parent select hacks var $elem = $(elem); var $parent = $elem.parent;

$parent.hover(function {			$(this).css({ cursor: 'pointer', background: 'rgba(0,0,0,.2)' });		}, function {			$(this).css({ background: 'initial' });		});

$parent.click(function(e) {			if (e.target === this) { // prevent event double firing				var input = $(this).children('input')[0];				input.checked = !input.checked;			}			displayCount;		}); }

function invertSelection { $('.selectiveDel').each(function {			this.checked = !this.checked;		}); $(this).text($(this).text === strings.invert ? strings.uninvert : strings.invert); displayCount; }

function displayCount { $('.btn-mfd-delete').text(			strings.delete			+ ' (' + $('.selectiveDel:checked').length + ')');	}

function reset { $('.btn-mfd-delete') .attr('disabled', false) .text(strings.delete) .css({				'background-image': "",			});

$('.btn-mfd-check').text(strings.check); $('.btn-mfd-invert').text(strings.invert); }

function apiDelete(page, reason, $link, cur, count) { page = decodeURIComponent(page); // Api doesn't like percent encodes page names

api.postWithEditToken({			format: 'json',			action: 'delete',			title: page,			reason: reason,			bot: true		}).then(function(d) {			mw.notify('Successfully deleted ' + page);			logger.log('Successfully deleted ' + page);			var $target = specialPageType === 3 ? $link.parent.parent.parent : $link.parent;			$target.remove;

if (cur === count) { reset; }

}, function(_, e) { mw.notify('Failed to delete deleted ' + page + ": " + e.error.info, { type: "warn" }); logger.warn('Failed to delete deleted ' + page + ": " + e.error.info); });	}

mw.loader.using('mediawiki.api').done(function {		init;	}); })(this.jQuery, this.mediaWiki);