<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.endmyopia.org/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AGadget-twinklebatchdelete.js</id>
	<title>MediaWiki:Gadget-twinklebatchdelete.js - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.endmyopia.org/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AGadget-twinklebatchdelete.js"/>
	<link rel="alternate" type="text/html" href="https://wiki.endmyopia.org/index.php?title=MediaWiki:Gadget-twinklebatchdelete.js&amp;action=history"/>
	<updated>2026-05-06T20:30:58Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>https://wiki.endmyopia.org/index.php?title=MediaWiki:Gadget-twinklebatchdelete.js&amp;diff=8599&amp;oldid=prev</id>
		<title>NottNott: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://wiki.endmyopia.org/index.php?title=MediaWiki:Gadget-twinklebatchdelete.js&amp;diff=8599&amp;oldid=prev"/>
		<updated>2020-06-12T10:46:06Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 10:46, 12 June 2020&lt;/td&gt;
				&lt;/tr&gt;
&lt;!-- diff cache key jakeendmy_mw1720-mwnr_:diff::1.12:old-8598:rev-8599 --&gt;
&lt;/table&gt;</summary>
		<author><name>NottNott</name></author>
	</entry>
	<entry>
		<id>https://wiki.endmyopia.org/index.php?title=MediaWiki:Gadget-twinklebatchdelete.js&amp;diff=8598&amp;oldid=prev</id>
		<title>en&gt;Amorymeltzer: Repo at ffe5bbed: Use Morebits.date .calendar to format protection confirmations/notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.endmyopia.org/index.php?title=MediaWiki:Gadget-twinklebatchdelete.js&amp;diff=8598&amp;oldid=prev"/>
		<updated>2020-04-25T17:26:32Z</updated>

		<summary type="html">&lt;p&gt;Repo at ffe5bbed: Use Morebits.date .calendar to format protection confirmations/notes&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;// &amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function($) {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 ****************************************&lt;br /&gt;
 *** twinklebatchdelete.js: Batch delete module (sysops only)&lt;br /&gt;
 ****************************************&lt;br /&gt;
 * Mode of invocation:     Tab (&amp;quot;D-batch&amp;quot;)&lt;br /&gt;
 * Active on:              Existing non-articles, and Special:PrefixIndex&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
Twinkle.batchdelete = function twinklebatchdelete() {&lt;br /&gt;
	if (&lt;br /&gt;
		Morebits.userIsSysop &amp;amp;&amp;amp; (&lt;br /&gt;
			(mw.config.get('wgCurRevisionId') &amp;amp;&amp;amp; mw.config.get('wgNamespaceNumber') &amp;gt; 0) ||&lt;br /&gt;
			mw.config.get('wgCanonicalSpecialPageName') === 'Prefixindex'&lt;br /&gt;
		)&lt;br /&gt;
	) {&lt;br /&gt;
		Twinkle.addPortletLink(Twinkle.batchdelete.callback, 'D-batch', 'tw-batch', 'Delete pages found in this category/on this page');&lt;br /&gt;
	}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
Twinkle.batchdelete.unlinkCache = {};&lt;br /&gt;
&lt;br /&gt;
// Has the subpages list been loaded?&lt;br /&gt;
var subpagesLoaded;&lt;br /&gt;
&lt;br /&gt;
Twinkle.batchdelete.callback = function twinklebatchdeleteCallback() {&lt;br /&gt;
	subpagesLoaded = false;&lt;br /&gt;
	var Window = new Morebits.simpleWindow(600, 400);&lt;br /&gt;
	Window.setTitle('Batch deletion');&lt;br /&gt;
	Window.setScriptName('Twinkle');&lt;br /&gt;
	Window.addFooterLink('Twinkle help', 'WP:TW/DOC#batchdelete');&lt;br /&gt;
&lt;br /&gt;
	var form = new Morebits.quickForm(Twinkle.batchdelete.callback.evaluate);&lt;br /&gt;
	form.append({&lt;br /&gt;
		type: 'checkbox',&lt;br /&gt;
		list: [&lt;br /&gt;
			{&lt;br /&gt;
				label: 'Delete pages',&lt;br /&gt;
				name: 'delete_page',&lt;br /&gt;
				value: 'delete',&lt;br /&gt;
				checked: true,&lt;br /&gt;
				subgroup: {&lt;br /&gt;
					type: 'checkbox',&lt;br /&gt;
					list: [&lt;br /&gt;
						{&lt;br /&gt;
							label: 'Delete associated talk pages (except user talk pages)',&lt;br /&gt;
							name: 'delete_talk',&lt;br /&gt;
							value: 'delete_talk',&lt;br /&gt;
							checked: true&lt;br /&gt;
						},&lt;br /&gt;
						{&lt;br /&gt;
							label: 'Delete redirects to deleted pages',&lt;br /&gt;
							name: 'delete_redirects',&lt;br /&gt;
							value: 'delete_redirects',&lt;br /&gt;
							checked: true&lt;br /&gt;
						},&lt;br /&gt;
						{&lt;br /&gt;
							label: 'Delete subpages of deleted pages',&lt;br /&gt;
							name: 'delete_subpages',&lt;br /&gt;
							value: 'delete_subpages',&lt;br /&gt;
							checked: false,&lt;br /&gt;
							event: Twinkle.batchdelete.callback.toggleSubpages,&lt;br /&gt;
							subgroup: {&lt;br /&gt;
								type: 'checkbox',&lt;br /&gt;
								list: [&lt;br /&gt;
									{&lt;br /&gt;
										label: 'Delete talk pages of deleted subpages',&lt;br /&gt;
										name: 'delete_subpage_talks',&lt;br /&gt;
										value: 'delete_subpage_talks'&lt;br /&gt;
									},&lt;br /&gt;
									{&lt;br /&gt;
										label: 'Delete redirects to deleted subpages',&lt;br /&gt;
										name: 'delete_subpage_redirects',&lt;br /&gt;
										value: 'delete_subpage_redirects'&lt;br /&gt;
									},&lt;br /&gt;
									{&lt;br /&gt;
										label: 'Unlink backlinks to each deleted subpage (in Main and Portal namespaces only)',&lt;br /&gt;
										name: 'unlink_subpages',&lt;br /&gt;
										value: 'unlink_subpages'&lt;br /&gt;
									}&lt;br /&gt;
								]&lt;br /&gt;
							}&lt;br /&gt;
						}&lt;br /&gt;
					]&lt;br /&gt;
				}&lt;br /&gt;
			},&lt;br /&gt;
			{&lt;br /&gt;
				label: 'Unlink backlinks to each page (in Main and Portal namespaces only)',&lt;br /&gt;
				name: 'unlink_page',&lt;br /&gt;
				value: 'unlink',&lt;br /&gt;
				checked: false&lt;br /&gt;
			},&lt;br /&gt;
			{&lt;br /&gt;
				label: 'Remove usages of each file (in all namespaces)',&lt;br /&gt;
				name: 'unlink_file',&lt;br /&gt;
				value: 'unlink_file',&lt;br /&gt;
				checked: true&lt;br /&gt;
			}&lt;br /&gt;
		]&lt;br /&gt;
	});&lt;br /&gt;
	form.append({&lt;br /&gt;
		type: 'input',&lt;br /&gt;
		name: 'reason',&lt;br /&gt;
		label: 'Reason: ',&lt;br /&gt;
		size: 60&lt;br /&gt;
	});&lt;br /&gt;
&lt;br /&gt;
	var query = {&lt;br /&gt;
		'action': 'query',&lt;br /&gt;
		'prop': 'revisions|info|imageinfo',&lt;br /&gt;
		'inprop': 'protection',&lt;br /&gt;
		'rvprop': 'size|user'&lt;br /&gt;
	};&lt;br /&gt;
&lt;br /&gt;
	// On categories&lt;br /&gt;
	if (mw.config.get('wgNamespaceNumber') === 14) {&lt;br /&gt;
		query.generator = 'categorymembers';&lt;br /&gt;
		query.gcmtitle = mw.config.get('wgPageName');&lt;br /&gt;
		query.gcmlimit = Twinkle.getPref('batchMax');&lt;br /&gt;
&lt;br /&gt;
	// On Special:PrefixIndex&lt;br /&gt;
	} else if (mw.config.get('wgCanonicalSpecialPageName') === 'Prefixindex') {&lt;br /&gt;
&lt;br /&gt;
		query.generator = 'allpages';&lt;br /&gt;
		query.gaplimit = Twinkle.getPref('batchMax');&lt;br /&gt;
		if (mw.util.getParamValue('prefix')) {&lt;br /&gt;
			query.gapnamespace = mw.util.getParamValue('namespace');&lt;br /&gt;
			query.gapprefix = mw.util.getParamValue('prefix');&lt;br /&gt;
		} else {&lt;br /&gt;
			var pathSplit = decodeURIComponent(location.pathname).split('/');&lt;br /&gt;
			if (pathSplit.length &amp;lt; 3 || pathSplit[2] !== 'Special:PrefixIndex') {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			var titleSplit = pathSplit[3].split(':');&lt;br /&gt;
			query.gapnamespace = mw.config.get('wgNamespaceIds')[titleSplit[0].toLowerCase()];&lt;br /&gt;
			if (titleSplit.length &amp;lt; 2 || typeof query.gapnamespace === 'undefined') {&lt;br /&gt;
				query.gapnamespace = 0;  // article namespace&lt;br /&gt;
				query.gapprefix = pathSplit.splice(3).join('/');&lt;br /&gt;
			} else {&lt;br /&gt;
				pathSplit = pathSplit.splice(4);&lt;br /&gt;
				pathSplit.splice(0, 0, titleSplit.splice(1).join(':'));&lt;br /&gt;
				query.gapprefix = pathSplit.join('/');&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	// On normal pages&lt;br /&gt;
	} else {&lt;br /&gt;
		query.generator = 'links';&lt;br /&gt;
		query.titles = mw.config.get('wgPageName');&lt;br /&gt;
		query.gpllimit = Twinkle.getPref('batchMax');&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	var statusdiv = document.createElement('div');&lt;br /&gt;
	statusdiv.style.padding = '15px';  // just so it doesn't look broken&lt;br /&gt;
	Window.setContent(statusdiv);&lt;br /&gt;
	Morebits.status.init(statusdiv);&lt;br /&gt;
	Window.display();&lt;br /&gt;
&lt;br /&gt;
	Twinkle.batchdelete.pages = {};&lt;br /&gt;
&lt;br /&gt;
	var statelem = new Morebits.status('Grabbing list of pages');&lt;br /&gt;
	var wikipedia_api = new Morebits.wiki.api('loading...', query, function(apiobj) {&lt;br /&gt;
		var xml = apiobj.responseXML;&lt;br /&gt;
		var $pages = $(xml).find('page').filter(':not([missing])');  // :not([imagerepository=&amp;quot;shared&amp;quot;])&lt;br /&gt;
		$pages.each(function(index, page) {&lt;br /&gt;
			var $page = $(page);&lt;br /&gt;
			var ns = $page.attr('ns');&lt;br /&gt;
			var title = $page.attr('title');&lt;br /&gt;
			var isRedir = $page.attr('redirect') === '';&lt;br /&gt;
			var $editprot = $page.find('pr[type=&amp;quot;edit&amp;quot;][level=&amp;quot;sysop&amp;quot;]');&lt;br /&gt;
			var isProtected = $editprot.length &amp;gt; 0;&lt;br /&gt;
			var size = $page.find('rev').attr('size');&lt;br /&gt;
&lt;br /&gt;
			var metadata = [];&lt;br /&gt;
			if (isRedir) {&lt;br /&gt;
				metadata.push('redirect');&lt;br /&gt;
			}&lt;br /&gt;
			if (isProtected) {&lt;br /&gt;
				metadata.push('fully protected' +&lt;br /&gt;
				($editprot.attr('expiry') === 'infinity' ? ' indefinitely' : ', expires ' + new Morebits.date($editprot.attr('expiry')).calendar('utc') + ' (UTC)'));&lt;br /&gt;
			}&lt;br /&gt;
			if (ns === '6') {  // mimic what delimages used to show for files&lt;br /&gt;
				metadata.push('uploader: ' + $page.find('ii').attr('user'));&lt;br /&gt;
				metadata.push('last edit from: ' + $page.find('rev').attr('user'));&lt;br /&gt;
			} else {&lt;br /&gt;
				metadata.push(size + ' bytes');&lt;br /&gt;
			}&lt;br /&gt;
			Twinkle.batchdelete.pages[title] = {&lt;br /&gt;
				label: title + (metadata.length ? ' (' + metadata.join('; ') + ')' : ''),&lt;br /&gt;
				value: title,&lt;br /&gt;
				checked: true,&lt;br /&gt;
				style: isProtected ? 'color:red' : ''&lt;br /&gt;
			};&lt;br /&gt;
		});&lt;br /&gt;
&lt;br /&gt;
		var form = apiobj.params.form;&lt;br /&gt;
		form.append({ type: 'header', label: 'Pages to delete' });&lt;br /&gt;
		form.append({&lt;br /&gt;
			type: 'button',&lt;br /&gt;
			label: 'Select All',&lt;br /&gt;
			event: function dBatchSelectAll() {&lt;br /&gt;
				$(result).find('input[name=pages]:not(:checked)').each(function(_, e) {&lt;br /&gt;
					e.click(); // check it, and invoke click event so that subgroup can be shown&lt;br /&gt;
				});&lt;br /&gt;
&lt;br /&gt;
				// Check any unchecked subpages too&lt;br /&gt;
				$('input[name=&amp;quot;pages.subpages&amp;quot;]').prop('checked', true);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
		form.append({&lt;br /&gt;
			type: 'button',&lt;br /&gt;
			label: 'Deselect All',&lt;br /&gt;
			event: function dBatchDeselectAll() {&lt;br /&gt;
				$(result).find('input[name=pages]:checked').each(function(_, e) {&lt;br /&gt;
					e.click(); // uncheck it, and invoke click event so that subgroup can be hidden&lt;br /&gt;
				});&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
		form.append({&lt;br /&gt;
			type: 'checkbox',&lt;br /&gt;
			name: 'pages',&lt;br /&gt;
			id: 'tw-dbatch-pages',&lt;br /&gt;
			list: $.map(Twinkle.batchdelete.pages, function (e) {&lt;br /&gt;
				return e;&lt;br /&gt;
			})&lt;br /&gt;
		});&lt;br /&gt;
		form.append({ type: 'submit' });&lt;br /&gt;
&lt;br /&gt;
		var result = form.render();&lt;br /&gt;
		apiobj.params.Window.setContent(result);&lt;br /&gt;
&lt;br /&gt;
		var pageCheckboxes = Morebits.quickForm.getElements(result, 'pages') || [];&lt;br /&gt;
		pageCheckboxes.forEach(generateArrowLinks);&lt;br /&gt;
		Morebits.checkboxShiftClickSupport(pageCheckboxes);&lt;br /&gt;
&lt;br /&gt;
	}, statelem);&lt;br /&gt;
&lt;br /&gt;
	wikipedia_api.params = { form: form, Window: Window };&lt;br /&gt;
	wikipedia_api.post();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function generateArrowLinks (checkbox) {&lt;br /&gt;
	var link = Morebits.htmlNode('a', ' &amp;gt;');&lt;br /&gt;
	link.setAttribute('class', 'tw-dbatch-page-link');&lt;br /&gt;
	link.setAttribute('href', mw.util.getUrl(checkbox.value));&lt;br /&gt;
	link.setAttribute('target', '_blank');&lt;br /&gt;
	checkbox.nextElementSibling.append(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Twinkle.batchdelete.generateNewPageList = function(form) {&lt;br /&gt;
&lt;br /&gt;
	// Update the list of checked pages in Twinkle.batchdelete.pages object&lt;br /&gt;
	var elements = form.elements.pages;&lt;br /&gt;
	if (elements instanceof NodeList) { // if there are multiple pages&lt;br /&gt;
		for (var i = 0; i &amp;lt; elements.length; ++i) {&lt;br /&gt;
			Twinkle.batchdelete.pages[elements[i].value].checked = elements[i].checked;&lt;br /&gt;
		}&lt;br /&gt;
	} else if (elements instanceof HTMLInputElement) { // if there is just one page&lt;br /&gt;
		Twinkle.batchdelete.pages[elements.value].checked = elements.checked;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	return new Morebits.quickForm.element({&lt;br /&gt;
		type: 'checkbox',&lt;br /&gt;
		name: 'pages',&lt;br /&gt;
		id: 'tw-dbatch-pages',&lt;br /&gt;
		list: $.map(Twinkle.batchdelete.pages, function (e) {&lt;br /&gt;
			return e;&lt;br /&gt;
		})&lt;br /&gt;
	}).render();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
Twinkle.batchdelete.callback.toggleSubpages = function twDbatchToggleSubpages(e) {&lt;br /&gt;
&lt;br /&gt;
	var form = e.target.form;&lt;br /&gt;
	var newPageList, pageCheckboxes, subpageCheckboxes;&lt;br /&gt;
&lt;br /&gt;
	if (e.target.checked) {&lt;br /&gt;
&lt;br /&gt;
		form.delete_subpage_redirects.checked = form.delete_redirects.checked;&lt;br /&gt;
		form.delete_subpage_talks.checked = form.delete_talk.checked;&lt;br /&gt;
		form.unlink_subpages.checked = form.unlink_page.checked;&lt;br /&gt;
&lt;br /&gt;
		// If lists of subpages were already loaded once, they are&lt;br /&gt;
		// available without use of any API calls&lt;br /&gt;
		if (subpagesLoaded) {&lt;br /&gt;
&lt;br /&gt;
			$.each(Twinkle.batchdelete.pages, function(i, el) {&lt;br /&gt;
				// Get back the subgroup from subgroup_, where we saved it&lt;br /&gt;
				if (el.subgroup === null &amp;amp;&amp;amp; el.subgroup_) {&lt;br /&gt;
					el.subgroup = el.subgroup_;&lt;br /&gt;
				}&lt;br /&gt;
			});&lt;br /&gt;
&lt;br /&gt;
			newPageList = Twinkle.batchdelete.generateNewPageList(form);&lt;br /&gt;
			$('#tw-dbatch-pages').replaceWith(newPageList);&lt;br /&gt;
&lt;br /&gt;
			pageCheckboxes = Morebits.quickForm.getElements(newPageList, 'pages') || [];&lt;br /&gt;
			pageCheckboxes.forEach(generateArrowLinks);&lt;br /&gt;
			Morebits.checkboxShiftClickSupport(pageCheckboxes);&lt;br /&gt;
&lt;br /&gt;
			subpageCheckboxes = Morebits.quickForm.getElements(newPageList, 'pages.subpages') || [];&lt;br /&gt;
			subpageCheckboxes.forEach(generateArrowLinks);&lt;br /&gt;
			Morebits.checkboxShiftClickSupport(subpageCheckboxes);&lt;br /&gt;
&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// Proceed with API calls to get list of subpages&lt;br /&gt;
		var loadingText = '&amp;lt;strong id=&amp;quot;dbatch-subpage-loading&amp;quot;&amp;gt;Loading... &amp;lt;/strong&amp;gt;';&lt;br /&gt;
		$(e.target).after(loadingText);&lt;br /&gt;
&lt;br /&gt;
		var pages = $(form.pages).map(function(i, el) {&lt;br /&gt;
			return el.value;&lt;br /&gt;
		}).get();&lt;br /&gt;
&lt;br /&gt;
		var subpageLister = new Morebits.batchOperation();&lt;br /&gt;
		subpageLister.setOption('chunkSize', Twinkle.getPref('batchdeleteChunks'));&lt;br /&gt;
		subpageLister.setPageList(pages);&lt;br /&gt;
		subpageLister.run(function worker (pageName) {&lt;br /&gt;
			var pageTitle = mw.Title.newFromText(pageName);&lt;br /&gt;
&lt;br /&gt;
			// No need to look for subpages in main/file/mediawiki space&lt;br /&gt;
			if ([0, 6, 8].indexOf(pageTitle.namespace) &amp;gt; -1) {&lt;br /&gt;
				subpageLister.workerSuccess();&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			var wikipedia_api = new Morebits.wiki.api('Getting list of subpages of ' + pageName, {&lt;br /&gt;
				action: 'query',&lt;br /&gt;
				prop: 'revisions|info|imageinfo',&lt;br /&gt;
				generator: 'allpages',&lt;br /&gt;
				rvprop: 'size',&lt;br /&gt;
				inprop: 'protection',&lt;br /&gt;
				gapprefix: pageTitle.title + '/',&lt;br /&gt;
				gapnamespace: pageTitle.namespace,&lt;br /&gt;
				gaplimit: 'max', // 500 is max for normal users, 5000 for bots and sysops&lt;br /&gt;
				pageNameFull: pageName // Not used by API, but added for access in onSuccess()&lt;br /&gt;
			}, function onSuccess(apiobj) {&lt;br /&gt;
				var xml = apiobj.responseXML;&lt;br /&gt;
				var $pages = $(xml).find('page');&lt;br /&gt;
				var subpageList = [];&lt;br /&gt;
				$pages.each(function(index, page) {&lt;br /&gt;
					var $page = $(page);&lt;br /&gt;
					var ns = $page.attr('ns');&lt;br /&gt;
					var title = $page.attr('title');&lt;br /&gt;
					var isRedir = $page.attr('redirect') === '';&lt;br /&gt;
					var $editprot = $page.find('pr[type=&amp;quot;edit&amp;quot;][level=&amp;quot;sysop&amp;quot;]');&lt;br /&gt;
&lt;br /&gt;
					var isProtected = $editprot.length &amp;gt; 0;&lt;br /&gt;
					var size = $page.find('rev').attr('size');&lt;br /&gt;
&lt;br /&gt;
					var metadata = [];&lt;br /&gt;
					if (isRedir) {&lt;br /&gt;
						metadata.push('redirect');&lt;br /&gt;
					}&lt;br /&gt;
					if (isProtected) {&lt;br /&gt;
						metadata.push('fully protected' +&lt;br /&gt;
						($editprot.attr('expiry') === 'infinity' ? ' indefinitely' : ', expires ' + new Morebits.date($editprot.attr('expiry')).calendar('utc') + ' (UTC)'));&lt;br /&gt;
					}&lt;br /&gt;
					if (ns === '6') {  // mimic what delimages used to show for files&lt;br /&gt;
						metadata.push('uploader: ' + $page.find('ii').attr('user'));&lt;br /&gt;
						metadata.push('last edit from: ' + $page.find('rev').attr('user'));&lt;br /&gt;
					} else {&lt;br /&gt;
						metadata.push(size + ' bytes');&lt;br /&gt;
					}&lt;br /&gt;
					subpageList.push({&lt;br /&gt;
						label: title + (metadata.length ? ' (' + metadata.join('; ') + ')' : ''),&lt;br /&gt;
						value: title,&lt;br /&gt;
						checked: true,&lt;br /&gt;
						style: isProtected ? 'color:red' : ''&lt;br /&gt;
					});&lt;br /&gt;
				});&lt;br /&gt;
				if (subpageList.length) {&lt;br /&gt;
					var pageName = apiobj.query.pageNameFull;&lt;br /&gt;
					Twinkle.batchdelete.pages[pageName].subgroup = {&lt;br /&gt;
						type: 'checkbox',&lt;br /&gt;
						name: 'subpages',&lt;br /&gt;
						className: 'dbatch-subpages',&lt;br /&gt;
						list: subpageList&lt;br /&gt;
					};&lt;br /&gt;
				}&lt;br /&gt;
				subpageLister.workerSuccess();&lt;br /&gt;
			}, null /* statusElement */, function onFailure() {&lt;br /&gt;
				subpageLister.workerFailure();&lt;br /&gt;
			});&lt;br /&gt;
			wikipedia_api.post();&lt;br /&gt;
&lt;br /&gt;
		}, function postFinish () {&lt;br /&gt;
			// List 'em on the interface&lt;br /&gt;
&lt;br /&gt;
			newPageList = Twinkle.batchdelete.generateNewPageList(form);&lt;br /&gt;
			$('#tw-dbatch-pages').replaceWith(newPageList);&lt;br /&gt;
&lt;br /&gt;
			pageCheckboxes = Morebits.quickForm.getElements(newPageList, 'pages') || [];&lt;br /&gt;
			pageCheckboxes.forEach(generateArrowLinks);&lt;br /&gt;
			Morebits.checkboxShiftClickSupport(pageCheckboxes);&lt;br /&gt;
&lt;br /&gt;
			subpageCheckboxes = Morebits.quickForm.getElements(newPageList, 'pages.subpages') || [];&lt;br /&gt;
			subpageCheckboxes.forEach(generateArrowLinks);&lt;br /&gt;
			Morebits.checkboxShiftClickSupport(subpageCheckboxes);&lt;br /&gt;
&lt;br /&gt;
			subpagesLoaded = true;&lt;br /&gt;
&lt;br /&gt;
			// Remove &amp;quot;Loading... &amp;quot; text&lt;br /&gt;
			$('#dbatch-subpage-loading').remove();&lt;br /&gt;
&lt;br /&gt;
		});&lt;br /&gt;
&lt;br /&gt;
	} else if (!e.target.checked) {&lt;br /&gt;
&lt;br /&gt;
		$.each(Twinkle.batchdelete.pages, function(i, el) {&lt;br /&gt;
			if (el.subgroup) {&lt;br /&gt;
				// Remove subgroup after saving its contents in subgroup_&lt;br /&gt;
				// so that it can be retrieved easily if user decides to&lt;br /&gt;
				// delete the subpages again&lt;br /&gt;
				el.subgroup_ = el.subgroup;&lt;br /&gt;
				el.subgroup = null;&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
&lt;br /&gt;
		newPageList = Twinkle.batchdelete.generateNewPageList(form);&lt;br /&gt;
		$('#tw-dbatch-pages').replaceWith(newPageList);&lt;br /&gt;
&lt;br /&gt;
		pageCheckboxes = Morebits.quickForm.getElements(newPageList, 'pages') || [];&lt;br /&gt;
		pageCheckboxes.forEach(generateArrowLinks);&lt;br /&gt;
		Morebits.checkboxShiftClickSupport(pageCheckboxes);&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
Twinkle.batchdelete.callback.evaluate = function twinklebatchdeleteCallbackEvaluate(event) {&lt;br /&gt;
	Morebits.wiki.actionCompleted.notice = 'Batch deletion is now complete';&lt;br /&gt;
&lt;br /&gt;
	var form = event.target;&lt;br /&gt;
&lt;br /&gt;
	var numProtected = $(Morebits.quickForm.getElements(form, 'pages')).filter(function(index, element) {&lt;br /&gt;
		return element.checked &amp;amp;&amp;amp; element.nextElementSibling.style.color === 'red';&lt;br /&gt;
	}).length;&lt;br /&gt;
	if (numProtected &amp;gt; 0 &amp;amp;&amp;amp; !confirm('You are about to delete ' + numProtected + ' fully protected page(s). Are you sure?')) {&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	var pages = form.getChecked('pages');&lt;br /&gt;
	var subpages = form.getChecked('pages.subpages');&lt;br /&gt;
	var reason = form.reason.value;&lt;br /&gt;
	var delete_page = form.delete_page.checked;&lt;br /&gt;
	var delete_talk, delete_redirects, delete_subpages;&lt;br /&gt;
	var delete_subpage_redirects, delete_subpage_talks, unlink_subpages;&lt;br /&gt;
	if (delete_page) {&lt;br /&gt;
		delete_talk = form.delete_talk.checked;&lt;br /&gt;
		delete_redirects = form.delete_redirects.checked;&lt;br /&gt;
		delete_subpages = form.delete_subpages.checked;&lt;br /&gt;
		if (delete_subpages) {&lt;br /&gt;
			delete_subpage_redirects = form.delete_subpage_redirects.checked;&lt;br /&gt;
			delete_subpage_talks = form.delete_subpage_talks.checked;&lt;br /&gt;
			unlink_subpages = form.unlink_subpages.checked;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	var unlink_page = form.unlink_page.checked;&lt;br /&gt;
	var unlink_file = form.unlink_file.checked;&lt;br /&gt;
	if (!reason) {&lt;br /&gt;
		alert('You need to give a reason, you cabal crony!');&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	Morebits.simpleWindow.setButtonsEnabled(false);&lt;br /&gt;
	Morebits.status.init(form);&lt;br /&gt;
	if (!pages) {&lt;br /&gt;
		Morebits.status.error('Error', 'nothing to delete, aborting');&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	var pageDeleter = new Morebits.batchOperation(delete_page ? 'Deleting pages' : 'Initiating requested tasks');&lt;br /&gt;
	pageDeleter.setOption('chunkSize', Twinkle.getPref('batchdeleteChunks'));&lt;br /&gt;
	// we only need the initial status lines if we're deleting the pages in the pages array&lt;br /&gt;
	pageDeleter.setOption('preserveIndividualStatusLines', delete_page);&lt;br /&gt;
	pageDeleter.setPageList(pages);&lt;br /&gt;
	pageDeleter.run(function worker(pageName) {&lt;br /&gt;
		var params = {&lt;br /&gt;
			page: pageName,&lt;br /&gt;
			delete_page: delete_page,&lt;br /&gt;
			delete_talk: delete_talk,&lt;br /&gt;
			delete_redirects: delete_redirects,&lt;br /&gt;
			unlink_page: unlink_page,&lt;br /&gt;
			unlink_file: unlink_file &amp;amp;&amp;amp; /^(File|Image):/i.test(pageName),&lt;br /&gt;
			reason: reason,&lt;br /&gt;
			pageDeleter: pageDeleter&lt;br /&gt;
		};&lt;br /&gt;
&lt;br /&gt;
		var wikipedia_page = new Morebits.wiki.page(pageName, 'Deleting page ' + pageName);&lt;br /&gt;
		wikipedia_page.setCallbackParameters(params);&lt;br /&gt;
		if (delete_page) {&lt;br /&gt;
			wikipedia_page.setEditSummary(reason + Twinkle.getPref('deletionSummaryAd'));&lt;br /&gt;
			wikipedia_page.suppressProtectWarning();&lt;br /&gt;
			wikipedia_page.deletePage(Twinkle.batchdelete.callbacks.doExtras, pageDeleter.workerFailure);&lt;br /&gt;
		} else {&lt;br /&gt;
			Twinkle.batchdelete.callbacks.doExtras(wikipedia_page);&lt;br /&gt;
		}&lt;br /&gt;
	}, function postFinish() {&lt;br /&gt;
		if (delete_subpages) {&lt;br /&gt;
			var subpageDeleter = new Morebits.batchOperation('Deleting subpages');&lt;br /&gt;
			subpageDeleter.setOption('chunkSize', Twinkle.getPref('batchdeleteChunks'));&lt;br /&gt;
			subpageDeleter.setOption('preserveIndividualStatusLines', true);&lt;br /&gt;
			subpageDeleter.setPageList(subpages);&lt;br /&gt;
			subpageDeleter.run(function(pageName) {&lt;br /&gt;
				var params = {&lt;br /&gt;
					page: pageName,&lt;br /&gt;
					delete_page: true,&lt;br /&gt;
					delete_talk: delete_subpage_talks,&lt;br /&gt;
					delete_redirects: delete_subpage_redirects,&lt;br /&gt;
					unlink_page: unlink_subpages,&lt;br /&gt;
					unlink_file: false,&lt;br /&gt;
					reason: reason,&lt;br /&gt;
					pageDeleter: subpageDeleter&lt;br /&gt;
				};&lt;br /&gt;
&lt;br /&gt;
				var wikipedia_page = new Morebits.wiki.page(pageName, 'Deleting subpage ' + pageName);&lt;br /&gt;
				wikipedia_page.setCallbackParameters(params);&lt;br /&gt;
				wikipedia_page.setEditSummary(reason + Twinkle.getPref('deletionSummaryAd'));&lt;br /&gt;
				wikipedia_page.suppressProtectWarning();&lt;br /&gt;
				wikipedia_page.deletePage(Twinkle.batchdelete.callbacks.doExtras, pageDeleter.workerFailure);&lt;br /&gt;
			});&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
Twinkle.batchdelete.callbacks = {&lt;br /&gt;
	// this stupid parameter name is a temporary thing until I implement an overhaul&lt;br /&gt;
	// of Morebits.wiki.* callback parameters&lt;br /&gt;
	doExtras: function(thingWithParameters) {&lt;br /&gt;
		var params = thingWithParameters.parent ? thingWithParameters.parent.getCallbackParameters() :&lt;br /&gt;
			thingWithParameters.getCallbackParameters();&lt;br /&gt;
		// the initial batch operation's job is to delete the page, and that has&lt;br /&gt;
		// succeeded by now&lt;br /&gt;
		params.pageDeleter.workerSuccess(thingWithParameters);&lt;br /&gt;
&lt;br /&gt;
		var query, wikipedia_api;&lt;br /&gt;
&lt;br /&gt;
		if (params.unlink_page) {&lt;br /&gt;
			Twinkle.batchdelete.unlinkCache = {};&lt;br /&gt;
			query = {&lt;br /&gt;
				'action': 'query',&lt;br /&gt;
				'list': 'backlinks',&lt;br /&gt;
				'blfilterredir': 'nonredirects',&lt;br /&gt;
				'blnamespace': [0, 100], // main space and portal space only&lt;br /&gt;
				'bltitle': params.page,&lt;br /&gt;
				'bllimit': 'max' // 500 is max for normal users, 5000 for bots and sysops&lt;br /&gt;
			};&lt;br /&gt;
			wikipedia_api = new Morebits.wiki.api('Grabbing backlinks', query, Twinkle.batchdelete.callbacks.unlinkBacklinksMain);&lt;br /&gt;
			wikipedia_api.params = params;&lt;br /&gt;
			wikipedia_api.post();&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		if (params.unlink_file) {&lt;br /&gt;
			query = {&lt;br /&gt;
				'action': 'query',&lt;br /&gt;
				'list': 'imageusage',&lt;br /&gt;
				'iutitle': params.page,&lt;br /&gt;
				'iulimit': 'max' // 500 is max for normal users, 5000 for bots and sysops&lt;br /&gt;
			};&lt;br /&gt;
			wikipedia_api = new Morebits.wiki.api('Grabbing file links', query, Twinkle.batchdelete.callbacks.unlinkImageInstancesMain);&lt;br /&gt;
			wikipedia_api.params = params;&lt;br /&gt;
			wikipedia_api.post();&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		if (params.delete_page) {&lt;br /&gt;
			if (params.delete_redirects) {&lt;br /&gt;
				query = {&lt;br /&gt;
					'action': 'query',&lt;br /&gt;
					'titles': params.page,&lt;br /&gt;
					'prop': 'redirects',&lt;br /&gt;
					'rdlimit': 'max' // 500 is max for normal users, 5000 for bots and sysops&lt;br /&gt;
				};&lt;br /&gt;
				wikipedia_api = new Morebits.wiki.api('Grabbing redirects', query, Twinkle.batchdelete.callbacks.deleteRedirectsMain);&lt;br /&gt;
				wikipedia_api.params = params;&lt;br /&gt;
				wikipedia_api.post();&lt;br /&gt;
			}&lt;br /&gt;
			if (params.delete_talk) {&lt;br /&gt;
				var pageTitle = mw.Title.newFromText(params.page);&lt;br /&gt;
				if (pageTitle &amp;amp;&amp;amp; pageTitle.namespace % 2 === 0 &amp;amp;&amp;amp; pageTitle.namespace !== 2) {&lt;br /&gt;
					pageTitle.namespace++;  // now pageTitle is the talk page title!&lt;br /&gt;
					query = {&lt;br /&gt;
						'action': 'query',&lt;br /&gt;
						'titles': pageTitle.toText()&lt;br /&gt;
					};&lt;br /&gt;
					wikipedia_api = new Morebits.wiki.api('Checking whether talk page exists', query, Twinkle.batchdelete.callbacks.deleteTalk);&lt;br /&gt;
					wikipedia_api.params = params;&lt;br /&gt;
					wikipedia_api.params.talkPage = pageTitle.toText();&lt;br /&gt;
					wikipedia_api.post();&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	},&lt;br /&gt;
	deleteRedirectsMain: function(apiobj) {&lt;br /&gt;
		var xml = apiobj.responseXML;&lt;br /&gt;
		var pages = $(xml).find('rd').map(function() {&lt;br /&gt;
			return $(this).attr('title');&lt;br /&gt;
		}).get();&lt;br /&gt;
		if (!pages.length) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		var redirectDeleter = new Morebits.batchOperation('Deleting redirects to ' + apiobj.params.page);&lt;br /&gt;
		redirectDeleter.setOption('chunkSize', Twinkle.getPref('batchdeleteChunks'));&lt;br /&gt;
		redirectDeleter.setPageList(pages);&lt;br /&gt;
		redirectDeleter.run(function(pageName) {&lt;br /&gt;
			var wikipedia_page = new Morebits.wiki.page(pageName, 'Deleting ' + pageName);&lt;br /&gt;
			wikipedia_page.setEditSummary('[[WP:CSD#G8|G8]]: Redirect to deleted page &amp;quot;' + apiobj.params.page + '&amp;quot;' + Twinkle.getPref('deletionSummaryAd'));&lt;br /&gt;
			wikipedia_page.deletePage(redirectDeleter.workerSuccess, redirectDeleter.workerFailure);&lt;br /&gt;
		});&lt;br /&gt;
	},&lt;br /&gt;
	deleteTalk: function(apiobj) {&lt;br /&gt;
		var xml = apiobj.responseXML;&lt;br /&gt;
		var exists = $(xml).find('page:not([missing])').length &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
		if (!exists) {&lt;br /&gt;
			// no talk page; forget about it&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		var page = new Morebits.wiki.page(apiobj.params.talkPage, 'Deleting talk page of article ' + apiobj.params.page);&lt;br /&gt;
		page.setEditSummary('[[WP:CSD#G8|G8]]: [[Help:Talk page|Talk page]] of deleted page &amp;quot;' + apiobj.params.page + '&amp;quot;' + Twinkle.getPref('deletionSummaryAd'));&lt;br /&gt;
		page.deletePage();&lt;br /&gt;
	},&lt;br /&gt;
	unlinkBacklinksMain: function(apiobj) {&lt;br /&gt;
		var xml = apiobj.responseXML;&lt;br /&gt;
		var pages = $(xml).find('bl').map(function() {&lt;br /&gt;
			return $(this).attr('title');&lt;br /&gt;
		}).get();&lt;br /&gt;
		if (!pages.length) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		var unlinker = new Morebits.batchOperation('Unlinking backlinks to ' + apiobj.params.page);&lt;br /&gt;
		unlinker.setOption('chunkSize', Twinkle.getPref('batchdeleteChunks'));&lt;br /&gt;
		unlinker.setPageList(pages);&lt;br /&gt;
		unlinker.run(function(pageName) {&lt;br /&gt;
			var wikipedia_page = new Morebits.wiki.page(pageName, 'Unlinking on ' + pageName);&lt;br /&gt;
			var params = $.extend({}, apiobj.params);&lt;br /&gt;
			params.title = pageName;&lt;br /&gt;
			params.unlinker = unlinker;&lt;br /&gt;
			wikipedia_page.setCallbackParameters(params);&lt;br /&gt;
			wikipedia_page.load(Twinkle.batchdelete.callbacks.unlinkBacklinks);&lt;br /&gt;
		});&lt;br /&gt;
	},&lt;br /&gt;
	unlinkBacklinks: function(pageobj) {&lt;br /&gt;
		var params = pageobj.getCallbackParameters();&lt;br /&gt;
		if (!pageobj.exists()) {&lt;br /&gt;
			// we probably just deleted it, as a recursive backlink&lt;br /&gt;
			params.unlinker.workerSuccess(pageobj);&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		var text;&lt;br /&gt;
		if (params.title in Twinkle.batchdelete.unlinkCache) {&lt;br /&gt;
			text = Twinkle.batchdelete.unlinkCache[params.title];&lt;br /&gt;
		} else {&lt;br /&gt;
			text = pageobj.getPageText();&lt;br /&gt;
		}&lt;br /&gt;
		var old_text = text;&lt;br /&gt;
		var wikiPage = new Morebits.wikitext.page(text);&lt;br /&gt;
		wikiPage.removeLink(params.page);&lt;br /&gt;
&lt;br /&gt;
		text = wikiPage.getText();&lt;br /&gt;
		Twinkle.batchdelete.unlinkCache[params.title] = text;&lt;br /&gt;
		if (text === old_text) {&lt;br /&gt;
			// Nothing to do, return&lt;br /&gt;
			params.unlinker.workerSuccess(pageobj);&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		pageobj.setEditSummary('Removing link(s) to deleted page ' + params.page + Twinkle.getPref('deletionSummaryAd'));&lt;br /&gt;
		pageobj.setPageText(text);&lt;br /&gt;
		pageobj.setCreateOption('nocreate');&lt;br /&gt;
		pageobj.setMaxConflictRetries(10);&lt;br /&gt;
		pageobj.save(params.unlinker.workerSuccess, params.unlinker.workerFailure);&lt;br /&gt;
	},&lt;br /&gt;
	unlinkImageInstancesMain: function(apiobj) {&lt;br /&gt;
		var xml = apiobj.responseXML;&lt;br /&gt;
		var pages = $(xml).find('iu').map(function() {&lt;br /&gt;
			return $(this).attr('title');&lt;br /&gt;
		}).get();&lt;br /&gt;
		if (!pages.length) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		var unlinker = new Morebits.batchOperation('Unlinking backlinks to ' + apiobj.params.page);&lt;br /&gt;
		unlinker.setOption('chunkSize', Twinkle.getPref('batchdeleteChunks'));&lt;br /&gt;
		unlinker.setPageList(pages);&lt;br /&gt;
		unlinker.run(function(pageName) {&lt;br /&gt;
			var wikipedia_page = new Morebits.wiki.page(pageName, 'Removing file usages on ' + pageName);&lt;br /&gt;
			var params = $.extend({}, apiobj.params);&lt;br /&gt;
			params.title = pageName;&lt;br /&gt;
			params.unlinker = unlinker;&lt;br /&gt;
			wikipedia_page.setCallbackParameters(params);&lt;br /&gt;
			wikipedia_page.load(Twinkle.batchdelete.callbacks.unlinkImageInstances);&lt;br /&gt;
		});&lt;br /&gt;
	},&lt;br /&gt;
	unlinkImageInstances: function(pageobj) {&lt;br /&gt;
		var params = pageobj.getCallbackParameters();&lt;br /&gt;
		if (!pageobj.exists()) {&lt;br /&gt;
			// we probably just deleted it, as a recursive backlink&lt;br /&gt;
			params.unlinker.workerSuccess(pageobj);&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		var image = params.page.replace(/^(?:Image|File):/, '');&lt;br /&gt;
		var text;&lt;br /&gt;
		if (params.title in Twinkle.batchdelete.unlinkCache) {&lt;br /&gt;
			text = Twinkle.batchdelete.unlinkCache[params.title];&lt;br /&gt;
		} else {&lt;br /&gt;
			text = pageobj.getPageText();&lt;br /&gt;
		}&lt;br /&gt;
		var old_text = text;&lt;br /&gt;
		var wikiPage = new Morebits.wikitext.page(text);&lt;br /&gt;
		wikiPage.commentOutImage(image, 'Commented out because image was deleted');&lt;br /&gt;
&lt;br /&gt;
		text = wikiPage.getText();&lt;br /&gt;
		Twinkle.batchdelete.unlinkCache[params.title] = text;&lt;br /&gt;
		if (text === old_text) {&lt;br /&gt;
			pageobj.getStatusElement().error('failed to unlink image ' + image + ' from ' + pageobj.getPageName());&lt;br /&gt;
			params.unlinker.workerFailure(pageobj);&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		pageobj.setEditSummary('Removing instance of file ' + image + ' that has been deleted because &amp;quot;' + params.reason + '&amp;quot;)' + Twinkle.getPref('deletionSummaryAd'));&lt;br /&gt;
		pageobj.setPageText(text);&lt;br /&gt;
		pageobj.setCreateOption('nocreate');&lt;br /&gt;
		pageobj.setMaxConflictRetries(10);&lt;br /&gt;
		pageobj.save(params.unlinker.workerSuccess, params.unlinker.workerFailure);&lt;br /&gt;
	}&lt;br /&gt;
};&lt;br /&gt;
})(jQuery);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>en&gt;Amorymeltzer</name></author>
	</entry>
</feed>